From fb708f76eda8ff225e11f804d9645480a54c1e35 Mon Sep 17 00:00:00 2001 From: Sanel Zukan Date: Mon, 17 Dec 2012 15:49:33 +0000 Subject: [PATCH] Closing #212: Panel buttons are reodered on titlebar click. By default, pekwm will reorder window list on input focus (probably to optimize things) and this would also reorder buttons inside taskbar. Also, on new window list, all panel buttons would be recreated again, causing many allocations and deallocations. Now, window list received from wm is compared agains internal window storage for diffs. Fixing this issue made removal some old edewm specific code and made panel nicely working under sawfish ;) --- ede-panel/Panel.cpp | 10 +- ede-panel/applets/system-tray/Tray.cpp | 3 + ede-panel/applets/taskbar/TaskButton.cpp | 15 +-- ede-panel/applets/taskbar/Taskbar.cpp | 155 ++++++++++++++--------- ede-panel/applets/taskbar/Taskbar.h | 7 +- ede-panel/ede-panel.cpp | 16 +-- 6 files changed, 115 insertions(+), 91 deletions(-) diff --git a/ede-panel/Panel.cpp b/ede-panel/Panel.cpp index 675f9af..9ee9c98 100644 --- a/ede-panel/Panel.cpp +++ b/ede-panel/Panel.cpp @@ -357,10 +357,7 @@ void Panel::do_layout(void) { } void Panel::show(void) { - if(shown()) { - Fl_Window::show(); - return; - } + if(shown()) return; /* * hush known FLTK bug with XGetImage; a lot of errors will be print when menu icons goes @@ -375,10 +372,15 @@ void Panel::show(void) { void Panel::hide(void) { Fl::remove_handler(x_events); + netwm_window_remove_strut(fl_xid(this)); + + E_DEBUG("Panel::hide()\n"); /* strange; this is not called when panel goes out :S */ mgr.clear(); save_config(); + + Fl_Window::hide(); } void Panel::update_size_and_pos(bool create_xid, bool update_strut) { diff --git a/ede-panel/applets/system-tray/Tray.cpp b/ede-panel/applets/system-tray/Tray.cpp index 35ac8d3..5baae4a 100644 --- a/ede-panel/applets/system-tray/Tray.cpp +++ b/ede-panel/applets/system-tray/Tray.cpp @@ -44,6 +44,7 @@ static int handle_xevent(int e) { } } else if(fl_xevent->type == DestroyNotify) { XDestroyWindowEvent xev = fl_xevent->xdestroywindow; + E_DEBUG(E_STRLOC ": Unock request for %i\n", fl_xevent->xclient.data.l[2]); curr_tray->unembed_window(xev.window); return false; } else if(fl_xevent->type == ConfigureNotify) { @@ -67,6 +68,7 @@ static int validate_drawable(Display *d, Window xid) { } Tray::Tray() : Fl_Group(0, 0, 1, 25), opcode(0) { + //color(FL_RED); box(FL_FLAT_BOX); register_notification_area(); } @@ -87,6 +89,7 @@ void Tray::distribute_children(void) { Y = y(); for(int i = 0; i < children(); i++) { child(i)->position(X, Y); + E_DEBUG(E_STRLOC ": child %i at %i %i\n", i, child(i)->x(), child(i)->y()); X += child(i)->w() + TRAY_ICONS_SPACE; } } diff --git a/ede-panel/applets/taskbar/TaskButton.cpp b/ede-panel/applets/taskbar/TaskButton.cpp index 831a06e..65aaf10 100644 --- a/ede-panel/applets/taskbar/TaskButton.cpp +++ b/ede-panel/applets/taskbar/TaskButton.cpp @@ -47,12 +47,10 @@ EDELIB_NS_USING(netwm_window_set_active) EDELIB_NS_USING(netwm_window_get_title) EDELIB_NS_USING(netwm_window_get_icon) EDELIB_NS_USING(netwm_window_set_state) -EDELIB_NS_USING(wm_window_ede_restore) -EDELIB_NS_USING(wm_window_get_state) -EDELIB_NS_USING(wm_window_set_state) -EDELIB_NS_USING(WM_WINDOW_STATE_ICONIC) EDELIB_NS_USING(NETWM_STATE_ACTION_TOGGLE) +EDELIB_NS_USING(NETWM_STATE_ACTION_ADD) EDELIB_NS_USING(NETWM_STATE_MAXIMIZED) +EDELIB_NS_USING(NETWM_STATE_HIDDEN) static Fl_Pixmap image_window(window_xpm); @@ -83,25 +81,22 @@ static void close_cb(Fl_Widget*, void *b) { static void restore_cb(Fl_Widget*, void *b) { TaskButton *bb = (TaskButton*)b; - wm_window_ede_restore(bb->get_window_xid()); - netwm_window_set_active(bb->get_window_xid()); + netwm_window_set_active(bb->get_window_xid(), 1); redraw_whole_panel(bb); } static void minimize_cb(Fl_Widget*, void *b) { TaskButton *bb = (TaskButton*)b; - if(wm_window_get_state(bb->get_window_xid()) != WM_WINDOW_STATE_ICONIC) - wm_window_set_state(bb->get_window_xid(), WM_WINDOW_STATE_ICONIC); - + netwm_window_set_state(bb->get_window_xid(), NETWM_STATE_HIDDEN, NETWM_STATE_ACTION_ADD); redraw_whole_panel(bb); } static void maximize_cb(Fl_Widget*, void *b) { TaskButton *bb = (TaskButton*)b; - netwm_window_set_active(bb->get_window_xid()); + netwm_window_set_active(bb->get_window_xid(), 1); netwm_window_set_state(bb->get_window_xid(), NETWM_STATE_MAXIMIZED, NETWM_STATE_ACTION_TOGGLE); redraw_whole_panel(bb); diff --git a/ede-panel/applets/taskbar/Taskbar.cpp b/ede-panel/applets/taskbar/Taskbar.cpp index 1ec30fe..f34547f 100644 --- a/ede-panel/applets/taskbar/Taskbar.cpp +++ b/ede-panel/applets/taskbar/Taskbar.cpp @@ -22,14 +22,15 @@ #include #include #include +#include #include "TaskButton.h" #include "Taskbar.h" -#include "Panel.h" #define DEFAULT_CHILD_W 175 #define DEFAULT_SPACING 5 +EDELIB_NS_USING(list) EDELIB_NS_USING(netwm_callback_add) EDELIB_NS_USING(netwm_callback_remove) EDELIB_NS_USING(netwm_window_get_all_mapped) @@ -37,6 +38,7 @@ EDELIB_NS_USING(netwm_window_is_manageable) EDELIB_NS_USING(netwm_window_get_workspace) EDELIB_NS_USING(netwm_window_get_active) EDELIB_NS_USING(netwm_window_set_active) +EDELIB_NS_USING(netwm_window_set_state) EDELIB_NS_USING(netwm_workspace_get_current) EDELIB_NS_USING(wm_window_set_state) EDELIB_NS_USING(wm_window_get_state) @@ -46,6 +48,11 @@ EDELIB_NS_USING(NETWM_CHANGED_WINDOW_LIST) EDELIB_NS_USING(NETWM_CHANGED_WINDOW_NAME) EDELIB_NS_USING(NETWM_CHANGED_WINDOW_ICON) EDELIB_NS_USING(WM_WINDOW_STATE_ICONIC) +EDELIB_NS_USING(NETWM_STATE_ACTION_TOGGLE) +EDELIB_NS_USING(NETWM_STATE_HIDDEN) + +typedef list WindowList; +typedef list::iterator WindowListIt; static void button_cb(TaskButton *b, void *t) { Taskbar *tt = (Taskbar*)t; @@ -59,9 +66,16 @@ static void button_cb(TaskButton *b, void *t) { static void net_event_cb(int action, Window xid, void *data) { E_RETURN_IF_FAIL(data != NULL); + /* this is a message, so property is not changed and netwm_window_get_active() must be called */ + if(action == NETWM_CHANGED_ACTIVE_WINDOW) { + Taskbar *tt = (Taskbar*)data; + tt->update_active_button(); + return; + } + if(action == NETWM_CHANGED_CURRENT_WORKSPACE || action == NETWM_CHANGED_WINDOW_LIST) { Taskbar *tt = (Taskbar*)data; - tt->create_task_buttons(); + tt->update_task_buttons(); return; } @@ -71,13 +85,6 @@ static void net_event_cb(int action, Window xid, void *data) { return; } - /* this is a message, so property is not changed and netwm_window_get_active() must be called */ - if(action == NETWM_CHANGED_ACTIVE_WINDOW) { - Taskbar *tt = (Taskbar*)data; - tt->update_active_button(); - return; - } - if(action == NETWM_CHANGED_WINDOW_ICON) { Taskbar *tt = (Taskbar*)data; tt->update_child_icon(xid); @@ -85,11 +92,10 @@ static void net_event_cb(int action, Window xid, void *data) { } } -Taskbar::Taskbar() : Fl_Group(0, 0, 40, 25), curr_active(NULL), prev_active(NULL), panel(NULL) { +Taskbar::Taskbar() : Fl_Group(0, 0, 40, 25), curr_active(NULL), prev_active(NULL) { end(); - panel = EDE_PANEL_GET_PANEL_OBJECT(this); - create_task_buttons(); + update_task_buttons(); netwm_callback_add(net_event_cb, this); } @@ -97,64 +103,92 @@ Taskbar::~Taskbar() { netwm_callback_remove(net_event_cb); } -void Taskbar::create_task_buttons(void) { - /* erase all current elements */ - if(children()) - clear(); +void Taskbar::update_task_buttons(void) { + Window *wins; + int nwins = netwm_window_get_all_mapped(&wins); - /* also current/prev storage */ - curr_active = prev_active = NULL; + if(nwins < 1) { + if(children() > 0) clear(); + return; + } - /* redraw it, in case no windows exists in this workspace */ - panel_redraw(); + TaskButton *b; + int curr_workspace = netwm_workspace_get_current(); + bool need_full_redraw = false; - Window *wins, transient_prop_win; - int nwins = netwm_window_get_all_mapped(&wins); + /* + * first remove windows not available in list received by wm + * + * TODO: FLTK 1.3.x got new function remove(int index) which will make + * faster removal, comparing to remove(Fl_Widget*) + */ + for(int i = 0, found; i < children(); i++) { + found = 0; + b = (TaskButton*)child(i); - if(nwins > 0) { - TaskButton *b; - int curr_workspace = netwm_workspace_get_current(); + for(int j = 0; j < nwins; j++) { + if(b->get_window_xid() == wins[j]) { + found = 1; + break; + } + } - for(int i = 0; i < nwins; i++) { - transient_prop_win = None; + if(!found) { + remove(b); + /* Fl_Group does not call delete on remove() */ + delete b; + need_full_redraw = true; + } + } - if(!netwm_window_is_manageable(wins[i])) - continue; + /* now see which one needs to create */ + for(int i = 0, found; i < nwins; i++) { + found = 0; - /* - * see if it has WM_TRANSIENT_FOR hint set; transient_prop_win would point to parent window, but - * parent should not be root window for this screen - */ - if(XGetTransientForHint(fl_display, wins[i], &transient_prop_win) - && (transient_prop_win != None) - && (transient_prop_win != RootWindow(fl_display, fl_screen))) - { - continue; - } + for(int j = 0; j < children(); j++) { + b = (TaskButton*)child(j); - /* - * show window per workspace - * TODO: allow showing all windows in each workspace - */ - if(curr_workspace == netwm_window_get_workspace(wins[i])) { - b = new TaskButton(0, 0, DEFAULT_CHILD_W, 25); - b->set_window_xid(wins[i]); - b->update_title_from_xid(); - b->update_image_from_xid(); - - /* catch the name changes */ - XSelectInput(fl_display, wins[i], PropertyChangeMask | StructureNotifyMask); - - b->callback((Fl_Callback*)button_cb, this); - add(b); + if(b->get_window_xid() == wins[i]) { + found = 1; + break; } } - XFree(wins); + if(found || !netwm_window_is_manageable(wins[i])) + continue; + + Window transient_prop_win = None; + + /* + * see if it has WM_TRANSIENT_FOR hint set; transient_prop_win would point to parent window, but + * parent should not be root window for this screen + */ + if(XGetTransientForHint(fl_display, wins[i], &transient_prop_win) + && (transient_prop_win != None) + && (transient_prop_win != RootWindow(fl_display, fl_screen))) + { + continue; + } + + /* TODO: allow showing all windows in each workspace */ + if(curr_workspace == netwm_window_get_workspace(wins[i])) { + b = new TaskButton(0, 0, DEFAULT_CHILD_W, 25); + b->set_window_xid(wins[i]); + b->update_title_from_xid(); + b->update_image_from_xid(); + + /* catch the name changes */ + XSelectInput(fl_display, wins[i], PropertyChangeMask | StructureNotifyMask); + b->callback((Fl_Callback*)button_cb, this); + add(b); + } } + XFree(wins); layout_children(); - update_active_button(); + update_active_button(!need_full_redraw); + + if(need_full_redraw) panel_redraw(); } void Taskbar::resize(int X, int Y, int W, int H) { @@ -193,7 +227,7 @@ void Taskbar::layout_children(void) { } } -void Taskbar::update_active_button(int xid) { +void Taskbar::update_active_button(bool do_redraw, int xid) { if(!children()) return; @@ -212,7 +246,7 @@ void Taskbar::update_active_button(int xid) { o->box(FL_UP_BOX); } - redraw(); + if(do_redraw) redraw(); } void Taskbar::activate_window(TaskButton *b) { @@ -239,7 +273,7 @@ void Taskbar::activate_window(TaskButton *b) { } /* active or restore minimized */ - netwm_window_set_active(xid); + netwm_window_set_active(xid, 1); update_active_button(xid); /* TODO: use stack for this (case when this can't handle: minimize three window, out of four on the workspace) */ @@ -277,8 +311,7 @@ void Taskbar::update_child_icon(Window xid) { } void Taskbar::panel_redraw(void) { - E_RETURN_IF_FAIL(panel != NULL); - panel->redraw(); + parent()->redraw(); } EDE_PANEL_APPLET_EXPORT ( diff --git a/ede-panel/applets/taskbar/Taskbar.h b/ede-panel/applets/taskbar/Taskbar.h index 830748b..6d557f0 100644 --- a/ede-panel/applets/taskbar/Taskbar.h +++ b/ede-panel/applets/taskbar/Taskbar.h @@ -25,23 +25,20 @@ #include "Applet.h" class TaskButton; -class Panel; class Taskbar : public Fl_Group { public: TaskButton *curr_active, *prev_active; - Panel *panel; - public: Taskbar(); ~Taskbar(); - void create_task_buttons(void); + void update_task_buttons(void); void resize(int X, int Y, int W, int H); void layout_children(void); - void update_active_button(int xid = -1); + void update_active_button(bool do_redraw = true, int xid = -1); void activate_window(TaskButton *b); void update_child_title(Window xid); void update_child_icon(Window xid); diff --git a/ede-panel/ede-panel.cpp b/ede-panel/ede-panel.cpp index 446e1a8..00baaa6 100644 --- a/ede-panel/ede-panel.cpp +++ b/ede-panel/ede-panel.cpp @@ -31,28 +31,22 @@ #include "Panel.h" #include "AppletManager.h" -static bool running; +static Panel *panel; static void exit_signal(int signum) { - running = false; + if(panel) panel->hide(); } int main(int argc, char **argv) { EDE_APPLICATION("ede-panel"); + panel = NULL; signal(SIGTERM, exit_signal); signal(SIGKILL, exit_signal); signal(SIGINT, exit_signal); - Panel *panel = new Panel(); + panel = new Panel(); panel->load_applets(); panel->show(); - running = true; - - while(running) - Fl::wait(); - - /* so Panel::hide() can be called */ - panel->hide(); - return 0; + return Fl::run(); }