[vte] widget: Listen for toplevel focus change
- From: Christian Persch <chpe src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [vte] widget: Listen for toplevel focus change
- Date: Wed, 3 Aug 2022 20:59:10 +0000 (UTC)
commit d46756b89cfbb61929812ca2bd1d8c13a9504044
Author: Christian Persch <chpe src gnome org>
Date: Wed Aug 3 22:58:02 2022 +0200
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
src/vte.cc | 9 +++++
src/vteinternal.hh | 1 +
src/widget.cc | 113 +++++++++++++++++++++++++++++++++++++++++++++++++++++
src/widget.hh | 12 ++++++
4 files changed, 135 insertions(+)
---
diff --git a/src/vte.cc b/src/vte.cc
index 601b89ad..e09ff384 100644
--- a/src/vte.cc
+++ b/src/vte.cc
@@ -7009,6 +7009,15 @@ Terminal::widget_focus_out()
check_cursor_blink();
}
+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)
{
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();
}
@@ -1660,9 +1707,68 @@ 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
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]