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