From: Gerd Möllmann Date: Mon, 21 Oct 2024 16:32:04 +0000 (+0200) Subject: Initial child frames based on master X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=e835e849a7a41fa1628efb56327a6cf6ca9cd279;p=emacs.git 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. (cherry picked from commit 414de92a562e8912ffdc8ed2995e7ea10d05f13b) --- 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 d5c29753a4f..69ddd28c7de 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 c77d763702c..82ffc2db5f1 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 9df6eaf623a..a040da3a13f 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 @@ -3835,7 +3843,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 *); @@ -3859,7 +3867,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. */ @@ -3941,6 +3949,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; } - -/*********************************************************************** - Frame Update - ***********************************************************************/ +/********************************************************************** + TTY Child Frames + **********************************************************************/ -/* Update frame F based on the data in desired matrices. +/* 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. - If FORCE_P, don't let redisplay be stopped by detecting pending input. - If INHIBIT_HAIRY_ID_P, don't try scrolling. + 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. - Value is true if redisplay was stopped due to pending input. */ + Building the desired matrix of root frame proceeds by -bool -update_frame (struct frame *f, bool force_p, bool inhibit_hairy_id_p) + - 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 { - /* True means display has been paused because of pending input. */ - bool paused_p; - struct window *root_window = XWINDOW (f->root_window); + int x, y, w, h; +}; - if (redisplay_dont_pause) - force_p = true; - else if (!force_p && detect_input_pending_ignore_squeezables ()) +/* 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)) { - paused_p = true; - goto do_pause; + *x += f->left_pos; + *y += f->top_pos; } +} - if (FRAME_WINDOW_P (f)) +/* 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) { - /* We are working on window matrix basis. All windows whose - flag must_be_updated_p is set have to be updated. */ + struct frame *f = XFRAME (frame); + if (FRAME_PARENT_FRAME (f) == parent) + z_order = max (z_order, f->z_order); + } + return z_order; +} - /* Record that we are not working on frame matrices. */ - set_frame_matrix_frame (NULL); +/* Return true if F1 is an ancestor of F2. */ - /* Update all windows in the window tree of F, maybe stopping - when pending input is detected. */ - update_begin (f); +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; +} -#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 +/* Return a list of all frames having root frame ROOT. + If VISIBLE_ONLY is true, return only visible frames. */ -#if defined (HAVE_WINDOW_SYSTEM) - /* Update the tab-bar window, if present. */ - if (WINDOWP (f->tab_bar_window)) +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)) { - struct window *w = XWINDOW (f->tab_bar_window); + SET_GLYPH_FROM_GLYPH_CODE (g, gc); + /* Sorry, but I really don't care if the glyph has a face :-). */ + } + } - /* Update tab-bar window. */ - if (w->must_be_updated_p) - { - Lisp_Object tem; + 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; + } +} - update_window (w, true); - w->must_be_updated_p = false; +/* 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. */ - /* 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); - } +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 +} -#if defined (HAVE_WINDOW_SYSTEM) && ! defined (HAVE_EXT_TOOL_BAR) - /* Update the tool-bar window, if present. */ - if (WINDOWP (f->tool_bar_window)) +#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) { - struct window *w = XWINDOW (f->tool_bar_window); + update_window (w, true); + w->must_be_updated_p = false; + Lisp_Object tem = *current; + *current = *desired; + *desired = tem; + } + } +} +#endif - /* Update tool-bar window. */ - if (w->must_be_updated_p) - { - Lisp_Object tem; +/* Update the tab-bar window of frame F, if present. */ - update_window (w, true); - w->must_be_updated_p = false; +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 +} - /* 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); - } - } +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 +} - /* Update windows. */ - paused_p = update_window_tree (root_window, force_p); - update_end (f); - } - else +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 ()) { - /* We are working on frame matrix basis. Set the frame on whose - frame matrix we operate. */ - set_frame_matrix_frame (f); + Lisp_Object frame; + XSETFRAME (frame, topmost_child); - /* Build F's desired matrix from window matrices. */ - build_frame_matrix (f); + 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)); + } + } +} - /* 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. */ +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, paused_p); + add_frame_display_history (f, false); #endif } - do_pause: - /* Reset flags indicating that a window should be updated. */ - set_window_update_flags (root_window, false); + return paused; +} - display_completed = !paused_p; - return paused_p; +/* 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_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)) + paused = update_window_frame (f, force_p); + else if (FRAME_INITIAL_P (f)) + paused = update_initial_frame (f, force_p); + else + 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 @@ -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); - - eassert (current_matrix && desired_matrix); - - 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; - } + return true; /* If we cannot insert/delete lines, it's no use trying it. */ if (!FRAME_LINE_INS_DEL_OK (f)) - inhibit_id_p = 1; + inhibit_id_p = true; - /* 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; + if (baud_rate != FRAME_COST_BAUD_RATE (f)) + calculate_costs (f); - /* Try doing i/d line, if not yet inhibited. */ - if (!inhibit_id_p && i < desired_matrix->nrows) + /* See if any of the desired lines are enabled; don't compute for + 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); - /* 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; - - /* 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); + tty_set_cursor (); - /* 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 21f8b35e0a2..e0ff5d57ee4 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); - /* 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); + /* 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 (!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; - 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); - } + 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); + 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 64c9fe8b2dc..a70c07026df 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 5ef7b1f71b1..2f77dbecc07 100644 --- a/src/minibuf.c +++ b/src/minibuf.c @@ -853,7 +853,11 @@ read_minibuf (Lisp_Object map, Lisp_Object initial, 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 dceb3cebb4d..c705a3c78f4 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 0c9c9ea9b5b..9451e166b47 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); } } @@ -3350,9 +3350,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) { @@ -13556,7 +13554,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 @@ -17035,6 +17037,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) { @@ -17057,6 +17062,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; @@ -17200,7 +17206,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. */ @@ -17449,22 +17454,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 @@ -17481,7 +17499,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 @@ -17507,7 +17525,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) @@ -17592,6 +17610,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) @@ -17613,7 +17634,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); @@ -17664,7 +17685,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)) @@ -17675,6 +17696,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; } @@ -17687,10 +17712,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)) @@ -23977,6 +24004,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 @@ -23996,6 +24024,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 @@ -24004,6 +24033,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; } @@ -24368,9 +24398,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 { @@ -24379,7 +24411,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; + } } } } @@ -27232,7 +27267,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]; @@ -27253,7 +27288,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); } /* Produce glyphs for a menu separator on a tty. @@ -27331,7 +27366,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 f6264802fa4..5f60f387165 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);