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