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.
This commit is contained in:
Sanel Zukan
2007-09-18 14:06:09 +00:00
parent 00f5f2d59a
commit ad69c2fc2c
7 changed files with 265 additions and 11 deletions

View File

@ -19,7 +19,7 @@
#include "Autostart.h"
#include <edelib/File.h>
#include <edelib/Regex.h>
//#include <edelib/Regex.h>
#include <edelib/Config.h>
#include <edelib/DesktopFile.h>
#include <edelib/Directory.h>
@ -195,14 +195,17 @@ void service_watcher_cb(int pid, int signum) {
EvokeService::instance()->service_watcher(pid, signum);
}
EvokeService::EvokeService() : is_running(0), logfile(NULL), pidfile(NULL), lockfile(NULL) {
top_win = NULL;
EvokeService::EvokeService() :
is_running(0), logfile(NULL), xsm(NULL), pidfile(NULL), lockfile(NULL), top_win(NULL) {
}
EvokeService::~EvokeService() {
if(logfile)
delete logfile;
if(xsm)
delete xsm;
if(lockfile) {
edelib::file_remove(lockfile);
free(lockfile);
@ -434,6 +437,30 @@ void EvokeService::init_autostart(bool safe) {
dlg.run();
}
void EvokeService::init_xsettings_manager(void) {
xsm = new Xsm;
if(xsm->is_running()) {
int ret = edelib::ask(_("XSETTINGS manager already running on this screen. Would you like to replace it?"));
if(ret < 1) {
stop_xsettings_manager();
return;
} else
goto do_it;
}
do_it:
if(!xsm->init()) {
edelib::alert(_("Unable to load XSETTINGS manager properly"));
stop_xsettings_manager();
}
}
void EvokeService::stop_xsettings_manager(void) {
delete xsm;
xsm = NULL;
}
void EvokeService::setup_atoms(Display* d) {
// with them must be send '1' or property will be ignored (except _EDE_EVOKE_SPAWN)
_ede_shutdown_all = XInternAtom(d, "_EDE_EVOKE_SHUTDOWN_ALL", False);
@ -694,7 +721,10 @@ bool EvokeService::find_and_unregister_process(pid_t pid, EvokeProcess& pc) {
int EvokeService::handle(const XEvent* ev) {
logfile->printf("Got event %i\n", ev->type);
if(ev->type == MapNotify) {
if(xsm && xsm->should_quit(ev)) {
stop_xsettings_manager();
return 1;
} else if(ev->type == MapNotify) {
if(top_win) {
// for splash to keep it at top (working in old edewm)
XRaiseWindow(fl_display, fl_xid(top_win));

View File

@ -14,10 +14,12 @@
#define __EVOKESERVICE_H__
#include "Log.h"
#include "Xsm.h"
#include <edelib/List.h>
#include <edelib/String.h>
#include <FL/x.h>
#include <FL/x.h>
#include <pthread.h>
struct EvokeClient {
@ -46,6 +48,7 @@ class EvokeService {
private:
bool is_running;
Log* logfile;
Xsm* xsm;
char* pidfile;
char* lockfile;
@ -73,6 +76,9 @@ class EvokeService {
bool init_splash(const char* config, bool no_splash, bool dry_run);
void init_autostart(bool safe);
void init_xsettings_manager(void);
void stop_xsettings_manager(void);
int handle(const XEvent* ev);
Log* log(void) { return logfile; }

View File

@ -13,7 +13,7 @@ SubDir TOP evoke ;
# use SIGHUP for now as default
ObjectC++Flags evoke.cpp : -DUSE_SIGHUP ;
SOURCE = evoke.cpp EvokeService.cpp Spawn.cpp Splash.cpp Log.cpp Logout.cpp Crash.cpp Autostart.cpp ;
SOURCE = evoke.cpp EvokeService.cpp Xsm.cpp Spawn.cpp Splash.cpp Log.cpp Logout.cpp Crash.cpp Autostart.cpp ;
LinkAgainst evoke : -lao -lvorbis -lvorbisfile -lmad ;

View File

@ -26,7 +26,10 @@
#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
extern int xmessage_handler(int e);
int splash_xmessage_handler(int ev) {
return EvokeService::instance()->handle(fl_xevent);
}
/*
* repeatedly call runner() untill all clients are
@ -184,7 +187,7 @@ void Splash::run(void) {
* and redirect them to EvokeService::handle().
*/
XSelectInput(fl_display, RootWindow(fl_display, fl_screen), SubstructureNotifyMask);
Fl::add_handler(xmessage_handler);
Fl::add_handler(splash_xmessage_handler);
// make sure MappingNotify keeps this window at the top
EvokeService::instance()->register_top(this);

154
evoke/Xsm.cpp Normal file
View File

@ -0,0 +1,154 @@
/*
* $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 "Xsm.h"
#include <edelib/Debug.h>
#include <FL/x.h>
#include <stdio.h> // snprintf
struct XsmData {
Window window;
Atom manager_atom;
Atom selection_atom;
Atom xsettings_atom;
unsigned long serial;
};
struct XsettingsColor {
unsigned char red, green, blue, alpha;
};
struct XsettingsSetting {
char* name;
XsettingsType type;
union {
int v_int;
char* v_string;
XsettingsColor v_color;
} data;
unsigned long last_changed_serial;
};
struct TimeStampInfo {
Window window;
Atom timestamp_prop_atom;
};
// Bool (X type) is used since this function is going to XIfEvent()
Bool timestamp_predicate(Display* dpy, XEvent* xev, XPointer arg) {
TimeStampInfo* info = (TimeStampInfo*)arg;
if(xev->type == PropertyNotify &&
xev->xproperty.window == info->window &&
xev->xproperty.atom == info->timestamp_prop_atom) {
return True;
}
return False;
}
Time get_server_time(Display* dpy, Window win) {
unsigned char c = 'a';
TimeStampInfo info;
XEvent xev;
info.timestamp_prop_atom = XInternAtom(dpy, "_TIMESTAMP_PROP", False);
info.window = win;
XChangeProperty(dpy, win, info.timestamp_prop_atom, info.timestamp_prop_atom,
8, PropModeReplace, &c, 1);
XIfEvent(dpy, &xev, timestamp_predicate, (XPointer)&info);
return xev.xproperty.time;
}
Xsm::Xsm() : data(NULL) { }
Xsm::~Xsm() {
if(data) {
XDestroyWindow(fl_display, data->window);
delete data;
}
puts("Xsm::~Xsm()");
}
bool Xsm::is_running(void) {
char buff[256];
snprintf(buff, sizeof(buff)-1, "_XSETTINGS_S%d", fl_screen);
Atom selection = XInternAtom(fl_display, buff, False);
if(XGetSelectionOwner(fl_display, selection))
return true;
return false;
}
bool Xsm::init(void) {
char buff[256];
data = new XsmData;
snprintf(buff, sizeof(buff)-1, "_XSETTINGS_S%d", fl_screen);
data->selection_atom = XInternAtom(fl_display, buff, False);
data->xsettings_atom = XInternAtom(fl_display, "_XSETTINGS_SETTINGS", False);
data->manager_atom = XInternAtom(fl_display, "MANAGER", False);
data->serial = 0;
data->window = XCreateSimpleWindow(fl_display, RootWindow(fl_display, fl_screen),
0, 0, 10, 10, 0, WhitePixel(fl_display, fl_screen), WhitePixel(fl_display, fl_screen));
XSelectInput(fl_display, data->window, PropertyChangeMask);
Time timestamp = get_server_time(fl_display, data->window);
XSetSelectionOwner(fl_display, data->selection_atom, data->window, timestamp);
// check if we got ownership
if(XGetSelectionOwner(fl_display, data->selection_atom) == data->window) {
XClientMessageEvent xev;
xev.type = ClientMessage;
xev.window = RootWindow(fl_display, fl_screen);
xev.message_type = data->manager_atom;
xev.format = 32;
xev.data.l[0] = timestamp;
xev.data.l[1] = data->selection_atom;
xev.data.l[2] = data->window;
xev.data.l[3] = 0; // manager specific data
xev.data.l[4] = 0; // manager specific data
XSendEvent(fl_display, RootWindow(fl_display, fl_screen), False, StructureNotifyMask, (XEvent*)&xev);
return true;
}
return false;
}
bool Xsm::should_quit(const XEvent* xev) {
EASSERT(data != NULL);
if(xev->xany.window == data->window &&
xev->xany.type == SelectionClear &&
xev->xselectionclear.selection == data->selection_atom) {
puts("XXXXXXXXXXXXX");
return true;
}
return false;
}

53
evoke/Xsm.h Normal file
View File

@ -0,0 +1,53 @@
/*
* $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.
*/
#ifndef __XSM_H__
#define __XSM_H__
#include <X11/Xlib.h> // XEvent
/*
* This is manager class for XSETTINGS protocol. XSETTINGS provides a mechanism
* for applications to share simple configuration settings like background
* colors no matter what toolkit is used. For now only gtk fully supports it
* and support for ede apps is going to be added.
*
* The protocol (0.5 version) is described at:
* http://standards.freedesktop.org/xsettings-spec/xsettings-spec-0.5.html
*
* This code is greatly based on xsettings referent implementation I found on
* freedesktop.org cvs, since specs are very unclear about the details.
* Author of referent implementation is Owen Taylor.
*/
enum XsettingsType {
XS_TYPE_INT = 0,
XS_TYPE_COLOR,
XS_TYPE_STRING
};
struct XsmData;
struct XsettingsSetting;
class Xsm {
private:
XsmData* data;
public:
Xsm();
~Xsm();
bool is_running(void);
bool init(void);
bool should_quit(const XEvent* xev);
};
#endif

View File

@ -40,8 +40,12 @@ void quit_signal(int sig) {
EvokeService::instance()->stop();
}
int xmessage_handler(int e) {
return EvokeService::instance()->handle(fl_xevent);
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) {
@ -165,6 +169,7 @@ int main(int argc, char** argv) {
}
service->setup_atoms(fl_display);
service->init_xsettings_manager();
signal(SIGINT, quit_signal);
signal(SIGTERM, quit_signal);
@ -193,8 +198,11 @@ int main(int argc, char** argv) {
* 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_handler(xmessage_handler);
Fl::add_fd(ConnectionNumber(fl_display), 1, xmessage_handler);
while(service->running())
Fl::wait(FOREVER);