1 /* gcc -o pager pager.c -lX11 -lXmu -ldockapp */
3 #include <X11/extensions/Xrender.h>
8 #define DOCKAPP_SIZE 56
11 static GC dockapp_border1GC, dockapp_border2GC, window_border1GC, window_border2GC, active_desktopGC, inactive_desktopGC, active_windowGC, inactive_windowGC;
12 static Atom num_desktops_atom, current_desktop_atom, client_list_atom, client_desktop_atom, client_state_atom, active_window_atom;
13 static Atom shaded_state, skip_pager_state, hidden_state;
14 static long desktop = -1;
16 int error_handler(Display *display, XErrorEvent *event) {
20 switch (event->error_code) {
22 /* The window may have gone away since we queried the window manager. */
26 if (XGetErrorText(display, event->error_code, buffer, sizeof(buffer))) {
27 fprintf(stderr, "%s\n", buffer);
36 void setup_atom(Atom *atom, const char *prop) {
37 *atom = XInternAtom(DADisplay, prop, True);
38 if (*atom == None) exit(111);
41 void get_atom_longs(Atom atom, Atom type, Window window, long **data, unsigned long *num_items) {
44 unsigned long num_bytes;
46 XGetWindowProperty(DADisplay, window, atom, 0, 8192, False, type, &actual, &format, num_items, &num_bytes, (unsigned char **) data);
49 long get_atom_long(Atom atom, Atom type, Window window) {
52 unsigned long num_items;
54 get_atom_longs(atom, type, window, &data, &num_items);
55 if (num_items) ret = data[0];
65 gcv.foreground = DAGetColor("darkGray");
66 XChangeGC(DADisplay, DAClearGC, GCForeground, &gcv);
68 gcv.foreground = DAGetColor("lightGray");
69 gcv.graphics_exposures = False;
71 dockapp_border1GC = XCreateGC(DADisplay, DAWindow, GCForeground|GCGraphicsExposures, &gcv);
73 gcv.foreground = DAGetColor("#222222");
74 dockapp_border2GC = XCreateGC(DADisplay, DAWindow, GCForeground|GCGraphicsExposures, &gcv);
76 gcv.foreground = DAGetColor("#0088ff");
77 active_desktopGC = XCreateGC(DADisplay, DAWindow, GCForeground|GCGraphicsExposures, &gcv);
79 gcv.foreground = DAGetColor("darkGray");
80 inactive_desktopGC = XCreateGC(DADisplay, DAWindow, GCForeground|GCGraphicsExposures, &gcv);
82 gcv.foreground = DAGetColor("white");
83 active_windowGC = XCreateGC(DADisplay, DAWindow, GCForeground|GCGraphicsExposures, &gcv);
85 gcv.foreground = DAGetColor("#999999");
86 inactive_windowGC = XCreateGC(DADisplay, DAWindow, GCForeground|GCGraphicsExposures, &gcv);
88 gcv.foreground = DAGetColor("black");
89 window_border1GC = XCreateGC(DADisplay, DAWindow, GCForeground|GCGraphicsExposures, &gcv);
91 gcv.foreground = DAGetColor("#333333");
92 window_border2GC = XCreateGC(DADisplay, DAWindow, GCForeground|GCGraphicsExposures, &gcv);
95 void draw_relief(Pixmap pixmap, unsigned int width, unsigned int height, GC desktopGC) {
97 XFillRectangle(DADisplay, pixmap, desktopGC, 0, 0, width, height);
99 XDrawLine(DADisplay, pixmap, dockapp_border2GC, 0, 0, 0, height - 2);
100 XDrawLine(DADisplay, pixmap, dockapp_border2GC, 1, 0, width - 1, 0);
102 XDrawLine(DADisplay, pixmap, dockapp_border1GC, 0, height - 1, width - 1, height - 1);
103 XDrawLine(DADisplay, pixmap, dockapp_border1GC, width - 1, 1, width - 1, height - 2);
108 Window root = DefaultRootWindow(DADisplay);
110 event.type = ClientMessage;
111 event.xclient.type = ClientMessage;
112 event.xclient.window = root;
113 event.xclient.message_type = current_desktop_atom;
114 event.xclient.format = 32;
115 event.xclient.data.l[0] = desktop;
117 XSendEvent(DADisplay, root, False, SubstructureNotifyMask, &event);
121 Window root, dockapp_root, child, active_window;
122 XWindowAttributes attr;
126 unsigned long num_clients, num_states;
127 unsigned int root_width, root_height;
128 unsigned int dockapp_x, dockapp_y, dockapp_width, dockapp_height, dockapp_border, dockapp_depth;
129 unsigned int x, y, width, height, border, depth;
131 long *clients, *states;
132 long client_desktop, active_desktop;
136 /* XXX: Use _NET_DESKTOP_GEOMETRY. */
137 root_width = DisplayWidth(DADisplay, DefaultScreen(DADisplay));
138 root_height = DisplayWidth(DADisplay, DefaultScreen(DADisplay));
140 pixmap = DAMakePixmap();
141 XGetGeometry(DADisplay, pixmap, &dockapp_root, &dockapp_x, &dockapp_y, &dockapp_width, &dockapp_height, &dockapp_border, &dockapp_depth);
142 scale = (double) root_width / (double) dockapp_width;
144 active_window = get_atom_long(active_window_atom, XA_WINDOW, dockapp_root);
145 active_desktop = get_atom_long(current_desktop_atom, XA_CARDINAL, DefaultRootWindow(DADisplay));
147 if (active_desktop == desktop) gc = active_desktopGC;
148 else gc = inactive_desktopGC;
149 draw_relief(pixmap, dockapp_width, dockapp_height, gc);
151 get_atom_longs(client_list_atom, XA_WINDOW, dockapp_root, &clients, &num_clients);
152 for (i = 0; i < num_clients; i++) {
154 client_desktop = get_atom_long(client_desktop_atom, XA_CARDINAL, clients[i]);
155 if (client_desktop != desktop && client_desktop != -1) continue;
156 if (! XGetGeometry(DADisplay, clients[i], &root, &x, &y, &width, &height, &border, &depth)) continue;
157 if (! XTranslateCoordinates(DADisplay, clients[i], root, x, y, &x, &y, &child)) continue;
158 get_atom_longs(client_state_atom, XA_ATOM, clients[i], &states, &num_states);
159 for (j = 0; j < num_states; j++) {
160 if (states[j] == shaded_state) draw = 0;
161 if (states[j] == skip_pager_state) draw = 0;
162 if (states[j] == hidden_state) draw = 0;
164 if (! draw) continue;
166 rect.x = (double) x / scale;
167 rect.y = (double) y / scale;
168 rect.width = (double) width / scale;
169 rect.height = (double) height / scale;
171 if (rect.width < 2 || rect.height < 2) gc = window_border1GC;
172 else if (clients[i] == active_window) gc = active_windowGC;
173 else gc = inactive_windowGC;
174 XFillRectangle(DADisplay, pixmap, gc, rect.x, rect.y, rect.width, rect.height);
175 if (rect.width < 2 || rect.height < 2) continue;
179 XRenderPictureAttributes pa;
180 Pixmap client_pixmap = XCreatePixmap(DADisplay, wins[i], width, height, DefaultDepth(DADisplay, DefaultScreen(DADisplay)));
181 //XCopyArea(DADisplay, wins[i], client_pixmap, DefaultGC(DADisplay, DefaultScreen(DADisplay)), 0, 0, width, height, 0, 0);
182 Picture client_picture = XRenderCreatePicture(DADisplay, client_pixmap, XRenderFindVisualFormat(DADisplay, attr.visual), CPSubwindowMode, &pa);
184 XTransform xform = {{
185 { XDoubleToFixed(1.0), 0, 0 },
186 { 0, XDoubleToFixed(1.0), 0 },
187 { 0, 0, XDoubleToFixed(scale) },
190 XRenderSetPictureFilter(DADisplay, client_picture, FilterBilinear, 0, 0);
191 XRenderSetPictureTransform(DADisplay, client_picture, &xform);
192 XRenderComposite(DADisplay, PictOpSrc, client_picture, None, picture, 0, 0, 0, 0, rect.x, rect.y, rect.width, rect.height);
193 XFreePixmap(DADisplay, client_pixmap);
194 XSync(DADisplay, False);
197 XDrawLine(DADisplay, pixmap, window_border1GC, rect.x, rect.y, rect.x, rect.y + rect.height - 2);
198 XDrawLine(DADisplay, pixmap, window_border1GC, rect.x + 1, rect.y, rect.x + rect.width - 1, rect.y);
199 XDrawLine(DADisplay, pixmap, window_border2GC, rect.x, rect.y + rect.height - 1, rect.x + rect.width - 1, rect.y + rect.height - 1);
200 XDrawLine(DADisplay, pixmap, window_border2GC, rect.x + rect.width - 1, rect.y + 1, rect.x + rect.width - 1, rect.y + rect.height - 2);
204 XFreePixmap(DADisplay, pixmap);
207 int main(int argc, char **argv) {
209 unsigned int root_width, root_height;
210 unsigned int dockapp_width, dockapp_height;
213 DACallbacks callbacks = { 0, change, 0, 0, 0, 0, page };
214 DAProgramOption options = { "-d", "--desktop", "Desktop to page", DOInteger, 0, { (int *) &desktop } };
216 DASetExpectedVersion(20020126);
218 display = XOpenDisplay(0);
220 root_width = DisplayWidth(display, DefaultScreen(display));
221 root_height = DisplayHeight(display, DefaultScreen(display));
222 aspect = (double) root_width / (double) root_height;
224 if (root_width > root_height) {
225 dockapp_width = DOCKAPP_SIZE;
226 dockapp_height = (double) DOCKAPP_SIZE / aspect;
229 dockapp_height = DOCKAPP_SIZE;
230 dockapp_width = (double) DOCKAPP_SIZE / aspect;
233 DAParseArguments(argc, argv, &options, 1, "BLURB", "BLORB");
234 DAOpenDisplay(0, argc, argv);
235 DACreateIcon("pager", dockapp_width, dockapp_height, argc, argv);
237 DASetCallbacks(&callbacks);
240 setup_atom(&num_desktops_atom, "_NET_NUMBER_OF_DESKTOPS");
241 setup_atom(¤t_desktop_atom, "_NET_CURRENT_DESKTOP");
242 setup_atom(&client_list_atom, "_NET_CLIENT_LIST_STACKING");
243 setup_atom(&client_desktop_atom, "_NET_WM_DESKTOP");
244 setup_atom(&client_state_atom, "_NET_WM_STATE");
245 setup_atom(&active_window_atom, "_NET_ACTIVE_WINDOW");
247 setup_atom(&shaded_state, "_NET_WM_STATE_SHADED");
248 setup_atom(&skip_pager_state, "_NET_WM_STATE_SKIP_PAGER");
249 setup_atom(&hidden_state, "_NET_WM_STATE_HIDDEN");
251 num_desktops = get_atom_long(num_desktops_atom, XA_CARDINAL, DefaultRootWindow(DADisplay));
253 desktop = get_atom_long(current_desktop_atom, XA_CARDINAL, DefaultRootWindow(DADisplay));
255 else if (desktop-- > num_desktops) {
256 fprintf(stderr, "There are only %d desktops!\n", num_desktops);
260 XSetErrorHandler(error_handler);