commit e2d96ffa6a920684e67f013b5e5eae8c2379bc84 (HEAD, refs/remotes/origin/master) Author: Po Lu Date: Sun Feb 27 14:56:34 2022 +0800 * src/xterm.c (handle_one_xevent): Translate motion events on Motif. diff --git a/src/xterm.c b/src/xterm.c index 37d193cc92..2656b30472 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -11614,6 +11614,26 @@ handle_one_xevent (struct x_display_info *dpyinfo, ev.window = xev->event; ev.time = xev->time; +#ifdef USE_MOTIF + use_copy = true; + + copy.xmotion.type = MotionNotify; + copy.xmotion.serial = xev->serial; + copy.xmotion.send_event = xev->send_event; + copy.xmotion.display = dpyinfo->display; + copy.xmotion.window = xev->event; + copy.xmotion.root = xev->root; + copy.xmotion.subwindow = xev->child; + copy.xmotion.time = xev->time; + copy.xmotion.x = lrint (xev->event_x); + copy.xmotion.y = lrint (xev->event_y); + copy.xmotion.x_root = lrint (xev->root_x); + copy.xmotion.y_root = lrint (xev->root_y); + copy.xmotion.state = 0; + copy.xmotion.is_hint = False; + copy.xmotion.same_screen = True; +#endif + previous_help_echo_string = help_echo_string; help_echo_string = Qnil; commit 14c80c9db8dd4abf547bfe3e15020fc977e4bdba Author: Po Lu Date: Sun Feb 27 14:40:26 2022 +0800 Work around some problems with Motif and the input extension * src/xmenu.c (create_and_show_popup_menu): Restore input focus to the frame's outer window if there was an input extension grab. diff --git a/src/xmenu.c b/src/xmenu.c index 2bc9f5a93a..93bc90514c 100644 --- a/src/xmenu.c +++ b/src/xmenu.c @@ -1687,6 +1687,14 @@ create_and_show_popup_menu (struct frame *f, widget_value *first_wv, unbind_to (specpdl_count, Qnil); } + +#if defined HAVE_XINPUT2 && defined USE_MOTIF + /* For some reason input focus isn't always restored to the outer + window after the menu pops down. */ + if (any_xi_grab_p) + XSetInputFocus (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f), + RevertToParent, CurrentTime); +#endif } #endif /* not USE_GTK */ commit 4c12a16aa7593a3d11025bdf851a98a94c167df5 Author: Po Lu Date: Sun Feb 27 14:30:58 2022 +0800 Translate some more input extension events needed by Motif * src/xterm.c (handle_one_xevent): Translate XI_Enter and XI_Leave events when built with Motif. diff --git a/src/xterm.c b/src/xterm.c index 03bfbabf31..37d193cc92 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -9513,7 +9513,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, XEvent configureEvent; XEvent next_event; Lisp_Object coding; -#ifdef USE_MOTIF +#if defined USE_MOTIF && defined HAVE_XINPUT2 /* Some XInput 2 events are important for Motif menu bars to work correctly, so they must be translated into core events before being passed to XtDispatchEvent. */ @@ -11236,13 +11236,34 @@ handle_one_xevent (struct x_display_info *dpyinfo, goto XI_OTHER; case XI_Enter: - any = x_top_window_to_frame (dpyinfo, enter->event); ev.x = lrint (enter->event_x); ev.y = lrint (enter->event_y); ev.window = enter->event; x_display_set_last_user_time (dpyinfo, xi_event->time); +#ifdef USE_MOTIF + use_copy = true; + + copy.xcrossing.type = EnterNotify; + copy.xcrossing.serial = enter->serial; + copy.xcrossing.send_event = enter->send_event; + copy.xcrossing.display = dpyinfo->display; + copy.xcrossing.window = enter->event; + copy.xcrossing.root = enter->root; + copy.xcrossing.subwindow = enter->child; + copy.xcrossing.time = enter->time; + copy.xcrossing.x = lrint (enter->event_x); + copy.xcrossing.y = lrint (enter->event_y); + copy.xcrossing.x_root = lrint (enter->root_x); + copy.xcrossing.y_root = lrint (enter->root_y); + copy.xcrossing.mode = enter->mode; + copy.xcrossing.detail = enter->detail; + copy.xcrossing.focus = enter->focus; + copy.xcrossing.state = 0; + copy.xcrossing.same_screen = True; +#endif + /* There is no need to handle entry/exit events for passive focus from non-top windows at all, since they are an inferiors of the frame's top window, which will @@ -11307,6 +11328,28 @@ handle_one_xevent (struct x_display_info *dpyinfo, any = x_any_window_to_frame (dpyinfo, leave->event); #endif +#ifdef USE_MOTIF + use_copy = true; + + copy.xcrossing.type = LeaveNotify; + copy.xcrossing.serial = leave->serial; + copy.xcrossing.send_event = leave->send_event; + copy.xcrossing.display = dpyinfo->display; + copy.xcrossing.window = leave->event; + copy.xcrossing.root = leave->root; + copy.xcrossing.subwindow = leave->child; + copy.xcrossing.time = leave->time; + copy.xcrossing.x = lrint (leave->event_x); + copy.xcrossing.y = lrint (leave->event_y); + copy.xcrossing.x_root = lrint (leave->root_x); + copy.xcrossing.y_root = lrint (leave->root_y); + copy.xcrossing.mode = leave->mode; + copy.xcrossing.detail = leave->detail; + copy.xcrossing.focus = leave->focus; + copy.xcrossing.state = 0; + copy.xcrossing.same_screen = True; +#endif + /* One problem behind the design of XInput 2 scrolling is that valuators are not unique to each window, but only the window that has grabbed the valuator's device or @@ -11667,35 +11710,32 @@ handle_one_xevent (struct x_display_info *dpyinfo, #endif #ifdef USE_MOTIF - if (popup_activated ()) + use_copy = true; + copy.xbutton.type = (xev->evtype == XI_ButtonPress + ? ButtonPress : ButtonRelease); + copy.xbutton.serial = xev->serial; + copy.xbutton.send_event = xev->send_event; + copy.xbutton.display = dpyinfo->display; + copy.xbutton.window = xev->event; + copy.xbutton.root = xev->root; + copy.xbutton.subwindow = xev->child; + copy.xbutton.time = xev->time; + copy.xbutton.x = lrint (xev->event_x); + copy.xbutton.y = lrint (xev->event_y); + copy.xbutton.x_root = lrint (xev->root_x); + copy.xbutton.y_root = lrint (xev->root_y); + copy.xbutton.state = xev->mods.effective; + copy.xbutton.button = xev->detail; + copy.xbutton.same_screen = True; + + if (xev->buttons.mask_len) { - use_copy = true; - copy.xbutton.type = (xev->evtype == XI_ButtonPress - ? ButtonPress : ButtonRelease); - copy.xbutton.serial = xev->serial; - copy.xbutton.send_event = xev->send_event; - copy.xbutton.display = dpyinfo->display; - copy.xbutton.window = xev->event; - copy.xbutton.root = xev->root; - copy.xbutton.subwindow = xev->child; - copy.xbutton.time = xev->time; - copy.xbutton.x = lrint (xev->event_x); - copy.xbutton.y = lrint (xev->event_y); - copy.xbutton.x_root = lrint (xev->root_x); - copy.xbutton.y_root = lrint (xev->root_y); - copy.xbutton.state = xev->mods.effective; - copy.xbutton.button = xev->detail; - copy.xbutton.same_screen = True; - - if (xev->buttons.mask_len) - { - if (XIMaskIsSet (xev->buttons.mask, 1)) - copy.xbutton.state |= Button1Mask; - if (XIMaskIsSet (xev->buttons.mask, 2)) - copy.xbutton.state |= Button2Mask; - if (XIMaskIsSet (xev->buttons.mask, 3)) - copy.xbutton.state |= Button3Mask; - } + if (XIMaskIsSet (xev->buttons.mask, 1)) + copy.xbutton.state |= Button1Mask; + if (XIMaskIsSet (xev->buttons.mask, 2)) + copy.xbutton.state |= Button2Mask; + if (XIMaskIsSet (xev->buttons.mask, 3)) + copy.xbutton.state |= Button3Mask; } #endif @@ -12740,7 +12780,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, || (event->xconfigure.width != 0 && event->xconfigure.height != 0)) { -#ifdef USE_MOTIF +#if defined USE_MOTIF && defined HAVE_XINPUT2 XtDispatchEvent (use_copy ? © : (XEvent *) event); #else XtDispatchEvent ((XEvent *) event); commit 2fdc7d504477198334c7de75c46585d1bcf19c40 Merge: 796bb6f1e7 a50f8dec09 Author: Stefan Kangas Date: Sun Feb 27 06:31:54 2022 +0100 Merge from origin/emacs-28 a50f8dec09 Follow OpenSSH changes in Tramp e86eae21a9 Document better how to reset attributes of faces for new f... commit 796bb6f1e707cc5086ae9dbb6395f7a35554c63d Author: Po Lu Date: Sun Feb 27 11:44:06 2022 +0800 * commands.texi (Misc Events): Update description of wheel events. diff --git a/doc/lispref/commands.texi b/doc/lispref/commands.texi index a1628eabaa..a4ae68af5b 100644 --- a/doc/lispref/commands.texi +++ b/doc/lispref/commands.texi @@ -2091,11 +2091,13 @@ wheel. @vindex mouse-wheel-up-event @vindex mouse-wheel-down-event -This kind of event is generated only on some kinds of systems. On some -systems, @code{mouse-4} and @code{mouse-5} are used instead. For -portable code, use the variables @code{mouse-wheel-up-event} and -@code{mouse-wheel-down-event} defined in @file{mwheel.el} to determine -what event types to expect for the mouse wheel. +This kind of event is generated only on some kinds of systems. On +some systems, @code{mouse-4} and @code{mouse-5} are used instead. For +portable code, use the variables @code{mouse-wheel-up-event}, +@code{mouse-wheel-up-alternate-event}, @code{mouse-wheel-down-event} +and @code{mouse-wheel-down-alternate-event} defined in +@file{mwheel.el} to determine what event types to expect for the mouse +wheel. @cindex @code{pinch} event @item (pinch @var{position} @var{dx} @var{dy} @var{scale} @var{angle}) commit bc0d1f1c46553ea4ec721f2a758adbdbf4992833 Author: Manuel Uberti Date: Wed Feb 23 09:25:32 2022 +0100 Add project-ignore-buffer-conditions * lisp/progmodes/project.el (project-ignore-buffer-conditions): New defcustom. (project--read-project-buffer): Use it (bug#54100). diff --git a/lisp/progmodes/project.el b/lisp/progmodes/project.el index 880c5b5517..4d6b93ceb5 100644 --- a/lisp/progmodes/project.el +++ b/lisp/progmodes/project.el @@ -1112,6 +1112,29 @@ If non-nil, it overrides `compilation-buffer-name-function' for compilation-buffer-name-function))) (call-interactively #'compile))) +(defcustom project-ignore-buffer-conditions nil + "List of conditions to filter the buffers to be switched to. +If any of these conditions are satisfied for a buffer in the +current project, `project-switch-to-buffer', +`project-display-buffer' and `project-display-buffer-other-frame' +ignore it. +See the doc string of `project-kill-buffer-conditions' for the +general form of conditions." + :type '(repeat (choice regexp function symbol + (cons :tag "Major mode" + (const major-mode) symbol) + (cons :tag "Derived mode" + (const derived-mode) symbol) + (cons :tag "Negation" + (const not) sexp) + (cons :tag "Conjunction" + (const and) sexp) + (cons :tag "Disjunction" + (const or) sexp))) + :version "29.1" + :group 'project + :package-version '(project . "0.8.2")) + (defun project--read-project-buffer () (let* ((pr (project-current t)) (current-buffer (current-buffer)) @@ -1121,7 +1144,10 @@ If non-nil, it overrides `compilation-buffer-name-function' for (predicate (lambda (buffer) ;; BUFFER is an entry (BUF-NAME . BUF-OBJ) of Vbuffer_alist. - (memq (cdr buffer) buffers)))) + (and (memq (cdr buffer) buffers) + (not + (project--buffer-check + (cdr buffer) project-ignore-buffer-conditions)))))) (read-buffer "Switch to buffer: " (when (funcall predicate (cons other-name other-buffer)) @@ -1239,11 +1265,12 @@ Used by `project-kill-buffers'." (push buf bufs))) (nreverse bufs))) -(defun project--kill-buffer-check (buf conditions) +(defun project--buffer-check (buf conditions) "Check if buffer BUF matches any element of the list CONDITIONS. -See `project-kill-buffer-conditions' for more details on the form -of CONDITIONS." - (catch 'kill +See `project-kill-buffer-conditions' or +`project-ignore-buffer-conditions' for more details on the +form of CONDITIONS." + (catch 'match (dolist (c conditions) (when (cond ((stringp c) @@ -1258,15 +1285,15 @@ of CONDITIONS." (buffer-local-value 'major-mode buf) (cdr c))) ((eq (car-safe c) 'not) - (not (project--kill-buffer-check buf (cdr c)))) + (not (project--buffer-check buf (cdr c)))) ((eq (car-safe c) 'or) - (project--kill-buffer-check buf (cdr c))) + (project--buffer-check buf (cdr c))) ((eq (car-safe c) 'and) (seq-every-p - (apply-partially #'project--kill-buffer-check + (apply-partially #'project--buffer-check buf) (mapcar #'list (cdr c))))) - (throw 'kill t))))) + (throw 'match t))))) (defun project--buffers-to-kill (pr) "Return list of buffers in project PR to kill. @@ -1274,7 +1301,7 @@ What buffers should or should not be killed is described in `project-kill-buffer-conditions'." (let (bufs) (dolist (buf (project-buffers pr)) - (when (project--kill-buffer-check buf project-kill-buffer-conditions) + (when (project--buffer-check buf project-kill-buffer-conditions) (push buf bufs))) bufs)) commit 422ad3a01f482867572502d93961c0f0f3d530f1 Author: Po Lu Date: Sun Feb 27 10:49:19 2022 +0800 * src/xterm.c (handle_one_xevent): Fix translation of button events. diff --git a/src/xterm.c b/src/xterm.c index 33a6613e14..03bfbabf31 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -11670,7 +11670,8 @@ handle_one_xevent (struct x_display_info *dpyinfo, if (popup_activated ()) { use_copy = true; - copy.xbutton.type = ButtonRelease; + copy.xbutton.type = (xev->evtype == XI_ButtonPress + ? ButtonPress : ButtonRelease); copy.xbutton.serial = xev->serial; copy.xbutton.send_event = xev->send_event; copy.xbutton.display = dpyinfo->display; commit 16702f183f34cba880a04e08db9d6b644b38b424 Author: Po Lu Date: Sun Feb 27 10:37:17 2022 +0800 Fix Motif menu and menu bar dismissal on XI2 * src/xmenu.c (x_activate_menubar): Improve ungrabbing logic on XI2. (server_timestamp_predicate): New function. (create_and_show_popup_menu): If the display supports XI2, make sure the timestamps are correct by dispatching a PropertyNotify event to Xt. * src/xterm.c (handle_one_xevent): Translate XI_ButtonRelease events into core events before dispatching them to Xt. diff --git a/src/xmenu.c b/src/xmenu.c index 21e8f0f9ec..2bc9f5a93a 100644 --- a/src/xmenu.c +++ b/src/xmenu.c @@ -572,11 +572,11 @@ x_activate_menubar (struct frame *f) { for (int i = 0; i < dpyinfo->num_devices; ++i) { -#ifndef USE_MOTIF if (dpyinfo->devices[i].grab) -#endif - XIUngrabDevice (dpyinfo->display, dpyinfo->devices[i].device_id, - CurrentTime); + { + XIUngrabDevice (dpyinfo->display, dpyinfo->devices[i].device_id, + CurrentTime); + } } } #endif @@ -1514,6 +1514,23 @@ pop_down_menu (int id) popup_activated_flag = 0; } +#ifdef HAVE_XINPUT2 +static Bool +server_timestamp_predicate (Display *display, + XEvent *xevent, + XPointer arg) +{ + XID *args = (XID *) arg; + + if (xevent->type == PropertyNotify + && xevent->xproperty.window == args[0] + && xevent->xproperty.atom == args[1]) + return True; + + return False; +} +#endif + /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the menu pops down. menu_item_selection will be set to the selection. */ @@ -1529,6 +1546,10 @@ create_and_show_popup_menu (struct frame *f, widget_value *first_wv, LWLIB_ID menu_id; Widget menu; Window dummy_window; +#ifdef HAVE_XINPUT2 + XEvent property_dummy; + Atom property_atom; +#endif eassert (FRAME_X_P (f)); @@ -1609,14 +1630,37 @@ create_and_show_popup_menu (struct frame *f, widget_value *first_wv, } if (any_xi_grab_p) - XGrabPointer (dpyinfo->display, - FRAME_X_WINDOW (f), - False, (PointerMotionMask - | PointerMotionHintMask - | ButtonReleaseMask - | ButtonPressMask), - GrabModeSync, GrabModeAsync, - None, None, CurrentTime); + { +#ifndef USE_MOTIF + XGrabPointer (dpyinfo->display, + FRAME_X_WINDOW (f), + False, (PointerMotionMask + | PointerMotionHintMask + | ButtonReleaseMask + | ButtonPressMask), + GrabModeSync, GrabModeAsync, + None, None, CurrentTime); +#endif + } + + if (dpyinfo->supports_xi2) + { + /* Dispatch a PropertyNotify to Xt with the current server time. + Motif tries to set a grab with the timestamp of the last event + processed by Xt, but Xt doesn't consider GenericEvents, so the + timestamp is always less than the last grab time. */ + + property_atom = XInternAtom (dpyinfo->display, "EMACS_SERVER_TIME_PROP", False); + + XChangeProperty (dpyinfo->display, FRAME_OUTER_WINDOW (f), + property_atom, XA_ATOM, 32, + PropModeReplace, (unsigned char *) &property_atom, 1); + + XIfEvent (dpyinfo->display, &property_dummy, server_timestamp_predicate, + (XPointer) &(XID[]) {(XID) FRAME_OUTER_WINDOW (f), (XID) property_atom}); + + XtDispatchEvent (&property_dummy); + } if (dpyinfo->supports_xi2) XUngrabServer (dpyinfo->display); @@ -1626,7 +1670,7 @@ create_and_show_popup_menu (struct frame *f, widget_value *first_wv, lw_popup_menu (menu, &dummy); popup_activated_flag = 1; -#ifdef HAVE_XINPUT2 +#if defined HAVE_XINPUT2 && !defined USE_MOTIF if (any_xi_grab_p) XAllowEvents (dpyinfo->display, AsyncPointer, CurrentTime); #endif diff --git a/src/xterm.c b/src/xterm.c index 040397777b..33a6613e14 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -9513,6 +9513,13 @@ handle_one_xevent (struct x_display_info *dpyinfo, XEvent configureEvent; XEvent next_event; Lisp_Object coding; +#ifdef USE_MOTIF + /* Some XInput 2 events are important for Motif menu bars to work + correctly, so they must be translated into core events before + being passed to XtDispatchEvent. */ + bool use_copy = false; + XEvent copy; +#endif *finish = X_EVENT_NORMAL; @@ -10924,7 +10931,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, x_display_set_last_user_time (dpyinfo, event->xbutton.time); #ifdef HAVE_XWIDGETS - struct xwidget_view *xvw = xwidget_view_from_window (event->xmotion.window); + struct xwidget_view *xvw = xwidget_view_from_window (event->xbutton.window); if (xvw) { @@ -11659,6 +11666,38 @@ handle_one_xevent (struct x_display_info *dpyinfo, struct xwidget_view *xvw; #endif +#ifdef USE_MOTIF + if (popup_activated ()) + { + use_copy = true; + copy.xbutton.type = ButtonRelease; + copy.xbutton.serial = xev->serial; + copy.xbutton.send_event = xev->send_event; + copy.xbutton.display = dpyinfo->display; + copy.xbutton.window = xev->event; + copy.xbutton.root = xev->root; + copy.xbutton.subwindow = xev->child; + copy.xbutton.time = xev->time; + copy.xbutton.x = lrint (xev->event_x); + copy.xbutton.y = lrint (xev->event_y); + copy.xbutton.x_root = lrint (xev->root_x); + copy.xbutton.y_root = lrint (xev->root_y); + copy.xbutton.state = xev->mods.effective; + copy.xbutton.button = xev->detail; + copy.xbutton.same_screen = True; + + if (xev->buttons.mask_len) + { + if (XIMaskIsSet (xev->buttons.mask, 1)) + copy.xbutton.state |= Button1Mask; + if (XIMaskIsSet (xev->buttons.mask, 2)) + copy.xbutton.state |= Button2Mask; + if (XIMaskIsSet (xev->buttons.mask, 3)) + copy.xbutton.state |= Button3Mask; + } + } +#endif + #ifdef HAVE_XINPUT2_1 /* Ignore emulated scroll events when XI2 native scroll events are present. */ @@ -12699,7 +12738,13 @@ handle_one_xevent (struct x_display_info *dpyinfo, if (event->type != ConfigureNotify || (event->xconfigure.width != 0 && event->xconfigure.height != 0)) - XtDispatchEvent ((XEvent *) event); + { +#ifdef USE_MOTIF + XtDispatchEvent (use_copy ? © : (XEvent *) event); +#else + XtDispatchEvent ((XEvent *) event); +#endif + } } unblock_input (); #endif /* USE_X_TOOLKIT */ commit a2768c2f745eb4203a006ad86d6cccd160c7a3c8 Author: Po Lu Date: Sat Feb 26 12:25:51 2022 +0000 Ignore irrelevant button events on Haiku scroll bars * src/haiku_support.cc (MouseDown): Ignore if there are too many buttons pressed. diff --git a/src/haiku_support.cc b/src/haiku_support.cc index fe91986e8c..12990b3378 100644 --- a/src/haiku_support.cc +++ b/src/haiku_support.cc @@ -1684,33 +1684,51 @@ class EmacsScrollBar : public BScrollBar struct haiku_scroll_bar_drag_event rq; struct haiku_scroll_bar_part_event part; BRegion r; + BLooper *looper; + BMessage *message; + int32 buttons; - r = ButtonRegionFor (HAIKU_SCROLL_BAR_UP_BUTTON); + looper = Looper (); - if (r.Contains (pt)) + if (!looper) + GetMouse (&pt, (uint32 *) &buttons, false); + else { - part.scroll_bar = this; - part.window = Window (); - part.part = HAIKU_SCROLL_BAR_UP_BUTTON; - dragging = 1; - current_part = HAIKU_SCROLL_BAR_UP_BUTTON; - - haiku_write (SCROLL_BAR_PART_EVENT, &part); - goto out; - } + message = looper->CurrentMessage (); - r = ButtonRegionFor (HAIKU_SCROLL_BAR_DOWN_BUTTON); + if (!message || message->FindInt32 ("buttons", &buttons) != B_OK) + GetMouse (&pt, (uint32 *) &buttons, false); + } - if (r.Contains (pt)) + if (buttons == B_PRIMARY_MOUSE_BUTTON) { - part.scroll_bar = this; - part.window = Window (); - part.part = HAIKU_SCROLL_BAR_DOWN_BUTTON; - dragging = 1; - current_part = HAIKU_SCROLL_BAR_DOWN_BUTTON; - - haiku_write (SCROLL_BAR_PART_EVENT, &part); - goto out; + r = ButtonRegionFor (HAIKU_SCROLL_BAR_UP_BUTTON); + + if (r.Contains (pt)) + { + part.scroll_bar = this; + part.window = Window (); + part.part = HAIKU_SCROLL_BAR_UP_BUTTON; + dragging = 1; + current_part = HAIKU_SCROLL_BAR_UP_BUTTON; + + haiku_write (SCROLL_BAR_PART_EVENT, &part); + goto out; + } + + r = ButtonRegionFor (HAIKU_SCROLL_BAR_DOWN_BUTTON); + + if (r.Contains (pt)) + { + part.scroll_bar = this; + part.window = Window (); + part.part = HAIKU_SCROLL_BAR_DOWN_BUTTON; + dragging = 1; + current_part = HAIKU_SCROLL_BAR_DOWN_BUTTON; + + haiku_write (SCROLL_BAR_PART_EVENT, &part); + goto out; + } } rq.dragging_p = 1; commit a50f8dec092ecc82814fd21ed2cd1bfdc693655d (refs/remotes/origin/emacs-28) Author: Michael Albinus Date: Sat Feb 26 12:51:26 2022 +0100 Follow OpenSSH changes in Tramp * lisp/net/tramp-sh.el (tramp-ssh-controlmaster-options): Reimplement. OpenSSH has changed its diagnostics messages. diff --git a/lisp/net/tramp-sh.el b/lisp/net/tramp-sh.el index 80fd99e7f6..de4d579740 100644 --- a/lisp/net/tramp-sh.el +++ b/lisp/net/tramp-sh.el @@ -4753,36 +4753,33 @@ Goes through the list `tramp-inline-compress-commands'." (t (setq tramp-ssh-controlmaster-options "") (let ((case-fold-search t)) (ignore-errors - (when (executable-find "ssh") - (with-tramp-progress-reporter - vec 4 "Computing ControlMaster options" - (with-temp-buffer - (tramp-call-process vec "ssh" nil t nil "-o" "ControlMaster") - (goto-char (point-min)) - (when (search-forward-regexp "\\(missing\\|no\\).+argument" nil t) - (setq tramp-ssh-controlmaster-options - "-o ControlMaster=auto"))) - (unless (zerop (length tramp-ssh-controlmaster-options)) - (with-temp-buffer - ;; We use a non-existing IP address, in order to - ;; avoid useless connections, and DNS timeouts. - ;; Setting ConnectTimeout is needed since OpenSSH 7. - (tramp-call-process - vec "ssh" nil t nil - "-o" "ConnectTimeout=1" "-o" "ControlPath=%C" "0.0.0.1") - (goto-char (point-min)) + (with-tramp-progress-reporter + vec 4 "Computing ControlMaster options" + ;; We use a non-existing IP address, in order to avoid + ;; useless connections, and DNS timeouts. + (when (zerop + (tramp-call-process + vec "ssh" nil nil nil + "-G" "-o" "ControlMaster=auto" "0.0.0.1")) + (setq tramp-ssh-controlmaster-options + "-o ControlMaster=auto") + (if (zerop + (tramp-call-process + vec "ssh" nil nil nil + "-G" "-o" "ControlPath='tramp.%C'" "0.0.0.1")) (setq tramp-ssh-controlmaster-options (concat tramp-ssh-controlmaster-options - (if (search-forward-regexp "unknown.+key" nil t) - " -o ControlPath='tramp.%%r@%%h:%%p'" - " -o ControlPath='tramp.%%C'")))) - (with-temp-buffer - (tramp-call-process vec "ssh" nil t nil "-o" "ControlPersist") - (goto-char (point-min)) - (when (search-forward-regexp "missing.+argument" nil t) - (setq tramp-ssh-controlmaster-options - (concat tramp-ssh-controlmaster-options - " -o ControlPersist=no"))))))))) + " -o ControlPath='tramp.%%C'")) + (setq tramp-ssh-controlmaster-options + (concat tramp-ssh-controlmaster-options + " -o ControlPath='tramp.%%r@%%h:%%p'"))) + (when (zerop + (tramp-call-process + vec "ssh" nil nil nil + "-G" "-o" "ControlPersist=no" "0.0.0.1")) + (setq tramp-ssh-controlmaster-options + (concat tramp-ssh-controlmaster-options + " -o ControlPersist=no"))))))) tramp-ssh-controlmaster-options))) (defun tramp-scp-strict-file-name-checking (vec) commit e86eae21a9b72a751d2dc3419b56debfce2022a9 Author: Eli Zaretskii Date: Sat Feb 26 09:41:05 2022 +0200 Document better how to reset attributes of faces for new frames * doc/lispref/display.texi (Attribute Functions): * lisp/faces.el (set-face-attribute): Explain how to reset an attribute's value for future frames. (Bug#54156) diff --git a/doc/lispref/display.texi b/doc/lispref/display.texi index 0ea421c774..8a138588d3 100644 --- a/doc/lispref/display.texi +++ b/doc/lispref/display.texi @@ -2915,12 +2915,21 @@ names (such as @code{:family} or @code{:underline}) and values. Thus, sets the attribute @code{:weight} to @code{bold} and the attribute @code{:slant} to @code{italic}. - If @var{frame} is @code{t}, this function sets the default attributes for newly created frames; they will effectively override the attribute values specified by @code{defface}. If @var{frame} is @code{nil}, this function sets the attributes for all existing frames, as well as -for newly created frames. +for newly created frames. However, if you want to @emph{reset} the +value of an attribute to @code{unspecified} in a way that also affects +newly created frames, you @emph{must} explicitly call this function +with @var{frame} set to @code{t} and the value of the attribute set to +@code{unspecified} (@emph{not} @code{nil}!@:), in addition to the call +with @var{frame} set to @code{nil}. This is because the default +attributes for newly created frames are merged with the face's spec in +@code{defface} when a new frame is created, and so having +@code{unspecified} in the default attributes for new frames will be +unable to override @code{defface}; the special call to this function +as described above will arrange for @code{defface} to be overridden. @end defun The following commands and functions mostly provide compatibility diff --git a/lisp/faces.el b/lisp/faces.el index 50a82d454b..1d21a21622 100644 --- a/lisp/faces.el +++ b/lisp/faces.el @@ -663,7 +663,12 @@ face spec. It is mostly intended for internal use only. If FRAME is nil, set the attributes for all existing frames, as well as the default for new frames. If FRAME is t, change the -default for new frames only. +default for new frames only. As an exception, to reset the value +of some attribute to `unspecified' in a way that overrides the +non-`unspecified' value defined by the face's spec in `defface', +for new frames, you must explicitly call this function with FRAME +set to t and the attribute's value set to `unspecified'; just +using FRAME of nil will not affect new frames in this case. ARGS must come in pairs ATTRIBUTE VALUE. ATTRIBUTE must be a valid face attribute name. All attributes can be set to