diff --git a/evoke/Autostart.cpp b/evoke/Autostart.cpp index f7a0bba..7cb062c 100644 --- a/evoke/Autostart.cpp +++ b/evoke/Autostart.cpp @@ -78,6 +78,8 @@ void AstartDialog::add_item(const edelib::String& n, const edelib::String& e) { lst[curr++] = it; } +#include +#include 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) { diff --git a/evoke/Composite.cpp b/evoke/Composite.cpp index d9a5e6d..03dc959 100644 --- a/evoke/Composite.cpp +++ b/evoke/Composite.cpp @@ -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; } diff --git a/evoke/Composite.h b/evoke/Composite.h index 18e69bf..4d13f1e 100644 --- a/evoke/Composite.h +++ b/evoke/Composite.h @@ -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 diff --git a/evoke/EvokeService.cpp b/evoke/EvokeService.cpp index 4bafa30..46d7870 100644 --- a/evoke/EvokeService.cpp +++ b/evoke/EvokeService.cpp @@ -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 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 } diff --git a/evoke/EvokeService.h b/evoke/EvokeService.h index 2431c61..1fd7f60 100644 --- a/evoke/EvokeService.h +++ b/evoke/EvokeService.h @@ -51,8 +51,6 @@ typedef edelib::list::iterator ProcessListIter; typedef edelib::list SignalQueue; typedef edelib::list::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 diff --git a/evoke/Jamfile b/evoke/Jamfile index ce2dea1..53191d9 100644 --- a/evoke/Jamfile +++ b/evoke/Jamfile @@ -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 ; diff --git a/evoke/Splash.cpp b/evoke/Splash.cpp index ad96ab4..d4a33af 100644 --- a/evoke/Splash.cpp +++ b/evoke/Splash.cpp @@ -16,7 +16,6 @@ #include #include #include -#include #include #include @@ -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 diff --git a/evoke/Splash.h b/evoke/Splash.h index dcc10e8..7a0b226 100644 --- a/evoke/Splash.h +++ b/evoke/Splash.h @@ -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 diff --git a/evoke/evoke.cpp b/evoke/evoke.cpp index b849349..cbea8b7 100644 --- a/evoke/evoke.cpp +++ b/evoke/evoke.cpp @@ -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; }