2010-12-18 20:38:49 +00:00
|
|
|
/*
|
|
|
|
* Copyright © 2010 Intel Corporation
|
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public License
|
|
|
|
* as published by the Free Software Foundation; either version 2 of
|
|
|
|
* the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful, but
|
|
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
2012-02-27 13:01:10 +00:00
|
|
|
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
2010-12-18 20:38:49 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
2020-10-12 15:40:19 +00:00
|
|
|
#include "gdksurface-wayland.h"
|
2010-12-18 20:38:49 +00:00
|
|
|
|
2020-03-07 21:08:43 +00:00
|
|
|
#include "gdkdeviceprivate.h"
|
2010-12-18 20:38:49 +00:00
|
|
|
#include "gdkdisplay-wayland.h"
|
2020-03-07 21:08:43 +00:00
|
|
|
#include "gdkdragsurfaceprivate.h"
|
2021-09-24 19:49:38 +00:00
|
|
|
#include "gdkeventsprivate.h"
|
2019-04-22 01:14:46 +00:00
|
|
|
#include "gdkframeclockidleprivate.h"
|
2020-03-07 21:08:43 +00:00
|
|
|
#include "gdkglcontext-wayland.h"
|
|
|
|
#include "gdkmonitor-wayland.h"
|
|
|
|
#include "gdkpopupprivate.h"
|
2010-12-18 20:38:49 +00:00
|
|
|
#include "gdkprivate-wayland.h"
|
2023-04-29 03:07:03 +00:00
|
|
|
#include "gdkrectangleprivate.h"
|
2019-04-20 00:08:14 +00:00
|
|
|
#include "gdkseat-wayland.h"
|
2020-03-07 21:08:43 +00:00
|
|
|
#include "gdksurfaceprivate.h"
|
|
|
|
#include "gdktoplevelprivate.h"
|
2020-08-26 20:04:25 +00:00
|
|
|
#include "gdkdevice-wayland-private.h"
|
2023-10-28 01:47:30 +00:00
|
|
|
#include "gdkdmabuftextureprivate.h"
|
|
|
|
#include "gdksubsurfaceprivate.h"
|
|
|
|
#include "gdksubsurface-wayland-private.h"
|
2020-03-07 21:08:43 +00:00
|
|
|
|
2016-09-10 18:39:07 +00:00
|
|
|
#include <wayland/xdg-shell-unstable-v6-client-protocol.h>
|
2022-11-09 11:22:00 +00:00
|
|
|
#include <wayland/xdg-foreign-unstable-v2-client-protocol.h>
|
2010-12-18 20:38:49 +00:00
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
2012-04-19 16:18:46 +00:00
|
|
|
#include <errno.h>
|
2010-12-18 20:38:49 +00:00
|
|
|
|
2020-10-12 15:40:19 +00:00
|
|
|
#include <netinet/in.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
|
2022-11-10 14:27:04 +00:00
|
|
|
#include "gdksurface-wayland-private.h"
|
2023-01-06 18:53:27 +00:00
|
|
|
#include "gdktoplevel-wayland-private.h"
|
2022-11-10 14:27:04 +00:00
|
|
|
|
2023-10-28 01:47:30 +00:00
|
|
|
#include "linux-dmabuf-unstable-v1-client-protocol.h"
|
|
|
|
|
|
|
|
|
2021-02-21 15:40:24 +00:00
|
|
|
/**
|
|
|
|
* GdkWaylandSurface:
|
|
|
|
*
|
|
|
|
* The Wayland implementation of `GdkSurface`.
|
|
|
|
*
|
|
|
|
* Beyond the [class@Gdk.Surface] API, the Wayland implementation offers
|
|
|
|
* access to the Wayland `wl_surface` object with
|
|
|
|
* [method@GdkWayland.WaylandSurface.get_wl_surface].
|
|
|
|
*/
|
|
|
|
|
2020-03-17 14:23:57 +00:00
|
|
|
G_DEFINE_TYPE (GdkWaylandSurface, gdk_wayland_surface, GDK_TYPE_SURFACE)
|
|
|
|
|
2019-07-12 13:54:32 +00:00
|
|
|
static void gdk_wayland_surface_configure (GdkSurface *surface);
|
|
|
|
|
2023-01-06 18:44:18 +00:00
|
|
|
/* {{{ Utilities */
|
2020-11-24 15:05:26 +00:00
|
|
|
|
2010-12-18 20:38:49 +00:00
|
|
|
static void
|
2023-01-06 18:44:18 +00:00
|
|
|
fill_presentation_time_from_frame_time (GdkFrameTimings *timings,
|
|
|
|
guint32 frame_time)
|
2011-01-06 21:51:12 +00:00
|
|
|
{
|
2023-01-06 18:44:18 +00:00
|
|
|
/* The timestamp in a wayland frame is a msec time value that in some
|
|
|
|
* way reflects the time at which the server started drawing the frame.
|
|
|
|
* This is not useful from our perspective.
|
|
|
|
*
|
|
|
|
* However, for the DRM backend of Weston, on reasonably recent
|
|
|
|
* Linux, we know that the time is the
|
|
|
|
* clock_gettime (CLOCK_MONOTONIC) value at the vblank, and that
|
|
|
|
* backend starts drawing immediately after receiving the vblank
|
|
|
|
* notification. If we detect this, and make the assumption that the
|
|
|
|
* compositor will finish drawing before the next vblank, we can
|
|
|
|
* then determine the presentation time as the frame time we
|
|
|
|
* received plus one refresh interval.
|
|
|
|
*
|
|
|
|
* If a backend is using clock_gettime(CLOCK_MONOTONIC), but not
|
|
|
|
* picking values right at the vblank, then the presentation times
|
|
|
|
* we compute won't be accurate, but not really worse than then
|
|
|
|
* the alternative of not providing presentation times at all.
|
|
|
|
*
|
|
|
|
* The complexity here is dealing with the fact that we receive
|
|
|
|
* only the low 32 bits of the CLOCK_MONOTONIC value in milliseconds.
|
|
|
|
*/
|
|
|
|
gint64 now_monotonic = g_get_monotonic_time ();
|
|
|
|
gint64 now_monotonic_msec = now_monotonic / 1000;
|
|
|
|
uint32_t now_monotonic_low = (uint32_t)now_monotonic_msec;
|
|
|
|
|
|
|
|
if (frame_time - now_monotonic_low < 1000 ||
|
|
|
|
frame_time - now_monotonic_low > (uint32_t)-1000)
|
|
|
|
{
|
|
|
|
/* Timestamp we received is within one second of the current time.
|
|
|
|
*/
|
|
|
|
gint64 last_frame_time = now_monotonic + (gint64)1000 * (gint32)(frame_time - now_monotonic_low);
|
|
|
|
if ((gint32)now_monotonic_low < 0 && (gint32)frame_time > 0)
|
|
|
|
last_frame_time += (gint64)1000 * G_GINT64_CONSTANT(0x100000000);
|
|
|
|
else if ((gint32)now_monotonic_low > 0 && (gint32)frame_time < 0)
|
|
|
|
last_frame_time -= (gint64)1000 * G_GINT64_CONSTANT(0x100000000);
|
|
|
|
|
|
|
|
timings->presentation_time = last_frame_time + timings->refresh_interval;
|
|
|
|
}
|
2010-12-18 20:38:49 +00:00
|
|
|
}
|
|
|
|
|
2023-01-06 18:44:18 +00:00
|
|
|
static gboolean
|
|
|
|
is_realized_shell_surface (GdkWaylandSurface *impl)
|
|
|
|
{
|
|
|
|
return (impl->display_server.xdg_surface ||
|
|
|
|
impl->display_server.zxdg_surface_v6);
|
|
|
|
}
|
|
|
|
|
2022-11-17 13:24:40 +00:00
|
|
|
void
|
2023-01-06 18:53:27 +00:00
|
|
|
gdk_wayland_surface_get_window_geometry (GdkSurface *surface,
|
|
|
|
GdkRectangle *geometry)
|
|
|
|
{
|
|
|
|
GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
|
|
|
|
|
|
|
|
*geometry = (GdkRectangle) {
|
|
|
|
.x = impl->shadow_left,
|
|
|
|
.y = impl->shadow_top,
|
|
|
|
.width = surface->width - (impl->shadow_left + impl->shadow_right),
|
|
|
|
.height = surface->height - (impl->shadow_top + impl->shadow_bottom)
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct wl_region *
|
|
|
|
wl_region_from_cairo_region (GdkWaylandDisplay *display,
|
|
|
|
cairo_region_t *region)
|
|
|
|
{
|
|
|
|
struct wl_region *wl_region;
|
|
|
|
int i, n_rects;
|
|
|
|
|
|
|
|
wl_region = wl_compositor_create_region (display->compositor);
|
|
|
|
if (wl_region == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
n_rects = cairo_region_num_rectangles (region);
|
|
|
|
for (i = 0; i < n_rects; i++)
|
|
|
|
{
|
|
|
|
cairo_rectangle_int_t rect;
|
|
|
|
cairo_region_get_rectangle (region, i, &rect);
|
|
|
|
wl_region_add (wl_region, rect.x, rect.y, rect.width, rect.height);
|
|
|
|
}
|
|
|
|
|
|
|
|
return wl_region;
|
|
|
|
}
|
|
|
|
|
2023-01-06 18:44:18 +00:00
|
|
|
/* }}} */
|
2023-10-28 01:47:30 +00:00
|
|
|
/* {{{ Surface implementation */
|
2023-01-06 18:44:18 +00:00
|
|
|
|
|
|
|
static void
|
|
|
|
gdk_wayland_surface_init (GdkWaylandSurface *impl)
|
|
|
|
{
|
2023-04-01 11:40:14 +00:00
|
|
|
impl->scale = GDK_FRACTIONAL_SCALE_INIT_INT (1);
|
2023-04-01 12:41:30 +00:00
|
|
|
impl->viewport_dirty = TRUE;
|
2023-01-06 18:44:18 +00:00
|
|
|
}
|
|
|
|
|
2022-11-17 13:24:40 +00:00
|
|
|
void
|
2023-01-06 18:44:18 +00:00
|
|
|
gdk_wayland_surface_freeze_state (GdkSurface *surface)
|
|
|
|
{
|
|
|
|
GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
|
|
|
|
|
|
|
|
impl->state_freeze_count++;
|
|
|
|
}
|
|
|
|
|
2022-11-17 13:24:40 +00:00
|
|
|
void
|
2023-01-06 18:44:18 +00:00
|
|
|
gdk_wayland_surface_thaw_state (GdkSurface *surface)
|
|
|
|
{
|
|
|
|
GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
|
|
|
|
|
|
|
|
g_assert (impl->state_freeze_count > 0);
|
|
|
|
|
|
|
|
impl->state_freeze_count--;
|
|
|
|
|
|
|
|
if (impl->state_freeze_count > 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (impl->pending.is_dirty)
|
|
|
|
gdk_wayland_surface_configure (surface);
|
|
|
|
}
|
|
|
|
|
2023-04-02 14:24:37 +00:00
|
|
|
static inline void
|
|
|
|
get_egl_window_size (GdkSurface *surface,
|
|
|
|
int *width,
|
|
|
|
int *height)
|
|
|
|
{
|
|
|
|
GdkDisplay *display = gdk_surface_get_display (surface);
|
|
|
|
GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
|
|
|
|
|
2024-01-25 15:59:14 +00:00
|
|
|
if (GDK_DISPLAY_DEBUG_CHECK (display, GL_NO_FRACTIONAL))
|
2023-04-02 14:24:37 +00:00
|
|
|
{
|
2024-01-25 15:59:14 +00:00
|
|
|
GDK_DISPLAY_DEBUG (display, OPENGL, "Using integer scale %d for EGL window", gdk_fractional_scale_to_int (&impl->scale));
|
2023-04-02 14:24:37 +00:00
|
|
|
|
2024-01-25 15:59:14 +00:00
|
|
|
*width = surface->width * gdk_fractional_scale_to_int (&impl->scale);
|
|
|
|
*height = surface->height * gdk_fractional_scale_to_int (&impl->scale);
|
2023-04-02 14:24:37 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2024-01-25 15:59:14 +00:00
|
|
|
GDK_DISPLAY_DEBUG (display, OPENGL, "Using fractional scale %g for EGL window", gdk_fractional_scale_to_double (&impl->scale));
|
2023-04-02 14:24:37 +00:00
|
|
|
|
2024-01-25 15:59:14 +00:00
|
|
|
*width = gdk_fractional_scale_scale (&impl->scale, surface->width),
|
|
|
|
*height = gdk_fractional_scale_scale (&impl->scale, surface->height);
|
2023-04-02 14:24:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-11-10 14:27:04 +00:00
|
|
|
void
|
2023-04-01 11:40:14 +00:00
|
|
|
gdk_wayland_surface_update_size (GdkSurface *surface,
|
|
|
|
int32_t width,
|
|
|
|
int32_t height,
|
|
|
|
const GdkFractionalScale *scale)
|
2010-12-18 20:38:49 +00:00
|
|
|
{
|
2019-04-22 01:14:46 +00:00
|
|
|
GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
|
2023-04-02 17:23:19 +00:00
|
|
|
gboolean width_changed, height_changed, scale_changed, scale_factor_changed;
|
2010-12-18 20:38:49 +00:00
|
|
|
|
2021-01-16 20:17:08 +00:00
|
|
|
width_changed = surface->width != width;
|
|
|
|
height_changed = surface->height != height;
|
2023-04-01 11:40:14 +00:00
|
|
|
scale_changed = !gdk_fractional_scale_equal (&impl->scale, scale);
|
2023-04-02 17:23:19 +00:00
|
|
|
scale_factor_changed = gdk_fractional_scale_to_int (&impl->scale) != gdk_fractional_scale_to_int (scale);
|
2021-01-16 20:17:08 +00:00
|
|
|
|
|
|
|
if (!width_changed && !height_changed && !scale_changed)
|
2016-03-17 06:35:20 +00:00
|
|
|
return;
|
|
|
|
|
2018-03-20 14:14:10 +00:00
|
|
|
surface->width = width;
|
|
|
|
surface->height = height;
|
2023-04-01 11:40:14 +00:00
|
|
|
if (scale_changed)
|
|
|
|
{
|
|
|
|
impl->scale = *scale;
|
|
|
|
impl->buffer_scale_dirty = TRUE;
|
2023-04-01 12:41:30 +00:00
|
|
|
impl->viewport_dirty = TRUE;
|
2023-04-01 11:40:14 +00:00
|
|
|
}
|
2023-04-01 12:41:30 +00:00
|
|
|
if (width_changed || height_changed)
|
|
|
|
impl->viewport_dirty = TRUE;
|
2011-02-11 03:37:51 +00:00
|
|
|
|
2016-02-02 16:42:52 +00:00
|
|
|
if (impl->display_server.egl_window)
|
2023-04-02 14:24:37 +00:00
|
|
|
{
|
|
|
|
int w, h;
|
|
|
|
get_egl_window_size (surface, &w, &h);
|
|
|
|
wl_egl_window_resize (impl->display_server.egl_window, w, h, 0, 0);
|
|
|
|
}
|
2014-10-09 09:06:48 +00:00
|
|
|
|
2018-03-21 03:07:37 +00:00
|
|
|
gdk_surface_invalidate_rect (surface, NULL);
|
2021-01-16 20:17:08 +00:00
|
|
|
|
|
|
|
if (width_changed)
|
|
|
|
g_object_notify (G_OBJECT (surface), "width");
|
|
|
|
if (height_changed)
|
|
|
|
g_object_notify (G_OBJECT (surface), "height");
|
|
|
|
if (scale_changed)
|
2023-04-02 17:23:19 +00:00
|
|
|
g_object_notify (G_OBJECT (surface), "scale");
|
|
|
|
if (scale_factor_changed)
|
|
|
|
g_object_notify (G_OBJECT (surface), "scale-factor");
|
2021-03-09 18:50:56 +00:00
|
|
|
|
|
|
|
_gdk_surface_update_size (surface);
|
2010-12-18 20:38:49 +00:00
|
|
|
}
|
|
|
|
|
2023-11-10 13:26:10 +00:00
|
|
|
void
|
|
|
|
gdk_wayland_surface_frame_callback (GdkSurface *surface,
|
|
|
|
uint32_t time)
|
2013-04-24 22:14:22 +00:00
|
|
|
{
|
2019-04-22 01:14:46 +00:00
|
|
|
GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
|
2016-04-26 03:16:56 +00:00
|
|
|
GdkWaylandDisplay *display_wayland =
|
2018-03-20 14:14:10 +00:00
|
|
|
GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface));
|
|
|
|
GdkFrameClock *clock = gdk_surface_get_frame_clock (surface);
|
2013-04-24 22:14:22 +00:00
|
|
|
GdkFrameTimings *timings;
|
|
|
|
|
2024-01-21 18:58:09 +00:00
|
|
|
gdk_profiler_add_mark (GDK_PROFILER_CURRENT_TIME, 0, "Wayland frame event", NULL);
|
2022-09-23 00:50:05 +00:00
|
|
|
GDK_DISPLAY_DEBUG (GDK_DISPLAY (display_wayland), EVENTS, "frame %p", surface);
|
2015-02-28 05:15:13 +00:00
|
|
|
|
2023-04-28 20:21:42 +00:00
|
|
|
g_clear_pointer (&impl->frame_callback, wl_callback_destroy);
|
2015-02-25 13:46:54 +00:00
|
|
|
|
2023-11-10 13:26:10 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2023-01-06 21:35:16 +00:00
|
|
|
GDK_WAYLAND_SURFACE_GET_CLASS (impl)->handle_frame (impl);
|
2020-02-16 11:59:24 +00:00
|
|
|
|
2019-12-10 18:23:17 +00:00
|
|
|
if (impl->awaiting_frame_frozen)
|
|
|
|
{
|
|
|
|
impl->awaiting_frame_frozen = FALSE;
|
|
|
|
gdk_surface_thaw_updates (surface);
|
|
|
|
}
|
2013-04-24 22:14:22 +00:00
|
|
|
|
|
|
|
timings = gdk_frame_clock_get_timings (clock, impl->pending_frame_counter);
|
|
|
|
impl->pending_frame_counter = 0;
|
|
|
|
|
|
|
|
if (timings == NULL)
|
|
|
|
return;
|
|
|
|
|
2013-04-25 15:19:31 +00:00
|
|
|
timings->refresh_interval = 16667; /* default to 1/60th of a second */
|
2016-02-02 16:42:52 +00:00
|
|
|
if (impl->display_server.outputs)
|
2013-04-25 15:19:31 +00:00
|
|
|
{
|
2018-03-20 14:14:10 +00:00
|
|
|
/* We pick a random output out of the outputs that the surface touches
|
2013-04-25 15:19:31 +00:00
|
|
|
* The rate here is in milli-hertz */
|
2016-04-26 03:16:56 +00:00
|
|
|
int refresh_rate =
|
2017-11-01 23:25:45 +00:00
|
|
|
gdk_wayland_display_get_output_refresh_rate (display_wayland,
|
2016-04-26 03:16:56 +00:00
|
|
|
impl->display_server.outputs->data);
|
2013-04-25 15:19:31 +00:00
|
|
|
if (refresh_rate != 0)
|
|
|
|
timings->refresh_interval = G_GINT64_CONSTANT(1000000000) / refresh_rate;
|
|
|
|
}
|
|
|
|
|
2013-04-25 15:46:31 +00:00
|
|
|
fill_presentation_time_from_frame_time (timings, time);
|
|
|
|
|
2013-04-24 22:14:22 +00:00
|
|
|
timings->complete = TRUE;
|
|
|
|
|
|
|
|
if ((_gdk_debug_flags & GDK_DEBUG_FRAMES) != 0)
|
|
|
|
_gdk_frame_clock_debug_print_timings (clock, timings);
|
2019-05-16 19:08:34 +00:00
|
|
|
|
2020-02-12 10:05:01 +00:00
|
|
|
if (GDK_PROFILER_IS_RUNNING)
|
2019-05-16 19:08:34 +00:00
|
|
|
_gdk_frame_clock_add_timings_to_profiler (clock, timings);
|
2013-04-24 22:14:22 +00:00
|
|
|
}
|
|
|
|
|
2023-11-10 13:26:10 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2014-06-21 21:33:09 +00:00
|
|
|
static const struct wl_callback_listener frame_listener = {
|
2013-04-24 22:14:22 +00:00
|
|
|
frame_callback
|
|
|
|
};
|
|
|
|
|
|
|
|
static void
|
|
|
|
on_frame_clock_before_paint (GdkFrameClock *clock,
|
2018-03-20 14:14:10 +00:00
|
|
|
GdkSurface *surface)
|
2013-04-24 22:14:22 +00:00
|
|
|
{
|
2013-04-25 15:46:31 +00:00
|
|
|
GdkFrameTimings *timings = gdk_frame_clock_get_current_timings (clock);
|
|
|
|
gint64 presentation_time;
|
|
|
|
gint64 refresh_interval;
|
|
|
|
|
2018-03-20 14:14:10 +00:00
|
|
|
if (surface->update_freeze_count > 0)
|
2016-07-01 09:03:36 +00:00
|
|
|
return;
|
|
|
|
|
2013-04-25 15:46:31 +00:00
|
|
|
gdk_frame_clock_get_refresh_info (clock,
|
|
|
|
timings->frame_time,
|
|
|
|
&refresh_interval, &presentation_time);
|
|
|
|
|
|
|
|
if (presentation_time != 0)
|
|
|
|
{
|
|
|
|
/* Assume the algorithm used by the DRM backend of Weston - it
|
|
|
|
* starts drawing at the next vblank after receiving the commit
|
|
|
|
* for this frame, and presentation occurs at the vblank
|
|
|
|
* after that.
|
|
|
|
*/
|
|
|
|
timings->predicted_presentation_time = presentation_time + refresh_interval;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* As above, but we don't actually know the phase of the vblank,
|
|
|
|
* so just assume that we're half way through a refresh cycle.
|
|
|
|
*/
|
|
|
|
timings->predicted_presentation_time = timings->frame_time + refresh_interval / 2 + refresh_interval;
|
|
|
|
}
|
2020-11-23 16:26:06 +00:00
|
|
|
|
|
|
|
gdk_surface_apply_state_change (surface);
|
2013-04-24 22:14:22 +00:00
|
|
|
}
|
|
|
|
|
2020-12-02 10:50:55 +00:00
|
|
|
static void
|
|
|
|
gdk_wayland_surface_request_layout (GdkSurface *surface)
|
|
|
|
{
|
|
|
|
GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
|
|
|
|
|
|
|
|
impl->next_layout.surface_geometry_dirty = TRUE;
|
|
|
|
}
|
|
|
|
|
2018-04-10 13:10:56 +00:00
|
|
|
void
|
|
|
|
gdk_wayland_surface_request_frame (GdkSurface *surface)
|
|
|
|
{
|
2023-04-28 20:21:42 +00:00
|
|
|
GdkWaylandSurface *self = GDK_WAYLAND_SURFACE (surface);
|
2018-04-10 13:10:56 +00:00
|
|
|
GdkFrameClock *clock;
|
|
|
|
|
2023-05-09 12:41:24 +00:00
|
|
|
if (self->frame_callback != NULL)
|
|
|
|
return;
|
2018-04-10 13:10:56 +00:00
|
|
|
|
|
|
|
clock = gdk_surface_get_frame_clock (surface);
|
|
|
|
|
2023-04-28 20:21:42 +00:00
|
|
|
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);
|
2023-11-10 13:26:10 +00:00
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2023-04-28 20:21:42 +00:00
|
|
|
self->pending_frame_counter = gdk_frame_clock_get_frame_counter (clock);
|
2018-04-10 13:10:56 +00:00
|
|
|
}
|
|
|
|
|
2020-11-19 09:54:20 +00:00
|
|
|
gboolean
|
|
|
|
gdk_wayland_surface_has_surface (GdkSurface *surface)
|
|
|
|
{
|
|
|
|
GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
|
|
|
|
|
|
|
|
return !!impl->display_server.wl_surface;
|
|
|
|
}
|
|
|
|
|
2020-09-17 15:35:35 +00:00
|
|
|
void
|
|
|
|
gdk_wayland_surface_commit (GdkSurface *surface)
|
|
|
|
{
|
|
|
|
GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
|
|
|
|
|
|
|
|
wl_surface_commit (impl->display_server.wl_surface);
|
|
|
|
}
|
|
|
|
|
2020-09-17 16:20:08 +00:00
|
|
|
void
|
|
|
|
gdk_wayland_surface_notify_committed (GdkSurface *surface)
|
|
|
|
{
|
|
|
|
GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
|
|
|
|
|
|
|
|
impl->has_uncommitted_ack_configure = FALSE;
|
2023-10-28 01:47:30 +00:00
|
|
|
impl->has_pending_subsurface_commits = FALSE;
|
2020-09-17 16:20:08 +00:00
|
|
|
}
|
|
|
|
|
2013-04-24 22:14:22 +00:00
|
|
|
static void
|
|
|
|
on_frame_clock_after_paint (GdkFrameClock *clock,
|
2018-04-13 00:13:27 +00:00
|
|
|
GdkSurface *surface)
|
2013-04-24 22:14:22 +00:00
|
|
|
{
|
2019-04-22 01:14:46 +00:00
|
|
|
GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
|
2013-04-24 22:14:22 +00:00
|
|
|
|
2023-10-28 01:47:30 +00:00
|
|
|
if (surface->update_freeze_count == 0 &&
|
|
|
|
(impl->has_uncommitted_ack_configure ||
|
|
|
|
impl->has_pending_subsurface_commits))
|
2020-09-17 16:20:08 +00:00
|
|
|
{
|
|
|
|
gdk_wayland_surface_commit (surface);
|
|
|
|
gdk_wayland_surface_notify_committed (surface);
|
|
|
|
}
|
|
|
|
|
2023-04-28 20:21:42 +00:00
|
|
|
if (impl->frame_callback &&
|
2019-06-28 16:45:44 +00:00
|
|
|
impl->pending_frame_counter == gdk_frame_clock_get_frame_counter (clock))
|
2019-12-10 18:23:17 +00:00
|
|
|
{
|
2023-04-28 20:21:42 +00:00
|
|
|
g_assert (!impl->awaiting_frame_frozen);
|
2019-12-10 18:23:17 +00:00
|
|
|
impl->awaiting_frame_frozen = TRUE;
|
|
|
|
gdk_surface_freeze_updates (surface);
|
|
|
|
}
|
2013-04-24 22:14:22 +00:00
|
|
|
}
|
|
|
|
|
2017-11-01 01:48:58 +00:00
|
|
|
void
|
2018-03-20 14:14:10 +00:00
|
|
|
gdk_wayland_surface_update_scale (GdkSurface *surface)
|
2013-06-04 09:39:36 +00:00
|
|
|
{
|
2019-04-22 01:14:46 +00:00
|
|
|
GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
|
2018-03-20 14:14:10 +00:00
|
|
|
GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface));
|
2013-06-04 09:39:36 +00:00
|
|
|
guint32 scale;
|
|
|
|
GSList *l;
|
|
|
|
|
2023-04-01 10:48:26 +00:00
|
|
|
/* We can't set the scale on this surface */
|
2023-03-31 23:39:47 +00:00
|
|
|
if (!impl->display_server.wl_surface ||
|
|
|
|
wl_surface_get_version (impl->display_server.wl_surface) < WL_SURFACE_SET_BUFFER_SCALE_SINCE_VERSION)
|
2023-04-01 10:48:26 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
/* scale is tracked by the fractional scale extension */
|
|
|
|
if (impl->display_server.fractional_scale)
|
|
|
|
return;
|
2013-07-12 14:49:52 +00:00
|
|
|
|
2022-01-07 18:28:36 +00:00
|
|
|
if (!impl->display_server.outputs)
|
2023-04-01 11:40:14 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
scale = 1;
|
|
|
|
for (l = impl->display_server.outputs; l != NULL; l = l->next)
|
2013-06-04 09:39:36 +00:00
|
|
|
{
|
2023-04-01 11:40:14 +00:00
|
|
|
struct wl_output *output = l->data;
|
|
|
|
uint32_t output_scale;
|
2022-01-07 18:28:36 +00:00
|
|
|
|
2023-04-01 11:40:14 +00:00
|
|
|
output_scale = gdk_wayland_display_get_output_scale (display_wayland,
|
|
|
|
output);
|
|
|
|
scale = MAX (scale, output_scale);
|
2013-06-04 09:39:36 +00:00
|
|
|
}
|
|
|
|
|
2015-02-24 08:11:48 +00:00
|
|
|
/* Notify app that scale changed */
|
2023-04-13 00:47:51 +00:00
|
|
|
gdk_wayland_surface_update_size (surface,
|
|
|
|
surface->width, surface->height,
|
|
|
|
&GDK_FRACTIONAL_SCALE_INIT_INT (scale));
|
2013-06-04 09:39:36 +00:00
|
|
|
}
|
|
|
|
|
2018-04-17 21:05:41 +00:00
|
|
|
void
|
|
|
|
gdk_wayland_surface_attach_image (GdkSurface *surface,
|
|
|
|
cairo_surface_t *cairo_surface,
|
|
|
|
const cairo_region_t *damage)
|
2011-01-08 01:49:40 +00:00
|
|
|
{
|
2019-04-22 01:14:46 +00:00
|
|
|
GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
|
2018-04-17 21:05:41 +00:00
|
|
|
cairo_rectangle_int_t rect;
|
2023-04-29 03:07:03 +00:00
|
|
|
uint32_t wl_surface_version;
|
2018-04-17 21:05:41 +00:00
|
|
|
int i, n;
|
2010-12-18 20:38:49 +00:00
|
|
|
|
2018-03-20 14:14:10 +00:00
|
|
|
if (GDK_SURFACE_DESTROYED (surface))
|
2011-01-08 01:49:40 +00:00
|
|
|
return;
|
|
|
|
|
2018-04-17 21:05:41 +00:00
|
|
|
g_assert (_gdk_wayland_is_shm_surface (cairo_surface));
|
2015-02-24 10:10:07 +00:00
|
|
|
|
2023-04-29 03:07:03 +00:00
|
|
|
wl_surface_version = wl_surface_get_version (impl->display_server.wl_surface);
|
|
|
|
|
2012-03-06 21:24:20 +00:00
|
|
|
/* Attach this new buffer to the surface */
|
2016-02-02 16:42:52 +00:00
|
|
|
wl_surface_attach (impl->display_server.wl_surface,
|
2018-04-17 21:05:41 +00:00
|
|
|
_gdk_wayland_shm_surface_get_wl_buffer (cairo_surface),
|
2023-03-07 04:50:08 +00:00
|
|
|
0, 0);
|
|
|
|
|
|
|
|
if ((impl->pending_buffer_offset_x || impl->pending_buffer_offset_y) &&
|
2023-04-29 03:07:03 +00:00
|
|
|
wl_surface_version >= WL_SURFACE_OFFSET_SINCE_VERSION)
|
2023-03-07 04:50:08 +00:00
|
|
|
wl_surface_offset (impl->display_server.wl_surface,
|
|
|
|
impl->pending_buffer_offset_x,
|
|
|
|
impl->pending_buffer_offset_y);
|
2015-12-08 10:19:33 +00:00
|
|
|
impl->pending_buffer_offset_x = 0;
|
|
|
|
impl->pending_buffer_offset_y = 0;
|
2013-07-12 14:49:52 +00:00
|
|
|
|
2018-04-17 21:05:41 +00:00
|
|
|
n = cairo_region_num_rectangles (damage);
|
|
|
|
for (i = 0; i < n; i++)
|
wayland: stage uncommitted changes to dedicated buffer
Right now we use one buffer for both staged changes (freshly painted
changes waiting for the frame clock to send to the compositor) and
committed changes (changes actively being read by the compositor
process). This creates a problem in the event we need to stage updates
at the same time the compositor is processing committed updates: we
can't change what the compositor is actively processing.
The current solution for handling this contention is to allocate a
temporary buffer on the spot at the time the updates are staged, and to
copy that buffer back to the shared buffer later. The problem, though,
is that the copy to the shared buffer currently happens as soon as
the updates are finished being staged, not when the shared buffer is
done being processed by the compositor.
In order to address that problem, this commit changes the code to always
stage changes to a dedicated staging buffer. The staging buffer is
used exclusively by the client until the client is done with it, and then
once that staging buffer is committed, the client never writes to that
buffer again. If the client needs to stage new updates, it allocates a
brand new staging buffer, draws to it, and back fills the undrawn parts
of the buffer from a copy of the contents of the committed buffer.
As an optimization, the compositor has the option of releasing the
committed buffer back to the client. If it does so before the client
needs to stage new updates, then the client will reuse the buffer
for staging future updates. This optimization prevents having to allocate
a new staging buffer and the associated cost of back filling
that new buffer with a readback of the committed buffer.
https://bugzilla.gnome.org/show_bug.cgi?id=761312
2016-01-29 16:19:03 +00:00
|
|
|
{
|
2018-04-17 21:05:41 +00:00
|
|
|
cairo_region_get_rectangle (damage, i, &rect);
|
2023-04-29 03:07:03 +00:00
|
|
|
if (wl_surface_version >= WL_SURFACE_DAMAGE_BUFFER_SINCE_VERSION)
|
|
|
|
{
|
|
|
|
float scale = gdk_surface_get_scale (surface);
|
|
|
|
gdk_rectangle_transform_affine (&rect, scale, scale, 0, 0, &rect);
|
|
|
|
wl_surface_damage_buffer (impl->display_server.wl_surface, rect.x, rect.y, rect.width, rect.height);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
wl_surface_damage (impl->display_server.wl_surface, rect.x, rect.y, rect.width, rect.height);
|
|
|
|
}
|
wayland: stage uncommitted changes to dedicated buffer
Right now we use one buffer for both staged changes (freshly painted
changes waiting for the frame clock to send to the compositor) and
committed changes (changes actively being read by the compositor
process). This creates a problem in the event we need to stage updates
at the same time the compositor is processing committed updates: we
can't change what the compositor is actively processing.
The current solution for handling this contention is to allocate a
temporary buffer on the spot at the time the updates are staged, and to
copy that buffer back to the shared buffer later. The problem, though,
is that the copy to the shared buffer currently happens as soon as
the updates are finished being staged, not when the shared buffer is
done being processed by the compositor.
In order to address that problem, this commit changes the code to always
stage changes to a dedicated staging buffer. The staging buffer is
used exclusively by the client until the client is done with it, and then
once that staging buffer is committed, the client never writes to that
buffer again. If the client needs to stage new updates, it allocates a
brand new staging buffer, draws to it, and back fills the undrawn parts
of the buffer from a copy of the contents of the committed buffer.
As an optimization, the compositor has the option of releasing the
committed buffer back to the client. If it does so before the client
needs to stage new updates, then the client will reuse the buffer
for staging future updates. This optimization prevents having to allocate
a new staging buffer and the associated cost of back filling
that new buffer with a readback of the committed buffer.
https://bugzilla.gnome.org/show_bug.cgi?id=761312
2016-01-29 16:19:03 +00:00
|
|
|
}
|
2016-12-06 17:01:34 +00:00
|
|
|
}
|
|
|
|
|
2016-03-07 04:41:31 +00:00
|
|
|
static gboolean
|
2019-04-22 01:14:46 +00:00
|
|
|
gdk_wayland_surface_beep (GdkSurface *surface)
|
2016-03-07 04:41:31 +00:00
|
|
|
{
|
2023-01-06 18:44:18 +00:00
|
|
|
gdk_wayland_display_system_bell (gdk_surface_get_display (surface), surface);
|
2016-03-07 04:41:31 +00:00
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2020-01-07 16:13:22 +00:00
|
|
|
static void
|
|
|
|
gdk_wayland_surface_dispose (GObject *object)
|
|
|
|
{
|
|
|
|
GdkSurface *surface = GDK_SURFACE (object);
|
|
|
|
GdkWaylandSurface *impl;
|
|
|
|
|
|
|
|
g_return_if_fail (GDK_IS_WAYLAND_SURFACE (surface));
|
|
|
|
|
|
|
|
impl = GDK_WAYLAND_SURFACE (surface);
|
|
|
|
|
|
|
|
if (impl->event_queue)
|
|
|
|
{
|
|
|
|
GdkWaylandDisplay *display_wayland =
|
|
|
|
GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface));
|
|
|
|
|
|
|
|
display_wayland->event_queues =
|
2023-04-16 02:36:12 +00:00
|
|
|
g_list_remove (display_wayland->event_queues, impl->event_queue);
|
2020-01-07 16:13:22 +00:00
|
|
|
g_clear_pointer (&impl->event_queue, wl_event_queue_destroy);
|
|
|
|
}
|
|
|
|
|
|
|
|
G_OBJECT_CLASS (gdk_wayland_surface_parent_class)->dispose (object);
|
|
|
|
}
|
|
|
|
|
2012-04-04 13:05:27 +00:00
|
|
|
static void
|
2019-04-22 01:14:46 +00:00
|
|
|
gdk_wayland_surface_finalize (GObject *object)
|
2012-04-04 13:05:27 +00:00
|
|
|
{
|
2019-04-22 01:14:46 +00:00
|
|
|
GdkWaylandSurface *impl;
|
2012-04-04 13:05:27 +00:00
|
|
|
|
2019-04-22 01:14:46 +00:00
|
|
|
g_return_if_fail (GDK_IS_WAYLAND_SURFACE (object));
|
2012-04-04 13:05:27 +00:00
|
|
|
|
2019-04-22 01:14:46 +00:00
|
|
|
impl = GDK_WAYLAND_SURFACE (object);
|
2012-04-04 13:05:27 +00:00
|
|
|
|
2014-03-17 20:08:35 +00:00
|
|
|
g_clear_pointer (&impl->opaque_region, cairo_region_destroy);
|
2014-03-17 20:02:47 +00:00
|
|
|
g_clear_pointer (&impl->input_region, cairo_region_destroy);
|
2017-03-22 09:21:02 +00:00
|
|
|
|
2019-04-22 01:14:46 +00:00
|
|
|
G_OBJECT_CLASS (gdk_wayland_surface_parent_class)->finalize (object);
|
2012-04-04 13:05:27 +00:00
|
|
|
}
|
|
|
|
|
2014-02-27 21:54:20 +00:00
|
|
|
static void
|
2020-12-02 16:08:43 +00:00
|
|
|
gdk_wayland_surface_sync_shadow (GdkSurface *surface)
|
2014-02-27 21:54:20 +00:00
|
|
|
{
|
2019-04-22 01:14:46 +00:00
|
|
|
GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
|
2023-01-06 18:44:18 +00:00
|
|
|
GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface));
|
2016-07-01 09:02:11 +00:00
|
|
|
GdkRectangle geometry;
|
2014-02-27 21:54:20 +00:00
|
|
|
|
2020-09-19 17:05:57 +00:00
|
|
|
if (!is_realized_shell_surface (impl))
|
2014-02-27 21:54:20 +00:00
|
|
|
return;
|
|
|
|
|
2018-03-20 14:14:10 +00:00
|
|
|
gdk_wayland_surface_get_window_geometry (surface, &geometry);
|
2022-11-15 11:50:02 +00:00
|
|
|
if (GDK_IS_WAYLAND_TOPLEVEL (impl))
|
|
|
|
{
|
|
|
|
GdkWaylandToplevel *toplevel = GDK_WAYLAND_TOPLEVEL (impl);
|
2023-01-06 18:44:18 +00:00
|
|
|
gdk_wayland_toplevel_set_geometry_hints (toplevel, NULL, 0);
|
2022-11-15 11:50:02 +00:00
|
|
|
}
|
2017-12-18 12:00:36 +00:00
|
|
|
|
2020-07-30 21:06:59 +00:00
|
|
|
if (gdk_rectangle_equal (&geometry, &impl->last_sent_window_geometry))
|
|
|
|
return;
|
|
|
|
|
2017-12-18 12:00:36 +00:00
|
|
|
switch (display_wayland->shell_variant)
|
|
|
|
{
|
|
|
|
case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL:
|
|
|
|
xdg_surface_set_window_geometry (impl->display_server.xdg_surface,
|
2016-07-01 09:03:36 +00:00
|
|
|
geometry.x,
|
|
|
|
geometry.y,
|
|
|
|
geometry.width,
|
|
|
|
geometry.height);
|
2017-12-18 12:00:36 +00:00
|
|
|
break;
|
|
|
|
case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6:
|
|
|
|
zxdg_surface_v6_set_window_geometry (impl->display_server.zxdg_surface_v6,
|
|
|
|
geometry.x,
|
|
|
|
geometry.y,
|
|
|
|
geometry.width,
|
|
|
|
geometry.height);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
g_assert_not_reached ();
|
|
|
|
}
|
2020-07-30 21:06:59 +00:00
|
|
|
|
|
|
|
impl->last_sent_window_geometry = geometry;
|
2014-02-27 21:54:20 +00:00
|
|
|
}
|
|
|
|
|
2014-03-17 20:08:35 +00:00
|
|
|
static void
|
2018-03-20 14:14:10 +00:00
|
|
|
gdk_wayland_surface_sync_opaque_region (GdkSurface *surface)
|
2014-03-17 20:08:35 +00:00
|
|
|
{
|
2019-04-22 01:14:46 +00:00
|
|
|
GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
|
2014-03-17 20:08:35 +00:00
|
|
|
struct wl_region *wl_region = NULL;
|
|
|
|
|
2016-02-02 16:42:52 +00:00
|
|
|
if (!impl->display_server.wl_surface)
|
2014-03-17 20:08:35 +00:00
|
|
|
return;
|
|
|
|
|
2016-07-01 08:48:16 +00:00
|
|
|
if (!impl->opaque_region_dirty)
|
|
|
|
return;
|
|
|
|
|
2014-03-17 20:08:35 +00:00
|
|
|
if (impl->opaque_region != NULL)
|
2023-10-28 01:47:30 +00:00
|
|
|
{
|
|
|
|
if (gdk_surface_get_n_subsurfaces (surface) > 0)
|
|
|
|
{
|
|
|
|
cairo_region_t *region = cairo_region_copy (impl->opaque_region);
|
|
|
|
for (gsize i = 0; i < gdk_surface_get_n_subsurfaces (surface); i++)
|
|
|
|
{
|
2024-02-07 11:18:57 +00:00
|
|
|
GdkSubsurface *subsurface = gdk_surface_get_subsurface (surface, i);
|
|
|
|
GdkWaylandSubsurface *sub = (GdkWaylandSubsurface *) subsurface;
|
|
|
|
|
|
|
|
if (subsurface->above_parent)
|
2023-12-04 21:12:40 +00:00
|
|
|
continue;
|
2024-02-07 11:18:57 +00:00
|
|
|
|
2023-10-28 01:47:30 +00:00
|
|
|
if (sub->texture != NULL)
|
|
|
|
cairo_region_subtract_rectangle (region, &sub->dest);
|
|
|
|
}
|
|
|
|
|
|
|
|
wl_region = wl_region_from_cairo_region (GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface)),
|
|
|
|
region);
|
|
|
|
cairo_region_destroy (region);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
wl_region = wl_region_from_cairo_region (GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface)),
|
|
|
|
impl->opaque_region);
|
|
|
|
}
|
2014-03-17 20:08:35 +00:00
|
|
|
|
2017-08-23 14:40:12 +00:00
|
|
|
wl_surface_set_opaque_region (impl->display_server.wl_surface, wl_region);
|
2014-03-17 20:08:35 +00:00
|
|
|
|
|
|
|
if (wl_region != NULL)
|
|
|
|
wl_region_destroy (wl_region);
|
2016-07-01 08:48:16 +00:00
|
|
|
|
|
|
|
impl->opaque_region_dirty = FALSE;
|
2014-03-17 20:08:35 +00:00
|
|
|
}
|
|
|
|
|
2014-03-17 20:02:47 +00:00
|
|
|
static void
|
2018-03-20 14:14:10 +00:00
|
|
|
gdk_wayland_surface_sync_input_region (GdkSurface *surface)
|
2014-03-17 20:02:47 +00:00
|
|
|
{
|
2019-04-22 01:14:46 +00:00
|
|
|
GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
|
2014-03-17 20:02:47 +00:00
|
|
|
struct wl_region *wl_region = NULL;
|
|
|
|
|
2016-02-02 16:42:52 +00:00
|
|
|
if (!impl->display_server.wl_surface)
|
2014-03-17 20:02:47 +00:00
|
|
|
return;
|
|
|
|
|
2016-07-01 08:48:16 +00:00
|
|
|
if (!impl->input_region_dirty)
|
|
|
|
return;
|
|
|
|
|
2014-03-17 20:02:47 +00:00
|
|
|
if (impl->input_region != NULL)
|
2018-03-20 14:14:10 +00:00
|
|
|
wl_region = wl_region_from_cairo_region (GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface)),
|
2014-03-17 20:02:47 +00:00
|
|
|
impl->input_region);
|
|
|
|
|
2016-02-02 16:42:52 +00:00
|
|
|
wl_surface_set_input_region (impl->display_server.wl_surface, wl_region);
|
2014-03-17 20:02:47 +00:00
|
|
|
|
|
|
|
if (wl_region != NULL)
|
|
|
|
wl_region_destroy (wl_region);
|
2016-07-01 08:48:16 +00:00
|
|
|
|
|
|
|
impl->input_region_dirty = FALSE;
|
2014-03-17 20:02:47 +00:00
|
|
|
}
|
|
|
|
|
2023-03-21 23:04:56 +00:00
|
|
|
static void
|
|
|
|
gdk_wayland_surface_sync_buffer_scale (GdkSurface *surface)
|
|
|
|
{
|
2023-04-01 12:41:30 +00:00
|
|
|
GdkWaylandSurface *self = GDK_WAYLAND_SURFACE (surface);
|
2023-03-21 23:04:56 +00:00
|
|
|
|
2023-04-01 12:41:30 +00:00
|
|
|
if (!self->display_server.wl_surface)
|
2023-03-21 23:04:56 +00:00
|
|
|
return;
|
|
|
|
|
2023-04-01 12:41:30 +00:00
|
|
|
if (!self->buffer_scale_dirty)
|
2023-03-21 23:04:56 +00:00
|
|
|
return;
|
|
|
|
|
2023-04-01 12:41:30 +00:00
|
|
|
if (self->display_server.viewport)
|
|
|
|
{
|
|
|
|
/* The viewport takes care of buffer scale */
|
|
|
|
}
|
|
|
|
else if (wl_surface_get_version (self->display_server.wl_surface) >= WL_SURFACE_SET_BUFFER_SCALE_SINCE_VERSION)
|
|
|
|
{
|
|
|
|
wl_surface_set_buffer_scale (self->display_server.wl_surface,
|
|
|
|
gdk_fractional_scale_to_int (&self->scale));
|
|
|
|
}
|
2023-03-21 23:04:56 +00:00
|
|
|
|
2023-04-01 12:41:30 +00:00
|
|
|
self->buffer_scale_dirty = FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gdk_wayland_surface_sync_viewport (GdkSurface *surface)
|
|
|
|
{
|
|
|
|
GdkWaylandSurface *self = GDK_WAYLAND_SURFACE (surface);
|
|
|
|
|
|
|
|
if (!self->display_server.viewport)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!self->viewport_dirty)
|
|
|
|
return;
|
|
|
|
|
|
|
|
wp_viewport_set_destination (self->display_server.viewport,
|
|
|
|
surface->width,
|
|
|
|
surface->height);
|
|
|
|
|
|
|
|
self->viewport_dirty = FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gdk_wayland_surface_sync (GdkSurface *surface)
|
|
|
|
{
|
|
|
|
gdk_wayland_surface_sync_shadow (surface);
|
|
|
|
gdk_wayland_surface_sync_opaque_region (surface);
|
|
|
|
gdk_wayland_surface_sync_input_region (surface);
|
|
|
|
gdk_wayland_surface_sync_buffer_scale (surface);
|
|
|
|
gdk_wayland_surface_sync_viewport (surface);
|
2023-03-21 23:04:56 +00:00
|
|
|
}
|
|
|
|
|
2024-01-28 13:37:49 +00:00
|
|
|
gboolean
|
|
|
|
gdk_wayland_surface_needs_commit (GdkSurface *surface)
|
|
|
|
{
|
|
|
|
GdkWaylandSurface *self = GDK_WAYLAND_SURFACE (surface);
|
|
|
|
|
|
|
|
return self->has_pending_subsurface_commits ||
|
|
|
|
self->opaque_region_dirty ||
|
|
|
|
self->input_region_dirty ||
|
|
|
|
self->buffer_scale_dirty ||
|
|
|
|
self->viewport_dirty;
|
|
|
|
}
|
|
|
|
|
2023-04-01 10:48:26 +00:00
|
|
|
static void
|
|
|
|
gdk_wayland_surface_fractional_scale_preferred_scale_cb (void *data,
|
|
|
|
struct wp_fractional_scale_v1 *fractional_scale,
|
|
|
|
uint32_t scale)
|
|
|
|
{
|
|
|
|
GdkWaylandSurface *self = GDK_WAYLAND_SURFACE (data);
|
|
|
|
GdkSurface *surface = GDK_SURFACE (self);
|
|
|
|
|
|
|
|
/* Notify app that scale changed */
|
2023-04-13 00:47:51 +00:00
|
|
|
gdk_wayland_surface_update_size (surface,
|
|
|
|
surface->width, surface->height,
|
|
|
|
&GDK_FRACTIONAL_SCALE_INIT (scale));
|
2023-04-01 10:48:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static const struct wp_fractional_scale_v1_listener fractional_scale_listener = {
|
|
|
|
gdk_wayland_surface_fractional_scale_preferred_scale_cb,
|
|
|
|
};
|
|
|
|
|
2013-04-25 15:19:31 +00:00
|
|
|
static void
|
2013-09-16 21:23:29 +00:00
|
|
|
surface_enter (void *data,
|
2013-04-25 15:19:31 +00:00
|
|
|
struct wl_surface *wl_surface,
|
2013-09-16 21:23:29 +00:00
|
|
|
struct wl_output *output)
|
2013-04-25 15:19:31 +00:00
|
|
|
{
|
2018-03-20 14:14:10 +00:00
|
|
|
GdkSurface *surface = GDK_SURFACE (data);
|
2019-04-22 01:14:46 +00:00
|
|
|
GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
|
2017-11-29 03:37:42 +00:00
|
|
|
GdkDisplay *display = gdk_surface_get_display (surface);
|
|
|
|
GdkMonitor *monitor;
|
2013-04-25 15:19:31 +00:00
|
|
|
|
2022-09-23 00:50:05 +00:00
|
|
|
GDK_DISPLAY_DEBUG(gdk_surface_get_display (surface), EVENTS,
|
|
|
|
"surface enter, surface %p output %p", surface, output);
|
2015-02-28 05:15:13 +00:00
|
|
|
|
2016-02-02 16:42:52 +00:00
|
|
|
impl->display_server.outputs = g_slist_prepend (impl->display_server.outputs, output);
|
2013-06-04 09:39:36 +00:00
|
|
|
|
2018-03-20 14:14:10 +00:00
|
|
|
gdk_wayland_surface_update_scale (surface);
|
2017-11-29 03:37:42 +00:00
|
|
|
|
|
|
|
monitor = gdk_wayland_display_get_monitor_for_output (display, output);
|
|
|
|
gdk_surface_enter_monitor (surface, monitor);
|
2013-04-25 15:19:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2013-09-16 21:23:29 +00:00
|
|
|
surface_leave (void *data,
|
2013-04-25 15:19:31 +00:00
|
|
|
struct wl_surface *wl_surface,
|
2013-09-16 21:23:29 +00:00
|
|
|
struct wl_output *output)
|
2013-04-25 15:19:31 +00:00
|
|
|
{
|
2018-03-20 14:14:10 +00:00
|
|
|
GdkSurface *surface = GDK_SURFACE (data);
|
2019-04-22 01:14:46 +00:00
|
|
|
GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
|
2017-11-29 03:37:42 +00:00
|
|
|
GdkDisplay *display = gdk_surface_get_display (surface);
|
|
|
|
GdkMonitor *monitor;
|
2013-04-25 15:19:31 +00:00
|
|
|
|
2022-09-23 00:50:05 +00:00
|
|
|
GDK_DISPLAY_DEBUG (gdk_surface_get_display (surface), EVENTS,
|
|
|
|
"surface leave, surface %p output %p", surface, output);
|
2015-02-28 05:15:13 +00:00
|
|
|
|
2016-02-02 16:42:52 +00:00
|
|
|
impl->display_server.outputs = g_slist_remove (impl->display_server.outputs, output);
|
2013-06-04 09:39:36 +00:00
|
|
|
|
2016-11-15 14:07:39 +00:00
|
|
|
if (impl->display_server.outputs)
|
2018-03-20 14:14:10 +00:00
|
|
|
gdk_wayland_surface_update_scale (surface);
|
2017-11-29 03:37:42 +00:00
|
|
|
|
|
|
|
monitor = gdk_wayland_display_get_monitor_for_output (display, output);
|
|
|
|
gdk_surface_leave_monitor (surface, monitor);
|
2013-04-25 15:19:31 +00:00
|
|
|
}
|
|
|
|
|
2013-11-11 23:02:19 +00:00
|
|
|
static const struct wl_surface_listener surface_listener = {
|
|
|
|
surface_enter,
|
|
|
|
surface_leave
|
|
|
|
};
|
|
|
|
|
2023-04-13 01:33:59 +00:00
|
|
|
static void
|
2022-11-10 14:27:04 +00:00
|
|
|
gdk_wayland_surface_create_wl_surface (GdkSurface *surface)
|
2013-11-11 23:02:19 +00:00
|
|
|
{
|
2023-04-01 10:48:26 +00:00
|
|
|
GdkWaylandSurface *self = GDK_WAYLAND_SURFACE (surface);
|
2018-03-20 14:14:10 +00:00
|
|
|
GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface));
|
2020-01-07 16:13:22 +00:00
|
|
|
struct wl_surface *wl_surface;
|
|
|
|
|
|
|
|
wl_surface = wl_compositor_create_surface (display_wayland->compositor);
|
2023-04-01 10:48:26 +00:00
|
|
|
wl_proxy_set_queue ((struct wl_proxy *) wl_surface, self->event_queue);
|
|
|
|
wl_surface_add_listener (wl_surface, &surface_listener, self);
|
|
|
|
if (display_wayland->fractional_scale)
|
|
|
|
{
|
|
|
|
self->display_server.fractional_scale =
|
|
|
|
wp_fractional_scale_manager_v1_get_fractional_scale (display_wayland->fractional_scale,
|
|
|
|
wl_surface);
|
|
|
|
wp_fractional_scale_v1_add_listener (self->display_server.fractional_scale,
|
|
|
|
&fractional_scale_listener, self);
|
|
|
|
}
|
2023-04-01 12:41:30 +00:00
|
|
|
if (display_wayland->viewporter)
|
|
|
|
{
|
|
|
|
self->display_server.viewport =
|
|
|
|
wp_viewporter_get_viewport (display_wayland->viewporter, wl_surface);
|
|
|
|
}
|
2013-11-11 23:02:19 +00:00
|
|
|
|
2023-04-01 10:48:26 +00:00
|
|
|
self->display_server.wl_surface = wl_surface;
|
2013-11-11 23:02:19 +00:00
|
|
|
}
|
2013-06-04 09:39:36 +00:00
|
|
|
|
2023-04-16 23:26:45 +00:00
|
|
|
static void
|
|
|
|
gdk_wayland_surface_constructed (GObject *object)
|
|
|
|
{
|
|
|
|
GdkSurface *surface = GDK_SURFACE (object);
|
|
|
|
GdkWaylandSurface *self = GDK_WAYLAND_SURFACE (surface);
|
|
|
|
GdkDisplay *display = gdk_surface_get_display (surface);
|
|
|
|
GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (display);
|
|
|
|
GdkFrameClock *frame_clock = gdk_surface_get_frame_clock (surface);
|
|
|
|
|
|
|
|
self->event_queue = wl_display_create_queue (display_wayland->wl_display);
|
|
|
|
display_wayland->event_queues = g_list_prepend (display_wayland->event_queues,
|
|
|
|
self->event_queue);
|
|
|
|
|
|
|
|
/* More likely to be right than just assuming 1 */
|
|
|
|
if (wl_compositor_get_version (display_wayland->compositor) >= WL_SURFACE_SET_BUFFER_SCALE_SINCE_VERSION)
|
|
|
|
{
|
|
|
|
GdkMonitor *monitor = g_list_model_get_item (gdk_display_get_monitors (display), 0);
|
|
|
|
if (monitor)
|
|
|
|
{
|
|
|
|
guint32 monitor_scale = gdk_monitor_get_scale_factor (monitor);
|
|
|
|
|
|
|
|
if (monitor_scale != 1)
|
|
|
|
{
|
|
|
|
self->scale = GDK_FRACTIONAL_SCALE_INIT_INT (monitor_scale);
|
|
|
|
self->buffer_scale_dirty = TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
g_object_unref (monitor);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
gdk_wayland_surface_create_wl_surface (surface);
|
|
|
|
|
|
|
|
g_signal_connect (frame_clock, "before-paint", G_CALLBACK (on_frame_clock_before_paint), surface);
|
|
|
|
g_signal_connect (frame_clock, "after-paint", G_CALLBACK (on_frame_clock_after_paint), surface);
|
|
|
|
|
|
|
|
G_OBJECT_CLASS (gdk_wayland_surface_parent_class)->constructed (object);
|
|
|
|
}
|
|
|
|
|
2023-04-13 00:56:12 +00:00
|
|
|
static void
|
|
|
|
gdk_wayland_surface_destroy_wl_surface (GdkWaylandSurface *self)
|
|
|
|
{
|
2023-04-13 02:30:24 +00:00
|
|
|
if (self->display_server.egl_window)
|
|
|
|
{
|
|
|
|
gdk_surface_set_egl_native_window (GDK_SURFACE (self), NULL);
|
|
|
|
g_clear_pointer (&self->display_server.egl_window, wl_egl_window_destroy);
|
|
|
|
}
|
|
|
|
|
2023-04-13 00:56:12 +00:00
|
|
|
g_clear_pointer (&self->display_server.viewport, wp_viewport_destroy);
|
|
|
|
g_clear_pointer (&self->display_server.fractional_scale, wp_fractional_scale_v1_destroy);
|
|
|
|
|
|
|
|
g_clear_pointer (&self->display_server.wl_surface, wl_surface_destroy);
|
|
|
|
|
|
|
|
g_clear_pointer (&self->display_server.outputs, g_slist_free);
|
|
|
|
}
|
|
|
|
|
2020-07-30 21:06:59 +00:00
|
|
|
static void
|
2023-01-06 18:44:18 +00:00
|
|
|
maybe_notify_mapped (GdkSurface *surface)
|
2020-07-30 21:06:59 +00:00
|
|
|
{
|
2023-01-06 18:44:18 +00:00
|
|
|
if (surface->destroyed)
|
|
|
|
return;
|
2020-07-30 21:06:59 +00:00
|
|
|
|
2023-01-06 18:44:18 +00:00
|
|
|
if (!GDK_SURFACE_IS_MAPPED (surface))
|
|
|
|
gdk_surface_set_is_mapped (surface, TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gdk_wayland_surface_configure (GdkSurface *surface)
|
|
|
|
{
|
|
|
|
GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
|
|
|
|
|
|
|
|
if (!impl->initial_configure_received)
|
2020-08-04 14:52:20 +00:00
|
|
|
{
|
2023-01-06 18:44:18 +00:00
|
|
|
gdk_surface_thaw_updates (surface);
|
|
|
|
impl->initial_configure_received = TRUE;
|
|
|
|
impl->pending.is_initial_configure = TRUE;
|
|
|
|
maybe_notify_mapped (surface);
|
2020-08-04 14:52:20 +00:00
|
|
|
}
|
|
|
|
|
2023-01-06 18:44:18 +00:00
|
|
|
impl->has_uncommitted_ack_configure = TRUE;
|
2022-11-07 11:08:18 +00:00
|
|
|
|
2023-01-06 21:35:16 +00:00
|
|
|
GDK_WAYLAND_SURFACE_GET_CLASS (impl)->handle_configure (impl);
|
2022-11-07 11:08:18 +00:00
|
|
|
|
2023-01-06 18:44:18 +00:00
|
|
|
impl->last_configure_serial = impl->pending.serial;
|
2020-07-30 21:06:59 +00:00
|
|
|
|
2023-01-06 18:44:18 +00:00
|
|
|
memset (&impl->pending, 0, sizeof (impl->pending));
|
|
|
|
}
|
2020-07-30 21:06:59 +00:00
|
|
|
|
2023-01-06 18:44:18 +00:00
|
|
|
static void
|
|
|
|
gdk_wayland_surface_handle_configure (GdkWaylandSurface *impl,
|
|
|
|
uint32_t serial)
|
|
|
|
{
|
|
|
|
impl->pending.is_dirty = TRUE;
|
|
|
|
impl->pending.serial = serial;
|
2022-11-15 11:50:02 +00:00
|
|
|
|
2023-01-06 18:44:18 +00:00
|
|
|
if (impl->state_freeze_count > 0)
|
|
|
|
return;
|
2020-11-24 15:05:26 +00:00
|
|
|
|
2023-01-06 18:44:18 +00:00
|
|
|
gdk_wayland_surface_configure (GDK_SURFACE (impl));
|
|
|
|
}
|
2020-11-24 15:05:26 +00:00
|
|
|
|
2020-11-23 15:46:29 +00:00
|
|
|
static void
|
2023-01-06 18:44:18 +00:00
|
|
|
xdg_surface_configure (void *data,
|
|
|
|
struct xdg_surface *xdg_surface,
|
|
|
|
uint32_t serial)
|
2020-11-23 15:46:29 +00:00
|
|
|
{
|
2023-01-06 18:44:18 +00:00
|
|
|
gdk_wayland_surface_handle_configure (GDK_WAYLAND_SURFACE (data), serial);
|
2020-11-23 15:46:29 +00:00
|
|
|
}
|
|
|
|
|
2023-01-06 18:44:18 +00:00
|
|
|
static const struct xdg_surface_listener xdg_surface_listener = {
|
|
|
|
xdg_surface_configure,
|
|
|
|
};
|
|
|
|
|
2013-11-11 23:02:19 +00:00
|
|
|
static void
|
2023-01-06 18:44:18 +00:00
|
|
|
zxdg_surface_v6_configure (void *data,
|
|
|
|
struct zxdg_surface_v6 *xdg_surface,
|
|
|
|
uint32_t serial)
|
2011-12-05 15:55:37 +00:00
|
|
|
{
|
2023-01-06 18:44:18 +00:00
|
|
|
gdk_wayland_surface_handle_configure (GDK_WAYLAND_SURFACE (data), serial);
|
|
|
|
}
|
2011-12-05 15:55:37 +00:00
|
|
|
|
2023-01-06 18:44:18 +00:00
|
|
|
static const struct zxdg_surface_v6_listener zxdg_surface_v6_listener = {
|
|
|
|
zxdg_surface_v6_configure,
|
|
|
|
};
|
2016-06-28 07:01:22 +00:00
|
|
|
|
2023-01-06 18:53:27 +00:00
|
|
|
void
|
2023-01-06 18:44:18 +00:00
|
|
|
gdk_wayland_surface_create_xdg_surface_resources (GdkSurface *surface)
|
|
|
|
{
|
|
|
|
GdkWaylandDisplay *display =
|
|
|
|
GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface));
|
|
|
|
GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
|
2020-12-02 10:38:17 +00:00
|
|
|
|
2023-01-06 18:44:18 +00:00
|
|
|
switch (display->shell_variant)
|
2020-08-04 14:52:20 +00:00
|
|
|
{
|
2023-01-06 18:44:18 +00:00
|
|
|
case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL:
|
|
|
|
impl->display_server.xdg_surface =
|
|
|
|
xdg_wm_base_get_xdg_surface (display->xdg_wm_base,
|
|
|
|
impl->display_server.wl_surface);
|
|
|
|
wl_proxy_set_queue ((struct wl_proxy *) impl->display_server.xdg_surface,
|
|
|
|
impl->event_queue);
|
|
|
|
xdg_surface_add_listener (impl->display_server.xdg_surface,
|
|
|
|
&xdg_surface_listener,
|
|
|
|
surface);
|
|
|
|
break;
|
|
|
|
case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6:
|
|
|
|
impl->display_server.zxdg_surface_v6 =
|
|
|
|
zxdg_shell_v6_get_xdg_surface (display->zxdg_shell_v6,
|
|
|
|
impl->display_server.wl_surface);
|
|
|
|
zxdg_surface_v6_add_listener (impl->display_server.zxdg_surface_v6,
|
|
|
|
&zxdg_surface_v6_listener,
|
|
|
|
surface);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
g_assert_not_reached ();
|
2020-08-04 14:52:20 +00:00
|
|
|
}
|
2023-01-06 18:44:18 +00:00
|
|
|
}
|
2020-08-04 14:52:20 +00:00
|
|
|
|
2023-01-06 18:44:18 +00:00
|
|
|
static void
|
|
|
|
unmap_popups_for_surface (GdkSurface *surface)
|
|
|
|
{
|
|
|
|
GdkWaylandDisplay *display_wayland;
|
|
|
|
GList *l;
|
2017-12-18 12:00:36 +00:00
|
|
|
|
2023-01-06 18:44:18 +00:00
|
|
|
display_wayland = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface));
|
|
|
|
for (l = display_wayland->current_popups; l; l = l->next)
|
2017-12-18 12:00:36 +00:00
|
|
|
{
|
2023-01-06 18:44:18 +00:00
|
|
|
GdkSurface *popup = l->data;
|
|
|
|
|
|
|
|
if (popup->parent == surface)
|
|
|
|
{
|
|
|
|
g_warning ("Tried to unmap the parent of a popup");
|
|
|
|
gdk_surface_hide (popup);
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
2017-12-18 12:00:36 +00:00
|
|
|
}
|
2014-02-06 19:28:51 +00:00
|
|
|
}
|
|
|
|
|
2022-11-17 13:24:40 +00:00
|
|
|
void
|
2023-01-06 18:44:18 +00:00
|
|
|
gdk_wayland_surface_hide_surface (GdkSurface *surface)
|
2019-07-12 13:54:32 +00:00
|
|
|
{
|
2023-01-06 18:44:18 +00:00
|
|
|
GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
|
2019-07-12 13:54:32 +00:00
|
|
|
|
2023-04-13 01:33:59 +00:00
|
|
|
if (!impl->mapped)
|
|
|
|
return;
|
|
|
|
|
2023-01-06 18:44:18 +00:00
|
|
|
unmap_popups_for_surface (surface);
|
|
|
|
|
2023-04-28 20:21:42 +00:00
|
|
|
g_clear_pointer (&impl->frame_callback, wl_callback_destroy);
|
2023-04-13 01:33:59 +00:00
|
|
|
if (impl->awaiting_frame_frozen)
|
|
|
|
{
|
|
|
|
impl->awaiting_frame_frozen = FALSE;
|
|
|
|
gdk_surface_thaw_updates (surface);
|
|
|
|
}
|
2023-03-05 19:54:40 +00:00
|
|
|
|
2023-04-13 01:33:59 +00:00
|
|
|
GDK_WAYLAND_SURFACE_GET_CLASS (impl)->hide_surface (impl);
|
2020-02-16 19:09:42 +00:00
|
|
|
|
2023-04-13 01:33:59 +00:00
|
|
|
if (impl->display_server.xdg_surface)
|
|
|
|
{
|
|
|
|
xdg_surface_destroy (impl->display_server.xdg_surface);
|
|
|
|
impl->display_server.xdg_surface = NULL;
|
|
|
|
if (!impl->initial_configure_received)
|
|
|
|
gdk_surface_thaw_updates (surface);
|
|
|
|
else
|
|
|
|
impl->initial_configure_received = FALSE;
|
2020-02-16 11:59:24 +00:00
|
|
|
}
|
2023-04-13 01:33:59 +00:00
|
|
|
if (impl->display_server.zxdg_surface_v6)
|
|
|
|
{
|
|
|
|
g_clear_pointer (&impl->display_server.zxdg_surface_v6, zxdg_surface_v6_destroy);
|
|
|
|
if (!impl->initial_configure_received)
|
|
|
|
gdk_surface_thaw_updates (surface);
|
|
|
|
else
|
|
|
|
impl->initial_configure_received = FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
wl_surface_attach (impl->display_server.wl_surface, NULL, 0, 0);
|
|
|
|
wl_surface_commit (impl->display_server.wl_surface);
|
2020-02-16 11:59:24 +00:00
|
|
|
|
2023-01-06 18:44:18 +00:00
|
|
|
impl->has_uncommitted_ack_configure = FALSE;
|
2023-10-28 01:47:30 +00:00
|
|
|
impl->has_pending_subsurface_commits = FALSE;
|
2019-07-12 13:54:32 +00:00
|
|
|
|
2023-01-06 18:44:18 +00:00
|
|
|
impl->last_sent_window_geometry = (GdkRectangle) { 0 };
|
|
|
|
impl->mapped = FALSE;
|
2019-07-12 13:54:32 +00:00
|
|
|
}
|
|
|
|
|
2020-11-19 09:54:20 +00:00
|
|
|
static void
|
2023-01-06 18:44:18 +00:00
|
|
|
gdk_wayland_surface_hide (GdkSurface *surface)
|
2020-11-19 09:54:20 +00:00
|
|
|
{
|
2023-01-06 18:44:18 +00:00
|
|
|
GdkSeat *seat;
|
2020-11-19 09:54:20 +00:00
|
|
|
|
2023-01-06 18:44:18 +00:00
|
|
|
seat = gdk_display_get_default_seat (surface->display);
|
|
|
|
if (seat)
|
|
|
|
{
|
|
|
|
if (surface->autohide)
|
|
|
|
gdk_seat_ungrab (seat);
|
|
|
|
|
|
|
|
gdk_wayland_seat_clear_touchpoints (GDK_WAYLAND_SEAT (seat), surface);
|
|
|
|
}
|
|
|
|
gdk_wayland_surface_hide_surface (surface);
|
|
|
|
_gdk_surface_clear_update_area (surface);
|
2020-11-19 09:54:20 +00:00
|
|
|
}
|
|
|
|
|
2022-11-17 13:24:40 +00:00
|
|
|
void
|
2023-01-06 18:44:18 +00:00
|
|
|
gdk_wayland_surface_move_resize (GdkSurface *surface,
|
|
|
|
int x,
|
|
|
|
int y,
|
|
|
|
int width,
|
|
|
|
int height)
|
2019-07-12 13:54:32 +00:00
|
|
|
{
|
|
|
|
GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
|
|
|
|
|
2023-01-06 18:44:18 +00:00
|
|
|
surface->x = x;
|
|
|
|
surface->y = y;
|
2023-04-13 00:47:51 +00:00
|
|
|
gdk_wayland_surface_update_size (surface, width, height, &impl->scale);
|
2023-01-06 18:44:18 +00:00
|
|
|
}
|
2020-09-17 16:20:08 +00:00
|
|
|
|
2023-01-06 18:44:18 +00:00
|
|
|
static void
|
|
|
|
gdk_wayland_surface_get_geometry (GdkSurface *surface,
|
|
|
|
int *x,
|
|
|
|
int *y,
|
|
|
|
int *width,
|
|
|
|
int *height)
|
|
|
|
{
|
|
|
|
if (!GDK_SURFACE_DESTROYED (surface))
|
2021-12-09 23:29:38 +00:00
|
|
|
{
|
2023-01-06 18:44:18 +00:00
|
|
|
if (x)
|
|
|
|
*x = surface->x;
|
|
|
|
if (y)
|
|
|
|
*y = surface->y;
|
|
|
|
if (width)
|
|
|
|
*width = surface->width;
|
|
|
|
if (height)
|
|
|
|
*height = surface->height;
|
2021-12-09 23:29:38 +00:00
|
|
|
}
|
2019-07-12 13:54:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2023-01-06 18:44:18 +00:00
|
|
|
gdk_wayland_surface_get_root_coords (GdkSurface *surface,
|
|
|
|
int x,
|
|
|
|
int y,
|
|
|
|
int *root_x,
|
|
|
|
int *root_y)
|
2019-07-12 13:54:32 +00:00
|
|
|
{
|
2023-01-06 18:44:18 +00:00
|
|
|
/*
|
|
|
|
* Wayland does not have a global coordinate space shared between surfaces. In
|
|
|
|
* fact, for regular toplevels, we have no idea where our surfaces are
|
|
|
|
* positioned, relatively.
|
|
|
|
*
|
|
|
|
* However, there are some cases like popups and subsurfaces where we do have
|
|
|
|
* some amount of control over the placement of our surface, and we can
|
|
|
|
* semi-accurately control the x/y position of these surfaces, if they are
|
|
|
|
* relative to another surface.
|
|
|
|
*
|
|
|
|
* To pretend we have something called a root coordinate space, assume all
|
|
|
|
* parent-less surfaces are positioned in (0, 0), and all relative positioned
|
|
|
|
* popups and subsurfaces are placed within this fake root coordinate space.
|
|
|
|
*
|
|
|
|
* For example a 200x200 large toplevel surface will have the position (0, 0).
|
|
|
|
* If a popup positioned in the middle of the toplevel will have the fake
|
|
|
|
* position (100,100). Furthermore, if a positioned is placed in the middle
|
|
|
|
* that popup, will have the fake position (150,150), even though it has the
|
|
|
|
* relative position (50,50). These three surfaces would make up one single
|
|
|
|
* fake root coordinate space.
|
|
|
|
*/
|
2019-07-12 13:54:32 +00:00
|
|
|
|
2023-01-06 18:44:18 +00:00
|
|
|
if (root_x)
|
|
|
|
*root_x = surface->x + x;
|
2020-02-16 11:59:24 +00:00
|
|
|
|
2023-01-06 18:44:18 +00:00
|
|
|
if (root_y)
|
|
|
|
*root_y = surface->y + y;
|
2019-07-12 13:54:32 +00:00
|
|
|
}
|
|
|
|
|
2023-01-06 18:44:18 +00:00
|
|
|
static gboolean
|
|
|
|
gdk_wayland_surface_get_device_state (GdkSurface *surface,
|
|
|
|
GdkDevice *device,
|
|
|
|
double *x,
|
|
|
|
double *y,
|
|
|
|
GdkModifierType *mask)
|
2017-12-18 12:00:36 +00:00
|
|
|
{
|
2023-01-06 18:44:18 +00:00
|
|
|
if (GDK_SURFACE_DESTROYED (surface))
|
|
|
|
return FALSE;
|
2017-12-18 12:00:36 +00:00
|
|
|
|
2023-01-06 18:44:18 +00:00
|
|
|
gdk_wayland_device_query_state (device, surface, x, y, mask);
|
|
|
|
|
|
|
|
return *x >= 0 && *y >= 0 && *x < surface->width && *y < surface->height;
|
2017-12-18 12:00:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2023-01-06 18:44:18 +00:00
|
|
|
gdk_wayland_surface_set_input_region (GdkSurface *surface,
|
|
|
|
cairo_region_t *input_region)
|
2017-12-18 12:00:36 +00:00
|
|
|
{
|
2023-01-06 18:44:18 +00:00
|
|
|
GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
|
2017-12-18 12:00:36 +00:00
|
|
|
|
2023-01-06 18:44:18 +00:00
|
|
|
if (GDK_SURFACE_DESTROYED (surface))
|
|
|
|
return;
|
2017-12-18 12:00:36 +00:00
|
|
|
|
2023-01-06 18:44:18 +00:00
|
|
|
g_clear_pointer (&impl->input_region, cairo_region_destroy);
|
2017-12-18 12:00:36 +00:00
|
|
|
|
2023-01-06 18:44:18 +00:00
|
|
|
if (input_region)
|
|
|
|
impl->input_region = cairo_region_copy (input_region);
|
2017-12-18 12:00:36 +00:00
|
|
|
|
2023-01-06 18:44:18 +00:00
|
|
|
impl->input_region_dirty = TRUE;
|
2017-12-18 12:00:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2023-01-06 18:44:18 +00:00
|
|
|
gdk_wayland_surface_destroy (GdkSurface *surface,
|
|
|
|
gboolean foreign_destroy)
|
2017-12-18 12:00:36 +00:00
|
|
|
{
|
2023-01-06 18:44:18 +00:00
|
|
|
GdkFrameClock *frame_clock;
|
2017-12-18 12:00:36 +00:00
|
|
|
|
2023-01-06 18:44:18 +00:00
|
|
|
/* Wayland surfaces can't be externally destroyed; we may possibly
|
|
|
|
* eventually want to use this path at display close-down
|
|
|
|
*/
|
|
|
|
g_return_if_fail (!foreign_destroy);
|
2016-07-01 09:03:36 +00:00
|
|
|
|
2023-01-06 18:44:18 +00:00
|
|
|
gdk_wayland_surface_hide_surface (surface);
|
2021-02-03 21:09:11 +00:00
|
|
|
|
2023-05-14 21:37:41 +00:00
|
|
|
if (GDK_IS_TOPLEVEL (surface))
|
|
|
|
gdk_wayland_toplevel_destroy (GDK_TOPLEVEL (surface));
|
|
|
|
|
|
|
|
gdk_wayland_surface_destroy_wl_surface (GDK_WAYLAND_SURFACE (surface));
|
2023-04-13 01:33:59 +00:00
|
|
|
|
2023-01-06 18:44:18 +00:00
|
|
|
frame_clock = gdk_surface_get_frame_clock (surface);
|
|
|
|
g_signal_handlers_disconnect_by_func (frame_clock, on_frame_clock_before_paint, surface);
|
|
|
|
g_signal_handlers_disconnect_by_func (frame_clock, on_frame_clock_after_paint, surface);
|
|
|
|
}
|
2021-02-03 21:09:11 +00:00
|
|
|
|
|
|
|
static void
|
2023-01-06 18:44:18 +00:00
|
|
|
gdk_wayland_surface_destroy_notify (GdkSurface *surface)
|
2021-02-03 21:09:11 +00:00
|
|
|
{
|
2023-01-06 18:44:18 +00:00
|
|
|
if (!GDK_SURFACE_DESTROYED (surface))
|
2021-02-03 21:09:11 +00:00
|
|
|
{
|
2023-01-06 18:44:18 +00:00
|
|
|
g_warning ("GdkSurface %p unexpectedly destroyed", surface);
|
|
|
|
_gdk_surface_destroy (surface, TRUE);
|
2021-02-03 21:09:11 +00:00
|
|
|
}
|
2023-01-06 18:44:18 +00:00
|
|
|
|
|
|
|
g_object_unref (surface);
|
2021-02-03 21:09:11 +00:00
|
|
|
}
|
|
|
|
|
2023-04-01 18:51:11 +00:00
|
|
|
static double
|
|
|
|
gdk_wayland_surface_get_scale (GdkSurface *surface)
|
2017-12-18 12:00:36 +00:00
|
|
|
{
|
2023-01-06 18:44:18 +00:00
|
|
|
GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
|
2017-12-18 12:00:36 +00:00
|
|
|
|
2023-04-01 18:51:11 +00:00
|
|
|
return gdk_fractional_scale_to_double (&impl->scale);
|
2017-12-18 12:00:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2023-01-06 18:44:18 +00:00
|
|
|
gdk_wayland_surface_set_opaque_region (GdkSurface *surface,
|
|
|
|
cairo_region_t *region)
|
2016-07-01 09:03:36 +00:00
|
|
|
{
|
2023-01-06 18:44:18 +00:00
|
|
|
GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
|
2017-12-18 12:00:36 +00:00
|
|
|
|
2023-01-06 18:44:18 +00:00
|
|
|
if (GDK_SURFACE_DESTROYED (surface))
|
|
|
|
return;
|
|
|
|
|
|
|
|
g_clear_pointer (&impl->opaque_region, cairo_region_destroy);
|
|
|
|
impl->opaque_region = cairo_region_reference (region);
|
|
|
|
impl->opaque_region_dirty = TRUE;
|
2017-12-18 12:00:36 +00:00
|
|
|
}
|
|
|
|
|
2023-01-06 21:35:16 +00:00
|
|
|
static void
|
|
|
|
gdk_wayland_surface_default_handle_configure (GdkWaylandSurface *surface)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gdk_wayland_surface_default_handle_frame (GdkWaylandSurface *surface)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gdk_wayland_surface_default_hide_surface (GdkWaylandSurface *surface)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2020-08-04 14:52:20 +00:00
|
|
|
static void
|
2023-01-06 18:44:18 +00:00
|
|
|
gdk_wayland_surface_class_init (GdkWaylandSurfaceClass *klass)
|
2020-08-04 14:52:20 +00:00
|
|
|
{
|
2023-01-06 18:44:18 +00:00
|
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
2023-01-06 19:46:47 +00:00
|
|
|
GdkSurfaceClass *surface_class = GDK_SURFACE_CLASS (klass);
|
2020-08-04 14:52:20 +00:00
|
|
|
|
2023-01-06 18:44:18 +00:00
|
|
|
object_class->constructed = gdk_wayland_surface_constructed;
|
|
|
|
object_class->dispose = gdk_wayland_surface_dispose;
|
|
|
|
object_class->finalize = gdk_wayland_surface_finalize;
|
|
|
|
|
2023-01-06 19:46:47 +00:00
|
|
|
surface_class->hide = gdk_wayland_surface_hide;
|
|
|
|
surface_class->get_geometry = gdk_wayland_surface_get_geometry;
|
|
|
|
surface_class->get_root_coords = gdk_wayland_surface_get_root_coords;
|
|
|
|
surface_class->get_device_state = gdk_wayland_surface_get_device_state;
|
|
|
|
surface_class->set_input_region = gdk_wayland_surface_set_input_region;
|
|
|
|
surface_class->destroy = gdk_wayland_surface_destroy;
|
|
|
|
surface_class->beep = gdk_wayland_surface_beep;
|
|
|
|
|
|
|
|
surface_class->destroy_notify = gdk_wayland_surface_destroy_notify;
|
|
|
|
surface_class->drag_begin = _gdk_wayland_surface_drag_begin;
|
2023-04-01 18:51:11 +00:00
|
|
|
surface_class->get_scale = gdk_wayland_surface_get_scale;
|
2023-01-06 19:46:47 +00:00
|
|
|
surface_class->set_opaque_region = gdk_wayland_surface_set_opaque_region;
|
|
|
|
surface_class->request_layout = gdk_wayland_surface_request_layout;
|
2023-10-28 01:47:30 +00:00
|
|
|
surface_class->create_subsurface = gdk_wayland_surface_create_subsurface;
|
2023-01-06 21:35:16 +00:00
|
|
|
|
|
|
|
klass->handle_configure = gdk_wayland_surface_default_handle_configure;
|
|
|
|
klass->handle_frame = gdk_wayland_surface_default_handle_frame;
|
|
|
|
klass->hide_surface = gdk_wayland_surface_default_hide_surface;
|
2020-08-04 14:52:20 +00:00
|
|
|
}
|
|
|
|
|
2023-01-06 18:44:18 +00:00
|
|
|
/* }}} */
|
|
|
|
/* {{{ Private Surface API */
|
2017-12-18 12:00:36 +00:00
|
|
|
|
2023-01-06 18:44:18 +00:00
|
|
|
struct wl_output *
|
|
|
|
gdk_wayland_surface_get_wl_output (GdkSurface *surface)
|
2017-12-18 12:00:36 +00:00
|
|
|
{
|
2023-01-06 18:44:18 +00:00
|
|
|
GdkWaylandSurface *impl;
|
2017-12-18 12:00:36 +00:00
|
|
|
|
2023-01-06 18:44:18 +00:00
|
|
|
g_return_val_if_fail (GDK_IS_WAYLAND_SURFACE (surface), NULL);
|
|
|
|
|
|
|
|
impl = GDK_WAYLAND_SURFACE (surface);
|
|
|
|
/* We pick the head of the list as this is the last entered output */
|
|
|
|
if (impl->display_server.outputs)
|
|
|
|
return (struct wl_output *) impl->display_server.outputs->data;
|
|
|
|
|
|
|
|
return NULL;
|
2017-12-18 12:00:36 +00:00
|
|
|
}
|
|
|
|
|
2023-01-06 18:44:18 +00:00
|
|
|
void
|
|
|
|
_gdk_wayland_surface_offset_next_wl_buffer (GdkSurface *surface,
|
|
|
|
int x,
|
|
|
|
int y)
|
2017-12-18 12:00:36 +00:00
|
|
|
{
|
2023-01-06 18:44:18 +00:00
|
|
|
GdkWaylandSurface *impl;
|
2020-12-02 10:38:17 +00:00
|
|
|
|
2023-01-06 18:44:18 +00:00
|
|
|
g_return_if_fail (GDK_IS_WAYLAND_SURFACE (surface));
|
2017-12-18 12:00:36 +00:00
|
|
|
|
2023-01-06 18:44:18 +00:00
|
|
|
impl = GDK_WAYLAND_SURFACE (surface);
|
2016-07-01 09:03:36 +00:00
|
|
|
|
2023-01-06 18:44:18 +00:00
|
|
|
impl->pending_buffer_offset_x = x;
|
|
|
|
impl->pending_buffer_offset_y = y;
|
2016-07-01 09:03:36 +00:00
|
|
|
}
|
|
|
|
|
2023-01-06 18:44:18 +00:00
|
|
|
void
|
|
|
|
gdk_wayland_surface_ensure_wl_egl_window (GdkSurface *surface)
|
2014-02-07 22:16:40 +00:00
|
|
|
{
|
2023-01-06 18:44:18 +00:00
|
|
|
GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
|
2014-02-07 22:16:40 +00:00
|
|
|
|
2023-01-06 18:44:18 +00:00
|
|
|
if (impl->display_server.egl_window == NULL)
|
|
|
|
{
|
2023-04-02 14:24:37 +00:00
|
|
|
int width, height;
|
|
|
|
|
|
|
|
get_egl_window_size (surface, &width, &height);
|
2023-01-06 18:44:18 +00:00
|
|
|
impl->display_server.egl_window =
|
2023-04-02 14:24:37 +00:00
|
|
|
wl_egl_window_create (impl->display_server.wl_surface, width, height);
|
2023-01-06 18:44:18 +00:00
|
|
|
gdk_surface_set_egl_native_window (surface, impl->display_server.egl_window);
|
|
|
|
}
|
2017-12-18 12:00:36 +00:00
|
|
|
}
|
2018-01-12 00:48:27 +00:00
|
|
|
|
2023-01-06 18:44:18 +00:00
|
|
|
/* }}} */
|
|
|
|
/* {{{ Surface API */
|
2015-02-28 05:15:13 +00:00
|
|
|
|
2023-01-06 18:44:18 +00:00
|
|
|
/**
|
|
|
|
* gdk_wayland_surface_get_wl_surface: (skip)
|
|
|
|
* @surface: (type GdkWaylandSurface): a `GdkSurface`
|
|
|
|
*
|
|
|
|
* Returns the Wayland `wl_surface` of a `GdkSurface`.
|
|
|
|
*
|
|
|
|
* Returns: (transfer none): a Wayland `wl_surface`
|
|
|
|
*/
|
|
|
|
struct wl_surface *
|
|
|
|
gdk_wayland_surface_get_wl_surface (GdkSurface *surface)
|
2017-12-18 12:00:36 +00:00
|
|
|
{
|
2023-01-06 18:44:18 +00:00
|
|
|
g_return_val_if_fail (GDK_IS_WAYLAND_SURFACE (surface), NULL);
|
2014-02-07 22:16:40 +00:00
|
|
|
|
2023-01-06 18:44:18 +00:00
|
|
|
return GDK_WAYLAND_SURFACE (surface)->display_server.wl_surface;
|
2017-12-18 12:00:36 +00:00
|
|
|
}
|
2013-11-11 23:02:19 +00:00
|
|
|
|
2023-01-06 18:44:18 +00:00
|
|
|
/* }}}} */
|
|
|
|
/* vim:set foldmethod=marker expandtab: */
|