aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexander Gramiak2017-06-10 12:28:03 +0300
committerEli Zaretskii2017-06-10 12:28:03 +0300
commitbdf41152af3434307218ac2863b737c4486f740e (patch)
treed8c2275a5814aa0c3be2761c1282b30007551bc1
parent187a71df596a331a23bf86ee314c12035f42aff2 (diff)
downloademacs-bdf41152af3434307218ac2863b737c4486f740e.tar.gz
emacs-bdf41152af3434307218ac2863b737c4486f740e.zip
Fix the placement of GTK menus on multi-monitor systems
menu_position_func did not properly use the current monitor's resolution. Also see commit '2016-02-06 22:12:53 +0100'. * lisp/frame.el (frame-monitor-attribute, frame-monitor-geometry) (frame-monitor-workarea): New functions. * src/xmenu.c (menu_position_func): Take into account the workarea of the monitor that contains the mouse. (Bug#23568)
-rw-r--r--lisp/frame.el69
-rw-r--r--src/xmenu.c46
2 files changed, 108 insertions, 7 deletions
diff --git a/lisp/frame.el b/lisp/frame.el
index 02871e0551d..dc7bb24bb3a 100644
--- a/lisp/frame.el
+++ b/lisp/frame.el
@@ -1498,6 +1498,75 @@ keys and their meanings."
1498 for frames = (cdr (assq 'frames attributes)) 1498 for frames = (cdr (assq 'frames attributes))
1499 if (memq frame frames) return attributes)) 1499 if (memq frame frames) return attributes))
1500 1500
1501(defun frame-monitor-attribute (attribute &optional frame x y)
1502 "Return the value of ATTRIBUTE on FRAME's monitor.
1503If FRAME is omitted or nil, use currently selected frame.
1504
1505By default, the current monitor is the physical monitor
1506dominating the selected frame. A frame is dominated by a
1507physical monitor when either the largest area of the frame
1508resides in the monitor, or the monitor is the closest to the
1509frame if the frame does not intersect any physical monitors.
1510
1511If X and Y are both numbers, then ignore the value of FRAME; the
1512monitor is determined to be the physical monitor that contains
1513the pixel coordinate (X, Y).
1514
1515See `display-monitor-attributes-list' for the list of attribute
1516keys and their meanings."
1517 (if (and (numberp x)
1518 (numberp y))
1519 (cl-loop for monitor in (display-monitor-attributes-list)
1520 for geometry = (alist-get 'geometry monitor)
1521 for min-x = (pop geometry)
1522 for min-y = (pop geometry)
1523 for max-x = (+ min-x (pop geometry))
1524 for max-y = (+ min-y (car geometry))
1525 when (and (<= min-x x)
1526 (< x max-x)
1527 (<= min-y y)
1528 (< y max-y))
1529 return (alist-get attribute monitor))
1530 (alist-get attribute (frame-monitor-attributes frame))))
1531
1532(defun frame-monitor-geometry (&optional frame x y)
1533 "Return the geometry of FRAME's monitor.
1534FRAME can be a frame name, a terminal name, or a frame.
1535If FRAME is omitted or nil, use the currently selected frame.
1536
1537By default, the current monitor is said to be the physical
1538monitor dominating teh selected frame. A frame is dominated by
1539a physical monitor when either the largest area of the frame resides
1540in the monitor, or the monitor is the closest to the frame if the
1541frame does not intersect any physical monitors.
1542
1543If X and Y are both numbers, then ignore the value of FRAME; the
1544monitor is determined to be the physical monitor that contains
1545the pixel coordinate (X, Y).
1546
1547See `display-monitor-attributes-list' for information on the
1548geometry attribute."
1549 (frame-monitor-attribute 'geometry frame x y))
1550
1551(defun frame-monitor-workarea (&optional frame x y)
1552 "Return the workarea of FRAME's monitor.
1553FRAME can be a frame name, a terminal name, or a frame.
1554If FRAME is omitted or nil, use currently selected frame.
1555
1556By default, the current monitor is said to be the physical
1557monitor dominating the selected frame. A frame is dominated by
1558a physical monitor when either the largest area of the frame resides
1559in the monitor, or the monitor is the closest to the frame if the
1560frame does not intersect any physical monitors.
1561
1562If X and Y are both numbers, then ignore the value of FRAME; the
1563monitor is determined to be the physical monitor that contains
1564the pixel coordinate (X, Y).
1565
1566See `display-monitor-attributes-list' for information on the
1567workarea attribute."
1568 (frame-monitor-attribute 'workarea frame x y))
1569
1501(declare-function x-frame-list-z-order "xfns.c" (&optional display)) 1570(declare-function x-frame-list-z-order "xfns.c" (&optional display))
1502(declare-function w32-frame-list-z-order "w32fns.c" (&optional display)) 1571(declare-function w32-frame-list-z-order "w32fns.c" (&optional display))
1503(declare-function ns-frame-list-z-order "nsfns.m" (&optional display)) 1572(declare-function ns-frame-list-z-order "nsfns.m" (&optional display))
diff --git a/src/xmenu.c b/src/xmenu.c
index 28052491646..6c8a0c506cc 100644
--- a/src/xmenu.c
+++ b/src/xmenu.c
@@ -1160,9 +1160,37 @@ menu_position_func (GtkMenu *menu, gint *x, gint *y, gboolean *push_in, gpointer
1160{ 1160{
1161 struct next_popup_x_y *data = user_data; 1161 struct next_popup_x_y *data = user_data;
1162 GtkRequisition req; 1162 GtkRequisition req;
1163 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (data->f); 1163 int max_x = -1;
1164 int disp_width = x_display_pixel_width (dpyinfo); 1164 int max_y = -1;
1165 int disp_height = x_display_pixel_height (dpyinfo); 1165
1166 Lisp_Object frame, workarea;
1167
1168 XSETFRAME (frame, data->f);
1169
1170 /* TODO: Get the monitor workarea directly without calculating other
1171 items in x-display-monitor-attributes-list. */
1172 workarea = call3 (Qframe_monitor_workarea,
1173 Qnil,
1174 make_number (data->x),
1175 make_number (data->y));
1176
1177 if (CONSP (workarea))
1178 {
1179 int min_x, min_y;
1180
1181 min_x = XINT (XCAR (workarea));
1182 min_y = XINT (Fnth (make_number (1), workarea));
1183 max_x = min_x + XINT (Fnth (make_number (2), workarea));
1184 max_y = min_y + XINT (Fnth (make_number (3), workarea));
1185 }
1186
1187 if (max_x < 0 || max_y < 0)
1188 {
1189 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (data->f);
1190
1191 max_x = x_display_pixel_width (dpyinfo);
1192 max_y = x_display_pixel_height (dpyinfo);
1193 }
1166 1194
1167 *x = data->x; 1195 *x = data->x;
1168 *y = data->y; 1196 *y = data->y;
@@ -1170,10 +1198,10 @@ menu_position_func (GtkMenu *menu, gint *x, gint *y, gboolean *push_in, gpointer
1170 /* Check if there is room for the menu. If not, adjust x/y so that 1198 /* Check if there is room for the menu. If not, adjust x/y so that
1171 the menu is fully visible. */ 1199 the menu is fully visible. */
1172 gtk_widget_get_preferred_size (GTK_WIDGET (menu), NULL, &req); 1200 gtk_widget_get_preferred_size (GTK_WIDGET (menu), NULL, &req);
1173 if (data->x + req.width > disp_width) 1201 if (data->x + req.width > max_x)
1174 *x -= data->x + req.width - disp_width; 1202 *x -= data->x + req.width - max_x;
1175 if (data->y + req.height > disp_height) 1203 if (data->y + req.height > max_y)
1176 *y -= data->y + req.height - disp_height; 1204 *y -= data->y + req.height - max_y;
1177} 1205}
1178 1206
1179static void 1207static void
@@ -2361,6 +2389,10 @@ syms_of_xmenu (void)
2361 DEFSYM (Qdebug_on_next_call, "debug-on-next-call"); 2389 DEFSYM (Qdebug_on_next_call, "debug-on-next-call");
2362 defsubr (&Smenu_or_popup_active_p); 2390 defsubr (&Smenu_or_popup_active_p);
2363 2391
2392#ifdef USE_GTK
2393 DEFSYM (Qframe_monitor_workarea, "frame-monitor-workarea");
2394#endif
2395
2364#if defined (USE_GTK) || defined (USE_X_TOOLKIT) 2396#if defined (USE_GTK) || defined (USE_X_TOOLKIT)
2365 defsubr (&Sx_menu_bar_open_internal); 2397 defsubr (&Sx_menu_bar_open_internal);
2366 Ffset (intern_c_string ("accelerate-menu"), 2398 Ffset (intern_c_string ("accelerate-menu"),