1 #include "render/render.h"
2 #include "render/theme.h"
10 #ifdef HAVE_SYS_SELECT_H
11 # include <sys/select.h>
14 #define TITLE_EVENT_MASK (ButtonPressMask | ButtonReleaseMask | \
16 #define ROOT_EVENT_MASK (PropertyChangeMask | StructureNotifyMask | \
17 SubstructureNotifyMask)
18 #define SLITAPP_EVENT_MASK (StructureNotifyMask)
28 /* user-requested position stuff */
32 /* actual position (when not auto-hidden) */
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;
63 static gboolean quit = FALSE;
64 static gboolean reconfig = FALSE;
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);
73 void sighandler(int signal)
75 if (signal == SIGUSR1)
81 int xerrorhandler(Display *d, XErrorEvent *e)
84 XGetErrorText(d, e->error_code, errtxt, 127);
85 g_error("X Error: %s", errtxt);
92 guint desk = 0xffffffff;
94 XSetWindowAttributes attrib;
95 struct sigaction action;
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);
113 ob_display = XOpenDisplay(NULL);
114 ob_screen = DefaultScreen(ob_display);
115 ob_root = RootWindow(ob_display, ob_screen);
117 XSetErrorHandler(xerrorhandler);
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);
132 slit = g_new0(struct Slit, nslits);
134 for (i = 0; i < nslits; ++i) {
137 slit[i].frame = XCreateWindow(ob_display, ob_root, 0, 0, 1, 1, 0,
138 render_depth, InputOutput, render_visual,
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);
146 XChangeProperty(ob_display, slit[i].frame, atom_type, atom_atom,
147 32, PropModeReplace, (guchar*)&atom_type_dock, 1);
149 XChangeProperty(ob_display, slit[i].frame, atom_desktop, atom_card,
150 32, PropModeReplace, (guchar*)&desk, 1);
155 XSelectInput(ob_display, ob_root, ROOT_EVENT_MASK);
159 xfd = ConnectionNumber(ob_display);
161 FD_SET(xfd, &selset);
163 gboolean hadevent = FALSE;
164 while (XPending(ob_display)) {
165 XNextEvent(ob_display, &e);
174 select(xfd + 1, &selset, NULL, NULL, NULL);
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);
182 XDestroyWindow(ob_display, slit[i].title);
183 XDestroyWindow(ob_display, slit[i].frame);
185 appearance_free(slit[i].a_frame);
186 appearance_free(slit[i].a_title);
191 XCloseDisplay(ob_display);
195 Window find_client(Window win)
201 unsigned long ret_items, ret_bytesleft;
202 unsigned long *prop_return;
204 XQueryTree(ob_display, win, &r, &r, &children, &n);
205 for (i = 0; i < n; ++i) {
206 Window w = find_client(children[i]);
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)
217 return win; /* found it! */
220 void event_handle(XEvent *e)
224 static guint button = 0;
232 button = e->xbutton.button;
236 if (button == e->xbutton.button)
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));
247 if (e->xmotion.x_root < sw / 3) /* left edge */
249 else if (e->xmotion.x_root < sw / 3 * 2) /* middle */
251 else /* right edge */
253 if (e->xmotion.y_root < sh / 3) /* top edge */
255 else if (e->xmotion.y_root < sh / 3 * 2) /* middle */
257 else /* bottom edge */
260 if (xpos == 1 && ypos == 1)
261 return; /* cant go in middle middle */
267 g = NorthWestGravity;
268 } else if (ypos == 1) {
275 g = SouthWestGravity;
277 } else if (xpos == 1) {
291 g = NorthEastGravity;
292 } else if (ypos == 1) {
299 g = SouthEastGravity;
302 if (x != slit[i].x || y != slit[i].y ||
303 g != slit[i].gravity) {
313 g_message("PropertyNotify on 0x%lx", e->xproperty.window);
314 if (e->xproperty.window == ob_root) {
315 if (e->xproperty.atom == atom_theme)
319 case ConfigureNotify:
320 g_message("ConfigureNotify on 0x%lx", e->xconfigure.window);
321 if (e->xconfigure.window == ob_root) {
326 /* an owned slitapp? */
327 for (i = 0; i < nslits; ++i) {
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;
348 g_message("MapNotify on 0x%lx", e->xmap.window);
350 win = find_client(e->xmap.window);
353 for (i = 0; i < nslits; ++i)
354 if (win == slit[i].frame)
360 g_message("UnmapNotify on 0x%lx", e->xunmap.window);
361 for (i = 0; i < nslits; ++i) {
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) {
370 r = !XCheckTypedWindowEvent(ob_display, app->icon_win,
373 if (XCheckTypedWindowEvent(ob_display, app->icon_win,
374 ReparentNotify, &e)) {
375 XPutBackEvent(ob_display, &e);
379 slit_remove_app(&slit[i], app, r);
386 g_message("ReparentNotify on 0x%lx", e->xdestroywindow.window);
387 for (i = 0; i < nslits; ++i) {
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);
399 g_message("DestroyNotify on 0x%lx", e->xdestroywindow.window);
400 for (i = 0; i < nslits; ++i) {
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);
415 void slit_add_existing()
417 unsigned int i, nchild;
420 XWindowAttributes attrib;
422 XQueryTree(ob_display, ob_root, &w, &w, &children, &nchild);
424 for (i = 0; i < nchild; ++i) {
425 for (j = 0; j < nslits; ++j)
426 if (children[i] == slit[j].frame)
428 if (children[i] == None)
430 if ((children[i] = find_client(children[i])) == None)
432 if (XGetWindowAttributes(ob_display, children[i], &attrib)) {
433 if (attrib.override_redirect) continue;
435 slit_add_app(children[i]);
441 void slit_add_app(Window win)
445 XWindowAttributes attrib;
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);
455 app->icon_win = (h->flags & IconWindowHint) ?
456 h->icon_window : win;
460 for (i = 0; i < nslits; ++i) {
462 for (it = slit[i].slit_apps; it; it = it->next)
464 ((struct SlitApp*)it->data)->icon_win)
465 /* already managed! */
469 if (XGetWindowAttributes(ob_display, app->icon_win, &attrib)) {
470 app->w = attrib.width;
471 app->h = attrib.height;
478 s->slit_apps = g_list_append(s->slit_apps, app);
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,
488 g_message("Managed: 0x%lx", app->icon_win);
494 void slit_remove_app(struct Slit *slit, struct SlitApp *app, gboolean reparent)
497 XSelectInput(ob_display, app->icon_win, NoEventMask);
498 XSync(ob_display, False);
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);
507 slit->slit_apps = g_list_remove(slit->slit_apps, app);
511 void slit_read_theme()
517 if (XGetTextProperty(ob_display, ob_root, &prop,
518 XInternAtom(ob_display, "_OPENBOX_THEME", False))) {
519 theme = theme_load((char*)prop.value);
522 theme = theme_load(NULL);
525 if (!theme) exit(EXIT_FAILURE);
527 for (i = 0; i < nslits; ++i) {
528 appearance_free(slit[i].a_frame);
529 appearance_free(slit[i].a_title);
531 slit[i].a_frame = appearance_copy(theme_a_unfocused_title);
532 slit[i].a_title = appearance_copy(theme_a_unfocused_title);
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);
543 void slit_configure()
552 for (i = 0; i < nslits; ++i) {
562 for (it = slit[i].slit_apps; it; it = it->next) {
563 struct SlitApp *app = it->data;
565 g_message("%d", spot);
569 slit[i].h = MAX(slit[i].h, app->h);
574 slit[i].w = MAX(slit[i].h, app->w);
579 XMoveWindow(ob_display, app->icon_win, app->x, app->y);
582 /* calculate position */
583 slit[i].x = slit[i].user_x;
584 slit[i].y = slit[i].user_y;
586 switch(slit[i].gravity) {
590 slit[i].x -= slit[i].w / 2;
592 case NorthEastGravity:
594 case SouthEastGravity:
595 slit[i].x -= slit[i].w;
598 switch(slit[i].gravity) {
602 slit[i].y -= slit[i].h / 2;
604 case SouthWestGravity:
606 case SouthEastGravity:
607 slit[i].y -= slit[i].h;
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);
619 RECT_SET(slit[i].a_title->area, 0, 0, titleh, slit[i].h);
620 XMoveResizeWindow(ob_display, slit[i].title, 0, 0,
623 RECT_SET(slit[i].a_title->area, 0, 0, slit[i].w, titleh);
624 XMoveResizeWindow(ob_display, slit[i].title, 0, 0,
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);
632 XUnmapWindow(ob_display, slit[i].frame);