]> Dogcows Code - chaz/openbox/blob - openbox/dock.c
experimental change. when apps map, make them fit inside the struts and the screen...
[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 {
419 STRUT_PARTIAL_SET(dock_strut, 0, 0, 0, 0,
420 0, 0, 0, 0, 0, 0, 0, 0);
421 } else {
422 switch (config_dock_pos) {
423 case OB_DIRECTION_NORTHWEST:
424 switch (config_dock_orient) {
425 case OB_ORIENTATION_HORZ:
426 STRUT_PARTIAL_SET(dock_strut, 0, strh, 0, 0,
427 0, 0, dock->x, dock->x + dock->w - 1,
428 0, 0, 0, 0);
429 break;
430 case OB_ORIENTATION_VERT:
431 STRUT_PARTIAL_SET(dock_strut, strw, 0, 0, 0,
432 dock->y, dock->y + dock->h - 1,
433 0, 0, 0, 0, 0, 0);
434 break;
435 }
436 break;
437 case OB_DIRECTION_NORTH:
438 STRUT_PARTIAL_SET(dock_strut, 0, strh, 0, 0,
439 dock->x, dock->x + dock->w - 1,
440 0, 0, 0, 0, 0, 0);
441 break;
442 case OB_DIRECTION_NORTHEAST:
443 switch (config_dock_orient) {
444 case OB_ORIENTATION_HORZ:
445 STRUT_PARTIAL_SET(dock_strut, 0, strh, 0, 0,
446 0, 0, dock->x, dock->x + dock->w -1,
447 0, 0, 0, 0);
448 break;
449 case OB_ORIENTATION_VERT:
450 STRUT_PARTIAL_SET(dock_strut, 0, 0, strw, 0,
451 0, 0, 0, 0,
452 dock->y, dock->y + dock->h - 1, 0, 0);
453 break;
454 }
455 break;
456 case OB_DIRECTION_WEST:
457 STRUT_PARTIAL_SET(dock_strut, strw, 0, 0, 0,
458 dock->y, dock->y + dock->h - 1,
459 0, 0, 0, 0, 0, 0);
460 break;
461 case OB_DIRECTION_EAST:
462 STRUT_PARTIAL_SET(dock_strut, 0, 0, strw, 0,
463 0, 0, 0, 0,
464 dock->y, dock->y + dock->h - 1, 0, 0);
465 break;
466 case OB_DIRECTION_SOUTHWEST:
467 switch (config_dock_orient) {
468 case OB_ORIENTATION_HORZ:
469 STRUT_PARTIAL_SET(dock_strut, 0, 0, 0, strh,
470 0, 0, 0, 0, 0, 0,
471 dock->x, dock->x + dock->w - 1);
472 break;
473 case OB_ORIENTATION_VERT:
474 STRUT_PARTIAL_SET(dock_strut, strw, 0, 0, 0,
475 dock->y, dock->y + dock->h - 1,
476 0, 0, 0, 0, 0, 0);
477 break;
478 }
479 break;
480 case OB_DIRECTION_SOUTH:
481 STRUT_PARTIAL_SET(dock_strut, 0, 0, 0, strh,
482 0, 0, 0, 0, 0, 0,
483 dock->x, dock->x + dock->w - 1);
484 break;
485 case OB_DIRECTION_SOUTHEAST:
486 switch (config_dock_orient) {
487 case OB_ORIENTATION_HORZ:
488 STRUT_PARTIAL_SET(dock_strut, 0, 0, 0, strh,
489 0, 0, 0, 0, 0, 0,
490 dock->x, dock->x + dock->w - 1);
491 break;
492 case OB_ORIENTATION_VERT:
493 STRUT_PARTIAL_SET(dock_strut, 0, 0, strw, 0,
494 0, 0, 0, 0,
495 dock->y, dock->y + dock->h - 1, 0, 0);
496 break;
497 }
498 break;
499 }
500 }
501
502 dock->w += minw;
503 dock->h += minh;
504
505 /* not used for actually sizing shit */
506 dock->w -= ob_rr_theme->fbwidth * 2;
507 dock->h -= ob_rr_theme->fbwidth * 2;
508
509 if (dock->dock_apps) {
510 g_assert(dock->w > 0);
511 g_assert(dock->h > 0);
512
513 XMoveResizeWindow(ob_display, dock->frame,
514 dock->x, dock->y, dock->w, dock->h);
515
516 RrPaint(dock->a_frame, dock->frame, dock->w, dock->h);
517 XMapWindow(ob_display, dock->frame);
518 } else
519 XUnmapWindow(ob_display, dock->frame);
520
521 /* but they are useful outside of this function! */
522 dock->w += ob_rr_theme->fbwidth * 2;
523 dock->h += ob_rr_theme->fbwidth * 2;
524
525 screen_update_areas();
526 }
527
528 void dock_app_configure(ObDockApp *app, gint w, gint h)
529 {
530 app->w = w;
531 app->h = h;
532 dock_configure();
533 }
534
535 void dock_app_drag(ObDockApp *app, XMotionEvent *e)
536 {
537 ObDockApp *over = NULL;
538 GList *it;
539 gint x, y;
540 gboolean after;
541 gboolean stop;
542
543 x = e->x_root;
544 y = e->y_root;
545
546 /* are we on top of the dock? */
547 if (!(x >= dock->x &&
548 y >= dock->y &&
549 x < dock->x + dock->w &&
550 y < dock->y + dock->h))
551 return;
552
553 x -= dock->x;
554 y -= dock->y;
555
556 /* which dock app are we on top of? */
557 stop = FALSE;
558 for (it = dock->dock_apps; it; it = g_list_next(it)) {
559 over = it->data;
560 switch (config_dock_orient) {
561 case OB_ORIENTATION_HORZ:
562 if (x >= over->x && x < over->x + over->w)
563 stop = TRUE;
564 break;
565 case OB_ORIENTATION_VERT:
566 if (y >= over->y && y < over->y + over->h)
567 stop = TRUE;
568 break;
569 }
570 /* dont go to it->next! */
571 if (stop) break;
572 }
573 if (!it || app == over) return;
574
575 x -= over->x;
576 y -= over->y;
577
578 switch (config_dock_orient) {
579 case OB_ORIENTATION_HORZ:
580 after = (x > over->w / 2);
581 break;
582 case OB_ORIENTATION_VERT:
583 after = (y > over->h / 2);
584 break;
585 default:
586 g_assert_not_reached();
587 }
588
589 /* remove before doing the it->next! */
590 dock->dock_apps = g_list_remove(dock->dock_apps, app);
591
592 if (after) it = it->next;
593
594 dock->dock_apps = g_list_insert_before(dock->dock_apps, it, app);
595 dock_configure();
596 }
597
598 static gboolean hide_timeout(gpointer data)
599 {
600 /* hide */
601 dock->hidden = TRUE;
602 dock_configure();
603
604 return FALSE; /* don't repeat */
605 }
606
607 static gboolean show_timeout(gpointer data)
608 {
609 /* hide */
610 dock->hidden = FALSE;
611 dock_configure();
612
613 return FALSE; /* don't repeat */
614 }
615
616 void dock_hide(gboolean hide)
617 {
618 if (!hide) {
619 if (dock->hidden && config_dock_hide) {
620 ob_main_loop_timeout_add(ob_main_loop, config_dock_show_delay,
621 show_timeout, NULL, g_direct_equal, NULL);
622 } else if (!dock->hidden && config_dock_hide) {
623 ob_main_loop_timeout_remove(ob_main_loop, hide_timeout);
624 }
625 } else {
626 if (!dock->hidden && config_dock_hide) {
627 ob_main_loop_timeout_add(ob_main_loop, config_dock_hide_delay,
628 hide_timeout, NULL, g_direct_equal, NULL);
629 } else if (dock->hidden && config_dock_hide) {
630 ob_main_loop_timeout_remove(ob_main_loop, show_timeout);
631 }
632 }
633 }
This page took 0.064683 seconds and 4 git commands to generate.