/* Switch to requested view */ static void _xfdashboard_application_switch_to_view(XfdashboardApplication *self, const gchar *inInternalViewName) { GSList *stages, *iter; g_return_if_fail(XFDASHBOARD_IS_APPLICATION(self)); /* If no view name was specified then do nothing and return immediately */ if(!inInternalViewName || !inInternalViewName[0]) { g_debug("No view to switch to specified"); return; } /* Iterate through list of stages and set specified view at stage */ g_debug("Trying to switch to view '%s'", inInternalViewName); stages=clutter_stage_manager_list_stages(clutter_stage_manager_get_default()); for(iter=stages; iter; iter=g_slist_next(iter)) { /* Tell stage to switch view */ if(XFDASHBOARD_IS_STAGE(iter->data)) { xfdashboard_stage_set_switch_to_view(XFDASHBOARD_STAGE(iter->data), inInternalViewName); } } }
/* Quit running application and restart application */ static gboolean _restart(XfdashboardApplication *inApplication) { GMainLoop *mainLoop; guint dbusWatcherID; GSource *timeoutSource; RestartData restartData; g_return_val_if_fail(XFDASHBOARD_IS_APPLICATION(inApplication), FALSE); /* Create main loop for watching DBUS for application to disappear */ mainLoop=g_main_loop_new(NULL, FALSE); /* Set up user data for callbacks */ restartData.mainLoop=mainLoop; restartData.application=inApplication; restartData.appHasQuitted=FALSE; /* Set up DBUS watcher to get noticed when application disappears * which means it is safe to start a new instance. But if it takes * too long assume that either application did not quit and is still * running or we did get notified although we set up DBUS watcher * before quitting application. */ dbusWatcherID=g_bus_watch_name(G_BUS_TYPE_SESSION, g_application_get_application_id(G_APPLICATION(inApplication)), G_BUS_NAME_WATCHER_FLAGS_NONE, _on_dbus_watcher_name_appeared, _on_dbus_watcher_name_vanished, &restartData, NULL); /* Add an idle source to main loop to quit running application _after_ * the main loop is running and the DBUS watcher was set up. */ timeoutSource=g_timeout_source_new(DEFAULT_RESTART_WAIT_TIMEOUT); g_source_set_callback(timeoutSource, _on_quit_timeout, &restartData, NULL); g_source_attach(timeoutSource, g_main_loop_get_context(mainLoop)); g_source_unref(timeoutSource); /* Run main loop */ g_debug("Starting main loop for waiting the application to quit"); g_main_loop_run(mainLoop); g_debug("Returned from main loop for waiting the application to quit"); /* Show warning if timeout had been reached */ if(!restartData.appHasQuitted) { g_warning(_("Cannot restart application: Failed to quit running instance")); } /* Destroy DBUS watcher */ g_bus_unwatch_name(dbusWatcherID); /* Return TRUE if application was quitted successfully * otherwise FALSE. */ return(restartData.appHasQuitted); }
/* The session is going to quit */ static void _xfdashboard_application_on_session_quit(XfdashboardApplication *self, gpointer inUserData) { g_return_if_fail(XFDASHBOARD_IS_APPLICATION(self)); g_return_if_fail(XFCE_IS_SM_CLIENT(inUserData)); /* Force application to quit */ g_debug("Received 'quit' from session management client - initiating shutdown"); _xfdashboard_application_quit(self, TRUE); }
/* Set theme name and reload theme */ static void _xfdashboard_application_set_theme_name(XfdashboardApplication *self, const gchar *inThemeName) { XfdashboardApplicationPrivate *priv; GError *error; XfdashboardTheme *theme; g_return_if_fail(XFDASHBOARD_IS_APPLICATION(self)); g_return_if_fail(inThemeName && *inThemeName); priv=self->priv; error=NULL; /* Set value if changed */ if(g_strcmp0(priv->themeName, inThemeName)!=0) { /* Set value */ if(priv->themeName) g_free(priv->themeName); priv->themeName=g_strdup(inThemeName); /* Notify about property change */ g_object_notify_by_pspec(G_OBJECT(self), XfdashboardApplicationProperties[PROP_THEME_NAME]); /* Create new theme instance and load theme */ theme=xfdashboard_theme_new(); if(!xfdashboard_theme_load(theme, priv->themeName, &error)) { /* Show critical warning at console */ g_critical(_("Could not load theme '%s': %s"), priv->themeName, (error && error->message) ? error->message : _("unknown error")); /* Show warning as notification */ xfdashboard_notify(NULL, "gtk-dialog-error", _("Could not load theme '%s': %s"), priv->themeName, (error && error->message) ? error->message : _("unknown error")); /* Release allocated resources */ if(error!=NULL) g_error_free(error); g_object_unref(theme); return; } /* Release current theme and store new one */ if(priv->theme) g_object_unref(priv->theme); priv->theme=theme; /* Emit signal that theme has changed to get all top-level actors * to apply new theme. */ g_signal_emit(self, XfdashboardApplicationSignals[SIGNAL_THEME_CHANGED], 0, priv->theme); } }
/* A stage window should be destroyed */ static gboolean _xfdashboard_application_on_delete_stage(XfdashboardApplication *self, ClutterEvent *inEvent, gpointer inUserData) { g_return_val_if_fail(XFDASHBOARD_IS_APPLICATION(self), FALSE); /* Quit application */ _xfdashboard_application_quit(self, FALSE); /* Prevent the default handler being called */ return(CLUTTER_EVENT_STOP); }
/* Application was fully initialized so enabled all loaded plugin except the * ones which are already enabled, e.g. plugins which requested early initialization. */ static void _xfdashboard_plugins_manager_on_application_initialized(XfdashboardPluginsManager *self, gpointer inUserData) { XfdashboardPluginsManagerPrivate *priv; GList *iter; XfdashboardPlugin *plugin; g_return_if_fail(XFDASHBOARD_IS_PLUGINS_MANAGER(self)); g_return_if_fail(XFDASHBOARD_IS_APPLICATION(inUserData)); priv=self->priv; /* Iterate through all loaded plugins and enable all plugins which are * not enabled yet. */ XFDASHBOARD_DEBUG(self, PLUGINS, "Plugin manager will now enable all remaining plugins because application is fully initialized now"); for(iter=priv->plugins; iter; iter=g_list_next(iter)) { /* Get plugin */ plugin=XFDASHBOARD_PLUGIN(iter->data); /* If plugin is not enabled do it now */ if(!xfdashboard_plugin_is_enabled(plugin)) { /* Enable plugin */ XFDASHBOARD_DEBUG(self, PLUGINS, "Enabling plugin '%s'", xfdashboard_plugin_get_id(plugin)); xfdashboard_plugin_enable(plugin); } } /* Disconnect signal handler as this signal is emitted only once */ if(priv->application) { if(priv->applicationInitializedSignalID) { g_signal_handler_disconnect(priv->application, priv->applicationInitializedSignalID); priv->applicationInitializedSignalID=0; } priv->application=NULL; } }
/* Received "activate" signal on primary instance */ static void _xfdashboard_application_activate(GApplication *inApplication) { XfdashboardApplication *self; XfdashboardApplicationPrivate *priv; g_return_if_fail(XFDASHBOARD_IS_APPLICATION(inApplication)); self=XFDASHBOARD_APPLICATION(inApplication); priv=self->priv; /* Emit "resume" signal */ g_signal_emit(self, XfdashboardApplicationSignals[SIGNAL_RESUME], 0); /* Unset flag for suspension */ if(priv->isSuspended) { priv->isSuspended=FALSE; g_object_notify_by_pspec(G_OBJECT(self), XfdashboardApplicationProperties[PROP_SUSPENDED]); } }
/* Get flag if application is running in daemonized mode */ gboolean xfdashboard_application_is_daemonized(XfdashboardApplication *self) { g_return_val_if_fail(XFDASHBOARD_IS_APPLICATION(self), FALSE); return(self->priv->isDaemon); }
/* Handle command-line on primary instance */ static int _xfdashboard_application_command_line(GApplication *inApplication, GApplicationCommandLine *inCommandLine) { XfdashboardApplication *self; XfdashboardApplicationPrivate *priv; XfdashboardStage *stage; GOptionContext *context; gboolean result; gint argc; gchar **argv; GError *error; gboolean optionDaemonize; gboolean optionQuit; gboolean optionRestart; gboolean optionToggle; gchar *optionSwitchToView; GOptionEntry XfdashboardApplicationOptions[]= { { "daemonize", 'd', 0, G_OPTION_ARG_NONE, &optionDaemonize, N_("Fork to background"), NULL }, { "quit", 'q', 0, G_OPTION_ARG_NONE, &optionQuit, N_("Quit running instance"), NULL }, { "restart", 'r', 0, G_OPTION_ARG_NONE, &optionRestart, N_("Restart running instance"), NULL }, { "toggle", 't', 0, G_OPTION_ARG_NONE, &optionToggle, N_("Toggles suspend/resume state if running instance was started in daemon mode otherwise it quits running non-daemon instance"), NULL }, { "view", 0, 0, G_OPTION_ARG_STRING, &optionSwitchToView, N_(""), NULL }, { NULL } }; g_return_val_if_fail(XFDASHBOARD_IS_APPLICATION(inApplication), 1); self=XFDASHBOARD_APPLICATION(inApplication); priv=self->priv; error=NULL; stage=NULL; /* Set up options */ optionDaemonize=FALSE; optionQuit=FALSE; optionRestart=FALSE; optionToggle=FALSE; optionSwitchToView=NULL; /* Parse command-line arguments */ argv=g_application_command_line_get_arguments(inCommandLine, &argc); /* Setup command-line options */ context=g_option_context_new(N_("- A Gnome Shell like dashboard for Xfce4")); g_option_context_add_group(context, gtk_get_option_group(TRUE)); g_option_context_add_group(context, clutter_get_option_group_without_init()); g_option_context_add_group(context, xfce_sm_client_get_option_group(argc, argv)); g_option_context_add_main_entries(context, XfdashboardApplicationOptions, GETTEXT_PACKAGE); #ifdef DEBUG /* I always forget the name of the environment variable to get the debug * message display which are emitted with g_debug(). So display a hint * if application was compiled with debug enabled. */ g_print("** To get debug messages set environment variable G_MESSAGES_DEBUG to %s\n", PACKAGE_NAME); g_print("** e.g.: G_MESSAGES_DEBUG=%s %s\n", PACKAGE_NAME, argv[0]); #endif result=g_option_context_parse(context, &argc, &argv, &error); g_strfreev(argv); g_option_context_free(context); if(result==FALSE) { /* Show error */ g_print(N_("%s\n"), (error && error->message) ? error->message : _("unknown error")); if(error) g_error_free(error); /* Release allocated resources */ if(optionSwitchToView) g_free(optionSwitchToView); return(XFDASHBOARD_APPLICATION_ERROR_FAILED); } /* Handle options: restart * - Only handle option if application was inited already */ if(priv->inited && optionRestart) { /* Return state to restart this applicationa */ g_debug("Received request to restart application!"); /* Release allocated resources */ if(optionSwitchToView) g_free(optionSwitchToView); return(XFDASHBOARD_APPLICATION_ERROR_RESTART); } /* Handle options: quit */ if(optionQuit) { /* Quit existing instance */ g_debug("Quitting running instance!"); _xfdashboard_application_quit(self, TRUE); /* Release allocated resources */ if(optionSwitchToView) g_free(optionSwitchToView); return(XFDASHBOARD_APPLICATION_ERROR_QUIT); } /* Handle options: toggle * - If application was not inited yet, perform normal start-up as usual * with command-line options given * - If running in daemon mode, resume if suspended otherwise suspend * - If not running in daemon mode, quit application */ if(priv->inited && optionToggle) { /* If application is running in daemon mode, toggle between suspend/resume ... */ if(priv->isDaemon) { if(priv->isSuspended) { /* Switch to view if requested */ _xfdashboard_application_switch_to_view(self, optionSwitchToView); /* Show application again */ _xfdashboard_application_activate(inApplication); } else { /* Hide application */ _xfdashboard_application_quit(self, FALSE); } } /* ... otherwise if not running in daemon mode, just quit */ else { /* Hide application */ _xfdashboard_application_quit(self, FALSE); } /* Release allocated resources */ if(optionSwitchToView) g_free(optionSwitchToView); /* Stop here because option was handled and application does not get initialized */ return(XFDASHBOARD_APPLICATION_ERROR_NONE); } /* Handle options: daemonize */ if(!priv->inited) { priv->isDaemon=optionDaemonize; g_object_notify_by_pspec(G_OBJECT(self), XfdashboardApplicationProperties[PROP_DAEMONIZED]); if(priv->isDaemon) { priv->isSuspended=TRUE; g_object_notify_by_pspec(G_OBJECT(self), XfdashboardApplicationProperties[PROP_SUSPENDED]); } } /* Check if this instance needs to be initialized fully */ if(!priv->inited) { /* Perform full initialization of this application instance */ result=_xfdashboard_application_initialize_full(self, &stage); if(result==FALSE) return(XFDASHBOARD_APPLICATION_ERROR_FAILED); /* Switch to view if requested */ _xfdashboard_application_switch_to_view(self, optionSwitchToView); /* Show application if not started daemonized */ if(!priv->isDaemon) clutter_actor_show(CLUTTER_ACTOR(stage)); } /* Check if this instance need to be activated. Is should only be done * if instance is initialized */ if(priv->inited) { /* Switch to view if requested */ _xfdashboard_application_switch_to_view(self, optionSwitchToView); /* Show application */ _xfdashboard_application_activate(inApplication); } /* Release allocated resources */ if(optionSwitchToView) g_free(optionSwitchToView); /* All done successfully so return status code 0 for success */ priv->inited=TRUE; return(XFDASHBOARD_APPLICATION_ERROR_NONE); }
/* Perform full initialization of this application instance */ static gboolean _xfdashboard_application_initialize_full(XfdashboardApplication *self, XfdashboardStage **outStage) { XfdashboardApplicationPrivate *priv; GError *error; ClutterActor *stage; #if !GARCON_CHECK_VERSION(0,3,0) const gchar *desktop; #endif g_return_val_if_fail(XFDASHBOARD_IS_APPLICATION(self), FALSE); g_return_val_if_fail(outStage==NULL || *outStage==NULL, FALSE); priv=self->priv; error=NULL; /* Initialize garcon for current desktop environment */ #if !GARCON_CHECK_VERSION(0,3,0) desktop=g_getenv("XDG_CURRENT_DESKTOP"); if(G_LIKELY(desktop==NULL)) { /* If we could not determine current desktop environment * assume Xfce as this application is developed for this DE. */ desktop="XFCE"; } /* If desktop enviroment was found but has no name * set NULL to get all menu items shown. */ else if(*desktop==0) desktop=NULL; garcon_set_environment(desktop); #else garcon_set_environment_xdg(GARCON_ENVIRONMENT_XFCE); #endif /* Setup the session management */ priv->sessionManagementClient=xfce_sm_client_get(); xfce_sm_client_set_priority(priv->sessionManagementClient, XFCE_SM_CLIENT_PRIORITY_DEFAULT); xfce_sm_client_set_restart_style(priv->sessionManagementClient, XFCE_SM_CLIENT_RESTART_IMMEDIATELY); g_signal_connect_swapped(priv->sessionManagementClient, "quit", G_CALLBACK(_xfdashboard_application_on_session_quit), self); if(!xfce_sm_client_connect(priv->sessionManagementClient, &error)) { g_warning("Failed to connect to session manager: %s", (error && error->message) ? error->message : _("unknown error")); g_clear_error(&error); } /* Initialize xfconf */ if(!xfconf_init(&error)) { g_critical(_("Could not initialize xfconf: %s"), (error && error->message) ? error->message : _("unknown error")); if(error) g_error_free(error); return(FALSE); } priv->xfconfChannel=xfconf_channel_get(XFDASHBOARD_XFCONF_CHANNEL); /* Set up keyboard and pointer bindings */ priv->bindings=xfdashboard_bindings_pool_get_default(); if(!priv->bindings) { g_critical(_("Could not initialize bindings")); return(FALSE); } if(!xfdashboard_bindings_pool_load(priv->bindings, &error)) { g_critical(_("Could not load bindings: %s"), (error && error->message) ? error->message : _("unknown error")); if(error!=NULL) g_error_free(error); return(FALSE); } /* Set up application database */ priv->appDatabase=xfdashboard_application_database_get_default(); if(!priv->appDatabase) { g_critical(_("Could not initialize application database")); return(FALSE); } if(!xfdashboard_application_database_load(priv->appDatabase, &error)) { g_critical(_("Could not load application database: %s"), (error && error->message) ? error->message : _("unknown error")); if(error!=NULL) g_error_free(error); return(FALSE); } /* Set up application tracker */ priv->appTracker=xfdashboard_application_tracker_get_default(); if(!priv->appTracker) { g_critical(_("Could not initialize application tracker")); return(FALSE); } /* Set up and load theme */ priv->xfconfThemeChangedSignalID=xfconf_g_property_bind(priv->xfconfChannel, THEME_NAME_XFCONF_PROP, G_TYPE_STRING, self, "theme-name"); if(!priv->xfconfThemeChangedSignalID) { g_warning(_("Could not create binding between xfconf property and local resource for theme change notification.")); } /* Set up default theme in Xfcond if property in channel does not exist * because it indicates first start. */ if(!xfconf_channel_has_property(priv->xfconfChannel, THEME_NAME_XFCONF_PROP)) { xfconf_channel_set_string(priv->xfconfChannel, THEME_NAME_XFCONF_PROP, DEFAULT_THEME_NAME); } /* At this time the theme must have been loaded, either because we * set the default theme name because of missing theme property in * xfconf channel or the value of xfconf channel property has been read * and set when setting up binding (between xfconf property and local property) * what caused a call to function to set theme name in this object * and also caused a reload of theme. * So if no theme object is set in this object then loading theme has * failed and we have to return FALSE. */ if(!priv->theme) return(FALSE); /* Register built-in views (order of registration is important) */ priv->viewManager=xfdashboard_view_manager_get_default(); xfdashboard_view_manager_register(priv->viewManager, XFDASHBOARD_TYPE_WINDOWS_VIEW); xfdashboard_view_manager_register(priv->viewManager, XFDASHBOARD_TYPE_APPLICATIONS_VIEW); xfdashboard_view_manager_register(priv->viewManager, XFDASHBOARD_TYPE_SEARCH_VIEW); /* Register built-in search providers */ priv->searchManager=xfdashboard_search_manager_get_default(); xfdashboard_search_manager_register(priv->searchManager, XFDASHBOARD_TYPE_APPLICATIONS_SEARCH_PROVIDER); /* Create single-instance of focus manager to keep it alive while * application is running. */ priv->focusManager=xfdashboard_focus_manager_get_default(); /* Create stage containing all monitors */ stage=xfdashboard_stage_new(); g_signal_connect_swapped(stage, "delete-event", G_CALLBACK(_xfdashboard_application_on_delete_stage), self); /* Emit signal 'theme-changed' to get current theme loaded at each stage created */ g_signal_emit(self, XfdashboardApplicationSignals[SIGNAL_THEME_CHANGED], 0, priv->theme); /* Set return results */ if(outStage) *outStage=XFDASHBOARD_STAGE(stage); /* Initialization was successful so return TRUE */ #ifdef DEBUG xfdashboard_notify(NULL, NULL, _("Welcome to %s (%s)!"), PACKAGE_NAME, PACKAGE_VERSION); #else xfdashboard_notify(NULL, NULL, _("Welcome to %s!"), PACKAGE_NAME); #endif return(TRUE); }
/* Quit application depending on daemon mode and force parameter */ static void _xfdashboard_application_quit(XfdashboardApplication *self, gboolean inForceQuit) { XfdashboardApplicationPrivate *priv; gboolean shouldQuit; GSList *stages, *entry; g_return_if_fail(XFDASHBOARD_IS_APPLICATION(self)); priv=self->priv; shouldQuit=FALSE; /* Check if we should really quit this instance */ if(inForceQuit==TRUE || priv->isDaemon==FALSE) shouldQuit=TRUE; /* Do nothing if application is already quitting. This can happen if * application is running in daemon mode (primary instance) and another * instance was called with "quit" or "restart" parameter which would * cause this function to be called twice. */ if(priv->isQuitting) return; /* If application is not in daemon mode or if forced is set to TRUE * destroy all stage windows ... */ if(shouldQuit==TRUE) { /* Set flag that application is going to quit */ priv->isQuitting=TRUE; /* If application is told to quit, set the restart style to something * where it won't restart itself. */ if(priv->sessionManagementClient && XFCE_IS_SM_CLIENT(priv->sessionManagementClient)) { xfce_sm_client_set_restart_style(priv->sessionManagementClient, XFCE_SM_CLIENT_RESTART_NORMAL); } /* Destroy stages */ stages=clutter_stage_manager_list_stages(clutter_stage_manager_get_default()); for(entry=stages; entry!=NULL; entry=g_slist_next(entry)) clutter_actor_destroy(CLUTTER_ACTOR(entry->data)); g_slist_free(stages); /* Emit "quit" signal */ g_signal_emit(self, XfdashboardApplicationSignals[SIGNAL_QUIT], 0); /* Really quit application here and now */ if(priv->inited) clutter_main_quit(); } /* ... otherwise emit "suspend" signal */ else { /* Only send signal if not suspended already */ if(!priv->isSuspended) { /* Send signal */ g_signal_emit(self, XfdashboardApplicationSignals[SIGNAL_SUSPEND], 0); /* Set flag for suspension */ priv->isSuspended=TRUE; g_object_notify_by_pspec(G_OBJECT(self), XfdashboardApplicationProperties[PROP_SUSPENDED]); } } }
/* Get flag if application is going to quit */ gboolean xfdashboard_application_is_quitting(XfdashboardApplication *self) { g_return_val_if_fail(XFDASHBOARD_IS_APPLICATION(self), FALSE); return(self->priv->isQuitting); }