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)
This commit is contained in:
parent
187a71df59
commit
bdf41152af
2 changed files with 108 additions and 7 deletions
|
@ -1498,6 +1498,75 @@ keys and their meanings."
|
|||
for frames = (cdr (assq 'frames attributes))
|
||||
if (memq frame frames) return attributes))
|
||||
|
||||
(defun frame-monitor-attribute (attribute &optional frame x y)
|
||||
"Return the value of ATTRIBUTE on FRAME's monitor.
|
||||
If FRAME is omitted or nil, use currently selected frame.
|
||||
|
||||
By default, the current monitor is the physical monitor
|
||||
dominating the selected frame. A frame is dominated by a
|
||||
physical monitor when either the largest area of the frame
|
||||
resides in the monitor, or the monitor is the closest to the
|
||||
frame if the frame does not intersect any physical monitors.
|
||||
|
||||
If X and Y are both numbers, then ignore the value of FRAME; the
|
||||
monitor is determined to be the physical monitor that contains
|
||||
the pixel coordinate (X, Y).
|
||||
|
||||
See `display-monitor-attributes-list' for the list of attribute
|
||||
keys and their meanings."
|
||||
(if (and (numberp x)
|
||||
(numberp y))
|
||||
(cl-loop for monitor in (display-monitor-attributes-list)
|
||||
for geometry = (alist-get 'geometry monitor)
|
||||
for min-x = (pop geometry)
|
||||
for min-y = (pop geometry)
|
||||
for max-x = (+ min-x (pop geometry))
|
||||
for max-y = (+ min-y (car geometry))
|
||||
when (and (<= min-x x)
|
||||
(< x max-x)
|
||||
(<= min-y y)
|
||||
(< y max-y))
|
||||
return (alist-get attribute monitor))
|
||||
(alist-get attribute (frame-monitor-attributes frame))))
|
||||
|
||||
(defun frame-monitor-geometry (&optional frame x y)
|
||||
"Return the geometry of FRAME's monitor.
|
||||
FRAME can be a frame name, a terminal name, or a frame.
|
||||
If FRAME is omitted or nil, use the currently selected frame.
|
||||
|
||||
By default, the current monitor is said to be the physical
|
||||
monitor dominating teh selected frame. A frame is dominated by
|
||||
a physical monitor when either the largest area of the frame resides
|
||||
in the monitor, or the monitor is the closest to the frame if the
|
||||
frame does not intersect any physical monitors.
|
||||
|
||||
If X and Y are both numbers, then ignore the value of FRAME; the
|
||||
monitor is determined to be the physical monitor that contains
|
||||
the pixel coordinate (X, Y).
|
||||
|
||||
See `display-monitor-attributes-list' for information on the
|
||||
geometry attribute."
|
||||
(frame-monitor-attribute 'geometry frame x y))
|
||||
|
||||
(defun frame-monitor-workarea (&optional frame x y)
|
||||
"Return the workarea of FRAME's monitor.
|
||||
FRAME can be a frame name, a terminal name, or a frame.
|
||||
If FRAME is omitted or nil, use currently selected frame.
|
||||
|
||||
By default, the current monitor is said to be the physical
|
||||
monitor dominating the selected frame. A frame is dominated by
|
||||
a physical monitor when either the largest area of the frame resides
|
||||
in the monitor, or the monitor is the closest to the frame if the
|
||||
frame does not intersect any physical monitors.
|
||||
|
||||
If X and Y are both numbers, then ignore the value of FRAME; the
|
||||
monitor is determined to be the physical monitor that contains
|
||||
the pixel coordinate (X, Y).
|
||||
|
||||
See `display-monitor-attributes-list' for information on the
|
||||
workarea attribute."
|
||||
(frame-monitor-attribute 'workarea frame x y))
|
||||
|
||||
(declare-function x-frame-list-z-order "xfns.c" (&optional display))
|
||||
(declare-function w32-frame-list-z-order "w32fns.c" (&optional display))
|
||||
(declare-function ns-frame-list-z-order "nsfns.m" (&optional display))
|
||||
|
|
46
src/xmenu.c
46
src/xmenu.c
|
@ -1160,9 +1160,37 @@ 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 max_x = -1;
|
||||
int max_y = -1;
|
||||
|
||||
Lisp_Object frame, workarea;
|
||||
|
||||
XSETFRAME (frame, data->f);
|
||||
|
||||
/* TODO: Get the monitor workarea directly without calculating other
|
||||
items in x-display-monitor-attributes-list. */
|
||||
workarea = call3 (Qframe_monitor_workarea,
|
||||
Qnil,
|
||||
make_number (data->x),
|
||||
make_number (data->y));
|
||||
|
||||
if (CONSP (workarea))
|
||||
{
|
||||
int min_x, min_y;
|
||||
|
||||
min_x = XINT (XCAR (workarea));
|
||||
min_y = XINT (Fnth (make_number (1), workarea));
|
||||
max_x = min_x + XINT (Fnth (make_number (2), workarea));
|
||||
max_y = min_y + XINT (Fnth (make_number (3), workarea));
|
||||
}
|
||||
|
||||
if (max_x < 0 || max_y < 0)
|
||||
{
|
||||
struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (data->f);
|
||||
|
||||
max_x = x_display_pixel_width (dpyinfo);
|
||||
max_y = x_display_pixel_height (dpyinfo);
|
||||
}
|
||||
|
||||
*x = data->x;
|
||||
*y = data->y;
|
||||
|
@ -1170,10 +1198,10 @@ menu_position_func (GtkMenu *menu, gint *x, gint *y, gboolean *push_in, gpointer
|
|||
/* Check if there is room for the menu. If not, adjust x/y so that
|
||||
the menu is fully visible. */
|
||||
gtk_widget_get_preferred_size (GTK_WIDGET (menu), NULL, &req);
|
||||
if (data->x + req.width > disp_width)
|
||||
*x -= data->x + req.width - disp_width;
|
||||
if (data->y + req.height > disp_height)
|
||||
*y -= data->y + req.height - disp_height;
|
||||
if (data->x + req.width > max_x)
|
||||
*x -= data->x + req.width - max_x;
|
||||
if (data->y + req.height > max_y)
|
||||
*y -= data->y + req.height - max_y;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -2361,6 +2389,10 @@ syms_of_xmenu (void)
|
|||
DEFSYM (Qdebug_on_next_call, "debug-on-next-call");
|
||||
defsubr (&Smenu_or_popup_active_p);
|
||||
|
||||
#ifdef USE_GTK
|
||||
DEFSYM (Qframe_monitor_workarea, "frame-monitor-workarea");
|
||||
#endif
|
||||
|
||||
#if defined (USE_GTK) || defined (USE_X_TOOLKIT)
|
||||
defsubr (&Sx_menu_bar_open_internal);
|
||||
Ffset (intern_c_string ("accelerate-menu"),
|
||||
|
|
Loading…
Add table
Reference in a new issue