A lot of changes, especially the ways how screen is repainted (in composite).

Composite will now draw only damaged regions, and their damage is (now) correctly
reported, mostly due changes in main FLTK loop.

Also there are two ways how evoke will be running: if USE_FLTK_LOOP_EMULATION
is defined (default yes), it will fully emulate FLTK loop (as done before). Oposite 
way (without emulation) it will relay on FLTK message passing, but it is very unpredictable 
since FLTK will sometime miss SelectionClear events (XSETTINGS relay on it), probably due
large XDamageNotify throttling. When emulation is used, there are no such problems
since all events are processed before they are routed to FLTK.

In composite is added another way of repainting (when USE_CHECK is defined), and it will
relay on Fl::add_check() function; there are some differences between this function
and timer used for screen refresh. Timer will try to refresh it every XX ms and when
there are large number of XDamageNotify reports, this will not be suitable for 
movements smoothing on the screen; on other hand add_check() will call callback every
time when event is processed, which brings smooth movements. For now only timer is used
untill I finish compositing stuff.

Also composite will handle messages from it's own add_handler() since (somehow), all pending
XDamageNotify events will not be correctly reported inside EvokeService handler.

And about splash... splash will now keep it's window at the top, no matter what window is
raised. This is a small hack until I implement _NET_WM_WINDOW_TYPE_SPLASH in edewm (I don't
have to say that this hack works for all wm's I tested :P).

Sound from splash is removed; reason for this is when evoke starts childs (only when X session
was started), device descriptors will be used by childs too making sound device unusable and 
marked as busy. This can be solved by using better sound library, which is story for itself...
This commit is contained in:
Sanel Zukan 2008-01-14 12:50:30 +00:00
parent d0eab95b75
commit 7ff8841ea8
9 changed files with 254 additions and 118 deletions

View File

@ -78,6 +78,8 @@ void AstartDialog::add_item(const edelib::String& n, const edelib::String& e) {
lst[curr++] = it;
}
#include <stdio.h>
#include <unistd.h>
void AstartDialog::run(void) {
if(!show_dialog) {
@ -91,8 +93,10 @@ void AstartDialog::run(void) {
if(!shown())
show();
while(shown())
while(shown()) {
//puts("WAIT WAIT");
Fl::wait();
}
}
void AstartDialog::run_selected(void) {

View File

@ -110,17 +110,32 @@ double shadowOpacity = .75;
bool hasNamePixmap = true;
Composite* global_composite;
#define DO_BETTER_REPAINT 1
void idle_cb(void* c) {
Composite* comp = (Composite*)c;
#ifdef DO_BETTER_REPAINT
if(allDamage != None) {
comp->paint_all(allDamage);
XFixesDestroyRegion(fl_display, allDamage);
allDamage = None;
clipChanged = false;
}
#else
comp->paint_all(allDamage);
allDamage = None;
clipChanged = false;
if(allDamage != None) {
XFixesDestroyRegion(fl_display, allDamage);
allDamage = None;
clipChanged = false;
}
#endif
#ifndef USE_CHECK
Fl::repeat_timeout(REFRESH_TIMEOUT, idle_cb, c);
#endif
}
int xerror_handler(Display* display, XErrorEvent* xev) {
@ -170,8 +185,8 @@ int xerror_handler(Display* display, XErrorEvent* xev) {
break;
}
EDEBUG(ESTRLOC ": (%s) : error %i request %i minor %i serial %i\n",
(name ? name : "unknown"), xev->error_code, xev->request_code, xev->minor_code, xev->serial);
//EDEBUG(ESTRLOC ": (%s) : error %i request %i minor %i serial %i\n",
// (name ? name : "unknown"), xev->error_code, xev->request_code, xev->minor_code, xev->serial);
#if 0
char buff[128];
@ -218,11 +233,11 @@ unsigned int get_opacity_property(CWindow* win, unsigned int dflt) {
// TODO: replace memcpy call
memcpy(&p, data, sizeof(unsigned int));
XFree(data);
EDEBUG(":) Opacity for %i = %i\n", win->id, p);
// EDEBUG(":) Opacity for %i = %i\n", win->id, p);
return p;
}
EDEBUG("Opacity for %i = %i\n", win->id, dflt);
//EDEBUG("Opacity for %i = %i\n", win->id, dflt);
return dflt;
}
@ -232,14 +247,6 @@ double get_opacity_percent(CWindow* win, double dflt) {
return opacity * 1.0 / OPAQUE;
}
const char* get_window_label(Window win) {
XTextProperty tp;
if(XGetWMName(fl_display, win, &tp) != 0)
return (const char*)tp.value;
else
return "(none)";
}
Atom get_window_type_property(Window win) {
Atom actual;
int format;
@ -270,7 +277,7 @@ Atom determine_window_type(Window win) {
Window* children = NULL;
unsigned int nchildren;
if(!XQueryTree(fl_display, win, &root_return, &parent_return, &children, &nchildren)) {
if(XQueryTree(fl_display, win, &root_return, &parent_return, &children, &nchildren) != 0) {
if(children)
XFree(children);
return _XA_NET_WM_WINDOW_TYPE_NORMAL;
@ -288,7 +295,7 @@ Atom determine_window_type(Window win) {
}
void add_damage(XserverRegion damage) {
if(allDamage) {
if(allDamage != None) {
XFixesUnionRegion(fl_display, allDamage, allDamage, damage);
XFixesDestroyRegion(fl_display, damage);
} else
@ -429,13 +436,23 @@ Composite::Composite() : manual_redirect(true) {
Composite::~Composite() {
EDEBUG("Composite::~Composite()\n");
#ifdef USE_CHECK
Fl::remove_check(idle_cb);
#else
Fl::remove_timeout(idle_cb);
#endif
// TODO: this part should call finish_destroy_window()
CWindowListIter it = window_list.begin(), it_end = window_list.end();
while(it != it_end) {
delete *it;
++it;
}
}
bool Composite::init(void) {
another_is_running = false;
global_composite = this;
// set error handler first
XSetErrorHandler(xerror_handler);
@ -528,8 +545,21 @@ bool Composite::init(void) {
* since window_list will be empty
*/
if(manual_redirect) {
paint_all(None); // XXX: probably not needed since will be called in idle_cb()
paint_all(None);
/*
* Using add_check() instead add_timeout() makes difference in redrawing
* since add_check() callback function will be called before FLTK flushes
* the display which makes it very suitable for smooth redrawing.
*
* On other hand, using add_timeout() will trigger timer each REFRESH_TIMEOUT
* no matter for pending events (especially XDamageNotifyEvent) and due that
* timeout we can miss some XDamage events, yielding little bit non-smooth redrawing.
*/
#ifdef USE_CHECK
Fl::add_check(idle_cb, this);
#else
Fl::add_timeout(REFRESH_TIMEOUT, idle_cb, this);
#endif
}
return true;
@ -557,7 +587,7 @@ void Composite::add_window(Window id, Window previous) {
new_win->damage = None;
} else {
new_win->damage_sequence = NextRequest(fl_display);
new_win->damage = XDamageCreate(fl_display, id, XDamageReportNonEmpty);
new_win->damage = XDamageCreate(fl_display, new_win->id, XDamageReportNonEmpty);
}
new_win->picture_alpha = None;
@ -565,10 +595,10 @@ void Composite::add_window(Window id, Window previous) {
new_win->border_size = None;
new_win->extents = None;
new_win->shadow = None;
new_win->shadow_dx = None;
new_win->shadow_dy = None;
new_win->shadow_w = None;
new_win->shadow_h = None;
new_win->shadow_dx = 0;
new_win->shadow_dy = 0;
new_win->shadow_w = 0;
new_win->shadow_h = 0;
new_win->opacity = get_opacity_property(new_win, OPAQUE);
new_win->border_clip = None;
@ -591,14 +621,15 @@ void Composite::map_window(Window id, unsigned long sequence, bool fade) {
win->attr.map_state = IsViewable;
// this needs to be here or we loose transparency messages
XSelectInput(fl_display, win->id, PropertyChangeMask);
//XSelectInput(fl_display, win->id, PropertyChangeMask);
XSelectInput(fl_display, win->id, PropertyChangeMask | win->attr.your_event_mask | StructureNotifyMask);
win->damaged = 0;
/*
* XXX: a hack, not present in xcompmgr due main event
* loop changes
*/
repair_window(win);
//repair_window(win);
// TODO: fading support
}
@ -747,7 +778,12 @@ void Composite::restack_window(CWindow* win, Window new_above) {
old_above = None;
else {
++it; // get the next one
old_above = (*it)->id;
// check again
if(it == it_end)
old_above = None;
else
old_above = (*it)->id;
}
if(old_above != new_above) {
@ -1008,9 +1044,9 @@ void Composite::paint_all(XserverRegion region) {
if(win->pixmap)
draw = win->pixmap;
#endif
XRenderPictureAttributes pa;
XRenderPictFormat* format = XRenderFindVisualFormat(fl_display, win->attr.visual);
XRenderPictureAttributes pa;
pa.subwindow_mode = IncludeInferiors;
win->picture = XRenderCreatePicture(fl_display, draw, format, CPSubwindowMode, &pa);
}
@ -1105,7 +1141,6 @@ void Composite::paint_all(XserverRegion region) {
// TODO: check this, xcompmgr have the same code for WIN_MODE_TRANS and WIN_MODE_ARGB
if(win->mode == WIN_MODE_TRANS || win->mode == WIN_MODE_ARGB) {
EDEBUG("!!!!!!!!!!!!!!!!!!!!!!!!!\n");
int x, y, wid, hei;
#if HAVE_NAME_WINDOW_PIXMAP
x = win->attr.x;
@ -1119,9 +1154,33 @@ void Composite::paint_all(XserverRegion region) {
hei = win->attr.height;
#endif
set_ignore(NextRequest(fl_display));
#if 0
XRenderComposite(fl_display, PictOpOver, win->picture, win->picture_alpha, rootBuffer,
0, 0, 0, 0,
x, y, wid, hei);
#endif
//////////////////////////////////////////
XRenderComposite(fl_display, PictOpOver, win->picture, win->picture_alpha, rootBuffer,
10, 0,
0, 0,
x+10, y, wid-10, 100);
// solid
XRenderComposite(fl_display, PictOpSrc, win->picture, None, rootBuffer,
10, 100,
0, 0,
x+10, y+100, wid-10, hei-100);
XRenderComposite(fl_display, PictOpSrc, win->picture, None, rootBuffer,
0, 0,
0, 0,
x, y, 10, hei);
//////////////////////////////////////////
}
// XXX: a lot of errors here ?
@ -1150,19 +1209,26 @@ void Composite::damage_window(XDamageNotifyEvent* de) {
CWindow* win = find_window(de->drawable);
if(!win)
return;
#if 0
// XXX: addon
while(XPending(fl_display)) {
XEvent ev;
if(XPeekEvent(fl_display, &ev) && ev.type == (damage_event + XDamageNotify) && ev.xany.window == win->id) {
XNextEvent(fl_display, &ev);
repair_window(win);
EDEBUG("XXXXXXXXXXXXX\n");
continue;
}
break;
}
#endif
repair_window(win);
}
void Composite::repair_window(CWindow* win) {
XserverRegion parts;
EDEBUG("Repairing %i (%i) (area: x:%i y:%i w:%i h:%i)\n", win->id, win->damaged,
win->attr.x,
win->attr.y,
win->attr.width,
win->attr.height);
if(!win->damaged) {
parts = window_extents(win);
set_ignore(NextRequest(fl_display));
@ -1238,9 +1304,17 @@ void Composite::finish_destroy_window(Window id, bool gone) {
}
}
void Composite::handle_xevents(const XEvent* xev) {
void Composite::update_screen(void) {
if(allDamage != None) {
paint_all(allDamage);
allDamage = None;
clipChanged = false;
}
}
int Composite::handle_xevents(const XEvent* xev) {
if(another_is_running || !manual_redirect)
return;
return 0;
switch(xev->type) {
case CreateNotify:
@ -1280,10 +1354,13 @@ void Composite::handle_xevents(const XEvent* xev) {
property_notify(&xev->xproperty);
break;
default:
if(xev->type == damage_event + XDamageNotify) {
EDEBUG("---------> %i <---------\n", damage_event);
if(xev->type == (damage_event + XDamageNotify)) {
//EDEBUG("---------> %i <---------\n", damage_event + XDamageNotify);
damage_window((XDamageNotifyEvent*)xev);
return 0;
}
break;
}
return 1;
}

View File

@ -52,9 +52,10 @@ class Composite {
Composite();
~Composite();
bool init(void);
void handle_xevents(const XEvent* xev);
int handle_xevents(const XEvent* xev);
void paint_all(XserverRegion region);
void update_screen(void);
};
#endif

View File

@ -202,7 +202,6 @@ EvokeService::EvokeService() :
is_running(0), logfile(NULL), xsm(NULL), composite(NULL), pidfile(NULL), lockfile(NULL) {
wake_up_pipe[0] = wake_up_pipe[1] = -1;
//quit_child_pid = quit_child_ret = -1;
}
EvokeService::~EvokeService() {
@ -589,6 +588,7 @@ void EvokeService::service_watcher(int pid, int ret) {
write(wake_up_pipe[1], &ret, sizeof(int));
}
#include <FL/fl_ask.h>
void EvokeService::wake_up(int fd) {
puts("=== wake_up() ===");
@ -632,6 +632,7 @@ void EvokeService::wake_up(int fd) {
break;
case 127:
edelib::alert(_("Program not found"));
//fl_alert(_("Program not found"));
break;
case 126:
edelib::alert(_("Program not executable"));
@ -727,6 +728,12 @@ bool EvokeService::find_and_unregister_process(pid_t pid, EvokeProcess& pc) {
return 0;
}
int EvokeService::composite_handle(const XEvent* xev) {
if(composite)
return composite->handle_xevents(xev);
return 1;
}
/*
* Main loop for processing got X events.
*
@ -736,33 +743,13 @@ bool EvokeService::find_and_unregister_process(pid_t pid, EvokeProcess& pc) {
* whole program.
*/
int EvokeService::handle(const XEvent* xev) {
EVOKE_LOG("Got event %i\n", xev->type);
if(xsm && xsm->should_terminate(xev)) {
EVOKE_LOG("XSETTINGS manager shutdown\n");
stop_xsettings_manager(true);
return 1;
}
if(composite)
composite->handle_xevents(xev);
#if 0
else if(xev->type == MapNotify) {
puts("=================");
if(top_win) {
// for splash to keep it at top (working in old edewm)
XRaiseWindow(fl_display, fl_xid(top_win));
// return 1;
}
} else if(xev->type == ConfigureNotify) {
if(xev->xconfigure.event == DefaultRootWindow(fl_display) && top_win) {
// splash too, but keep window under other wm's
XRaiseWindow(fl_display, fl_xid(top_win));
// return 1;
}
}
#endif
else if(xev->type == PropertyNotify) {
if(xev->type == PropertyNotify) {
if(xev->xproperty.atom == _ede_spawn) {
char buff[1024];
if(get_string_property_value(_ede_spawn, buff, sizeof(buff))) {
@ -798,6 +785,12 @@ int EvokeService::handle(const XEvent* xev) {
}
}
#ifdef USE_FLTK_LOOP_EMULATION
// let FLTK handle the rest
return fl_handle(*xev);
fl_handle(*xev);
return 0;
#else
// let composite manager do the rest
return composite_handle(xev);
#endif
}

View File

@ -51,8 +51,6 @@ typedef edelib::list<EvokeProcess>::iterator ProcessListIter;
typedef edelib::list<QueuedSignal> SignalQueue;
typedef edelib::list<QueuedSignal>::iterator SignalQueueIter;
class Fl_Double_Window;
class EvokeService {
private:
bool is_running;
@ -92,6 +90,7 @@ class EvokeService {
void init_composite(void);
int handle(const XEvent* ev);
int composite_handle(const XEvent* ev);
Log* log(void) { return logfile; }
@ -104,6 +103,8 @@ class EvokeService {
bool find_and_unregister_process(pid_t pid, EvokeProcess& pc);
void quit_x11(void);
//void update_screen(void);
};
#define EVOKE_LOG EvokeService::instance()->log()->printf

View File

@ -12,6 +12,10 @@ SubDir TOP evoke ;
# use SIGHUP for now as default
ObjectC++Flags evoke.cpp : -DUSE_SIGHUP ;
# relay on FLTK loop emulation for now
ObjectC++Flags EvokeService.cpp evoke.cpp : -DUSE_FLTK_LOOP_EMULATION ;
# for smooth repainting
#ObjectC++Flags Composite.cpp : -DUSE_CHECK ;
SOURCE = evoke.cpp
EvokeService.cpp
@ -32,5 +36,6 @@ EdeProgram evoke : $(SOURCE) ;
FltkProgramBare test/evoke_test : test/evoke_test.cpp ;
FltkProgramBare test/stress_test : test/stress_test.cpp ;
FltkProgramBare test/opacity_test : test/opacity_test.cpp ;
#TranslationStrings locale : $(SOURCE) ;
EdeManual doc/evoke.txt ;

View File

@ -16,7 +16,6 @@
#include <edelib/Run.h>
#include <edelib/Debug.h>
#include <edelib/Nls.h>
#include <edelib/Sound.h>
#include <FL/Fl_Shared_Image.h>
#include <FL/Fl.h>
@ -26,20 +25,27 @@
#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 void service_watcher_cb(int pid, int signum);
Fl_Double_Window* splash_win = 0;
#ifndef EDEWM_HAVE_NET_SPLASH
Splash* global_splash = NULL;
int splash_xmessage_handler(int e) {
if(fl_xevent->type == MapNotify || fl_xevent->type == ConfigureNotify) {
if(splash_win) {
XRaiseWindow(fl_display, fl_xid(splash_win));
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() untill all clients are
@ -67,8 +73,8 @@ Splash::~Splash() {
}
#if 0
// after edewm got _NET_WM_WINDOW_TYPE_SPLASH support
#if EDEWM_HAVE_NET_SPLASH
void Splash::show(void) {
if(shown())
return;
@ -185,35 +191,22 @@ void Splash::run(void) {
int sh = DisplayHeight(fl_display, fl_screen);
position(sw/2 - w()/2, sh/2 - h()/2);
bool sound_loaded = false;
if(sound && !sound->empty())
sound_loaded = edelib::SoundSystem::init();
show();
Fl::add_timeout(TIMEOUT_START, runner_cb, this);
/*
* Force keeping splash window at the top of all. To do this, we will listen
* MappingNotify and ConfigureNotify events, and when they be triggered we will
* raise splash window.
*/
splash_win = this;
//XSelectInput(fl_display, RootWindow(fl_display, fl_screen), SubstructureNotifyMask);
//Fl::add_handler(splash_xmessage_handler);
if(sound_loaded)
edelib::SoundSystem::play(sound->c_str(), 0);
// to keep splash at the top
#ifndef 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();
if(sound_loaded) {
edelib::SoundSystem::stop();
edelib::SoundSystem::shutdown();
}
splash_win = 0;
#ifndef EDEWM_HAVE_NET_SPLASH
Fl::remove_handler(splash_xmessage_handler);
#endif
}
// called when splash option is on

View File

@ -49,7 +49,10 @@ class Splash : public Fl_Double_Window {
bool next_client_nosplash(void);
void run(void);
//virtual void show(void);
#if EDEWM_HAVE_NET_SPLASH
virtual void show(void);
#endif
};
#endif

View File

@ -3,7 +3,7 @@
*
* Evoke, head honcho of everything
* Part of Equinox Desktop Environment (EDE).
* Copyright (c) 2000-2007 EDE Authors.
* Copyright (c) 2007-2008 EDE Authors.
*
* This program is licensed under terms of the
* GNU General Public License version 2 or newer.
@ -24,7 +24,6 @@
#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
@ -48,6 +47,14 @@ void xmessage_handler(int, void*) {
}
}
int xmessage_handler2(int) {
return EvokeService::instance()->handle(fl_xevent);
}
int composite_handler(int ev) {
return EvokeService::instance()->composite_handle(fl_xevent);
}
const char* next_param(int curr, char** argv, int argc) {
int j = curr + 1;
if(j >= argc)
@ -58,7 +65,7 @@ const char* next_param(int curr, char** argv, int argc) {
}
void help(void) {
puts("Usage: "APPNAME" [OPTIONS]");
puts("Usage: evoke [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");
@ -125,7 +132,7 @@ int main(int argc, char** argv) {
else if(CHECK_ARGV(a, "-u", "--autostart-safe"))
do_autostart_safe = 1;
else {
printf("Unknown parameter '%s'. Run '"APPNAME" -h' for options\n", a);
printf("Unknown parameter '%s'. Run 'evoke -h' for options\n", a);
return 1;
}
}
@ -134,6 +141,7 @@ int main(int argc, char** argv) {
// make sure X11 is running before rest of code is called
fl_open_display();
// initialize main service object
EvokeService* service = EvokeService::instance();
if(!service->setup_logging(log_file)) {
@ -146,15 +154,15 @@ int main(int argc, char** argv) {
return 1;
}
EVOKE_LOG("= "APPNAME" started =\n");
EVOKE_LOG("= evoke started =\n");
if(!pid_file)
pid_file = DEFAULT_PID;
if(!service->setup_pid(pid_file, LOCK_FILE)) {
printf("Either another "APPNAME" instance is running or can't create pid file. Please correct this\n");
printf("Either another evoke instance is running or can't create pid file. Please correct this\n");
printf("Note: if program abnormaly crashed before, just remove '%s' and start it again\n", LOCK_FILE);
printf("= "APPNAME" abrupted shutdown =\n");
printf("= evoke abrupted shutdown =\n");
return 1;
}
@ -164,17 +172,26 @@ int main(int argc, char** argv) {
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");
EVOKE_LOG("= evoke 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();
/*
* Run autostart code after XSETTINGS manager since some Gtk apps (mozilla) will eats a lot
* of cpu during runtime settings changes
*/
if(do_autostart || do_autostart_safe)
service->init_autostart(do_autostart_safe);
/*
* Let composite manager be run the latest. Running autostart after it will not deliver
* X events to possible shown autostart window, and I'm not sure why. Probably due event
* throttle from XDamage ?
*/
service->init_composite();
signal(SIGINT, quit_signal);
@ -192,12 +209,9 @@ int main(int argc, char** argv) {
signal(SIGHUP, quit_signal);
#endif
service->start();
#if 0
XSelectInput(fl_display, RootWindow(fl_display, fl_screen), PropertyChangeMask | SubstructureNotifyMask | ClientMessage);
#endif
// composite engine included too
XSelectInput(fl_display, RootWindow(fl_display, fl_screen),
SubstructureNotifyMask | ExposureMask | StructureNotifyMask | PropertyChangeMask | ClientMessage);
@ -206,18 +220,63 @@ int main(int argc, char** argv) {
* 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
* I choose to use fltk for this since wait() will nicely poll 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
* Also note that '1' in add_fd (when USE_FLTK_LOOP_EMULATION is defined) parameter
* means POLLIN, and for the details see Fl_x.cxx
*
* Let me explaint what these USE_FLTK_LOOP_EMULATION parts means. It was introduced
* since FLTK eats up SelectionClear event and so other parts (evoke specific atoms, splash etc.)
* could be used and tested. FLTK does not have event handler that could be registered
* _before_ it process events, but only add_handler() which will be called _after_ FLTK process
* all events and where will be reported ones that FLTK does not understainds or for those
* windows it already don't know.
*/
#ifdef USE_FLTK_LOOP_EMULATION
Fl::add_fd(ConnectionNumber(fl_display), 1, xmessage_handler);
Fl::add_handler(composite_handler);
#else
/*
* NOTE: composite_handler() is not needed since it will be included
* within xmessage_handler2() call
*/
Fl::add_handler(xmessage_handler2);
#endif
service->start();
while(service->running()) {
#ifdef USE_FLTK_LOOP_EMULATION
/*
* Seems that when XQLength() is not used, damage events will not be correctly
* send to xmessage_handler() and composite will wrongly draw the screen.
*/
if(XQLength(fl_display)) {
xmessage_handler(0, 0);
continue;
}
#else
/*
* 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);
#endif
while(service->running())
Fl::wait(FOREVER);
EVOKE_LOG("= "APPNAME" nice shutdown =\n");
#ifndef USE_FLTK_LOOP_EMULATION
if(fl_xevent && fl_xevent->type == SelectionClear)
service->handle(fl_xevent);
#endif
}
EVOKE_LOG("= evoke nice shutdown =\n");
return 0;
}