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