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