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