2009-02-19 11:12:29 +03:00
|
|
|
/*
|
|
|
|
* $Id$
|
|
|
|
*
|
|
|
|
* Evoke, head honcho of everything
|
|
|
|
* Part of Equinox Desktop Environment (EDE).
|
|
|
|
* Copyright (c) 2007-2009 EDE Authors.
|
|
|
|
*
|
|
|
|
* This program is licensed under terms of the
|
|
|
|
* GNU General Public License version 2 or newer.
|
|
|
|
* See COPYING for details.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include <config.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <string.h>
|
|
|
|
#include <signal.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <FL/Fl.H>
|
|
|
|
#include <FL/x.H>
|
2009-03-03 14:47:30 +03:00
|
|
|
#include <edelib/Run.h>
|
2009-02-19 11:12:29 +03:00
|
|
|
|
|
|
|
#include "EvokeService.h"
|
|
|
|
#include "Autostart.h"
|
|
|
|
|
2009-03-03 14:47:30 +03:00
|
|
|
EDELIB_NS_USING(run_async)
|
|
|
|
|
2009-02-19 11:12:29 +03:00
|
|
|
#define FOREVER 1e20
|
|
|
|
#define LOCK_FILE "/tmp/.evoke.lock"
|
|
|
|
|
|
|
|
#define CHECK_ARGV(argv, pshort, plong) ((strcmp(argv, pshort) == 0) || (strcmp(argv, plong) == 0))
|
|
|
|
|
|
|
|
static void quit_signal(int sig) {
|
|
|
|
EvokeService::instance()->stop();
|
|
|
|
}
|
|
|
|
|
|
|
|
static int xmessage_handler(int) {
|
|
|
|
return EvokeService::instance()->handle(fl_xevent);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void help(void) {
|
|
|
|
puts("Usage: evoke [OPTIONS]");
|
|
|
|
puts("EDE startup manager responsible for desktop starting and quitting");
|
|
|
|
puts("(including various bits and pieces desktop needs)");
|
|
|
|
puts("Options:");
|
|
|
|
puts(" -h, --help this help");
|
2009-02-20 19:39:27 +03:00
|
|
|
puts(" -s, --startup run in startup mode");
|
|
|
|
puts(" -n, --no-splash do not show splash screen in startup mode");
|
|
|
|
puts(" -d, --dry-run run in startup mode, but don't execute anything");
|
2009-02-19 11:12:29 +03:00
|
|
|
puts(" -a, --autostart read autostart directory and run all items");
|
|
|
|
puts(" -u, --autostart-safe read autostart directory and display dialog what will be run\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
int main(int argc, char** argv) {
|
|
|
|
bool do_startup = false;
|
|
|
|
bool do_dryrun = false;
|
|
|
|
bool show_splash = true;
|
|
|
|
bool do_autostart = false;
|
|
|
|
bool do_autostart_safe = false;
|
|
|
|
|
|
|
|
if(argc > 1) {
|
|
|
|
const char* a;
|
|
|
|
for(int i = 1; i < argc; i++) {
|
|
|
|
a = argv[i];
|
|
|
|
if(CHECK_ARGV(a, "-h", "--help")) {
|
|
|
|
help();
|
|
|
|
return 0;
|
|
|
|
}
|
2009-02-20 19:39:27 +03:00
|
|
|
else if(CHECK_ARGV(a, "-s", "--startup"))
|
2009-02-19 11:12:29 +03:00
|
|
|
do_startup = true;
|
|
|
|
else if(CHECK_ARGV(a, "-d", "--dry-run"))
|
|
|
|
do_dryrun = true;
|
|
|
|
else if(CHECK_ARGV(a, "-n", "--no-splash"))
|
|
|
|
show_splash = false;
|
|
|
|
else if(CHECK_ARGV(a, "-a", "--autostart"))
|
|
|
|
do_autostart = true;
|
|
|
|
else if(CHECK_ARGV(a, "-u", "--autostart-safe"))
|
|
|
|
do_autostart_safe = true;
|
|
|
|
else {
|
|
|
|
printf("Unknown parameter '%s'. Run 'evoke -h' for options\n", a);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* make sure X11 is running before rest of code is called */
|
|
|
|
fl_open_display();
|
|
|
|
|
|
|
|
/* initialize main service object */
|
|
|
|
EvokeService* service = EvokeService::instance();
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Main loop is not initialized before startup (and splash) are finished;
|
|
|
|
* this is intentional so we could use 'dryrun' to test a splash theme and startup items
|
|
|
|
* without interfering with already running evoke instance (and getting lock error)
|
|
|
|
*
|
|
|
|
* TODO: dryrun option is pretty dummy; better to use "test-splash" or similar
|
|
|
|
*/
|
|
|
|
if(do_startup) {
|
|
|
|
service->read_startup();
|
|
|
|
service->run_startup(show_splash, do_dryrun);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* only testing, quit nicely */
|
|
|
|
if(do_dryrun)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if(!service->setup_lock(LOCK_FILE)) {
|
2009-03-03 14:47:30 +03:00
|
|
|
printf("*** Either another evoke instance is running or I can't create lock file.\n");
|
|
|
|
printf("*** If program abnormaly crashed before, just remove '%s' and start it again.\n", LOCK_FILE);
|
2009-02-19 11:12:29 +03:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
signal(SIGINT, quit_signal);
|
|
|
|
signal(SIGTERM, quit_signal);
|
|
|
|
signal(SIGKILL, quit_signal);
|
|
|
|
signal(SIGQUIT, quit_signal);
|
|
|
|
|
|
|
|
#ifdef USE_SIGHUP
|
|
|
|
/*
|
|
|
|
* This is mostly used when we get request to shutdown session and close/kill all windows.
|
|
|
|
* If evoke is started from gui console (xterm, rxvt), closing that window we will get
|
|
|
|
* SIGHUP since terminal will disconnect all controlling processes. On other hand, if evoke
|
|
|
|
* is started as session carrier (eg. run from xinitrc), this is not needed.
|
|
|
|
*/
|
|
|
|
signal(SIGHUP, quit_signal);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if(do_autostart || do_autostart_safe)
|
|
|
|
perform_autostart(do_autostart_safe);
|
|
|
|
|
|
|
|
service->start_xsettings_manager();
|
|
|
|
|
|
|
|
/* set stuff so xsettings manager can receive events */
|
|
|
|
XSelectInput(fl_display, RootWindow(fl_display, fl_screen),
|
|
|
|
PropertyChangeMask | SubstructureNotifyMask | ClientMessage);
|
|
|
|
Fl::add_handler(xmessage_handler);
|
|
|
|
|
2009-03-03 14:47:30 +03:00
|
|
|
/* run applicator for settings; it must be done after manager is fully on */
|
|
|
|
if(do_startup)
|
|
|
|
run_async("ede-settings-apply");
|
|
|
|
|
2009-02-19 11:12:29 +03:00
|
|
|
service->start();
|
|
|
|
|
|
|
|
while(service->running()) {
|
|
|
|
/*
|
|
|
|
* FLTK will not report SelectionClear needed for XSETTINGS manager
|
|
|
|
* so we must catch it first before FLTK discards it (if we can :P)
|
|
|
|
* This can be missed greatly due a large number of XDamage events
|
|
|
|
* and using this method is not quite safe.
|
|
|
|
*/
|
|
|
|
if(fl_xevent && fl_xevent->type == SelectionClear)
|
|
|
|
service->handle(fl_xevent);
|
|
|
|
|
|
|
|
Fl::wait(FOREVER);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|