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 ;)
This commit is contained in:
Sanel Zukan 2012-12-17 15:49:33 +00:00
parent 9751acdd9e
commit fb708f76ed
6 changed files with 115 additions and 91 deletions

View File

@ -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) {

View File

@ -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;
}
}

View File

@ -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);

View File

@ -22,14 +22,15 @@
#include <FL/Fl_Button.H>
#include <edelib/Debug.h>
#include <edelib/Netwm.h>
#include <edelib/List.h>
#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<Window> WindowList;
typedef list<Window>::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 i = 0; i < nwins; i++) {
transient_prop_win = None;
if(!netwm_window_is_manageable(wins[i]))
continue;
/*
* 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;
}
/*
* 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);
for(int j = 0; j < nwins; j++) {
if(b->get_window_xid() == wins[j]) {
found = 1;
break;
}
}
XFree(wins);
if(!found) {
remove(b);
/* Fl_Group does not call delete on remove() */
delete b;
need_full_redraw = true;
}
}
/* now see which one needs to create */
for(int i = 0, found; i < nwins; i++) {
found = 0;
for(int j = 0; j < children(); j++) {
b = (TaskButton*)child(j);
if(b->get_window_xid() == wins[i]) {
found = 1;
break;
}
}
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 (

View File

@ -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);

View File

@ -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();
}