/* * $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 #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "EvokeService.h" #include "Splash.h" #include "Logout.h" #include "Xsm.h" #include "Xshutdown.h" EDELIB_NS_USING(Config) EDELIB_NS_USING(Resource) EDELIB_NS_USING(EdbusMessage) EDELIB_NS_USING(EdbusConnection) EDELIB_NS_USING(EdbusError) EDELIB_NS_USING(EDBUS_SESSION) EDELIB_NS_USING(EDBUS_SYSTEM) EDELIB_NS_USING(RES_SYS_ONLY) EDELIB_NS_USING(file_remove) EDELIB_NS_USING(file_test) EDELIB_NS_USING(str_trim) EDELIB_NS_USING(run_sync) EDELIB_NS_USING(alert) EDELIB_NS_USING(FILE_TEST_IS_REGULAR) #ifdef USE_LOCAL_CONFIG # define CONFIG_GET_STRVAL(object, section, key, buff) object.get(section, key, buff, sizeof(buff)) #else # define CONFIG_GET_STRVAL(object, section, key, buff) object.get(section, key, buff, sizeof(buff), RES_SYS_ONLY) #endif /* stolen from xfce's xfsm-shutdown-helper */ #if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) # define POWEROFF_CMD "/sbin/shutdown -p now" # define REBOOT_CMD "/sbin/shutdown -r now" #elif defined(sun) || defined(__sun) # define POWEROFF_CMD "/usr/sbin/shutdown -i 5 -g 0 -y" # define REBOOT_CMD "/usr/sbin/shutdown -i 6 -g 0 -y" #else # define POWEROFF_CMD "/sbin/shutdown -h now" # define REBOOT_CMD "/sbin/shutdown -r now" #endif static Atom XA_EDE_EVOKE_SHUTDOWN_ALL; static Atom XA_EDE_EVOKE_QUIT; static int get_int_property_value(Atom at) { Atom real; int format; unsigned long n, extra; unsigned char* prop; int status = XGetWindowProperty(fl_display, RootWindow(fl_display, fl_screen), at, 0L, 0x7fffffff, False, XA_CARDINAL, &real, &format, &n, &extra, (unsigned char**)&prop); int ret = -1; if(status != Success && !prop) return ret; ret = int(*(long*)prop); XFree(prop); return ret; } static void send_dbus_ede_quit(void) { EdbusConnection c; E_RETURN_IF_FAIL(c.connect(EDBUS_SESSION)); EdbusMessage msg; msg.create_signal("/org/equinoxproject/Shutdown", "org.equinoxproject.Shutdown", "Shutdown"); c.send(msg); } static bool do_shutdown_or_restart(bool restart) { #ifdef HAVE_HAL EdbusConnection c; if(!c.connect(EDBUS_SYSTEM)) { alert(_("Unable to connect to HAL daemon. Make sure both D-BUS and HAL daemons are running")); return false; } const char* hal_cmd = "Shutdown"; if(restart) hal_cmd = "Reboot"; EdbusMessage msg; msg.create_method_call("org.freedesktop.Hal", "/org/freedesktop/Hal/devices/computer", "org.freedesktop.Hal.Device.SystemPowerManagement", hal_cmd); EdbusMessage ret; if(!c.send_with_reply_and_block(msg, 100, ret)) { EdbusError* err = c.error(); if(err && err->valid()) { if(strcmp(err->name(), "org.freedesktop.DBus.Error.AccessDenied") == 0) { alert(_("Unable to send a message to HAL.\n\n" "Make sure you have permissions to restart and shutdown " "the computer with HAL daemon")); return false; } else if(strcmp(err->name(), "org.freedesktop.DBus.Error.NoReply") == 0) { /* 'Reboot' do not send reply and that is considered as error from D-BUS daemon */ return true; } else { /* just print whatever error was received */ alert("%s\n\n%s", err->name(), err->message()); return false; } } alert(_("Unable to send a message to HAL and unable to find out the reasons for that")); return false; } #else int ret = 0; const char* cmd = _("restart"); if(restart) { ret = run_sync(REBOOT_CMD); } else { ret = run_sync(POWEROFF_CMD); cmd = _("shutdown"); } if(ret) { alert(_("Unable to %s the computer. Probably you do not have enough permissions to do that"), cmd); return false; } #endif return true; } EvokeService::EvokeService() : lock_name(NULL), xsm(NULL), is_running(false) { /* TODO: or add setup_atoms() function */ XA_EDE_EVOKE_SHUTDOWN_ALL = XInternAtom(fl_display, "_EDE_EVOKE_SHUTDOWN_ALL", False); XA_EDE_EVOKE_QUIT = XInternAtom(fl_display, "_EDE_EVOKE_QUIT", False); } EvokeService::~EvokeService() { clear_startup_items(); stop_xsettings_manager(true); remove_lock(); } EvokeService* EvokeService::instance(void) { static EvokeService es; return &es; } bool EvokeService::setup_lock(const char* name) { if(file_test(name, FILE_TEST_IS_REGULAR)) return false; FILE* f = fopen(name, "w"); if(!f) return false; fclose(f); lock_name = strdup(name); return true; } void EvokeService::remove_lock(void) { if(!lock_name) return; file_remove(lock_name); free(lock_name); lock_name = NULL; } void EvokeService::clear_startup_items(void) { if(startup_items.empty()) return; StartupItemListIter it = startup_items.begin(), it_end = startup_items.end(); for(; it != it_end; ++it) delete *it; startup_items.clear(); } void EvokeService::read_startup(void) { #ifdef USE_LOCAL_CONFIG /* * this will load SETTINGS_FILENAME only from local directory; * intended for development and testing only */ Config c; int ret = c.load("ede-startup.conf"); #else /* only system resource will be loaded; use ede-startup will be skipped */ Resource c; int ret = c.load("ede-startup"); #endif if(!ret) { E_WARNING(E_STRLOC ": Unable to load EDE startup file\n"); return; } char tok_buff[256], buff[256]; /* if nothing found, exit */ if(!CONFIG_GET_STRVAL(c, "Startup", "start_order", tok_buff)) return; if(CONFIG_GET_STRVAL(c, "Startup", "splash_theme", buff)) splash_theme = buff; for(const char* sect = strtok(tok_buff, ","); sect; sect = strtok(NULL, ",")) { /* remove leading/ending spaces, if exists */ str_trim(buff); /* assure each startup item has 'exec' key */ if(!CONFIG_GET_STRVAL(c, sect, "exec", buff)) { E_WARNING(E_STRLOC ": Startup item '%s' does not have anything to execute. Skipping...\n", sect); continue; } StartupItem *s = new StartupItem; s->exec = buff; if(CONFIG_GET_STRVAL(c, sect, "icon", buff)) s->icon = buff; if(CONFIG_GET_STRVAL(c, sect, "description", buff)) s->description = buff; startup_items.push_back(s); } } void EvokeService::run_startup(bool splash, bool dryrun) { if(startup_items.empty()) return; Splash s(startup_items, splash_theme, splash, dryrun); s.run(); clear_startup_items(); } void EvokeService::start_xsettings_manager(void) { xsm = new Xsm; if(Xsm::manager_running(fl_display, fl_screen)) { int ret = edelib::ask(_("XSETTINGS manager already running on this screen. Would you like to replace it?")); if(ret < 1) { stop_xsettings_manager(false); return; } } if(!xsm->init(fl_display, fl_screen)) { edelib::alert(_("Unable to load XSETTINGS manager properly :-(")); stop_xsettings_manager(false); } E_RETURN_IF_FAIL(xsm); if(xsm->load_serialized()) xsm->notify(); } void EvokeService::stop_xsettings_manager(bool serialize) { if(!xsm) return; if(serialize) xsm->save_serialized(); delete xsm; xsm = NULL; } int EvokeService::handle(const XEvent* xev) { if(xsm && xsm->should_terminate(xev)) { E_DEBUG(E_STRLOC ": Terminating XSETTINGS manager on request by X event\n"); stop_xsettings_manager(true); return 1; } if(xev->xproperty.atom == XA_EDE_EVOKE_QUIT) { int val = get_int_property_value(XA_EDE_EVOKE_QUIT); if(val == 1) stop(); } if(xev->xproperty.atom == XA_EDE_EVOKE_SHUTDOWN_ALL) { int val = get_int_property_value(XA_EDE_EVOKE_SHUTDOWN_ALL); if(val == 1) { int dw = DisplayWidth(fl_display, fl_screen); int dh = DisplayHeight(fl_display, fl_screen); int ret = logout_dialog_show(dw, dh, LOGOUT_OPT_SHUTDOWN | LOGOUT_OPT_RESTART); if(ret == LOGOUT_RET_CANCEL) return 1; send_dbus_ede_quit(); switch(ret) { case LOGOUT_RET_RESTART: if(!do_shutdown_or_restart(true)) return 1; break; case LOGOUT_RET_SHUTDOWN: if(!do_shutdown_or_restart(false)) return 1; break; case LOGOUT_RET_LOGOUT: default: x_shutdown(); break; } stop(); } } return 0; }