unofficial mirror of bug-gnu-emacs@gnu.org 
 help / color / mirror / code / Atom feed
* bug#56538: 29.0.50; [PATCH] Colored highlight in Lucid backend
@ 2022-07-13 13:38 Manuel Giraud
  2022-07-14  0:53 ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 1 reply; 13+ messages in thread
From: Manuel Giraud @ 2022-07-13 13:38 UTC (permalink / raw)
  To: 56538

[-- Attachment #1: Type: text/plain, Size: 499 bytes --]


Hi,

Here is a patch that add a X resource to color the highlighted menu
entry in the Lucid backend.  There is much going on here because I
needed to understand this code and end up needed to refactor some part
to implement this feature.  This was about ten clunky patches that I
finally squashed into this one.

I have tested that it works with the 2 following configuration
     - 	--with-x-toolkit=athena
     - 	--with-x-toolkit=athena --without-xft --without-cairo

Here is how it looks like:

[-- Attachment #2: sshot.png --]
[-- Type: image/png, Size: 98806 bytes --]

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #3: 0001-Colored-menu-highlight-in-Lucid-backend.patch --]
[-- Type: text/x-patch, Size: 26131 bytes --]

From f51e1dbd3174d727a12e673e0b820b4cf35e7046 Mon Sep 17 00:00:00 2001
From: Manuel Giraud <manuel@ledu-giraud.fr>
Date: Mon, 11 Jul 2022 11:14:08 +0200
Subject: [PATCH] Colored menu highlight in Lucid backend

* lwlib/xlwmenuP.h:
* lwlib/xlwmenu.h:
* lwlib/xlwmenu.c: Introduce resources to handle colored highlighting
of menu entries.
* doc/emacs/xresources.texi (Lucid Resources): Documentation.
---
 doc/emacs/xresources.texi |   4 +
 etc/NEWS                  |   4 +
 lwlib/xlwmenu.c           | 341 ++++++++++++++++++++++++++++----------
 lwlib/xlwmenu.h           |  14 ++
 lwlib/xlwmenuP.h          |  18 +-
 5 files changed, 293 insertions(+), 88 deletions(-)

diff --git a/doc/emacs/xresources.texi b/doc/emacs/xresources.texi
index 2c2700bc15..f8be06b5e7 100644
--- a/doc/emacs/xresources.texi
+++ b/doc/emacs/xresources.texi
@@ -449,6 +449,10 @@ Lucid Resources
 Foreground color.
 @item disabledForeground
 Foreground color for a disabled menu item.
+@item highlightForeground
+Foreground color for a highlighted menu item.
+@item highlightBackground
+Background color for a highlighted menu item.
 @ifnottex
 @item horizontalSpacing
 Horizontal spacing in pixels between items.  Default is 3.
diff --git a/etc/NEWS b/etc/NEWS
index bf36316890..b33d604a6f 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -544,6 +544,10 @@ and pop-up menus.
 This controls the style of the pre-edit and status areas of X input
 methods.
 
++++
+** New X resources: "highlightForeground" and "highlightBackground"
+This controls colors used for highlighted menu item.
+
 +++
 ** On X11, Emacs now tries to synchronize window resize with the window manager.
 This leads to less flicker and empty areas of a frame being displayed
diff --git a/lwlib/xlwmenu.c b/lwlib/xlwmenu.c
index 68f49e646d..32310e18ef 100644
--- a/lwlib/xlwmenu.c
+++ b/lwlib/xlwmenu.c
@@ -121,6 +121,10 @@ #define DEFAULT_FONTNAME "XtDefaultFont"
    offset(menu.disabled_foreground), XtRString, (XtPointer)NULL},
   {XtNbuttonForeground, XtCButtonForeground, XtRPixel, sizeof(Pixel),
      offset(menu.button_foreground), XtRString, "XtDefaultForeground"},
+  {XtNhighlightForeground, XtCHighlightForeground, XtRPixel, sizeof(Pixel),
+   offset(menu.highlight_foreground), XtRString, "XtDefaultForeground"},
+  {XtNhighlightBackground, XtCHighlightBackground, XtRPixel, sizeof(Pixel),
+   offset(menu.highlight_background), XtRImmediate, (XtPointer)-1},
   {XtNmargin, XtCMargin, XtRDimension,  sizeof(Dimension),
      offset(menu.margin), XtRImmediate, (XtPointer)1},
   {XtNhorizontalSpacing, XtCMargin, XtRDimension,  sizeof(Dimension),
@@ -142,6 +146,19 @@ #define DEFAULT_FONTNAME "XtDefaultFont"
   {XmNbottomShadowPixmap, XmCBottomShadowPixmap, XtRPixmap, sizeof (Pixmap),
      offset (menu.bottom_shadow_pixmap), XtRImmediate, (XtPointer)None},
 
+  {XmNtopHighlightShadowColor, XmCTopHighlightShadowColor, XtRPixel,
+   sizeof (Pixel), offset (menu.top_highlight_shadow_color),
+   XtRImmediate, (XtPointer)-1},
+  {XmNbottomHighlightShadowColor, XmCBottomHighlightShadowColor, XtRPixel,
+   sizeof (Pixel), offset (menu.bottom_highlight_shadow_color),
+   XtRImmediate, (XtPointer)-1},
+  {XmNtopHighlightShadowPixmap, XmCTopHighlightShadowPixmap, XtRPixmap,
+   sizeof (Pixmap), offset (menu.top_highlight_shadow_pixmap),XtRImmediate,
+   (XtPointer)None},
+  {XmNbottomHighlightShadowPixmap, XmCBottomHighlightShadowPixmap, XtRPixmap,
+   sizeof (Pixmap), offset (menu.bottom_highlight_shadow_pixmap),XtRImmediate,
+   (XtPointer)None},
+
   {XtNopen, XtCCallback, XtRCallback, sizeof(XtPointer),
      offset(menu.open), XtRCallback, (XtPointer)NULL},
   {XtNselect, XtCCallback, XtRCallback, sizeof(XtPointer),
@@ -570,8 +587,7 @@ draw_arrow (XlwMenuWidget mw,
             int down_p)
 {
   Display *dpy = XtDisplay (mw);
-  GC top_gc = mw->menu.shadow_top_gc;
-  GC bottom_gc = mw->menu.shadow_bottom_gc;
+  GC top_gc, bottom_gc;
   int thickness = mw->menu.shadow_thickness;
   int height = width;
   XPoint pt[10];
@@ -584,10 +600,14 @@ draw_arrow (XlwMenuWidget mw,
 
   if (down_p)
     {
-      GC temp;
-      temp = top_gc;
-      top_gc = bottom_gc;
-      bottom_gc = temp;
+      /* XXX the following permutation is on purpose */
+      top_gc = mw->menu.highlight_shadow_bottom_gc;
+      bottom_gc = mw->menu.highlight_shadow_top_gc;
+    }
+  else
+    {
+      top_gc = mw->menu.shadow_top_gc;
+      bottom_gc = mw->menu.shadow_bottom_gc;
     }
 
   pt[0].x = x;
@@ -621,8 +641,12 @@ draw_arrow (XlwMenuWidget mw,
   XFillPolygon (dpy, window, bottom_gc, pt, 4, Convex, CoordModeOrigin);
 }
 
-
-
+/*
+ * Generic draw shadow rectangle function.  It is used to draw menus, menu items
+ * and also toggle buttons.  When ERASE_P is true, it clears shadows.  DOWN_P is
+ * true when a menu item is pushed or a button toggled.  TOP_GC and BOTTOM_GC
+ * are the graphic contexts used to draw the top and bottom shadow respectively.
+ */
 static void
 draw_shadow_rectangle (XlwMenuWidget mw,
                        Window window,
@@ -631,14 +655,28 @@ draw_shadow_rectangle (XlwMenuWidget mw,
                        int width,
                        int height,
                        int erase_p,
-                       int down_p)
+                       int down_p,
+		       GC top_gc,
+		       GC bottom_gc)
 {
   Display *dpy = XtDisplay (mw);
-  GC top_gc = !erase_p ? mw->menu.shadow_top_gc : mw->menu.background_gc;
-  GC bottom_gc = !erase_p ? mw->menu.shadow_bottom_gc : mw->menu.background_gc;
   int thickness = !x && !y ? mw->menu.border_thickness : mw->menu.shadow_thickness;
   XPoint points [4];
 
+  /* Choose correct GC with a standard default if NULL */
+  if (erase_p)
+    {
+      top_gc = mw->menu.background_gc;
+      bottom_gc = mw->menu.background_gc;
+    }
+  else
+    {
+      if (top_gc == NULL)
+	top_gc = mw->menu.shadow_top_gc;
+      if (bottom_gc == NULL)
+	bottom_gc = mw->menu.shadow_bottom_gc;
+    }
+
   if (!erase_p && width == height && width == toggle_button_width (mw))
     {
       points [0].x = x;
@@ -654,6 +692,7 @@ draw_shadow_rectangle (XlwMenuWidget mw,
                     points, 4, Convex, CoordModeOrigin);
     }
 
+
   if (!erase_p && down_p)
     {
       GC temp;
@@ -662,6 +701,7 @@ draw_shadow_rectangle (XlwMenuWidget mw,
       bottom_gc = temp;
     }
 
+  /* Do draw (or erase) shadows */
   points [0].x = x;
   points [0].y = y;
   points [1].x = x + width;
@@ -709,14 +749,28 @@ draw_shadow_rhombus (XlwMenuWidget mw,
                      int width,
                      int height,
                      int erase_p,
-                     int down_p)
+                     int down_p,
+		     GC top_gc,
+		     GC bottom_gc)
 {
   Display *dpy = XtDisplay (mw);
-  GC top_gc = !erase_p ? mw->menu.shadow_top_gc : mw->menu.background_gc;
-  GC bottom_gc = !erase_p ? mw->menu.shadow_bottom_gc : mw->menu.background_gc;
   int thickness = mw->menu.shadow_thickness;
   XPoint points [4];
 
+  /* Choose correct GC with a standard default if NULL */
+  if (erase_p)
+    {
+      top_gc = mw->menu.background_gc;
+      bottom_gc = mw->menu.background_gc;
+    }
+  else
+    {
+      if (top_gc == NULL)
+	top_gc = mw->menu.shadow_top_gc;
+      if (bottom_gc == NULL)
+	top_gc = mw->menu.shadow_bottom_gc;
+    }
+
   if (!erase_p && width == height && width == radio_button_width (mw))
     {
       points [0].x = x;
@@ -784,15 +838,29 @@ draw_shadow_rhombus (XlwMenuWidget mw,
    toggle button is selected.  */
 
 static void
-draw_toggle (XlwMenuWidget mw, Window window, int x, int y, int selected_p)
+draw_toggle (XlwMenuWidget mw, Window window, int x, int y, int selected_p,
+	     int highlighted_p)
 {
   int width, height;
+  GC top_gc, bottom_gc;
+
+  if (highlighted_p)
+    {
+      top_gc = mw->menu.highlight_shadow_top_gc;
+      bottom_gc = mw->menu.highlight_shadow_bottom_gc;
+    }
+  else
+    {
+      top_gc = mw->menu.shadow_top_gc;
+      bottom_gc = mw->menu.shadow_bottom_gc;
+    }
 
   width = toggle_button_width (mw);
   height = width;
   x += mw->menu.horizontal_spacing;
   y += (MENU_FONT_ASCENT (mw) - height) / 2;
-  draw_shadow_rectangle (mw, window, x, y, width, height, False, selected_p);
+  draw_shadow_rectangle (mw, window, x, y, width, height, False,
+			 selected_p, top_gc, bottom_gc);
 }
 
 
@@ -801,15 +869,29 @@ draw_toggle (XlwMenuWidget mw, Window window, int x, int y, int selected_p)
    toggle button is selected.  */
 
 static void
-draw_radio (XlwMenuWidget mw, Window window, int x, int y, int selected_p)
+draw_radio (XlwMenuWidget mw, Window window, int x, int y, int selected_p,
+	    int highlighted_p)
 {
   int width, height;
+  GC top_gc, bottom_gc;
+
+  if (highlighted_p)
+    {
+      top_gc = mw->menu.highlight_shadow_top_gc;
+      bottom_gc = mw->menu.highlight_shadow_bottom_gc;
+    }
+  else
+    {
+      top_gc = mw->menu.shadow_top_gc;
+      bottom_gc = mw->menu.shadow_bottom_gc;
+    }
 
   width = radio_button_width (mw);
   height = width;
   x += mw->menu.horizontal_spacing;
   y += (MENU_FONT_ASCENT (mw) - height) / 2;
-  draw_shadow_rhombus (mw, window, x, y, width, height, False, selected_p);
+  draw_shadow_rhombus (mw, window, x, y, width, height, False, selected_p,
+		       top_gc, bottom_gc);
 }
 
 
@@ -968,6 +1050,33 @@ separator_height (enum menu_separator separator)
     }
 }
 
+static void
+draw_highlight (XlwMenuWidget mw,
+		Window window,
+		int x,
+		int y,
+		int width,
+		int height)
+{
+  Display *dpy = XtDisplay (mw);
+  XPoint points [4];
+
+  points [0].x = x;
+  points [0].y = y;
+  points [1].x = x + width;
+  points [1].y = y;
+  points [2].x = x + width;
+  points [2].y = y + height;
+  points [3].x = x;
+  points [3].y = y + height;
+  XFillPolygon (dpy, window,
+		mw->menu.highlight_background_gc,
+		points, 4, Convex, CoordModeOrigin);
+
+  draw_shadow_rectangle(mw, window, x, y, width, height, False, False,
+			mw->menu.highlight_shadow_top_gc,
+			mw->menu.highlight_shadow_bottom_gc);
+}
 
 /* Display the menu item and increment where.x and where.y to show how large
    the menu item was.  */
@@ -983,7 +1092,6 @@ display_menu_item (XlwMenuWidget mw,
 {
   GC deco_gc;
   GC text_gc;
-  int font_height = MENU_FONT_HEIGHT (mw);
   int font_ascent = MENU_FONT_ASCENT (mw);
   int shadow = mw->menu.shadow_thickness;
   int margin = mw->menu.margin;
@@ -1032,12 +1140,21 @@ display_menu_item (XlwMenuWidget mw,
 
       /* pick the foreground and background GC. */
       if (val->enabled)
-	text_gc = mw->menu.foreground_gc;
+	if (highlighted_p)
+	  text_gc = mw->menu.highlight_foreground_gc;
+	else
+	  text_gc = mw->menu.foreground_gc;
       else
 	text_gc = mw->menu.disabled_gc;
       deco_gc = mw->menu.foreground_gc;
 #if defined USE_CAIRO || defined HAVE_XFT
-      xftfg = val->enabled ? &mw->menu.xft_fg : &mw->menu.xft_disabled_fg;
+      if (val->enabled)
+	if (highlighted_p)
+	  xftfg = &mw->menu.xft_highlight_fg;
+	else
+	  xftfg = &mw->menu.xft_fg;
+      else
+	xftfg = &mw->menu.xft_disabled_fg;
 #endif
 
       if (separator_p)
@@ -1048,8 +1165,11 @@ display_menu_item (XlwMenuWidget mw,
 	{
 	  int x_offset = x + h_spacing + shadow;
 	  char* display_string = resource_widget_value (mw, val);
-	  draw_shadow_rectangle (mw, ws->pixmap, x, y, width, height, True,
-				 False);
+	  /* Clears shadows and maybe highlight */
+	  draw_shadow_rectangle (mw, ws->pixmap, x, y, width, height,
+				 True, False, NULL, NULL);
+	  if (highlighted_p)
+	    draw_highlight (mw, ws->pixmap, x, y, width, height);
 
 	  /* Deal with centering a menu title. */
 	  if (!horizontal_p && !val->contents && !val->call_data)
@@ -1095,10 +1215,10 @@ display_menu_item (XlwMenuWidget mw,
 	    {
 	      if (val->button_type == BUTTON_TYPE_TOGGLE)
 		draw_toggle (mw, ws->pixmap, x, y + v_spacing + shadow,
-			     val->selected);
+			     val->selected, highlighted_p);
 	      else if (val->button_type == BUTTON_TYPE_RADIO)
 		draw_radio (mw, ws->pixmap, x, y + v_spacing + shadow,
-			    val->selected);
+			    val->selected, highlighted_p);
 
 	      if (val->contents)
 		{
@@ -1145,25 +1265,18 @@ display_menu_item (XlwMenuWidget mw,
 	    }
 	  else
 	    {
-	      XDrawRectangle (XtDisplay (mw), ws->pixmap,
-			      mw->menu.background_gc,
-			      x + shadow, y + shadow,
-			      label_width + h_spacing - 1,
-			      font_height + 2 * v_spacing - 1);
-	      draw_shadow_rectangle (mw, ws->pixmap, x, y, width, height,
-				     True, False);
+	      /* If not highlighted, clears shadows for horizontal
+		 menu item */
+	      if (!highlighted_p)
+		draw_shadow_rectangle (mw, ws->pixmap, x, y, width, height,
+				       True, False, NULL, NULL);
 	    }
 #ifdef USE_CAIRO
 	  if (ws->xft_draw)
 	    cairo_surface_flush (cairo_get_target (ws->xft_draw));
 #endif
-
-	  if (highlighted_p)
-	    draw_shadow_rectangle (mw, ws->pixmap, x, y, width, height, False,
-				   False);
 	}
     }
-
   where->x += width;
   where->y += height;
 }
@@ -1257,7 +1370,7 @@ display_menu (XlwMenuWidget mw,
   if (!just_compute_p)
     {
       draw_shadow_rectangle (mw, ws->pixmap, 0, 0, ws->width, ws->height,
-                             False, False);
+                             False, False, NULL, NULL);
       XCopyArea (XtDisplay (mw), ws->pixmap, ws->window,
                  mw->menu.foreground_gc, 0, 0, ws->width, ws->height, 0, 0);
     }
@@ -1714,6 +1827,16 @@ #define BRIGHTNESS(color) (((color) & 0xff) + (((color) >> 8) & 0xff) + (((color
   xgcv.foreground = mw->core.background_pixel;
   xgcv.background = mw->menu.foreground;
   mw->menu.background_gc = XtGetGC ((Widget)mw, mask, &xgcv);
+
+  xgcv.foreground = mw->menu.highlight_foreground;
+  xgcv.background = (mw->menu.highlight_background == -1) ?
+    mw->core.background_pixel : mw->menu.highlight_background;
+  mw->menu.highlight_foreground_gc = XtGetGC ((Widget)mw, mask, &xgcv);
+
+  xgcv.foreground = (mw->menu.highlight_background == -1) ?
+    mw->core.background_pixel : mw->menu.highlight_background;
+  xgcv.background = mw->menu.foreground;
+  mw->menu.highlight_background_gc = XtGetGC ((Widget)mw, mask, &xgcv);
 }
 
 static void
@@ -1724,12 +1847,16 @@ release_drawing_gcs (XlwMenuWidget mw)
   XtReleaseGC ((Widget) mw, mw->menu.disabled_gc);
   XtReleaseGC ((Widget) mw, mw->menu.inactive_button_gc);
   XtReleaseGC ((Widget) mw, mw->menu.background_gc);
+  XtReleaseGC ((Widget) mw, mw->menu.highlight_foreground_gc);
+  XtReleaseGC ((Widget) mw, mw->menu.highlight_background_gc);
   /* let's get some segvs if we try to use these... */
   mw->menu.foreground_gc = (GC) -1;
   mw->menu.button_gc = (GC) -1;
   mw->menu.disabled_gc = (GC) -1;
   mw->menu.inactive_button_gc = (GC) -1;
   mw->menu.background_gc = (GC) -1;
+  mw->menu.highlight_foreground_gc = (GC) -1;
+  mw->menu.highlight_background_gc = (GC) -1;
 }
 
 #ifndef emacs
@@ -1738,29 +1865,34 @@ #define MINL(x,y) ((((unsigned long) (x)) < ((unsigned long) (y))) \
 #endif
 
 static void
-make_shadow_gcs (XlwMenuWidget mw)
+compute_shadow_colors(XlwMenuWidget mw,
+		      Pixel *top_color,
+		      Pixel *bottom_color,
+		      Boolean *free_top_p,
+		      Boolean *free_bottom_p,
+		      Pixmap *top_pixmap,
+		      Pixmap *bottom_pixmap,
+		      Pixel fore_color,
+		      Pixel back_color)
 {
-  XGCValues xgcv;
-  unsigned long pm = 0;
   Display *dpy = XtDisplay ((Widget) mw);
   Screen *screen = XtScreen ((Widget) mw);
   Colormap cmap = mw->core.colormap;
   XColor topc, botc;
   int top_frobbed = 0, bottom_frobbed = 0;
 
-  mw->menu.free_top_shadow_color_p = 0;
-  mw->menu.free_bottom_shadow_color_p = 0;
+  *free_top_p = False;
+  *free_bottom_p = False;
 
-  if (mw->menu.top_shadow_color == -1)
-    mw->menu.top_shadow_color = mw->core.background_pixel;
+  if (*top_color == -1)
+    *top_color = back_color;
 
-  if (mw->menu.bottom_shadow_color == -1)
-    mw->menu.bottom_shadow_color = mw->menu.foreground;
+  if (*bottom_color == -1)
+    *bottom_color = fore_color;
 
-  if (mw->menu.top_shadow_color == mw->core.background_pixel ||
-      mw->menu.top_shadow_color == mw->menu.foreground)
+  if (*top_color == back_color || *top_color == fore_color)
     {
-      topc.pixel = mw->core.background_pixel;
+      topc.pixel = back_color;
 #ifdef emacs
       if (x_alloc_lighter_color_for_widget ((Widget) mw, dpy, cmap,
 					    &topc.pixel,
@@ -1774,15 +1906,14 @@ make_shadow_gcs (XlwMenuWidget mw)
       if (XAllocColor (dpy, cmap, &topc))
 #endif
 	{
-	  mw->menu.top_shadow_color = topc.pixel;
-	  mw->menu.free_top_shadow_color_p = 1;
+	  *top_color = topc.pixel;
+	  *free_top_p = True;
 	  top_frobbed = 1;
 	}
     }
-  if (mw->menu.bottom_shadow_color == mw->menu.foreground ||
-      mw->menu.bottom_shadow_color == mw->core.background_pixel)
+  if (*bottom_color == fore_color || *bottom_color == back_color)
     {
-      botc.pixel = mw->core.background_pixel;
+      botc.pixel = back_color;
 #ifdef emacs
       if (x_alloc_lighter_color_for_widget ((Widget) mw, dpy, cmap,
 					    &botc.pixel,
@@ -1795,8 +1926,8 @@ make_shadow_gcs (XlwMenuWidget mw)
       if (XAllocColor (dpy, cmap, &botc))
 #endif
 	{
-	  mw->menu.bottom_shadow_color = botc.pixel;
-	  mw->menu.free_bottom_shadow_color_p = 1;
+	  *bottom_color = botc.pixel;
+	  *free_bottom_p = True;
 	  bottom_frobbed = 1;
 	}
     }
@@ -1805,52 +1936,76 @@ make_shadow_gcs (XlwMenuWidget mw)
     {
       if (topc.pixel == botc.pixel)
 	{
-	  if (botc.pixel == mw->menu.foreground)
+	  if (botc.pixel == fore_color)
 	    {
-	      if (mw->menu.free_top_shadow_color_p)
+	      if (*free_top_p)
 		{
-		  x_free_dpy_colors (dpy, screen, cmap,
-				     &mw->menu.top_shadow_color, 1);
-		  mw->menu.free_top_shadow_color_p = 0;
+		  x_free_dpy_colors (dpy, screen, cmap, top_color, 1);
+		  *free_top_p = False;
 		}
-	      mw->menu.top_shadow_color = mw->core.background_pixel;
+	      *top_color = back_color;
 	    }
 	  else
 	    {
-	      if (mw->menu.free_bottom_shadow_color_p)
+	      if (*free_bottom_p)
 		{
-		  x_free_dpy_colors (dpy, screen, cmap,
-				     &mw->menu.bottom_shadow_color, 1);
-		  mw->menu.free_bottom_shadow_color_p = 0;
+		  x_free_dpy_colors (dpy, screen, cmap, bottom_color, 1);
+		  *free_bottom_p = False;
 		}
-	      mw->menu.bottom_shadow_color = mw->menu.foreground;
+	      *bottom_color = fore_color;
 	    }
 	}
     }
 
-  if (!mw->menu.top_shadow_pixmap
-      && mw->menu.top_shadow_color == mw->core.background_pixel)
+  if (!*top_pixmap && *top_color == back_color)
     {
-      mw->menu.top_shadow_pixmap = mw->menu.gray_pixmap;
-      if (mw->menu.free_top_shadow_color_p)
+      *top_pixmap = mw->menu.gray_pixmap;
+      if (*free_top_p)
 	{
-	  x_free_dpy_colors (dpy, screen, cmap, &mw->menu.top_shadow_color, 1);
-	  mw->menu.free_top_shadow_color_p = 0;
+	  x_free_dpy_colors (dpy, screen, cmap, top_color, 1);
+	  *free_top_p = False;
 	}
-      mw->menu.top_shadow_color = mw->menu.foreground;
+      *top_color = fore_color;
     }
-  if (!mw->menu.bottom_shadow_pixmap
-      && mw->menu.bottom_shadow_color == mw->core.background_pixel)
+  if (!*bottom_pixmap && *bottom_color == back_color)
     {
-      mw->menu.bottom_shadow_pixmap = mw->menu.gray_pixmap;
-      if (mw->menu.free_bottom_shadow_color_p)
+      *bottom_pixmap = mw->menu.gray_pixmap;
+      if (*free_bottom_p)
 	{
-	  x_free_dpy_colors (dpy, screen, cmap,
-			     &mw->menu.bottom_shadow_color, 1);
-	  mw->menu.free_bottom_shadow_color_p = 0;
+	  x_free_dpy_colors (dpy, screen, cmap, bottom_color, 1);
+	  *free_bottom_p = False;
 	}
-      mw->menu.bottom_shadow_color = mw->menu.foreground;
+      *bottom_color = fore_color;
     }
+}
+
+static void
+make_shadow_gcs (XlwMenuWidget mw)
+{
+  XGCValues xgcv;
+  unsigned long pm = 0;
+
+  /* Normal shadows */
+  compute_shadow_colors(mw,
+			&(mw->menu.top_shadow_color),
+			&(mw->menu.bottom_shadow_color),
+			&(mw->menu.free_top_shadow_color_p),
+			&(mw->menu.free_bottom_shadow_color_p),
+			&(mw->menu.top_shadow_pixmap),
+			&(mw->menu.bottom_shadow_pixmap),
+			mw->menu.foreground,
+			mw->core.background_pixel);
+
+  /* Highlight shadows */
+  compute_shadow_colors(mw,
+			&(mw->menu.top_highlight_shadow_color),
+			&(mw->menu.bottom_highlight_shadow_color),
+			&(mw->menu.free_top_highlight_shadow_color_p),
+			&(mw->menu.free_bottom_highlight_shadow_color_p),
+			&(mw->menu.top_highlight_shadow_pixmap),
+			&(mw->menu.bottom_highlight_shadow_pixmap),
+			mw->menu.highlight_foreground,
+			mw->menu.highlight_background);
 
   xgcv.fill_style = FillStippled;
   xgcv.foreground = mw->menu.top_shadow_color;
@@ -1862,6 +2017,16 @@ make_shadow_gcs (XlwMenuWidget mw)
   xgcv.stipple = mw->menu.bottom_shadow_pixmap;
   pm = (xgcv.stipple ? GCStipple|GCFillStyle : 0);
   mw->menu.shadow_bottom_gc = XtGetGC ((Widget)mw, GCForeground | pm, &xgcv);
+
+  xgcv.foreground = mw->menu.top_highlight_shadow_color;
+  xgcv.stipple = mw->menu.top_highlight_shadow_pixmap;
+  pm = (xgcv.stipple ? GCStipple|GCFillStyle : 0);
+  mw->menu.highlight_shadow_top_gc = XtGetGC ((Widget)mw, GCForeground | pm, &xgcv);
+
+  xgcv.foreground = mw->menu.bottom_highlight_shadow_color;
+  xgcv.stipple = mw->menu.bottom_highlight_shadow_pixmap;
+  pm = (xgcv.stipple ? GCStipple|GCFillStyle : 0);
+  mw->menu.highlight_shadow_bottom_gc = XtGetGC ((Widget)mw, GCForeground | pm, &xgcv);
 }
 
 
@@ -2038,12 +2203,14 @@ XlwMenuRealize (Widget w, Mask *valueMask, XSetWindowAttributes *attributes)
 #if defined USE_CAIRO || defined HAVE_XFT
   if (mw->menu.xft_font)
     {
-      XColor colors[3];
+      XColor colors[4];
       colors[0].pixel = mw->menu.xft_fg.pixel = mw->menu.foreground;
       colors[1].pixel = mw->menu.xft_bg.pixel = mw->core.background_pixel;
       colors[2].pixel = mw->menu.xft_disabled_fg.pixel
         = mw->menu.disabled_foreground;
-      XQueryColors (XtDisplay (mw), mw->core.colormap, colors, 3);
+      colors[3].pixel = mw->menu.xft_highlight_fg.pixel
+	= mw->menu.highlight_foreground;
+      XQueryColors (XtDisplay (mw), mw->core.colormap, colors, 4);
       mw->menu.xft_fg.color.alpha = 0xFFFF;
       mw->menu.xft_fg.color.red = colors[0].red;
       mw->menu.xft_fg.color.green = colors[0].green;
@@ -2056,6 +2223,10 @@ XlwMenuRealize (Widget w, Mask *valueMask, XSetWindowAttributes *attributes)
       mw->menu.xft_disabled_fg.color.red = colors[2].red;
       mw->menu.xft_disabled_fg.color.green = colors[2].green;
       mw->menu.xft_disabled_fg.color.blue = colors[2].blue;
+      mw->menu.xft_highlight_fg.color.alpha = 0xFFFF;
+      mw->menu.xft_highlight_fg.color.red = colors[3].red;
+      mw->menu.xft_highlight_fg.color.green = colors[3].green;
+      mw->menu.xft_highlight_fg.color.blue = colors[3].blue;
     }
 #endif
 }
diff --git a/lwlib/xlwmenu.h b/lwlib/xlwmenu.h
index 7f4bf35939..f68d913b5a 100644
--- a/lwlib/xlwmenu.h
+++ b/lwlib/xlwmenu.h
@@ -58,6 +58,10 @@ #define XtNallowResize "allowResize"
 #define XtCAllowResize "AllowResize"
 #define XtNborderThickness "borderThickness"
 #define XtCBorderThickness "BorderThickness"
+#define XtNhighlightForeground "highlightForeground"
+#define XtCHighlightForeground "HighlightForeground"
+#define XtNhighlightBackground "highlightBackground"
+#define XtCHighlightBackground "HighlightBackground"
 
 /* Motif-compatible resource names */
 #define XmNshadowThickness	"shadowThickness"
@@ -70,6 +74,16 @@ #define XmNtopShadowPixmap	"topShadowPixmap"
 #define XmCTopShadowPixmap	"TopShadowPixmap"
 #define XmNbottomShadowPixmap	"bottomShadowPixmap"
 #define XmCBottomShadowPixmap	"BottomShadowPixmap"
+
+#define XmNtopHighlightShadowColor	"topHighlightShadowColor"
+#define XmCTopHighlightShadowColor	"TopHighlightShadowColor"
+#define XmNbottomHighlightShadowColor	"bottomHighlightShadowColor"
+#define XmCBottomHighlightShadowColor	"BottomHighlightShadowColor"
+#define XmNtopHighlightShadowPixmap	"topHighlightShadowPixmap"
+#define XmCTopHighlightShadowPixmap	"TopHighlightShadowPixmap"
+#define XmNbottomHighlightShadowPixmap	"bottomHighlightShadowPixmap"
+#define XmCBottomHighlightShadowPixmap	"BottomHighlightShadowPixmap"
+
 #define XmRHorizontalDimension	"HorizontalDimension"
 
 typedef struct _XlwMenuRec *XlwMenuWidget;
diff --git a/lwlib/xlwmenuP.h b/lwlib/xlwmenuP.h
index 455ecdbce0..c314eb3e91 100644
--- a/lwlib/xlwmenuP.h
+++ b/lwlib/xlwmenuP.h
@@ -63,13 +63,15 @@ #define _XlwMenuP_h
 #if defined USE_CAIRO || defined HAVE_XFT
   int           default_face;
   XftFont*      xft_font;
-  XftColor      xft_fg, xft_bg, xft_disabled_fg;
+  XftColor      xft_fg, xft_bg, xft_disabled_fg, xft_highlight_fg;
 #endif
   String	fontName;
   XFontStruct*	font;
   Pixel		foreground;
   Pixel		disabled_foreground;
   Pixel		button_foreground;
+  Pixel		highlight_foreground;
+  Pixel		highlight_background;
   Dimension	margin;
   Dimension	horizontal_spacing;
   Dimension	vertical_spacing;
@@ -80,6 +82,10 @@ #define _XlwMenuP_h
   Pixel 	bottom_shadow_color;
   Pixmap	top_shadow_pixmap;
   Pixmap	bottom_shadow_pixmap;
+  Pixel 	top_highlight_shadow_color;
+  Pixel 	bottom_highlight_shadow_color;
+  Pixmap	top_highlight_shadow_pixmap;
+  Pixmap	bottom_highlight_shadow_pixmap;
   Cursor	cursor_shape;
   XtCallbackList	open;
   XtCallbackList	select, highlight;
@@ -88,8 +94,10 @@ #define _XlwMenuP_h
   int		horizontal;
 
   /* True means top_shadow_color and/or bottom_shadow_color must be freed.  */
-  bool_bf free_top_shadow_color_p : 1;
-  bool_bf free_bottom_shadow_color_p : 1;
+  Boolean free_top_shadow_color_p;
+  Boolean free_bottom_shadow_color_p;
+  Boolean free_top_highlight_shadow_color_p;
+  Boolean free_bottom_highlight_shadow_color_p;
 
   /* State of the XlwMenu */
   int                   top_depth;
@@ -112,9 +120,13 @@ #define _XlwMenuP_h
   GC			button_gc;
   GC			background_gc;
   GC			disabled_gc;
+  GC			highlight_foreground_gc;
+  GC			highlight_background_gc;
   GC			inactive_button_gc;
   GC			shadow_top_gc;
   GC			shadow_bottom_gc;
+  GC			highlight_shadow_top_gc;
+  GC			highlight_shadow_bottom_gc;
   Cursor		cursor;
   Boolean		popped_up;
   Pixmap		gray_pixmap;
-- 
2.36.1


[-- Attachment #4: Type: text/plain, Size: 6968 bytes --]



In GNU Emacs 29.0.50 (build 1, x86_64-unknown-openbsd7.1, X toolkit, cairo version 1.17.6, Xaw scroll bars)
 of 2022-07-13 built on elite.giraud
Repository revision: f51e1dbd3174d727a12e673e0b820b4cf35e7046
Repository branch: mgi/ui3
Windowing system distributor 'The X.Org Foundation', version 11.0.12101003
System Description: OpenBSD elite.giraud 7.1 GENERIC.MP#579 amd64

Configured using:
 'configure --prefix=/home/manuel/emacs --bindir=/home/manuel/bin
 --with-x-toolkit=athena --without-sound --without-compress-install
 CPPFLAGS=-I/usr/local/include LDFLAGS=-L/usr/local/lib'

Configured features:
CAIRO DBUS FREETYPE GIF GLIB GMP GNUTLS GSETTINGS HARFBUZZ JPEG JSON
LCMS2 LIBOTF LIBXML2 MODULES NOTIFY KQUEUE PDUMPER PNG RSVG SQLITE3
THREADS TIFF TOOLKIT_SCROLL_BARS WEBP X11 XDBE XIM XINPUT2 XPM LUCID
ZLIB

Important settings:
  value of $LC_ALL: en_US.UTF-8
  locale-coding-system: utf-8-unix

Major mode: Lisp Interaction

Minor modes in effect:
  global-git-commit-mode: t
  magit-auto-revert-mode: t
  paredit-mode: t
  icomplete-mode: t
  display-time-mode: t
  shell-dirtrack-mode: t
  global-so-long-mode: t
  repeat-mode: t
  global-eldoc-mode: t
  eldoc-mode: t
  show-paren-mode: t
  electric-indent-mode: t
  mouse-wheel-mode: t
  menu-bar-mode: t
  file-name-shadow-mode: t
  global-font-lock-mode: t
  font-lock-mode: t
  line-number-mode: t
  indent-tabs-mode: t
  transient-mark-mode: t
  auto-composition-mode: t
  auto-encryption-mode: t
  auto-compression-mode: t

Load-path shadows:
/home/manuel/.emacs.d/elpa/transient-20220527.2213/transient hides /home/manuel/emacs/share/emacs/29.0.50/lisp/transient

Features:
(shadow sort mail-extr emacsbug vc-git whitespace magit-patch
magit-extras face-remap magit-bookmark magit-submodule magit-obsolete
magit-blame magit-stash magit-reflog magit-bisect magit-push magit-pull
magit-fetch magit-clone magit-remote magit-commit magit-sequence
magit-notes magit-worktree magit-tag magit-merge magit-branch
magit-reset magit-files magit-refs magit-status magit magit-repos
magit-apply magit-wip magit-log which-func imenu magit-diff smerge-mode
diff git-commit log-edit pcvs-util add-log magit-core magit-autorevert
autorevert magit-margin magit-transient magit-process with-editor
magit-mode transient magit-git magit-base magit-section dash compat-27
compat-26 compat pulse vc-hg diff-mode vc-dispatcher vc-svn conf-mode
facemenu paredit edmacro icomplete time battery exwm-randr xcb-randr
exwm-config exwm exwm-input xcb-keysyms xcb-xkb exwm-manage
exwm-floating xcb-cursor xcb-render exwm-layout exwm-workspace exwm-core
xcb-ewmh xcb-icccm xcb xcb-xproto xcb-types xcb-debug kmacro server
stimmung-themes modus-operandi-theme modus-themes osm bookmark mingus
libmpdee transmission diary-lib diary-loaddefs color calc-bin calc-ext
calc calc-loaddefs rect calc-macs w3m-load mu4e mu4e-org mu4e-main
mu4e-view mu4e-view-gnus mu4e-view-common mu4e-headers mu4e-compose
mu4e-context mu4e-draft mu4e-actions ido rfc2368 smtpmail mu4e-mark
mu4e-proc mu4e-utils doc-view filenotify jka-compr image-mode exif
mu4e-lists mu4e-message flow-fill mule-util hl-line mu4e-vars mu4e-meta
supercite regi ebdb-message ebdb-gnus gnus-msg gnus-art mm-uu mml2015
mm-view mml-smime smime gnutls dig gnus-sum shr pixel-fill kinsoku
url-file url-dired svg dom gnus-group gnus-undo gnus-start gnus-dbus
gnus-cloud nnimap nnmail mail-source utf7 netrc nnoo gnus-spec gnus-int
gnus-range message sendmail yank-media puny rfc822 mml mml-sec epa
derived epg rfc6068 epg-config mm-decode mm-bodies mm-encode mail-parse
rfc2231 rfc2047 rfc2045 ietf-drums gmm-utils mailheader gnus-win gnus
nnheader gnus-util mail-utils range mm-util mail-prsvr ebdb-mua ebdb-com
crm ebdb-format ebdb mailabbrev eieio-opt cl-extra help-mode speedbar
ezimage dframe eieio-base pcase timezone org ob ob-tangle ob-ref ob-lob
ob-table ob-exp org-macro org-footnote org-src ob-comint org-pcomplete
org-list org-faces org-entities org-version ob-emacs-lisp ob-core
ob-eval org-table oc-basic bibtex ol rx org-keys oc org-compat org-macs
org-loaddefs find-func cal-menu calendar cal-loaddefs visual-basic-mode
cl web-mode disp-table erlang-start smart-tabs-mode skeleton cc-mode
cc-fonts cc-guess cc-menus cc-cmds cc-styles cc-align cc-engine cc-vars
cc-defs slime-asdf grep slime-tramp tramp tramp-loaddefs trampver
tramp-integration cus-edit cus-load wid-edit files-x tramp-compat shell
pcomplete parse-time iso8601 time-date ls-lisp format-spec slime-fancy
slime-indentation slime-cl-indent cl-indent slime-trace-dialog
slime-fontifying-fu slime-package-fu slime-references
slime-compiler-notes-tree advice slime-scratch slime-presentations
bridge slime-macrostep macrostep slime-mdot-fu slime-enclosing-context
slime-fuzzy slime-fancy-trace slime-fancy-inspector slime-c-p-c
slime-editing-commands slime-autodoc slime-repl slime-parse slime
compile text-property-search etags fileloop generator xref project
arc-mode archive-mode noutline outline pp comint ansi-color ring
hyperspec thingatpt slime-autoloads dired-aux dired-x dired
dired-loaddefs so-long notifications dbus xml repeat easy-mmode tex-site
hyperbole-autoloads magit-autoloads git-commit-autoloads
magit-section-autoloads dash-autoloads rust-mode-autoloads
stimmung-themes-autoloads with-editor-autoloads info compat-autoloads
package browse-url url url-proxy url-privacy url-expand url-methods
url-history url-cookie generate-lisp-file url-domsuf url-util mailcap
url-handlers url-parse auth-source cl-seq eieio eieio-core cl-macs
password-cache json subr-x map byte-opt gv bytecomp byte-compile cconv
url-vars cl-loaddefs cl-lib rmc iso-transl tooltip eldoc paren electric
uniquify ediff-hook vc-hooks lisp-float-type elisp-mode mwheel
term/x-win x-win term/common-win x-dnd tool-bar dnd fontset image
regexp-opt fringe tabulated-list replace newcomment text-mode lisp-mode
prog-mode register page tab-bar menu-bar rfn-eshadow isearch easymenu
timer select scroll-bar mouse jit-lock font-lock syntax font-core
term/tty-colors frame minibuffer nadvice seq simple cl-generic
indonesian philippine cham georgian utf-8-lang misc-lang vietnamese
tibetan thai tai-viet lao korean japanese eucjp-ms cp51932 hebrew greek
romanian slovak czech european ethiopic indian cyrillic chinese
composite emoji-zwj charscript charprop case-table epa-hook
jka-cmpr-hook help abbrev obarray oclosure cl-preloaded button loaddefs
faces cus-face macroexp files window text-properties overlay sha1 md5
base64 format env code-pages mule custom widget keymap
hashtable-print-readable backquote threads dbusbind kqueue lcms2
dynamic-setting system-font-setting font-render-setting cairo x-toolkit
xinput2 x multi-tty make-network-process emacs)

Memory information:
((conses 16 563139 59476)
 (symbols 48 54905 4)
 (strings 32 171200 8786)
 (string-bytes 1 5703800)
 (vectors 16 99692)
 (vector-slots 8 1289985 58168)
 (floats 8 522 566)
 (intervals 56 2981 2094)
 (buffers 992 16))

-- 
Manuel Giraud

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* bug#56538: 29.0.50; [PATCH] Colored highlight in Lucid backend
  2022-07-13 13:38 bug#56538: 29.0.50; [PATCH] Colored highlight in Lucid backend Manuel Giraud
@ 2022-07-14  0:53 ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2022-07-14  9:42   ` Manuel Giraud
  0 siblings, 1 reply; 13+ messages in thread
From: Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2022-07-14  0:53 UTC (permalink / raw)
  To: Manuel Giraud; +Cc: 56538

Manuel Giraud <manuel@ledu-giraud.fr> writes:

> ++++
> +** New X resources: "highlightForeground" and "highlightBackground"
> +This controls colors used for highlighted menu item.

This should say which widget it applies to, and that it only applies
under the Lucid build.

> +  {XmNtopHighlightShadowColor, XmCTopHighlightShadowColor, XtRPixel,
> +   sizeof (Pixel), offset (menu.top_highlight_shadow_color),
> +   XtRImmediate, (XtPointer)-1},
> +  {XmNbottomHighlightShadowColor, XmCBottomHighlightShadowColor, XtRPixel,
> +   sizeof (Pixel), offset (menu.bottom_highlight_shadow_color),
> +   XtRImmediate, (XtPointer)-1},
> +  {XmNtopHighlightShadowPixmap, XmCTopHighlightShadowPixmap, XtRPixmap,
> +   sizeof (Pixmap), offset (menu.top_highlight_shadow_pixmap),XtRImmediate,
> +   (XtPointer)None},
> +  {XmNbottomHighlightShadowPixmap, XmCBottomHighlightShadowPixmap, XtRPixmap,
> +   sizeof (Pixmap), offset (menu.bottom_highlight_shadow_pixmap),XtRImmediate,
> +   (XtPointer)None},

Please fix the coding style here so that there is at least a space
between casts and what is being casted.

I know the rest of xlwmenu.c doesn't follow that coding style strictly,
but there is no excuse to add even more incorrectly formatted code.

> +      /* XXX the following permutation is on purpose */

This comment seems redundant.

> +/*
> + * Generic draw shadow rectangle function.  It is used to draw menus, menu items
> + * and also toggle buttons.  When ERASE_P is true, it clears shadows.  DOWN_P is
> + * true when a menu item is pushed or a button toggled.  TOP_GC and BOTTOM_GC
> + * are the graphic contexts used to draw the top and bottom shadow respectively.
> + */

Please fix and re-fill the comment.  We write comments like this:

  /* Take BAR and BAZ, and call foo_1 if appropriate.
     Otherwise, return false.  */

> +  xgcv.foreground = mw->menu.highlight_foreground;
> +  xgcv.background = (mw->menu.highlight_background == -1) ?
> +    mw->core.background_pixel : mw->menu.highlight_background;
> +  mw->menu.highlight_foreground_gc = XtGetGC ((Widget)mw, mask, &xgcv);
> +
> +  xgcv.foreground = (mw->menu.highlight_background == -1) ?
> +    mw->core.background_pixel : mw->menu.highlight_background;
> +  xgcv.background = mw->menu.foreground;
> +  mw->menu.highlight_background_gc = XtGetGC ((Widget)mw, mask, &xgcv);

What I said about coding style also applies here.  Also, don't write:

  abc = foo_1_2 () ?
    mw->core.background_pixel : foo_1 ();

but write:

  abc = (foo_1_2 ()
  	 ? mw->core.background_pixel
	 : foo_1 ());

>  static void
> @@ -1724,12 +1847,16 @@ release_drawing_gcs (XlwMenuWidget mw)
>    XtReleaseGC ((Widget) mw, mw->menu.disabled_gc);
>    XtReleaseGC ((Widget) mw, mw->menu.inactive_button_gc);
>    XtReleaseGC ((Widget) mw, mw->menu.background_gc);
> +  XtReleaseGC ((Widget) mw, mw->menu.highlight_foreground_gc);
> +  XtReleaseGC ((Widget) mw, mw->menu.highlight_background_gc);
>    /* let's get some segvs if we try to use these... */
>    mw->menu.foreground_gc = (GC) -1;
>    mw->menu.button_gc = (GC) -1;
>    mw->menu.disabled_gc = (GC) -1;
>    mw->menu.inactive_button_gc = (GC) -1;
>    mw->menu.background_gc = (GC) -1;
> +  mw->menu.highlight_foreground_gc = (GC) -1;
> +  mw->menu.highlight_background_gc = (GC) -1;
>  }
>  
>  #ifndef emacs
> @@ -1738,29 +1865,34 @@ #define MINL(x,y) ((((unsigned long) (x)) < ((unsigned long) (y))) \
>  #endif
>  
>  static void
> -make_shadow_gcs (XlwMenuWidget mw)
> +compute_shadow_colors(XlwMenuWidget mw,
> +		      Pixel *top_color,
> +		      Pixel *bottom_color,
> +		      Boolean *free_top_p,
> +		      Boolean *free_bottom_p,
> +		      Pixmap *top_pixmap,
> +		      Pixmap *bottom_pixmap,
> +		      Pixel fore_color,
> +		      Pixel back_color)

There should be a space after "compute_shadow_colors".

> +static void
> +make_shadow_gcs (XlwMenuWidget mw)
> +{
> +  XGCValues xgcv;
> +  unsigned long pm = 0;
> +
> +  /* Normal shadows */
> +  compute_shadow_colors(mw,
> +			&(mw->menu.top_shadow_color),
> +			&(mw->menu.bottom_shadow_color),
> +			&(mw->menu.free_top_shadow_color_p),
> +			&(mw->menu.free_bottom_shadow_color_p),
> +			&(mw->menu.top_shadow_pixmap),
> +			&(mw->menu.bottom_shadow_pixmap),
> +			mw->menu.foreground,
> +			mw->core.background_pixel);
> +
> +  /* Highlight shadows */
> +  compute_shadow_colors(mw,
> +			&(mw->menu.top_highlight_shadow_color),
> +			&(mw->menu.bottom_highlight_shadow_color),
> +			&(mw->menu.free_top_highlight_shadow_color_p),
> +			&(mw->menu.free_bottom_highlight_shadow_color_p),
> +			&(mw->menu.top_highlight_shadow_pixmap),
> +			&(mw->menu.bottom_highlight_shadow_pixmap),
> +			mw->menu.highlight_foreground,
> +			mw->menu.highlight_background);
>  
>    xgcv.fill_style = FillStippled;
>    xgcv.foreground = mw->menu.top_shadow_color;
> @@ -1862,6 +2017,16 @@ make_shadow_gcs (XlwMenuWidget mw)
>    xgcv.stipple = mw->menu.bottom_shadow_pixmap;
>    pm = (xgcv.stipple ? GCStipple|GCFillStyle : 0);

Please put spaces between "GCStipple", "|", and "GCFillStyle".  Also,
place a space after "compute_shadow_colors".

>    mw->menu.shadow_bottom_gc = XtGetGC ((Widget)mw, GCForeground | pm, &xgcv);
> +
> +  xgcv.foreground = mw->menu.top_highlight_shadow_color;
> +  xgcv.stipple = mw->menu.top_highlight_shadow_pixmap;
> +  pm = (xgcv.stipple ? GCStipple|GCFillStyle : 0);
> +  mw->menu.highlight_shadow_top_gc = XtGetGC ((Widget)mw, GCForeground | pm, &xgcv);
> +
> +  xgcv.foreground = mw->menu.bottom_highlight_shadow_color;
> +  xgcv.stipple = mw->menu.bottom_highlight_shadow_pixmap;
> +  pm = (xgcv.stipple ? GCStipple|GCFillStyle : 0);
> +  mw->menu.highlight_shadow_bottom_gc = XtGetGC ((Widget)mw, GCForeground | pm, &xgcv);
>  }

What was said about casts also applies here.

> @@ -2038,12 +2203,14 @@ XlwMenuRealize (Widget w, Mask *valueMask, XSetWindowAttributes *attributes)
>  #if defined USE_CAIRO || defined HAVE_XFT
>    if (mw->menu.xft_font)
>      {
> -      XColor colors[3];
> +      XColor colors[4];
>        colors[0].pixel = mw->menu.xft_fg.pixel = mw->menu.foreground;
>        colors[1].pixel = mw->menu.xft_bg.pixel = mw->core.background_pixel;
>        colors[2].pixel = mw->menu.xft_disabled_fg.pixel
>          = mw->menu.disabled_foreground;
> -      XQueryColors (XtDisplay (mw), mw->core.colormap, colors, 3);
> +      colors[3].pixel = mw->menu.xft_highlight_fg.pixel
> +	= mw->menu.highlight_foreground;
> +      XQueryColors (XtDisplay (mw), mw->core.colormap, colors, 4);
>        mw->menu.xft_fg.color.alpha = 0xFFFF;
>        mw->menu.xft_fg.color.red = colors[0].red;
>        mw->menu.xft_fg.color.green = colors[0].green;
> @@ -2056,6 +2223,10 @@ XlwMenuRealize (Widget w, Mask *valueMask, XSetWindowAttributes *attributes)
>        mw->menu.xft_disabled_fg.color.red = colors[2].red;
>        mw->menu.xft_disabled_fg.color.green = colors[2].green;
>        mw->menu.xft_disabled_fg.color.blue = colors[2].blue;
> +      mw->menu.xft_highlight_fg.color.alpha = 0xFFFF;
> +      mw->menu.xft_highlight_fg.color.red = colors[3].red;
> +      mw->menu.xft_highlight_fg.color.green = colors[3].green;
> +      mw->menu.xft_highlight_fg.color.blue = colors[3].blue;
>      }
>  #endif
>  }
> diff --git a/lwlib/xlwmenu.h b/lwlib/xlwmenu.h
> index 7f4bf35939..f68d913b5a 100644
> --- a/lwlib/xlwmenu.h
> +++ b/lwlib/xlwmenu.h
> @@ -58,6 +58,10 @@ #define XtNallowResize "allowResize"
>  #define XtCAllowResize "AllowResize"
>  #define XtNborderThickness "borderThickness"
>  #define XtCBorderThickness "BorderThickness"
> +#define XtNhighlightForeground "highlightForeground"
> +#define XtCHighlightForeground "HighlightForeground"
> +#define XtNhighlightBackground "highlightBackground"
> +#define XtCHighlightBackground "HighlightBackground"
>  
>  /* Motif-compatible resource names */
>  #define XmNshadowThickness	"shadowThickness"
> @@ -70,6 +74,16 @@ #define XmNtopShadowPixmap	"topShadowPixmap"
>  #define XmCTopShadowPixmap	"TopShadowPixmap"
>  #define XmNbottomShadowPixmap	"bottomShadowPixmap"
>  #define XmCBottomShadowPixmap	"BottomShadowPixmap"

> +#define XmNtopHighlightShadowColor	"topHighlightShadowColor"
> +#define XmCTopHighlightShadowColor	"TopHighlightShadowColor"
> +#define XmNbottomHighlightShadowColor	"bottomHighlightShadowColor"
> +#define XmCBottomHighlightShadowColor	"BottomHighlightShadowColor"
> +#define XmNtopHighlightShadowPixmap	"topHighlightShadowPixmap"
> +#define XmCTopHighlightShadowPixmap	"TopHighlightShadowPixmap"
> +#define XmNbottomHighlightShadowPixmap	"bottomHighlightShadowPixmap"
> +#define XmCBottomHighlightShadowPixmap	"BottomHighlightShadowPixmap"

Motif doesn't have widget resources named topHighlightShadowColor,
bottomHighlightShadowColor, topHighlightShadowPixmap or
bottomHighlightShadowPixmap.  So please delete these.

>  #define XmRHorizontalDimension	"HorizontalDimension"
>  
>  typedef struct _XlwMenuRec *XlwMenuWidget;
> diff --git a/lwlib/xlwmenuP.h b/lwlib/xlwmenuP.h
> index 455ecdbce0..c314eb3e91 100644
> --- a/lwlib/xlwmenuP.h
> +++ b/lwlib/xlwmenuP.h
> @@ -63,13 +63,15 @@ #define _XlwMenuP_h
>  #if defined USE_CAIRO || defined HAVE_XFT
>    int           default_face;
>    XftFont*      xft_font;
> -  XftColor      xft_fg, xft_bg, xft_disabled_fg;
> +  XftColor      xft_fg, xft_bg, xft_disabled_fg, xft_highlight_fg;
>  #endif
>    String	fontName;
>    XFontStruct*	font;
>    Pixel		foreground;
>    Pixel		disabled_foreground;
>    Pixel		button_foreground;
> +  Pixel		highlight_foreground;
> +  Pixel		highlight_background;
>    Dimension	margin;
>    Dimension	horizontal_spacing;
>    Dimension	vertical_spacing;
> @@ -80,6 +82,10 @@ #define _XlwMenuP_h
>    Pixel 	bottom_shadow_color;
>    Pixmap	top_shadow_pixmap;
>    Pixmap	bottom_shadow_pixmap;
> +  Pixel 	top_highlight_shadow_color;
> +  Pixel 	bottom_highlight_shadow_color;
> +  Pixmap	top_highlight_shadow_pixmap;
> +  Pixmap	bottom_highlight_shadow_pixmap;
>    Cursor	cursor_shape;
>    XtCallbackList	open;
>    XtCallbackList	select, highlight;
> @@ -88,8 +94,10 @@ #define _XlwMenuP_h
>    int		horizontal;
>  
>    /* True means top_shadow_color and/or bottom_shadow_color must be freed.  */
> -  bool_bf free_top_shadow_color_p : 1;
> -  bool_bf free_bottom_shadow_color_p : 1;
> +  Boolean free_top_shadow_color_p;
> +  Boolean free_bottom_shadow_color_p;
> +  Boolean free_top_highlight_shadow_color_p;
> +  Boolean free_bottom_highlight_shadow_color_p;
>  
>    /* State of the XlwMenu */
>    int                   top_depth;
> @@ -112,9 +120,13 @@ #define _XlwMenuP_h
>    GC			button_gc;
>    GC			background_gc;
>    GC			disabled_gc;
> +  GC			highlight_foreground_gc;
> +  GC			highlight_background_gc;
>    GC			inactive_button_gc;
>    GC			shadow_top_gc;
>    GC			shadow_bottom_gc;
> +  GC			highlight_shadow_top_gc;
> +  GC			highlight_shadow_bottom_gc;
>    Cursor		cursor;
>    Boolean		popped_up;
>    Pixmap		gray_pixmap;

I haven't looked at the code here in much detail yet, but please verify
that it builds and works correctly under Xft, Cairo, and without either
of the two, and under a pseudo-color visual.  (To get an X server with a
pseudo color visual, run "Xephyr -screen 800x800x8".)

Thanks.





^ permalink raw reply	[flat|nested] 13+ messages in thread

* bug#56538: 29.0.50; [PATCH] Colored highlight in Lucid backend
  2022-07-14  0:53 ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2022-07-14  9:42   ` Manuel Giraud
  2022-07-14 10:34     ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 1 reply; 13+ messages in thread
From: Manuel Giraud @ 2022-07-14  9:42 UTC (permalink / raw)
  To: Po Lu; +Cc: 56538

[-- Attachment #1: Type: text/plain, Size: 1633 bytes --]

Po Lu <luangruo@yahoo.com> writes:

Hi Po and thanks for your comments,

[...]

>> +      /* XXX the following permutation is on purpose */
>
> This comment seems redundant.

I have attached a new version of my patch taking your remarks into
account but I did not remove this comment.  I think it could be useful
to understand that "top_gc = something_bottom_gc" is not a typo here.

I have also done the following testing with Xft/cairo/PseudoColor
combinations:

|-------------+-----------------+-----------------+-----------------+---------------------|
|             | Xft + cairo     | Xft only        | cairo only      | None                |
|-------------+-----------------+-----------------+-----------------+---------------------|
| X Truecolor | ok              | ok              | ok              | ok but with a       |
|             |                 |                 |                 | default tiny face   |
|-------------+-----------------+-----------------+-----------------+---------------------|
| Xephyr      | ok but color    | ok but color    | ok but color    | ok, colors ok, but  |
| Pseudocolor | not quite right | not quite right | not quite right | with a default tiny |
|             | around each     | around menu     | around each     | face [fn:2]         |
|             | glyph [fn:1]    | labels [fn:2]   | glyph [fn:1]    |                     |
|-------------+-----------------+-----------------+-----------------+---------------------|

* Footnotes
[fn:1] Aside from the Lucid widget, the emacs buffer is completly
blank.

[fn:2] This time the emacs buffer is here. tool-bar icons are ugly.


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Colored-menu-highlight-in-Lucid-backend.patch --]
[-- Type: text/x-patch, Size: 25151 bytes --]

From e0fb799bc55367c08b2511fda78f98570bda6fdc Mon Sep 17 00:00:00 2001
From: Manuel Giraud <manuel@ledu-giraud.fr>
Date: Mon, 11 Jul 2022 11:14:08 +0200
Subject: [PATCH] Colored menu highlight in Lucid backend

* lwlib/xlwmenuP.h:
* lwlib/xlwmenu.h:
* lwlib/xlwmenu.c: Introduce resources to handle colored highlighting
of menu entries.
* doc/emacs/xresources.texi (Lucid Resources): Documentation.
---
 doc/emacs/xresources.texi |   4 +
 etc/NEWS                  |   5 +
 lwlib/xlwmenu.c           | 342 ++++++++++++++++++++++++++++----------
 lwlib/xlwmenu.h           |   4 +
 lwlib/xlwmenuP.h          |  18 +-
 5 files changed, 281 insertions(+), 92 deletions(-)

diff --git a/doc/emacs/xresources.texi b/doc/emacs/xresources.texi
index 2c2700bc15..f8be06b5e7 100644
--- a/doc/emacs/xresources.texi
+++ b/doc/emacs/xresources.texi
@@ -449,6 +449,10 @@ Lucid Resources
 Foreground color.
 @item disabledForeground
 Foreground color for a disabled menu item.
+@item highlightForeground
+Foreground color for a highlighted menu item.
+@item highlightBackground
+Background color for a highlighted menu item.
 @ifnottex
 @item horizontalSpacing
 Horizontal spacing in pixels between items.  Default is 3.
diff --git a/etc/NEWS b/etc/NEWS
index bf36316890..e1c708ca9d 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -544,6 +544,11 @@ and pop-up menus.
 This controls the style of the pre-edit and status areas of X input
 methods.
 
++++
+** New X resources: "highlightForeground" and "highlightBackground"
+Only in the Lucid build, this controls colors used for highlighted
+menu item widget.
+
 +++
 ** On X11, Emacs now tries to synchronize window resize with the window manager.
 This leads to less flicker and empty areas of a frame being displayed
diff --git a/lwlib/xlwmenu.c b/lwlib/xlwmenu.c
index 68f49e646d..a15803cfc3 100644
--- a/lwlib/xlwmenu.c
+++ b/lwlib/xlwmenu.c
@@ -121,6 +121,10 @@ #define DEFAULT_FONTNAME "XtDefaultFont"
    offset(menu.disabled_foreground), XtRString, (XtPointer)NULL},
   {XtNbuttonForeground, XtCButtonForeground, XtRPixel, sizeof(Pixel),
      offset(menu.button_foreground), XtRString, "XtDefaultForeground"},
+  {XtNhighlightForeground, XtCHighlightForeground, XtRPixel, sizeof(Pixel),
+   offset(menu.highlight_foreground), XtRString, "XtDefaultForeground"},
+  {XtNhighlightBackground, XtCHighlightBackground, XtRPixel, sizeof(Pixel),
+   offset(menu.highlight_background), XtRImmediate, (XtPointer)-1},
   {XtNmargin, XtCMargin, XtRDimension,  sizeof(Dimension),
      offset(menu.margin), XtRImmediate, (XtPointer)1},
   {XtNhorizontalSpacing, XtCMargin, XtRDimension,  sizeof(Dimension),
@@ -570,8 +574,7 @@ draw_arrow (XlwMenuWidget mw,
             int down_p)
 {
   Display *dpy = XtDisplay (mw);
-  GC top_gc = mw->menu.shadow_top_gc;
-  GC bottom_gc = mw->menu.shadow_bottom_gc;
+  GC top_gc, bottom_gc;
   int thickness = mw->menu.shadow_thickness;
   int height = width;
   XPoint pt[10];
@@ -584,10 +587,14 @@ draw_arrow (XlwMenuWidget mw,
 
   if (down_p)
     {
-      GC temp;
-      temp = top_gc;
-      top_gc = bottom_gc;
-      bottom_gc = temp;
+      /* XXX the following permutation is on purpose */
+      top_gc = mw->menu.highlight_shadow_bottom_gc;
+      bottom_gc = mw->menu.highlight_shadow_top_gc;
+    }
+  else
+    {
+      top_gc = mw->menu.shadow_top_gc;
+      bottom_gc = mw->menu.shadow_bottom_gc;
     }
 
   pt[0].x = x;
@@ -621,8 +628,11 @@ draw_arrow (XlwMenuWidget mw,
   XFillPolygon (dpy, window, bottom_gc, pt, 4, Convex, CoordModeOrigin);
 }
 
-
-
+/* Generic draw shadow rectangle function.  It is used to draw menus,
+   menu items and also toggle buttons.  When ERASE_P is true, it
+   clears shadows.  DOWN_P is true when a menu item is pushed or a
+   button toggled.  TOP_GC and BOTTOM_GC are the graphic contexts used
+   to draw the top and bottom shadow respectively.  */
 static void
 draw_shadow_rectangle (XlwMenuWidget mw,
                        Window window,
@@ -631,14 +641,28 @@ draw_shadow_rectangle (XlwMenuWidget mw,
                        int width,
                        int height,
                        int erase_p,
-                       int down_p)
+                       int down_p,
+		       GC top_gc,
+		       GC bottom_gc)
 {
   Display *dpy = XtDisplay (mw);
-  GC top_gc = !erase_p ? mw->menu.shadow_top_gc : mw->menu.background_gc;
-  GC bottom_gc = !erase_p ? mw->menu.shadow_bottom_gc : mw->menu.background_gc;
   int thickness = !x && !y ? mw->menu.border_thickness : mw->menu.shadow_thickness;
   XPoint points [4];
 
+  /* Choose correct GC with a standard default if NULL.  */
+  if (erase_p)
+    {
+      top_gc = mw->menu.background_gc;
+      bottom_gc = mw->menu.background_gc;
+    }
+  else
+    {
+      if (top_gc == NULL)
+	top_gc = mw->menu.shadow_top_gc;
+      if (bottom_gc == NULL)
+	bottom_gc = mw->menu.shadow_bottom_gc;
+    }
+
   if (!erase_p && width == height && width == toggle_button_width (mw))
     {
       points [0].x = x;
@@ -654,6 +678,7 @@ draw_shadow_rectangle (XlwMenuWidget mw,
                     points, 4, Convex, CoordModeOrigin);
     }
 
+
   if (!erase_p && down_p)
     {
       GC temp;
@@ -662,6 +687,7 @@ draw_shadow_rectangle (XlwMenuWidget mw,
       bottom_gc = temp;
     }
 
+  /* Do draw (or erase) shadows */
   points [0].x = x;
   points [0].y = y;
   points [1].x = x + width;
@@ -709,14 +735,28 @@ draw_shadow_rhombus (XlwMenuWidget mw,
                      int width,
                      int height,
                      int erase_p,
-                     int down_p)
+                     int down_p,
+		     GC top_gc,
+		     GC bottom_gc)
 {
   Display *dpy = XtDisplay (mw);
-  GC top_gc = !erase_p ? mw->menu.shadow_top_gc : mw->menu.background_gc;
-  GC bottom_gc = !erase_p ? mw->menu.shadow_bottom_gc : mw->menu.background_gc;
   int thickness = mw->menu.shadow_thickness;
   XPoint points [4];
 
+  /* Choose correct GC with a standard default if NULL */
+  if (erase_p)
+    {
+      top_gc = mw->menu.background_gc;
+      bottom_gc = mw->menu.background_gc;
+    }
+  else
+    {
+      if (top_gc == NULL)
+	top_gc = mw->menu.shadow_top_gc;
+      if (bottom_gc == NULL)
+	top_gc = mw->menu.shadow_bottom_gc;
+    }
+
   if (!erase_p && width == height && width == radio_button_width (mw))
     {
       points [0].x = x;
@@ -784,15 +824,29 @@ draw_shadow_rhombus (XlwMenuWidget mw,
    toggle button is selected.  */
 
 static void
-draw_toggle (XlwMenuWidget mw, Window window, int x, int y, int selected_p)
+draw_toggle (XlwMenuWidget mw, Window window, int x, int y, int selected_p,
+	     int highlighted_p)
 {
   int width, height;
+  GC top_gc, bottom_gc;
+
+  if (highlighted_p)
+    {
+      top_gc = mw->menu.highlight_shadow_top_gc;
+      bottom_gc = mw->menu.highlight_shadow_bottom_gc;
+    }
+  else
+    {
+      top_gc = mw->menu.shadow_top_gc;
+      bottom_gc = mw->menu.shadow_bottom_gc;
+    }
 
   width = toggle_button_width (mw);
   height = width;
   x += mw->menu.horizontal_spacing;
   y += (MENU_FONT_ASCENT (mw) - height) / 2;
-  draw_shadow_rectangle (mw, window, x, y, width, height, False, selected_p);
+  draw_shadow_rectangle (mw, window, x, y, width, height, False,
+			 selected_p, top_gc, bottom_gc);
 }
 
 
@@ -801,15 +855,29 @@ draw_toggle (XlwMenuWidget mw, Window window, int x, int y, int selected_p)
    toggle button is selected.  */
 
 static void
-draw_radio (XlwMenuWidget mw, Window window, int x, int y, int selected_p)
+draw_radio (XlwMenuWidget mw, Window window, int x, int y, int selected_p,
+	    int highlighted_p)
 {
   int width, height;
+  GC top_gc, bottom_gc;
+
+  if (highlighted_p)
+    {
+      top_gc = mw->menu.highlight_shadow_top_gc;
+      bottom_gc = mw->menu.highlight_shadow_bottom_gc;
+    }
+  else
+    {
+      top_gc = mw->menu.shadow_top_gc;
+      bottom_gc = mw->menu.shadow_bottom_gc;
+    }
 
   width = radio_button_width (mw);
   height = width;
   x += mw->menu.horizontal_spacing;
   y += (MENU_FONT_ASCENT (mw) - height) / 2;
-  draw_shadow_rhombus (mw, window, x, y, width, height, False, selected_p);
+  draw_shadow_rhombus (mw, window, x, y, width, height, False, selected_p,
+		       top_gc, bottom_gc);
 }
 
 
@@ -968,6 +1036,33 @@ separator_height (enum menu_separator separator)
     }
 }
 
+static void
+draw_highlight (XlwMenuWidget mw,
+		Window window,
+		int x,
+		int y,
+		int width,
+		int height)
+{
+  Display *dpy = XtDisplay (mw);
+  XPoint points [4];
+
+  points [0].x = x;
+  points [0].y = y;
+  points [1].x = x + width;
+  points [1].y = y;
+  points [2].x = x + width;
+  points [2].y = y + height;
+  points [3].x = x;
+  points [3].y = y + height;
+  XFillPolygon (dpy, window,
+		mw->menu.highlight_background_gc,
+		points, 4, Convex, CoordModeOrigin);
+
+  draw_shadow_rectangle(mw, window, x, y, width, height, False, False,
+			mw->menu.highlight_shadow_top_gc,
+			mw->menu.highlight_shadow_bottom_gc);
+}
 
 /* Display the menu item and increment where.x and where.y to show how large
    the menu item was.  */
@@ -983,7 +1078,6 @@ display_menu_item (XlwMenuWidget mw,
 {
   GC deco_gc;
   GC text_gc;
-  int font_height = MENU_FONT_HEIGHT (mw);
   int font_ascent = MENU_FONT_ASCENT (mw);
   int shadow = mw->menu.shadow_thickness;
   int margin = mw->menu.margin;
@@ -1032,12 +1126,21 @@ display_menu_item (XlwMenuWidget mw,
 
       /* pick the foreground and background GC. */
       if (val->enabled)
-	text_gc = mw->menu.foreground_gc;
+	if (highlighted_p)
+	  text_gc = mw->menu.highlight_foreground_gc;
+	else
+	  text_gc = mw->menu.foreground_gc;
       else
 	text_gc = mw->menu.disabled_gc;
       deco_gc = mw->menu.foreground_gc;
 #if defined USE_CAIRO || defined HAVE_XFT
-      xftfg = val->enabled ? &mw->menu.xft_fg : &mw->menu.xft_disabled_fg;
+      if (val->enabled)
+	if (highlighted_p)
+	  xftfg = &mw->menu.xft_highlight_fg;
+	else
+	  xftfg = &mw->menu.xft_fg;
+      else
+	xftfg = &mw->menu.xft_disabled_fg;
 #endif
 
       if (separator_p)
@@ -1048,8 +1151,11 @@ display_menu_item (XlwMenuWidget mw,
 	{
 	  int x_offset = x + h_spacing + shadow;
 	  char* display_string = resource_widget_value (mw, val);
-	  draw_shadow_rectangle (mw, ws->pixmap, x, y, width, height, True,
-				 False);
+	  /* Clears shadows and maybe highlight */
+	  draw_shadow_rectangle (mw, ws->pixmap, x, y, width, height,
+				 True, False, NULL, NULL);
+	  if (highlighted_p)
+	    draw_highlight (mw, ws->pixmap, x, y, width, height);
 
 	  /* Deal with centering a menu title. */
 	  if (!horizontal_p && !val->contents && !val->call_data)
@@ -1095,10 +1201,10 @@ display_menu_item (XlwMenuWidget mw,
 	    {
 	      if (val->button_type == BUTTON_TYPE_TOGGLE)
 		draw_toggle (mw, ws->pixmap, x, y + v_spacing + shadow,
-			     val->selected);
+			     val->selected, highlighted_p);
 	      else if (val->button_type == BUTTON_TYPE_RADIO)
 		draw_radio (mw, ws->pixmap, x, y + v_spacing + shadow,
-			    val->selected);
+			    val->selected, highlighted_p);
 
 	      if (val->contents)
 		{
@@ -1145,25 +1251,18 @@ display_menu_item (XlwMenuWidget mw,
 	    }
 	  else
 	    {
-	      XDrawRectangle (XtDisplay (mw), ws->pixmap,
-			      mw->menu.background_gc,
-			      x + shadow, y + shadow,
-			      label_width + h_spacing - 1,
-			      font_height + 2 * v_spacing - 1);
-	      draw_shadow_rectangle (mw, ws->pixmap, x, y, width, height,
-				     True, False);
+	      /* If not highlighted, clears shadows for horizontal
+		 menu item */
+	      if (!highlighted_p)
+		draw_shadow_rectangle (mw, ws->pixmap, x, y, width, height,
+				       True, False, NULL, NULL);
 	    }
 #ifdef USE_CAIRO
 	  if (ws->xft_draw)
 	    cairo_surface_flush (cairo_get_target (ws->xft_draw));
 #endif
-
-	  if (highlighted_p)
-	    draw_shadow_rectangle (mw, ws->pixmap, x, y, width, height, False,
-				   False);
 	}
     }
-
   where->x += width;
   where->y += height;
 }
@@ -1257,7 +1356,7 @@ display_menu (XlwMenuWidget mw,
   if (!just_compute_p)
     {
       draw_shadow_rectangle (mw, ws->pixmap, 0, 0, ws->width, ws->height,
-                             False, False);
+                             False, False, NULL, NULL);
       XCopyArea (XtDisplay (mw), ws->pixmap, ws->window,
                  mw->menu.foreground_gc, 0, 0, ws->width, ws->height, 0, 0);
     }
@@ -1714,6 +1813,18 @@ #define BRIGHTNESS(color) (((color) & 0xff) + (((color) >> 8) & 0xff) + (((color
   xgcv.foreground = mw->core.background_pixel;
   xgcv.background = mw->menu.foreground;
   mw->menu.background_gc = XtGetGC ((Widget)mw, mask, &xgcv);
+
+  xgcv.foreground = mw->menu.highlight_foreground;
+  xgcv.background = ((mw->menu.highlight_background == -1)
+		     ? mw->core.background_pixel
+		     : mw->menu.highlight_background);
+  mw->menu.highlight_foreground_gc = XtGetGC ((Widget)mw, mask, &xgcv);
+
+  xgcv.foreground = ((mw->menu.highlight_background == -1)
+		     ? mw->core.background_pixel
+		     : mw->menu.highlight_background);
+  xgcv.background = mw->menu.foreground;
+  mw->menu.highlight_background_gc = XtGetGC ((Widget)mw, mask, &xgcv);
 }
 
 static void
@@ -1724,12 +1835,16 @@ release_drawing_gcs (XlwMenuWidget mw)
   XtReleaseGC ((Widget) mw, mw->menu.disabled_gc);
   XtReleaseGC ((Widget) mw, mw->menu.inactive_button_gc);
   XtReleaseGC ((Widget) mw, mw->menu.background_gc);
+  XtReleaseGC ((Widget) mw, mw->menu.highlight_foreground_gc);
+  XtReleaseGC ((Widget) mw, mw->menu.highlight_background_gc);
   /* let's get some segvs if we try to use these... */
   mw->menu.foreground_gc = (GC) -1;
   mw->menu.button_gc = (GC) -1;
   mw->menu.disabled_gc = (GC) -1;
   mw->menu.inactive_button_gc = (GC) -1;
   mw->menu.background_gc = (GC) -1;
+  mw->menu.highlight_foreground_gc = (GC) -1;
+  mw->menu.highlight_background_gc = (GC) -1;
 }
 
 #ifndef emacs
@@ -1738,29 +1853,34 @@ #define MINL(x,y) ((((unsigned long) (x)) < ((unsigned long) (y))) \
 #endif
 
 static void
-make_shadow_gcs (XlwMenuWidget mw)
+compute_shadow_colors (XlwMenuWidget mw,
+		       Pixel *top_color,
+		       Pixel *bottom_color,
+		       Boolean *free_top_p,
+		       Boolean *free_bottom_p,
+		       Pixmap *top_pixmap,
+		       Pixmap *bottom_pixmap,
+		       Pixel fore_color,
+		       Pixel back_color)
 {
-  XGCValues xgcv;
-  unsigned long pm = 0;
   Display *dpy = XtDisplay ((Widget) mw);
   Screen *screen = XtScreen ((Widget) mw);
   Colormap cmap = mw->core.colormap;
   XColor topc, botc;
   int top_frobbed = 0, bottom_frobbed = 0;
 
-  mw->menu.free_top_shadow_color_p = 0;
-  mw->menu.free_bottom_shadow_color_p = 0;
+  *free_top_p = False;
+  *free_bottom_p = False;
 
-  if (mw->menu.top_shadow_color == -1)
-    mw->menu.top_shadow_color = mw->core.background_pixel;
+  if (*top_color == -1)
+    *top_color = back_color;
 
-  if (mw->menu.bottom_shadow_color == -1)
-    mw->menu.bottom_shadow_color = mw->menu.foreground;
+  if (*bottom_color == -1)
+    *bottom_color = fore_color;
 
-  if (mw->menu.top_shadow_color == mw->core.background_pixel ||
-      mw->menu.top_shadow_color == mw->menu.foreground)
+  if (*top_color == back_color || *top_color == fore_color)
     {
-      topc.pixel = mw->core.background_pixel;
+      topc.pixel = back_color;
 #ifdef emacs
       if (x_alloc_lighter_color_for_widget ((Widget) mw, dpy, cmap,
 					    &topc.pixel,
@@ -1774,15 +1894,14 @@ make_shadow_gcs (XlwMenuWidget mw)
       if (XAllocColor (dpy, cmap, &topc))
 #endif
 	{
-	  mw->menu.top_shadow_color = topc.pixel;
-	  mw->menu.free_top_shadow_color_p = 1;
+	  *top_color = topc.pixel;
+	  *free_top_p = True;
 	  top_frobbed = 1;
 	}
     }
-  if (mw->menu.bottom_shadow_color == mw->menu.foreground ||
-      mw->menu.bottom_shadow_color == mw->core.background_pixel)
+  if (*bottom_color == fore_color || *bottom_color == back_color)
     {
-      botc.pixel = mw->core.background_pixel;
+      botc.pixel = back_color;
 #ifdef emacs
       if (x_alloc_lighter_color_for_widget ((Widget) mw, dpy, cmap,
 					    &botc.pixel,
@@ -1795,8 +1914,8 @@ make_shadow_gcs (XlwMenuWidget mw)
       if (XAllocColor (dpy, cmap, &botc))
 #endif
 	{
-	  mw->menu.bottom_shadow_color = botc.pixel;
-	  mw->menu.free_bottom_shadow_color_p = 1;
+	  *bottom_color = botc.pixel;
+	  *free_bottom_p = True;
 	  bottom_frobbed = 1;
 	}
     }
@@ -1805,63 +1924,97 @@ make_shadow_gcs (XlwMenuWidget mw)
     {
       if (topc.pixel == botc.pixel)
 	{
-	  if (botc.pixel == mw->menu.foreground)
+	  if (botc.pixel == fore_color)
 	    {
-	      if (mw->menu.free_top_shadow_color_p)
+	      if (*free_top_p)
 		{
-		  x_free_dpy_colors (dpy, screen, cmap,
-				     &mw->menu.top_shadow_color, 1);
-		  mw->menu.free_top_shadow_color_p = 0;
+		  x_free_dpy_colors (dpy, screen, cmap, top_color, 1);
+		  *free_top_p = False;
 		}
-	      mw->menu.top_shadow_color = mw->core.background_pixel;
+	      *top_color = back_color;
 	    }
 	  else
 	    {
-	      if (mw->menu.free_bottom_shadow_color_p)
+	      if (*free_bottom_p)
 		{
-		  x_free_dpy_colors (dpy, screen, cmap,
-				     &mw->menu.bottom_shadow_color, 1);
-		  mw->menu.free_bottom_shadow_color_p = 0;
+		  x_free_dpy_colors (dpy, screen, cmap, bottom_color, 1);
+		  *free_bottom_p = False;
 		}
-	      mw->menu.bottom_shadow_color = mw->menu.foreground;
+	      *bottom_color = fore_color;
 	    }
 	}
     }
 
-  if (!mw->menu.top_shadow_pixmap
-      && mw->menu.top_shadow_color == mw->core.background_pixel)
+  if (!*top_pixmap && *top_color == back_color)
     {
-      mw->menu.top_shadow_pixmap = mw->menu.gray_pixmap;
-      if (mw->menu.free_top_shadow_color_p)
+      *top_pixmap = mw->menu.gray_pixmap;
+      if (*free_top_p)
 	{
-	  x_free_dpy_colors (dpy, screen, cmap, &mw->menu.top_shadow_color, 1);
-	  mw->menu.free_top_shadow_color_p = 0;
+	  x_free_dpy_colors (dpy, screen, cmap, top_color, 1);
+	  *free_top_p = False;
 	}
-      mw->menu.top_shadow_color = mw->menu.foreground;
+      *top_color = fore_color;
     }
-  if (!mw->menu.bottom_shadow_pixmap
-      && mw->menu.bottom_shadow_color == mw->core.background_pixel)
+  if (!*bottom_pixmap && *bottom_color == back_color)
     {
-      mw->menu.bottom_shadow_pixmap = mw->menu.gray_pixmap;
-      if (mw->menu.free_bottom_shadow_color_p)
+      *bottom_pixmap = mw->menu.gray_pixmap;
+      if (*free_bottom_p)
 	{
-	  x_free_dpy_colors (dpy, screen, cmap,
-			     &mw->menu.bottom_shadow_color, 1);
-	  mw->menu.free_bottom_shadow_color_p = 0;
+	  x_free_dpy_colors (dpy, screen, cmap, bottom_color, 1);
+	  *free_bottom_p = False;
 	}
-      mw->menu.bottom_shadow_color = mw->menu.foreground;
+      *bottom_color = fore_color;
     }
+}
+
+static void
+make_shadow_gcs (XlwMenuWidget mw)
+{
+  XGCValues xgcv;
+  unsigned long pm = 0;
+
+  /* Normal shadows */
+  compute_shadow_colors (mw,
+			 &(mw->menu.top_shadow_color),
+			 &(mw->menu.bottom_shadow_color),
+			 &(mw->menu.free_top_shadow_color_p),
+			 &(mw->menu.free_bottom_shadow_color_p),
+			 &(mw->menu.top_shadow_pixmap),
+			 &(mw->menu.bottom_shadow_pixmap),
+			 mw->menu.foreground,
+			 mw->core.background_pixel);
+
+  /* Highlight shadows */
+  compute_shadow_colors (mw,
+			 &(mw->menu.top_highlight_shadow_color),
+			 &(mw->menu.bottom_highlight_shadow_color),
+			 &(mw->menu.free_top_highlight_shadow_color_p),
+			 &(mw->menu.free_bottom_highlight_shadow_color_p),
+			 &(mw->menu.top_highlight_shadow_pixmap),
+			 &(mw->menu.bottom_highlight_shadow_pixmap),
+			 mw->menu.highlight_foreground,
+			 mw->menu.highlight_background);
 
   xgcv.fill_style = FillStippled;
   xgcv.foreground = mw->menu.top_shadow_color;
   xgcv.stipple = mw->menu.top_shadow_pixmap;
-  pm = (xgcv.stipple ? GCStipple|GCFillStyle : 0);
-  mw->menu.shadow_top_gc = XtGetGC ((Widget)mw, GCForeground | pm, &xgcv);
+  pm = (xgcv.stipple ? GCStipple | GCFillStyle : 0);
+  mw->menu.shadow_top_gc = XtGetGC ((Widget) mw, GCForeground | pm, &xgcv);
 
   xgcv.foreground = mw->menu.bottom_shadow_color;
   xgcv.stipple = mw->menu.bottom_shadow_pixmap;
-  pm = (xgcv.stipple ? GCStipple|GCFillStyle : 0);
-  mw->menu.shadow_bottom_gc = XtGetGC ((Widget)mw, GCForeground | pm, &xgcv);
+  pm = (xgcv.stipple ? GCStipple | GCFillStyle : 0);
+  mw->menu.shadow_bottom_gc = XtGetGC ((Widget) mw, GCForeground | pm, &xgcv);
+
+  xgcv.foreground = mw->menu.top_highlight_shadow_color;
+  xgcv.stipple = mw->menu.top_highlight_shadow_pixmap;
+  pm = (xgcv.stipple ? GCStipple | GCFillStyle : 0);
+  mw->menu.highlight_shadow_top_gc = XtGetGC ((Widget) mw, GCForeground | pm, &xgcv);
+
+  xgcv.foreground = mw->menu.bottom_highlight_shadow_color;
+  xgcv.stipple = mw->menu.bottom_highlight_shadow_pixmap;
+  pm = (xgcv.stipple ? GCStipple | GCFillStyle : 0);
+  mw->menu.highlight_shadow_bottom_gc = XtGetGC ((Widget) mw, GCForeground | pm, &xgcv);
 }
 
 
@@ -1964,6 +2117,11 @@ XlwMenuInitialize (Widget request, Widget w, ArgList args, Cardinal *num_args)
     mw->menu.font_extents = XExtentsOfFontSet (mw->menu.fontSet);
 #endif
 
+  mw->menu.top_highlight_shadow_color = -1;
+  mw->menu.bottom_highlight_shadow_color = -1;
+  mw->menu.top_highlight_shadow_pixmap = None;
+  mw->menu.bottom_highlight_shadow_pixmap = None;
+
   make_drawing_gcs (mw);
   make_shadow_gcs (mw);
 
@@ -2038,12 +2196,14 @@ XlwMenuRealize (Widget w, Mask *valueMask, XSetWindowAttributes *attributes)
 #if defined USE_CAIRO || defined HAVE_XFT
   if (mw->menu.xft_font)
     {
-      XColor colors[3];
+      XColor colors[4];
       colors[0].pixel = mw->menu.xft_fg.pixel = mw->menu.foreground;
       colors[1].pixel = mw->menu.xft_bg.pixel = mw->core.background_pixel;
       colors[2].pixel = mw->menu.xft_disabled_fg.pixel
         = mw->menu.disabled_foreground;
-      XQueryColors (XtDisplay (mw), mw->core.colormap, colors, 3);
+      colors[3].pixel = mw->menu.xft_highlight_fg.pixel
+	= mw->menu.highlight_foreground;
+      XQueryColors (XtDisplay (mw), mw->core.colormap, colors, 4);
       mw->menu.xft_fg.color.alpha = 0xFFFF;
       mw->menu.xft_fg.color.red = colors[0].red;
       mw->menu.xft_fg.color.green = colors[0].green;
@@ -2056,6 +2216,10 @@ XlwMenuRealize (Widget w, Mask *valueMask, XSetWindowAttributes *attributes)
       mw->menu.xft_disabled_fg.color.red = colors[2].red;
       mw->menu.xft_disabled_fg.color.green = colors[2].green;
       mw->menu.xft_disabled_fg.color.blue = colors[2].blue;
+      mw->menu.xft_highlight_fg.color.alpha = 0xFFFF;
+      mw->menu.xft_highlight_fg.color.red = colors[3].red;
+      mw->menu.xft_highlight_fg.color.green = colors[3].green;
+      mw->menu.xft_highlight_fg.color.blue = colors[3].blue;
     }
 #endif
 }
diff --git a/lwlib/xlwmenu.h b/lwlib/xlwmenu.h
index 7f4bf35939..4e36bde3fb 100644
--- a/lwlib/xlwmenu.h
+++ b/lwlib/xlwmenu.h
@@ -58,6 +58,10 @@ #define XtNallowResize "allowResize"
 #define XtCAllowResize "AllowResize"
 #define XtNborderThickness "borderThickness"
 #define XtCBorderThickness "BorderThickness"
+#define XtNhighlightForeground "highlightForeground"
+#define XtCHighlightForeground "HighlightForeground"
+#define XtNhighlightBackground "highlightBackground"
+#define XtCHighlightBackground "HighlightBackground"
 
 /* Motif-compatible resource names */
 #define XmNshadowThickness	"shadowThickness"
diff --git a/lwlib/xlwmenuP.h b/lwlib/xlwmenuP.h
index 455ecdbce0..c314eb3e91 100644
--- a/lwlib/xlwmenuP.h
+++ b/lwlib/xlwmenuP.h
@@ -63,13 +63,15 @@ #define _XlwMenuP_h
 #if defined USE_CAIRO || defined HAVE_XFT
   int           default_face;
   XftFont*      xft_font;
-  XftColor      xft_fg, xft_bg, xft_disabled_fg;
+  XftColor      xft_fg, xft_bg, xft_disabled_fg, xft_highlight_fg;
 #endif
   String	fontName;
   XFontStruct*	font;
   Pixel		foreground;
   Pixel		disabled_foreground;
   Pixel		button_foreground;
+  Pixel		highlight_foreground;
+  Pixel		highlight_background;
   Dimension	margin;
   Dimension	horizontal_spacing;
   Dimension	vertical_spacing;
@@ -80,6 +82,10 @@ #define _XlwMenuP_h
   Pixel 	bottom_shadow_color;
   Pixmap	top_shadow_pixmap;
   Pixmap	bottom_shadow_pixmap;
+  Pixel 	top_highlight_shadow_color;
+  Pixel 	bottom_highlight_shadow_color;
+  Pixmap	top_highlight_shadow_pixmap;
+  Pixmap	bottom_highlight_shadow_pixmap;
   Cursor	cursor_shape;
   XtCallbackList	open;
   XtCallbackList	select, highlight;
@@ -88,8 +94,10 @@ #define _XlwMenuP_h
   int		horizontal;
 
   /* True means top_shadow_color and/or bottom_shadow_color must be freed.  */
-  bool_bf free_top_shadow_color_p : 1;
-  bool_bf free_bottom_shadow_color_p : 1;
+  Boolean free_top_shadow_color_p;
+  Boolean free_bottom_shadow_color_p;
+  Boolean free_top_highlight_shadow_color_p;
+  Boolean free_bottom_highlight_shadow_color_p;
 
   /* State of the XlwMenu */
   int                   top_depth;
@@ -112,9 +120,13 @@ #define _XlwMenuP_h
   GC			button_gc;
   GC			background_gc;
   GC			disabled_gc;
+  GC			highlight_foreground_gc;
+  GC			highlight_background_gc;
   GC			inactive_button_gc;
   GC			shadow_top_gc;
   GC			shadow_bottom_gc;
+  GC			highlight_shadow_top_gc;
+  GC			highlight_shadow_bottom_gc;
   Cursor		cursor;
   Boolean		popped_up;
   Pixmap		gray_pixmap;
-- 
2.36.1


[-- Attachment #3: Type: text/plain, Size: 18 bytes --]

-- 
Manuel Giraud

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* bug#56538: 29.0.50; [PATCH] Colored highlight in Lucid backend
  2022-07-14  9:42   ` Manuel Giraud
@ 2022-07-14 10:34     ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2022-07-14 13:17       ` Manuel Giraud
  0 siblings, 1 reply; 13+ messages in thread
From: Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2022-07-14 10:34 UTC (permalink / raw)
  To: Manuel Giraud; +Cc: 56538

Manuel Giraud <manuel@ledu-giraud.fr> writes:

> I have attached a new version of my patch taking your remarks into
> account but I did not remove this comment.  I think it could be useful
> to understand that "top_gc = something_bottom_gc" is not a typo here.

We have the same general pattern (random_gc = random_opposite_gc) in
most of the X code, so it is redundant IMHO.  But I won't insist.

> I have also done the following testing with Xft/cairo/PseudoColor
> combinations:
>
> |-------------+-----------------+-----------------+-----------------+---------------------|
> |             | Xft + cairo     | Xft only        | cairo only      | None                |
> |-------------+-----------------+-----------------+-----------------+---------------------|
> | X Truecolor | ok              | ok              | ok              | ok but with a       |
> |             |                 |                 |                 | default tiny face   |
> |-------------+-----------------+-----------------+-----------------+---------------------|
> | Xephyr      | ok but color    | ok but color    | ok but color    | ok, colors ok, but  |
> | Pseudocolor | not quite right | not quite right | not quite right | with a default tiny |
> |             | around each     | around menu     | around each     | face [fn:2]         |
> |             | glyph [fn:1]    | labels [fn:2]   | glyph [fn:1]    |                     |
> |-------------+-----------------+-----------------+-----------------+---------------------|
>
> * Footnotes
> [fn:1] Aside from the Lucid widget, the emacs buffer is completly
> blank.

Yes, that isn't expected to work, because Cairo is broken.  Also, you
can't build Emacs with both Xft and Cairo, since they're mutually
exclusive.

> [fn:2] This time the emacs buffer is here. tool-bar icons are ugly.

Could you please describe how the colors are "not quite right"?

One last nit:

> +static void
> +draw_highlight (XlwMenuWidget mw,
> +		Window window,
> +		int x,
> +		int y,
> +		int width,
> +		int height)

[...]

>  static void
> -make_shadow_gcs (XlwMenuWidget mw)
> +compute_shadow_colors (XlwMenuWidget mw,
> +		       Pixel *top_color,
> +		       Pixel *bottom_color,
> +		       Boolean *free_top_p,
> +		       Boolean *free_bottom_p,
> +		       Pixmap *top_pixmap,
> +		       Pixmap *bottom_pixmap,
> +		       Pixel fore_color,
> +		       Pixel back_color)

Here and elsewhere new functions are added, the argument list should be
reformatted to not place each argument on its own line.

Thanks.





^ permalink raw reply	[flat|nested] 13+ messages in thread

* bug#56538: 29.0.50; [PATCH] Colored highlight in Lucid backend
  2022-07-14 10:34     ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2022-07-14 13:17       ` Manuel Giraud
  2022-07-15  2:06         ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 1 reply; 13+ messages in thread
From: Manuel Giraud @ 2022-07-14 13:17 UTC (permalink / raw)
  To: Po Lu; +Cc: 56538

[-- Attachment #1: Type: text/plain, Size: 612 bytes --]

Po Lu <luangruo@yahoo.com> writes:

[...]

> We have the same general pattern (random_gc = random_opposite_gc) in
> most of the X code, so it is redundant IMHO.  But I won't insist.

Ok.  I can remove this comment then.

[...]

> Yes, that isn't expected to work, because Cairo is broken.  Also, you
> can't build Emacs with both Xft and Cairo, since they're mutually
> exclusive.

😅 sorry. So then "Xft + cairo" is just "cairo".

> Could you please describe how the colors are "not quite right"?

Here is how it look here™ on a PseudoColor Xephyr.  This is Cairo with a
bitmap font:


[-- Attachment #2: sshot-pseudo-cairo.png --]
[-- Type: image/png, Size: 5056 bytes --]

[-- Attachment #3: Type: text/plain, Size: 31 bytes --]


This Xft with the same font:


[-- Attachment #4: sshot-pseudo-xft.png --]
[-- Type: image/png, Size: 5158 bytes --]

[-- Attachment #5: Type: text/plain, Size: 60 bytes --]


And for the record, here are the same with a vector font:


[-- Attachment #6: sshot-pseudo-cairo-vector.png --]
[-- Type: image/png, Size: 9602 bytes --]

[-- Attachment #7: sshot-pseudo-xft-vector.png --]
[-- Type: image/png, Size: 9660 bytes --]

[-- Attachment #8: Type: text/plain, Size: 355 bytes --]


[...]

> Here and elsewhere new functions are added, the argument list should be
> reformatted to not place each argument on its own line.

FWIW, draw_shadow_rectangle, draw_shadow_rhombus… are already like that.

I'll do it but what are your recommandations?  Split at fill-colum +
indent?  Leave the old ones untouched?
-- 
Manuel Giraud

^ permalink raw reply	[flat|nested] 13+ messages in thread

* bug#56538: 29.0.50; [PATCH] Colored highlight in Lucid backend
  2022-07-14 13:17       ` Manuel Giraud
@ 2022-07-15  2:06         ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2022-07-15 11:50           ` Manuel Giraud
  2022-07-15 11:56           ` Manuel Giraud
  0 siblings, 2 replies; 13+ messages in thread
From: Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2022-07-15  2:06 UTC (permalink / raw)
  To: Manuel Giraud; +Cc: 56538

Manuel Giraud <manuel@ledu-giraud.fr> writes:

> Here is how it look here™ on a PseudoColor Xephyr.  This is Cairo with a
> bitmap font:
>
>
>
>
> This Xft with the same font:
>
>
>
>
> And for the record, here are the same with a vector font:
>
>
>
>
>

Right, that's acceptable.  I think the problem will go away if you
disable the rendering extension on the X server.

> FWIW, draw_shadow_rectangle, draw_shadow_rhombus… are already like that.
>
> I'll do it but what are your recommandations?  Split at fill-colum +
> indent?  Leave the old ones untouched?

Yes.  Looking at functions like `x_dnd_do_unsupported_drop' in xterm.c
should help as well.

Otherwise, LGTM.





^ permalink raw reply	[flat|nested] 13+ messages in thread

* bug#56538: 29.0.50; [PATCH] Colored highlight in Lucid backend
  2022-07-15  2:06         ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2022-07-15 11:50           ` Manuel Giraud
  2022-07-15 11:56           ` Manuel Giraud
  1 sibling, 0 replies; 13+ messages in thread
From: Manuel Giraud @ 2022-07-15 11:50 UTC (permalink / raw)
  To: Po Lu; +Cc: 56538

[-- Attachment #1: Type: text/plain, Size: 609 bytes --]

Po Lu <luangruo@yahoo.com> writes:

[...]

> Right, that's acceptable.  I think the problem will go away if you
> disable the rendering extension on the X server.

Ok and I guess that not many people are using a PseudoColor display
nowadays.

> Yes.  Looking at functions like `x_dnd_do_unsupported_drop' in xterm.c
> should help as well.
>
> Otherwise, LGTM.

Here is a new version of this patch.  What's new:

     - fix some comments
     
     - format arguments list on both new functions and the one I have
       modified their arguments
       
     - add some forgot freeing in `release_shadow_gcs'


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Colored-menu-highlight-in-Lucid-backend.patch --]
[-- Type: text/x-patch, Size: 26214 bytes --]

From d8b7a008163c776756da42dbbb208e9c88ed9b2d Mon Sep 17 00:00:00 2001
From: Manuel Giraud <manuel@ledu-giraud.fr>
Date: Mon, 11 Jul 2022 11:14:08 +0200
Subject: [PATCH] Colored menu highlight in Lucid backend

* lwlib/xlwmenuP.h:
* lwlib/xlwmenu.h:
* lwlib/xlwmenu.c: Introduce resources to handle colored highlighting
of menu entries.
* doc/emacs/xresources.texi (Lucid Resources): Documentation.
---
 doc/emacs/xresources.texi |   4 +
 etc/NEWS                  |   5 +
 lwlib/xlwmenu.c           | 352 +++++++++++++++++++++++++++-----------
 lwlib/xlwmenu.h           |   4 +
 lwlib/xlwmenuP.h          |  18 +-
 5 files changed, 276 insertions(+), 107 deletions(-)

diff --git a/doc/emacs/xresources.texi b/doc/emacs/xresources.texi
index 2c2700bc15..f8be06b5e7 100644
--- a/doc/emacs/xresources.texi
+++ b/doc/emacs/xresources.texi
@@ -449,6 +449,10 @@ Lucid Resources
 Foreground color.
 @item disabledForeground
 Foreground color for a disabled menu item.
+@item highlightForeground
+Foreground color for a highlighted menu item.
+@item highlightBackground
+Background color for a highlighted menu item.
 @ifnottex
 @item horizontalSpacing
 Horizontal spacing in pixels between items.  Default is 3.
diff --git a/etc/NEWS b/etc/NEWS
index bf36316890..e1c708ca9d 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -544,6 +544,11 @@ and pop-up menus.
 This controls the style of the pre-edit and status areas of X input
 methods.
 
++++
+** New X resources: "highlightForeground" and "highlightBackground"
+Only in the Lucid build, this controls colors used for highlighted
+menu item widget.
+
 +++
 ** On X11, Emacs now tries to synchronize window resize with the window manager.
 This leads to less flicker and empty areas of a frame being displayed
diff --git a/lwlib/xlwmenu.c b/lwlib/xlwmenu.c
index 68f49e646d..2450e718c2 100644
--- a/lwlib/xlwmenu.c
+++ b/lwlib/xlwmenu.c
@@ -121,6 +121,10 @@ #define DEFAULT_FONTNAME "XtDefaultFont"
    offset(menu.disabled_foreground), XtRString, (XtPointer)NULL},
   {XtNbuttonForeground, XtCButtonForeground, XtRPixel, sizeof(Pixel),
      offset(menu.button_foreground), XtRString, "XtDefaultForeground"},
+  {XtNhighlightForeground, XtCHighlightForeground, XtRPixel, sizeof(Pixel),
+   offset(menu.highlight_foreground), XtRString, "XtDefaultForeground"},
+  {XtNhighlightBackground, XtCHighlightBackground, XtRPixel, sizeof(Pixel),
+   offset(menu.highlight_background), XtRImmediate, (XtPointer)-1},
   {XtNmargin, XtCMargin, XtRDimension,  sizeof(Dimension),
      offset(menu.margin), XtRImmediate, (XtPointer)1},
   {XtNhorizontalSpacing, XtCMargin, XtRDimension,  sizeof(Dimension),
@@ -570,8 +574,7 @@ draw_arrow (XlwMenuWidget mw,
             int down_p)
 {
   Display *dpy = XtDisplay (mw);
-  GC top_gc = mw->menu.shadow_top_gc;
-  GC bottom_gc = mw->menu.shadow_bottom_gc;
+  GC top_gc, bottom_gc;
   int thickness = mw->menu.shadow_thickness;
   int height = width;
   XPoint pt[10];
@@ -584,10 +587,13 @@ draw_arrow (XlwMenuWidget mw,
 
   if (down_p)
     {
-      GC temp;
-      temp = top_gc;
-      top_gc = bottom_gc;
-      bottom_gc = temp;
+      top_gc = mw->menu.highlight_shadow_bottom_gc;
+      bottom_gc = mw->menu.highlight_shadow_top_gc;
+    }
+  else
+    {
+      top_gc = mw->menu.shadow_top_gc;
+      bottom_gc = mw->menu.shadow_bottom_gc;
     }
 
   pt[0].x = x;
@@ -621,24 +627,34 @@ draw_arrow (XlwMenuWidget mw,
   XFillPolygon (dpy, window, bottom_gc, pt, 4, Convex, CoordModeOrigin);
 }
 
-
-
+/* Generic draw shadow rectangle function.  It is used to draw shadows
+   on menus, menu items and also toggle buttons.  When ERASE_P is
+   true, it clears shadows.  DOWN_P is true when a menu item is pushed
+   or a button toggled.  TOP_GC and BOTTOM_GC are the graphic contexts
+   used to draw the top and bottom shadow respectively.  */
 static void
-draw_shadow_rectangle (XlwMenuWidget mw,
-                       Window window,
-                       int x,
-                       int y,
-                       int width,
-                       int height,
-                       int erase_p,
-                       int down_p)
+draw_shadow_rectangle (XlwMenuWidget mw, Window window, int x, int y,
+		       int width, int height, int erase_p, int down_p,
+		       GC top_gc, GC bottom_gc)
 {
   Display *dpy = XtDisplay (mw);
-  GC top_gc = !erase_p ? mw->menu.shadow_top_gc : mw->menu.background_gc;
-  GC bottom_gc = !erase_p ? mw->menu.shadow_bottom_gc : mw->menu.background_gc;
   int thickness = !x && !y ? mw->menu.border_thickness : mw->menu.shadow_thickness;
   XPoint points [4];
 
+  /* Choose correct GC with a standard default if NULL.  */
+  if (erase_p)
+    {
+      top_gc = mw->menu.background_gc;
+      bottom_gc = mw->menu.background_gc;
+    }
+  else
+    {
+      if (top_gc == NULL)
+	top_gc = mw->menu.shadow_top_gc;
+      if (bottom_gc == NULL)
+	bottom_gc = mw->menu.shadow_bottom_gc;
+    }
+
   if (!erase_p && width == height && width == toggle_button_width (mw))
     {
       points [0].x = x;
@@ -662,6 +678,7 @@ draw_shadow_rectangle (XlwMenuWidget mw,
       bottom_gc = temp;
     }
 
+  /* Do draw (or erase) shadows */
   points [0].x = x;
   points [0].y = y;
   points [1].x = x + width;
@@ -702,21 +719,28 @@ draw_shadow_rectangle (XlwMenuWidget mw,
 
 
 static void
-draw_shadow_rhombus (XlwMenuWidget mw,
-                     Window window,
-                     int x,
-                     int y,
-                     int width,
-                     int height,
-                     int erase_p,
-                     int down_p)
+draw_shadow_rhombus (XlwMenuWidget mw, Window window, int x, int y,
+                     int width, int height, int erase_p, int down_p,
+		     GC top_gc, GC bottom_gc)
 {
   Display *dpy = XtDisplay (mw);
-  GC top_gc = !erase_p ? mw->menu.shadow_top_gc : mw->menu.background_gc;
-  GC bottom_gc = !erase_p ? mw->menu.shadow_bottom_gc : mw->menu.background_gc;
   int thickness = mw->menu.shadow_thickness;
   XPoint points [4];
 
+  /* Choose correct GC with a standard default if NULL */
+  if (erase_p)
+    {
+      top_gc = mw->menu.background_gc;
+      bottom_gc = mw->menu.background_gc;
+    }
+  else
+    {
+      if (top_gc == NULL)
+	top_gc = mw->menu.shadow_top_gc;
+      if (bottom_gc == NULL)
+	top_gc = mw->menu.shadow_bottom_gc;
+    }
+
   if (!erase_p && width == height && width == radio_button_width (mw))
     {
       points [0].x = x;
@@ -784,15 +808,29 @@ draw_shadow_rhombus (XlwMenuWidget mw,
    toggle button is selected.  */
 
 static void
-draw_toggle (XlwMenuWidget mw, Window window, int x, int y, int selected_p)
+draw_toggle (XlwMenuWidget mw, Window window, int x, int y, int selected_p,
+	     int highlighted_p)
 {
   int width, height;
+  GC top_gc, bottom_gc;
+
+  if (highlighted_p)
+    {
+      top_gc = mw->menu.highlight_shadow_top_gc;
+      bottom_gc = mw->menu.highlight_shadow_bottom_gc;
+    }
+  else
+    {
+      top_gc = mw->menu.shadow_top_gc;
+      bottom_gc = mw->menu.shadow_bottom_gc;
+    }
 
   width = toggle_button_width (mw);
   height = width;
   x += mw->menu.horizontal_spacing;
   y += (MENU_FONT_ASCENT (mw) - height) / 2;
-  draw_shadow_rectangle (mw, window, x, y, width, height, False, selected_p);
+  draw_shadow_rectangle (mw, window, x, y, width, height, False,
+			 selected_p, top_gc, bottom_gc);
 }
 
 
@@ -801,15 +839,29 @@ draw_toggle (XlwMenuWidget mw, Window window, int x, int y, int selected_p)
    toggle button is selected.  */
 
 static void
-draw_radio (XlwMenuWidget mw, Window window, int x, int y, int selected_p)
+draw_radio (XlwMenuWidget mw, Window window, int x, int y, int selected_p,
+	    int highlighted_p)
 {
   int width, height;
+  GC top_gc, bottom_gc;
+
+  if (highlighted_p)
+    {
+      top_gc = mw->menu.highlight_shadow_top_gc;
+      bottom_gc = mw->menu.highlight_shadow_bottom_gc;
+    }
+  else
+    {
+      top_gc = mw->menu.shadow_top_gc;
+      bottom_gc = mw->menu.shadow_bottom_gc;
+    }
 
   width = radio_button_width (mw);
   height = width;
   x += mw->menu.horizontal_spacing;
   y += (MENU_FONT_ASCENT (mw) - height) / 2;
-  draw_shadow_rhombus (mw, window, x, y, width, height, False, selected_p);
+  draw_shadow_rhombus (mw, window, x, y, width, height, False, selected_p,
+		       top_gc, bottom_gc);
 }
 
 
@@ -968,6 +1020,31 @@ separator_height (enum menu_separator separator)
     }
 }
 
+/* Draw the highlighted background and shadows.  */
+
+static void
+draw_highlight (XlwMenuWidget mw, Window window, int x, int y, int width,
+		int height)
+{
+  Display *dpy = XtDisplay (mw);
+  XPoint points [4];
+
+  points [0].x = x;
+  points [0].y = y;
+  points [1].x = x + width;
+  points [1].y = y;
+  points [2].x = x + width;
+  points [2].y = y + height;
+  points [3].x = x;
+  points [3].y = y + height;
+  XFillPolygon (dpy, window,
+		mw->menu.highlight_background_gc,
+		points, 4, Convex, CoordModeOrigin);
+
+  draw_shadow_rectangle(mw, window, x, y, width, height, False, False,
+			mw->menu.highlight_shadow_top_gc,
+			mw->menu.highlight_shadow_bottom_gc);
+}
 
 /* Display the menu item and increment where.x and where.y to show how large
    the menu item was.  */
@@ -983,7 +1060,6 @@ display_menu_item (XlwMenuWidget mw,
 {
   GC deco_gc;
   GC text_gc;
-  int font_height = MENU_FONT_HEIGHT (mw);
   int font_ascent = MENU_FONT_ASCENT (mw);
   int shadow = mw->menu.shadow_thickness;
   int margin = mw->menu.margin;
@@ -1032,12 +1108,21 @@ display_menu_item (XlwMenuWidget mw,
 
       /* pick the foreground and background GC. */
       if (val->enabled)
-	text_gc = mw->menu.foreground_gc;
+	if (highlighted_p)
+	  text_gc = mw->menu.highlight_foreground_gc;
+	else
+	  text_gc = mw->menu.foreground_gc;
       else
 	text_gc = mw->menu.disabled_gc;
       deco_gc = mw->menu.foreground_gc;
 #if defined USE_CAIRO || defined HAVE_XFT
-      xftfg = val->enabled ? &mw->menu.xft_fg : &mw->menu.xft_disabled_fg;
+      if (val->enabled)
+	if (highlighted_p)
+	  xftfg = &mw->menu.xft_highlight_fg;
+	else
+	  xftfg = &mw->menu.xft_fg;
+      else
+	xftfg = &mw->menu.xft_disabled_fg;
 #endif
 
       if (separator_p)
@@ -1048,8 +1133,11 @@ display_menu_item (XlwMenuWidget mw,
 	{
 	  int x_offset = x + h_spacing + shadow;
 	  char* display_string = resource_widget_value (mw, val);
-	  draw_shadow_rectangle (mw, ws->pixmap, x, y, width, height, True,
-				 False);
+	  /* Clears shadows and maybe highlight */
+	  draw_shadow_rectangle (mw, ws->pixmap, x, y, width, height,
+				 True, False, NULL, NULL);
+	  if (highlighted_p)
+	    draw_highlight (mw, ws->pixmap, x, y, width, height);
 
 	  /* Deal with centering a menu title. */
 	  if (!horizontal_p && !val->contents && !val->call_data)
@@ -1095,10 +1183,10 @@ display_menu_item (XlwMenuWidget mw,
 	    {
 	      if (val->button_type == BUTTON_TYPE_TOGGLE)
 		draw_toggle (mw, ws->pixmap, x, y + v_spacing + shadow,
-			     val->selected);
+			     val->selected, highlighted_p);
 	      else if (val->button_type == BUTTON_TYPE_RADIO)
 		draw_radio (mw, ws->pixmap, x, y + v_spacing + shadow,
-			    val->selected);
+			    val->selected, highlighted_p);
 
 	      if (val->contents)
 		{
@@ -1145,25 +1233,18 @@ display_menu_item (XlwMenuWidget mw,
 	    }
 	  else
 	    {
-	      XDrawRectangle (XtDisplay (mw), ws->pixmap,
-			      mw->menu.background_gc,
-			      x + shadow, y + shadow,
-			      label_width + h_spacing - 1,
-			      font_height + 2 * v_spacing - 1);
-	      draw_shadow_rectangle (mw, ws->pixmap, x, y, width, height,
-				     True, False);
+	      /* If not highlighted, clears shadows for horizontal
+		 menu item */
+	      if (!highlighted_p)
+		draw_shadow_rectangle (mw, ws->pixmap, x, y, width, height,
+				       True, False, NULL, NULL);
 	    }
 #ifdef USE_CAIRO
 	  if (ws->xft_draw)
 	    cairo_surface_flush (cairo_get_target (ws->xft_draw));
 #endif
-
-	  if (highlighted_p)
-	    draw_shadow_rectangle (mw, ws->pixmap, x, y, width, height, False,
-				   False);
 	}
     }
-
   where->x += width;
   where->y += height;
 }
@@ -1257,7 +1338,7 @@ display_menu (XlwMenuWidget mw,
   if (!just_compute_p)
     {
       draw_shadow_rectangle (mw, ws->pixmap, 0, 0, ws->width, ws->height,
-                             False, False);
+                             False, False, NULL, NULL);
       XCopyArea (XtDisplay (mw), ws->pixmap, ws->window,
                  mw->menu.foreground_gc, 0, 0, ws->width, ws->height, 0, 0);
     }
@@ -1714,6 +1795,18 @@ #define BRIGHTNESS(color) (((color) & 0xff) + (((color) >> 8) & 0xff) + (((color
   xgcv.foreground = mw->core.background_pixel;
   xgcv.background = mw->menu.foreground;
   mw->menu.background_gc = XtGetGC ((Widget)mw, mask, &xgcv);
+
+  xgcv.foreground = mw->menu.highlight_foreground;
+  xgcv.background = ((mw->menu.highlight_background == -1)
+		     ? mw->core.background_pixel
+		     : mw->menu.highlight_background);
+  mw->menu.highlight_foreground_gc = XtGetGC ((Widget)mw, mask, &xgcv);
+
+  xgcv.foreground = ((mw->menu.highlight_background == -1)
+		     ? mw->core.background_pixel
+		     : mw->menu.highlight_background);
+  xgcv.background = mw->menu.foreground;
+  mw->menu.highlight_background_gc = XtGetGC ((Widget)mw, mask, &xgcv);
 }
 
 static void
@@ -1724,12 +1817,16 @@ release_drawing_gcs (XlwMenuWidget mw)
   XtReleaseGC ((Widget) mw, mw->menu.disabled_gc);
   XtReleaseGC ((Widget) mw, mw->menu.inactive_button_gc);
   XtReleaseGC ((Widget) mw, mw->menu.background_gc);
+  XtReleaseGC ((Widget) mw, mw->menu.highlight_foreground_gc);
+  XtReleaseGC ((Widget) mw, mw->menu.highlight_background_gc);
   /* let's get some segvs if we try to use these... */
   mw->menu.foreground_gc = (GC) -1;
   mw->menu.button_gc = (GC) -1;
   mw->menu.disabled_gc = (GC) -1;
   mw->menu.inactive_button_gc = (GC) -1;
   mw->menu.background_gc = (GC) -1;
+  mw->menu.highlight_foreground_gc = (GC) -1;
+  mw->menu.highlight_background_gc = (GC) -1;
 }
 
 #ifndef emacs
@@ -1738,29 +1835,29 @@ #define MINL(x,y) ((((unsigned long) (x)) < ((unsigned long) (y))) \
 #endif
 
 static void
-make_shadow_gcs (XlwMenuWidget mw)
+compute_shadow_colors (XlwMenuWidget mw, Pixel *top_color, Pixel *bottom_color,
+		       Boolean *free_top_p, Boolean *free_bottom_p,
+		       Pixmap *top_pixmap, Pixmap *bottom_pixmap,
+		       Pixel fore_color, Pixel back_color)
 {
-  XGCValues xgcv;
-  unsigned long pm = 0;
   Display *dpy = XtDisplay ((Widget) mw);
   Screen *screen = XtScreen ((Widget) mw);
   Colormap cmap = mw->core.colormap;
   XColor topc, botc;
   int top_frobbed = 0, bottom_frobbed = 0;
 
-  mw->menu.free_top_shadow_color_p = 0;
-  mw->menu.free_bottom_shadow_color_p = 0;
+  *free_top_p = False;
+  *free_bottom_p = False;
 
-  if (mw->menu.top_shadow_color == -1)
-    mw->menu.top_shadow_color = mw->core.background_pixel;
+  if (*top_color == -1)
+    *top_color = back_color;
 
-  if (mw->menu.bottom_shadow_color == -1)
-    mw->menu.bottom_shadow_color = mw->menu.foreground;
+  if (*bottom_color == -1)
+    *bottom_color = fore_color;
 
-  if (mw->menu.top_shadow_color == mw->core.background_pixel ||
-      mw->menu.top_shadow_color == mw->menu.foreground)
+  if (*top_color == back_color || *top_color == fore_color)
     {
-      topc.pixel = mw->core.background_pixel;
+      topc.pixel = back_color;
 #ifdef emacs
       if (x_alloc_lighter_color_for_widget ((Widget) mw, dpy, cmap,
 					    &topc.pixel,
@@ -1774,15 +1871,14 @@ make_shadow_gcs (XlwMenuWidget mw)
       if (XAllocColor (dpy, cmap, &topc))
 #endif
 	{
-	  mw->menu.top_shadow_color = topc.pixel;
-	  mw->menu.free_top_shadow_color_p = 1;
+	  *top_color = topc.pixel;
+	  *free_top_p = True;
 	  top_frobbed = 1;
 	}
     }
-  if (mw->menu.bottom_shadow_color == mw->menu.foreground ||
-      mw->menu.bottom_shadow_color == mw->core.background_pixel)
+  if (*bottom_color == fore_color || *bottom_color == back_color)
     {
-      botc.pixel = mw->core.background_pixel;
+      botc.pixel = back_color;
 #ifdef emacs
       if (x_alloc_lighter_color_for_widget ((Widget) mw, dpy, cmap,
 					    &botc.pixel,
@@ -1795,8 +1891,8 @@ make_shadow_gcs (XlwMenuWidget mw)
       if (XAllocColor (dpy, cmap, &botc))
 #endif
 	{
-	  mw->menu.bottom_shadow_color = botc.pixel;
-	  mw->menu.free_bottom_shadow_color_p = 1;
+	  *bottom_color = botc.pixel;
+	  *free_bottom_p = True;
 	  bottom_frobbed = 1;
 	}
     }
@@ -1805,63 +1901,94 @@ make_shadow_gcs (XlwMenuWidget mw)
     {
       if (topc.pixel == botc.pixel)
 	{
-	  if (botc.pixel == mw->menu.foreground)
+	  if (botc.pixel == fore_color)
 	    {
-	      if (mw->menu.free_top_shadow_color_p)
+	      if (*free_top_p)
 		{
-		  x_free_dpy_colors (dpy, screen, cmap,
-				     &mw->menu.top_shadow_color, 1);
-		  mw->menu.free_top_shadow_color_p = 0;
+		  x_free_dpy_colors (dpy, screen, cmap, top_color, 1);
+		  *free_top_p = False;
 		}
-	      mw->menu.top_shadow_color = mw->core.background_pixel;
+	      *top_color = back_color;
 	    }
 	  else
 	    {
-	      if (mw->menu.free_bottom_shadow_color_p)
+	      if (*free_bottom_p)
 		{
-		  x_free_dpy_colors (dpy, screen, cmap,
-				     &mw->menu.bottom_shadow_color, 1);
-		  mw->menu.free_bottom_shadow_color_p = 0;
+		  x_free_dpy_colors (dpy, screen, cmap, bottom_color, 1);
+		  *free_bottom_p = False;
 		}
-	      mw->menu.bottom_shadow_color = mw->menu.foreground;
+	      *bottom_color = fore_color;
 	    }
 	}
     }
 
-  if (!mw->menu.top_shadow_pixmap
-      && mw->menu.top_shadow_color == mw->core.background_pixel)
+  if (!*top_pixmap && *top_color == back_color)
     {
-      mw->menu.top_shadow_pixmap = mw->menu.gray_pixmap;
-      if (mw->menu.free_top_shadow_color_p)
+      *top_pixmap = mw->menu.gray_pixmap;
+      if (*free_top_p)
 	{
-	  x_free_dpy_colors (dpy, screen, cmap, &mw->menu.top_shadow_color, 1);
-	  mw->menu.free_top_shadow_color_p = 0;
+	  x_free_dpy_colors (dpy, screen, cmap, top_color, 1);
+	  *free_top_p = False;
 	}
-      mw->menu.top_shadow_color = mw->menu.foreground;
+      *top_color = fore_color;
     }
-  if (!mw->menu.bottom_shadow_pixmap
-      && mw->menu.bottom_shadow_color == mw->core.background_pixel)
+  if (!*bottom_pixmap && *bottom_color == back_color)
     {
-      mw->menu.bottom_shadow_pixmap = mw->menu.gray_pixmap;
-      if (mw->menu.free_bottom_shadow_color_p)
+      *bottom_pixmap = mw->menu.gray_pixmap;
+      if (*free_bottom_p)
 	{
-	  x_free_dpy_colors (dpy, screen, cmap,
-			     &mw->menu.bottom_shadow_color, 1);
-	  mw->menu.free_bottom_shadow_color_p = 0;
+	  x_free_dpy_colors (dpy, screen, cmap, bottom_color, 1);
+	  *free_bottom_p = False;
 	}
-      mw->menu.bottom_shadow_color = mw->menu.foreground;
+      *bottom_color = fore_color;
     }
+}
+
+static void
+make_shadow_gcs (XlwMenuWidget mw)
+{
+  XGCValues xgcv;
+  unsigned long pm = 0;
+
+  /* Normal shadows */
+  compute_shadow_colors (mw, &(mw->menu.top_shadow_color),
+			 &(mw->menu.bottom_shadow_color),
+			 &(mw->menu.free_top_shadow_color_p),
+			 &(mw->menu.free_bottom_shadow_color_p),
+			 &(mw->menu.top_shadow_pixmap),
+			 &(mw->menu.bottom_shadow_pixmap),
+			 mw->menu.foreground, mw->core.background_pixel);
+
+  /* Highlight shadows */
+  compute_shadow_colors (mw, &(mw->menu.top_highlight_shadow_color),
+			 &(mw->menu.bottom_highlight_shadow_color),
+			 &(mw->menu.free_top_highlight_shadow_color_p),
+			 &(mw->menu.free_bottom_highlight_shadow_color_p),
+			 &(mw->menu.top_highlight_shadow_pixmap),
+			 &(mw->menu.bottom_highlight_shadow_pixmap),
+			 mw->menu.highlight_foreground,
+			 mw->menu.highlight_background);
 
   xgcv.fill_style = FillStippled;
   xgcv.foreground = mw->menu.top_shadow_color;
   xgcv.stipple = mw->menu.top_shadow_pixmap;
-  pm = (xgcv.stipple ? GCStipple|GCFillStyle : 0);
-  mw->menu.shadow_top_gc = XtGetGC ((Widget)mw, GCForeground | pm, &xgcv);
+  pm = (xgcv.stipple ? GCStipple | GCFillStyle : 0);
+  mw->menu.shadow_top_gc = XtGetGC ((Widget) mw, GCForeground | pm, &xgcv);
 
   xgcv.foreground = mw->menu.bottom_shadow_color;
   xgcv.stipple = mw->menu.bottom_shadow_pixmap;
-  pm = (xgcv.stipple ? GCStipple|GCFillStyle : 0);
-  mw->menu.shadow_bottom_gc = XtGetGC ((Widget)mw, GCForeground | pm, &xgcv);
+  pm = (xgcv.stipple ? GCStipple | GCFillStyle : 0);
+  mw->menu.shadow_bottom_gc = XtGetGC ((Widget) mw, GCForeground | pm, &xgcv);
+
+  xgcv.foreground = mw->menu.top_highlight_shadow_color;
+  xgcv.stipple = mw->menu.top_highlight_shadow_pixmap;
+  pm = (xgcv.stipple ? GCStipple | GCFillStyle : 0);
+  mw->menu.highlight_shadow_top_gc = XtGetGC ((Widget) mw, GCForeground | pm, &xgcv);
+
+  xgcv.foreground = mw->menu.bottom_highlight_shadow_color;
+  xgcv.stipple = mw->menu.bottom_highlight_shadow_pixmap;
+  pm = (xgcv.stipple ? GCStipple | GCFillStyle : 0);
+  mw->menu.highlight_shadow_bottom_gc = XtGetGC ((Widget) mw, GCForeground | pm, &xgcv);
 }
 
 
@@ -1871,18 +1998,24 @@ release_shadow_gcs (XlwMenuWidget mw)
   Display *dpy = XtDisplay ((Widget) mw);
   Screen *screen = XtScreen ((Widget) mw);
   Colormap cmap = mw->core.colormap;
-  Pixel px[2];
+  Pixel px[4];
   int i = 0;
 
   if (mw->menu.free_top_shadow_color_p)
     px[i++] = mw->menu.top_shadow_color;
   if (mw->menu.free_bottom_shadow_color_p)
     px[i++] = mw->menu.bottom_shadow_color;
+  if (mw->menu.free_top_highlight_shadow_color_p)
+    px[i++] = mw->menu.top_highlight_shadow_color;
+  if (mw->menu.free_bottom_highlight_shadow_color_p)
+    px[i++] = mw->menu.bottom_highlight_shadow_color;
   if (i > 0)
     x_free_dpy_colors (dpy, screen, cmap, px, i);
 
   XtReleaseGC ((Widget) mw, mw->menu.shadow_top_gc);
   XtReleaseGC ((Widget) mw, mw->menu.shadow_bottom_gc);
+  XtReleaseGC ((Widget) mw, mw->menu.highlight_shadow_top_gc);
+  XtReleaseGC ((Widget) mw, mw->menu.highlight_shadow_bottom_gc);
 }
 
 #if defined USE_CAIRO || defined HAVE_XFT
@@ -1964,6 +2097,11 @@ XlwMenuInitialize (Widget request, Widget w, ArgList args, Cardinal *num_args)
     mw->menu.font_extents = XExtentsOfFontSet (mw->menu.fontSet);
 #endif
 
+  mw->menu.top_highlight_shadow_color = -1;
+  mw->menu.bottom_highlight_shadow_color = -1;
+  mw->menu.top_highlight_shadow_pixmap = None;
+  mw->menu.bottom_highlight_shadow_pixmap = None;
+
   make_drawing_gcs (mw);
   make_shadow_gcs (mw);
 
@@ -2038,12 +2176,14 @@ XlwMenuRealize (Widget w, Mask *valueMask, XSetWindowAttributes *attributes)
 #if defined USE_CAIRO || defined HAVE_XFT
   if (mw->menu.xft_font)
     {
-      XColor colors[3];
+      XColor colors[4];
       colors[0].pixel = mw->menu.xft_fg.pixel = mw->menu.foreground;
       colors[1].pixel = mw->menu.xft_bg.pixel = mw->core.background_pixel;
       colors[2].pixel = mw->menu.xft_disabled_fg.pixel
         = mw->menu.disabled_foreground;
-      XQueryColors (XtDisplay (mw), mw->core.colormap, colors, 3);
+      colors[3].pixel = mw->menu.xft_highlight_fg.pixel
+	= mw->menu.highlight_foreground;
+      XQueryColors (XtDisplay (mw), mw->core.colormap, colors, 4);
       mw->menu.xft_fg.color.alpha = 0xFFFF;
       mw->menu.xft_fg.color.red = colors[0].red;
       mw->menu.xft_fg.color.green = colors[0].green;
@@ -2056,6 +2196,10 @@ XlwMenuRealize (Widget w, Mask *valueMask, XSetWindowAttributes *attributes)
       mw->menu.xft_disabled_fg.color.red = colors[2].red;
       mw->menu.xft_disabled_fg.color.green = colors[2].green;
       mw->menu.xft_disabled_fg.color.blue = colors[2].blue;
+      mw->menu.xft_highlight_fg.color.alpha = 0xFFFF;
+      mw->menu.xft_highlight_fg.color.red = colors[3].red;
+      mw->menu.xft_highlight_fg.color.green = colors[3].green;
+      mw->menu.xft_highlight_fg.color.blue = colors[3].blue;
     }
 #endif
 }
diff --git a/lwlib/xlwmenu.h b/lwlib/xlwmenu.h
index 7f4bf35939..4e36bde3fb 100644
--- a/lwlib/xlwmenu.h
+++ b/lwlib/xlwmenu.h
@@ -58,6 +58,10 @@ #define XtNallowResize "allowResize"
 #define XtCAllowResize "AllowResize"
 #define XtNborderThickness "borderThickness"
 #define XtCBorderThickness "BorderThickness"
+#define XtNhighlightForeground "highlightForeground"
+#define XtCHighlightForeground "HighlightForeground"
+#define XtNhighlightBackground "highlightBackground"
+#define XtCHighlightBackground "HighlightBackground"
 
 /* Motif-compatible resource names */
 #define XmNshadowThickness	"shadowThickness"
diff --git a/lwlib/xlwmenuP.h b/lwlib/xlwmenuP.h
index 455ecdbce0..c314eb3e91 100644
--- a/lwlib/xlwmenuP.h
+++ b/lwlib/xlwmenuP.h
@@ -63,13 +63,15 @@ #define _XlwMenuP_h
 #if defined USE_CAIRO || defined HAVE_XFT
   int           default_face;
   XftFont*      xft_font;
-  XftColor      xft_fg, xft_bg, xft_disabled_fg;
+  XftColor      xft_fg, xft_bg, xft_disabled_fg, xft_highlight_fg;
 #endif
   String	fontName;
   XFontStruct*	font;
   Pixel		foreground;
   Pixel		disabled_foreground;
   Pixel		button_foreground;
+  Pixel		highlight_foreground;
+  Pixel		highlight_background;
   Dimension	margin;
   Dimension	horizontal_spacing;
   Dimension	vertical_spacing;
@@ -80,6 +82,10 @@ #define _XlwMenuP_h
   Pixel 	bottom_shadow_color;
   Pixmap	top_shadow_pixmap;
   Pixmap	bottom_shadow_pixmap;
+  Pixel 	top_highlight_shadow_color;
+  Pixel 	bottom_highlight_shadow_color;
+  Pixmap	top_highlight_shadow_pixmap;
+  Pixmap	bottom_highlight_shadow_pixmap;
   Cursor	cursor_shape;
   XtCallbackList	open;
   XtCallbackList	select, highlight;
@@ -88,8 +94,10 @@ #define _XlwMenuP_h
   int		horizontal;
 
   /* True means top_shadow_color and/or bottom_shadow_color must be freed.  */
-  bool_bf free_top_shadow_color_p : 1;
-  bool_bf free_bottom_shadow_color_p : 1;
+  Boolean free_top_shadow_color_p;
+  Boolean free_bottom_shadow_color_p;
+  Boolean free_top_highlight_shadow_color_p;
+  Boolean free_bottom_highlight_shadow_color_p;
 
   /* State of the XlwMenu */
   int                   top_depth;
@@ -112,9 +120,13 @@ #define _XlwMenuP_h
   GC			button_gc;
   GC			background_gc;
   GC			disabled_gc;
+  GC			highlight_foreground_gc;
+  GC			highlight_background_gc;
   GC			inactive_button_gc;
   GC			shadow_top_gc;
   GC			shadow_bottom_gc;
+  GC			highlight_shadow_top_gc;
+  GC			highlight_shadow_bottom_gc;
   Cursor		cursor;
   Boolean		popped_up;
   Pixmap		gray_pixmap;
-- 
2.37.0


[-- Attachment #3: Type: text/plain, Size: 18 bytes --]

-- 
Manuel Giraud

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* bug#56538: 29.0.50; [PATCH] Colored highlight in Lucid backend
  2022-07-15  2:06         ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2022-07-15 11:50           ` Manuel Giraud
@ 2022-07-15 11:56           ` Manuel Giraud
  2022-07-15 12:58             ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
  1 sibling, 1 reply; 13+ messages in thread
From: Manuel Giraud @ 2022-07-15 11:56 UTC (permalink / raw)
  To: Po Lu; +Cc: 56538

[-- Attachment #1: Type: text/plain, Size: 609 bytes --]

Po Lu <luangruo@yahoo.com> writes:

[...]

> Right, that's acceptable.  I think the problem will go away if you
> disable the rendering extension on the X server.

Ok and I guess that not many people are using a PseudoColor display
nowadays.

> Yes.  Looking at functions like `x_dnd_do_unsupported_drop' in xterm.c
> should help as well.
>
> Otherwise, LGTM.

Here is a new version of this patch.  What's new:

     - fix some comments
     
     - format arguments list on both new functions and the one I have
       modified their arguments
       
     - add some forgot freeing in `release_shadow_gcs'


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Colored-menu-highlight-in-Lucid-backend.patch --]
[-- Type: text/x-patch, Size: 26214 bytes --]

From d8b7a008163c776756da42dbbb208e9c88ed9b2d Mon Sep 17 00:00:00 2001
From: Manuel Giraud <manuel@ledu-giraud.fr>
Date: Mon, 11 Jul 2022 11:14:08 +0200
Subject: [PATCH] Colored menu highlight in Lucid backend

* lwlib/xlwmenuP.h:
* lwlib/xlwmenu.h:
* lwlib/xlwmenu.c: Introduce resources to handle colored highlighting
of menu entries.
* doc/emacs/xresources.texi (Lucid Resources): Documentation.
---
 doc/emacs/xresources.texi |   4 +
 etc/NEWS                  |   5 +
 lwlib/xlwmenu.c           | 352 +++++++++++++++++++++++++++-----------
 lwlib/xlwmenu.h           |   4 +
 lwlib/xlwmenuP.h          |  18 +-
 5 files changed, 276 insertions(+), 107 deletions(-)

diff --git a/doc/emacs/xresources.texi b/doc/emacs/xresources.texi
index 2c2700bc15..f8be06b5e7 100644
--- a/doc/emacs/xresources.texi
+++ b/doc/emacs/xresources.texi
@@ -449,6 +449,10 @@ Lucid Resources
 Foreground color.
 @item disabledForeground
 Foreground color for a disabled menu item.
+@item highlightForeground
+Foreground color for a highlighted menu item.
+@item highlightBackground
+Background color for a highlighted menu item.
 @ifnottex
 @item horizontalSpacing
 Horizontal spacing in pixels between items.  Default is 3.
diff --git a/etc/NEWS b/etc/NEWS
index bf36316890..e1c708ca9d 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -544,6 +544,11 @@ and pop-up menus.
 This controls the style of the pre-edit and status areas of X input
 methods.
 
++++
+** New X resources: "highlightForeground" and "highlightBackground"
+Only in the Lucid build, this controls colors used for highlighted
+menu item widget.
+
 +++
 ** On X11, Emacs now tries to synchronize window resize with the window manager.
 This leads to less flicker and empty areas of a frame being displayed
diff --git a/lwlib/xlwmenu.c b/lwlib/xlwmenu.c
index 68f49e646d..2450e718c2 100644
--- a/lwlib/xlwmenu.c
+++ b/lwlib/xlwmenu.c
@@ -121,6 +121,10 @@ #define DEFAULT_FONTNAME "XtDefaultFont"
    offset(menu.disabled_foreground), XtRString, (XtPointer)NULL},
   {XtNbuttonForeground, XtCButtonForeground, XtRPixel, sizeof(Pixel),
      offset(menu.button_foreground), XtRString, "XtDefaultForeground"},
+  {XtNhighlightForeground, XtCHighlightForeground, XtRPixel, sizeof(Pixel),
+   offset(menu.highlight_foreground), XtRString, "XtDefaultForeground"},
+  {XtNhighlightBackground, XtCHighlightBackground, XtRPixel, sizeof(Pixel),
+   offset(menu.highlight_background), XtRImmediate, (XtPointer)-1},
   {XtNmargin, XtCMargin, XtRDimension,  sizeof(Dimension),
      offset(menu.margin), XtRImmediate, (XtPointer)1},
   {XtNhorizontalSpacing, XtCMargin, XtRDimension,  sizeof(Dimension),
@@ -570,8 +574,7 @@ draw_arrow (XlwMenuWidget mw,
             int down_p)
 {
   Display *dpy = XtDisplay (mw);
-  GC top_gc = mw->menu.shadow_top_gc;
-  GC bottom_gc = mw->menu.shadow_bottom_gc;
+  GC top_gc, bottom_gc;
   int thickness = mw->menu.shadow_thickness;
   int height = width;
   XPoint pt[10];
@@ -584,10 +587,13 @@ draw_arrow (XlwMenuWidget mw,
 
   if (down_p)
     {
-      GC temp;
-      temp = top_gc;
-      top_gc = bottom_gc;
-      bottom_gc = temp;
+      top_gc = mw->menu.highlight_shadow_bottom_gc;
+      bottom_gc = mw->menu.highlight_shadow_top_gc;
+    }
+  else
+    {
+      top_gc = mw->menu.shadow_top_gc;
+      bottom_gc = mw->menu.shadow_bottom_gc;
     }
 
   pt[0].x = x;
@@ -621,24 +627,34 @@ draw_arrow (XlwMenuWidget mw,
   XFillPolygon (dpy, window, bottom_gc, pt, 4, Convex, CoordModeOrigin);
 }
 
-
-
+/* Generic draw shadow rectangle function.  It is used to draw shadows
+   on menus, menu items and also toggle buttons.  When ERASE_P is
+   true, it clears shadows.  DOWN_P is true when a menu item is pushed
+   or a button toggled.  TOP_GC and BOTTOM_GC are the graphic contexts
+   used to draw the top and bottom shadow respectively.  */
 static void
-draw_shadow_rectangle (XlwMenuWidget mw,
-                       Window window,
-                       int x,
-                       int y,
-                       int width,
-                       int height,
-                       int erase_p,
-                       int down_p)
+draw_shadow_rectangle (XlwMenuWidget mw, Window window, int x, int y,
+		       int width, int height, int erase_p, int down_p,
+		       GC top_gc, GC bottom_gc)
 {
   Display *dpy = XtDisplay (mw);
-  GC top_gc = !erase_p ? mw->menu.shadow_top_gc : mw->menu.background_gc;
-  GC bottom_gc = !erase_p ? mw->menu.shadow_bottom_gc : mw->menu.background_gc;
   int thickness = !x && !y ? mw->menu.border_thickness : mw->menu.shadow_thickness;
   XPoint points [4];
 
+  /* Choose correct GC with a standard default if NULL.  */
+  if (erase_p)
+    {
+      top_gc = mw->menu.background_gc;
+      bottom_gc = mw->menu.background_gc;
+    }
+  else
+    {
+      if (top_gc == NULL)
+	top_gc = mw->menu.shadow_top_gc;
+      if (bottom_gc == NULL)
+	bottom_gc = mw->menu.shadow_bottom_gc;
+    }
+
   if (!erase_p && width == height && width == toggle_button_width (mw))
     {
       points [0].x = x;
@@ -662,6 +678,7 @@ draw_shadow_rectangle (XlwMenuWidget mw,
       bottom_gc = temp;
     }
 
+  /* Do draw (or erase) shadows */
   points [0].x = x;
   points [0].y = y;
   points [1].x = x + width;
@@ -702,21 +719,28 @@ draw_shadow_rectangle (XlwMenuWidget mw,
 
 
 static void
-draw_shadow_rhombus (XlwMenuWidget mw,
-                     Window window,
-                     int x,
-                     int y,
-                     int width,
-                     int height,
-                     int erase_p,
-                     int down_p)
+draw_shadow_rhombus (XlwMenuWidget mw, Window window, int x, int y,
+                     int width, int height, int erase_p, int down_p,
+		     GC top_gc, GC bottom_gc)
 {
   Display *dpy = XtDisplay (mw);
-  GC top_gc = !erase_p ? mw->menu.shadow_top_gc : mw->menu.background_gc;
-  GC bottom_gc = !erase_p ? mw->menu.shadow_bottom_gc : mw->menu.background_gc;
   int thickness = mw->menu.shadow_thickness;
   XPoint points [4];
 
+  /* Choose correct GC with a standard default if NULL */
+  if (erase_p)
+    {
+      top_gc = mw->menu.background_gc;
+      bottom_gc = mw->menu.background_gc;
+    }
+  else
+    {
+      if (top_gc == NULL)
+	top_gc = mw->menu.shadow_top_gc;
+      if (bottom_gc == NULL)
+	top_gc = mw->menu.shadow_bottom_gc;
+    }
+
   if (!erase_p && width == height && width == radio_button_width (mw))
     {
       points [0].x = x;
@@ -784,15 +808,29 @@ draw_shadow_rhombus (XlwMenuWidget mw,
    toggle button is selected.  */
 
 static void
-draw_toggle (XlwMenuWidget mw, Window window, int x, int y, int selected_p)
+draw_toggle (XlwMenuWidget mw, Window window, int x, int y, int selected_p,
+	     int highlighted_p)
 {
   int width, height;
+  GC top_gc, bottom_gc;
+
+  if (highlighted_p)
+    {
+      top_gc = mw->menu.highlight_shadow_top_gc;
+      bottom_gc = mw->menu.highlight_shadow_bottom_gc;
+    }
+  else
+    {
+      top_gc = mw->menu.shadow_top_gc;
+      bottom_gc = mw->menu.shadow_bottom_gc;
+    }
 
   width = toggle_button_width (mw);
   height = width;
   x += mw->menu.horizontal_spacing;
   y += (MENU_FONT_ASCENT (mw) - height) / 2;
-  draw_shadow_rectangle (mw, window, x, y, width, height, False, selected_p);
+  draw_shadow_rectangle (mw, window, x, y, width, height, False,
+			 selected_p, top_gc, bottom_gc);
 }
 
 
@@ -801,15 +839,29 @@ draw_toggle (XlwMenuWidget mw, Window window, int x, int y, int selected_p)
    toggle button is selected.  */
 
 static void
-draw_radio (XlwMenuWidget mw, Window window, int x, int y, int selected_p)
+draw_radio (XlwMenuWidget mw, Window window, int x, int y, int selected_p,
+	    int highlighted_p)
 {
   int width, height;
+  GC top_gc, bottom_gc;
+
+  if (highlighted_p)
+    {
+      top_gc = mw->menu.highlight_shadow_top_gc;
+      bottom_gc = mw->menu.highlight_shadow_bottom_gc;
+    }
+  else
+    {
+      top_gc = mw->menu.shadow_top_gc;
+      bottom_gc = mw->menu.shadow_bottom_gc;
+    }
 
   width = radio_button_width (mw);
   height = width;
   x += mw->menu.horizontal_spacing;
   y += (MENU_FONT_ASCENT (mw) - height) / 2;
-  draw_shadow_rhombus (mw, window, x, y, width, height, False, selected_p);
+  draw_shadow_rhombus (mw, window, x, y, width, height, False, selected_p,
+		       top_gc, bottom_gc);
 }
 
 
@@ -968,6 +1020,31 @@ separator_height (enum menu_separator separator)
     }
 }
 
+/* Draw the highlighted background and shadows.  */
+
+static void
+draw_highlight (XlwMenuWidget mw, Window window, int x, int y, int width,
+		int height)
+{
+  Display *dpy = XtDisplay (mw);
+  XPoint points [4];
+
+  points [0].x = x;
+  points [0].y = y;
+  points [1].x = x + width;
+  points [1].y = y;
+  points [2].x = x + width;
+  points [2].y = y + height;
+  points [3].x = x;
+  points [3].y = y + height;
+  XFillPolygon (dpy, window,
+		mw->menu.highlight_background_gc,
+		points, 4, Convex, CoordModeOrigin);
+
+  draw_shadow_rectangle(mw, window, x, y, width, height, False, False,
+			mw->menu.highlight_shadow_top_gc,
+			mw->menu.highlight_shadow_bottom_gc);
+}
 
 /* Display the menu item and increment where.x and where.y to show how large
    the menu item was.  */
@@ -983,7 +1060,6 @@ display_menu_item (XlwMenuWidget mw,
 {
   GC deco_gc;
   GC text_gc;
-  int font_height = MENU_FONT_HEIGHT (mw);
   int font_ascent = MENU_FONT_ASCENT (mw);
   int shadow = mw->menu.shadow_thickness;
   int margin = mw->menu.margin;
@@ -1032,12 +1108,21 @@ display_menu_item (XlwMenuWidget mw,
 
       /* pick the foreground and background GC. */
       if (val->enabled)
-	text_gc = mw->menu.foreground_gc;
+	if (highlighted_p)
+	  text_gc = mw->menu.highlight_foreground_gc;
+	else
+	  text_gc = mw->menu.foreground_gc;
       else
 	text_gc = mw->menu.disabled_gc;
       deco_gc = mw->menu.foreground_gc;
 #if defined USE_CAIRO || defined HAVE_XFT
-      xftfg = val->enabled ? &mw->menu.xft_fg : &mw->menu.xft_disabled_fg;
+      if (val->enabled)
+	if (highlighted_p)
+	  xftfg = &mw->menu.xft_highlight_fg;
+	else
+	  xftfg = &mw->menu.xft_fg;
+      else
+	xftfg = &mw->menu.xft_disabled_fg;
 #endif
 
       if (separator_p)
@@ -1048,8 +1133,11 @@ display_menu_item (XlwMenuWidget mw,
 	{
 	  int x_offset = x + h_spacing + shadow;
 	  char* display_string = resource_widget_value (mw, val);
-	  draw_shadow_rectangle (mw, ws->pixmap, x, y, width, height, True,
-				 False);
+	  /* Clears shadows and maybe highlight */
+	  draw_shadow_rectangle (mw, ws->pixmap, x, y, width, height,
+				 True, False, NULL, NULL);
+	  if (highlighted_p)
+	    draw_highlight (mw, ws->pixmap, x, y, width, height);
 
 	  /* Deal with centering a menu title. */
 	  if (!horizontal_p && !val->contents && !val->call_data)
@@ -1095,10 +1183,10 @@ display_menu_item (XlwMenuWidget mw,
 	    {
 	      if (val->button_type == BUTTON_TYPE_TOGGLE)
 		draw_toggle (mw, ws->pixmap, x, y + v_spacing + shadow,
-			     val->selected);
+			     val->selected, highlighted_p);
 	      else if (val->button_type == BUTTON_TYPE_RADIO)
 		draw_radio (mw, ws->pixmap, x, y + v_spacing + shadow,
-			    val->selected);
+			    val->selected, highlighted_p);
 
 	      if (val->contents)
 		{
@@ -1145,25 +1233,18 @@ display_menu_item (XlwMenuWidget mw,
 	    }
 	  else
 	    {
-	      XDrawRectangle (XtDisplay (mw), ws->pixmap,
-			      mw->menu.background_gc,
-			      x + shadow, y + shadow,
-			      label_width + h_spacing - 1,
-			      font_height + 2 * v_spacing - 1);
-	      draw_shadow_rectangle (mw, ws->pixmap, x, y, width, height,
-				     True, False);
+	      /* If not highlighted, clears shadows for horizontal
+		 menu item */
+	      if (!highlighted_p)
+		draw_shadow_rectangle (mw, ws->pixmap, x, y, width, height,
+				       True, False, NULL, NULL);
 	    }
 #ifdef USE_CAIRO
 	  if (ws->xft_draw)
 	    cairo_surface_flush (cairo_get_target (ws->xft_draw));
 #endif
-
-	  if (highlighted_p)
-	    draw_shadow_rectangle (mw, ws->pixmap, x, y, width, height, False,
-				   False);
 	}
     }
-
   where->x += width;
   where->y += height;
 }
@@ -1257,7 +1338,7 @@ display_menu (XlwMenuWidget mw,
   if (!just_compute_p)
     {
       draw_shadow_rectangle (mw, ws->pixmap, 0, 0, ws->width, ws->height,
-                             False, False);
+                             False, False, NULL, NULL);
       XCopyArea (XtDisplay (mw), ws->pixmap, ws->window,
                  mw->menu.foreground_gc, 0, 0, ws->width, ws->height, 0, 0);
     }
@@ -1714,6 +1795,18 @@ #define BRIGHTNESS(color) (((color) & 0xff) + (((color) >> 8) & 0xff) + (((color
   xgcv.foreground = mw->core.background_pixel;
   xgcv.background = mw->menu.foreground;
   mw->menu.background_gc = XtGetGC ((Widget)mw, mask, &xgcv);
+
+  xgcv.foreground = mw->menu.highlight_foreground;
+  xgcv.background = ((mw->menu.highlight_background == -1)
+		     ? mw->core.background_pixel
+		     : mw->menu.highlight_background);
+  mw->menu.highlight_foreground_gc = XtGetGC ((Widget)mw, mask, &xgcv);
+
+  xgcv.foreground = ((mw->menu.highlight_background == -1)
+		     ? mw->core.background_pixel
+		     : mw->menu.highlight_background);
+  xgcv.background = mw->menu.foreground;
+  mw->menu.highlight_background_gc = XtGetGC ((Widget)mw, mask, &xgcv);
 }
 
 static void
@@ -1724,12 +1817,16 @@ release_drawing_gcs (XlwMenuWidget mw)
   XtReleaseGC ((Widget) mw, mw->menu.disabled_gc);
   XtReleaseGC ((Widget) mw, mw->menu.inactive_button_gc);
   XtReleaseGC ((Widget) mw, mw->menu.background_gc);
+  XtReleaseGC ((Widget) mw, mw->menu.highlight_foreground_gc);
+  XtReleaseGC ((Widget) mw, mw->menu.highlight_background_gc);
   /* let's get some segvs if we try to use these... */
   mw->menu.foreground_gc = (GC) -1;
   mw->menu.button_gc = (GC) -1;
   mw->menu.disabled_gc = (GC) -1;
   mw->menu.inactive_button_gc = (GC) -1;
   mw->menu.background_gc = (GC) -1;
+  mw->menu.highlight_foreground_gc = (GC) -1;
+  mw->menu.highlight_background_gc = (GC) -1;
 }
 
 #ifndef emacs
@@ -1738,29 +1835,29 @@ #define MINL(x,y) ((((unsigned long) (x)) < ((unsigned long) (y))) \
 #endif
 
 static void
-make_shadow_gcs (XlwMenuWidget mw)
+compute_shadow_colors (XlwMenuWidget mw, Pixel *top_color, Pixel *bottom_color,
+		       Boolean *free_top_p, Boolean *free_bottom_p,
+		       Pixmap *top_pixmap, Pixmap *bottom_pixmap,
+		       Pixel fore_color, Pixel back_color)
 {
-  XGCValues xgcv;
-  unsigned long pm = 0;
   Display *dpy = XtDisplay ((Widget) mw);
   Screen *screen = XtScreen ((Widget) mw);
   Colormap cmap = mw->core.colormap;
   XColor topc, botc;
   int top_frobbed = 0, bottom_frobbed = 0;
 
-  mw->menu.free_top_shadow_color_p = 0;
-  mw->menu.free_bottom_shadow_color_p = 0;
+  *free_top_p = False;
+  *free_bottom_p = False;
 
-  if (mw->menu.top_shadow_color == -1)
-    mw->menu.top_shadow_color = mw->core.background_pixel;
+  if (*top_color == -1)
+    *top_color = back_color;
 
-  if (mw->menu.bottom_shadow_color == -1)
-    mw->menu.bottom_shadow_color = mw->menu.foreground;
+  if (*bottom_color == -1)
+    *bottom_color = fore_color;
 
-  if (mw->menu.top_shadow_color == mw->core.background_pixel ||
-      mw->menu.top_shadow_color == mw->menu.foreground)
+  if (*top_color == back_color || *top_color == fore_color)
     {
-      topc.pixel = mw->core.background_pixel;
+      topc.pixel = back_color;
 #ifdef emacs
       if (x_alloc_lighter_color_for_widget ((Widget) mw, dpy, cmap,
 					    &topc.pixel,
@@ -1774,15 +1871,14 @@ make_shadow_gcs (XlwMenuWidget mw)
       if (XAllocColor (dpy, cmap, &topc))
 #endif
 	{
-	  mw->menu.top_shadow_color = topc.pixel;
-	  mw->menu.free_top_shadow_color_p = 1;
+	  *top_color = topc.pixel;
+	  *free_top_p = True;
 	  top_frobbed = 1;
 	}
     }
-  if (mw->menu.bottom_shadow_color == mw->menu.foreground ||
-      mw->menu.bottom_shadow_color == mw->core.background_pixel)
+  if (*bottom_color == fore_color || *bottom_color == back_color)
     {
-      botc.pixel = mw->core.background_pixel;
+      botc.pixel = back_color;
 #ifdef emacs
       if (x_alloc_lighter_color_for_widget ((Widget) mw, dpy, cmap,
 					    &botc.pixel,
@@ -1795,8 +1891,8 @@ make_shadow_gcs (XlwMenuWidget mw)
       if (XAllocColor (dpy, cmap, &botc))
 #endif
 	{
-	  mw->menu.bottom_shadow_color = botc.pixel;
-	  mw->menu.free_bottom_shadow_color_p = 1;
+	  *bottom_color = botc.pixel;
+	  *free_bottom_p = True;
 	  bottom_frobbed = 1;
 	}
     }
@@ -1805,63 +1901,94 @@ make_shadow_gcs (XlwMenuWidget mw)
     {
       if (topc.pixel == botc.pixel)
 	{
-	  if (botc.pixel == mw->menu.foreground)
+	  if (botc.pixel == fore_color)
 	    {
-	      if (mw->menu.free_top_shadow_color_p)
+	      if (*free_top_p)
 		{
-		  x_free_dpy_colors (dpy, screen, cmap,
-				     &mw->menu.top_shadow_color, 1);
-		  mw->menu.free_top_shadow_color_p = 0;
+		  x_free_dpy_colors (dpy, screen, cmap, top_color, 1);
+		  *free_top_p = False;
 		}
-	      mw->menu.top_shadow_color = mw->core.background_pixel;
+	      *top_color = back_color;
 	    }
 	  else
 	    {
-	      if (mw->menu.free_bottom_shadow_color_p)
+	      if (*free_bottom_p)
 		{
-		  x_free_dpy_colors (dpy, screen, cmap,
-				     &mw->menu.bottom_shadow_color, 1);
-		  mw->menu.free_bottom_shadow_color_p = 0;
+		  x_free_dpy_colors (dpy, screen, cmap, bottom_color, 1);
+		  *free_bottom_p = False;
 		}
-	      mw->menu.bottom_shadow_color = mw->menu.foreground;
+	      *bottom_color = fore_color;
 	    }
 	}
     }
 
-  if (!mw->menu.top_shadow_pixmap
-      && mw->menu.top_shadow_color == mw->core.background_pixel)
+  if (!*top_pixmap && *top_color == back_color)
     {
-      mw->menu.top_shadow_pixmap = mw->menu.gray_pixmap;
-      if (mw->menu.free_top_shadow_color_p)
+      *top_pixmap = mw->menu.gray_pixmap;
+      if (*free_top_p)
 	{
-	  x_free_dpy_colors (dpy, screen, cmap, &mw->menu.top_shadow_color, 1);
-	  mw->menu.free_top_shadow_color_p = 0;
+	  x_free_dpy_colors (dpy, screen, cmap, top_color, 1);
+	  *free_top_p = False;
 	}
-      mw->menu.top_shadow_color = mw->menu.foreground;
+      *top_color = fore_color;
     }
-  if (!mw->menu.bottom_shadow_pixmap
-      && mw->menu.bottom_shadow_color == mw->core.background_pixel)
+  if (!*bottom_pixmap && *bottom_color == back_color)
     {
-      mw->menu.bottom_shadow_pixmap = mw->menu.gray_pixmap;
-      if (mw->menu.free_bottom_shadow_color_p)
+      *bottom_pixmap = mw->menu.gray_pixmap;
+      if (*free_bottom_p)
 	{
-	  x_free_dpy_colors (dpy, screen, cmap,
-			     &mw->menu.bottom_shadow_color, 1);
-	  mw->menu.free_bottom_shadow_color_p = 0;
+	  x_free_dpy_colors (dpy, screen, cmap, bottom_color, 1);
+	  *free_bottom_p = False;
 	}
-      mw->menu.bottom_shadow_color = mw->menu.foreground;
+      *bottom_color = fore_color;
     }
+}
+
+static void
+make_shadow_gcs (XlwMenuWidget mw)
+{
+  XGCValues xgcv;
+  unsigned long pm = 0;
+
+  /* Normal shadows */
+  compute_shadow_colors (mw, &(mw->menu.top_shadow_color),
+			 &(mw->menu.bottom_shadow_color),
+			 &(mw->menu.free_top_shadow_color_p),
+			 &(mw->menu.free_bottom_shadow_color_p),
+			 &(mw->menu.top_shadow_pixmap),
+			 &(mw->menu.bottom_shadow_pixmap),
+			 mw->menu.foreground, mw->core.background_pixel);
+
+  /* Highlight shadows */
+  compute_shadow_colors (mw, &(mw->menu.top_highlight_shadow_color),
+			 &(mw->menu.bottom_highlight_shadow_color),
+			 &(mw->menu.free_top_highlight_shadow_color_p),
+			 &(mw->menu.free_bottom_highlight_shadow_color_p),
+			 &(mw->menu.top_highlight_shadow_pixmap),
+			 &(mw->menu.bottom_highlight_shadow_pixmap),
+			 mw->menu.highlight_foreground,
+			 mw->menu.highlight_background);
 
   xgcv.fill_style = FillStippled;
   xgcv.foreground = mw->menu.top_shadow_color;
   xgcv.stipple = mw->menu.top_shadow_pixmap;
-  pm = (xgcv.stipple ? GCStipple|GCFillStyle : 0);
-  mw->menu.shadow_top_gc = XtGetGC ((Widget)mw, GCForeground | pm, &xgcv);
+  pm = (xgcv.stipple ? GCStipple | GCFillStyle : 0);
+  mw->menu.shadow_top_gc = XtGetGC ((Widget) mw, GCForeground | pm, &xgcv);
 
   xgcv.foreground = mw->menu.bottom_shadow_color;
   xgcv.stipple = mw->menu.bottom_shadow_pixmap;
-  pm = (xgcv.stipple ? GCStipple|GCFillStyle : 0);
-  mw->menu.shadow_bottom_gc = XtGetGC ((Widget)mw, GCForeground | pm, &xgcv);
+  pm = (xgcv.stipple ? GCStipple | GCFillStyle : 0);
+  mw->menu.shadow_bottom_gc = XtGetGC ((Widget) mw, GCForeground | pm, &xgcv);
+
+  xgcv.foreground = mw->menu.top_highlight_shadow_color;
+  xgcv.stipple = mw->menu.top_highlight_shadow_pixmap;
+  pm = (xgcv.stipple ? GCStipple | GCFillStyle : 0);
+  mw->menu.highlight_shadow_top_gc = XtGetGC ((Widget) mw, GCForeground | pm, &xgcv);
+
+  xgcv.foreground = mw->menu.bottom_highlight_shadow_color;
+  xgcv.stipple = mw->menu.bottom_highlight_shadow_pixmap;
+  pm = (xgcv.stipple ? GCStipple | GCFillStyle : 0);
+  mw->menu.highlight_shadow_bottom_gc = XtGetGC ((Widget) mw, GCForeground | pm, &xgcv);
 }
 
 
@@ -1871,18 +1998,24 @@ release_shadow_gcs (XlwMenuWidget mw)
   Display *dpy = XtDisplay ((Widget) mw);
   Screen *screen = XtScreen ((Widget) mw);
   Colormap cmap = mw->core.colormap;
-  Pixel px[2];
+  Pixel px[4];
   int i = 0;
 
   if (mw->menu.free_top_shadow_color_p)
     px[i++] = mw->menu.top_shadow_color;
   if (mw->menu.free_bottom_shadow_color_p)
     px[i++] = mw->menu.bottom_shadow_color;
+  if (mw->menu.free_top_highlight_shadow_color_p)
+    px[i++] = mw->menu.top_highlight_shadow_color;
+  if (mw->menu.free_bottom_highlight_shadow_color_p)
+    px[i++] = mw->menu.bottom_highlight_shadow_color;
   if (i > 0)
     x_free_dpy_colors (dpy, screen, cmap, px, i);
 
   XtReleaseGC ((Widget) mw, mw->menu.shadow_top_gc);
   XtReleaseGC ((Widget) mw, mw->menu.shadow_bottom_gc);
+  XtReleaseGC ((Widget) mw, mw->menu.highlight_shadow_top_gc);
+  XtReleaseGC ((Widget) mw, mw->menu.highlight_shadow_bottom_gc);
 }
 
 #if defined USE_CAIRO || defined HAVE_XFT
@@ -1964,6 +2097,11 @@ XlwMenuInitialize (Widget request, Widget w, ArgList args, Cardinal *num_args)
     mw->menu.font_extents = XExtentsOfFontSet (mw->menu.fontSet);
 #endif
 
+  mw->menu.top_highlight_shadow_color = -1;
+  mw->menu.bottom_highlight_shadow_color = -1;
+  mw->menu.top_highlight_shadow_pixmap = None;
+  mw->menu.bottom_highlight_shadow_pixmap = None;
+
   make_drawing_gcs (mw);
   make_shadow_gcs (mw);
 
@@ -2038,12 +2176,14 @@ XlwMenuRealize (Widget w, Mask *valueMask, XSetWindowAttributes *attributes)
 #if defined USE_CAIRO || defined HAVE_XFT
   if (mw->menu.xft_font)
     {
-      XColor colors[3];
+      XColor colors[4];
       colors[0].pixel = mw->menu.xft_fg.pixel = mw->menu.foreground;
       colors[1].pixel = mw->menu.xft_bg.pixel = mw->core.background_pixel;
       colors[2].pixel = mw->menu.xft_disabled_fg.pixel
         = mw->menu.disabled_foreground;
-      XQueryColors (XtDisplay (mw), mw->core.colormap, colors, 3);
+      colors[3].pixel = mw->menu.xft_highlight_fg.pixel
+	= mw->menu.highlight_foreground;
+      XQueryColors (XtDisplay (mw), mw->core.colormap, colors, 4);
       mw->menu.xft_fg.color.alpha = 0xFFFF;
       mw->menu.xft_fg.color.red = colors[0].red;
       mw->menu.xft_fg.color.green = colors[0].green;
@@ -2056,6 +2196,10 @@ XlwMenuRealize (Widget w, Mask *valueMask, XSetWindowAttributes *attributes)
       mw->menu.xft_disabled_fg.color.red = colors[2].red;
       mw->menu.xft_disabled_fg.color.green = colors[2].green;
       mw->menu.xft_disabled_fg.color.blue = colors[2].blue;
+      mw->menu.xft_highlight_fg.color.alpha = 0xFFFF;
+      mw->menu.xft_highlight_fg.color.red = colors[3].red;
+      mw->menu.xft_highlight_fg.color.green = colors[3].green;
+      mw->menu.xft_highlight_fg.color.blue = colors[3].blue;
     }
 #endif
 }
diff --git a/lwlib/xlwmenu.h b/lwlib/xlwmenu.h
index 7f4bf35939..4e36bde3fb 100644
--- a/lwlib/xlwmenu.h
+++ b/lwlib/xlwmenu.h
@@ -58,6 +58,10 @@ #define XtNallowResize "allowResize"
 #define XtCAllowResize "AllowResize"
 #define XtNborderThickness "borderThickness"
 #define XtCBorderThickness "BorderThickness"
+#define XtNhighlightForeground "highlightForeground"
+#define XtCHighlightForeground "HighlightForeground"
+#define XtNhighlightBackground "highlightBackground"
+#define XtCHighlightBackground "HighlightBackground"
 
 /* Motif-compatible resource names */
 #define XmNshadowThickness	"shadowThickness"
diff --git a/lwlib/xlwmenuP.h b/lwlib/xlwmenuP.h
index 455ecdbce0..c314eb3e91 100644
--- a/lwlib/xlwmenuP.h
+++ b/lwlib/xlwmenuP.h
@@ -63,13 +63,15 @@ #define _XlwMenuP_h
 #if defined USE_CAIRO || defined HAVE_XFT
   int           default_face;
   XftFont*      xft_font;
-  XftColor      xft_fg, xft_bg, xft_disabled_fg;
+  XftColor      xft_fg, xft_bg, xft_disabled_fg, xft_highlight_fg;
 #endif
   String	fontName;
   XFontStruct*	font;
   Pixel		foreground;
   Pixel		disabled_foreground;
   Pixel		button_foreground;
+  Pixel		highlight_foreground;
+  Pixel		highlight_background;
   Dimension	margin;
   Dimension	horizontal_spacing;
   Dimension	vertical_spacing;
@@ -80,6 +82,10 @@ #define _XlwMenuP_h
   Pixel 	bottom_shadow_color;
   Pixmap	top_shadow_pixmap;
   Pixmap	bottom_shadow_pixmap;
+  Pixel 	top_highlight_shadow_color;
+  Pixel 	bottom_highlight_shadow_color;
+  Pixmap	top_highlight_shadow_pixmap;
+  Pixmap	bottom_highlight_shadow_pixmap;
   Cursor	cursor_shape;
   XtCallbackList	open;
   XtCallbackList	select, highlight;
@@ -88,8 +94,10 @@ #define _XlwMenuP_h
   int		horizontal;
 
   /* True means top_shadow_color and/or bottom_shadow_color must be freed.  */
-  bool_bf free_top_shadow_color_p : 1;
-  bool_bf free_bottom_shadow_color_p : 1;
+  Boolean free_top_shadow_color_p;
+  Boolean free_bottom_shadow_color_p;
+  Boolean free_top_highlight_shadow_color_p;
+  Boolean free_bottom_highlight_shadow_color_p;
 
   /* State of the XlwMenu */
   int                   top_depth;
@@ -112,9 +120,13 @@ #define _XlwMenuP_h
   GC			button_gc;
   GC			background_gc;
   GC			disabled_gc;
+  GC			highlight_foreground_gc;
+  GC			highlight_background_gc;
   GC			inactive_button_gc;
   GC			shadow_top_gc;
   GC			shadow_bottom_gc;
+  GC			highlight_shadow_top_gc;
+  GC			highlight_shadow_bottom_gc;
   Cursor		cursor;
   Boolean		popped_up;
   Pixmap		gray_pixmap;
-- 
2.37.0


[-- Attachment #3: Type: text/plain, Size: 18 bytes --]

-- 
Manuel Giraud

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* bug#56538: 29.0.50; [PATCH] Colored highlight in Lucid backend
  2022-07-15 11:56           ` Manuel Giraud
@ 2022-07-15 12:58             ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2022-07-15 13:27               ` Manuel Giraud
  0 siblings, 1 reply; 13+ messages in thread
From: Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2022-07-15 12:58 UTC (permalink / raw)
  To: Manuel Giraud; +Cc: 56538

Manuel Giraud <manuel@ledu-giraud.fr> writes:

> Here is a new version of this patch.  What's new:
>
>      - fix some comments
>      
>      - format arguments list on both new functions and the one I have
>        modified their arguments
>        
>      - add some forgot freeing in `release_shadow_gcs'

Thanks.  One (late) last comment on the documentation:

> +@item highlightForeground
> +Foreground color for a highlighted menu item.
> +@item highlightBackground
> +Background color for a highlighted menu item.

Shouldn't this say "the menu item highlighted by the mouse"?  Otherwise,
what "highlighted" means is not exactly clear.

> +** New X resources: "highlightForeground" and "highlightBackground"
> +Only in the Lucid build, this controls colors used for highlighted
> +menu item widget.

And here, shouldn't "widget" be in plural?





^ permalink raw reply	[flat|nested] 13+ messages in thread

* bug#56538: 29.0.50; [PATCH] Colored highlight in Lucid backend
  2022-07-15 12:58             ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2022-07-15 13:27               ` Manuel Giraud
  2022-07-16  3:04                 ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 1 reply; 13+ messages in thread
From: Manuel Giraud @ 2022-07-15 13:27 UTC (permalink / raw)
  To: Po Lu; +Cc: 56538

Po Lu <luangruo@yahoo.com> writes:

[...]

>> +@item highlightForeground
>> +Foreground color for a highlighted menu item.
>> +@item highlightBackground
>> +Background color for a highlighted menu item.
>
> Shouldn't this say "the menu item highlighted by the mouse"?  Otherwise,
> what "highlighted" means is not exactly clear.

I did not add "by the mouse" because menus could also be navigated with
keyboard arrows.  Do you have any other suggestions to make it clearer?

>> +** New X resources: "highlightForeground" and "highlightBackground"
>> +Only in the Lucid build, this controls colors used for highlighted
>> +menu item widget.
>
> And here, shouldn't "widget" be in plural?

Ok.  I'll add it to the next patch when the previous issue is resolved.
-- 
Manuel Giraud





^ permalink raw reply	[flat|nested] 13+ messages in thread

* bug#56538: 29.0.50; [PATCH] Colored highlight in Lucid backend
  2022-07-15 13:27               ` Manuel Giraud
@ 2022-07-16  3:04                 ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2022-07-16 10:56                   ` Manuel Giraud
  0 siblings, 1 reply; 13+ messages in thread
From: Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2022-07-16  3:04 UTC (permalink / raw)
  To: Manuel Giraud; +Cc: 56538

Manuel Giraud <manuel@ledu-giraud.fr> writes:

>> Shouldn't this say "the menu item highlighted by the mouse"?  Otherwise,
>> what "highlighted" means is not exactly clear.
>
> I did not add "by the mouse" because menus could also be navigated with
> keyboard arrows.  Do you have any other suggestions to make it clearer?

How about "by the mouse or key navigation"?

>>> +** New X resources: "highlightForeground" and "highlightBackground"
>>> +Only in the Lucid build, this controls colors used for highlighted
>>> +menu item widget.
>>
>> And here, shouldn't "widget" be in plural?
>
> Ok.  I'll add it to the next patch when the previous issue is resolved.

Thanks.





^ permalink raw reply	[flat|nested] 13+ messages in thread

* bug#56538: 29.0.50; [PATCH] Colored highlight in Lucid backend
  2022-07-16  3:04                 ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2022-07-16 10:56                   ` Manuel Giraud
  2022-07-16 10:59                     ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 1 reply; 13+ messages in thread
From: Manuel Giraud @ 2022-07-16 10:56 UTC (permalink / raw)
  To: Po Lu; +Cc: 56538

[-- Attachment #1: Type: text/plain, Size: 123 bytes --]

Po Lu <luangruo@yahoo.com> writes:

> How about "by the mouse or key navigation"?

👍 Here's the updated version.


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Colored-menu-highlight-in-Lucid-backend.patch --]
[-- Type: text/x-patch, Size: 26279 bytes --]

From f0a2392c04b2d3f514716df9757f0b8ed96efa22 Mon Sep 17 00:00:00 2001
From: Manuel Giraud <manuel@ledu-giraud.fr>
Date: Mon, 11 Jul 2022 11:14:08 +0200
Subject: [PATCH] Colored menu highlight in Lucid backend

* lwlib/xlwmenuP.h:
* lwlib/xlwmenu.h:
* lwlib/xlwmenu.c: Introduce resources to handle colored highlighting
of menu entries.
* doc/emacs/xresources.texi (Lucid Resources): Documentation.
---
 doc/emacs/xresources.texi |   6 +
 etc/NEWS                  |   5 +
 lwlib/xlwmenu.c           | 352 +++++++++++++++++++++++++++-----------
 lwlib/xlwmenu.h           |   4 +
 lwlib/xlwmenuP.h          |  18 +-
 5 files changed, 278 insertions(+), 107 deletions(-)

diff --git a/doc/emacs/xresources.texi b/doc/emacs/xresources.texi
index 2c2700bc15..8915d2025b 100644
--- a/doc/emacs/xresources.texi
+++ b/doc/emacs/xresources.texi
@@ -449,6 +449,12 @@ Lucid Resources
 Foreground color.
 @item disabledForeground
 Foreground color for a disabled menu item.
+@item highlightForeground
+Foreground color for a menu item highlighted by the mouse or key
+navigation.
+@item highlightBackground
+Background color for a menu item highlighted by the mouse or key
+navigation.
 @ifnottex
 @item horizontalSpacing
 Horizontal spacing in pixels between items.  Default is 3.
diff --git a/etc/NEWS b/etc/NEWS
index bf36316890..b85f3eef83 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -544,6 +544,11 @@ and pop-up menus.
 This controls the style of the pre-edit and status areas of X input
 methods.
 
++++
+** New X resources: "highlightForeground" and "highlightBackground"
+Only in the Lucid build, this controls colors used for highlighted
+menu item widgets.
+
 +++
 ** On X11, Emacs now tries to synchronize window resize with the window manager.
 This leads to less flicker and empty areas of a frame being displayed
diff --git a/lwlib/xlwmenu.c b/lwlib/xlwmenu.c
index 68f49e646d..2450e718c2 100644
--- a/lwlib/xlwmenu.c
+++ b/lwlib/xlwmenu.c
@@ -121,6 +121,10 @@ #define DEFAULT_FONTNAME "XtDefaultFont"
    offset(menu.disabled_foreground), XtRString, (XtPointer)NULL},
   {XtNbuttonForeground, XtCButtonForeground, XtRPixel, sizeof(Pixel),
      offset(menu.button_foreground), XtRString, "XtDefaultForeground"},
+  {XtNhighlightForeground, XtCHighlightForeground, XtRPixel, sizeof(Pixel),
+   offset(menu.highlight_foreground), XtRString, "XtDefaultForeground"},
+  {XtNhighlightBackground, XtCHighlightBackground, XtRPixel, sizeof(Pixel),
+   offset(menu.highlight_background), XtRImmediate, (XtPointer)-1},
   {XtNmargin, XtCMargin, XtRDimension,  sizeof(Dimension),
      offset(menu.margin), XtRImmediate, (XtPointer)1},
   {XtNhorizontalSpacing, XtCMargin, XtRDimension,  sizeof(Dimension),
@@ -570,8 +574,7 @@ draw_arrow (XlwMenuWidget mw,
             int down_p)
 {
   Display *dpy = XtDisplay (mw);
-  GC top_gc = mw->menu.shadow_top_gc;
-  GC bottom_gc = mw->menu.shadow_bottom_gc;
+  GC top_gc, bottom_gc;
   int thickness = mw->menu.shadow_thickness;
   int height = width;
   XPoint pt[10];
@@ -584,10 +587,13 @@ draw_arrow (XlwMenuWidget mw,
 
   if (down_p)
     {
-      GC temp;
-      temp = top_gc;
-      top_gc = bottom_gc;
-      bottom_gc = temp;
+      top_gc = mw->menu.highlight_shadow_bottom_gc;
+      bottom_gc = mw->menu.highlight_shadow_top_gc;
+    }
+  else
+    {
+      top_gc = mw->menu.shadow_top_gc;
+      bottom_gc = mw->menu.shadow_bottom_gc;
     }
 
   pt[0].x = x;
@@ -621,24 +627,34 @@ draw_arrow (XlwMenuWidget mw,
   XFillPolygon (dpy, window, bottom_gc, pt, 4, Convex, CoordModeOrigin);
 }
 
-
-
+/* Generic draw shadow rectangle function.  It is used to draw shadows
+   on menus, menu items and also toggle buttons.  When ERASE_P is
+   true, it clears shadows.  DOWN_P is true when a menu item is pushed
+   or a button toggled.  TOP_GC and BOTTOM_GC are the graphic contexts
+   used to draw the top and bottom shadow respectively.  */
 static void
-draw_shadow_rectangle (XlwMenuWidget mw,
-                       Window window,
-                       int x,
-                       int y,
-                       int width,
-                       int height,
-                       int erase_p,
-                       int down_p)
+draw_shadow_rectangle (XlwMenuWidget mw, Window window, int x, int y,
+		       int width, int height, int erase_p, int down_p,
+		       GC top_gc, GC bottom_gc)
 {
   Display *dpy = XtDisplay (mw);
-  GC top_gc = !erase_p ? mw->menu.shadow_top_gc : mw->menu.background_gc;
-  GC bottom_gc = !erase_p ? mw->menu.shadow_bottom_gc : mw->menu.background_gc;
   int thickness = !x && !y ? mw->menu.border_thickness : mw->menu.shadow_thickness;
   XPoint points [4];
 
+  /* Choose correct GC with a standard default if NULL.  */
+  if (erase_p)
+    {
+      top_gc = mw->menu.background_gc;
+      bottom_gc = mw->menu.background_gc;
+    }
+  else
+    {
+      if (top_gc == NULL)
+	top_gc = mw->menu.shadow_top_gc;
+      if (bottom_gc == NULL)
+	bottom_gc = mw->menu.shadow_bottom_gc;
+    }
+
   if (!erase_p && width == height && width == toggle_button_width (mw))
     {
       points [0].x = x;
@@ -662,6 +678,7 @@ draw_shadow_rectangle (XlwMenuWidget mw,
       bottom_gc = temp;
     }
 
+  /* Do draw (or erase) shadows */
   points [0].x = x;
   points [0].y = y;
   points [1].x = x + width;
@@ -702,21 +719,28 @@ draw_shadow_rectangle (XlwMenuWidget mw,
 
 
 static void
-draw_shadow_rhombus (XlwMenuWidget mw,
-                     Window window,
-                     int x,
-                     int y,
-                     int width,
-                     int height,
-                     int erase_p,
-                     int down_p)
+draw_shadow_rhombus (XlwMenuWidget mw, Window window, int x, int y,
+                     int width, int height, int erase_p, int down_p,
+		     GC top_gc, GC bottom_gc)
 {
   Display *dpy = XtDisplay (mw);
-  GC top_gc = !erase_p ? mw->menu.shadow_top_gc : mw->menu.background_gc;
-  GC bottom_gc = !erase_p ? mw->menu.shadow_bottom_gc : mw->menu.background_gc;
   int thickness = mw->menu.shadow_thickness;
   XPoint points [4];
 
+  /* Choose correct GC with a standard default if NULL */
+  if (erase_p)
+    {
+      top_gc = mw->menu.background_gc;
+      bottom_gc = mw->menu.background_gc;
+    }
+  else
+    {
+      if (top_gc == NULL)
+	top_gc = mw->menu.shadow_top_gc;
+      if (bottom_gc == NULL)
+	top_gc = mw->menu.shadow_bottom_gc;
+    }
+
   if (!erase_p && width == height && width == radio_button_width (mw))
     {
       points [0].x = x;
@@ -784,15 +808,29 @@ draw_shadow_rhombus (XlwMenuWidget mw,
    toggle button is selected.  */
 
 static void
-draw_toggle (XlwMenuWidget mw, Window window, int x, int y, int selected_p)
+draw_toggle (XlwMenuWidget mw, Window window, int x, int y, int selected_p,
+	     int highlighted_p)
 {
   int width, height;
+  GC top_gc, bottom_gc;
+
+  if (highlighted_p)
+    {
+      top_gc = mw->menu.highlight_shadow_top_gc;
+      bottom_gc = mw->menu.highlight_shadow_bottom_gc;
+    }
+  else
+    {
+      top_gc = mw->menu.shadow_top_gc;
+      bottom_gc = mw->menu.shadow_bottom_gc;
+    }
 
   width = toggle_button_width (mw);
   height = width;
   x += mw->menu.horizontal_spacing;
   y += (MENU_FONT_ASCENT (mw) - height) / 2;
-  draw_shadow_rectangle (mw, window, x, y, width, height, False, selected_p);
+  draw_shadow_rectangle (mw, window, x, y, width, height, False,
+			 selected_p, top_gc, bottom_gc);
 }
 
 
@@ -801,15 +839,29 @@ draw_toggle (XlwMenuWidget mw, Window window, int x, int y, int selected_p)
    toggle button is selected.  */
 
 static void
-draw_radio (XlwMenuWidget mw, Window window, int x, int y, int selected_p)
+draw_radio (XlwMenuWidget mw, Window window, int x, int y, int selected_p,
+	    int highlighted_p)
 {
   int width, height;
+  GC top_gc, bottom_gc;
+
+  if (highlighted_p)
+    {
+      top_gc = mw->menu.highlight_shadow_top_gc;
+      bottom_gc = mw->menu.highlight_shadow_bottom_gc;
+    }
+  else
+    {
+      top_gc = mw->menu.shadow_top_gc;
+      bottom_gc = mw->menu.shadow_bottom_gc;
+    }
 
   width = radio_button_width (mw);
   height = width;
   x += mw->menu.horizontal_spacing;
   y += (MENU_FONT_ASCENT (mw) - height) / 2;
-  draw_shadow_rhombus (mw, window, x, y, width, height, False, selected_p);
+  draw_shadow_rhombus (mw, window, x, y, width, height, False, selected_p,
+		       top_gc, bottom_gc);
 }
 
 
@@ -968,6 +1020,31 @@ separator_height (enum menu_separator separator)
     }
 }
 
+/* Draw the highlighted background and shadows.  */
+
+static void
+draw_highlight (XlwMenuWidget mw, Window window, int x, int y, int width,
+		int height)
+{
+  Display *dpy = XtDisplay (mw);
+  XPoint points [4];
+
+  points [0].x = x;
+  points [0].y = y;
+  points [1].x = x + width;
+  points [1].y = y;
+  points [2].x = x + width;
+  points [2].y = y + height;
+  points [3].x = x;
+  points [3].y = y + height;
+  XFillPolygon (dpy, window,
+		mw->menu.highlight_background_gc,
+		points, 4, Convex, CoordModeOrigin);
+
+  draw_shadow_rectangle(mw, window, x, y, width, height, False, False,
+			mw->menu.highlight_shadow_top_gc,
+			mw->menu.highlight_shadow_bottom_gc);
+}
 
 /* Display the menu item and increment where.x and where.y to show how large
    the menu item was.  */
@@ -983,7 +1060,6 @@ display_menu_item (XlwMenuWidget mw,
 {
   GC deco_gc;
   GC text_gc;
-  int font_height = MENU_FONT_HEIGHT (mw);
   int font_ascent = MENU_FONT_ASCENT (mw);
   int shadow = mw->menu.shadow_thickness;
   int margin = mw->menu.margin;
@@ -1032,12 +1108,21 @@ display_menu_item (XlwMenuWidget mw,
 
       /* pick the foreground and background GC. */
       if (val->enabled)
-	text_gc = mw->menu.foreground_gc;
+	if (highlighted_p)
+	  text_gc = mw->menu.highlight_foreground_gc;
+	else
+	  text_gc = mw->menu.foreground_gc;
       else
 	text_gc = mw->menu.disabled_gc;
       deco_gc = mw->menu.foreground_gc;
 #if defined USE_CAIRO || defined HAVE_XFT
-      xftfg = val->enabled ? &mw->menu.xft_fg : &mw->menu.xft_disabled_fg;
+      if (val->enabled)
+	if (highlighted_p)
+	  xftfg = &mw->menu.xft_highlight_fg;
+	else
+	  xftfg = &mw->menu.xft_fg;
+      else
+	xftfg = &mw->menu.xft_disabled_fg;
 #endif
 
       if (separator_p)
@@ -1048,8 +1133,11 @@ display_menu_item (XlwMenuWidget mw,
 	{
 	  int x_offset = x + h_spacing + shadow;
 	  char* display_string = resource_widget_value (mw, val);
-	  draw_shadow_rectangle (mw, ws->pixmap, x, y, width, height, True,
-				 False);
+	  /* Clears shadows and maybe highlight */
+	  draw_shadow_rectangle (mw, ws->pixmap, x, y, width, height,
+				 True, False, NULL, NULL);
+	  if (highlighted_p)
+	    draw_highlight (mw, ws->pixmap, x, y, width, height);
 
 	  /* Deal with centering a menu title. */
 	  if (!horizontal_p && !val->contents && !val->call_data)
@@ -1095,10 +1183,10 @@ display_menu_item (XlwMenuWidget mw,
 	    {
 	      if (val->button_type == BUTTON_TYPE_TOGGLE)
 		draw_toggle (mw, ws->pixmap, x, y + v_spacing + shadow,
-			     val->selected);
+			     val->selected, highlighted_p);
 	      else if (val->button_type == BUTTON_TYPE_RADIO)
 		draw_radio (mw, ws->pixmap, x, y + v_spacing + shadow,
-			    val->selected);
+			    val->selected, highlighted_p);
 
 	      if (val->contents)
 		{
@@ -1145,25 +1233,18 @@ display_menu_item (XlwMenuWidget mw,
 	    }
 	  else
 	    {
-	      XDrawRectangle (XtDisplay (mw), ws->pixmap,
-			      mw->menu.background_gc,
-			      x + shadow, y + shadow,
-			      label_width + h_spacing - 1,
-			      font_height + 2 * v_spacing - 1);
-	      draw_shadow_rectangle (mw, ws->pixmap, x, y, width, height,
-				     True, False);
+	      /* If not highlighted, clears shadows for horizontal
+		 menu item */
+	      if (!highlighted_p)
+		draw_shadow_rectangle (mw, ws->pixmap, x, y, width, height,
+				       True, False, NULL, NULL);
 	    }
 #ifdef USE_CAIRO
 	  if (ws->xft_draw)
 	    cairo_surface_flush (cairo_get_target (ws->xft_draw));
 #endif
-
-	  if (highlighted_p)
-	    draw_shadow_rectangle (mw, ws->pixmap, x, y, width, height, False,
-				   False);
 	}
     }
-
   where->x += width;
   where->y += height;
 }
@@ -1257,7 +1338,7 @@ display_menu (XlwMenuWidget mw,
   if (!just_compute_p)
     {
       draw_shadow_rectangle (mw, ws->pixmap, 0, 0, ws->width, ws->height,
-                             False, False);
+                             False, False, NULL, NULL);
       XCopyArea (XtDisplay (mw), ws->pixmap, ws->window,
                  mw->menu.foreground_gc, 0, 0, ws->width, ws->height, 0, 0);
     }
@@ -1714,6 +1795,18 @@ #define BRIGHTNESS(color) (((color) & 0xff) + (((color) >> 8) & 0xff) + (((color
   xgcv.foreground = mw->core.background_pixel;
   xgcv.background = mw->menu.foreground;
   mw->menu.background_gc = XtGetGC ((Widget)mw, mask, &xgcv);
+
+  xgcv.foreground = mw->menu.highlight_foreground;
+  xgcv.background = ((mw->menu.highlight_background == -1)
+		     ? mw->core.background_pixel
+		     : mw->menu.highlight_background);
+  mw->menu.highlight_foreground_gc = XtGetGC ((Widget)mw, mask, &xgcv);
+
+  xgcv.foreground = ((mw->menu.highlight_background == -1)
+		     ? mw->core.background_pixel
+		     : mw->menu.highlight_background);
+  xgcv.background = mw->menu.foreground;
+  mw->menu.highlight_background_gc = XtGetGC ((Widget)mw, mask, &xgcv);
 }
 
 static void
@@ -1724,12 +1817,16 @@ release_drawing_gcs (XlwMenuWidget mw)
   XtReleaseGC ((Widget) mw, mw->menu.disabled_gc);
   XtReleaseGC ((Widget) mw, mw->menu.inactive_button_gc);
   XtReleaseGC ((Widget) mw, mw->menu.background_gc);
+  XtReleaseGC ((Widget) mw, mw->menu.highlight_foreground_gc);
+  XtReleaseGC ((Widget) mw, mw->menu.highlight_background_gc);
   /* let's get some segvs if we try to use these... */
   mw->menu.foreground_gc = (GC) -1;
   mw->menu.button_gc = (GC) -1;
   mw->menu.disabled_gc = (GC) -1;
   mw->menu.inactive_button_gc = (GC) -1;
   mw->menu.background_gc = (GC) -1;
+  mw->menu.highlight_foreground_gc = (GC) -1;
+  mw->menu.highlight_background_gc = (GC) -1;
 }
 
 #ifndef emacs
@@ -1738,29 +1835,29 @@ #define MINL(x,y) ((((unsigned long) (x)) < ((unsigned long) (y))) \
 #endif
 
 static void
-make_shadow_gcs (XlwMenuWidget mw)
+compute_shadow_colors (XlwMenuWidget mw, Pixel *top_color, Pixel *bottom_color,
+		       Boolean *free_top_p, Boolean *free_bottom_p,
+		       Pixmap *top_pixmap, Pixmap *bottom_pixmap,
+		       Pixel fore_color, Pixel back_color)
 {
-  XGCValues xgcv;
-  unsigned long pm = 0;
   Display *dpy = XtDisplay ((Widget) mw);
   Screen *screen = XtScreen ((Widget) mw);
   Colormap cmap = mw->core.colormap;
   XColor topc, botc;
   int top_frobbed = 0, bottom_frobbed = 0;
 
-  mw->menu.free_top_shadow_color_p = 0;
-  mw->menu.free_bottom_shadow_color_p = 0;
+  *free_top_p = False;
+  *free_bottom_p = False;
 
-  if (mw->menu.top_shadow_color == -1)
-    mw->menu.top_shadow_color = mw->core.background_pixel;
+  if (*top_color == -1)
+    *top_color = back_color;
 
-  if (mw->menu.bottom_shadow_color == -1)
-    mw->menu.bottom_shadow_color = mw->menu.foreground;
+  if (*bottom_color == -1)
+    *bottom_color = fore_color;
 
-  if (mw->menu.top_shadow_color == mw->core.background_pixel ||
-      mw->menu.top_shadow_color == mw->menu.foreground)
+  if (*top_color == back_color || *top_color == fore_color)
     {
-      topc.pixel = mw->core.background_pixel;
+      topc.pixel = back_color;
 #ifdef emacs
       if (x_alloc_lighter_color_for_widget ((Widget) mw, dpy, cmap,
 					    &topc.pixel,
@@ -1774,15 +1871,14 @@ make_shadow_gcs (XlwMenuWidget mw)
       if (XAllocColor (dpy, cmap, &topc))
 #endif
 	{
-	  mw->menu.top_shadow_color = topc.pixel;
-	  mw->menu.free_top_shadow_color_p = 1;
+	  *top_color = topc.pixel;
+	  *free_top_p = True;
 	  top_frobbed = 1;
 	}
     }
-  if (mw->menu.bottom_shadow_color == mw->menu.foreground ||
-      mw->menu.bottom_shadow_color == mw->core.background_pixel)
+  if (*bottom_color == fore_color || *bottom_color == back_color)
     {
-      botc.pixel = mw->core.background_pixel;
+      botc.pixel = back_color;
 #ifdef emacs
       if (x_alloc_lighter_color_for_widget ((Widget) mw, dpy, cmap,
 					    &botc.pixel,
@@ -1795,8 +1891,8 @@ make_shadow_gcs (XlwMenuWidget mw)
       if (XAllocColor (dpy, cmap, &botc))
 #endif
 	{
-	  mw->menu.bottom_shadow_color = botc.pixel;
-	  mw->menu.free_bottom_shadow_color_p = 1;
+	  *bottom_color = botc.pixel;
+	  *free_bottom_p = True;
 	  bottom_frobbed = 1;
 	}
     }
@@ -1805,63 +1901,94 @@ make_shadow_gcs (XlwMenuWidget mw)
     {
       if (topc.pixel == botc.pixel)
 	{
-	  if (botc.pixel == mw->menu.foreground)
+	  if (botc.pixel == fore_color)
 	    {
-	      if (mw->menu.free_top_shadow_color_p)
+	      if (*free_top_p)
 		{
-		  x_free_dpy_colors (dpy, screen, cmap,
-				     &mw->menu.top_shadow_color, 1);
-		  mw->menu.free_top_shadow_color_p = 0;
+		  x_free_dpy_colors (dpy, screen, cmap, top_color, 1);
+		  *free_top_p = False;
 		}
-	      mw->menu.top_shadow_color = mw->core.background_pixel;
+	      *top_color = back_color;
 	    }
 	  else
 	    {
-	      if (mw->menu.free_bottom_shadow_color_p)
+	      if (*free_bottom_p)
 		{
-		  x_free_dpy_colors (dpy, screen, cmap,
-				     &mw->menu.bottom_shadow_color, 1);
-		  mw->menu.free_bottom_shadow_color_p = 0;
+		  x_free_dpy_colors (dpy, screen, cmap, bottom_color, 1);
+		  *free_bottom_p = False;
 		}
-	      mw->menu.bottom_shadow_color = mw->menu.foreground;
+	      *bottom_color = fore_color;
 	    }
 	}
     }
 
-  if (!mw->menu.top_shadow_pixmap
-      && mw->menu.top_shadow_color == mw->core.background_pixel)
+  if (!*top_pixmap && *top_color == back_color)
     {
-      mw->menu.top_shadow_pixmap = mw->menu.gray_pixmap;
-      if (mw->menu.free_top_shadow_color_p)
+      *top_pixmap = mw->menu.gray_pixmap;
+      if (*free_top_p)
 	{
-	  x_free_dpy_colors (dpy, screen, cmap, &mw->menu.top_shadow_color, 1);
-	  mw->menu.free_top_shadow_color_p = 0;
+	  x_free_dpy_colors (dpy, screen, cmap, top_color, 1);
+	  *free_top_p = False;
 	}
-      mw->menu.top_shadow_color = mw->menu.foreground;
+      *top_color = fore_color;
     }
-  if (!mw->menu.bottom_shadow_pixmap
-      && mw->menu.bottom_shadow_color == mw->core.background_pixel)
+  if (!*bottom_pixmap && *bottom_color == back_color)
     {
-      mw->menu.bottom_shadow_pixmap = mw->menu.gray_pixmap;
-      if (mw->menu.free_bottom_shadow_color_p)
+      *bottom_pixmap = mw->menu.gray_pixmap;
+      if (*free_bottom_p)
 	{
-	  x_free_dpy_colors (dpy, screen, cmap,
-			     &mw->menu.bottom_shadow_color, 1);
-	  mw->menu.free_bottom_shadow_color_p = 0;
+	  x_free_dpy_colors (dpy, screen, cmap, bottom_color, 1);
+	  *free_bottom_p = False;
 	}
-      mw->menu.bottom_shadow_color = mw->menu.foreground;
+      *bottom_color = fore_color;
     }
+}
+
+static void
+make_shadow_gcs (XlwMenuWidget mw)
+{
+  XGCValues xgcv;
+  unsigned long pm = 0;
+
+  /* Normal shadows */
+  compute_shadow_colors (mw, &(mw->menu.top_shadow_color),
+			 &(mw->menu.bottom_shadow_color),
+			 &(mw->menu.free_top_shadow_color_p),
+			 &(mw->menu.free_bottom_shadow_color_p),
+			 &(mw->menu.top_shadow_pixmap),
+			 &(mw->menu.bottom_shadow_pixmap),
+			 mw->menu.foreground, mw->core.background_pixel);
+
+  /* Highlight shadows */
+  compute_shadow_colors (mw, &(mw->menu.top_highlight_shadow_color),
+			 &(mw->menu.bottom_highlight_shadow_color),
+			 &(mw->menu.free_top_highlight_shadow_color_p),
+			 &(mw->menu.free_bottom_highlight_shadow_color_p),
+			 &(mw->menu.top_highlight_shadow_pixmap),
+			 &(mw->menu.bottom_highlight_shadow_pixmap),
+			 mw->menu.highlight_foreground,
+			 mw->menu.highlight_background);
 
   xgcv.fill_style = FillStippled;
   xgcv.foreground = mw->menu.top_shadow_color;
   xgcv.stipple = mw->menu.top_shadow_pixmap;
-  pm = (xgcv.stipple ? GCStipple|GCFillStyle : 0);
-  mw->menu.shadow_top_gc = XtGetGC ((Widget)mw, GCForeground | pm, &xgcv);
+  pm = (xgcv.stipple ? GCStipple | GCFillStyle : 0);
+  mw->menu.shadow_top_gc = XtGetGC ((Widget) mw, GCForeground | pm, &xgcv);
 
   xgcv.foreground = mw->menu.bottom_shadow_color;
   xgcv.stipple = mw->menu.bottom_shadow_pixmap;
-  pm = (xgcv.stipple ? GCStipple|GCFillStyle : 0);
-  mw->menu.shadow_bottom_gc = XtGetGC ((Widget)mw, GCForeground | pm, &xgcv);
+  pm = (xgcv.stipple ? GCStipple | GCFillStyle : 0);
+  mw->menu.shadow_bottom_gc = XtGetGC ((Widget) mw, GCForeground | pm, &xgcv);
+
+  xgcv.foreground = mw->menu.top_highlight_shadow_color;
+  xgcv.stipple = mw->menu.top_highlight_shadow_pixmap;
+  pm = (xgcv.stipple ? GCStipple | GCFillStyle : 0);
+  mw->menu.highlight_shadow_top_gc = XtGetGC ((Widget) mw, GCForeground | pm, &xgcv);
+
+  xgcv.foreground = mw->menu.bottom_highlight_shadow_color;
+  xgcv.stipple = mw->menu.bottom_highlight_shadow_pixmap;
+  pm = (xgcv.stipple ? GCStipple | GCFillStyle : 0);
+  mw->menu.highlight_shadow_bottom_gc = XtGetGC ((Widget) mw, GCForeground | pm, &xgcv);
 }
 
 
@@ -1871,18 +1998,24 @@ release_shadow_gcs (XlwMenuWidget mw)
   Display *dpy = XtDisplay ((Widget) mw);
   Screen *screen = XtScreen ((Widget) mw);
   Colormap cmap = mw->core.colormap;
-  Pixel px[2];
+  Pixel px[4];
   int i = 0;
 
   if (mw->menu.free_top_shadow_color_p)
     px[i++] = mw->menu.top_shadow_color;
   if (mw->menu.free_bottom_shadow_color_p)
     px[i++] = mw->menu.bottom_shadow_color;
+  if (mw->menu.free_top_highlight_shadow_color_p)
+    px[i++] = mw->menu.top_highlight_shadow_color;
+  if (mw->menu.free_bottom_highlight_shadow_color_p)
+    px[i++] = mw->menu.bottom_highlight_shadow_color;
   if (i > 0)
     x_free_dpy_colors (dpy, screen, cmap, px, i);
 
   XtReleaseGC ((Widget) mw, mw->menu.shadow_top_gc);
   XtReleaseGC ((Widget) mw, mw->menu.shadow_bottom_gc);
+  XtReleaseGC ((Widget) mw, mw->menu.highlight_shadow_top_gc);
+  XtReleaseGC ((Widget) mw, mw->menu.highlight_shadow_bottom_gc);
 }
 
 #if defined USE_CAIRO || defined HAVE_XFT
@@ -1964,6 +2097,11 @@ XlwMenuInitialize (Widget request, Widget w, ArgList args, Cardinal *num_args)
     mw->menu.font_extents = XExtentsOfFontSet (mw->menu.fontSet);
 #endif
 
+  mw->menu.top_highlight_shadow_color = -1;
+  mw->menu.bottom_highlight_shadow_color = -1;
+  mw->menu.top_highlight_shadow_pixmap = None;
+  mw->menu.bottom_highlight_shadow_pixmap = None;
+
   make_drawing_gcs (mw);
   make_shadow_gcs (mw);
 
@@ -2038,12 +2176,14 @@ XlwMenuRealize (Widget w, Mask *valueMask, XSetWindowAttributes *attributes)
 #if defined USE_CAIRO || defined HAVE_XFT
   if (mw->menu.xft_font)
     {
-      XColor colors[3];
+      XColor colors[4];
       colors[0].pixel = mw->menu.xft_fg.pixel = mw->menu.foreground;
       colors[1].pixel = mw->menu.xft_bg.pixel = mw->core.background_pixel;
       colors[2].pixel = mw->menu.xft_disabled_fg.pixel
         = mw->menu.disabled_foreground;
-      XQueryColors (XtDisplay (mw), mw->core.colormap, colors, 3);
+      colors[3].pixel = mw->menu.xft_highlight_fg.pixel
+	= mw->menu.highlight_foreground;
+      XQueryColors (XtDisplay (mw), mw->core.colormap, colors, 4);
       mw->menu.xft_fg.color.alpha = 0xFFFF;
       mw->menu.xft_fg.color.red = colors[0].red;
       mw->menu.xft_fg.color.green = colors[0].green;
@@ -2056,6 +2196,10 @@ XlwMenuRealize (Widget w, Mask *valueMask, XSetWindowAttributes *attributes)
       mw->menu.xft_disabled_fg.color.red = colors[2].red;
       mw->menu.xft_disabled_fg.color.green = colors[2].green;
       mw->menu.xft_disabled_fg.color.blue = colors[2].blue;
+      mw->menu.xft_highlight_fg.color.alpha = 0xFFFF;
+      mw->menu.xft_highlight_fg.color.red = colors[3].red;
+      mw->menu.xft_highlight_fg.color.green = colors[3].green;
+      mw->menu.xft_highlight_fg.color.blue = colors[3].blue;
     }
 #endif
 }
diff --git a/lwlib/xlwmenu.h b/lwlib/xlwmenu.h
index 7f4bf35939..4e36bde3fb 100644
--- a/lwlib/xlwmenu.h
+++ b/lwlib/xlwmenu.h
@@ -58,6 +58,10 @@ #define XtNallowResize "allowResize"
 #define XtCAllowResize "AllowResize"
 #define XtNborderThickness "borderThickness"
 #define XtCBorderThickness "BorderThickness"
+#define XtNhighlightForeground "highlightForeground"
+#define XtCHighlightForeground "HighlightForeground"
+#define XtNhighlightBackground "highlightBackground"
+#define XtCHighlightBackground "HighlightBackground"
 
 /* Motif-compatible resource names */
 #define XmNshadowThickness	"shadowThickness"
diff --git a/lwlib/xlwmenuP.h b/lwlib/xlwmenuP.h
index 455ecdbce0..c314eb3e91 100644
--- a/lwlib/xlwmenuP.h
+++ b/lwlib/xlwmenuP.h
@@ -63,13 +63,15 @@ #define _XlwMenuP_h
 #if defined USE_CAIRO || defined HAVE_XFT
   int           default_face;
   XftFont*      xft_font;
-  XftColor      xft_fg, xft_bg, xft_disabled_fg;
+  XftColor      xft_fg, xft_bg, xft_disabled_fg, xft_highlight_fg;
 #endif
   String	fontName;
   XFontStruct*	font;
   Pixel		foreground;
   Pixel		disabled_foreground;
   Pixel		button_foreground;
+  Pixel		highlight_foreground;
+  Pixel		highlight_background;
   Dimension	margin;
   Dimension	horizontal_spacing;
   Dimension	vertical_spacing;
@@ -80,6 +82,10 @@ #define _XlwMenuP_h
   Pixel 	bottom_shadow_color;
   Pixmap	top_shadow_pixmap;
   Pixmap	bottom_shadow_pixmap;
+  Pixel 	top_highlight_shadow_color;
+  Pixel 	bottom_highlight_shadow_color;
+  Pixmap	top_highlight_shadow_pixmap;
+  Pixmap	bottom_highlight_shadow_pixmap;
   Cursor	cursor_shape;
   XtCallbackList	open;
   XtCallbackList	select, highlight;
@@ -88,8 +94,10 @@ #define _XlwMenuP_h
   int		horizontal;
 
   /* True means top_shadow_color and/or bottom_shadow_color must be freed.  */
-  bool_bf free_top_shadow_color_p : 1;
-  bool_bf free_bottom_shadow_color_p : 1;
+  Boolean free_top_shadow_color_p;
+  Boolean free_bottom_shadow_color_p;
+  Boolean free_top_highlight_shadow_color_p;
+  Boolean free_bottom_highlight_shadow_color_p;
 
   /* State of the XlwMenu */
   int                   top_depth;
@@ -112,9 +120,13 @@ #define _XlwMenuP_h
   GC			button_gc;
   GC			background_gc;
   GC			disabled_gc;
+  GC			highlight_foreground_gc;
+  GC			highlight_background_gc;
   GC			inactive_button_gc;
   GC			shadow_top_gc;
   GC			shadow_bottom_gc;
+  GC			highlight_shadow_top_gc;
+  GC			highlight_shadow_bottom_gc;
   Cursor		cursor;
   Boolean		popped_up;
   Pixmap		gray_pixmap;
-- 
2.37.0


[-- Attachment #3: Type: text/plain, Size: 18 bytes --]

-- 
Manuel Giraud

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* bug#56538: 29.0.50; [PATCH] Colored highlight in Lucid backend
  2022-07-16 10:56                   ` Manuel Giraud
@ 2022-07-16 10:59                     ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 0 replies; 13+ messages in thread
From: Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2022-07-16 10:59 UTC (permalink / raw)
  To: Manuel Giraud; +Cc: 56538-done

Manuel Giraud <manuel@ledu-giraud.fr> writes:

> Po Lu <luangruo@yahoo.com> writes:
>
>> How about "by the mouse or key navigation"?
>
> 👍 Here's the updated version.
>
> From f0a2392c04b2d3f514716df9757f0b8ed96efa22 Mon Sep 17 00:00:00 2001
> From: Manuel Giraud <manuel@ledu-giraud.fr>
> Date: Mon, 11 Jul 2022 11:14:08 +0200
> Subject: [PATCH] Colored menu highlight in Lucid backend

Installed, so I'm closing this bug.

Thanks for working on Emacs.





^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2022-07-16 10:59 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2022-07-13 13:38 bug#56538: 29.0.50; [PATCH] Colored highlight in Lucid backend Manuel Giraud
2022-07-14  0:53 ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
2022-07-14  9:42   ` Manuel Giraud
2022-07-14 10:34     ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
2022-07-14 13:17       ` Manuel Giraud
2022-07-15  2:06         ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
2022-07-15 11:50           ` Manuel Giraud
2022-07-15 11:56           ` Manuel Giraud
2022-07-15 12:58             ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
2022-07-15 13:27               ` Manuel Giraud
2022-07-16  3:04                 ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
2022-07-16 10:56                   ` Manuel Giraud
2022-07-16 10:59                     ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).