Merge pull request #230 from dkondor/dbus_own_name

DBus: make Cairo-Dock single instance by default
This commit is contained in:
Daniel Kondor
2025-12-30 19:36:46 +01:00
committed by GitHub
6 changed files with 167 additions and 17 deletions

View File

@@ -74,6 +74,7 @@
#include "cairo-dock-packages.h"
#include "cairo-dock-utils.h" // cairo_dock_launch_command
#include "cairo-dock-core.h"
#include "cairo-dock-dbus-priv.h" // cairo_dock_dbus_own_name
#include "cairo-dock-gui-manager.h"
#include "cairo-dock-gui-backend.h"
@@ -366,7 +367,9 @@ int main (int argc, char** argv)
textdomain (CAIRO_DOCK_GETTEXT_PACKAGE);
//\___________________ get app's options.
gboolean bSafeMode = FALSE, bMaintenance = FALSE, bNoSticky = FALSE, bCappuccino = FALSE, bPrintVersion = FALSE, bTesting = FALSE, bForceOpenGL = FALSE, bToggleIndirectRendering = FALSE, bKeepAbove = FALSE, bForceColors = FALSE, bAskBackend = FALSE, bTransparencyWorkaround = FALSE;
gboolean bSafeMode = FALSE, bMaintenance = FALSE, bNoSticky = FALSE, bCappuccino = FALSE, bPrintVersion = FALSE,
bTesting = FALSE, bForceOpenGL = FALSE, bToggleIndirectRendering = FALSE, bKeepAbove = FALSE, bForceColors = FALSE,
bAskBackend = FALSE, bTransparencyWorkaround = FALSE, bAllowMultiInstance = FALSE, bNoDBusName = FALSE;
gchar *cEnvironment = NULL, *cUserDefinedDataDir = NULL, *cVerbosity = 0, *cUserDefinedModuleDir = NULL, *cExcludeModule = NULL, *cThemeServerAdress = NULL;
int iDelay = 0;
GOptionEntry pOptionsTable[] =
@@ -445,6 +448,12 @@ int main (int argc, char** argv)
{"x11", 'X', G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_NONE,
&g_bForceX11,
_("Force using the X11 backend (disable any Wayland functionality)."), NULL},
{"allow-multi-instance", 'I', G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_NONE,
&bAllowMultiInstance,
_("Allow multiple instances of Cairo-Dock to run."), NULL},
{"no-dbus-name", 0, G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_NONE,
&bNoDBusName,
_("Do not try to own the \"org.cairodock.CairoDock\" DBus name (DBus interface will be unavailable)."), NULL},
{"egl", 0, G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_NONE,
&g_bX11UseEgl,
_("Use EGL on X11."), NULL},
@@ -529,6 +538,18 @@ int main (int argc, char** argv)
g_free (cEnvironment);
}
//\___________________ try to own our DBus name
if (!bNoDBusName && !cairo_dock_dbus_own_name ())
{
if (!cairo_dock_dbus_is_enabled ())
cd_warning ("DBus is unavailable, functions to communicate with apps and system components will not work!");
else if (!bAllowMultiInstance)
{
//!! TODO: check if another instance is really running and responsive? (e.g. with a Ping-like call)
cd_error ("Cairo-Dock is already running, not starting another instance (use the \"-I\" command line option to override).");
}
}
//\___________________ get global config.
gboolean bFirstLaunch = FALSE;
gchar *cRootDataDirPath;

View File

@@ -55,7 +55,7 @@ SET(core_lib_SRCS
cairo-dock-gui-manager.c cairo-dock-gui-manager.h
cairo-dock-gui-factory.c cairo-dock-gui-factory.h
cairo-dock-keybinder.c cairo-dock-keybinder.h
cairo-dock-dbus.c cairo-dock-dbus.h
cairo-dock-dbus.c cairo-dock-dbus.h cairo-dock-dbus-priv.h
cairo-dock-keyfile-utilities.c cairo-dock-keyfile-utilities.h
cairo-dock-packages.c cairo-dock-packages.h
cairo-dock-particle-system.c cairo-dock-particle-system.h

View File

@@ -0,0 +1,36 @@
/*
* This file is a part of the Cairo-Dock project
*
* Copyright : (C) see the 'copyright' file.
* E-mail : see the 'copyright' file.
*
* 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 3
* 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, see <http://www.gnu.org/licenses/>.
*/
#ifndef __CAIRO_DOCK_DBUS_PRIV__
#define __CAIRO_DOCK_DBUS_PRIV__
#include "cairo-dock-dbus.h"
G_BEGIN_DECLS
/** Try to own our DBus name (org.cairodock.CairoDock). This is a synchronous
* function that will block until the name is acquired or rejected. It should
* be only called during initialization as it will iterate the default context.
*@return TRUE if the name has been acquired
*/
gboolean cairo_dock_dbus_own_name (void);
G_END_DECLS
#endif

View File

@@ -21,7 +21,68 @@
#include <glib.h>
#include "cairo-dock-log.h"
#include "cairo-dock-dbus.h"
#include "cairo-dock-dbus-priv.h"
/***********************************************************************
* New interface */
static GDBusConnection *s_pMainConnection = NULL;
static const gchar *s_cBusName = "org.cairodock.CairoDock";
static gboolean s_bNameOwned = FALSE;
gboolean cairo_dock_dbus_is_enabled (void)
{
return (s_pMainConnection != NULL);
}
GDBusConnection *cairo_dock_dbus_get_session_bus (void)
{
return s_pMainConnection;
}
const gchar *cairo_dock_dbus_get_owned_name (void)
{
return s_bNameOwned ? s_cBusName : NULL;
}
static void _on_bus_acquired (GDBusConnection *pConn, G_GNUC_UNUSED const gchar* cName, G_GNUC_UNUSED gpointer ptr)
{
s_pMainConnection = pConn;
}
gboolean s_bNameAcquiredOrLost = FALSE;
static void _on_name_acquired (G_GNUC_UNUSED GDBusConnection* pConn, G_GNUC_UNUSED const gchar* cName, G_GNUC_UNUSED gpointer data)
{
s_bNameOwned = TRUE;
s_bNameAcquiredOrLost = TRUE;
}
static void _on_name_lost (G_GNUC_UNUSED GDBusConnection* pConn, G_GNUC_UNUSED const gchar* cName, G_GNUC_UNUSED gpointer data)
{
s_bNameOwned = FALSE;
s_bNameAcquiredOrLost = TRUE;
}
gboolean cairo_dock_dbus_own_name (void)
{
//\____________ Register the service name (the service name is registerd once by the first gldi instance).
g_bus_own_name (G_BUS_TYPE_SESSION, s_cBusName, G_BUS_NAME_OWNER_FLAGS_DO_NOT_QUEUE, _on_bus_acquired, // bus acquired handler
_on_name_acquired, _on_name_lost, NULL, NULL);
// Wait until we have acquired the bus. This is necessary as we want to know whether we succeeded.
GMainContext *pContext = g_main_context_default ();
do g_main_context_iteration (pContext, TRUE);
while (!s_bNameAcquiredOrLost);
return s_bNameOwned;
}
/***********************************************************************
* Deprecated interface -- to be removed. */
static DBusGConnection *s_pSessionConnexion = NULL;
static DBusGConnection *s_pSystemConnexion = NULL;
@@ -101,12 +162,6 @@ gboolean cairo_dock_register_service_name (const gchar *cServiceName)
return TRUE;
}
gboolean cairo_dock_dbus_is_enabled (void)
{
return (cairo_dock_get_session_connection () != NULL && cairo_dock_get_system_connection () != NULL);
}
static void on_name_owner_changed (G_GNUC_UNUSED DBusGProxy *pProxy, const gchar *cName, G_GNUC_UNUSED const gchar *cPrevOwner, const gchar *cNewOwner, G_GNUC_UNUSED gpointer data)
{
//g_print ("%s (%s)\n", __func__, cName);

View File

@@ -22,6 +22,7 @@
#define __CAIRO_DOCK_DBUS__
#include <glib.h>
#include <gio/gio.h>
#include <dbus/dbus-glib.h>
#include <dbus/dbus-glib-bindings.h>
G_BEGIN_DECLS
@@ -32,6 +33,29 @@ G_BEGIN_DECLS
*/
/***********************************************************************
* New interface */
/** Say if the bus is available or not.
*@return TRUE if the connection to the bus has been established.
*/
gboolean cairo_dock_dbus_is_enabled (void);
/** Get a connection to the session bus (if connected).
*@return main DBusConnection to the session bus or NULL if unavailable
*/
GDBusConnection *cairo_dock_dbus_get_session_bus (void);
/** Get the DBus well-known name under which Cairo-Dock is registered
* on the session bus. By default, it is "org.CairoDock.cairodock".
*@return the DBus name registered or NULL if we do not own a DBus name
*/
const gchar *cairo_dock_dbus_get_owned_name (void);
/** Deprecated interface -- to be removed. */
typedef void (*CairoDockDbusNameOwnerChangedFunc) (const gchar *cName, gboolean bOwned, gpointer data);
/** Get the connection to the 'session' Bus.
@@ -50,10 +74,6 @@ DBusGProxy *cairo_dock_get_main_system_proxy (void);
*/
gboolean cairo_dock_register_service_name (const gchar *cServiceName);
/** Say if the bus is available or not.
*@return TRUE if the connection to the bus has been established.
*/
gboolean cairo_dock_dbus_is_enabled (void);
void cairo_dock_watch_dbus_name_owner (const char *cName, CairoDockDbusNameOwnerChangedFunc pCallback, gpointer data);

View File

@@ -95,17 +95,16 @@ static void _read_module_config (GKeyFile *pKeyFile, GldiModuleInstance *pInstan
bFlushConfFileNeeded = pInterface->read_conf_file (pInstance, pKeyFile);
}
if (! bFlushConfFileNeeded)
bFlushConfFileNeeded = cairo_dock_conf_file_needs_update (pKeyFile, pVisitCard->cModuleVersion);
if (bFlushConfFileNeeded)
{
// if there were still missing values (the plug-in uses some setting not in its template)
gchar *cTemplate = g_strdup_printf ("%s/%s", pVisitCard->cShareDataDir, pVisitCard->cConfFileName);
cairo_dock_upgrade_conf_file_full (pInstance->cConfFilePath, pKeyFile, cTemplate, FALSE); // keep private keys.
g_free (cTemplate);
}
}
GKeyFile *gldi_module_instance_open_conf_file (GldiModuleInstance *pInstance, CairoDockMinimalAppletConfig *pMinimalConfig)
static GKeyFile *_open_conf_file (GldiModuleInstance *pInstance, CairoDockMinimalAppletConfig *pMinimalConfig, gboolean bCheckUpdate)
{
g_return_val_if_fail (pInstance != NULL, NULL);
//\____________________ we open its config file.
@@ -117,6 +116,20 @@ GKeyFile *gldi_module_instance_open_conf_file (GldiModuleInstance *pInstance, Ca
if (pKeyFile == NULL) // unreadable file.
return NULL;
// check if we need to update the key file
if (bCheckUpdate && cairo_dock_conf_file_needs_update (pKeyFile, pInstance->pModule->pVisitCard->cModuleVersion))
{
// update to the new version first, so that default values will be read already (no missing values in the next step)
gchar *cTemplate = g_strdup_printf ("%s/%s", pInstance->pModule->pVisitCard->cShareDataDir, pInstance->pModule->pVisitCard->cConfFileName);
cairo_dock_upgrade_conf_file_full (cInstanceConfFilePath, pKeyFile, cTemplate, FALSE); // keep private keys.
g_free (cTemplate);
// re-read the updated file -- this is a bit wasteful, but this does not happen often
g_key_file_free (pKeyFile);
pKeyFile = cairo_dock_open_key_file (cInstanceConfFilePath);
g_return_val_if_fail (pKeyFile, NULL); // something went wrong -- should not happen
}
if (pInstance->pModule->pVisitCard->iContainerType == CAIRO_DOCK_MODULE_IS_PLUGIN) // This module doesn't have any icon (not an applet).
{
return pKeyFile;
@@ -255,6 +268,11 @@ GKeyFile *gldi_module_instance_open_conf_file (GldiModuleInstance *pInstance, Ca
return pKeyFile;
}
GKeyFile *gldi_module_instance_open_conf_file (GldiModuleInstance *pInstance, CairoDockMinimalAppletConfig *pMinimalConfig)
{
return _open_conf_file (pInstance, pMinimalConfig, FALSE);
}
void gldi_module_instance_free_generic_config (CairoDockMinimalAppletConfig *pMinimalConfig)
{
if (pMinimalConfig == NULL)
@@ -407,7 +425,7 @@ static void init_object (GldiObject *obj, gpointer attr)
//\____________________ open the conf file.
CairoDockMinimalAppletConfig *pMinimalConfig = g_new0 (CairoDockMinimalAppletConfig, 1);
GKeyFile *pKeyFile = gldi_module_instance_open_conf_file (pInstance, pMinimalConfig);
GKeyFile *pKeyFile = _open_conf_file (pInstance, pMinimalConfig, TRUE); // TRUE -> already apply any update from settings template
if (pInstance->cConfFilePath != NULL && pKeyFile == NULL) // we have a conf file, but it was unreadable -> cancel
{
//!! TODO: pInstance will likely be leaked in this case !!