]> Dogcows Code - chaz/openbox/blob - openbox/dock.c
dont need client.h in this header
[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 == 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(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 int 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 struct DockApp *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 struct DockApp *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 switch (config_dock_pos) {
199 case DockPos_Floating:
200 dock->x = config_dock_x;
201 dock->y = config_dock_y;
202 gravity = NorthWestGravity;
203 break;
204 case DockPos_TopLeft:
205 dock->x = 0;
206 dock->y = 0;
207 gravity = NorthWestGravity;
208 break;
209 case DockPos_Top:
210 dock->x = a->width / 2;
211 dock->y = 0;
212 gravity = NorthGravity;
213 break;
214 case DockPos_TopRight:
215 dock->x = a->width;
216 dock->y = 0;
217 gravity = NorthEastGravity;
218 break;
219 case DockPos_Left:
220 dock->x = 0;
221 dock->y = a->height / 2;
222 gravity = WestGravity;
223 break;
224 case DockPos_Right:
225 dock->x = a->width;
226 dock->y = a->height / 2;
227 gravity = EastGravity;
228 break;
229 case DockPos_BottomLeft:
230 dock->x = 0;
231 dock->y = a->height;
232 gravity = SouthWestGravity;
233 break;
234 case DockPos_Bottom:
235 dock->x = a->width / 2;
236 dock->y = a->height;
237 gravity = SouthGravity;
238 break;
239 case DockPos_BottomRight:
240 dock->x = a->width;
241 dock->y = a->height;
242 gravity = SouthEastGravity;
243 break;
244 }
245
246 switch(gravity) {
247 case NorthGravity:
248 case CenterGravity:
249 case SouthGravity:
250 dock->x -= dock->w / 2;
251 break;
252 case NorthEastGravity:
253 case EastGravity:
254 case SouthEastGravity:
255 dock->x -= dock->w;
256 break;
257 }
258 switch(gravity) {
259 case WestGravity:
260 case CenterGravity:
261 case EastGravity:
262 dock->y -= dock->h / 2;
263 break;
264 case SouthWestGravity:
265 case SouthGravity:
266 case SouthEastGravity:
267 dock->y -= dock->h;
268 break;
269 }
270
271 if (config_dock_hide && dock->hidden) {
272 switch (config_dock_pos) {
273 case DockPos_Floating:
274 break;
275 case DockPos_TopLeft:
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 DockPos_Top:
282 dock->y -= dock->h - ob_rr_theme->bwidth;
283 break;
284 case DockPos_TopRight:
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 DockPos_Left:
291 dock->x -= dock->w - ob_rr_theme->bwidth;
292 break;
293 case DockPos_Right:
294 dock->x += dock->w - ob_rr_theme->bwidth;
295 break;
296 case DockPos_BottomLeft:
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 DockPos_Bottom:
303 dock->y += dock->h - ob_rr_theme->bwidth;
304 break;
305 case DockPos_BottomRight:
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 if (config_dock_pos != DockPos_Floating && config_dock_hide) {
315 strw = strh = ob_rr_theme->bwidth;
316 } else {
317 strw = dock->w;
318 strh = dock->h;
319 }
320
321 /* set the strut */
322 switch (config_dock_pos) {
323 case DockPos_Floating:
324 STRUT_SET(dock_strut, 0, 0, 0, 0);
325 break;
326 case DockPos_TopLeft:
327 if (config_dock_horz)
328 STRUT_SET(dock_strut, 0, strh, 0, 0);
329 else
330 STRUT_SET(dock_strut, strw, 0, 0, 0);
331 break;
332 case DockPos_Top:
333 STRUT_SET(dock_strut, 0, strh, 0, 0);
334 break;
335 case DockPos_TopRight:
336 if (config_dock_horz)
337 STRUT_SET(dock_strut, 0, strh, 0, 0);
338 else
339 STRUT_SET(dock_strut, 0, 0, strw, 0);
340 break;
341 case DockPos_Left:
342 STRUT_SET(dock_strut, strw, 0, 0, 0);
343 break;
344 case DockPos_Right:
345 STRUT_SET(dock_strut, 0, 0, strw, 0);
346 break;
347 case DockPos_BottomLeft:
348 if (config_dock_horz)
349 STRUT_SET(dock_strut, 0, 0, 0, strh);
350 else
351 STRUT_SET(dock_strut, strw, 0, 0, 0);
352 break;
353 case DockPos_Bottom:
354 STRUT_SET(dock_strut, 0, 0, 0, strh);
355 break;
356 case DockPos_BottomRight:
357 if (config_dock_horz)
358 STRUT_SET(dock_strut, 0, 0, 0, strh);
359 else
360 STRUT_SET(dock_strut, 0, 0, strw, 0);
361 break;
362 }
363
364 dock->w += minw;
365 dock->h += minh;
366
367 /* not used for actually sizing shit */
368 dock->w -= ob_rr_theme->bwidth * 2;
369 dock->h -= ob_rr_theme->bwidth * 2;
370
371 if (dock->w > 0 && dock->h > 0) {
372 XMoveResizeWindow(ob_display, dock->frame,
373 dock->x, dock->y, dock->w, dock->h);
374
375 RrPaint(dock->a_frame, dock->frame, dock->w, dock->h);
376 XMapWindow(ob_display, dock->frame);
377 } else
378 XUnmapWindow(ob_display, dock->frame);
379
380 /* but they are useful outside of this function! */
381 dock->w += ob_rr_theme->bwidth * 2;
382 dock->h += ob_rr_theme->bwidth * 2;
383
384 screen_update_areas();
385 }
386
387 void dock_app_configure(DockApp *app, int w, int h)
388 {
389 app->w = w;
390 app->h = h;
391 dock_configure();
392 }
393
394 void dock_app_drag(DockApp *app, XMotionEvent *e)
395 {
396 DockApp *over = NULL;
397 GList *it;
398 int x, y;
399 gboolean after;
400
401 x = e->x_root;
402 y = e->y_root;
403
404 /* are we on top of the dock? */
405 if (!(x >= dock->x &&
406 y >= dock->y &&
407 x < dock->x + dock->w &&
408 y < dock->y + dock->h))
409 return;
410
411 x -= dock->x;
412 y -= dock->y;
413
414 /* which dock app are we on top of? */
415 for (it = dock->dock_apps; it; it = it->next) {
416 over = it->data;
417 if (config_dock_horz) {
418 if (x >= over->x && x < over->x + over->w)
419 break;
420 } else {
421 if (y >= over->y && y < over->y + over->h)
422 break;
423 }
424 }
425 if (!it || app == over) return;
426
427 x -= over->x;
428 y -= over->y;
429
430 if (config_dock_horz)
431 after = (x > over->w / 2);
432 else
433 after = (y > over->h / 2);
434
435 /* remove before doing the it->next! */
436 dock->dock_apps = g_list_remove(dock->dock_apps, app);
437
438 if (after) it = it->next;
439
440 dock->dock_apps = g_list_insert_before(dock->dock_apps, it, app);
441 dock_configure();
442 }
443
444 static void hide_timeout(void *n)
445 {
446 /* dont repeat */
447 timer_stop(dock->hide_timer);
448 dock->hide_timer = NULL;
449
450 /* hide */
451 dock->hidden = TRUE;
452 dock_configure();
453 }
454
455 void dock_hide(gboolean hide)
456 {
457 if (dock->hidden == hide || !config_dock_hide)
458 return;
459 if (!hide) {
460 /* show */
461 dock->hidden = FALSE;
462 dock_configure();
463
464 /* if was hiding, stop it */
465 if (dock->hide_timer) {
466 timer_stop(dock->hide_timer);
467 dock->hide_timer = NULL;
468 }
469 } else {
470 g_assert(!dock->hide_timer);
471 dock->hide_timer = timer_start(config_dock_hide_timeout * 1000,
472 (TimeoutHandler)hide_timeout,
473 NULL);
474 }
475 }
This page took 0.061134 seconds and 4 git commands to generate.