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