]> Dogcows Code - chaz/openbox/blob - openbox/dock.c
fix crash when reconfigure changes the stacking layer of the dock
[chaz/openbox] / openbox / dock.c
1 #include "debug.h"
2 #include "dock.h"
3 #include "mainloop.h"
4 #include "screen.h"
5 #include "prop.h"
6 #include "config.h"
7 #include "grab.h"
8 #include "openbox.h"
9 #include "render/theme.h"
10
11 #define DOCK_EVENT_MASK (ButtonPressMask | ButtonReleaseMask | \
12 EnterWindowMask | LeaveWindowMask)
13 #define DOCKAPP_EVENT_MASK (StructureNotifyMask)
14
15 static ObDock *dock;
16
17 StrutPartial dock_strut;
18
19 void dock_startup(gboolean reconfig)
20 {
21 XSetWindowAttributes attrib;
22
23 if (reconfig) {
24 stacking_add(DOCK_AS_WINDOW(dock));
25 dock_configure();
26 return;
27 }
28
29 STRUT_PARTIAL_SET(dock_strut, 0, 0, 0, 0,
30 0, 0, 0, 0, 0, 0, 0, 0);
31
32 dock = g_new0(ObDock, 1);
33 dock->obwin.type = Window_Dock;
34
35 dock->hidden = TRUE;
36
37 attrib.event_mask = DOCK_EVENT_MASK;
38 attrib.override_redirect = True;
39 dock->frame = XCreateWindow(ob_display, RootWindow(ob_display, ob_screen),
40 0, 0, 1, 1, 0,
41 RrDepth(ob_rr_inst), InputOutput,
42 RrVisual(ob_rr_inst),
43 CWOverrideRedirect | CWEventMask,
44 &attrib);
45 dock->a_frame = RrAppearanceCopy(ob_rr_theme->a_unfocused_title);
46 XSetWindowBorder(ob_display, dock->frame,
47 RrColorPixel(ob_rr_theme->b_color));
48 XSetWindowBorderWidth(ob_display, dock->frame, ob_rr_theme->bwidth);
49
50 g_hash_table_insert(window_map, &dock->frame, dock);
51 stacking_add(DOCK_AS_WINDOW(dock));
52 }
53
54 void dock_shutdown(gboolean reconfig)
55 {
56 if (reconfig) {
57 stacking_remove(DOCK_AS_WINDOW(dock));
58 return;
59 }
60
61 XDestroyWindow(ob_display, dock->frame);
62 RrAppearanceFree(dock->a_frame);
63 g_hash_table_remove(window_map, &dock->frame);
64 stacking_remove(dock);
65 }
66
67 void dock_add(Window win, XWMHints *wmhints)
68 {
69 ObDockApp *app;
70 XWindowAttributes attrib;
71 gchar **data;
72
73 app = g_new0(ObDockApp, 1);
74 app->obwin.type = Window_DockApp;
75 app->win = win;
76 app->icon_win = (wmhints->flags & IconWindowHint) ?
77 wmhints->icon_window : win;
78
79 if (PROP_GETSS(app->win, wm_class, locale, &data)) {
80 if (data[0]) {
81 app->name = g_strdup(data[0]);
82 if (data[1])
83 app->class = g_strdup(data[1]);
84 }
85 g_strfreev(data);
86 }
87
88 if (app->name == NULL) app->name = g_strdup("");
89 if (app->class == NULL) app->class = g_strdup("");
90
91 if (XGetWindowAttributes(ob_display, app->icon_win, &attrib)) {
92 app->w = attrib.width;
93 app->h = attrib.height;
94 } else {
95 app->w = app->h = 64;
96 }
97
98 dock->dock_apps = g_list_append(dock->dock_apps, app);
99 dock_configure();
100
101 XReparentWindow(ob_display, app->icon_win, dock->frame, app->x, app->y);
102 /*
103 This is the same case as in frame.c for client windows. When Openbox is
104 starting, the window is already mapped so we see unmap events occur for
105 it. There are 2 unmap events generated that we see, one with the 'event'
106 member set the root window, and one set to the client, but both get
107 handled and need to be ignored.
108 */
109 if (ob_state() == OB_STATE_STARTING)
110 app->ignore_unmaps += 2;
111
112 if (app->win != app->icon_win) {
113 /* have to map it so that it can be re-managed on a restart */
114 XMoveWindow(ob_display, app->win, -1000, -1000);
115 XMapWindow(ob_display, app->win);
116 }
117 XMapWindow(ob_display, app->icon_win);
118 XSync(ob_display, False);
119
120 /* specify that if we exit, the window should not be destroyed and should
121 be reparented back to root automatically */
122 XChangeSaveSet(ob_display, app->icon_win, SetModeInsert);
123 XSelectInput(ob_display, app->icon_win, DOCKAPP_EVENT_MASK);
124
125 grab_button_full(2, 0, app->icon_win,
126 ButtonPressMask | ButtonReleaseMask | ButtonMotionMask,
127 GrabModeAsync, OB_CURSOR_MOVE);
128
129 g_hash_table_insert(window_map, &app->icon_win, app);
130
131 ob_debug("Managed Dock App: 0x%lx (%s)\n", app->icon_win, app->class);
132 }
133
134 void dock_remove_all()
135 {
136 while (dock->dock_apps)
137 dock_remove(dock->dock_apps->data, TRUE);
138 }
139
140 void dock_remove(ObDockApp *app, gboolean reparent)
141 {
142 ungrab_button(2, 0, app->icon_win);
143 XSelectInput(ob_display, app->icon_win, NoEventMask);
144 /* remove the window from our save set */
145 XChangeSaveSet(ob_display, app->icon_win, SetModeDelete);
146 XSync(ob_display, False);
147
148 g_hash_table_remove(window_map, &app->icon_win);
149
150 if (reparent)
151 XReparentWindow(ob_display, app->icon_win,
152 RootWindow(ob_display, ob_screen), app->x, app->y);
153
154 dock->dock_apps = g_list_remove(dock->dock_apps, app);
155 dock_configure();
156
157 ob_debug("Unmanaged Dock App: 0x%lx (%s)\n", app->icon_win, app->class);
158
159 g_free(app->name);
160 g_free(app->class);
161 g_free(app);
162 }
163
164 void dock_configure()
165 {
166 GList *it;
167 gint spot;
168 gint gravity;
169 gint minw, minh;
170 gint strw, strh;
171 Rect *a;
172
173 RrMinsize(dock->a_frame, &minw, &minh);
174
175 dock->w = dock->h = 0;
176
177 /* get the size */
178 for (it = dock->dock_apps; it; it = it->next) {
179 ObDockApp *app = it->data;
180 switch (config_dock_orient) {
181 case OB_ORIENTATION_HORZ:
182 dock->w += app->w;
183 dock->h = MAX(dock->h, app->h);
184 break;
185 case OB_ORIENTATION_VERT:
186 dock->w = MAX(dock->w, app->w);
187 dock->h += app->h;
188 break;
189 }
190 }
191
192 spot = (config_dock_orient == OB_ORIENTATION_HORZ ? minw : minh) / 2;
193
194 /* position the apps */
195 for (it = dock->dock_apps; it; it = it->next) {
196 ObDockApp *app = it->data;
197 switch (config_dock_orient) {
198 case OB_ORIENTATION_HORZ:
199 app->x = spot;
200 app->y = (dock->h - app->h) / 2;
201 spot += app->w;
202 break;
203 case OB_ORIENTATION_VERT:
204 app->x = (dock->w - app->w) / 2;
205 app->y = spot;
206 spot += app->h;
207 break;
208 }
209
210 XMoveWindow(ob_display, app->icon_win, app->x, app->y);
211 }
212
213 /* used for calculating offsets */
214 dock->w += ob_rr_theme->bwidth * 2;
215 dock->h += ob_rr_theme->bwidth * 2;
216
217 a = screen_physical_area();
218
219 /* calculate position */
220 if (config_dock_floating) {
221 dock->x = config_dock_x;
222 dock->y = config_dock_y;
223 gravity = NorthWestGravity;
224 } else {
225 switch (config_dock_pos) {
226 case OB_DIRECTION_NORTHWEST:
227 dock->x = 0;
228 dock->y = 0;
229 gravity = NorthWestGravity;
230 break;
231 case OB_DIRECTION_NORTH:
232 dock->x = a->width / 2;
233 dock->y = 0;
234 gravity = NorthGravity;
235 break;
236 case OB_DIRECTION_NORTHEAST:
237 dock->x = a->width;
238 dock->y = 0;
239 gravity = NorthEastGravity;
240 break;
241 case OB_DIRECTION_WEST:
242 dock->x = 0;
243 dock->y = a->height / 2;
244 gravity = WestGravity;
245 break;
246 case OB_DIRECTION_EAST:
247 dock->x = a->width;
248 dock->y = a->height / 2;
249 gravity = EastGravity;
250 break;
251 case OB_DIRECTION_SOUTHWEST:
252 dock->x = 0;
253 dock->y = a->height;
254 gravity = SouthWestGravity;
255 break;
256 case OB_DIRECTION_SOUTH:
257 dock->x = a->width / 2;
258 dock->y = a->height;
259 gravity = SouthGravity;
260 break;
261 case OB_DIRECTION_SOUTHEAST:
262 dock->x = a->width;
263 dock->y = a->height;
264 gravity = SouthEastGravity;
265 break;
266 }
267 }
268
269 switch(gravity) {
270 case NorthGravity:
271 case CenterGravity:
272 case SouthGravity:
273 dock->x -= dock->w / 2;
274 break;
275 case NorthEastGravity:
276 case EastGravity:
277 case SouthEastGravity:
278 dock->x -= dock->w;
279 break;
280 }
281 switch(gravity) {
282 case WestGravity:
283 case CenterGravity:
284 case EastGravity:
285 dock->y -= dock->h / 2;
286 break;
287 case SouthWestGravity:
288 case SouthGravity:
289 case SouthEastGravity:
290 dock->y -= dock->h;
291 break;
292 }
293
294 if (config_dock_hide && dock->hidden) {
295 if (!config_dock_floating) {
296 switch (config_dock_pos) {
297 case OB_DIRECTION_NORTHWEST:
298 switch (config_dock_orient) {
299 case OB_ORIENTATION_HORZ:
300 dock->y -= dock->h - ob_rr_theme->bwidth;
301 break;
302 case OB_ORIENTATION_VERT:
303 dock->x -= dock->w - ob_rr_theme->bwidth;
304 break;
305 }
306 break;
307 case OB_DIRECTION_NORTH:
308 dock->y -= dock->h - ob_rr_theme->bwidth;
309 break;
310 case OB_DIRECTION_NORTHEAST:
311 switch (config_dock_orient) {
312 case OB_ORIENTATION_HORZ:
313 dock->y -= dock->h - ob_rr_theme->bwidth;
314 break;
315 case OB_ORIENTATION_VERT:
316 dock->x += dock->w - ob_rr_theme->bwidth;
317 break;
318 }
319 break;
320 case OB_DIRECTION_WEST:
321 dock->x -= dock->w - ob_rr_theme->bwidth;
322 break;
323 case OB_DIRECTION_EAST:
324 dock->x += dock->w - ob_rr_theme->bwidth;
325 break;
326 case OB_DIRECTION_SOUTHWEST:
327 switch (config_dock_orient) {
328 case OB_ORIENTATION_HORZ:
329 dock->y += dock->h - ob_rr_theme->bwidth;
330 break;
331 case OB_ORIENTATION_VERT:
332 dock->x -= dock->w - ob_rr_theme->bwidth;
333 break;
334 } break;
335 case OB_DIRECTION_SOUTH:
336 dock->y += dock->h - ob_rr_theme->bwidth;
337 break;
338 case OB_DIRECTION_SOUTHEAST:
339 switch (config_dock_orient) {
340 case OB_ORIENTATION_HORZ:
341 dock->y += dock->h - ob_rr_theme->bwidth;
342 break;
343 case OB_ORIENTATION_VERT:
344 dock->x += dock->w - ob_rr_theme->bwidth;
345 break;
346 }
347 break;
348 }
349 }
350 }
351
352 if (!config_dock_floating && config_dock_hide) {
353 strw = ob_rr_theme->bwidth;
354 strh = ob_rr_theme->bwidth;
355 } else {
356 strw = dock->w;
357 strh = dock->h;
358 }
359
360 /* set the strut */
361 if (!dock->dock_apps) {
362 STRUT_PARTIAL_SET(dock_strut, 0, 0, 0, 0,
363 0, 0, 0, 0, 0, 0, 0, 0);
364 } else if (config_dock_floating) {
365 STRUT_PARTIAL_SET(dock_strut, 0, 0, 0, 0,
366 0, 0, 0, 0, 0, 0, 0, 0);
367 } else {
368 switch (config_dock_pos) {
369 case OB_DIRECTION_NORTHWEST:
370 switch (config_dock_orient) {
371 case OB_ORIENTATION_HORZ:
372 STRUT_PARTIAL_SET(dock_strut, 0, strh, 0, 0,
373 0, 0, dock->x, dock->x + dock->w - 1,
374 0, 0, 0, 0);
375 break;
376 case OB_ORIENTATION_VERT:
377 STRUT_PARTIAL_SET(dock_strut, strw, 0, 0, 0,
378 dock->y, dock->y + dock->h - 1,
379 0, 0, 0, 0, 0, 0);
380 break;
381 }
382 break;
383 case OB_DIRECTION_NORTH:
384 STRUT_PARTIAL_SET(dock_strut, 0, strh, 0, 0,
385 dock->x, dock->x + dock->w - 1,
386 0, 0, 0, 0, 0, 0);
387 break;
388 case OB_DIRECTION_NORTHEAST:
389 switch (config_dock_orient) {
390 case OB_ORIENTATION_HORZ:
391 STRUT_PARTIAL_SET(dock_strut, 0, strh, 0, 0,
392 0, 0, dock->x, dock->x + dock->w -1,
393 0, 0, 0, 0);
394 break;
395 case OB_ORIENTATION_VERT:
396 STRUT_PARTIAL_SET(dock_strut, 0, 0, strw, 0,
397 0, 0, 0, 0,
398 dock->y, dock->y + dock->h - 1, 0, 0);
399 break;
400 }
401 break;
402 case OB_DIRECTION_WEST:
403 STRUT_PARTIAL_SET(dock_strut, strw, 0, 0, 0,
404 dock->y, dock->y + dock->h - 1,
405 0, 0, 0, 0, 0, 0);
406 break;
407 case OB_DIRECTION_EAST:
408 STRUT_PARTIAL_SET(dock_strut, 0, 0, strw, 0,
409 0, 0, 0, 0,
410 dock->y, dock->y + dock->h - 1, 0, 0);
411 break;
412 case OB_DIRECTION_SOUTHWEST:
413 switch (config_dock_orient) {
414 case OB_ORIENTATION_HORZ:
415 STRUT_PARTIAL_SET(dock_strut, 0, 0, 0, strh,
416 0, 0, 0, 0, 0, 0,
417 dock->x, dock->x + dock->w - 1);
418 break;
419 case OB_ORIENTATION_VERT:
420 STRUT_PARTIAL_SET(dock_strut, strw, 0, 0, 0,
421 dock->y, dock->y + dock->h - 1,
422 0, 0, 0, 0, 0, 0);
423 break;
424 }
425 break;
426 case OB_DIRECTION_SOUTH:
427 STRUT_PARTIAL_SET(dock_strut, 0, 0, 0, strh,
428 0, 0, 0, 0, 0, 0,
429 dock->x, dock->x + dock->w - 1);
430 break;
431 case OB_DIRECTION_SOUTHEAST:
432 switch (config_dock_orient) {
433 case OB_ORIENTATION_HORZ:
434 STRUT_PARTIAL_SET(dock_strut, 0, 0, 0, strh,
435 0, 0, 0, 0, 0, 0,
436 dock->x, dock->x + dock->w - 1);
437 break;
438 case OB_ORIENTATION_VERT:
439 STRUT_PARTIAL_SET(dock_strut, 0, 0, strw, 0,
440 0, 0, 0, 0,
441 dock->y, dock->y + dock->h - 1, 0, 0);
442 break;
443 }
444 break;
445 }
446 }
447
448 dock->w += minw;
449 dock->h += minh;
450
451 /* not used for actually sizing shit */
452 dock->w -= ob_rr_theme->bwidth * 2;
453 dock->h -= ob_rr_theme->bwidth * 2;
454
455 if (dock->dock_apps) {
456 g_assert(dock->w > 0);
457 g_assert(dock->h > 0);
458
459 XMoveResizeWindow(ob_display, dock->frame,
460 dock->x, dock->y, dock->w, dock->h);
461
462 RrPaint(dock->a_frame, dock->frame, dock->w, dock->h);
463 XMapWindow(ob_display, dock->frame);
464 } else
465 XUnmapWindow(ob_display, dock->frame);
466
467 /* but they are useful outside of this function! */
468 dock->w += ob_rr_theme->bwidth * 2;
469 dock->h += ob_rr_theme->bwidth * 2;
470
471 screen_update_areas();
472 }
473
474 void dock_app_configure(ObDockApp *app, gint w, gint h)
475 {
476 app->w = w;
477 app->h = h;
478 dock_configure();
479 }
480
481 void dock_app_drag(ObDockApp *app, XMotionEvent *e)
482 {
483 ObDockApp *over = NULL;
484 GList *it;
485 gint x, y;
486 gboolean after;
487 gboolean stop;
488
489 x = e->x_root;
490 y = e->y_root;
491
492 /* are we on top of the dock? */
493 if (!(x >= dock->x &&
494 y >= dock->y &&
495 x < dock->x + dock->w &&
496 y < dock->y + dock->h))
497 return;
498
499 x -= dock->x;
500 y -= dock->y;
501
502 /* which dock app are we on top of? */
503 stop = FALSE;
504 for (it = dock->dock_apps; it; it = it->next) {
505 over = it->data;
506 switch (config_dock_orient) {
507 case OB_ORIENTATION_HORZ:
508 if (x >= over->x && x < over->x + over->w)
509 stop = TRUE;
510 break;
511 case OB_ORIENTATION_VERT:
512 if (y >= over->y && y < over->y + over->h)
513 stop = TRUE;
514 break;
515 }
516 /* dont go to it->next! */
517 if (stop) break;
518 }
519 if (!it || app == over) return;
520
521 x -= over->x;
522 y -= over->y;
523
524 switch (config_dock_orient) {
525 case OB_ORIENTATION_HORZ:
526 after = (x > over->w / 2);
527 break;
528 case OB_ORIENTATION_VERT:
529 after = (y > over->h / 2);
530 break;
531 }
532
533 /* remove before doing the it->next! */
534 dock->dock_apps = g_list_remove(dock->dock_apps, app);
535
536 if (after) it = it->next;
537
538 dock->dock_apps = g_list_insert_before(dock->dock_apps, it, app);
539 dock_configure();
540 }
541
542 static gboolean hide_timeout(gpointer data)
543 {
544 /* hide */
545 dock->hidden = TRUE;
546 dock_configure();
547
548 return FALSE; /* don't repeat */
549 }
550
551 void dock_hide(gboolean hide)
552 {
553 if (dock->hidden == hide || !config_dock_hide)
554 return;
555 if (!hide) {
556 /* show */
557 dock->hidden = FALSE;
558 dock_configure();
559
560 /* if was hiding, stop it */
561 ob_main_loop_timeout_remove(ob_main_loop, hide_timeout);
562 } else {
563 ob_main_loop_timeout_add(ob_main_loop, config_dock_hide_timeout * 1000,
564 hide_timeout, NULL, NULL);
565 }
566 }
This page took 0.064694 seconds and 5 git commands to generate.