From fc16ec7a71f743f2b62a47e8df2d35e9b627798f Mon Sep 17 00:00:00 2001 From: Bob Ham Date: Thu, 8 Aug 2019 13:51:17 +0100 Subject: [PATCH 1/2] calls-application: Add --daemon option to not display main window --- src/calls-application.c | 58 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 53 insertions(+), 5 deletions(-) diff --git a/src/calls-application.c b/src/calls-application.c index 281e02e..b67c5dc 100644 --- a/src/calls-application.c +++ b/src/calls-application.c @@ -55,6 +55,7 @@ struct _CallsApplication { GtkApplication parent_instance; + gboolean daemon; GString *provider_name; CallsProvider *provider; CallsRinger *ringer; @@ -90,6 +91,14 @@ handle_local_options (GApplication *application, g_variant_new_string (name)); } + ok = g_variant_dict_contains (options, "daemon"); + if (ok) + { + g_action_group_activate_action (G_ACTION_GROUP (application), + "set-daemon", + NULL); + } + return -1; // Continue processing signal } @@ -120,9 +129,30 @@ set_provider_name_action (GSimpleAction *action, } +static void +set_daemon_action (GSimpleAction *action, + GVariant *parameter, + gpointer user_data) +{ + CallsApplication *self = CALLS_APPLICATION (user_data); + + if (self->main_window) + { + g_warning ("Cannot set application as a daemon" + " because application is already started"); + return; + } + + self->daemon = TRUE; + + g_debug ("Application marked as daemon"); +} + + static const GActionEntry actions[] = { { "set-provider-name", set_provider_name_action, "s" }, + { "set-daemon", set_daemon_action, NULL }, }; @@ -268,17 +298,29 @@ static void activate (GApplication *application) { CallsApplication *self = CALLS_APPLICATION (application); - gboolean ok; + gboolean present; g_debug ("Activated"); - ok = start_proper (self); - if (!ok) + if (self->main_window) { - return; + present = TRUE; + } + else + { + gboolean ok = start_proper (self); + if (!ok) + { + return; + } + + present = !self->daemon; } - gtk_window_present (GTK_WINDOW (self->main_window)); + if (present) + { + gtk_window_present (GTK_WINDOW (self->main_window)); + } } @@ -426,6 +468,12 @@ calls_application_init (CallsApplication *self) _("The name of the plugin to use for the call Provider"), _("PLUGIN") }, + { + "daemon", 'd', G_OPTION_FLAG_NONE, + G_OPTION_ARG_NONE, NULL, + _("Whether to present the main window on startup"), + NULL + }, { NULL } From 646682b8780d77bce3b093a343907dd7421d9c1c Mon Sep 17 00:00:00 2001 From: Bob Ham Date: Thu, 8 Aug 2019 14:38:28 +0100 Subject: [PATCH 2/2] Start up in daemon mode when GNOME starts Hat tip to Guido for the session.{c,h} files. Closes #45 --- data/meson.build | 8 ++ data/sm.puri.Calls-daemon.desktop | 16 ++++ src/calls-application.c | 5 ++ src/meson.build | 1 + src/session.c | 145 ++++++++++++++++++++++++++++++ src/session.h | 15 ++++ 6 files changed, 190 insertions(+) create mode 100644 data/sm.puri.Calls-daemon.desktop create mode 100644 src/session.c create mode 100644 src/session.h diff --git a/data/meson.build b/data/meson.build index 6122e44..0093fff 100644 --- a/data/meson.build +++ b/data/meson.build @@ -1,8 +1,12 @@ datadir = get_option('datadir') +sysconfdir = get_option('sysconfdir') # Desktop file install_data('sm.puri.Calls.desktop', install_dir : join_paths(datadir, 'applications')) +install_data('sm.puri.Calls-daemon.desktop', + rename : 'sm.puri.Calls.desktop', + install_dir : join_paths(sysconfdir, 'xdg/autostart')) desktop_utils = find_program('desktop-file-validate', required: false) if desktop_utils.found() @@ -10,6 +14,10 @@ if desktop_utils.found() args: [join_paths(meson.current_source_dir(), 'sm.puri.Calls.desktop') ]) + test('Validate daemon desktop file', desktop_utils, + args: [join_paths(meson.current_source_dir(), + 'sm.puri.Calls-daemon.desktop') + ]) endif # Appdata file diff --git a/data/sm.puri.Calls-daemon.desktop b/data/sm.puri.Calls-daemon.desktop new file mode 100644 index 0000000..5b2b672 --- /dev/null +++ b/data/sm.puri.Calls-daemon.desktop @@ -0,0 +1,16 @@ +[Desktop Entry] +Name=Calls (daemon) +GenericName=Phone +Comment=A phone dialer and call handler (daemon mode) +# Translators: These are desktop search terms. Do not translate semicolons, end line with a semicolon. +Keywords=Telephone;Call;Phone;Dial;Dialer;PTSN; +# Translators: Do NOT translate or transliterate this text (this is an icon file name)! +Icon=sm.puri.Calls +TryExec=calls +Exec=calls --daemon +Type=Application +StartupNotify=true +NoDisplay=true +Terminal=false +Categories=GNOME;GTK;Telephony; +X-GNOME-AutoRestart=true diff --git a/src/calls-application.c b/src/calls-application.c index b67c5dc..50b3ac3 100644 --- a/src/calls-application.c +++ b/src/calls-application.c @@ -34,6 +34,7 @@ #include "calls-call-window.h" #include "calls-main-window.h" #include "calls-application.h" +#include "session.h" #define HANDY_USE_UNSTABLE_API #include @@ -402,6 +403,8 @@ constructed (GObject *object) actions, G_N_ELEMENTS (actions), self); g_object_unref (action_group); + calls_session_register (APP_ID); + parent_class->constructed (object); } @@ -411,6 +414,8 @@ dispose (GObject *object) { CallsApplication *self = (CallsApplication *)object; + calls_session_unregister (); + g_clear_object (&self->call_window); g_clear_object (&self->main_window); g_clear_object (&self->record_store); diff --git a/src/meson.build b/src/meson.build index 9216028..4b712af 100644 --- a/src/meson.build +++ b/src/meson.build @@ -56,6 +56,7 @@ calls_sources = files(['calls-message-source.c', 'calls-message-source.h', 'calls-call-record.c', 'calls-call-record.h', 'calls-record-store.c', 'calls-record-store.h', 'calls-call-record-row.c', 'calls-call-record-row.h', + 'session.c', 'session.h', ]) calls_config_data = config_data diff --git a/src/session.c b/src/session.c new file mode 100644 index 0000000..60d4cfa --- /dev/null +++ b/src/session.c @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2018, 2019 Purism SPC + * SPDX-License-Identifier: GPL-3.0+ + * Author: Guido Günther + * + * Copied from phosh and modified for Calls + * by Bob Ham + * + * Based on code from gnome-settings-daemon + */ + +#define G_LOG_DOMAIN "calls-session" + +#include "session.h" + +#include +#include + +#define GNOME_SESSION_DBUS_NAME "org.gnome.SessionManager" +#define GNOME_SESSION_DBUS_OBJECT "/org/gnome/SessionManager" +#define GNOME_SESSION_DBUS_INTERFACE "org.gnome.SessionManager" +#define GNOME_SESSION_CLIENT_PRIVATE_DBUS_INTERFACE "org.gnome.SessionManager.ClientPrivate" + +static GDBusProxy *_proxy; + + +static void +respond_to_end_session (GDBusProxy *proxy) +{ + /* we must answer with "EndSessionResponse" */ + g_dbus_proxy_call (proxy, "EndSessionResponse", + g_variant_new ("(bs)", TRUE, ""), + G_DBUS_CALL_FLAGS_NONE, + -1, NULL, NULL, NULL); +} + + +static void +do_stop (void) +{ + gtk_main_quit (); +} + + +static void +client_proxy_signal_cb (GDBusProxy *proxy, + gchar *sender_name, + gchar *signal_name, + GVariant *parameters, + gpointer user_data) +{ + if (g_strcmp0 (signal_name, "QueryEndSession") == 0) { + g_debug ("Got QueryEndSession signal"); + respond_to_end_session (proxy); + } else if (g_strcmp0 (signal_name, "EndSession") == 0) { + g_debug ("Got EndSession signal"); + respond_to_end_session (proxy); + } else if (g_strcmp0 (signal_name, "Stop") == 0) { + g_debug ("Got Stop signal"); + do_stop (); + } +} + + +static void +on_client_registered (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + GVariant *variant; + GDBusProxy *client_proxy; + GError *error = NULL; + gchar *object_path = NULL; + + variant = g_dbus_proxy_call_finish (G_DBUS_PROXY (source_object), res, &error); + if (!variant) { + g_warning ("Unable to register client: %s", error->message); + g_error_free (error); + return; + } + + g_variant_get (variant, "(o)", &object_path); + + g_debug ("Registered client at path %s", object_path); + + client_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION, 0, NULL, + GNOME_SESSION_DBUS_NAME, + object_path, + GNOME_SESSION_CLIENT_PRIVATE_DBUS_INTERFACE, + NULL, + &error); + if (!client_proxy) { + g_warning ("Unable to get the session client proxy: %s", error->message); + g_error_free (error); + return; + } + + g_signal_connect (client_proxy, "g-signal", + G_CALLBACK (client_proxy_signal_cb), NULL); + + g_free (object_path); + g_variant_unref (variant); +} + + +void +calls_session_register (const char *client_id) +{ + const char *startup_id; + GError *err = NULL; + + if (!_proxy) { + _proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION, + G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | + G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START_AT_CONSTRUCTION, + NULL, + GNOME_SESSION_DBUS_NAME, + GNOME_SESSION_DBUS_OBJECT, + GNOME_SESSION_DBUS_INTERFACE, + NULL, + &err); + if (!_proxy) { + g_debug ("Failed to contact gnome-session: %s", err->message); + g_clear_error (&err); + return; + } + }; + + startup_id = g_getenv ("DESKTOP_AUTOSTART_ID"); + g_dbus_proxy_call (_proxy, + "RegisterClient", + g_variant_new ("(ss)", client_id, startup_id ? startup_id : ""), + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + (GAsyncReadyCallback) on_client_registered, + NULL); +} + + +void +calls_session_unregister (void) +{ + g_clear_object (&_proxy); +} diff --git a/src/session.h b/src/session.h new file mode 100644 index 0000000..c1717e9 --- /dev/null +++ b/src/session.h @@ -0,0 +1,15 @@ +/* + * Copyright (C) 2018, 2019 Purism SPC + * SPDX-License-Identifier: GPL-3.0+ + * Author: Guido Günther + * + * Copied from phosh and modified for Calls + * by Bob Ham + */ + +#pragma once + +#include + +void calls_session_register (const char *client_id); +void calls_session_unregister (void);