aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPo Lu2022-08-07 13:46:52 +0800
committerPo Lu2022-10-20 19:30:50 +0800
commit6f3ade1c08c6cbf56c0dc0d12e9508c261eb42bf (patch)
tree5eb2e8320ee3b8eb80acd209112908fb65f3db0e /src
parente0616f2d3cbc559560bf15346dd8a1824603bd80 (diff)
downloademacs-6f3ade1c08c6cbf56c0dc0d12e9508c261eb42bf.tar.gz
emacs-6f3ade1c08c6cbf56c0dc0d12e9508c261eb42bf.zip
Work around problems setting input focus when a frame is in the background
* src/xterm.c (server_timestamp_predicate, x_get_server_time): New functions. (x_ewmh_activate_frame, x_focus_frame, syms_of_xterm): Apply various workarounds for window manager "focus stealing prevention". (bug#57012)
Diffstat (limited to 'src')
-rw-r--r--src/xterm.c119
1 files changed, 119 insertions, 0 deletions
diff --git a/src/xterm.c b/src/xterm.c
index ade5600f4da..8b3d6f77a6c 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -27134,6 +27134,64 @@ xembed_request_focus (struct frame *f)
27134 XEMBED_REQUEST_FOCUS, 0, 0, 0); 27134 XEMBED_REQUEST_FOCUS, 0, 0, 0);
27135} 27135}
27136 27136
27137static Bool
27138server_timestamp_predicate (Display *display, XEvent *xevent,
27139 XPointer arg)
27140{
27141 XID *args = (XID *) arg;
27142
27143 if (xevent->type == PropertyNotify
27144 && xevent->xproperty.window == args[0]
27145 && xevent->xproperty.atom == args[1])
27146 return True;
27147
27148 return False;
27149}
27150
27151/* Get the server time. The X server is guaranteed to deliver the
27152 PropertyNotify event, so there is no reason to use x_if_event. */
27153
27154static Time
27155x_get_server_time (struct frame *f)
27156{
27157 Atom property_atom;
27158 XEvent property_dummy;
27159 struct x_display_info *dpyinfo;
27160 XID client_data[2];
27161#if defined HAVE_XSYNC && !defined USE_GTK && defined HAVE_CLOCK_GETTIME
27162 uint_fast64_t current_monotonic_time;
27163#endif
27164
27165 /* If the server time is the same as the monotonic time, avoid a
27166 roundtrip by using that instead. */
27167
27168#if defined HAVE_XSYNC && !defined USE_GTK && defined HAVE_CLOCK_GETTIME
27169 if (FRAME_DISPLAY_INFO (f)->server_time_monotonic_p)
27170 {
27171 current_monotonic_time = x_sync_current_monotonic_time ();
27172
27173 if (current_monotonic_time)
27174 /* Truncate the time to CARD32. */
27175 return (current_monotonic_time / 1000) & X_ULONG_MAX;
27176 }
27177#endif
27178
27179 dpyinfo = FRAME_DISPLAY_INFO (f);
27180 property_atom = dpyinfo->Xatom_EMACS_SERVER_TIME_PROP;
27181 client_data[0] = FRAME_OUTER_WINDOW (f);
27182 client_data[1] = property_atom;
27183
27184 XChangeProperty (dpyinfo->display, FRAME_OUTER_WINDOW (f),
27185 property_atom, XA_ATOM, 32,
27186 PropModeReplace,
27187 (unsigned char *) &property_atom, 1);
27188
27189 XIfEvent (dpyinfo->display, &property_dummy,
27190 server_timestamp_predicate, (XPointer) client_data);
27191
27192 return property_dummy.xproperty.time;
27193}
27194
27137/* Activate frame with Extended Window Manager Hints */ 27195/* Activate frame with Extended Window Manager Hints */
27138 27196
27139static void 27197static void
@@ -27141,6 +27199,7 @@ x_ewmh_activate_frame (struct frame *f)
27141{ 27199{
27142 XEvent msg; 27200 XEvent msg;
27143 struct x_display_info *dpyinfo; 27201 struct x_display_info *dpyinfo;
27202 Time time;
27144 27203
27145 dpyinfo = FRAME_DISPLAY_INFO (f); 27204 dpyinfo = FRAME_DISPLAY_INFO (f);
27146 27205
@@ -27161,6 +27220,43 @@ x_ewmh_activate_frame (struct frame *f)
27161 msg.xclient.data.l[3] = 0; 27220 msg.xclient.data.l[3] = 0;
27162 msg.xclient.data.l[4] = 0; 27221 msg.xclient.data.l[4] = 0;
27163 27222
27223 /* No frame is currently focused on that display, so apply any
27224 bypass for focus stealing prevention that the user has
27225 specified. */
27226 if (!dpyinfo->x_focus_frame)
27227 {
27228 if (EQ (Vx_allow_focus_stealing, Qimitate_pager))
27229 msg.xclient.data.l[0] = 2;
27230 else if (EQ (Vx_allow_focus_stealing, Qnewer_time))
27231 {
27232 block_input ();
27233 time = x_get_server_time (f);
27234#ifdef USE_GTK
27235 x_set_gtk_user_time (f, time);
27236#endif
27237 /* Temporarily override dpyinfo->x_focus_frame so the
27238 user time property is set on the right window. */
27239 dpyinfo->x_focus_frame = f;
27240 x_display_set_last_user_time (dpyinfo, time, true, true);
27241 dpyinfo->x_focus_frame = NULL;
27242 unblock_input ();
27243
27244 msg.xclient.data.l[1] = time;
27245 }
27246 else if (EQ (Vx_allow_focus_stealing, Qraise_and_focus))
27247 {
27248 time = x_get_server_time (f);
27249
27250 x_ignore_errors_for_next_request (dpyinfo);
27251 XSetInputFocus (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
27252 RevertToParent, time);
27253 XRaiseWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f));
27254 x_stop_ignoring_errors (dpyinfo);
27255
27256 return;
27257 }
27258 }
27259
27164 XSendEvent (dpyinfo->display, dpyinfo->root_window, 27260 XSendEvent (dpyinfo->display, dpyinfo->root_window,
27165 False, (SubstructureRedirectMask 27261 False, (SubstructureRedirectMask
27166 | SubstructureNotifyMask), &msg); 27262 | SubstructureNotifyMask), &msg);
@@ -30649,6 +30745,9 @@ With MS Windows, Haiku windowing or Nextstep, the value is t. */);
30649 Fput (Qsuper, Qmodifier_value, make_fixnum (super_modifier)); 30745 Fput (Qsuper, Qmodifier_value, make_fixnum (super_modifier));
30650 DEFSYM (QXdndSelection, "XdndSelection"); 30746 DEFSYM (QXdndSelection, "XdndSelection");
30651 DEFSYM (Qx_selection_alias_alist, "x-selection-alias-alist"); 30747 DEFSYM (Qx_selection_alias_alist, "x-selection-alias-alist");
30748 DEFSYM (Qimitate_pager, "imitate-pager");
30749 DEFSYM (Qnewer_time, "newer-time");
30750 DEFSYM (Qraise_and_focus, "raise-and-focus");
30652 30751
30653 DEFVAR_LISP ("x-ctrl-keysym", Vx_ctrl_keysym, 30752 DEFVAR_LISP ("x-ctrl-keysym", Vx_ctrl_keysym,
30654 doc: /* Which keys Emacs uses for the ctrl modifier. 30753 doc: /* Which keys Emacs uses for the ctrl modifier.
@@ -30902,4 +31001,24 @@ connection setup. */);
30902 /* The default value of this variable is chosen so that updating the 31001 /* The default value of this variable is chosen so that updating the
30903 tool bar does not require a call to _XReply. */ 31002 tool bar does not require a call to _XReply. */
30904 Vx_fast_selection_list = list1 (QCLIPBOARD); 31003 Vx_fast_selection_list = list1 (QCLIPBOARD);
31004
31005 DEFVAR_LISP ("x-allow-focus-stealing", Vx_allow_focus_stealing,
31006 doc: /* How to bypass window manager focus stealing prevention.
31007
31008Some window managers prevent `x-focus-frame' from activating the given
31009frame when Emacs is in the background, which is especially prone to
31010cause problems when the Emacs server wants to activate itself. This
31011variable specifies the strategy used to activate frames when that is
31012the case, and has several valid values (any other value means to not
31013bypass window manager focus stealing prevention):
31014
31015 - The symbol `imitate-pager', which means to pretend that Emacs is a
31016 pager.
31017
31018 - The symbol `newer-time', which means to fetch the current time
31019 from the X server and use it to activate the frame.
31020
31021 - The symbol `raise-and-focus', which means to raise the window and
31022 focus it manually. */);
31023 Vx_allow_focus_stealing = Qnewer_time;
30905} 31024}