1
0
Fork 0
mutter-performance-source/src/backends/meta-backend.c

1684 lines
47 KiB
C
Raw Normal View History

/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Copyright (C) 2014 Red Hat
*
* 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
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
* Written by:
* Jasper St. Pierre <jstpierre@mecheye.net>
*/
2018-10-19 07:15:54 +00:00
/**
* SECTION:meta-backend
* @title: MetaBackend
* @short_description: Handles monitor config, modesetting, cursor sprites, ...
*
* MetaBackend is the abstraction that deals with several things like:
* - Modesetting (depending on the backend, this can be done either by X or KMS)
* - Initializing the #MetaSettings
* - Setting up Monitor configuration
* - Input device configuration (using the #ClutterDeviceManager)
* - Creating the #MetaRenderer
* - Setting up the stage of the scene graph (using #MetaStage)
* - Creating the object that deals with the cursor (using #MetaCursorTracker)
2018-10-19 07:15:54 +00:00
* and its possible pointer constraint (using #MetaPointerConstraint)
* - Setting the cursor sprite (using #MetaCursorRenderer)
* - Interacting with logind (using the appropriate D-Bus interface)
* - Querying UPower (over D-Bus) to know when the lid is closed
* - Setup Remote Desktop / Screencasting (#MetaRemoteDesktop)
* - Setup the #MetaEgl object
*
* Note that the #MetaBackend is not a subclass of #ClutterBackend. It is
* responsible for creating the correct one, based on the backend that is
* used (#MetaBackendNative or #MetaBackendX11).
*/
#include "config.h"
#include "backends/meta-backend-private.h"
#include <stdlib.h>
#include "backends/meta-cursor-renderer.h"
#include "backends/meta-cursor-tracker-private.h"
#include "backends/meta-idle-manager.h"
#include "backends/meta-idle-monitor-private.h"
#include "backends/meta-input-mapper-private.h"
#include "backends/meta-input-settings-private.h"
#include "backends/meta-logical-monitor.h"
#include "backends/meta-monitor-manager-dummy.h"
#include "backends/meta-settings-private.h"
#include "backends/meta-stage-private.h"
#include "backends/x11/meta-backend-x11.h"
#include "clutter/clutter-mutter.h"
#include "clutter/clutter-seat-private.h"
#include "core/meta-context-private.h"
#include "meta/main.h"
#include "meta/meta-backend.h"
#include "meta/meta-context.h"
#include "meta/util.h"
2014-05-29 16:11:26 +00:00
#ifdef HAVE_PROFILER
#include "backends/meta-profiler.h"
#endif
Add remote desktop and screen cast functionality This commit adds basic screen casting and remote desktoping functionalty. This works by exposing two D-Bus API services: org.gnome.Mutter.ScreenCast and org.gnome.Mutter.RemoteDesktop. The remote desktop API is used to create remote desktop sessions. For each session, a D-Bus object is created, and an application can manage the session by sending messages to the session object. A remote desktop session the user to emit input events using the D-Bus methods on the session object. To get framebuffer content, the application should create an associated screen cast session. The screen cast API is used to create screen cast sessions. One can so far either create stand-alone screen cast sessions, or a screen cast session associated with a remote desktop session. A remote desktop associated screen cast session is managed by the remote desktop session. So far only remote desktop managed screen cast sessions are implemented. Each screen cast session may have one or more streams. A screen cast stream is a stream of buffers of some part of the compositor content. So far API exists for creating streams of monitors and windows, but only monitor streams are implemented. When a screen cast session is started, the one PipeWire stream is created for each screen cast stream created for the session. When this has happened, a PipeWireStreamAdded signal is emitted on the stream object, passing a unique identifier. The application may use this identifier to find the associated stream being advertised by the PipeWire daemon. The remote desktop and screen cast functionality must be explicitly be enabled at ./configure time by passing --enable-remote-desktop to ./configure. Doing this will build both screen cast and remote desktop support. To actually enable the screen casting and remote desktop, the user must enable the experimental feature. See org.gnome.mutter.experimental-features. https://bugzilla.gnome.org/show_bug.cgi?id=784199
2017-06-21 06:23:44 +00:00
#ifdef HAVE_REMOTE_DESKTOP
#include "backends/meta-dbus-session-watcher.h"
#include "backends/meta-remote-access-controller-private.h"
Add remote desktop and screen cast functionality This commit adds basic screen casting and remote desktoping functionalty. This works by exposing two D-Bus API services: org.gnome.Mutter.ScreenCast and org.gnome.Mutter.RemoteDesktop. The remote desktop API is used to create remote desktop sessions. For each session, a D-Bus object is created, and an application can manage the session by sending messages to the session object. A remote desktop session the user to emit input events using the D-Bus methods on the session object. To get framebuffer content, the application should create an associated screen cast session. The screen cast API is used to create screen cast sessions. One can so far either create stand-alone screen cast sessions, or a screen cast session associated with a remote desktop session. A remote desktop associated screen cast session is managed by the remote desktop session. So far only remote desktop managed screen cast sessions are implemented. Each screen cast session may have one or more streams. A screen cast stream is a stream of buffers of some part of the compositor content. So far API exists for creating streams of monitors and windows, but only monitor streams are implemented. When a screen cast session is started, the one PipeWire stream is created for each screen cast stream created for the session. When this has happened, a PipeWireStreamAdded signal is emitted on the stream object, passing a unique identifier. The application may use this identifier to find the associated stream being advertised by the PipeWire daemon. The remote desktop and screen cast functionality must be explicitly be enabled at ./configure time by passing --enable-remote-desktop to ./configure. Doing this will build both screen cast and remote desktop support. To actually enable the screen casting and remote desktop, the user must enable the experimental feature. See org.gnome.mutter.experimental-features. https://bugzilla.gnome.org/show_bug.cgi?id=784199
2017-06-21 06:23:44 +00:00
#include "backends/meta-remote-desktop.h"
#include "backends/meta-screen-cast.h"
Add remote desktop and screen cast functionality This commit adds basic screen casting and remote desktoping functionalty. This works by exposing two D-Bus API services: org.gnome.Mutter.ScreenCast and org.gnome.Mutter.RemoteDesktop. The remote desktop API is used to create remote desktop sessions. For each session, a D-Bus object is created, and an application can manage the session by sending messages to the session object. A remote desktop session the user to emit input events using the D-Bus methods on the session object. To get framebuffer content, the application should create an associated screen cast session. The screen cast API is used to create screen cast sessions. One can so far either create stand-alone screen cast sessions, or a screen cast session associated with a remote desktop session. A remote desktop associated screen cast session is managed by the remote desktop session. So far only remote desktop managed screen cast sessions are implemented. Each screen cast session may have one or more streams. A screen cast stream is a stream of buffers of some part of the compositor content. So far API exists for creating streams of monitors and windows, but only monitor streams are implemented. When a screen cast session is started, the one PipeWire stream is created for each screen cast stream created for the session. When this has happened, a PipeWireStreamAdded signal is emitted on the stream object, passing a unique identifier. The application may use this identifier to find the associated stream being advertised by the PipeWire daemon. The remote desktop and screen cast functionality must be explicitly be enabled at ./configure time by passing --enable-remote-desktop to ./configure. Doing this will build both screen cast and remote desktop support. To actually enable the screen casting and remote desktop, the user must enable the experimental feature. See org.gnome.mutter.experimental-features. https://bugzilla.gnome.org/show_bug.cgi?id=784199
2017-06-21 06:23:44 +00:00
#endif
2014-05-29 16:11:26 +00:00
#ifdef HAVE_NATIVE_BACKEND
#include "backends/native/meta-backend-native.h"
2014-05-29 16:11:26 +00:00
#endif
#ifdef HAVE_WAYLAND
#include "wayland/meta-wayland.h"
#endif
enum
{
PROP_0,
PROP_CONTEXT,
N_PROPS
};
static GParamSpec *obj_props[N_PROPS];
enum
{
KEYMAP_CHANGED,
KEYMAP_LAYOUT_GROUP_CHANGED,
LAST_DEVICE_CHANGED,
LID_IS_CLOSED_CHANGED,
GPU_ADDED,
PREPARE_SHUTDOWN,
N_SIGNALS
};
static guint signals[N_SIGNALS];
static MetaBackend *_backend;
static gboolean stage_views_disabled = FALSE;
/**
* meta_get_backend:
*
* Accessor for the singleton MetaBackend.
*
* Returns: (transfer none): The only #MetaBackend there is.
*/
MetaBackend *
meta_get_backend (void)
{
return _backend;
}
struct _MetaBackendPrivate
{
MetaContext *context;
MetaMonitorManager *monitor_manager;
MetaOrientationManager *orientation_manager;
MetaCursorTracker *cursor_tracker;
MetaInputMapper *input_mapper;
MetaIdleManager *idle_manager;
MetaRenderer *renderer;
#ifdef HAVE_EGL
MetaEgl *egl;
#endif
MetaSettings *settings;
Add remote desktop and screen cast functionality This commit adds basic screen casting and remote desktoping functionalty. This works by exposing two D-Bus API services: org.gnome.Mutter.ScreenCast and org.gnome.Mutter.RemoteDesktop. The remote desktop API is used to create remote desktop sessions. For each session, a D-Bus object is created, and an application can manage the session by sending messages to the session object. A remote desktop session the user to emit input events using the D-Bus methods on the session object. To get framebuffer content, the application should create an associated screen cast session. The screen cast API is used to create screen cast sessions. One can so far either create stand-alone screen cast sessions, or a screen cast session associated with a remote desktop session. A remote desktop associated screen cast session is managed by the remote desktop session. So far only remote desktop managed screen cast sessions are implemented. Each screen cast session may have one or more streams. A screen cast stream is a stream of buffers of some part of the compositor content. So far API exists for creating streams of monitors and windows, but only monitor streams are implemented. When a screen cast session is started, the one PipeWire stream is created for each screen cast stream created for the session. When this has happened, a PipeWireStreamAdded signal is emitted on the stream object, passing a unique identifier. The application may use this identifier to find the associated stream being advertised by the PipeWire daemon. The remote desktop and screen cast functionality must be explicitly be enabled at ./configure time by passing --enable-remote-desktop to ./configure. Doing this will build both screen cast and remote desktop support. To actually enable the screen casting and remote desktop, the user must enable the experimental feature. See org.gnome.mutter.experimental-features. https://bugzilla.gnome.org/show_bug.cgi?id=784199
2017-06-21 06:23:44 +00:00
#ifdef HAVE_REMOTE_DESKTOP
MetaRemoteAccessController *remote_access_controller;
Add remote desktop and screen cast functionality This commit adds basic screen casting and remote desktoping functionalty. This works by exposing two D-Bus API services: org.gnome.Mutter.ScreenCast and org.gnome.Mutter.RemoteDesktop. The remote desktop API is used to create remote desktop sessions. For each session, a D-Bus object is created, and an application can manage the session by sending messages to the session object. A remote desktop session the user to emit input events using the D-Bus methods on the session object. To get framebuffer content, the application should create an associated screen cast session. The screen cast API is used to create screen cast sessions. One can so far either create stand-alone screen cast sessions, or a screen cast session associated with a remote desktop session. A remote desktop associated screen cast session is managed by the remote desktop session. So far only remote desktop managed screen cast sessions are implemented. Each screen cast session may have one or more streams. A screen cast stream is a stream of buffers of some part of the compositor content. So far API exists for creating streams of monitors and windows, but only monitor streams are implemented. When a screen cast session is started, the one PipeWire stream is created for each screen cast stream created for the session. When this has happened, a PipeWireStreamAdded signal is emitted on the stream object, passing a unique identifier. The application may use this identifier to find the associated stream being advertised by the PipeWire daemon. The remote desktop and screen cast functionality must be explicitly be enabled at ./configure time by passing --enable-remote-desktop to ./configure. Doing this will build both screen cast and remote desktop support. To actually enable the screen casting and remote desktop, the user must enable the experimental feature. See org.gnome.mutter.experimental-features. https://bugzilla.gnome.org/show_bug.cgi?id=784199
2017-06-21 06:23:44 +00:00
MetaDbusSessionWatcher *dbus_session_watcher;
MetaScreenCast *screen_cast;
MetaRemoteDesktop *remote_desktop;
#endif
#ifdef HAVE_PROFILER
MetaProfiler *profiler;
#endif
#ifdef HAVE_LIBWACOM
WacomDeviceDatabase *wacom_db;
#endif
Explicitly create the clutter context and backend This changes the setup phase of clutter to not be result of calling an init function that sets up a few global singletons, via global singleton setup vfuncs. The way it worked was that mutter first did some initial setup (connecting to the X11 server), then set a "custom backend" setup vfunc global, before calling clutter_init(). During the clutter_init() call, the context and backend was setup by calling the global singleton getters, which implicitly created the backend and context on-demand. This has now changed to mutter explicitly creating a `ClutterContext` (which is actually a `ClutterMainContext`, but with the name shortened to be consistent with `CoglContext` and `MetaContext`), calling it with a backend constructor vfunc and user data pointer. This function now explicitly creates the backend, without having to go via the previously set global vfunc. This changes the behavior of some "get_default()" like functions, which will now fail if called after mutter has shut down, as when it does so, it now destroys the backends and contexts, not only its own, but the clutter ones too. The "ownership" of the clutter backend is also moved to `ClutterContext`, and MetaBackend is changed to fetch it via the clutter context. This also removed the unused option parsing that existed in clutter. In some places, NULL checks for fetching the clutter context, or backend, and fetching the cogl context from the clutter backend, had to be added. The reason for this is that some code that handles EGL contexts attempts to restore the cogl EGL context tracking so that the right EGL context is used by cogl the next time. This makes no sense to do before Cogl and Clutter are even initialized, which was the case. It wasn't noticed because the relevant singletons were initialized on demand via their "getters". Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2002>
2021-09-16 09:38:49 +00:00
ClutterContext *clutter_context;
ClutterSeat *default_seat;
ClutterActor *stage;
GList *gpus;
GList *hw_cursor_inhibitors;
gboolean is_pointer_position_initialized;
guint device_update_idle_id;
ClutterInputDevice *current_device;
MetaPointerConstraint *client_pointer_constraint;
MetaDnd *dnd;
guint upower_watch_id;
GDBusProxy *upower_proxy;
gboolean lid_is_closed;
gboolean on_battery;
guint sleep_signal_id;
GCancellable *cancellable;
GDBusConnection *system_bus;
};
typedef struct _MetaBackendPrivate MetaBackendPrivate;
typedef struct _MetaBackendSource MetaBackendSource;
struct _MetaBackendSource
{
GSource parent;
MetaBackend *backend;
};
static void
initable_iface_init (GInitableIface *initable_iface);
G_DEFINE_ABSTRACT_TYPE_WITH_CODE (MetaBackend, meta_backend, G_TYPE_OBJECT,
G_ADD_PRIVATE (MetaBackend)
G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
initable_iface_init));
static void
meta_backend_dispose (GObject *object)
{
MetaBackend *backend = META_BACKEND (object);
MetaBackendPrivate *priv = meta_backend_get_instance_private (backend);
_backend = NULL;
g_clear_pointer (&priv->cursor_tracker, meta_cursor_tracker_destroy);
backend: Keep a refcount on backend's current_device Otherwise we might run into a use-after-free and crash on (virtual) device removal: Invalid read of size 8 at clutter_input_device_get_device_type (clutter-input-device.c:811) by update_last_device (meta-backend.c:1282) by g_main_dispatch (gmain.c:3325) by g_main_context_dispatch (gmain.c:4016) by g_main_context_iterate.constprop.0 (gmain.c:4092) by g_main_loop_run (gmain.c:4290) by meta_run_main_loop (main.c:708) by meta_run (main.c:723) by main (main.c:550) Address is 32 bytes inside a block of size 504 free'd at free (vg_replace_malloc.c:538) by g_type_free_instance (gtype.c:1939) by clutter_event_free (clutter-event.c:1420) by _clutter_stage_process_queued_events (clutter-stage.c:830) by handle_frame_clock_before_frame (clutter-stage-view.c:1064) by clutter_frame_clock_dispatch (clutter-frame-clock.c:405) by frame_clock_source_dispatch (clutter-frame-clock.c:456) by g_main_dispatch (gmain.c:3325) by g_main_context_dispatch (gmain.c:4016) by g_main_context_iterate.constprop.0 (gmain.c:4092) by g_main_loop_run (gmain.c:4290) by meta_run_main_loop (main.c:708) by meta_run (main.c:723) Block was alloc'd at at malloc (vg_replace_malloc.c:307) by g_malloc (gmem.c:106) by g_slice_alloc (gslice.c:1025) by g_slice_alloc0 (gslice.c:1051) by g_type_create_instance (gtype.c:1839) by g_object_new_internal (gobject.c:1939) by g_object_new_valist (gobject.c:2264) by g_object_new (gobject.c:1782) by meta_input_device_native_new_virtual (meta-input-device-native.c:1365) by meta_virtual_input_device_native_constructed (meta-virtual-input-device-native.c:705) by g_object_new_internal (gobject.c:1979) by g_object_new_valist (gobject.c:2264) Suggested-by: Carlos Garnacho <carlosg@gnome.org> https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1529
2020-10-26 17:34:05 +00:00
g_clear_object (&priv->current_device);
g_clear_object (&priv->monitor_manager);
g_clear_object (&priv->orientation_manager);
Add remote desktop and screen cast functionality This commit adds basic screen casting and remote desktoping functionalty. This works by exposing two D-Bus API services: org.gnome.Mutter.ScreenCast and org.gnome.Mutter.RemoteDesktop. The remote desktop API is used to create remote desktop sessions. For each session, a D-Bus object is created, and an application can manage the session by sending messages to the session object. A remote desktop session the user to emit input events using the D-Bus methods on the session object. To get framebuffer content, the application should create an associated screen cast session. The screen cast API is used to create screen cast sessions. One can so far either create stand-alone screen cast sessions, or a screen cast session associated with a remote desktop session. A remote desktop associated screen cast session is managed by the remote desktop session. So far only remote desktop managed screen cast sessions are implemented. Each screen cast session may have one or more streams. A screen cast stream is a stream of buffers of some part of the compositor content. So far API exists for creating streams of monitors and windows, but only monitor streams are implemented. When a screen cast session is started, the one PipeWire stream is created for each screen cast stream created for the session. When this has happened, a PipeWireStreamAdded signal is emitted on the stream object, passing a unique identifier. The application may use this identifier to find the associated stream being advertised by the PipeWire daemon. The remote desktop and screen cast functionality must be explicitly be enabled at ./configure time by passing --enable-remote-desktop to ./configure. Doing this will build both screen cast and remote desktop support. To actually enable the screen casting and remote desktop, the user must enable the experimental feature. See org.gnome.mutter.experimental-features. https://bugzilla.gnome.org/show_bug.cgi?id=784199
2017-06-21 06:23:44 +00:00
#ifdef HAVE_REMOTE_DESKTOP
g_clear_object (&priv->remote_desktop);
g_clear_object (&priv->screen_cast);
g_clear_object (&priv->dbus_session_watcher);
g_clear_object (&priv->remote_access_controller);
Add remote desktop and screen cast functionality This commit adds basic screen casting and remote desktoping functionalty. This works by exposing two D-Bus API services: org.gnome.Mutter.ScreenCast and org.gnome.Mutter.RemoteDesktop. The remote desktop API is used to create remote desktop sessions. For each session, a D-Bus object is created, and an application can manage the session by sending messages to the session object. A remote desktop session the user to emit input events using the D-Bus methods on the session object. To get framebuffer content, the application should create an associated screen cast session. The screen cast API is used to create screen cast sessions. One can so far either create stand-alone screen cast sessions, or a screen cast session associated with a remote desktop session. A remote desktop associated screen cast session is managed by the remote desktop session. So far only remote desktop managed screen cast sessions are implemented. Each screen cast session may have one or more streams. A screen cast stream is a stream of buffers of some part of the compositor content. So far API exists for creating streams of monitors and windows, but only monitor streams are implemented. When a screen cast session is started, the one PipeWire stream is created for each screen cast stream created for the session. When this has happened, a PipeWireStreamAdded signal is emitted on the stream object, passing a unique identifier. The application may use this identifier to find the associated stream being advertised by the PipeWire daemon. The remote desktop and screen cast functionality must be explicitly be enabled at ./configure time by passing --enable-remote-desktop to ./configure. Doing this will build both screen cast and remote desktop support. To actually enable the screen casting and remote desktop, the user must enable the experimental feature. See org.gnome.mutter.experimental-features. https://bugzilla.gnome.org/show_bug.cgi?id=784199
2017-06-21 06:23:44 +00:00
#endif
#ifdef HAVE_LIBWACOM
g_clear_pointer (&priv->wacom_db, libwacom_database_destroy);
#endif
if (priv->sleep_signal_id)
{
g_dbus_connection_signal_unsubscribe (priv->system_bus, priv->sleep_signal_id);
priv->sleep_signal_id = 0;
}
if (priv->upower_watch_id)
{
g_bus_unwatch_name (priv->upower_watch_id);
priv->upower_watch_id = 0;
}
g_cancellable_cancel (priv->cancellable);
g_clear_object (&priv->cancellable);
g_clear_object (&priv->system_bus);
g_clear_object (&priv->upower_proxy);
g_clear_handle_id (&priv->device_update_idle_id, g_source_remove);
g_clear_object (&priv->settings);
#ifdef HAVE_PROFILER
g_clear_object (&priv->profiler);
#endif
g_clear_pointer (&priv->default_seat, clutter_seat_destroy);
g_clear_pointer (&priv->stage, clutter_actor_destroy);
g_clear_pointer (&priv->idle_manager, meta_idle_manager_free);
g_clear_object (&priv->renderer);
Explicitly create the clutter context and backend This changes the setup phase of clutter to not be result of calling an init function that sets up a few global singletons, via global singleton setup vfuncs. The way it worked was that mutter first did some initial setup (connecting to the X11 server), then set a "custom backend" setup vfunc global, before calling clutter_init(). During the clutter_init() call, the context and backend was setup by calling the global singleton getters, which implicitly created the backend and context on-demand. This has now changed to mutter explicitly creating a `ClutterContext` (which is actually a `ClutterMainContext`, but with the name shortened to be consistent with `CoglContext` and `MetaContext`), calling it with a backend constructor vfunc and user data pointer. This function now explicitly creates the backend, without having to go via the previously set global vfunc. This changes the behavior of some "get_default()" like functions, which will now fail if called after mutter has shut down, as when it does so, it now destroys the backends and contexts, not only its own, but the clutter ones too. The "ownership" of the clutter backend is also moved to `ClutterContext`, and MetaBackend is changed to fetch it via the clutter context. This also removed the unused option parsing that existed in clutter. In some places, NULL checks for fetching the clutter context, or backend, and fetching the cogl context from the clutter backend, had to be added. The reason for this is that some code that handles EGL contexts attempts to restore the cogl EGL context tracking so that the right EGL context is used by cogl the next time. This makes no sense to do before Cogl and Clutter are even initialized, which was the case. It wasn't noticed because the relevant singletons were initialized on demand via their "getters". Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2002>
2021-09-16 09:38:49 +00:00
g_clear_pointer (&priv->clutter_context, clutter_context_free);
g_clear_list (&priv->gpus, g_object_unref);
G_OBJECT_CLASS (meta_backend_parent_class)->dispose (object);
}
void
meta_backend_destroy (MetaBackend *backend)
{
g_object_run_dispose (G_OBJECT (backend));
g_object_unref (backend);
}
static void
meta_backend_sync_screen_size (MetaBackend *backend)
{
MetaBackendPrivate *priv = meta_backend_get_instance_private (backend);
int width, height;
meta_monitor_manager_get_screen_size (priv->monitor_manager, &width, &height);
META_BACKEND_GET_CLASS (backend)->update_screen_size (backend, width, height);
}
static void
reset_pointer_position (MetaBackend *backend)
{
MetaBackendPrivate *priv = meta_backend_get_instance_private (backend);
MetaMonitorManager *monitor_manager = priv->monitor_manager;
ClutterSeat *seat = priv->default_seat;
MetaLogicalMonitor *primary;
primary =
meta_monitor_manager_get_primary_logical_monitor (monitor_manager);
/* Move the pointer out of the way to avoid hovering over reactive
* elements (e.g. users list at login) causing undesired behaviour. */
clutter_seat_warp_pointer (seat,
primary->rect.x + primary->rect.width * 0.9,
primary->rect.y + primary->rect.height * 0.9);
}
static gboolean
should_have_cursor_renderer (ClutterInputDevice *device)
{
switch (clutter_input_device_get_device_type (device))
{
case CLUTTER_POINTER_DEVICE:
if (clutter_input_device_get_device_mode (device) ==
CLUTTER_INPUT_MODE_LOGICAL)
return TRUE;
return FALSE;
case CLUTTER_TABLET_DEVICE:
return TRUE;
default:
return FALSE;
}
}
static void
update_cursors (MetaBackend *backend)
{
MetaBackendPrivate *priv = meta_backend_get_instance_private (backend);
ClutterSeat *seat = priv->default_seat;
MetaCursorRenderer *cursor_renderer;
ClutterInputDevice *pointer, *device;
GList *devices, *l;
pointer = clutter_seat_get_pointer (seat);
devices = clutter_seat_list_devices (seat);
devices = g_list_prepend (devices, pointer);
for (l = devices; l; l = l->next)
{
device = l->data;
if (!should_have_cursor_renderer (device))
continue;
cursor_renderer = meta_backend_get_cursor_renderer_for_device (backend,
device);
if (cursor_renderer)
meta_cursor_renderer_force_update (cursor_renderer);
}
g_list_free (devices);
}
void
meta_backend_monitors_changed (MetaBackend *backend)
{
meta_backend_sync_screen_size (backend);
update_cursors (backend);
}
static inline gboolean
check_has_pointing_device (ClutterSeat *seat)
{
GList *l, *devices;
gboolean found = FALSE;
devices = clutter_seat_list_devices (seat);
for (l = devices; l; l = l->next)
{
ClutterInputDevice *device = l->data;
if (clutter_input_device_get_device_mode (device) == CLUTTER_INPUT_MODE_LOGICAL)
continue;
if (clutter_input_device_get_device_type (device) == CLUTTER_TOUCHSCREEN_DEVICE ||
clutter_input_device_get_device_type (device) == CLUTTER_KEYBOARD_DEVICE)
continue;
found = TRUE;
break;
}
g_list_free (devices);
return found;
}
static void
on_device_added (ClutterSeat *seat,
ClutterInputDevice *device,
gpointer user_data)
{
MetaBackend *backend = META_BACKEND (user_data);
MetaBackendPrivate *priv = meta_backend_get_instance_private (backend);
ClutterInputDeviceType device_type;
if (clutter_input_device_get_device_mode (device) ==
CLUTTER_INPUT_MODE_LOGICAL)
return;
device_type = clutter_input_device_get_device_type (device);
if (device_type == CLUTTER_TOUCHSCREEN_DEVICE)
meta_cursor_tracker_set_pointer_visible (priv->cursor_tracker, FALSE);
else if (device_type == CLUTTER_POINTER_DEVICE &&
!clutter_seat_has_touchscreen (seat))
meta_cursor_tracker_set_pointer_visible (priv->cursor_tracker, TRUE);
if (device_type == CLUTTER_TOUCHSCREEN_DEVICE ||
device_type == CLUTTER_TABLET_DEVICE ||
device_type == CLUTTER_PEN_DEVICE ||
device_type == CLUTTER_ERASER_DEVICE ||
device_type == CLUTTER_CURSOR_DEVICE ||
device_type == CLUTTER_PAD_DEVICE)
meta_input_mapper_add_device (priv->input_mapper, device);
}
static void
on_device_removed (ClutterSeat *seat,
ClutterInputDevice *device,
gpointer user_data)
{
MetaBackend *backend = META_BACKEND (user_data);
MetaBackendPrivate *priv = meta_backend_get_instance_private (backend);
if (clutter_input_device_get_device_mode (device) ==
CLUTTER_INPUT_MODE_LOGICAL)
return;
meta_input_mapper_remove_device (priv->input_mapper, device);
/* If the device the user last interacted goes away, check again pointer
* visibility.
*/
if (priv->current_device == device)
{
MetaCursorTracker *cursor_tracker = priv->cursor_tracker;
gboolean has_touchscreen, has_pointing_device;
ClutterInputDeviceType device_type;
backend: Keep a refcount on backend's current_device Otherwise we might run into a use-after-free and crash on (virtual) device removal: Invalid read of size 8 at clutter_input_device_get_device_type (clutter-input-device.c:811) by update_last_device (meta-backend.c:1282) by g_main_dispatch (gmain.c:3325) by g_main_context_dispatch (gmain.c:4016) by g_main_context_iterate.constprop.0 (gmain.c:4092) by g_main_loop_run (gmain.c:4290) by meta_run_main_loop (main.c:708) by meta_run (main.c:723) by main (main.c:550) Address is 32 bytes inside a block of size 504 free'd at free (vg_replace_malloc.c:538) by g_type_free_instance (gtype.c:1939) by clutter_event_free (clutter-event.c:1420) by _clutter_stage_process_queued_events (clutter-stage.c:830) by handle_frame_clock_before_frame (clutter-stage-view.c:1064) by clutter_frame_clock_dispatch (clutter-frame-clock.c:405) by frame_clock_source_dispatch (clutter-frame-clock.c:456) by g_main_dispatch (gmain.c:3325) by g_main_context_dispatch (gmain.c:4016) by g_main_context_iterate.constprop.0 (gmain.c:4092) by g_main_loop_run (gmain.c:4290) by meta_run_main_loop (main.c:708) by meta_run (main.c:723) Block was alloc'd at at malloc (vg_replace_malloc.c:307) by g_malloc (gmem.c:106) by g_slice_alloc (gslice.c:1025) by g_slice_alloc0 (gslice.c:1051) by g_type_create_instance (gtype.c:1839) by g_object_new_internal (gobject.c:1939) by g_object_new_valist (gobject.c:2264) by g_object_new (gobject.c:1782) by meta_input_device_native_new_virtual (meta-input-device-native.c:1365) by meta_virtual_input_device_native_constructed (meta-virtual-input-device-native.c:705) by g_object_new_internal (gobject.c:1979) by g_object_new_valist (gobject.c:2264) Suggested-by: Carlos Garnacho <carlosg@gnome.org> https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1529
2020-10-26 17:34:05 +00:00
g_clear_object (&priv->current_device);
g_clear_handle_id (&priv->device_update_idle_id, g_source_remove);
device_type = clutter_input_device_get_device_type (device);
has_touchscreen = clutter_seat_has_touchscreen (seat);
if (device_type == CLUTTER_TOUCHSCREEN_DEVICE && has_touchscreen)
{
/* There's more touchscreens left, keep the pointer hidden */
meta_cursor_tracker_set_pointer_visible (cursor_tracker, FALSE);
}
else if (device_type != CLUTTER_KEYBOARD_DEVICE)
{
has_pointing_device = check_has_pointing_device (seat);
meta_cursor_tracker_set_pointer_visible (cursor_tracker,
has_pointing_device &&
!has_touchscreen);
}
}
if (priv->current_device == device)
meta_backend_update_last_device (backend, NULL);
}
static void
input_mapper_device_mapped_cb (MetaInputMapper *mapper,
ClutterInputDevice *device,
float matrix[6],
MetaInputSettings *input_settings)
{
meta_input_settings_set_device_matrix (input_settings, device, matrix);
}
static void
input_mapper_device_enabled_cb (MetaInputMapper *mapper,
ClutterInputDevice *device,
gboolean enabled,
MetaInputSettings *input_settings)
{
meta_input_settings_set_device_enabled (input_settings, device, enabled);
}
static void
input_mapper_device_aspect_ratio_cb (MetaInputMapper *mapper,
ClutterInputDevice *device,
double aspect_ratio,
MetaInputSettings *input_settings)
{
meta_input_settings_set_device_aspect_ratio (input_settings, device, aspect_ratio);
}
static void
on_stage_shown_cb (MetaBackend *backend)
{
MetaBackendPrivate *priv = meta_backend_get_instance_private (backend);
ClutterSeat *seat = priv->default_seat;
g_autoptr (GList) devices = NULL;
const GList *l;
devices = clutter_seat_list_devices (seat);
for (l = devices; l; l = l->next)
{
ClutterInputDevice *device = l->data;
if (clutter_input_device_get_device_mode (device) ==
CLUTTER_INPUT_MODE_LOGICAL)
continue;
if (clutter_input_device_get_device_type (device) !=
CLUTTER_POINTER_DEVICE)
continue;
meta_cursor_tracker_set_pointer_visible (priv->cursor_tracker, TRUE);
break;
}
}
static void
meta_backend_real_post_init (MetaBackend *backend)
{
MetaBackendPrivate *priv = meta_backend_get_instance_private (backend);
ClutterSeat *seat = priv->default_seat;
MetaInputSettings *input_settings;
priv->stage = meta_stage_new (backend);
clutter_actor_realize (priv->stage);
META_BACKEND_GET_CLASS (backend)->select_stage_events (backend);
g_signal_connect_object (priv->stage, "show",
G_CALLBACK (on_stage_shown_cb), backend,
G_CONNECT_SWAPPED);
meta_monitor_manager_setup (priv->monitor_manager);
meta_backend_sync_screen_size (backend);
priv->idle_manager = meta_idle_manager_new (backend);
g_signal_connect_object (seat, "device-added",
G_CALLBACK (on_device_added), backend, 0);
g_signal_connect_object (seat, "device-removed",
G_CALLBACK (on_device_removed), backend,
G_CONNECT_AFTER);
priv->input_mapper = meta_input_mapper_new ();
input_settings = meta_backend_get_input_settings (backend);
if (input_settings)
{
g_signal_connect (priv->input_mapper, "device-mapped",
G_CALLBACK (input_mapper_device_mapped_cb),
input_settings);
g_signal_connect (priv->input_mapper, "device-enabled",
G_CALLBACK (input_mapper_device_enabled_cb),
input_settings);
g_signal_connect (priv->input_mapper, "device-aspect-ratio",
G_CALLBACK (input_mapper_device_aspect_ratio_cb),
input_settings);
}
Add remote desktop and screen cast functionality This commit adds basic screen casting and remote desktoping functionalty. This works by exposing two D-Bus API services: org.gnome.Mutter.ScreenCast and org.gnome.Mutter.RemoteDesktop. The remote desktop API is used to create remote desktop sessions. For each session, a D-Bus object is created, and an application can manage the session by sending messages to the session object. A remote desktop session the user to emit input events using the D-Bus methods on the session object. To get framebuffer content, the application should create an associated screen cast session. The screen cast API is used to create screen cast sessions. One can so far either create stand-alone screen cast sessions, or a screen cast session associated with a remote desktop session. A remote desktop associated screen cast session is managed by the remote desktop session. So far only remote desktop managed screen cast sessions are implemented. Each screen cast session may have one or more streams. A screen cast stream is a stream of buffers of some part of the compositor content. So far API exists for creating streams of monitors and windows, but only monitor streams are implemented. When a screen cast session is started, the one PipeWire stream is created for each screen cast stream created for the session. When this has happened, a PipeWireStreamAdded signal is emitted on the stream object, passing a unique identifier. The application may use this identifier to find the associated stream being advertised by the PipeWire daemon. The remote desktop and screen cast functionality must be explicitly be enabled at ./configure time by passing --enable-remote-desktop to ./configure. Doing this will build both screen cast and remote desktop support. To actually enable the screen casting and remote desktop, the user must enable the experimental feature. See org.gnome.mutter.experimental-features. https://bugzilla.gnome.org/show_bug.cgi?id=784199
2017-06-21 06:23:44 +00:00
#ifdef HAVE_REMOTE_DESKTOP
priv->dbus_session_watcher = g_object_new (META_TYPE_DBUS_SESSION_WATCHER, NULL);
priv->screen_cast = meta_screen_cast_new (backend,
priv->dbus_session_watcher);
priv->remote_desktop = meta_remote_desktop_new (backend,
priv->dbus_session_watcher);
priv->remote_access_controller =
meta_remote_access_controller_new (priv->remote_desktop, priv->screen_cast);
Add remote desktop and screen cast functionality This commit adds basic screen casting and remote desktoping functionalty. This works by exposing two D-Bus API services: org.gnome.Mutter.ScreenCast and org.gnome.Mutter.RemoteDesktop. The remote desktop API is used to create remote desktop sessions. For each session, a D-Bus object is created, and an application can manage the session by sending messages to the session object. A remote desktop session the user to emit input events using the D-Bus methods on the session object. To get framebuffer content, the application should create an associated screen cast session. The screen cast API is used to create screen cast sessions. One can so far either create stand-alone screen cast sessions, or a screen cast session associated with a remote desktop session. A remote desktop associated screen cast session is managed by the remote desktop session. So far only remote desktop managed screen cast sessions are implemented. Each screen cast session may have one or more streams. A screen cast stream is a stream of buffers of some part of the compositor content. So far API exists for creating streams of monitors and windows, but only monitor streams are implemented. When a screen cast session is started, the one PipeWire stream is created for each screen cast stream created for the session. When this has happened, a PipeWireStreamAdded signal is emitted on the stream object, passing a unique identifier. The application may use this identifier to find the associated stream being advertised by the PipeWire daemon. The remote desktop and screen cast functionality must be explicitly be enabled at ./configure time by passing --enable-remote-desktop to ./configure. Doing this will build both screen cast and remote desktop support. To actually enable the screen casting and remote desktop, the user must enable the experimental feature. See org.gnome.mutter.experimental-features. https://bugzilla.gnome.org/show_bug.cgi?id=784199
2017-06-21 06:23:44 +00:00
#endif /* HAVE_REMOTE_DESKTOP */
if (!meta_monitor_manager_is_headless (priv->monitor_manager))
{
reset_pointer_position (backend);
priv->is_pointer_position_initialized = TRUE;
}
meta_monitor_manager_post_init (priv->monitor_manager);
2014-04-22 19:15:11 +00:00
}
static gboolean
meta_backend_real_grab_device (MetaBackend *backend,
int device_id,
uint32_t timestamp)
{
/* Do nothing */
return TRUE;
}
static gboolean
meta_backend_real_ungrab_device (MetaBackend *backend,
int device_id,
uint32_t timestamp)
{
/* Do nothing */
return TRUE;
}
static void
meta_backend_real_select_stage_events (MetaBackend *backend)
{
/* Do nothing */
}
static gboolean
meta_backend_real_is_lid_closed (MetaBackend *backend)
{
MetaBackendPrivate *priv = meta_backend_get_instance_private (backend);
return priv->lid_is_closed;
}
static MetaCursorTracker *
meta_backend_real_create_cursor_tracker (MetaBackend *backend)
{
return g_object_new (META_TYPE_CURSOR_TRACKER,
"backend", backend,
NULL);
}
static gboolean
meta_backend_real_is_headless (MetaBackend *backend)
{
return FALSE;
}
gboolean
meta_backend_is_lid_closed (MetaBackend *backend)
{
return META_BACKEND_GET_CLASS (backend)->is_lid_closed (backend);
}
gboolean
meta_backend_is_headless (MetaBackend *backend)
{
return META_BACKEND_GET_CLASS (backend)->is_headless (backend);
}
static void
upower_properties_changed (GDBusProxy *proxy,
GVariant *changed_properties,
GStrv invalidated_properties,
gpointer user_data)
{
MetaBackend *backend = user_data;
MetaBackendPrivate *priv = meta_backend_get_instance_private (backend);
GVariant *v;
gboolean reset_idle_time = FALSE;
v = g_variant_lookup_value (changed_properties,
"LidIsClosed",
G_VARIANT_TYPE_BOOLEAN);
if (v)
{
gboolean lid_is_closed;
lid_is_closed = g_variant_get_boolean (v);
g_variant_unref (v);
if (lid_is_closed != priv->lid_is_closed)
{
priv->lid_is_closed = lid_is_closed;
g_signal_emit (backend, signals[LID_IS_CLOSED_CHANGED], 0,
priv->lid_is_closed);
if (!lid_is_closed)
reset_idle_time = TRUE;
}
}
v = g_variant_lookup_value (changed_properties,
"OnBattery",
G_VARIANT_TYPE_BOOLEAN);
if (v)
{
gboolean on_battery;
on_battery = g_variant_get_boolean (v);
g_variant_unref (v);
if (on_battery != priv->on_battery)
{
priv->on_battery = on_battery;
reset_idle_time = TRUE;
}
}
if (reset_idle_time)
meta_idle_manager_reset_idle_time (priv->idle_manager);
}
static void
upower_ready_cb (GObject *source_object,
GAsyncResult *res,
gpointer user_data)
{
MetaBackend *backend;
MetaBackendPrivate *priv;
GDBusProxy *proxy;
GError *error = NULL;
GVariant *v;
proxy = g_dbus_proxy_new_finish (res, &error);
if (!proxy)
{
if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
g_warning ("Failed to create UPower proxy: %s", error->message);
g_error_free (error);
return;
}
backend = META_BACKEND (user_data);
priv = meta_backend_get_instance_private (backend);
priv->upower_proxy = proxy;
g_signal_connect (proxy, "g-properties-changed",
G_CALLBACK (upower_properties_changed), backend);
v = g_dbus_proxy_get_cached_property (proxy, "LidIsClosed");
if (v)
{
priv->lid_is_closed = g_variant_get_boolean (v);
g_variant_unref (v);
if (priv->lid_is_closed)
{
g_signal_emit (backend, signals[LID_IS_CLOSED_CHANGED], 0,
priv->lid_is_closed);
}
}
v = g_dbus_proxy_get_cached_property (proxy, "OnBattery");
if (v)
{
priv->on_battery = g_variant_get_boolean (v);
g_variant_unref (v);
}
}
static void
upower_appeared (GDBusConnection *connection,
const gchar *name,
const gchar *name_owner,
gpointer user_data)
{
MetaBackend *backend = META_BACKEND (user_data);
MetaBackendPrivate *priv = meta_backend_get_instance_private (backend);
g_dbus_proxy_new (connection,
G_DBUS_PROXY_FLAGS_NONE,
NULL,
"org.freedesktop.UPower",
"/org/freedesktop/UPower",
"org.freedesktop.UPower",
priv->cancellable,
upower_ready_cb,
backend);
}
static void
upower_vanished (GDBusConnection *connection,
const gchar *name,
gpointer user_data)
{
MetaBackend *backend = META_BACKEND (user_data);
MetaBackendPrivate *priv = meta_backend_get_instance_private (backend);
g_clear_object (&priv->upower_proxy);
}
static void
meta_backend_constructed (GObject *object)
{
MetaBackend *backend = META_BACKEND (object);
MetaBackendPrivate *priv = meta_backend_get_instance_private (backend);
MetaBackendClass *backend_class =
META_BACKEND_GET_CLASS (backend);
g_assert (priv->context);
#ifdef HAVE_LIBWACOM
priv->wacom_db = libwacom_database_new ();
if (!priv->wacom_db)
{
g_warning ("Could not create database of Wacom devices, "
"expect tablets to misbehave");
}
#endif
if (backend_class->is_lid_closed != meta_backend_real_is_lid_closed)
return;
priv->upower_watch_id = g_bus_watch_name (G_BUS_TYPE_SYSTEM,
"org.freedesktop.UPower",
G_BUS_NAME_WATCHER_FLAGS_NONE,
upower_appeared,
upower_vanished,
backend,
NULL);
}
static void
meta_backend_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
MetaBackend *backend = META_BACKEND (object);
MetaBackendPrivate *priv = meta_backend_get_instance_private (backend);
switch (prop_id)
{
case PROP_CONTEXT:
priv->context = g_value_get_object (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
meta_backend_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
MetaBackend *backend = META_BACKEND (object);
MetaBackendPrivate *priv = meta_backend_get_instance_private (backend);
switch (prop_id)
{
case PROP_CONTEXT:
g_value_set_object (value, priv->context);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
meta_backend_class_init (MetaBackendClass *klass)
{
const gchar *mutter_stage_views;
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->dispose = meta_backend_dispose;
object_class->constructed = meta_backend_constructed;
object_class->set_property = meta_backend_set_property;
object_class->get_property = meta_backend_get_property;
klass->post_init = meta_backend_real_post_init;
klass->grab_device = meta_backend_real_grab_device;
klass->ungrab_device = meta_backend_real_ungrab_device;
klass->select_stage_events = meta_backend_real_select_stage_events;
klass->is_lid_closed = meta_backend_real_is_lid_closed;
klass->create_cursor_tracker = meta_backend_real_create_cursor_tracker;
klass->is_headless = meta_backend_real_is_headless;
2014-08-14 21:32:41 +00:00
obj_props[PROP_CONTEXT] =
g_param_spec_object ("context",
"context",
"MetaContext",
META_TYPE_CONTEXT,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (object_class, N_PROPS, obj_props);
signals[KEYMAP_CHANGED] =
g_signal_new ("keymap-changed",
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
0,
NULL, NULL, NULL,
G_TYPE_NONE, 0);
signals[KEYMAP_LAYOUT_GROUP_CHANGED] =
g_signal_new ("keymap-layout-group-changed",
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
0,
NULL, NULL, NULL,
G_TYPE_NONE, 1, G_TYPE_UINT);
signals[LAST_DEVICE_CHANGED] =
g_signal_new ("last-device-changed",
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
0,
NULL, NULL, NULL,
G_TYPE_NONE, 1, CLUTTER_TYPE_INPUT_DEVICE);
signals[LID_IS_CLOSED_CHANGED] =
g_signal_new ("lid-is-closed-changed",
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
0,
NULL, NULL, NULL,
G_TYPE_NONE, 1, G_TYPE_BOOLEAN);
/**
* MetaBackend::gpu-added: (skip)
* @backend: the #MetaBackend
* @gpu: the #MetaGpu
*/
signals[GPU_ADDED] =
g_signal_new ("gpu-added",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
0,
NULL, NULL, NULL,
G_TYPE_NONE, 1, META_TYPE_GPU);
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);
mutter_stage_views = g_getenv ("MUTTER_STAGE_VIEWS");
stage_views_disabled = g_strcmp0 (mutter_stage_views, "0") == 0;
}
static MetaMonitorManager *
meta_backend_create_monitor_manager (MetaBackend *backend,
GError **error)
{
return META_BACKEND_GET_CLASS (backend)->create_monitor_manager (backend,
error);
}
static MetaRenderer *
meta_backend_create_renderer (MetaBackend *backend,
GError **error)
{
return META_BACKEND_GET_CLASS (backend)->create_renderer (backend, error);
}
static void
prepare_for_sleep_cb (GDBusConnection *connection,
const gchar *sender_name,
const gchar *object_path,
const gchar *interface_name,
const gchar *signal_name,
GVariant *parameters,
gpointer user_data)
{
MetaBackend *backend = user_data;
MetaBackendPrivate *priv = meta_backend_get_instance_private (backend);
gboolean suspending;
g_variant_get (parameters, "(b)", &suspending);
if (suspending)
return;
meta_idle_manager_reset_idle_time (priv->idle_manager);
}
static void
system_bus_gotten_cb (GObject *object,
GAsyncResult *res,
gpointer user_data)
{
MetaBackend *backend = user_data;
MetaBackendPrivate *priv;
GDBusConnection *bus;
bus = g_bus_get_finish (res, NULL);
if (!bus)
return;
priv = meta_backend_get_instance_private (backend);
priv->system_bus = bus;
priv->sleep_signal_id =
g_dbus_connection_signal_subscribe (priv->system_bus,
"org.freedesktop.login1",
"org.freedesktop.login1.Manager",
"PrepareForSleep",
"/org/freedesktop/login1",
NULL,
G_DBUS_SIGNAL_FLAGS_NONE,
prepare_for_sleep_cb,
backend,
NULL);
}
/* Mutter is responsible for pulling events off the X queue, so Clutter
* doesn't need (and shouldn't) run its normal event source which polls
* the X fd, but we do have to deal with dispatching events that accumulate
* in the clutter queue. This happens, for example, when clutter generate
* enter/leave events on mouse motion - several events are queued in the
* clutter queue but only one dispatched. It could also happen because of
* explicit calls to clutter_event_put(). We add a very simple custom
* event loop source which is simply responsible for pulling events off
* of the queue and dispatching them before we block for new events.
*/
static gboolean
clutter_source_prepare (GSource *source,
int *timeout)
{
*timeout = -1;
return clutter_events_pending ();
}
static gboolean
clutter_source_check (GSource *source)
{
return clutter_events_pending ();
}
static gboolean
clutter_source_dispatch (GSource *source,
GSourceFunc callback,
gpointer user_data)
{
MetaBackendSource *backend_source = (MetaBackendSource *) source;
ClutterEvent *event = clutter_event_get ();
if (event)
{
event->any.stage =
CLUTTER_STAGE (meta_backend_get_stage (backend_source->backend));
clutter_do_event (event);
clutter_event_free (event);
}
return TRUE;
}
static GSourceFuncs clutter_source_funcs = {
clutter_source_prepare,
clutter_source_check,
clutter_source_dispatch
};
static ClutterBackend *
Explicitly create the clutter context and backend This changes the setup phase of clutter to not be result of calling an init function that sets up a few global singletons, via global singleton setup vfuncs. The way it worked was that mutter first did some initial setup (connecting to the X11 server), then set a "custom backend" setup vfunc global, before calling clutter_init(). During the clutter_init() call, the context and backend was setup by calling the global singleton getters, which implicitly created the backend and context on-demand. This has now changed to mutter explicitly creating a `ClutterContext` (which is actually a `ClutterMainContext`, but with the name shortened to be consistent with `CoglContext` and `MetaContext`), calling it with a backend constructor vfunc and user data pointer. This function now explicitly creates the backend, without having to go via the previously set global vfunc. This changes the behavior of some "get_default()" like functions, which will now fail if called after mutter has shut down, as when it does so, it now destroys the backends and contexts, not only its own, but the clutter ones too. The "ownership" of the clutter backend is also moved to `ClutterContext`, and MetaBackend is changed to fetch it via the clutter context. This also removed the unused option parsing that existed in clutter. In some places, NULL checks for fetching the clutter context, or backend, and fetching the cogl context from the clutter backend, had to be added. The reason for this is that some code that handles EGL contexts attempts to restore the cogl EGL context tracking so that the right EGL context is used by cogl the next time. This makes no sense to do before Cogl and Clutter are even initialized, which was the case. It wasn't noticed because the relevant singletons were initialized on demand via their "getters". Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2002>
2021-09-16 09:38:49 +00:00
meta_clutter_backend_constructor (gpointer user_data)
{
Explicitly create the clutter context and backend This changes the setup phase of clutter to not be result of calling an init function that sets up a few global singletons, via global singleton setup vfuncs. The way it worked was that mutter first did some initial setup (connecting to the X11 server), then set a "custom backend" setup vfunc global, before calling clutter_init(). During the clutter_init() call, the context and backend was setup by calling the global singleton getters, which implicitly created the backend and context on-demand. This has now changed to mutter explicitly creating a `ClutterContext` (which is actually a `ClutterMainContext`, but with the name shortened to be consistent with `CoglContext` and `MetaContext`), calling it with a backend constructor vfunc and user data pointer. This function now explicitly creates the backend, without having to go via the previously set global vfunc. This changes the behavior of some "get_default()" like functions, which will now fail if called after mutter has shut down, as when it does so, it now destroys the backends and contexts, not only its own, but the clutter ones too. The "ownership" of the clutter backend is also moved to `ClutterContext`, and MetaBackend is changed to fetch it via the clutter context. This also removed the unused option parsing that existed in clutter. In some places, NULL checks for fetching the clutter context, or backend, and fetching the cogl context from the clutter backend, had to be added. The reason for this is that some code that handles EGL contexts attempts to restore the cogl EGL context tracking so that the right EGL context is used by cogl the next time. This makes no sense to do before Cogl and Clutter are even initialized, which was the case. It wasn't noticed because the relevant singletons were initialized on demand via their "getters". Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2002>
2021-09-16 09:38:49 +00:00
MetaBackend *backend = META_BACKEND (user_data);
Explicitly create the clutter context and backend This changes the setup phase of clutter to not be result of calling an init function that sets up a few global singletons, via global singleton setup vfuncs. The way it worked was that mutter first did some initial setup (connecting to the X11 server), then set a "custom backend" setup vfunc global, before calling clutter_init(). During the clutter_init() call, the context and backend was setup by calling the global singleton getters, which implicitly created the backend and context on-demand. This has now changed to mutter explicitly creating a `ClutterContext` (which is actually a `ClutterMainContext`, but with the name shortened to be consistent with `CoglContext` and `MetaContext`), calling it with a backend constructor vfunc and user data pointer. This function now explicitly creates the backend, without having to go via the previously set global vfunc. This changes the behavior of some "get_default()" like functions, which will now fail if called after mutter has shut down, as when it does so, it now destroys the backends and contexts, not only its own, but the clutter ones too. The "ownership" of the clutter backend is also moved to `ClutterContext`, and MetaBackend is changed to fetch it via the clutter context. This also removed the unused option parsing that existed in clutter. In some places, NULL checks for fetching the clutter context, or backend, and fetching the cogl context from the clutter backend, had to be added. The reason for this is that some code that handles EGL contexts attempts to restore the cogl EGL context tracking so that the right EGL context is used by cogl the next time. This makes no sense to do before Cogl and Clutter are even initialized, which was the case. It wasn't noticed because the relevant singletons were initialized on demand via their "getters". Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2002>
2021-09-16 09:38:49 +00:00
return META_BACKEND_GET_CLASS (backend)->create_clutter_backend (backend);
}
static ClutterSeat *
meta_backend_create_default_seat (MetaBackend *backend,
GError **error)
{
return META_BACKEND_GET_CLASS (backend)->create_default_seat (backend, error);
}
static gboolean
init_clutter (MetaBackend *backend,
GError **error)
{
MetaBackendPrivate *priv = meta_backend_get_instance_private (backend);
MetaBackendSource *backend_source;
GSource *source;
Explicitly create the clutter context and backend This changes the setup phase of clutter to not be result of calling an init function that sets up a few global singletons, via global singleton setup vfuncs. The way it worked was that mutter first did some initial setup (connecting to the X11 server), then set a "custom backend" setup vfunc global, before calling clutter_init(). During the clutter_init() call, the context and backend was setup by calling the global singleton getters, which implicitly created the backend and context on-demand. This has now changed to mutter explicitly creating a `ClutterContext` (which is actually a `ClutterMainContext`, but with the name shortened to be consistent with `CoglContext` and `MetaContext`), calling it with a backend constructor vfunc and user data pointer. This function now explicitly creates the backend, without having to go via the previously set global vfunc. This changes the behavior of some "get_default()" like functions, which will now fail if called after mutter has shut down, as when it does so, it now destroys the backends and contexts, not only its own, but the clutter ones too. The "ownership" of the clutter backend is also moved to `ClutterContext`, and MetaBackend is changed to fetch it via the clutter context. This also removed the unused option parsing that existed in clutter. In some places, NULL checks for fetching the clutter context, or backend, and fetching the cogl context from the clutter backend, had to be added. The reason for this is that some code that handles EGL contexts attempts to restore the cogl EGL context tracking so that the right EGL context is used by cogl the next time. This makes no sense to do before Cogl and Clutter are even initialized, which was the case. It wasn't noticed because the relevant singletons were initialized on demand via their "getters". Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2002>
2021-09-16 09:38:49 +00:00
priv->clutter_context = clutter_context_new (meta_clutter_backend_constructor,
backend,
error);
if (!priv->clutter_context)
return FALSE;
priv->default_seat = meta_backend_create_default_seat (backend, error);
if (!priv->default_seat)
return FALSE;
source = g_source_new (&clutter_source_funcs, sizeof (MetaBackendSource));
backend_source = (MetaBackendSource *) source;
backend_source->backend = backend;
g_source_attach (source, NULL);
g_source_unref (source);
return TRUE;
}
static void
meta_backend_post_init (MetaBackend *backend)
{
MetaBackendPrivate *priv = meta_backend_get_instance_private (backend);
META_BACKEND_GET_CLASS (backend)->post_init (backend);
meta_settings_post_init (priv->settings);
}
static gboolean
meta_backend_initable_init (GInitable *initable,
GCancellable *cancellable,
GError **error)
{
MetaBackend *backend = META_BACKEND (initable);
MetaBackendPrivate *priv = meta_backend_get_instance_private (backend);
priv->settings = meta_settings_new (backend);
#ifdef HAVE_EGL
priv->egl = g_object_new (META_TYPE_EGL, NULL);
#endif
priv->orientation_manager = g_object_new (META_TYPE_ORIENTATION_MANAGER, NULL);
priv->monitor_manager = meta_backend_create_monitor_manager (backend, error);
if (!priv->monitor_manager)
return FALSE;
priv->renderer = meta_backend_create_renderer (backend, error);
if (!priv->renderer)
return FALSE;
priv->cursor_tracker =
META_BACKEND_GET_CLASS (backend)->create_cursor_tracker (backend);
priv->dnd = g_object_new (META_TYPE_DND, NULL);
priv->cancellable = g_cancellable_new ();
g_bus_get (G_BUS_TYPE_SYSTEM,
priv->cancellable,
system_bus_gotten_cb,
backend);
#ifdef HAVE_PROFILER
priv->profiler = meta_profiler_new ();
#endif
if (!init_clutter (backend, error))
return FALSE;
meta_backend_post_init (backend);
return TRUE;
}
static void
initable_iface_init (GInitableIface *initable_iface)
{
initable_iface->init = meta_backend_initable_init;
}
static void
meta_backend_init (MetaBackend *backend)
{
_backend = backend;
}
/**
* meta_backend_get_idle_monitor: (skip)
*/
MetaIdleMonitor *
meta_backend_get_idle_monitor (MetaBackend *backend,
ClutterInputDevice *device)
{
MetaBackendPrivate *priv = meta_backend_get_instance_private (backend);
return meta_idle_manager_get_monitor (priv->idle_manager, device);
}
/**
* meta_backend_get_core_idle_monitor:
*
* Returns: (transfer none): the #MetaIdleMonitor that tracks server-global
* idle time for all devices.
*/
MetaIdleMonitor *
meta_backend_get_core_idle_monitor (MetaBackend *backend)
{
MetaBackendPrivate *priv = meta_backend_get_instance_private (backend);
return meta_idle_manager_get_core_monitor (priv->idle_manager);
}
/**
* meta_backend_get_idle_manager: (skip)
*/
MetaIdleManager *
meta_backend_get_idle_manager (MetaBackend *backend)
{
MetaBackendPrivate *priv = meta_backend_get_instance_private (backend);
return priv->idle_manager;
}
/**
* meta_backend_get_monitor_manager:
*
* Returns: (transfer none): A #MetaMonitorManager
*/
MetaMonitorManager *
meta_backend_get_monitor_manager (MetaBackend *backend)
{
MetaBackendPrivate *priv = meta_backend_get_instance_private (backend);
return priv->monitor_manager;
}
/**
* meta_backend_get_orientation_manager: (skip)
*/
MetaOrientationManager *
meta_backend_get_orientation_manager (MetaBackend *backend)
{
MetaBackendPrivate *priv = meta_backend_get_instance_private (backend);
return priv->orientation_manager;
}
MetaCursorTracker *
meta_backend_get_cursor_tracker (MetaBackend *backend)
{
MetaBackendPrivate *priv = meta_backend_get_instance_private (backend);
return priv->cursor_tracker;
}
/**
* meta_backend_get_cursor_renderer: (skip)
*/
MetaCursorRenderer *
meta_backend_get_cursor_renderer (MetaBackend *backend)
{
MetaBackendPrivate *priv = meta_backend_get_instance_private (backend);
ClutterInputDevice *pointer;
if (!priv->default_seat)
return NULL;
pointer = clutter_seat_get_pointer (priv->default_seat);
return meta_backend_get_cursor_renderer_for_device (backend, pointer);
}
MetaCursorRenderer *
meta_backend_get_cursor_renderer_for_device (MetaBackend *backend,
ClutterInputDevice *device)
{
g_return_val_if_fail (META_IS_BACKEND (backend), NULL);
g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), NULL);
g_return_val_if_fail (clutter_input_device_get_device_type (device) !=
CLUTTER_KEYBOARD_DEVICE, NULL);
return META_BACKEND_GET_CLASS (backend)->get_cursor_renderer (backend,
device);
}
/**
* meta_backend_get_renderer: (skip)
*/
MetaRenderer *
meta_backend_get_renderer (MetaBackend *backend)
{
MetaBackendPrivate *priv = meta_backend_get_instance_private (backend);
return priv->renderer;
}
#ifdef HAVE_EGL
/**
* meta_backend_get_egl: (skip)
*/
MetaEgl *
meta_backend_get_egl (MetaBackend *backend)
{
MetaBackendPrivate *priv = meta_backend_get_instance_private (backend);
return priv->egl;
}
#endif /* HAVE_EGL */
/**
* meta_backend_get_settings: (skip)
*/
MetaSettings *
meta_backend_get_settings (MetaBackend *backend)
{
MetaBackendPrivate *priv = meta_backend_get_instance_private (backend);
return priv->settings;
}
Add remote desktop and screen cast functionality This commit adds basic screen casting and remote desktoping functionalty. This works by exposing two D-Bus API services: org.gnome.Mutter.ScreenCast and org.gnome.Mutter.RemoteDesktop. The remote desktop API is used to create remote desktop sessions. For each session, a D-Bus object is created, and an application can manage the session by sending messages to the session object. A remote desktop session the user to emit input events using the D-Bus methods on the session object. To get framebuffer content, the application should create an associated screen cast session. The screen cast API is used to create screen cast sessions. One can so far either create stand-alone screen cast sessions, or a screen cast session associated with a remote desktop session. A remote desktop associated screen cast session is managed by the remote desktop session. So far only remote desktop managed screen cast sessions are implemented. Each screen cast session may have one or more streams. A screen cast stream is a stream of buffers of some part of the compositor content. So far API exists for creating streams of monitors and windows, but only monitor streams are implemented. When a screen cast session is started, the one PipeWire stream is created for each screen cast stream created for the session. When this has happened, a PipeWireStreamAdded signal is emitted on the stream object, passing a unique identifier. The application may use this identifier to find the associated stream being advertised by the PipeWire daemon. The remote desktop and screen cast functionality must be explicitly be enabled at ./configure time by passing --enable-remote-desktop to ./configure. Doing this will build both screen cast and remote desktop support. To actually enable the screen casting and remote desktop, the user must enable the experimental feature. See org.gnome.mutter.experimental-features. https://bugzilla.gnome.org/show_bug.cgi?id=784199
2017-06-21 06:23:44 +00:00
#ifdef HAVE_REMOTE_DESKTOP
/**
* meta_backend_get_remote_desktop: (skip)
*/
MetaRemoteDesktop *
meta_backend_get_remote_desktop (MetaBackend *backend)
{
MetaBackendPrivate *priv = meta_backend_get_instance_private (backend);
return priv->remote_desktop;
}
/**
* meta_backend_get_screen_cast: (skip)
*/
MetaScreenCast *
meta_backend_get_screen_cast (MetaBackend *backend)
{
MetaBackendPrivate *priv = meta_backend_get_instance_private (backend);
return priv->screen_cast;
}
Add remote desktop and screen cast functionality This commit adds basic screen casting and remote desktoping functionalty. This works by exposing two D-Bus API services: org.gnome.Mutter.ScreenCast and org.gnome.Mutter.RemoteDesktop. The remote desktop API is used to create remote desktop sessions. For each session, a D-Bus object is created, and an application can manage the session by sending messages to the session object. A remote desktop session the user to emit input events using the D-Bus methods on the session object. To get framebuffer content, the application should create an associated screen cast session. The screen cast API is used to create screen cast sessions. One can so far either create stand-alone screen cast sessions, or a screen cast session associated with a remote desktop session. A remote desktop associated screen cast session is managed by the remote desktop session. So far only remote desktop managed screen cast sessions are implemented. Each screen cast session may have one or more streams. A screen cast stream is a stream of buffers of some part of the compositor content. So far API exists for creating streams of monitors and windows, but only monitor streams are implemented. When a screen cast session is started, the one PipeWire stream is created for each screen cast stream created for the session. When this has happened, a PipeWireStreamAdded signal is emitted on the stream object, passing a unique identifier. The application may use this identifier to find the associated stream being advertised by the PipeWire daemon. The remote desktop and screen cast functionality must be explicitly be enabled at ./configure time by passing --enable-remote-desktop to ./configure. Doing this will build both screen cast and remote desktop support. To actually enable the screen casting and remote desktop, the user must enable the experimental feature. See org.gnome.mutter.experimental-features. https://bugzilla.gnome.org/show_bug.cgi?id=784199
2017-06-21 06:23:44 +00:00
#endif /* HAVE_REMOTE_DESKTOP */
/**
* meta_backend_get_remote_access_controller:
* @backend: A #MetaBackend
*
* Return Value: (transfer none): The #MetaRemoteAccessController
*/
MetaRemoteAccessController *
meta_backend_get_remote_access_controller (MetaBackend *backend)
{
#ifdef HAVE_REMOTE_DESKTOP
MetaBackendPrivate *priv = meta_backend_get_instance_private (backend);
return priv->remote_access_controller;
#else
return NULL;
#endif
}
/**
* meta_backend_is_rendering_hardware_accelerated:
* @backend: A #MetaBackend
*
* Returns: %TRUE if the rendering is hardware accelerated, otherwise
* %FALSE.
*/
gboolean
meta_backend_is_rendering_hardware_accelerated (MetaBackend *backend)
{
MetaRenderer *renderer = meta_backend_get_renderer (backend);
return meta_renderer_is_hardware_accelerated (renderer);
}
/**
* meta_backend_grab_device: (skip)
*/
gboolean
meta_backend_grab_device (MetaBackend *backend,
int device_id,
uint32_t timestamp)
{
return META_BACKEND_GET_CLASS (backend)->grab_device (backend, device_id, timestamp);
}
/**
* meta_backend_get_context:
* @backend: the #MetaBackend
*
* Returns: (transfer none): The #MetaContext
*/
MetaContext *
meta_backend_get_context (MetaBackend *backend)
{
MetaBackendPrivate *priv = meta_backend_get_instance_private (backend);
return priv->context;
}
/**
* meta_backend_ungrab_device: (skip)
*/
gboolean
meta_backend_ungrab_device (MetaBackend *backend,
int device_id,
uint32_t timestamp)
{
return META_BACKEND_GET_CLASS (backend)->ungrab_device (backend, device_id, timestamp);
}
/**
* meta_backend_finish_touch_sequence: (skip)
*/
void
meta_backend_finish_touch_sequence (MetaBackend *backend,
ClutterEventSequence *sequence,
MetaSequenceState state)
{
if (META_BACKEND_GET_CLASS (backend)->finish_touch_sequence)
META_BACKEND_GET_CLASS (backend)->finish_touch_sequence (backend,
sequence,
state);
}
MetaLogicalMonitor *
meta_backend_get_current_logical_monitor (MetaBackend *backend)
{
return META_BACKEND_GET_CLASS (backend)->get_current_logical_monitor (backend);
}
void
meta_backend_set_keymap (MetaBackend *backend,
const char *layouts,
const char *variants,
const char *options)
{
META_BACKEND_GET_CLASS (backend)->set_keymap (backend, layouts, variants, options);
}
/**
* meta_backend_get_keymap: (skip)
*/
struct xkb_keymap *
meta_backend_get_keymap (MetaBackend *backend)
{
return META_BACKEND_GET_CLASS (backend)->get_keymap (backend);
}
xkb_layout_index_t
meta_backend_get_keymap_layout_group (MetaBackend *backend)
{
return META_BACKEND_GET_CLASS (backend)->get_keymap_layout_group (backend);
}
void
meta_backend_lock_layout_group (MetaBackend *backend,
guint idx)
{
META_BACKEND_GET_CLASS (backend)->lock_layout_group (backend, idx);
}
/**
* meta_backend_get_stage:
* @backend: A #MetaBackend
*
* Gets the global #ClutterStage that's managed by this backend.
*
* Returns: (transfer none): the #ClutterStage
*/
ClutterActor *
meta_backend_get_stage (MetaBackend *backend)
{
MetaBackendPrivate *priv = meta_backend_get_instance_private (backend);
return priv->stage;
}
ClutterSeat *
meta_backend_get_default_seat (MetaBackend *backend)
{
MetaBackendPrivate *priv = meta_backend_get_instance_private (backend);
return priv->default_seat;
}
static gboolean
update_last_device (MetaBackend *backend)
{
MetaBackendPrivate *priv = meta_backend_get_instance_private (backend);
MetaCursorTracker *cursor_tracker = priv->cursor_tracker;
ClutterInputDeviceType device_type;
priv->device_update_idle_id = 0;
device_type = clutter_input_device_get_device_type (priv->current_device);
g_signal_emit (backend, signals[LAST_DEVICE_CHANGED], 0,
priv->current_device);
switch (device_type)
{
case CLUTTER_KEYBOARD_DEVICE:
break;
case CLUTTER_TOUCHSCREEN_DEVICE:
meta_cursor_tracker_set_pointer_visible (cursor_tracker, FALSE);
break;
default:
meta_cursor_tracker_set_pointer_visible (cursor_tracker, TRUE);
break;
}
return G_SOURCE_REMOVE;
}
void
meta_backend_update_last_device (MetaBackend *backend,
ClutterInputDevice *device)
{
MetaBackendPrivate *priv = meta_backend_get_instance_private (backend);
if (priv->current_device == device)
return;
if (!device ||
clutter_input_device_get_device_mode (device) == CLUTTER_INPUT_MODE_LOGICAL)
return;
backend: Keep a refcount on backend's current_device Otherwise we might run into a use-after-free and crash on (virtual) device removal: Invalid read of size 8 at clutter_input_device_get_device_type (clutter-input-device.c:811) by update_last_device (meta-backend.c:1282) by g_main_dispatch (gmain.c:3325) by g_main_context_dispatch (gmain.c:4016) by g_main_context_iterate.constprop.0 (gmain.c:4092) by g_main_loop_run (gmain.c:4290) by meta_run_main_loop (main.c:708) by meta_run (main.c:723) by main (main.c:550) Address is 32 bytes inside a block of size 504 free'd at free (vg_replace_malloc.c:538) by g_type_free_instance (gtype.c:1939) by clutter_event_free (clutter-event.c:1420) by _clutter_stage_process_queued_events (clutter-stage.c:830) by handle_frame_clock_before_frame (clutter-stage-view.c:1064) by clutter_frame_clock_dispatch (clutter-frame-clock.c:405) by frame_clock_source_dispatch (clutter-frame-clock.c:456) by g_main_dispatch (gmain.c:3325) by g_main_context_dispatch (gmain.c:4016) by g_main_context_iterate.constprop.0 (gmain.c:4092) by g_main_loop_run (gmain.c:4290) by meta_run_main_loop (main.c:708) by meta_run (main.c:723) Block was alloc'd at at malloc (vg_replace_malloc.c:307) by g_malloc (gmem.c:106) by g_slice_alloc (gslice.c:1025) by g_slice_alloc0 (gslice.c:1051) by g_type_create_instance (gtype.c:1839) by g_object_new_internal (gobject.c:1939) by g_object_new_valist (gobject.c:2264) by g_object_new (gobject.c:1782) by meta_input_device_native_new_virtual (meta-input-device-native.c:1365) by meta_virtual_input_device_native_constructed (meta-virtual-input-device-native.c:705) by g_object_new_internal (gobject.c:1979) by g_object_new_valist (gobject.c:2264) Suggested-by: Carlos Garnacho <carlosg@gnome.org> https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1529
2020-10-26 17:34:05 +00:00
g_set_object (&priv->current_device, device);
if (priv->device_update_idle_id == 0)
{
priv->device_update_idle_id =
g_idle_add ((GSourceFunc) update_last_device, backend);
g_source_set_name_by_id (priv->device_update_idle_id,
"[mutter] update_last_device");
}
}
MetaPointerConstraint *
meta_backend_get_client_pointer_constraint (MetaBackend *backend)
{
MetaBackendPrivate *priv = meta_backend_get_instance_private (backend);
return priv->client_pointer_constraint;
}
2018-10-19 07:15:54 +00:00
/**
* meta_backend_set_client_pointer_constraint:
* @backend: a #MetaBackend object.
* @constraint: (nullable): the client constraint to follow.
*
* Sets the current pointer constraint and removes (and unrefs) the previous
* one. If @constraint is %NULL, this means that there is no
2018-10-19 07:15:54 +00:00
* #MetaPointerConstraint active.
*/
void
meta_backend_set_client_pointer_constraint (MetaBackend *backend,
MetaPointerConstraint *constraint)
{
MetaBackendPrivate *priv = meta_backend_get_instance_private (backend);
META_BACKEND_GET_CLASS (backend)->set_pointer_constraint (backend, constraint);
g_set_object (&priv->client_pointer_constraint, constraint);
}
ClutterBackend *
meta_backend_get_clutter_backend (MetaBackend *backend)
{
MetaBackendPrivate *priv = meta_backend_get_instance_private (backend);
Explicitly create the clutter context and backend This changes the setup phase of clutter to not be result of calling an init function that sets up a few global singletons, via global singleton setup vfuncs. The way it worked was that mutter first did some initial setup (connecting to the X11 server), then set a "custom backend" setup vfunc global, before calling clutter_init(). During the clutter_init() call, the context and backend was setup by calling the global singleton getters, which implicitly created the backend and context on-demand. This has now changed to mutter explicitly creating a `ClutterContext` (which is actually a `ClutterMainContext`, but with the name shortened to be consistent with `CoglContext` and `MetaContext`), calling it with a backend constructor vfunc and user data pointer. This function now explicitly creates the backend, without having to go via the previously set global vfunc. This changes the behavior of some "get_default()" like functions, which will now fail if called after mutter has shut down, as when it does so, it now destroys the backends and contexts, not only its own, but the clutter ones too. The "ownership" of the clutter backend is also moved to `ClutterContext`, and MetaBackend is changed to fetch it via the clutter context. This also removed the unused option parsing that existed in clutter. In some places, NULL checks for fetching the clutter context, or backend, and fetching the cogl context from the clutter backend, had to be added. The reason for this is that some code that handles EGL contexts attempts to restore the cogl EGL context tracking so that the right EGL context is used by cogl the next time. This makes no sense to do before Cogl and Clutter are even initialized, which was the case. It wasn't noticed because the relevant singletons were initialized on demand via their "getters". Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2002>
2021-09-16 09:38:49 +00:00
ClutterContext *clutter_context;
Explicitly create the clutter context and backend This changes the setup phase of clutter to not be result of calling an init function that sets up a few global singletons, via global singleton setup vfuncs. The way it worked was that mutter first did some initial setup (connecting to the X11 server), then set a "custom backend" setup vfunc global, before calling clutter_init(). During the clutter_init() call, the context and backend was setup by calling the global singleton getters, which implicitly created the backend and context on-demand. This has now changed to mutter explicitly creating a `ClutterContext` (which is actually a `ClutterMainContext`, but with the name shortened to be consistent with `CoglContext` and `MetaContext`), calling it with a backend constructor vfunc and user data pointer. This function now explicitly creates the backend, without having to go via the previously set global vfunc. This changes the behavior of some "get_default()" like functions, which will now fail if called after mutter has shut down, as when it does so, it now destroys the backends and contexts, not only its own, but the clutter ones too. The "ownership" of the clutter backend is also moved to `ClutterContext`, and MetaBackend is changed to fetch it via the clutter context. This also removed the unused option parsing that existed in clutter. In some places, NULL checks for fetching the clutter context, or backend, and fetching the cogl context from the clutter backend, had to be added. The reason for this is that some code that handles EGL contexts attempts to restore the cogl EGL context tracking so that the right EGL context is used by cogl the next time. This makes no sense to do before Cogl and Clutter are even initialized, which was the case. It wasn't noticed because the relevant singletons were initialized on demand via their "getters". Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2002>
2021-09-16 09:38:49 +00:00
clutter_context = priv->clutter_context;
if (!clutter_context)
return NULL;
Explicitly create the clutter context and backend This changes the setup phase of clutter to not be result of calling an init function that sets up a few global singletons, via global singleton setup vfuncs. The way it worked was that mutter first did some initial setup (connecting to the X11 server), then set a "custom backend" setup vfunc global, before calling clutter_init(). During the clutter_init() call, the context and backend was setup by calling the global singleton getters, which implicitly created the backend and context on-demand. This has now changed to mutter explicitly creating a `ClutterContext` (which is actually a `ClutterMainContext`, but with the name shortened to be consistent with `CoglContext` and `MetaContext`), calling it with a backend constructor vfunc and user data pointer. This function now explicitly creates the backend, without having to go via the previously set global vfunc. This changes the behavior of some "get_default()" like functions, which will now fail if called after mutter has shut down, as when it does so, it now destroys the backends and contexts, not only its own, but the clutter ones too. The "ownership" of the clutter backend is also moved to `ClutterContext`, and MetaBackend is changed to fetch it via the clutter context. This also removed the unused option parsing that existed in clutter. In some places, NULL checks for fetching the clutter context, or backend, and fetching the cogl context from the clutter backend, had to be added. The reason for this is that some code that handles EGL contexts attempts to restore the cogl EGL context tracking so that the right EGL context is used by cogl the next time. This makes no sense to do before Cogl and Clutter are even initialized, which was the case. It wasn't noticed because the relevant singletons were initialized on demand via their "getters". Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2002>
2021-09-16 09:38:49 +00:00
return clutter_context_get_backend (clutter_context);
}
void
meta_backend_prepare_shutdown (MetaBackend *backend)
{
g_signal_emit (backend, signals[PREPARE_SHUTDOWN], 0);
}
2018-10-19 07:15:54 +00:00
/**
* meta_is_stage_views_enabled:
*
* Returns whether the #ClutterStage can be rendered using multiple stage views.
* In practice, this means we can define a separate framebuffer for each
* #MetaLogicalMonitor, rather than rendering everything into a single
* framebuffer. For example: in X11, onle one single framebuffer is allowed.
*/
gboolean
meta_is_stage_views_enabled (void)
{
if (!meta_is_wayland_compositor ())
return FALSE;
return !stage_views_disabled;
}
gboolean
meta_is_stage_views_scaled (void)
{
MetaBackend *backend = meta_get_backend ();
MetaMonitorManager *monitor_manager =
meta_backend_get_monitor_manager (backend);
MetaLogicalMonitorLayoutMode layout_mode;
if (!meta_is_stage_views_enabled ())
return FALSE;
layout_mode = monitor_manager->layout_mode;
return layout_mode == META_LOGICAL_MONITOR_LAYOUT_MODE_LOGICAL;
}
MetaInputMapper *
meta_backend_get_input_mapper (MetaBackend *backend)
{
MetaBackendPrivate *priv = meta_backend_get_instance_private (backend);
return priv->input_mapper;
}
MetaInputSettings *
meta_backend_get_input_settings (MetaBackend *backend)
{
return META_BACKEND_GET_CLASS (backend)->get_input_settings (backend);
}
/**
* meta_backend_get_dnd:
* @backend: A #MetaDnd
*
* Gets the global #MetaDnd that's managed by this backend.
*
* Returns: (transfer none): the #MetaDnd
*/
MetaDnd *
meta_backend_get_dnd (MetaBackend *backend)
{
MetaBackendPrivate *priv = meta_backend_get_instance_private (backend);
return priv->dnd;
}
void
meta_backend_notify_keymap_changed (MetaBackend *backend)
{
g_signal_emit (backend, signals[KEYMAP_CHANGED], 0);
}
void
meta_backend_notify_keymap_layout_group_changed (MetaBackend *backend,
unsigned int locked_group)
{
g_signal_emit (backend, signals[KEYMAP_LAYOUT_GROUP_CHANGED], 0,
locked_group);
}
void
meta_backend_add_gpu (MetaBackend *backend,
MetaGpu *gpu)
{
MetaBackendPrivate *priv = meta_backend_get_instance_private (backend);
priv->gpus = g_list_append (priv->gpus, gpu);
g_signal_emit (backend, signals[GPU_ADDED], 0, gpu);
}
GList *
meta_backend_get_gpus (MetaBackend *backend)
{
MetaBackendPrivate *priv = meta_backend_get_instance_private (backend);
return priv->gpus;
}
#ifdef HAVE_LIBWACOM
WacomDeviceDatabase *
meta_backend_get_wacom_database (MetaBackend *backend)
{
MetaBackendPrivate *priv = meta_backend_get_instance_private (backend);
return priv->wacom_db;
}
#endif
void
meta_backend_add_hw_cursor_inhibitor (MetaBackend *backend,
MetaHwCursorInhibitor *inhibitor)
{
MetaBackendPrivate *priv = meta_backend_get_instance_private (backend);
priv->hw_cursor_inhibitors = g_list_prepend (priv->hw_cursor_inhibitors,
inhibitor);
}
void
meta_backend_remove_hw_cursor_inhibitor (MetaBackend *backend,
MetaHwCursorInhibitor *inhibitor)
{
MetaBackendPrivate *priv = meta_backend_get_instance_private (backend);
priv->hw_cursor_inhibitors = g_list_remove (priv->hw_cursor_inhibitors,
inhibitor);
}
gboolean
meta_backend_is_hw_cursors_inhibited (MetaBackend *backend)
{
MetaBackendPrivate *priv = meta_backend_get_instance_private (backend);
GList *l;
for (l = priv->hw_cursor_inhibitors; l; l = l->next)
{
MetaHwCursorInhibitor *inhibitor = l->data;
if (meta_hw_cursor_inhibitor_is_cursor_inhibited (inhibitor))
return TRUE;
}
return FALSE;
}