Add a hook run upon monitor configuration changes

* 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.
This commit is contained in:
Po Lu 2022-05-21 11:17:34 +08:00
parent 1cbabe973b
commit edf9700c3c
6 changed files with 98 additions and 6 deletions

View 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

View file

@ -1850,6 +1850,11 @@ functions.
* 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.

View 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);
}

View 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. */

View 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

View 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