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
);