Subject: bug#23568: 25.0.94; Mode line menus appear incorrectly in some monitor configurations

From: Alex <[email-masked]>
Date: Sun, 28 May 2017 01:09:17 -0600

Alex <[email-masked]> writes:

> The menus that display when clicking on various items in the mode line
> (major mode, minor mode, buffer position) don't display correctly with
> certain monitor setups on X, specifically when using multiple monitors
> where the bottoms of the monitors are not even. They appear squished and
> are effectively unusable.
>
> FWIW, a similar issue appeared with the mode line tooltips that
> displayed when hovering over these items in Emacs 24.5, but they have
> since been fixed.
>
> The menu bar menus do not suffer this problem.
>
> When running from the command line, the following message usually
> appears:
>
> *** BUG ***
> In pixman_region32_init_rect: Invalid rectangle passed
> Set a breakpoint on '_pixman_log_error' to debug
>
> I tried to debug this in gdb, but setting the breakpoint made X hang
> when encountering this issue, so I was unable to procure a backtrace.
>
> I have attached a picture showing the problem. The static displayed is
> the area that I am unable to see, but is included by scrot. The squished
> prompt was from clicking on `Lisp Interaction' in the mode line.

This is still an issue in current master.

The tooltip issue I mentioned above last year was fixed in 7b14da444, so
I tried using pretty much the same code to fix this issue; a proof of
concept diff is included below.

I don't know if it's a good approach though. Partially because I have no
idea why the values of req.{height, width} are so large, why they differ
in different Emacs sessions, and how they relate to the other
width/height variables.

In any case, perhaps this functionality should be abstracted into a
procedure that just computes the dimensions of the current monitor?

diff --git a/src/xmenu.c b/src/xmenu.c
index 2805249164..9a87fce380 100644
--- a/src/xmenu.c
+++ b/src/xmenu.c
@@ -1161,8 +1161,43 @@ menu_position_func (GtkMenu *menu, gint *x, gint *y, gboolean *push_in, gpointer
   struct next_popup_x_y *data = user_data;
   GtkRequisition req;
   struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (data->f);
-  int disp_width = x_display_pixel_width (dpyinfo);
-  int disp_height = x_display_pixel_height (dpyinfo);
+  int disp_width;
+  int disp_height;
+
+  int min_x, min_y, max_x, max_y = -1;
+  Lisp_Object frame, attributes, monitor, geometry;
+
+  XSETFRAME(frame, data->f);
+  attributes = Fx_display_monitor_attributes_list (frame);
+
+  /* Try to determine the current monitor's resolution */
+  while (CONSP (attributes))
+    {
+      monitor = XCAR (attributes);
+      geometry = Fassq (Qgeometry, monitor);
+      if (CONSP (geometry))
+        {
+          min_x = XINT (Fnth (make_number (1), geometry));
+          min_y = XINT (Fnth (make_number (2), geometry));
+          max_x = min_x + XINT (Fnth (make_number (3), geometry));
+          max_y = min_y + XINT (Fnth (make_number (4), geometry));
+          if (min_x <= data->x && data->x < max_x
+              && min_y <= data->y && data->y < max_y)
+            {
+              disp_width = max_x;
+              disp_height = max_y;
+              break;
+            }
+          max_y = -1;
+        }
+
+      attributes = XCDR (attributes);
+    }
+  if ( max_y < 0 )
+    {
+      disp_width = x_display_pixel_width (dpyinfo);
+      disp_height = x_display_pixel_height (dpyinfo);
+    }
 
   *x = data->x;
   *y = data->y;