/* gcc -o pager pager.c -lX11 -lXmu -ldockapp */ #if 0 #include #endif #include #include #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; int error_handler(Display *display, XErrorEvent *event) { char buffer[512]; int length; switch (event->error_code) { case BadWindow: /* The window may have gone away since we queried the window manager. */ break; default: if (XGetErrorText(display, event->error_code, buffer, sizeof(buffer))) { fprintf(stderr, "%s\n", buffer); exit(100); } break; } return 0; } 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; /* GC's */ gcv.foreground = DAGetColor("darkGray"); XChangeGC(DADisplay, DAClearGC, GCForeground, &gcv); gcv.foreground = DAGetColor("lightGray"); gcv.graphics_exposures = False; lightGrayGC = XCreateGC(DADisplay, DAWindow, GCForeground|GCGraphicsExposures, &gcv); gcv.foreground = DAGetColor("#222222"); darkGrayGC = XCreateGC(DADisplay, DAWindow, GCForeground|GCGraphicsExposures, &gcv); gcv.foreground = DAGetColor("#bbbbbb"); 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, GC desktopGC) { /* Drawing */ 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); XDrawLine(DADisplay, pixmap, lightGrayGC, 0, height - 1, width - 1, height - 1); 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 root, dockapp_root, child, active_window; XWindowAttributes attr; Pixmap pixmap; DARect rect; long i, j; unsigned long num_clients, num_states; unsigned int root_width, root_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; /* XXX: Use _NET_DESKTOP_GEOMETRY. */ root_width = DisplayWidth(DADisplay, DefaultScreen(DADisplay)); root_height = DisplayWidth(DADisplay, DefaultScreen(DADisplay)); pixmap = DAMakePixmap(); XGetGeometry(DADisplay, pixmap, &dockapp_root, &dockapp_x, &dockapp_y, &dockapp_width, &dockapp_height, &dockapp_border, &dockapp_depth); scale = (double) root_width / (double) dockapp_width; 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; rect.x = (double) x / scale; rect.y = (double) y / scale; rect.width = (double) width / scale; rect.height = (double) height / scale; 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 XRenderPictureAttributes pa; Pixmap client_pixmap = XCreatePixmap(DADisplay, wins[i], width, height, DefaultDepth(DADisplay, DefaultScreen(DADisplay))); //XCopyArea(DADisplay, wins[i], client_pixmap, DefaultGC(DADisplay, DefaultScreen(DADisplay)), 0, 0, width, height, 0, 0); Picture client_picture = XRenderCreatePicture(DADisplay, client_pixmap, XRenderFindVisualFormat(DADisplay, attr.visual), CPSubwindowMode, &pa); XTransform xform = {{ { XDoubleToFixed(1.0), 0, 0 }, { 0, XDoubleToFixed(1.0), 0 }, { 0, 0, XDoubleToFixed(scale) }, }}; XRenderSetPictureFilter(DADisplay, client_picture, FilterBilinear, 0, 0); XRenderSetPictureTransform(DADisplay, client_picture, &xform); XRenderComposite(DADisplay, PictOpSrc, client_picture, None, picture, 0, 0, 0, 0, rect.x, rect.y, rect.width, rect.height); XFreePixmap(DADisplay, client_pixmap); XSync(DADisplay, False); #endif XDrawLine(DADisplay, pixmap, darkGrayGC, rect.x, rect.y, rect.x, rect.y + rect.height - 2); XDrawLine(DADisplay, pixmap, darkGrayGC, rect.x + 1, rect.y, rect.x + rect.width - 1, rect.y); XDrawLine(DADisplay, pixmap, lightGrayGC, rect.x, rect.y + rect.height - 1, rect.x + rect.width - 1, rect.y + rect.height - 1); XDrawLine(DADisplay, pixmap, lightGrayGC, rect.x + rect.width - 1, rect.y + 1, rect.x + rect.width - 1, rect.y + rect.height - 2); } DASetPixmap(pixmap); XFreePixmap(DADisplay, pixmap); } 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, change, 0, 0, 0, 0, page }; DAProgramOption options = { "-d", "--desktop", "Desktop to page", DOInteger, 0, { (int *) &desktop } }; DASetExpectedVersion(20020126); display = XOpenDisplay(0); root_width = DisplayWidth(display, DefaultScreen(display)); root_height = DisplayHeight(display, DefaultScreen(display)); aspect = (double) root_width / (double) root_height; if (root_width > root_height) { dockapp_width = DOCKAPP_SIZE; dockapp_height = (double) DOCKAPP_SIZE / aspect; } else { dockapp_height = DOCKAPP_SIZE; dockapp_width = (double) DOCKAPP_SIZE / aspect; } 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); } XSetErrorHandler(error_handler); setup_GCs(); DAShow(); DAEventLoop(); }