From: Iain Patterson Date: Fri, 6 Mar 2009 13:56:51 +0000 (+0000) Subject: Use _NET_WM properties X-Git-Url: http://git.iain.cx/?a=commitdiff_plain;h=4368b9c4544687792b23d4083fdc0a2fa261a905;p=pager.git Use _NET_WM properties Querying the window manager is more efficient and reliable. Use different colours for active/inactive windows and desktops. --- diff --git a/pager.c b/pager.c index 2a7f9ca..cab6b42 100644 --- a/pager.c +++ b/pager.c @@ -2,9 +2,43 @@ #if 0 #include #endif +#include #include -static GC lightGrayGC, darkGrayGC, windowGC[4]; +#define DOCKAPP_SIZE 56 +#define SPEED 100 +#define ACTIVE_DESKTOP 1 +#define ACTIVE_WINDOW 2 + +static GC lightGrayGC, darkGrayGC, active_desktopGC, inactive_desktopGC, active_windowGC, inactive_windowGC; +static Atom num_desktops_atom, current_desktop_atom, client_list_atom, client_desktop_atom, client_state_atom, active_window_atom; +static Atom shaded_state, skip_pager_state, hidden_state; +static long desktop = -1; + +void setup_atom(Atom *atom, const char *prop) { + *atom = XInternAtom(DADisplay, prop, True); + if (*atom == None) exit(111); +} + +void get_atom_longs(Atom atom, Atom type, Window window, long **data, unsigned long *num_items) { + Atom actual; + int format; + unsigned long num_bytes; + + XGetWindowProperty(DADisplay, window, atom, 0, 8192, False, type, &actual, &format, num_items, &num_bytes, (unsigned char **) data); +} + +long get_atom_long(Atom atom, Atom type, Window window) { + long *data; + long ret = 0; + unsigned long num_items; + + get_atom_longs(atom, type, window, &data, &num_items); + if (num_items) ret = data[0]; + XFree(data); + + return ret; +} void setup_GCs() { XGCValues gcv; @@ -21,19 +55,22 @@ void setup_GCs() { gcv.foreground = DAGetColor("#222222"); darkGrayGC = XCreateGC(DADisplay, DAWindow, GCForeground|GCGraphicsExposures, &gcv); - gcv.foreground = DAGetColor("#333333"); - windowGC[0] = XCreateGC(DADisplay, DAWindow, GCForeground|GCGraphicsExposures, &gcv); - gcv.foreground = DAGetColor("#777777"); - windowGC[1] = XCreateGC(DADisplay, DAWindow, GCForeground|GCGraphicsExposures, &gcv); gcv.foreground = DAGetColor("#bbbbbb"); - windowGC[2] = XCreateGC(DADisplay, DAWindow, GCForeground|GCGraphicsExposures, &gcv); - gcv.foreground = DAGetColor("#ffffff"); - windowGC[3] = XCreateGC(DADisplay, DAWindow, GCForeground|GCGraphicsExposures, &gcv); + active_desktopGC = XCreateGC(DADisplay, DAWindow, GCForeground|GCGraphicsExposures, &gcv); + + gcv.foreground = DAGetColor("#777777"); + inactive_desktopGC = XCreateGC(DADisplay, DAWindow, GCForeground|GCGraphicsExposures, &gcv); + + gcv.foreground = DAGetColor("#20b2ae"); + active_windowGC = XCreateGC(DADisplay, DAWindow, GCForeground|GCGraphicsExposures, &gcv); + + gcv.foreground = DAGetColor("#999999"); + inactive_windowGC = XCreateGC(DADisplay, DAWindow, GCForeground|GCGraphicsExposures, &gcv); } -void draw_relief(Pixmap pixmap, unsigned int width, unsigned int height) { +void draw_relief(Pixmap pixmap, unsigned int width, unsigned int height, GC desktopGC) { /* Drawing */ - XFillRectangle(DADisplay, pixmap, DAClearGC, 0, 0, width, height); + XFillRectangle(DADisplay, pixmap, desktopGC, 0, 0, width, height); XDrawLine(DADisplay, pixmap, darkGrayGC, 0, 0, 0, height - 2); XDrawLine(DADisplay, pixmap, darkGrayGC, 1, 0, width - 1, 0); @@ -42,46 +79,74 @@ void draw_relief(Pixmap pixmap, unsigned int width, unsigned int height) { XDrawLine(DADisplay, pixmap, lightGrayGC, width - 1, 1, width - 1, height - 2); } +void change() { + XEvent event; + Window root = DefaultRootWindow(DADisplay); + + event.type = ClientMessage; + event.xclient.type = ClientMessage; + event.xclient.window = root; + event.xclient.message_type = current_desktop_atom; + event.xclient.format = 32; + event.xclient.data.l[0] = desktop; + + XSendEvent(DADisplay, root, False, SubstructureNotifyMask, &event); +} + void page() { - Window dockapp, root, qroot, qparent, *wins; + Window root, dockapp_root, child, active_window; XWindowAttributes attr; Pixmap pixmap; DARect rect; - unsigned int i, nwins; + long i, j; + unsigned long num_clients, num_states; unsigned int root_width, root_height; - unsigned int dockapp_width, dockapp_height; + unsigned int dockapp_x, dockapp_y, dockapp_width, dockapp_height, dockapp_border, dockapp_depth; + unsigned int x, y, width, height, border, depth; double scale; + long *clients, *states; + long client_desktop, active_desktop; + int active; + GC gc; - root = DefaultRootWindow(DADisplay); + /* XXX: Use _NET_DESKTOP_GEOMETRY. */ root_width = DisplayWidth(DADisplay, DefaultScreen(DADisplay)); root_height = DisplayWidth(DADisplay, DefaultScreen(DADisplay)); - XGetWindowAttributes(DADisplay, DAGetWindow(), &attr); - dockapp_width = attr.width; - dockapp_height = attr.height; - scale = (double) root_width / (double) dockapp_width; - pixmap = DAMakePixmap(); - draw_relief(pixmap, dockapp_width, dockapp_height); - - Picture picture = XRenderCreatePicture(DADisplay, pixmap, XRenderFindVisualFormat(DADisplay, DefaultVisual(DADisplay, DefaultScreen(DADisplay))), 0, 0); - XQueryTree(DADisplay, root, &qroot, &qparent, &wins, &nwins); - for (i = 0; i < nwins; i++) { - Window root; + XGetGeometry(DADisplay, pixmap, &dockapp_root, &dockapp_x, &dockapp_y, &dockapp_width, &dockapp_height, &dockapp_border, &dockapp_depth); + scale = (double) root_width / (double) dockapp_width; - Window client = XmuClientWindow(DADisplay, wins[i]); - XGetWindowAttributes(DADisplay, client, &attr); - unsigned int x, y, width, height, border, depth; - if (attr.override_redirect) continue; - if (attr.map_state != IsViewable) continue; + active_window = get_atom_long(active_window_atom, XA_WINDOW, dockapp_root); + active_desktop = get_atom_long(current_desktop_atom, XA_CARDINAL, DefaultRootWindow(DADisplay)); + + if (active_desktop == desktop) gc = active_desktopGC; + else gc = inactive_desktopGC; + draw_relief(pixmap, dockapp_width, dockapp_height, gc); + + get_atom_longs(client_list_atom, XA_WINDOW, dockapp_root, &clients, &num_clients); + for (i = 0; i < num_clients; i++) { + int draw = 1; + client_desktop = get_atom_long(client_desktop_atom, XA_CARDINAL, clients[i]); + if (client_desktop != desktop && client_desktop != -1) continue; + if (! XGetGeometry(DADisplay, clients[i], &root, &x, &y, &width, &height, &border, &depth)) continue; + if (! XTranslateCoordinates(DADisplay, clients[i], root, x, y, &x, &y, &child)) continue; + get_atom_longs(client_state_atom, XA_ATOM, clients[i], &states, &num_states); + for (j = 0; j < num_states; j++) { + if (states[j] == shaded_state) draw = 0; + if (states[j] == skip_pager_state) draw = 0; + if (states[j] == hidden_state) draw = 0; + } + if (! draw) continue; - if (! XGetGeometry(DADisplay, wins[i], &root, &x, &y, &width, &height, &border, &depth)) continue; rect.x = (double) x / scale; rect.y = (double) y / scale; rect.width = (double) width / scale; rect.height = (double) height / scale; - XFillRectangle(DADisplay, pixmap, windowGC[(int) wins[i] % 4], rect.x, rect.y, rect.width, rect.height); + if (clients[i] == active_window) gc = active_windowGC; + else gc = inactive_windowGC; + XFillRectangle(DADisplay, pixmap, gc, rect.x, rect.y, rect.width, rect.height); /* Thumbnail. */ #if 0 @@ -113,15 +178,14 @@ void page() { XFreePixmap(DADisplay, pixmap); } -#define DOCKAPP_SIZE 56 -#define SPEED 100 - int main(int argc, char **argv) { Display *display; unsigned int root_width, root_height; unsigned int dockapp_width, dockapp_height; + long num_desktops; double aspect; - DACallbacks callbacks = { 0, 0, 0, 0, 0, 0, page }; + DACallbacks callbacks = { 0, change, 0, 0, 0, 0, page }; + DAProgramOption options = { "-d", "--desktop", "Desktop to page", DOInteger, 0, { (int *) &desktop } }; DASetExpectedVersion(20020126); @@ -140,13 +204,33 @@ int main(int argc, char **argv) { dockapp_width = (double) DOCKAPP_SIZE / aspect; } - DAParseArguments(argc, argv, 0, 0, "BLURB", "BLORB"); + DAParseArguments(argc, argv, &options, 1, "BLURB", "BLORB"); DAOpenDisplay(0, argc, argv); DACreateIcon("pager", dockapp_width, dockapp_height, argc, argv); DASetCallbacks(&callbacks); DASetTimeout(SPEED); + setup_atom(&num_desktops_atom, "_NET_NUMBER_OF_DESKTOPS"); + setup_atom(¤t_desktop_atom, "_NET_CURRENT_DESKTOP"); + setup_atom(&client_list_atom, "_NET_CLIENT_LIST_STACKING"); + setup_atom(&client_desktop_atom, "_NET_WM_DESKTOP"); + setup_atom(&client_state_atom, "_NET_WM_STATE"); + setup_atom(&active_window_atom, "_NET_ACTIVE_WINDOW"); + + setup_atom(&shaded_state, "_NET_WM_STATE_SHADED"); + setup_atom(&skip_pager_state, "_NET_WM_STATE_SKIP_PAGER"); + setup_atom(&hidden_state, "_NET_WM_STATE_HIDDEN"); + + num_desktops = get_atom_long(num_desktops_atom, XA_CARDINAL, DefaultRootWindow(DADisplay)); + if (desktop < 1) { + desktop = get_atom_long(current_desktop_atom, XA_CARDINAL, DefaultRootWindow(DADisplay)); + } + else if (desktop-- > num_desktops) { + fprintf(stderr, "There are only %d desktops!\n", num_desktops); + exit(111); + } + setup_GCs(); DAShow(); DAEventLoop();