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