/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* * Copyright (C) 2015-2017 Red Hat Inc. * * 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. * */ #include "config.h" #include "backends/meta-screen-cast.h" #include #include "backends/meta-backend-private.h" #include "backends/meta-remote-desktop-session.h" #include "backends/meta-screen-cast-session.h" #define META_SCREEN_CAST_DBUS_SERVICE "org.gnome.Mutter.ScreenCast" #define META_SCREEN_CAST_DBUS_PATH "/org/gnome/Mutter/ScreenCast" #define META_SCREEN_CAST_API_VERSION 4 struct _MetaScreenCast { MetaDbusSessionManager parent; gboolean disable_dma_bufs; }; G_DEFINE_TYPE (MetaScreenCast, meta_screen_cast, META_TYPE_DBUS_SESSION_MANAGER) MetaBackend * meta_screen_cast_get_backend (MetaScreenCast *screen_cast) { MetaDbusSessionManager *session_manager = META_DBUS_SESSION_MANAGER (screen_cast); return meta_dbus_session_manager_get_backend (session_manager); } void meta_screen_cast_disable_dma_bufs (MetaScreenCast *screen_cast) { screen_cast->disable_dma_bufs = TRUE; } CoglDmaBufHandle * meta_screen_cast_create_dma_buf_handle (MetaScreenCast *screen_cast, int width, int height) { MetaDbusSessionManager *session_manager = META_DBUS_SESSION_MANAGER (screen_cast); MetaBackend *backend = meta_dbus_session_manager_get_backend (session_manager); 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; CoglDmaBufHandle *dmabuf_handle; if (screen_cast->disable_dma_bufs) return NULL; dmabuf_handle = cogl_renderer_create_dma_buf (cogl_renderer, width, height, &error); if (!dmabuf_handle) { g_warning ("Failed to allocate DMA buffer, " "disabling DMA buffer based screen casting: %s", error->message); screen_cast->disable_dma_bufs = TRUE; return NULL; } return dmabuf_handle; } static gboolean register_remote_desktop_screen_cast_session (MetaScreenCastSession *session, const char *remote_desktop_session_id, GError **error) { MetaScreenCast *screen_cast = meta_screen_cast_session_get_screen_cast (session); MetaDbusSessionManager *session_manager = META_DBUS_SESSION_MANAGER (screen_cast); MetaBackend *backend = meta_dbus_session_manager_get_backend (session_manager); MetaRemoteDesktop *remote_desktop = meta_backend_get_remote_desktop (backend); MetaDbusSessionManager *remote_desktop_session_manager = META_DBUS_SESSION_MANAGER (remote_desktop); MetaDbusSession *remote_desktop_dbus_session; MetaRemoteDesktopSession *remote_desktop_session; remote_desktop_dbus_session = meta_dbus_session_manager_get_session (remote_desktop_session_manager, remote_desktop_session_id); if (!remote_desktop_dbus_session) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "No remote desktop session found"); return FALSE; } remote_desktop_session = META_REMOTE_DESKTOP_SESSION (remote_desktop_dbus_session); if (!meta_remote_desktop_session_register_screen_cast (remote_desktop_session, session, error)) return FALSE; return TRUE; } static gboolean handle_create_session (MetaDBusScreenCast *skeleton, GDBusMethodInvocation *invocation, GVariant *properties, MetaScreenCast *screen_cast) { MetaDbusSessionManager *session_manager = META_DBUS_SESSION_MANAGER (screen_cast); char *remote_desktop_session_id = NULL; MetaScreenCastSessionType session_type; MetaDbusSession *dbus_session; MetaScreenCastSession *session; g_autoptr (GError) error = NULL; gboolean disable_animations; const char *session_path; g_variant_lookup (properties, "remote-desktop-session-id", "s", &remote_desktop_session_id); if (remote_desktop_session_id) session_type = META_SCREEN_CAST_SESSION_TYPE_REMOTE_DESKTOP; else session_type = META_SCREEN_CAST_SESSION_TYPE_NORMAL; dbus_session = meta_dbus_session_manager_create_session (session_manager, invocation, &error, "session-type", session_type, NULL); if (!dbus_session) { g_dbus_method_invocation_return_error_literal (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, error->message); return G_DBUS_METHOD_INVOCATION_HANDLED; } session = META_SCREEN_CAST_SESSION (dbus_session); if (remote_desktop_session_id) { if (!register_remote_desktop_screen_cast_session (session, remote_desktop_session_id, &error)) { g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "%s", error->message); meta_dbus_session_close (dbus_session); return G_DBUS_METHOD_INVOCATION_HANDLED; } } if (g_variant_lookup (properties, "disable-animations", "b", &disable_animations)) { meta_screen_cast_session_set_disable_animations (session, disable_animations); } session_path = meta_screen_cast_session_get_object_path (session); meta_dbus_screen_cast_complete_create_session (skeleton, invocation, session_path); return G_DBUS_METHOD_INVOCATION_HANDLED; } static void meta_screen_cast_constructed (GObject *object) { MetaScreenCast *screen_cast = META_SCREEN_CAST (object); MetaDbusSessionManager *session_manager = META_DBUS_SESSION_MANAGER (screen_cast); GDBusInterfaceSkeleton *interface_skeleton = meta_dbus_session_manager_get_interface_skeleton (session_manager); MetaDBusScreenCast *skeleton = META_DBUS_SCREEN_CAST (interface_skeleton); g_signal_connect (interface_skeleton, "handle-create-session", G_CALLBACK (handle_create_session), screen_cast); meta_dbus_screen_cast_set_version (skeleton, META_SCREEN_CAST_API_VERSION); G_OBJECT_CLASS (meta_screen_cast_parent_class)->constructed (object); } MetaScreenCast * meta_screen_cast_new (MetaBackend *backend) { MetaScreenCast *screen_cast; g_autoptr (MetaDBusScreenCast) skeleton = NULL; skeleton = meta_dbus_screen_cast_skeleton_new (); screen_cast = g_object_new (META_TYPE_SCREEN_CAST, "backend", backend, "service-name", META_SCREEN_CAST_DBUS_SERVICE, "service-path", META_SCREEN_CAST_DBUS_PATH, "session-gtype", META_TYPE_SCREEN_CAST_SESSION, "interface-skeleton", skeleton, NULL); return screen_cast; } static void meta_screen_cast_init (MetaScreenCast *screen_cast) { static gboolean is_pipewire_initialized = FALSE; if (!is_pipewire_initialized) { pw_init (NULL, NULL); is_pipewire_initialized = TRUE; } } static void meta_screen_cast_class_init (MetaScreenCastClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->constructed = meta_screen_cast_constructed; }