From ad76020af8498d148984daf4de545d5d610d0589 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sun, 6 Oct 2019 19:53:18 +0300 Subject: [PATCH] Support mouse clicks on tab bar on TTY frames This for now doesn't work on GPM. * src/xdisp.c (display_tab_bar): Make the loop over tab-bar items more efficient. (tab_bar_item_info, tool_bar_item_info): Correct data type for CHARPOS. (tty_get_tab_bar_item, tty_handle_tab_bar_click): New functions. (note_mouse_highlight): Handle help-echo of tab-bar tabs on TTY frames. * src/w32inevt.c (do_mouse_event): Call tty_handle_tab_bar_click to process mouse clicks on the tab bar. * src/termchar.h (tty_handle_tab_bar_click): Add prototype. * src/w32console.c (w32con_set_terminal_modes): Disable Quick Edit mode on entry, to make sure mouse events get reported to us. --- src/termchar.h | 4 ++ src/w32console.c | 9 +++- src/w32inevt.c | 25 ++++++---- src/xdisp.c | 125 ++++++++++++++++++++++++++++++++++++++++++++--- 4 files changed, 146 insertions(+), 17 deletions(-) diff --git a/src/termchar.h b/src/termchar.h index 796453d3cca..11c964b2b6d 100644 --- a/src/termchar.h +++ b/src/termchar.h @@ -231,4 +231,8 @@ extern struct tty_display_info *tty_list; #define CURTTY() FRAME_TTY (SELECTED_FRAME()) +struct input_event; +extern bool tty_handle_tab_bar_click (struct frame *, int, int, bool, + struct input_event *); + #endif /* EMACS_TERMCHAR_H */ diff --git a/src/w32console.c b/src/w32console.c index 8575c930a85..c50bb67cd2c 100644 --- a/src/w32console.c +++ b/src/w32console.c @@ -503,7 +503,14 @@ w32con_set_terminal_modes (struct terminal *t) SetConsoleActiveScreenBuffer (cur_screen); - SetConsoleMode (keyboard_handle, ENABLE_MOUSE_INPUT | ENABLE_WINDOW_INPUT); + /* If Quick Edit is enabled for the console, it will get in the way + of receiving mouse events, so we disable it. But leave the + Insert Mode as it was set by the user. */ + DWORD new_console_mode + = ENABLE_MOUSE_INPUT | ENABLE_WINDOW_INPUT | ENABLE_EXTENDED_FLAGS; + if ((prev_console_mode & ENABLE_INSERT_MODE) != 0) + new_console_mode |= ENABLE_INSERT_MODE; + SetConsoleMode (keyboard_handle, new_console_mode); /* Initialize input mode: interrupt_input off, no flow control, allow 8 bit character input, standard quit char. */ diff --git a/src/w32inevt.c b/src/w32inevt.c index 0a1321c6d89..1a901d4e0aa 100644 --- a/src/w32inevt.c +++ b/src/w32inevt.c @@ -559,8 +559,6 @@ do_mouse_event (MOUSE_EVENT_RECORD *event, if (event->dwButtonState == button_state) return 0; - emacs_ev->kind = MOUSE_CLICK_EVENT; - /* Find out what button has changed state since the last button event. */ but_change = button_state ^ event->dwButtonState; @@ -576,15 +574,24 @@ do_mouse_event (MOUSE_EVENT_RECORD *event, } button_state = event->dwButtonState; - emacs_ev->modifiers = - w32_kbd_mods_to_emacs (event->dwControlKeyState, 0) - | ((event->dwButtonState & mask) ? down_modifier : up_modifier); + emacs_ev->modifiers = w32_kbd_mods_to_emacs (event->dwControlKeyState, 0); + emacs_ev->timestamp = GetTickCount (); + + int x = event->dwMousePosition.X; + int y = event->dwMousePosition.Y; + struct frame *f = get_frame (); + if (tty_handle_tab_bar_click (f, x, y, (button_state & mask) != 0, + emacs_ev)) + return 0; /* tty_handle_tab_bar_click adds the event to queue */ - XSETFASTINT (emacs_ev->x, event->dwMousePosition.X); - XSETFASTINT (emacs_ev->y, event->dwMousePosition.Y); - XSETFRAME (emacs_ev->frame_or_window, get_frame ()); + emacs_ev->modifiers |= ((button_state & mask) + ? down_modifier : up_modifier); + + emacs_ev->kind = MOUSE_CLICK_EVENT; + XSETFASTINT (emacs_ev->x, x); + XSETFASTINT (emacs_ev->y, y); + XSETFRAME (emacs_ev->frame_or_window, f); emacs_ev->arg = Qnil; - emacs_ev->timestamp = GetTickCount (); return 1; } diff --git a/src/xdisp.c b/src/xdisp.c index f5dedc218e2..8aa38c8034c 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -12746,12 +12746,12 @@ display_tab_bar (struct window *w) /* Display all items of the tab bar. */ items = it.f->tab_bar_items; - for (i = 0; i < it.f->n_tab_bar_items; ++i) + int j; + for (i = 0, j = 0; i < it.f->n_tab_bar_items; ++i, j += TAB_BAR_ITEM_NSLOTS) { - Lisp_Object string; + Lisp_Object string = AREF (items, j + TAB_BAR_ITEM_CAPTION); /* Stop at nil string. */ - string = AREF (items, i * TAB_BAR_ITEM_NSLOTS + TAB_BAR_ITEM_CAPTION); if (NILP (string)) break; @@ -13180,7 +13180,7 @@ tab_bar_item_info (struct frame *f, struct glyph *glyph, int *prop_idx, bool *close_p) { Lisp_Object prop; - int charpos; + ptrdiff_t charpos; /* This function can be called asynchronously, which means we must exclude any possibility that Fget_text_property signals an @@ -13256,7 +13256,7 @@ get_tab_bar_item (struct frame *f, int x, int y, struct glyph **glyph, void handle_tab_bar_click (struct frame *f, int x, int y, bool down_p, - int modifiers) + int modifiers) { Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f); struct window *w = XWINDOW (f->tab_bar_window); @@ -13420,6 +13420,96 @@ note_tab_bar_highlight (struct frame *f, int x, int y) #endif /* HAVE_WINDOW_SYSTEM */ +/* Find the tab-bar item at X coordinate and return its information. */ +static Lisp_Object +tty_get_tab_bar_item (struct frame *f, int x, int *idx, ptrdiff_t *end) +{ + ptrdiff_t clen = 0; + Lisp_Object caption; + + int i, j; + for (i = 0, j = 0; i < f->n_tab_bar_items; i++, j += TAB_BAR_ITEM_NSLOTS) + { + caption = AREF (f->tab_bar_items, j + TAB_BAR_ITEM_CAPTION); + if (NILP (caption)) + return Qnil; + clen += SCHARS (caption); + if (x < clen) + break; + } + if (i < f->n_tab_bar_items) + { + *idx = i; + *end = clen; + return caption; + } + else + return Qnil; +} + +/* Handle a mouse click at X/Y on the tab bar of TTY frame F. If the + click was on the tab bar and was handled, populate the EVENT + structure, store it in keyboard queue, and return true; otherwise + return false. MODIFIERS are event modifiers for generating the tab + release event. */ +bool +tty_handle_tab_bar_click (struct frame *f, int x, int y, bool down_p, + struct input_event *event) +{ + /* Did they click on the tab bar? */ + if (y < FRAME_MENU_BAR_LINES (f) + || y >= FRAME_MENU_BAR_LINES (f) + FRAME_TAB_BAR_LINES (f)) + return false; + + /* Find the tab-bar item where the X,Y coordinates belong. */ + int prop_idx; + ptrdiff_t clen; + Lisp_Object caption = tty_get_tab_bar_item (f, x, &prop_idx, &clen); + + if (NILP (caption)) + return false; + + if (NILP (AREF (f->tab_bar_items, + prop_idx * TAB_BAR_ITEM_NSLOTS + TAB_BAR_ITEM_ENABLED_P))) + return false; + + if (down_p) + f->last_tab_bar_item = prop_idx; + else + { + /* Generate a TAB_BAR_EVENT event. */ + Lisp_Object frame; + Lisp_Object key = AREF (f->tab_bar_items, + prop_idx * TAB_BAR_ITEM_NSLOTS + + TAB_BAR_ITEM_KEY); + /* Kludge alert: we assume the last two characters of a tab + label are " x", and treat clicks on those 2 characters as a + Close Tab command. */ + eassert (STRINGP (caption)); + int lastc = SSDATA (caption)[SCHARS (caption) - 1]; + bool close_p = false; + if ((x == clen - 1 || (clen > 1 && x == clen - 2)) && lastc == 'x') + close_p = true; + + event->code = 0; + XSETFRAME (frame, f); + event->kind = TAB_BAR_EVENT; + event->frame_or_window = frame; + event->arg = frame; + kbd_buffer_store_event (event); + + event->kind = TAB_BAR_EVENT; + event->frame_or_window = frame; + event->arg = key; + if (close_p) + event->modifiers |= ctrl_modifier; + kbd_buffer_store_event (event); + f->last_tab_bar_item = -1; + } + + return true; +} + /*********************************************************************** @@ -14065,7 +14155,7 @@ static bool tool_bar_item_info (struct frame *f, struct glyph *glyph, int *prop_idx) { Lisp_Object prop; - int charpos; + ptrdiff_t charpos; /* This function can be called asynchronously, which means we must exclude any possibility that Fget_text_property signals an @@ -32711,9 +32801,30 @@ note_mouse_highlight (struct frame *f, int x, int y) && part != ON_TAB_LINE)) clear_mouse_face (hlinfo); - /* Reset help_echo_string. It will get recomputed below. */ + /* Reset help_echo_string. It will get recomputed below. */ help_echo_string = Qnil; + /* Handle tab-bar highlight on mouse-capable TTY frames. */ + if (!FRAME_WINDOW_P (f) + && (y >= FRAME_MENU_BAR_LINES (f) + && y < FRAME_MENU_BAR_LINES (f) + FRAME_TAB_BAR_LINES (f))) + { + int prop_idx; + ptrdiff_t ignore; + Lisp_Object caption = tty_get_tab_bar_item (f, x, &prop_idx, &ignore); + + if (!NILP (caption)) + { + help_echo_object = help_echo_window = Qnil; + help_echo_pos = -1; + help_echo_string = AREF (f->tab_bar_items, + prop_idx * TAB_BAR_ITEM_NSLOTS + + TAB_BAR_ITEM_HELP); + if (NILP (help_echo_string)) + help_echo_string = caption; + } + } + #ifdef HAVE_WINDOW_SYSTEM /* If the cursor is on the internal border of FRAME and FRAME's internal border is draggable, provide some visual feedback. */ -- 2.39.5