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