diff options
| author | Alexander Gramiak | 2017-06-10 12:28:03 +0300 |
|---|---|---|
| committer | Eli Zaretskii | 2017-06-10 12:28:03 +0300 |
| commit | bdf41152af3434307218ac2863b737c4486f740e (patch) | |
| tree | d8c2275a5814aa0c3be2761c1282b30007551bc1 | |
| parent | 187a71df596a331a23bf86ee314c12035f42aff2 (diff) | |
| download | emacs-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.el | 69 | ||||
| -rw-r--r-- | src/xmenu.c | 46 |
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. | ||
| 1503 | If FRAME is omitted or nil, use currently selected frame. | ||
| 1504 | |||
| 1505 | By default, the current monitor is the physical monitor | ||
| 1506 | dominating the selected frame. A frame is dominated by a | ||
| 1507 | physical monitor when either the largest area of the frame | ||
| 1508 | resides in the monitor, or the monitor is the closest to the | ||
| 1509 | frame if the frame does not intersect any physical monitors. | ||
| 1510 | |||
| 1511 | If X and Y are both numbers, then ignore the value of FRAME; the | ||
| 1512 | monitor is determined to be the physical monitor that contains | ||
| 1513 | the pixel coordinate (X, Y). | ||
| 1514 | |||
| 1515 | See `display-monitor-attributes-list' for the list of attribute | ||
| 1516 | keys 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. | ||
| 1534 | FRAME can be a frame name, a terminal name, or a frame. | ||
| 1535 | If FRAME is omitted or nil, use the currently selected frame. | ||
| 1536 | |||
| 1537 | By default, the current monitor is said to be the physical | ||
| 1538 | monitor dominating teh selected frame. A frame is dominated by | ||
| 1539 | a physical monitor when either the largest area of the frame resides | ||
| 1540 | in the monitor, or the monitor is the closest to the frame if the | ||
| 1541 | frame does not intersect any physical monitors. | ||
| 1542 | |||
| 1543 | If X and Y are both numbers, then ignore the value of FRAME; the | ||
| 1544 | monitor is determined to be the physical monitor that contains | ||
| 1545 | the pixel coordinate (X, Y). | ||
| 1546 | |||
| 1547 | See `display-monitor-attributes-list' for information on the | ||
| 1548 | geometry 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. | ||
| 1553 | FRAME can be a frame name, a terminal name, or a frame. | ||
| 1554 | If FRAME is omitted or nil, use currently selected frame. | ||
| 1555 | |||
| 1556 | By default, the current monitor is said to be the physical | ||
| 1557 | monitor dominating the selected frame. A frame is dominated by | ||
| 1558 | a physical monitor when either the largest area of the frame resides | ||
| 1559 | in the monitor, or the monitor is the closest to the frame if the | ||
| 1560 | frame does not intersect any physical monitors. | ||
| 1561 | |||
| 1562 | If X and Y are both numbers, then ignore the value of FRAME; the | ||
| 1563 | monitor is determined to be the physical monitor that contains | ||
| 1564 | the pixel coordinate (X, Y). | ||
| 1565 | |||
| 1566 | See `display-monitor-attributes-list' for information on the | ||
| 1567 | workarea 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 | ||
| 1179 | static void | 1207 | static 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"), |