1
0
Fork 0
mutter-performance-source/src/backends/native/meta-backend-native.c
Carlos Garnacho 35abb8ab53 backends: Add meta_backend_get_cursor_renderer_for_device()
Different devices may get standalone cursor renderers, add this API
to adapt slowly to this. The meta_backend_get_cursor_renderer() call
still exists, but shortcuts to the mouse pointer's renderer (as it
actually did before).

Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403>
2020-11-27 15:14:33 +00:00

675 lines
20 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 <sched.h>
#include <stdlib.h>
#include "backends/meta-cursor-tracker-private.h"
#include "backends/meta-idle-monitor-private.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-event-native.h"
#include "backends/native/meta-input-settings-native.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-kms.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"
#ifdef HAVE_REMOTE_DESKTOP
#include "backends/meta-screen-cast.h"
#endif
struct _MetaBackendNative
{
MetaBackend parent;
MetaLauncher *launcher;
MetaUdev *udev;
MetaKms *kms;
gulong udev_device_added_handler_id;
};
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
disconnect_udev_device_added_handler (MetaBackendNative *native);
static void
meta_backend_native_finalize (GObject *object)
{
MetaBackendNative *native = META_BACKEND_NATIVE (object);
if (native->udev_device_added_handler_id)
disconnect_udev_device_added_handler (native);
g_clear_object (&native->udev);
g_clear_object (&native->kms);
meta_launcher_free (native->launcher);
G_OBJECT_CLASS (meta_backend_native_parent_class)->finalize (object);
}
static ClutterBackend *
meta_backend_native_create_clutter_backend (MetaBackend *backend)
{
return g_object_new (META_TYPE_CLUTTER_BACKEND_NATIVE, NULL);
}
#ifdef HAVE_REMOTE_DESKTOP
static void
maybe_disable_screen_cast_dma_bufs (MetaBackendNative *native)
{
MetaBackend *backend = META_BACKEND (native);
MetaSettings *settings = meta_backend_get_settings (backend);
MetaRenderer *renderer = meta_backend_get_renderer (backend);
MetaRendererNative *renderer_native = META_RENDERER_NATIVE (renderer);
MetaScreenCast *screen_cast = meta_backend_get_screen_cast (backend);
MetaGpuKms *primary_gpu;
MetaKmsDevice *kms_device;
const char *driver_name;
static const char *enable_dma_buf_drivers[] = {
"i915",
NULL,
};
primary_gpu = meta_renderer_native_get_primary_gpu (renderer_native);
kms_device = meta_gpu_kms_get_kms_device (primary_gpu);
driver_name = meta_kms_device_get_driver_name (kms_device);
if (g_strv_contains (enable_dma_buf_drivers, driver_name))
return;
if (meta_settings_is_experimental_feature_enabled (settings,
META_EXPERIMENTAL_FEATURE_DMA_BUF_SCREEN_SHARING))
return;
g_message ("Disabling DMA buffer screen sharing for driver '%s'.",
driver_name);
meta_screen_cast_disable_dma_bufs (screen_cast);
}
#endif /* HAVE_REMOTE_DESKTOP */
static void
meta_backend_native_post_init (MetaBackend *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))
{
int retval;
struct sched_param sp = {
.sched_priority = sched_get_priority_min (SCHED_RR)
};
retval = sched_setscheduler (0, SCHED_RR | SCHED_RESET_ON_FORK, &sp);
if (retval != 0)
g_warning ("Failed to set RT scheduler: %m");
}
#ifdef HAVE_REMOTE_DESKTOP
maybe_disable_screen_cast_dma_bufs (META_BACKEND_NATIVE (backend));
#endif
#ifdef HAVE_WAYLAND
meta_backend_init_wayland (backend);
#endif
}
static MetaMonitorManager *
meta_backend_native_create_monitor_manager (MetaBackend *backend,
GError **error)
{
return g_initable_new (META_TYPE_MONITOR_MANAGER_KMS, NULL, error,
"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_create_input_settings (MetaBackend *backend)
{
return g_object_new (META_TYPE_INPUT_SETTINGS_NATIVE, NULL);
}
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);
struct xkb_rule_names names;
struct xkb_keymap *keymap;
struct xkb_context *context;
ClutterSeat *seat;
names.rules = DEFAULT_XKB_RULES_FILE;
names.model = DEFAULT_XKB_MODEL;
names.layout = layouts;
names.variant = variants;
names.options = options;
context = meta_create_xkb_context ();
keymap = xkb_keymap_new_from_names (context, &names, XKB_KEYMAP_COMPILE_NO_FLAGS);
xkb_context_unref (context);
if (keymap == NULL)
{
g_warning ("Unable to load configured keymap: rules=%s, model=%s, layout=%s, variant=%s, options=%s",
DEFAULT_XKB_RULES_FILE, DEFAULT_XKB_MODEL, layouts,
variants, options);
return;
}
seat = clutter_backend_get_default_seat (clutter_backend);
meta_seat_native_set_keyboard_map (META_SEAT_NATIVE (seat), keymap);
meta_backend_notify_keymap_changed (backend);
xkb_keymap_unref (keymap);
}
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);
}
static void
meta_backend_native_set_numlock (MetaBackend *backend,
gboolean numlock_state)
{
ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend);
ClutterSeat *seat;
seat = clutter_backend_get_default_seat (clutter_backend);
meta_seat_native_set_keyboard_numlock (META_SEAT_NATIVE (seat),
numlock_state);
}
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)
{
region = meta_pointer_constraint_get_region (constraint);
constraint_impl = meta_pointer_constraint_impl_native_new (constraint,
region);
}
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)
{
ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend);
MetaStageNative *stage_native;
ClutterActor *stage = meta_backend_get_stage (backend);
stage_native = meta_clutter_backend_native_get_stage_native (clutter_backend);
meta_stage_native_rebuild_views (stage_native);
clutter_actor_set_size (stage, width, height);
}
static MetaGpuKms *
create_gpu_from_udev_device (MetaBackendNative *native,
GUdevDevice *device,
GError **error)
{
MetaKmsDeviceFlag flags = META_KMS_DEVICE_FLAG_NONE;
const char *device_path;
MetaKmsDevice *kms_device;
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_requires_modifiers (device))
flags |= META_KMS_DEVICE_FLAG_REQUIRES_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);
kms_device = meta_kms_create_device (native->kms, device_path, flags,
error);
if (!kms_device)
return NULL;
return meta_gpu_kms_new (native, kms_device, error);
}
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;
MetaGpuKms *new_gpu_kms;
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;
}
}
new_gpu_kms = create_gpu_from_udev_device (native, device, &error);
if (!new_gpu_kms)
{
g_warning ("Failed to hotplug secondary gpu '%s': %s",
device_path, error->message);
return;
}
meta_backend_add_gpu (backend, META_GPU (new_gpu_kms));
}
static void
connect_udev_device_added_handler (MetaBackendNative *native)
{
native->udev_device_added_handler_id =
g_signal_connect (native->udev, "device-added",
G_CALLBACK (on_udev_device_added), native);
}
static void
disconnect_udev_device_added_handler (MetaBackendNative *native)
{
g_clear_signal_handler (&native->udev_device_added_handler_id, native->udev);
}
static gboolean
init_gpus (MetaBackendNative *native,
GError **error)
{
MetaBackend *backend = META_BACKEND (native);
MetaUdev *udev = meta_backend_native_get_udev (native);
GList *devices;
GList *l;
devices = meta_udev_list_drm_devices (udev, error);
if (!devices)
return FALSE;
for (l = devices; l; l = l->next)
{
GUdevDevice *device = l->data;
MetaGpuKms *gpu_kms;
GError *local_error = NULL;
gpu_kms = create_gpu_from_udev_device (native, device, &local_error);
if (!gpu_kms)
{
g_warning ("Failed to open gpu '%s': %s",
g_udev_device_get_device_file (device),
local_error->message);
g_clear_error (&local_error);
continue;
}
meta_backend_add_gpu (backend, META_GPU (gpu_kms));
}
g_list_free_full (devices, g_object_unref);
if (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;
}
connect_udev_device_added_handler (native);
return TRUE;
}
static gboolean
meta_backend_native_initable_init (GInitable *initable,
GCancellable *cancellable,
GError **error)
{
MetaBackendNative *native = META_BACKEND_NATIVE (initable);
if (!meta_is_stage_views_enabled ())
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"The native backend requires stage views");
return FALSE;
}
native->launcher = meta_launcher_new (error);
if (!native->launcher)
return FALSE;
#ifdef HAVE_WAYLAND
meta_backend_init_wayland_display (META_BACKEND (native));
#endif
native->udev = meta_udev_new (native);
native->kms = meta_kms_new (META_BACKEND (native), error);
if (!native->kms)
return FALSE;
if (!init_gpus (native, error))
return FALSE;
return initable_parent_iface->init (initable, cancellable, error);
}
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->finalize = meta_backend_native_finalize;
backend_class->create_clutter_backend = meta_backend_native_create_clutter_backend;
backend_class->post_init = meta_backend_native_post_init;
backend_class->create_monitor_manager = meta_backend_native_create_monitor_manager;
backend_class->get_cursor_renderer = meta_backend_native_get_cursor_renderer;
backend_class->create_renderer = meta_backend_native_create_renderer;
backend_class->create_input_settings = meta_backend_native_create_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_numlock = meta_backend_native_set_numlock;
backend_class->set_pointer_constraint = meta_backend_native_set_pointer_constraint;
}
static void
meta_backend_native_init (MetaBackendNative *native)
{
}
MetaLauncher *
meta_backend_native_get_launcher (MetaBackendNative *native)
{
return native->launcher;
}
MetaUdev *
meta_backend_native_get_udev (MetaBackendNative *native)
{
return native->udev;
}
MetaKms *
meta_backend_native_get_kms (MetaBackendNative *native)
{
return native->kms;
}
gboolean
meta_activate_vt (int vt, GError **error)
{
MetaBackend *backend = meta_get_backend ();
MetaBackendNative *native = META_BACKEND_NATIVE (backend);
MetaLauncher *launcher = meta_backend_native_get_launcher (native);
return meta_launcher_activate_vt (launcher, vt, error);
}
/**
* meta_activate_session:
*
* Tells mutter to activate the session. When mutter is a
* display server, this tells logind to switch over to
* the new session.
*/
gboolean
meta_activate_session (void)
{
GError *error = NULL;
MetaBackend *backend = meta_get_backend ();
/* Do nothing. */
if (!META_IS_BACKEND_NATIVE (backend))
return TRUE;
MetaBackendNative *native = META_BACKEND_NATIVE (backend);
if (!meta_launcher_activate_session (native->launcher, &error))
{
g_warning ("Could not activate session: %s", error->message);
g_error_free (error);
return FALSE;
}
return TRUE;
}
void
meta_backend_native_pause (MetaBackendNative *native)
{
MetaBackend *backend = META_BACKEND (native);
MetaMonitorManager *monitor_manager =
meta_backend_get_monitor_manager (backend);
MetaMonitorManagerKms *monitor_manager_kms =
META_MONITOR_MANAGER_KMS (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);
disconnect_udev_device_added_handler (native);
meta_monitor_manager_kms_pause (monitor_manager_kms);
}
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);
MetaMonitorManagerKms *monitor_manager_kms =
META_MONITOR_MANAGER_KMS (monitor_manager);
MetaInputSettings *input_settings;
MetaIdleMonitor *idle_monitor;
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 (MetaBackendNativeResume,
"Backend (resume)");
meta_monitor_manager_kms_resume (monitor_manager_kms);
connect_udev_device_added_handler (native);
meta_seat_native_reclaim_devices (seat);
meta_renderer_resume (renderer);
clutter_actor_queue_redraw (CLUTTER_ACTOR (stage));
idle_monitor = meta_idle_monitor_get_core ();
meta_idle_monitor_reset_idletime (idle_monitor);
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));
}