summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Persch <chpe@src.gnome.org>2022-08-03 22:58:02 +0200
committerChristian Persch <chpe@src.gnome.org>2022-08-03 22:58:34 +0200
commitd46756b89cfbb61929812ca2bd1d8c13a9504044 (patch)
tree917a00712ce21756677be40cef865fb081882d2c
parent901558bf471299e483976770e062730f35c13414 (diff)
downloadvte-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.cc9
-rw-r--r--src/vteinternal.hh1
-rw-r--r--src/widget.cc113
-rw-r--r--src/widget.hh12
4 files changed, 135 insertions, 0 deletions
diff --git a/src/vte.cc b/src/vte.cc
index 601b89ad..e09ff384 100644
--- a/src/vte.cc
+++ b/src/vte.cc
@@ -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