]> Dogcows Code - chaz/openbox/blob - tools/slit/slit.c
add shit that i made in the last week!
[chaz/openbox] / tools / slit / slit.c
1 #include "render/render.h"
2 #include "render/theme.h"
3
4 #include <X11/Xlib.h>
5 #include <stdlib.h>
6 #include <glib.h>
7 #ifdef HAVE_SIGNAL_H
8 # include <signal.h>
9 #endif
10 #ifdef HAVE_SYS_SELECT_H
11 # include <sys/select.h>
12 #endif
13
14 #define TITLE_EVENT_MASK (ButtonPressMask | ButtonReleaseMask | \
15 ButtonMotionMask)
16 #define ROOT_EVENT_MASK (PropertyChangeMask | StructureNotifyMask | \
17 SubstructureNotifyMask)
18 #define SLITAPP_EVENT_MASK (StructureNotifyMask)
19
20 Display *ob_display;
21 Window ob_root;
22 int ob_screen;
23
24 static struct Slit {
25 Window frame;
26 Window title;
27
28 /* user-requested position stuff */
29 int gravity;
30 int user_x, user_y;
31
32 /* actual position (when not auto-hidden) */
33 int x, y;
34 int w, h;
35
36 gboolean horz;
37
38 Appearance *a_frame;
39 Appearance *a_title;
40
41 GList *slit_apps;
42 } *slit;
43 static int nslits;
44
45 struct SlitApp {
46 Window icon_win;
47 Window win;
48 int x;
49 int y;
50 int w;
51 int h;
52 };
53
54 static Atom atom_atom;
55 static Atom atom_card;
56 static Atom atom_theme;
57 static Atom atom_type;
58 static Atom atom_type_dock;
59 static Atom atom_desktop;
60 static Atom atom_state;
61 static Atom atom_strut;
62
63 static gboolean quit = FALSE;
64 static gboolean reconfig = FALSE;
65
66 void slit_read_theme();
67 void slit_configure();
68 void event_handle(XEvent *e);
69 void slit_add_existing();
70 void slit_add_app(Window win);
71 void slit_remove_app(struct Slit *slit, struct SlitApp *app,gboolean reparent);
72
73 void sighandler(int signal)
74 {
75 if (signal == SIGUSR1)
76 reconfig =TRUE;
77 else
78 quit = TRUE;
79 }
80
81 int xerrorhandler(Display *d, XErrorEvent *e)
82 {
83 char errtxt[128];
84 XGetErrorText(d, e->error_code, errtxt, 127);
85 g_error("X Error: %s", errtxt);
86 return 0;
87 }
88
89 int main()
90 {
91 int i;
92 guint desk = 0xffffffff;
93 XEvent e;
94 XSetWindowAttributes attrib;
95 struct sigaction action;
96 sigset_t sigset;
97 int xfd;
98 fd_set selset;
99
100 /* set up signal handler */
101 sigemptyset(&sigset);
102 action.sa_handler = sighandler;
103 action.sa_mask = sigset;
104 action.sa_flags = SA_NOCLDSTOP;
105 sigaction(SIGUSR1, &action, (struct sigaction *) NULL);
106 sigaction(SIGPIPE, &action, (struct sigaction *) NULL);
107 sigaction(SIGSEGV, &action, (struct sigaction *) NULL);
108 sigaction(SIGFPE, &action, (struct sigaction *) NULL);
109 sigaction(SIGTERM, &action, (struct sigaction *) NULL);
110 sigaction(SIGINT, &action, (struct sigaction *) NULL);
111 sigaction(SIGHUP, &action, (struct sigaction *) NULL);
112
113 ob_display = XOpenDisplay(NULL);
114 ob_screen = DefaultScreen(ob_display);
115 ob_root = RootWindow(ob_display, ob_screen);
116
117 XSetErrorHandler(xerrorhandler);
118
119 render_startup();
120 theme_startup();
121
122 atom_atom = XInternAtom(ob_display, "ATOM", False);
123 atom_card = XInternAtom(ob_display, "CARDINAL", False);
124 atom_theme = XInternAtom(ob_display, "_OPENBOX_THEME", False);
125 atom_type = XInternAtom(ob_display, "_NET_WM_WINDOW_TYPE", False);
126 atom_type_dock = XInternAtom(ob_display, "_NET_WM_WINDOW_TYPE_DOCK",False);
127 atom_desktop =XInternAtom(ob_display, "_NET_WM_DESKTOP", False);
128 atom_state = XInternAtom(ob_display, "WM_STATE", False);
129 atom_strut = XInternAtom(ob_display, "_NET_WM_STRUT", False);
130
131 nslits = 1;
132 slit = g_new0(struct Slit, nslits);
133
134 for (i = 0; i < nslits; ++i) {
135 slit[i].horz = TRUE;
136
137 slit[i].frame = XCreateWindow(ob_display, ob_root, 0, 0, 1, 1, 0,
138 render_depth, InputOutput, render_visual,
139 0, NULL);
140 attrib.event_mask = TITLE_EVENT_MASK;
141 slit[i].title = XCreateWindow(ob_display, slit[i].frame, 0, 0, 1, 1, 0,
142 render_depth, InputOutput, render_visual,
143 CWEventMask, &attrib);
144 XMapWindow(ob_display, slit[i].title);
145
146 XChangeProperty(ob_display, slit[i].frame, atom_type, atom_atom,
147 32, PropModeReplace, (guchar*)&atom_type_dock, 1);
148
149 XChangeProperty(ob_display, slit[i].frame, atom_desktop, atom_card,
150 32, PropModeReplace, (guchar*)&desk, 1);
151 }
152
153 slit_read_theme();
154
155 XSelectInput(ob_display, ob_root, ROOT_EVENT_MASK);
156
157 slit_add_existing();
158
159 xfd = ConnectionNumber(ob_display);
160 FD_ZERO(&selset);
161 FD_SET(xfd, &selset);
162 while (!quit) {
163 gboolean hadevent = FALSE;
164 while (XPending(ob_display)) {
165 XNextEvent(ob_display, &e);
166 event_handle(&e);
167 hadevent = TRUE;
168 }
169 if (!hadevent) {
170 if (reconfig)
171 slit_read_theme();
172
173 if (!quit)
174 select(xfd + 1, &selset, NULL, NULL, NULL);
175 }
176 }
177
178 for (i = 0; i < nslits; ++i) {
179 while (slit[i].slit_apps)
180 slit_remove_app(&slit[i], slit[i].slit_apps->data, TRUE);
181
182 XDestroyWindow(ob_display, slit[i].title);
183 XDestroyWindow(ob_display, slit[i].frame);
184
185 appearance_free(slit[i].a_frame);
186 appearance_free(slit[i].a_title);
187 }
188
189 theme_shutdown();
190 render_shutdown();
191 XCloseDisplay(ob_display);
192 return 0;
193 }
194
195 Window find_client(Window win)
196 {
197 Window r, *children;
198 unsigned int n, i;
199 Atom ret_type;
200 int ret_format;
201 unsigned long ret_items, ret_bytesleft;
202 unsigned long *prop_return;
203
204 XQueryTree(ob_display, win, &r, &r, &children, &n);
205 for (i = 0; i < n; ++i) {
206 Window w = find_client(children[i]);
207 if (w) return w;
208 }
209
210 /* try me */
211 XGetWindowProperty(ob_display, win, atom_state, 0, 1,
212 False, atom_state, &ret_type, &ret_format,
213 &ret_items, &ret_bytesleft,
214 (unsigned char**) &prop_return);
215 if (ret_type == None || ret_items < 1)
216 return None;
217 return win; /* found it! */
218 }
219
220 void event_handle(XEvent *e)
221 {
222 int i;
223 Window win;
224 static guint button = 0;
225 int sw, sh;
226 int xpos, ypos;
227 int x, y, g;
228
229 switch (e->type) {
230 case ButtonPress:
231 if (!button) {
232 button = e->xbutton.button;
233 }
234 break;
235 case ButtonRelease:
236 if (button == e->xbutton.button)
237 button = 0;
238 break;
239 case MotionNotify:
240 if (button == 1) {
241 for (i = 0; i < nslits; ++i)
242 if (slit[i].title == e->xmotion.window) {
243 /* pick a corner and move it */
244 sw = WidthOfScreen(ScreenOfDisplay(ob_display, ob_screen));
245 sh = HeightOfScreen(ScreenOfDisplay(ob_display,ob_screen));
246
247 if (e->xmotion.x_root < sw / 3) /* left edge */
248 xpos = 0;
249 else if (e->xmotion.x_root < sw / 3 * 2) /* middle */
250 xpos = 1;
251 else /* right edge */
252 xpos = 2;
253 if (e->xmotion.y_root < sh / 3) /* top edge */
254 ypos = 0;
255 else if (e->xmotion.y_root < sh / 3 * 2) /* middle */
256 ypos = 1;
257 else /* bottom edge */
258 ypos = 2;
259
260 if (xpos == 1 && ypos == 1)
261 return; /* cant go in middle middle */
262
263 if (xpos == 0) {
264 if (ypos == 0) {
265 x = 0;
266 y = 0;
267 g = NorthWestGravity;
268 } else if (ypos == 1) {
269 x = 0;
270 y = sh / 2;
271 g = WestGravity;
272 } else {
273 x = 0;
274 y = sh;
275 g = SouthWestGravity;
276 }
277 } else if (xpos == 1) {
278 if (ypos == 0) {
279 x = sw / 2;
280 y = 0;
281 g = NorthGravity;
282 } else {
283 x = sw / 2;
284 y = sh;
285 g = SouthGravity;
286 }
287 } else {
288 if (ypos == 0) {
289 x = sw;
290 y = 0;
291 g = NorthEastGravity;
292 } else if (ypos == 1) {
293 x = sw;
294 y = sh / 2;
295 g = EastGravity;
296 } else {
297 x = sw;
298 y = sh;
299 g = SouthEastGravity;
300 }
301 }
302 if (x != slit[i].x || y != slit[i].y ||
303 g != slit[i].gravity) {
304 slit[i].user_x = x;
305 slit[i].user_y = y;
306 slit[i].gravity = g;
307 slit_configure();
308 }
309 }
310 }
311 break;
312 case PropertyNotify:
313 g_message("PropertyNotify on 0x%lx", e->xproperty.window);
314 if (e->xproperty.window == ob_root) {
315 if (e->xproperty.atom == atom_theme)
316 slit_read_theme();
317 }
318 break;
319 case ConfigureNotify:
320 g_message("ConfigureNotify on 0x%lx", e->xconfigure.window);
321 if (e->xconfigure.window == ob_root) {
322 slit_configure();
323 return;
324 }
325
326 /* an owned slitapp? */
327 for (i = 0; i < nslits; ++i) {
328 GList *it;
329
330 for (it = slit[i].slit_apps; it; it = it->next) {
331 struct SlitApp *app = it->data;
332 if (e->xconfigure.window == app->icon_win) {
333 if (app->w != e->xconfigure.width ||
334 app->h != e->xconfigure.height) {
335 g_message("w %d h %d w %d h %d",
336 app->w, e->xconfigure.width,
337 app->h, e->xconfigure.height);
338 app->w = e->xconfigure.width;
339 app->h = e->xconfigure.height;
340 slit_configure();
341 }
342 return;
343 }
344 }
345 }
346 break;
347 case MapNotify:
348 g_message("MapNotify on 0x%lx", e->xmap.window);
349
350 win = find_client(e->xmap.window);
351 if (!win) return;
352
353 for (i = 0; i < nslits; ++i)
354 if (win == slit[i].frame)
355 return;
356
357 slit_add_app(win);
358 break;
359 case UnmapNotify:
360 g_message("UnmapNotify on 0x%lx", e->xunmap.window);
361 for (i = 0; i < nslits; ++i) {
362 GList *it;
363
364 for (it = slit[i].slit_apps; it; it = it->next) {
365 struct SlitApp *app = it->data;
366 if (e->xunmap.window == app->icon_win) {
367 gboolean r;
368 XEvent e;
369
370 r = !XCheckTypedWindowEvent(ob_display, app->icon_win,
371 DestroyNotify, &e);
372 if (r) {
373 if (XCheckTypedWindowEvent(ob_display, app->icon_win,
374 ReparentNotify, &e)) {
375 XPutBackEvent(ob_display, &e);
376 r = FALSE;
377 }
378 }
379 slit_remove_app(&slit[i], app, r);
380 break;
381 }
382 }
383 }
384 break;
385 case ReparentNotify:
386 g_message("ReparentNotify on 0x%lx", e->xdestroywindow.window);
387 for (i = 0; i < nslits; ++i) {
388 GList *it;
389
390 for (it = slit[i].slit_apps; it; it = it->next) {
391 struct SlitApp *app = it->data;
392 if (e->xdestroywindow.window == app->icon_win) {
393 slit_remove_app(&slit[i], app, FALSE);
394 break;
395 }
396 }
397 }
398 case DestroyNotify:
399 g_message("DestroyNotify on 0x%lx", e->xdestroywindow.window);
400 for (i = 0; i < nslits; ++i) {
401 GList *it;
402
403 for (it = slit[i].slit_apps; it; it = it->next) {
404 struct SlitApp *app = it->data;
405 if (e->xdestroywindow.window == app->icon_win) {
406 slit_remove_app(&slit[i], app, FALSE);
407 break;
408 }
409 }
410 }
411 break;
412 }
413 }
414
415 void slit_add_existing()
416 {
417 unsigned int i, nchild;
418 int j;
419 Window w, *children;
420 XWindowAttributes attrib;
421
422 XQueryTree(ob_display, ob_root, &w, &w, &children, &nchild);
423
424 for (i = 0; i < nchild; ++i) {
425 for (j = 0; j < nslits; ++j)
426 if (children[i] == slit[j].frame)
427 continue;
428 if (children[i] == None)
429 continue;
430 if ((children[i] = find_client(children[i])) == None)
431 continue;
432 if (XGetWindowAttributes(ob_display, children[i], &attrib)) {
433 if (attrib.override_redirect) continue;
434
435 slit_add_app(children[i]);
436 }
437 }
438 XFree(children);
439 }
440
441 void slit_add_app(Window win)
442 {
443 int i;
444 XWMHints *h;
445 XWindowAttributes attrib;
446 struct Slit *s;
447
448 s = &slit[0];
449
450 if ((h = XGetWMHints(ob_display, win))) {
451 if (h->flags & StateHint && h->initial_state == WithdrawnState) {
452 struct SlitApp *app = g_new(struct SlitApp, 1);
453
454 app->win = win;
455 app->icon_win = (h->flags & IconWindowHint) ?
456 h->icon_window : win;
457
458 XFree(h);
459
460 for (i = 0; i < nslits; ++i) {
461 GList *it;
462 for (it = slit[i].slit_apps; it; it = it->next)
463 if (app->icon_win ==
464 ((struct SlitApp*)it->data)->icon_win)
465 /* already managed! */
466 return;
467 }
468
469 if (XGetWindowAttributes(ob_display, app->icon_win, &attrib)) {
470 app->w = attrib.width;
471 app->h = attrib.height;
472 } else {
473 g_free(app);
474 app = NULL;
475 }
476
477 if (app) {
478 s->slit_apps = g_list_append(s->slit_apps, app);
479 slit_configure();
480 XReparentWindow(ob_display, app->icon_win,
481 s->frame, app->x, app->y);
482 /* if (app->win != app->icon_win)
483 XUnmapWindow(ob_display, app->win);*/
484 XSync(ob_display, False);
485 XSelectInput(ob_display, app->icon_win,
486 SLITAPP_EVENT_MASK);
487 }
488 g_message("Managed: 0x%lx", app->icon_win);
489 } else
490 XFree(h);
491 }
492 }
493
494 void slit_remove_app(struct Slit *slit, struct SlitApp *app, gboolean reparent)
495 {
496
497 XSelectInput(ob_display, app->icon_win, NoEventMask);
498 XSync(ob_display, False);
499 if (reparent) {
500 g_message("reparenting");
501 /* if (app->win != app->icon_win)
502 XMapWindow(ob_display, app->win);*/
503 XReparentWindow(ob_display, app->icon_win, ob_root, 0, 0);
504 }
505
506 g_free(app);
507 slit->slit_apps = g_list_remove(slit->slit_apps, app);
508 slit_configure();
509 }
510
511 void slit_read_theme()
512 {
513 XTextProperty prop;
514 int i;
515 char *theme = NULL;
516
517 if (XGetTextProperty(ob_display, ob_root, &prop,
518 XInternAtom(ob_display, "_OPENBOX_THEME", False))) {
519 theme = theme_load((char*)prop.value);
520 XFree(prop.value);
521 } else
522 theme = theme_load(NULL);
523
524 g_free(theme);
525 if (!theme) exit(EXIT_FAILURE);
526
527 for (i = 0; i < nslits; ++i) {
528 appearance_free(slit[i].a_frame);
529 appearance_free(slit[i].a_title);
530
531 slit[i].a_frame = appearance_copy(theme_a_unfocused_title);
532 slit[i].a_title = appearance_copy(theme_a_unfocused_title);
533
534 XSetWindowBorder(ob_display, slit[i].frame, theme_b_color->pixel);
535 XSetWindowBorderWidth(ob_display, slit[i].frame, theme_bwidth);
536 XSetWindowBorder(ob_display, slit[i].frame, BlackPixel(ob_display, ob_screen));
537 XSetWindowBorderWidth(ob_display, slit[i].frame, 30);
538 }
539
540 slit_configure();
541 }
542
543 void slit_configure()
544 {
545 int i;
546 int titleh;
547 GList *it;
548 int spot;
549
550 titleh = 4;
551
552 for (i = 0; i < nslits; ++i) {
553 if (slit[i].horz) {
554 slit[i].w = titleh;
555 slit[i].h = 0;
556 } else {
557 slit[i].w = 0;
558 slit[i].h = titleh;
559 }
560 spot = titleh;
561
562 for (it = slit[i].slit_apps; it; it = it->next) {
563 struct SlitApp *app = it->data;
564 if (slit[i].horz) {
565 g_message("%d", spot);
566 app->x = spot;
567 app->y = 0;
568 slit[i].w += app->w;
569 slit[i].h = MAX(slit[i].h, app->h);
570 spot += app->w;
571 } else {
572 app->x = 0;
573 app->y = spot;
574 slit[i].w = MAX(slit[i].h, app->w);
575 slit[i].h += app->h;
576 spot += app->h;
577 }
578
579 XMoveWindow(ob_display, app->icon_win, app->x, app->y);
580 }
581
582 /* calculate position */
583 slit[i].x = slit[i].user_x;
584 slit[i].y = slit[i].user_y;
585
586 switch(slit[i].gravity) {
587 case NorthGravity:
588 case CenterGravity:
589 case SouthGravity:
590 slit[i].x -= slit[i].w / 2;
591 break;
592 case NorthEastGravity:
593 case EastGravity:
594 case SouthEastGravity:
595 slit[i].x -= slit[i].w;
596 break;
597 }
598 switch(slit[i].gravity) {
599 case WestGravity:
600 case CenterGravity:
601 case EastGravity:
602 slit[i].y -= slit[i].h / 2;
603 break;
604 case SouthWestGravity:
605 case SouthGravity:
606 case SouthEastGravity:
607 slit[i].y -= slit[i].h;
608 break;
609 }
610
611 if (slit[i].w > 0 && slit[i].h > 0) {
612 RECT_SET(slit[i].a_frame->area, 0, 0, slit[i].w, slit[i].h);
613 XMoveResizeWindow(ob_display, slit[i].frame,
614 slit[i].x - theme_bwidth,
615 slit[i].y - theme_bwidth,
616 slit[i].w, slit[i].h);
617
618 if (slit[i].horz) {
619 RECT_SET(slit[i].a_title->area, 0, 0, titleh, slit[i].h);
620 XMoveResizeWindow(ob_display, slit[i].title, 0, 0,
621 titleh, slit[i].h);
622 } else {
623 RECT_SET(slit[i].a_title->area, 0, 0, slit[i].w, titleh);
624 XMoveResizeWindow(ob_display, slit[i].title, 0, 0,
625 slit[i].w, titleh);
626 }
627
628 paint(slit[i].frame, slit[i].a_frame);
629 paint(slit[i].title, slit[i].a_title);
630 XMapWindow(ob_display, slit[i].frame);
631 } else
632 XUnmapWindow(ob_display, slit[i].frame);
633 }
634 }
This page took 0.060815 seconds and 4 git commands to generate.