diff options
author | Christian Persch <chpe@src.gnome.org> | 2022-08-03 22:58:02 +0200 |
---|---|---|
committer | Christian Persch <chpe@src.gnome.org> | 2022-08-03 22:58:34 +0200 |
commit | d46756b89cfbb61929812ca2bd1d8c13a9504044 (patch) | |
tree | 917a00712ce21756677be40cef865fb081882d2c | |
parent | 901558bf471299e483976770e062730f35c13414 (diff) | |
download | vte-d46756b89cfbb61929812ca2bd1d8c13a9504044.tar.gz |
widget: Listen for toplevel focus change
Need to listen to notify::state on the toplevel the widget is in, so
as to generate the correct focus notifications (DECSET 1004).
https://gitlab.gnome.org/GNOME/vte/-/issues/2555
-rw-r--r-- | src/vte.cc | 9 | ||||
-rw-r--r-- | src/vteinternal.hh | 1 | ||||
-rw-r--r-- | src/widget.cc | 113 | ||||
-rw-r--r-- | src/widget.hh | 12 |
4 files changed, 135 insertions, 0 deletions
@@ -7010,6 +7010,15 @@ Terminal::widget_focus_out() } void +Terminal::widget_root_focused_changed(bool focused) noexcept +{ + if (!widget_realized()) + return; + + maybe_feed_focus_event(focused); +} + +void Terminal::widget_mouse_enter(vte::platform::MouseEvent const& event) { auto pos = view_coords_from_event(event); diff --git a/src/vteinternal.hh b/src/vteinternal.hh index 88464760..05e21d97 100644 --- a/src/vteinternal.hh +++ b/src/vteinternal.hh @@ -954,6 +954,7 @@ public: Alignment yalign, bool xfill, bool yfill) noexcept; + void widget_root_focused_changed(bool focused) noexcept; #endif /* VTE_GTK */ void set_blink_settings(bool blink, diff --git a/src/widget.cc b/src/widget.cc index ddf22df9..1d28d905 100644 --- a/src/widget.cc +++ b/src/widget.cc @@ -395,6 +395,43 @@ catch (...) vte::log_exception(); } +static void +root_realize_cb(GtkRoot* r, + vte::platform::Widget* that) noexcept +try +{ + that->root_realize(); +} +catch (...) +{ + vte::log_exception(); +} + +static void +root_unrealize_cb(GtkRoot* r, + vte::platform::Widget* that) noexcept +try +{ + that->root_unrealize(); +} +catch (...) +{ + vte::log_exception(); +} + +static void +root_surface_state_notify_cb(GdkToplevel* toplevel, + GParamSpec* pspec, + Widget* that) noexcept +try +{ + that->root_surface_state_notify(); +} +catch (...) +{ + vte::log_exception(); +} + #endif /* VTE_GTK == 4 */ Widget::Widget(VteTerminal* t) @@ -765,6 +802,11 @@ Widget::event_focus_in(GdkEventFocus *event) { _vte_debug_print(VTE_DEBUG_EVENTS, "Focus In"); +#if VTE_GTK == 4 + if (!root_focused()) + return; +#endif + m_terminal->widget_focus_in(); } @@ -773,6 +815,11 @@ Widget::event_focus_out(GdkEventFocus *event) { _vte_debug_print(VTE_DEBUG_EVENTS, "Focus Out"); +#if VTE_GTK == 4 + if (!root_focused()) + return; +#endif + m_terminal->widget_focus_out(); } @@ -1661,8 +1708,67 @@ Widget::realize() noexcept #if VTE_GTK == 4 void +Widget::root_surface_state_notify() +{ + auto const r = gtk_widget_get_root(gtk()); + auto const toplevel = GDK_TOPLEVEL(gtk_native_get_surface(GTK_NATIVE(r))); + auto const new_state = toplevel ? gdk_toplevel_get_state(toplevel) : GdkToplevelState(0); + auto const changed_mask = new_state ^ m_root_surface_state; + + m_root_surface_state = new_state; + + if (changed_mask & GDK_TOPLEVEL_STATE_FOCUSED) { + terminal()->widget_root_focused_changed(root_focused()); + } +} + +void +Widget::root_realize() +{ + if (m_root_surface_state_notify_id != 0) + return; + + auto const r = gtk_widget_get_root(gtk()); + auto const toplevel = GDK_TOPLEVEL(gtk_native_get_surface(GTK_NATIVE(r))); + m_root_surface_state_notify_id = g_signal_connect(toplevel, + "notify::state", + G_CALLBACK(root_surface_state_notify_cb), + this); + + root_surface_state_notify(); +} + +void +Widget::root_unrealize() +{ + root_surface_state_notify(); + m_root_surface_state = GdkToplevelState(0); + + if (m_root_surface_state_notify_id == 0) + return; + + auto const r = gtk_widget_get_root(gtk()); + auto const toplevel = GDK_TOPLEVEL(gtk_native_get_surface(GTK_NATIVE(r))); + g_signal_handler_disconnect(toplevel, m_root_surface_state_notify_id); + m_root_surface_state_notify_id = 0; +} + +void Widget::root() { + auto const r = gtk_widget_get_root(gtk()); + m_root_realize_id = g_signal_connect(r, + "realize", + G_CALLBACK(root_realize_cb), + this); + m_root_unrealize_id = g_signal_connect(r, + "unrealize", + G_CALLBACK(root_unrealize_cb), + this); + + /* Already realised? */ + if (gtk_widget_get_realized(GTK_WIDGET(r))) + root_realize(); } #endif /* VTE_GTK == 4 */ @@ -2031,6 +2137,13 @@ Widget::unrealize() noexcept void Widget::unroot() { + root_unrealize(); + + auto const r = gtk_widget_get_root(gtk()); + g_signal_handler_disconnect(r, m_root_realize_id); + m_root_realize_id = 0; + g_signal_handler_disconnect(r, m_root_unrealize_id); + m_root_unrealize_id = 0; } #endif /* VTE_GTK == 4 */ diff --git a/src/widget.hh b/src/widget.hh index 308edb57..cd8ee771 100644 --- a/src/widget.hh +++ b/src/widget.hh @@ -318,6 +318,11 @@ public: int* natural_baseline) noexcept; std::pair<bool, bool> compute_expand(); void css_changed(GtkCssStyleChange* change); + void root_realize(); + void root_unrealize(); + void root_surface_state_notify(); + void root_surface_focused_changed(); + auto root_focused() const noexcept { return (m_root_surface_state & GDK_TOPLEVEL_STATE_FOCUSED) != 0; } void system_setting_changed(GtkSystemSetting setting); void snapshot(GtkSnapshot* snapshot) noexcept { terminal()->widget_snapshot(snapshot); } bool contains(double x, @@ -662,6 +667,13 @@ private: VteAlign m_yalign{VTE_ALIGN_START}; bool m_xfill{true}; bool m_yfill{true}; + +#if VTE_GTK == 4 + GdkToplevelState m_root_surface_state{GdkToplevelState(0)}; + long m_root_realize_id{0}; + long m_root_unrealize_id{0}; + long m_root_surface_state_notify_id{0}; +#endif /* VTE_GTK == 4 */ }; } // namespace platform |