]> Dogcows Code - chaz/openbox/blob - openbox/dock.c
change the "handle" context to "bottom". add a "top" context. make the top
[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->
61 frame_focused_border_color));
62 XSetWindowBorderWidth(ob_display, dock->frame, ob_rr_theme->fbwidth);
63
64 RrAppearanceFree(dock->a_frame);
65 dock->a_frame = RrAppearanceCopy(ob_rr_theme->a_focused_title);
66
67 stacking_add(DOCK_AS_WINDOW(dock));
68
69 dock_configure();
70 dock_hide(TRUE);
71
72 for (it = dock->dock_apps; it; it = g_list_next(it))
73 dock_app_grab_button(it->data, TRUE);
74 return;
75 }
76
77 STRUT_PARTIAL_SET(dock_strut, 0, 0, 0, 0,
78 0, 0, 0, 0, 0, 0, 0, 0);
79
80 dock = g_new0(ObDock, 1);
81 dock->obwin.type = Window_Dock;
82
83 dock->hidden = TRUE;
84
85 attrib.event_mask = DOCK_EVENT_MASK;
86 attrib.override_redirect = True;
87 dock->frame = XCreateWindow(ob_display, RootWindow(ob_display, ob_screen),
88 0, 0, 1, 1, 0,
89 RrDepth(ob_rr_inst), InputOutput,
90 RrVisual(ob_rr_inst),
91 CWOverrideRedirect | CWEventMask,
92 &attrib);
93 dock->a_frame = RrAppearanceCopy(ob_rr_theme->a_focused_title);
94 XSetWindowBorder(ob_display, dock->frame,
95 RrColorPixel(ob_rr_theme->frame_focused_border_color));
96 XSetWindowBorderWidth(ob_display, dock->frame, ob_rr_theme->fbwidth);
97
98 g_hash_table_insert(window_map, &dock->frame, dock);
99 stacking_add(DOCK_AS_WINDOW(dock));
100 }
101
102 void dock_shutdown(gboolean reconfig)
103 {
104 if (reconfig) {
105 GList *it;
106
107 stacking_remove(DOCK_AS_WINDOW(dock));
108
109 for (it = dock->dock_apps; it; it = g_list_next(it))
110 dock_app_grab_button(it->data, FALSE);
111 return;
112 }
113
114 XDestroyWindow(ob_display, dock->frame);
115 RrAppearanceFree(dock->a_frame);
116 g_hash_table_remove(window_map, &dock->frame);
117 stacking_remove(dock);
118 }
119
120 void dock_add(Window win, XWMHints *wmhints)
121 {
122 ObDockApp *app;
123 XWindowAttributes attrib;
124 gchar **data;
125
126 app = g_new0(ObDockApp, 1);
127 app->obwin.type = Window_DockApp;
128 app->win = win;
129 app->icon_win = (wmhints->flags & IconWindowHint) ?
130 wmhints->icon_window : win;
131
132 if (PROP_GETSS(app->win, wm_class, locale, &data)) {
133 if (data[0]) {
134 app->name = g_strdup(data[0]);
135 if (data[1])
136 app->class = g_strdup(data[1]);
137 }
138 g_strfreev(data);
139 }
140
141 if (app->name == NULL) app->name = g_strdup("");
142 if (app->class == NULL) app->class = g_strdup("");
143
144 if (XGetWindowAttributes(ob_display, app->icon_win, &attrib)) {
145 app->w = attrib.width;
146 app->h = attrib.height;
147 } else {
148 app->w = app->h = 64;
149 }
150
151 dock->dock_apps = g_list_append(dock->dock_apps, app);
152 dock_configure();
153
154 XReparentWindow(ob_display, app->icon_win, dock->frame, app->x, app->y);
155 /*
156 This is the same case as in frame.c for client windows. When Openbox is
157 starting, the window is already mapped so we see unmap events occur for
158 it. There are 2 unmap events generated that we see, one with the 'event'
159 member set the root window, and one set to the client, but both get
160 handled and need to be ignored.
161 */
162 if (ob_state() == OB_STATE_STARTING)
163 app->ignore_unmaps += 2;
164
165 if (app->win != app->icon_win) {
166 /* have to map it so that it can be re-managed on a restart */
167 XMoveWindow(ob_display, app->win, -1000, -1000);
168 XMapWindow(ob_display, app->win);
169 }
170 XMapWindow(ob_display, app->icon_win);
171 XSync(ob_display, False);
172
173 /* specify that if we exit, the window should not be destroyed and should
174 be reparented back to root automatically */
175 XChangeSaveSet(ob_display, app->icon_win, SetModeInsert);
176 XSelectInput(ob_display, app->icon_win, DOCKAPP_EVENT_MASK);
177
178 dock_app_grab_button(app, TRUE);
179
180 g_hash_table_insert(window_map, &app->icon_win, app);
181
182 ob_debug("Managed Dock App: 0x%lx (%s)\n", app->icon_win, app->class);
183 }
184
185 void dock_remove_all()
186 {
187 while (dock->dock_apps)
188 dock_remove(dock->dock_apps->data, TRUE);
189 }
190
191 void dock_remove(ObDockApp *app, gboolean reparent)
192 {
193 dock_app_grab_button(app, FALSE);
194 XSelectInput(ob_display, app->icon_win, NoEventMask);
195 /* remove the window from our save set */
196 XChangeSaveSet(ob_display, app->icon_win, SetModeDelete);
197 XSync(ob_display, False);
198
199 g_hash_table_remove(window_map, &app->icon_win);
200
201 if (reparent)
202 XReparentWindow(ob_display, app->icon_win,
203 RootWindow(ob_display, ob_screen), app->x, app->y);
204
205 dock->dock_apps = g_list_remove(dock->dock_apps, app);
206 dock_configure();
207
208 ob_debug("Unmanaged Dock App: 0x%lx (%s)\n", app->icon_win, app->class);
209
210 g_free(app->name);
211 g_free(app->class);
212 g_free(app);
213 }
214
215 void dock_configure()
216 {
217 GList *it;
218 gint spot;
219 gint gravity;
220 gint minw, minh;
221 gint strw, strh;
222 Rect *a;
223
224 RrMinSize(dock->a_frame, &minw, &minh);
225
226 dock->w = dock->h = 0;
227
228 /* get the size */
229 for (it = dock->dock_apps; it; it = g_list_next(it)) {
230 ObDockApp *app = it->data;
231 switch (config_dock_orient) {
232 case OB_ORIENTATION_HORZ:
233 dock->w += app->w;
234 dock->h = MAX(dock->h, app->h);
235 break;
236 case OB_ORIENTATION_VERT:
237 dock->w = MAX(dock->w, app->w);
238 dock->h += app->h;
239 break;
240 }
241 }
242
243 spot = (config_dock_orient == OB_ORIENTATION_HORZ ? minw : minh) / 2;
244
245 /* position the apps */
246 for (it = dock->dock_apps; it; it = g_list_next(it)) {
247 ObDockApp *app = it->data;
248 switch (config_dock_orient) {
249 case OB_ORIENTATION_HORZ:
250 app->x = spot;
251 app->y = (dock->h - app->h) / 2;
252 spot += app->w;
253 break;
254 case OB_ORIENTATION_VERT:
255 app->x = (dock->w - app->w) / 2;
256 app->y = spot;
257 spot += app->h;
258 break;
259 }
260
261 XMoveWindow(ob_display, app->icon_win, app->x, app->y);
262 }
263
264 /* used for calculating offsets */
265 dock->w += ob_rr_theme->fbwidth * 2;
266 dock->h += ob_rr_theme->fbwidth * 2;
267
268 a = screen_physical_area();
269
270 /* calculate position */
271 if (config_dock_floating) {
272 dock->x = config_dock_x;
273 dock->y = config_dock_y;
274 gravity = NorthWestGravity;
275 } else {
276 switch (config_dock_pos) {
277 case OB_DIRECTION_NORTHWEST:
278 dock->x = 0;
279 dock->y = 0;
280 gravity = NorthWestGravity;
281 break;
282 case OB_DIRECTION_NORTH:
283 dock->x = a->width / 2;
284 dock->y = 0;
285 gravity = NorthGravity;
286 break;
287 case OB_DIRECTION_NORTHEAST:
288 dock->x = a->width;
289 dock->y = 0;
290 gravity = NorthEastGravity;
291 break;
292 case OB_DIRECTION_WEST:
293 dock->x = 0;
294 dock->y = a->height / 2;
295 gravity = WestGravity;
296 break;
297 case OB_DIRECTION_EAST:
298 dock->x = a->width;
299 dock->y = a->height / 2;
300 gravity = EastGravity;
301 break;
302 case OB_DIRECTION_SOUTHWEST:
303 dock->x = 0;
304 dock->y = a->height;
305 gravity = SouthWestGravity;
306 break;
307 case OB_DIRECTION_SOUTH:
308 dock->x = a->width / 2;
309 dock->y = a->height;
310 gravity = SouthGravity;
311 break;
312 case OB_DIRECTION_SOUTHEAST:
313 dock->x = a->width;
314 dock->y = a->height;
315 gravity = SouthEastGravity;
316 break;
317 default:
318 g_assert_not_reached();
319 }
320 }
321
322 switch(gravity) {
323 case NorthGravity:
324 case CenterGravity:
325 case SouthGravity:
326 dock->x -= dock->w / 2;
327 break;
328 case NorthEastGravity:
329 case EastGravity:
330 case SouthEastGravity:
331 dock->x -= dock->w;
332 break;
333 }
334 switch(gravity) {
335 case WestGravity:
336 case CenterGravity:
337 case EastGravity:
338 dock->y -= dock->h / 2;
339 break;
340 case SouthWestGravity:
341 case SouthGravity:
342 case SouthEastGravity:
343 dock->y -= dock->h;
344 break;
345 }
346
347 if (config_dock_hide && dock->hidden) {
348 if (!config_dock_floating) {
349 switch (config_dock_pos) {
350 case OB_DIRECTION_NORTHWEST:
351 switch (config_dock_orient) {
352 case OB_ORIENTATION_HORZ:
353 dock->y -= dock->h - ob_rr_theme->fbwidth;
354 break;
355 case OB_ORIENTATION_VERT:
356 dock->x -= dock->w - ob_rr_theme->fbwidth;
357 break;
358 }
359 break;
360 case OB_DIRECTION_NORTH:
361 dock->y -= dock->h - ob_rr_theme->fbwidth;
362 break;
363 case OB_DIRECTION_NORTHEAST:
364 switch (config_dock_orient) {
365 case OB_ORIENTATION_HORZ:
366 dock->y -= dock->h - ob_rr_theme->fbwidth;
367 break;
368 case OB_ORIENTATION_VERT:
369 dock->x += dock->w - ob_rr_theme->fbwidth;
370 break;
371 }
372 break;
373 case OB_DIRECTION_WEST:
374 dock->x -= dock->w - ob_rr_theme->fbwidth;
375 break;
376 case OB_DIRECTION_EAST:
377 dock->x += dock->w - ob_rr_theme->fbwidth;
378 break;
379 case OB_DIRECTION_SOUTHWEST:
380 switch (config_dock_orient) {
381 case OB_ORIENTATION_HORZ:
382 dock->y += dock->h - ob_rr_theme->fbwidth;
383 break;
384 case OB_ORIENTATION_VERT:
385 dock->x -= dock->w - ob_rr_theme->fbwidth;
386 break;
387 } break;
388 case OB_DIRECTION_SOUTH:
389 dock->y += dock->h - ob_rr_theme->fbwidth;
390 break;
391 case OB_DIRECTION_SOUTHEAST:
392 switch (config_dock_orient) {
393 case OB_ORIENTATION_HORZ:
394 dock->y += dock->h - ob_rr_theme->fbwidth;
395 break;
396 case OB_ORIENTATION_VERT:
397 dock->x += dock->w - ob_rr_theme->fbwidth;
398 break;
399 }
400 break;
401 }
402 }
403 }
404
405 if (!config_dock_floating && config_dock_hide) {
406 strw = ob_rr_theme->fbwidth;
407 strh = ob_rr_theme->fbwidth;
408 } else {
409 strw = dock->w;
410 strh = dock->h;
411 }
412
413 /* set the strut */
414 if (!dock->dock_apps) {
415 STRUT_PARTIAL_SET(dock_strut, 0, 0, 0, 0,
416 0, 0, 0, 0, 0, 0, 0, 0);
417 } else if (config_dock_floating || config_dock_nostrut) {
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->fbwidth * 2;
506 dock->h -= ob_rr_theme->fbwidth * 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->fbwidth * 2;
522 dock->h += ob_rr_theme->fbwidth * 2;
523
524 screen_update_areas();
525 }
526
527 void dock_app_configure(ObDockApp *app, gint w, gint h)
528 {
529 app->w = w;
530 app->h = h;
531 dock_configure();
532 }
533
534 void dock_app_drag(ObDockApp *app, XMotionEvent *e)
535 {
536 ObDockApp *over = NULL;
537 GList *it;
538 gint x, y;
539 gboolean after;
540 gboolean stop;
541
542 x = e->x_root;
543 y = e->y_root;
544
545 /* are we on top of the dock? */
546 if (!(x >= dock->x &&
547 y >= dock->y &&
548 x < dock->x + dock->w &&
549 y < dock->y + dock->h))
550 return;
551
552 x -= dock->x;
553 y -= dock->y;
554
555 /* which dock app are we on top of? */
556 stop = FALSE;
557 for (it = dock->dock_apps; it; it = g_list_next(it)) {
558 over = it->data;
559 switch (config_dock_orient) {
560 case OB_ORIENTATION_HORZ:
561 if (x >= over->x && x < over->x + over->w)
562 stop = TRUE;
563 break;
564 case OB_ORIENTATION_VERT:
565 if (y >= over->y && y < over->y + over->h)
566 stop = TRUE;
567 break;
568 }
569 /* dont go to it->next! */
570 if (stop) break;
571 }
572 if (!it || app == over) return;
573
574 x -= over->x;
575 y -= over->y;
576
577 switch (config_dock_orient) {
578 case OB_ORIENTATION_HORZ:
579 after = (x > over->w / 2);
580 break;
581 case OB_ORIENTATION_VERT:
582 after = (y > over->h / 2);
583 break;
584 default:
585 g_assert_not_reached();
586 }
587
588 /* remove before doing the it->next! */
589 dock->dock_apps = g_list_remove(dock->dock_apps, app);
590
591 if (after) it = it->next;
592
593 dock->dock_apps = g_list_insert_before(dock->dock_apps, it, app);
594 dock_configure();
595 }
596
597 static gboolean hide_timeout(gpointer data)
598 {
599 /* hide */
600 dock->hidden = TRUE;
601 dock_configure();
602
603 return FALSE; /* don't repeat */
604 }
605
606 static gboolean show_timeout(gpointer data)
607 {
608 /* hide */
609 dock->hidden = FALSE;
610 dock_configure();
611
612 return FALSE; /* don't repeat */
613 }
614
615 void dock_hide(gboolean hide)
616 {
617 if (!hide) {
618 if (dock->hidden && config_dock_hide) {
619 ob_main_loop_timeout_add(ob_main_loop, config_dock_show_delay,
620 show_timeout, NULL, g_direct_equal, NULL);
621 } else if (!dock->hidden && config_dock_hide) {
622 ob_main_loop_timeout_remove(ob_main_loop, hide_timeout);
623 }
624 } else {
625 if (!dock->hidden && config_dock_hide) {
626 ob_main_loop_timeout_add(ob_main_loop, config_dock_hide_delay,
627 hide_timeout, NULL, g_direct_equal, NULL);
628 } else if (dock->hidden && config_dock_hide) {
629 ob_main_loop_timeout_remove(ob_main_loop, show_timeout);
630 }
631 }
632 }
This page took 0.059801 seconds and 4 git commands to generate.