From 414de92a562e8912ffdc8ed2995e7ea10d05f13b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerd=20M=C3=B6llmann?= Date: Mon, 21 Oct 2024 18:32:04 +0200 Subject: [PATCH 01/53] Initial child frames based on master This is based on a diff from 2024-10-15 which still applied. Since then, I've inadvertantly modified the igc branch so that it is no longer possible to get a clean diff of what has changed since I created the branch. --- lisp/disp-table.el | 54 +- lisp/frame.el | 46 +- lisp/xt-mouse.el | 15 +- src/alloc.c | 8 +- src/chartab.c | 2 - src/dispextern.h | 40 +- src/dispnew.c | 1192 +++++++++++++++++++++++++++++++------------- src/disptab.h | 12 +- src/frame.c | 452 +++++++++++++---- src/frame.h | 84 ++-- src/keyboard.c | 2 +- src/minibuf.c | 6 +- src/nsfns.m | 4 +- src/nsterm.m | 4 +- src/scroll.c | 4 +- src/term.c | 266 ++++++++-- src/termhooks.h | 3 + src/terminal.c | 6 +- src/xdisp.c | 89 +++- src/xfaces.c | 1 - 20 files changed, 1672 insertions(+), 618 deletions(-) diff --git a/lisp/disp-table.el b/lisp/disp-table.el index 50428d911a3..b4b60f751f4 100644 --- a/lisp/disp-table.el +++ b/lisp/disp-table.el @@ -28,7 +28,7 @@ ;;; Code: -(put 'display-table 'char-table-extra-slots 6) +(put 'display-table 'char-table-extra-slots 12) ;;;###autoload (defun make-display-table () @@ -46,13 +46,21 @@ (put 'control 'display-table-slot 3) (put 'selective-display 'display-table-slot 4) (put 'vertical-border 'display-table-slot 5) +(put 'box-vertical 'display-table-slot 6) +(put 'box-horizontal 'display-table-slot 7) +(put 'box-down-right 'display-table-slot 8) +(put 'box-down-left 'display-table-slot 9) +(put 'box-up-right 'display-table-slot 10) +(put 'box-up-left 'display-table-slot 11) ;;;###autoload (defun display-table-slot (display-table slot) "Return the value of the extra slot in DISPLAY-TABLE named SLOT. -SLOT may be a number from 0 to 5 inclusive, or a slot name (symbol). +SLOT may be a number from 0 to 11 inclusive, or a slot name (symbol). Valid symbols are `truncation', `wrap', `escape', `control', -`selective-display', and `vertical-border'." +`selective-display', `vertical-border', `box-vertical', +`box-horizontal', `box-down-right', `box-down-left', `box-up-right', +and `box-up-left'." (let ((slot-number (if (numberp slot) slot (or (get slot 'display-table-slot) @@ -62,9 +70,11 @@ Valid symbols are `truncation', `wrap', `escape', `control', ;;;###autoload (defun set-display-table-slot (display-table slot value) "Set the value of the extra slot in DISPLAY-TABLE named SLOT to VALUE. -SLOT may be a number from 0 to 5 inclusive, or a name (symbol). +SLOT may be a number from 0 to 11 inclusive, or a name (symbol). Valid symbols are `truncation', `wrap', `escape', `control', -`selective-display', and `vertical-border'." +`selective-display', `vertical-border', `box-vertical', +`box-horizontal', `box-down-right', `box-down-left', `box-up-right', +and `box-up-left'." (let ((slot-number (if (numberp slot) slot (or (get slot 'display-table-slot) @@ -87,6 +97,18 @@ Valid symbols are `truncation', `wrap', `escape', `control', (prin1 (display-table-slot dt 'selective-display)) (princ "\nVertical window border glyph: ") (prin1 (display-table-slot dt 'vertical-border)) + (princ "\nBox vertical line glyph: ") + (prin1 (display-table-slot dt 'box-vertical)) + (princ "\nBox horizonal line glyph: ") + (prin1 (display-table-slot dt 'box-horizontal)) + (princ "\nBox upper left corner glyph: ") + (prin1 (display-table-slot dt 'box-down-right)) + (princ "\nBox upper right corner glyph: ") + (prin1 (display-table-slot dt 'box-down-left)) + (princ "\nBox lower left corner glyph: ") + (prin1 (display-table-slot dt 'box-up-right)) + (princ "\nBox lower right corner glyph: ") + (prin1 (display-table-slot dt 'box-up-left)) (princ "\nCharacter display glyph sequences:\n") (with-current-buffer standard-output (let ((vector (make-vector 256 nil)) @@ -126,6 +148,28 @@ Valid symbols are `truncation', `wrap', `escape', `control', (describe-display-table disptab) (message "No display table")))) +;;;###autoload +(defun standard-display-unicode-special-glyphs () + "Display some glyps using Unicode characters. +The glyphs being changed by this function are `vertical-border', +`box-vertical', `box-horizontal', `box-down-right', `box-down-left', +`box-up-right', and `box-up-left'." + (interactive) + (set-display-table-slot standard-display-table + 'vertical-border (make-glyph-code #x2502)) + (set-display-table-slot standard-display-table + 'box-vertical (make-glyph-code #x2502)) + (set-display-table-slot standard-display-table + 'box-horizontal (make-glyph-code #x2500)) + (set-display-table-slot standard-display-table + 'box-down-right (make-glyph-code #x250c)) + (set-display-table-slot standard-display-table + 'box-down-left (make-glyph-code #x2510)) + (set-display-table-slot standard-display-table + 'box-up-right (make-glyph-code #x2514)) + (set-display-table-slot standard-display-table + 'box-up-left (make-glyph-code #x2518))) + ;;;###autoload (defun standard-display-8bit (l h) "Display characters representing raw bytes in the range L to H literally. diff --git a/lisp/frame.el b/lisp/frame.el index 1b5aa8cff08..14a78ea4833 100644 --- a/lisp/frame.el +++ b/lisp/frame.el @@ -1495,6 +1495,13 @@ FRAME defaults to the selected frame." (let ((edges (frame-edges frame 'outer-edges))) (- (nth 3 edges) (nth 1 edges)))) +(defun frame-at (x y) + "Return frame containing pixel position X, Y." + (cl-loop for frame in (frame-list-z-order) + as (x0 y0 x1 y1) = (frame-edges frame) + when (and (<= x0 x (1- x1)) (<= y0 y (1- y1))) + return frame)) + (declare-function x-list-fonts "xfaces.c" (pattern &optional face frame maximum width)) @@ -1722,6 +1729,7 @@ live frame and defaults to the selected one." (declare-function pgtk-frame-geometry "pgtkfns.c" (&optional frame)) (declare-function haiku-frame-geometry "haikufns.c" (&optional frame)) (declare-function android-frame-geometry "androidfns.c" (&optional frame)) +(declare-function tty-frame-geometry "term.c" (&optional frame)) (defun frame-geometry (&optional frame) "Return geometric attributes of FRAME. @@ -1778,24 +1786,7 @@ and width values are in pixels. ((eq frame-type 'android) (android-frame-geometry frame)) (t - (list - '(outer-position 0 . 0) - (cons 'outer-size (cons (frame-width frame) (frame-height frame))) - '(external-border-size 0 . 0) - '(outer-border-width . 0) - '(title-bar-size 0 . 0) - '(menu-bar-external . nil) - (let ((menu-bar-lines (frame-parameter frame 'menu-bar-lines))) - (cons 'menu-bar-size - (if menu-bar-lines - (cons (frame-width frame) 1) - 1 0))) - '(tool-bar-external . nil) - '(tool-bar-position . nil) - '(tool-bar-size 0 . 0) - '(tab-bar-size 0 . 0) - (cons 'internal-border-width - (frame-parameter frame 'internal-border-width))))))) + (tty-frame-geometry frame))))) (defun frame--size-history (&optional frame) "Print history of resize operations for FRAME. @@ -1904,6 +1895,7 @@ of frames like calls to map a frame or change its visibility." (declare-function pgtk-frame-edges "pgtkfns.c" (&optional frame type)) (declare-function haiku-frame-edges "haikufns.c" (&optional frame type)) (declare-function android-frame-edges "androidfns.c" (&optional frame type)) +(declare-function tty-frame-edges "term.c" (&optional frame type)) (defun frame-edges (&optional frame type) "Return coordinates of FRAME's edges. @@ -1934,7 +1926,7 @@ FRAME." ((eq frame-type 'android) (android-frame-edges frame type)) (t - (list 0 0 (frame-width frame) (frame-height frame)))))) + (tty-frame-edges frame type))))) (declare-function w32-mouse-absolute-pixel-position "w32fns.c") (declare-function x-mouse-absolute-pixel-position "xfns.c") @@ -2087,6 +2079,7 @@ workarea attribute." ;; (declare-function pgtk-frame-list-z-order "pgtkfns.c" (&optional display)) (declare-function haiku-frame-list-z-order "haikufns.c" (&optional display)) (declare-function android-frame-list-z-order "androidfns.c" (&optional display)) +(declare-function tty-frame-list-z-order "term.c" (&optional display)) (defun frame-list-z-order (&optional display) "Return list of Emacs's frames, in Z (stacking) order. @@ -2114,7 +2107,9 @@ Return nil if DISPLAY contains no Emacs frame." ((eq frame-type 'haiku) (haiku-frame-list-z-order display)) ((eq frame-type 'android) - (android-frame-list-z-order display))))) + (android-frame-list-z-order display)) + (t + (tty-frame-list-z-order display))))) (declare-function x-frame-restack "xfns.c" (frame1 frame2 &optional above)) (declare-function w32-frame-restack "w32fns.c" (frame1 frame2 &optional above)) @@ -2123,6 +2118,7 @@ Return nil if DISPLAY contains no Emacs frame." (declare-function haiku-frame-restack "haikufns.c" (frame1 frame2 &optional above)) (declare-function android-frame-restack "androidfns.c" (frame1 frame2 &optional above)) +(declare-function tty-frame-restack "term.c" (frame1 frame2 &optional above)) (defun frame-restack (frame1 frame2 &optional above) "Restack FRAME1 below FRAME2. @@ -2158,7 +2154,9 @@ Some window managers may refuse to restack windows." ((eq frame-type 'pgtk) (pgtk-frame-restack frame1 frame2 above)) ((eq frame-type 'android) - (android-frame-restack frame1 frame2 above)))) + (android-frame-restack frame1 frame2 above)) + (t + (tty-frame-restack frame1 frame2 above)))) (error "Cannot restack frames"))) (defun frame-size-changed-p (&optional frame) @@ -2311,6 +2309,7 @@ If DISPLAY is omitted or nil, it defaults to the selected frame's display." 1)))) (declare-function x-display-pixel-height "xfns.c" (&optional terminal)) +(declare-function tty-display-pixel-height "term.c" (&optional terminal)) (defun display-pixel-height (&optional display) "Return the height of DISPLAY's screen in pixels. @@ -2328,9 +2327,10 @@ with DISPLAY. To get information for each physical monitor, use ((memq frame-type '(x w32 ns haiku pgtk android)) (x-display-pixel-height display)) (t - (frame-height (if (framep display) display (selected-frame))))))) + (tty-display-pixel-height display))))) (declare-function x-display-pixel-width "xfns.c" (&optional terminal)) +(declare-function tty-display-pixel-width "term.c" (&optional terminal)) (defun display-pixel-width (&optional display) "Return the width of DISPLAY's screen in pixels. @@ -2348,7 +2348,7 @@ with DISPLAY. To get information for each physical monitor, use ((memq frame-type '(x w32 ns haiku pgtk android)) (x-display-pixel-width display)) (t - (frame-width (if (framep display) display (selected-frame))))))) + (tty-display-pixel-width display))))) (defcustom display-mm-dimensions-alist nil "Alist for specifying screen dimensions in millimeters. diff --git a/lisp/xt-mouse.el b/lisp/xt-mouse.el index 8cbb44ece14..131c99d790d 100644 --- a/lisp/xt-mouse.el +++ b/lisp/xt-mouse.el @@ -133,7 +133,8 @@ https://invisible-island.net/xterm/ctlseqs/ctlseqs.html)." (defun xterm-mouse--handle-mouse-movement () "Handle mouse motion that was just generated for XTerm mouse." - (display--update-for-mouse-movement (terminal-parameter nil 'xterm-mouse-x) + (display--update-for-mouse-movement (terminal-parameter nil 'xterm-mouse-frame) + (terminal-parameter nil 'xterm-mouse-x) (terminal-parameter nil 'xterm-mouse-y))) ;; These two variables have been converted to terminal parameters. @@ -293,7 +294,16 @@ which is the \"1006\" extension implemented in Xterm >= 277." (progn (setq xt-mouse-epoch (float-time)) 0) (car (time-convert (time-since xt-mouse-epoch) 1000)))) - (w (window-at x y)) + (frame (frame-at x y)) + ;;(_ (message (format "*** %S" frame))) + (frame-pos (frame-position frame)) + ;;(_ (message (format "*** %S" frame-pos))) + (x (- x (car frame-pos))) + (y (- y (cdr frame-pos))) + ;;(_ (message (format "*** %S %S" x y))) + (w (window-at x y frame)) + ;;(_ (message (format "*** %S" w))) + (ltrb (window-edges w)) (left (nth 0 ltrb)) (top (nth 1 ltrb)) @@ -345,6 +355,7 @@ which is the \"1006\" extension implemented in Xterm >= 277." (set-terminal-parameter nil 'xterm-mouse-x x) (set-terminal-parameter nil 'xterm-mouse-y y) + (set-terminal-parameter nil 'xterm-mouse-frame frame) (setq last-input-event event))))) ;;;###autoload diff --git a/src/alloc.c b/src/alloc.c index 4fab0d54248..bbabd8c95e8 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -6853,9 +6853,11 @@ mark_glyph_matrix (struct glyph_matrix *matrix) struct glyph *end_glyph = glyph + row->used[area]; for (; glyph < end_glyph; ++glyph) - if (STRINGP (glyph->object) - && !string_marked_p (XSTRING (glyph->object))) - mark_object (glyph->object); + { + if (STRINGP (glyph->object) + && !string_marked_p (XSTRING (glyph->object))) + mark_object (glyph->object); + } } } } diff --git a/src/chartab.c b/src/chartab.c index 58bb1658504..76a40ca7cc4 100644 --- a/src/chartab.c +++ b/src/chartab.c @@ -122,8 +122,6 @@ the char-table has no extra slot. */) else { CHECK_FIXNAT (n); - if (XFIXNUM (n) > 10) - args_out_of_range (n, Qnil); n_extras = XFIXNUM (n); } diff --git a/src/dispextern.h b/src/dispextern.h index cc248a4472e..468aee8d1ba 100644 --- a/src/dispextern.h +++ b/src/dispextern.h @@ -482,6 +482,11 @@ struct glyph continuation glyphs, or the overlay-arrow glyphs on TTYs. */ Lisp_Object object; + /* Frame on which the glyph was produced. The face_id of this glyph + refers to the face_cache of this frame. This is used on tty frames + only. */ + struct frame *frame; + /* Width in pixels. */ short pixel_width; @@ -626,10 +631,12 @@ struct glyph #define FONT_TYPE_UNKNOWN 0 -/* Is GLYPH a space? */ +/* Is GLYPH a space in default face on frame FRAME? */ -#define CHAR_GLYPH_SPACE_P(GLYPH) \ - ((GLYPH).u.ch == SPACEGLYPH && (GLYPH).face_id == DEFAULT_FACE_ID) +# define CHAR_GLYPH_SPACE_P(FRAME, GLYPH) \ + ((GLYPH).u.ch == SPACEGLYPH \ + && (GLYPH).face_id == DEFAULT_FACE_ID \ + && (GLYPH).frame == (FRAME)) /* Are glyph slices of glyphs *X and *Y equal? It assumes that both glyphs have the same type. @@ -654,6 +661,7 @@ struct glyph && (X)->u.val == (Y)->u.val \ && GLYPH_SLICE_EQUAL_P (X, Y) \ && (X)->face_id == (Y)->face_id \ + && (X)->frame == (Y)->frame \ && (X)->padding_p == (Y)->padding_p \ && (X)->left_box_line_p == (Y)->left_box_line_p \ && (X)->right_box_line_p == (Y)->right_box_line_p \ @@ -665,16 +673,18 @@ struct glyph #define GLYPH_CHAR_AND_FACE_EQUAL_P(X, Y) \ ((X)->u.ch == (Y)->u.ch \ && (X)->face_id == (Y)->face_id \ + && (X)->frame == (Y)->frame \ && (X)->padding_p == (Y)->padding_p) /* Fill a character glyph GLYPH. CODE, FACE_ID, PADDING_P correspond to the bits defined for the typedef `GLYPH' in lisp.h. */ -#define SET_CHAR_GLYPH(GLYPH, CODE, FACE_ID, PADDING_P) \ +#define SET_CHAR_GLYPH(FRAME, GLYPH, CODE, FACE_ID, PADDING_P) \ do \ { \ (GLYPH).u.ch = (CODE); \ (GLYPH).face_id = (FACE_ID); \ + (GLYPH).frame = (FRAME); \ (GLYPH).padding_p = (PADDING_P); \ } \ while (false) @@ -682,11 +692,9 @@ struct glyph /* Fill a character type glyph GLYPH from a glyph typedef FROM as defined in lisp.h. */ -#define SET_CHAR_GLYPH_FROM_GLYPH(GLYPH, FROM) \ - SET_CHAR_GLYPH (GLYPH, \ - GLYPH_CHAR (FROM), \ - GLYPH_FACE (FROM), \ - false) +#define SET_CHAR_GLYPH_FROM_GLYPH(FRAME, GLYPH, FROM) \ + SET_CHAR_GLYPH (FRAME, GLYPH, GLYPH_CHAR (FROM), \ + GLYPH_FACE (FROM), false) /* Construct a glyph code from a character glyph GLYPH. If the character is multibyte, return -1 as we can't use glyph table for a @@ -3805,7 +3813,7 @@ extern void adjust_frame_glyphs (struct frame *); void free_glyphs (struct frame *); void free_window_matrices (struct window *); void check_glyph_memory (void); -void mirrored_line_dance (struct glyph_matrix *, int, int, int *, char *); +void mirrored_line_dance (struct frame *f, int, int, int *, char *); void clear_glyph_matrix (struct glyph_matrix *); void clear_current_matrices (struct frame *f); void clear_desired_matrices (struct frame *); @@ -3829,7 +3837,7 @@ extern bool frame_size_change_delayed (struct frame *); void init_display (void); void syms_of_display (void); extern void spec_glyph_lookup_face (struct window *, GLYPH *); -extern void fill_up_frame_row_with_spaces (struct glyph_row *, int); +extern void fill_up_frame_row_with_spaces (struct frame *, struct glyph_row *, int); /* Defined in terminal.c. */ @@ -3911,6 +3919,16 @@ extern void gui_redo_mouse_highlight (Display_Info *); #endif /* HAVE_WINDOW_SYSTEM */ +struct frame *root_frame (struct frame *f); +Lisp_Object frames_in_reverse_z_order (struct frame *f, bool visible); +bool is_tty_frame (struct frame *f); +bool is_tty_child_frame (struct frame *f); +bool is_tty_root_frame (struct frame *f); +bool combine_updates (Lisp_Object root_frames, bool force_p, bool inhibit_id_p); +bool combine_updates_for_frame (struct frame *f, bool force_p, bool inhibit_id_p); +void tty_raise_lower_frame (struct frame *f, bool raise); +int max_child_z_order (struct frame *parent); + INLINE_HEADER_END #endif /* not DISPEXTERN_H_INCLUDED */ diff --git a/src/dispnew.c b/src/dispnew.c index 1a243079e46..26181c36399 100644 --- a/src/dispnew.c +++ b/src/dispnew.c @@ -42,6 +42,8 @@ along with GNU Emacs. If not, see . */ #include "tparam.h" #include "xwidget.h" #include "pdumper.h" +#include "disptab.h" +#include "cm.h" #ifdef HAVE_ANDROID #include "android.h" @@ -71,7 +73,7 @@ struct dim /* Function prototypes. */ -static void update_frame_line (struct frame *, int, bool); +static void write_row (struct frame *f, int vpos, bool updating_menu_p); static int required_matrix_height (struct window *); static int required_matrix_width (struct window *); static void increment_row_positions (struct glyph_row *, ptrdiff_t, ptrdiff_t); @@ -80,9 +82,9 @@ static void build_frame_matrix_from_window_tree (struct glyph_matrix *, static void build_frame_matrix_from_leaf_window (struct glyph_matrix *, struct window *); static void adjust_decode_mode_spec_buffer (struct frame *); -static void fill_up_glyph_row_with_spaces (struct glyph_row *); +static void fill_up_glyph_row_with_spaces (struct frame *, struct glyph_row *); static void clear_window_matrices (struct window *, bool); -static void fill_up_glyph_row_area_with_spaces (struct glyph_row *, int); +static void fill_up_glyph_row_area_with_spaces (struct frame *, struct glyph_row *, int); static int scrolling_window (struct window *, int); static bool update_window_line (struct window *, int, bool *); static void mirror_make_current (struct window *, int); @@ -93,7 +95,7 @@ static void check_matrix_pointers (struct glyph_matrix *, static void mirror_line_dance (struct window *, int, int, int *, char *); static bool update_window_tree (struct window *, bool); static bool update_window (struct window *, bool); -static bool update_frame_1 (struct frame *, bool, bool, bool, bool); +static bool write_matrix (struct frame *, bool, bool, bool, bool); static bool scrolling (struct frame *); static void set_window_cursor_after_update (struct window *); static void adjust_frame_glyphs_for_window_redisplay (struct frame *); @@ -122,11 +124,6 @@ static int glyph_pool_count; #endif /* GLYPH_DEBUG and ENABLE_CHECKING */ -/* If non-null, the frame whose frame matrices are manipulated. If - null, window matrices are worked on. */ - -static struct frame *frame_matrix_frame; - /* Convert vpos and hpos from frame to window and vice versa. This may only be used for terminal frames. */ @@ -1179,6 +1176,11 @@ line_hash_code (struct frame *f, struct glyph_row *row) { int c = glyph->u.ch; int face_id = glyph->face_id; + /* Struct frame can move with igc, and so on. But we need + something that takes different frames into account. Use the + face_cache pointer for that which is malloc'd. */ + if (glyph->frame && glyph->frame != f) + face_id += (ptrdiff_t) glyph->frame->face_cache; if (FRAME_MUST_WRITE_SPACES (f)) c -= SPACEGLYPH; hash = (((hash << 4) + (hash >> 24)) & 0x0fffffff) + c; @@ -1213,7 +1215,7 @@ line_draw_cost (struct frame *f, struct glyph_matrix *matrix, int vpos) if (!FRAME_MUST_WRITE_SPACES (f)) { /* Skip from the end over trailing spaces. */ - while (end > beg && CHAR_GLYPH_SPACE_P (*(end - 1))) + while (end > beg && CHAR_GLYPH_SPACE_P (f, *(end - 1))) --end; /* All blank line. */ @@ -1221,7 +1223,7 @@ line_draw_cost (struct frame *f, struct glyph_matrix *matrix, int vpos) return 0; /* Skip over leading spaces. */ - while (CHAR_GLYPH_SPACE_P (*beg)) + while (CHAR_GLYPH_SPACE_P (f, *beg)) ++beg; } @@ -2558,6 +2560,7 @@ build_frame_matrix_from_leaf_window (struct glyph_matrix *frame_matrix, struct w int window_y, frame_y; /* If non-zero, a glyph to insert at the right border of W. */ GLYPH right_border_glyph; + struct frame *f = XFRAME (w->frame); SET_GLYPH_FROM_CHAR (right_border_glyph, 0); @@ -2599,10 +2602,10 @@ build_frame_matrix_from_leaf_window (struct glyph_matrix *frame_matrix, struct w /* Fill up the frame row with spaces up to the left margin of the window row. */ - fill_up_frame_row_with_spaces (frame_row, window_matrix->matrix_x); + fill_up_frame_row_with_spaces (f, frame_row, window_matrix->matrix_x); /* Fill up areas in the window matrix row with spaces. */ - fill_up_glyph_row_with_spaces (window_row); + fill_up_glyph_row_with_spaces (f, window_row); /* If only part of W's desired matrix has been built, and window_row wasn't displayed, use the corresponding current @@ -2638,7 +2641,7 @@ build_frame_matrix_from_leaf_window (struct glyph_matrix *frame_matrix, struct w glyph with the vertical border glyph. */ eassert (border->type == CHAR_GLYPH); border->type = CHAR_GLYPH; - SET_CHAR_GLYPH_FROM_GLYPH (*border, right_border_glyph); + SET_CHAR_GLYPH_FROM_GLYPH (f, *border, right_border_glyph); } #ifdef GLYPH_DEBUG @@ -2701,11 +2704,11 @@ spec_glyph_lookup_face (struct window *w, GLYPH *glyph) To be called for frame-based redisplay, only. */ static void -fill_up_glyph_row_with_spaces (struct glyph_row *row) +fill_up_glyph_row_with_spaces (struct frame *f, struct glyph_row *row) { - fill_up_glyph_row_area_with_spaces (row, LEFT_MARGIN_AREA); - fill_up_glyph_row_area_with_spaces (row, TEXT_AREA); - fill_up_glyph_row_area_with_spaces (row, RIGHT_MARGIN_AREA); + fill_up_glyph_row_area_with_spaces (f, row, LEFT_MARGIN_AREA); + fill_up_glyph_row_area_with_spaces (f, row, TEXT_AREA); + fill_up_glyph_row_area_with_spaces (f, row, RIGHT_MARGIN_AREA); } @@ -2713,15 +2716,19 @@ fill_up_glyph_row_with_spaces (struct glyph_row *row) frame-based redisplay only. */ static void -fill_up_glyph_row_area_with_spaces (struct glyph_row *row, int area) +fill_up_glyph_row_area_with_spaces (struct frame *f, struct glyph_row *row, + int area) { if (row->glyphs[area] < row->glyphs[area + 1]) { struct glyph *end = row->glyphs[area + 1]; struct glyph *text = row->glyphs[area] + row->used[area]; - while (text < end) - *text++ = space_glyph; + for (; text < end; ++text) + { + *text = space_glyph; + text->frame = f; + } row->used[area] = text - row->glyphs[area]; } } @@ -2731,13 +2738,16 @@ fill_up_glyph_row_area_with_spaces (struct glyph_row *row, int area) reached. In frame matrices only one area, TEXT_AREA, is used. */ void -fill_up_frame_row_with_spaces (struct glyph_row *row, int upto) +fill_up_frame_row_with_spaces (struct frame *f, struct glyph_row *row, int upto) { int i = row->used[TEXT_AREA]; struct glyph *glyph = row->glyphs[TEXT_AREA]; - while (i < upto) - glyph[i++] = space_glyph; + for (; i < upto; ++i) + { + glyph[i] = space_glyph; + glyph[i].frame = f; + } row->used[TEXT_AREA] = i; } @@ -2748,17 +2758,6 @@ fill_up_frame_row_with_spaces (struct glyph_row *row, int upto) Mirroring operations on frame matrices in window matrices **********************************************************************/ -/* Set frame being updated via frame-based redisplay to F. This - function must be called before updates to make explicit that we are - working on frame matrices or not. */ - -static void -set_frame_matrix_frame (struct frame *f) -{ - frame_matrix_frame = f; -} - - /* Make sure glyph row ROW in CURRENT_MATRIX is up to date. DESIRED_MATRIX is the desired matrix corresponding to CURRENT_MATRIX. The update is done by exchanging glyph pointers @@ -2768,9 +2767,10 @@ set_frame_matrix_frame (struct frame *f) operations in window matrices of frame_matrix_frame. */ static void -make_current (struct glyph_matrix *desired_matrix, - struct glyph_matrix *current_matrix, int row) +make_current (struct frame *f, struct window *w, int row) { + struct glyph_matrix *desired_matrix = f ? f->desired_matrix : w->desired_matrix; + struct glyph_matrix *current_matrix = f ? f->current_matrix : w->current_matrix; struct glyph_row *current_row = MATRIX_ROW (current_matrix, row); struct glyph_row *desired_row = MATRIX_ROW (desired_matrix, row); bool mouse_face_p = current_row->mouse_face_p; @@ -2797,8 +2797,8 @@ make_current (struct glyph_matrix *desired_matrix, /* If we are called on frame matrices, perform analogous operations for window matrices. */ - if (frame_matrix_frame) - mirror_make_current (XWINDOW (frame_matrix_frame->root_window), row); + if (f) + mirror_make_current (XWINDOW (f->root_window), row); } @@ -2862,9 +2862,11 @@ mirror_make_current (struct window *w, int frame_row) This function is called from do_scrolling and do_direct_scrolling. */ void -mirrored_line_dance (struct glyph_matrix *matrix, int unchanged_at_top, int nlines, +mirrored_line_dance (struct frame *f, int unchanged_at_top, int nlines, int *copy_from, char *retained_p) { + struct glyph_matrix *matrix = f->current_matrix; + /* A copy of original rows. */ struct glyph_row *old_rows; @@ -2894,9 +2896,8 @@ mirrored_line_dance (struct glyph_matrix *matrix, int unchanged_at_top, int nlin } /* Do the same for window matrices, if MATRIX is a frame matrix. */ - if (frame_matrix_frame) - mirror_line_dance (XWINDOW (frame_matrix_frame->root_window), - unchanged_at_top, nlines, copy_from, retained_p); + mirror_line_dance (XWINDOW (f->root_window), + unchanged_at_top, nlines, copy_from, retained_p); SAFE_FREE (); } @@ -3194,7 +3195,10 @@ redraw_frame (struct frame *f) future. */ SET_FRAME_GARBAGED (f); - clear_frame (f); + /* Clear_frame is actually a "clear_terminal", i.e. + is clears the entire screen. */ + if (!FRAME_PARENT_FRAME (f)) + clear_frame (f); clear_current_matrices (f); update_end (f); fset_redisplay (f); @@ -3229,145 +3233,676 @@ DEFUN ("redraw-display", Fredraw_display, Sredraw_display, 0, 0, "", return Qnil; } - +/********************************************************************** + TTY Child Frames + **********************************************************************/ + +/* The new thing that child frames on ttys provide is that frames on a + tty no longer always occupy the whole terminal. They can overlap + instead. + + Let a "root" frame be a frame that has no parent frame. Such root + frames we require to be the size of the terminal screen. The current + glyph matrix of a root frame of a termimnal represents what is on the + screen. The desired matrix of a root frame represents what should be + one the screen. + + Building the desired matrix of root frame proceeds by + + - building the desired matrix of the root frame itself which is + the bottommost frame in z-order, + - building desired matrices of child frames in z-order, topmost last, + - copying the desired glyphs from child frames to the desired glyphs + of the root frame + + Updating the screen is then done using root frame matrices as it was + before child frames were introduced. Child frame current matrices are + updated by copying glyph contents of the current matrix of the root + frames to the current matrices of child frames. This imnplicitly + also updates the glyph contents of their windows' current matrices. */ + +struct rect +{ + int x, y, w, h; +}; + +/* Compute the intersection of R1 and R2 in R. Value is true if R1 and + R2 intersect, false otherwise. */ + +static bool +rect_intersect (struct rect *r, struct rect r1, struct rect r2) +{ + int x1 = max (r1.x, r2.x); + int x2 = min (r1.x + r1.w, r2.x + r2.w); + if (x2 < x1) + return false; + int y1 = max (r1.y, r2.y); + int y2 = min (r1.y + r1.h, r2.y + r2.h); + if (y2 < y1) + return false; + *r = (struct rect) { .x = x1, .y = y1, .w = x2 - x1, .h = y2 - y1 }; + return true; +} + +/* Return the absolute position of frame F in *X and *Y. */ + +static void +frame_pos_abs (struct frame *f, int *x, int *y) +{ + *x = *y = 0; + for (; f; f = FRAME_PARENT_FRAME (f)) + { + *x += f->left_pos; + *y += f->top_pos; + } +} + +/* Return the rectangle frame F occupies. X and Y are in absolute coordinates. */ + +static struct rect +frame_rect_abs (struct frame *f) +{ + int x, y; + frame_pos_abs (f, &x, &y); + return (struct rect) { x, y, f->total_cols, f->total_lines }; +} + +/* Return the root frame of frame F. Follow the parent_frame chain until + we reach a frame that has no parent. That is the root frame. Note + that the root of a root frame is itself. */ + +struct frame * +root_frame (struct frame *f) +{ + while (FRAME_PARENT_FRAME (f)) + f = FRAME_PARENT_FRAME (f); + return f; +} + +int +max_child_z_order (struct frame *parent) +{ + Lisp_Object tail, frame; + int z_order = 0; + FOR_EACH_FRAME (tail, frame) + { + struct frame *f = XFRAME (frame); + if (FRAME_PARENT_FRAME (f) == parent) + z_order = max (z_order, f->z_order); + } + return z_order; +} + +/* Return true if F1 is an ancestor of F2. */ + +static bool +is_frame_ancestor (struct frame *f1, struct frame *f2) +{ + for (struct frame *f = FRAME_PARENT_FRAME (f2); f; f = FRAME_PARENT_FRAME (f)) + if (f == f1) + return true; + return false; +} + +/* Return a list of all frames having root frame ROOT. + If VISIBLE_ONLY is true, return only visible frames. */ + +static Lisp_Object +frames_with_root (struct frame *root, bool visible_only) +{ + Lisp_Object list = Qnil; + Lisp_Object tail, frame; + FOR_EACH_FRAME (tail, frame) + { + struct frame *f = XFRAME (frame); + if (root_frame (f) == root + && (!visible_only || FRAME_VISIBLE_P (f))) + list = Fcons (frame, list); + } + return list; +} + +/* Return a list of frames having parent frame PARENT. + If VISIBLE_ONLY is true, return only visible frames. */ + +static Lisp_Object +frames_with_parent (struct frame *parent, bool visible_only) +{ + Lisp_Object list = Qnil; + Lisp_Object tail, frame; + FOR_EACH_FRAME (tail, frame) + { + struct frame *f = XFRAME (frame); + if (FRAME_PARENT_FRAME (f) == parent + && (!visible_only || FRAME_VISIBLE_P (f))) + list = Fcons (frame, list); + } + return list; +} + +/* Compare frames F1 and F2 for z-order. Value is like strcmp. */ + +static int +frame_z_order_cmp (struct frame *f1, struct frame *f2) +{ + if (f1 == f2) + return 0; + if (is_frame_ancestor (f1, f2)) + return -1; + if (is_frame_ancestor (f2, f1)) + return 1; + return f1->z_order - f2->z_order; +} + +DEFUN ("frame--z-order-lessp", Fframe__z_order_lessp, Sframe__z_order_lessp, + 2, 2, 0, doc: /* Internal frame sorting function A < B. */) + (Lisp_Object a, Lisp_Object b) +{ + eassert (FRAMEP (a) && FRAMEP (b)); + return frame_z_order_cmp (XFRAME (a), XFRAME (b)) < 0 ? Qt : Qnil; +} + +/* Return a z-order list of frames with the same root as F. The list + is ordered topmost frame last. Note that this list contains + the root frame of F itself as first element. */ + +Lisp_Object +frames_in_reverse_z_order (struct frame *f, bool visible_only) +{ + struct frame *root = root_frame (f); + Lisp_Object frames = frames_with_root (root, visible_only); + frames = CALLN (Fsort, frames, QClessp, Qframe__z_order_lessp); + eassert (FRAMEP (XCAR (frames))); + eassert (XFRAME (XCAR (frames)) == root); + return frames; +} + +/* Raise of lower frame F in z-order. If RAISE is true, raise F, else + lower f. */ + +void +tty_raise_lower_frame (struct frame *f, bool raise) +{ + struct frame *parent = FRAME_PARENT_FRAME (f); + if (parent == NULL) + return; + + Lisp_Object siblings = frames_with_parent (parent, false); + siblings = CALLN (Fsort, siblings, QClessp, Qframe__z_order_lessp); + + int i = 0; + for (Lisp_Object tail = siblings; CONSP (tail); tail = XCDR (tail)) + { + struct frame *child = XFRAME (XCAR (tail)); + if (child != f) + child->z_order = i++; + } + f->z_order = raise ? i : 0; +} + +/* Return true if frame F is a tty frame. */ + +bool +is_tty_frame (struct frame *f) +{ + return FRAME_TERMCAP_P (f); +} + +/* Return true if frame F is a tty child frame. */ + +bool +is_tty_child_frame (struct frame *f) +{ + return FRAME_PARENT_FRAME (f) && is_tty_frame (f); +} + +/* Return true if frame F is a tty root frame. */ + +bool +is_tty_root_frame (struct frame *f) +{ + return !FRAME_PARENT_FRAME (f) && is_tty_frame (f); +} + +/* Return the index of the first enabled row in MATRIX, or -1 if there + is none. */ + +static int +first_enabled_row (struct glyph_matrix *matrix) +{ + for (int i = 0; i < matrix->nrows; ++i) + if (MATRIX_ROW_ENABLED_P (matrix, i)) + return i; + return -1; +} + +/* On tty frame F, make desired matrix current, without writing + to the terminal. */ + +static void +make_matrix_current (struct frame *f) +{ + int first_row = first_enabled_row (f->desired_matrix); + if (first_row >= 0) + for (int i = first_row; i < f->desired_matrix->nrows; ++i) + if (MATRIX_ROW_ENABLED_P (f->desired_matrix, i)) + make_current (f, NULL, i); +} + +/* Prepare ROOT's desired row at index Y for copying child + frame contents to it. */ + +static struct glyph_row * +prepare_desired_root_row (struct frame *root, int y) +{ + /* Start with the root's desired matrix row. If that hasn't + been redisplayed, copy from the root's current matrix. */ + struct glyph_row *root_row = MATRIX_ROW (root->desired_matrix, y); + if (!root_row->enabled_p) + { + struct glyph_row *from = MATRIX_ROW (root->current_matrix, y); + memcpy (root_row->glyphs[0], from->glyphs[0], + root->current_matrix->matrix_w * sizeof (struct glyph)); + root_row->enabled_p = true; + } + return root_row; +} + +/* Produce glyphs for box character BOX in ROW. X ist the position in ROW + where to start producing glyphs. N is the number of glyphs to produce. + CHILD is the frame to use for the face of the glyphs. */ + +static void +produce_box_glyphs (enum box box, struct glyph_row *row, int x, int n, + struct frame *child) +{ + int dflt; + switch (box) + { + case BOX_VERTICAL: + dflt = '|'; + break; + case BOX_HORIZONTAL: + dflt = '-'; + break; + case BOX_DOWN_RIGHT: + case BOX_DOWN_LEFT: + case BOX_UP_RIGHT: + case BOX_UP_LEFT: + dflt = '+'; + break; + } + + // FIXME/tty some face for the border. + int face_id = BORDER_FACE_ID; + GLYPH g; + SET_GLYPH (g, dflt, face_id); + + if (DISP_TABLE_P (Vstandard_display_table)) + { + struct Lisp_Char_Table *dp = XCHAR_TABLE (Vstandard_display_table); + Lisp_Object gc = dp->extras[box]; + if (GLYPH_CODE_P (gc)) + { + SET_GLYPH_FROM_GLYPH_CODE (g, gc); + /* Sorry, but I really don't care if the glyph has a face :-). */ + } + } + + struct glyph *glyph = row->glyphs[0] + x; + for (int i = 0; i < n; ++i, ++glyph) + { + glyph->type = CHAR_GLYPH; + glyph->u.ch = GLYPH_CHAR (g); + glyph->charpos = -1; + glyph->pixel_width = 1; + glyph->multibyte_p = 1; + glyph->face_id = GLYPH_FACE (g); + glyph->frame = child; + glyph->multibyte_p = 1; + glyph->object = Qnil; + } +} + +/* Produce box glyphs LEFT and RIGHT in ROOT_ROW. X and W are the start + and width of a range in ROOT_ROW before and after which to put the + box glyphs, if they fit. ROOT and CHILD are root and child frame we + are working on. ROOT is the root frame whose matrix dimensions + determines if the box glyphs fit. CHILD is the frame whose faces to + use for the box glyphs. */ + +static void +produce_box_sides (enum box left, enum box right, struct glyph_row *root_row, int x, + int w, struct frame *root, struct frame *child) +{ + if (x > 0) + produce_box_glyphs (left, root_row, x - 1, 1, child); + if (x + w < root->desired_matrix->matrix_w) + produce_box_glyphs (right, root_row, x + w, 1, child); +} + +static void +produce_box_line (struct frame *root, struct frame *child, int x, int y, int w, + bool first) +{ + struct glyph_row *root_row = prepare_desired_root_row (root, y); + if (first) + produce_box_sides (BOX_DOWN_RIGHT, BOX_DOWN_LEFT, root_row, x, w, root, child); + else + produce_box_sides (BOX_UP_RIGHT, BOX_UP_LEFT, root_row, x, w, root, child); + produce_box_glyphs (BOX_HORIZONTAL, root_row, x, w, child); + root_row->hash = row_hash (root_row); +} + +/* Copy to ROOT's desired matrix what we need from CHILD. */ + +static void +copy_child_glyphs (struct frame *root, struct frame *child) +{ + eassert (!FRAME_PARENT_FRAME (root)); + eassert (is_frame_ancestor (root, child)); + + /* Determine the intersection of the child frame rectangle with + the root frame. This is basically clipping the child frame to + the root frame rectangle. */ + struct rect r; + if (!rect_intersect (&r, frame_rect_abs (root), frame_rect_abs (child))) + return; + + /* Build CHILD's current matrix which we need to copy from it. */ + make_matrix_current (child); + + /* Draw borders around the child frame. */ + if (!FRAME_UNDECORATED (child)) + { + /* Horizontal line above. */ + if (r.y > 0) + produce_box_line (root, child, r.x, r.y - 1, r.w, true); + + for (int y = r.y; y < r.y + r.h; ++y) + { + struct glyph_row *root_row = prepare_desired_root_row (root, y); + produce_box_sides (BOX_VERTICAL, BOX_VERTICAL, root_row, r.x, r.w, + root, child); + } + + /* Horizontal line below */ + if (r.y + r.h < root->desired_matrix->matrix_h) + produce_box_line (root, child, r.x, r.y + r.h, r.w, false); + } + + /* First visible row/col, relative to the child frame. */ + int child_x = child->left_pos < 0 ? - child->left_pos : 0; + int child_y = child->top_pos < 0 ? - child->top_pos : 0; + + /* For all rows in the intersection, copy glyphs from the child's + current matrix to the root's desired matrix, enabling those + rows if they aren't already. */ + for (int y = r.y; y < r.y + r.h; ++y, ++child_y) + { + struct glyph_row *root_row = prepare_desired_root_row (root, y); + + /* Copy what's visible from the child's current row. */ + struct glyph_row *child_row = MATRIX_ROW (child->current_matrix, child_y); + memcpy (root_row->glyphs[0] + r.x, child_row->glyphs[0] + child_x, + r.w * sizeof (struct glyph)); + + /* Compute a new hash since we changed glyphs. */ + root_row->hash = row_hash (root_row); + } +} + /*********************************************************************** Frame Update ***********************************************************************/ +/* Update the menu bar on X frames that don't have toolkit + support. */ + +static void +update_menu_bar (struct frame *f) +{ +#if defined HAVE_WINDOW_SYSTEM && !defined HAVE_EXT_MENU_BAR + if (WINDOWP (f->menu_bar_window)) + update_window (XWINDOW (f->menu_bar_window), true); +#endif +} + +#ifdef HAVE_WINDOW_SYSTEM +static void +update_bar_window (Lisp_Object window, Lisp_Object *current, + Lisp_Object *desired) +{ + if (WINDOWP (window)) + { + struct window *w = XWINDOW (window); + if (w->must_be_updated_p) + { + update_window (w, true); + w->must_be_updated_p = false; + Lisp_Object tem = *current; + *current = *desired; + *desired = tem; + } + } +} +#endif + +/* Update the tab-bar window of frame F, if present. */ + +static void +update_tab_bar (struct frame *f) +{ +#if defined(HAVE_WINDOW_SYSTEM) + update_bar_window (f->tab_bar_window, &f->current_tab_bar_string, + &f->desired_tab_bar_string); +#endif +} + +static void +update_tool_bar (struct frame *f) +{ +#if defined(HAVE_WINDOW_SYSTEM) && !defined(HAVE_EXT_TOOL_BAR) + update_bar_window (f->tool_bar_window, &f->current_tool_bar_string, + &f->desired_tool_bar_string); +#endif +} + +static bool +update_window_frame (struct frame *f, bool force_p) +{ + eassert (FRAME_WINDOW_P (f)); + update_begin (f); + update_menu_bar (f); + update_tab_bar (f); + update_tool_bar (f); + struct window *root_window = XWINDOW (f->root_window); + bool paused_p = update_window_tree (root_window, force_p); + update_end (f); + set_window_update_flags (root_window, false); + return paused_p; +} + +static bool +update_initial_frame (struct frame *f, bool force_p) +{ + build_frame_matrix (f); + struct window *root_window = XWINDOW (f->root_window); + set_window_update_flags (root_window, false); + return false; +} + +static void +flush_terminal (struct frame *f) +{ + if (FRAME_TTY (f)->termscript) + fflush (FRAME_TTY (f)->termscript); + fflush (FRAME_TTY (f)->output); +} + +static bool +update_tty_frame (struct frame *f, bool force_p) +{ + build_frame_matrix (f); + return false; +} + +static void +abs_cursor_pos (struct frame *f, int *x, int *y) +{ + frame_pos_abs (f, x, y); + struct window *w = XWINDOW (f->selected_window); + *x += w->cursor.x; + *y += w->cursor.y; +} + +/* Is the terminal cursor of frame F obscured by a child frame? */ + +static bool +is_cursor_obscured (void) +{ + int x, y; + abs_cursor_pos (SELECTED_FRAME (), &x, &y); + struct frame *root = root_frame (SELECTED_FRAME ()); + struct glyph_row *cursor_row = MATRIX_ROW (root->current_matrix, y); + eassert (x < root->current_matrix->matrix_w); + struct glyph *cursor_glyph = cursor_row->glyphs[0] + x; + return cursor_glyph->frame != SELECTED_FRAME (); +} + +/* Decide where to show the cursor, and if to hide it or not. + + This works very well for Vertico-Posframe, Transient-Posframe and + Corfu, but it's debatable if it's the right thing for a general use + of child frames of all sorts, nested and so on. But it is also debatable + if that's a realistic use case from my POV. */ + +static void +terminal_cursor_magic (struct frame *root, struct frame *topmost_child) +{ + /* By default, prevent the cursor "shining through" child frames. */ + if (is_cursor_obscured ()) + tty_hide_cursor (FRAME_TTY (root)); + + /* If the terminal cursor is not in the topmost child, the topmost + child's tty-cursor-if-topmost determines what to do. If it is + non-nil, display the cursor in this "non-selected" topmost child + frame to compensate for the fact that we can't display a + non-selected cursor like on a window system frame. */ + if (topmost_child != SELECTED_FRAME ()) + { + Lisp_Object frame; + XSETFRAME (frame, topmost_child); + + Lisp_Object cursor = Fframe_parameter (frame, Qtty_non_selected_cursor); + if (!NILP (cursor)) + { + int x, y; + abs_cursor_pos (topmost_child, &x, &y); + cursor_to (root, y, x); + tty_show_cursor (FRAME_TTY (topmost_child)); + } + } +} + +bool +combine_updates_for_frame (struct frame *f, bool force_p, bool inhibit_scrolling) +{ + struct frame *root = root_frame (f); + eassert (FRAME_VISIBLE_P (root)); + + /* Process child frames in reverse z-order, topmost last. For each + child, copy what we need to the root's desired matrix. */ + Lisp_Object z_order = frames_in_reverse_z_order (root, true); + struct frame *topmost_child = NULL; + for (Lisp_Object tail = XCDR (z_order); CONSP (tail); tail = XCDR (tail)) + { + topmost_child = XFRAME (XCAR (tail)); + copy_child_glyphs (root, topmost_child); + } + + update_begin (root); + bool paused = write_matrix (root, force_p, inhibit_scrolling, 1, false); + if (!paused) + make_matrix_current (root); + update_end (root); + + /* If a child is displayed, and the cursor is displayed in another + frame, the child might lay above the cursor, so that it appers to + "shine through" the child. Avoid that because it's confusing. */ + if (topmost_child) + terminal_cursor_magic (root, topmost_child); + flush_terminal (root); + + for (Lisp_Object tail = z_order; CONSP (tail); tail = XCDR (tail)) + { + struct frame *f = XFRAME (XCAR (tail)); + struct window *root_window = XWINDOW (f->root_window); + set_window_update_flags (root_window, false); + clear_desired_matrices (f); +#ifdef GLYPH_DEBUG + check_window_matrix_pointers (root_window); + add_frame_display_history (f, false); +#endif + } + + return paused; +} + +/* Update on the screen all root frames ROOTS. Called from + redisplay_internal as the last step of redisplaying. */ + +bool +combine_updates (Lisp_Object roots, bool force_p, bool inhibit_scrolling) +{ + for (; CONSP (roots); roots = XCDR (roots)) + { + struct frame *root = XFRAME (XCAR (roots)); + if (combine_updates_for_frame (root, force_p, inhibit_scrolling)) + { + display_completed = false; + return true; + } + } + + display_completed = true; + return false; +} + /* Update frame F based on the data in desired matrices. If FORCE_P, don't let redisplay be stopped by detecting pending input. - If INHIBIT_HAIRY_ID_P, don't try scrolling. + If INHIBIT_SCROLLING, don't try scrolling. Value is true if redisplay was stopped due to pending input. */ bool -update_frame (struct frame *f, bool force_p, bool inhibit_hairy_id_p) +update_frame (struct frame *f, bool force_p, bool inhibit_scrolling) { - /* True means display has been paused because of pending input. */ - bool paused_p; struct window *root_window = XWINDOW (f->root_window); if (redisplay_dont_pause) force_p = true; else if (!force_p && detect_input_pending_ignore_squeezables ()) { - paused_p = true; - goto do_pause; + /* Reset flags indicating that a window should be updated. */ + set_window_update_flags (root_window, false); + display_completed = false; + return true; } + bool paused; if (FRAME_WINDOW_P (f)) - { - /* We are working on window matrix basis. All windows whose - flag must_be_updated_p is set have to be updated. */ - - /* Record that we are not working on frame matrices. */ - set_frame_matrix_frame (NULL); - - /* Update all windows in the window tree of F, maybe stopping - when pending input is detected. */ - update_begin (f); - -#if defined HAVE_WINDOW_SYSTEM && !defined HAVE_EXT_MENU_BAR - /* Update the menu bar on X frames that don't have toolkit - support. */ - if (WINDOWP (f->menu_bar_window)) - update_window (XWINDOW (f->menu_bar_window), true); -#endif - -#if defined (HAVE_WINDOW_SYSTEM) - /* Update the tab-bar window, if present. */ - if (WINDOWP (f->tab_bar_window)) - { - struct window *w = XWINDOW (f->tab_bar_window); - - /* Update tab-bar window. */ - if (w->must_be_updated_p) - { - Lisp_Object tem; - - update_window (w, true); - w->must_be_updated_p = false; - - /* Swap tab-bar strings. We swap because we want to - reuse strings. */ - tem = f->current_tab_bar_string; - fset_current_tab_bar_string (f, f->desired_tab_bar_string); - fset_desired_tab_bar_string (f, tem); - } - } -#endif - -#if defined (HAVE_WINDOW_SYSTEM) && ! defined (HAVE_EXT_TOOL_BAR) - /* Update the tool-bar window, if present. */ - if (WINDOWP (f->tool_bar_window)) - { - struct window *w = XWINDOW (f->tool_bar_window); - - /* Update tool-bar window. */ - if (w->must_be_updated_p) - { - Lisp_Object tem; - - update_window (w, true); - w->must_be_updated_p = false; - - /* Swap tool-bar strings. We swap because we want to - reuse strings. */ - tem = f->current_tool_bar_string; - fset_current_tool_bar_string (f, f->desired_tool_bar_string); - fset_desired_tool_bar_string (f, tem); - } - } -#endif - - /* Update windows. */ - paused_p = update_window_tree (root_window, force_p); - update_end (f); - } + paused = update_window_frame (f, force_p); + else if (FRAME_INITIAL_P (f)) + paused = update_initial_frame (f, force_p); else - { - /* We are working on frame matrix basis. Set the frame on whose - frame matrix we operate. */ - set_frame_matrix_frame (f); + paused = update_tty_frame (f, force_p); - /* Build F's desired matrix from window matrices. */ - build_frame_matrix (f); - - /* Update the display. */ - if (FRAME_INITIAL_P (f)) - /* No actual display to update so the "update" is a nop and - obviously isn't interrupted by pending input. */ - paused_p = false; - else - { - update_begin (f); - paused_p = update_frame_1 (f, force_p, inhibit_hairy_id_p, 1, false); - update_end (f); - } - - if (FRAME_TERMCAP_P (f) || FRAME_MSDOS_P (f)) - { - if (FRAME_TTY (f)->termscript) - fflush (FRAME_TTY (f)->termscript); - if (FRAME_TERMCAP_P (f)) - fflush (FRAME_TTY (f)->output); - } - - /* Check window matrices for lost pointers. */ -#ifdef GLYPH_DEBUG - check_window_matrix_pointers (root_window); - add_frame_display_history (f, paused_p); -#endif - } - - do_pause: - /* Reset flags indicating that a window should be updated. */ - set_window_update_flags (root_window, false); - - display_completed = !paused_p; - return paused_p; + if (paused) + display_completed = false; + return paused; } /* Update a TTY frame F that has a menu dropped down over some of its @@ -3384,29 +3919,25 @@ void update_frame_with_menu (struct frame *f, int row, int col) { struct window *root_window = XWINDOW (f->root_window); - bool paused_p, cursor_at_point_p; + bool cursor_at_point_p; eassert (FRAME_TERMCAP_P (f)); - /* We are working on frame matrix basis. Set the frame on whose - frame matrix we operate. */ - set_frame_matrix_frame (f); - /* Update the display. */ update_begin (f); cursor_at_point_p = !(row >= 0 && col >= 0); - /* Force update_frame_1 not to stop due to pending input, and not - try scrolling. */ - paused_p = update_frame_1 (f, 1, 1, cursor_at_point_p, true); + /* Do not stop due to pending input, and do not try scrolling. This + means that write_glyphs will always return false. */ + write_matrix (f, 1, 1, cursor_at_point_p, true); + make_matrix_current (f); + clear_desired_matrices (f); /* ROW and COL tell us where in the menu to position the cursor, so that screen readers know the active region on the screen. */ if (!cursor_at_point_p) cursor_to (f, row, col); update_end (f); + flush_terminal (f); - if (FRAME_TTY (f)->termscript) - fflush (FRAME_TTY (f)->termscript); - fflush (FRAME_TTY (f)->output); /* Check window matrices for lost pointers. */ #if GLYPH_DEBUG #if 0 @@ -3415,12 +3946,12 @@ update_frame_with_menu (struct frame *f, int row, int col) making any updates to the window matrices. */ check_window_matrix_pointers (root_window); #endif - add_frame_display_history (f, paused_p); + add_frame_display_history (f, false); #endif /* Reset flags indicating that a window should be updated. */ set_window_update_flags (root_window, false); - display_completed = !paused_p; + display_completed = true; } /* Update the mouse position for a frame F. This handles both @@ -3453,19 +3984,20 @@ update_mouse_position (struct frame *f, int x, int y) } DEFUN ("display--update-for-mouse-movement", Fdisplay__update_for_mouse_movement, - Sdisplay__update_for_mouse_movement, 2, 2, 0, + Sdisplay__update_for_mouse_movement, 3, 3, 0, doc: /* Handle mouse movement detected by Lisp code. This function should be called when Lisp code detects the mouse has moved, even if `track-mouse' is nil. This handles updates that do not rely on input events such as updating display for mouse-face properties or updating the help echo text. */) - (Lisp_Object mouse_x, Lisp_Object mouse_y) + (Lisp_Object mouse_frame, Lisp_Object mouse_x, Lisp_Object mouse_y) { + CHECK_FRAME (mouse_frame); CHECK_FIXNUM (mouse_x); CHECK_FIXNUM (mouse_y); - update_mouse_position (SELECTED_FRAME (), XFIXNUM (mouse_x), + update_mouse_position (XFRAME (mouse_frame), XFIXNUM (mouse_x), XFIXNUM (mouse_y)); return Qnil; } @@ -3507,9 +4039,6 @@ update_single_window (struct window *w) { struct frame *f = XFRAME (WINDOW_FRAME (w)); - /* Record that this is not a frame-based redisplay. */ - set_frame_matrix_frame (NULL); - /* Update W. */ update_begin (f); update_window (w, true); @@ -3688,6 +4217,8 @@ update_window (struct window *w, bool force_p) #ifdef HAVE_WINDOW_SYSTEM gui_update_window_begin (w); +#else + (void) changed_p; #endif yb = window_text_bottom_y (w); row = MATRIX_ROW (desired_matrix, 0); @@ -4321,7 +4852,7 @@ update_window_line (struct window *w, int vpos, bool *mouse_face_overwritten_p) /* Update current_row from desired_row. */ was_stipple = current_row->stipple_p; - make_current (w->desired_matrix, w->current_matrix, vpos); + make_current (NULL, w, vpos); /* If only a partial update was performed, any stipple already displayed in MATRIX_ROW (w->current_matrix, vpos) might still be @@ -4931,7 +5462,92 @@ scrolling_window (struct window *w, int tab_line_p) Frame-Based Updates ************************************************************************/ -/* Update the desired frame matrix of frame F. +static void +tty_set_cursor (void) +{ + struct frame *f = SELECTED_FRAME (); + + if ((cursor_in_echo_area + /* If we are showing a message instead of the mini-buffer, + show the cursor for the message instead of for the + (now hidden) mini-buffer contents. */ + || (BASE_EQ (minibuf_window, selected_window) + && BASE_EQ (minibuf_window, echo_area_window) + && !NILP (echo_area_buffer[0]))) + /* These cases apply only to the frame that contains + the active mini-buffer window. */ + && FRAME_HAS_MINIBUF_P (f) + && BASE_EQ (FRAME_MINIBUF_WINDOW (f), echo_area_window)) + { + int top = WINDOW_TOP_EDGE_LINE (XWINDOW (FRAME_MINIBUF_WINDOW (f))); + int col; + + /* Put cursor at the end of the prompt. If the mini-buffer + is several lines high, find the last line that has + any text on it. */ + int row = FRAME_TOTAL_LINES (f); + do + { + row--; + col = 0; + + if (MATRIX_ROW_ENABLED_P (f->current_matrix, row)) + { + /* Frame rows are filled up with spaces that + must be ignored here. */ + struct glyph_row *r = MATRIX_ROW (f->current_matrix, row); + struct glyph *start = r->glyphs[TEXT_AREA]; + + col = r->used[TEXT_AREA]; + while (0 < col && start[col - 1].charpos < 0) + col--; + } + } + while (row > top && col == 0); + + /* We exit the loop with COL at the glyph _after_ the last one. */ + if (col > 0) + col--; + + /* Make sure COL is not out of range. */ + if (col >= FRAME_CURSOR_X_LIMIT (f)) + { + /* If we have another row, advance cursor into it. */ + if (row < FRAME_TOTAL_LINES (f) - 1) + { + col = FRAME_LEFT_SCROLL_BAR_COLS (f); + row++; + } + /* Otherwise move it back in range. */ + else + col = FRAME_CURSOR_X_LIMIT (f) - 1; + } + + cursor_to (f, row, col); + } + else + { + /* We have only one cursor on terminal frames. Use it to + display the cursor of the selected window. */ + struct window *w = XWINDOW (FRAME_SELECTED_WINDOW (f)); + if (w->cursor.vpos >= 0 + /* The cursor vpos may be temporarily out of bounds + in the following situation: There is one window, + with the cursor in the lower half of it. The window + is split, and a message causes a redisplay before + a new cursor position has been computed. */ + && w->cursor.vpos < WINDOW_TOTAL_LINES (w)) + { + int x = WINDOW_TO_FRAME_HPOS (w, w->cursor.hpos); + int y = WINDOW_TO_FRAME_VPOS (w, w->cursor.vpos); + + x += max (0, w->left_margin_cols); + cursor_to (f, y, x); + } + } +} + +/* Write desired matix of tty frame F and make it current. FORCE_P means that the update should not be stopped by pending input. INHIBIT_ID_P means that scrolling by insert/delete should not be tried. @@ -4940,167 +5556,58 @@ scrolling_window (struct window *w, int tab_line_p) Value is true if update was stopped due to pending input. */ static bool -update_frame_1 (struct frame *f, bool force_p, bool inhibit_id_p, - bool set_cursor_p, bool updating_menu_p) +write_matrix (struct frame *f, bool force_p, bool inhibit_id_p, + bool set_cursor_p, bool updating_menu_p) { - /* Frame matrices to work on. */ - struct glyph_matrix *current_matrix = f->current_matrix; - struct glyph_matrix *desired_matrix = f->desired_matrix; - int i; - bool pause_p; - int preempt_count = clip_to_bounds (1, baud_rate / 2400 + 1, INT_MAX); + if (!force_p && detect_input_pending_ignore_squeezables ()) + return true; - eassert (current_matrix && desired_matrix); + /* If we cannot insert/delete lines, it's no use trying it. */ + if (!FRAME_LINE_INS_DEL_OK (f)) + inhibit_id_p = true; if (baud_rate != FRAME_COST_BAUD_RATE (f)) calculate_costs (f); - if (!force_p && detect_input_pending_ignore_squeezables ()) - { - pause_p = 1; - goto do_pause; - } - - /* If we cannot insert/delete lines, it's no use trying it. */ - if (!FRAME_LINE_INS_DEL_OK (f)) - inhibit_id_p = 1; - - /* See if any of the desired lines are enabled; don't compute for + /* See if any of the desired lines are enabled; don't compute for i/d line if just want cursor motion. */ - for (i = 0; i < desired_matrix->nrows; i++) - if (MATRIX_ROW_ENABLED_P (desired_matrix, i)) - break; - - /* Try doing i/d line, if not yet inhibited. */ - if (!inhibit_id_p && i < desired_matrix->nrows) + int first_row = first_enabled_row (f->desired_matrix); + if (!inhibit_id_p && first_row >= 0) force_p |= scrolling (f); - /* Update the individual lines as needed. Do bottom line first. */ - if (MATRIX_ROW_ENABLED_P (desired_matrix, desired_matrix->nrows - 1)) - update_frame_line (f, desired_matrix->nrows - 1, updating_menu_p); + /* Update the individual lines as needed. Do bottom line first. This + is done so that messages are made visible when pausing. */ + int last_row = f->desired_matrix->nrows - 1; + if (MATRIX_ROW_ENABLED_P (f->desired_matrix, last_row)) + write_row (f, last_row, updating_menu_p); - /* Now update the rest of the lines. */ - for (i = 0; i < desired_matrix->nrows - 1 && (force_p || !input_pending); i++) + bool pause_p = false; + if (first_row >= 0) { - if (MATRIX_ROW_ENABLED_P (desired_matrix, i)) - { - /* Note that output_buffer_size being 0 means that we want the - old default behavior of flushing output every now and then. */ - if (FRAME_TERMCAP_P (f) && FRAME_TTY (f)->output_buffer_size == 0) - { - /* Flush out every so many lines. - Also flush out if likely to have more than 1k buffered - otherwise. I'm told that some telnet connections get - really screwed by more than 1k output at once. */ - FILE *display_output = FRAME_TTY (f)->output; - if (display_output) - { - ptrdiff_t outq = __fpending (display_output); - if (outq > 900 - || (outq > 20 && ((i - 1) % preempt_count == 0))) - fflush (display_output); - } - } + const int preempt_count = clip_to_bounds (1, baud_rate / 2400 + 1, INT_MAX); - if (!force_p && (i - 1) % preempt_count == 0) - detect_input_pending_ignore_squeezables (); + for (int i = first_row, n = 0; i < last_row; ++i) + if (MATRIX_ROW_ENABLED_P (f->desired_matrix, i)) + { + if (!force_p && n % preempt_count == 0 + && detect_input_pending_ignore_squeezables ()) + { + pause_p = true; + break; + } - update_frame_line (f, i, updating_menu_p); - } + write_row (f, i, updating_menu_p); + ++n; + } } - pause_p = 0 < i && i < FRAME_TOTAL_LINES (f) - 1; - /* Now just clean up termcap drivers and set cursor, etc. */ if (!pause_p && set_cursor_p) - { - if ((cursor_in_echo_area - /* If we are showing a message instead of the mini-buffer, - show the cursor for the message instead of for the - (now hidden) mini-buffer contents. */ - || (BASE_EQ (minibuf_window, selected_window) - && BASE_EQ (minibuf_window, echo_area_window) - && !NILP (echo_area_buffer[0]))) - /* These cases apply only to the frame that contains - the active mini-buffer window. */ - && FRAME_HAS_MINIBUF_P (f) - && BASE_EQ (FRAME_MINIBUF_WINDOW (f), echo_area_window)) - { - int top = WINDOW_TOP_EDGE_LINE (XWINDOW (FRAME_MINIBUF_WINDOW (f))); - int col; + tty_set_cursor (); - /* Put cursor at the end of the prompt. If the mini-buffer - is several lines high, find the last line that has - any text on it. */ - int row = FRAME_TOTAL_LINES (f); - do - { - row--; - col = 0; - - if (MATRIX_ROW_ENABLED_P (current_matrix, row)) - { - /* Frame rows are filled up with spaces that - must be ignored here. */ - struct glyph_row *r = MATRIX_ROW (current_matrix, row); - struct glyph *start = r->glyphs[TEXT_AREA]; - - col = r->used[TEXT_AREA]; - while (0 < col && start[col - 1].charpos < 0) - col--; - } - } - while (row > top && col == 0); - - /* We exit the loop with COL at the glyph _after_ the last one. */ - if (col > 0) - col--; - - /* Make sure COL is not out of range. */ - if (col >= FRAME_CURSOR_X_LIMIT (f)) - { - /* If we have another row, advance cursor into it. */ - if (row < FRAME_TOTAL_LINES (f) - 1) - { - col = FRAME_LEFT_SCROLL_BAR_COLS (f); - row++; - } - /* Otherwise move it back in range. */ - else - col = FRAME_CURSOR_X_LIMIT (f) - 1; - } - - cursor_to (f, row, col); - } - else - { - /* We have only one cursor on terminal frames. Use it to - display the cursor of the selected window. */ - struct window *w = XWINDOW (FRAME_SELECTED_WINDOW (f)); - if (w->cursor.vpos >= 0 - /* The cursor vpos may be temporarily out of bounds - in the following situation: There is one window, - with the cursor in the lower half of it. The window - is split, and a message causes a redisplay before - a new cursor position has been computed. */ - && w->cursor.vpos < WINDOW_TOTAL_LINES (w)) - { - int x = WINDOW_TO_FRAME_HPOS (w, w->cursor.hpos); - int y = WINDOW_TO_FRAME_VPOS (w, w->cursor.vpos); - - x += max (0, w->left_margin_cols); - cursor_to (f, y, x); - } - } - } - - do_pause: - - clear_desired_matrices (f); return pause_p; } - /* Do line insertions/deletions on frame F for frame-based redisplay. */ static bool @@ -5209,12 +5716,12 @@ scrolling (struct frame *frame) which is LEN glyphs long. */ static int -count_blanks (struct glyph *r, int len) +count_blanks (struct frame *f, struct glyph *r, int len) { int i; for (i = 0; i < len; ++i) - if (!CHAR_GLYPH_SPACE_P (r[i])) + if (!CHAR_GLYPH_SPACE_P (f, r[i])) break; return i; @@ -5250,7 +5757,7 @@ count_match (struct glyph *str1, struct glyph *end1, struct glyph *str2, struct /* Perform a frame-based update on line VPOS in frame FRAME. */ static void -update_frame_line (struct frame *f, int vpos, bool updating_menu_p) +write_row (struct frame *f, int vpos, bool updating_menu_p) { struct glyph *obody, *nbody, *op1, *op2, *np1, *nend; int tem; @@ -5264,11 +5771,6 @@ update_frame_line (struct frame *f, int vpos, bool updating_menu_p) bool colored_spaces_p = (FACE_FROM_ID (f, DEFAULT_FACE_ID)->background != FACE_TTY_DEFAULT_BG_COLOR); - /* This should never happen, but evidently sometimes does if one - resizes the frame quickly enough. Prevent aborts in cmcheckmagic. */ - if (vpos >= FRAME_TOTAL_LINES (f)) - return; - if (colored_spaces_p) write_spaces_p = 1; @@ -5287,7 +5789,7 @@ update_frame_line (struct frame *f, int vpos, bool updating_menu_p) /* Ignore trailing spaces, if we can. */ if (!write_spaces_p) - while (olen > 0 && CHAR_GLYPH_SPACE_P (obody[olen-1])) + while (olen > 0 && CHAR_GLYPH_SPACE_P (f, obody[olen-1])) olen--; } @@ -5316,7 +5818,7 @@ update_frame_line (struct frame *f, int vpos, bool updating_menu_p) { /* Ignore spaces at the end, if we can. */ if (!write_spaces_p) - while (nlen > 0 && CHAR_GLYPH_SPACE_P (nbody[nlen - 1])) + while (nlen > 0 && CHAR_GLYPH_SPACE_P (f, nbody[nlen - 1])) --nlen; /* Write the contents of the desired line. */ @@ -5338,15 +5840,13 @@ update_frame_line (struct frame *f, int vpos, bool updating_menu_p) /* Make sure we are in the right row, otherwise cursor movement with cmgoto might use `ch' in the wrong row. */ cursor_to (f, vpos, 0); - - make_current (desired_matrix, current_matrix, vpos); return; } /* Pretend trailing spaces are not there at all, unless for one reason or another we must write all spaces. */ if (!write_spaces_p) - while (nlen > 0 && CHAR_GLYPH_SPACE_P (nbody[nlen - 1])) + while (nlen > 0 && CHAR_GLYPH_SPACE_P (f, nbody[nlen - 1])) nlen--; /* If there's no i/d char, quickly do the best we can without it. */ @@ -5383,9 +5883,6 @@ update_frame_line (struct frame *f, int vpos, bool updating_menu_p) cursor_to (f, vpos, nlen); clear_end_of_line (f, olen); } - - /* Make current row = desired row. */ - make_current (desired_matrix, current_matrix, vpos); return; } @@ -5399,7 +5896,7 @@ update_frame_line (struct frame *f, int vpos, bool updating_menu_p) if (write_spaces_p) nsp = 0; else - nsp = count_blanks (nbody, nlen); + nsp = count_blanks (f, nbody, nlen); if (nlen > nsp) { @@ -5407,14 +5904,12 @@ update_frame_line (struct frame *f, int vpos, bool updating_menu_p) write_glyphs (f, nbody + nsp, nlen - nsp); } - /* Exchange contents between current_frame and new_frame. */ - make_current (desired_matrix, current_matrix, vpos); return; } /* Compute number of leading blanks in old and new contents. */ - osp = count_blanks (obody, olen); - nsp = (colored_spaces_p ? 0 : count_blanks (nbody, nlen)); + osp = count_blanks (f, obody, olen); + nsp = (colored_spaces_p ? 0 : count_blanks (f, nbody, nlen)); /* Compute number of matching chars starting with first non-blank. */ begmatch = count_match (obody + osp, obody + olen, @@ -5425,7 +5920,7 @@ update_frame_line (struct frame *f, int vpos, bool updating_menu_p) if (!write_spaces_p && osp + begmatch == olen) { np1 = nbody + nsp; - while (np1 + begmatch < nend && CHAR_GLYPH_SPACE_P (np1[begmatch])) + while (np1 + begmatch < nend && CHAR_GLYPH_SPACE_P (f, np1[begmatch])) ++begmatch; } @@ -5566,9 +6061,6 @@ update_frame_line (struct frame *f, int vpos, bool updating_menu_p) cursor_to (f, vpos, nlen); clear_end_of_line (f, olen); } - - /* Exchange contents between current_frame and new_frame. */ - make_current (desired_matrix, current_matrix, vpos); } @@ -5967,7 +6459,8 @@ handle_window_change_signal (int sig) { struct frame *f = XFRAME (frame); - if (FRAME_TERMCAP_P (f) && FRAME_TTY (f) == tty) + if (FRAME_TERMCAP_P (f) && FRAME_TTY (f) == tty + && !FRAME_PARENT_FRAME (f)) /* Record the new sizes, but don't reallocate the data structures now. Let that be done later outside of the signal handler. */ @@ -6534,7 +7027,7 @@ init_display_interactive (void) /* Construct the space glyph. */ space_glyph.type = CHAR_GLYPH; - SET_CHAR_GLYPH (space_glyph, ' ', DEFAULT_FACE_ID, 0); + SET_CHAR_GLYPH (NULL, space_glyph, ' ', DEFAULT_FACE_ID, 0); space_glyph.charpos = -1; inverse_video = 0; @@ -6808,6 +7301,7 @@ syms_of_display (void) defsubr (&Ssend_string_to_terminal); defsubr (&Sinternal_show_cursor); defsubr (&Sinternal_show_cursor_p); + defsubr (&Sframe__z_order_lessp); #ifdef GLYPH_DEBUG defsubr (&Sdump_redisplay_history); @@ -6818,8 +7312,10 @@ syms_of_display (void) /* This is the "purpose" slot of a display table. */ DEFSYM (Qdisplay_table, "display-table"); + DEFSYM (Qframe__z_order_lessp, "frame--z-order-lessp"); DEFSYM (Qredisplay_dont_pause, "redisplay-dont-pause"); + DEFSYM (Qtty_non_selected_cursor, "tty-non-selected-cursor"); DEFVAR_INT ("baud-rate", baud_rate, doc: /* The output baud rate of the terminal. @@ -6921,6 +7417,8 @@ Possible values are t (below the tool bar), nil (above the tool bar). This option affects only builds where the tool bar is not external. */); pdumper_do_now_and_after_load (syms_of_display_for_pdumper); + + Fprovide (intern_c_string ("tty-child-frames"), Qnil); } static void diff --git a/src/disptab.h b/src/disptab.h index 2080181610a..f51d1d3044b 100644 --- a/src/disptab.h +++ b/src/disptab.h @@ -28,7 +28,7 @@ along with GNU Emacs. If not, see . */ && EQ (XCHAR_TABLE (obj)->purpose, Qdisplay_table) \ && CHAR_TABLE_EXTRA_SLOTS (XCHAR_TABLE (obj)) == DISP_TABLE_EXTRA_SLOTS) -#define DISP_TABLE_EXTRA_SLOTS 6 +#define DISP_TABLE_EXTRA_SLOTS 12 #define DISP_TRUNC_GLYPH(dp) ((dp)->extras[0]) #define DISP_CONTINUE_GLYPH(dp) ((dp)->extras[1]) #define DISP_ESCAPE_GLYPH(dp) ((dp)->extras[2]) @@ -36,6 +36,16 @@ along with GNU Emacs. If not, see . */ #define DISP_INVIS_VECTOR(dp) ((dp)->extras[4]) #define DISP_BORDER_GLYPH(dp) ((dp)->extras[5]) +enum box +{ + BOX_VERTICAL = 6, + BOX_HORIZONTAL, + BOX_DOWN_RIGHT, + BOX_DOWN_LEFT, + BOX_UP_RIGHT, + BOX_UP_LEFT +}; + extern Lisp_Object disp_char_vector (struct Lisp_Char_Table *, int); #define DISP_CHAR_VECTOR(dp, c) \ diff --git a/src/frame.c b/src/frame.c index 7f4bf274ad9..8133b646216 100644 --- a/src/frame.c +++ b/src/frame.c @@ -130,6 +130,14 @@ decode_window_system_frame (Lisp_Object frame) #endif } +struct frame * +decode_tty_frame (Lisp_Object frame) +{ + struct frame *f = decode_live_frame (frame); + check_tty (f); + return f; +} + void check_window_system (struct frame *f) { @@ -141,6 +149,13 @@ check_window_system (struct frame *f) : "Window system is not in use or not initialized"); } +void +check_tty (struct frame *f) +{ + if (!f || !FRAME_TERMCAP_P (f)) + error ("tty frame should be used"); +} + /* Return the value of frame parameter PROP in frame FRAME. */ Lisp_Object @@ -182,6 +197,17 @@ set_menu_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval) int olines = FRAME_MENU_BAR_LINES (f); int nlines = TYPE_RANGED_FIXNUMP (int, value) ? XFIXNUM (value) : 0; + /* Menu bars on child frames don't work on all platforms, + which is the reason why prepare_menu_bar does not update_menu_bar + for child frames (info from Martin Rudalics). This could be + implemented in ttys, but it's probaly not worth it. */ + if (is_tty_child_frame (f)) + { + FRAME_MENU_BAR_LINES (f) = 0; + FRAME_MENU_BAR_HEIGHT (f) = 0; + return; + } + /* Right now, menu bars don't work properly in minibuf-only frames; most of the commands try to apply themselves to the minibuffer frame itself, and get an error because you can't switch buffers @@ -370,17 +396,17 @@ frame_windows_min_size (Lisp_Object frame, Lisp_Object horizontal, } else retval = XFIXNUM (call4 (Qframe_windows_min_size, frame, horizontal, - ignore, pixelwise)); + ignore, pixelwise)); /* Don't allow too small height of text-mode frames, or else cm.c might abort in cmcheckmagic. */ if ((FRAME_TERMCAP_P (f) || FRAME_MSDOS_P (f)) && NILP (horizontal)) { - int min_height = (FRAME_MENU_BAR_LINES (f) - + FRAME_TAB_BAR_LINES (f) + int min_height = (FRAME_MENU_BAR_LINES (f) + FRAME_TAB_BAR_LINES (f) + FRAME_WANTS_MODELINE_P (f) - + 2); /* one text line and one echo-area line */ - + + FRAME_HAS_MINIBUF_P (f)); + if (min_height == 0) + min_height = 1; if (retval < min_height) retval = min_height; } @@ -389,7 +415,6 @@ frame_windows_min_size (Lisp_Object frame, Lisp_Object horizontal, } -#ifdef HAVE_WINDOW_SYSTEM /** * keep_ratio: * @@ -508,7 +533,6 @@ keep_ratio (struct frame *f, struct frame *p, int old_width, int old_height, } } } -#endif static void @@ -833,8 +857,9 @@ adjust_frame_size (struct frame *f, int new_text_width, int new_text_height, /* MSDOS frames cannot PRETEND, as they change frame size by manipulating video hardware. */ - if ((FRAME_TERMCAP_P (f) && !pretend) || FRAME_MSDOS_P (f)) - FrameCols (FRAME_TTY (f)) = new_text_cols; + if (is_tty_root_frame (f)) + if ((FRAME_TERMCAP_P (f) && !pretend) || FRAME_MSDOS_P (f)) + FrameCols (FRAME_TTY (f)) = new_text_cols; #if defined (HAVE_WINDOW_SYSTEM) if (WINDOWP (f->tab_bar_window)) @@ -866,9 +891,10 @@ adjust_frame_size (struct frame *f, int new_text_width, int new_text_height, resize_frame_windows (f, new_inner_height, false); /* MSDOS frames cannot PRETEND, as they change frame size by - manipulating video hardware. */ - if ((FRAME_TERMCAP_P (f) && !pretend) || FRAME_MSDOS_P (f)) - FrameRows (FRAME_TTY (f)) = new_text_lines + FRAME_TOP_MARGIN (f); + manipulating video hardware. */ + if (is_tty_root_frame (f)) + if ((FRAME_TERMCAP_P (f) && !pretend) || FRAME_MSDOS_P (f)) + FrameRows (FRAME_TTY (f)) = new_text_lines + FRAME_TOP_MARGIN (f); } else if (new_text_lines != old_text_lines) call2 (Qwindow__pixel_to_total, frame, Qnil); @@ -898,6 +924,9 @@ adjust_frame_size (struct frame *f, int new_text_width, int new_text_height, adjust_frame_glyphs (f); calculate_costs (f); SET_FRAME_GARBAGED (f); + if (is_tty_child_frame (f)) + SET_FRAME_GARBAGED (root_frame (f)); + /* We now say here that F was resized instead of using the old condition below. Some resizing must have taken place and if it was only shifting the root window's position (paranoia?). */ @@ -910,7 +939,6 @@ adjust_frame_size (struct frame *f, int new_text_width, int new_text_height, unblock_input (); -#ifdef HAVE_WINDOW_SYSTEM { /* Adjust size of F's child frames. */ Lisp_Object frames, frame1; @@ -920,7 +948,6 @@ adjust_frame_size (struct frame *f, int new_text_width, int new_text_height, keep_ratio (XFRAME (frame1), f, old_native_width, old_native_height, new_native_width, new_native_height); } -#endif } /* Allocate basically initialized frame. */ @@ -967,12 +994,12 @@ make_frame (bool mini_p) f->line_height = 1; /* !FRAME_WINDOW_P value. */ f->new_width = -1; f->new_height = -1; + f->no_special_glyphs = false; #ifdef HAVE_WINDOW_SYSTEM f->vertical_scroll_bar_type = vertical_scroll_bar_none; f->horizontal_scroll_bars = false; f->want_fullscreen = FULLSCREEN_NONE; f->undecorated = false; - f->no_special_glyphs = false; #ifndef HAVE_NTGUI f->override_redirect = false; #endif @@ -1089,7 +1116,6 @@ make_frame (bool mini_p) return f; } -#ifdef HAVE_WINDOW_SYSTEM /* Make a frame using a separate minibuffer window on another frame. MINI_WINDOW is the minibuffer window to use. nil means use the default (the global minibuffer). */ @@ -1183,7 +1209,7 @@ make_minibuffer_frame (void) : Fcar (Vminibuffer_list)), 0, 0); return f; } -#endif /* HAVE_WINDOW_SYSTEM */ + /* Construct a frame that refers to a terminal. */ @@ -1209,7 +1235,7 @@ make_initial_frame (void) tty_frame_count = 1; fset_name (f, build_pure_c_string ("F1")); - SET_FRAME_VISIBLE (f, 1); + SET_FRAME_VISIBLE (f, true); f->output_method = terminal->type; f->terminal = terminal; @@ -1246,23 +1272,55 @@ make_initial_frame (void) #ifndef HAVE_ANDROID static struct frame * -make_terminal_frame (struct terminal *terminal) +make_terminal_frame (struct terminal *terminal, Lisp_Object parent, + Lisp_Object params) { - register struct frame *f; - Lisp_Object frame; char name[sizeof "F" + INT_STRLEN_BOUND (tty_frame_count)]; if (!terminal->name) error ("Terminal is not live, can't create new frames on it"); - f = make_frame (1); + struct frame *f; + if (NILP (parent)) + f = make_frame (true); + else + { + CHECK_FRAME (parent); + f = NULL; + Lisp_Object mini = Fassq (Qminibuffer, params); + if (CONSP (mini)) + { + mini = Fcdr (mini); + struct kboard *kb = FRAME_KBOARD (XFRAME (parent)); + if (EQ (mini, Qnone) || NILP (mini)) + f = make_frame_without_minibuffer (Qnil, kb, Qnil); + else if (EQ (mini, Qonly)) + { +# if 0 /* No interest in this feature at the moment, */ + f = make_minibuffer_frame (); + /* Not sure about this plus the unsplittable frame + paran. */ + f->no_split = true; +# endif + } + else if (WINDOWP (mini)) + f = make_frame_without_minibuffer (mini, kb, Qnil); + } + + if (f == NULL) + f = make_frame (true); + f->parent_frame = parent; + f->z_order = 1 + max_child_z_order (XFRAME (parent)); + } + + Lisp_Object frame; XSETFRAME (frame, f); Vframe_list = Fcons (frame, Vframe_list); fset_name (f, make_formatted_string (name, "F%"PRIdMAX, ++tty_frame_count)); - SET_FRAME_VISIBLE (f, 1); + SET_FRAME_VISIBLE (f, true); f->terminal = terminal; f->terminal->reference_count++; @@ -1287,7 +1345,15 @@ make_terminal_frame (struct terminal *terminal) f->horizontal_scroll_bars = false; #endif - FRAME_MENU_BAR_LINES (f) = NILP (Vmenu_bar_mode) ? 0 : 1; + /* Menu bars on child frames don't work on all platforms, + which is the reason why prepare_menu_bar does not update_menu_bar + for child frames (info from Martin Rudalics). This could be + implemented in ttys, but it's unclear if it is worth it. */ + if (NILP (parent)) + FRAME_MENU_BAR_LINES (f) = NILP (Vmenu_bar_mode) ? 0 : 1; + else + FRAME_MENU_BAR_LINES (f) = 0; + FRAME_TAB_BAR_LINES (f) = NILP (Vtab_bar_mode) ? 0 : 1; FRAME_LINES (f) = FRAME_LINES (f) - FRAME_MENU_BAR_LINES (f) - FRAME_TAB_BAR_LINES (f); @@ -1296,16 +1362,19 @@ make_terminal_frame (struct terminal *terminal) FRAME_TEXT_HEIGHT (f) = FRAME_TEXT_HEIGHT (f) - FRAME_MENU_BAR_HEIGHT (f) - FRAME_TAB_BAR_HEIGHT (f); + /* Mark current topmost frame obscured if we make a new root frame. + Child frames don't completely obscure other frames. */ + if (NILP (parent) && FRAMEP (FRAME_TTY (f)->top_frame)) + { + struct frame *top = XFRAME (FRAME_TTY (f)->top_frame); + struct frame *root = root_frame (top); + if (FRAME_LIVE_P (root)) + SET_FRAME_VISIBLE (root, false); + } + /* Set the top frame to the newly created frame. */ - if (FRAMEP (FRAME_TTY (f)->top_frame) - && FRAME_LIVE_P (XFRAME (FRAME_TTY (f)->top_frame))) - SET_FRAME_VISIBLE (XFRAME (FRAME_TTY (f)->top_frame), 2); /* obscured */ - - FRAME_TTY (f)->top_frame = frame; - - if (!noninteractive) - init_frame_faces (f); - + if (!FRAME_PARENT_FRAME (f)) + FRAME_TTY (f)->top_frame = frame; return f; } @@ -1335,6 +1404,62 @@ get_future_frame_param (Lisp_Object parameter, #endif +static int +tty_child_pos_param (struct frame *child, Lisp_Object key, + Lisp_Object params, int dflt) +{ + Lisp_Object val = Fassq (key, params); + if (CONSP (val)) + { + val = XCDR (val); + if (FIXNUMP (val)) + return XFIXNUM (val); + } + return dflt; +} + +static int +tty_child_size_param (struct frame *child, Lisp_Object key, + Lisp_Object params, int dflt) +{ + Lisp_Object val = Fassq (key, params); + if (CONSP (val)) + { + val = XCDR (val); + if (CONSP (val)) + { + /* Width and height may look like (width text-pixels + . PIXELS) on window systems. Mimic that. */ + val = XCDR (val); + if (EQ (val, Qtext_pixels)) + val = XCDR (val); + } + else if (FLOATP (val)) + { + /* Width and height may be a float, in which case + it's a multiple of the parent's value. */ + struct frame *parent = FRAME_PARENT_FRAME (child); + int sz = (EQ (key, Qwidth) ? FRAME_TOTAL_COLS (parent) + : FRAME_TOTAL_LINES (parent)); + val = make_fixnum (XFLOAT_DATA (val) * sz); + } + + if (FIXNUMP (val) && XFIXNUM (val) > 0) + return XFIXNUM (val); + } + return dflt; +} + +static void +child_frame_rect (struct frame *f, Lisp_Object params, + int *x, int *y, int *w, int *h) +{ + *x = tty_child_pos_param (f, Qleft, params, 0); + *y = tty_child_pos_param (f, Qtop, params, 0); + *w = tty_child_size_param (f, Qwidth, params, FRAME_TOTAL_COLS (f)); + *h = tty_child_size_param (f, Qheight, params, FRAME_TOTAL_LINES (f)); +} + DEFUN ("make-terminal-frame", Fmake_terminal_frame, Smake_terminal_frame, 1, 1, 0, doc: /* Create an additional terminal frame, possibly on another terminal. @@ -1358,9 +1483,7 @@ affects all frames on the same terminal device. */) error ("Text terminals are not supported on this platform"); return Qnil; #else - struct frame *f; struct terminal *t = NULL; - Lisp_Object frame; struct frame *sf = SELECTED_FRAME (); #ifdef MSDOS @@ -1390,7 +1513,7 @@ affects all frames on the same terminal device. */) error ("Multiple terminals are not supported on this platform"); if (!t) t = the_only_display_info.terminal; -#endif +# endif } if (!t) @@ -1417,19 +1540,67 @@ affects all frames on the same terminal device. */) SAFE_FREE (); } - f = make_terminal_frame (t); + /* Make a new frame. We need to know upfront if if a parent frame is + specified because we behave differently in this case, e.g. child + frames don't obscure other frames. */ + Lisp_Object parent = Fcdr (Fassq (Qparent_frame, parms)); + struct frame *f = make_terminal_frame (t, parent, parms); - { - int width, height; + if (!noninteractive) + init_frame_faces (f); + + /* Visibility of root frames cannot be set with a frame parameter. + Their visibility solely depends on whether or not they are the + top_frame on the terminal. */ + if (FRAME_PARENT_FRAME (f)) + { + Lisp_Object visible = Fassq (Qvisibility, parms); + if (CONSP (visible)) + SET_FRAME_VISIBLE (f, !NILP (visible)); + + /* FIXME/tty: The only way to get borders on a tty is + to allow decorations for now. */ + Lisp_Object undecorated = Fassq (Qundecorated, parms); + if (CONSP (undecorated) && !NILP (XCDR (undecorated))) + f->undecorated = true; + + /* FIXME/tty: The only way to get borders on a tty is + to allow decorations for now. */ + Lisp_Object no_focus = Fassq (Qno_accept_focus, parms); + if (CONSP (no_focus) && !NILP (XCDR (no_focus))) + f->no_accept_focus = true; + + /* FIXME/tty: The only way to get borders on a tty is + to allow decorations for now. */ + Lisp_Object no_split = Fassq (Qunsplittable, parms); + if (CONSP (no_split) && !NILP (XCDR (no_split))) + f->no_split = true; + } + + /* Determine width and height of the frame. For root frames use the + width/height of the terminal. For child frames, take it from frame + parameters. Note that a default (80x25) has been set in + make_frame. We handle root frames in this way because otherwise we + would end up needing glyph matrices for the terminal, which is both + more work and has its downsides (think of clipping frames to the + terminal size). */ + int x = 0, y = 0, width, height; + if (FRAME_PARENT_FRAME (f)) + child_frame_rect (f, parms, &x, &y, &width, &height); + else get_tty_size (fileno (FRAME_TTY (f)->input), &width, &height); - /* With INHIBIT 5 pass correct text height to adjust_frame_size. */ - adjust_frame_size (f, width, height - FRAME_TOP_MARGIN (f), - 5, 0, Qterminal_frame); - } - + adjust_frame_size (f, width, height - FRAME_TOP_MARGIN (f), 5, 0, + Qterminal_frame); adjust_frame_glyphs (f); + calculate_costs (f); - XSETFRAME (frame, f); + + f->left_pos = x; + f->top_pos = y; + store_in_alist (&parms, Qleft, make_fixnum (x)); + store_in_alist (&parms, Qtop, make_fixnum (y)); + store_in_alist (&parms, Qwidth, make_fixnum (width)); + store_in_alist (&parms, Qheight, make_fixnum (height)); store_in_alist (&parms, Qtty_type, build_string (t->display_info.tty->type)); store_in_alist (&parms, Qtty, @@ -1451,7 +1622,11 @@ affects all frames on the same terminal device. */) /* On terminal frames the `minibuffer' frame parameter is always virtually t. Avoid that a different value in parms causes complaints, see Bug#24758. */ - store_in_alist (&parms, Qminibuffer, Qt); + if (!FRAME_PARENT_FRAME (f)) + store_in_alist (&parms, Qminibuffer, Qt); + + Lisp_Object frame; + XSETFRAME (frame, f); Fmodify_frame_parameters (frame, parms); f->can_set_window_size = true; @@ -1480,8 +1655,6 @@ affects all frames on the same terminal device. */) Lisp_Object do_switch_frame (Lisp_Object frame, int track, int for_deletion, Lisp_Object norecord) { - struct frame *sf = SELECTED_FRAME (), *f; - /* If FRAME is a switch-frame event, extract the frame we should switch to. */ if (CONSP (frame) @@ -1493,7 +1666,9 @@ do_switch_frame (Lisp_Object frame, int track, int for_deletion, Lisp_Object nor a switch-frame event to arrive after a frame is no longer live, especially when deleting the initial frame during startup. */ CHECK_FRAME (frame); - f = XFRAME (frame); + struct frame *f = XFRAME (frame); + struct frame *sf = SELECTED_FRAME (); + /* Silently ignore dead and tooltip frames (Bug#47207). */ if (!FRAME_LIVE_P (f) || FRAME_TOOLTIP_P (f)) return Qnil; @@ -1546,24 +1721,37 @@ do_switch_frame (Lisp_Object frame, int track, int for_deletion, Lisp_Object nor struct tty_display_info *tty = FRAME_TTY (f); Lisp_Object top_frame = tty->top_frame; - /* Don't mark the frame garbaged and/or obscured if we are - switching to the frame that is already the top frame of that - TTY. */ + /* Don't mark the frame garbaged if we are switching to the frame + that is already the top frame of that TTY. */ if (!EQ (frame, top_frame)) { + struct frame *new_root = root_frame (f); + SET_FRAME_VISIBLE (new_root, true); + SET_FRAME_VISIBLE (f, true); + + /* Mark previously displayed frame as no longer visible. */ if (FRAMEP (top_frame)) - /* Mark previously displayed frame as now obscured. */ - SET_FRAME_VISIBLE (XFRAME (top_frame), 2); - SET_FRAME_VISIBLE (f, 1); - /* If the new TTY frame changed dimensions, we need to - resync term.c's idea of the frame size with the new - frame's data. */ - if (FRAME_COLS (f) != FrameCols (tty)) - FrameCols (tty) = FRAME_COLS (f); - if (FRAME_TOTAL_LINES (f) != FrameRows (tty)) - FrameRows (tty) = FRAME_TOTAL_LINES (f); + { + struct frame *top = XFRAME (top_frame); + struct frame *old_root = root_frame (top); + if (old_root != new_root) + SET_FRAME_VISIBLE (old_root, false); + } + + tty->top_frame = frame; + + /* Why is it correct to set FrameCols/Rows? */ + if (!FRAME_PARENT_FRAME (f)) + { + /* If the new TTY frame changed dimensions, we need to + resync term.c's idea of the frame size with the new + frame's data. */ + if (FRAME_COLS (f) != FrameCols (tty)) + FrameCols (tty) = FRAME_COLS (f); + if (FRAME_TOTAL_LINES (f) != FrameRows (tty)) + FrameRows (tty) = FRAME_TOTAL_LINES (f); + } } - tty->top_frame = frame; } sf->select_mini_window_flag = MINI_WINDOW_P (XWINDOW (sf->selected_window)); @@ -1605,9 +1793,7 @@ do_switch_frame (Lisp_Object frame, int track, int for_deletion, Lisp_Object nor (select-window (frame-root-window (make-frame))) doesn't end up with your typing being interpreted in the new frame instead of the one you're actually typing in. */ -#ifdef HAVE_WINDOW_SYSTEM if (!frame_ancestor_p (f, sf)) -#endif internal_last_event_frame = Qnil; return frame; @@ -1725,7 +1911,6 @@ parent window is the window-system's root window) or an embedded window return Qnil; } -#ifdef HAVE_WINDOW_SYSTEM bool frame_ancestor_p (struct frame *af, struct frame *df) { @@ -1741,7 +1926,6 @@ frame_ancestor_p (struct frame *af, struct frame *df) return false; } -#endif DEFUN ("frame-ancestor-p", Fframe_ancestor_p, Sframe_ancestor_p, 2, 2, 0, @@ -1752,15 +1936,10 @@ ANCESTOR and DESCENDANT must be live frames and default to the selected frame. */) (Lisp_Object ancestor, Lisp_Object descendant) { -#ifdef HAVE_WINDOW_SYSTEM struct frame *af = decode_live_frame (ancestor); struct frame *df = decode_live_frame (descendant); - return frame_ancestor_p (af, df) ? Qt : Qnil; -#else - return Qnil; -#endif - } +} /* Return CANDIDATE if it can be used as 'other-than-FRAME' frame on the same tty (for tty frames) or among frames which uses FRAME's keyboard. @@ -2021,7 +2200,9 @@ other_frames (struct frame *f, bool invisible, bool force) && (invisible || NILP (get_frame_param (f1, Qdelete_before))) /* For invisibility and normal deletions, at least one visible or iconified frame must remain (Bug#26682). */ - && (FRAME_VISIBLE_P (f1) || FRAME_ICONIFIED_P (f1) + && (FRAME_VISIBLE_P (f1) + || is_tty_frame (f1) + || FRAME_ICONIFIED_P (f1) || (!invisible && (force /* Allow deleting the terminal frame when at @@ -2282,7 +2463,7 @@ delete_frame (Lisp_Object frame, Lisp_Object force) fset_root_window (f, Qnil); Vframe_list = Fdelq (frame, Vframe_list); - SET_FRAME_VISIBLE (f, 0); + SET_FRAME_VISIBLE (f, false); /* Allow the vector of menu bar contents to be freed in the next garbage collection. The frame object itself may not be garbage @@ -2868,6 +3049,12 @@ If omitted, FRAME defaults to the currently selected frame. */) if (FRAME_WINDOW_P (f) && FRAME_TERMINAL (f)->frame_visible_invisible_hook) FRAME_TERMINAL (f)->frame_visible_invisible_hook (f, true); + if (is_tty_frame (f)) + { + SET_FRAME_VISIBLE (f, true); + tty_raise_lower_frame (f, true); + } + make_frame_visible_1 (f->root_window); /* Make menu bar update for the Buffers and Frames menus. */ @@ -2918,6 +3105,12 @@ displayed in the terminal. */) if (FRAME_WINDOW_P (f) && FRAME_TERMINAL (f)->frame_visible_invisible_hook) FRAME_TERMINAL (f)->frame_visible_invisible_hook (f, false); + /* The Elisp info manual says that this "usually" makes child frames + invisible, too, but without saying when not. Since users can't rely + on this, it's not implemented. */ + if (is_tty_frame (f)) + SET_FRAME_VISIBLE (f, false); + /* Make menu bar update for the Buffers and Frames menus. */ windows_or_buffers_changed = 16; @@ -2977,10 +3170,13 @@ currently being displayed on the terminal. */) (Lisp_Object frame) { CHECK_LIVE_FRAME (frame); + struct frame *f = XFRAME (frame); - if (FRAME_VISIBLE_P (XFRAME (frame))) + if (FRAME_VISIBLE_P (f)) return Qt; - if (FRAME_ICONIFIED_P (XFRAME (frame))) + else if (is_tty_root_frame (f)) + return Qt; + if (FRAME_ICONIFIED_P (f)) return Qicon; return Qnil; } @@ -3012,12 +3208,7 @@ doesn't support multiple overlapping frames, this function selects FRAME. */) XSETFRAME (frame, f); - if (FRAME_TERMCAP_P (f)) - /* On a text terminal select FRAME. */ - Fselect_frame (frame, Qnil); - else - /* Do like the documentation says. */ - Fmake_frame_visible (frame); + Fmake_frame_visible (frame); if (FRAME_TERMINAL (f)->frame_raise_lower_hook) (*FRAME_TERMINAL (f)->frame_raise_lower_hook) (f, true); @@ -3318,6 +3509,15 @@ store_frame_param (struct frame *f, Lisp_Object prop, Lisp_Object val) val = old_val; } + /* Re-parenting is currently not implemented when changing a root + frame to a child frame or vice versa. */ + if (is_tty_frame (f) && EQ (prop, Qparent_frame)) + { + if (NILP (f->parent_frame) != NILP (val)) + error ("Making a root frame a child or vice versa is not supported"); + f->parent_frame = val; + } + /* The tty color needed to be set before the frame's parameter alist was updated with the new value. This is not true any more, but we still do this test early on. */ @@ -3441,13 +3641,10 @@ If FRAME is omitted or nil, return information on the currently selected frame. else #endif { - /* This ought to be correct in f->param_alist for an X frame. */ - Lisp_Object lines; - - XSETFASTINT (lines, FRAME_MENU_BAR_LINES (f)); - store_in_alist (&alist, Qmenu_bar_lines, lines); - XSETFASTINT (lines, FRAME_TAB_BAR_LINES (f)); - store_in_alist (&alist, Qtab_bar_lines, lines); + store_in_alist (&alist, Qmenu_bar_lines, make_fixnum (FRAME_MENU_BAR_LINES (f))); + store_in_alist (&alist, Qtab_bar_lines, make_fixnum (FRAME_TAB_BAR_LINES (f))); + store_in_alist (&alist, Qvisibility, FRAME_VISIBLE_P (f) ? Qt : Qnil); + store_in_alist (&alist, Qno_accept_focus, FRAME_NO_ACCEPT_FOCUS (f) ? Qt : Qnil); } return alist; @@ -3525,7 +3722,6 @@ If FRAME is nil, describe the currently selected frame. */) return value; } - DEFUN ("modify-frame-parameters", Fmodify_frame_parameters, Smodify_frame_parameters, 2, 2, 0, doc: /* Modify FRAME according to new values of its parameters in ALIST. @@ -3563,6 +3759,7 @@ list, but are otherwise ignored. */) USE_SAFE_ALLOCA; SAFE_ALLOCA_LISP (parms, 2 * length); values = parms + length; + Lisp_Object params = alist; /* Extract parm names and values into those vectors. */ @@ -3588,6 +3785,31 @@ list, but are otherwise ignored. */) update_face_from_frame_parameter (f, prop, val); } + if (is_tty_child_frame (f)) + { + int x = tty_child_pos_param (f, Qleft, params, f->left_pos); + int y = tty_child_pos_param (f, Qtop, params, f->top_pos); + if (x != f->left_pos || y != f->top_pos) + { + f->left_pos = x; + f->top_pos = y; + SET_FRAME_GARBAGED (root_frame (f)); + } + + int w = tty_child_size_param (f, Qwidth, params, f->total_cols); + int h = tty_child_size_param (f, Qheight, params, f->total_lines); + if (w != f->total_cols || h != f->total_lines) + change_frame_size (f, w, h, false, false, false); + + Lisp_Object visible = Fassq (Qvisibility, params); + if (CONSP (visible)) + SET_FRAME_VISIBLE (f, !NILP (Fcdr (visible))); + + Lisp_Object no_special = Fassq (Qno_special_glyphs, params); + if (CONSP (no_special)) + FRAME_NO_SPECIAL_GLYPHS (f) = !NILP (Fcdr (no_special)); + } + SAFE_FREE (); } return Qnil; @@ -3935,6 +4157,11 @@ bottom edge of FRAME's display. */) (void) yval; #endif } + else if (is_tty_child_frame (f)) + { + f->left_pos = xval; + f->top_pos = yval; + } return Qt; } @@ -4246,6 +4473,28 @@ frame_float (struct frame *f, Lisp_Object val, enum frame_float_type what, } } +/* Handle frame parameter change with frame parameter handler. F is the + frame whose frame parameter was changed. PROP is the name of the + frame parameter. VAL and OLD_VALUE are the current value and old + value of the frame parameter. */ + +static void +handle_frame_param (struct frame *f, Lisp_Object prop, Lisp_Object val, + Lisp_Object old_value) +{ + Lisp_Object param_index = Fget (prop, Qx_frame_parameter); + if (FIXNATP (param_index) && XFIXNAT (param_index) < ARRAYELTS (frame_parms)) + { + if (FRAME_RIF (f)) + { + frame_parm_handler handler + = FRAME_RIF (f)->frame_parm_handlers[XFIXNAT (param_index)]; + if (handler) + handler (f, val, old_value); + } + } +} + /* Change the parameters of frame F as specified by ALIST. If a parameter is not specially recognized, do nothing special; otherwise call the `gui_set_...' function for that parameter. @@ -4387,17 +4636,9 @@ gui_set_frame_parameters_1 (struct frame *f, Lisp_Object alist, } else { - Lisp_Object param_index, old_value; - - old_value = get_frame_param (f, prop); - + Lisp_Object old_value = get_frame_param (f, prop); store_frame_param (f, prop, val); - - param_index = Fget (prop, Qx_frame_parameter); - if (FIXNATP (param_index) - && XFIXNAT (param_index) < ARRAYELTS (frame_parms) - && FRAME_RIF (f)->frame_parm_handlers[XFIXNUM (param_index)]) - (*(FRAME_RIF (f)->frame_parm_handlers[XFIXNUM (param_index)])) (f, val, old_value); + handle_frame_param (f, prop, val, old_value); if (!default_parameter && EQ (prop, Qfont)) /* The user manually specified the `font' frame parameter. @@ -4716,14 +4957,7 @@ gui_set_screen_gamma (struct frame *f, Lisp_Object new_value, Lisp_Object old_va /* Apply the new gamma value to the frame background. */ bgcolor = Fassq (Qbackground_color, f->param_alist); if (CONSP (bgcolor) && (bgcolor = XCDR (bgcolor), STRINGP (bgcolor))) - { - Lisp_Object parm_index = Fget (Qbackground_color, Qx_frame_parameter); - if (FIXNATP (parm_index) - && XFIXNAT (parm_index) < ARRAYELTS (frame_parms) - && FRAME_RIF (f)->frame_parm_handlers[XFIXNAT (parm_index)]) - (*FRAME_RIF (f)->frame_parm_handlers[XFIXNAT (parm_index)]) - (f, bgcolor, Qnil); - } + handle_frame_param (f, Qbackground_color, bgcolor, Qnil); clear_face_cache (true); /* FIXME: Why of all frames? */ fset_redisplay (f); diff --git a/src/frame.h b/src/frame.h index 1d920d1a6bc..0b7368fb29b 100644 --- a/src/frame.h +++ b/src/frame.h @@ -161,10 +161,8 @@ struct frame Usually it is nil. */ Lisp_Object title; -#if defined (HAVE_WINDOW_SYSTEM) /* This frame's parent frame, if it has one. */ Lisp_Object parent_frame; -#endif /* HAVE_WINDOW_SYSTEM */ /* Last device to move over this frame. Any value that isn't a string means the "Virtual core pointer". */ @@ -385,15 +383,8 @@ struct frame zero if the frame has been made invisible without an icon. */ /* Nonzero if the frame is currently displayed; we check - it to see if we should bother updating the frame's contents. - - On ttys and on Windows NT/9X, to avoid wasting effort updating - visible frames that are actually completely obscured by other - windows on the display, we bend the meaning of visible slightly: - if equal to 2, then the frame is obscured - we still consider - it to be "visible" as seen from lisp, but we don't bother - updating it. */ - unsigned visible : 2; + it to see if we should bother updating the frame's contents. */ + unsigned visible : 1; /* True if the frame is currently iconified. Do not set this directly, use SET_FRAME_ICONIFIED instead. */ @@ -451,7 +442,15 @@ struct frame This must be the same as the terminal->type. */ ENUM_BF (output_method) output_method : 4; + /* True if this is an undecorated frame. */ + bool_bf undecorated : 1; + + /* Nonzero if this frame's window does not want to receive input focus + via mouse clicks or by moving the mouse into it. */ + bool_bf no_accept_focus : 1; + #ifdef HAVE_WINDOW_SYSTEM +# ifndef HAVE_NTGUI /* True if this frame is a tooltip frame. */ bool_bf tooltip : 1; @@ -465,10 +464,7 @@ struct frame /* Nonzero if we should actually display horizontal scroll bars on this frame. */ bool_bf horizontal_scroll_bars : 1; - /* True if this is an undecorated frame. */ - bool_bf undecorated : 1; -#ifndef HAVE_NTGUI /* True if this is an override_redirect frame. */ bool_bf override_redirect : 1; #endif @@ -480,17 +476,13 @@ struct frame receive input focus when it is mapped. */ bool_bf no_focus_on_map : 1; - /* Nonzero if this frame's window does not want to receive input focus - via mouse clicks or by moving the mouse into it. */ - bool_bf no_accept_focus : 1; - /* The z-group this frame's window belongs to. */ ENUM_BF (z_group) z_group : 2; +#endif /* HAVE_WINDOW_SYSTEM */ /* Non-zero if display of truncation and continuation glyphs outside the fringes is suppressed. */ bool_bf no_special_glyphs : 1; -#endif /* HAVE_WINDOW_SYSTEM */ /* True means set_window_size_hook requests can be processed for this frame. */ @@ -740,7 +732,10 @@ struct frame #ifdef HAVE_TEXT_CONVERSION /* Text conversion state used by certain input methods. */ struct text_conversion_state conversion; -#endif +# endif + + /* Z-order of child frames. */ + int z_order; } GCALIGNED_STRUCT; /* Most code should use these functions to set Lisp fields in struct frame. */ @@ -1021,9 +1016,11 @@ default_pixels_per_inch_y (void) does not have FRAME_DISPLAY_INFO. */ #ifdef HAVE_WINDOW_SYSTEM #ifndef HAVE_ANDROID -# define MOUSE_HL_INFO(F) \ +# define MOUSE_HL_INFO(F) \ (FRAME_WINDOW_P (F) \ - ? &FRAME_DISPLAY_INFO(F)->mouse_highlight \ + ? (FRAME_OUTPUT_DATA (F) \ + ? &FRAME_DISPLAY_INFO (F)->mouse_highlight \ + : NULL) \ : &(F)->output_data.tty->display_info->mouse_highlight) #else /* There is no "struct tty_output" on Android at all. */ @@ -1176,9 +1173,6 @@ default_pixels_per_inch_y (void) && FRAME_X_VISIBLE (f))) #endif -/* True if frame F is currently visible but hidden. */ -#define FRAME_OBSCURED_P(f) ((f)->visible > 1) - /* True if frame F is currently iconified. */ #define FRAME_ICONIFIED_P(f) (f)->iconified @@ -1243,21 +1237,23 @@ default_pixels_per_inch_y (void) #define FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT(f) ((void) (f), 0) #endif /* HAVE_WINDOW_SYSTEM */ -#if defined (HAVE_WINDOW_SYSTEM) +INLINE struct frame * +FRAME_PARENT_FRAME (struct frame *f) +{ + return NILP (f->parent_frame) ? NULL : XFRAME (f->parent_frame); +} + #define FRAME_UNDECORATED(f) ((f)->undecorated) + +#if defined (HAVE_WINDOW_SYSTEM) #ifdef HAVE_NTGUI #define FRAME_OVERRIDE_REDIRECT(f) ((void) (f), 0) #else #define FRAME_OVERRIDE_REDIRECT(f) ((f)->override_redirect) #endif -#define FRAME_PARENT_FRAME(f) \ - (NILP ((f)->parent_frame) \ - ? NULL \ - : XFRAME ((f)->parent_frame)) #define FRAME_SKIP_TASKBAR(f) ((f)->skip_taskbar) #define FRAME_NO_FOCUS_ON_MAP(f) ((f)->no_focus_on_map) #define FRAME_NO_ACCEPT_FOCUS(f) ((f)->no_accept_focus) -#define FRAME_NO_SPECIAL_GLYPHS(f) ((f)->no_special_glyphs) #define FRAME_Z_GROUP(f) ((f)->z_group) #define FRAME_Z_GROUP_NONE(f) ((f)->z_group == z_group_none) #define FRAME_Z_GROUP_ABOVE(f) ((f)->z_group == z_group_above) @@ -1270,13 +1266,10 @@ default_pixels_per_inch_y (void) #define FRAME_NS_TRANSPARENT_TITLEBAR(f) ((f)->ns_transparent_titlebar) #endif #else /* not HAVE_WINDOW_SYSTEM */ -#define FRAME_UNDECORATED(f) ((void) (f), 0) #define FRAME_OVERRIDE_REDIRECT(f) ((void) (f), 0) -#define FRAME_PARENT_FRAME(f) ((void) (f), NULL) #define FRAME_SKIP_TASKBAR(f) ((void) (f), 0) #define FRAME_NO_FOCUS_ON_MAP(f) ((void) (f), 0) #define FRAME_NO_ACCEPT_FOCUS(f) ((void) (f), 0) -#define FRAME_NO_SPECIAL_GLYPHS(f) ((void) (f), 0) #define FRAME_Z_GROUP(f) ((void) (f), z_group_none) #define FRAME_Z_GROUP_NONE(f) ((void) (f), true) #define FRAME_Z_GROUP_ABOVE(f) ((void) (f), false) @@ -1284,6 +1277,8 @@ default_pixels_per_inch_y (void) #define FRAME_TOOLTIP_P(f) ((void) f, false) #endif /* HAVE_WINDOW_SYSTEM */ +#define FRAME_NO_SPECIAL_GLYPHS(f) ((f)->no_special_glyphs) + /* Whether horizontal scroll bars are currently enabled for frame F. */ #if USE_HORIZONTAL_SCROLL_BARS #define FRAME_HAS_HORIZONTAL_SCROLL_BARS(f) \ @@ -1445,9 +1440,8 @@ extern bool frame_garbaged; if some changes were applied to it while it wasn't visible (and hence wasn't redisplayed). */ INLINE void -SET_FRAME_VISIBLE (struct frame *f, int v) +SET_FRAME_VISIBLE (struct frame *f, bool v) { - eassert (0 <= v && v <= 2); if (v) { if (v == 1 && f->visible != 1) @@ -1504,13 +1498,14 @@ extern struct frame *decode_any_frame (Lisp_Object); extern struct frame *make_initial_frame (void); extern struct frame *make_frame (bool); #ifdef HAVE_WINDOW_SYSTEM -extern struct frame *make_minibuffer_frame (void); -extern struct frame *make_frame_without_minibuffer (Lisp_Object, - struct kboard *, - Lisp_Object); extern bool display_available (void); #endif +struct frame *make_minibuffer_frame (void); +struct frame * +make_frame_without_minibuffer (Lisp_Object mini_window, + KBOARD *kb, Lisp_Object display); + INLINE bool window_system_available (struct frame *f) { @@ -1522,6 +1517,8 @@ window_system_available (struct frame *f) } extern WINDOW_SYSTEM_RETURN void check_window_system (struct frame *); +void check_tty (struct frame *f); +struct frame *decode_tty_frame (Lisp_Object frame); extern void frame_make_pointer_invisible (struct frame *); extern void frame_make_pointer_visible (struct frame *); extern Lisp_Object delete_frame (Lisp_Object, Lisp_Object); @@ -1617,15 +1614,11 @@ FRAME_CHILD_FRAME_BORDER_WIDTH (struct frame *f) INLINE int FRAME_INTERNAL_BORDER_WIDTH (struct frame *f) { -#ifdef HAVE_WINDOW_SYSTEM return (FRAME_PARENT_FRAME(f) ? (FRAME_CHILD_FRAME_BORDER_WIDTH(f) >= 0 ? FRAME_CHILD_FRAME_BORDER_WIDTH(f) : frame_dimension (f->internal_border_width)) : frame_dimension (f->internal_border_width)); -#else - return frame_dimension (f->internal_border_width); -#endif } /* Pixel-size of window divider lines. */ @@ -1880,7 +1873,6 @@ extern Lisp_Object gui_display_get_resource (Display_Info *, extern void set_frame_menubar (struct frame *f, bool deep_p); extern void frame_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y); extern void free_frame_menubar (struct frame *); -extern bool frame_ancestor_p (struct frame *af, struct frame *df); extern enum internal_border_part frame_internal_border_part (struct frame *f, int x, int y); #if defined HAVE_X_WINDOWS @@ -1907,6 +1899,8 @@ gui_set_bitmap_icon (struct frame *f) #endif /* !HAVE_NS */ #endif /* HAVE_WINDOW_SYSTEM */ +extern bool frame_ancestor_p (struct frame *af, struct frame *df); + INLINE void flush_frame (struct frame *f) { diff --git a/src/keyboard.c b/src/keyboard.c index 6d28dca9aeb..bfb5fd3592b 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -5415,7 +5415,7 @@ static const char *const lispy_kana_keys[] = /* You'll notice that this table is arranged to be conveniently indexed by X Windows keysym values. */ -#ifdef HAVE_NS +#if defined HAVE_NS || !defined HAVE_WINDOW_SYSTEM /* FIXME: Why are we using X11 keysym values for NS? */ static #endif diff --git a/src/minibuf.c b/src/minibuf.c index 1f94e0e650e..c8267045397 100644 --- a/src/minibuf.c +++ b/src/minibuf.c @@ -913,7 +913,11 @@ read_minibuf (Lisp_Object map, Lisp_Object initial, Lisp_Object prompt, XWINDOW (minibuf_window)->cursor.hpos = 0; XWINDOW (minibuf_window)->cursor.x = 0; XWINDOW (minibuf_window)->must_be_updated_p = true; - update_frame (XFRAME (selected_frame), true, true); + struct frame *sf = XFRAME (selected_frame); + update_frame (sf, true, true); + if (is_tty_frame (sf)) + combine_updates_for_frame (sf, true, true); + #ifndef HAVE_NTGUI flush_frame (XFRAME (XWINDOW (minibuf_window)->frame)); #else diff --git a/src/nsfns.m b/src/nsfns.m index 3c012ca8f05..1055a4b37df 100644 --- a/src/nsfns.m +++ b/src/nsfns.m @@ -3351,7 +3351,7 @@ DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0, [nswindow orderFront: NSApp]; [nswindow display]; - SET_FRAME_VISIBLE (tip_f, 1); + SET_FRAME_VISIBLE (tip_f, true); unblock_input (); goto start_timer; @@ -3534,7 +3534,7 @@ DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0, [nswindow orderFront: NSApp]; [nswindow display]; - SET_FRAME_VISIBLE (tip_f, YES); + SET_FRAME_VISIBLE (tip_f, true); FRAME_PIXEL_WIDTH (tip_f) = width; FRAME_PIXEL_HEIGHT (tip_f) = height; unblock_input (); diff --git a/src/nsterm.m b/src/nsterm.m index f68a22d9fbc..7ad794b6bdb 100644 --- a/src/nsterm.m +++ b/src/nsterm.m @@ -1505,7 +1505,7 @@ ns_make_frame_visible (struct frame *f) EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f); EmacsWindow *window = (EmacsWindow *)[view window]; - SET_FRAME_VISIBLE (f, 1); + SET_FRAME_VISIBLE (f, true); ns_raise_frame (f, ! FRAME_NO_FOCUS_ON_MAP (f)); /* Making a new frame from a fullscreen frame will make the new frame @@ -1550,7 +1550,7 @@ ns_make_frame_invisible (struct frame *f) check_window_system (f); view = FRAME_NS_VIEW (f); [[view window] orderOut: NSApp]; - SET_FRAME_VISIBLE (f, 0); + SET_FRAME_VISIBLE (f, false); SET_FRAME_ICONIFIED (f, 0); } diff --git a/src/scroll.c b/src/scroll.c index fd2a9e71207..1d01ae90d72 100644 --- a/src/scroll.c +++ b/src/scroll.c @@ -366,7 +366,7 @@ do_scrolling (struct frame *frame, struct glyph_matrix *current_matrix, eassert (copy_from[k] >= 0 && copy_from[k] < window_size); /* Perform the row swizzling. */ - mirrored_line_dance (current_matrix, unchanged_at_top, window_size, + mirrored_line_dance (frame, unchanged_at_top, window_size, copy_from, retained_p); /* Some sanity checks if GLYPH_DEBUG is defined. */ @@ -780,7 +780,7 @@ do_direct_scrolling (struct frame *frame, struct glyph_matrix *current_matrix, copy_from[i] gives the original line to copy to I, and retained_p[copy_from[i]] is zero if line I in the new display is empty. */ - mirrored_line_dance (current_matrix, unchanged_at_top, window_size, + mirrored_line_dance (frame, unchanged_at_top, window_size, copy_from, retained_p); if (terminal_window_p) diff --git a/src/term.c b/src/term.c index 1f524880054..330da251e18 100644 --- a/src/term.c +++ b/src/term.c @@ -65,11 +65,9 @@ static int been_here = -1; #ifndef HAVE_ANDROID static void tty_set_scroll_region (struct frame *f, int start, int stop); -static void turn_on_face (struct frame *, int face_id); -static void turn_off_face (struct frame *, int face_id); +static void turn_on_face (struct frame *f, struct face *face); +static void turn_off_face (struct frame *f, struct face *face); static void tty_turn_off_highlight (struct tty_display_info *); -static void tty_show_cursor (struct tty_display_info *); -static void tty_hide_cursor (struct tty_display_info *); static void tty_background_highlight (struct tty_display_info *tty); static void clear_tty_hooks (struct terminal *terminal); static void set_tty_hooks (struct terminal *terminal); @@ -336,7 +334,7 @@ tty_toggle_highlight (struct tty_display_info *tty) /* Make cursor invisible. */ -static void +void tty_hide_cursor (struct tty_display_info *tty) { if (tty->cursor_hidden == 0) @@ -353,7 +351,7 @@ tty_hide_cursor (struct tty_display_info *tty) /* Ensure that cursor is visible. */ -static void +void tty_show_cursor (struct tty_display_info *tty) { if (tty->cursor_hidden) @@ -788,13 +786,20 @@ tty_write_glyphs (struct frame *f, struct glyph *string, int len) /* Identify a run of glyphs with the same face. */ int face_id = string->face_id; + /* FIXME/tty: it happens that a single glyph's frame is NULL. It + might depend on a tab bar line being present, then switching + from a buffer without header line to one with header line and + opening a child frame. */ + struct frame *face_id_frame = string->frame ? string->frame : f; + for (n = 1; n < stringlen; ++n) - if (string[n].face_id != face_id) + if (string[n].face_id != face_id || string[n].frame != face_id_frame) break; /* Turn appearance modes of the face of the run on. */ tty_highlight_if_desired (tty); - turn_on_face (f, face_id); + struct face *face = FACE_FROM_ID (face_id_frame, face_id); + turn_on_face (f, face); if (n == stringlen) /* This is the last run. */ @@ -812,7 +817,7 @@ tty_write_glyphs (struct frame *f, struct glyph *string, int len) string += n; /* Turn appearance modes off. */ - turn_off_face (f, face_id); + turn_off_face (f, face); tty_turn_off_highlight (tty); } @@ -822,8 +827,8 @@ tty_write_glyphs (struct frame *f, struct glyph *string, int len) #ifndef DOS_NT static void -tty_write_glyphs_with_face (register struct frame *f, register struct glyph *string, - register int len, register int face_id) +tty_write_glyphs_with_face (struct frame *f, struct glyph *string, + int len, struct face *face) { unsigned char *conversion_buffer; struct coding_system *coding; @@ -856,7 +861,7 @@ tty_write_glyphs_with_face (register struct frame *f, register struct glyph *str /* Turn appearance modes of the face. */ tty_highlight_if_desired (tty); - turn_on_face (f, face_id); + turn_on_face (f, face); coding->mode |= CODING_MODE_LAST_BLOCK; conversion_buffer = encode_terminal_code (string, len, coding); @@ -871,7 +876,7 @@ tty_write_glyphs_with_face (register struct frame *f, register struct glyph *str } /* Turn appearance modes off. */ - turn_off_face (f, face_id); + turn_off_face (f, face); tty_turn_off_highlight (tty); cmcheckmagic (tty); @@ -919,6 +924,7 @@ tty_insert_glyphs (struct frame *f, struct glyph *start, int len) while (len-- > 0) { + struct face *face = NULL; OUTPUT1_IF (tty, tty->TS_ins_char); if (!start) { @@ -928,7 +934,10 @@ tty_insert_glyphs (struct frame *f, struct glyph *start, int len) else { tty_highlight_if_desired (tty); - turn_on_face (f, start->face_id); + int face_id = start->face_id; + struct frame *face_id_frame = start->frame; + face = FACE_FROM_ID (face_id_frame, face_id); + turn_on_face (f, face); glyph = start; ++start; /* We must open sufficient space for a character which @@ -957,9 +966,9 @@ tty_insert_glyphs (struct frame *f, struct glyph *start, int len) } OUTPUT1_IF (tty, tty->TS_pad_inserted_char); - if (start) + if (face) { - turn_off_face (f, glyph->face_id); + turn_off_face (f, face); tty_turn_off_highlight (tty); } } @@ -1542,6 +1551,7 @@ append_glyph (struct it *it) glyph->type = CHAR_GLYPH; glyph->pixel_width = 1; glyph->u.ch = it->char_to_display; + glyph->frame = it->f; glyph->face_id = it->face_id; glyph->avoid_cursor_p = it->avoid_cursor_p; glyph->multibyte_p = it->multibyte_p; @@ -1769,6 +1779,7 @@ append_composite_glyph (struct it *it) glyph->avoid_cursor_p = it->avoid_cursor_p; glyph->multibyte_p = it->multibyte_p; + glyph->frame = it->f; glyph->face_id = it->face_id; glyph->padding_p = false; glyph->charpos = CHARPOS (it->position); @@ -1855,6 +1866,7 @@ append_glyphless_glyph (struct it *it, int face_id, const char *str) glyph->pixel_width = 1; glyph->avoid_cursor_p = it->avoid_cursor_p; glyph->multibyte_p = it->multibyte_p; + glyph->frame = it->f; glyph->face_id = face_id; glyph->padding_p = false; glyph->charpos = CHARPOS (it->position); @@ -1981,9 +1993,8 @@ produce_glyphless_glyph (struct it *it, Lisp_Object acronym) FACE_ID is a realized face ID number, in the face cache. */ static void -turn_on_face (struct frame *f, int face_id) +turn_on_face (struct frame *f, struct face *face) { - struct face *face = FACE_FROM_ID (f, face_id); unsigned long fg = face->foreground; unsigned long bg = face->background; struct tty_display_info *tty = FRAME_TTY (f); @@ -2064,9 +2075,8 @@ turn_on_face (struct frame *f, int face_id) /* Turn off appearances of face FACE_ID on tty frame F. */ static void -turn_off_face (struct frame *f, int face_id) +turn_off_face (struct frame *f, struct face *face) { - struct face *face = FACE_FROM_ID (f, face_id); struct tty_display_info *tty = FRAME_TTY (f); if (tty->TS_exit_attribute_mode) @@ -2399,8 +2409,10 @@ A suspended tty may be resumed by calling `resume-tty' on it. */) t->display_info.tty->output = 0; if (FRAMEP (t->display_info.tty->top_frame)) - SET_FRAME_VISIBLE (XFRAME (t->display_info.tty->top_frame), 0); - + { + struct frame *top = XFRAME (t->display_info.tty->top_frame); + SET_FRAME_VISIBLE (root_frame (top), false); + } } /* Clear display hooks to prevent further output. */ @@ -2472,7 +2484,8 @@ frame's terminal). */) if (FRAMEP (t->display_info.tty->top_frame)) { - struct frame *f = XFRAME (t->display_info.tty->top_frame); + struct frame *top = XFRAME (t->display_info.tty->top_frame); + struct frame *f = root_frame (top); int width, height; int old_height = FRAME_COLS (f); int old_width = FRAME_TOTAL_LINES (f); @@ -2482,7 +2495,7 @@ frame's terminal). */) get_tty_size (fileno (t->display_info.tty->input), &width, &height); if (width != old_width || height != old_height) change_frame_size (f, width, height, false, false, false); - SET_FRAME_VISIBLE (XFRAME (t->display_info.tty->top_frame), 1); + SET_FRAME_VISIBLE (f, true); } set_tty_hooks (t); @@ -2563,22 +2576,24 @@ tty_draw_row_with_mouse_face (struct window *w, struct glyph_row *row, struct frame *f = XFRAME (WINDOW_FRAME (w)); struct tty_display_info *tty = FRAME_TTY (f); int face_id = tty->mouse_highlight.mouse_face_face_id; - int save_x, save_y, pos_x, pos_y; if (end_hpos >= row->used[TEXT_AREA]) nglyphs = row->used[TEXT_AREA] - start_hpos; - pos_y = row->y + WINDOW_TOP_EDGE_Y (w); - pos_x = row->used[LEFT_MARGIN_AREA] + start_hpos + WINDOW_LEFT_EDGE_X (w); + int pos_y = row->y + WINDOW_TOP_EDGE_Y (w); + int pos_x = row->used[LEFT_MARGIN_AREA] + start_hpos + WINDOW_LEFT_EDGE_X (w); /* Save current cursor coordinates. */ - save_y = curY (tty); - save_x = curX (tty); + int save_y = curY (tty); + int save_x = curX (tty); cursor_to (f, pos_y, pos_x); if (draw == DRAW_MOUSE_FACE) - tty_write_glyphs_with_face (f, row->glyphs[TEXT_AREA] + start_hpos, - nglyphs, face_id); + { + struct glyph *glyph = row->glyphs[TEXT_AREA] + start_hpos; + struct face *face = FACE_FROM_ID (f, face_id); + tty_write_glyphs_with_face (f, glyph, nglyphs, face); + } else if (draw == DRAW_NORMAL_TEXT) write_glyphs (f, row->glyphs[TEXT_AREA] + start_hpos, nglyphs); @@ -3969,7 +3984,7 @@ tty_free_frame_resources (struct frame *f) #endif - + #ifndef HAVE_ANDROID @@ -4044,6 +4059,8 @@ set_tty_hooks (struct terminal *terminal) terminal->read_socket_hook = &tty_read_avail_input; /* keyboard.c */ terminal->delete_frame_hook = &tty_free_frame_resources; terminal->delete_terminal_hook = &delete_tty; + + terminal->frame_raise_lower_hook = tty_raise_lower_frame; /* Other hooks are NULL by default. */ } @@ -4714,6 +4731,184 @@ delete_tty (struct terminal *terminal) #endif +/* Return geometric attributes of FRAME. According to the value of + ATTRIBUTES return the outer edges of FRAME (Qouter_edges), the + native edges of FRAME (Qnative_edges), or the inner edges of frame + (Qinner_edges). Any other value means to return the geometry as + returned by Fx_frame_geometry. */ + +static Lisp_Object +tty_frame_geometry (Lisp_Object frame, Lisp_Object attribute) +{ + struct frame *f = decode_live_frame (frame); + if (FRAME_INITIAL_P (f) || !FRAME_TTY (f)) + return Qnil; + + int native_width = f->pixel_width; + int native_height = f->pixel_height; + + eassert (FRAME_PARENT_FRAME (f) || (f->left_pos == 0 && f->top_pos == 0)); + int outer_left = f->left_pos; + int outer_top = f->top_pos; + int outer_right = outer_left + native_width; + int outer_bottom = outer_top + native_height; + + int native_left = outer_left; + int native_top = outer_top; + int native_right = outer_right; + int native_bottom = outer_bottom; + + int internal_border_width = FRAME_INTERNAL_BORDER_WIDTH (f); + int inner_left = native_left + internal_border_width; + int inner_top = native_top + internal_border_width; + int inner_right = native_right - internal_border_width; + int inner_bottom = native_bottom - internal_border_width; + + int menu_bar_height = FRAME_MENU_BAR_HEIGHT (f); + inner_top += menu_bar_height; + int menu_bar_width = menu_bar_height ? native_width : 0; + + int tab_bar_height = FRAME_TAB_BAR_HEIGHT (f); + int tab_bar_width = (tab_bar_height + ? native_width - 2 * internal_border_width + : 0); + inner_top += tab_bar_height; + + int tool_bar_height = FRAME_TOOL_BAR_HEIGHT (f); + int tool_bar_width = (tool_bar_height + ? native_width - 2 * internal_border_width + : 0); + + /* Subtract or add to the inner dimensions based on the tool bar + position. */ + if (EQ (FRAME_TOOL_BAR_POSITION (f), Qtop)) + inner_top += tool_bar_height; + else + inner_bottom -= tool_bar_height; + + /* Construct list. */ + if (EQ (attribute, Qouter_edges)) + return list4i (outer_left, outer_top, outer_right, outer_bottom); + else if (EQ (attribute, Qnative_edges)) + return list4i (native_left, native_top, native_right, native_bottom); + else if (EQ (attribute, Qinner_edges)) + return list4i (inner_left, inner_top, inner_right, inner_bottom); + else + return list (Fcons (Qouter_position, Fcons (make_fixnum (outer_left), + make_fixnum (outer_top))), + Fcons (Qouter_size, + Fcons (make_fixnum (outer_right - outer_left), + make_fixnum (outer_bottom - outer_top))), + Fcons (Qouter_border_width, make_fixnum (0)), + Fcons (Qexternal_border_size, + Fcons (make_fixnum (0), make_fixnum (0))), + Fcons (Qtitle_bar_size, + Fcons (make_fixnum (0), make_fixnum (0))), + Fcons (Qmenu_bar_external, Qnil), + Fcons (Qmenu_bar_size, + Fcons (make_fixnum (menu_bar_width), + make_fixnum (menu_bar_height))), + Fcons (Qtab_bar_size, + Fcons (make_fixnum (tab_bar_width), + make_fixnum (tab_bar_height))), + Fcons (Qtool_bar_external, Qnil), + Fcons (Qtool_bar_position, FRAME_TOOL_BAR_POSITION (f)), + Fcons (Qtool_bar_size, + Fcons (make_fixnum (tool_bar_width), + make_fixnum (tool_bar_height))), + Fcons (Qinternal_border_width, + make_fixnum (internal_border_width))); +} + +DEFUN ("tty-frame-geometry", Ftty_frame_geometry, Stty_frame_geometry, 0, 1, 0, + doc: /* Return geometric attributes of terminal frame FRAME. + See also `frame-geometry'. */) + (Lisp_Object frame) +{ + return tty_frame_geometry (frame, Qnil); +} + +DEFUN ("tty-frame-edges", Ftty_frame_edges, Stty_frame_edges, 0, 2, 0, + doc: /* Return coordinates of FRAME's edges. + See also `frame-edges'. */) + (Lisp_Object frame, Lisp_Object type) +{ + if (!EQ (type, Qouter_edges) && !EQ (type, Qinner_edges)) + type = Qnative_edges; + return tty_frame_geometry (frame, type); +} + +DEFUN ("tty-frame-list-z-order", Ftty_frame_list_z_order, + Stty_frame_list_z_order, 0, 1, 0, + doc: /* Return list of Emacs's frames, in Z (stacking) order. + See also `frame-list-z-order'. */) + (Lisp_Object frame) +{ + struct frame *f = decode_tty_frame (frame); + Lisp_Object frames = frames_in_reverse_z_order (f, true); + return Fnreverse (frames); +} + +DEFUN ("tty-frame-restack", Ftty_frame_restack, + Stty_frame_restack, 2, 3, 0, + doc: /* Restack FRAME1 below FRAME2 on terminals. +. See also `frame-restack'. */) + (Lisp_Object frame1, Lisp_Object frame2, Lisp_Object above) +{ + /* FIXME/tty: tty-frame-restack implementation. */ + return Qnil; +} + +static void +tty_display_dimension (Lisp_Object frame, int *width, int *height) +{ + if (!FRAMEP (frame)) + frame = Fselected_frame (); + struct frame *f = XFRAME (frame); + switch (f->output_method) + { + case output_initial: + *width = 80; + *height = 25; + break; + case output_termcap: + *width = FrameCols (FRAME_TTY (f)); + *height = FrameRows (FRAME_TTY (f)); + break; + case output_x_window: + case output_msdos_raw: + case output_w32: + case output_ns: + case output_pgtk: + case output_haiku: + case output_android: + emacs_abort (); + break; + } +} + +DEFUN ("tty-display-pixel-width", Ftty_display_pixel_width, + Stty_display_pixel_width, 0, 1, 0, + doc: /* Return the width of DISPLAY's screen in pixels. +. See also `display-pixel-width'. */) + (Lisp_Object display) +{ + int width, height; + tty_display_dimension (display, &width, &height); + return make_fixnum (width); +} + +DEFUN ("tty-display-pixel-height", Ftty_display_pixel_height, + Stty_display_pixel_height, 0, 1, 0, + doc: /* Return the height of DISPLAY's screen in pixels. + See also `display-pixel-height'. */) + (Lisp_Object display) +{ + int width, height; + tty_display_dimension (display, &width, &height); + return make_fixnum (height); +} + void syms_of_term (void) { @@ -4770,6 +4965,13 @@ trigger redisplay. */); defsubr (&Sgpm_mouse_stop); #endif /* HAVE_GPM */ + defsubr (&Stty_frame_geometry); + defsubr (&Stty_frame_edges); + defsubr (&Stty_frame_list_z_order); + defsubr (&Stty_frame_restack); + defsubr (&Stty_display_pixel_width); + defsubr (&Stty_display_pixel_height); + #if !defined DOS_NT && !defined HAVE_ANDROID default_orig_pair = NULL; default_set_foreground = NULL; diff --git a/src/termhooks.h b/src/termhooks.h index d6a9300bac9..1c2cd46e44e 100644 --- a/src/termhooks.h +++ b/src/termhooks.h @@ -974,6 +974,9 @@ extern int cursorY (struct tty_display_info *); #define cursorY(t) curY(t) #endif +void tty_hide_cursor (struct tty_display_info *tty); +void tty_show_cursor (struct tty_display_info *tty); + INLINE_HEADER_END #endif /* EMACS_TERMHOOKS_H */ diff --git a/src/terminal.c b/src/terminal.c index 5c21341d905..ad488ea3b52 100644 --- a/src/terminal.c +++ b/src/terminal.c @@ -111,7 +111,8 @@ void cursor_to (struct frame *f, int vpos, int hpos) { if (FRAME_TERMINAL (f)->cursor_to_hook) - (*FRAME_TERMINAL (f)->cursor_to_hook) (f, vpos, hpos); + (*FRAME_TERMINAL (f)->cursor_to_hook) (f, vpos + f->top_pos, + hpos + f->left_pos); } /* Similar but don't take any account of the wasted characters. */ @@ -120,7 +121,8 @@ void raw_cursor_to (struct frame *f, int row, int col) { if (FRAME_TERMINAL (f)->raw_cursor_to_hook) - (*FRAME_TERMINAL (f)->raw_cursor_to_hook) (f, row, col); + (*FRAME_TERMINAL (f)->raw_cursor_to_hook) (f, row + f->top_pos, + col + f->left_pos); } /* Erase operations. */ diff --git a/src/xdisp.c b/src/xdisp.c index c74e81a3933..935c75a8230 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -943,7 +943,7 @@ redisplay_trace (char const *fmt, ...) { va_list ap; va_start (ap, fmt); - vprintf (fmt, ap); + vfprintf (stderr, fmt, ap); va_end (ap); } } @@ -961,7 +961,7 @@ move_trace (char const *fmt, ...) { va_list ap; va_start (ap, fmt); - vprintf (fmt, ap); + vfprintf (stderr, fmt, ap); va_end (ap); } } @@ -3348,9 +3348,7 @@ init_iterator (struct it *it, struct window *w, of the iterator's frame, when set, suppresses their display - by default for tooltip frames and when set via the 'no-special-glyphs' frame parameter. */ -#ifdef HAVE_WINDOW_SYSTEM - if (!(FRAME_WINDOW_P (it->f) && it->f->no_special_glyphs)) -#endif + if (!it->f->no_special_glyphs) { if (it->line_wrap == TRUNCATE) { @@ -13554,7 +13552,11 @@ echo_area_display (bool update_frame_p) flush_frame (f); } else - update_frame (f, true, true); + { + update_frame (f, true, true); + if (is_tty_frame (f)) + combine_updates_for_frame (f, true, true); + } /* If cursor is in the echo area, make sure that the next redisplay displays the minibuffer, so that the cursor will @@ -17033,6 +17035,9 @@ redisplay_internal (void) if (face_change) windows_or_buffers_changed = 47; + /* Can we do better for tty child frames? It could be + a bit faster when we switch between child frames of the same + root frame. OTOH, it's probably not a frequent use case. */ if ((FRAME_TERMCAP_P (sf) || FRAME_MSDOS_P (sf)) && FRAME_TTY (sf)->previous_frame != sf) { @@ -17055,6 +17060,7 @@ redisplay_internal (void) { struct frame *f = XFRAME (frame); + /* FRAME_REDISPLAY_P true basically means the frame is visible. */ if (FRAME_REDISPLAY_P (f)) { ++number_of_visible_frames; @@ -17198,7 +17204,6 @@ redisplay_internal (void) && !current_buffer->clip_changed && !current_buffer->prevent_redisplay_optimizations_p && FRAME_REDISPLAY_P (XFRAME (w->frame)) - && !FRAME_OBSCURED_P (XFRAME (w->frame)) && !XFRAME (w->frame)->cursor_type_changed && !XFRAME (w->frame)->face_change /* Make sure recorded data applies to current buffer, etc. */ @@ -17447,22 +17452,35 @@ redisplay_internal (void) propagate_buffer_redisplay (); + Lisp_Object tty_root_frames = Qnil; FOR_EACH_FRAME (tail, frame) { struct frame *f = XFRAME (frame); - /* We don't have to do anything for unselected terminal - frames. */ - if ((FRAME_TERMCAP_P (f) || FRAME_MSDOS_P (f)) - && !EQ (FRAME_TTY (f)->top_frame, frame)) - continue; + if (is_tty_frame (f)) + { + /* Ignore all invisble tty frames, children or root. */ + if (!FRAME_VISIBLE_P (root_frame (f))) + continue; + + /* Remember tty root frames seen. */ + if (!FRAME_PARENT_FRAME (f)) + { + Lisp_Object found; + for (found = tty_root_frames; + CONSP (found) && !EQ (XCAR (found), frame); + found = XCDR (found)) + ; + if (!CONSP (found)) + tty_root_frames = Fcons (frame, tty_root_frames); + } + } retry_frame: if (FRAME_WINDOW_P (f) || FRAME_TERMCAP_P (f) || f == sf) { - bool gcscrollbars - /* Only GC scrollbars when we redisplay the whole frame. */ - = f->redisplay || !REDISPLAY_SOME_P (); + /* Only GC scrollbars when we redisplay the whole frame. */ + bool gcscrollbars = f->redisplay || !REDISPLAY_SOME_P (); bool f_redisplay_flag = f->redisplay; /* The X error handler may have deleted that frame before @@ -17479,7 +17497,7 @@ redisplay_internal (void) if (gcscrollbars && FRAME_TERMINAL (f)->condemn_scroll_bars_hook) FRAME_TERMINAL (f)->condemn_scroll_bars_hook (f); - if (FRAME_REDISPLAY_P (f) && !FRAME_OBSCURED_P (f)) + if (FRAME_REDISPLAY_P (f)) { /* Don't allow freeing images and faces for this frame as long as the frame's update wasn't @@ -17505,7 +17523,7 @@ redisplay_internal (void) if (gcscrollbars && FRAME_TERMINAL (f)->judge_scroll_bars_hook) FRAME_TERMINAL (f)->judge_scroll_bars_hook (f); - if (FRAME_REDISPLAY_P (f) && !FRAME_OBSCURED_P (f)) + if (FRAME_REDISPLAY_P (f)) { /* If fonts changed on visible frame, display again. */ if (f->fonts_changed) @@ -17590,6 +17608,9 @@ redisplay_internal (void) } } + if (CONSP (tty_root_frames)) + pending |= combine_updates (tty_root_frames, false, false); + eassert (EQ (XFRAME (selected_frame)->selected_window, selected_window)); if (!pending) @@ -17611,7 +17632,7 @@ redisplay_internal (void) } } } - else if (FRAME_REDISPLAY_P (sf) && !FRAME_OBSCURED_P (sf)) + else if (FRAME_REDISPLAY_P (sf)) { sf->inhibit_clear_image_cache = true; displayed_buffer = XBUFFER (XWINDOW (selected_window)->contents); @@ -17662,7 +17683,7 @@ redisplay_internal (void) unrequest_sigio (); STOP_POLLING; - if (FRAME_REDISPLAY_P (sf) && !FRAME_OBSCURED_P (sf)) + if (FRAME_REDISPLAY_P (sf)) { if (hscroll_retries <= MAX_HSCROLL_RETRIES && hscroll_windows (selected_window)) @@ -17673,6 +17694,10 @@ redisplay_internal (void) XWINDOW (selected_window)->must_be_updated_p = true; pending = update_frame (sf, false, false); + + if (is_tty_frame (sf)) + pending |= combine_updates_for_frame (sf, false, false); + sf->cursor_type_changed = false; sf->inhibit_clear_image_cache = false; } @@ -17685,10 +17710,12 @@ redisplay_internal (void) Lisp_Object mini_window = FRAME_MINIBUF_WINDOW (sf); struct frame *mini_frame = XFRAME (WINDOW_FRAME (XWINDOW (mini_window))); - if (mini_frame != sf && FRAME_WINDOW_P (mini_frame)) + if (mini_frame != sf) { XWINDOW (mini_window)->must_be_updated_p = true; pending |= update_frame (mini_frame, false, false); + if (is_tty_frame (mini_frame)) + pending |= combine_updates_for_frame (mini_frame, false, false); mini_frame->cursor_type_changed = false; if (!pending && hscroll_retries <= MAX_HSCROLL_RETRIES && hscroll_windows (mini_window)) @@ -23975,6 +24002,7 @@ extend_face_to_end_of_line (struct it *it) { it->glyph_row->glyphs[TEXT_AREA][0] = space_glyph; it->glyph_row->glyphs[TEXT_AREA][0].face_id = face->id; + it->glyph_row->glyphs[TEXT_AREA][0].frame = f; it->glyph_row->used[TEXT_AREA] = 1; } /* Mode line and the header line don't have margins, and @@ -23994,6 +24022,7 @@ extend_face_to_end_of_line (struct it *it) it->glyph_row->glyphs[LEFT_MARGIN_AREA][0] = space_glyph; it->glyph_row->glyphs[LEFT_MARGIN_AREA][0].face_id = default_face->id; + it->glyph_row->glyphs[LEFT_MARGIN_AREA][0].frame = f; it->glyph_row->used[LEFT_MARGIN_AREA] = 1; } if (WINDOW_RIGHT_MARGIN_WIDTH (it->w) > 0 @@ -24002,6 +24031,7 @@ extend_face_to_end_of_line (struct it *it) it->glyph_row->glyphs[RIGHT_MARGIN_AREA][0] = space_glyph; it->glyph_row->glyphs[RIGHT_MARGIN_AREA][0].face_id = default_face->id; + it->glyph_row->glyphs[RIGHT_MARGIN_AREA][0].frame = f; it->glyph_row->used[RIGHT_MARGIN_AREA] = 1; } @@ -24366,9 +24396,11 @@ highlight_trailing_whitespace (struct it *it) while (glyph >= start && BUFFERP (glyph->object) && (glyph->type == STRETCH_GLYPH - || (glyph->type == CHAR_GLYPH - && glyph->u.ch == ' '))) - (glyph--)->face_id = face_id; + || (glyph->type == CHAR_GLYPH && glyph->u.ch == ' '))) + { + glyph->frame = it->f; + (glyph--)->face_id = face_id; + } } else { @@ -24377,7 +24409,10 @@ highlight_trailing_whitespace (struct it *it) && (glyph->type == STRETCH_GLYPH || (glyph->type == CHAR_GLYPH && glyph->u.ch == ' '))) - (glyph++)->face_id = face_id; + { + glyph->frame = it->f; + (glyph++)->face_id = face_id; + } } } } @@ -27230,7 +27265,7 @@ display_menu_bar (struct window *w) /* Deep copy of a glyph row, including the glyphs. */ static void -deep_copy_glyph_row (struct glyph_row *to, struct glyph_row *from) +deep_copy_glyph_row (struct frame *f, struct glyph_row *to, struct glyph_row *from) { struct glyph *pointers[1 + LAST_AREA]; int to_used = to->used[TEXT_AREA]; @@ -27251,7 +27286,7 @@ deep_copy_glyph_row (struct glyph_row *to, struct glyph_row *from) /* If we filled only part of the TO row, fill the rest with space_glyph (which will display as empty space). */ if (to_used > from->used[TEXT_AREA]) - fill_up_frame_row_with_spaces (to, to_used); + fill_up_frame_row_with_spaces (f, to, to_used); } /* Display one menu item on a TTY, by overwriting the glyphs in the @@ -27300,7 +27335,7 @@ display_tty_menu_item (const char *item_text, int width, int face_id, it.last_visible_x = FRAME_COLS (f) - 1; row = it.glyph_row; /* Start with the row contents from the current matrix. */ - deep_copy_glyph_row (row, f->current_matrix->rows + y); + deep_copy_glyph_row (f, row, f->current_matrix->rows + y); bool saved_width = row->full_width_p; row->full_width_p = true; bool saved_reversed = row->reversed_p; diff --git a/src/xfaces.c b/src/xfaces.c index e248279e9b7..fd321734d14 100644 --- a/src/xfaces.c +++ b/src/xfaces.c @@ -696,7 +696,6 @@ void free_frame_faces (struct frame *f) { struct face_cache *face_cache = FRAME_FACE_CACHE (f); - if (face_cache) { free_face_cache (face_cache); From 5445062fabc765b316ecedc26bbb395c75d44405 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerd=20M=C3=B6llmann?= Date: Thu, 17 Oct 2024 20:02:57 +0200 Subject: [PATCH 02/53] Check for tty-child-frames feature in show-paren * lisp/paren.el (show-paren-function): Don't rely on display-graphic-p, also check tty-child-frames feature. --- lisp/paren.el | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lisp/paren.el b/lisp/paren.el index cb29b8311a5..6e1111779fa 100644 --- a/lisp/paren.el +++ b/lisp/paren.el @@ -524,7 +524,8 @@ It is the default value of `show-paren-data-function'." (cond ((and (eq show-paren-context-when-offscreen 'child-frame) - (display-graphic-p)) + (or (display-graphic-p) + (featurep 'tty-child-frames))) (show-paren--show-context-in-child-frame context)) ((eq show-paren-context-when-offscreen 'overlay) (show-paren--show-context-in-overlay context)) From 55b72ad87554e3de518366754da64dad239a04bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerd=20M=C3=B6llmann?= Date: Fri, 18 Oct 2024 14:58:48 +0200 Subject: [PATCH 03/53] Set top terminal frame also to children * src/frame.c (make_terminal_frame): Don't check for being root when setting top_frame. --- src/frame.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/frame.c b/src/frame.c index 8133b646216..4724ff1ae67 100644 --- a/src/frame.c +++ b/src/frame.c @@ -1373,8 +1373,7 @@ make_terminal_frame (struct terminal *terminal, Lisp_Object parent, } /* Set the top frame to the newly created frame. */ - if (!FRAME_PARENT_FRAME (f)) - FRAME_TTY (f)->top_frame = frame; + FRAME_TTY (f)->top_frame = frame; return f; } From e0ca1256a5747470f3867b231524cc93b87ca2f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerd=20M=C3=B6llmann?= Date: Fri, 18 Oct 2024 14:59:36 +0200 Subject: [PATCH 04/53] Don't check for child frame support * lisp/paren.el (show-paren-function): Don't check with display-graphics-p or featurep. --- lisp/paren.el | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/lisp/paren.el b/lisp/paren.el index 6e1111779fa..7661e8efbf1 100644 --- a/lisp/paren.el +++ b/lisp/paren.el @@ -522,10 +522,7 @@ It is the default value of `show-paren-data-function'." openparen)) (message-log-max nil)) (cond - ((and - (eq show-paren-context-when-offscreen 'child-frame) - (or (display-graphic-p) - (featurep 'tty-child-frames))) + ((eq show-paren-context-when-offscreen 'child-frame) (show-paren--show-context-in-child-frame context)) ((eq show-paren-context-when-offscreen 'overlay) (show-paren--show-context-in-overlay context)) From 23409041b135d7b89dcb010a7f22ce9c817d8c76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerd=20M=C3=B6llmann?= Date: Fri, 18 Oct 2024 15:25:10 +0200 Subject: [PATCH 05/53] Accept frame param width/height of 0 * src/frame.c (tty_child_size_param): Accept values of 0. --- src/frame.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/frame.c b/src/frame.c index 4724ff1ae67..5f07f8e8976 100644 --- a/src/frame.c +++ b/src/frame.c @@ -1443,7 +1443,7 @@ tty_child_size_param (struct frame *child, Lisp_Object key, val = make_fixnum (XFLOAT_DATA (val) * sz); } - if (FIXNUMP (val) && XFIXNUM (val) > 0) + if (FIXNUMP (val) && XFIXNUM (val) >= 0) return XFIXNUM (val); } return dflt; From 6aa203bb04fa75e7562064e9261d7760c1b6562a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerd=20M=C3=B6llmann?= Date: Fri, 18 Oct 2024 16:21:46 +0200 Subject: [PATCH 06/53] Minor refactoring --- src/frame.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/frame.c b/src/frame.c index 5f07f8e8976..69ffc53ebbf 100644 --- a/src/frame.c +++ b/src/frame.c @@ -1435,23 +1435,23 @@ tty_child_size_param (struct frame *child, Lisp_Object key, } else if (FLOATP (val)) { - /* Width and height may be a float, in which case - it's a multiple of the parent's value. */ - struct frame *parent = FRAME_PARENT_FRAME (child); - int sz = (EQ (key, Qwidth) ? FRAME_TOTAL_COLS (parent) - : FRAME_TOTAL_LINES (parent)); - val = make_fixnum (XFLOAT_DATA (val) * sz); + /* Width and height may be a float, in which case + it's a multiple of the parent's value. */ + struct frame *parent = FRAME_PARENT_FRAME (child); + int sz = (EQ (key, Qwidth) ? FRAME_TOTAL_COLS (parent) + : FRAME_TOTAL_LINES (parent)); + val = make_fixnum (XFLOAT_DATA (val) * sz); } - if (FIXNUMP (val) && XFIXNUM (val) >= 0) + if (FIXNATP (val)) return XFIXNUM (val); } return dflt; } static void -child_frame_rect (struct frame *f, Lisp_Object params, - int *x, int *y, int *w, int *h) +tty_child_frame_rect (struct frame *f, Lisp_Object params, + int *x, int *y, int *w, int *h) { *x = tty_child_pos_param (f, Qleft, params, 0); *y = tty_child_pos_param (f, Qtop, params, 0); @@ -1585,7 +1585,7 @@ affects all frames on the same terminal device. */) terminal size). */ int x = 0, y = 0, width, height; if (FRAME_PARENT_FRAME (f)) - child_frame_rect (f, parms, &x, &y, &width, &height); + tty_child_frame_rect (f, parms, &x, &y, &width, &height); else get_tty_size (fileno (FRAME_TTY (f)->input), &width, &height); adjust_frame_size (f, width, height - FRAME_TOP_MARGIN (f), 5, 0, From 0012e555d963b1df2d2c8be9f515ddf09417e110 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerd=20M=C3=B6llmann?= Date: Mon, 21 Oct 2024 11:21:17 +0200 Subject: [PATCH 07/53] Don't set internal_last_event_frame to nil * src/frame.c (do_switch_frame): Do not set internal_last_event_frame to nil on ttys. --- src/frame.c | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/src/frame.c b/src/frame.c index 69ffc53ebbf..1cdd923150d 100644 --- a/src/frame.c +++ b/src/frame.c @@ -1792,8 +1792,29 @@ do_switch_frame (Lisp_Object frame, int track, int for_deletion, Lisp_Object nor (select-window (frame-root-window (make-frame))) doesn't end up with your typing being interpreted in the new frame instead of the one you're actually typing in. */ - if (!frame_ancestor_p (f, sf)) - internal_last_event_frame = Qnil; + + /* FIXME/tty: I don't understand this. Setting the last event + frame to nil leads to switch-frame events being generated even + if they normally wouldn't because the frame in question equals + selected-frame. This leads to problems at least on ttys. + + Imagine that we have functions on post-command-hook that use + with-selected-window (which is the case with Vertico-Posframe), + Secondly, let these functions select/restore windows on different + frames, so there will be select-frame calls with different frames + during the execution of post-command-hook. Setting + internal_last_event_frame to nil makes these select-frame calls + potentially generate switch-frame events (but only in one direction + (frame_ancestor_p), which I also don't understand). + + These switch-frame events form an endless loop in command_loop_1 by + running post-command-hook, which generates switch-frame events, + which command_loop_1 finds (bound to '#ignore) and executes, which + again runs post-command-hook etc. ad infinitum. */ + + if (!is_tty_frame (f)) + if (!frame_ancestor_p (f, sf)) + internal_last_event_frame = Qnil; return frame; } From 4a3ba42e6f86fa85b457bdeba9e08ccb4219107d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerd=20M=C3=B6llmann?= Date: Mon, 21 Oct 2024 15:40:15 +0200 Subject: [PATCH 08/53] Comment --- src/frame.c | 44 ++++++++++++++++++++++++-------------------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/src/frame.c b/src/frame.c index 1cdd923150d..25c307b3c6a 100644 --- a/src/frame.c +++ b/src/frame.c @@ -1563,14 +1563,11 @@ affects all frames on the same terminal device. */) if (CONSP (undecorated) && !NILP (XCDR (undecorated))) f->undecorated = true; - /* FIXME/tty: The only way to get borders on a tty is - to allow decorations for now. */ + /* Unused at present. */ Lisp_Object no_focus = Fassq (Qno_accept_focus, parms); if (CONSP (no_focus) && !NILP (XCDR (no_focus))) f->no_accept_focus = true; - /* FIXME/tty: The only way to get borders on a tty is - to allow decorations for now. */ Lisp_Object no_split = Fassq (Qunsplittable, parms); if (CONSP (no_split) && !NILP (XCDR (no_split))) f->no_split = true; @@ -1793,25 +1790,32 @@ do_switch_frame (Lisp_Object frame, int track, int for_deletion, Lisp_Object nor with your typing being interpreted in the new frame instead of the one you're actually typing in. */ - /* FIXME/tty: I don't understand this. Setting the last event - frame to nil leads to switch-frame events being generated even - if they normally wouldn't because the frame in question equals - selected-frame. This leads to problems at least on ttys. + /* FIXME/tty: I don't understand this. (The comment aove is from + Jim BLandy 1993 BTW.) - Imagine that we have functions on post-command-hook that use - with-selected-window (which is the case with Vertico-Posframe), - Secondly, let these functions select/restore windows on different - frames, so there will be select-frame calls with different frames - during the execution of post-command-hook. Setting - internal_last_event_frame to nil makes these select-frame calls - potentially generate switch-frame events (but only in one direction - (frame_ancestor_p), which I also don't understand). + Setting the last event frame to nil leads to switch-frame events + being generated even if they normally wouldn't be because the frame + in question equals selected-frame. See the places in keyboard.c + where make_lispy_switch_frame is called. - These switch-frame events form an endless loop in command_loop_1 by - running post-command-hook, which generates switch-frame events, - which command_loop_1 finds (bound to '#ignore) and executes, which - again runs post-command-hook etc. ad infinitum. */ + This leads to problems at least on ttys. + Imagine that we have functions in post-command-hook that use + select-frame in some way (e.g. with-selected-window). Let these + functions select different frames during the execution of + post-command-hook in command_loop_1. Setting + internal_last_event_frame to nil here makes these select-frame + calls (potentially, and reality) generate switch-frame events. (But + only in one direction (frame_ancestor_p), which I also don't + understand). + + These switch-frame events form an endless loop in + command_loop_1. It runs post-command-hook, which generates + switch-frame events, which command_loop_1 finds (bound to '#ignore) + and executes, which again runs post-command-hook etc. ad + infinitum. + + Let's not do that for now on ttys. */ if (!is_tty_frame (f)) if (!frame_ancestor_p (f, sf)) internal_last_event_frame = Qnil; From fbe63a33f1a0a0df2700245c4cd44cc446ac986e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerd=20M=C3=B6llmann?= Date: Mon, 21 Oct 2024 15:42:03 +0200 Subject: [PATCH 09/53] Comment --- src/frame.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/frame.c b/src/frame.c index 25c307b3c6a..2b90d9b524c 100644 --- a/src/frame.c +++ b/src/frame.c @@ -1790,8 +1790,8 @@ do_switch_frame (Lisp_Object frame, int track, int for_deletion, Lisp_Object nor with your typing being interpreted in the new frame instead of the one you're actually typing in. */ - /* FIXME/tty: I don't understand this. (The comment aove is from - Jim BLandy 1993 BTW.) + /* FIXME/tty: I don't understand this. (The comment above is from + Jim BLandy 1993 BTW, and the frame_ancestor_p from 2017.) Setting the last event frame to nil leads to switch-frame events being generated even if they normally wouldn't be because the frame From 55af24a1c29724401d66ddd485cf6e4776fe5050 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerd=20M=C3=B6llmann?= Date: Mon, 21 Oct 2024 18:50:26 +0200 Subject: [PATCH 10/53] Don't ignore .patch files This is VERY bad for magit users like me. --- .gitignore | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitignore b/.gitignore index c1f31514d06..ccf3f256579 100644 --- a/.gitignore +++ b/.gitignore @@ -323,7 +323,6 @@ gnustmp* *~ \#*\# ChangeLog -[0-9]*.patch [0-9]*.txt /vc-dwim-log-* From 9accfc24bcd82087d936cf7ee37470f86cac8ea7 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Tue, 22 Oct 2024 04:56:19 -0400 Subject: [PATCH 11/53] Fix compilation warnings * src/frame.c (tty_child_size_param): * src/frame.h (MOUSE_HL_INFO): Avoid NULL dereference warnings. --- src/frame.c | 16 +++++++++++----- src/frame.h | 4 +--- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/frame.c b/src/frame.c index 2b90d9b524c..6b7f04aed80 100644 --- a/src/frame.c +++ b/src/frame.c @@ -1428,7 +1428,7 @@ tty_child_size_param (struct frame *child, Lisp_Object key, if (CONSP (val)) { /* Width and height may look like (width text-pixels - . PIXELS) on window systems. Mimic that. */ + . PIXELS) on window systems. Mimic that. */ val = XCDR (val); if (EQ (val, Qtext_pixels)) val = XCDR (val); @@ -1436,11 +1436,17 @@ tty_child_size_param (struct frame *child, Lisp_Object key, else if (FLOATP (val)) { /* Width and height may be a float, in which case - it's a multiple of the parent's value. */ + it's a multiple of the parent's value. */ struct frame *parent = FRAME_PARENT_FRAME (child); - int sz = (EQ (key, Qwidth) ? FRAME_TOTAL_COLS (parent) - : FRAME_TOTAL_LINES (parent)); - val = make_fixnum (XFLOAT_DATA (val) * sz); + eassert (parent); /* the caller ensures this, but... */ + if (parent) + { + int sz = (EQ (key, Qwidth) ? FRAME_TOTAL_COLS (parent) + : FRAME_TOTAL_LINES (parent)); + val = make_fixnum (XFLOAT_DATA (val) * sz); + } + else + val = Qnil; } if (FIXNATP (val)) diff --git a/src/frame.h b/src/frame.h index 0b7368fb29b..9a9d025e638 100644 --- a/src/frame.h +++ b/src/frame.h @@ -1018,9 +1018,7 @@ default_pixels_per_inch_y (void) #ifndef HAVE_ANDROID # define MOUSE_HL_INFO(F) \ (FRAME_WINDOW_P (F) \ - ? (FRAME_OUTPUT_DATA (F) \ - ? &FRAME_DISPLAY_INFO (F)->mouse_highlight \ - : NULL) \ + ? &FRAME_DISPLAY_INFO (F)->mouse_highlight \ : &(F)->output_data.tty->display_info->mouse_highlight) #else /* There is no "struct tty_output" on Android at all. */ From 4ef5ade5da60075418e0f6db1b91ec08a38bb884 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Tue, 22 Oct 2024 05:42:05 -0400 Subject: [PATCH 12/53] Fix commenting conventions. --- src/dispextern.h | 6 +-- src/dispnew.c | 133 ++++++++++++++++++++++++----------------------- src/frame.c | 85 +++++++++++++++--------------- src/frame.h | 2 +- src/term.c | 4 +- src/xdisp.c | 6 +-- 6 files changed, 119 insertions(+), 117 deletions(-) diff --git a/src/dispextern.h b/src/dispextern.h index 468aee8d1ba..c368e665c61 100644 --- a/src/dispextern.h +++ b/src/dispextern.h @@ -482,9 +482,9 @@ struct glyph continuation glyphs, or the overlay-arrow glyphs on TTYs. */ Lisp_Object object; - /* Frame on which the glyph was produced. The face_id of this glyph - refers to the face_cache of this frame. This is used on tty frames - only. */ + /* Frame on which the glyph was produced. The face_id of this glyph + refers to the face_cache of this frame. This is used on tty + frames only. */ struct frame *frame; /* Width in pixels. */ diff --git a/src/dispnew.c b/src/dispnew.c index 26181c36399..200ffaaca21 100644 --- a/src/dispnew.c +++ b/src/dispnew.c @@ -1177,8 +1177,8 @@ line_hash_code (struct frame *f, struct glyph_row *row) int c = glyph->u.ch; int face_id = glyph->face_id; /* Struct frame can move with igc, and so on. But we need - something that takes different frames into account. Use the - face_cache pointer for that which is malloc'd. */ + something that takes different frames into account. Use the + face_cache pointer for that which is malloc'd. */ if (glyph->frame && glyph->frame != f) face_id += (ptrdiff_t) glyph->frame->face_cache; if (FRAME_MUST_WRITE_SPACES (f)) @@ -3195,8 +3195,8 @@ redraw_frame (struct frame *f) future. */ SET_FRAME_GARBAGED (f); - /* Clear_frame is actually a "clear_terminal", i.e. - is clears the entire screen. */ + /* clear_frame is actually a "clear_terminal", i.e. + it clears the entire screen. */ if (!FRAME_PARENT_FRAME (f)) clear_frame (f); clear_current_matrices (f); @@ -3238,37 +3238,37 @@ DEFUN ("redraw-display", Fredraw_display, Sredraw_display, 0, 0, "", TTY Child Frames **********************************************************************/ -/* The new thing that child frames on ttys provide is that frames on a - tty no longer always occupy the whole terminal. They can overlap - instead. +/* Child frames on ttys break the assumption that frames on a tty + always occupy the whole terminal. They can overlap instead. - Let a "root" frame be a frame that has no parent frame. Such root - frames we require to be the size of the terminal screen. The current - glyph matrix of a root frame of a termimnal represents what is on the - screen. The desired matrix of a root frame represents what should be - one the screen. + Let a "root" frame be a frame that has no parent frame. Such root + frames are required to be the size of the terminal screen. The + current glyph matrix of a root frame of a termimnal represents what + is on the screen. The desired matrix of a root frame represents + what should be one the screen. Building the desired matrix of root frame proceeds by - building the desired matrix of the root frame itself which is - the bottommost frame in z-order, - - building desired matrices of child frames in z-order, topmost last, + the bottommost frame in z-order; + - building desired matrices of child frames in z-order, topmost last; - copying the desired glyphs from child frames to the desired glyphs of the root frame - Updating the screen is then done using root frame matrices as it was - before child frames were introduced. Child frame current matrices are - updated by copying glyph contents of the current matrix of the root - frames to the current matrices of child frames. This imnplicitly - also updates the glyph contents of their windows' current matrices. */ + Updating the screen is then done using root frame matrices as it + was before child frames were introduced. Child frame's current + matrices are updated by copying glyph contents of the current + matrix of the root frames to the current matrices of child + frames. This implicitly also updates the glyph contents of their + windows' current matrices. */ struct rect { int x, y, w, h; }; -/* Compute the intersection of R1 and R2 in R. Value is true if R1 and - R2 intersect, false otherwise. */ +/* Compute the intersection of R1 and R2 in R. Value is true if R1 and + R2 intersect, false otherwise. */ static bool rect_intersect (struct rect *r, struct rect r1, struct rect r2) @@ -3285,7 +3285,7 @@ rect_intersect (struct rect *r, struct rect r1, struct rect r2) return true; } -/* Return the absolute position of frame F in *X and *Y. */ +/* Return the absolute position of frame F in *X and *Y. */ static void frame_pos_abs (struct frame *f, int *x, int *y) @@ -3298,7 +3298,8 @@ frame_pos_abs (struct frame *f, int *x, int *y) } } -/* Return the rectangle frame F occupies. X and Y are in absolute coordinates. */ +/* Return the rectangle frame F occupies. X and Y are in absolute + coordinates. */ static struct rect frame_rect_abs (struct frame *f) @@ -3308,9 +3309,9 @@ frame_rect_abs (struct frame *f) return (struct rect) { x, y, f->total_cols, f->total_lines }; } -/* Return the root frame of frame F. Follow the parent_frame chain until - we reach a frame that has no parent. That is the root frame. Note - that the root of a root frame is itself. */ +/* Return the root frame of frame F. Follow the parent_frame chain + until we reach a frame that has no parent. That is the root frame. + Note that the root of a root frame is itself. */ struct frame * root_frame (struct frame *f) @@ -3441,7 +3442,7 @@ tty_raise_lower_frame (struct frame *f, bool raise) f->z_order = raise ? i : 0; } -/* Return true if frame F is a tty frame. */ +/* Return true if frame F is a tty frame. */ bool is_tty_frame (struct frame *f) @@ -3449,7 +3450,7 @@ is_tty_frame (struct frame *f) return FRAME_TERMCAP_P (f); } -/* Return true if frame F is a tty child frame. */ +/* Return true if frame F is a tty child frame. */ bool is_tty_child_frame (struct frame *f) @@ -3457,7 +3458,7 @@ is_tty_child_frame (struct frame *f) return FRAME_PARENT_FRAME (f) && is_tty_frame (f); } -/* Return true if frame F is a tty root frame. */ +/* Return true if frame F is a tty root frame. */ bool is_tty_root_frame (struct frame *f) @@ -3466,7 +3467,7 @@ is_tty_root_frame (struct frame *f) } /* Return the index of the first enabled row in MATRIX, or -1 if there - is none. */ + is none. */ static int first_enabled_row (struct glyph_matrix *matrix) @@ -3478,7 +3479,7 @@ first_enabled_row (struct glyph_matrix *matrix) } /* On tty frame F, make desired matrix current, without writing - to the terminal. */ + to the terminal. */ static void make_matrix_current (struct frame *f) @@ -3496,8 +3497,8 @@ make_matrix_current (struct frame *f) static struct glyph_row * prepare_desired_root_row (struct frame *root, int y) { - /* Start with the root's desired matrix row. If that hasn't - been redisplayed, copy from the root's current matrix. */ + /* Start with the root's desired matrix row. If that hasn't been + redisplayed, copy from the root's current matrix. */ struct glyph_row *root_row = MATRIX_ROW (root->desired_matrix, y); if (!root_row->enabled_p) { @@ -3509,9 +3510,9 @@ prepare_desired_root_row (struct frame *root, int y) return root_row; } -/* Produce glyphs for box character BOX in ROW. X ist the position in ROW - where to start producing glyphs. N is the number of glyphs to produce. - CHILD is the frame to use for the face of the glyphs. */ +/* Produce glyphs for box character BOX in ROW. X is the position in + ROW where to start producing glyphs. N is the number of glyphs to + produce. CHILD is the frame to use for the face of the glyphs. */ static void produce_box_glyphs (enum box box, struct glyph_row *row, int x, int n, @@ -3534,7 +3535,7 @@ produce_box_glyphs (enum box box, struct glyph_row *row, int x, int n, break; } - // FIXME/tty some face for the border. + /* FIXME/tty: some face for the border. */ int face_id = BORDER_FACE_ID; GLYPH g; SET_GLYPH (g, dflt, face_id); @@ -3546,7 +3547,7 @@ produce_box_glyphs (enum box box, struct glyph_row *row, int x, int n, if (GLYPH_CODE_P (gc)) { SET_GLYPH_FROM_GLYPH_CODE (g, gc); - /* Sorry, but I really don't care if the glyph has a face :-). */ + /* Sorry, but I really don't care if the glyph has a face :-). */ } } @@ -3567,7 +3568,7 @@ produce_box_glyphs (enum box box, struct glyph_row *row, int x, int n, /* Produce box glyphs LEFT and RIGHT in ROOT_ROW. X and W are the start and width of a range in ROOT_ROW before and after which to put the - box glyphs, if they fit. ROOT and CHILD are root and child frame we + box glyphs, if they fit. ROOT and CHILD are root and child frame we are working on. ROOT is the root frame whose matrix dimensions determines if the box glyphs fit. CHILD is the frame whose faces to use for the box glyphs. */ @@ -3595,7 +3596,7 @@ produce_box_line (struct frame *root, struct frame *child, int x, int y, int w, root_row->hash = row_hash (root_row); } -/* Copy to ROOT's desired matrix what we need from CHILD. */ +/* Copy to ROOT's desired matrix what we need from CHILD. */ static void copy_child_glyphs (struct frame *root, struct frame *child) @@ -3603,20 +3604,20 @@ copy_child_glyphs (struct frame *root, struct frame *child) eassert (!FRAME_PARENT_FRAME (root)); eassert (is_frame_ancestor (root, child)); - /* Determine the intersection of the child frame rectangle with - the root frame. This is basically clipping the child frame to - the root frame rectangle. */ + /* Determine the intersection of the child frame rectangle with the + root frame. This is basically clipping the child frame to the + root frame rectangle. */ struct rect r; if (!rect_intersect (&r, frame_rect_abs (root), frame_rect_abs (child))) return; - /* Build CHILD's current matrix which we need to copy from it. */ + /* Build CHILD's current matrix which we need to copy from it. */ make_matrix_current (child); - /* Draw borders around the child frame. */ + /* Draw borders around the child frame. */ if (!FRAME_UNDECORATED (child)) { - /* Horizontal line above. */ + /* Horizontal line above. */ if (r.y > 0) produce_box_line (root, child, r.x, r.y - 1, r.w, true); @@ -3627,28 +3628,28 @@ copy_child_glyphs (struct frame *root, struct frame *child) root, child); } - /* Horizontal line below */ + /* Horizontal line below. */ if (r.y + r.h < root->desired_matrix->matrix_h) produce_box_line (root, child, r.x, r.y + r.h, r.w, false); } - /* First visible row/col, relative to the child frame. */ + /* First visible row/col, relative to the child frame. */ int child_x = child->left_pos < 0 ? - child->left_pos : 0; int child_y = child->top_pos < 0 ? - child->top_pos : 0; /* For all rows in the intersection, copy glyphs from the child's - current matrix to the root's desired matrix, enabling those - rows if they aren't already. */ + current matrix to the root's desired matrix, enabling those rows + if they aren't already. */ for (int y = r.y; y < r.y + r.h; ++y, ++child_y) { struct glyph_row *root_row = prepare_desired_root_row (root, y); - /* Copy what's visible from the child's current row. */ + /* Copy what's visible from the child's current row. */ struct glyph_row *child_row = MATRIX_ROW (child->current_matrix, child_y); memcpy (root_row->glyphs[0] + r.x, child_row->glyphs[0] + child_x, r.w * sizeof (struct glyph)); - /* Compute a new hash since we changed glyphs. */ + /* Compute a new hash since we changed glyphs. */ root_row->hash = row_hash (root_row); } } @@ -3689,7 +3690,7 @@ update_bar_window (Lisp_Object window, Lisp_Object *current, } #endif -/* Update the tab-bar window of frame F, if present. */ +/* Update the tab-bar window of frame F, if present. */ static void update_tab_bar (struct frame *f) @@ -3757,7 +3758,7 @@ abs_cursor_pos (struct frame *f, int *x, int *y) *y += w->cursor.y; } -/* Is the terminal cursor of frame F obscured by a child frame? */ +/* Is the terminal cursor of frame F obscured by a child frame? */ static bool is_cursor_obscured (void) @@ -3771,17 +3772,17 @@ is_cursor_obscured (void) return cursor_glyph->frame != SELECTED_FRAME (); } -/* Decide where to show the cursor, and if to hide it or not. +/* Decide where to show the cursor, and whether to hide it. This works very well for Vertico-Posframe, Transient-Posframe and Corfu, but it's debatable if it's the right thing for a general use - of child frames of all sorts, nested and so on. But it is also debatable - if that's a realistic use case from my POV. */ + of child frames of all sorts, nested and so on. But it is also + debatable if that's a realistic use case from my POV. */ static void terminal_cursor_magic (struct frame *root, struct frame *topmost_child) { - /* By default, prevent the cursor "shining through" child frames. */ + /* By default, prevent the cursor "shining through" child frames. */ if (is_cursor_obscured ()) tty_hide_cursor (FRAME_TTY (root)); @@ -3812,8 +3813,8 @@ combine_updates_for_frame (struct frame *f, bool force_p, bool inhibit_scrolling struct frame *root = root_frame (f); eassert (FRAME_VISIBLE_P (root)); - /* Process child frames in reverse z-order, topmost last. For each - child, copy what we need to the root's desired matrix. */ + /* Process child frames in reverse z-order, topmost last. For each + child, copy what we need to the root's desired matrix. */ Lisp_Object z_order = frames_in_reverse_z_order (root, true); struct frame *topmost_child = NULL; for (Lisp_Object tail = XCDR (z_order); CONSP (tail); tail = XCDR (tail)) @@ -3830,7 +3831,7 @@ combine_updates_for_frame (struct frame *f, bool force_p, bool inhibit_scrolling /* If a child is displayed, and the cursor is displayed in another frame, the child might lay above the cursor, so that it appers to - "shine through" the child. Avoid that because it's confusing. */ + "shine through" the child. Avoid that because it's confusing. */ if (topmost_child) terminal_cursor_magic (root, topmost_child); flush_terminal (root); @@ -3850,8 +3851,8 @@ combine_updates_for_frame (struct frame *f, bool force_p, bool inhibit_scrolling return paused; } -/* Update on the screen all root frames ROOTS. Called from - redisplay_internal as the last step of redisplaying. */ +/* Update on the screen all root frames ROOTS. Called from + redisplay_internal as the last step of redisplaying. */ bool combine_updates (Lisp_Object roots, bool force_p, bool inhibit_scrolling) @@ -3926,8 +3927,8 @@ update_frame_with_menu (struct frame *f, int row, int col) /* Update the display. */ update_begin (f); cursor_at_point_p = !(row >= 0 && col >= 0); - /* Do not stop due to pending input, and do not try scrolling. This - means that write_glyphs will always return false. */ + /* Do not stop due to pending input, and do not try scrolling. This + means that write_glyphs will always return false. */ write_matrix (f, 1, 1, cursor_at_point_p, true); make_matrix_current (f); clear_desired_matrices (f); @@ -5576,7 +5577,7 @@ write_matrix (struct frame *f, bool force_p, bool inhibit_id_p, force_p |= scrolling (f); /* Update the individual lines as needed. Do bottom line first. This - is done so that messages are made visible when pausing. */ + is done so that messages are made visible when pausing. */ int last_row = f->desired_matrix->nrows - 1; if (MATRIX_ROW_ENABLED_P (f->desired_matrix, last_row)) write_row (f, last_row, updating_menu_p); diff --git a/src/frame.c b/src/frame.c index 6b7f04aed80..0d45c2de197 100644 --- a/src/frame.c +++ b/src/frame.c @@ -197,10 +197,10 @@ set_menu_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval) int olines = FRAME_MENU_BAR_LINES (f); int nlines = TYPE_RANGED_FIXNUMP (int, value) ? XFIXNUM (value) : 0; - /* Menu bars on child frames don't work on all platforms, - which is the reason why prepare_menu_bar does not update_menu_bar - for child frames (info from Martin Rudalics). This could be - implemented in ttys, but it's probaly not worth it. */ + /* Menu bars on child frames don't work on all platforms, which is + the reason why prepare_menu_bar does not update_menu_bar for + child frames (info from Martin Rudalics). This could be + implemented in ttys, but it's probaly not worth it. */ if (is_tty_child_frame (f)) { FRAME_MENU_BAR_LINES (f) = 0; @@ -1297,10 +1297,10 @@ make_terminal_frame (struct terminal *terminal, Lisp_Object parent, f = make_frame_without_minibuffer (Qnil, kb, Qnil); else if (EQ (mini, Qonly)) { -# if 0 /* No interest in this feature at the moment, */ +# if 0 /* No interest in this feature at the moment. */ f = make_minibuffer_frame (); - /* Not sure about this plus the unsplittable frame - paran. */ + /* Not sure about this, plus the unsplittable frame + param. */ f->no_split = true; # endif } @@ -1345,10 +1345,10 @@ make_terminal_frame (struct terminal *terminal, Lisp_Object parent, f->horizontal_scroll_bars = false; #endif - /* Menu bars on child frames don't work on all platforms, - which is the reason why prepare_menu_bar does not update_menu_bar - for child frames (info from Martin Rudalics). This could be - implemented in ttys, but it's unclear if it is worth it. */ + /* Menu bars on child frames don't work on all platforms, which is + the reason why prepare_menu_bar does not update_menu_bar for + child frames (info from Martin Rudalics). This could be + implemented in ttys, but it's unclear if it is worth it. */ if (NILP (parent)) FRAME_MENU_BAR_LINES (f) = NILP (Vmenu_bar_mode) ? 0 : 1; else @@ -1363,7 +1363,7 @@ make_terminal_frame (struct terminal *terminal, Lisp_Object parent, - FRAME_TAB_BAR_HEIGHT (f); /* Mark current topmost frame obscured if we make a new root frame. - Child frames don't completely obscure other frames. */ + Child frames don't completely obscure other frames. */ if (NILP (parent) && FRAMEP (FRAME_TTY (f)->top_frame)) { struct frame *top = XFRAME (FRAME_TTY (f)->top_frame); @@ -1427,8 +1427,8 @@ tty_child_size_param (struct frame *child, Lisp_Object key, val = XCDR (val); if (CONSP (val)) { - /* Width and height may look like (width text-pixels - . PIXELS) on window systems. Mimic that. */ + /* Width and height may look like (width text-pixels . PIXELS) + on window systems. Mimic that. */ val = XCDR (val); if (EQ (val, Qtext_pixels)) val = XCDR (val); @@ -1545,9 +1545,9 @@ affects all frames on the same terminal device. */) SAFE_FREE (); } - /* Make a new frame. We need to know upfront if if a parent frame is - specified because we behave differently in this case, e.g. child - frames don't obscure other frames. */ + /* Make a new frame. We need to know up front if a parent frame is + specified because we behave differently in this case, e.g., child + frames don't obscure other frames. */ Lisp_Object parent = Fcdr (Fassq (Qparent_frame, parms)); struct frame *f = make_terminal_frame (t, parent, parms); @@ -1556,20 +1556,20 @@ affects all frames on the same terminal device. */) /* Visibility of root frames cannot be set with a frame parameter. Their visibility solely depends on whether or not they are the - top_frame on the terminal. */ + top_frame on the terminal. */ if (FRAME_PARENT_FRAME (f)) { Lisp_Object visible = Fassq (Qvisibility, parms); if (CONSP (visible)) SET_FRAME_VISIBLE (f, !NILP (visible)); - /* FIXME/tty: The only way to get borders on a tty is - to allow decorations for now. */ + /* FIXME/tty: The only way, for now, to get borders on a tty is + to allow decorations. */ Lisp_Object undecorated = Fassq (Qundecorated, parms); if (CONSP (undecorated) && !NILP (XCDR (undecorated))) f->undecorated = true; - /* Unused at present. */ + /* Unused at present. */ Lisp_Object no_focus = Fassq (Qno_accept_focus, parms); if (CONSP (no_focus) && !NILP (XCDR (no_focus))) f->no_accept_focus = true; @@ -1579,10 +1579,10 @@ affects all frames on the same terminal device. */) f->no_split = true; } - /* Determine width and height of the frame. For root frames use the - width/height of the terminal. For child frames, take it from frame - parameters. Note that a default (80x25) has been set in - make_frame. We handle root frames in this way because otherwise we + /* Determine width and height of the frame. For root frames use the + width/height of the terminal. For child frames, take it from frame + parameters. Note that a default (80x25) has been set in + make_frame. We handle root frames in this way because otherwise we would end up needing glyph matrices for the terminal, which is both more work and has its downsides (think of clipping frames to the terminal size). */ @@ -1742,7 +1742,7 @@ do_switch_frame (Lisp_Object frame, int track, int for_deletion, Lisp_Object nor tty->top_frame = frame; - /* Why is it correct to set FrameCols/Rows? */ + /* FIXME: Why is it correct to set FrameCols/Rows? */ if (!FRAME_PARENT_FRAME (f)) { /* If the new TTY frame changed dimensions, we need to @@ -1796,32 +1796,32 @@ do_switch_frame (Lisp_Object frame, int track, int for_deletion, Lisp_Object nor with your typing being interpreted in the new frame instead of the one you're actually typing in. */ - /* FIXME/tty: I don't understand this. (The comment above is from + /* FIXME/tty: I don't understand this. (The comment above is from Jim BLandy 1993 BTW, and the frame_ancestor_p from 2017.) Setting the last event frame to nil leads to switch-frame events being generated even if they normally wouldn't be because the frame - in question equals selected-frame. See the places in keyboard.c + in question equals selected-frame. See the places in keyboard.c where make_lispy_switch_frame is called. This leads to problems at least on ttys. Imagine that we have functions in post-command-hook that use - select-frame in some way (e.g. with-selected-window). Let these + select-frame in some way (e.g., with-selected-window). Let these functions select different frames during the execution of - post-command-hook in command_loop_1. Setting + post-command-hook in command_loop_1. Setting internal_last_event_frame to nil here makes these select-frame - calls (potentially, and reality) generate switch-frame events. (But - only in one direction (frame_ancestor_p), which I also don't + calls (potentially and in reality) generate switch-frame events. + (But only in one direction (frame_ancestor_p), which I also don't understand). These switch-frame events form an endless loop in - command_loop_1. It runs post-command-hook, which generates + command_loop_1. It runs post-command-hook, which generates switch-frame events, which command_loop_1 finds (bound to '#ignore) - and executes, which again runs post-command-hook etc. ad + and executes, which again runs post-command-hook etc., ad infinitum. - Let's not do that for now on ttys. */ + Let's not do that for now on ttys. */ if (!is_tty_frame (f)) if (!frame_ancestor_p (f, sf)) internal_last_event_frame = Qnil; @@ -3135,9 +3135,9 @@ displayed in the terminal. */) if (FRAME_WINDOW_P (f) && FRAME_TERMINAL (f)->frame_visible_invisible_hook) FRAME_TERMINAL (f)->frame_visible_invisible_hook (f, false); - /* The Elisp info manual says that this "usually" makes child frames - invisible, too, but without saying when not. Since users can't rely - on this, it's not implemented. */ + /* The ELisp manual says that this "usually" makes child frames + invisible, too, but without saying when not. Since users can't + rely on this, it's not implemented. */ if (is_tty_frame (f)) SET_FRAME_VISIBLE (f, false); @@ -4503,10 +4503,11 @@ frame_float (struct frame *f, Lisp_Object val, enum frame_float_type what, } } -/* Handle frame parameter change with frame parameter handler. F is the - frame whose frame parameter was changed. PROP is the name of the - frame parameter. VAL and OLD_VALUE are the current value and old - value of the frame parameter. */ +/* Handle frame parameter change with frame parameter handler. + F is the frame whose frame parameter was changed. + PROP is the name of the frame parameter. + VAL and OLD_VALUE are the current and the old value of the + frame parameter. */ static void handle_frame_param (struct frame *f, Lisp_Object prop, Lisp_Object val, diff --git a/src/frame.h b/src/frame.h index 9a9d025e638..bf0a4169f21 100644 --- a/src/frame.h +++ b/src/frame.h @@ -734,7 +734,7 @@ struct frame struct text_conversion_state conversion; # endif - /* Z-order of child frames. */ + /* Z-order of child frames. */ int z_order; } GCALIGNED_STRUCT; diff --git a/src/term.c b/src/term.c index 330da251e18..6379b4ce4a1 100644 --- a/src/term.c +++ b/src/term.c @@ -786,10 +786,10 @@ tty_write_glyphs (struct frame *f, struct glyph *string, int len) /* Identify a run of glyphs with the same face. */ int face_id = string->face_id; - /* FIXME/tty: it happens that a single glyph's frame is NULL. It + /* FIXME/tty: it happens that a single glyph's frame is NULL. It might depend on a tab bar line being present, then switching from a buffer without header line to one with header line and - opening a child frame. */ + opening a child frame. */ struct frame *face_id_frame = string->frame ? string->frame : f; for (n = 1; n < stringlen; ++n) diff --git a/src/xdisp.c b/src/xdisp.c index 935c75a8230..bd3e8f3138d 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -17035,9 +17035,9 @@ redisplay_internal (void) if (face_change) windows_or_buffers_changed = 47; - /* Can we do better for tty child frames? It could be + /* FIXME: Can we do better for tty child frames? It could be a bit faster when we switch between child frames of the same - root frame. OTOH, it's probably not a frequent use case. */ + root frame. OTOH, it's probably not a frequent use case. */ if ((FRAME_TERMCAP_P (sf) || FRAME_MSDOS_P (sf)) && FRAME_TTY (sf)->previous_frame != sf) { @@ -17463,7 +17463,7 @@ redisplay_internal (void) if (!FRAME_VISIBLE_P (root_frame (f))) continue; - /* Remember tty root frames seen. */ + /* Remember tty root frames which we've seen. */ if (!FRAME_PARENT_FRAME (f)) { Lisp_Object found; From 560260a631489576e99caedda3233670f2fcd66c Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Tue, 22 Oct 2024 06:19:12 -0400 Subject: [PATCH 13/53] * src/term.c (tty_display_dimension): Avoid warnings. --- src/term.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/term.c b/src/term.c index 6379b4ce4a1..69abbc23d92 100644 --- a/src/term.c +++ b/src/term.c @@ -4882,6 +4882,7 @@ tty_display_dimension (Lisp_Object frame, int *width, int *height) case output_pgtk: case output_haiku: case output_android: + default: emacs_abort (); break; } From 4182dfb7e844bcc7148a3d7f1084cef6982b36d9 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Tue, 22 Oct 2024 10:33:45 -0400 Subject: [PATCH 14/53] ; Clarify a comment in dispnew.c --- src/dispnew.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/dispnew.c b/src/dispnew.c index 200ffaaca21..9caeb9d1694 100644 --- a/src/dispnew.c +++ b/src/dispnew.c @@ -1176,9 +1176,12 @@ line_hash_code (struct frame *f, struct glyph_row *row) { int c = glyph->u.ch; int face_id = glyph->face_id; - /* Struct frame can move with igc, and so on. But we need - something that takes different frames into account. Use the - face_cache pointer for that which is malloc'd. */ + /* A given row of a frame glyph matrix could have glyphs + from more than one frame, if child frames are displayed. + Since face_id of a face depends on the frame (it's an + index into the frame's face cache), we need the hash + value to include something specific to the frame, and we + use the frame cache's address for that purpose. */ if (glyph->frame && glyph->frame != f) face_id += (ptrdiff_t) glyph->frame->face_cache; if (FRAME_MUST_WRITE_SPACES (f)) From 5cc5fa79bfdf0f905723e592baa41c3f0b12316d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerd=20M=C3=B6llmann?= Date: Wed, 23 Oct 2024 05:01:51 +0200 Subject: [PATCH 15/53] Some cleanup of frame_parm_table * src/frame.c (frame_parms): Use built-in symbols for all entries. (syms_of_frame): Check that entries are valid built-in symbols. --- src/frame.c | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/src/frame.c b/src/frame.c index 0d45c2de197..c3b6565101c 100644 --- a/src/frame.c +++ b/src/frame.c @@ -4249,9 +4249,9 @@ multiplied to find the real number of pixels. */) /* Connect the frame-parameter names for frames to the ways of passing the parameter values to the window system. - The name of a parameter, as a Lisp symbol, has a - `frame-parameter-pos' property which is an integer in Lisp that is - an index in this table. */ + The name of a parameter, a Lisp symbol, has an `x-frame-parameter' + property which is its index in this table. This is initialized in + syms_of_frame. */ struct frame_parm_table { const char *name; @@ -4262,13 +4262,13 @@ static const struct frame_parm_table frame_parms[] = { {"auto-raise", SYMBOL_INDEX (Qauto_raise)}, {"auto-lower", SYMBOL_INDEX (Qauto_lower)}, - {"background-color", -1}, + {"background-color", SYMBOL_INDEX (Qbackground_color)}, {"border-color", SYMBOL_INDEX (Qborder_color)}, {"border-width", SYMBOL_INDEX (Qborder_width)}, {"cursor-color", SYMBOL_INDEX (Qcursor_color)}, {"cursor-type", SYMBOL_INDEX (Qcursor_type)}, - {"font", -1}, - {"foreground-color", -1}, + {"font", SYMBOL_INDEX (Qfont)}, + {"foreground-color", SYMBOL_INDEX (Qforeground_color)}, {"icon-name", SYMBOL_INDEX (Qicon_name)}, {"icon-type", SYMBOL_INDEX (Qicon_type)}, {"child-frame-border-width", SYMBOL_INDEX (Qchild_frame_border_width)}, @@ -6720,17 +6720,13 @@ syms_of_frame (void) DEFSYM (Quse_frame_synchronization, "use-frame-synchronization"); DEFSYM (Qfont_parameter, "font-parameter"); - { - int i; - - for (i = 0; i < ARRAYELTS (frame_parms); i++) - { - Lisp_Object v = (frame_parms[i].sym < 0 - ? intern_c_string (frame_parms[i].name) - : builtin_lisp_symbol (frame_parms[i].sym)); - Fput (v, Qx_frame_parameter, make_fixnum (i)); - } - } + for (int i = 0; i < ARRAYELTS (frame_parms); i++) + { + int sym = frame_parms[i].sym; + eassert (sym >= 0 && sym < ARRAYELTS (lispsym)); + Lisp_Object v = builtin_lisp_symbol (sym); + Fput (v, Qx_frame_parameter, make_fixnum (i)); + } #ifdef HAVE_WINDOW_SYSTEM DEFVAR_LISP ("x-resource-name", Vx_resource_name, From dac51f1f66ef93cec6d9ea17e74a193de9ae1ff3 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Tue, 22 Oct 2024 12:18:14 -0700 Subject: [PATCH 16/53] Fix UB in line_hash_code * src/dispnew.c (line_hash_code): Avoid undefined behavior on integer overflow. --- src/dispnew.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/dispnew.c b/src/dispnew.c index 200ffaaca21..1ece9cc1d45 100644 --- a/src/dispnew.c +++ b/src/dispnew.c @@ -1175,12 +1175,12 @@ line_hash_code (struct frame *f, struct glyph_row *row) while (glyph < end) { int c = glyph->u.ch; - int face_id = glyph->face_id; + unsigned int face_id = glyph->face_id; /* Struct frame can move with igc, and so on. But we need something that takes different frames into account. Use the face_cache pointer for that which is malloc'd. */ if (glyph->frame && glyph->frame != f) - face_id += (ptrdiff_t) glyph->frame->face_cache; + face_id += (uintptr_t) glyph->frame->face_cache; if (FRAME_MUST_WRITE_SPACES (f)) c -= SPACEGLYPH; hash = (((hash << 4) + (hash >> 24)) & 0x0fffffff) + c; From 40aa1e329b637e42fc945cba6213b4e7b4a5d60f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerd=20M=C3=B6llmann?= Date: Wed, 23 Oct 2024 07:51:12 +0200 Subject: [PATCH 17/53] Fix copy/paste error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * src/dispnew.c (produce_box_glyphs): DonÄt set multibyte_p twice, set padding_p. --- src/dispnew.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/dispnew.c b/src/dispnew.c index 1ece9cc1d45..8aa8e0fb5f5 100644 --- a/src/dispnew.c +++ b/src/dispnew.c @@ -3561,8 +3561,9 @@ produce_box_glyphs (enum box box, struct glyph_row *row, int x, int n, glyph->multibyte_p = 1; glyph->face_id = GLYPH_FACE (g); glyph->frame = child; - glyph->multibyte_p = 1; + glyph->padding_p = 0; glyph->object = Qnil; + glyph->padding_p = 0; } } From d1fd1d8fba8a6cfe774f6982bb6ad6c874d0c960 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerd=20M=C3=B6llmann?= Date: Wed, 23 Oct 2024 09:55:26 +0200 Subject: [PATCH 18/53] Deal with wide characters * src/dispnew.c (make_glyph_space): New function. (neutralize_wide_char): New function. (produce_box_sides, copy_child_glyphs): Call neutralize_wide_char. --- src/dispnew.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 56 insertions(+), 2 deletions(-) diff --git a/src/dispnew.c b/src/dispnew.c index 9a41b6be578..6a6f983a2ce 100644 --- a/src/dispnew.c +++ b/src/dispnew.c @@ -3513,6 +3513,45 @@ prepare_desired_root_row (struct frame *root, int y) return root_row; } +/* Change GLYPH to be a space glyph. */ + +static void +make_glyph_space (struct glyph *glyph) +{ + glyph->u.ch = ' '; + glyph->pixel_width = 1; + glyph->padding_p = 0; +} + +/* On root frame ROOT, if the glyph in ROW at position X is part of a + sequence of glyphs for a wide character, change every glyph belonging + to the sequence to a space. If X is outside of ROOT, do nothing. */ + +static void +neutralize_wide_char (struct frame *root, struct glyph_row *row, int x) +{ + if (x < 0 || x >= root->desired_matrix->matrix_w) + return; + + struct glyph *glyph = row->glyphs[0] + x; + if (glyph->type == CHAR_GLYPH && CHARACTER_WIDTH (glyph->u.ch) > 1) + { + struct glyph *row_start = row->glyphs[0]; + struct glyph *row_limit = row_start + row->used[0]; + + /* Glyph is somewhere in a sequence of glyphs for a wide + character, find the start. */ + while (glyph > row_start && glyph->padding_p) + --glyph; + + /* Make everything in the sequence a space glyph. */ + eassert (!glyph->padding_p); + make_glyph_space (glyph); + for (++glyph; glyph < row_limit && glyph->padding_p; ++glyph) + make_glyph_space (glyph); + } +} + /* Produce glyphs for box character BOX in ROW. X is the position in ROW where to start producing glyphs. N is the number of glyphs to produce. CHILD is the frame to use for the face of the glyphs. */ @@ -3582,9 +3621,16 @@ produce_box_sides (enum box left, enum box right, struct glyph_row *root_row, in int w, struct frame *root, struct frame *child) { if (x > 0) - produce_box_glyphs (left, root_row, x - 1, 1, child); + { + neutralize_wide_char (root, root_row, x - 1); + produce_box_glyphs (left, root_row, x - 1, 1, child); + } + if (x + w < root->desired_matrix->matrix_w) - produce_box_glyphs (right, root_row, x + w, 1, child); + { + neutralize_wide_char (root, root_row, x + w); + produce_box_glyphs (right, root_row, x + w, 1, child); + } } static void @@ -3648,6 +3694,14 @@ copy_child_glyphs (struct frame *root, struct frame *child) { struct glyph_row *root_row = prepare_desired_root_row (root, y); + /* Deal with wide characters unless already done as part of + drawing a box around the child frame. */ + if (FRAME_UNDECORATED (child)) + { + neutralize_wide_char (root, root_row, r.x - 1); + neutralize_wide_char (root, root_row, r.x + r.w); + } + /* Copy what's visible from the child's current row. */ struct glyph_row *child_row = MATRIX_ROW (child->current_matrix, child_y); memcpy (root_row->glyphs[0] + r.x, child_row->glyphs[0] + child_x, From 9b8d1e0addeca9b508324537e7743d0af508a630 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerd=20M=C3=B6llmann?= Date: Wed, 23 Oct 2024 12:59:09 +0200 Subject: [PATCH 19/53] Handle obscured cursor differently This also fixes an error made when porting this to savannah. * src/dispnew.c (abs_cursor_pos, (is_cursor_obscured) (terminal_cursor_magic): Port correctly and fix. --- src/dispnew.c | 73 ++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 60 insertions(+), 13 deletions(-) diff --git a/src/dispnew.c b/src/dispnew.c index 6a6f983a2ce..2afd2cd3c5a 100644 --- a/src/dispnew.c +++ b/src/dispnew.c @@ -3807,25 +3807,68 @@ update_tty_frame (struct frame *f, bool force_p) return false; } -static void +/* Return the cursor position of the selected window of frame F, in + absolute coordinates in *X and *Y. Note that if F is a child frame, + its cursor may be clipped, i.e. outside of the bounds of the terminal + window. Value is false if the selected window of F doesn't have + valid cursor position info. */ + +static bool abs_cursor_pos (struct frame *f, int *x, int *y) { - frame_pos_abs (f, x, y); struct window *w = XWINDOW (f->selected_window); - *x += w->cursor.x; - *y += w->cursor.y; + if (w->cursor.vpos >= 0 + /* The cursor vpos may be temporarily out of bounds + in the following situation: There is one window, + with the cursor in the lower half of it. The window + is split, and a message causes a redisplay before + a new cursor position has been computed. */ + && w->cursor.vpos < WINDOW_TOTAL_LINES (w)) + { + int wx = WINDOW_TO_FRAME_HPOS (w, w->cursor.hpos); + int wy = WINDOW_TO_FRAME_VPOS (w, w->cursor.vpos); + + wx += max (0, w->left_margin_cols); + + int fx, fy; + frame_pos_abs (f, &fx, &fy); + *x = fx + wx; + *y = fy + wy; + return true; + } + + *x = *y = 0; + return false; } -/* Is the terminal cursor of frame F obscured by a child frame? */ +static bool +is_in_matrix (struct frame *f, int x, int y) +{ + struct frame *root = root_frame (f); + if (x < 0 || x >= root->current_matrix->matrix_w || y < 0 + || y >= root->current_matrix->matrix_h) + return false; + return true; +} + +/* Is the terminal cursor of the selected frame obscured by a child + frame? */ static bool is_cursor_obscured (void) { + /* Give up if we can't tell where the cursor currently is. */ int x, y; - abs_cursor_pos (SELECTED_FRAME (), &x, &y); + if (!abs_cursor_pos (SELECTED_FRAME (), &x, &y)) + return false; + + /* (x, y) may be outside of the root frame in case the selected frame is a + child frame which is clipped. */ struct frame *root = root_frame (SELECTED_FRAME ()); + if (!is_in_matrix (root, x, y)) + return true; + struct glyph_row *cursor_row = MATRIX_ROW (root->current_matrix, y); - eassert (x < root->current_matrix->matrix_w); struct glyph *cursor_glyph = cursor_row->glyphs[0] + x; return cursor_glyph->frame != SELECTED_FRAME (); } @@ -3854,14 +3897,18 @@ terminal_cursor_magic (struct frame *root, struct frame *topmost_child) Lisp_Object frame; XSETFRAME (frame, topmost_child); + int x, y; Lisp_Object cursor = Fframe_parameter (frame, Qtty_non_selected_cursor); - if (!NILP (cursor)) + if (!NILP (cursor) && abs_cursor_pos (topmost_child, &x, &y)) { - int x, y; - abs_cursor_pos (topmost_child, &x, &y); - cursor_to (root, y, x); - tty_show_cursor (FRAME_TTY (topmost_child)); - } + if (is_in_matrix (root, x, y)) + { + cursor_to (root, y, x); + tty_show_cursor (FRAME_TTY (topmost_child)); + } + else + tty_hide_cursor (FRAME_TTY (root)); + } } } From 33586db3d34bcbe6441d98542df2b3370a1e2622 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sat, 26 Oct 2024 11:18:41 +0300 Subject: [PATCH 20/53] Adapt w32 console to tty-child-frame changes * src/w32console.c (w32con_write_glyphs): Use the glyph's frame, not the root frame, to resolve faces from face IDs. --- src/w32console.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/w32console.c b/src/w32console.c index 7dcbc795cac..b9a84bbf86a 100644 --- a/src/w32console.c +++ b/src/w32console.c @@ -327,14 +327,19 @@ w32con_write_glyphs (struct frame *f, register struct glyph *string, { /* Identify a run of glyphs with the same face. */ int face_id = string->face_id; + /* Since this is called to deliver the frame glyph matrix to the + glass, some of the glyphs might be from a child frame, which + affects the interpretation of face ID. */ + struct frame *face_id_frame = string->frame ? string->frame : f; int n; for (n = 1; n < len; ++n) - if (string[n].face_id != face_id) + if (!(string[n].face_id == face_id + && string[n].frame == face_id_frame)) break; /* Turn appearance modes of the face of the run on. */ - char_attr = w32_face_attributes (f, face_id); + char_attr = w32_face_attributes (face_id_frame, face_id); if (n == len) /* This is the last run. */ From 4cb7f3935e2b600d23ae78bde2ce54a8a320e08b Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sat, 26 Oct 2024 12:14:21 +0300 Subject: [PATCH 21/53] More fixes for w32 console build * src/w32term.c (w32_read_socket): Don't use FRAME_OBSCURED_P, which was removed. * src/frame.h (struct frame): Move !HAVE_NTGUI to its original place. * src/treesit.c (treesit_load_language): Shut up GCC warning. --- src/frame.h | 3 +-- src/treesit.c | 2 +- src/w32term.c | 25 +++---------------------- 3 files changed, 5 insertions(+), 25 deletions(-) diff --git a/src/frame.h b/src/frame.h index bf0a4169f21..bc8c3498634 100644 --- a/src/frame.h +++ b/src/frame.h @@ -450,7 +450,6 @@ struct frame bool_bf no_accept_focus : 1; #ifdef HAVE_WINDOW_SYSTEM -# ifndef HAVE_NTGUI /* True if this frame is a tooltip frame. */ bool_bf tooltip : 1; @@ -464,7 +463,7 @@ struct frame /* Nonzero if we should actually display horizontal scroll bars on this frame. */ bool_bf horizontal_scroll_bars : 1; - +# ifndef HAVE_NTGUI /* True if this is an override_redirect frame. */ bool_bf override_redirect : 1; #endif diff --git a/src/treesit.c b/src/treesit.c index 6677158b9de..c02f94ec758 100644 --- a/src/treesit.c +++ b/src/treesit.c @@ -651,7 +651,7 @@ treesit_load_language (Lisp_Object language_symbol, /* Override the library name and C name, if appropriate. */ Lisp_Object override_name; - Lisp_Object override_c_name; + Lisp_Object override_c_name UNINIT; bool found_override = treesit_find_override_name (language_symbol, &override_name, &override_c_name); diff --git a/src/w32term.c b/src/w32term.c index 3a627308137..e41d2fa3c34 100644 --- a/src/w32term.c +++ b/src/w32term.c @@ -6347,14 +6347,13 @@ w32_read_socket (struct terminal *terminal, if (FRAME_TOOLTIP_P (f)) continue; - /* Check "visible" frames and mark each as obscured or not. + /* Check "visible" frames and mark each as visible or not. Note that visible is nonzero for unobscured and obscured frames, but zero for hidden and iconified frames. */ if (FRAME_W32_P (f) && FRAME_VISIBLE_P (f)) { RECT clipbox; HDC hdc; - bool obscured; enter_crit (); /* Query clipping rectangle for the entire window area @@ -6368,29 +6367,11 @@ w32_read_socket (struct terminal *terminal, ReleaseDC (FRAME_W32_WINDOW (f), hdc); leave_crit (); - obscured = FRAME_OBSCURED_P (f); - - if (clipbox.right == clipbox.left || clipbox.bottom == clipbox.top) - { - /* Frame has become completely obscured so mark as such (we - do this by setting visible to 2 so that FRAME_VISIBLE_P - is still true, but redisplay will skip it). */ - SET_FRAME_VISIBLE (f, 2); - - if (!obscured) - DebPrint (("frame %p (%s) obscured\n", f, SDATA (f->name))); - } - else + if (!(clipbox.right == clipbox.left + || clipbox.bottom == clipbox.top)) { /* Frame is not obscured, so mark it as such. */ SET_FRAME_VISIBLE (f, 1); - - if (obscured) - { - SET_FRAME_GARBAGED (f); - DebPrint (("obscured frame %p (%s) found to be visible\n", - f, SDATA (f->name))); - } } } } From 0d6a014750c63a9a9d6e5bcc195e80bf58dfa276 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sat, 26 Oct 2024 14:26:02 +0300 Subject: [PATCH 22/53] Fix dimensions of child frames on w32 console * src/w32inevt.c (maybe_generate_resize_event): Don't generate resize events for child frames. --- src/w32inevt.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/w32inevt.c b/src/w32inevt.c index 35d3420e39f..95c0927b55b 100644 --- a/src/w32inevt.c +++ b/src/w32inevt.c @@ -619,6 +619,10 @@ maybe_generate_resize_event (void) CONSOLE_SCREEN_BUFFER_INFO info; struct frame *f = get_frame (); + /* Only resize the root frame. */ + if (FRAMEP (f->parent_frame)) + return; + GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &info); /* It is okay to call this unconditionally, since it will do nothing From a3e41874c1b3d75d18dab9e20e0f183a3086fea4 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sat, 26 Oct 2024 15:19:53 +0300 Subject: [PATCH 23/53] * src/w32console.c (w32con_update_end): Fix cursor display. --- src/w32console.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/w32console.c b/src/w32console.c index b9a84bbf86a..7393e5b3f6b 100644 --- a/src/w32console.c +++ b/src/w32console.c @@ -535,6 +535,11 @@ static void w32con_update_end (struct frame * f) { SetConsoleCursorPosition (cur_screen, cursor_coords); + if (!XWINDOW (selected_window)->cursor_off_p + && cursor_coords.X < FRAME_COLS (f)) + w32con_show_cursor (); + else + w32con_hide_cursor (); } /*********************************************************************** From d7bf2cfd5d5713c9a9014807567e3f7e723280cf Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sat, 26 Oct 2024 15:31:42 +0300 Subject: [PATCH 24/53] Temporary fix for mouse events on child frames * src/w32inevt.c (do_mouse_event): Ignore mouse events when the selected frame is a child frame. --- src/w32inevt.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/w32inevt.c b/src/w32inevt.c index 95c0927b55b..63d322087bc 100644 --- a/src/w32inevt.c +++ b/src/w32inevt.c @@ -471,8 +471,13 @@ do_mouse_event (MOUSE_EVENT_RECORD *event, DWORD but_change, mask, flags = event->dwEventFlags; int i; - /* Mouse didn't move unless MOUSE_MOVED says it did. */ struct frame *f = get_frame (); + + /* For now, mouse events on child frames are ignored, because the + coordinate conversion is not in place; FIXME. */ + if (FRAMEP (f->parent_frame)) + return 0; + /* Mouse didn't move unless MOUSE_MOVED says it did. */ f->mouse_moved = 0; switch (flags) From d3f8ed730fa10d7283c6638dc4cc20cabbe4f4bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerd=20M=C3=B6llmann?= Date: Sun, 27 Oct 2024 12:05:58 +0100 Subject: [PATCH 25/53] Don't work around a corner case once observed * src/term.c (tty_write_glyphs): Refactor a bit. Don't check for null glyph frame. --- src/term.c | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/src/term.c b/src/term.c index 69abbc23d92..bd48e1f3e55 100644 --- a/src/term.c +++ b/src/term.c @@ -751,18 +751,12 @@ encode_terminal_code (struct glyph *src, int src_len, static void tty_write_glyphs (struct frame *f, struct glyph *string, int len) { - unsigned char *conversion_buffer; - struct coding_system *coding; - int n, stringlen; - struct tty_display_info *tty = FRAME_TTY (f); - tty_turn_off_insert (tty); tty_hide_cursor (tty); /* Don't dare write in last column of bottom line, if Auto-Wrap, since that would scroll the whole frame on some terminals. */ - if (AutoWrap (tty) && curY (tty) + 1 == FRAME_TOTAL_LINES (f) && (curX (tty) + len) == FRAME_COLS (f)) @@ -775,22 +769,19 @@ tty_write_glyphs (struct frame *f, struct glyph *string, int len) /* If terminal_coding does any conversion, use it, otherwise use safe_terminal_coding. We can't use CODING_REQUIRE_ENCODING here because it always return 1 if the member src_multibyte is 1. */ - coding = (FRAME_TERMINAL_CODING (f)->common_flags & CODING_REQUIRE_ENCODING_MASK - ? FRAME_TERMINAL_CODING (f) : &safe_terminal_coding); + struct coding_system *coding + = (FRAME_TERMINAL_CODING (f)->common_flags & CODING_REQUIRE_ENCODING_MASK + ? FRAME_TERMINAL_CODING (f) : &safe_terminal_coding); + /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at the tail. */ coding->mode &= ~CODING_MODE_LAST_BLOCK; - for (stringlen = len; stringlen != 0; stringlen -= n) + for (int stringlen = len, n; stringlen; stringlen -= n, string += n) { /* Identify a run of glyphs with the same face. */ int face_id = string->face_id; - - /* FIXME/tty: it happens that a single glyph's frame is NULL. It - might depend on a tab bar line being present, then switching - from a buffer without header line to one with header line and - opening a child frame. */ - struct frame *face_id_frame = string->frame ? string->frame : f; + struct frame *face_id_frame = string->frame; for (n = 1; n < stringlen; ++n) if (string[n].face_id != face_id || string[n].frame != face_id_frame) @@ -804,7 +795,8 @@ tty_write_glyphs (struct frame *f, struct glyph *string, int len) if (n == stringlen) /* This is the last run. */ coding->mode |= CODING_MODE_LAST_BLOCK; - conversion_buffer = encode_terminal_code (string, n, coding); + unsigned char *conversion_buffer + = encode_terminal_code (string, n, coding); if (coding->produced > 0) { block_input (); @@ -814,7 +806,6 @@ tty_write_glyphs (struct frame *f, struct glyph *string, int len) fwrite (conversion_buffer, 1, coding->produced, tty->termscript); unblock_input (); } - string += n; /* Turn appearance modes off. */ turn_off_face (f, face); From 7aa00fa90d6eb9347034106da10cdbbdc23b3d3a Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Mon, 28 Oct 2024 15:43:08 +0200 Subject: [PATCH 26/53] Remove unneeded workaround from w32console.c * src/w32console.c (w32con_write_glyphs): Remove unneeded test. (w32con_clear_end_of_line): Fill in the glyph.frame member. --- src/w32console.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/w32console.c b/src/w32console.c index 7393e5b3f6b..cd01fb9de38 100644 --- a/src/w32console.c +++ b/src/w32console.c @@ -167,6 +167,7 @@ w32con_clear_end_of_line (struct frame *f, int end) for (i = 0; i < glyphs_len; i++) { memcpy (&glyphs[i], &space_glyph, sizeof (struct glyph)); + glyphs[i].frame = f; } ceol_initialized = TRUE; } @@ -330,7 +331,7 @@ w32con_write_glyphs (struct frame *f, register struct glyph *string, /* Since this is called to deliver the frame glyph matrix to the glass, some of the glyphs might be from a child frame, which affects the interpretation of face ID. */ - struct frame *face_id_frame = string->frame ? string->frame : f; + struct frame *face_id_frame = string->frame; int n; for (n = 1; n < len; ++n) From dfb7f1942659cab4464e01f7e498efc4b269de3e Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Mon, 28 Oct 2024 09:04:41 -0400 Subject: [PATCH 27/53] More workarounds for GDB bug 32313 * src/eval.c (backtrace_args): Same treatment as backtrace_function. cherry-picked from commit b7b55df. --- src/eval.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/src/eval.c b/src/eval.c index 874cf6d868c..d0a2abf0089 100644 --- a/src/eval.c +++ b/src/eval.c @@ -50,8 +50,6 @@ Lisp_Object Vsignaling_function; /* These would ordinarily be static, but they need to be visible to GDB. */ bool backtrace_p (union specbinding *) EXTERNALLY_VISIBLE; -Lisp_Object *backtrace_args (union specbinding *) EXTERNALLY_VISIBLE; -Lisp_Object backtrace_function (union specbinding *) EXTERNALLY_VISIBLE; union specbinding *backtrace_next (union specbinding *) EXTERNALLY_VISIBLE; union specbinding *backtrace_top (void) EXTERNALLY_VISIBLE; @@ -108,12 +106,22 @@ specpdl_arg (union specbinding *pdl) return pdl->unwind.arg; } -Lisp_Object -backtrace_function (union specbinding *pdl) +/* To work around GDB bug 32313 + make + backtrace_* functions visible-to-GDB pointers instead of merely + being an externally visible functions themselves. Declare the + pointer first to pacify gcc -Wmissing-variable-declarations. */ +#define GDB_FUNCPTR(func, resulttype, params) \ + extern resulttype (*const func) params EXTERNALLY_VISIBLE; \ + resulttype (*const func) params = func##_body + +static Lisp_Object +backtrace_function_body (union specbinding *pdl) { eassert (pdl->kind == SPECPDL_BACKTRACE); return pdl->bt.function; } +GDB_FUNCPTR (backtrace_function, Lisp_Object, (union specbinding *)); static ptrdiff_t backtrace_nargs (union specbinding *pdl) @@ -122,12 +130,13 @@ backtrace_nargs (union specbinding *pdl) return pdl->bt.nargs; } -Lisp_Object * -backtrace_args (union specbinding *pdl) +static Lisp_Object * +backtrace_args_body (union specbinding *pdl) { eassert (pdl->kind == SPECPDL_BACKTRACE); return pdl->bt.args; } +GDB_FUNCPTR (backtrace_args, Lisp_Object *, (union specbinding *)); /* Functions to modify slots of backtrace records. */ From e2323775246c6f09b2d7fb82f8888ebe8f317b0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerd=20M=C3=B6llmann?= Date: Thu, 31 Oct 2024 21:16:13 +0100 Subject: [PATCH 28/53] Fix mouse-position for xterm-mouse-mode * lisp/xt-mouse.el (xterm-mouse-position-function): Return the frame recorded in the terminal parameter xterm-mouse-frame. --- lisp/xt-mouse.el | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/lisp/xt-mouse.el b/lisp/xt-mouse.el index 131c99d790d..130bbc6ece0 100644 --- a/lisp/xt-mouse.el +++ b/lisp/xt-mouse.el @@ -151,10 +151,11 @@ https://invisible-island.net/xterm/ctlseqs/ctlseqs.html)." (defun xterm-mouse-position-function (pos) "Bound to `mouse-position-function' in XTerm mouse mode." - (when (terminal-parameter nil 'xterm-mouse-x) - (setcdr pos (cons (terminal-parameter nil 'xterm-mouse-x) - (terminal-parameter nil 'xterm-mouse-y)))) - pos) + (if (terminal-parameter nil 'xterm-mouse-x) + (cons (terminal-parameter nil 'xterm-mouse-frame) + (cons (terminal-parameter nil 'xterm-mouse-x) + (terminal-parameter nil 'xterm-mouse-y))) + pos)) (define-obsolete-function-alias 'xterm-mouse-truncate-wrap 'truncate "27.1") From 33f1ab5034c7a5a9333ab6ead01f14a0f91c5f97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerd=20M=C3=B6llmann?= Date: Tue, 5 Nov 2024 10:24:31 +0100 Subject: [PATCH 29/53] * src/frame.c (make_terminal_frame): Check parent is live. --- src/frame.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/frame.c b/src/frame.c index c3b6565101c..6ea1a31cdb8 100644 --- a/src/frame.c +++ b/src/frame.c @@ -1285,7 +1285,7 @@ make_terminal_frame (struct terminal *terminal, Lisp_Object parent, f = make_frame (true); else { - CHECK_FRAME (parent); + CHECK_LIVE_FRAME (parent); f = NULL; Lisp_Object mini = Fassq (Qminibuffer, params); From 56708ea676e0fdfaeec36607333bb2955ec3b40e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerd=20M=C3=B6llmann?= Date: Tue, 5 Nov 2024 10:25:22 +0100 Subject: [PATCH 30/53] Don't copy non-enabled rows from child * src/dispnew.c (copy_child_glyphs): Check if child row is enabled. --- src/dispnew.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/src/dispnew.c b/src/dispnew.c index 2afd2cd3c5a..a7adbfb6f16 100644 --- a/src/dispnew.c +++ b/src/dispnew.c @@ -102,6 +102,20 @@ static void adjust_frame_glyphs_for_window_redisplay (struct frame *); static void adjust_frame_glyphs_for_frame_redisplay (struct frame *); static void set_window_update_flags (struct window *w, bool on_p); +#if 0 /* Please leave this in as a debugging aid. */ +static void +check_rows (struct frame *f) +{ + for (int y = 0; y < f->desired_matrix->nrows; ++y) + if (MATRIX_ROW_ENABLED_P (f->desired_matrix, y)) + { + struct glyph_row *row = MATRIX_ROW (f->desired_matrix, y); + for (int x = 0; x < row->used[TEXT_AREA]; ++x) + eassert (row->glyphs[TEXT_AREA][x].frame != 0); + } +} +#endif + /* True means last display completed. False means it was preempted. */ bool display_completed; @@ -3702,10 +3716,12 @@ copy_child_glyphs (struct frame *root, struct frame *child) neutralize_wide_char (root, root_row, r.x + r.w); } - /* Copy what's visible from the child's current row. */ + /* Copy what's visible from the child's current row. If that row + is not enabled_p, we can't copy anything that makes sense. */ struct glyph_row *child_row = MATRIX_ROW (child->current_matrix, child_y); - memcpy (root_row->glyphs[0] + r.x, child_row->glyphs[0] + child_x, - r.w * sizeof (struct glyph)); + if (child_row->enabled_p) + memcpy (root_row->glyphs[0] + r.x, child_row->glyphs[0] + child_x, + r.w * sizeof (struct glyph)); /* Compute a new hash since we changed glyphs. */ root_row->hash = row_hash (root_row); From 56efab930b5c129aa9c87f99f657b7d704c6d5f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerd=20M=C3=B6llmann?= Date: Tue, 5 Nov 2024 10:26:36 +0100 Subject: [PATCH 31/53] TTY menus: handle saved state referencing dead frames * src/term.c (restore_desired_matrix): If a tty menu saves a current matrix that contains glyphs from a child frame, handle the case that that child frame dies before the saved state is restored. --- src/term.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/src/term.c b/src/term.c index bd48e1f3e55..a7f7baa6e3c 100644 --- a/src/term.c +++ b/src/term.c @@ -3121,9 +3121,7 @@ save_and_enable_current_matrix (struct frame *f) static void restore_desired_matrix (struct frame *f, struct glyph_matrix *saved) { - int i; - - for (i = 0; i < saved->nrows; ++i) + for (int i = 0; i < saved->nrows; ++i) { struct glyph_row *from = saved->rows + i; struct glyph_row *to = f->desired_matrix->rows + i; @@ -3133,7 +3131,23 @@ restore_desired_matrix (struct frame *f, struct glyph_matrix *saved) memcpy (to->glyphs[TEXT_AREA], from->glyphs[TEXT_AREA], nbytes); to->used[TEXT_AREA] = from->used[TEXT_AREA]; to->enabled_p = from->enabled_p; - to->hash = from->hash; + + bool need_new_hash = false; + for (int x = 0; x < f->desired_matrix->matrix_w; ++x) + { + struct glyph *glyph = to->glyphs[0] + x; + if (!FRAME_LIVE_P (glyph->frame)) + { + glyph->frame = f; + glyph->face_id = DEFAULT_FACE_ID; + need_new_hash = true; + } + } + + if (need_new_hash) + to->hash = row_hash (to); + else + to->hash = from->hash; } } From 908a18c463bf7d2da3c39ea6141cab68fd7eac30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerd=20M=C3=B6llmann?= Date: Tue, 5 Nov 2024 20:10:38 +0100 Subject: [PATCH 32/53] * src/dispnew.c (neutralize_wide_char): Don't use used[0] --- src/dispnew.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/dispnew.c b/src/dispnew.c index a7adbfb6f16..b8bc9f73afa 100644 --- a/src/dispnew.c +++ b/src/dispnew.c @@ -3547,20 +3547,19 @@ neutralize_wide_char (struct frame *root, struct glyph_row *row, int x) if (x < 0 || x >= root->desired_matrix->matrix_w) return; - struct glyph *glyph = row->glyphs[0] + x; + struct glyph *glyph = row->glyphs[TEXT_AREA] + x; if (glyph->type == CHAR_GLYPH && CHARACTER_WIDTH (glyph->u.ch) > 1) { - struct glyph *row_start = row->glyphs[0]; - struct glyph *row_limit = row_start + row->used[0]; - /* Glyph is somewhere in a sequence of glyphs for a wide character, find the start. */ + struct glyph *row_start = row->glyphs[TEXT_AREA]; while (glyph > row_start && glyph->padding_p) --glyph; /* Make everything in the sequence a space glyph. */ eassert (!glyph->padding_p); make_glyph_space (glyph); + struct glyph *row_limit = row_start + row->used[TEXT_AREA]; for (++glyph; glyph < row_limit && glyph->padding_p; ++glyph) make_glyph_space (glyph); } From d27fc61755d8dd4a65db6291f1c83492003b30b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerd=20M=C3=B6llmann?= Date: Wed, 6 Nov 2024 05:48:46 +0100 Subject: [PATCH 33/53] Add tty-tip.el, not tooltips, but very close --- lisp/tty-tip.el | 196 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 196 insertions(+) create mode 100644 lisp/tty-tip.el diff --git a/lisp/tty-tip.el b/lisp/tty-tip.el new file mode 100644 index 00000000000..92a115b2008 --- /dev/null +++ b/lisp/tty-tip.el @@ -0,0 +1,196 @@ +;;; -*- lexical-binding: t; symbol-packages: t; -*- +;;; tty-tip.el --- Display help in kind of tooltips on ttys + +;; Copyright (C) 2024 Free Software Foundation, Inc. + +;; GNU Emacs is free software: you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; GNU Emacs is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs. If not, see . + +;;; Commentary: + +;; This uses tty child frames to display help which looks and feels much +;; like using tooltips (but they really aren't). + +;; Use `tty-tip-mode' to activate or toggle this feature. +;; +;; You can customize face `tooltip', `tooltip-short-delay', +;; `tooltip-delay', `tooltip-recent-seconds'. + +(require 'tooltip) + +(defvar tty-tip--frame nil) + +(defun tty-tip--make-buffer (text) + (with-current-buffer + (get-buffer-create " *tty-tip*") + ;; Redirect focus to parent. + (add-hook 'pre-command-hook #'tty-tip--delete-frame nil t) + ;; Use an empty keymap. + (use-local-map (make-keymap)) + (dolist (var '((mode-line-format . nil) + (header-line-format . nil) + (tab-line-format . nil) + (tab-bar-format . nil) ;; Emacs 28 tab-bar-format + (frame-title-format . "") + (truncate-lines . t) + (cursor-in-non-selected-windows . nil) + (cursor-type . nil) + (show-trailing-whitespace . nil) + (display-line-numbers . nil) + (left-fringe-width . nil) + (right-fringe-width . nil) + (left-margin-width . 0) + (right-margin-width . 0) + (fringes-outside-margins . 0) + (buffer-read-only . t))) + (set (make-local-variable (car var)) (cdr var))) + (let ((inhibit-modification-hooks t) + (inhibit-read-only t)) + (erase-buffer) + (insert text) + (goto-char (point-min))) + (current-buffer))) + +(defvar tty-tip-frame-parameters + `((visibility . nil) + (background-color . "lightyellow") + (foreground-color . "black") + (width . 0) (height . 0) + (min-width . t) (min-height . t) + (no-accept-focus . t) + (no-focus-on-map . t) + (border-width . 0) + (child-frame-border-width . 1) + (left-fringe . 0) + (right-fringe . 0) + (vertical-scroll-bars . nil) + (horizontal-scroll-bars . nil) + (menu-bar-lines . 0) + (tool-bar-lines . 0) + (tab-bar-lines . 0) + (no-other-frame . t) + (no-other-window . t) + (no-delete-other-windows . t) + (unsplittable . t) + (undecorated . t) + (cursor-type . nil) + (no-special-glyphs . t) + (desktop-dont-save . t))) + +(defun tty-tip--frame-parameters () + (let ((params (copy-sequence tty-tip-frame-parameters)) + (fg (face-attribute 'tooltip :foreground)) + (bg (face-attribute 'tooltip :background))) + (when (stringp fg) + (setf (alist-get 'foreground-color params) fg)) + (when (stringp bg) + (setf (alist-get 'background-color params) bg)) + params)) + +(defun tty-tip--delete-frame () + (when tty-tip--frame + (delete-frame tty-tip--frame) + (setq tty-tip--frame nil) + t)) + +(defun tty-tip--compute-position () + (let* ((pos (mouse-position)) + (mouse-x (car (cdr pos))) + (mouse-y (cdr (cdr pos))) + (x (+ mouse-x 1)) + (y (+ mouse-y 1)) + (tip-width (frame-width tty-tip--frame)) + (tip-height (frame-height tty-tip--frame)) + (tty-width (display-pixel-width)) + (tty-height (display-pixel-height))) + (when (> (+ x tip-width) tty-width) + (setq x (max 0 (- x tip-width 1)))) + (when (> (+ y tip-height) tty-height) + (setq y (max 0 (- y tip-height 1)))) + (cons x y))) + +(defun tty-tip--create-frame (text) + (let* ((minibuffer (minibuffer-window (window-frame))) + (buffer (tty-tip--make-buffer text)) + (window-min-height 1) + (window-min-width 1) + after-make-frame-functions + (text-lines (string-lines text))) + (setq tty-tip--frame + (make-frame + `((parent-frame . ,(car (mouse-position))) + (minibuffer . ,minibuffer) + ,@(tty-tip--frame-parameters)))) + (let ((win (frame-root-window tty-tip--frame))) + (set-window-buffer win buffer) + (set-window-dedicated-p win t) + (set-frame-size tty-tip--frame + (apply #'max (mapcar #'string-width text-lines)) + (length text-lines)) + (let* ((pos (tty-tip--compute-position)) + (x (car pos)) + (y (cdr pos))) + (set-frame-position tty-tip--frame x y)) + (make-frame-visible tty-tip--frame)))) + +(defvar tty-tip--help-message nil) +(defvar tty-tip--hide-time nil) +(defvar tty-tip--timeout-id nil) + +(defun tty-tip--delay () + (if (and tty-tip--hide-time + (time-less-p (time-since tty-tip--hide-time) + tooltip-recent-seconds)) + tooltip-short-delay + tooltip-delay)) + +(defun tty-tip--cancel-delayed-tip () + (when tty-tip--timeout-id + (cancel-timer tty-tip--timeout-id) + (setq tty-tip--timeout-id nil))) + +(defun tty-tip--start-delayed-tip () + (setq tty-tip--timeout-id + (run-with-timer (tty-tip--delay) nil + (lambda () + (tty-tip--create-frame + tty-tip--help-message))))) + +(defun tty-tip--hide (&optional _ignored-arg) + (tty-tip--cancel-delayed-tip) + (when (tty-tip--delete-frame) + (setq tty-tip--hide-time (float-time)))) + +(defun tty-tip--show-help (msg) + (let ((previous-help tty-tip--help-message)) + (setq tty-tip--help-message msg) + (cond ((null msg) + (tty-tip--hide)) + ((equal previous-help msg) + nil) + (t + (tty-tip--hide) + (tty-tip--start-delayed-tip))))) + +;;;###autoload +(define-minor-mode tty-tip-mode + "Global minor mode for displaying help in tty child frames." + :global t :group 'help + (unless (display-graphic-p) + (if tty-tip-mode + (setq show-help-function #'tty-tip--show-help) + (setq show-help-function nil)))) + +(provide 'tty-tip) + +;;; End From e0bfd3ce23eafb13ab0400f3046074b83784d9f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerd=20M=C3=B6llmann?= Date: Wed, 6 Nov 2024 10:22:50 +0100 Subject: [PATCH 34/53] Let tty tips disappear automatically * lisp/tty-tip.el (tty-tip--create-frame): Delete tip frame after x-show-tooltip-timeout seconds. --- lisp/tty-tip.el | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lisp/tty-tip.el b/lisp/tty-tip.el index 92a115b2008..7f600fd3772 100644 --- a/lisp/tty-tip.el +++ b/lisp/tty-tip.el @@ -3,6 +3,8 @@ ;; Copyright (C) 2024 Free Software Foundation, Inc. +;; This file is part of GNU Emacs. + ;; GNU Emacs is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or @@ -141,7 +143,8 @@ (x (car pos)) (y (cdr pos))) (set-frame-position tty-tip--frame x y)) - (make-frame-visible tty-tip--frame)))) + (make-frame-visible tty-tip--frame) + (run-at-time x-show-tooltip-timeout nil #'tty-tip--delete-frame)))) (defvar tty-tip--help-message nil) (defvar tty-tip--hide-time nil) From 907c735402dd26e721ca8534df1e326fc53a3012 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerd=20M=C3=B6llmann?= Date: Wed, 6 Nov 2024 11:42:53 +0100 Subject: [PATCH 35/53] Remove tip in pre-command-hook * lisp/tty-tip.el (tty-tip-mode): install pre-command-hook that deleted the tip frame. --- lisp/tty-tip.el | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/lisp/tty-tip.el b/lisp/tty-tip.el index 7f600fd3772..33b4c81bfca 100644 --- a/lisp/tty-tip.el +++ b/lisp/tty-tip.el @@ -190,9 +190,12 @@ "Global minor mode for displaying help in tty child frames." :global t :group 'help (unless (display-graphic-p) - (if tty-tip-mode - (setq show-help-function #'tty-tip--show-help) - (setq show-help-function nil)))) + (cond (tty-tip-mode + (setq show-help-function #'tty-tip--show-help) + (add-hook 'pre-command-hook #'tty-tip--delete-frame)) + (t + (setq show-help-function nil) + (remove-hook 'pre-command-hook #'tty-tip--delete-frame))))) (provide 'tty-tip) From c42b90b21a4efb3c5a8ebc6e3bd6be2908d1f2ac Mon Sep 17 00:00:00 2001 From: Jeff Walsh Date: Tue, 5 Nov 2024 23:09:56 +1100 Subject: [PATCH 36/53] Mark atimer allocation as ambiguous root * src/atimer.c (start_atimer): Time could be passed a lisp object for data, we should allocate this as an ambiguous root --- src/atimer.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/atimer.c b/src/atimer.c index 8253ae3a166..5bd282a310d 100644 --- a/src/atimer.c +++ b/src/atimer.c @@ -17,6 +17,7 @@ You should have received a copy of the GNU General Public License along with GNU Emacs. If not, see . */ #include +#include "igc.h" #ifdef WINDOWSNT #define raise(s) w32_raise(s) @@ -132,7 +133,13 @@ start_atimer (enum atimer_type type, struct timespec timestamp, free_atimers = t->next; } else - t = xmalloc (sizeof *t); + { +#ifdef HAVE_MPS + t = igc_xzalloc_ambig (sizeof *t); +#else + t = xmalloc (sizeof *t); +#endif + } /* Fill the atimer structure. */ memset (t, 0, sizeof *t); From cc3c05cad9ef42cd7b0231efdbdba228aa06de92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerd=20M=C3=B6llmann?= Date: Wed, 6 Nov 2024 14:34:47 +0100 Subject: [PATCH 37/53] Revert "Mark atimer allocation as ambiguous root" This reverts commit c42b90b21a4efb3c5a8ebc6e3bd6be2908d1f2ac. --- src/atimer.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/atimer.c b/src/atimer.c index 5bd282a310d..8253ae3a166 100644 --- a/src/atimer.c +++ b/src/atimer.c @@ -17,7 +17,6 @@ You should have received a copy of the GNU General Public License along with GNU Emacs. If not, see . */ #include -#include "igc.h" #ifdef WINDOWSNT #define raise(s) w32_raise(s) @@ -133,13 +132,7 @@ start_atimer (enum atimer_type type, struct timespec timestamp, free_atimers = t->next; } else - { -#ifdef HAVE_MPS - t = igc_xzalloc_ambig (sizeof *t); -#else - t = xmalloc (sizeof *t); -#endif - } + t = xmalloc (sizeof *t); /* Fill the atimer structure. */ memset (t, 0, sizeof *t); From 6cd7ce7cf2a36a790c7e1e0a5496c35fc9d56495 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerd=20M=C3=B6llmann?= Date: Wed, 6 Nov 2024 14:55:59 +0100 Subject: [PATCH 38/53] Fix hiding tips from pre-command-hook * lisp/tty-tip.el (tty-tip-mode): Put #'tty-tip--hide on the pre-command-hook. --- lisp/tty-tip.el | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lisp/tty-tip.el b/lisp/tty-tip.el index 33b4c81bfca..728c16b6856 100644 --- a/lisp/tty-tip.el +++ b/lisp/tty-tip.el @@ -192,10 +192,10 @@ (unless (display-graphic-p) (cond (tty-tip-mode (setq show-help-function #'tty-tip--show-help) - (add-hook 'pre-command-hook #'tty-tip--delete-frame)) + (add-hook 'pre-command-hook #'tty-tip--hide)) (t (setq show-help-function nil) - (remove-hook 'pre-command-hook #'tty-tip--delete-frame))))) + (remove-hook 'pre-command-hook #'tty-tip--hide))))) (provide 'tty-tip) From 8fa26765c0dcedcadf884195189e337cb9778cb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerd=20M=C3=B6llmann?= Date: Sat, 9 Nov 2024 08:26:06 +0100 Subject: [PATCH 39/53] Don't copy from non-enabled current glyphs (bug#74274) * src/dispnew.c (prepare_desired_root_row): Check if current row is enabled. --- src/dispnew.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/dispnew.c b/src/dispnew.c index b8bc9f73afa..260e7ef2d1d 100644 --- a/src/dispnew.c +++ b/src/dispnew.c @@ -3520,9 +3520,12 @@ prepare_desired_root_row (struct frame *root, int y) if (!root_row->enabled_p) { struct glyph_row *from = MATRIX_ROW (root->current_matrix, y); - memcpy (root_row->glyphs[0], from->glyphs[0], - root->current_matrix->matrix_w * sizeof (struct glyph)); - root_row->enabled_p = true; + if (from->enabled_p) + { + memcpy (root_row->glyphs[0], from->glyphs[0], + root->current_matrix->matrix_w * sizeof (struct glyph)); + root_row->enabled_p = true; + } } return root_row; } From aa8bebf9b3eff9e53eeb1dc1a91fcc9ee5ee1095 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sat, 9 Nov 2024 14:07:09 +0200 Subject: [PATCH 40/53] ; * src/dispnew.c (prepare_desired_root_row): Add commentary (bug#74274). --- src/dispnew.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/dispnew.c b/src/dispnew.c index 260e7ef2d1d..1b8b726b7f3 100644 --- a/src/dispnew.c +++ b/src/dispnew.c @@ -3517,6 +3517,8 @@ prepare_desired_root_row (struct frame *root, int y) /* Start with the root's desired matrix row. If that hasn't been redisplayed, copy from the root's current matrix. */ struct glyph_row *root_row = MATRIX_ROW (root->desired_matrix, y); + /* Don't copy rows that aren't enabled, in particuler because they + might not have the 'frame' member of glyphs set. */ if (!root_row->enabled_p) { struct glyph_row *from = MATRIX_ROW (root->current_matrix, y); From 582ebedd33ed957b9ad409e35ed7ba9dafa42c01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerd=20M=C3=B6llmann?= Date: Sun, 10 Nov 2024 16:18:29 +0100 Subject: [PATCH 41/53] Another case of copying from non-enabled glyphs (bug#74274) * src/dispnew.c (build_frame_matrix_from_leaf_window): If current window row is not enabled, don't copy from it. --- src/dispnew.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/dispnew.c b/src/dispnew.c index 1b8b726b7f3..4758aabe967 100644 --- a/src/dispnew.c +++ b/src/dispnew.c @@ -2636,10 +2636,21 @@ build_frame_matrix_from_leaf_window (struct glyph_matrix *frame_matrix, struct w if (current_row_p) { - /* Copy window row to frame row. */ - memcpy (frame_row->glyphs[TEXT_AREA] + window_matrix->matrix_x, - window_row->glyphs[0], - window_matrix->matrix_w * sizeof (struct glyph)); + /* If the desired glyphs for this row haven't been built, + copy from the corresponding current row, but only if it + is enabled, because ottherwise its contents are invalid. */ + struct glyph *to = frame_row->glyphs[TEXT_AREA] + window_matrix->matrix_x; + struct glyph *from = window_row->glyphs[0]; + for (int i = 0; i < window_matrix->matrix_w; ++i) + { + if (window_row->enabled_p) + to[i] = from[i]; + else + { + to[i] = space_glyph; + to[i].frame = f; + } + } } else { From 437ccbe612b377fd5ac492572702978ec75ea0df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerd=20M=C3=B6llmann?= Date: Sun, 10 Nov 2024 16:19:40 +0100 Subject: [PATCH 42/53] Change interface of prepare_desired_root_row * src/dispnew.c (prepare_desired_root_row): Return NULL if we can't prepare the row. (produce_box_line, copy_child_glyphs): Callers changed accordingly. --- src/dispnew.c | 41 +++++++++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/src/dispnew.c b/src/dispnew.c index 4758aabe967..06d1ae3e6c6 100644 --- a/src/dispnew.c +++ b/src/dispnew.c @@ -3519,28 +3519,32 @@ make_matrix_current (struct frame *f) make_current (f, NULL, i); } -/* Prepare ROOT's desired row at index Y for copying child - frame contents to it. */ +/* Prepare ROOT's desired row at index Y for copying child frame + contents to it. Value is the prepared desired row or NULL if we + don't have, and can't contruct a desired row. */ static struct glyph_row * prepare_desired_root_row (struct frame *root, int y) { - /* Start with the root's desired matrix row. If that hasn't been - redisplayed, copy from the root's current matrix. */ - struct glyph_row *root_row = MATRIX_ROW (root->desired_matrix, y); + /* If we have a desired row that has been displayed, use that. */ + struct glyph_row *desired_row = MATRIX_ROW (root->desired_matrix, y); + if (desired_row->enabled_p) + return desired_row; + + /* If we have a current row that is up to date, copy that to the + desired row and use that. */ /* Don't copy rows that aren't enabled, in particuler because they might not have the 'frame' member of glyphs set. */ - if (!root_row->enabled_p) + struct glyph_row *current_row = MATRIX_ROW (root->current_matrix, y); + if (current_row->enabled_p) { - struct glyph_row *from = MATRIX_ROW (root->current_matrix, y); - if (from->enabled_p) - { - memcpy (root_row->glyphs[0], from->glyphs[0], - root->current_matrix->matrix_w * sizeof (struct glyph)); - root_row->enabled_p = true; - } + memcpy (desired_row->glyphs[0], current_row->glyphs[0], + root->current_matrix->matrix_w * sizeof (struct glyph)); + desired_row->enabled_p = true; + return desired_row; } - return root_row; + + return NULL; } /* Change GLYPH to be a space glyph. */ @@ -3667,6 +3671,8 @@ produce_box_line (struct frame *root, struct frame *child, int x, int y, int w, bool first) { struct glyph_row *root_row = prepare_desired_root_row (root, y); + if (root_row == NULL) + return; if (first) produce_box_sides (BOX_DOWN_RIGHT, BOX_DOWN_LEFT, root_row, x, w, root, child); else @@ -3703,8 +3709,9 @@ copy_child_glyphs (struct frame *root, struct frame *child) for (int y = r.y; y < r.y + r.h; ++y) { struct glyph_row *root_row = prepare_desired_root_row (root, y); - produce_box_sides (BOX_VERTICAL, BOX_VERTICAL, root_row, r.x, r.w, - root, child); + if (root_row) + produce_box_sides (BOX_VERTICAL, BOX_VERTICAL, root_row, r.x, r.w, + root, child); } /* Horizontal line below. */ @@ -3722,6 +3729,8 @@ copy_child_glyphs (struct frame *root, struct frame *child) for (int y = r.y; y < r.y + r.h; ++y, ++child_y) { struct glyph_row *root_row = prepare_desired_root_row (root, y); + if (root_row == NULL) + continue; /* Deal with wide characters unless already done as part of drawing a box around the child frame. */ From 37cdf2897ad51f45a228c86f5f12feeb284673df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerd=20M=C3=B6llmann?= Date: Tue, 12 Nov 2024 09:23:27 +0100 Subject: [PATCH 43/53] Fix a FIXME In redisplay_internal * src/xdisp.c (redisplay_internal): Compare root frames before setting the frame garbaged. --- src/xdisp.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/xdisp.c b/src/xdisp.c index bd3e8f3138d..f9764f82e03 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -17035,19 +17035,22 @@ redisplay_internal (void) if (face_change) windows_or_buffers_changed = 47; - /* FIXME: Can we do better for tty child frames? It could be - a bit faster when we switch between child frames of the same - root frame. OTOH, it's probably not a frequent use case. */ + struct frame *previous_frame; if ((FRAME_TERMCAP_P (sf) || FRAME_MSDOS_P (sf)) - && FRAME_TTY (sf)->previous_frame != sf) + && (previous_frame = FRAME_TTY (sf)->previous_frame, + previous_frame != sf)) { - /* Since frames on a single ASCII terminal share the same - display area, displaying a different frame means redisplay - the whole thing. */ - SET_FRAME_GARBAGED (sf); + if (previous_frame == NULL + || root_frame (previous_frame) != root_frame (sf)) + { + /* Since frames on a single terminal share the same display + area, displaying a different frame means redisplay the + whole thing. */ + SET_FRAME_GARBAGED (sf); #if !defined DOS_NT && !defined HAVE_ANDROID - set_tty_color_mode (FRAME_TTY (sf), sf); + set_tty_color_mode (FRAME_TTY (sf), sf); #endif + } FRAME_TTY (sf)->previous_frame = sf; } From 4da9abe653fe536afc67fe5e175227eac10e31cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerd=20M=C3=B6llmann?= Date: Fri, 15 Nov 2024 08:15:10 +0100 Subject: [PATCH 44/53] Respect redisplay_dont_pause in combined update * src/dispnew.c (combine_updates): Respect redisplay_dont_pause. This is important for echo_area_display which binds that variable. --- src/dispnew.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/dispnew.c b/src/dispnew.c index 06d1ae3e6c6..d473a77e3ad 100644 --- a/src/dispnew.c +++ b/src/dispnew.c @@ -4002,6 +4002,9 @@ combine_updates_for_frame (struct frame *f, bool force_p, bool inhibit_scrolling bool combine_updates (Lisp_Object roots, bool force_p, bool inhibit_scrolling) { + if (redisplay_dont_pause) + force_p = true; + for (; CONSP (roots); roots = XCDR (roots)) { struct frame *root = XFRAME (XCAR (roots)); From f62d70f52f4f6b7ed158d618bf790df21f171172 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerd=20M=C3=B6llmann?= Date: Fri, 15 Nov 2024 13:34:55 +0100 Subject: [PATCH 45/53] Don't pause display for pending input * src/dispnew.c: Remove display_completed, redisplay_dont_pause, redisplay-dont-pause was declared obsolete in Emacs 24. Remove anything checking pending input, change function signatures accordingly, and so on. * src/keyboard.c (read_char): Don't use redisplay_dont_pause. * src/minibuf.c (read_minibuf): Use new function signatures. * src/xdisp.c: Don't check display_completed. Use new API. * lisp/subr.el (redisplay-dont-pause): Remove declaration. --- lisp/subr.el | 1 - src/dispextern.h | 9 +- src/dispnew.c | 601 +++++++++++++++++++---------------------------- src/keyboard.c | 3 +- src/minibuf.c | 4 +- src/xdisp.c | 199 ++++------------ 6 files changed, 291 insertions(+), 526 deletions(-) diff --git a/lisp/subr.el b/lisp/subr.el index 4771ac1fba2..8f0b6c5939c 100644 --- a/lisp/subr.el +++ b/lisp/subr.el @@ -1990,7 +1990,6 @@ be a list of the form returned by `event-start' and `event-end'." ;; It's been announced as obsolete in NEWS and in the docstring since Emacs-25, ;; but it's only been marked for compilation warnings since Emacs-29. "25.1") -(make-obsolete-variable 'redisplay-dont-pause nil "24.5") (make-obsolete-variable 'operating-system-release nil "28.1") (make-obsolete-variable 'inhibit-changing-match-data 'save-match-data "29.1") diff --git a/src/dispextern.h b/src/dispextern.h index c368e665c61..4a013236432 100644 --- a/src/dispextern.h +++ b/src/dispextern.h @@ -1322,9 +1322,6 @@ struct glyph_row *matrix_row (struct glyph_matrix *, int); extern struct glyph space_glyph; -/* True means last display completed. False means it was preempted. */ - -extern bool display_completed; /************************************************************************ Glyph Strings @@ -3805,7 +3802,7 @@ extern Lisp_Object marginal_area_string (struct window *, enum window_part, Lisp_Object *, int *, int *, int *, int *); extern void redraw_frame (struct frame *); -extern bool update_frame (struct frame *, bool, bool); +void update_frame (struct frame *, bool); extern void update_frame_with_menu (struct frame *, int, int); extern int update_mouse_position (struct frame *, int, int); extern void bitch_at_user (void); @@ -3924,8 +3921,8 @@ Lisp_Object frames_in_reverse_z_order (struct frame *f, bool visible); bool is_tty_frame (struct frame *f); bool is_tty_child_frame (struct frame *f); bool is_tty_root_frame (struct frame *f); -bool combine_updates (Lisp_Object root_frames, bool force_p, bool inhibit_id_p); -bool combine_updates_for_frame (struct frame *f, bool force_p, bool inhibit_id_p); +void combine_updates (Lisp_Object root_frames, bool inhibit_id_p); +void combine_updates_for_frame (struct frame *f, bool inhibit_id_p); void tty_raise_lower_frame (struct frame *f, bool raise); int max_child_z_order (struct frame *parent); diff --git a/src/dispnew.c b/src/dispnew.c index d473a77e3ad..37ec37b752e 100644 --- a/src/dispnew.c +++ b/src/dispnew.c @@ -93,10 +93,10 @@ static void check_matrix_pointers (struct glyph_matrix *, struct glyph_matrix *); #endif static void mirror_line_dance (struct window *, int, int, int *, char *); -static bool update_window_tree (struct window *, bool); -static bool update_window (struct window *, bool); -static bool write_matrix (struct frame *, bool, bool, bool, bool); -static bool scrolling (struct frame *); +static void update_window_tree (struct window *); +static void update_window (struct window *); +static void write_matrix (struct frame *, bool, bool, bool); +static void scrolling (struct frame *); static void set_window_cursor_after_update (struct window *); static void adjust_frame_glyphs_for_window_redisplay (struct frame *); static void adjust_frame_glyphs_for_frame_redisplay (struct frame *); @@ -116,10 +116,6 @@ check_rows (struct frame *f) } #endif -/* True means last display completed. False means it was preempted. */ - -bool display_completed; - /* True means SIGWINCH happened when not safe. */ static bool delayed_size_change; @@ -175,11 +171,10 @@ static uintmax_t history_tick; /* Add to the redisplay history how window W has been displayed. MSG is a trace containing the information how W's glyph matrix - has been constructed. PAUSED_P means that the update - has been interrupted for pending input. */ + has been constructed. */ static void -add_window_display_history (struct window *w, const char *msg, bool paused_p) +add_window_display_history (struct window *w, const char *msg) { char *buf; void *ptr = w; @@ -190,14 +185,13 @@ add_window_display_history (struct window *w, const char *msg, bool paused_p) ++history_idx; snprintf (buf, sizeof redisplay_history[0].trace, - "%"PRIuMAX": window %p (%s)%s\n%s", + "%"PRIuMAX": window %p %s\n%s", history_tick++, ptr, ((BUFFERP (w->contents) && STRINGP (BVAR (XBUFFER (w->contents), name))) ? SSDATA (BVAR (XBUFFER (w->contents), name)) : "???"), - paused_p ? " ***paused***" : "", msg); } @@ -2136,8 +2130,7 @@ adjust_frame_glyphs_for_frame_redisplay (struct frame *f) current matrix over a call to adjust_glyph_matrix, we must make a copy of the current glyphs, and restore the current matrix' contents from that copy. */ - if (display_completed - && !FRAME_GARBAGED_P (f) + if (!FRAME_GARBAGED_P (f) && matrix_dim.width == f->current_matrix->matrix_w && matrix_dim.height == f->current_matrix->matrix_h /* For some reason, the frame glyph matrix gets corrupted if @@ -2682,7 +2675,7 @@ build_frame_matrix_from_leaf_window (struct glyph_matrix *frame_matrix, struct w frame and window share glyphs. */ strcpy (w->current_matrix->method, w->desired_matrix->method); - add_window_display_history (w, w->current_matrix->method, 0); + add_window_display_history (w, w->current_matrix->method); #endif } @@ -3778,7 +3771,7 @@ update_bar_window (Lisp_Object window, Lisp_Object *current, struct window *w = XWINDOW (window); if (w->must_be_updated_p) { - update_window (w, true); + update_window (w); w->must_be_updated_p = false; Lisp_Object tem = *current; *current = *desired; @@ -3808,8 +3801,8 @@ update_tool_bar (struct frame *f) #endif } -static bool -update_window_frame (struct frame *f, bool force_p) +static void +update_window_frame (struct frame *f) { eassert (FRAME_WINDOW_P (f)); update_begin (f); @@ -3817,19 +3810,17 @@ update_window_frame (struct frame *f, bool force_p) update_tab_bar (f); update_tool_bar (f); struct window *root_window = XWINDOW (f->root_window); - bool paused_p = update_window_tree (root_window, force_p); + update_window_tree (root_window); update_end (f); set_window_update_flags (root_window, false); - return paused_p; } -static bool -update_initial_frame (struct frame *f, bool force_p) +static void +update_initial_frame (struct frame *f) { build_frame_matrix (f); struct window *root_window = XWINDOW (f->root_window); set_window_update_flags (root_window, false); - return false; } static void @@ -3840,11 +3831,10 @@ flush_terminal (struct frame *f) fflush (FRAME_TTY (f)->output); } -static bool -update_tty_frame (struct frame *f, bool force_p) +static void +update_tty_frame (struct frame *f) { build_frame_matrix (f); - return false; } /* Return the cursor position of the selected window of frame F, in @@ -3952,8 +3942,8 @@ terminal_cursor_magic (struct frame *root, struct frame *topmost_child) } } -bool -combine_updates_for_frame (struct frame *f, bool force_p, bool inhibit_scrolling) +void +combine_updates_for_frame (struct frame *f, bool inhibit_scrolling) { struct frame *root = root_frame (f); eassert (FRAME_VISIBLE_P (root)); @@ -3969,13 +3959,12 @@ combine_updates_for_frame (struct frame *f, bool force_p, bool inhibit_scrolling } update_begin (root); - bool paused = write_matrix (root, force_p, inhibit_scrolling, 1, false); - if (!paused) - make_matrix_current (root); + write_matrix (root, inhibit_scrolling, 1, false); + make_matrix_current (root); update_end (root); /* If a child is displayed, and the cursor is displayed in another - frame, the child might lay above the cursor, so that it appers to + frame, the child might lay above the cursor, so that it appears to "shine through" the child. Avoid that because it's confusing. */ if (topmost_child) terminal_cursor_magic (root, topmost_child); @@ -3992,66 +3981,33 @@ combine_updates_for_frame (struct frame *f, bool force_p, bool inhibit_scrolling add_frame_display_history (f, false); #endif } - - return paused; } /* Update on the screen all root frames ROOTS. Called from redisplay_internal as the last step of redisplaying. */ -bool -combine_updates (Lisp_Object roots, bool force_p, bool inhibit_scrolling) +void +combine_updates (Lisp_Object roots, bool inhibit_scrolling) { - if (redisplay_dont_pause) - force_p = true; - for (; CONSP (roots); roots = XCDR (roots)) { struct frame *root = XFRAME (XCAR (roots)); - if (combine_updates_for_frame (root, force_p, inhibit_scrolling)) - { - display_completed = false; - return true; - } + combine_updates_for_frame (root, inhibit_scrolling); } - - display_completed = true; - return false; } /* Update frame F based on the data in desired matrices. + If INHIBIT_SCROLLING, don't try scrolling. */ - If FORCE_P, don't let redisplay be stopped by detecting pending input. - If INHIBIT_SCROLLING, don't try scrolling. - - Value is true if redisplay was stopped due to pending input. */ - -bool -update_frame (struct frame *f, bool force_p, bool inhibit_scrolling) +void +update_frame (struct frame *f, bool inhibit_scrolling) { - struct window *root_window = XWINDOW (f->root_window); - - if (redisplay_dont_pause) - force_p = true; - else if (!force_p && detect_input_pending_ignore_squeezables ()) - { - /* Reset flags indicating that a window should be updated. */ - set_window_update_flags (root_window, false); - display_completed = false; - return true; - } - - bool paused; if (FRAME_WINDOW_P (f)) - paused = update_window_frame (f, force_p); + update_window_frame (f); else if (FRAME_INITIAL_P (f)) - paused = update_initial_frame (f, force_p); + update_initial_frame (f); else - paused = update_tty_frame (f, force_p); - - if (paused) - display_completed = false; - return paused; + update_tty_frame (f); } /* Update a TTY frame F that has a menu dropped down over some of its @@ -4077,7 +4033,7 @@ update_frame_with_menu (struct frame *f, int row, int col) cursor_at_point_p = !(row >= 0 && col >= 0); /* Do not stop due to pending input, and do not try scrolling. This means that write_glyphs will always return false. */ - write_matrix (f, 1, 1, cursor_at_point_p, true); + write_matrix (f, 1, cursor_at_point_p, true); make_matrix_current (f); clear_desired_matrices (f); /* ROW and COL tell us where in the menu to position the cursor, so @@ -4100,7 +4056,6 @@ update_frame_with_menu (struct frame *f, int row, int col) /* Reset flags indicating that a window should be updated. */ set_window_update_flags (root_window, false); - display_completed = true; } /* Update the mouse position for a frame F. This handles both @@ -4156,30 +4111,24 @@ properties or updating the help echo text. */) Window-based updates ************************************************************************/ -/* Perform updates in window tree rooted at W. - If FORCE_P, don't stop updating if input is pending. */ +/* Perform updates in window tree rooted at W. */ -static bool -update_window_tree (struct window *w, bool force_p) +static void +update_window_tree (struct window *w) { - bool paused_p = 0; - - while (w && !paused_p) + while (w) { if (WINDOWP (w->contents)) - paused_p |= update_window_tree (XWINDOW (w->contents), force_p); + update_window_tree (XWINDOW (w->contents)); else if (w->must_be_updated_p) - paused_p |= update_window (w, force_p); + update_window (w); w = NILP (w->next) ? 0 : XWINDOW (w->next); } - - return paused_p; } -/* Update window W if its flag must_be_updated_p is set. - If FORCE_P, don't stop updating if input is pending. */ +/* Update window W if its flag must_be_updated_p is set. */ void update_single_window (struct window *w) @@ -4190,7 +4139,7 @@ update_single_window (struct window *w) /* Update W. */ update_begin (f); - update_window (w, true); + update_window (w); update_end (f); /* Reset flag in W. */ @@ -4330,15 +4279,12 @@ check_current_matrix_flags (struct window *w) #endif /* GLYPH_DEBUG */ -/* Update display of window W. - If FORCE_P, don't stop updating when input is pending. */ +/* Update display of window W. */ -static bool -update_window (struct window *w, bool force_p) +static void +update_window (struct window *w) { struct glyph_matrix *desired_matrix = w->desired_matrix; - bool paused_p; - int preempt_count = clip_to_bounds (1, baud_rate / 2400 + 1, INT_MAX); #ifdef HAVE_WINDOW_SYSTEM struct redisplay_interface *rif = FRAME_RIF (XFRAME (WINDOW_FRAME (w))); #endif @@ -4347,224 +4293,200 @@ update_window (struct window *w, bool force_p) eassert (FRAME_WINDOW_P (XFRAME (WINDOW_FRAME (w)))); #endif - /* Check pending input the first time so that we can quickly return. */ - if (!force_p) - detect_input_pending_ignore_squeezables (); - /* If forced to complete the update, no input is pending, or we are tracking the mouse, do the update. */ - if (force_p || !input_pending || !NILP (track_mouse)) - { - struct glyph_row *row, *end; - struct glyph_row *mode_line_row; - struct glyph_row *tab_line_row; - struct glyph_row *header_line_row; - int yb; - bool changed_p = 0, mouse_face_overwritten_p = 0; - int n_updated = 0; - bool invisible_rows_marked = false; + struct glyph_row *row, *end; + struct glyph_row *mode_line_row; + struct glyph_row *tab_line_row; + struct glyph_row *header_line_row; + int yb; + bool changed_p = 0, mouse_face_overwritten_p = 0; + bool invisible_rows_marked = false; #ifdef HAVE_WINDOW_SYSTEM - gui_update_window_begin (w); + gui_update_window_begin (w); #else - (void) changed_p; + (void) changed_p; #endif - yb = window_text_bottom_y (w); - row = MATRIX_ROW (desired_matrix, 0); - end = MATRIX_MODE_LINE_ROW (desired_matrix); + yb = window_text_bottom_y (w); + row = MATRIX_ROW (desired_matrix, 0); + end = MATRIX_MODE_LINE_ROW (desired_matrix); - /* Take note of the tab line, if there is one. We will - update it below, after updating all of the window's lines. */ - if (row->mode_line_p && row->tab_line_p) - { - tab_line_row = row; - ++row; - } - else - tab_line_row = NULL; - - /* Take note of the header line, if there is one. We will - update it below, after updating all of the window's lines. */ - if (row->mode_line_p) - { - header_line_row = row; - ++row; - } - else - header_line_row = NULL; - - /* Update the mode line, if necessary. */ - mode_line_row = MATRIX_MODE_LINE_ROW (desired_matrix); - if (mode_line_row->mode_line_p && mode_line_row->enabled_p) - { - mode_line_row->y = yb + WINDOW_SCROLL_BAR_AREA_HEIGHT (w); - update_window_line (w, MATRIX_ROW_VPOS (mode_line_row, - desired_matrix), - &mouse_face_overwritten_p); - } - - /* Find first enabled row. Optimizations in redisplay_internal - may lead to an update with only one row enabled. There may - be also completely empty matrices. */ - while (row < end && !row->enabled_p) - ++row; - - /* Try reusing part of the display by copying. */ - if (row < end && !desired_matrix->no_scrolling_p) - { - int rc = scrolling_window (w, (tab_line_row != NULL ? 1 : 0) - + (header_line_row != NULL ? 1 : 0)); - if (rc < 0) - { - /* All rows were found to be equal. */ - paused_p = 0; - goto set_cursor; - } - else if (rc > 0) - { - /* We've scrolled the display. */ - force_p = 1; - changed_p = 1; - } - } - - /* Update the rest of the lines. */ - for (; row < end && (force_p || !input_pending); ++row) - /* scrolling_window resets the enabled_p flag of the rows it - reuses from current_matrix. */ - if (row->enabled_p) - { - int vpos = MATRIX_ROW_VPOS (row, desired_matrix); - int i; - - /* We'll have to play a little bit with when to - detect_input_pending. If it's done too often, - scrolling large windows with repeated scroll-up - commands will too quickly pause redisplay. */ - if (!force_p && ++n_updated % preempt_count == 0) - detect_input_pending_ignore_squeezables (); - changed_p |= update_window_line (w, vpos, - &mouse_face_overwritten_p); - - /* Mark all rows below the last visible one in the current - matrix as invalid. This is necessary because of - variable line heights. Consider the case of three - successive redisplays, where the first displays 5 - lines, the second 3 lines, and the third 5 lines again. - If the second redisplay wouldn't mark rows in the - current matrix invalid, the third redisplay might be - tempted to optimize redisplay based on lines displayed - in the first redisplay. */ - if (MATRIX_ROW_BOTTOM_Y (row) >= yb) - { - for (i = vpos + 1; i < w->current_matrix->nrows - 1; ++i) - SET_MATRIX_ROW_ENABLED_P (w->current_matrix, i, false); - invisible_rows_marked = true; - } - } - - /* If the window doesn't display its mode line, make sure the - corresponding row of the current glyph matrix is disabled, so - that if and when the mode line is displayed again, it will be - cleared and completely redrawn. */ - if (!window_wants_mode_line (w)) - SET_MATRIX_ROW_ENABLED_P (w->current_matrix, - w->current_matrix->nrows - 1, false); - - /* Was display preempted? */ - paused_p = row < end; - - if (!paused_p && !invisible_rows_marked) - { - /* If we didn't mark the invisible rows in the current - matrix as invalid above, do that now. This can happen if - scrolling_window updates the last visible rows of the - current matrix, in which case the above loop doesn't get - to examine the last visible row. */ - int i; - for (i = 0; i < w->current_matrix->nrows - 1; ++i) - { - struct glyph_row *current_row = MATRIX_ROW (w->current_matrix, i); - if (current_row->enabled_p - && MATRIX_ROW_BOTTOM_Y (current_row) >= yb) - { - for (++i ; i < w->current_matrix->nrows - 1; ++i) - SET_MATRIX_ROW_ENABLED_P (w->current_matrix, i, false); - } - } - } - - set_cursor: - - /* Update the tab line after scrolling because a new tab - line would otherwise overwrite lines at the top of the window - that can be scrolled. */ - if (tab_line_row && tab_line_row->enabled_p) - { - tab_line_row->y = 0; - update_window_line (w, 0, &mouse_face_overwritten_p); - } - - /* Update the header line after scrolling because a new header - line would otherwise overwrite lines at the top of the window - that can be scrolled. */ - if (header_line_row && header_line_row->enabled_p) - { - header_line_row->y = tab_line_row ? CURRENT_TAB_LINE_HEIGHT (w) : 0; - update_window_line (w, tab_line_row ? 1 : 0, &mouse_face_overwritten_p); - } - - /* Fix the appearance of overlapping/overlapped rows. */ - if (!paused_p && !w->pseudo_window_p) - { -#ifdef HAVE_WINDOW_SYSTEM - if (changed_p && rif->fix_overlapping_area) - { - redraw_overlapped_rows (w, yb); - redraw_overlapping_rows (w, yb); - } -#endif - - /* Make cursor visible at cursor position of W. */ - set_window_cursor_after_update (w); - -#if 0 /* Check that current matrix invariants are satisfied. This is - for debugging only. See the comment of check_matrix_invariants. */ - IF_DEBUG (check_matrix_invariants (w)); -#endif - } - -#ifdef GLYPH_DEBUG - /* Remember the redisplay method used to display the matrix. */ - strcpy (w->current_matrix->method, w->desired_matrix->method); -#endif - -#ifdef HAVE_WINDOW_SYSTEM - update_window_fringes (w, 0); - - /* End the update of window W. Don't set the cursor if we - paused updating the display because in this case, - set_window_cursor_after_update hasn't been called, and - W->output_cursor doesn't contain the cursor location. */ - gui_update_window_end (w, !paused_p, mouse_face_overwritten_p); -#endif - /* If the update wasn't interrupted, this window has been - completely updated. */ - if (!paused_p) - w->must_be_updated_p = false; + /* Take note of the tab line, if there is one. We will + update it below, after updating all of the window's lines. */ + if (row->mode_line_p && row->tab_line_p) + { + tab_line_row = row; + ++row; } else - paused_p = 1; + tab_line_row = NULL; + + /* Take note of the header line, if there is one. We will + update it below, after updating all of the window's lines. */ + if (row->mode_line_p) + { + header_line_row = row; + ++row; + } + else + header_line_row = NULL; + + /* Update the mode line, if necessary. */ + mode_line_row = MATRIX_MODE_LINE_ROW (desired_matrix); + if (mode_line_row->mode_line_p && mode_line_row->enabled_p) + { + mode_line_row->y = yb + WINDOW_SCROLL_BAR_AREA_HEIGHT (w); + update_window_line (w, MATRIX_ROW_VPOS (mode_line_row, + desired_matrix), + &mouse_face_overwritten_p); + } + + /* Find first enabled row. Optimizations in redisplay_internal + may lead to an update with only one row enabled. There may + be also completely empty matrices. */ + while (row < end && !row->enabled_p) + ++row; + + /* Try reusing part of the display by copying. */ + if (row < end && !desired_matrix->no_scrolling_p) + { + int rc = scrolling_window (w, (tab_line_row != NULL ? 1 : 0) + + (header_line_row != NULL ? 1 : 0)); + if (rc < 0) + { + /* All rows were found to be equal. */ + goto set_cursor; + } + else if (rc > 0) + { + /* We've scrolled the display. */ + changed_p = 1; + } + } + + /* Update the rest of the lines. */ + for (; row < end; ++row) + /* scrolling_window resets the enabled_p flag of the rows it + reuses from current_matrix. */ + if (row->enabled_p) + { + int vpos = MATRIX_ROW_VPOS (row, desired_matrix); + int i; + + changed_p |= update_window_line (w, vpos, + &mouse_face_overwritten_p); + + /* Mark all rows below the last visible one in the current + matrix as invalid. This is necessary because of + variable line heights. Consider the case of three + successive redisplays, where the first displays 5 + lines, the second 3 lines, and the third 5 lines again. + If the second redisplay wouldn't mark rows in the + current matrix invalid, the third redisplay might be + tempted to optimize redisplay based on lines displayed + in the first redisplay. */ + if (MATRIX_ROW_BOTTOM_Y (row) >= yb) + { + for (i = vpos + 1; i < w->current_matrix->nrows - 1; ++i) + SET_MATRIX_ROW_ENABLED_P (w->current_matrix, i, false); + invisible_rows_marked = true; + } + } + + /* If the window doesn't display its mode line, make sure the + corresponding row of the current glyph matrix is disabled, so + that if and when the mode line is displayed again, it will be + cleared and completely redrawn. */ + if (!window_wants_mode_line (w)) + SET_MATRIX_ROW_ENABLED_P (w->current_matrix, + w->current_matrix->nrows - 1, false); + + if (!invisible_rows_marked) + { + /* If we didn't mark the invisible rows in the current + matrix as invalid above, do that now. This can happen if + scrolling_window updates the last visible rows of the + current matrix, in which case the above loop doesn't get + to examine the last visible row. */ + int i; + for (i = 0; i < w->current_matrix->nrows - 1; ++i) + { + struct glyph_row *current_row = MATRIX_ROW (w->current_matrix, i); + if (current_row->enabled_p + && MATRIX_ROW_BOTTOM_Y (current_row) >= yb) + { + for (++i ; i < w->current_matrix->nrows - 1; ++i) + SET_MATRIX_ROW_ENABLED_P (w->current_matrix, i, false); + } + } + } + + set_cursor: + + /* Update the tab line after scrolling because a new tab + line would otherwise overwrite lines at the top of the window + that can be scrolled. */ + if (tab_line_row && tab_line_row->enabled_p) + { + tab_line_row->y = 0; + update_window_line (w, 0, &mouse_face_overwritten_p); + } + + /* Update the header line after scrolling because a new header + line would otherwise overwrite lines at the top of the window + that can be scrolled. */ + if (header_line_row && header_line_row->enabled_p) + { + header_line_row->y = tab_line_row ? CURRENT_TAB_LINE_HEIGHT (w) : 0; + update_window_line (w, tab_line_row ? 1 : 0, &mouse_face_overwritten_p); + } + + /* Fix the appearance of overlapping/overlapped rows. */ + if (!w->pseudo_window_p) + { +#ifdef HAVE_WINDOW_SYSTEM + if (changed_p && rif->fix_overlapping_area) + { + redraw_overlapped_rows (w, yb); + redraw_overlapping_rows (w, yb); + } +#endif + + /* Make cursor visible at cursor position of W. */ + set_window_cursor_after_update (w); + +#if 0 /* Check that current matrix invariants are satisfied. This is + for debugging only. See the comment of check_matrix_invariants. */ + IF_DEBUG (check_matrix_invariants (w)); +#endif + } + +#ifdef GLYPH_DEBUG + /* Remember the redisplay method used to display the matrix. */ + strcpy (w->current_matrix->method, w->desired_matrix->method); +#endif + +#ifdef HAVE_WINDOW_SYSTEM + update_window_fringes (w, 0); + + /* End the update of window W. Don't set the cursor if we + paused updating the display because in this case, + set_window_cursor_after_update hasn't been called, and + W->output_cursor doesn't contain the cursor location. */ + gui_update_window_end (w, true, mouse_face_overwritten_p); +#endif + /* If the update wasn't interrupted, this window has been + completely updated. */ + w->must_be_updated_p = false; #ifdef GLYPH_DEBUG /* check_current_matrix_flags (w); */ - add_window_display_history (w, w->current_matrix->method, paused_p); + add_window_display_history (w, w->current_matrix->method); #endif xwidget_end_redisplay (w, w->current_matrix); clear_glyph_matrix (desired_matrix); - - return paused_p; } #ifdef HAVE_WINDOW_SYSTEM @@ -5697,20 +5619,13 @@ tty_set_cursor (void) } /* Write desired matix of tty frame F and make it current. - - FORCE_P means that the update should not be stopped by pending input. INHIBIT_ID_P means that scrolling by insert/delete should not be tried. - SET_CURSOR_P false means do not set cursor at point in selected window. + SET_CURSOR_P false means do not set cursor at point in selected window. */ - Value is true if update was stopped due to pending input. */ - -static bool -write_matrix (struct frame *f, bool force_p, bool inhibit_id_p, +static void +write_matrix (struct frame *f, bool inhibit_id_p, bool set_cursor_p, bool updating_menu_p) { - if (!force_p && detect_input_pending_ignore_squeezables ()) - return true; - /* If we cannot insert/delete lines, it's no use trying it. */ if (!FRAME_LINE_INS_DEL_OK (f)) inhibit_id_p = true; @@ -5722,7 +5637,7 @@ write_matrix (struct frame *f, bool force_p, bool inhibit_id_p, i/d line if just want cursor motion. */ int first_row = first_enabled_row (f->desired_matrix); if (!inhibit_id_p && first_row >= 0) - force_p |= scrolling (f); + scrolling (f); /* Update the individual lines as needed. Do bottom line first. This is done so that messages are made visible when pausing. */ @@ -5730,36 +5645,19 @@ write_matrix (struct frame *f, bool force_p, bool inhibit_id_p, if (MATRIX_ROW_ENABLED_P (f->desired_matrix, last_row)) write_row (f, last_row, updating_menu_p); - bool pause_p = false; if (first_row >= 0) - { - const int preempt_count = clip_to_bounds (1, baud_rate / 2400 + 1, INT_MAX); - - for (int i = first_row, n = 0; i < last_row; ++i) - if (MATRIX_ROW_ENABLED_P (f->desired_matrix, i)) - { - if (!force_p && n % preempt_count == 0 - && detect_input_pending_ignore_squeezables ()) - { - pause_p = true; - break; - } - - write_row (f, i, updating_menu_p); - ++n; - } - } + for (int i = first_row; i < last_row; ++i) + if (MATRIX_ROW_ENABLED_P (f->desired_matrix, i)) + write_row (f, i, updating_menu_p); /* Now just clean up termcap drivers and set cursor, etc. */ - if (!pause_p && set_cursor_p) + if (set_cursor_p) tty_set_cursor (); - - return pause_p; } /* Do line insertions/deletions on frame F for frame-based redisplay. */ -static bool +static void scrolling (struct frame *frame) { /* In fact this code should never be reached at all under @@ -5796,7 +5694,7 @@ scrolling (struct frame *frame) if (!MATRIX_ROW_ENABLED_P (current_matrix, i)) { SAFE_FREE (); - return false; + return; } old_hash[i] = line_hash_code (frame, MATRIX_ROW (current_matrix, i)); if (! MATRIX_ROW_ENABLED_P (desired_matrix, i)) @@ -5827,7 +5725,7 @@ scrolling (struct frame *frame) || unchanged_at_bottom == height) { SAFE_FREE (); - return true; + return; } window_size = (height - unchanged_at_top @@ -5857,7 +5755,6 @@ scrolling (struct frame *frame) SAFE_FREE (); #endif - return false; } @@ -6989,27 +6886,18 @@ sit_for (Lisp_Object timeout, bool reading, int display_option) DEFUN ("redisplay", Fredisplay, Sredisplay, 0, 1, 0, - doc: /* Perform redisplay. -Optional arg FORCE, if non-nil, prevents redisplay from being -preempted by arriving input, even if `redisplay-dont-pause' is nil. -If `redisplay-dont-pause' is non-nil (the default), redisplay is never -preempted by arriving input, so FORCE does nothing. - -Return t if redisplay was performed, nil if redisplay was preempted -immediately by pending input. */) + doc : /* Perform redisplay. +Optional arg FORCE exists for historical reasons and is ignored. +Value is t if redisplay has been performed, nil if executing a +keyboard macro. */) (Lisp_Object force) { swallow_events (true); - if ((detect_input_pending_run_timers (1) - && NILP (force) && !redisplay_dont_pause) - || !NILP (Vexecuting_kbd_macro)) + if (!NILP (Vexecuting_kbd_macro)) return Qnil; - specpdl_ref count = SPECPDL_INDEX (); - if (!NILP (force) && !redisplay_dont_pause) - specbind (Qredisplay_dont_pause, Qt); redisplay_preserve_echo_area (2); - return unbind_to (count, Qt); + return Qt; } @@ -7462,8 +7350,6 @@ syms_of_display (void) /* This is the "purpose" slot of a display table. */ DEFSYM (Qdisplay_table, "display-table"); DEFSYM (Qframe__z_order_lessp, "frame--z-order-lessp"); - - DEFSYM (Qredisplay_dont_pause, "redisplay-dont-pause"); DEFSYM (Qtty_non_selected_cursor, "tty-non-selected-cursor"); DEFVAR_INT ("baud-rate", baud_rate, @@ -7545,17 +7431,6 @@ It is also used for standard output and error streams. See `buffer-display-table' for more information. */); Vstandard_display_table = Qnil; - DEFVAR_BOOL ("redisplay-dont-pause", redisplay_dont_pause, - doc: /* Nil means display update is paused when input is detected. */); - /* Contrary to expectations, a value of "false" can be detrimental to - responsiveness since aborting a redisplay throws away some of the - work already performed. It's usually more efficient (and gives - more prompt feedback to the user) to let the redisplay terminate, - and just completely skip the next command's redisplay (which is - done regardless of this setting if there's pending input at the - beginning of the next redisplay). */ - redisplay_dont_pause = true; - DEFVAR_LISP ("x-show-tooltip-timeout", Vx_show_tooltip_timeout, doc: /* The default timeout (in seconds) for `x-show-tip'. */); Vx_show_tooltip_timeout = make_fixnum (5); diff --git a/src/keyboard.c b/src/keyboard.c index bfb5fd3592b..fe485a3efd6 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -2663,8 +2663,7 @@ read_char (int commandflag, Lisp_Object map, swallow_events (false); /* May clear input_pending. */ /* Redisplay if no pending input. */ - while (!(input_pending - && (input_was_pending || !redisplay_dont_pause))) + while (!(input_pending && input_was_pending)) { input_was_pending = input_pending; if (help_echo_showing_p && !BASE_EQ (selected_window, minibuf_window)) diff --git a/src/minibuf.c b/src/minibuf.c index c8267045397..390db0d31fa 100644 --- a/src/minibuf.c +++ b/src/minibuf.c @@ -914,9 +914,9 @@ read_minibuf (Lisp_Object map, Lisp_Object initial, Lisp_Object prompt, XWINDOW (minibuf_window)->cursor.x = 0; XWINDOW (minibuf_window)->must_be_updated_p = true; struct frame *sf = XFRAME (selected_frame); - update_frame (sf, true, true); + update_frame (sf, true); if (is_tty_frame (sf)) - combine_updates_for_frame (sf, true, true); + combine_updates_for_frame (sf, true); #ifndef HAVE_NTGUI flush_frame (XFRAME (XWINDOW (minibuf_window)->frame)); diff --git a/src/xdisp.c b/src/xdisp.c index f9764f82e03..7d9dd6e8e85 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -1116,7 +1116,6 @@ static void set_iterator_to_next (struct it *, bool); static void mark_window_display_accurate_1 (struct window *, bool); static bool row_for_charpos_p (struct glyph_row *, ptrdiff_t); static bool cursor_row_p (struct glyph_row *); -static int redisplay_mode_lines (Lisp_Object, bool); static void handle_line_prefix (struct it *); @@ -13511,24 +13510,6 @@ echo_area_display (bool update_frame_p) here could cause confusion. */ if (update_frame_p && !redisplaying_p) { - int n = 0; - - /* If the display update has been interrupted by pending - input, update mode lines in the frame. Due to the - pending input, it might have been that redisplay hasn't - been called, so that mode lines above the echo area are - garbaged. This looks odd, so we prevent it here. */ - if (!display_completed) - { - n = redisplay_mode_lines (FRAME_ROOT_WINDOW (f), false); - -#ifdef HAVE_WINDOW_SYSTEM - if (FRAME_WINDOW_P (f) - && FRAME_RIF (f)->clear_under_internal_border) - FRAME_RIF (f)->clear_under_internal_border (f); -#endif - } - if (window_height_changed_p /* Don't do this if Emacs is shutting down. Redisplay needs to run hooks. */ @@ -13537,13 +13518,10 @@ echo_area_display (bool update_frame_p) /* Must update other windows. Likewise as in other cases, don't let this update be interrupted by pending input. */ - specpdl_ref count = SPECPDL_INDEX (); - specbind (Qredisplay_dont_pause, Qt); fset_redisplay (f); redisplay_internal (); - unbind_to (count, Qnil); } - else if (FRAME_WINDOW_P (f) && n == 0) + else if (FRAME_WINDOW_P (f)) { /* Window configuration is the same as before. Can do with a display update of the echo area, @@ -13553,9 +13531,9 @@ echo_area_display (bool update_frame_p) } else { - update_frame (f, true, true); + update_frame (f, true); if (is_tty_frame (f)) - combine_updates_for_frame (f, true, true); + combine_updates_for_frame (f, true); } /* If cursor is in the echo area, make sure that the next @@ -16938,7 +16916,6 @@ redisplay_internal (void) struct window *w = XWINDOW (selected_window); struct window *sw; struct frame *fr; - bool pending; bool must_finish = false, match_p; struct text_pos tlbufpos, tlendpos; int number_of_visible_frames; @@ -17024,7 +17001,6 @@ redisplay_internal (void) /* Remember the currently selected window. */ sw = w; - pending = false; forget_escape_and_glyphless_faces (); inhibit_free_realized_faces = false; @@ -17590,7 +17566,7 @@ redisplay_internal (void) unrequest_sigio (); STOP_POLLING; - pending |= update_frame (f, false, false); + update_frame (f, false); /* On some platforms (at least MS-Windows), the scroll_run_hook called from scrolling_window called from update_frame could set the frame's @@ -17612,27 +17588,24 @@ redisplay_internal (void) } if (CONSP (tty_root_frames)) - pending |= combine_updates (tty_root_frames, false, false); + combine_updates (tty_root_frames, false); eassert (EQ (XFRAME (selected_frame)->selected_window, selected_window)); - if (!pending) + /* Do the mark_window_display_accurate after all windows have + been redisplayed because this call resets flags in buffers + which are needed for proper redisplay. */ + FOR_EACH_FRAME (tail, frame) { - /* Do the mark_window_display_accurate after all windows have - been redisplayed because this call resets flags in buffers - which are needed for proper redisplay. */ - FOR_EACH_FRAME (tail, frame) - { - struct frame *f = XFRAME (frame); - if (f->updated_p) - { - f->redisplay = false; - f->garbaged = false; - mark_window_display_accurate (f->root_window, true); - if (FRAME_TERMINAL (f)->frame_up_to_date_hook) - FRAME_TERMINAL (f)->frame_up_to_date_hook (f); - } - } + struct frame *f = XFRAME (frame); + if (f->updated_p) + { + f->redisplay = false; + f->garbaged = false; + mark_window_display_accurate (f->root_window, true); + if (FRAME_TERMINAL (f)->frame_up_to_date_hook) + FRAME_TERMINAL (f)->frame_up_to_date_hook (f); + } } } else if (FRAME_REDISPLAY_P (sf)) @@ -17696,10 +17669,10 @@ redisplay_internal (void) } XWINDOW (selected_window)->must_be_updated_p = true; - pending = update_frame (sf, false, false); + update_frame (sf, false); if (is_tty_frame (sf)) - pending |= combine_updates_for_frame (sf, false, false); + combine_updates_for_frame (sf, false); sf->cursor_type_changed = false; sf->inhibit_clear_image_cache = false; @@ -17716,11 +17689,11 @@ redisplay_internal (void) if (mini_frame != sf) { XWINDOW (mini_window)->must_be_updated_p = true; - pending |= update_frame (mini_frame, false, false); + update_frame (mini_frame, false); if (is_tty_frame (mini_frame)) - pending |= combine_updates_for_frame (mini_frame, false, false); + combine_updates_for_frame (mini_frame, false); mini_frame->cursor_type_changed = false; - if (!pending && hscroll_retries <= MAX_HSCROLL_RETRIES + if (hscroll_retries <= MAX_HSCROLL_RETRIES && hscroll_windows (mini_window)) { hscroll_retries++; @@ -17729,47 +17702,26 @@ redisplay_internal (void) } } - /* If display was paused because of pending input, make sure we do a - thorough update the next time. */ - if (pending) + if (!consider_all_windows_p) { - /* Prevent the optimization at the beginning of - redisplay_internal that tries a single-line update of the - line containing the cursor in the selected window. */ - CHARPOS (this_line_start_pos) = 0; + /* This has already been done above if + consider_all_windows_p is set. */ + if (XBUFFER (w->contents)->text->redisplay + && buffer_window_count (XBUFFER (w->contents)) > 1) + /* This can happen if b->text->redisplay was set during + jit-lock. */ + propagate_buffer_redisplay (); + mark_window_display_accurate_1 (w, true); - /* Let the overlay arrow be updated the next time. */ - update_overlay_arrows (0); + /* Say overlay arrows are up to date. */ + update_overlay_arrows (1); - /* If we pause after scrolling, some rows in the current - matrices of some windows are not valid. */ - if (!WINDOW_FULL_WIDTH_P (w) - && !FRAME_WINDOW_P (XFRAME (w->frame))) - update_mode_lines = 36; + if (FRAME_TERMINAL (sf)->frame_up_to_date_hook != 0) + FRAME_TERMINAL (sf)->frame_up_to_date_hook (sf); } - else - { - if (!consider_all_windows_p) - { - /* This has already been done above if - consider_all_windows_p is set. */ - if (XBUFFER (w->contents)->text->redisplay - && buffer_window_count (XBUFFER (w->contents)) > 1) - /* This can happen if b->text->redisplay was set during - jit-lock. */ - propagate_buffer_redisplay (); - mark_window_display_accurate_1 (w, true); - /* Say overlay arrows are up to date. */ - update_overlay_arrows (1); - - if (FRAME_TERMINAL (sf)->frame_up_to_date_hook != 0) - FRAME_TERMINAL (sf)->frame_up_to_date_hook (sf); - } - - update_mode_lines = 0; - windows_or_buffers_changed = 0; - } + update_mode_lines = 0; + windows_or_buffers_changed = 0; /* Start SIGIO interrupts coming again. Having them off during the code above makes it less likely one will discard output, but not @@ -17785,26 +17737,23 @@ redisplay_internal (void) redisplay constructing glyphs, so simply exposing a frame won't display anything in this case. So, we have to display these frames here explicitly. */ - if (!pending) + int new_count = 0; + + FOR_EACH_FRAME (tail, frame) { - int new_count = 0; - - FOR_EACH_FRAME (tail, frame) - { - if (FRAME_REDISPLAY_P (XFRAME (frame))) - new_count++; - } - - if (new_count != number_of_visible_frames) - windows_or_buffers_changed = 52; + if (FRAME_REDISPLAY_P (XFRAME (frame))) + new_count++; } + if (new_count != number_of_visible_frames) + windows_or_buffers_changed = 52; + /* Change frame size now if a change is pending. */ do_pending_window_change (true); /* If we just did a pending size change, or have additional visible frames, or selected_window changed, redisplay again. */ - if ((windows_or_buffers_changed && !pending) + if (windows_or_buffers_changed || (WINDOWP (selected_window) && (w = XWINDOW (selected_window)) != sw)) goto retry; @@ -27394,60 +27343,6 @@ display_tty_menu_item (const char *item_text, int width, int face_id, Mode Line ***********************************************************************/ -/* Redisplay mode lines in the window tree whose root is WINDOW. - If FORCE, redisplay mode lines unconditionally. - Otherwise, redisplay only mode lines that are garbaged. Value is - the number of windows whose mode lines were redisplayed. */ - -static int -redisplay_mode_lines (Lisp_Object window, bool force) -{ - int nwindows = 0; - - while (!NILP (window)) - { - struct window *w = XWINDOW (window); - - if (WINDOWP (w->contents)) - nwindows += redisplay_mode_lines (w->contents, force); - else if (force - || FRAME_GARBAGED_P (XFRAME (w->frame)) - || !MATRIX_MODE_LINE_ROW (w->current_matrix)->enabled_p) - { - struct text_pos lpoint; - struct buffer *old = current_buffer; - - /* Set the window's buffer for the mode line display. */ - SET_TEXT_POS (lpoint, PT, PT_BYTE); - set_buffer_internal_1 (XBUFFER (w->contents)); - - /* Point refers normally to the selected window. For any - other window, set up appropriate value. */ - if (!EQ (window, selected_window)) - { - struct text_pos pt; - - CLIP_TEXT_POS_FROM_MARKER (pt, w->pointm); - TEMP_SET_PT_BOTH (CHARPOS (pt), BYTEPOS (pt)); - } - - /* Display mode lines. */ - clear_glyph_matrix (w->desired_matrix); - if (display_mode_lines (w)) - ++nwindows; - - /* Restore old settings. */ - set_buffer_internal_1 (old); - TEMP_SET_PT_BOTH (CHARPOS (lpoint), BYTEPOS (lpoint)); - } - - window = w->next; - } - - return nwindows; -} - - /* Display the mode line, the header line, and the tab-line of window W. Value is the sum number of mode lines, header lines, and tab lines actually displayed. */ From 627cbf05b53756883a789ff45727acf23f5066a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerd=20M=C3=B6llmann?= Date: Sat, 16 Nov 2024 08:57:35 +0100 Subject: [PATCH 46/53] Remove an unused parameter * src/dispnew.c (combine_updates): Remove unused parameter inhibit_scrolling. * src/xdisp.c (redisplay_internal): Adjust caller. * src/dispextern.h: Change function prototype. --- src/dispextern.h | 2 +- src/dispnew.c | 4 ++-- src/xdisp.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/dispextern.h b/src/dispextern.h index 47afc48bb60..0bbd7beeb91 100644 --- a/src/dispextern.h +++ b/src/dispextern.h @@ -3922,7 +3922,7 @@ Lisp_Object frames_in_reverse_z_order (struct frame *f, bool visible); bool is_tty_frame (struct frame *f); bool is_tty_child_frame (struct frame *f); bool is_tty_root_frame (struct frame *f); -void combine_updates (Lisp_Object root_frames, bool inhibit_id_p); +void combine_updates (Lisp_Object root_frames); void combine_updates_for_frame (struct frame *f, bool inhibit_id_p); void tty_raise_lower_frame (struct frame *f, bool raise); int max_child_z_order (struct frame *parent); diff --git a/src/dispnew.c b/src/dispnew.c index 37ec37b752e..cbc7d4d7aaf 100644 --- a/src/dispnew.c +++ b/src/dispnew.c @@ -3987,12 +3987,12 @@ combine_updates_for_frame (struct frame *f, bool inhibit_scrolling) redisplay_internal as the last step of redisplaying. */ void -combine_updates (Lisp_Object roots, bool inhibit_scrolling) +combine_updates (Lisp_Object roots) { for (; CONSP (roots); roots = XCDR (roots)) { struct frame *root = XFRAME (XCAR (roots)); - combine_updates_for_frame (root, inhibit_scrolling); + combine_updates_for_frame (root, false); } } diff --git a/src/xdisp.c b/src/xdisp.c index 3364c6870cf..66140fe6010 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -17588,7 +17588,7 @@ redisplay_internal (void) } if (CONSP (tty_root_frames)) - combine_updates (tty_root_frames, false); + combine_updates (tty_root_frames); eassert (EQ (XFRAME (selected_frame)->selected_window, selected_window)); From e5a2bc740dc43de63acb6e9603ad1905fac1e2c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerd=20M=C3=B6llmann?= Date: Sat, 16 Nov 2024 13:51:50 +0100 Subject: [PATCH 47/53] Revert "Remove an unused parameter" This reverts commit 627cbf05b53756883a789ff45727acf23f5066a4. --- src/dispextern.h | 2 +- src/dispnew.c | 4 ++-- src/xdisp.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/dispextern.h b/src/dispextern.h index 0bbd7beeb91..47afc48bb60 100644 --- a/src/dispextern.h +++ b/src/dispextern.h @@ -3922,7 +3922,7 @@ Lisp_Object frames_in_reverse_z_order (struct frame *f, bool visible); bool is_tty_frame (struct frame *f); bool is_tty_child_frame (struct frame *f); bool is_tty_root_frame (struct frame *f); -void combine_updates (Lisp_Object root_frames); +void combine_updates (Lisp_Object root_frames, bool inhibit_id_p); void combine_updates_for_frame (struct frame *f, bool inhibit_id_p); void tty_raise_lower_frame (struct frame *f, bool raise); int max_child_z_order (struct frame *parent); diff --git a/src/dispnew.c b/src/dispnew.c index cbc7d4d7aaf..37ec37b752e 100644 --- a/src/dispnew.c +++ b/src/dispnew.c @@ -3987,12 +3987,12 @@ combine_updates_for_frame (struct frame *f, bool inhibit_scrolling) redisplay_internal as the last step of redisplaying. */ void -combine_updates (Lisp_Object roots) +combine_updates (Lisp_Object roots, bool inhibit_scrolling) { for (; CONSP (roots); roots = XCDR (roots)) { struct frame *root = XFRAME (XCAR (roots)); - combine_updates_for_frame (root, false); + combine_updates_for_frame (root, inhibit_scrolling); } } diff --git a/src/xdisp.c b/src/xdisp.c index 66140fe6010..3364c6870cf 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -17588,7 +17588,7 @@ redisplay_internal (void) } if (CONSP (tty_root_frames)) - combine_updates (tty_root_frames); + combine_updates (tty_root_frames, false); eassert (EQ (XFRAME (selected_frame)->selected_window, selected_window)); From e7359fbbc40bbf714fb5b4bffc256b455fbe9a6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerd=20M=C3=B6llmann?= Date: Sat, 16 Nov 2024 13:52:17 +0100 Subject: [PATCH 48/53] Revert "Don't pause display for pending input" This reverts commit f62d70f52f4f6b7ed158d618bf790df21f171172. --- lisp/subr.el | 1 + src/dispextern.h | 9 +- src/dispnew.c | 553 +++++++++++++++++++++++++++++------------------ src/keyboard.c | 3 +- src/minibuf.c | 4 +- src/xdisp.c | 199 +++++++++++++---- 6 files changed, 502 insertions(+), 267 deletions(-) diff --git a/lisp/subr.el b/lisp/subr.el index 648e6f0f38f..6472c9d6916 100644 --- a/lisp/subr.el +++ b/lisp/subr.el @@ -1990,6 +1990,7 @@ be a list of the form returned by `event-start' and `event-end'." ;; It's been announced as obsolete in NEWS and in the docstring since Emacs-25, ;; but it's only been marked for compilation warnings since Emacs-29. "25.1") +(make-obsolete-variable 'redisplay-dont-pause nil "24.5") (make-obsolete-variable 'operating-system-release nil "28.1") (make-obsolete-variable 'inhibit-changing-match-data 'save-match-data "29.1") diff --git a/src/dispextern.h b/src/dispextern.h index 47afc48bb60..cb43d330b86 100644 --- a/src/dispextern.h +++ b/src/dispextern.h @@ -1322,6 +1322,9 @@ struct glyph_row *matrix_row (struct glyph_matrix *, int); extern struct glyph space_glyph; +/* True means last display completed. False means it was preempted. */ + +extern bool display_completed; /************************************************************************ Glyph Strings @@ -3803,7 +3806,7 @@ extern Lisp_Object marginal_area_string (struct window *, enum window_part, Lisp_Object *, int *, int *, int *, int *); extern void redraw_frame (struct frame *); -void update_frame (struct frame *, bool); +extern bool update_frame (struct frame *, bool, bool); extern void update_frame_with_menu (struct frame *, int, int); extern int update_mouse_position (struct frame *, int, int); extern void bitch_at_user (void); @@ -3922,8 +3925,8 @@ Lisp_Object frames_in_reverse_z_order (struct frame *f, bool visible); bool is_tty_frame (struct frame *f); bool is_tty_child_frame (struct frame *f); bool is_tty_root_frame (struct frame *f); -void combine_updates (Lisp_Object root_frames, bool inhibit_id_p); -void combine_updates_for_frame (struct frame *f, bool inhibit_id_p); +bool combine_updates (Lisp_Object root_frames, bool force_p, bool inhibit_id_p); +bool combine_updates_for_frame (struct frame *f, bool force_p, bool inhibit_id_p); void tty_raise_lower_frame (struct frame *f, bool raise); int max_child_z_order (struct frame *parent); diff --git a/src/dispnew.c b/src/dispnew.c index 37ec37b752e..d473a77e3ad 100644 --- a/src/dispnew.c +++ b/src/dispnew.c @@ -93,10 +93,10 @@ static void check_matrix_pointers (struct glyph_matrix *, struct glyph_matrix *); #endif static void mirror_line_dance (struct window *, int, int, int *, char *); -static void update_window_tree (struct window *); -static void update_window (struct window *); -static void write_matrix (struct frame *, bool, bool, bool); -static void scrolling (struct frame *); +static bool update_window_tree (struct window *, bool); +static bool update_window (struct window *, bool); +static bool write_matrix (struct frame *, bool, bool, bool, bool); +static bool scrolling (struct frame *); static void set_window_cursor_after_update (struct window *); static void adjust_frame_glyphs_for_window_redisplay (struct frame *); static void adjust_frame_glyphs_for_frame_redisplay (struct frame *); @@ -116,6 +116,10 @@ check_rows (struct frame *f) } #endif +/* True means last display completed. False means it was preempted. */ + +bool display_completed; + /* True means SIGWINCH happened when not safe. */ static bool delayed_size_change; @@ -171,10 +175,11 @@ static uintmax_t history_tick; /* Add to the redisplay history how window W has been displayed. MSG is a trace containing the information how W's glyph matrix - has been constructed. */ + has been constructed. PAUSED_P means that the update + has been interrupted for pending input. */ static void -add_window_display_history (struct window *w, const char *msg) +add_window_display_history (struct window *w, const char *msg, bool paused_p) { char *buf; void *ptr = w; @@ -185,13 +190,14 @@ add_window_display_history (struct window *w, const char *msg) ++history_idx; snprintf (buf, sizeof redisplay_history[0].trace, - "%"PRIuMAX": window %p %s\n%s", + "%"PRIuMAX": window %p (%s)%s\n%s", history_tick++, ptr, ((BUFFERP (w->contents) && STRINGP (BVAR (XBUFFER (w->contents), name))) ? SSDATA (BVAR (XBUFFER (w->contents), name)) : "???"), + paused_p ? " ***paused***" : "", msg); } @@ -2130,7 +2136,8 @@ adjust_frame_glyphs_for_frame_redisplay (struct frame *f) current matrix over a call to adjust_glyph_matrix, we must make a copy of the current glyphs, and restore the current matrix' contents from that copy. */ - if (!FRAME_GARBAGED_P (f) + if (display_completed + && !FRAME_GARBAGED_P (f) && matrix_dim.width == f->current_matrix->matrix_w && matrix_dim.height == f->current_matrix->matrix_h /* For some reason, the frame glyph matrix gets corrupted if @@ -2675,7 +2682,7 @@ build_frame_matrix_from_leaf_window (struct glyph_matrix *frame_matrix, struct w frame and window share glyphs. */ strcpy (w->current_matrix->method, w->desired_matrix->method); - add_window_display_history (w, w->current_matrix->method); + add_window_display_history (w, w->current_matrix->method, 0); #endif } @@ -3771,7 +3778,7 @@ update_bar_window (Lisp_Object window, Lisp_Object *current, struct window *w = XWINDOW (window); if (w->must_be_updated_p) { - update_window (w); + update_window (w, true); w->must_be_updated_p = false; Lisp_Object tem = *current; *current = *desired; @@ -3801,8 +3808,8 @@ update_tool_bar (struct frame *f) #endif } -static void -update_window_frame (struct frame *f) +static bool +update_window_frame (struct frame *f, bool force_p) { eassert (FRAME_WINDOW_P (f)); update_begin (f); @@ -3810,17 +3817,19 @@ update_window_frame (struct frame *f) update_tab_bar (f); update_tool_bar (f); struct window *root_window = XWINDOW (f->root_window); - update_window_tree (root_window); + bool paused_p = update_window_tree (root_window, force_p); update_end (f); set_window_update_flags (root_window, false); + return paused_p; } -static void -update_initial_frame (struct frame *f) +static bool +update_initial_frame (struct frame *f, bool force_p) { build_frame_matrix (f); struct window *root_window = XWINDOW (f->root_window); set_window_update_flags (root_window, false); + return false; } static void @@ -3831,10 +3840,11 @@ flush_terminal (struct frame *f) fflush (FRAME_TTY (f)->output); } -static void -update_tty_frame (struct frame *f) +static bool +update_tty_frame (struct frame *f, bool force_p) { build_frame_matrix (f); + return false; } /* Return the cursor position of the selected window of frame F, in @@ -3942,8 +3952,8 @@ terminal_cursor_magic (struct frame *root, struct frame *topmost_child) } } -void -combine_updates_for_frame (struct frame *f, bool inhibit_scrolling) +bool +combine_updates_for_frame (struct frame *f, bool force_p, bool inhibit_scrolling) { struct frame *root = root_frame (f); eassert (FRAME_VISIBLE_P (root)); @@ -3959,12 +3969,13 @@ combine_updates_for_frame (struct frame *f, bool inhibit_scrolling) } update_begin (root); - write_matrix (root, inhibit_scrolling, 1, false); - make_matrix_current (root); + bool paused = write_matrix (root, force_p, inhibit_scrolling, 1, false); + if (!paused) + make_matrix_current (root); update_end (root); /* If a child is displayed, and the cursor is displayed in another - frame, the child might lay above the cursor, so that it appears to + frame, the child might lay above the cursor, so that it appers to "shine through" the child. Avoid that because it's confusing. */ if (topmost_child) terminal_cursor_magic (root, topmost_child); @@ -3981,33 +3992,66 @@ combine_updates_for_frame (struct frame *f, bool inhibit_scrolling) add_frame_display_history (f, false); #endif } + + return paused; } /* Update on the screen all root frames ROOTS. Called from redisplay_internal as the last step of redisplaying. */ -void -combine_updates (Lisp_Object roots, bool inhibit_scrolling) +bool +combine_updates (Lisp_Object roots, bool force_p, bool inhibit_scrolling) { + if (redisplay_dont_pause) + force_p = true; + for (; CONSP (roots); roots = XCDR (roots)) { struct frame *root = XFRAME (XCAR (roots)); - combine_updates_for_frame (root, inhibit_scrolling); + if (combine_updates_for_frame (root, force_p, inhibit_scrolling)) + { + display_completed = false; + return true; + } } + + display_completed = true; + return false; } /* Update frame F based on the data in desired matrices. - If INHIBIT_SCROLLING, don't try scrolling. */ -void -update_frame (struct frame *f, bool inhibit_scrolling) + If FORCE_P, don't let redisplay be stopped by detecting pending input. + If INHIBIT_SCROLLING, don't try scrolling. + + Value is true if redisplay was stopped due to pending input. */ + +bool +update_frame (struct frame *f, bool force_p, bool inhibit_scrolling) { + struct window *root_window = XWINDOW (f->root_window); + + if (redisplay_dont_pause) + force_p = true; + else if (!force_p && detect_input_pending_ignore_squeezables ()) + { + /* Reset flags indicating that a window should be updated. */ + set_window_update_flags (root_window, false); + display_completed = false; + return true; + } + + bool paused; if (FRAME_WINDOW_P (f)) - update_window_frame (f); + paused = update_window_frame (f, force_p); else if (FRAME_INITIAL_P (f)) - update_initial_frame (f); + paused = update_initial_frame (f, force_p); else - update_tty_frame (f); + paused = update_tty_frame (f, force_p); + + if (paused) + display_completed = false; + return paused; } /* Update a TTY frame F that has a menu dropped down over some of its @@ -4033,7 +4077,7 @@ update_frame_with_menu (struct frame *f, int row, int col) cursor_at_point_p = !(row >= 0 && col >= 0); /* Do not stop due to pending input, and do not try scrolling. This means that write_glyphs will always return false. */ - write_matrix (f, 1, cursor_at_point_p, true); + write_matrix (f, 1, 1, cursor_at_point_p, true); make_matrix_current (f); clear_desired_matrices (f); /* ROW and COL tell us where in the menu to position the cursor, so @@ -4056,6 +4100,7 @@ update_frame_with_menu (struct frame *f, int row, int col) /* Reset flags indicating that a window should be updated. */ set_window_update_flags (root_window, false); + display_completed = true; } /* Update the mouse position for a frame F. This handles both @@ -4111,24 +4156,30 @@ properties or updating the help echo text. */) Window-based updates ************************************************************************/ -/* Perform updates in window tree rooted at W. */ +/* Perform updates in window tree rooted at W. + If FORCE_P, don't stop updating if input is pending. */ -static void -update_window_tree (struct window *w) +static bool +update_window_tree (struct window *w, bool force_p) { - while (w) + bool paused_p = 0; + + while (w && !paused_p) { if (WINDOWP (w->contents)) - update_window_tree (XWINDOW (w->contents)); + paused_p |= update_window_tree (XWINDOW (w->contents), force_p); else if (w->must_be_updated_p) - update_window (w); + paused_p |= update_window (w, force_p); w = NILP (w->next) ? 0 : XWINDOW (w->next); } + + return paused_p; } -/* Update window W if its flag must_be_updated_p is set. */ +/* Update window W if its flag must_be_updated_p is set. + If FORCE_P, don't stop updating if input is pending. */ void update_single_window (struct window *w) @@ -4139,7 +4190,7 @@ update_single_window (struct window *w) /* Update W. */ update_begin (f); - update_window (w); + update_window (w, true); update_end (f); /* Reset flag in W. */ @@ -4279,12 +4330,15 @@ check_current_matrix_flags (struct window *w) #endif /* GLYPH_DEBUG */ -/* Update display of window W. */ +/* Update display of window W. + If FORCE_P, don't stop updating when input is pending. */ -static void -update_window (struct window *w) +static bool +update_window (struct window *w, bool force_p) { struct glyph_matrix *desired_matrix = w->desired_matrix; + bool paused_p; + int preempt_count = clip_to_bounds (1, baud_rate / 2400 + 1, INT_MAX); #ifdef HAVE_WINDOW_SYSTEM struct redisplay_interface *rif = FRAME_RIF (XFRAME (WINDOW_FRAME (w))); #endif @@ -4293,200 +4347,224 @@ update_window (struct window *w) eassert (FRAME_WINDOW_P (XFRAME (WINDOW_FRAME (w)))); #endif + /* Check pending input the first time so that we can quickly return. */ + if (!force_p) + detect_input_pending_ignore_squeezables (); + /* If forced to complete the update, no input is pending, or we are tracking the mouse, do the update. */ - struct glyph_row *row, *end; - struct glyph_row *mode_line_row; - struct glyph_row *tab_line_row; - struct glyph_row *header_line_row; - int yb; - bool changed_p = 0, mouse_face_overwritten_p = 0; - bool invisible_rows_marked = false; + if (force_p || !input_pending || !NILP (track_mouse)) + { + struct glyph_row *row, *end; + struct glyph_row *mode_line_row; + struct glyph_row *tab_line_row; + struct glyph_row *header_line_row; + int yb; + bool changed_p = 0, mouse_face_overwritten_p = 0; + int n_updated = 0; + bool invisible_rows_marked = false; #ifdef HAVE_WINDOW_SYSTEM - gui_update_window_begin (w); + gui_update_window_begin (w); #else - (void) changed_p; + (void) changed_p; #endif - yb = window_text_bottom_y (w); - row = MATRIX_ROW (desired_matrix, 0); - end = MATRIX_MODE_LINE_ROW (desired_matrix); + yb = window_text_bottom_y (w); + row = MATRIX_ROW (desired_matrix, 0); + end = MATRIX_MODE_LINE_ROW (desired_matrix); - /* Take note of the tab line, if there is one. We will - update it below, after updating all of the window's lines. */ - if (row->mode_line_p && row->tab_line_p) - { - tab_line_row = row; - ++row; - } - else - tab_line_row = NULL; - - /* Take note of the header line, if there is one. We will - update it below, after updating all of the window's lines. */ - if (row->mode_line_p) - { - header_line_row = row; - ++row; - } - else - header_line_row = NULL; - - /* Update the mode line, if necessary. */ - mode_line_row = MATRIX_MODE_LINE_ROW (desired_matrix); - if (mode_line_row->mode_line_p && mode_line_row->enabled_p) - { - mode_line_row->y = yb + WINDOW_SCROLL_BAR_AREA_HEIGHT (w); - update_window_line (w, MATRIX_ROW_VPOS (mode_line_row, - desired_matrix), - &mouse_face_overwritten_p); - } - - /* Find first enabled row. Optimizations in redisplay_internal - may lead to an update with only one row enabled. There may - be also completely empty matrices. */ - while (row < end && !row->enabled_p) - ++row; - - /* Try reusing part of the display by copying. */ - if (row < end && !desired_matrix->no_scrolling_p) - { - int rc = scrolling_window (w, (tab_line_row != NULL ? 1 : 0) - + (header_line_row != NULL ? 1 : 0)); - if (rc < 0) + /* Take note of the tab line, if there is one. We will + update it below, after updating all of the window's lines. */ + if (row->mode_line_p && row->tab_line_p) { - /* All rows were found to be equal. */ - goto set_cursor; + tab_line_row = row; + ++row; } - else if (rc > 0) + else + tab_line_row = NULL; + + /* Take note of the header line, if there is one. We will + update it below, after updating all of the window's lines. */ + if (row->mode_line_p) { - /* We've scrolled the display. */ - changed_p = 1; + header_line_row = row; + ++row; } - } + else + header_line_row = NULL; - /* Update the rest of the lines. */ - for (; row < end; ++row) - /* scrolling_window resets the enabled_p flag of the rows it - reuses from current_matrix. */ - if (row->enabled_p) - { - int vpos = MATRIX_ROW_VPOS (row, desired_matrix); - int i; - - changed_p |= update_window_line (w, vpos, - &mouse_face_overwritten_p); - - /* Mark all rows below the last visible one in the current - matrix as invalid. This is necessary because of - variable line heights. Consider the case of three - successive redisplays, where the first displays 5 - lines, the second 3 lines, and the third 5 lines again. - If the second redisplay wouldn't mark rows in the - current matrix invalid, the third redisplay might be - tempted to optimize redisplay based on lines displayed - in the first redisplay. */ - if (MATRIX_ROW_BOTTOM_Y (row) >= yb) - { - for (i = vpos + 1; i < w->current_matrix->nrows - 1; ++i) - SET_MATRIX_ROW_ENABLED_P (w->current_matrix, i, false); - invisible_rows_marked = true; - } - } - - /* If the window doesn't display its mode line, make sure the - corresponding row of the current glyph matrix is disabled, so - that if and when the mode line is displayed again, it will be - cleared and completely redrawn. */ - if (!window_wants_mode_line (w)) - SET_MATRIX_ROW_ENABLED_P (w->current_matrix, - w->current_matrix->nrows - 1, false); - - if (!invisible_rows_marked) - { - /* If we didn't mark the invisible rows in the current - matrix as invalid above, do that now. This can happen if - scrolling_window updates the last visible rows of the - current matrix, in which case the above loop doesn't get - to examine the last visible row. */ - int i; - for (i = 0; i < w->current_matrix->nrows - 1; ++i) + /* Update the mode line, if necessary. */ + mode_line_row = MATRIX_MODE_LINE_ROW (desired_matrix); + if (mode_line_row->mode_line_p && mode_line_row->enabled_p) { - struct glyph_row *current_row = MATRIX_ROW (w->current_matrix, i); - if (current_row->enabled_p - && MATRIX_ROW_BOTTOM_Y (current_row) >= yb) + mode_line_row->y = yb + WINDOW_SCROLL_BAR_AREA_HEIGHT (w); + update_window_line (w, MATRIX_ROW_VPOS (mode_line_row, + desired_matrix), + &mouse_face_overwritten_p); + } + + /* Find first enabled row. Optimizations in redisplay_internal + may lead to an update with only one row enabled. There may + be also completely empty matrices. */ + while (row < end && !row->enabled_p) + ++row; + + /* Try reusing part of the display by copying. */ + if (row < end && !desired_matrix->no_scrolling_p) + { + int rc = scrolling_window (w, (tab_line_row != NULL ? 1 : 0) + + (header_line_row != NULL ? 1 : 0)); + if (rc < 0) { - for (++i ; i < w->current_matrix->nrows - 1; ++i) - SET_MATRIX_ROW_ENABLED_P (w->current_matrix, i, false); + /* All rows were found to be equal. */ + paused_p = 0; + goto set_cursor; + } + else if (rc > 0) + { + /* We've scrolled the display. */ + force_p = 1; + changed_p = 1; } } - } - set_cursor: + /* Update the rest of the lines. */ + for (; row < end && (force_p || !input_pending); ++row) + /* scrolling_window resets the enabled_p flag of the rows it + reuses from current_matrix. */ + if (row->enabled_p) + { + int vpos = MATRIX_ROW_VPOS (row, desired_matrix); + int i; - /* Update the tab line after scrolling because a new tab - line would otherwise overwrite lines at the top of the window - that can be scrolled. */ - if (tab_line_row && tab_line_row->enabled_p) - { - tab_line_row->y = 0; - update_window_line (w, 0, &mouse_face_overwritten_p); - } + /* We'll have to play a little bit with when to + detect_input_pending. If it's done too often, + scrolling large windows with repeated scroll-up + commands will too quickly pause redisplay. */ + if (!force_p && ++n_updated % preempt_count == 0) + detect_input_pending_ignore_squeezables (); + changed_p |= update_window_line (w, vpos, + &mouse_face_overwritten_p); - /* Update the header line after scrolling because a new header - line would otherwise overwrite lines at the top of the window - that can be scrolled. */ - if (header_line_row && header_line_row->enabled_p) - { - header_line_row->y = tab_line_row ? CURRENT_TAB_LINE_HEIGHT (w) : 0; - update_window_line (w, tab_line_row ? 1 : 0, &mouse_face_overwritten_p); - } + /* Mark all rows below the last visible one in the current + matrix as invalid. This is necessary because of + variable line heights. Consider the case of three + successive redisplays, where the first displays 5 + lines, the second 3 lines, and the third 5 lines again. + If the second redisplay wouldn't mark rows in the + current matrix invalid, the third redisplay might be + tempted to optimize redisplay based on lines displayed + in the first redisplay. */ + if (MATRIX_ROW_BOTTOM_Y (row) >= yb) + { + for (i = vpos + 1; i < w->current_matrix->nrows - 1; ++i) + SET_MATRIX_ROW_ENABLED_P (w->current_matrix, i, false); + invisible_rows_marked = true; + } + } - /* Fix the appearance of overlapping/overlapped rows. */ - if (!w->pseudo_window_p) - { -#ifdef HAVE_WINDOW_SYSTEM - if (changed_p && rif->fix_overlapping_area) + /* If the window doesn't display its mode line, make sure the + corresponding row of the current glyph matrix is disabled, so + that if and when the mode line is displayed again, it will be + cleared and completely redrawn. */ + if (!window_wants_mode_line (w)) + SET_MATRIX_ROW_ENABLED_P (w->current_matrix, + w->current_matrix->nrows - 1, false); + + /* Was display preempted? */ + paused_p = row < end; + + if (!paused_p && !invisible_rows_marked) { - redraw_overlapped_rows (w, yb); - redraw_overlapping_rows (w, yb); + /* If we didn't mark the invisible rows in the current + matrix as invalid above, do that now. This can happen if + scrolling_window updates the last visible rows of the + current matrix, in which case the above loop doesn't get + to examine the last visible row. */ + int i; + for (i = 0; i < w->current_matrix->nrows - 1; ++i) + { + struct glyph_row *current_row = MATRIX_ROW (w->current_matrix, i); + if (current_row->enabled_p + && MATRIX_ROW_BOTTOM_Y (current_row) >= yb) + { + for (++i ; i < w->current_matrix->nrows - 1; ++i) + SET_MATRIX_ROW_ENABLED_P (w->current_matrix, i, false); + } + } } + + set_cursor: + + /* Update the tab line after scrolling because a new tab + line would otherwise overwrite lines at the top of the window + that can be scrolled. */ + if (tab_line_row && tab_line_row->enabled_p) + { + tab_line_row->y = 0; + update_window_line (w, 0, &mouse_face_overwritten_p); + } + + /* Update the header line after scrolling because a new header + line would otherwise overwrite lines at the top of the window + that can be scrolled. */ + if (header_line_row && header_line_row->enabled_p) + { + header_line_row->y = tab_line_row ? CURRENT_TAB_LINE_HEIGHT (w) : 0; + update_window_line (w, tab_line_row ? 1 : 0, &mouse_face_overwritten_p); + } + + /* Fix the appearance of overlapping/overlapped rows. */ + if (!paused_p && !w->pseudo_window_p) + { +#ifdef HAVE_WINDOW_SYSTEM + if (changed_p && rif->fix_overlapping_area) + { + redraw_overlapped_rows (w, yb); + redraw_overlapping_rows (w, yb); + } #endif - /* Make cursor visible at cursor position of W. */ - set_window_cursor_after_update (w); + /* Make cursor visible at cursor position of W. */ + set_window_cursor_after_update (w); #if 0 /* Check that current matrix invariants are satisfied. This is - for debugging only. See the comment of check_matrix_invariants. */ - IF_DEBUG (check_matrix_invariants (w)); + for debugging only. See the comment of check_matrix_invariants. */ + IF_DEBUG (check_matrix_invariants (w)); #endif - } + } #ifdef GLYPH_DEBUG - /* Remember the redisplay method used to display the matrix. */ - strcpy (w->current_matrix->method, w->desired_matrix->method); + /* Remember the redisplay method used to display the matrix. */ + strcpy (w->current_matrix->method, w->desired_matrix->method); #endif #ifdef HAVE_WINDOW_SYSTEM - update_window_fringes (w, 0); + update_window_fringes (w, 0); - /* End the update of window W. Don't set the cursor if we - paused updating the display because in this case, - set_window_cursor_after_update hasn't been called, and - W->output_cursor doesn't contain the cursor location. */ - gui_update_window_end (w, true, mouse_face_overwritten_p); + /* End the update of window W. Don't set the cursor if we + paused updating the display because in this case, + set_window_cursor_after_update hasn't been called, and + W->output_cursor doesn't contain the cursor location. */ + gui_update_window_end (w, !paused_p, mouse_face_overwritten_p); #endif - /* If the update wasn't interrupted, this window has been - completely updated. */ - w->must_be_updated_p = false; + /* If the update wasn't interrupted, this window has been + completely updated. */ + if (!paused_p) + w->must_be_updated_p = false; + } + else + paused_p = 1; #ifdef GLYPH_DEBUG /* check_current_matrix_flags (w); */ - add_window_display_history (w, w->current_matrix->method); + add_window_display_history (w, w->current_matrix->method, paused_p); #endif xwidget_end_redisplay (w, w->current_matrix); clear_glyph_matrix (desired_matrix); + + return paused_p; } #ifdef HAVE_WINDOW_SYSTEM @@ -5619,13 +5697,20 @@ tty_set_cursor (void) } /* Write desired matix of tty frame F and make it current. - INHIBIT_ID_P means that scrolling by insert/delete should not be tried. - SET_CURSOR_P false means do not set cursor at point in selected window. */ -static void -write_matrix (struct frame *f, bool inhibit_id_p, + FORCE_P means that the update should not be stopped by pending input. + INHIBIT_ID_P means that scrolling by insert/delete should not be tried. + SET_CURSOR_P false means do not set cursor at point in selected window. + + Value is true if update was stopped due to pending input. */ + +static bool +write_matrix (struct frame *f, bool force_p, bool inhibit_id_p, bool set_cursor_p, bool updating_menu_p) { + if (!force_p && detect_input_pending_ignore_squeezables ()) + return true; + /* If we cannot insert/delete lines, it's no use trying it. */ if (!FRAME_LINE_INS_DEL_OK (f)) inhibit_id_p = true; @@ -5637,7 +5722,7 @@ write_matrix (struct frame *f, bool inhibit_id_p, i/d line if just want cursor motion. */ int first_row = first_enabled_row (f->desired_matrix); if (!inhibit_id_p && first_row >= 0) - scrolling (f); + force_p |= scrolling (f); /* Update the individual lines as needed. Do bottom line first. This is done so that messages are made visible when pausing. */ @@ -5645,19 +5730,36 @@ write_matrix (struct frame *f, bool inhibit_id_p, if (MATRIX_ROW_ENABLED_P (f->desired_matrix, last_row)) write_row (f, last_row, updating_menu_p); + bool pause_p = false; if (first_row >= 0) - for (int i = first_row; i < last_row; ++i) - if (MATRIX_ROW_ENABLED_P (f->desired_matrix, i)) - write_row (f, i, updating_menu_p); + { + const int preempt_count = clip_to_bounds (1, baud_rate / 2400 + 1, INT_MAX); + + for (int i = first_row, n = 0; i < last_row; ++i) + if (MATRIX_ROW_ENABLED_P (f->desired_matrix, i)) + { + if (!force_p && n % preempt_count == 0 + && detect_input_pending_ignore_squeezables ()) + { + pause_p = true; + break; + } + + write_row (f, i, updating_menu_p); + ++n; + } + } /* Now just clean up termcap drivers and set cursor, etc. */ - if (set_cursor_p) + if (!pause_p && set_cursor_p) tty_set_cursor (); + + return pause_p; } /* Do line insertions/deletions on frame F for frame-based redisplay. */ -static void +static bool scrolling (struct frame *frame) { /* In fact this code should never be reached at all under @@ -5694,7 +5796,7 @@ scrolling (struct frame *frame) if (!MATRIX_ROW_ENABLED_P (current_matrix, i)) { SAFE_FREE (); - return; + return false; } old_hash[i] = line_hash_code (frame, MATRIX_ROW (current_matrix, i)); if (! MATRIX_ROW_ENABLED_P (desired_matrix, i)) @@ -5725,7 +5827,7 @@ scrolling (struct frame *frame) || unchanged_at_bottom == height) { SAFE_FREE (); - return; + return true; } window_size = (height - unchanged_at_top @@ -5755,6 +5857,7 @@ scrolling (struct frame *frame) SAFE_FREE (); #endif + return false; } @@ -6886,18 +6989,27 @@ sit_for (Lisp_Object timeout, bool reading, int display_option) DEFUN ("redisplay", Fredisplay, Sredisplay, 0, 1, 0, - doc : /* Perform redisplay. -Optional arg FORCE exists for historical reasons and is ignored. -Value is t if redisplay has been performed, nil if executing a -keyboard macro. */) + doc: /* Perform redisplay. +Optional arg FORCE, if non-nil, prevents redisplay from being +preempted by arriving input, even if `redisplay-dont-pause' is nil. +If `redisplay-dont-pause' is non-nil (the default), redisplay is never +preempted by arriving input, so FORCE does nothing. + +Return t if redisplay was performed, nil if redisplay was preempted +immediately by pending input. */) (Lisp_Object force) { swallow_events (true); - if (!NILP (Vexecuting_kbd_macro)) + if ((detect_input_pending_run_timers (1) + && NILP (force) && !redisplay_dont_pause) + || !NILP (Vexecuting_kbd_macro)) return Qnil; + specpdl_ref count = SPECPDL_INDEX (); + if (!NILP (force) && !redisplay_dont_pause) + specbind (Qredisplay_dont_pause, Qt); redisplay_preserve_echo_area (2); - return Qt; + return unbind_to (count, Qt); } @@ -7350,6 +7462,8 @@ syms_of_display (void) /* This is the "purpose" slot of a display table. */ DEFSYM (Qdisplay_table, "display-table"); DEFSYM (Qframe__z_order_lessp, "frame--z-order-lessp"); + + DEFSYM (Qredisplay_dont_pause, "redisplay-dont-pause"); DEFSYM (Qtty_non_selected_cursor, "tty-non-selected-cursor"); DEFVAR_INT ("baud-rate", baud_rate, @@ -7431,6 +7545,17 @@ It is also used for standard output and error streams. See `buffer-display-table' for more information. */); Vstandard_display_table = Qnil; + DEFVAR_BOOL ("redisplay-dont-pause", redisplay_dont_pause, + doc: /* Nil means display update is paused when input is detected. */); + /* Contrary to expectations, a value of "false" can be detrimental to + responsiveness since aborting a redisplay throws away some of the + work already performed. It's usually more efficient (and gives + more prompt feedback to the user) to let the redisplay terminate, + and just completely skip the next command's redisplay (which is + done regardless of this setting if there's pending input at the + beginning of the next redisplay). */ + redisplay_dont_pause = true; + DEFVAR_LISP ("x-show-tooltip-timeout", Vx_show_tooltip_timeout, doc: /* The default timeout (in seconds) for `x-show-tip'. */); Vx_show_tooltip_timeout = make_fixnum (5); diff --git a/src/keyboard.c b/src/keyboard.c index fe485a3efd6..bfb5fd3592b 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -2663,7 +2663,8 @@ read_char (int commandflag, Lisp_Object map, swallow_events (false); /* May clear input_pending. */ /* Redisplay if no pending input. */ - while (!(input_pending && input_was_pending)) + while (!(input_pending + && (input_was_pending || !redisplay_dont_pause))) { input_was_pending = input_pending; if (help_echo_showing_p && !BASE_EQ (selected_window, minibuf_window)) diff --git a/src/minibuf.c b/src/minibuf.c index 390db0d31fa..c8267045397 100644 --- a/src/minibuf.c +++ b/src/minibuf.c @@ -914,9 +914,9 @@ read_minibuf (Lisp_Object map, Lisp_Object initial, Lisp_Object prompt, XWINDOW (minibuf_window)->cursor.x = 0; XWINDOW (minibuf_window)->must_be_updated_p = true; struct frame *sf = XFRAME (selected_frame); - update_frame (sf, true); + update_frame (sf, true, true); if (is_tty_frame (sf)) - combine_updates_for_frame (sf, true); + combine_updates_for_frame (sf, true, true); #ifndef HAVE_NTGUI flush_frame (XFRAME (XWINDOW (minibuf_window)->frame)); diff --git a/src/xdisp.c b/src/xdisp.c index 3364c6870cf..8196d1236ba 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -1116,6 +1116,7 @@ static void set_iterator_to_next (struct it *, bool); static void mark_window_display_accurate_1 (struct window *, bool); static bool row_for_charpos_p (struct glyph_row *, ptrdiff_t); static bool cursor_row_p (struct glyph_row *); +static int redisplay_mode_lines (Lisp_Object, bool); static void handle_line_prefix (struct it *); @@ -13510,6 +13511,24 @@ echo_area_display (bool update_frame_p) here could cause confusion. */ if (update_frame_p && !redisplaying_p) { + int n = 0; + + /* If the display update has been interrupted by pending + input, update mode lines in the frame. Due to the + pending input, it might have been that redisplay hasn't + been called, so that mode lines above the echo area are + garbaged. This looks odd, so we prevent it here. */ + if (!display_completed) + { + n = redisplay_mode_lines (FRAME_ROOT_WINDOW (f), false); + +#ifdef HAVE_WINDOW_SYSTEM + if (FRAME_WINDOW_P (f) + && FRAME_RIF (f)->clear_under_internal_border) + FRAME_RIF (f)->clear_under_internal_border (f); +#endif + } + if (window_height_changed_p /* Don't do this if Emacs is shutting down. Redisplay needs to run hooks. */ @@ -13518,10 +13537,13 @@ echo_area_display (bool update_frame_p) /* Must update other windows. Likewise as in other cases, don't let this update be interrupted by pending input. */ + specpdl_ref count = SPECPDL_INDEX (); + specbind (Qredisplay_dont_pause, Qt); fset_redisplay (f); redisplay_internal (); + unbind_to (count, Qnil); } - else if (FRAME_WINDOW_P (f)) + else if (FRAME_WINDOW_P (f) && n == 0) { /* Window configuration is the same as before. Can do with a display update of the echo area, @@ -13531,9 +13553,9 @@ echo_area_display (bool update_frame_p) } else { - update_frame (f, true); + update_frame (f, true, true); if (is_tty_frame (f)) - combine_updates_for_frame (f, true); + combine_updates_for_frame (f, true, true); } /* If cursor is in the echo area, make sure that the next @@ -16916,6 +16938,7 @@ redisplay_internal (void) struct window *w = XWINDOW (selected_window); struct window *sw; struct frame *fr; + bool pending; bool must_finish = false, match_p; struct text_pos tlbufpos, tlendpos; int number_of_visible_frames; @@ -17001,6 +17024,7 @@ redisplay_internal (void) /* Remember the currently selected window. */ sw = w; + pending = false; forget_escape_and_glyphless_faces (); inhibit_free_realized_faces = false; @@ -17566,7 +17590,7 @@ redisplay_internal (void) unrequest_sigio (); STOP_POLLING; - update_frame (f, false); + pending |= update_frame (f, false, false); /* On some platforms (at least MS-Windows), the scroll_run_hook called from scrolling_window called from update_frame could set the frame's @@ -17588,24 +17612,27 @@ redisplay_internal (void) } if (CONSP (tty_root_frames)) - combine_updates (tty_root_frames, false); + pending |= combine_updates (tty_root_frames, false, false); eassert (EQ (XFRAME (selected_frame)->selected_window, selected_window)); - /* Do the mark_window_display_accurate after all windows have - been redisplayed because this call resets flags in buffers - which are needed for proper redisplay. */ - FOR_EACH_FRAME (tail, frame) + if (!pending) { - struct frame *f = XFRAME (frame); - if (f->updated_p) - { - f->redisplay = false; - f->garbaged = false; - mark_window_display_accurate (f->root_window, true); - if (FRAME_TERMINAL (f)->frame_up_to_date_hook) - FRAME_TERMINAL (f)->frame_up_to_date_hook (f); - } + /* Do the mark_window_display_accurate after all windows have + been redisplayed because this call resets flags in buffers + which are needed for proper redisplay. */ + FOR_EACH_FRAME (tail, frame) + { + struct frame *f = XFRAME (frame); + if (f->updated_p) + { + f->redisplay = false; + f->garbaged = false; + mark_window_display_accurate (f->root_window, true); + if (FRAME_TERMINAL (f)->frame_up_to_date_hook) + FRAME_TERMINAL (f)->frame_up_to_date_hook (f); + } + } } } else if (FRAME_REDISPLAY_P (sf)) @@ -17669,10 +17696,10 @@ redisplay_internal (void) } XWINDOW (selected_window)->must_be_updated_p = true; - update_frame (sf, false); + pending = update_frame (sf, false, false); if (is_tty_frame (sf)) - combine_updates_for_frame (sf, false); + pending |= combine_updates_for_frame (sf, false, false); sf->cursor_type_changed = false; sf->inhibit_clear_image_cache = false; @@ -17689,11 +17716,11 @@ redisplay_internal (void) if (mini_frame != sf) { XWINDOW (mini_window)->must_be_updated_p = true; - update_frame (mini_frame, false); + pending |= update_frame (mini_frame, false, false); if (is_tty_frame (mini_frame)) - combine_updates_for_frame (mini_frame, false); + pending |= combine_updates_for_frame (mini_frame, false, false); mini_frame->cursor_type_changed = false; - if (hscroll_retries <= MAX_HSCROLL_RETRIES + if (!pending && hscroll_retries <= MAX_HSCROLL_RETRIES && hscroll_windows (mini_window)) { hscroll_retries++; @@ -17702,26 +17729,47 @@ redisplay_internal (void) } } - if (!consider_all_windows_p) + /* If display was paused because of pending input, make sure we do a + thorough update the next time. */ + if (pending) { - /* This has already been done above if - consider_all_windows_p is set. */ - if (XBUFFER (w->contents)->text->redisplay - && buffer_window_count (XBUFFER (w->contents)) > 1) - /* This can happen if b->text->redisplay was set during - jit-lock. */ - propagate_buffer_redisplay (); - mark_window_display_accurate_1 (w, true); + /* Prevent the optimization at the beginning of + redisplay_internal that tries a single-line update of the + line containing the cursor in the selected window. */ + CHARPOS (this_line_start_pos) = 0; - /* Say overlay arrows are up to date. */ - update_overlay_arrows (1); + /* Let the overlay arrow be updated the next time. */ + update_overlay_arrows (0); - if (FRAME_TERMINAL (sf)->frame_up_to_date_hook != 0) - FRAME_TERMINAL (sf)->frame_up_to_date_hook (sf); + /* If we pause after scrolling, some rows in the current + matrices of some windows are not valid. */ + if (!WINDOW_FULL_WIDTH_P (w) + && !FRAME_WINDOW_P (XFRAME (w->frame))) + update_mode_lines = 36; } + else + { + if (!consider_all_windows_p) + { + /* This has already been done above if + consider_all_windows_p is set. */ + if (XBUFFER (w->contents)->text->redisplay + && buffer_window_count (XBUFFER (w->contents)) > 1) + /* This can happen if b->text->redisplay was set during + jit-lock. */ + propagate_buffer_redisplay (); + mark_window_display_accurate_1 (w, true); - update_mode_lines = 0; - windows_or_buffers_changed = 0; + /* Say overlay arrows are up to date. */ + update_overlay_arrows (1); + + if (FRAME_TERMINAL (sf)->frame_up_to_date_hook != 0) + FRAME_TERMINAL (sf)->frame_up_to_date_hook (sf); + } + + update_mode_lines = 0; + windows_or_buffers_changed = 0; + } /* Start SIGIO interrupts coming again. Having them off during the code above makes it less likely one will discard output, but not @@ -17737,23 +17785,26 @@ redisplay_internal (void) redisplay constructing glyphs, so simply exposing a frame won't display anything in this case. So, we have to display these frames here explicitly. */ - int new_count = 0; - - FOR_EACH_FRAME (tail, frame) + if (!pending) { - if (FRAME_REDISPLAY_P (XFRAME (frame))) - new_count++; - } + int new_count = 0; - if (new_count != number_of_visible_frames) - windows_or_buffers_changed = 52; + FOR_EACH_FRAME (tail, frame) + { + if (FRAME_REDISPLAY_P (XFRAME (frame))) + new_count++; + } + + if (new_count != number_of_visible_frames) + windows_or_buffers_changed = 52; + } /* Change frame size now if a change is pending. */ do_pending_window_change (true); /* If we just did a pending size change, or have additional visible frames, or selected_window changed, redisplay again. */ - if (windows_or_buffers_changed + if ((windows_or_buffers_changed && !pending) || (WINDOWP (selected_window) && (w = XWINDOW (selected_window)) != sw)) goto retry; @@ -27343,6 +27394,60 @@ display_tty_menu_item (const char *item_text, int width, int face_id, Mode Line ***********************************************************************/ +/* Redisplay mode lines in the window tree whose root is WINDOW. + If FORCE, redisplay mode lines unconditionally. + Otherwise, redisplay only mode lines that are garbaged. Value is + the number of windows whose mode lines were redisplayed. */ + +static int +redisplay_mode_lines (Lisp_Object window, bool force) +{ + int nwindows = 0; + + while (!NILP (window)) + { + struct window *w = XWINDOW (window); + + if (WINDOWP (w->contents)) + nwindows += redisplay_mode_lines (w->contents, force); + else if (force + || FRAME_GARBAGED_P (XFRAME (w->frame)) + || !MATRIX_MODE_LINE_ROW (w->current_matrix)->enabled_p) + { + struct text_pos lpoint; + struct buffer *old = current_buffer; + + /* Set the window's buffer for the mode line display. */ + SET_TEXT_POS (lpoint, PT, PT_BYTE); + set_buffer_internal_1 (XBUFFER (w->contents)); + + /* Point refers normally to the selected window. For any + other window, set up appropriate value. */ + if (!EQ (window, selected_window)) + { + struct text_pos pt; + + CLIP_TEXT_POS_FROM_MARKER (pt, w->pointm); + TEMP_SET_PT_BOTH (CHARPOS (pt), BYTEPOS (pt)); + } + + /* Display mode lines. */ + clear_glyph_matrix (w->desired_matrix); + if (display_mode_lines (w)) + ++nwindows; + + /* Restore old settings. */ + set_buffer_internal_1 (old); + TEMP_SET_PT_BOTH (CHARPOS (lpoint), BYTEPOS (lpoint)); + } + + window = w->next; + } + + return nwindows; +} + + /* Display the mode line, the header line, and the tab-line of window W. Value is the sum number of mode lines, header lines, and tab lines actually displayed. */ From 7608563d3b274d805111827a39cc73aaa147eaa1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerd=20M=C3=B6llmann?= Date: Mon, 18 Nov 2024 08:21:22 +0100 Subject: [PATCH 49/53] * src/xdisp.c (redisplay_internal): Use assq_no_quit. --- src/xdisp.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/src/xdisp.c b/src/xdisp.c index 8196d1236ba..7b6a3f3694a 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -17467,16 +17467,9 @@ redisplay_internal (void) continue; /* Remember tty root frames which we've seen. */ - if (!FRAME_PARENT_FRAME (f)) - { - Lisp_Object found; - for (found = tty_root_frames; - CONSP (found) && !EQ (XCAR (found), frame); - found = XCDR (found)) - ; - if (!CONSP (found)) - tty_root_frames = Fcons (frame, tty_root_frames); - } + if (!FRAME_PARENT_FRAME (f) + && NILP (assq_no_quit (frame, tty_root_frames))) + tty_root_frames = Fcons (frame, tty_root_frames); } retry_frame: From 196c761c66d47ff6a93d9134ca73d1c08a9125db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerd=20M=C3=B6llmann?= Date: Mon, 18 Nov 2024 16:50:51 +0100 Subject: [PATCH 50/53] Consider all windows for redisplay if frames have been cleared * src/xdisp.c (clear_garbaged_frames): Return true if any tty frame's current matrix has been cleared. (redisplay_internal): Consider all windows if clear_garbaged_frames returns true. --- src/xdisp.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/xdisp.c b/src/xdisp.c index 7b6a3f3694a..9ca8dda0ac7 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -13413,18 +13413,22 @@ clear_message (bool current_p, bool last_displayed_p) message_buf_print = false; } -/* Clear garbaged frames. +/* Clear garbaged frames. Value is true if current matrices have been + cleared on at least one tty frame. This information is needed to + determine if more than one window has to be updated on ttys, whose + update requires building a frame matrix from window matrices. This function is used where the old redisplay called redraw_garbaged_frames which in turn called redraw_frame which in turn called clear_frame. The call to clear_frame was a source of flickering. I believe a clear_frame is not necessary. It should suffice in the new redisplay to invalidate all current matrices, - and ensure a complete redisplay of all windows. */ + and ensure a complete redisplay of all windows. */ -static void +static bool clear_garbaged_frames (void) { + bool current_matrices_cleared = false; if (frame_garbaged) { Lisp_Object tail, frame; @@ -13446,6 +13450,8 @@ clear_garbaged_frames (void) redraw_frame (f); else clear_current_matrices (f); + if (is_tty_frame (f)) + current_matrices_cleared = true; #ifdef HAVE_WINDOW_SYSTEM if (FRAME_WINDOW_P (f) @@ -13460,6 +13466,8 @@ clear_garbaged_frames (void) frame_garbaged = false; } + + return current_matrices_cleared; } @@ -17092,7 +17100,7 @@ redisplay_internal (void) do_pending_window_change (true); /* Clear frames marked as garbaged. */ - clear_garbaged_frames (); + bool current_matrices_cleared = clear_garbaged_frames (); /* Build menubar and tool-bar items. */ if (NILP (Vmemory_full)) @@ -17183,7 +17191,8 @@ redisplay_internal (void) overlay_arrows_changed_p (true); consider_all_windows_p = (update_mode_lines - || windows_or_buffers_changed); + || windows_or_buffers_changed + || current_matrices_cleared); #define AINC(a,i) \ { \ From d22882e418eb100423c53d90cca257bb0c197b86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerd=20M=C3=B6llmann?= Date: Sun, 8 Dec 2024 06:54:47 +0100 Subject: [PATCH 51/53] Prevent too early hiding of tty tips * lisp/tty-tip.el (tty-tip--show-timer): Renamed from tty-tip--timeout-id. (tty-tip--hide-timer): New variable. (tty-tip--delete-frame): Cancel hide timer if set. (tty-tip--create-frame): Use run-with-timer instead of run-at-time for consistency. --- lisp/tty-tip.el | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/lisp/tty-tip.el b/lisp/tty-tip.el index 728c16b6856..1e44aaba02b 100644 --- a/lisp/tty-tip.el +++ b/lisp/tty-tip.el @@ -99,8 +99,16 @@ (setf (alist-get 'background-color params) bg)) params)) +(defvar tty-tip--help-message nil) +(defvar tty-tip--hide-time nil) +(defvar tty-tip--show-timer nil) +(defvar tty-tip--hide-timer nil) + (defun tty-tip--delete-frame () (when tty-tip--frame + (when tty-tip--hide-timer + (cancel-timer tty-tip--hide-timer) + (setq tty-tip--hide-timer nil)) (delete-frame tty-tip--frame) (setq tty-tip--frame nil) t)) @@ -144,11 +152,9 @@ (y (cdr pos))) (set-frame-position tty-tip--frame x y)) (make-frame-visible tty-tip--frame) - (run-at-time x-show-tooltip-timeout nil #'tty-tip--delete-frame)))) - -(defvar tty-tip--help-message nil) -(defvar tty-tip--hide-time nil) -(defvar tty-tip--timeout-id nil) + (setq tty-tip--hide-timer + (run-with-timer x-show-tooltip-timeout nil + #'tty-tip--delete-frame))))) (defun tty-tip--delay () (if (and tty-tip--hide-time @@ -158,12 +164,12 @@ tooltip-delay)) (defun tty-tip--cancel-delayed-tip () - (when tty-tip--timeout-id - (cancel-timer tty-tip--timeout-id) - (setq tty-tip--timeout-id nil))) + (when tty-tip--show-timer + (cancel-timer tty-tip--show-timer) + (setq tty-tip--show-timer nil))) (defun tty-tip--start-delayed-tip () - (setq tty-tip--timeout-id + (setq tty-tip--show-timer (run-with-timer (tty-tip--delay) nil (lambda () (tty-tip--create-frame From b67feec95e8f7526fecab0bb10f91233ba06fef8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerd=20M=C3=B6llmann?= Date: Sun, 8 Dec 2024 08:56:22 +0100 Subject: [PATCH 52/53] * lisp/tty-tip.el (tty-tip--create-frame): Use tooltip-hide-delay --- lisp/tty-tip.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lisp/tty-tip.el b/lisp/tty-tip.el index 1e44aaba02b..4052fca4b52 100644 --- a/lisp/tty-tip.el +++ b/lisp/tty-tip.el @@ -153,7 +153,7 @@ (set-frame-position tty-tip--frame x y)) (make-frame-visible tty-tip--frame) (setq tty-tip--hide-timer - (run-with-timer x-show-tooltip-timeout nil + (run-with-timer tooltip-hide-delay nil #'tty-tip--delete-frame))))) (defun tty-tip--delay () From 6fa2050ee7663441e4d0aa4fff974cc5d45bffc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerd=20M=C3=B6llmann?= Date: Thu, 12 Dec 2024 08:00:44 +0100 Subject: [PATCH 53/53] Signal errors for unimplemented features * src/frame.c (make_terminal_frame): Error for minibuffer-only frames. * src/term.c (Ftty_frame_restack): Signal error. --- src/frame.c | 9 +-------- src/term.c | 1 + 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/src/frame.c b/src/frame.c index 6ea1a31cdb8..6552567386e 100644 --- a/src/frame.c +++ b/src/frame.c @@ -1296,14 +1296,7 @@ make_terminal_frame (struct terminal *terminal, Lisp_Object parent, if (EQ (mini, Qnone) || NILP (mini)) f = make_frame_without_minibuffer (Qnil, kb, Qnil); else if (EQ (mini, Qonly)) - { -# if 0 /* No interest in this feature at the moment. */ - f = make_minibuffer_frame (); - /* Not sure about this, plus the unsplittable frame - param. */ - f->no_split = true; -# endif - } + error ("minibuffer-only child frames are not implemented"); else if (WINDOWP (mini)) f = make_frame_without_minibuffer (mini, kb, Qnil); } diff --git a/src/term.c b/src/term.c index a7f7baa6e3c..64df5261e50 100644 --- a/src/term.c +++ b/src/term.c @@ -4861,6 +4861,7 @@ DEFUN ("tty-frame-restack", Ftty_frame_restack, (Lisp_Object frame1, Lisp_Object frame2, Lisp_Object above) { /* FIXME/tty: tty-frame-restack implementation. */ + error ("tty-frame-restack is not implemented"); return Qnil; }