/* -*- 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 */ /** * 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 #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); 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); } }