shell: Add device monitor for cameras
Pipewire allows us to easily track whether any cameras are in used by checking the state of camera nodes. Add a simple camera monitor to the shell, allowing us to show e.g. a status indicator. Naturally the monitor is limited to apps using Pipewire for camera access and thus subject to the same chicken-egg problem like the camera portal - it could confuse users that apps may use the camera without being noticed by the monitor. The hope and assumption here is that a better shell integration might speed up adoption of the new camera APIs Pipewire 0.3.49 is required for refcounted `pw_init()`/`pw_deinit()`. Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/2840>
This commit is contained in:
parent
02f1952851
commit
d09d24666a
@ -22,6 +22,9 @@
|
|||||||
/* Define if we have NetworkManager */
|
/* Define if we have NetworkManager */
|
||||||
#mesondefine HAVE_NETWORKMANAGER
|
#mesondefine HAVE_NETWORKMANAGER
|
||||||
|
|
||||||
|
/* Define if we have Pipewire */
|
||||||
|
#mesondefine HAVE_PIPEWIRE
|
||||||
|
|
||||||
/* Define if we have systemd */
|
/* Define if we have systemd */
|
||||||
#mesondefine HAVE_SYSTEMD
|
#mesondefine HAVE_SYSTEMD
|
||||||
|
|
||||||
|
11
meson.build
11
meson.build
@ -32,6 +32,7 @@ startup_req = '>= 0.11'
|
|||||||
systemd_req = '>= 246'
|
systemd_req = '>= 246'
|
||||||
ibus_req = '>= 1.5.19'
|
ibus_req = '>= 1.5.19'
|
||||||
gnome_desktop_req = '>= 40'
|
gnome_desktop_req = '>= 40'
|
||||||
|
pipewire_req = '>= 0.3.49'
|
||||||
|
|
||||||
nm_req = '>= 1.10.4'
|
nm_req = '>= 1.10.4'
|
||||||
secret_req = '>= 0.18'
|
secret_req = '>= 0.18'
|
||||||
@ -102,6 +103,14 @@ else
|
|||||||
have_networkmanager = false
|
have_networkmanager = false
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
if get_option('camera_monitor')
|
||||||
|
libpipewire_dep = dependency('libpipewire-0.3', version: pipewire_req)
|
||||||
|
have_pipewire = true
|
||||||
|
else
|
||||||
|
libpipewire_dep = []
|
||||||
|
have_pipewire = false
|
||||||
|
endif
|
||||||
|
|
||||||
if get_option('systemd')
|
if get_option('systemd')
|
||||||
libsystemd_dep = dependency('libsystemd', version: systemd_req)
|
libsystemd_dep = dependency('libsystemd', version: systemd_req)
|
||||||
systemd_dep = dependency('systemd', version: systemd_req)
|
systemd_dep = dependency('systemd', version: systemd_req)
|
||||||
@ -136,6 +145,7 @@ cdata.set_quoted('VERSION', meson.project_version())
|
|||||||
cdata.set_quoted('PACKAGE_VERSION', meson.project_version())
|
cdata.set_quoted('PACKAGE_VERSION', meson.project_version())
|
||||||
|
|
||||||
cdata.set('HAVE_NETWORKMANAGER', have_networkmanager)
|
cdata.set('HAVE_NETWORKMANAGER', have_networkmanager)
|
||||||
|
cdata.set('HAVE_PIPEWIRE', have_pipewire)
|
||||||
cdata.set('HAVE_SYSTEMD', have_systemd)
|
cdata.set('HAVE_SYSTEMD', have_systemd)
|
||||||
|
|
||||||
# New API added in glib-2.57.2
|
# New API added in glib-2.57.2
|
||||||
@ -311,6 +321,7 @@ meson.add_dist_script('meson/generate-stylesheets.py')
|
|||||||
meson.add_dist_script('meson/check-version.py', meson.project_version(), 'NEWS')
|
meson.add_dist_script('meson/check-version.py', meson.project_version(), 'NEWS')
|
||||||
|
|
||||||
summary_options = {
|
summary_options = {
|
||||||
|
'camera_monitor': get_option('camera_monitor'),
|
||||||
'networkmanager': get_option('networkmanager'),
|
'networkmanager': get_option('networkmanager'),
|
||||||
'systemd': get_option('systemd'),
|
'systemd': get_option('systemd'),
|
||||||
'extensions_app': get_option('extensions_app'),
|
'extensions_app': get_option('extensions_app'),
|
||||||
|
@ -1,3 +1,9 @@
|
|||||||
|
option('camera_monitor',
|
||||||
|
type: 'boolean',
|
||||||
|
value: true,
|
||||||
|
description: 'Enable the camera monitor'
|
||||||
|
)
|
||||||
|
|
||||||
option('extensions_tool',
|
option('extensions_tool',
|
||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
value: true,
|
value: true,
|
||||||
|
@ -63,7 +63,8 @@ gnome_shell_deps = [
|
|||||||
gi_dep,
|
gi_dep,
|
||||||
polkit_dep,
|
polkit_dep,
|
||||||
gcr_dep,
|
gcr_dep,
|
||||||
libsystemd_dep
|
libsystemd_dep,
|
||||||
|
libpipewire_dep,
|
||||||
]
|
]
|
||||||
|
|
||||||
gnome_shell_deps += nm_deps
|
gnome_shell_deps += nm_deps
|
||||||
@ -97,6 +98,7 @@ libshell_public_headers = [
|
|||||||
'shell-app-system.h',
|
'shell-app-system.h',
|
||||||
'shell-app-usage.h',
|
'shell-app-usage.h',
|
||||||
'shell-blur-effect.h',
|
'shell-blur-effect.h',
|
||||||
|
'shell-camera-monitor.h',
|
||||||
'shell-glsl-effect.h',
|
'shell-glsl-effect.h',
|
||||||
'shell-global.h',
|
'shell-global.h',
|
||||||
'shell-invert-lightness-effect.h',
|
'shell-invert-lightness-effect.h',
|
||||||
@ -136,6 +138,7 @@ libshell_sources = [
|
|||||||
'shell-app-system.c',
|
'shell-app-system.c',
|
||||||
'shell-app-usage.c',
|
'shell-app-usage.c',
|
||||||
'shell-blur-effect.c',
|
'shell-blur-effect.c',
|
||||||
|
'shell-camera-monitor.c',
|
||||||
'shell-global.c',
|
'shell-global.c',
|
||||||
'shell-glsl-effect.c',
|
'shell-glsl-effect.c',
|
||||||
'shell-invert-lightness-effect.c',
|
'shell-invert-lightness-effect.c',
|
||||||
|
435
src/shell-camera-monitor.c
Normal file
435
src/shell-camera-monitor.c
Normal file
@ -0,0 +1,435 @@
|
|||||||
|
/*
|
||||||
|
* Shell camera monitor
|
||||||
|
*
|
||||||
|
* Copyright (C) 2023 Collabora Ltd.
|
||||||
|
*
|
||||||
|
* 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 "shell-camera-monitor.h"
|
||||||
|
|
||||||
|
#ifdef HAVE_PIPEWIRE
|
||||||
|
#include <pipewire/pipewire.h>
|
||||||
|
#include <spa/utils/result.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define RECONNECT_DELAY_MS 5000
|
||||||
|
|
||||||
|
enum {
|
||||||
|
PROP_0,
|
||||||
|
PROP_CAMERAS_IN_USE,
|
||||||
|
PROP_LAST
|
||||||
|
};
|
||||||
|
|
||||||
|
static GParamSpec *obj_props[PROP_LAST];
|
||||||
|
|
||||||
|
struct _ShellCameraMonitor {
|
||||||
|
GObject parent;
|
||||||
|
|
||||||
|
gboolean cameras_in_use;
|
||||||
|
|
||||||
|
#ifdef HAVE_PIPEWIRE
|
||||||
|
GPtrArray *node_list;
|
||||||
|
guint reconnect_id;
|
||||||
|
|
||||||
|
GSource *pipewire_source;
|
||||||
|
struct pw_context *context;
|
||||||
|
struct pw_core *core;
|
||||||
|
struct pw_registry *registry;
|
||||||
|
struct spa_hook core_listener;
|
||||||
|
struct spa_hook registry_listener;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
G_DEFINE_TYPE (ShellCameraMonitor, shell_camera_monitor, G_TYPE_OBJECT);
|
||||||
|
|
||||||
|
#ifdef HAVE_PIPEWIRE
|
||||||
|
typedef struct _Node {
|
||||||
|
ShellCameraMonitor *monitor;
|
||||||
|
gboolean running;
|
||||||
|
struct spa_hook proxy_listener;
|
||||||
|
struct spa_hook object_listener;
|
||||||
|
} Node;
|
||||||
|
|
||||||
|
typedef struct _MetaPipeWireSource
|
||||||
|
{
|
||||||
|
GSource source;
|
||||||
|
|
||||||
|
struct pw_loop *pipewire_loop;
|
||||||
|
} MetaPipeWireSource;
|
||||||
|
|
||||||
|
static gboolean shell_camera_monitor_connect_core (ShellCameraMonitor *monitor);
|
||||||
|
static void shell_camera_monitor_disconnect_core (ShellCameraMonitor *monitor);
|
||||||
|
|
||||||
|
static void
|
||||||
|
shell_camera_monitor_update_state (ShellCameraMonitor *monitor)
|
||||||
|
{
|
||||||
|
gboolean new_cameras_in_use = FALSE;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < monitor->node_list->len; i++)
|
||||||
|
{
|
||||||
|
struct pw_proxy *proxy;
|
||||||
|
Node *node;
|
||||||
|
|
||||||
|
proxy = g_ptr_array_index (monitor->node_list, i);
|
||||||
|
node = pw_proxy_get_user_data (proxy);
|
||||||
|
|
||||||
|
if (node->running)
|
||||||
|
{
|
||||||
|
new_cameras_in_use = TRUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (new_cameras_in_use != monitor->cameras_in_use)
|
||||||
|
{
|
||||||
|
monitor->cameras_in_use = new_cameras_in_use;
|
||||||
|
g_object_notify_by_pspec (G_OBJECT (monitor),
|
||||||
|
obj_props[PROP_CAMERAS_IN_USE]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
proxy_destroy (void *data)
|
||||||
|
{
|
||||||
|
Node *node = data;
|
||||||
|
|
||||||
|
spa_hook_remove (&node->proxy_listener);
|
||||||
|
spa_hook_remove (&node->object_listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct pw_proxy_events proxy_events = {
|
||||||
|
PW_VERSION_PROXY_EVENTS,
|
||||||
|
.destroy = proxy_destroy,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
node_event_info (void *data,
|
||||||
|
const struct pw_node_info *info)
|
||||||
|
{
|
||||||
|
Node *node = data;
|
||||||
|
|
||||||
|
node->running = (info->state == PW_NODE_STATE_RUNNING ||
|
||||||
|
info->state == PW_NODE_STATE_IDLE);
|
||||||
|
|
||||||
|
shell_camera_monitor_update_state (node->monitor);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct pw_node_events node_events = {
|
||||||
|
PW_VERSION_NODE_EVENTS,
|
||||||
|
.info = node_event_info,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
registry_event_global (void *data,
|
||||||
|
uint32_t id,
|
||||||
|
uint32_t permissions,
|
||||||
|
const char *type,
|
||||||
|
uint32_t version,
|
||||||
|
const struct spa_dict *props)
|
||||||
|
{
|
||||||
|
ShellCameraMonitor *monitor = SHELL_CAMERA_MONITOR (data);
|
||||||
|
struct pw_proxy *proxy;
|
||||||
|
const char *prop_str;
|
||||||
|
Node *node;
|
||||||
|
|
||||||
|
if (!props || !(spa_streq (type, PW_TYPE_INTERFACE_Node)))
|
||||||
|
return;
|
||||||
|
|
||||||
|
prop_str = spa_dict_lookup (props, PW_KEY_MEDIA_ROLE);
|
||||||
|
if (!prop_str || (strcmp (prop_str, "Camera") != 0))
|
||||||
|
return;
|
||||||
|
|
||||||
|
proxy = pw_registry_bind (monitor->registry,
|
||||||
|
id,
|
||||||
|
PW_TYPE_INTERFACE_Node,
|
||||||
|
PW_VERSION_NODE,
|
||||||
|
sizeof (Node));
|
||||||
|
node = pw_proxy_get_user_data (proxy);
|
||||||
|
node->monitor = monitor;
|
||||||
|
|
||||||
|
pw_proxy_add_listener (proxy,
|
||||||
|
&node->proxy_listener,
|
||||||
|
&proxy_events,
|
||||||
|
node);
|
||||||
|
|
||||||
|
pw_proxy_add_object_listener (proxy,
|
||||||
|
&node->object_listener,
|
||||||
|
&node_events,
|
||||||
|
node);
|
||||||
|
|
||||||
|
g_ptr_array_add (monitor->node_list, proxy);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
registry_event_global_remove (void *data,
|
||||||
|
uint32_t id)
|
||||||
|
{
|
||||||
|
ShellCameraMonitor *monitor = SHELL_CAMERA_MONITOR (data);
|
||||||
|
struct pw_proxy *proxy_to_remove = NULL;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < monitor->node_list->len; i++)
|
||||||
|
{
|
||||||
|
struct pw_proxy *proxy;
|
||||||
|
|
||||||
|
proxy = g_ptr_array_index (monitor->node_list, i);
|
||||||
|
if (pw_proxy_get_bound_id (proxy) == id)
|
||||||
|
{
|
||||||
|
proxy_to_remove = proxy;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (proxy_to_remove)
|
||||||
|
g_ptr_array_remove (monitor->node_list, proxy_to_remove);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct pw_registry_events registry_events = {
|
||||||
|
PW_VERSION_REGISTRY_EVENTS,
|
||||||
|
.global = registry_event_global,
|
||||||
|
.global_remove = registry_event_global_remove,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
idle_reconnect (gpointer data)
|
||||||
|
{
|
||||||
|
ShellCameraMonitor *monitor = SHELL_CAMERA_MONITOR (data);
|
||||||
|
|
||||||
|
if (shell_camera_monitor_connect_core (monitor))
|
||||||
|
monitor->reconnect_id = 0;
|
||||||
|
else
|
||||||
|
monitor->reconnect_id =
|
||||||
|
g_timeout_add_once (RECONNECT_DELAY_MS, idle_reconnect, monitor);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
on_core_error (void *data,
|
||||||
|
uint32_t id,
|
||||||
|
int seq,
|
||||||
|
int res,
|
||||||
|
const char *message)
|
||||||
|
{
|
||||||
|
if (id == 0 && res == -EPIPE)
|
||||||
|
{
|
||||||
|
ShellCameraMonitor *monitor = SHELL_CAMERA_MONITOR (data);
|
||||||
|
|
||||||
|
shell_camera_monitor_disconnect_core (monitor);
|
||||||
|
if (monitor->cameras_in_use)
|
||||||
|
{
|
||||||
|
monitor->cameras_in_use = FALSE;
|
||||||
|
g_object_notify_by_pspec (G_OBJECT (monitor),
|
||||||
|
obj_props[PROP_CAMERAS_IN_USE]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (monitor->reconnect_id == 0)
|
||||||
|
monitor->reconnect_id =
|
||||||
|
g_timeout_add_once (RECONNECT_DELAY_MS, idle_reconnect, monitor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct pw_core_events core_events = {
|
||||||
|
PW_VERSION_CORE_EVENTS,
|
||||||
|
.error = on_core_error,
|
||||||
|
};
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
shell_camera_monitor_connect_core (ShellCameraMonitor *monitor)
|
||||||
|
{
|
||||||
|
monitor->core = pw_context_connect (monitor->context, NULL, 0);
|
||||||
|
if (!monitor->core)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
pw_core_add_listener (monitor->core,
|
||||||
|
&monitor->core_listener,
|
||||||
|
&core_events,
|
||||||
|
monitor);
|
||||||
|
|
||||||
|
monitor->registry = pw_core_get_registry (monitor->core,
|
||||||
|
PW_VERSION_REGISTRY,
|
||||||
|
0);
|
||||||
|
pw_registry_add_listener (monitor->registry,
|
||||||
|
&monitor->registry_listener,
|
||||||
|
®istry_events,
|
||||||
|
monitor);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
shell_camera_monitor_disconnect_core (ShellCameraMonitor *monitor)
|
||||||
|
{
|
||||||
|
g_ptr_array_set_size (monitor->node_list, 0);
|
||||||
|
|
||||||
|
g_clear_pointer ((struct pw_proxy**) &monitor->registry, pw_proxy_destroy);
|
||||||
|
spa_hook_remove (&monitor->registry_listener);
|
||||||
|
g_clear_pointer (&monitor->core, pw_core_disconnect);
|
||||||
|
spa_hook_remove (&monitor->core_listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
pipewire_loop_source_prepare (GSource *source,
|
||||||
|
int *timeout)
|
||||||
|
{
|
||||||
|
*timeout = -1;
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
pipewire_loop_source_dispatch (GSource *source,
|
||||||
|
GSourceFunc callback,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
MetaPipeWireSource *pipewire_source = (MetaPipeWireSource *) source;
|
||||||
|
int result;
|
||||||
|
|
||||||
|
result = pw_loop_iterate (pipewire_source->pipewire_loop, 0);
|
||||||
|
if (result < 0)
|
||||||
|
g_warning ("pipewire_loop_iterate failed: %s", spa_strerror (result));
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
pipewire_loop_source_finalize (GSource *source)
|
||||||
|
{
|
||||||
|
MetaPipeWireSource *pipewire_source = (MetaPipeWireSource *) source;
|
||||||
|
|
||||||
|
pw_loop_leave (pipewire_source->pipewire_loop);
|
||||||
|
pw_loop_destroy (pipewire_source->pipewire_loop);
|
||||||
|
}
|
||||||
|
|
||||||
|
static GSourceFuncs pipewire_source_funcs =
|
||||||
|
{
|
||||||
|
pipewire_loop_source_prepare,
|
||||||
|
NULL,
|
||||||
|
pipewire_loop_source_dispatch,
|
||||||
|
pipewire_loop_source_finalize
|
||||||
|
};
|
||||||
|
|
||||||
|
static GSource *
|
||||||
|
create_pipewire_source (struct pw_loop *pipewire_loop)
|
||||||
|
{
|
||||||
|
GSource *source;
|
||||||
|
MetaPipeWireSource *pipewire_source;
|
||||||
|
|
||||||
|
source = g_source_new (&pipewire_source_funcs, sizeof (MetaPipeWireSource));
|
||||||
|
g_source_set_name (source, "[gnome-shell] PipeWire");
|
||||||
|
|
||||||
|
pipewire_source = (MetaPipeWireSource *) source;
|
||||||
|
pipewire_source->pipewire_loop = pipewire_loop;
|
||||||
|
|
||||||
|
g_source_add_unix_fd (source,
|
||||||
|
pw_loop_get_fd (pipewire_source->pipewire_loop),
|
||||||
|
G_IO_IN | G_IO_ERR);
|
||||||
|
|
||||||
|
pw_loop_enter (pipewire_source->pipewire_loop);
|
||||||
|
g_source_attach (source, NULL);
|
||||||
|
g_source_unref (source);
|
||||||
|
|
||||||
|
return source;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void
|
||||||
|
shell_camera_monitor_finalize (GObject *object)
|
||||||
|
{
|
||||||
|
#ifdef HAVE_PIPEWIRE
|
||||||
|
ShellCameraMonitor *monitor = SHELL_CAMERA_MONITOR (object);
|
||||||
|
|
||||||
|
shell_camera_monitor_disconnect_core (monitor);
|
||||||
|
g_clear_pointer (&monitor->node_list, g_ptr_array_unref);
|
||||||
|
g_clear_pointer (&monitor->context, pw_context_destroy);
|
||||||
|
g_clear_pointer (&monitor->pipewire_source, g_source_destroy);
|
||||||
|
g_clear_handle_id (&monitor->reconnect_id, g_source_remove);
|
||||||
|
pw_deinit ();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
G_OBJECT_CLASS (shell_camera_monitor_parent_class)->finalize (object);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
shell_camera_monitor_get_property (GObject *object,
|
||||||
|
guint prop_id,
|
||||||
|
GValue *value,
|
||||||
|
GParamSpec *pspec)
|
||||||
|
{
|
||||||
|
ShellCameraMonitor *monitor = SHELL_CAMERA_MONITOR (object);
|
||||||
|
|
||||||
|
switch (prop_id)
|
||||||
|
{
|
||||||
|
case PROP_CAMERAS_IN_USE:
|
||||||
|
g_value_set_boolean (value, monitor->cameras_in_use);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
shell_camera_monitor_class_init (ShellCameraMonitorClass *klass)
|
||||||
|
{
|
||||||
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||||
|
|
||||||
|
object_class->finalize = shell_camera_monitor_finalize;
|
||||||
|
object_class->get_property = shell_camera_monitor_get_property;
|
||||||
|
|
||||||
|
obj_props[PROP_CAMERAS_IN_USE] =
|
||||||
|
g_param_spec_boolean ("cameras-in-use",
|
||||||
|
"Cameras in use",
|
||||||
|
"Whether any camera is currently used by an app",
|
||||||
|
FALSE,
|
||||||
|
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
|
||||||
|
|
||||||
|
g_object_class_install_properties (object_class, PROP_LAST, obj_props);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
shell_camera_monitor_init (ShellCameraMonitor *monitor)
|
||||||
|
{
|
||||||
|
#ifdef HAVE_PIPEWIRE
|
||||||
|
struct pw_loop *pipewire_loop;
|
||||||
|
|
||||||
|
monitor->node_list =
|
||||||
|
g_ptr_array_new_full (5, (GDestroyNotify) pw_proxy_destroy);
|
||||||
|
|
||||||
|
pw_init (NULL, NULL);
|
||||||
|
|
||||||
|
pipewire_loop = pw_loop_new (NULL);
|
||||||
|
if (!pipewire_loop)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
monitor->pipewire_source = create_pipewire_source (pipewire_loop);
|
||||||
|
if (!monitor->pipewire_source)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
monitor->context = pw_context_new (pipewire_loop, NULL, 0);
|
||||||
|
if (!monitor->context)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
if (!shell_camera_monitor_connect_core (monitor))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
error:
|
||||||
|
g_message ("Failed to start camera monitor");
|
||||||
|
#endif
|
||||||
|
}
|
35
src/shell-camera-monitor.h
Normal file
35
src/shell-camera-monitor.h
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* Shell camera monitor
|
||||||
|
*
|
||||||
|
* Copyright (C) 2023 Collabora Ltd.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __SHELL_CAMERA_MONITOR_H__
|
||||||
|
#define __SHELL_CAMERA_MONITOR_H__
|
||||||
|
|
||||||
|
#include <glib-object.h>
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
#define SHELL_TYPE_CAMERA_MONITOR (shell_camera_monitor_get_type ())
|
||||||
|
G_DECLARE_FINAL_TYPE (ShellCameraMonitor, shell_camera_monitor,
|
||||||
|
SHELL, CAMERA_MONITOR, GObject)
|
||||||
|
|
||||||
|
G_END_DECLS
|
||||||
|
|
||||||
|
#endif /* __SHELL_CAMERA_MONITOR_H__ */
|
Loading…
Reference in New Issue
Block a user