ede/evoke/evoke.cpp
Sanel Zukan ad69c2fc2c Replaced X event notifying via add_fd(). Now all X events could be reported
without possible stealing from fltk. Prevous, add_handler(), would send only
unknown events for fltk which leave us without really important ones, like selection events
used by XSETTINGS manager.

Added XSETTINGS support (yet unfinished) which will make evoke as XSETTINGS manager.
2007-09-18 14:06:09 +00:00

212 lines
6.1 KiB
C++

/*
* $Id$
*
* Evoke, head honcho of everything
* Part of Equinox Desktop Environment (EDE).
* Copyright (c) 2000-2007 EDE Authors.
*
* This program is licensed under terms of the
* GNU General Public License version 2 or newer.
* See COPYING for details.
*/
#include "EvokeService.h"
#include <FL/Fl.h>
#include <FL/x.h>
#include <edelib/Config.h>
#include <edelib/Debug.h>
#include <edelib/File.h>
#include <string.h>
#include <signal.h>
#define FOREVER 1e20
#define CONFIG_FILE "evoke.conf"
#define APPNAME "evoke"
#define DEFAULT_PID "/tmp/evoke.pid"
/*
* Used to assure unique instance, even if is given another
* path for pid. This option can't be modified by user.
* TODO: add lock on file so it can't be removed ?
*/
#define LOCK_FILE "/tmp/.evoke.lock"
#define CHECK_ARGV(argv, pshort, plong) ((strcmp(argv, pshort) == 0) || (strcmp(argv, plong) == 0))
void quit_signal(int sig) {
EVOKE_LOG("Got quit signal %i\n", sig);
EvokeService::instance()->stop();
}
void xmessage_handler(int, void*) {
XEvent xev;
while(XEventsQueued(fl_display, QueuedAfterReading)) {
XNextEvent(fl_display, &xev);
EvokeService::instance()->handle((const XEvent*)&xev);
}
}
const char* next_param(int curr, char** argv, int argc) {
int j = curr + 1;
if(j >= argc)
return NULL;
if(argv[j][0] == '-')
return NULL;
return argv[j];
}
void help(void) {
puts("Usage: "APPNAME" [OPTIONS]");
puts("EDE startup manager responsible for starting, quitting and tracking");
puts("various pieces of desktop environment and external programs.");
puts("...and to popup a nice window when something crashes...\n");
puts("Options:");
puts(" -h, --help this help");
puts(" -s, --startup run in starup mode");
puts(" -n, --no-splash do not show splash screen in starup mode");
puts(" -d, --dry-run run in starup mode, but don't execute anything");
puts(" -a, --autostart read autostart directory and run all items");
puts(" -u, --autostart-safe read autostart directory and display dialog what will be run");
puts(" -c, --config [FILE] use FILE as config file");
puts(" -p, --pid [FILE] use FILE to store PID number");
puts(" -l, --log [FILE] log traffic to FILE (FILE can be stdout/stderr for console output)\n");
}
int main(int argc, char** argv) {
const char* config_file = NULL;
const char* pid_file = NULL;
const char* log_file = NULL;
bool do_startup = 0;
bool do_dryrun = 0;
bool no_splash = 0;
bool do_autostart = 0;
bool do_autostart_safe = 0;
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;
} else if(CHECK_ARGV(a, "-c", "--config")) {
config_file = next_param(i, argv, argc);
if(!config_file) {
puts("Missing configuration filename");
return 1;
}
i++;
} else if(CHECK_ARGV(a, "-p", "--pid")) {
pid_file = next_param(i, argv, argc);
if(!pid_file) {
puts("Missing pid filename");
return 1;
}
i++;
} else if(CHECK_ARGV(a, "-l", "--log")) {
log_file = next_param(i, argv, argc);
if(!log_file) {
puts("Missing log filename");
return 1;
}
i++;
}
else if(CHECK_ARGV(a, "-s", "--startup"))
do_startup = 1;
else if(CHECK_ARGV(a, "-d", "--dry-run"))
do_dryrun = 1;
else if(CHECK_ARGV(a, "-n", "--no-splash"))
no_splash = 1;
else if(CHECK_ARGV(a, "-a", "--autostart"))
do_autostart = 1;
else if(CHECK_ARGV(a, "-u", "--autostart-safe"))
do_autostart_safe = 1;
else {
printf("Unknown parameter '%s'. Run '"APPNAME" -h' for options\n", a);
return 1;
}
}
}
// make sure X11 is running before rest of code is called
fl_open_display();
EvokeService* service = EvokeService::instance();
if(!service->setup_logging(log_file)) {
printf("Can't open %s for logging. Please choose some writeable place\n", log_file);
return 1;
}
EVOKE_LOG("= "APPNAME" started =\n");
if(!pid_file)
pid_file = DEFAULT_PID;
if(!service->setup_pid(pid_file, LOCK_FILE)) {
EVOKE_LOG("Either another "APPNAME" instance is running or can't create pid file. Please correct this\n");
EVOKE_LOG("Note: if program abnormaly crashed before, just remove '%s' and start it again\n", LOCK_FILE);
EVOKE_LOG("= "APPNAME" abrupted shutdown =\n");
return 1;
}
if(!config_file)
config_file = CONFIG_FILE; // TODO: XDG paths
if(do_startup) {
if(!service->init_splash(config_file, no_splash, do_dryrun)) {
EVOKE_LOG("Unable to read correctly %s. Please check it is correct config file\n", config_file);
EVOKE_LOG("= "APPNAME" abrupted shutdown =\n");
return 1;
}
}
if(do_autostart || do_autostart_safe) {
service->init_autostart(do_autostart_safe);
}
service->setup_atoms(fl_display);
service->init_xsettings_manager();
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
service->start();
XSelectInput(fl_display, RootWindow(fl_display, fl_screen), PropertyChangeMask | SubstructureNotifyMask | ClientMessage);
/*
* Register event listener and run in infinite loop. Loop will be
* interrupted from one of the received signals.
*
* I choose to use fltk for this since wait() will nicely pool events
* and pass expecting ones to xmessage_handler(). Other (non-fltk) solution would
* be to manually pool events via select() and that code could be very messy.
* So stick with the simplicity :)
*
* Also note that '1' parameter means POLLIN, and for the details see Fl_x.cxx
*/
Fl::add_fd(ConnectionNumber(fl_display), 1, xmessage_handler);
while(service->running())
Fl::wait(FOREVER);
EVOKE_LOG("= "APPNAME" nice shutdown =\n");
return 0;
}