mirror of
https://git.savannah.gnu.org/git/emacs.git
synced 2025-01-19 18:13:55 +00:00
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.
This commit is contained in:
parent
1a724cc2d2
commit
b6b2f797d9
@ -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)))
|
||||
|
137
src/xfns.c
137
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,
|
||||
|
15
src/xterm.c
15
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,
|
||||
|
@ -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. */
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user