]> Dogcows Code - chaz/openbox/blob - openbox/dock.c
little bit of an actions overhaul, added action_run* so that duplicated code can...
[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 (!dock->dock_apps) {
359 STRUT_PARTIAL_SET(dock_strut, 0, 0, 0, 0,
360 0, 0, 0, 0, 0, 0, 0, 0);
361 } else if (config_dock_floating) {
362 STRUT_PARTIAL_SET(dock_strut, 0, 0, 0, 0,
363 0, 0, 0, 0, 0, 0, 0, 0);
364 } else {
365 switch (config_dock_pos) {
366 case OB_DIRECTION_NORTHWEST:
367 switch (config_dock_orient) {
368 case OB_ORIENTATION_HORZ:
369 STRUT_PARTIAL_SET(dock_strut, 0, strh, 0, 0,
370 0, 0, dock->x, dock->x + dock->w - 1,
371 0, 0, 0, 0);
372 break;
373 case OB_ORIENTATION_VERT:
374 STRUT_PARTIAL_SET(dock_strut, strw, 0, 0, 0,
375 dock->y, dock->y + dock->h - 1,
376 0, 0, 0, 0, 0, 0);
377 break;
378 }
379 break;
380 case OB_DIRECTION_NORTH:
381 STRUT_PARTIAL_SET(dock_strut, 0, strh, 0, 0,
382 dock->x, dock->x + dock->w - 1,
383 0, 0, 0, 0, 0, 0);
384 break;
385 case OB_DIRECTION_NORTHEAST:
386 switch (config_dock_orient) {
387 case OB_ORIENTATION_HORZ:
388 STRUT_PARTIAL_SET(dock_strut, 0, strh, 0, 0,
389 0, 0, dock->x, dock->x + dock->w -1,
390 0, 0, 0, 0);
391 break;
392 case OB_ORIENTATION_VERT:
393 STRUT_PARTIAL_SET(dock_strut, 0, 0, strw, 0,
394 0, 0, 0, 0,
395 dock->y, dock->y + dock->h - 1, 0, 0);
396 break;
397 }
398 break;
399 case OB_DIRECTION_WEST:
400 STRUT_PARTIAL_SET(dock_strut, strw, 0, 0, 0,
401 dock->y, dock->y + dock->h - 1,
402 0, 0, 0, 0, 0, 0);
403 break;
404 case OB_DIRECTION_EAST:
405 STRUT_PARTIAL_SET(dock_strut, 0, 0, strw, 0,
406 0, 0, 0, 0,
407 dock->y, dock->y + dock->h - 1, 0, 0);
408 break;
409 case OB_DIRECTION_SOUTHWEST:
410 switch (config_dock_orient) {
411 case OB_ORIENTATION_HORZ:
412 STRUT_PARTIAL_SET(dock_strut, 0, 0, 0, strh,
413 0, 0, 0, 0, 0, 0,
414 dock->x, dock->x + dock->w - 1);
415 break;
416 case OB_ORIENTATION_VERT:
417 STRUT_PARTIAL_SET(dock_strut, strw, 0, 0, 0,
418 dock->y, dock->y + dock->h - 1,
419 0, 0, 0, 0, 0, 0);
420 break;
421 }
422 break;
423 case OB_DIRECTION_SOUTH:
424 STRUT_PARTIAL_SET(dock_strut, 0, 0, 0, strh,
425 0, 0, 0, 0, 0, 0,
426 dock->x, dock->x + dock->w - 1);
427 break;
428 case OB_DIRECTION_SOUTHEAST:
429 switch (config_dock_orient) {
430 case OB_ORIENTATION_HORZ:
431 STRUT_PARTIAL_SET(dock_strut, 0, 0, 0, strh,
432 0, 0, 0, 0, 0, 0,
433 dock->x, dock->x + dock->w - 1);
434 break;
435 case OB_ORIENTATION_VERT:
436 STRUT_PARTIAL_SET(dock_strut, 0, 0, strw, 0,
437 0, 0, 0, 0,
438 dock->y, dock->y + dock->h - 1, 0, 0);
439 break;
440 }
441 break;
442 }
443 }
444
445 dock->w += minw;
446 dock->h += minh;
447
448 /* not used for actually sizing shit */
449 dock->w -= ob_rr_theme->bwidth * 2;
450 dock->h -= ob_rr_theme->bwidth * 2;
451
452 if (dock->dock_apps) {
453 g_assert(dock->w > 0);
454 g_assert(dock->h > 0);
455
456 XMoveResizeWindow(ob_display, dock->frame,
457 dock->x, dock->y, dock->w, dock->h);
458
459 RrPaint(dock->a_frame, dock->frame, dock->w, dock->h);
460 XMapWindow(ob_display, dock->frame);
461 } else
462 XUnmapWindow(ob_display, dock->frame);
463
464 /* but they are useful outside of this function! */
465 dock->w += ob_rr_theme->bwidth * 2;
466 dock->h += ob_rr_theme->bwidth * 2;
467
468 screen_update_areas();
469 }
470
471 void dock_app_configure(ObDockApp *app, gint w, gint h)
472 {
473 app->w = w;
474 app->h = h;
475 dock_configure();
476 }
477
478 void dock_app_drag(ObDockApp *app, XMotionEvent *e)
479 {
480 ObDockApp *over = NULL;
481 GList *it;
482 gint x, y;
483 gboolean after;
484 gboolean stop;
485
486 x = e->x_root;
487 y = e->y_root;
488
489 /* are we on top of the dock? */
490 if (!(x >= dock->x &&
491 y >= dock->y &&
492 x < dock->x + dock->w &&
493 y < dock->y + dock->h))
494 return;
495
496 x -= dock->x;
497 y -= dock->y;
498
499 /* which dock app are we on top of? */
500 stop = FALSE;
501 for (it = dock->dock_apps; it; it = it->next) {
502 over = it->data;
503 switch (config_dock_orient) {
504 case OB_ORIENTATION_HORZ:
505 if (x >= over->x && x < over->x + over->w)
506 stop = TRUE;
507 break;
508 case OB_ORIENTATION_VERT:
509 if (y >= over->y && y < over->y + over->h)
510 stop = TRUE;
511 break;
512 }
513 /* dont go to it->next! */
514 if (stop) break;
515 }
516 if (!it || app == over) return;
517
518 x -= over->x;
519 y -= over->y;
520
521 switch (config_dock_orient) {
522 case OB_ORIENTATION_HORZ:
523 after = (x > over->w / 2);
524 break;
525 case OB_ORIENTATION_VERT:
526 after = (y > over->h / 2);
527 break;
528 }
529
530 /* remove before doing the it->next! */
531 dock->dock_apps = g_list_remove(dock->dock_apps, app);
532
533 if (after) it = it->next;
534
535 dock->dock_apps = g_list_insert_before(dock->dock_apps, it, app);
536 dock_configure();
537 }
538
539 static gboolean hide_timeout(gpointer data)
540 {
541 /* hide */
542 dock->hidden = TRUE;
543 dock_configure();
544
545 return FALSE; /* don't repeat */
546 }
547
548 void dock_hide(gboolean hide)
549 {
550 if (dock->hidden == hide || !config_dock_hide)
551 return;
552 if (!hide) {
553 /* show */
554 dock->hidden = FALSE;
555 dock_configure();
556
557 /* if was hiding, stop it */
558 ob_main_loop_timeout_remove(ob_main_loop, hide_timeout);
559 } else {
560 ob_main_loop_timeout_add(ob_main_loop, config_dock_hide_timeout * 1000,
561 hide_timeout, NULL, NULL);
562 }
563 }
This page took 0.06056 seconds and 4 git commands to generate.