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