From 5b30aa8b0212575701e46cf70fc762deae0daa65 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Mon, 21 Oct 2019 20:14:51 +0200 Subject: [PATCH] LibVT: Make TerminalWidget logically focusable when not a main widget TerminalWidget was relying on the "window became active/inactive" events from WindowServer to update its own internal focus state. Unfortunately those events are only sent to the window's main widget, so this was not working when the TerminalWidget was embedded deeper in a widget tree. This patch hooks the focusin and focusout events and uses those to set the focus state when received. This makes TerminalWidget behave nicely in both configurations. This design is kind of a workaround for this awkward focus architecture and we should figure out something better in the long term. --- Libraries/LibVT/TerminalWidget.cpp | 52 +++++++++++++++++++----------- Libraries/LibVT/TerminalWidget.h | 8 ++++- 2 files changed, 41 insertions(+), 19 deletions(-) diff --git a/Libraries/LibVT/TerminalWidget.cpp b/Libraries/LibVT/TerminalWidget.cpp index f63a9b1e48..579af2e25d 100644 --- a/Libraries/LibVT/TerminalWidget.cpp +++ b/Libraries/LibVT/TerminalWidget.cpp @@ -1,7 +1,7 @@ #include "TerminalWidget.h" #include "XtermColors.h" -#include #include +#include #include #include #include @@ -101,20 +101,38 @@ Rect TerminalWidget::row_rect(u16 row) return rect; } +void TerminalWidget::set_logical_focus(bool focus) +{ + m_has_logical_focus = focus; + if (!m_has_logical_focus) { + m_cursor_blink_timer->stop(); + } else { + m_cursor_blink_state = true; + m_cursor_blink_timer->start(); + } + invalidate_cursor(); + update(); +} + +void TerminalWidget::focusin_event(CEvent& event) +{ + set_logical_focus(true); + return GFrame::focusin_event(event); +} + +void TerminalWidget::focusout_event(CEvent& event) +{ + set_logical_focus(false); + return GFrame::focusout_event(event); +} + void TerminalWidget::event(CEvent& event) { - if (event.type() == GEvent::WindowBecameActive || event.type() == GEvent::WindowBecameInactive) { - m_in_active_window = event.type() == GEvent::WindowBecameActive; - if (!m_in_active_window) { - m_cursor_blink_timer->stop(); - } else { - m_cursor_blink_state = true; - m_cursor_blink_timer->start(); - } - invalidate_cursor(); - update(); - } - return GWidget::event(event); + if (event.type() == GEvent::WindowBecameActive) + set_logical_focus(true); + else if (event.type() == GEvent::WindowBecameInactive) + set_logical_focus(false); + return GFrame::event(event); } void TerminalWidget::keydown_event(GKeyEvent& event) @@ -239,7 +257,6 @@ void TerminalWidget::paint_event(GPaintEvent& event) else if (has_only_one_background_color) painter.fill_rect(row_rect, lookup_color(line.attributes[0].background_color).with_alpha(m_opacity)); - // The terminal insists on thinking characters and // bytes are the same thing. We want to still draw // emojis in *some* way, but it won't be completely @@ -265,9 +282,8 @@ void TerminalWidget::paint_event(GPaintEvent& event) VT::Attribute attribute; for (u16 column = this_char_column; column < next_char_column; ++column) { - should_reverse_fill_for_cursor_or_selection |= - m_cursor_blink_state - && m_in_active_window + should_reverse_fill_for_cursor_or_selection |= m_cursor_blink_state + && m_has_logical_focus && row == row_with_cursor && column == m_terminal.cursor_column(); should_reverse_fill_for_cursor_or_selection |= selection_contains({ row, column }); @@ -295,7 +311,7 @@ void TerminalWidget::paint_event(GPaintEvent& event) } } - if (!m_in_active_window && row_with_cursor < m_terminal.rows()) { + if (!m_has_logical_focus && row_with_cursor < m_terminal.rows()) { auto& cursor_line = line_for_visual_row(row_with_cursor); if (m_terminal.cursor_row() < (m_terminal.rows() - rows_from_history)) { auto cell_rect = glyph_rect(row_with_cursor, m_terminal.cursor_column()).inflated(0, m_line_spacing); diff --git a/Libraries/LibVT/TerminalWidget.h b/Libraries/LibVT/TerminalWidget.h index 9f8ca2eed6..053775483f 100644 --- a/Libraries/LibVT/TerminalWidget.h +++ b/Libraries/LibVT/TerminalWidget.h @@ -41,6 +41,8 @@ public: bool is_scrollable() const; + virtual bool accepts_focus() const override { return true; } + private: // ^GWidget virtual void event(CEvent&) override; @@ -52,6 +54,8 @@ private: virtual void mouseup_event(GMouseEvent&) override; virtual void mousewheel_event(GMouseEvent&) override; virtual void doubleclick_event(GMouseEvent&) override; + virtual void focusin_event(CEvent&) override; + virtual void focusout_event(CEvent&) override; // ^TerminalClient virtual void beep() override; @@ -59,6 +63,8 @@ private: virtual void terminal_did_resize(u16 columns, u16 rows) override; virtual void terminal_history_changed() override; + void set_logical_focus(bool); + Rect glyph_rect(u16 row, u16 column); Rect row_rect(u16 row); @@ -86,7 +92,7 @@ private: int m_ptm_fd { -1 }; - bool m_in_active_window { false }; + bool m_has_logical_focus { false }; RefPtr m_notifier;