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