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