fix(engine/linux): add GTK4 close-request and monitor updates

This commit is contained in:
Rich Young 2026-02-05 19:03:35 -05:00
parent d012f1e1a9
commit 33235f42ae
3 changed files with 99 additions and 6 deletions

View File

@ -84,6 +84,49 @@ static void monitor_removed_cb(FlDisplayMonitor* self, GdkMonitor* monitor) {
notify_display_update(self);
}
#if FLUTTER_LINUX_GTK4
static void prune_display_ids_for_current_monitors(FlDisplayMonitor* self) {
GListModel* monitors = gdk_display_get_monitors(self->display);
guint n_monitors = g_list_model_get_n_items(monitors);
GHashTable* current = g_hash_table_new(g_direct_hash, g_direct_equal);
for (guint i = 0; i < n_monitors; i++) {
GdkMonitor* monitor = GDK_MONITOR(g_list_model_get_item(monitors, i));
g_hash_table_add(current, monitor);
}
GHashTableIter iter;
gpointer key = nullptr;
g_hash_table_iter_init(&iter, self->display_ids_by_monitor);
while (g_hash_table_iter_next(&iter, &key, nullptr)) {
if (!g_hash_table_contains(current, key)) {
g_hash_table_iter_remove(&iter);
}
}
GHashTableIter current_iter;
g_hash_table_iter_init(&current_iter, current);
while (g_hash_table_iter_next(&current_iter, &key, nullptr)) {
g_object_unref(G_OBJECT(key));
}
g_hash_table_unref(current);
}
static void monitors_changed_cb(GListModel* list,
guint position,
guint removed,
guint added,
gpointer user_data) {
(void)list;
(void)position;
(void)removed;
(void)added;
FlDisplayMonitor* self = FL_DISPLAY_MONITOR(user_data);
prune_display_ids_for_current_monitors(self);
notify_display_update(self);
}
#endif
static void fl_display_monitor_dispose(GObject* object) {
FlDisplayMonitor* self = FL_DISPLAY_MONITOR(object);
@ -117,12 +160,19 @@ FlDisplayMonitor* fl_display_monitor_new(FlEngine* engine,
void fl_display_monitor_start(FlDisplayMonitor* self) {
g_return_if_fail(FL_IS_DISPLAY_MONITOR(self));
#if FLUTTER_LINUX_GTK4
GListModel* monitors = gdk_display_get_monitors(self->display);
g_signal_connect_object(monitors, "items-changed",
G_CALLBACK(monitors_changed_cb), self,
static_cast<GConnectFlags>(0));
#else
g_signal_connect_object(self->display, "monitor-added",
G_CALLBACK(monitor_added_cb), self,
G_CONNECT_SWAPPED);
g_signal_connect_object(self->display, "monitor-removed",
G_CALLBACK(monitor_removed_cb), self,
G_CONNECT_SWAPPED);
#endif
notify_display_update(self);
}

View File

@ -153,13 +153,23 @@ static FlGdkSurface* fl_view_get_toplevel_surface(FlView* self) {
return toplevel != nullptr ? fl_gtk_widget_get_surface(toplevel) : nullptr;
}
// Signal handler for GtkWidget::delete-event
// Signal handler for GtkWidget::delete-event (GTK3 only)
static gboolean window_delete_event_cb(FlView* self) {
fl_engine_request_app_exit(self->engine);
// Stop the event from propagating.
return TRUE;
}
#if FLUTTER_LINUX_GTK4
// Signal handler for GtkWindow::close-request.
static gboolean window_close_request_cb(GtkWindow* window, FlView* self) {
(void)window;
fl_engine_request_app_exit(self->engine);
// Stop the event from propagating.
return TRUE;
}
#endif
static void init_scrolling(FlView* self) {
g_clear_object(&self->scrolling_manager);
self->scrolling_manager =
@ -754,8 +764,13 @@ static void realize_cb(FlView* self) {
GTK_WINDOW(toplevel_window));
// Handle requests by the user to close the application.
#if FLUTTER_LINUX_GTK4
g_signal_connect(toplevel_window, "close-request",
G_CALLBACK(window_close_request_cb), self);
#else
g_signal_connect_swapped(toplevel_window, "delete-event",
G_CALLBACK(window_delete_event_cb), self);
#endif
// Flutter engine will need to make the context current from raster thread
// during initialization.
@ -767,6 +782,11 @@ static void realize_cb(FlView* self) {
return;
}
#if FLUTTER_LINUX_GTK4
fl_text_input_handler_set_widget(
fl_engine_get_text_input_handler(self->engine), GTK_WIDGET(self));
#endif
setup_cursor(self);
handle_geometry_changed(self);
@ -1014,11 +1034,6 @@ static void setup_engine(FlView* self) {
init_scrolling(self);
init_touch(self);
#if FLUTTER_LINUX_GTK4
fl_text_input_handler_set_widget(
fl_engine_get_text_input_handler(self->engine),
GTK_WIDGET(self));
#endif
self->on_pre_engine_restart_cb_id =
g_signal_connect_swapped(self->engine, "on-pre-engine-restart",

View File

@ -55,6 +55,13 @@ static void title_notify_cb(FlWindowMonitor* self) {
self->on_title_notify();
}
#if FLUTTER_LINUX_GTK4
static gboolean close_request_cb(FlWindowMonitor* self) {
flutter::IsolateScope scope(self->isolate);
self->on_close();
return TRUE;
}
#else
static gboolean delete_event_cb(FlWindowMonitor* self, GdkEvent* event) {
flutter::IsolateScope scope(self->isolate);
self->on_close();
@ -62,6 +69,18 @@ static gboolean delete_event_cb(FlWindowMonitor* self, GdkEvent* event) {
// Stop default behaviour of destroying the window.
return TRUE;
}
#endif
#if FLUTTER_LINUX_GTK4
static gboolean close_request_cb(GtkWindow* window, FlWindowMonitor* self) {
(void)window;
flutter::IsolateScope scope(self->isolate);
self->on_close();
// Stop default behaviour of destroying the window.
return TRUE;
}
#endif
static void destroy_cb(FlWindowMonitor* self) {
flutter::IsolateScope scope(self->isolate);
@ -114,8 +133,17 @@ G_MODULE_EXPORT FlWindowMonitor* fl_window_monitor_new(
G_CALLBACK(is_active_notify_cb), self);
g_signal_connect_swapped(window, "notify::title", G_CALLBACK(title_notify_cb),
self);
#if FLUTTER_LINUX_GTK4
g_signal_connect(window, "close-request", G_CALLBACK(close_request_cb), self);
#else
#if FLUTTER_LINUX_GTK4
g_signal_connect_swapped(window, "close-request",
G_CALLBACK(close_request_cb), self);
#else
g_signal_connect_swapped(window, "delete-event", G_CALLBACK(delete_event_cb),
self);
#endif
#endif
g_signal_connect_swapped(window, "destroy", G_CALLBACK(destroy_cb), self);
return self;