diff options
author | Matthias Clasen <mclasen@redhat.com> | 2021-02-12 12:46:37 +0000 |
---|---|---|
committer | Matthias Clasen <mclasen@redhat.com> | 2021-02-12 12:46:37 +0000 |
commit | 2ca1fe61a4ae1ccf940f401ecaa1c56c39a19640 (patch) | |
tree | 25654aaf35a716b44f8dde6b2578ab48e25c2383 | |
parent | 6fd951e53d9d28a6702a0413638157cc21cb66e9 (diff) | |
parent | d3316a37edb0ff7b8faf7115ea11fdce76578d95 (diff) | |
download | gtk+-2ca1fe61a4ae1ccf940f401ecaa1c56c39a19640.tar.gz |
Merge branch 'frame-request-api' into 'gtk-3-24'
wayland/window: Add API to overwrite surface frame requests
See merge request GNOME/gtk!3111
-rw-r--r-- | docs/reference/gdk/gdk3-sections.txt | 2 | ||||
-rw-r--r-- | gdk/wayland/gdkwaylandwindow.h | 8 | ||||
-rw-r--r-- | gdk/wayland/gdkwindow-wayland.c | 120 |
3 files changed, 126 insertions, 4 deletions
diff --git a/docs/reference/gdk/gdk3-sections.txt b/docs/reference/gdk/gdk3-sections.txt index 7b5649c7bd..1833777500 100644 --- a/docs/reference/gdk/gdk3-sections.txt +++ b/docs/reference/gdk/gdk3-sections.txt @@ -1279,6 +1279,8 @@ GdkWaylandWindowExported gdk_wayland_window_export_handle gdk_wayland_window_unexport_handle gdk_wayland_window_set_transient_for_exported +gdk_wayland_window_add_frame_callback_surface +gdk_wayland_window_remove_frame_callback_surface <SUBSECTION Standard> GDK_TYPE_WAYLAND_DEVICE diff --git a/gdk/wayland/gdkwaylandwindow.h b/gdk/wayland/gdkwaylandwindow.h index 3b76822962..b8a8a02243 100644 --- a/gdk/wayland/gdkwaylandwindow.h +++ b/gdk/wayland/gdkwaylandwindow.h @@ -87,6 +87,14 @@ void gdk_wayland_window_announce_csd (GdkWindow *window); GDK_AVAILABLE_IN_3_24 void gdk_wayland_window_announce_ssd (GdkWindow *window); +GDK_AVAILABLE_IN_3_24 +void gdk_wayland_window_add_frame_callback_surface (GdkWindow *window, + struct wl_surface *surface); + +GDK_AVAILABLE_IN_3_24 +void gdk_wayland_window_remove_frame_callback_surface (GdkWindow *window, + struct wl_surface *surface); + G_END_DECLS #endif /* __GDK_WAYLAND_WINDOW_H__ */ diff --git a/gdk/wayland/gdkwindow-wayland.c b/gdk/wayland/gdkwindow-wayland.c index 8d14db56f0..2d7c42bd7a 100644 --- a/gdk/wayland/gdkwindow-wayland.c +++ b/gdk/wayland/gdkwindow-wayland.c @@ -236,6 +236,9 @@ struct _GdkWindowImplWayland struct zxdg_imported_v1 *imported_transient_for; GHashTable *shortcuts_inhibitors; + + struct wl_callback *surface_callback; + GHashTable *frame_callback_surfaces; }; struct _GdkWindowImplWaylandClass @@ -572,9 +575,25 @@ frame_callback (void *data, GdkFrameClock *clock = gdk_window_get_frame_clock (window); GdkFrameTimings *timings; - GDK_NOTE (EVENTS, - g_message ("frame %p", window)); + if (callback == impl->surface_callback) + { + impl->surface_callback = NULL; + } + else + { + GHashTableIter iter; + gpointer surface_callback; + g_hash_table_iter_init (&iter, impl->frame_callback_surfaces); + while (g_hash_table_iter_next (&iter, NULL, &surface_callback)) + { + if (callback == surface_callback) + { + g_hash_table_iter_replace (&iter, NULL); + break; + } + } + } wl_callback_destroy (callback); if (GDK_WINDOW_DESTROYED (window)) @@ -583,6 +602,9 @@ frame_callback (void *data, if (!impl->awaiting_frame) return; + GDK_NOTE (EVENTS, + g_message ("frame %p", window)); + impl->awaiting_frame = FALSE; _gdk_frame_clock_thaw (clock); @@ -660,6 +682,8 @@ on_frame_clock_after_paint (GdkFrameClock *clock, { GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl); struct wl_callback *callback; + GHashTableIter iter; + gpointer surface, surface_callback; if (!impl->pending_commit) return; @@ -667,8 +691,6 @@ on_frame_clock_after_paint (GdkFrameClock *clock, if (window->update_freeze_count > 0) return; - callback = wl_surface_frame (impl->display_server.wl_surface); - wl_callback_add_listener (callback, &frame_listener, window); _gdk_frame_clock_freeze (clock); /* Before we commit a new buffer, make sure we've backfilled @@ -677,6 +699,24 @@ on_frame_clock_after_paint (GdkFrameClock *clock, if (impl->pending_buffer_attached) read_back_cairo_surface (window); + if (impl->surface_callback == NULL) + { + callback = wl_surface_frame (impl->display_server.wl_surface); + wl_callback_add_listener (callback, &frame_listener, window); + impl->surface_callback = callback; + } + + g_hash_table_iter_init (&iter, impl->frame_callback_surfaces); + while (g_hash_table_iter_next (&iter, &surface, &surface_callback)) + { + if (surface_callback) + continue; + + callback = wl_surface_frame (surface); + wl_callback_add_listener (callback, &frame_listener, window); + g_hash_table_iter_replace (&iter, callback); + } + /* From this commit forward, we can't write to the buffer, * it's "live". In the future, if we need to stage more changes * we have to allocate a new staging buffer and draw to it instead. @@ -756,6 +796,8 @@ _gdk_wayland_display_create_window_impl (GdkDisplay *display, impl->wrapper = GDK_WINDOW (window); impl->shortcuts_inhibitors = g_hash_table_new (NULL, NULL); impl->using_csd = TRUE; + impl->surface_callback = NULL; + impl->frame_callback_surfaces = g_hash_table_new (NULL, NULL); if (window->width > 65535) { @@ -1067,6 +1109,7 @@ gdk_window_impl_wayland_finalize (GObject *object) g_clear_pointer (&impl->staged_updates_region, cairo_region_destroy); g_clear_pointer (&impl->shortcuts_inhibitors, g_hash_table_unref); + g_clear_pointer (&impl->frame_callback_surfaces, g_hash_table_unref); G_OBJECT_CLASS (_gdk_window_impl_wayland_parent_class)->finalize (object); } @@ -3352,6 +3395,7 @@ gdk_wayland_window_hide_surface (GdkWindow *window) wl_surface_destroy (impl->display_server.wl_surface); impl->display_server.wl_surface = NULL; + impl->surface_callback = NULL; g_slist_free (impl->display_server.outputs); impl->display_server.outputs = NULL; @@ -5397,3 +5441,71 @@ gdk_wayland_window_restore_shortcuts (GdkWindow *window, g_hash_table_remove (impl->shortcuts_inhibitors, seat); } +/** + * gdk_wayland_window_add_frame_callback_surface: + * @window: the #GdkWindow requesting callbacks + * @surface: the wl_surface to add + * + * Add @surface to a list of surfaces for which frame callback + * listeners will get set up, additionally to the one of @window. + * + * This is useful when clients use subsurfaces independently of GDK. + * For example if a client creates a subsurface that covers @window + * entirely. If this subsurface is opaque, Wayland compositors may not + * emit callbacks for the surface of @window any more. + * Adding the covering subsurface via this function ensures the + * @window will continue to update. + * + * A single callback is sufficient to trigger the next update. If more + * than one are triggered, the later ones will get ignored. + * + * Before @surface gets destroyed it must get removed again using + * gdk_wayland_window_remove_frame_callback_surface(). + * + * Note that the client is responsible to commit the @surface. + * One way to archive this is to always commit after the + * #GdkSurface::after-paint signal was triggered. + * + * Since: 3.24.25 + */ +void +gdk_wayland_window_add_frame_callback_surface (GdkWindow *window, + struct wl_surface *surface) +{ + GdkWindowImplWayland *impl; + + g_return_if_fail (GDK_IS_WAYLAND_WINDOW (window)); + g_return_if_fail (GDK_IS_WINDOW_IMPL_WAYLAND (window->impl)); + g_return_if_fail (surface != NULL); + + impl = GDK_WINDOW_IMPL_WAYLAND (window->impl); + + g_hash_table_insert (impl->frame_callback_surfaces, surface, NULL); +} + +/** + * gdk_wayland_window_remove_frame_callback_surface: + * @window: the #GdkWindow requesting callbacks + * @surface: the surface to remove + * + * Remove @surface from the list of surfaces again that got added via + * gdk_wayland_window_add_frame_callback_surface(). + * + * This function must be called before @surface gets destroyed. + * + * Since: 3.24.25 + */ +void +gdk_wayland_window_remove_frame_callback_surface (GdkWindow *window, + struct wl_surface *surface) +{ + GdkWindowImplWayland *impl; + + g_return_if_fail (GDK_IS_WAYLAND_WINDOW (window)); + g_return_if_fail (GDK_IS_WINDOW_IMPL_WAYLAND (window->impl)); + g_return_if_fail (surface != NULL); + + impl = GDK_WINDOW_IMPL_WAYLAND (window->impl); + + g_hash_table_remove (impl->frame_callback_surfaces, surface); +} |