21.5 APPROVED
Sometimes I'm fine with the usual geometry of frames, sometimes I want
them vertically maximized (which the quartzwm doesn't provide an easy
way to do), so I have a Lisp function to do it. That function was
unreliable because #'device-system-metric was. This patch fixes it.
History and analysis:
Several months ago I got an external monitor, which when plugged in to
my notebook automatically changes the dimensions of the X screen from
1280x800 to something like 2560x1420. #'device-system-metric doesn't
recognize those changes. I believe that's because Xlib caches screen
metrics in the screen struct, and doesn't catch the change on the fly.
The information on the root window, which of course fills the screen,
*is* updated (I assume this costs a protocol request, but this
function is not used often -- not at all in core Lisp as far as I
could tell). The patch changes x_device_system_metrics to get the
geometry of the root window rather than using the ScreenWidth and
ScreenHeight macros. It does the trick in light testing.
It also changes x_set_frame_position and balloon_help_create to use
Fdevice_system_metric for the same reason (specifically, if the screen
shrinks and a small window is positioned against the right or bottom
edges, it could easily end up off-screen!)
I considered selecting ConfigureNotify and caching in XEmacs, but
decided against it. The rationale is in the source (see attached patch).
diff -r 2d6c322fbf80 src/ChangeLog
--- a/src/ChangeLog Thu Mar 28 19:10:32 2019 +0000
+++ b/src/ChangeLog Fri Apr 05 19:02:12 2019 +0900
@@ -1,3 +1,16 @@
+2019-04-02 Stephen J. Turnbull <turnbull(a)sk.tsukuba.ac.jp>
+
+ * device-x.c (x_device_system_metrics):
+ Use geometry of root window to get pixel size of display, not the
+ Display* macros. The Xlib macros (and functions!) seem to cache
+ old values, which gives wrong results on displays that can change
+ size on the fly.
+
+ * frame-x.c (x_set_frame_position):
+ * balloon_help.c (balloon_help_create):
+ Use Fdevice_system_metric for width and height in case screen size
+ has changed. Change "frame_[wh]" to "screen_[wh]".
+
2019-03-23 Jerry James <james(a)xemacs.org>
* array.h (XD_DYNARR_DESC,XD_LISP_DYNARR_DESC): fix segfaults when
diff -r 2d6c322fbf80 src/balloon_help.c
--- a/src/balloon_help.c Thu Mar 28 19:10:32 2019 +0000
+++ b/src/balloon_help.c Fri Apr 05 19:02:12 2019 +0900
@@ -507,6 +507,8 @@
Pixel fg, Pixel bg, Pixel shine, Pixel shadow,
XFontStruct* font)
{
+ Lisp_Object root_size;
+
if (b_dpy) balloon_help_destroy ();
b_dpy = dpy;
@@ -526,8 +528,11 @@
b_timer = None;
b_delay = 500;
- b_screenWidth = DisplayWidth (b_dpy, DefaultScreen(b_dpy));
- b_screenHeight = DisplayHeight (b_dpy, DefaultScreen(b_dpy));
+ root_size = Fdevice_system_metric (get_device_from_display (dpy),
+ Qsize_device,
+ Qnil);
+ b_screenWidth = XFIXNUM (XCAR (root_size));
+ b_screenHeight = XFIXNUM (XCDR (root_size));
b_lastShape = SHAPE_CONE_FREE;
}
diff -r 2d6c322fbf80 src/device-x.c
--- a/src/device-x.c Thu Mar 28 19:10:32 2019 +0000
+++ b/src/device-x.c Fri Apr 05 19:02:12 2019 +0900
@@ -1755,12 +1755,29 @@
switch (m)
{
+ /* In Xlib, both macros and functions checking configuration
+ seem to cache the results from the first call. So we check on
+ the root window instead. I considered selecting ConfigureNotify
+ on the root window, checking the size on that event, and caching
+ the result in struct x_device. However, ConfigureNotify doesn't
+ seem to be used that way for any other device metrics, so
+ responding to the event immediately doesn't seem necessary, and
+ it would involve complexity I don't understand. I guess this is
+ because Xlib does so much caching itself, so that using Xlib
+ calls is not very expensive for rarely changing metrics. */
case DM_size_device:
- return Fcons (make_fixnum (DisplayWidth (dpy, DefaultScreen (dpy))),
- make_fixnum (DisplayHeight (dpy, DefaultScreen (dpy))));
+ {
+ int x, y;
+ /* Nobody would be running X on a smaller screen, right? */
+ Dimension w = 1024, h = 768, b, d;
+ Window root = RootWindow(dpy, DefaultScreen(dpy));
+ /* If this fails, Xlib promises w and h are not updated. */
+ XGetGeometry(dpy, root, &root, &x, &y, &w, &h, &b, &d);
+ Fcons (make_fixnum (w), make_fixnum (h));
+ }
case DM_size_device_mm:
- return Fcons (make_fixnum (DisplayWidthMM (dpy, DefaultScreen (dpy))),
- make_fixnum (DisplayHeightMM (dpy, DefaultScreen (dpy))));
+ return Fcons (make_fixnum (XDisplayWidthMM (dpy, DefaultScreen (dpy))),
+ make_fixnum (XDisplayHeightMM (dpy, DefaultScreen (dpy))));
case DM_num_bit_planes:
return make_fixnum (DisplayPlanes (dpy, DefaultScreen (dpy)));
case DM_num_color_cells:
diff -r 2d6c322fbf80 src/frame-x.c
--- a/src/frame-x.c Thu Mar 28 19:10:32 2019 +0000
+++ b/src/frame-x.c Fri Apr 05 19:02:12 2019 +0900
@@ -2228,8 +2228,11 @@
{
Widget w = FRAME_X_SHELL_WIDGET (f);
Display *dpy = XtDisplay (w);
- Dimension frame_w = DisplayWidth (dpy, DefaultScreen (dpy));
- Dimension frame_h = DisplayHeight (dpy, DefaultScreen (dpy));
+ Lisp_Object root_size = Fdevice_system_metric (FRAME_DEVICE (f),
+ Qsize_device,
+ Qnil);
+ Dimension screen_w = XFIXNUM (XCAR (root_size));
+ Dimension screen_h = XFIXNUM (XCDR (root_size));
Dimension shell_w, shell_h, shell_bord;
int win_gravity;
Arg al[3];
@@ -2245,9 +2248,9 @@
yoff >= 0 ? NorthEastGravity :
SouthEastGravity;
if (xoff < 0)
- xoff += frame_w - shell_w - 2*shell_bord;
+ xoff += screen_w - shell_w - 2*shell_bord;
if (yoff < 0)
- yoff += frame_h - shell_h - 2*shell_bord;
+ yoff += screen_h - shell_h - 2*shell_bord;
/* Update the hints so that, if this window is currently iconified, it will
come back at the right place. We can't look at s->visible to determine