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