Moving back an newer evoke

This commit is contained in:
Sanel Zukan 2009-02-19 08:12:29 +00:00
parent d0498c453d
commit 25119b834a
34 changed files with 2350 additions and 0 deletions

287
evoke/Autostart.cpp Normal file
View File

@ -0,0 +1,287 @@
/*
* $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.
*/
#include <string.h>
#include <stdlib.h>
#include <FL/Fl_Pixmap.H>
#include <FL/Fl_Check_Browser.H>
#include <FL/Fl_Button.H>
#include <FL/Fl_Window.H>
#include <FL/Fl_Box.H>
#include <FL/Fl.H>
#include <edelib/String.h>
#include <edelib/StrUtil.h>
#include <edelib/List.h>
#include <edelib/Util.h>
#include <edelib/DesktopFile.h>
#include <edelib/Directory.h>
#include <edelib/Nls.h>
#include <edelib/Debug.h>
#include <edelib/Run.h>
#include "Autostart.h"
#include "icons/warning.xpm"
EDELIB_NS_USING(String)
EDELIB_NS_USING(DesktopFile)
EDELIB_NS_USING(list)
EDELIB_NS_USING(dir_list)
EDELIB_NS_USING(system_config_dirs)
EDELIB_NS_USING(user_config_dir)
EDELIB_NS_USING(str_ends)
EDELIB_NS_USING(run_program)
#ifdef DEBUG_AUTOSTART_RUN
#define AUTOSTART_RUN(s) E_DEBUG("Executing %s\n", s)
#else
#define AUTOSTART_RUN(s) run_program(s, false)
#endif
struct DialogEntry {
String name;
String exec;
};
typedef list<String> StringList;
typedef list<String>::iterator StringListIter;
typedef list<DialogEntry*> DialogEntryList;
typedef list<DialogEntry*>::iterator DialogEntryListIter;
static Fl_Window* dialog_win;
static Fl_Check_Browser* cbrowser;
static Fl_Pixmap warnpix(warning_xpm);
static char* get_basename(const char* path) {
char* p = strrchr(path, '/');
if(p)
return (p + 1);
return (char*)path;
}
/*
* 'Remove' duplicate entries by looking at their basename
* (aka. filename, but ignoring directory path). Item is not actually removed from
* the list (will mess up list pointers, but this can be resolved), but data it points
* to is cleared, which is a sort of marker to caller to skip it. Dumb yes, but very simple.
*
* It will use brute force for lookup and 'removal' and (hopfully) it should not have
* a large impact on startup since, afaik, no one keeps hundreds of files in autostart
* directories (if keeps them, then that issue is not up to this program :-P).
*
* Alternative would be to sort items (by their basename) and apply consecutive unique on
* them, but... is it worth ?
*/
static void unique_by_basename(StringList& lst) {
if(lst.empty())
return;
StringListIter first, last, first1, last1;
first = lst.begin();
last = lst.end();
if(first == last)
return;
const char* p1, *p2;
for(; first != last; ++first) {
for(first1 = lst.begin(), last1 = lst.end(); first1 != last1; ++first1) {
p1 = (*first).c_str();
p2 = (*first1).c_str();
if(first != first1 && strcmp(get_basename(p1), get_basename(p2)) == 0)
(*first1).clear();
}
}
}
static void entry_list_run_clear(DialogEntryList& l, bool run) {
DialogEntryListIter dit = l.begin(), dit_end = l.end();
for(; dit != dit_end; ++dit) {
if(run)
AUTOSTART_RUN((*dit)->exec.c_str());
delete *dit;
}
l.clear();
}
static void dialog_runsel_cb(Fl_Widget*, void* e) {
DialogEntryList* lst = (DialogEntryList*)e;
E_ASSERT(lst->size() == (unsigned int)cbrowser->nitems() && "Size mismatch in local list and browser widget");
DialogEntryListIter it = lst->begin();
for(int i = 1; i <= cbrowser->nitems(); i++, ++it) {
if(cbrowser->checked(i))
AUTOSTART_RUN((*it)->exec.c_str());
}
dialog_win->hide();
entry_list_run_clear(*lst, false);
}
static void dialog_runall_cb(Fl_Widget*, void* e) {
DialogEntryList* lst = (DialogEntryList*)e;
E_DEBUG("%i != %i\n", lst->size(), cbrowser->nitems());
E_ASSERT(lst->size() == (unsigned int)cbrowser->nitems() && "Size mismatch in local list and browser widget");
dialog_win->hide();
entry_list_run_clear(*lst, true);
}
static void dialog_close_cb(Fl_Widget*, void* e) {
dialog_win->hide();
DialogEntryList* lst = (DialogEntryList*)e;
entry_list_run_clear(*lst, false);
}
static void run_autostart_dialog(DialogEntryList& l) {
DialogEntryList* ptr = (DialogEntryList*)&l;
dialog_win = new Fl_Window(370, 305, _("Autostart warning"));
dialog_win->begin();
Fl_Box* img = new Fl_Box(10, 10, 65, 60);
img->image(warnpix);
Fl_Box* txt = new Fl_Box(80, 10, 280, 60, _("The following applications are registered for starting. Please chose what to do next"));
txt->align(FL_ALIGN_INSIDE | FL_ALIGN_LEFT | FL_ALIGN_WRAP);
cbrowser = new Fl_Check_Browser(10, 75, 350, 185);
DialogEntryListIter it = l.begin(), it_end = l.end();
for(; it != it_end; ++it)
cbrowser->add((*it)->name.c_str());
Fl_Button* rsel = new Fl_Button(45, 270, 125, 25, _("Run &selected"));
rsel->callback(dialog_runsel_cb, ptr);
Fl_Button* rall = new Fl_Button(175, 270, 90, 25, _("&Run all"));
rall->callback(dialog_runall_cb, ptr);
Fl_Button* cancel = new Fl_Button(270, 270, 90, 25, _("&Cancel"));
cancel->callback(dialog_close_cb, ptr);
cancel->take_focus();
dialog_win->end();
dialog_win->show();
while(dialog_win->shown())
Fl::wait();
}
/*
* This is implementation of Autostart Spec
* (http://standards.freedesktop.org/autostart-spec/autostart-spec-0.5.html).
*
* The Autostart Directories are $XDG_CONFIG_DIRS/autostart.
* If the same filename is located under multiple Autostart Directories only the file under
* the most important directory should be used.
*
* Example: If $XDG_CONFIG_HOME is not set the Autostart Directory in the user's home directory
* is ~/.config/autostart/
* Example: If $XDG_CONFIG_DIRS is not set the system wide Autostart Directory is /etc/xdg/autostart/
* Example: If $XDG_CONFIG_HOME and $XDG_CONFIG_DIRS are not set and the two files
* /etc/xdg/autostart/foo.desktop and ~/.config/autostart/foo.desktop exist then only the file
* ~/.config/autostart/foo.desktop will be used because ~/.config/autostart/ is more important
* than /etc/xdg/autostart/.
*
* If Hidden key is set true in .desktop file, file MUST be ignored.
* OnlyShowIn and NotShowIn (list of strings identifying desktop environments) if (or if not)
* contains environment name, MUST not be started/not started.
* TryExec is same as for .desktop spec.
*/
void perform_autostart(bool safe) {
const char* autostart_dirname = "/autostart/";
String adir = edelib::user_config_dir();
adir += autostart_dirname;
StringList dfiles, sysdirs, tmp;
StringListIter it, it_end, tmp_it, tmp_it_end;
dir_list(adir.c_str(), dfiles, true);
system_config_dirs(sysdirs);
if(!sysdirs.empty()) {
for(it = sysdirs.begin(), it_end = sysdirs.end(); it != it_end; ++it) {
*it += autostart_dirname;
/*
* append content
* FIXME: too much of copying. There should be some way to merge list items
* probably via merge() member
*/
dir_list((*it).c_str(), tmp, true);
for(tmp_it = tmp.begin(), tmp_it_end = tmp.end(); tmp_it != tmp_it_end; ++tmp_it)
dfiles.push_back(*tmp_it);
}
}
if(dfiles.empty())
return;
/*
* Remove duplicates where first one seen have priority to be keept.
* This way is required by spec.
*
* Also handle this case (noted in spec):
* if $XDG_CONFIG_HOME/autostart/foo.desktop and $XDG_CONFIG_DIRS/autostart/foo.desktop
* exists, but $XDG_CONFIG_HOME/autostart/foo.desktop have 'Hidden = true',
* $XDG_CONFIG_DIRS/autostart/foo.autostart is ignored too.
*
* Latter is implied via unique_by_basename().
*/
unique_by_basename(dfiles);
const char* name;
char buff[1024];
DesktopFile df;
DialogEntryList entry_list;
for(it = dfiles.begin(), it_end = dfiles.end(); it != it_end; ++it) {
if((*it).empty())
continue;
name = (*it).c_str();
if(!str_ends(name, ".desktop"))
continue;
if(!df.load(name)) {
E_WARNING(E_STRLOC ": Can't load '%s'. Skipping...\n", name);
continue;
}
/* if Hidden key is set true in .desktop file, file MUST be ignored */
if(df.hidden())
continue;
if(!(df.try_exec(buff, sizeof(buff)) || df.exec(buff, sizeof(buff))))
continue;
DialogEntry* en = new DialogEntry;
en->exec = buff;
/* figure out the name */
if(df.name(buff, sizeof(buff)))
en->name = buff;
else
en->name = name;
entry_list.push_back(en);
}
if(safe)
run_autostart_dialog(entry_list);
else
entry_list_run_clear(entry_list, true);
}

18
evoke/Autostart.h Normal file
View File

@ -0,0 +1,18 @@
/*
* $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.
*/
#ifndef __AUTOSTART_H__
#define __AUTOSTART_H__
void perform_autostart(bool safe);
#endif

231
evoke/EvokeService.cpp Normal file
View File

@ -0,0 +1,231 @@
/*
* $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.
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <edelib/File.h>
#include <edelib/Debug.h>
#include <edelib/Config.h>
#include <edelib/Resource.h>
#include <edelib/StrUtil.h>
#include <edelib/MessageBox.h>
#include <edelib/Nls.h>
#include "EvokeService.h"
#include "Splash.h"
#include "Logout.h"
#include "Xsm.h"
EDELIB_NS_USING(Config)
EDELIB_NS_USING(Resource)
EDELIB_NS_USING(RES_SYS_ONLY)
EDELIB_NS_USING(file_exists)
EDELIB_NS_USING(file_remove)
EDELIB_NS_USING(str_trim)
#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
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;
}
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() {
E_DEBUG(E_STRLOC ": EvokeService::~EvokeService()\n");
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_exists(name))
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) {
E_DEBUG(E_STRLOC ": EvokeService::clear_startup_items()\n");
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/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);
logout_dialog_show(dw, dh, LOGOUT_OPT_SHUTDOWN | LOGOUT_OPT_RESTART);
}
}
return 0;
}

60
evoke/EvokeService.h Normal file
View File

@ -0,0 +1,60 @@
/*
* $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.
*/
#ifndef __EVOKESERVICE_H__
#define __EVOKESERVICE_H__
#include <FL/x.H>
#include <edelib/List.h>
#include <edelib/String.h>
struct StartupItem {
edelib::String exec;
edelib::String icon;
edelib::String description;
};
typedef edelib::list<StartupItem*> StartupItemList;
typedef edelib::list<StartupItem*>::iterator StartupItemListIter;
class Xsm;
class EvokeService {
private:
char* lock_name;
Xsm* xsm;
bool is_running;
StartupItemList startup_items;
edelib::String splash_theme;
void clear_startup_items(void);
public:
EvokeService();
~EvokeService();
static EvokeService* instance(void);
bool setup_lock(const char* name);
void remove_lock(void);
void start(void) { is_running = true; }
void stop(void) { is_running = false; }
bool running(void) { return is_running; }
void read_startup(void);
void run_startup(bool splash, bool dryrun);
int handle(const XEvent* xev);
void start_xsettings_manager(void);
void stop_xsettings_manager(bool serialize);
};
#endif

31
evoke/Jamfile Normal file
View File

@ -0,0 +1,31 @@
#
# $Id$
#
# Part of Equinox Desktop Environment (EDE).
# Copyright (c) 2009 EDE Authors.
#
# This program is licensed under terms of the
# GNU General Public License version 2 or newer.
# See COPYING for details.
SubDir TOP evoke ;
# use SIGHUP for now as default
ObjectC++Flags evoke.cpp : -DUSE_SIGHUP ;
SOURCE = evoke.cpp
EvokeService.cpp
Splash.cpp
Xsm.cpp
Logout.cpp
Autostart.cpp ;
#ObjectC++Flags $(SOURCE) : -DUSE_LOCAL_CONFIG ;
EdeProgram evoke : $(SOURCE) ;
TranslationStrings locale : $(SOURCE) ;
EdeManual doc/evoke.txt ;
FltkProgramBare test/evoke_test : test/evoke_test.cpp : "noinstall" ;
SubInclude TOP evoke splash-themes ;

95
evoke/Logout.cpp Normal file
View File

@ -0,0 +1,95 @@
/*
* $Id$
*
* Evoke, head honcho of everything
* Part of Equinox Desktop Environment (EDE).
* Copyright (c) 2008-2009 EDE Authors.
*
* This program is licensed under terms of the
* GNU General Public License version 2 or newer.
* See COPYING for details.
*/
#include <FL/Fl_Window.H>
#include <FL/Fl_Box.H>
#include <FL/Fl_Button.H>
#include <FL/Fl_Choice.H>
#include <FL/Fl.H>
#include <edelib/Nls.h>
#include "Logout.h"
/* Note that order of initialized items is important so LOGOUT_OPT_XXX can work */
struct LogoutOptions {
const char* opt_short;
const char* opt_long;
} logout_options[] = {
{ _("Logout"), _("This option will close all programs and logs out from the current session") },
{ _("Restart"), _("This option will restart the computer closing all running programs") },
{ _("Shut down"), _("This option will shut down the computer closing all running programs") }
};
static Fl_Window* win;
static Fl_Box* description;
static int ret_option;
static void ok_cb(Fl_Widget*, void*) {
win->hide();
}
static void cancel_cb(Fl_Widget*, void*) {
ret_option = LOGOUT_RET_CANCEL;
win->hide();
}
static void option_cb(Fl_Widget*, void* o) {
Fl_Choice* c = (Fl_Choice*)o;
int v = c->value();
description->label(logout_options[v].opt_long);
ret_option = v;
}
int logout_dialog_show(int screen_w, int screen_h, int opt) {
ret_option = LOGOUT_RET_LOGOUT;
win = new Fl_Window(335, 180, _("Quit EDE?"));
win->begin();
Fl_Box* b1 = new Fl_Box(10, 9, 315, 25, _("How do you want to quit EDE?"));
b1->labelfont(1);
b1->align(196|FL_ALIGN_INSIDE);
Fl_Choice* c = new Fl_Choice(10, 45, 315, 25);
c->down_box(FL_BORDER_BOX);
/* fill choice menu */
c->add(logout_options[0].opt_short, 0, option_cb, c);
if(opt & LOGOUT_OPT_RESTART)
c->add(logout_options[1].opt_short, 0, option_cb, c);
if(opt & LOGOUT_OPT_SHUTDOWN)
c->add(logout_options[2].opt_short, 0, option_cb, c);
description = new Fl_Box(10, 80, 315, 55);
description->align(197|FL_ALIGN_INSIDE);
/* set to first menu item */
c->value(0);
description->label(logout_options[0].opt_long);
Fl_Button* ok = new Fl_Button(140, 145, 90, 25, _("&OK"));
ok->callback(ok_cb, c);
Fl_Button* cancel = new Fl_Button(235, 145, 90, 25, _("&Cancel"));
cancel->callback(cancel_cb);
win->end();
/* so when X in titlebar was clicked, we can get LOGOUT_RET_CANCEL */
win->callback(cancel_cb);
win->position(screen_w / 2 - win->w() / 2, screen_h / 2 - win->h() / 2);
win->show();
while(win->shown())
Fl::wait();
return ret_option;
}

26
evoke/Logout.h Normal file
View File

@ -0,0 +1,26 @@
/*
* $Id$
*
* Evoke, head honcho of everything
* Part of Equinox Desktop Environment (EDE).
* Copyright (c) 2008-2009 EDE Authors.
*
* This program is licensed under terms of the
* GNU General Public License version 2 or newer.
* See COPYING for details.
*/
#ifndef __LOGOUT_H__
#define __LOGOUT_H__
#define LOGOUT_RET_CANCEL -1
#define LOGOUT_RET_LOGOUT 0
#define LOGOUT_RET_RESTART 1
#define LOGOUT_RET_SHUTDOWN 2
#define LOGOUT_OPT_RESTART (1 << 1)
#define LOGOUT_OPT_SHUTDOWN (1 << 2)
int logout_dialog_show(int screen_w, int screen_h, int opt);
#endif

311
evoke/Splash.cpp Normal file
View File

@ -0,0 +1,311 @@
/*
* $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.
*/
#include <stdio.h> // snprintf
#include <FL/Fl_Shared_Image.H>
#include <FL/Fl.H>
#include <edelib/Debug.h>
#include <edelib/Nls.h>
#include <edelib/Util.h>
#include <edelib/Directory.h>
#include <edelib/Resource.h>
#include <edelib/Run.h>
#include "Splash.h"
#define TIMEOUT_START 0.5 /* timeout when splash is first time shown (also for first client) */
#define TIMEOUT_CONTINUE 2.0 /* timeout between starting rest of the cliens */
EDELIB_NS_USING(String)
EDELIB_NS_USING(Resource)
EDELIB_NS_USING(build_filename)
EDELIB_NS_USING(dir_exists)
EDELIB_NS_USING(run_program)
EDELIB_NS_USING(RES_SYS_ONLY)
#ifndef EDEWM_HAVE_NET_SPLASH
static Splash* global_splash = NULL;
static int splash_xmessage_handler(int e) {
if(fl_xevent->type == MapNotify) {
XRaiseWindow(fl_display, fl_xid(global_splash));
return 1;
}
if(fl_xevent->type == ConfigureNotify) {
if(fl_xevent->xconfigure.event == DefaultRootWindow(fl_display)) {
XRaiseWindow(fl_display, fl_xid(global_splash));
return 1;
}
}
return 0;
}
#endif
/*
* repeatedly call runner() until all clients are
* started then hide splash window
*/
static void runner_cb(void* s) {
Splash* sp = (Splash*)s;
if(sp->next_client())
Fl::repeat_timeout(TIMEOUT_CONTINUE, runner_cb, sp);
else
sp->hide();
}
Splash::Splash(StartupItemList& s, String& theme, bool show_it, bool dr) : Fl_Double_Window(480, 365) {
slist = &s;
splash_theme = &theme;
show_splash = show_it;
dryrun = dr;
icons = NULL;
counter = 0;
box(FL_BORDER_BOX);
}
Splash::~Splash() {
E_DEBUG(E_STRLOC ": Cleaning splash data\n");
/* elements of icons cleans Fl_Group */
delete [] icons;
Fl::remove_timeout(runner_cb);
}
/* after edewm got _NET_WM_WINDOW_TYPE_SPLASH support */
#if EDEWM_HAVE_NET_SPLASH
void Splash::show(void) {
if(shown())
return;
Fl_X::make_xid(this);
/*
* Edewm does not implement this for now. Alternative, working solution
* is used via register_top()/unregister_top(); also looks like later
* is working on othe wm's too.
*/
Atom win_type = XInternAtom(fl_display, "_NET_WM_WINDOW_TYPE", False);
Atom win_splash = XInternAtom(fl_display, "_NET_WM_WINDOW_TYPE_SPLASH", False);
XChangeProperty(fl_display, fl_xid(this), win_type, XA_ATOM, 32, PropModeReplace,
(unsigned char*)&win_splash, sizeof(Atom));
}
#endif
void Splash::run(void) {
E_ASSERT(slist != NULL);
if(!show_splash) {
while(next_client_nosplash())
;
return;
}
fl_register_images();
String path, splash_theme_path;
#ifdef USE_LOCAL_CONFIG
splash_theme_path = "splash-themes/";
#else
splash_theme_path = Resource::find_data("ede/splash-themes", RES_SYS_ONLY);
if(splash_theme_path.empty()) {
E_WARNING(E_STRLOC ": Unable to locate splash themes in $XDG_DATA_DIRS directories\n");
return;
}
#endif
splash_theme_path += E_DIR_SEPARATOR;
splash_theme_path += *splash_theme;
if(!dir_exists(splash_theme_path.c_str())) {
E_WARNING(E_STRLOC ": Unable to locate '%s' in '%s' theme directory\n",
splash_theme->c_str(), splash_theme_path.c_str());
return;
}
/* setup widgets */
begin();
Fl_Box* bimg = new Fl_Box(0, 0, w(), h());
Fl_Image* splash_img = 0;
path = build_filename(splash_theme_path.c_str(), "background.png");
splash_img = Fl_Shared_Image::get(path.c_str());
if(splash_img) {
int W = splash_img->w();
int H = splash_img->h();
/* update window and Box sizes */
size(W, H);
bimg->size(W, H);
bimg->image(splash_img);
}
/*
* place message box at the bottom with
* nice offset (10 px) from window borders
*/
msgbox = new Fl_Box(10, h() - 25 - 10, w() - 20, 25);
/*
* Setup icons positions, based on position of msgbox assuming someone
* will not abuse splash to start hundrets of programs, since icons will
* be placed only in horizontal order, one line, so in case their large
* number, some of them will go out of window borders.
*
* Icon box will be 64x64 so larger icons can fit too.
*
* This code will use Fl_Group (moving group, later, will move all icons
* saving me from code mess), but will not update it's w() for two reasons:
* icons does not use it, and will be drawn correctly, and second, setting
* width will initiate fltk layout engine which will mess everything up.
*/
Fl_Group* icon_group = new Fl_Group(10, msgbox->y() - 10 - 64, 0, 64);
int X = icon_group->x();
int Y = icon_group->y();
/* offset between icons */
int ioffset = 5;
/* FIXME: use malloc/something instead this */
icons = new Fl_Box*[slist->size()];
icon_group->begin();
int i = 0;
const char* imgpath;
Fl_Image* iconimg = 0;
for(StartupItemListIter it = slist->begin(); it != slist->end(); ++it, ++i) {
Fl_Box* bb = new Fl_Box(X, Y, 64, 64);
path = build_filename(splash_theme_path.c_str(), (*it)->icon.c_str());
imgpath = path.c_str();
iconimg = Fl_Shared_Image::get(imgpath);
if(!iconimg) {
bb->label(_("No image"));
bb->align(FL_ALIGN_INSIDE | FL_ALIGN_WRAP);
} else
bb->image(iconimg);
bb->hide();
X += bb->w() + ioffset;
icons[i] = bb;
}
icon_group->end();
/* see X as width of all icons */
int gx = w()/2 - X/2;
/* gx can be negative */
gx = (gx > 10) ? gx : 10;
icon_group->position(gx, Y);
end();
clear_border();
/*
* If set_override() is used, message boxes will be
* popped behind splash. Using it or not ???
*/
set_override();
// make sure window is centered
int sw = DisplayWidth(fl_display, fl_screen);
int sh = DisplayHeight(fl_display, fl_screen);
position(sw/2 - w()/2, sh/2 - h()/2);
show();
Fl::add_timeout(TIMEOUT_START, runner_cb, this);
// to keep splash at the top
#ifndef EDEWM_HAVE_NET_SPLASH
global_splash = this;
XSelectInput(fl_display, RootWindow(fl_display, fl_screen), SubstructureNotifyMask);
Fl::add_handler(splash_xmessage_handler);
#endif
while(shown())
Fl::wait();
#ifndef EDEWM_HAVE_NET_SPLASH
Fl::remove_handler(splash_xmessage_handler);
#endif
}
/* called when splash option is on */
bool Splash::next_client(void) {
if(slist->empty())
return false;
if(counter == 0)
slist_it = slist->begin();
if(slist_it == slist->end()) {
counter = 0;
return false;
}
E_ASSERT(counter < slist->size() && "Internal error; 'counter' out of bounds");
char buff[1024];
const char* msg = (*slist_it)->description.c_str();
const char* cmd = (*slist_it)->exec.c_str();
snprintf(buff, sizeof(buff), _("Starting %s..."), msg);
icons[counter]->show();
msgbox->copy_label(buff);
redraw();
/* run command */
if(!dryrun)
run_program(cmd, false);
++slist_it;
++counter;
return true;
}
/* called when splash option is off */
bool Splash::next_client_nosplash(void) {
if(slist->empty())
return false;
if(counter == 0)
slist_it = slist->begin();
if(slist_it == slist->end()) {
counter = 0;
return false;
}
E_ASSERT(counter < slist->size() && "Internal error; 'counter' out of bounds");
char buff[1024];
const char* msg = (*slist_it)->description.c_str();
const char* cmd = (*slist_it)->exec.c_str();
snprintf(buff, sizeof(buff), _("Starting %s..."), msg);
printf("%s\n", buff);
/* run command */
if(!dryrun)
run_program(cmd, false);
++slist_it;
++counter;
return true;
}

48
evoke/Splash.h Normal file
View File

@ -0,0 +1,48 @@
/*
* $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.
*/
#ifndef __SPLASH_H__
#define __SPLASH_H__
#include <FL/Fl_Double_Window.H>
#include <FL/Fl_Box.H>
#include "EvokeService.h"
class Splash : public Fl_Double_Window {
private:
StartupItemList* slist;
StartupItemListIter slist_it;
edelib::String* splash_theme;
unsigned int counter;
bool show_splash;
bool dryrun;
Fl_Box* msgbox;
Fl_Box** icons;
public:
Splash(StartupItemList& s, edelib::String& theme, bool show_it, bool dr);
~Splash();
bool next_client(void);
bool next_client_nosplash(void);
void run(void);
#if EDEWM_HAVE_NET_SPLASH
virtual void show(void);
#endif
};
#endif

375
evoke/Xsm.cpp Normal file
View File

@ -0,0 +1,375 @@
/*
* $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.
*/
#include <string.h>
#include <stdio.h>
#include <limits.h>
#include <FL/x.H>
#include <X11/Xresource.h>
#include <edelib/Debug.h>
#include <edelib/TiXml.h>
#include <edelib/Color.h>
#include <edelib/String.h>
#include <edelib/Util.h>
#include <edelib/Directory.h>
#include <edelib/XSettingsCommon.h>
#include <edelib/File.h>
#include <edelib/Resource.h>
#include "Xsm.h"
#define USER_XRESOURCE ".Xdefaults"
#define USER_XRESOURCE_TMP ".Xdefaults-tmp"
#define USER_XRESOURCE_SAVED ".Xdefaults-ede-saved"
#define SETTINGS_FILENAME "ede-settings"
EDELIB_NS_USING(String)
EDELIB_NS_USING(Resource)
EDELIB_NS_USING(XSettingsSetting)
EDELIB_NS_USING(XSettingsList)
EDELIB_NS_USING(dir_home)
EDELIB_NS_USING(file_remove)
EDELIB_NS_USING(file_rename)
EDELIB_NS_USING(build_filename)
EDELIB_NS_USING(user_config_dir)
EDELIB_NS_USING(xsettings_list_find)
EDELIB_NS_USING(xsettings_list_free)
EDELIB_NS_USING(xsettings_decode)
EDELIB_NS_USING(color_rgb_to_fltk)
EDELIB_NS_USING(color_fltk_to_html)
EDELIB_NS_USING(XSETTINGS_TYPE_COLOR)
EDELIB_NS_USING(XSETTINGS_TYPE_INT)
EDELIB_NS_USING(XSETTINGS_TYPE_STRING)
struct ResourceMap {
char* name;
char* xresource_key;
char* xresource_klass;
};
/*
* Make sure xresource_klass with '*' is listed last since it have
* highest priority and will override all previous classes (X Resource class, not C++ one :P)
* with the same xresource_key.
*/
static ResourceMap resource_map [] = {
{ "Fltk/Background2", "background", "*Text" },
{ "Fltk/Background", "background", "*" },
{ "Fltk/Foreground", "foreground", "*" }
};
#define RESOURCE_MAP_SIZE(x) (sizeof(x)/sizeof(x[0]))
static int ignore_xerrors(Display* display, XErrorEvent* xev) {
return True;
}
Xsm::Xsm() {
}
Xsm::~Xsm() {
E_DEBUG(E_STRLOC ": Xsm::~Xsm()\n");
}
/*
* This is a short explaination how evoke's XSETTINGS part is combined
* with X Resource database (xrdb). First of all, why mess with this? Almost
* all pure X apps (xterm, xedit, rxvt) reads color (and more) from xrdb, not to say
* that FLTK apps do that too, at least those not linked with edelib::Window. On other
* hand since edelib::Window already have builtin XSETTINGS and FLTK backend, you will
* that colors for edelib::Window will be specified twice, but this is not a big deal
* since painting is done only once.
*
* Here, in the code, we look for XSETTINGS names listed in resource_map[] and they should
* be colors only; when they are found, their equivalents will be created in xrdb as class/key
* (see X Resource manual about these).
*
* Values picked up from XSETTINGS color items will be converted to html since because clients
* who reads xrdb expects html colors (or X11 ones, like red/green/blue names, but let we not
* complicate). After conversion, everything is stored in ~/.Xdefaults file. If this file
* already exists (someone else made it), it will be first merged, picking old values and backed up.
*
* After evoke quits, file is restored, if existed before or deleted if not. This is also a
* workaround for missing functions to delete key/value pairs from xrdb (what was they thinking for??).
*/
void Xsm::xresource_replace(void) {
// with inheritance we got manager_data
if(!manager_data->settings)
return;
String home = dir_home();
// try to open ~/.Xdefaults; if failed, X Resource will not complain
String db_file = build_filename(home.c_str(), USER_XRESOURCE);
// initialize XResource manager
XrmInitialize();
// load XResource database
XrmDatabase db = XrmGetFileDatabase(db_file.c_str());
XSettingsSetting* s;
int status;
char* type, *value;
XrmValue xrmv;
char color_val[8];
String tmp;
/*
* XSETTINGS does not contains duplicate entries so there is no need to
* check for them. We only scan ResourceMap table for XSETTINGS name and
* its X Resource equivalent.
*/
for(unsigned int i = 0; i < RESOURCE_MAP_SIZE(resource_map); i++) {
s = xsettings_list_find(manager_data->settings, resource_map[i].name);
if(!s)
continue;
// assure that XSETTINGS key is color type
if(s->type != XSETTINGS_TYPE_COLOR) {
E_WARNING(E_STRLOC ": Expected color type in %s, but it is not, skipping...\n", s->name);
continue;
}
// check if resource is present
status = XrmGetResource(db, resource_map[i].xresource_key, resource_map[i].xresource_klass, &type, &xrmv);
if(status && strcmp(type, "String") == 0) {
E_DEBUG(E_STRLOC ": %s.%s found in database\n",
resource_map[i].xresource_klass, resource_map[i].xresource_key);
value = xrmv.addr;
}
/*
* Now convert color from XSETTINGS to html value. First convert to fltk color.
* TODO: Strange, didn't implemented something like color_rgb_to_html in edelib ?
*/
int fltk_color = color_rgb_to_fltk(s->data.v_color.red, s->data.v_color.green, s->data.v_color.blue);
color_fltk_to_html(fltk_color, color_val);
// and save it
tmp.clear();
tmp.printf("%s.%s: %s", resource_map[i].xresource_klass, resource_map[i].xresource_key, color_val);
XrmPutLineResource(&db, tmp.c_str());
}
String tmp_db_file = build_filename(home.c_str(), USER_XRESOURCE_TMP);
/*
* Try to merge existing ~/.Xdefaults (if present) with our changes. If there is existing
* key/values, they will be replaced with our. If XrmCombineFileDatabase() fails, this means
* there is no ~/.Xdefaults, so we don't need to backup it; opposite, backup it before we do
* final rename.
*/
status = XrmCombineFileDatabase(db_file.c_str(), &db, 0);
XrmPutFileDatabase(db, tmp_db_file.c_str());
XrmDestroyDatabase(db);
if(status) {
String db_backup = build_filename(home.c_str(), USER_XRESOURCE_SAVED);
file_rename(db_file.c_str(), db_backup.c_str());
}
file_rename(tmp_db_file.c_str(), db_file.c_str());
}
void Xsm::xresource_undo(void) {
String home, db_file_backup, db_file;
home = dir_home();
db_file_backup = build_filename(home.c_str(), USER_XRESOURCE_SAVED);
db_file = build_filename(home.c_str(), USER_XRESOURCE);
/*
* If we have backup, restore it; otherwise delete ~/.Xdefaults.
* TODO: what if user something write in it? Changes will be lost...
*/
if(!file_rename(db_file_backup.c_str(), db_file.c_str()))
file_remove(db_file.c_str());
}
bool Xsm::load_serialized(void) {
#ifdef USE_LOCAL_CONFIG
/*
* this will load SETTINGS_FILENAME only from local directory;
* intended for development and testing only
*/
String file = SETTINGS_FILENAME".conf";
#else
/* try to find it in home directory, then will scan for the system one */
String file = Resource::find_config("ede/"SETTINGS_FILENAME);
if(file.empty()) {
E_WARNING(E_STRLOC ": Unable to load XSETTINGS data from '%s'\n", file.c_str());
return false;
}
#endif
TiXmlDocument doc(file.c_str());
if(!doc.LoadFile())
return false;
const char* name = NULL, *type = NULL;
const char* v_string = NULL;
int v_int = 0;
int v_red = 0, v_green = 0, v_blue = 0, v_alpha = 0;
int cmp = 0;
TiXmlNode* elem = doc.FirstChild("ede-settings");
if(!elem)
return false;
for(elem = elem->FirstChildElement(); elem; elem = elem->NextSibling()) {
if(strcmp(elem->Value(), "setting") != 0) {
E_WARNING(E_STRLOC ": Got unknown child in 'ede-setting' %s\n", elem->Value());
continue;
}
name = elem->ToElement()->Attribute("name");
if(!name) {
E_WARNING(E_STRLOC ": Missing name key\n");
continue;
}
type = elem->ToElement()->Attribute("type");
if(!type) {
E_WARNING(E_STRLOC ": Missing type key\n");
continue;
}
if(strcmp(type, "int") == 0)
cmp = 1;
else if(strcmp(type, "string") == 0)
cmp = 2;
else if(strcmp(type, "color") == 0)
cmp = 3;
else {
E_WARNING(E_STRLOC ": Unknown type %s\n", type);
continue;
}
switch(cmp) {
case 1:
if(elem->ToElement()->QueryIntAttribute("value", &v_int) == TIXML_SUCCESS)
set(name, v_int);
else
E_WARNING(E_STRLOC ": Unable to query integer value\n");
break;
case 2:
v_string = elem->ToElement()->Attribute("value");
if(v_string)
set(name, v_string);
break;
case 3:
if((elem->ToElement()->QueryIntAttribute("red", &v_red) == TIXML_SUCCESS) &&
(elem->ToElement()->QueryIntAttribute("green", &v_green) == TIXML_SUCCESS) &&
(elem->ToElement()->QueryIntAttribute("blue", &v_blue) == TIXML_SUCCESS) &&
(elem->ToElement()->QueryIntAttribute("alpha", &v_alpha) == TIXML_SUCCESS)) {
set(name, v_red, v_green, v_blue, v_alpha);
}
break;
default:
break;
}
}
xresource_replace();
return true;
}
bool Xsm::save_serialized(void) {
Atom type;
int format;
unsigned long n_items, bytes_after;
unsigned char* data;
int result;
XSettingsList* settings = NULL, *iter = NULL;
int (*old_handler)(Display*, XErrorEvent*);
/* possible ? */
if(!manager_data->manager_win)
return false;
old_handler = XSetErrorHandler(ignore_xerrors);
result = XGetWindowProperty(manager_data->display, manager_data->manager_win, manager_data->xsettings_atom,
0, LONG_MAX, False, manager_data->xsettings_atom,
&type, &format, &n_items, &bytes_after, (unsigned char**)&data);
XSetErrorHandler(old_handler);
if(result == Success && type != None) {
if(type != manager_data->xsettings_atom)
E_WARNING(E_STRLOC ": Invalid type for XSETTINGS property\n");
else if(format != 8)
E_WARNING(E_STRLOC ": Invalid format for XSETTINGS property\n");
else
settings = xsettings_decode(data, n_items, NULL);
XFree(data);
}
if(!settings)
return false;
#ifdef USE_LOCAL_CONFIG
/*
* this will load SETTINGS_FILENAME only from local directory;
* intended for development and testing only
*/
String file = SETTINGS_FILENAME".conf";
#else
String file = user_config_dir();
file += "/ede/"SETTINGS_FILENAME".conf";
#endif
FILE* setting_file = fopen(file.c_str(), "w");
if(!setting_file) {
E_WARNING(E_STRLOC ": Unable to write to %s\n", file.c_str());
xsettings_list_free(settings);
return false;
}
fprintf(setting_file, "<? xml version=\"1.0\" encoding=\"UTF-8\" ?>\n");
fprintf(setting_file, "<ede-settings>\n");
iter = settings;
while(iter) {
fprintf(setting_file, " <setting name=\"%s\" ", iter->setting->name);
switch(iter->setting->type) {
case XSETTINGS_TYPE_INT:
fprintf(setting_file, "type=\"int\" value=\"%i\" />\n", iter->setting->data.v_int);
break;
case XSETTINGS_TYPE_STRING:
fprintf(setting_file, "type=\"string\" value=\"%s\" />\n", iter->setting->data.v_string);
break;
case XSETTINGS_TYPE_COLOR:
fprintf(setting_file, "type=\"color\" red=\"%i\" green=\"%i\" blue=\"%i\" alpha=\"%i\" />\n",
iter->setting->data.v_color.red,
iter->setting->data.v_color.green,
iter->setting->data.v_color.blue,
iter->setting->data.v_color.alpha);
break;
}
iter = iter->next;
}
fprintf(setting_file, "</ede-settings>\n");
fclose(setting_file);
xsettings_list_free(settings);
xresource_undo();
return true;
}

36
evoke/Xsm.h Normal file
View File

@ -0,0 +1,36 @@
/*
* $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.
*/
#ifndef __XSM_H__
#define __XSM_H__
#include <edelib/XSettingsManager.h>
/*
* XSETTINGS manager with serialization capability.
* Also it will write/undo to xrdb (X Resource database).
*/
class Xsm : public edelib::XSettingsManager {
public:
Xsm();
~Xsm();
bool load_serialized(void);
bool save_serialized(void);
/* replace XResource values from one from XSETTINGS */
void xresource_replace(void);
/* undo old XResource values */
void xresource_undo(void);
};
#endif

121
evoke/doc/evoke.txt Normal file
View File

@ -0,0 +1,121 @@
evoke documentation
===================
[NOTE]
.TODO
=====================
Add info about splash themes; reorder document
=====================
evoke is EDE service responsible for starting and quitting desktop, including
all needed prerequisites. Also, it will autostart programs (run programs using
http://www.freedesktop.org/wiki/Specifications/autostart-spec[autostart specification])
and behave as http://www.freedesktop.org/wiki/Specifications/xsettings-spec[XSETTINGS] manager.
It is usually started at EDE startup, from 'startede' script and will allow only one instance of
itself to be running.
Options
-------
-s, --startup::
Run in starup mode. Startup mode should be used when environment is
starting and it will read 'ede-startup.conf' file looking for components to
be started.
-n, --no-splash::
Do not display splash during startup. Only usefull if in startup mode
(given '-s' or '--startup').
-d, --dry-run::
Only useful in startup mode (if '-s' or '--startup' are given). Mainly to test
splash screen themes
-a, --autostart::
Run in autostart mode. It will check 'autostart' directory and run .desktop
files from it. This will be done according to freedesktop.org autostart specification.
-u, --autostart-safe::
Same as '-a' or '--autostart' option, but display dialog with items that should
be run.
-c, --config [FILE]::
Read [FILE] as config file. This file is only used in startup mode to read
components to be started.
-h, --help::
This help.
Details
-------
evoke can be started with or without options. If started without options, it will behave
as XSETTINGS manager, reading options from 'ede-settings.conf'.
[NOTE]
.XSETTINGS support
==================================
Not all toolkits supports XSETTINGS protocol; currently only Gtk+ and edelib apps understainds
it (as I know).
==================================
As you can see from options, there are two 'modes' (if parameteres for them are given):
* autstart mode
* startup mode
*Autostart mode* is used to run applications from 'autostart' directory. This directory is
usually located at $HOME/.config/autostart or if not exists, in /etc/xdg/autostart. Of course,
both directories can exists and evoke will run applications from both, but with one exception:
if application with the same .desktop name exists in both (and is valid desktop file), it will
be run only from prefered directory, which is $HOME/.config/autostart.
If you want some application to be run at EDE startup (implying evoke is started with '-a' option),
just copy it's .desktop file to autostart directory. Before that, make sure that .desktop file
confirms to http://freedesktop.org specification for Desktop Files.
On other hand if you want to disable running some application from autostart directory, you can
simply delete that file, or set this:
---------------
Hidden = true
---------------
Make sure that 'Hidden' key is under '[Desktop Entry]' section.
Autostart mode can be run in two ways: safe and unsafe. Safe way ('-u' or '--autostart-safe') will
popup window with programs that are 'registered' for starting, from where you can choose either to
start some of them, start all of them or to start nothing. On other hand, unsafe way ('-a' or '--autostart')
will simply run all 'registered' items without any questioning (should I say that this can be very insecure).
These options are intentionally provided so you can choose startup policy depending on your security
options.
*Startup mode* is meant to be used when EDE is starting, running each component (or program)
from 'ede-startup.conf' (or file specified with '-c' option). This configuration file must be in the following form:
--------------
[Startup]
# start_order key is used to notify evoke what to start
# and program keys must be separated with comma (if multiple ones are given)
start_order = program1, program2, program3
# splash_data is directory with icons used for splash screen
splash_data = /some/path/some_dir_name
# now comes each value from Startup key as separate key
[program1]
# Icon is icon used in splash screen progress (searched in ImagesDirectory)
Icon = icon1.png
# Exec is program executable to be run
Exec = program1
# Description is used to describe what is starting
Description = my cool program
[program2]
Icon = icon2.png
Exec = program2
Description = my cool second program
...
--------------

19
evoke/ede-settings.conf Normal file
View File

@ -0,0 +1,19 @@
<? xml version="1.0" encoding="UTF-8" ?>
<ede-settings>
<setting name="Fltk/Background" type="color" red="220" green="222" blue="227" alpha="0" />
<setting name="Fltk/Background2" type="color" red="239" green="239" blue="239" alpha="0" />
<setting name="Gtk/CanChangeAccels" type="int" value="0" />
<setting name="Gtk/CursorThemeName" type="string" value="default" />
<setting name="Gtk/CursorThemeSize" type="int" value="16" />
<setting name="Gtk/FontName" type="string" value="Sans 8" />
<setting name="Gtk/KeyThemeName" type="string" value="Default" />
<setting name="Gtk/ToolbarStyle" type="string" value="icons" />
<setting name="Net/Background/Normal" type="color" red="186" green="45" blue="23" alpha="0" />
<setting name="Net/CursorBlink" type="int" value="1" />
<setting name="Net/CursorBlinkTime" type="int" value="500" />
<setting name="Net/DndDragThreshold" type="int" value="8" />
<setting name="Net/DoubleClickTime" type="int" value="300" />
<setting name="Net/IconThemeName" type="string" value="edeneu" />
<setting name="Net/ThemeName" type="string" value="Raleigh" />
<setting name="Net/UserName" type="string" value="John Foo" />
</ede-settings>

24
evoke/ede-startup.conf Normal file
View File

@ -0,0 +1,24 @@
# ede-startup configuration sample
[Startup]
start_order = edewm,eiconman,eworkpanel,xscreensaver
splash_theme = scape
[edewm]
exec = edewm
icon = edewm.png
description = window manager
[eiconman]
exec = eiconman
icon = eiconman.png
description = desktop
[eworkpanel]
exec = eworkpanel
icon = eworkpanel.png
description = panel
[xscreensaver]
exec = xscreensaver -nosplash
icon = xscreensaver.png
description = screensaver

153
evoke/evoke.cpp Normal file
View File

@ -0,0 +1,153 @@
/*
* $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>
#include "EvokeService.h"
#include "Autostart.h"
#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");
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\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;
}
else if(CHECK_ARGV(a, "-s", "--starup"))
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)) {
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);
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);
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;
}

33
evoke/fl/autostart.fl Normal file
View File

@ -0,0 +1,33 @@
# data file for the Fltk User Interface Designer (fluid)
version 1.0108
header_name {.h}
code_name {.cxx}
Function {} {open selected
} {
Fl_Window {} {open
xywh {344 264 370 305} type Double visible
} {
Fl_Box {} {
label {The following applications are registered to be started. Please choose what to do next}
xywh {80 10 280 61} align 148
}
Fl_Check_Browser {} {
xywh {10 75 350 185} labelsize 14
}
Fl_Button {} {
label {&Cancel}
xywh {270 270 90 25}
}
Fl_Button {} {
label {&Run all}
xywh {175 270 90 25}
}
Fl_Button {} {
label {Run &selected}
xywh {45 270 125 25}
}
Fl_Box {} {
image {../icons/warning.xpm} xywh {10 10 65 61} labelsize 14
}
}
}

30
evoke/fl/logout.fl Normal file
View File

@ -0,0 +1,30 @@
# data file for the Fltk User Interface Designer (fluid)
version 1.0108
header_name {.h}
code_name {.cxx}
Function {} {open
} {
Fl_Window {} {open
xywh {479 284 335 180} type Double visible
} {
Fl_Box {} {
label {How do you want to quit?}
xywh {10 9 315 25} labelfont 1 align 212
}
Fl_Choice {} {open
xywh {10 45 315 25} down_box BORDER_BOX labelsize 14 textsize 14
} {}
Fl_Box {} {
label {This option will close all programs and logs out from the current session}
xywh {10 80 315 55} align 213
}
Fl_Button {} {
label {&OK} selected
xywh {140 145 90 25}
}
Fl_Button {} {
label {&Cancel}
xywh {235 145 90 25}
}
}
}

319
evoke/icons/warning.xpm Normal file
View File

@ -0,0 +1,319 @@
/* XPM */
static char * warning_xpm[] = {
"32 32 284 2",
" c None",
". c #D04D00",
"+ c #D24E00",
"@ c #C64900",
"# c #E37B00",
"$ c #D14E00",
"% c #D55600",
"& c #FCBF00",
"* c #EE9A00",
"= c #FFC700",
"- c #DA6500",
"; c #FFD32E",
"> c #FFFDCB",
", c #CB4C00",
"' c #F4AA02",
") c #FFF3AB",
"! c #FFFFE1",
"~ c #B44300",
"{ c #E37C00",
"] c #FFDE58",
"^ c #FFFFE0",
"/ c #FFFFDF",
"( c #FFDE56",
"_ c #F9BF0D",
": c #FFF9C3",
"< c #C6C6B8",
"[ c #969696",
"} c #FFF8C1",
"| c #BD4600",
"1 c #E99002",
"2 c #FFEA7C",
"3 c #EDEDD4",
"4 c #979797",
"5 c #989898",
"6 c #949494",
"7 c #D9D9C6",
"8 c #FFEA7A",
"9 c #E98F01",
"0 c #D85F00",
"a c #FFDA26",
"b c #FFFCCD",
"c c #E5E5C8",
"d c #C9C9B6",
"e c #FFFCCB",
"f c #FFD924",
"g c #C94B00",
"h c #F1AB01",
"i c #FFF292",
"j c #FFFFD3",
"k c #EBEBC7",
"l c #959595",
"m c #929292",
"n c #DCDCBC",
"o c #FFFFD1",
"p c #FFF28C",
"q c #DD7100",
"r c #FFE43F",
"s c #FFFEC5",
"t c #FFFFCB",
"u c #FFFFCC",
"v c #989894",
"w c #919191",
"x c #909090",
"y c #8E8E8E",
"z c #F8F8C6",
"A c #FFFFC7",
"B c #FFFEBF",
"C c #FFE236",
"D c #F9CC0A",
"E c #FFF99D",
"F c #FFFFC4",
"G c #FFFFC3",
"H c #B7B7A1",
"I c #8B8B8B",
"J c #8A8A8A",
"K c #9E9E93",
"L c #FFFFC1",
"M c #FFFFBE",
"N c #FFFFBC",
"O c #FFF892",
"P c #F9CB06",
"Q c #B84500",
"R c #E68D00",
"S c #FFEC51",
"T c #FFFFBA",
"U c #FFFFB9",
"V c #FFFFBB",
"W c #D1D1A6",
"X c #838383",
"Y c #B8B898",
"Z c #FFFFB6",
"` c #FFFFB3",
" . c #FFFFAF",
".. c #FFFFAB",
"+. c #FFEA43",
"@. c #D55700",
"#. c #FCDB13",
"$. c #FFFB97",
"%. c #FFFFAE",
"&. c #EEEEA8",
"*. c #7A7A7A",
"=. c #797979",
"-. c #DCDC9E",
";. c #FFFFA9",
">. c #FFFFA5",
",. c #FFFFA1",
"'. c #FFFF9E",
"). c #FFFB82",
"!. c #FCDA0C",
"~. c #EEAC00",
"{. c #FFF356",
"]. c #FFFFA4",
"^. c #FFFFA2",
"/. c #FFFFA3",
"(. c #8B8B79",
"_. c #6E6E6E",
":. c #FFFF9D",
"<. c #FFFF9B",
"[. c #FFFF98",
"}. c #FFFF93",
"|. c #FFFF8D",
"1. c #FFFF8B",
"2. c #FFF243",
"3. c #DA6B00",
"4. c #FFEB18",
"5. c #FFFE8A",
"6. c #FFFF92",
"7. c #FFFF94",
"8. c #A7A776",
"9. c #88886C",
"0. c #FFFF8A",
"a. c #FFFF87",
"b. c #FFFF82",
"c. c #FFFF7C",
"d. c #FFFF78",
"e. c #FFFD6D",
"f. c #FFEA0E",
"g. c #F4C400",
"h. c #FFF854",
"i. c #FFFF81",
"j. c #FFFF80",
"k. c #F4F47C",
"l. c #E9E978",
"m. c #FFFF7A",
"n. c #FFFF77",
"o. c #FFFF73",
"p. c #FFFF6F",
"q. c #FFFF6B",
"r. c #FFFF65",
"s. c #FFFF62",
"t. c #FFF73A",
"u. c #E38A00",
"v. c #FFF21E",
"w. c #FFFF69",
"x. c #FFFF6E",
"y. c #FFFF6C",
"z. c #FFFF66",
"A. c #FFFF5F",
"B. c #FFFF5C",
"C. c #FFFF57",
"D. c #FFFF53",
"E. c #FFFF4D",
"F. c #FFFF4A",
"G. c #FFF111",
"H. c #D55800",
"I. c #F9DD01",
"J. c #FFFC43",
"K. c #FFFF58",
"L. c #FFFF5B",
"M. c #B5B54D",
"N. c #46463C",
"O. c #373737",
"P. c #9A9A44",
"Q. c #FFFF50",
"R. c #FFFF4C",
"S. c #FFFF49",
"T. c #FFFF45",
"U. c #FFFF40",
"V. c #FFFF3D",
"W. c #FFFF3A",
"X. c #FFFB29",
"Y. c #F9DD00",
"Z. c #E9A100",
"`. c #FFF819",
" + c #FFFF41",
".+ c #FFFF43",
"++ c #FFFF48",
"@+ c #FFFF47",
"#+ c #FFFF46",
"$+ c #3C3C31",
"%+ c #2E2E2E",
"&+ c #2C2C2C",
"*+ c #292929",
"=+ c #E4E43A",
"-+ c #FFFF39",
";+ c #FFFF37",
">+ c #FFFF33",
",+ c #FFFF30",
"'+ c #FFFF2C",
")+ c #FFFF29",
"!+ c #FFFF27",
"~+ c #FFF70D",
"{+ c #D86300",
"]+ c #FCED05",
"^+ c #FFFE25",
"/+ c #FFFF2D",
"(+ c #FFFF32",
"_+ c #FFFF31",
":+ c #323225",
"<+ c #232323",
"[+ c #202020",
"}+ c #1E1E1E",
"|+ c #E3E326",
"1+ c #FFFF25",
"2+ c #FFFF22",
"3+ c #FFFF20",
"4+ c #FFFF1E",
"5+ c #FFFF1B",
"6+ c #FFFF19",
"7+ c #FFFF17",
"8+ c #FFFE13",
"9+ c #FCED02",
"0+ c #C54900",
"a+ c #F1C500",
"b+ c #FFFB0E",
"c+ c #FFFF1A",
"d+ c #FFFF1D",
"e+ c #FFFF1F",
"f+ c #A9A91C",
"g+ c #191919",
"h+ c #181818",
"i+ c #6E6E16",
"j+ c #FFFF14",
"k+ c #FFFF13",
"l+ c #FFFF11",
"m+ c #FFFF0F",
"n+ c #FFFF0D",
"o+ c #FFFF0B",
"p+ c #FFFF0A",
"q+ c #FFFF08",
"r+ c #FFFB04",
"s+ c #DD7A00",
"t+ c #FFFE00",
"u+ c #FFFE0F",
"v+ c #FFFF15",
"w+ c #FFFF16",
"x+ c #FFFF12",
"y+ c #FFFF10",
"z+ c #FFFF0E",
"A+ c #FFFF0C",
"B+ c #FFFF09",
"C+ c #FFFF07",
"D+ c #FFFF06",
"E+ c #FFFF05",
"F+ c #FFFE02",
"G+ c #E08500",
"H+ c #F4D300",
"I+ c #F5D50C",
"J+ c #F5D50D",
"K+ c #F5D50E",
"L+ c #F5D60F",
"M+ c #F5D610",
"N+ c #F4D50B",
"O+ c #F4D509",
"P+ c #F4D408",
"Q+ c #F4D407",
"R+ c #F4D406",
"S+ c #F4D405",
"T+ c #F4D404",
"U+ c #F4D403",
"V+ c #F4D302",
"W+ c #F4D301",
"X+ c #CA4B00",
"Y+ c #D35104",
"Z+ c #D35307",
"`+ c #D35408",
" @ c #D45409",
".@ c #D4550A",
"+@ c #D35206",
"@@ c #D35105",
"#@ c #D35003",
"$@ c #D24F02",
"%@ c #D24F01",
"&@ c #B14200",
" ",
" ",
" . + + @ ",
" + # # + ",
" $ % & & % @ ",
" + * = = * + ",
" $ - ; > > ; - , ",
" . + ' ) ! ! ) ' + ~ ",
" $ { ] ^ / / / ( { . ",
" . % _ : < [ [ < } _ % | ",
" + 1 2 3 [ 4 5 6 7 8 9 + ",
" $ 0 a b c [ [ [ 6 d e f 0 g ",
" + h i j k l l 6 m n o p h + ",
" + q r s t u v w x y z A B C q . ",
" . + D E F G F H I J K L M N O P + Q ",
" + R S T U T V W X X Y Z ` ...+.R + ",
" $ @.#.$. .%. . .&.*.=.-.;.>.,.'.).!.@.@ ",
" + ~.{.].,.,.^./.,.(._.:.<.[.}.|.1.2.~.+ ",
" $ 3.4.5.6.6.7.7.7.6.8.9.|.0.a.b.c.d.e.f.3., ",
" . + g.h.i.j.i.b.b.i.i.k.l.m.n.o.p.q.r.s.t.g.+ ~ ",
" $ u.v.w.q.x.x.p.x.x.y.q.w.z.s.A.B.C.D.E.F.G.u.. ",
" . H.I.J.C.K.L.B.B.L.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.H.| ",
" + Z.`. +.+T.++++++@+#+$+%+&+*+=+-+;+>+,+'+)+!+~+Z.+ ",
" $ {+]+^+/+,+(+(+(+(+(+_+:+<+[+}+|+1+2+3+4+5+6+7+8+9+{+0+ ",
" + a+b+c+5+d+e+e+3+3+e+e+f+g+h+i+7+j+k+l+m+n+o+p+q+r+a++ ",
"$ s+t+u+k+j+v+w+7+w+7+v+v+j+k+x+y+m+z+A+A+B+q+C+D+E+F+t+s+, ",
"+ G+H+I+J+K+L+L+M+M+M+L+L+K+J+J+N+O+O+P+Q+R+S+T+U+V+W+H+G++ ",
"X++ + Y+Z+`+`+ @.@.@ @ @ @`+`+Z++@@@+@@@Y+Y+#@$@%@%@%@+ + &@ ",
" ",
" ",
" ",
" "};

View File

@ -0,0 +1,14 @@
#
# $Id$
#
# Part of Equinox Desktop Environment (EDE).
# Copyright (c) 2009 EDE Authors.
#
# This program is licensed under terms of the
# GNU General Public License version 2 or newer.
# See COPYING for details.
SubDir TOP evoke splash-themes ;
SubInclude TOP evoke splash-themes scape ;
SubInclude TOP evoke splash-themes standard ;

View File

@ -0,0 +1,14 @@
#
# $Id$
#
# Part of Equinox Desktop Environment (EDE).
# Copyright (c) 2009 EDE Authors.
#
# This program is licensed under terms of the
# GNU General Public License version 2 or newer.
# See COPYING for details.
SubDir TOP evoke splash-themes scape ;
DATA = background.png background.xcf edewm.png eiconman.png eworkpanel.png xscreensaver.png ;
InstallData $(datarootdir)/splash-themes/scape : $(DATA) ;

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@ -0,0 +1,14 @@
#
# $Id$
#
# Part of Equinox Desktop Environment (EDE).
# Copyright (c) 2009 EDE Authors.
#
# This program is licensed under terms of the
# GNU General Public License version 2 or newer.
# See COPYING for details.
SubDir TOP evoke splash-themes standard ;
DATA = background.png edewm.png eiconman.png eworkpanel.png xscreensaver.png ;
InstallData $(datarootdir)/splash-themes/standard : $(DATA) ;

Binary file not shown.

After

Width:  |  Height:  |  Size: 162 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

63
evoke/test/evoke_test.cpp Normal file
View File

@ -0,0 +1,63 @@
#include <FL/Fl.H>
#include <FL/Fl_Double_Window.H>
#include <FL/Fl_Input.H>
#include <FL/Fl_Button.H>
#include <FL/x.H>
#include <string.h>
Fl_Input* inp;
Fl_Double_Window* win;
void run_cb(Fl_Widget*, void*) {
Atom _XA_EDE_EVOKE_SPAWN = XInternAtom(fl_display, "_EDE_EVOKE_SPAWN", False);
// max size
unsigned char txt_send[8192];
int i;
const char* txt_val = inp->value() ? inp->value() : "(none)";
int len = strlen(txt_val);
for(i = 0; i < 8192-2 && i < len; i++)
txt_send[i] = txt_val[i];
txt_send[i] = '\0';
// send text
XChangeProperty(fl_display, RootWindow(fl_display, fl_screen),
_XA_EDE_EVOKE_SPAWN, XA_STRING, 8, PropModeReplace,
txt_send, i + 1);
}
void evoke_quit_cb(Fl_Widget*, void*) {
Atom _XA_EDE_EVOKE_QUIT = XInternAtom(fl_display, "_EDE_EVOKE_QUIT", False);
int dummy = 1;
XChangeProperty(fl_display, RootWindow(fl_display, fl_screen),
_XA_EDE_EVOKE_QUIT, XA_CARDINAL, 32, PropModeReplace,
(unsigned char*)&dummy, sizeof(int));
}
void quit_all_cb(Fl_Widget*, void*) {
Atom _XA_EDE_EVOKE_SHUTDOWN_ALL = XInternAtom(fl_display, "_EDE_EVOKE_SHUTDOWN_ALL", False);
int dummy = 1;
XChangeProperty(fl_display, RootWindow(fl_display, fl_screen),
_XA_EDE_EVOKE_SHUTDOWN_ALL, XA_CARDINAL, 32, PropModeReplace,
(unsigned char*)&dummy, sizeof(int));
}
int main(int argc, char **argv) {
win = new Fl_Double_Window(355, 94, "Evoke test");
win->begin();
inp = new Fl_Input(10, 25, 335, 25, "Program to run:");
inp->align(FL_ALIGN_TOP_LEFT);
Fl_Button* b1 = new Fl_Button(255, 60, 90, 25, "&Run");
b1->callback(run_cb);
Fl_Button* b2 = new Fl_Button(150, 60, 90, 25, "&Quit evoke");
b2->callback(evoke_quit_cb);
Fl_Button* b3 = new Fl_Button(55, 60, 90, 25, "&Quit all");
b3->callback(quit_all_cb);
win->end();
win->show(argc, argv);
return Fl::run();
}

28
evoke/test/evoke_test.fl Normal file
View File

@ -0,0 +1,28 @@
# data file for the Fltk User Interface Designer (fluid)
version 1.0108
header_name {.h}
code_name {.cxx}
Function {} {open
} {
Fl_Window {} {
label {Evoke test} open
xywh {493 478 355 94} type Double visible
} {
Fl_Input {} {
label {Program to run:} selected
xywh {10 25 335 25} labelsize 14 align 5 textsize 14
}
Fl_Button {} {
label {&Run}
xywh {255 60 90 25} labelsize 14
}
Fl_Button {} {
label {&Quit evoke}
xywh {150 60 90 25} labelsize 14
}
Fl_Button {} {
label {&Quit all}
xywh {55 60 90 25} labelsize 14
}
}
}