From e5a74c20c399cdcab6115197da4b96eec8d3a345 Mon Sep 17 00:00:00 2001 From: Lars Ingebrigtsen Date: Sat, 18 Dec 2021 09:24:17 +0100 Subject: Make multisession file reading more resilient on Windows * lisp/emacs-lisp/multisession.el (multisession--read-file-value): Rename and try harder on file errors on Windows. --- lisp/emacs-lisp/multisession.el | 45 ++++++++++++++++++++++++----------------- 1 file changed, 26 insertions(+), 19 deletions(-) diff --git a/lisp/emacs-lisp/multisession.el b/lisp/emacs-lisp/multisession.el index bce888acc68..6ef0da10f77 100644 --- a/lisp/emacs-lisp/multisession.el +++ b/lisp/emacs-lisp/multisession.el @@ -250,23 +250,30 @@ DOC should be a doc string, and ARGS are keywords as applicable to (defun multisession--encode-file-name (name) (url-hexify-string name)) -(defun multisession--update-file-value (file object) - (condition-case nil - (with-temp-buffer - (let* ((time (file-attribute-modification-time - (file-attributes file))) - (coding-system-for-read 'utf-8)) - (insert-file-contents file) - (let ((stored (read (current-buffer)))) - (setf (multisession--cached-value object) stored - (multisession--cached-sequence object) time) - stored))) - ;; If the file is contended (could happen with file locking in - ;; Windws) or unreadable, just return the current value. - (error - (if (eq (multisession--cached-value object) multisession--unbound) - (multisession--initial-value object) - (multisession--cached-value object))))) +(defun multisession--read-file-value (file object) + (catch 'done + (let ((i 0) + last-error) + (while (< i 10) + (condition-case err + (throw 'done + (with-temp-buffer + (let* ((time (file-attribute-modification-time + (file-attributes file))) + (coding-system-for-read 'utf-8)) + (insert-file-contents file) + (let ((stored (read (current-buffer)))) + (setf (multisession--cached-value object) stored + (multisession--cached-sequence object) time) + stored)))) + ;; Windows uses OS-level file locking that may preclude + ;; reading the file in some circumstances. So when that + ;; happens, wait a bit and try again. + (file-error + (setq i (1+ i) + last-error err) + (sleep-for (+ 0.1 (/ (float (random 10)) 10)))))) + (signal (car last-error) (cdr last-error))))) (defun multisession--object-file-name (object) (expand-file-name @@ -283,7 +290,7 @@ DOC should be a doc string, and ARGS are keywords as applicable to ;; We have no value yet; see whether it's stored. ((eq (multisession--cached-value object) multisession--unbound) (if (file-exists-p file) - (multisession--update-file-value file object) + (multisession--read-file-value file object) ;; Nope; return the initial value. (multisession--initial-value object))) ;; We have a value, but we want to update in case some other @@ -293,7 +300,7 @@ DOC should be a doc string, and ARGS are keywords as applicable to (time-less-p (multisession--cached-sequence object) (file-attribute-modification-time (file-attributes file)))) - (multisession--update-file-value file object) + (multisession--read-file-value file object) ;; Nothing, return the cached value. (multisession--cached-value object))) ;; Just return the cached value. -- cgit v1.2.3 From 3fea95b79f7a80fc84f0aee38e1f31234ed7c657 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sat, 18 Dec 2021 11:03:48 +0200 Subject: Fix display of window-specific overlays with 'display' property * src/xdisp.c (handle_display_prop): Pass the window to 'get_char_property_and_overlay', not the buffer. (Bug#52385) The assignment of the buffer to OBJECT was moved to before the call to 'get_char_property_and_overlay', for unknown reasons, as part of installing the support for the 'min-width' space spec. --- src/xdisp.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/xdisp.c b/src/xdisp.c index 5e549c9c63f..e74411c8178 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -5361,9 +5361,6 @@ handle_display_prop (struct it *it) if (!it->string_from_display_prop_p) it->area = TEXT_AREA; - if (!STRINGP (it->string)) - object = it->w->contents; - propval = get_char_property_and_overlay (make_fixnum (position->charpos), Qdisplay, object, &overlay); @@ -5377,6 +5374,9 @@ handle_display_prop (struct it *it) /* Now OVERLAY is the overlay that gave us this property, or nil if it was a text property. */ + if (!STRINGP (it->string)) + object = it->w->contents; + display_replaced = handle_display_spec (it, propval, object, overlay, position, bufpos, FRAME_WINDOW_P (it->f)); -- cgit v1.2.3 From 43c4cc2ea29fa93de17d35e9cce4949eae171c45 Mon Sep 17 00:00:00 2001 From: Po Lu Date: Sat, 18 Dec 2021 18:48:11 +0800 Subject: Add new argument `ignore-line-at-end' to `window-text-pixel-size' * doc/lispref/display.texi (Size of Displayed Text): Update documentation. * etc/NEWS: Announce new argument. * src/xdisp.c (window_text_pixel_size): Allow controlling if the iterator's ascent and descent will be appended to the pixel height returned. All callers changed. (Fwindow_text_pixel_size): New argument `ignore-line-at-end'. All callers changed. --- doc/lispref/display.texi | 6 +++++- etc/NEWS | 5 +++++ src/haikufns.c | 3 ++- src/w32fns.c | 3 ++- src/xdisp.c | 42 ++++++++++++++++++++++++++++++++---------- src/xfns.c | 3 ++- 6 files changed, 48 insertions(+), 14 deletions(-) diff --git a/doc/lispref/display.texi b/doc/lispref/display.texi index b82473f9c20..92bfd2fea19 100644 --- a/doc/lispref/display.texi +++ b/doc/lispref/display.texi @@ -2086,7 +2086,7 @@ displayed in a given window. This function is used by (@pxref{Resizing Windows}) to make a window exactly as large as the text it contains. -@defun window-text-pixel-size &optional window from to x-limit y-limit mode-lines +@defun window-text-pixel-size &optional window from to x-limit y-limit mode-lines ignore-line-at-end This function returns the size of the text of @var{window}'s buffer in pixels. @var{window} must be a live window and defaults to the selected one. The return value is a cons of the maximum pixel-width @@ -2136,6 +2136,10 @@ line, if present, in the return value. If it is @code{t}, include the height of all of these lines, if present, in the return value. @end defun +The optional argument @var{ignore-line-at-end} controls whether or +not to count the height of text in @var{to}'s screen line as part of +the returned pixel-height. + @code{window-text-pixel-size} treats the text displayed in a window as a whole and does not care about the size of individual lines. The following function does. diff --git a/etc/NEWS b/etc/NEWS index bd1ed4da00c..20056b30c58 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -984,6 +984,11 @@ when they have changed. This can be used to check whether a specific font has a glyph for a character. ++++ +** 'window-text-pixel-size' now accepts a new argument `ignore-line-at-end'. +This controls whether or not the screen line at the end of the +measured area will be counted during the height calculation. + ** XDG support *** New function 'xdg-state-home' returns 'XDG_STATE_HOME' environment variable. diff --git a/src/haikufns.c b/src/haikufns.c index 868fc71f979..737b0338994 100644 --- a/src/haikufns.c +++ b/src/haikufns.c @@ -1970,7 +1970,8 @@ DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0, try_window (window, pos, TRY_WINDOW_IGNORE_FONTS_CHANGE); /* Calculate size of tooltip window. */ size = Fwindow_text_pixel_size (window, Qnil, Qnil, Qnil, - make_fixnum (w->pixel_height), Qnil); + make_fixnum (w->pixel_height), Qnil, + Qnil); /* Add the frame's internal border to calculated size. */ width = XFIXNUM (Fcar (size)) + 2 * FRAME_INTERNAL_BORDER_WIDTH (tip_f); height = XFIXNUM (Fcdr (size)) + 2 * FRAME_INTERNAL_BORDER_WIDTH (tip_f); diff --git a/src/w32fns.c b/src/w32fns.c index 65463b52616..02a6d78b51c 100644 --- a/src/w32fns.c +++ b/src/w32fns.c @@ -7525,7 +7525,8 @@ DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0, try_window (window, pos, TRY_WINDOW_IGNORE_FONTS_CHANGE); /* Calculate size of tooltip window. */ size = Fwindow_text_pixel_size (window, Qnil, Qnil, Qnil, - make_fixnum (w->pixel_height), Qnil); + make_fixnum (w->pixel_height), Qnil, + Qnil); /* Add the frame's internal border to calculated size. */ width = XFIXNUM (Fcar (size)) + 2 * FRAME_INTERNAL_BORDER_WIDTH (tip_f); height = XFIXNUM (Fcdr (size)) + 2 * FRAME_INTERNAL_BORDER_WIDTH (tip_f); diff --git a/src/xdisp.c b/src/xdisp.c index e74411c8178..473c9f3f143 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -10833,7 +10833,7 @@ in_display_vector_p (struct it *it) argument. */ static Lisp_Object window_text_pixel_size (Lisp_Object window, Lisp_Object from, Lisp_Object to, Lisp_Object x_limit, - Lisp_Object y_limit, Lisp_Object mode_lines) + Lisp_Object y_limit, Lisp_Object mode_lines, Lisp_Object ignore_line_at_end) { struct window *w = decode_live_window (window); struct it it; @@ -10841,6 +10841,7 @@ window_text_pixel_size (Lisp_Object window, Lisp_Object from, Lisp_Object to, Li struct text_pos startp; void *itdata = NULL; int c, max_x = 0, max_y = 0, x = 0, y = 0; + int doff = 0; if (NILP (from)) { @@ -10969,8 +10970,18 @@ window_text_pixel_size (Lisp_Object window, Lisp_Object from, Lisp_Object to, Li if (IT_CHARPOS (it) == end) { x += it.pixel_width; - it.max_ascent = max (it.max_ascent, it.ascent); - it.max_descent = max (it.max_descent, it.descent); + + /* DTRT if ignore_line_at_end is t. */ + if (!NILP (ignore_line_at_end)) + { + doff = (max (it.max_ascent, it.ascent) + + max (it.max_descent, it.descent)); + } + else + { + it.max_ascent = max (it.max_ascent, it.ascent); + it.max_descent = max (it.max_descent, it.descent); + } } } else @@ -10991,8 +11002,14 @@ window_text_pixel_size (Lisp_Object window, Lisp_Object from, Lisp_Object to, Li /* Subtract height of header-line and tab-line which was counted automatically by start_display. */ - y = it.current_y + it.max_ascent + it.max_descent - - WINDOW_TAB_LINE_HEIGHT (w) - WINDOW_HEADER_LINE_HEIGHT (w); + if (!NILP (ignore_line_at_end)) + y = (it.current_y + doff + - WINDOW_TAB_LINE_HEIGHT (w) + - WINDOW_HEADER_LINE_HEIGHT (w)); + else + y = (it.current_y + it.max_ascent + it.max_descent + doff + - WINDOW_TAB_LINE_HEIGHT (w) - WINDOW_HEADER_LINE_HEIGHT (w)); + /* Don't return more than Y-LIMIT. */ if (y > max_y) y = max_y; @@ -11039,7 +11056,7 @@ window_text_pixel_size (Lisp_Object window, Lisp_Object from, Lisp_Object to, Li return Fcons (make_fixnum (x - start_x), make_fixnum (y)); } -DEFUN ("window-text-pixel-size", Fwindow_text_pixel_size, Swindow_text_pixel_size, 0, 6, 0, +DEFUN ("window-text-pixel-size", Fwindow_text_pixel_size, Swindow_text_pixel_size, 0, 7, 0, doc: /* Return the size of the text of WINDOW's buffer in pixels. WINDOW must be a live window and defaults to the selected one. The return value is a cons of the maximum pixel-width of any text line @@ -11086,9 +11103,12 @@ Optional argument MODE-LINES nil or omitted means do not include the height of the mode-, tab- or header-line of WINDOW in the return value. If it is the symbol `mode-line', 'tab-line' or `header-line', include only the height of that line, if present, in the return value. If t, -include the height of any of these, if present, in the return value. */) +include the height of any of these, if present, in the return value. + +IGNORE-LINE-AT-END means to not add the height of the screen line at +TO to the returned height. */) (Lisp_Object window, Lisp_Object from, Lisp_Object to, Lisp_Object x_limit, - Lisp_Object y_limit, Lisp_Object mode_lines) + Lisp_Object y_limit, Lisp_Object mode_lines, Lisp_Object ignore_line_at_end) { struct window *w = decode_live_window (window); struct buffer *b = XBUFFER (w->contents); @@ -11101,7 +11121,8 @@ include the height of any of these, if present, in the return value. */) set_buffer_internal_1 (b); } - value = window_text_pixel_size (window, from, to, x_limit, y_limit, mode_lines); + value = window_text_pixel_size (window, from, to, x_limit, y_limit, mode_lines, + ignore_line_at_end); if (old_b) set_buffer_internal_1 (old_b); @@ -11151,7 +11172,8 @@ WINDOW. */) set_marker_both (w->old_pointm, buffer, BEG, BEG_BYTE); } - value = window_text_pixel_size (window, Qnil, Qnil, x_limit, y_limit, Qnil); + value = window_text_pixel_size (window, Qnil, Qnil, x_limit, y_limit, Qnil, + Qnil); unbind_to (count, Qnil); diff --git a/src/xfns.c b/src/xfns.c index dc25d7bfca2..30ed358fb28 100644 --- a/src/xfns.c +++ b/src/xfns.c @@ -7169,7 +7169,8 @@ Text larger than the specified size is clipped. */) try_window (window, pos, TRY_WINDOW_IGNORE_FONTS_CHANGE); /* Calculate size of tooltip window. */ size = Fwindow_text_pixel_size (window, Qnil, Qnil, Qnil, - make_fixnum (w->pixel_height), Qnil); + make_fixnum (w->pixel_height), Qnil, + Qnil); /* Add the frame's internal border to calculated size. */ width = XFIXNUM (Fcar (size)) + 2 * FRAME_INTERNAL_BORDER_WIDTH (tip_f); height = XFIXNUM (Fcdr (size)) + 2 * FRAME_INTERNAL_BORDER_WIDTH (tip_f); -- cgit v1.2.3 From d99aa9461b1348741ee2df7b6c7a197005191716 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sat, 18 Dec 2021 13:56:10 +0200 Subject: ; Fix last change * src/xdisp.c (window_text_pixel_size): Fix whitespace and braces. * src/xdisp.c (Fwindow_text_pixel_size): * etc/NEWS: * doc/lispref/display.texi (Size of Displayed Text): Improve wording of the documentation of the new argument of 'window-text-pixel-size'. --- doc/lispref/display.texi | 4 +++- etc/NEWS | 7 ++++--- src/xdisp.c | 15 +++++++-------- 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/doc/lispref/display.texi b/doc/lispref/display.texi index 92bfd2fea19..1460e070a0a 100644 --- a/doc/lispref/display.texi +++ b/doc/lispref/display.texi @@ -2138,7 +2138,9 @@ height of all of these lines, if present, in the return value. The optional argument @var{ignore-line-at-end} controls whether or not to count the height of text in @var{to}'s screen line as part of -the returned pixel-height. +the returned pixel-height. This is useful if your Lisp program is +only interested in the dimensions of text up to and excluding the +visual beginning of @var{to}'s screen line. @code{window-text-pixel-size} treats the text displayed in a window as a whole and does not care about the size of individual lines. The diff --git a/etc/NEWS b/etc/NEWS index 20056b30c58..e3665b918a3 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -985,9 +985,10 @@ This can be used to check whether a specific font has a glyph for a character. +++ -** 'window-text-pixel-size' now accepts a new argument `ignore-line-at-end'. -This controls whether or not the screen line at the end of the -measured area will be counted during the height calculation. +** 'window-text-pixel-size' now accepts a new argument 'ignore-line-at-end'. +This controls whether or not the last screen line of the text being +measured will be counted for the purpose of calculating the text +dimensions. ** XDG support diff --git a/src/xdisp.c b/src/xdisp.c index 473c9f3f143..6dcfe3573a9 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -10832,8 +10832,9 @@ in_display_vector_p (struct it *it) set WINDOW's buffer to the buffer specified by its BUFFER_OR_NAME argument. */ static Lisp_Object -window_text_pixel_size (Lisp_Object window, Lisp_Object from, Lisp_Object to, Lisp_Object x_limit, - Lisp_Object y_limit, Lisp_Object mode_lines, Lisp_Object ignore_line_at_end) +window_text_pixel_size (Lisp_Object window, Lisp_Object from, Lisp_Object to, + Lisp_Object x_limit, Lisp_Object y_limit, + Lisp_Object mode_lines, Lisp_Object ignore_line_at_end) { struct window *w = decode_live_window (window); struct it it; @@ -10973,10 +10974,8 @@ window_text_pixel_size (Lisp_Object window, Lisp_Object from, Lisp_Object to, Li /* DTRT if ignore_line_at_end is t. */ if (!NILP (ignore_line_at_end)) - { - doff = (max (it.max_ascent, it.ascent) - + max (it.max_descent, it.descent)); - } + doff = (max (it.max_ascent, it.ascent) + + max (it.max_descent, it.descent)); else { it.max_ascent = max (it.max_ascent, it.ascent); @@ -11105,8 +11104,8 @@ If it is the symbol `mode-line', 'tab-line' or `header-line', include only the height of that line, if present, in the return value. If t, include the height of any of these, if present, in the return value. -IGNORE-LINE-AT-END means to not add the height of the screen line at -TO to the returned height. */) +IGNORE-LINE-AT-END, if non-nil, means to not add the height of the +screen line that includes TO to the returned height of the text. */) (Lisp_Object window, Lisp_Object from, Lisp_Object to, Lisp_Object x_limit, Lisp_Object y_limit, Lisp_Object mode_lines, Lisp_Object ignore_line_at_end) { -- cgit v1.2.3 From 4544651b3f62ce4a104a058e8c6aee42c23b76bc Mon Sep 17 00:00:00 2001 From: Po Lu Date: Sat, 18 Dec 2021 20:45:11 +0800 Subject: Work around some mysterious touch ownership race on GNOME Shell * src/xterm.c (x_unlink_touch_point): Return if touchpoint was actually unlinked. (handle_one_xevent): Catch and ignore errors during touch sequence grabbing. --- src/xterm.c | 88 +++++++++++++++++++++++++++++++++++-------------------------- 1 file changed, 51 insertions(+), 37 deletions(-) diff --git a/src/xterm.c b/src/xterm.c index 03f509ba868..7456b3b6beb 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -579,7 +579,7 @@ xi_link_touch_point (struct xi_device_t *device, device->touchpoints = touchpoint; } -static void +static bool xi_unlink_touch_point (int detail, struct xi_device_t *device) { @@ -596,9 +596,11 @@ xi_unlink_touch_point (int detail, last->next = tem->next; xfree (tem); - return; + return true; } } + + return false; } static struct xi_touch_point_t * @@ -10887,37 +10889,45 @@ handle_one_xevent (struct x_display_info *dpyinfo, if (f && device->direct_p) { - xi_link_touch_point (device, xev->detail, xev->event_x, - xev->event_y); + x_catch_errors (dpyinfo->display); + XIAllowTouchEvents (dpyinfo->display, xev->deviceid, + xev->detail, xev->event, XIAcceptTouch); + if (!x_had_errors_p (dpyinfo->display)) + { + xi_link_touch_point (device, xev->detail, xev->event_x, + xev->event_y); #ifdef HAVE_GTK3 - if (FRAME_X_OUTPUT (f)->menubar_widget - && xg_event_is_for_menubar (f, event)) - { - bool was_waiting_for_input = waiting_for_input; - /* This hack was adopted from the NS port. Whether - or not it is actually safe is a different story - altogether. */ - if (waiting_for_input) - waiting_for_input = 0; - set_frame_menubar (f, true); - waiting_for_input = was_waiting_for_input; - } + if (FRAME_X_OUTPUT (f)->menubar_widget + && xg_event_is_for_menubar (f, event)) + { + bool was_waiting_for_input = waiting_for_input; + /* This hack was adopted from the NS port. Whether + or not it is actually safe is a different story + altogether. */ + if (waiting_for_input) + waiting_for_input = 0; + set_frame_menubar (f, true); + waiting_for_input = was_waiting_for_input; + } #endif - inev.ie.kind = TOUCHSCREEN_BEGIN_EVENT; - inev.ie.timestamp = xev->time; - XSETFRAME (inev.ie.frame_or_window, f); - XSETINT (inev.ie.x, lrint (xev->event_x)); - XSETINT (inev.ie.y, lrint (xev->event_y)); - XSETINT (inev.ie.arg, xev->detail); - - XIAllowTouchEvents (dpyinfo->display, xev->deviceid, - xev->detail, xev->event, XIAcceptTouch); + inev.ie.kind = TOUCHSCREEN_BEGIN_EVENT; + inev.ie.timestamp = xev->time; + XSETFRAME (inev.ie.frame_or_window, f); + XSETINT (inev.ie.x, lrint (xev->event_x)); + XSETINT (inev.ie.y, lrint (xev->event_y)); + XSETINT (inev.ie.arg, xev->detail); + } + x_uncatch_errors_after_check (); } else - XIAllowTouchEvents (dpyinfo->display, xev->deviceid, - xev->detail, xev->event, XIRejectTouch); + { + x_catch_errors (dpyinfo->display); + XIAllowTouchEvents (dpyinfo->display, xev->deviceid, + xev->detail, xev->event, XIRejectTouch); + x_uncatch_errors (); + } goto XI_OTHER; } @@ -10965,24 +10975,28 @@ handle_one_xevent (struct x_display_info *dpyinfo, case XI_TouchEnd: { struct xi_device_t *device; + bool unlinked_p; device = xi_device_from_id (dpyinfo, xev->deviceid); if (!device) goto XI_OTHER; - xi_unlink_touch_point (xev->detail, device); - - f = x_any_window_to_frame (dpyinfo, xev->event); + unlinked_p = xi_unlink_touch_point (xev->detail, device); - if (f && device->direct_p) + if (unlinked_p) { - inev.ie.kind = TOUCHSCREEN_END_EVENT; - inev.ie.timestamp = xev->time; - XSETFRAME (inev.ie.frame_or_window, f); - XSETINT (inev.ie.x, lrint (xev->event_x)); - XSETINT (inev.ie.y, lrint (xev->event_y)); - XSETINT (inev.ie.arg, xev->detail); + f = x_any_window_to_frame (dpyinfo, xev->event); + + if (f && device->direct_p) + { + inev.ie.kind = TOUCHSCREEN_END_EVENT; + inev.ie.timestamp = xev->time; + XSETFRAME (inev.ie.frame_or_window, f); + XSETINT (inev.ie.x, lrint (xev->event_x)); + XSETINT (inev.ie.y, lrint (xev->event_y)); + XSETINT (inev.ie.arg, xev->detail); + } } goto XI_OTHER; -- cgit v1.2.3