diff --git a/gdk/wayland/gdksubsurface-wayland-private.h b/gdk/wayland/gdksubsurface-wayland-private.h index 313ea81e29..7c0b6cfed0 100644 --- a/gdk/wayland/gdksubsurface-wayland-private.h +++ b/gdk/wayland/gdksubsurface-wayland-private.h @@ -25,6 +25,8 @@ struct _GdkWaylandSubsurface struct wl_region *opaque_region; + struct wl_callback *frame_callback; + gboolean above_parent; }; @@ -34,3 +36,6 @@ struct _GdkWaylandSubsurfaceClass }; GType gdk_wayland_subsurface_get_type (void) G_GNUC_CONST; + +void gdk_wayland_subsurface_request_frame (GdkSubsurface *subsurface); +void gdk_wayland_subsurface_clear_frame_callback (GdkSubsurface *subsurface); diff --git a/gdk/wayland/gdksubsurface-wayland.c b/gdk/wayland/gdksubsurface-wayland.c index 3ed92c2026..f73afcee0e 100644 --- a/gdk/wayland/gdksubsurface-wayland.c +++ b/gdk/wayland/gdksubsurface-wayland.c @@ -41,6 +41,7 @@ gdk_wayland_subsurface_finalize (GObject *object) GdkWaylandSubsurface *self = GDK_WAYLAND_SUBSURFACE (object); g_clear_object (&self->texture); + g_clear_pointer (&self->frame_callback, wl_callback_destroy); g_clear_pointer (&self->opaque_region, wl_region_destroy); g_clear_pointer (&self->viewport, wp_viewport_destroy); g_clear_pointer (&self->subsurface, wl_subsurface_destroy); @@ -337,3 +338,39 @@ gdk_wayland_subsurface_class_init (GdkWaylandSubsurfaceClass *class) subsurface_class->place_below = gdk_wayland_subsurface_place_below; subsurface_class->is_above_parent = gdk_wayland_subsurface_is_above_parent; }; + +static void +frame_callback (void *data, + struct wl_callback *callback, + uint32_t time) +{ + GdkSubsurface *sub = data; + + g_assert (((GdkWaylandSubsurface *)sub)->frame_callback == callback); + g_assert (!GDK_SURFACE_DESTROYED (sub->parent)); + + gdk_wayland_surface_frame_callback (sub->parent, time); +} + +static const struct wl_callback_listener frame_listener = { + frame_callback +}; + +void +gdk_wayland_subsurface_request_frame (GdkSubsurface *sub) +{ + GdkWaylandSubsurface *self = (GdkWaylandSubsurface *)sub; + + self->frame_callback = wl_surface_frame (self->surface); + wl_proxy_set_queue ((struct wl_proxy *) self->frame_callback, NULL); + wl_callback_add_listener (self->frame_callback, &frame_listener, self); + wl_surface_commit (self->surface); +} + +void +gdk_wayland_subsurface_clear_frame_callback (GdkSubsurface *sub) +{ + GdkWaylandSubsurface *self = (GdkWaylandSubsurface *)sub; + + g_clear_pointer (&self->frame_callback, wl_callback_destroy); +} diff --git a/gdk/wayland/gdksurface-wayland-private.h b/gdk/wayland/gdksurface-wayland-private.h index 9532964829..c3a8ef96e8 100644 --- a/gdk/wayland/gdksurface-wayland-private.h +++ b/gdk/wayland/gdksurface-wayland-private.h @@ -123,6 +123,9 @@ void gdk_wayland_surface_get_window_geometry (GdkSurface *surface, void gdk_wayland_surface_freeze_state (GdkSurface *surface); void gdk_wayland_surface_thaw_state (GdkSurface *surface); +void gdk_wayland_surface_frame_callback (GdkSurface *surface, + uint32_t time); + #define GDK_TYPE_WAYLAND_DRAG_SURFACE (gdk_wayland_drag_surface_get_type ()) GType gdk_wayland_drag_surface_get_type (void) G_GNUC_CONST; diff --git a/gdk/wayland/gdksurface-wayland.c b/gdk/wayland/gdksurface-wayland.c index 022fe033cc..498745c6e9 100644 --- a/gdk/wayland/gdksurface-wayland.c +++ b/gdk/wayland/gdksurface-wayland.c @@ -264,12 +264,10 @@ gdk_wayland_surface_update_size (GdkSurface *surface, _gdk_surface_update_size (surface); } -static void -frame_callback (void *data, - struct wl_callback *callback, - uint32_t time) +void +gdk_wayland_surface_frame_callback (GdkSurface *surface, + uint32_t time) { - GdkSurface *surface = data; GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface)); @@ -279,11 +277,14 @@ frame_callback (void *data, gdk_profiler_add_mark (GDK_PROFILER_CURRENT_TIME, 0, "wayland", "frame event"); GDK_DISPLAY_DEBUG (GDK_DISPLAY (display_wayland), EVENTS, "frame %p", surface); - g_assert (impl->frame_callback == callback); - g_assert (!GDK_SURFACE_DESTROYED (surface)); - g_clear_pointer (&impl->frame_callback, wl_callback_destroy); + for (gsize i = 0; i < gdk_surface_get_n_subsurfaces (surface); i++) + { + GdkSubsurface *subsurface = gdk_surface_get_subsurface (surface, i); + gdk_wayland_subsurface_clear_frame_callback (subsurface); + } + GDK_WAYLAND_SURFACE_GET_CLASS (impl)->handle_frame (impl); if (impl->awaiting_frame_frozen) @@ -321,6 +322,19 @@ frame_callback (void *data, _gdk_frame_clock_add_timings_to_profiler (clock, timings); } +static void +frame_callback (void *data, + struct wl_callback *callback, + uint32_t time) +{ + GdkSurface *surface = data; + + g_assert (GDK_WAYLAND_SURFACE (surface)->frame_callback == callback); + g_assert (!GDK_SURFACE_DESTROYED (surface)); + + gdk_wayland_surface_frame_callback (surface, time); +} + static const struct wl_callback_listener frame_listener = { frame_callback }; @@ -382,6 +396,13 @@ gdk_wayland_surface_request_frame (GdkSurface *surface) self->frame_callback = wl_surface_frame (self->display_server.wl_surface); wl_proxy_set_queue ((struct wl_proxy *) self->frame_callback, NULL); wl_callback_add_listener (self->frame_callback, &frame_listener, surface); + + for (gsize i = 0; i < gdk_surface_get_n_subsurfaces (surface); i++) + { + GdkSubsurface *subsurface = gdk_surface_get_subsurface (surface, i); + gdk_wayland_subsurface_request_frame (subsurface); + } + self->pending_frame_counter = gdk_frame_clock_get_frame_counter (clock); }