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.
This commit is contained in:
Andreas Kling 2019-10-21 20:14:51 +02:00
parent 8b4903e733
commit 5b30aa8b02
Notes: sideshowbarker 2024-07-19 11:35:36 +09:00
2 changed files with 41 additions and 19 deletions

View file

@ -1,7 +1,7 @@
#include "TerminalWidget.h"
#include "XtermColors.h"
#include <AK/String.h>
#include <AK/StdLibExtras.h>
#include <AK/String.h>
#include <AK/StringBuilder.h>
#include <Kernel/KeyCode.h>
#include <LibDraw/Font.h>
@ -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);

View file

@ -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<CNotifier> m_notifier;