mutter/src/backends/native/meta-backend-native.c
Jonas Ådahl c390f70edc backend: Set up and use ownership chains
This means objects have an owner, where the chain eventually always
leads to a MetaContext. This also means that all objects can find their
way to other object instances via the chain, instead of scattered global
singletons.

This is a squashed commit originally containing the following:

cursor-tracker: Don't get backend from singleton

idle-manager: Don't get backend from singleton

input-device: Pass pointer to backend during construction

The backend is needed during construction to get the wacom database.

input-mapper: Pass backend when constructing

monitor: Don't get backend from singleton

monitor-manager: Get backend directly from monitor manager

remote: Get backend from manager class

For the remote desktop and screen cast implementations, replace getting
the backend from singletons with getting it via the manager classes.

launcher: Pass backend during construction

device-pool: Pass backend during construction

Instead of passing the (maybe null) launcher, pass the backend, and get
the launcher from there. That way we always have a way to some known
context from the device pool.

drm-buffer/gbm: Get backend via device pool

cursor-renderer: Get backend directly from renderer

input-device: Get backend getter

input-settings: Add backend construct property and getter

input-settings/x11: Don't get backend from singleton

renderer: Get backend from renderer itself

seat-impl: Add backend getter

seat/native: Get backend from instance struct

stage-impl: Get backend from stage impl itself

x11/xkb-a11y: Don't get backend from singleton

backend/x11/nested: Don't get Wayland compositor from singleton

crtc: Add backend property

Adding a link to the GPU isn't enough; the virtual CRTCs of virtual
monitors doesn't have one.

cursor-tracker: Don't get display from singleton

remote: Don't get display from singleton

seat: Don't get display from singleton

backend/x11: Don't get display from singleton

Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2718>
2022-12-17 13:52:51 +00:00

1031 lines
33 KiB
C

/* -*- 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>
*/
/**
* SECTION:meta-backend-native
* @title: MetaBackendNative
* @short_description: A native (KMS/evdev) MetaBackend
*
* MetaBackendNative is an implementation of #MetaBackend that uses "native"
* technologies like DRM/KMS and libinput/evdev to perform the necessary
* functions.
*/
#include "config.h"
#include "backends/native/meta-backend-native.h"
#include "backends/native/meta-backend-native-private.h"
#include "backends/native/meta-input-thread.h"
#include <stdlib.h>
#include "backends/meta-color-manager.h"
#include "backends/meta-cursor-tracker-private.h"
#include "backends/meta-idle-manager.h"
#include "backends/meta-keymap-utils.h"
#include "backends/meta-logical-monitor.h"
#include "backends/meta-monitor-manager-private.h"
#include "backends/meta-pointer-constraint.h"
#include "backends/meta-settings-private.h"
#include "backends/meta-stage-private.h"
#include "backends/native/meta-clutter-backend-native.h"
#include "backends/native/meta-device-pool-private.h"
#include "backends/native/meta-kms.h"
#include "backends/native/meta-kms-device.h"
#include "backends/native/meta-launcher.h"
#include "backends/native/meta-monitor-manager-native.h"
#include "backends/native/meta-render-device-gbm.h"
#include "backends/native/meta-renderer-native.h"
#include "backends/native/meta-seat-native.h"
#include "backends/native/meta-stage-native.h"
#include "cogl/cogl.h"
#include "core/meta-border.h"
#include "meta/main.h"
#include "meta-dbus-rtkit1.h"
#ifdef HAVE_REMOTE_DESKTOP
#include "backends/meta-screen-cast.h"
#endif
#ifdef HAVE_EGL_DEVICE
#include "backends/native/meta-render-device-egl-stream.h"
#endif
#include "meta-private-enum-types.h"
enum
{
PROP_0,
PROP_MODE,
N_PROPS
};
static GParamSpec *obj_props[N_PROPS];
struct _MetaBackendNative
{
MetaBackend parent;
MetaLauncher *launcher;
MetaDevicePool *device_pool;
MetaUdev *udev;
MetaKms *kms;
GHashTable *startup_render_devices;
MetaBackendNativeMode mode;
};
static GInitableIface *initable_parent_iface;
static void
initable_iface_init (GInitableIface *initable_iface);
G_DEFINE_TYPE_WITH_CODE (MetaBackendNative, meta_backend_native, META_TYPE_BACKEND,
G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
initable_iface_init))
static void
meta_backend_native_dispose (GObject *object)
{
MetaBackendNative *native = META_BACKEND_NATIVE (object);
if (native->kms)
meta_kms_prepare_shutdown (native->kms);
G_OBJECT_CLASS (meta_backend_native_parent_class)->dispose (object);
g_clear_pointer (&native->startup_render_devices, g_hash_table_unref);
g_clear_object (&native->kms);
g_clear_object (&native->udev);
g_clear_object (&native->device_pool);
g_clear_pointer (&native->launcher, meta_launcher_free);
}
static ClutterBackend *
meta_backend_native_create_clutter_backend (MetaBackend *backend)
{
return CLUTTER_BACKEND (meta_clutter_backend_native_new (backend));
}
static ClutterSeat *
meta_backend_native_create_default_seat (MetaBackend *backend,
GError **error)
{
MetaBackendNative *backend_native = META_BACKEND_NATIVE (backend);
const char *seat_id = NULL;
MetaSeatNativeFlag flags;
switch (backend_native->mode)
{
case META_BACKEND_NATIVE_MODE_DEFAULT:
case META_BACKEND_NATIVE_MODE_HEADLESS:
seat_id = meta_backend_native_get_seat_id (backend_native);
break;
case META_BACKEND_NATIVE_MODE_TEST:
seat_id = META_BACKEND_TEST_INPUT_SEAT;
break;
}
if (meta_backend_is_headless (backend))
flags = META_SEAT_NATIVE_FLAG_NO_LIBINPUT;
else
flags = META_SEAT_NATIVE_FLAG_NONE;
return CLUTTER_SEAT (g_object_new (META_TYPE_SEAT_NATIVE,
"backend", backend,
"seat-id", seat_id,
"flags", flags,
NULL));
}
#ifdef HAVE_REMOTE_DESKTOP
static void
maybe_disable_screen_cast_dma_bufs (MetaBackendNative *native)
{
MetaBackend *backend = META_BACKEND (native);
MetaRenderer *renderer = meta_backend_get_renderer (backend);
MetaScreenCast *screen_cast = meta_backend_get_screen_cast (backend);
ClutterBackend *clutter_backend =
meta_backend_get_clutter_backend (backend);
CoglContext *cogl_context =
clutter_backend_get_cogl_context (clutter_backend);
CoglRenderer *cogl_renderer = cogl_context_get_renderer (cogl_context);
g_autoptr (GError) error = NULL;
g_autoptr (CoglDmaBufHandle) dmabuf_handle = NULL;
if (!meta_renderer_is_hardware_accelerated (renderer))
{
g_message ("Disabling DMA buffer screen sharing "
"(not hardware accelerated)");
meta_screen_cast_disable_dma_bufs (screen_cast);
}
dmabuf_handle = cogl_renderer_create_dma_buf (cogl_renderer,
1, 1,
&error);
if (!dmabuf_handle)
{
g_message ("Disabling DMA buffer screen sharing "
"(implicit modifiers not supported)");
meta_screen_cast_disable_dma_bufs (screen_cast);
}
}
#endif /* HAVE_REMOTE_DESKTOP */
static void
update_viewports (MetaBackend *backend)
{
MetaMonitorManager *monitor_manager =
meta_backend_get_monitor_manager (backend);
ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend);
MetaSeatNative *seat =
META_SEAT_NATIVE (clutter_backend_get_default_seat (clutter_backend));
MetaViewportInfo *viewports;
viewports = meta_monitor_manager_get_viewports (monitor_manager);
meta_seat_native_set_viewports (seat, viewports);
g_object_unref (viewports);
}
static void
meta_backend_native_post_init (MetaBackend *backend)
{
MetaBackendNative *backend_native = META_BACKEND_NATIVE (backend);
MetaSettings *settings = meta_backend_get_settings (backend);
META_BACKEND_CLASS (meta_backend_native_parent_class)->post_init (backend);
if (meta_settings_is_experimental_feature_enabled (settings,
META_EXPERIMENTAL_FEATURE_RT_SCHEDULER))
{
g_autoptr (MetaDbusRealtimeKit1) rtkit_proxy = NULL;
g_autoptr (GError) error = NULL;
rtkit_proxy =
meta_dbus_realtime_kit1_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES |
G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS |
G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
"org.freedesktop.RealtimeKit1",
"/org/freedesktop/RealtimeKit1",
NULL,
&error);
if (rtkit_proxy)
{
uint32_t priority;
priority = sched_get_priority_min (SCHED_RR);
meta_dbus_realtime_kit1_call_make_thread_realtime_sync (rtkit_proxy,
gettid (),
priority,
NULL,
&error);
}
if (error)
{
g_dbus_error_strip_remote_error (error);
g_message ("Failed to set RT scheduler: %s", error->message);
}
}
#ifdef HAVE_REMOTE_DESKTOP
maybe_disable_screen_cast_dma_bufs (backend_native);
#endif
g_clear_pointer (&backend_native->startup_render_devices,
g_hash_table_unref);
update_viewports (backend);
}
static MetaBackendCapabilities
meta_backend_native_get_capabilities (MetaBackend *backend)
{
return META_BACKEND_CAPABILITY_BARRIERS;
}
static MetaMonitorManager *
meta_backend_native_create_monitor_manager (MetaBackend *backend,
GError **error)
{
MetaBackendNative *backend_native = META_BACKEND_NATIVE (backend);
MetaMonitorManager *manager;
gboolean needs_outputs;
needs_outputs = !(backend_native->mode & META_BACKEND_NATIVE_MODE_HEADLESS);
manager = g_initable_new (META_TYPE_MONITOR_MANAGER_NATIVE, NULL, error,
"backend", backend,
"needs-outputs", needs_outputs,
NULL);
if (!manager)
return NULL;
g_signal_connect_swapped (manager, "monitors-changed-internal",
G_CALLBACK (update_viewports), backend);
return manager;
}
static MetaColorManager *
meta_backend_native_create_color_manager (MetaBackend *backend)
{
return g_object_new (META_TYPE_COLOR_MANAGER,
"backend", backend,
NULL);
}
static MetaCursorRenderer *
meta_backend_native_get_cursor_renderer (MetaBackend *backend,
ClutterInputDevice *device)
{
ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend);
MetaSeatNative *seat_native =
META_SEAT_NATIVE (clutter_backend_get_default_seat (clutter_backend));
return meta_seat_native_maybe_ensure_cursor_renderer (seat_native, device);
}
static MetaRenderer *
meta_backend_native_create_renderer (MetaBackend *backend,
GError **error)
{
MetaBackendNative *native = META_BACKEND_NATIVE (backend);
MetaRendererNative *renderer_native;
renderer_native = meta_renderer_native_new (native, error);
if (!renderer_native)
return NULL;
return META_RENDERER (renderer_native);
}
static MetaInputSettings *
meta_backend_native_get_input_settings (MetaBackend *backend)
{
ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend);
MetaSeatNative *seat_native =
META_SEAT_NATIVE (clutter_backend_get_default_seat (clutter_backend));
return meta_seat_impl_get_input_settings (seat_native->impl);
}
static MetaLogicalMonitor *
meta_backend_native_get_current_logical_monitor (MetaBackend *backend)
{
MetaCursorTracker *cursor_tracker = meta_backend_get_cursor_tracker (backend);
MetaMonitorManager *monitor_manager =
meta_backend_get_monitor_manager (backend);
graphene_point_t point;
meta_cursor_tracker_get_pointer (cursor_tracker, &point, NULL);
return meta_monitor_manager_get_logical_monitor_at (monitor_manager,
point.x, point.y);
}
static void
meta_backend_native_set_keymap (MetaBackend *backend,
const char *layouts,
const char *variants,
const char *options)
{
ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend);
ClutterSeat *seat;
seat = clutter_backend_get_default_seat (clutter_backend);
meta_seat_native_set_keyboard_map (META_SEAT_NATIVE (seat),
layouts, variants, options);
meta_backend_notify_keymap_changed (backend);
}
static struct xkb_keymap *
meta_backend_native_get_keymap (MetaBackend *backend)
{
ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend);
ClutterSeat *seat;
seat = clutter_backend_get_default_seat (clutter_backend);
return meta_seat_native_get_keyboard_map (META_SEAT_NATIVE (seat));
}
static xkb_layout_index_t
meta_backend_native_get_keymap_layout_group (MetaBackend *backend)
{
ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend);
ClutterSeat *seat;
seat = clutter_backend_get_default_seat (clutter_backend);
return meta_seat_native_get_keyboard_layout_index (META_SEAT_NATIVE (seat));
}
static void
meta_backend_native_lock_layout_group (MetaBackend *backend,
guint idx)
{
ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend);
xkb_layout_index_t old_idx;
ClutterSeat *seat;
old_idx = meta_backend_native_get_keymap_layout_group (backend);
if (old_idx == idx)
return;
seat = clutter_backend_get_default_seat (clutter_backend);
meta_seat_native_set_keyboard_layout_index (META_SEAT_NATIVE (seat), idx);
meta_backend_notify_keymap_layout_group_changed (backend, idx);
}
const char *
meta_backend_native_get_seat_id (MetaBackendNative *backend_native)
{
switch (backend_native->mode)
{
case META_BACKEND_NATIVE_MODE_DEFAULT:
case META_BACKEND_NATIVE_MODE_TEST:
return meta_launcher_get_seat_id (backend_native->launcher);
case META_BACKEND_NATIVE_MODE_HEADLESS:
return "seat0";
}
g_assert_not_reached ();
}
static gboolean
meta_backend_native_is_headless (MetaBackend *backend)
{
MetaBackendNative *backend_native = META_BACKEND_NATIVE (backend);
return backend_native->mode == META_BACKEND_NATIVE_MODE_HEADLESS;
}
static void
meta_backend_native_set_pointer_constraint (MetaBackend *backend,
MetaPointerConstraint *constraint)
{
ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend);
ClutterSeat *seat = clutter_backend_get_default_seat (clutter_backend);
MetaPointerConstraintImpl *constraint_impl = NULL;
cairo_region_t *region;
if (constraint)
{
double min_edge_distance;
region = meta_pointer_constraint_get_region (constraint);
min_edge_distance =
meta_pointer_constraint_get_min_edge_distance (constraint);
constraint_impl = meta_pointer_constraint_impl_native_new (constraint,
region,
min_edge_distance);
}
meta_seat_native_set_pointer_constraint (META_SEAT_NATIVE (seat),
constraint_impl);
}
static void
meta_backend_native_update_screen_size (MetaBackend *backend,
int width, int height)
{
ClutterActor *stage = meta_backend_get_stage (backend);
ClutterStageWindow *stage_window =
_clutter_stage_get_window (CLUTTER_STAGE (stage));
MetaStageNative *stage_native = META_STAGE_NATIVE (stage_window);
meta_stage_native_rebuild_views (stage_native);
clutter_actor_set_size (stage, width, height);
}
static MetaRenderDevice *
create_render_device (MetaBackendNative *backend_native,
const char *device_path,
GError **error)
{
MetaBackend *backend = META_BACKEND (backend_native);
MetaDevicePool *device_pool =
meta_backend_native_get_device_pool (backend_native);
g_autoptr (MetaDeviceFile) device_file = NULL;
MetaDeviceFileFlags device_file_flags;
g_autoptr (MetaRenderDeviceGbm) render_device_gbm = NULL;
g_autoptr (GError) gbm_error = NULL;
#ifdef HAVE_EGL_DEVICE
g_autoptr (MetaRenderDeviceEglStream) render_device_egl_stream = NULL;
g_autoptr (GError) egl_stream_error = NULL;
#endif
if (meta_backend_is_headless (backend))
device_file_flags = META_DEVICE_FILE_FLAG_NONE;
else
device_file_flags = META_DEVICE_FILE_FLAG_TAKE_CONTROL;
device_file = meta_device_pool_open (device_pool,
device_path,
device_file_flags,
error);
if (!device_file)
return NULL;
if (meta_backend_is_headless (backend))
{
int fd;
g_autofree char *render_node_path = NULL;
g_autoptr (MetaDeviceFile) render_node_device_file = NULL;
fd = meta_device_file_get_fd (device_file);
render_node_path = drmGetRenderDeviceNameFromFd (fd);
if (!render_node_path)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Couldn't find render node device for '%s'",
meta_device_file_get_path (device_file));
return NULL;
}
meta_topic (META_DEBUG_KMS, "Found render node '%s' from '%s'",
render_node_path,
meta_device_file_get_path (device_file));
render_node_device_file =
meta_device_pool_open (device_pool, render_node_path,
META_DEVICE_FILE_FLAG_NONE,
error);
if (!render_node_device_file)
return NULL;
g_clear_pointer (&device_file, meta_device_file_release);
device_file = g_steal_pointer (&render_node_device_file);
}
#ifdef HAVE_EGL_DEVICE
if (g_strcmp0 (getenv ("MUTTER_DEBUG_FORCE_EGL_STREAM"), "1") != 0)
#endif
{
render_device_gbm = meta_render_device_gbm_new (backend, device_file,
&gbm_error);
if (render_device_gbm)
{
MetaRenderDevice *render_device =
META_RENDER_DEVICE (render_device_gbm);
if (meta_render_device_is_hardware_accelerated (render_device))
return META_RENDER_DEVICE (g_steal_pointer (&render_device_gbm));
}
}
#ifdef HAVE_EGL_DEVICE
else
{
g_set_error (&gbm_error, G_IO_ERROR, G_IO_ERROR_FAILED,
"GBM backend was disabled using env var");
}
#endif
#ifdef HAVE_EGL_DEVICE
render_device_egl_stream =
meta_render_device_egl_stream_new (backend,
device_file,
&egl_stream_error);
if (render_device_egl_stream)
return META_RENDER_DEVICE (g_steal_pointer (&render_device_egl_stream));
#endif
if (render_device_gbm)
return META_RENDER_DEVICE (g_steal_pointer (&render_device_gbm));
g_set_error (error, G_IO_ERROR,
G_IO_ERROR_FAILED,
"Failed to initialize render device for %s: "
"%s"
#ifdef HAVE_EGL_DEVICE
", %s"
#endif
, device_path
, gbm_error->message
#ifdef HAVE_EGL_DEVICE
, egl_stream_error->message
#endif
);
return NULL;
}
static gboolean
add_drm_device (MetaBackendNative *backend_native,
GUdevDevice *device,
GError **error)
{
MetaKmsDeviceFlag flags = META_KMS_DEVICE_FLAG_NONE;
const char *device_path;
g_autoptr (MetaRenderDevice) render_device = NULL;
MetaKmsDevice *kms_device;
MetaGpuKms *gpu_kms;
if (meta_is_udev_device_platform_device (device))
flags |= META_KMS_DEVICE_FLAG_PLATFORM_DEVICE;
if (meta_is_udev_device_boot_vga (device))
flags |= META_KMS_DEVICE_FLAG_BOOT_VGA;
if (meta_is_udev_device_disable_modifiers (device))
flags |= META_KMS_DEVICE_FLAG_DISABLE_MODIFIERS;
if (meta_is_udev_device_disable_client_modifiers (device))
flags |= META_KMS_DEVICE_FLAG_DISABLE_CLIENT_MODIFIERS;
if (meta_is_udev_device_preferred_primary (device))
flags |= META_KMS_DEVICE_FLAG_PREFERRED_PRIMARY;
device_path = g_udev_device_get_device_file (device);
render_device = create_render_device (backend_native, device_path, error);
if (!render_device)
return FALSE;
#ifdef HAVE_EGL_DEVICE
if (META_IS_RENDER_DEVICE_EGL_STREAM (render_device))
flags |= META_KMS_DEVICE_FLAG_FORCE_LEGACY;
#endif
kms_device = meta_kms_create_device (backend_native->kms, device_path, flags,
error);
if (!kms_device)
return FALSE;
g_hash_table_insert (backend_native->startup_render_devices,
g_strdup (device_path),
g_steal_pointer (&render_device));
gpu_kms = meta_gpu_kms_new (backend_native, kms_device, error);
meta_backend_add_gpu (META_BACKEND (backend_native), META_GPU (gpu_kms));
return TRUE;
}
static gboolean
should_ignore_device (MetaBackendNative *backend_native,
GUdevDevice *device)
{
switch (backend_native->mode)
{
case META_BACKEND_NATIVE_MODE_DEFAULT:
case META_BACKEND_NATIVE_MODE_HEADLESS:
return meta_is_udev_device_ignore (device);
case META_BACKEND_NATIVE_MODE_TEST:
return !meta_is_udev_test_device (device);
}
g_assert_not_reached ();
}
static void
on_udev_device_added (MetaUdev *udev,
GUdevDevice *device,
MetaBackendNative *native)
{
MetaBackend *backend = META_BACKEND (native);
g_autoptr (GError) error = NULL;
const char *device_path;
GList *gpus, *l;
if (!meta_udev_is_drm_device (udev, device))
return;
device_path = g_udev_device_get_device_file (device);
gpus = meta_backend_get_gpus (backend);
for (l = gpus; l; l = l->next)
{
MetaGpuKms *gpu_kms = l->data;
if (!g_strcmp0 (device_path, meta_gpu_kms_get_file_path (gpu_kms)))
{
g_warning ("Failed to hotplug secondary gpu '%s': %s",
device_path, "device already present");
return;
}
}
if (should_ignore_device (native, device))
{
g_message ("Ignoring DRM device '%s'", device_path);
return;
}
if (!add_drm_device (native, device, &error))
{
if (meta_backend_is_headless (backend) &&
g_error_matches (error, G_IO_ERROR,
G_IO_ERROR_PERMISSION_DENIED))
{
meta_topic (META_DEBUG_BACKEND,
"Ignoring unavailable secondary gpu '%s': %s",
device_path, error->message);
}
else
{
g_warning ("Failed to hotplug secondary gpu '%s': %s",
device_path, error->message);
}
}
}
static gboolean
init_gpus (MetaBackendNative *native,
GError **error)
{
MetaBackend *backend = META_BACKEND (native);
MetaUdev *udev = meta_backend_native_get_udev (native);
g_autoptr (GError) local_error = NULL;
GList *devices;
GList *l;
devices = meta_udev_list_drm_devices (udev, &local_error);
if (local_error)
{
g_propagate_error (error, g_steal_pointer (&local_error));
return FALSE;
}
for (l = devices; l; l = l->next)
{
GUdevDevice *device = l->data;
GError *local_error = NULL;
if (should_ignore_device (native, device))
{
g_message ("Ignoring DRM device '%s'",
g_udev_device_get_device_file (device));
continue;
}
if (!add_drm_device (native, device, &local_error))
{
if (meta_backend_is_headless (backend) &&
g_error_matches (local_error, G_IO_ERROR,
G_IO_ERROR_PERMISSION_DENIED))
{
meta_topic (META_DEBUG_BACKEND,
"Ignoring unavailable gpu '%s': %s'",
g_udev_device_get_device_file (device),
local_error->message);
}
else
{
g_warning ("Failed to open gpu '%s': %s",
g_udev_device_get_device_file (device),
local_error->message);
}
g_clear_error (&local_error);
continue;
}
}
g_list_free_full (devices, g_object_unref);
if (!meta_backend_is_headless (backend) &&
g_list_length (meta_backend_get_gpus (backend)) == 0)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
"No GPUs found");
return FALSE;
}
g_signal_connect_object (native->udev, "device-added",
G_CALLBACK (on_udev_device_added), native,
0);
return TRUE;
}
static gboolean
meta_backend_native_initable_init (GInitable *initable,
GCancellable *cancellable,
GError **error)
{
MetaBackendNative *native = META_BACKEND_NATIVE (initable);
MetaBackend *backend = META_BACKEND (native);
MetaKmsFlags kms_flags;
if (!meta_backend_is_headless (backend))
{
const char *session_id = NULL;
const char *seat_id = NULL;
switch (native->mode)
{
case META_BACKEND_NATIVE_MODE_DEFAULT:
break;
case META_BACKEND_NATIVE_MODE_HEADLESS:
g_assert_not_reached ();
break;
case META_BACKEND_NATIVE_MODE_TEST:
session_id = "dummy";
seat_id = "seat0";
break;
}
native->launcher = meta_launcher_new (backend,
session_id, seat_id,
error);
if (!native->launcher)
return FALSE;
}
native->device_pool = meta_device_pool_new (native);
native->udev = meta_udev_new (native);
kms_flags = META_KMS_FLAG_NONE;
if (meta_backend_is_headless (backend))
kms_flags |= META_KMS_FLAG_NO_MODE_SETTING;
native->kms = meta_kms_new (META_BACKEND (native), kms_flags, error);
if (!native->kms)
return FALSE;
if (!init_gpus (native, error))
return FALSE;
return initable_parent_iface->init (initable, cancellable, error);
}
static void
meta_backend_native_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
MetaBackendNative *backend_native = META_BACKEND_NATIVE (object);
switch (prop_id)
{
case PROP_MODE:
backend_native->mode = g_value_get_enum (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
initable_iface_init (GInitableIface *initable_iface)
{
initable_parent_iface = g_type_interface_peek_parent (initable_iface);
initable_iface->init = meta_backend_native_initable_init;
}
static void
meta_backend_native_class_init (MetaBackendNativeClass *klass)
{
MetaBackendClass *backend_class = META_BACKEND_CLASS (klass);
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->set_property = meta_backend_native_set_property;
object_class->dispose = meta_backend_native_dispose;
backend_class->create_clutter_backend = meta_backend_native_create_clutter_backend;
backend_class->create_default_seat = meta_backend_native_create_default_seat;
backend_class->post_init = meta_backend_native_post_init;
backend_class->get_capabilities = meta_backend_native_get_capabilities;
backend_class->create_monitor_manager = meta_backend_native_create_monitor_manager;
backend_class->create_color_manager = meta_backend_native_create_color_manager;
backend_class->get_cursor_renderer = meta_backend_native_get_cursor_renderer;
backend_class->create_renderer = meta_backend_native_create_renderer;
backend_class->get_input_settings = meta_backend_native_get_input_settings;
backend_class->get_current_logical_monitor = meta_backend_native_get_current_logical_monitor;
backend_class->set_keymap = meta_backend_native_set_keymap;
backend_class->get_keymap = meta_backend_native_get_keymap;
backend_class->get_keymap_layout_group = meta_backend_native_get_keymap_layout_group;
backend_class->lock_layout_group = meta_backend_native_lock_layout_group;
backend_class->update_screen_size = meta_backend_native_update_screen_size;
backend_class->set_pointer_constraint = meta_backend_native_set_pointer_constraint;
backend_class->is_headless = meta_backend_native_is_headless;
obj_props[PROP_MODE] =
g_param_spec_enum ("mode",
"mode",
"mode",
META_TYPE_BACKEND_NATIVE_MODE,
META_BACKEND_NATIVE_MODE_DEFAULT,
G_PARAM_WRITABLE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (object_class, N_PROPS, obj_props);
}
static void
meta_backend_native_init (MetaBackendNative *backend_native)
{
backend_native->startup_render_devices =
g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, g_object_unref);
}
MetaLauncher *
meta_backend_native_get_launcher (MetaBackendNative *native)
{
return native->launcher;
}
MetaDevicePool *
meta_backend_native_get_device_pool (MetaBackendNative *native)
{
return native->device_pool;
}
MetaUdev *
meta_backend_native_get_udev (MetaBackendNative *native)
{
return native->udev;
}
MetaKms *
meta_backend_native_get_kms (MetaBackendNative *native)
{
return native->kms;
}
gboolean
meta_backend_native_activate_vt (MetaBackendNative *backend_native,
int vt,
GError **error)
{
MetaLauncher *launcher = meta_backend_native_get_launcher (backend_native);
switch (backend_native->mode)
{
case META_BACKEND_NATIVE_MODE_DEFAULT:
return meta_launcher_activate_vt (launcher, vt, error);
case META_BACKEND_NATIVE_MODE_HEADLESS:
case META_BACKEND_NATIVE_MODE_TEST:
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Can't switch VT while headless");
return FALSE;
}
g_assert_not_reached ();
}
void
meta_backend_native_pause (MetaBackendNative *native)
{
MetaBackend *backend = META_BACKEND (native);
MetaMonitorManager *monitor_manager =
meta_backend_get_monitor_manager (backend);
MetaMonitorManagerNative *monitor_manager_native =
META_MONITOR_MANAGER_NATIVE (monitor_manager);
ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend);
MetaSeatNative *seat =
META_SEAT_NATIVE (clutter_backend_get_default_seat (clutter_backend));
MetaRenderer *renderer = meta_backend_get_renderer (backend);
COGL_TRACE_BEGIN_SCOPED (MetaBackendNativePause,
"Backend (pause)");
meta_seat_native_release_devices (seat);
meta_renderer_pause (renderer);
meta_udev_pause (native->udev);
meta_monitor_manager_native_pause (monitor_manager_native);
}
void meta_backend_native_resume (MetaBackendNative *native)
{
MetaBackend *backend = META_BACKEND (native);
ClutterStage *stage = CLUTTER_STAGE (meta_backend_get_stage (backend));
MetaMonitorManager *monitor_manager =
meta_backend_get_monitor_manager (backend);
MetaMonitorManagerNative *monitor_manager_native =
META_MONITOR_MANAGER_NATIVE (monitor_manager);
ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend);
MetaSeatNative *seat =
META_SEAT_NATIVE (clutter_backend_get_default_seat (clutter_backend));
MetaRenderer *renderer = meta_backend_get_renderer (backend);
MetaIdleManager *idle_manager;
MetaInputSettings *input_settings;
COGL_TRACE_BEGIN_SCOPED (MetaBackendNativeResume,
"Backend (resume)");
meta_monitor_manager_native_resume (monitor_manager_native);
meta_udev_resume (native->udev);
meta_kms_resume (native->kms);
meta_seat_native_reclaim_devices (seat);
meta_renderer_resume (renderer);
clutter_actor_queue_redraw (CLUTTER_ACTOR (stage));
idle_manager = meta_backend_get_idle_manager (backend);
meta_idle_manager_reset_idle_time (idle_manager);
input_settings = meta_backend_get_input_settings (backend);
meta_input_settings_maybe_restore_numlock_state (input_settings);
clutter_seat_ensure_a11y_state (CLUTTER_SEAT (seat));
}
static MetaRenderDevice *
meta_backend_native_create_render_device (MetaBackendNative *backend_native,
const char *device_path,
GError **error)
{
g_autoptr (MetaRenderDevice) render_device = NULL;
render_device = create_render_device (backend_native, device_path, error);
return g_steal_pointer (&render_device);
}
MetaRenderDevice *
meta_backend_native_take_render_device (MetaBackendNative *backend_native,
const char *device_path,
GError **error)
{
MetaRenderDevice *render_device;
if (g_hash_table_steal_extended (backend_native->startup_render_devices,
device_path,
NULL,
(gpointer *) &render_device))
{
return render_device;
}
else
{
return meta_backend_native_create_render_device (backend_native,
device_path, error);
}
}