2012-01-07 22:21:32 +00:00
|
|
|
/*
|
|
|
|
* Wayland Support
|
|
|
|
*
|
|
|
|
* Copyright (C) 2012,2013 Intel Corporation
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License as
|
|
|
|
* published by the Free Software Foundation; either version 2 of the
|
|
|
|
* License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program 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
|
|
|
|
* General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
2023-08-07 11:50:23 +02:00
|
|
|
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
2012-01-07 22:21:32 +00:00
|
|
|
*/
|
|
|
|
|
2014-10-07 20:05:57 -07:00
|
|
|
#include "config.h"
|
|
|
|
|
2018-07-10 10:36:24 +02:00
|
|
|
#include "wayland/meta-wayland.h"
|
2012-01-07 22:21:32 +00:00
|
|
|
|
|
|
|
#include <sys/time.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <wayland-server.h>
|
|
|
|
|
2018-07-10 10:36:24 +02:00
|
|
|
#include "clutter/clutter.h"
|
2021-05-06 12:12:34 +02:00
|
|
|
#include "cogl/cogl-egl.h"
|
2020-10-22 23:16:28 +02:00
|
|
|
#include "compositor/meta-surface-actor-wayland.h"
|
2022-05-09 11:48:57 +02:00
|
|
|
#include "core/events.h"
|
2021-03-02 10:21:20 +01:00
|
|
|
#include "core/meta-context-private.h"
|
2020-10-09 16:23:32 +02:00
|
|
|
#include "wayland/meta-wayland-activation.h"
|
2019-09-18 16:18:58 +02:00
|
|
|
#include "wayland/meta-wayland-buffer.h"
|
2018-07-10 10:36:24 +02:00
|
|
|
#include "wayland/meta-wayland-data-device.h"
|
|
|
|
#include "wayland/meta-wayland-dma-buf.h"
|
|
|
|
#include "wayland/meta-wayland-egl-stream.h"
|
2023-01-27 15:16:14 +01:00
|
|
|
#include "wayland/meta-wayland-filter-manager.h"
|
2023-08-26 01:40:20 +03:00
|
|
|
#include "wayland/meta-wayland-idle-inhibit.h"
|
2018-07-10 10:36:24 +02:00
|
|
|
#include "wayland/meta-wayland-inhibit-shortcuts-dialog.h"
|
|
|
|
#include "wayland/meta-wayland-inhibit-shortcuts.h"
|
2020-02-06 02:00:56 -05:00
|
|
|
#include "wayland/meta-wayland-legacy-xdg-foreign.h"
|
2018-07-10 10:36:24 +02:00
|
|
|
#include "wayland/meta-wayland-outputs.h"
|
2020-10-07 12:02:41 +03:00
|
|
|
#include "wayland/meta-wayland-presentation-time-private.h"
|
2018-07-10 10:36:24 +02:00
|
|
|
#include "wayland/meta-wayland-private.h"
|
|
|
|
#include "wayland/meta-wayland-region.h"
|
|
|
|
#include "wayland/meta-wayland-seat.h"
|
|
|
|
#include "wayland/meta-wayland-subsurface.h"
|
|
|
|
#include "wayland/meta-wayland-tablet-manager.h"
|
2021-05-30 15:00:13 +02:00
|
|
|
#include "wayland/meta-wayland-transaction.h"
|
2018-07-10 10:36:24 +02:00
|
|
|
#include "wayland/meta-wayland-xdg-foreign.h"
|
2022-06-13 10:09:26 +02:00
|
|
|
|
|
|
|
#ifdef HAVE_XWAYLAND
|
2023-02-01 17:55:41 +01:00
|
|
|
#include "wayland/meta-wayland-x11-interop.h"
|
2018-07-10 10:36:24 +02:00
|
|
|
#include "wayland/meta-xwayland-grab-keyboard.h"
|
|
|
|
#include "wayland/meta-xwayland-private.h"
|
|
|
|
#include "wayland/meta-xwayland.h"
|
2022-06-13 10:09:26 +02:00
|
|
|
#endif
|
2017-08-27 20:44:58 +02:00
|
|
|
|
2021-10-14 18:36:43 +02:00
|
|
|
#ifdef HAVE_NATIVE_BACKEND
|
2023-02-11 07:02:40 +01:00
|
|
|
#include "backends/native/meta-frame-native.h"
|
2021-10-14 18:36:43 +02:00
|
|
|
#include "backends/native/meta-renderer-native.h"
|
|
|
|
#endif
|
|
|
|
|
2022-06-15 13:12:35 +02:00
|
|
|
enum
|
|
|
|
{
|
|
|
|
PREPARE_SHUTDOWN,
|
|
|
|
|
|
|
|
N_SIGNALS
|
|
|
|
};
|
|
|
|
|
|
|
|
static guint signals[N_SIGNALS];
|
|
|
|
|
2016-12-05 21:23:46 +08:00
|
|
|
static char *_display_name_override;
|
2012-01-07 22:21:32 +00:00
|
|
|
|
2022-05-13 21:51:53 +02:00
|
|
|
typedef struct _MetaWaylandCompositorPrivate
|
|
|
|
{
|
|
|
|
gboolean is_wayland_egl_display_bound;
|
2023-01-27 15:16:14 +01:00
|
|
|
|
|
|
|
MetaWaylandFilterManager *filter_manager;
|
2023-02-11 07:02:40 +01:00
|
|
|
GHashTable *frame_callback_sources;
|
2022-05-13 21:51:53 +02:00
|
|
|
} MetaWaylandCompositorPrivate;
|
|
|
|
|
|
|
|
G_DEFINE_TYPE_WITH_PRIVATE (MetaWaylandCompositor, meta_wayland_compositor,
|
|
|
|
G_TYPE_OBJECT)
|
2018-08-23 15:49:17 +02:00
|
|
|
|
2014-10-07 20:50:57 -07:00
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
GSource source;
|
|
|
|
struct wl_display *display;
|
|
|
|
} WaylandEventSource;
|
|
|
|
|
2023-02-11 07:02:40 +01:00
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
GSource source;
|
|
|
|
|
|
|
|
MetaWaylandCompositor *compositor;
|
|
|
|
ClutterStageView *stage_view;
|
|
|
|
} FrameCallbackSource;
|
|
|
|
|
2023-11-02 14:30:59 +01:00
|
|
|
static void meta_wayland_compositor_update_focus (MetaWaylandCompositor *compositor,
|
|
|
|
MetaWindow *window);
|
|
|
|
|
2012-01-07 22:21:32 +00:00
|
|
|
static gboolean
|
2017-06-05 20:09:01 +08:00
|
|
|
wayland_event_source_prepare (GSource *base,
|
|
|
|
int *timeout)
|
2012-01-07 22:21:32 +00:00
|
|
|
{
|
|
|
|
WaylandEventSource *source = (WaylandEventSource *)base;
|
|
|
|
|
|
|
|
*timeout = -1;
|
|
|
|
|
|
|
|
wl_display_flush_clients (source->display);
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
2017-06-05 20:09:01 +08:00
|
|
|
wayland_event_source_dispatch (GSource *base,
|
2012-01-07 22:21:32 +00:00
|
|
|
GSourceFunc callback,
|
2017-06-05 20:09:01 +08:00
|
|
|
void *data)
|
2012-01-07 22:21:32 +00:00
|
|
|
{
|
|
|
|
WaylandEventSource *source = (WaylandEventSource *)base;
|
|
|
|
struct wl_event_loop *loop = wl_display_get_event_loop (source->display);
|
|
|
|
|
|
|
|
wl_event_loop_dispatch (loop, 0);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static GSourceFuncs wayland_event_source_funcs =
|
|
|
|
{
|
|
|
|
wayland_event_source_prepare,
|
2014-12-15 14:42:33 -08:00
|
|
|
NULL,
|
2012-01-07 22:21:32 +00:00
|
|
|
wayland_event_source_dispatch,
|
|
|
|
NULL
|
|
|
|
};
|
|
|
|
|
|
|
|
static GSource *
|
|
|
|
wayland_event_source_new (struct wl_display *display)
|
|
|
|
{
|
2021-07-12 13:54:26 +03:00
|
|
|
GSource *source;
|
|
|
|
WaylandEventSource *wayland_source;
|
2012-01-07 22:21:32 +00:00
|
|
|
struct wl_event_loop *loop = wl_display_get_event_loop (display);
|
|
|
|
|
2021-07-12 13:54:26 +03:00
|
|
|
source = g_source_new (&wayland_event_source_funcs,
|
|
|
|
sizeof (WaylandEventSource));
|
|
|
|
g_source_set_name (source, "[mutter] Wayland events");
|
|
|
|
wayland_source = (WaylandEventSource *) source;
|
|
|
|
wayland_source->display = display;
|
|
|
|
g_source_add_unix_fd (&wayland_source->source,
|
2014-12-15 14:42:33 -08:00
|
|
|
wl_event_loop_get_fd (loop),
|
|
|
|
G_IO_IN | G_IO_ERR);
|
2012-01-07 22:21:32 +00:00
|
|
|
|
2021-07-12 13:54:26 +03:00
|
|
|
return &wayland_source->source;
|
2012-01-07 22:21:32 +00:00
|
|
|
}
|
|
|
|
|
2023-02-11 07:02:40 +01:00
|
|
|
static void
|
|
|
|
emit_frame_callbacks_for_stage_view (MetaWaylandCompositor *compositor,
|
|
|
|
ClutterStageView *stage_view)
|
|
|
|
{
|
|
|
|
GList *l;
|
|
|
|
int64_t now_us;
|
|
|
|
|
|
|
|
now_us = g_get_monotonic_time ();
|
|
|
|
|
|
|
|
l = compositor->frame_callback_surfaces;
|
|
|
|
while (l)
|
|
|
|
{
|
|
|
|
GList *l_cur = l;
|
|
|
|
MetaWaylandSurface *surface = l->data;
|
|
|
|
MetaSurfaceActor *actor;
|
|
|
|
MetaWaylandActorSurface *actor_surface;
|
|
|
|
|
|
|
|
l = l->next;
|
|
|
|
|
|
|
|
actor = meta_wayland_surface_get_actor (surface);
|
|
|
|
if (!actor)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (!meta_surface_actor_wayland_is_view_primary (actor,
|
|
|
|
stage_view))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
actor_surface = META_WAYLAND_ACTOR_SURFACE (surface->role);
|
|
|
|
meta_wayland_actor_surface_emit_frame_callbacks (actor_surface,
|
|
|
|
now_us / 1000);
|
|
|
|
|
|
|
|
compositor->frame_callback_surfaces =
|
|
|
|
g_list_delete_link (compositor->frame_callback_surfaces, l_cur);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-03 10:52:08 +01:00
|
|
|
#ifdef HAVE_NATIVE_BACKEND
|
2023-02-11 07:02:40 +01:00
|
|
|
static gboolean
|
|
|
|
frame_callback_source_dispatch (GSource *source,
|
|
|
|
GSourceFunc callback,
|
|
|
|
gpointer user_data)
|
|
|
|
{
|
|
|
|
FrameCallbackSource *frame_callback_source = (FrameCallbackSource *) source;
|
|
|
|
MetaWaylandCompositor *compositor = frame_callback_source->compositor;
|
|
|
|
ClutterStageView *stage_view = frame_callback_source->stage_view;
|
|
|
|
|
|
|
|
emit_frame_callbacks_for_stage_view (compositor, stage_view);
|
|
|
|
g_source_set_ready_time (source, -1);
|
|
|
|
|
|
|
|
return G_SOURCE_CONTINUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
frame_callback_source_finalize (GSource *source)
|
|
|
|
{
|
|
|
|
FrameCallbackSource *frame_callback_source = (FrameCallbackSource *) source;
|
|
|
|
|
|
|
|
g_signal_handlers_disconnect_by_data (frame_callback_source->stage_view,
|
|
|
|
source);
|
|
|
|
}
|
|
|
|
|
|
|
|
static GSourceFuncs frame_callback_source_funcs = {
|
|
|
|
.dispatch = frame_callback_source_dispatch,
|
|
|
|
.finalize = frame_callback_source_finalize,
|
|
|
|
};
|
|
|
|
|
|
|
|
static void
|
|
|
|
on_stage_view_destroy (ClutterStageView *stage_view,
|
|
|
|
GSource *source)
|
|
|
|
{
|
|
|
|
FrameCallbackSource *frame_callback_source = (FrameCallbackSource *) source;
|
|
|
|
MetaWaylandCompositor *compositor = frame_callback_source->compositor;
|
|
|
|
MetaWaylandCompositorPrivate *priv =
|
|
|
|
meta_wayland_compositor_get_instance_private (compositor);
|
|
|
|
|
|
|
|
g_hash_table_remove (priv->frame_callback_sources, stage_view);
|
|
|
|
}
|
|
|
|
|
|
|
|
static GSource*
|
|
|
|
frame_callback_source_new (MetaWaylandCompositor *compositor,
|
|
|
|
ClutterStageView *stage_view)
|
|
|
|
{
|
|
|
|
FrameCallbackSource *frame_callback_source;
|
|
|
|
g_autofree char *name = NULL;
|
|
|
|
GSource *source;
|
|
|
|
|
|
|
|
source = g_source_new (&frame_callback_source_funcs,
|
|
|
|
sizeof (FrameCallbackSource));
|
|
|
|
frame_callback_source = (FrameCallbackSource *) source;
|
|
|
|
|
|
|
|
name =
|
|
|
|
g_strdup_printf ("[mutter] Wayland frame callbacks for stage view (%p)",
|
|
|
|
stage_view);
|
|
|
|
g_source_set_name (source, name);
|
|
|
|
g_source_set_priority (source, CLUTTER_PRIORITY_REDRAW);
|
|
|
|
g_source_set_can_recurse (source, FALSE);
|
|
|
|
|
|
|
|
frame_callback_source->compositor = compositor;
|
|
|
|
frame_callback_source->stage_view = stage_view;
|
|
|
|
|
|
|
|
g_signal_connect (stage_view,
|
|
|
|
"destroy",
|
|
|
|
G_CALLBACK (on_stage_view_destroy),
|
|
|
|
source);
|
|
|
|
|
|
|
|
return &frame_callback_source->source;
|
|
|
|
}
|
|
|
|
|
|
|
|
static GSource*
|
|
|
|
ensure_source_for_stage_view (MetaWaylandCompositor *compositor,
|
|
|
|
ClutterStageView *stage_view)
|
|
|
|
{
|
|
|
|
MetaWaylandCompositorPrivate *priv =
|
|
|
|
meta_wayland_compositor_get_instance_private (compositor);
|
|
|
|
GSource *source;
|
|
|
|
|
|
|
|
source = g_hash_table_lookup (priv->frame_callback_sources, stage_view);
|
|
|
|
if (!source)
|
|
|
|
{
|
|
|
|
source = frame_callback_source_new (compositor, stage_view);
|
|
|
|
g_hash_table_insert (priv->frame_callback_sources, stage_view, source);
|
|
|
|
g_source_attach (source, NULL);
|
|
|
|
g_source_unref (source);
|
|
|
|
}
|
|
|
|
|
|
|
|
return source;
|
|
|
|
}
|
2024-01-03 10:52:08 +01:00
|
|
|
#endif /* HAVE_NATIVE_BACKEND */
|
2023-02-11 07:02:40 +01:00
|
|
|
|
|
|
|
static void
|
|
|
|
on_after_update (ClutterStage *stage,
|
|
|
|
ClutterStageView *stage_view,
|
|
|
|
ClutterFrame *frame,
|
|
|
|
MetaWaylandCompositor *compositor)
|
|
|
|
{
|
|
|
|
#if defined(HAVE_NATIVE_BACKEND)
|
|
|
|
MetaContext *context = meta_wayland_compositor_get_context (compositor);
|
|
|
|
MetaBackend *backend = meta_context_get_backend (context);
|
|
|
|
GSource *source;
|
2023-09-25 12:41:48 +03:00
|
|
|
int64_t frame_deadline_us;
|
2023-02-11 07:02:40 +01:00
|
|
|
|
|
|
|
if (!META_IS_BACKEND_NATIVE (backend))
|
|
|
|
{
|
|
|
|
emit_frame_callbacks_for_stage_view (compositor, stage_view);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
source = ensure_source_for_stage_view (compositor, stage_view);
|
|
|
|
|
wayland: Emit frame callbacks when the frame is pending presentation
When Wayland clients send commits without a buffer attached ("empty"
commits), they may lead to stage updates that do not result in any
frame being submitted for presentation ("empty" updates).
Due to how frame scheduling is handled, there can be many such
"empty" updates in a single refresh cycle. If frame callbacks were
emitted after each of these "empty" updates, and if the client
sending "empty" commits was using frame callbacks to throttle the
same logic that results in these "empty" commits being sent, it would
result in a feedback loop between Mutter and the client where the
client would send "empty" commits and Mutter would reply almost
immediately with a frame callback causing the client to send "empty"
commits continuously.
As such, when an "empty" update is detected, frame callbacks are
scheduled to be emitted only once in every refresh cycle, avoiding the
feedback loop.
When a "non-empty" update is detected, frame callbacks are instead
emitted immediately to allow clients to draw their next frame as soon
as possible. It is safe to emit frame callbacks in this case because
the frame for the current refresh cycle is already "finalized" and
that any commit sent by the client at that point would only be handled
in a future refresh cycle.
To implement this, the previous logic had used
meta_frame_native_had_kms_update() to detect "non-empty" updates,
assuming that those would always result in a KMS presentation with the
native backend.
However, this approach misses the fact that virtual monitors do not
use KMS, and as such do not result in KMS presentation even for
"non-empty" updates. As a result, frame callbacks would not be emitted
immediately, resulting in unintended throttling of client rendering.
Instead, assume that it is safe to emit frame callbacks immediately
whenever an update results in the frame clock waiting to be notified
of presentation, since this is also when commits sent by clients are
scheduled to be handled in a future refresh cycle.
This issue was mostly hidden because frame callbacks would be sent
immediately when the target presentation time for the frame had
changed compared to the previous frame. However, this behavior was
removed in 26d8b9c69 ("wayland: Remove unnecessary dispatch of frame
callback source"), exposing the issue.
Fixes: a7a7933e0 ("wayland: Emit frame events in GSource after "empty" updates")
Closes: https://gitlab.gnome.org/GNOME/mutter/-/issues/3263
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/3549>
2024-01-26 17:08:27 +00:00
|
|
|
if (clutter_frame_get_result (frame) ==
|
|
|
|
CLUTTER_FRAME_RESULT_PENDING_PRESENTED ||
|
2023-09-24 16:18:42 +03:00
|
|
|
!clutter_frame_get_frame_deadline (frame,
|
|
|
|
&frame_deadline_us))
|
2023-02-11 07:02:40 +01:00
|
|
|
{
|
|
|
|
g_source_set_ready_time (source, -1);
|
|
|
|
emit_frame_callbacks_for_stage_view (compositor, stage_view);
|
2023-09-25 12:41:48 +03:00
|
|
|
return;
|
2023-02-11 07:02:40 +01:00
|
|
|
}
|
2023-09-25 12:41:48 +03:00
|
|
|
|
|
|
|
if (frame_deadline_us <= g_get_monotonic_time ())
|
2023-02-11 07:02:40 +01:00
|
|
|
{
|
2023-09-25 12:41:48 +03:00
|
|
|
g_source_set_ready_time (source, -1);
|
|
|
|
emit_frame_callbacks_for_stage_view (compositor, stage_view);
|
|
|
|
return;
|
2023-02-11 07:02:40 +01:00
|
|
|
}
|
2023-09-25 12:41:48 +03:00
|
|
|
|
|
|
|
if (g_source_get_ready_time (source) != -1)
|
|
|
|
return;
|
|
|
|
|
|
|
|
g_source_set_ready_time (source, frame_deadline_us);
|
2023-02-11 07:02:40 +01:00
|
|
|
#else
|
|
|
|
emit_frame_callbacks_for_stage_view (compositor, stage_view);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2013-05-03 18:51:22 +01:00
|
|
|
void
|
|
|
|
meta_wayland_compositor_set_input_focus (MetaWaylandCompositor *compositor,
|
|
|
|
MetaWindow *window)
|
|
|
|
{
|
2022-05-18 13:51:44 +02:00
|
|
|
MetaWaylandSurface *surface;
|
2013-05-03 18:51:22 +01:00
|
|
|
|
2022-05-18 13:51:44 +02:00
|
|
|
if (window)
|
|
|
|
surface = meta_window_get_wayland_surface (window);
|
|
|
|
else
|
|
|
|
surface = NULL;
|
2014-07-10 10:13:54 -04:00
|
|
|
meta_wayland_seat_set_input_focus (compositor->seat, surface);
|
2013-05-03 18:51:22 +01:00
|
|
|
}
|
|
|
|
|
2014-10-07 20:08:31 -07:00
|
|
|
static void
|
2017-06-05 20:09:01 +08:00
|
|
|
wl_compositor_create_surface (struct wl_client *client,
|
2014-10-07 20:08:31 -07:00
|
|
|
struct wl_resource *resource,
|
2017-06-05 20:09:01 +08:00
|
|
|
uint32_t id)
|
2014-10-07 20:08:31 -07:00
|
|
|
{
|
|
|
|
MetaWaylandCompositor *compositor = wl_resource_get_user_data (resource);
|
2017-06-05 20:09:01 +08:00
|
|
|
|
2014-10-07 20:08:31 -07:00
|
|
|
meta_wayland_surface_create (compositor, client, resource, id);
|
|
|
|
}
|
|
|
|
|
2012-01-07 22:21:32 +00:00
|
|
|
static void
|
2017-06-05 20:09:01 +08:00
|
|
|
wl_compositor_create_region (struct wl_client *client,
|
2014-10-07 20:12:36 -07:00
|
|
|
struct wl_resource *resource,
|
2017-06-05 20:09:01 +08:00
|
|
|
uint32_t id)
|
2012-01-07 22:21:32 +00:00
|
|
|
{
|
2014-10-07 20:12:36 -07:00
|
|
|
MetaWaylandCompositor *compositor = wl_resource_get_user_data (resource);
|
2017-06-05 20:09:01 +08:00
|
|
|
|
2014-10-07 20:12:36 -07:00
|
|
|
meta_wayland_region_create (compositor, client, resource, id);
|
2012-01-07 22:21:32 +00:00
|
|
|
}
|
|
|
|
|
2015-09-24 01:20:33 +02:00
|
|
|
static const struct wl_compositor_interface meta_wayland_wl_compositor_interface = {
|
2014-08-04 10:26:55 -04:00
|
|
|
wl_compositor_create_surface,
|
|
|
|
wl_compositor_create_region
|
2012-01-07 22:21:32 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static void
|
|
|
|
compositor_bind (struct wl_client *client,
|
2017-06-05 20:09:01 +08:00
|
|
|
void *data,
|
|
|
|
uint32_t version,
|
|
|
|
uint32_t id)
|
2012-01-07 22:21:32 +00:00
|
|
|
{
|
|
|
|
MetaWaylandCompositor *compositor = data;
|
|
|
|
struct wl_resource *resource;
|
|
|
|
|
2014-08-04 10:24:59 -04:00
|
|
|
resource = wl_resource_create (client, &wl_compositor_interface, version, id);
|
2017-06-05 20:09:01 +08:00
|
|
|
wl_resource_set_implementation (resource,
|
|
|
|
&meta_wayland_wl_compositor_interface,
|
|
|
|
compositor, NULL);
|
2012-01-07 22:21:32 +00:00
|
|
|
}
|
|
|
|
|
2014-03-18 18:00:48 +01:00
|
|
|
/**
|
|
|
|
* meta_wayland_compositor_update:
|
|
|
|
* @compositor: the #MetaWaylandCompositor instance
|
|
|
|
* @event: the #ClutterEvent used to update @seat's state
|
|
|
|
*
|
|
|
|
* This is used to update display server state like updating cursor
|
|
|
|
* position and keeping track of buttons and keys pressed. It must be
|
|
|
|
* called for all input events coming from the underlying devices.
|
|
|
|
*/
|
2013-11-13 21:41:29 +01:00
|
|
|
void
|
|
|
|
meta_wayland_compositor_update (MetaWaylandCompositor *compositor,
|
|
|
|
const ClutterEvent *event)
|
2013-08-23 15:07:57 +02:00
|
|
|
{
|
2023-11-02 14:35:23 +01:00
|
|
|
meta_wayland_seat_update (compositor->seat, event);
|
2013-08-23 15:07:57 +02:00
|
|
|
}
|
|
|
|
|
2020-10-08 15:34:28 +03:00
|
|
|
static MetaWaylandOutput *
|
|
|
|
get_output_for_stage_view (MetaWaylandCompositor *compositor,
|
|
|
|
ClutterStageView *stage_view)
|
|
|
|
{
|
|
|
|
MetaCrtc *crtc;
|
|
|
|
MetaOutput *output;
|
|
|
|
MetaMonitor *monitor;
|
|
|
|
|
|
|
|
crtc = meta_renderer_view_get_crtc (META_RENDERER_VIEW (stage_view));
|
|
|
|
|
|
|
|
/*
|
|
|
|
* All outputs occupy the same region of the screen, as their contents are
|
|
|
|
* the same, so pick the first one.
|
|
|
|
*/
|
|
|
|
output = meta_crtc_get_outputs (crtc)->data;
|
|
|
|
|
|
|
|
monitor = meta_output_get_monitor (output);
|
2021-02-05 17:22:30 +01:00
|
|
|
return g_hash_table_lookup (compositor->outputs,
|
|
|
|
meta_monitor_get_spec (monitor));
|
2020-10-08 15:34:28 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
on_presented (ClutterStage *stage,
|
|
|
|
ClutterStageView *stage_view,
|
|
|
|
ClutterFrameInfo *frame_info,
|
|
|
|
MetaWaylandCompositor *compositor)
|
|
|
|
{
|
|
|
|
MetaWaylandPresentationFeedback *feedback, *next;
|
|
|
|
struct wl_list *feedbacks;
|
|
|
|
MetaWaylandOutput *output;
|
|
|
|
|
|
|
|
feedbacks =
|
|
|
|
meta_wayland_presentation_time_ensure_feedbacks (&compositor->presentation_time,
|
|
|
|
stage_view);
|
|
|
|
|
|
|
|
output = get_output_for_stage_view (compositor, stage_view);
|
|
|
|
|
|
|
|
wl_list_for_each_safe (feedback, next, feedbacks, link)
|
|
|
|
{
|
|
|
|
meta_wayland_presentation_feedback_present (feedback,
|
|
|
|
frame_info,
|
|
|
|
output);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-11-02 14:30:59 +01:00
|
|
|
static void
|
|
|
|
on_started (MetaContext *context,
|
|
|
|
MetaWaylandCompositor *compositor)
|
|
|
|
{
|
|
|
|
MetaDisplay *display = meta_context_get_display (context);
|
|
|
|
|
|
|
|
g_signal_connect_object (display, "focus-window",
|
|
|
|
G_CALLBACK (meta_wayland_compositor_update_focus),
|
|
|
|
compositor,
|
|
|
|
G_CONNECT_SWAPPED);
|
|
|
|
}
|
|
|
|
|
2014-03-18 18:00:48 +01:00
|
|
|
/**
|
|
|
|
* meta_wayland_compositor_handle_event:
|
|
|
|
* @compositor: the #MetaWaylandCompositor instance
|
|
|
|
* @event: the #ClutterEvent to be sent
|
|
|
|
*
|
|
|
|
* This method sends events to the focused wayland client, if any.
|
|
|
|
*
|
|
|
|
* Return value: whether @event was sent to a wayland client.
|
|
|
|
*/
|
2013-10-04 02:29:43 -04:00
|
|
|
gboolean
|
|
|
|
meta_wayland_compositor_handle_event (MetaWaylandCompositor *compositor,
|
|
|
|
const ClutterEvent *event)
|
2013-05-03 18:51:22 +01:00
|
|
|
{
|
2013-10-04 02:33:10 -04:00
|
|
|
return meta_wayland_seat_handle_event (compositor->seat, event);
|
2013-05-03 18:51:22 +01:00
|
|
|
}
|
|
|
|
|
2015-08-21 16:25:53 -04:00
|
|
|
/* meta_wayland_compositor_update_key_state:
|
|
|
|
* @compositor: the #MetaWaylandCompositor
|
|
|
|
* @key_vector: bit vector of key states
|
|
|
|
* @key_vector_len: length of @key_vector
|
|
|
|
* @offset: the key for the first evdev keycode is found at this offset in @key_vector
|
|
|
|
*
|
|
|
|
* This function is used to resynchronize the key state that Mutter
|
|
|
|
* is tracking with the actual keyboard state. This is useful, for example,
|
|
|
|
* to handle changes in key state when a nested compositor doesn't
|
|
|
|
* have focus. We need to fix up the XKB modifier tracking and deliver
|
|
|
|
* any modifier changes to clients.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
meta_wayland_compositor_update_key_state (MetaWaylandCompositor *compositor,
|
|
|
|
char *key_vector,
|
|
|
|
int key_vector_len,
|
|
|
|
int offset)
|
|
|
|
{
|
2016-04-01 16:39:30 +08:00
|
|
|
meta_wayland_keyboard_update_key_state (compositor->seat->keyboard,
|
2015-08-21 16:25:53 -04:00
|
|
|
key_vector, key_vector_len, offset);
|
|
|
|
}
|
|
|
|
|
2015-02-25 16:26:01 +01:00
|
|
|
void
|
2020-04-27 15:43:19 +02:00
|
|
|
meta_wayland_compositor_add_frame_callback_surface (MetaWaylandCompositor *compositor,
|
|
|
|
MetaWaylandSurface *surface)
|
2015-02-25 16:26:01 +01:00
|
|
|
{
|
2020-04-27 15:43:19 +02:00
|
|
|
if (g_list_find (compositor->frame_callback_surfaces, surface))
|
|
|
|
return;
|
2015-02-25 16:26:01 +01:00
|
|
|
|
2020-04-27 15:43:19 +02:00
|
|
|
compositor->frame_callback_surfaces =
|
|
|
|
g_list_prepend (compositor->frame_callback_surfaces, surface);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
meta_wayland_compositor_remove_frame_callback_surface (MetaWaylandCompositor *compositor,
|
|
|
|
MetaWaylandSurface *surface)
|
|
|
|
{
|
|
|
|
compositor->frame_callback_surfaces =
|
|
|
|
g_list_remove (compositor->frame_callback_surfaces, surface);
|
2015-02-25 16:26:01 +01:00
|
|
|
}
|
|
|
|
|
2020-10-08 15:41:31 +03:00
|
|
|
void
|
|
|
|
meta_wayland_compositor_add_presentation_feedback_surface (MetaWaylandCompositor *compositor,
|
|
|
|
MetaWaylandSurface *surface)
|
|
|
|
{
|
|
|
|
if (g_list_find (compositor->presentation_time.feedback_surfaces, surface))
|
|
|
|
return;
|
|
|
|
|
|
|
|
compositor->presentation_time.feedback_surfaces =
|
|
|
|
g_list_prepend (compositor->presentation_time.feedback_surfaces, surface);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
meta_wayland_compositor_remove_presentation_feedback_surface (MetaWaylandCompositor *compositor,
|
|
|
|
MetaWaylandSurface *surface)
|
|
|
|
{
|
|
|
|
compositor->presentation_time.feedback_surfaces =
|
|
|
|
g_list_remove (compositor->presentation_time.feedback_surfaces, surface);
|
|
|
|
}
|
|
|
|
|
2021-05-30 15:00:13 +02:00
|
|
|
GQueue *
|
|
|
|
meta_wayland_compositor_get_committed_transactions (MetaWaylandCompositor *compositor)
|
|
|
|
{
|
|
|
|
return &compositor->committed_transactions;
|
|
|
|
}
|
|
|
|
|
2023-09-29 16:19:42 +02:00
|
|
|
static gboolean
|
2013-08-20 18:03:26 +02:00
|
|
|
set_gnome_env (const char *name,
|
|
|
|
const char *value)
|
|
|
|
{
|
|
|
|
GDBusConnection *session_bus;
|
2014-03-26 12:02:08 -04:00
|
|
|
GError *error = NULL;
|
2020-01-24 18:47:43 +01:00
|
|
|
g_autoptr (GVariant) result = NULL;
|
2013-08-20 18:03:26 +02:00
|
|
|
|
|
|
|
setenv (name, value, TRUE);
|
|
|
|
|
|
|
|
session_bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
|
|
|
|
g_assert (session_bus);
|
|
|
|
|
2020-01-24 18:47:43 +01:00
|
|
|
result = g_dbus_connection_call_sync (session_bus,
|
2013-08-20 18:03:26 +02:00
|
|
|
"org.gnome.SessionManager",
|
|
|
|
"/org/gnome/SessionManager",
|
|
|
|
"org.gnome.SessionManager",
|
|
|
|
"Setenv",
|
|
|
|
g_variant_new ("(ss)", name, value),
|
|
|
|
NULL,
|
2014-05-15 14:16:20 -04:00
|
|
|
G_DBUS_CALL_FLAGS_NO_AUTO_START,
|
2013-08-20 18:03:26 +02:00
|
|
|
-1, NULL, &error);
|
|
|
|
if (error)
|
|
|
|
{
|
2017-11-06 20:37:34 +01:00
|
|
|
char *remote_error;
|
|
|
|
|
|
|
|
remote_error = g_dbus_error_get_remote_error (error);
|
|
|
|
if (g_strcmp0 (remote_error, "org.gnome.SessionManager.NotInInitialization") != 0)
|
2020-10-02 17:47:22 +02:00
|
|
|
{
|
|
|
|
meta_warning ("Failed to set environment variable %s for gnome-session: %s",
|
|
|
|
name, error->message);
|
|
|
|
}
|
2014-03-26 12:02:08 -04:00
|
|
|
|
2017-11-06 20:37:34 +01:00
|
|
|
g_free (remote_error);
|
2014-03-26 12:02:08 -04:00
|
|
|
g_error_free (error);
|
2023-09-29 16:19:42 +02:00
|
|
|
|
|
|
|
return FALSE;
|
2013-08-20 18:03:26 +02:00
|
|
|
}
|
2023-09-29 16:19:42 +02:00
|
|
|
return TRUE;
|
2013-08-20 18:03:26 +02:00
|
|
|
}
|
|
|
|
|
2015-09-24 01:18:15 +02:00
|
|
|
static void meta_wayland_log_func (const char *, va_list) G_GNUC_PRINTF (1, 0);
|
|
|
|
|
2013-11-19 20:04:49 -05:00
|
|
|
static void
|
|
|
|
meta_wayland_log_func (const char *fmt,
|
|
|
|
va_list arg)
|
|
|
|
{
|
|
|
|
char *str = g_strdup_vprintf (fmt, arg);
|
|
|
|
g_warning ("WL: %s", str);
|
|
|
|
g_free (str);
|
|
|
|
}
|
|
|
|
|
2021-03-03 22:00:05 +01:00
|
|
|
void
|
|
|
|
meta_wayland_compositor_prepare_shutdown (MetaWaylandCompositor *compositor)
|
|
|
|
{
|
2022-06-15 13:12:35 +02:00
|
|
|
g_signal_emit (compositor, signals[PREPARE_SHUTDOWN], 0, NULL);
|
2021-03-03 22:00:05 +01:00
|
|
|
|
|
|
|
if (compositor->wayland_display)
|
|
|
|
wl_display_destroy_clients (compositor->wayland_display);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
meta_wayland_compositor_finalize (GObject *object)
|
|
|
|
{
|
|
|
|
MetaWaylandCompositor *compositor = META_WAYLAND_COMPOSITOR (object);
|
2023-01-27 15:16:14 +01:00
|
|
|
MetaWaylandCompositorPrivate *priv =
|
|
|
|
meta_wayland_compositor_get_instance_private (compositor);
|
2022-07-23 16:37:15 +02:00
|
|
|
MetaBackend *backend = meta_context_get_backend (compositor->context);
|
|
|
|
ClutterActor *stage = meta_backend_get_stage (backend);
|
|
|
|
|
2022-07-23 16:52:52 +02:00
|
|
|
meta_wayland_activation_finalize (compositor);
|
2022-07-23 17:06:59 +02:00
|
|
|
meta_wayland_outputs_finalize (compositor);
|
2022-07-23 17:00:09 +02:00
|
|
|
meta_wayland_presentation_time_finalize (compositor);
|
2022-07-23 16:52:52 +02:00
|
|
|
|
2022-07-23 16:42:56 +02:00
|
|
|
g_hash_table_destroy (compositor->scheduled_surface_associations);
|
|
|
|
|
2022-07-23 16:37:15 +02:00
|
|
|
g_signal_handlers_disconnect_by_func (stage, on_after_update, compositor);
|
|
|
|
g_signal_handlers_disconnect_by_func (stage, on_presented, compositor);
|
2021-03-03 22:00:05 +01:00
|
|
|
|
2021-05-30 15:00:13 +02:00
|
|
|
meta_wayland_transaction_finalize (compositor);
|
|
|
|
|
2021-08-06 15:23:15 +02:00
|
|
|
g_clear_object (&compositor->dma_buf_manager);
|
2021-08-04 10:12:33 +02:00
|
|
|
|
2021-03-03 22:00:05 +01:00
|
|
|
g_clear_pointer (&compositor->seat, meta_wayland_seat_free);
|
2023-11-02 14:35:23 +01:00
|
|
|
meta_wayland_tablet_manager_finalize (compositor);
|
2021-03-03 22:00:05 +01:00
|
|
|
|
2023-01-27 15:16:14 +01:00
|
|
|
g_clear_pointer (&priv->filter_manager, meta_wayland_filter_manager_free);
|
2023-02-11 07:02:40 +01:00
|
|
|
g_clear_pointer (&priv->frame_callback_sources, g_hash_table_destroy);
|
2023-01-27 15:16:14 +01:00
|
|
|
|
2021-03-03 22:00:05 +01:00
|
|
|
g_clear_pointer (&compositor->display_name, g_free);
|
|
|
|
g_clear_pointer (&compositor->wayland_display, wl_display_destroy);
|
2021-10-28 15:30:41 +02:00
|
|
|
g_clear_pointer (&compositor->source, g_source_destroy);
|
2021-03-03 22:00:05 +01:00
|
|
|
|
|
|
|
G_OBJECT_CLASS (meta_wayland_compositor_parent_class)->finalize (object);
|
|
|
|
}
|
|
|
|
|
2014-08-18 16:54:15 -04:00
|
|
|
static void
|
|
|
|
meta_wayland_compositor_init (MetaWaylandCompositor *compositor)
|
|
|
|
{
|
2023-01-27 15:16:14 +01:00
|
|
|
MetaWaylandCompositorPrivate *priv =
|
|
|
|
meta_wayland_compositor_get_instance_private (compositor);
|
|
|
|
|
2018-04-06 15:47:50 +02:00
|
|
|
compositor->scheduled_surface_associations = g_hash_table_new (NULL, NULL);
|
2014-08-18 16:54:15 -04:00
|
|
|
|
|
|
|
wl_log_set_handler_server (meta_wayland_log_func);
|
2012-01-07 22:21:32 +00:00
|
|
|
|
|
|
|
compositor->wayland_display = wl_display_create ();
|
|
|
|
if (compositor->wayland_display == NULL)
|
2014-08-18 16:54:15 -04:00
|
|
|
g_error ("Failed to create the global wl_display");
|
2023-01-27 15:16:14 +01:00
|
|
|
|
|
|
|
priv->filter_manager = meta_wayland_filter_manager_new (compositor);
|
2023-02-11 07:02:40 +01:00
|
|
|
priv->frame_callback_sources =
|
|
|
|
g_hash_table_new_full (NULL, NULL, NULL,
|
|
|
|
(GDestroyNotify) g_source_destroy);
|
2018-08-23 15:49:17 +02:00
|
|
|
}
|
2012-01-07 22:21:32 +00:00
|
|
|
|
2018-08-23 15:49:17 +02:00
|
|
|
static void
|
|
|
|
meta_wayland_compositor_class_init (MetaWaylandCompositorClass *klass)
|
|
|
|
{
|
2021-03-03 22:00:05 +01:00
|
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
|
|
|
|
|
|
object_class->finalize = meta_wayland_compositor_finalize;
|
2022-06-15 13:12:35 +02:00
|
|
|
|
|
|
|
signals[PREPARE_SHUTDOWN] =
|
|
|
|
g_signal_new ("prepare-shutdown",
|
|
|
|
G_TYPE_FROM_CLASS (klass),
|
|
|
|
G_SIGNAL_RUN_LAST,
|
|
|
|
0,
|
|
|
|
NULL, NULL, NULL,
|
|
|
|
G_TYPE_NONE, 0);
|
2018-08-23 15:49:17 +02:00
|
|
|
}
|
|
|
|
|
2016-12-05 21:23:46 +08:00
|
|
|
void
|
2019-01-20 11:46:46 +01:00
|
|
|
meta_wayland_override_display_name (const char *display_name)
|
2016-12-05 21:23:46 +08:00
|
|
|
{
|
2017-08-18 14:18:14 +08:00
|
|
|
g_clear_pointer (&_display_name_override, g_free);
|
2016-12-05 21:23:46 +08:00
|
|
|
_display_name_override = g_strdup (display_name);
|
|
|
|
}
|
|
|
|
|
2021-05-06 12:12:34 +02:00
|
|
|
static void
|
|
|
|
meta_wayland_init_egl (MetaWaylandCompositor *compositor)
|
|
|
|
{
|
2022-05-13 21:51:53 +02:00
|
|
|
MetaWaylandCompositorPrivate *priv =
|
|
|
|
meta_wayland_compositor_get_instance_private (compositor);
|
2022-05-30 23:48:44 +02:00
|
|
|
MetaContext *context = meta_wayland_compositor_get_context (compositor);
|
|
|
|
MetaBackend *backend = meta_context_get_backend (context);
|
2021-05-06 12:12:34 +02:00
|
|
|
MetaEgl *egl = meta_backend_get_egl (backend);
|
|
|
|
ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend);
|
|
|
|
CoglContext *cogl_context =
|
|
|
|
clutter_backend_get_cogl_context (clutter_backend);
|
|
|
|
EGLDisplay egl_display = cogl_egl_context_get_egl_display (cogl_context);
|
|
|
|
g_autoptr (GError) error = NULL;
|
|
|
|
|
|
|
|
if (!meta_egl_has_extensions (egl, egl_display, NULL,
|
|
|
|
"EGL_WL_bind_wayland_display",
|
|
|
|
NULL))
|
|
|
|
{
|
|
|
|
meta_topic (META_DEBUG_WAYLAND,
|
|
|
|
"Not binding Wayland display, missing extension");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
meta_topic (META_DEBUG_WAYLAND,
|
|
|
|
"Binding Wayland EGL display");
|
|
|
|
|
2022-05-13 21:51:53 +02:00
|
|
|
if (meta_egl_bind_wayland_display (egl,
|
|
|
|
egl_display,
|
|
|
|
compositor->wayland_display,
|
|
|
|
&error))
|
|
|
|
priv->is_wayland_egl_display_bound = TRUE;
|
|
|
|
else
|
2021-05-06 12:12:34 +02:00
|
|
|
g_warning ("Failed to bind Wayland display: %s", error->message);
|
|
|
|
}
|
|
|
|
|
2021-08-04 10:12:33 +02:00
|
|
|
static void
|
|
|
|
init_dma_buf_support (MetaWaylandCompositor *compositor)
|
|
|
|
{
|
|
|
|
g_autoptr (GError) error = NULL;
|
|
|
|
|
|
|
|
compositor->dma_buf_manager = meta_wayland_dma_buf_manager_new (compositor,
|
|
|
|
&error);
|
|
|
|
if (!compositor->dma_buf_manager)
|
|
|
|
{
|
|
|
|
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED))
|
|
|
|
{
|
|
|
|
meta_topic (META_DEBUG_WAYLAND,
|
|
|
|
"Wayland DMA buffer protocol support not enabled: %s",
|
|
|
|
error->message);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
g_warning ("Wayland DMA buffer protocol support not enabled: %s",
|
|
|
|
error->message);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-06 16:02:34 +02:00
|
|
|
MetaWaylandCompositor *
|
|
|
|
meta_wayland_compositor_new (MetaContext *context)
|
2014-08-18 16:54:15 -04:00
|
|
|
{
|
2021-05-06 16:02:34 +02:00
|
|
|
MetaBackend *backend = meta_context_get_backend (context);
|
2021-03-03 22:00:05 +01:00
|
|
|
ClutterActor *stage = meta_backend_get_stage (backend);
|
2021-05-06 16:02:34 +02:00
|
|
|
MetaWaylandCompositor *compositor;
|
2014-08-18 16:54:15 -04:00
|
|
|
GSource *wayland_event_source;
|
2023-02-10 16:15:40 +01:00
|
|
|
#ifdef HAVE_XWAYLAND
|
2021-04-16 20:34:29 +02:00
|
|
|
MetaX11DisplayPolicy x11_display_policy;
|
2023-02-10 16:15:40 +01:00
|
|
|
#endif
|
2012-01-07 22:21:32 +00:00
|
|
|
|
2021-05-06 16:02:34 +02:00
|
|
|
compositor = g_object_new (META_TYPE_WAYLAND_COMPOSITOR, NULL);
|
|
|
|
compositor->context = context;
|
|
|
|
|
2014-07-10 11:05:59 -04:00
|
|
|
wayland_event_source = wayland_event_source_new (compositor->wayland_display);
|
2012-01-07 22:21:32 +00:00
|
|
|
|
|
|
|
/* XXX: Here we are setting the wayland event source to have a
|
|
|
|
* slightly lower priority than the X event source, because we are
|
|
|
|
* much more likely to get confused being told about surface changes
|
|
|
|
* relating to X clients when we don't know what's happened to them
|
|
|
|
* according to the X protocol.
|
2014-10-07 20:51:28 -07:00
|
|
|
*/
|
2022-05-09 11:48:57 +02:00
|
|
|
g_source_set_priority (wayland_event_source, META_PRIORITY_EVENTS + 1);
|
2014-07-10 11:05:59 -04:00
|
|
|
g_source_attach (wayland_event_source, NULL);
|
2021-10-28 15:30:41 +02:00
|
|
|
compositor->source = wayland_event_source;
|
|
|
|
g_source_unref (wayland_event_source);
|
2012-01-07 22:21:32 +00:00
|
|
|
|
2020-06-03 11:38:32 +02:00
|
|
|
g_signal_connect (stage, "after-update",
|
|
|
|
G_CALLBACK (on_after_update), compositor);
|
2020-10-08 15:34:28 +03:00
|
|
|
g_signal_connect (stage, "presented",
|
|
|
|
G_CALLBACK (on_presented), compositor);
|
2020-06-03 11:38:32 +02:00
|
|
|
|
2023-11-02 14:30:59 +01:00
|
|
|
g_signal_connect (context, "started",
|
|
|
|
G_CALLBACK (on_started), compositor);
|
|
|
|
|
2014-10-07 20:54:28 -07:00
|
|
|
if (!wl_global_create (compositor->wayland_display,
|
2022-01-03 19:36:26 +01:00
|
|
|
&wl_compositor_interface,
|
|
|
|
META_WL_COMPOSITOR_VERSION,
|
|
|
|
compositor, compositor_bind))
|
2014-10-07 20:54:28 -07:00
|
|
|
g_error ("Failed to register the global wl_compositor");
|
|
|
|
|
2021-05-06 12:12:34 +02:00
|
|
|
meta_wayland_init_egl (compositor);
|
2019-09-18 16:18:58 +02:00
|
|
|
meta_wayland_init_shm (compositor);
|
2014-08-19 18:27:21 -04:00
|
|
|
|
2014-04-22 18:05:44 -04:00
|
|
|
meta_wayland_outputs_init (compositor);
|
|
|
|
meta_wayland_data_device_manager_init (compositor);
|
2020-05-13 18:07:27 +02:00
|
|
|
meta_wayland_data_device_primary_manager_init (compositor);
|
2017-12-20 17:40:22 +08:00
|
|
|
meta_wayland_subsurfaces_init (compositor);
|
2014-04-22 18:05:44 -04:00
|
|
|
meta_wayland_shell_init (compositor);
|
2015-07-22 16:50:20 +02:00
|
|
|
meta_wayland_pointer_gestures_init (compositor);
|
2015-01-09 17:28:42 +01:00
|
|
|
meta_wayland_tablet_manager_init (compositor);
|
2014-04-22 18:05:44 -04:00
|
|
|
meta_wayland_seat_init (compositor);
|
2015-06-02 16:26:34 +08:00
|
|
|
meta_wayland_relative_pointer_init (compositor);
|
2015-06-17 12:10:52 +08:00
|
|
|
meta_wayland_pointer_constraints_init (compositor);
|
2015-09-24 08:05:25 +08:00
|
|
|
meta_wayland_xdg_foreign_init (compositor);
|
2020-02-06 02:00:56 -05:00
|
|
|
meta_wayland_legacy_xdg_foreign_init (compositor);
|
2021-08-04 10:12:33 +02:00
|
|
|
init_dma_buf_support (compositor);
|
2022-01-19 11:49:32 +01:00
|
|
|
meta_wayland_init_single_pixel_buffer_manager (compositor);
|
2017-03-21 11:47:16 +01:00
|
|
|
meta_wayland_keyboard_shortcuts_inhibit_init (compositor);
|
2017-06-14 11:27:14 +02:00
|
|
|
meta_wayland_surface_inhibit_shortcuts_dialog_init ();
|
2018-08-13 18:59:02 +02:00
|
|
|
meta_wayland_text_input_init (compositor);
|
2020-10-07 12:02:41 +03:00
|
|
|
meta_wayland_init_presentation_time (compositor);
|
2020-10-09 16:23:32 +02:00
|
|
|
meta_wayland_activation_init (compositor);
|
2021-05-30 15:00:13 +02:00
|
|
|
meta_wayland_transaction_init (compositor);
|
2023-08-26 01:40:20 +03:00
|
|
|
meta_wayland_idle_inhibit_init (compositor);
|
2012-01-07 22:21:32 +00:00
|
|
|
|
2018-11-06 17:09:03 +01:00
|
|
|
#ifdef HAVE_WAYLAND_EGLSTREAM
|
2022-01-03 19:36:26 +01:00
|
|
|
{
|
|
|
|
gboolean should_enable_eglstream_controller = TRUE;
|
2021-10-14 18:36:43 +02:00
|
|
|
#if defined(HAVE_EGL_DEVICE) && defined(HAVE_NATIVE_BACKEND)
|
2022-01-03 19:36:26 +01:00
|
|
|
MetaRenderer *renderer = meta_backend_get_renderer (backend);
|
2021-10-14 18:36:43 +02:00
|
|
|
|
2022-01-03 19:36:26 +01:00
|
|
|
if (META_IS_RENDERER_NATIVE (renderer))
|
|
|
|
{
|
|
|
|
MetaRendererNative *renderer_native = META_RENDERER_NATIVE (renderer);
|
2021-10-14 18:36:43 +02:00
|
|
|
|
2022-01-03 19:36:26 +01:00
|
|
|
if (meta_renderer_native_get_mode (renderer_native) ==
|
|
|
|
META_RENDERER_NATIVE_MODE_GBM)
|
|
|
|
should_enable_eglstream_controller = FALSE;
|
|
|
|
}
|
2021-10-14 18:36:43 +02:00
|
|
|
#endif /* defined(HAVE_EGL_DEVICE) && defined(HAVE_NATIVE_BACKEND) */
|
|
|
|
|
2022-01-03 19:36:26 +01:00
|
|
|
if (should_enable_eglstream_controller)
|
|
|
|
meta_wayland_eglstream_controller_init (compositor);
|
|
|
|
}
|
2021-10-14 18:36:43 +02:00
|
|
|
#endif /* HAVE_WAYLAND_EGLSTREAM */
|
2017-06-27 16:37:30 -07:00
|
|
|
|
2023-02-10 16:15:40 +01:00
|
|
|
#ifdef HAVE_XWAYLAND
|
2023-02-01 17:55:41 +01:00
|
|
|
meta_wayland_x11_interop_init (compositor);
|
|
|
|
|
2021-04-16 20:34:29 +02:00
|
|
|
x11_display_policy =
|
|
|
|
meta_context_get_x11_display_policy (compositor->context);
|
|
|
|
if (x11_display_policy != META_X11_DISPLAY_POLICY_DISABLED)
|
2017-08-27 20:44:58 +02:00
|
|
|
{
|
2020-12-08 17:42:05 +01:00
|
|
|
g_autoptr (GError) error = NULL;
|
|
|
|
|
|
|
|
if (!meta_xwayland_init (&compositor->xwayland_manager,
|
2021-05-06 18:49:25 +02:00
|
|
|
compositor,
|
2020-12-08 17:42:05 +01:00
|
|
|
compositor->wayland_display,
|
|
|
|
&error))
|
|
|
|
g_error ("Failed to start X Wayland: %s", error->message);
|
2017-08-27 20:44:58 +02:00
|
|
|
}
|
2022-06-13 10:09:26 +02:00
|
|
|
#endif
|
2015-07-02 10:41:37 +02:00
|
|
|
|
2016-12-05 21:23:46 +08:00
|
|
|
if (_display_name_override)
|
|
|
|
{
|
2017-08-18 14:18:14 +08:00
|
|
|
compositor->display_name = g_steal_pointer (&_display_name_override);
|
2016-12-05 21:23:46 +08:00
|
|
|
|
|
|
|
if (wl_display_add_socket (compositor->wayland_display,
|
2017-08-18 14:18:14 +08:00
|
|
|
compositor->display_name) != 0)
|
2016-12-05 21:23:46 +08:00
|
|
|
g_error ("Failed to create_socket");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2017-09-04 12:32:53 +08:00
|
|
|
const char *display_name;
|
|
|
|
|
|
|
|
display_name = wl_display_add_socket_auto (compositor->wayland_display);
|
|
|
|
if (!display_name)
|
2016-12-05 21:23:46 +08:00
|
|
|
g_error ("Failed to create socket");
|
2017-09-04 12:32:53 +08:00
|
|
|
|
|
|
|
compositor->display_name = g_strdup (display_name);
|
2016-12-05 21:23:46 +08:00
|
|
|
}
|
2012-01-07 22:21:32 +00:00
|
|
|
|
2020-10-20 21:38:05 +02:00
|
|
|
g_message ("Using Wayland display name '%s'", compositor->display_name);
|
|
|
|
|
2023-02-10 16:15:40 +01:00
|
|
|
#ifdef HAVE_XWAYLAND
|
2021-04-16 20:34:29 +02:00
|
|
|
if (x11_display_policy != META_X11_DISPLAY_POLICY_DISABLED)
|
2019-06-18 16:12:46 +02:00
|
|
|
{
|
2023-09-29 16:39:06 +02:00
|
|
|
gboolean status = TRUE;
|
|
|
|
|
|
|
|
status &=
|
|
|
|
set_gnome_env ("GNOME_SETUP_DISPLAY", compositor->xwayland_manager.private_connection.name);
|
|
|
|
status &=
|
|
|
|
set_gnome_env ("DISPLAY", compositor->xwayland_manager.public_connection.name);
|
|
|
|
status &=
|
|
|
|
set_gnome_env ("XAUTHORITY", compositor->xwayland_manager.auth_file);
|
|
|
|
|
|
|
|
meta_xwayland_set_should_enable_ei_portal (&compositor->xwayland_manager, status);
|
2019-06-18 16:12:46 +02:00
|
|
|
}
|
2023-02-10 16:15:40 +01:00
|
|
|
#endif
|
2017-08-27 20:44:58 +02:00
|
|
|
|
2014-09-11 10:07:34 -04:00
|
|
|
set_gnome_env ("WAYLAND_DISPLAY", meta_wayland_get_wayland_display_name (compositor));
|
2021-05-06 16:02:34 +02:00
|
|
|
|
|
|
|
return compositor;
|
2014-09-11 10:07:34 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
const char *
|
|
|
|
meta_wayland_get_wayland_display_name (MetaWaylandCompositor *compositor)
|
|
|
|
{
|
|
|
|
return compositor->display_name;
|
|
|
|
}
|
|
|
|
|
2022-06-01 10:35:29 +02:00
|
|
|
#ifdef HAVE_XWAYLAND
|
2014-09-11 10:07:34 -04:00
|
|
|
const char *
|
2021-01-21 18:56:18 +01:00
|
|
|
meta_wayland_get_public_xwayland_display_name (MetaWaylandCompositor *compositor)
|
|
|
|
{
|
|
|
|
return compositor->xwayland_manager.public_connection.name;
|
|
|
|
}
|
|
|
|
|
|
|
|
const char *
|
|
|
|
meta_wayland_get_private_xwayland_display_name (MetaWaylandCompositor *compositor)
|
2014-09-11 10:07:34 -04:00
|
|
|
{
|
2019-07-19 22:50:31 +02:00
|
|
|
return compositor->xwayland_manager.private_connection.name;
|
2012-01-07 22:21:32 +00:00
|
|
|
}
|
2022-06-01 10:35:29 +02:00
|
|
|
#endif /* HAVE_XWAYLAND */
|
2012-01-07 22:21:32 +00:00
|
|
|
|
2017-03-17 13:34:52 +01:00
|
|
|
void
|
|
|
|
meta_wayland_compositor_restore_shortcuts (MetaWaylandCompositor *compositor,
|
|
|
|
ClutterInputDevice *source)
|
|
|
|
{
|
|
|
|
MetaWaylandKeyboard *keyboard;
|
|
|
|
|
|
|
|
/* Clutter is not multi-seat aware yet, use the default seat instead */
|
|
|
|
keyboard = compositor->seat->keyboard;
|
|
|
|
if (!keyboard || !keyboard->focus_surface)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!meta_wayland_surface_is_shortcuts_inhibited (keyboard->focus_surface,
|
|
|
|
compositor->seat))
|
|
|
|
return;
|
|
|
|
|
|
|
|
meta_wayland_surface_restore_shortcuts (keyboard->focus_surface,
|
|
|
|
compositor->seat);
|
|
|
|
}
|
|
|
|
|
|
|
|
gboolean
|
|
|
|
meta_wayland_compositor_is_shortcuts_inhibited (MetaWaylandCompositor *compositor,
|
|
|
|
ClutterInputDevice *source)
|
|
|
|
{
|
|
|
|
MetaWaylandKeyboard *keyboard;
|
|
|
|
|
|
|
|
/* Clutter is not multi-seat aware yet, use the default seat instead */
|
|
|
|
keyboard = compositor->seat->keyboard;
|
|
|
|
if (keyboard && keyboard->focus_surface != NULL)
|
|
|
|
return meta_wayland_surface_is_shortcuts_inhibited (keyboard->focus_surface,
|
|
|
|
compositor->seat);
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
2017-08-18 14:16:22 +08:00
|
|
|
|
|
|
|
void
|
|
|
|
meta_wayland_compositor_flush_clients (MetaWaylandCompositor *compositor)
|
|
|
|
{
|
|
|
|
wl_display_flush_clients (compositor->wayland_display);
|
|
|
|
}
|
2018-04-06 15:47:50 +02:00
|
|
|
|
|
|
|
static void on_scheduled_association_unmanaged (MetaWindow *window,
|
|
|
|
gpointer user_data);
|
|
|
|
|
|
|
|
static void
|
|
|
|
meta_wayland_compositor_remove_surface_association (MetaWaylandCompositor *compositor,
|
|
|
|
int id)
|
|
|
|
{
|
|
|
|
MetaWindow *window;
|
|
|
|
|
|
|
|
window = g_hash_table_lookup (compositor->scheduled_surface_associations,
|
|
|
|
GINT_TO_POINTER (id));
|
|
|
|
if (window)
|
|
|
|
{
|
|
|
|
g_signal_handlers_disconnect_by_func (window,
|
|
|
|
on_scheduled_association_unmanaged,
|
|
|
|
GINT_TO_POINTER (id));
|
|
|
|
g_hash_table_remove (compositor->scheduled_surface_associations,
|
|
|
|
GINT_TO_POINTER (id));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
on_scheduled_association_unmanaged (MetaWindow *window,
|
|
|
|
gpointer user_data)
|
|
|
|
{
|
2022-05-30 23:48:44 +02:00
|
|
|
MetaDisplay *display = meta_window_get_display (window);
|
|
|
|
MetaContext *context = meta_display_get_context (display);
|
|
|
|
MetaWaylandCompositor *compositor =
|
|
|
|
meta_context_get_wayland_compositor (context);
|
2018-04-06 15:47:50 +02:00
|
|
|
|
|
|
|
meta_wayland_compositor_remove_surface_association (compositor,
|
|
|
|
GPOINTER_TO_INT (user_data));
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
meta_wayland_compositor_schedule_surface_association (MetaWaylandCompositor *compositor,
|
|
|
|
int id,
|
|
|
|
MetaWindow *window)
|
|
|
|
{
|
|
|
|
g_signal_connect (window, "unmanaged",
|
|
|
|
G_CALLBACK (on_scheduled_association_unmanaged),
|
|
|
|
GINT_TO_POINTER (id));
|
|
|
|
g_hash_table_insert (compositor->scheduled_surface_associations,
|
|
|
|
GINT_TO_POINTER (id), window);
|
|
|
|
}
|
|
|
|
|
2022-06-13 10:09:26 +02:00
|
|
|
#ifdef HAVE_XWAYLAND
|
2018-04-06 15:47:50 +02:00
|
|
|
void
|
|
|
|
meta_wayland_compositor_notify_surface_id (MetaWaylandCompositor *compositor,
|
|
|
|
int id,
|
|
|
|
MetaWaylandSurface *surface)
|
|
|
|
{
|
|
|
|
MetaWindow *window;
|
|
|
|
|
|
|
|
window = g_hash_table_lookup (compositor->scheduled_surface_associations,
|
|
|
|
GINT_TO_POINTER (id));
|
|
|
|
if (window)
|
|
|
|
{
|
2022-06-01 10:35:29 +02:00
|
|
|
#ifdef HAVE_XWAYLAND
|
2018-04-06 15:47:50 +02:00
|
|
|
meta_xwayland_associate_window_with_surface (window, surface);
|
2022-06-01 10:35:29 +02:00
|
|
|
#endif
|
2018-04-06 15:47:50 +02:00
|
|
|
meta_wayland_compositor_remove_surface_association (compositor, id);
|
|
|
|
}
|
|
|
|
}
|
2022-06-13 10:09:26 +02:00
|
|
|
#endif
|
2022-05-13 21:51:53 +02:00
|
|
|
|
|
|
|
gboolean
|
|
|
|
meta_wayland_compositor_is_egl_display_bound (MetaWaylandCompositor *compositor)
|
|
|
|
{
|
|
|
|
MetaWaylandCompositorPrivate *priv =
|
|
|
|
meta_wayland_compositor_get_instance_private (compositor);
|
|
|
|
|
|
|
|
return priv->is_wayland_egl_display_bound;
|
|
|
|
}
|
2022-04-05 23:43:38 +02:00
|
|
|
|
2022-06-13 10:09:26 +02:00
|
|
|
#ifdef HAVE_XWAYLAND
|
2022-04-05 23:43:38 +02:00
|
|
|
MetaXWaylandManager *
|
|
|
|
meta_wayland_compositor_get_xwayland_manager (MetaWaylandCompositor *compositor)
|
|
|
|
{
|
|
|
|
return &compositor->xwayland_manager;
|
|
|
|
}
|
2022-06-13 10:09:26 +02:00
|
|
|
#endif
|
2022-08-01 21:18:42 +02:00
|
|
|
|
|
|
|
MetaContext *
|
|
|
|
meta_wayland_compositor_get_context (MetaWaylandCompositor *compositor)
|
|
|
|
{
|
|
|
|
return compositor->context;
|
|
|
|
}
|
2022-09-29 15:05:10 +02:00
|
|
|
|
|
|
|
gboolean
|
|
|
|
meta_wayland_compositor_is_grabbed (MetaWaylandCompositor *compositor)
|
|
|
|
{
|
|
|
|
return meta_wayland_seat_is_grabbed (compositor->seat);
|
|
|
|
}
|
2023-01-27 15:15:15 +01:00
|
|
|
|
2023-06-26 16:08:08 +02:00
|
|
|
/**
|
|
|
|
* meta_wayland_compositor_get_wayland_display:
|
|
|
|
* @compositor: The #MetaWaylandCompositor
|
|
|
|
*
|
|
|
|
* Returns: (transfer none): the Wayland display object
|
|
|
|
*/
|
2023-01-27 15:15:15 +01:00
|
|
|
struct wl_display *
|
|
|
|
meta_wayland_compositor_get_wayland_display (MetaWaylandCompositor *compositor)
|
|
|
|
{
|
|
|
|
return compositor->wayland_display;
|
|
|
|
}
|
2023-01-27 15:16:14 +01:00
|
|
|
|
|
|
|
MetaWaylandFilterManager *
|
|
|
|
meta_wayland_compositor_get_filter_manager (MetaWaylandCompositor *compositor)
|
|
|
|
{
|
|
|
|
MetaWaylandCompositorPrivate *priv =
|
|
|
|
meta_wayland_compositor_get_instance_private (compositor);
|
|
|
|
|
|
|
|
return priv->filter_manager;
|
|
|
|
}
|
2023-06-07 11:04:15 +02:00
|
|
|
|
|
|
|
MetaWaylandTextInput *
|
|
|
|
meta_wayland_compositor_get_text_input (MetaWaylandCompositor *compositor)
|
|
|
|
{
|
|
|
|
return compositor->seat->text_input;
|
|
|
|
}
|
2023-11-02 14:23:22 +01:00
|
|
|
|
|
|
|
static void
|
|
|
|
meta_wayland_compositor_update_focus (MetaWaylandCompositor *compositor,
|
|
|
|
MetaWindow *window)
|
|
|
|
{
|
|
|
|
MetaContext *context = meta_wayland_compositor_get_context (compositor);
|
|
|
|
MetaDisplay *display = meta_context_get_display (context);
|
|
|
|
MetaWindow *focus_window = NULL;
|
|
|
|
|
|
|
|
/* Compositor not ready yet */
|
|
|
|
if (!compositor->seat)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!display || !meta_display_windows_are_interactable (display))
|
|
|
|
focus_window = NULL;
|
|
|
|
else if (!window)
|
|
|
|
focus_window = NULL;
|
|
|
|
else if (window && meta_window_get_wayland_surface (window))
|
|
|
|
focus_window = window;
|
|
|
|
else
|
|
|
|
meta_topic (META_DEBUG_FOCUS, "Focus change has no effect, because there is no matching wayland surface");
|
|
|
|
|
|
|
|
meta_wayland_compositor_set_input_focus (compositor, focus_window);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
meta_wayland_compositor_sync_focus (MetaWaylandCompositor *compositor)
|
|
|
|
{
|
|
|
|
MetaContext *context = meta_wayland_compositor_get_context (compositor);
|
|
|
|
MetaDisplay *display = meta_context_get_display (context);
|
|
|
|
|
|
|
|
meta_wayland_compositor_update_focus (compositor,
|
|
|
|
display ? display->focus_window : NULL);
|
|
|
|
}
|