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