emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

master b6b2f797d9: Fix menu placement on multiple-display setups when us


From: Po Lu
Subject: master b6b2f797d9: Fix menu placement on multiple-display setups when using lwlib
Date: Mon, 27 Dec 2021 21:52:50 -0500 (EST)

branch: master
commit b6b2f797d9df3e5562b946d5f4c690f8967c1b88
Author: Po Lu <luangruo@yahoo.com>
Commit: Po Lu <luangruo@yahoo.com>

    Fix menu placement on multiple-display setups when using lwlib
    
    * lwlib/xlwmenu.c (fit_to_screen):
    (pop_up_menu): Adjust menu position based on dimensions of the
    current monitor's workarea.  (bug#52809)
    
    * src/xfns.c (x_get_monitor_attributes): Stop testing for the
    RandR extension here.
    (xlw_monitor_dimensions_at_pos_1):
    (xlw_monitor_dimensions_at_pos): New functions.
    
    * src/xterm.c (x_term_init): Query for the RandR extension when
    connecting to a display.
    * src/xterm.h (xlw_monitor_dimensions_at_pos): New prototype.
---
 lwlib/xlwmenu.c |  73 ++++++++++++++++++++----------
 src/xfns.c      | 137 +++++++++++++++++++++++++++++++++++++++++++++++++++-----
 src/xterm.c     |  15 +++++++
 src/xterm.h     |   4 ++
 4 files changed, 195 insertions(+), 34 deletions(-)

diff --git a/lwlib/xlwmenu.c b/lwlib/xlwmenu.c
index a0a10d13db..a065c53310 100644
--- a/lwlib/xlwmenu.c
+++ b/lwlib/xlwmenu.c
@@ -1390,27 +1390,40 @@ fit_to_screen (XlwMenuWidget mw,
                window_state *previous_ws,
                Boolean horizontal_p)
 {
-  unsigned int screen_width = WidthOfScreen (XtScreen (mw));
-  unsigned int screen_height = HeightOfScreen (XtScreen (mw));
+  int screen_width, screen_height;
+  int screen_x, screen_y;
+
+#ifdef emacs
+  xlw_monitor_dimensions_at_pos (XtDisplay (mw), XtScreen (mw),
+                                ws->x, ws->y, &screen_x, &screen_y,
+                                &screen_width, &screen_height);
+#else
+  screen_width = WidthOfScreen (XtScreen (mw));
+  screen_height = HeightOfScreen (XtScreen (mw));
+  screen_x = 0;
+  screen_y = 0;
+#endif
   /* 1 if we are unable to avoid an overlap between
      this menu and the parent menu in the X dimension.  */
   int horizontal_overlap = 0;
 
-  if (ws->x < 0)
+  if (ws->x < screen_x)
     ws->x = 0;
-  else if (ws->x + ws->width > screen_width)
+  else if (ws->x + ws->width > screen_x + screen_width)
     {
       if (!horizontal_p)
        /* The addition of shadow-thickness for a sub-menu's position is
           to reflect a similar adjustment when the menu is displayed to
           the right of the invoking menu-item; it makes the sub-menu
           look more `attached' to the menu-item.  */
-       ws->x = previous_ws->x - ws->width + mw->menu.shadow_thickness;
+       ws->x = screen_x + (previous_ws->x
+                           - ws->width
+                           + mw->menu.shadow_thickness);
       else
-       ws->x = screen_width - ws->width;
-      if (ws->x < 0)
+       ws->x = screen_x + (screen_width - ws->width);
+      if (ws->x < screen_x)
        {
-         ws->x = 0;
+         ws->x = screen_x;
          horizontal_overlap = 1;
        }
     }
@@ -1427,16 +1440,16 @@ fit_to_screen (XlwMenuWidget mw,
        ws->y = previous_ws->y - ws->height;
     }
 
-  if (ws->y < 0)
-    ws->y = 0;
-  else if (ws->y + ws->height > screen_height)
+  if (ws->y < screen_y)
+    ws->y = screen_y;
+  else if (ws->y + ws->height > screen_y + screen_height)
     {
       if (horizontal_p)
-       ws->y = previous_ws->y - ws->height;
+       ws->y = screen_y + (previous_ws->y - ws->height);
       else
-       ws->y = screen_height - ws->height;
-      if (ws->y < 0)
-        ws->y = 0;
+       ws->y = screen_y + (screen_height - ws->height);
+      if (ws->y < screen_y)
+        ws->y = screen_y;
     }
 }
 
@@ -2626,7 +2639,21 @@ pop_up_menu (XlwMenuWidget mw, XButtonPressedEvent 
*event)
   int          borderwidth = mw->menu.shadow_thickness;
   Screen*      screen = XtScreen (mw);
   Display       *display = XtDisplay (mw);
+  int          screen_x;
+  int          screen_y;
+  int          screen_w;
+  int          screen_h;
 
+#ifdef emacs
+  xlw_monitor_dimensions_at_pos (display, screen, x, y,
+                                &screen_x, &screen_y,
+                                &screen_w, &screen_h);
+#else
+  screen_x = 0;
+  screen_y = 0;
+  screen_w = WidthOfScreen (screen);
+  screen_h = HeightOfScreen (screen);
+#endif
   next_release_must_exit = 0;
 
   mw->menu.inside_entry = NULL;
@@ -2640,14 +2667,14 @@ pop_up_menu (XlwMenuWidget mw, XButtonPressedEvent 
*event)
 
   x -= borderwidth;
   y -= borderwidth;
-  if (x < borderwidth)
-    x = borderwidth;
-  if (x + w + 2 * borderwidth > WidthOfScreen (screen))
-    x = WidthOfScreen (screen) - w - 2 * borderwidth;
-  if (y < borderwidth)
-    y = borderwidth;
-  if (y + h + 2 * borderwidth> HeightOfScreen (screen))
-    y = HeightOfScreen (screen) - h - 2 * borderwidth;
+  if (x < screen_x + borderwidth)
+    x = screen_x + borderwidth;
+  if (x + w + 2 * borderwidth > screen_x + screen_w)
+    x = (screen_x + screen_w) - w - 2 * borderwidth;
+  if (y < screen_y + borderwidth)
+    y = screen_y + borderwidth;
+  if (y + h + 2 * borderwidth > screen_y + screen_h)
+    y = (screen_y + screen_h) - h - 2 * borderwidth;
 
   mw->menu.popped_up = True;
   if (XtIsShell (XtParent ((Widget)mw)))
diff --git a/src/xfns.c b/src/xfns.c
index ad77ebc8f4..8dc383ddfa 100644
--- a/src/xfns.c
+++ b/src/xfns.c
@@ -5041,17 +5041,9 @@ x_get_monitor_attributes (struct x_display_info *dpyinfo)
   (void) dpy; /* Suppress unused variable warning.  */
 
 #ifdef HAVE_XRANDR
-  int xrr_event_base, xrr_error_base;
-  bool xrr_ok = false;
-  xrr_ok = XRRQueryExtension (dpy, &xrr_event_base, &xrr_error_base);
-  if (xrr_ok)
-    {
-      XRRQueryVersion (dpy, &dpyinfo->xrandr_major_version,
-                      &dpyinfo->xrandr_minor_version);
-      xrr_ok = ((dpyinfo->xrandr_major_version == 1
-                && dpyinfo->xrandr_minor_version >= 2)
-               || dpyinfo->xrandr_major_version > 1);
-    }
+  bool xrr_ok = ((dpyinfo->xrandr_major_version == 1
+                 && dpyinfo->xrandr_minor_version >= 2)
+                || dpyinfo->xrandr_major_version > 1);
 
   if (xrr_ok)
     attributes_list = x_get_monitor_attributes_xrandr (dpyinfo);
@@ -5076,6 +5068,129 @@ x_get_monitor_attributes (struct x_display_info 
*dpyinfo)
 
 #endif /* !USE_GTK */
 
+#ifdef USE_LUCID
+/* This is used by the Lucid menu widget, but it's defined here so we
+   can make use of a great deal of existing code.  */
+static void
+xlw_monitor_dimensions_at_pos_1 (struct x_display_info *dpyinfo,
+                                Screen *screen, int src_x, int src_y,
+                                int *x, int *y, int *width, int *height)
+{
+  Lisp_Object attrs, tem, val;
+#ifdef HAVE_XRANDR
+#if RANDR_MAJOR > 1 || (RANDR_MAJOR == 1 && RANDR_MINOR >= 5)
+  int num_rr_monitors;
+  XRRMonitorInfo *rr_monitors;
+
+  /* If RandR 1.5 or later is available, use that instead, as some
+     video drivers don't report correct dimensions via other versions
+     of RandR.  */
+  if (dpyinfo->xrandr_major_version > 1
+      || (dpyinfo->xrandr_major_version == 1
+         && dpyinfo->xrandr_minor_version >= 5))
+    {
+      rr_monitors = XRRGetMonitors (dpyinfo->display,
+                                   RootWindowOfScreen (screen),
+                                   True, &num_rr_monitors);
+      if (!rr_monitors)
+       goto fallback;
+
+      for (int i = 0; i < num_rr_monitors; ++i)
+       {
+         if (rr_monitors[i].x <= src_x
+             && src_x < (rr_monitors[i].x
+                         + rr_monitors[i].width)
+             && rr_monitors[i].y <= src_y
+             && src_y < (rr_monitors[i].y
+                         + rr_monitors[i].height))
+           {
+             *x = rr_monitors[i].x;
+             *y = rr_monitors[i].y;
+             *width = rr_monitors[i].width;
+             *height = rr_monitors[i].height;
+
+             XRRFreeMonitors (rr_monitors);
+             return;
+           }
+       }
+      XRRFreeMonitors (rr_monitors);
+    }
+
+ fallback:
+#endif
+#endif
+
+  attrs = x_get_monitor_attributes (dpyinfo);
+
+  for (tem = attrs; CONSP (tem); tem = XCDR (tem))
+    {
+      int sx, sy, swidth, sheight;
+      val = assq_no_quit (Qgeometry, XCAR (tem));
+      if (!NILP (val))
+       {
+         sx = XFIXNUM (XCAR (XCDR (val)));
+         sy = XFIXNUM (XCAR (XCDR (XCDR (val))));
+         swidth = XFIXNUM (XCAR (XCDR (XCDR (XCDR (val)))));
+         sheight = XFIXNUM (XCAR (XCDR (XCDR (XCDR (XCDR (val))))));
+
+         if (sx <= src_x && src_x < (sx + swidth)
+             && sy <= src_y && src_y < (sy + swidth))
+           {
+             *x = sx;
+             *y = sy;
+             *width = swidth;
+             *height = sheight;
+             return;
+           }
+       }
+    }
+
+  *x = 0;
+  *y = 0;
+  *width = WidthOfScreen (screen);
+  *height = HeightOfScreen (screen);
+}
+
+void
+xlw_monitor_dimensions_at_pos (Display *dpy, Screen *screen, int src_x,
+                              int src_y, int *x, int *y, int *width, int 
*height)
+{
+  struct x_display_info *dpyinfo = x_display_info_for_display (dpy);
+  XRectangle rect, workarea, intersection;
+  int dim_x, dim_y, dim_w, dim_h;
+
+  if (!dpyinfo)
+    emacs_abort ();
+
+  block_input ();
+  xlw_monitor_dimensions_at_pos_1 (dpyinfo, screen, src_x, src_y,
+                                  &dim_x, &dim_y, &dim_w, &dim_h);
+  rect.x = dim_x;
+  rect.y = dim_y;
+  rect.width = dim_w;
+  rect.height = dim_h;
+
+  if (!x_get_net_workarea (dpyinfo, &workarea))
+    memset (&workarea, 0, sizeof workarea);
+  unblock_input ();
+
+  if (!gui_intersect_rectangles (&rect, &workarea, &intersection))
+    {
+      *x = 0;
+      *y = 0;
+      *width = 0;
+      *height = 0;
+      return;
+    }
+
+  *x = intersection.x;
+  *y = intersection.y;
+  *width = intersection.width;
+  *height = intersection.height;
+}
+#endif
+
+
 DEFUN ("x-display-monitor-attributes-list", Fx_display_monitor_attributes_list,
        Sx_display_monitor_attributes_list,
        0, 1, 0,
diff --git a/src/xterm.c b/src/xterm.c
index 698c1eba8b..3fdf214c3d 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -46,6 +46,10 @@ along with GNU Emacs.  If not, see 
<https://www.gnu.org/licenses/>.  */
 #include <X11/extensions/XInput2.h>
 #endif
 
+#ifdef HAVE_XRANDR
+#include <X11/extensions/Xrandr.h>
+#endif
+
 /* Load sys/types.h if not already loaded.
    In some systems loading it twice is suicidal.  */
 #ifndef makedev
@@ -14803,6 +14807,17 @@ x_term_init (Lisp_Object display_name, char 
*xrm_option, char *resource_name)
   dpyinfo->xi2_version = minor;
 #endif
 
+#ifdef HAVE_XRANDR
+  int xrr_event_base, xrr_error_base;
+  bool xrr_ok = false;
+  xrr_ok = XRRQueryExtension (dpy, &xrr_event_base, &xrr_error_base);
+  if (xrr_ok)
+    {
+      XRRQueryVersion (dpy, &dpyinfo->xrandr_major_version,
+                      &dpyinfo->xrandr_minor_version);
+    }
+#endif
+
 #ifdef HAVE_XKB
   dpyinfo->xkb_desc = XkbGetMap (dpyinfo->display,
                                 XkbAllComponentsMask,
diff --git a/src/xterm.h b/src/xterm.h
index d9ace002d5..5615a55d6b 100644
--- a/src/xterm.h
+++ b/src/xterm.h
@@ -1240,6 +1240,10 @@ extern void x_change_tool_bar_height (struct frame *, 
int);
 extern void x_implicitly_set_name (struct frame *, Lisp_Object, Lisp_Object);
 extern void x_set_scroll_bar_default_width (struct frame *);
 extern void x_set_scroll_bar_default_height (struct frame *);
+#ifdef USE_LUCID
+extern void xlw_monitor_dimensions_at_pos (Display *, Screen *, int, int,
+                                          int *, int *, int *, int *);
+#endif
 
 /* Defined in xselect.c.  */
 



reply via email to

[Prev in Thread] Current Thread [Next in Thread]