From f34729eaec648d9784e68cf407b3ca94b19e3b70 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Tue, 24 Sep 2013 19:07:35 +0300 Subject: [PATCH] Fix submenus and screen restoration. --- lisp/menu-bar.el | 4 ++- src/keyboard.c | 13 +++++++++- src/term.c | 65 ++++++++++++++++++++++++++++++++++++++++-------- src/termchar.h | 3 +++ 4 files changed, 73 insertions(+), 12 deletions(-) diff --git a/lisp/menu-bar.el b/lisp/menu-bar.el index 5cc79b9358e..37cbd9f0490 100644 --- a/lisp/menu-bar.el +++ b/lisp/menu-bar.el @@ -2323,7 +2323,9 @@ If FRAME is nil or not given, use the selected frame." ((eq type 'x) (x-menu-bar-open frame)) ((eq type 'w32) (w32-menu-bar-open frame)) ((null tty-menu-open-use-tmm) - (popup-menu menu-bar-file-menu (posn-at-x-y 0 0 nil t))) + ;; FIXME: This should open the leftmost menu, and let the user + ;; move to others via C-f or right-arrow. + (popup-menu menu-bar-tools-menu (posn-at-x-y 30 0 nil t))) (t (with-selected-frame (or frame (selected-frame)) (tmm-menubar)))))) diff --git a/src/keyboard.c b/src/keyboard.c index 4ace767484e..9faa3770cf3 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -3903,7 +3903,18 @@ kbd_buffer_get_event (KBOARD **kbp, } } else - wait_reading_process_output (0, 0, -1, 1, Qnil, NULL, 0); + { + bool do_display = true; + struct tty_display_info *tty = CURTTY (); + + /* When this TTY is displaying a menu, we must prevent any + redisplay, because we modify the frame's glyph matrix + behind the back of the display engine. */ + if (tty->showing_menu) + do_display = false; + + wait_reading_process_output (0, 0, -1, do_display, Qnil, NULL, 0); + } if (!interrupt_input && kbd_fetch_ptr == kbd_store_ptr) gobble_input (); diff --git a/src/term.c b/src/term.c index 4da5fd13905..b408a4a0907 100644 --- a/src/term.c +++ b/src/term.c @@ -3075,6 +3075,53 @@ struct tty_menu_state int x, y; }; +/* Save away the contents of frame F's current frame matrix, and + enable all its rows. Value is a glyph matrix holding the contents + of F's current frame matrix with all its glyph rows enabled. */ + +struct glyph_matrix * +save_and_enable_current_matrix (struct frame *f) +{ + int i; + struct glyph_matrix *saved = xzalloc (sizeof *saved); + saved->nrows = f->current_matrix->nrows; + saved->rows = xzalloc (saved->nrows * sizeof *saved->rows); + + for (i = 0; i < saved->nrows; ++i) + { + struct glyph_row *from = f->current_matrix->rows + i; + struct glyph_row *to = saved->rows + i; + ptrdiff_t nbytes = from->used[TEXT_AREA] * sizeof (struct glyph); + + to->glyphs[TEXT_AREA] = xmalloc (nbytes); + memcpy (to->glyphs[TEXT_AREA], from->glyphs[TEXT_AREA], nbytes); + to->used[TEXT_AREA] = from->used[TEXT_AREA]; + /* Make sure every row is enabled, or else update_frame will not + redraw them. (Rows that are identical to what is already on + screen will not be redrawn anyway.) */ + to->enabled_p = 1; + to->hash = from->hash; + if (from->used[LEFT_MARGIN_AREA]) + { + nbytes = from->used[LEFT_MARGIN_AREA] * sizeof (struct glyph); + to->glyphs[LEFT_MARGIN_AREA] = (struct glyph *) xmalloc (nbytes); + memcpy (to->glyphs[LEFT_MARGIN_AREA], + from->glyphs[LEFT_MARGIN_AREA], nbytes); + to->used[LEFT_MARGIN_AREA] = from->used[LEFT_MARGIN_AREA]; + } + if (from->used[RIGHT_MARGIN_AREA]) + { + nbytes = from->used[RIGHT_MARGIN_AREA] * sizeof (struct glyph); + to->glyphs[RIGHT_MARGIN_AREA] = (struct glyph *) xmalloc (nbytes); + memcpy (to->glyphs[RIGHT_MARGIN_AREA], + from->glyphs[RIGHT_MARGIN_AREA], nbytes); + to->used[RIGHT_MARGIN_AREA] = from->used[RIGHT_MARGIN_AREA]; + } + } + + return saved; +} + /* Restore the contents of frame F's desired frame matrix from SAVED, and free memory associated with SAVED. */ @@ -3094,7 +3141,6 @@ restore_desired_matrix (struct frame *f, struct glyph_matrix *saved) to->used[TEXT_AREA] = from->used[TEXT_AREA]; to->enabled_p = from->enabled_p; to->hash = from->hash; - xfree (from->glyphs[TEXT_AREA]); nbytes = from->used[LEFT_MARGIN_AREA] * sizeof (struct glyph); if (nbytes) { @@ -3102,7 +3148,6 @@ restore_desired_matrix (struct frame *f, struct glyph_matrix *saved) memcpy (to->glyphs[LEFT_MARGIN_AREA], from->glyphs[LEFT_MARGIN_AREA], nbytes); to->used[LEFT_MARGIN_AREA] = from->used[LEFT_MARGIN_AREA]; - xfree (from->glyphs[LEFT_MARGIN_AREA]); } else to->used[LEFT_MARGIN_AREA] = 0; @@ -3113,14 +3158,10 @@ restore_desired_matrix (struct frame *f, struct glyph_matrix *saved) memcpy (to->glyphs[RIGHT_MARGIN_AREA], from->glyphs[RIGHT_MARGIN_AREA], nbytes); to->used[RIGHT_MARGIN_AREA] = from->used[RIGHT_MARGIN_AREA]; - xfree (from->glyphs[RIGHT_MARGIN_AREA]); } else to->used[RIGHT_MARGIN_AREA] = 0; } - - xfree (saved->rows); - xfree (saved); } static void @@ -3182,10 +3223,15 @@ read_menu_input (struct frame *sf, int *x, int *y, int min_y, int max_y, Lisp_Object cmd; int usable_input = 1; int st = 0; + struct tty_display_info *tty = FRAME_TTY (sf); + /* Signal the keyboard reading routines we are displaying a menu + on this terminal. */ + tty->showing_menu = 1; do { cmd = read_menu_command (); } while NILP (cmd); + tty->showing_menu = 0; if (EQ (cmd, Qt) || EQ (cmd, Qtty_menu_exit)) return -1; @@ -3333,7 +3379,7 @@ tty_menu_activate (tty_menu *menu, int *pane, int *selidx, update_frame_with_menu (sf); state[0].menu = menu; mouse_off (); /* FIXME */ - state[0].screen_behind = save_current_matrix (sf); + state[0].screen_behind = save_and_enable_current_matrix (sf); /* Turn off the cursor. Otherwise it shows through the menu panes, which is ugly. */ @@ -3383,7 +3429,7 @@ tty_menu_activate (tty_menu *menu, int *pane, int *selidx, } leave = 1; } - else if (sf->mouse_moved) + if (sf->mouse_moved && input_status != -1) { sf->mouse_moved = 0; result = TTYM_IA_SELECT; @@ -3425,7 +3471,7 @@ tty_menu_activate (tty_menu *menu, int *pane, int *selidx, state[statecount].pane = state[i].menu->panenumber[dy]; mouse_off (); /* FIXME */ state[statecount].screen_behind - = save_current_matrix (sf); + = save_and_enable_current_matrix (sf); state[statecount].x = state[i].x + state[i].menu->width + 2; state[statecount].y = y; @@ -3476,7 +3522,6 @@ tty_menu_activate (tty_menu *menu, int *pane, int *selidx, /* FIXME: Since we set the fram's garbaged flag, do we need this call to screen_update? */ screen_update (sf, state[0].screen_behind); - state[0].screen_behind = NULL; #if 0 /* We have a situation here. ScreenUpdate has just restored the screen contents as it was before we started drawing this menu. diff --git a/src/termchar.h b/src/termchar.h index 687f7fbd119..9dea46f0b76 100644 --- a/src/termchar.h +++ b/src/termchar.h @@ -198,6 +198,9 @@ struct tty_display_info /* Nonzero means use ^S/^Q for flow control. */ unsigned flow_control : 1; + + /* Non-zero means we are displaying a TTY menu on this tty. */ + unsigned showing_menu : 1; }; /* A chain of structures for all tty devices currently in use. */ -- 2.39.2