]> Dogcows Code - chaz/openbox/blob - openbox/dock.c
prefixing for the dock. use ObDirection instead of dupliacting it in another enum...
[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 if (config_dock_horz) {
165 dock->w += app->w;
166 dock->h = MAX(dock->h, app->h);
167 } else {
168 dock->w = MAX(dock->w, app->w);
169 dock->h += app->h;
170 }
171 }
172
173 spot = (config_dock_horz ? minw : minh) / 2;
174
175 /* position the apps */
176 for (it = dock->dock_apps; it; it = it->next) {
177 ObDockApp *app = it->data;
178 if (config_dock_horz) {
179 app->x = spot;
180 app->y = (dock->h - app->h) / 2;
181 spot += app->w;
182 } else {
183 app->x = (dock->w - app->w) / 2;
184 app->y = spot;
185 spot += app->h;
186 }
187
188 XMoveWindow(ob_display, app->icon_win, app->x, app->y);
189 }
190
191 /* used for calculating offsets */
192 dock->w += ob_rr_theme->bwidth * 2;
193 dock->h += ob_rr_theme->bwidth * 2;
194
195 a = screen_physical_area();
196
197 /* calculate position */
198 if (config_dock_floating) {
199 dock->x = config_dock_x;
200 dock->y = config_dock_y;
201 gravity = NorthWestGravity;
202 } else {
203 switch (config_dock_pos) {
204 case OB_DIRECTION_NORTHWEST:
205 dock->x = 0;
206 dock->y = 0;
207 gravity = NorthWestGravity;
208 break;
209 case OB_DIRECTION_NORTH:
210 dock->x = a->width / 2;
211 dock->y = 0;
212 gravity = NorthGravity;
213 break;
214 case OB_DIRECTION_NORTHEAST:
215 dock->x = a->width;
216 dock->y = 0;
217 gravity = NorthEastGravity;
218 break;
219 case OB_DIRECTION_WEST:
220 dock->x = 0;
221 dock->y = a->height / 2;
222 gravity = WestGravity;
223 break;
224 case OB_DIRECTION_EAST:
225 dock->x = a->width;
226 dock->y = a->height / 2;
227 gravity = EastGravity;
228 break;
229 case OB_DIRECTION_SOUTHWEST:
230 dock->x = 0;
231 dock->y = a->height;
232 gravity = SouthWestGravity;
233 break;
234 case OB_DIRECTION_SOUTH:
235 dock->x = a->width / 2;
236 dock->y = a->height;
237 gravity = SouthGravity;
238 break;
239 case OB_DIRECTION_SOUTHEAST:
240 dock->x = a->width;
241 dock->y = a->height;
242 gravity = SouthEastGravity;
243 break;
244 }
245 }
246
247 switch(gravity) {
248 case NorthGravity:
249 case CenterGravity:
250 case SouthGravity:
251 dock->x -= dock->w / 2;
252 break;
253 case NorthEastGravity:
254 case EastGravity:
255 case SouthEastGravity:
256 dock->x -= dock->w;
257 break;
258 }
259 switch(gravity) {
260 case WestGravity:
261 case CenterGravity:
262 case EastGravity:
263 dock->y -= dock->h / 2;
264 break;
265 case SouthWestGravity:
266 case SouthGravity:
267 case SouthEastGravity:
268 dock->y -= dock->h;
269 break;
270 }
271
272 if (config_dock_hide && dock->hidden) {
273 if (!config_dock_floating) {
274 switch (config_dock_pos) {
275 case OB_DIRECTION_NORTHWEST:
276 if (config_dock_horz)
277 dock->y -= dock->h - ob_rr_theme->bwidth;
278 else
279 dock->x -= dock->w - ob_rr_theme->bwidth;
280 break;
281 case OB_DIRECTION_NORTH:
282 dock->y -= dock->h - ob_rr_theme->bwidth;
283 break;
284 case OB_DIRECTION_NORTHEAST:
285 if (config_dock_horz)
286 dock->y -= dock->h - ob_rr_theme->bwidth;
287 else
288 dock->x += dock->w - ob_rr_theme->bwidth;
289 break;
290 case OB_DIRECTION_WEST:
291 dock->x -= dock->w - ob_rr_theme->bwidth;
292 break;
293 case OB_DIRECTION_EAST:
294 dock->x += dock->w - ob_rr_theme->bwidth;
295 break;
296 case OB_DIRECTION_SOUTHWEST:
297 if (config_dock_horz)
298 dock->y += dock->h - ob_rr_theme->bwidth;
299 else
300 dock->x -= dock->w - ob_rr_theme->bwidth;
301 break;
302 case OB_DIRECTION_SOUTH:
303 dock->y += dock->h - ob_rr_theme->bwidth;
304 break;
305 case OB_DIRECTION_SOUTHEAST:
306 if (config_dock_horz)
307 dock->y += dock->h - ob_rr_theme->bwidth;
308 else
309 dock->x += dock->w - ob_rr_theme->bwidth;
310 break;
311 }
312 }
313 }
314
315 if (!config_dock_floating && config_dock_hide) {
316 strw = strh = ob_rr_theme->bwidth;
317 } else {
318 strw = dock->w;
319 strh = dock->h;
320 }
321
322 /* set the strut */
323 if (config_dock_floating) {
324 STRUT_SET(dock_strut, 0, 0, 0, 0);
325 } else {
326 switch (config_dock_pos) {
327 case OB_DIRECTION_NORTHWEST:
328 if (config_dock_horz)
329 STRUT_SET(dock_strut, 0, strh, 0, 0);
330 else
331 STRUT_SET(dock_strut, strw, 0, 0, 0);
332 break;
333 case OB_DIRECTION_NORTH:
334 STRUT_SET(dock_strut, 0, strh, 0, 0);
335 break;
336 case OB_DIRECTION_NORTHEAST:
337 if (config_dock_horz)
338 STRUT_SET(dock_strut, 0, strh, 0, 0);
339 else
340 STRUT_SET(dock_strut, 0, 0, strw, 0);
341 break;
342 case OB_DIRECTION_WEST:
343 STRUT_SET(dock_strut, strw, 0, 0, 0);
344 break;
345 case OB_DIRECTION_EAST:
346 STRUT_SET(dock_strut, 0, 0, strw, 0);
347 break;
348 case OB_DIRECTION_SOUTHWEST:
349 if (config_dock_horz)
350 STRUT_SET(dock_strut, 0, 0, 0, strh);
351 else
352 STRUT_SET(dock_strut, strw, 0, 0, 0);
353 break;
354 case OB_DIRECTION_SOUTH:
355 STRUT_SET(dock_strut, 0, 0, 0, strh);
356 break;
357 case OB_DIRECTION_SOUTHEAST:
358 if (config_dock_horz)
359 STRUT_SET(dock_strut, 0, 0, 0, strh);
360 else
361 STRUT_SET(dock_strut, 0, 0, strw, 0);
362 break;
363 }
364 }
365
366 dock->w += minw;
367 dock->h += minh;
368
369 /* not used for actually sizing shit */
370 dock->w -= ob_rr_theme->bwidth * 2;
371 dock->h -= ob_rr_theme->bwidth * 2;
372
373 if (dock->w > 0 && dock->h > 0) {
374 XMoveResizeWindow(ob_display, dock->frame,
375 dock->x, dock->y, dock->w, dock->h);
376
377 RrPaint(dock->a_frame, dock->frame, dock->w, dock->h);
378 XMapWindow(ob_display, dock->frame);
379 } else
380 XUnmapWindow(ob_display, dock->frame);
381
382 /* but they are useful outside of this function! */
383 dock->w += ob_rr_theme->bwidth * 2;
384 dock->h += ob_rr_theme->bwidth * 2;
385
386 screen_update_areas();
387 }
388
389 void dock_app_configure(ObDockApp *app, gint w, gint h)
390 {
391 app->w = w;
392 app->h = h;
393 dock_configure();
394 }
395
396 void dock_app_drag(ObDockApp *app, XMotionEvent *e)
397 {
398 ObDockApp *over = NULL;
399 GList *it;
400 gint x, y;
401 gboolean after;
402
403 x = e->x_root;
404 y = e->y_root;
405
406 /* are we on top of the dock? */
407 if (!(x >= dock->x &&
408 y >= dock->y &&
409 x < dock->x + dock->w &&
410 y < dock->y + dock->h))
411 return;
412
413 x -= dock->x;
414 y -= dock->y;
415
416 /* which dock app are we on top of? */
417 for (it = dock->dock_apps; it; it = it->next) {
418 over = it->data;
419 if (config_dock_horz) {
420 if (x >= over->x && x < over->x + over->w)
421 break;
422 } else {
423 if (y >= over->y && y < over->y + over->h)
424 break;
425 }
426 }
427 if (!it || app == over) return;
428
429 x -= over->x;
430 y -= over->y;
431
432 if (config_dock_horz)
433 after = (x > over->w / 2);
434 else
435 after = (y > over->h / 2);
436
437 /* remove before doing the it->next! */
438 dock->dock_apps = g_list_remove(dock->dock_apps, app);
439
440 if (after) it = it->next;
441
442 dock->dock_apps = g_list_insert_before(dock->dock_apps, it, app);
443 dock_configure();
444 }
445
446 static void hide_timeout(void *n)
447 {
448 /* dont repeat */
449 timer_stop(dock->hide_timer);
450 dock->hide_timer = NULL;
451
452 /* hide */
453 dock->hidden = TRUE;
454 dock_configure();
455 }
456
457 void dock_hide(gboolean hide)
458 {
459 if (dock->hidden == hide || !config_dock_hide)
460 return;
461 if (!hide) {
462 /* show */
463 dock->hidden = FALSE;
464 dock_configure();
465
466 /* if was hiding, stop it */
467 if (dock->hide_timer) {
468 timer_stop(dock->hide_timer);
469 dock->hide_timer = NULL;
470 }
471 } else {
472 g_assert(!dock->hide_timer);
473 dock->hide_timer = timer_start(config_dock_hide_timeout * 1000,
474 (TimeoutHandler)hide_timeout,
475 NULL);
476 }
477 }
This page took 0.058056 seconds and 4 git commands to generate.