]> git.eshelyaron.com Git - emacs.git/commitdiff
Add a hook run upon monitor configuration changes
authorPo Lu <luangruo@yahoo.com>
Sat, 21 May 2022 03:17:34 +0000 (11:17 +0800)
committerPo Lu <luangruo@yahoo.com>
Sat, 21 May 2022 03:17:34 +0000 (11:17 +0800)
* doc/lispref/frames.texi (Multiple Terminals): Document new
hook `display-monitors-changed-functions'.
* etc/NEWS: Announce new abnormal hook.

* src/keyboard.c (kbd_buffer_get_event): Handle
MONITORS_CHANGED_EVENT.
(syms_of_keyboard): New hook and defsyms.
* src/termhooks.h (enum event_kind): Add new event
`MONITORS_CHANGED_EVENT'.

* src/xterm.c (handle_one_xevent): Handle RRNotify and
RRScreenChangeNotify events.
(x_term_init): Select for RRScreenChange, RRCrtcChange and
RROutputChange.
* src/xterm.h (struct x_display_info): Improve RandR version
detection.

doc/lispref/frames.texi
etc/NEWS
src/keyboard.c
src/termhooks.h
src/xterm.c
src/xterm.h

index 5ea060871f4173e690d9f9367847c70ee67041c5..7d600b5a0c53c82622d8326f174ca4c98cb4a1c1 100644 (file)
@@ -458,6 +458,16 @@ monitor, the same string as returned by the function
 @var{display} should be the name of an X display (a string).
 @end deffn
 
+@cindex monitor change functions
+@defvar display-monitors-changed-functions
+This variable is an abnormal hook run when the monitor configuration
+changes, which can happen if a monitor is rotated, moved, added or
+removed from a multiple-monitor setup, if the primary monitor changes,
+or if the resolution of a monitor changes.  It is called with a single
+argument consisting of the terminal on which the monitor configuration
+changed.
+@end defvar
+
 @node Frame Geometry
 @section Frame Geometry
 @cindex frame geometry
index 70f2c0e6daf6511b2db9a33ba0d7ea0bb37158a3..5eab8e23bb24567bdbe3b1ea796313c3092a1de9 100644 (file)
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -1850,6 +1850,11 @@ functions.
 \f
 * Lisp Changes in Emacs 29.1
 
++++
+** New hook 'display-monitors-changed-functions'.
+It is called whenever the configuration of different monitors on a
+display changes.
+
 +++
 ** 'prin1' and 'prin1-to-string' now take an optional OVERRIDES parameter.
 This parameter can be used to override values of print-related settings.
index 481633f92feea67b888281008c912a8e102783d2..a2322f1b49d21769b13e91dea38b5986413c63dc 100644 (file)
@@ -4058,6 +4058,18 @@ kbd_buffer_get_event (KBOARD **kbp,
        }
 #endif
 
+      case MONITORS_CHANGED_EVENT:
+       {
+         kbd_fetch_ptr = next_kbd_event (event);
+         input_pending = readable_events (0);
+
+         CALLN (Frun_hook_with_args,
+                Qdisplay_monitors_changed_functions,
+                event->ie.arg);
+
+         break;
+       }
+
 #ifdef HAVE_EXT_MENU_BAR
       case MENU_BAR_ACTIVATE_EVENT:
        {
@@ -12609,6 +12621,8 @@ See also `pre-command-hook'.  */);
   DEFSYM (Qtouchscreen_end, "touchscreen-end");
   DEFSYM (Qtouchscreen_update, "touchscreen-update");
   DEFSYM (Qpinch, "pinch");
+  DEFSYM (Qdisplay_monitors_changed_functions,
+         "display-monitors-changed-functions");
 
   DEFSYM (Qcoding, "coding");
 
@@ -12953,6 +12967,15 @@ Otherwise, a wheel event will be sent every time the mouse wheel is
 moved.  */);
   mwheel_coalesce_scroll_events = true;
 
+  DEFVAR_LISP ("display-monitors-changed-functions", Vdisplay_monitors_changed_functions,
+    doc: /* Abnormal hook run when the monitor configuration changes.
+This can happen if a monitor is rotated, moved, plugged in or removed
+from a multi-monitor setup, if the primary monitor changes, or if the
+resolution of a monitor changes.  The hook should accept a single
+argument, which is the terminal on which the monitor configuration
+changed.  */);
+  Vdisplay_monitors_changed_functions = Qnil;
+
   pdumper_do_now_and_after_load (syms_of_keyboard_for_pdumper);
 }
 
index 08bde0aec0d2c374c5360f79e95d888d7da2de8d..d7190e77362a26d5563207ccc6a4eee8a55936ed 100644 (file)
@@ -31,7 +31,8 @@ struct glyph;
 
 INLINE_HEADER_BEGIN
 
-enum scroll_bar_part {
+enum scroll_bar_part
+{
   scroll_bar_nowhere,
   scroll_bar_above_handle,
   scroll_bar_handle,
@@ -301,8 +302,9 @@ enum event_kind
 #endif
 
 #ifdef HAVE_XWIDGETS
-  /* events generated by xwidgets*/
+  /* An event generated by an xwidget to tell us something.  */
    , XWIDGET_EVENT
+
    /* Event generated when WebKit asks us to display another widget.  */
    , XWIDGET_DISPLAY_EVENT
 #endif
@@ -349,6 +351,11 @@ enum event_kind
          positive delta represents a change clockwise, and a negative
          delta represents a change counter-clockwise.  */
   , PINCH_EVENT
+
+  /* In a MONITORS_CHANGED_EVENT, .arg gives the terminal on which the
+     monitor configuration changed.  .timestamp gives the time on
+     which the monitors changed.  */
+  , MONITORS_CHANGED_EVENT
 };
 
 /* Bit width of an enum event_kind tag at the start of structs and unions.  */
index cbe6426447eba40f33ba461ade45a3534a48d6b5..b321f43da16a396befd5a3b44c3ec9279a87166b 100644 (file)
@@ -20103,6 +20103,38 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                }
            }
        }
+#endif
+#ifdef HAVE_XRANDR
+      if (dpyinfo->xrandr_supported_p
+         && (event->type == (dpyinfo->xrandr_event_base
+                             + RRScreenChangeNotify)
+             || event->type == (dpyinfo->xrandr_event_base
+                                + RRNotify)))
+       {
+         union buffered_input_event *ev;
+         Time timestamp;
+
+         if (event->type == (dpyinfo->xrandr_event_base
+                             + RRScreenChangeNotify))
+           timestamp = ((XRRScreenChangeNotifyEvent *) event)->timestamp;
+         else
+           timestamp = 0;
+
+         ev = (kbd_store_ptr == kbd_buffer
+               ? kbd_buffer + KBD_BUFFER_SIZE - 1
+               : kbd_store_ptr - 1);
+
+         if (kbd_store_ptr != kbd_fetch_ptr
+             && ev->ie.kind == MONITORS_CHANGED_EVENT
+             && XTERMINAL (ev->ie.arg) == dpyinfo->terminal)
+           /* Don't store a MONITORS_CHANGED_EVENT if there is
+              already an undelivered event on the queue.  */
+           goto OTHER;
+
+         inev.ie.kind = MONITORS_CHANGED_EVENT;
+         inev.ie.timestamp = timestamp;
+         XSETTERMINAL (inev.ie.arg, dpyinfo->terminal);
+       }
 #endif
     OTHER:
 #ifdef USE_X_TOOLKIT
@@ -24405,13 +24437,25 @@ x_term_init (Lisp_Object display_name, char *xrm_option, char *resource_name)
 #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)
+  dpyinfo->xrandr_supported_p
+    = XRRQueryExtension (dpy, &dpyinfo->xrandr_event_base,
+                        &dpyinfo->xrandr_error_base);
+  if (dpyinfo->xrandr_supported_p)
     {
       XRRQueryVersion (dpy, &dpyinfo->xrandr_major_version,
                       &dpyinfo->xrandr_minor_version);
+
+      if (dpyinfo->xrandr_major_version == 1
+         && dpyinfo->xrandr_minor_version >= 2)
+       XRRSelectInput (dpyinfo->display,
+                       dpyinfo->root_window,
+                       (RRScreenChangeNotifyMask
+                        | RRCrtcChangeNotifyMask
+                        | RROutputChangeNotifyMask
+                        /* Emacs doesn't actually need this, but GTK
+                           selects for it when the display is
+                           initialized.  */
+                        | RROutputPropertyNotifyMask));
     }
 #endif
 
index a05bc404f6935ab0d0bcd06571704ec50d1eb1b0..8571bd9d39c7a64e5c3a93291e45cb61bddb1a23 100644 (file)
@@ -602,6 +602,9 @@ struct x_display_info
   XModifierKeymap *modmap;
 
 #ifdef HAVE_XRANDR
+  bool xrandr_supported_p;
+  int xrandr_event_base;
+  int xrandr_error_base;
   int xrandr_major_version;
   int xrandr_minor_version;
 #endif