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