/* $Id: xfce-mcs-manager.c 21674 2006-05-15 14:54:42Z benny $ */
/*-
* Copyright (c) 2002-2004 Olivier Fourdan <fourdan@xfce.org>
* Copyright (c) 2003-2006 Benedikt Meurer <benny@xfce.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#ifdef HAVE_SYS_WAIT_H
#include <sys/wait.h>
#endif
#ifdef HAVE_ERRNO_H
#include <errno.h>
#endif
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif
#ifdef HAVE_MEMORY_H
#include <memory.h>
#endif
#ifdef HAVE_SIGNAL_H
#include <signal.h>
#endif
#include <stdio.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef ENABLE_LOADPROF
#include <sys/time.h>
#endif
#include <gdk/gdkx.h>
#include <gmodule.h>
#include <libxfce4mcs/mcs-common.h>
#include <libxfce4mcs/mcs-manager.h>
#include <libxfcegui4/libxfcegui4.h>
#include <xfce-mcs-manager/manager-plugin.h>
#include <xfce-mcs-manager/xfce-mcs-dialog.h>
#define SOEXT ("." G_MODULE_SUFFIX)
#define SOEXT_LEN (strlen (SOEXT))
static gchar **rargv = NULL;
static GSList *plugin_list = NULL;
static GSList *module_list = NULL;
static McsManager *manager;
static enum
{
NOSIGNAL,
RESTART,
QUIT,
NUM_SIGNALS
} sigstate = NOSIGNAL;
G_MODULE_EXPORT gchar * mcs_plugin_check_version (gint version)
{
if (XFCE_MCS_PLUGIN_VERSION == version)
return NULL;
return _("Incorrect module version");
}
static gint
compare_plugins (gconstpointer plugin_a, gconstpointer plugin_b)
{
return strcmp (((const McsPlugin *) plugin_a)->plugin_name, ((const McsPlugin *) plugin_b)->plugin_name);
}
static gint
lookup_plugins (gconstpointer plugin, gconstpointer name)
{
return strcmp (((const McsPlugin *) plugin)->plugin_name, name);
}
static void
load_plugin (gchar * path)
{
McsPluginInitResult (*init) (McsPlugin *);
McsPlugin *plugin;
GModule *module;
#ifdef G_ENABLE_DEBUG
g_message ("- attempting to load module %s", path);
#endif
if ((module = g_module_open (path, 0)) == NULL)
{
g_warning ("Module %s cannot be opened (%s)", path, g_module_error ());
return;
}
if (g_module_symbol (module, "mcs_plugin_init", (gpointer) & init))
{
plugin = g_new0 (McsPlugin, 1);
plugin->manager = manager;
if ((*init) (plugin) != MCS_PLUGIN_INIT_OK)
{
if (G_UNLIKELY (plugin->icon != NULL))
g_object_unref (plugin->icon);
g_free (plugin->plugin_name);
g_free (plugin->caption);
g_free (plugin);
g_module_close (module);
return;
}
if (g_slist_find_custom (plugin_list, plugin, compare_plugins))
{
g_warning (" module %s (\"%s\") has already been loaded before", path, plugin->plugin_name);
if (G_LIKELY (plugin->icon != NULL))
g_object_unref (plugin->icon);
g_free (plugin->plugin_name);
g_free (plugin->caption);
g_module_close (module);
g_free (plugin);
}
else
{
#ifdef G_ENABLE_DEBUG
g_message (" module %s (\"%s\") successfully loaded", path, plugin->plugin_name);
#endif
plugin_list = g_slist_append (plugin_list, plugin);
module_list = g_slist_append (module_list, module);
}
}
else
{
g_warning (" incompatible module %s", path);
g_module_close (module);
}
}
#ifdef ENABLE_LOADPROF
static void
compute_delta_t (struct timeval *start, struct timeval *stop, struct timeval *delta)
{
delta->tv_sec = stop->tv_sec - start->tv_sec;
delta->tv_usec = stop->tv_usec - start->tv_usec;
if (delta->tv_usec >= 1000000)
{
delta->tv_sec += 1;
delta->tv_usec -= 1000000;
}
if (delta->tv_usec < 0)
{
delta->tv_sec -= 1;
delta->tv_usec += 1000000;
}
}
#endif
static void
plugins_load_dir (const gchar * dir)
{
const gchar *f;
gchar *plugin;
GDir *d;
d = g_dir_open (dir, 0, NULL);
if (d != NULL)
{
#ifdef ENABLE_LOADPROF
struct timeval t0;
gettimeofday (&t0, NULL);
#endif
while ((f = g_dir_read_name (d)) != NULL)
{
if (g_str_has_suffix (f, SOEXT))
{
#ifdef ENABLE_LOADPROF
struct timeval t1;
struct timeval delta_t;
#endif
plugin = g_build_filename (dir, f, NULL);
load_plugin (plugin);
#ifdef ENABLE_LOADPROF
gettimeofday (&t1, NULL);
compute_delta_t (&t0, &t1, &delta_t);
g_print ("Started %s in %u.%06u sec.\n", plugin, (unsigned int) delta_t.tv_sec, (unsigned int) delta_t.tv_usec);
t0.tv_sec = t1.tv_sec;
t0.tv_usec = t1.tv_usec;
#endif
g_free (plugin);
}
}
g_dir_close (d);
}
}
static void
plugin_load_all (void)
{
#ifdef G_ENABLE_DEBUG
g_message ("Loading mcs plugins");
#endif
/* load system plugins */
plugins_load_dir (PLUGINSDIR);
}
static void
unload_plugins (void)
{
#ifdef G_ENABLE_DEBUG
g_message ("Unloading mcs plugins");
#endif
/*
* NOTE: Grabbing the X-Server while reloading the
* plugins will not work (Don't know why)
*/
g_slist_foreach (module_list, (GFunc) g_module_close, NULL);
g_slist_free (module_list);
module_list = NULL;
g_slist_foreach (plugin_list, (GFunc) g_free, NULL);
g_slist_free (plugin_list);
plugin_list = NULL;
}
static void
terminate_cb (void *data)
{
#ifdef G_ENABLE_DEBUG
g_print ("Releasing the selection and exitingn");
#endif
*(gboolean *) data = TRUE;
gtk_main_quit ();
}
static void
show_cb (char *name, void *cb_data)
{
GSList *plugin_search;
McsPlugin *plugin;
if (strcmp ("", name) == 0 || g_ascii_strcasecmp ("all", name) == 0)
{
run_manager_dialog (plugin_list);
return;
}
plugin_search = g_slist_find_custom (plugin_list, name, lookup_plugins);
if (plugin_search != NULL)
{
plugin = (McsPlugin *) plugin_search->data;
plugin->run_dialog (plugin);
}
else
{
xfce_err (_("Xfce Settings Manager error:\nNo such plugin \"%s\""), name);
run_manager_dialog (plugin_list);
}
}
static GdkFilterReturn
manager_event_filter (GdkXEvent * xevent, GdkEvent * event, gpointer data)
{
if (mcs_manager_process_event (manager, (XEvent *) xevent))
return GDK_FILTER_REMOVE;
else
return GDK_FILTER_CONTINUE;
}
static void
sighandler (int signo)
{
switch (signo)
{
case SIGUSR1:
sigstate = RESTART;
break;
default:
sigstate = QUIT;
}
}
static gboolean
check_signal_state (void)
{
if (sigstate == RESTART)
{
/* unload all plugins and destroy the manager */
unload_plugins ();
mcs_manager_destroy (manager);
/* just run the MCS manager from scratch */
execvp (rargv[0], rargv);
_exit (EXIT_SUCCESS);
}
else if (sigstate == QUIT)
{
gtk_main_quit ();
return FALSE;
}
return TRUE;
}
int
main (int argc, char **argv)
{
#ifdef HAVE_SIGACTION
struct sigaction act;
#endif
McsManagerCheck status;
gboolean daemon_mode;
gboolean std_mgr;
int i;
/* save argv for restart */
rargv = g_strdupv (argv);
daemon_mode = TRUE;
std_mgr = TRUE;
xfce_textdomain (GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR, "UTF-8");
gtk_init (&argc, &argv);
/* Fake a SM client ID, so smproxy does not catch us */
gdk_set_sm_client_id ("FAKED CLIENTID");
for (i = 1; i < argc; i++)
if (strcmp (argv[i], "--no-daemon-debug") == 0)
daemon_mode = FALSE;
status = mcs_manager_check_running (gdk_display, DefaultScreen (gdk_display));
switch (status)
{
case MCS_MANAGER_MULTI_CHANNEL:
case MCS_MANAGER_BOTH:
g_warning ("Multi channel MCS manager already detected for screen %i", DefaultScreen (gdk_display));
return EXIT_FAILURE;
case MCS_MANAGER_STD:
g_message ("Standard XSETTINGS manager already detected for screen %i", DefaultScreen (gdk_display));
std_mgr = FALSE;
default:
break;
}
manager = mcs_manager_new (std_mgr, gdk_display, DefaultScreen (gdk_display), terminate_cb, show_cb, NULL);
if (manager == NULL)
{
g_warning ("Could not create manager!");
return EXIT_FAILURE;
}
gdk_window_add_filter (NULL, manager_event_filter, NULL);
plugin_load_all ();
gdk_flush ();
#ifdef HAVE_SIGACTION
act.sa_handler = sighandler;
#ifdef SA_RESTART
act.sa_flags = SA_RESTART;
#else
act.sa_flags = 0;
#endif
sigaction (SIGTERM, &act, NULL);
sigaction (SIGHUP, &act, NULL);
sigaction (SIGINT, &act, NULL);
sigaction (SIGUSR1, &act, NULL);
#else /* !HAVE_SIGACTION */
signal (SIGTERM, sighandler);
signal (SIGHUP, sighandler);
signal (SIGINT, sighandler);
signal (SIGUSR1, sighandler);
#endif
if (daemon_mode)
{
#ifdef HAVE_DAEMON
if (daemon (TRUE, TRUE) < 0)
{
g_warning ("Failed to switch to daemon mode: %s", g_strerror (errno));
return (EXIT_FAILURE);
}
#else /* !HAVE_DAEMON */
switch (fork ())
{
case -1:
g_warning ("fork() failed");
return (EXIT_FAILURE);
case 0:
#ifdef HAVE_SETSID
/* detach from session */
if (setsid () < 0)
{
g_warning ("Failed to detach from terminal " "session: %s", g_strerror (errno));
}
#endif /* !HAVE_SETSID */
break;
default:
/* parent */
_exit (EXIT_SUCCESS);
}
#endif /* !HAVE_DAEMON */
}
else
g_message ("Daemon mode disabled (for debug purpose only!)");
/* Establish signal-check timer */
g_timeout_add (500, (GSourceFunc) check_signal_state, NULL);
gtk_main ();
unload_plugins ();
mcs_manager_destroy (manager);
return EXIT_SUCCESS;
}
syntax highlighted by Code2HTML, v. 0.9.1