]> Dogcows Code - chaz/openbox/blob - openbox/dock.c
set teh dock sizes before the app uses it for positioning
[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 render_depth, InputOutput, render_visual,
32 CWOverrideRedirect | CWEventMask,
33 &attrib);
34 dock->a_frame = appearance_copy(theme_a_unfocused_title);
35 XSetWindowBorder(ob_display, dock->frame, theme_b_color->pixel);
36 XSetWindowBorderWidth(ob_display, dock->frame, theme_bwidth);
37
38 g_hash_table_insert(window_map, &dock->frame, dock);
39 stacking_add(DOCK_AS_WINDOW(dock));
40 stacking_raise(DOCK_AS_WINDOW(dock));
41 }
42
43 void dock_shutdown()
44 {
45 XDestroyWindow(ob_display, dock->frame);
46 appearance_free(dock->a_frame);
47 g_hash_table_remove(window_map, &dock->frame);
48 stacking_remove(dock);
49 }
50
51 void dock_add(Window win, XWMHints *wmhints)
52 {
53 DockApp *app;
54 XWindowAttributes attrib;
55 char **data;
56
57 app = g_new0(DockApp, 1);
58 app->obwin.type = Window_DockApp;
59 app->win = win;
60 app->icon_win = (wmhints->flags & IconWindowHint) ?
61 wmhints->icon_window : win;
62
63 if (PROP_GETSS(app->win, wm_class, locale, &data)) {
64 if (data[0]) {
65 app->name = g_strdup(data[0]);
66 if (data[1])
67 app->class = g_strdup(data[1]);
68 }
69 g_strfreev(data);
70 }
71
72 if (app->name == NULL) app->name = g_strdup("");
73 if (app->class == NULL) app->class = g_strdup("");
74
75 if (XGetWindowAttributes(ob_display, app->icon_win, &attrib)) {
76 app->w = attrib.width;
77 app->h = attrib.height;
78 } else {
79 app->w = app->h = 64;
80 }
81
82 dock->dock_apps = g_list_append(dock->dock_apps, app);
83 dock_configure();
84
85 XReparentWindow(ob_display, app->icon_win, dock->frame, app->x, app->y);
86 /*
87 This is the same case as in frame.c for client windows. When Openbox is
88 starting, the window is already mapped so we see unmap events occur for
89 it. There are 2 unmap events generated that we see, one with the 'event'
90 member set the root window, and one set to the client, but both get
91 handled and need to be ignored.
92 */
93 if (ob_state == State_Starting)
94 app->ignore_unmaps += 2;
95
96 if (app->win != app->icon_win) {
97 /* have to map it so that it can be re-managed on a restart */
98 XMoveWindow(ob_display, app->win, -1000, -1000);
99 XMapWindow(ob_display, app->win);
100 }
101 XMapWindow(ob_display, app->icon_win);
102 XSync(ob_display, False);
103
104 /* specify that if we exit, the window should not be destroyed and should
105 be reparented back to root automatically */
106 XChangeSaveSet(ob_display, app->icon_win, SetModeInsert);
107 XSelectInput(ob_display, app->icon_win, DOCKAPP_EVENT_MASK);
108
109 grab_button_full(2, 0, app->icon_win,
110 ButtonPressMask | ButtonReleaseMask | ButtonMotionMask,
111 GrabModeAsync, ob_cursors.move);
112
113 g_hash_table_insert(window_map, &app->icon_win, app);
114
115 g_message("Managed Dock App: 0x%lx (%s)", app->icon_win, app->class);
116 }
117
118 void dock_remove_all()
119 {
120 while (dock->dock_apps)
121 dock_remove(dock->dock_apps->data, TRUE);
122 }
123
124 void dock_remove(DockApp *app, gboolean reparent)
125 {
126 ungrab_button(2, 0, app->icon_win);
127 XSelectInput(ob_display, app->icon_win, NoEventMask);
128 /* remove the window from our save set */
129 XChangeSaveSet(ob_display, app->icon_win, SetModeDelete);
130 XSync(ob_display, False);
131
132 g_hash_table_remove(window_map, &app->icon_win);
133
134 if (reparent)
135 XReparentWindow(ob_display, app->icon_win, ob_root, app->x, app->y);
136
137 dock->dock_apps = g_list_remove(dock->dock_apps, app);
138 dock_configure();
139
140 g_message("Unmanaged Dock App: 0x%lx (%s)", app->icon_win, app->class);
141
142 g_free(app->name);
143 g_free(app->class);
144 g_free(app);
145 }
146
147 void dock_configure()
148 {
149 GList *it;
150 int spot;
151 int gravity;
152
153 dock->w = dock->h = spot = 0;
154
155 for (it = dock->dock_apps; it; it = it->next) {
156 struct DockApp *app = it->data;
157 if (config_dock_horz) {
158 dock->w += app->w;
159 dock->h = MAX(dock->h, app->h);
160 app->x = spot;
161 app->y = (dock->h - app->h) / 2;
162 spot += app->w;
163 } else {
164 dock->w = MAX(dock->w, app->w);
165 dock->h += app->h;
166 app->x = (dock->w - app->w) / 2;
167 app->y = spot;
168 spot += app->h;
169 }
170
171 XMoveWindow(ob_display, app->icon_win, app->x, app->y);
172 }
173
174 /* used for calculating offsets */
175 dock->w += theme_bwidth * 2;
176 dock->h += theme_bwidth * 2;
177
178 /* calculate position */
179 switch (config_dock_pos) {
180 case DockPos_Floating:
181 dock->x = config_dock_x;
182 dock->y = config_dock_y;
183 gravity = NorthWestGravity;
184 break;
185 case DockPos_TopLeft:
186 dock->x = 0;
187 dock->y = 0;
188 gravity = NorthWestGravity;
189 break;
190 case DockPos_Top:
191 dock->x = screen_physical_size.width / 2;
192 dock->y = 0;
193 gravity = NorthGravity;
194 break;
195 case DockPos_TopRight:
196 dock->x = screen_physical_size.width;
197 dock->y = 0;
198 gravity = NorthEastGravity;
199 break;
200 case DockPos_Left:
201 dock->x = 0;
202 dock->y = screen_physical_size.height / 2;
203 gravity = WestGravity;
204 break;
205 case DockPos_Right:
206 dock->x = screen_physical_size.width;
207 dock->y = screen_physical_size.height / 2;
208 gravity = EastGravity;
209 break;
210 case DockPos_BottomLeft:
211 dock->x = 0;
212 dock->y = screen_physical_size.height;
213 gravity = SouthWestGravity;
214 break;
215 case DockPos_Bottom:
216 dock->x = screen_physical_size.width / 2;
217 dock->y = screen_physical_size.height;
218 gravity = SouthGravity;
219 break;
220 case DockPos_BottomRight:
221 dock->x = screen_physical_size.width;
222 dock->y = screen_physical_size.height;
223 gravity = SouthEastGravity;
224 break;
225 }
226
227 switch(gravity) {
228 case NorthGravity:
229 case CenterGravity:
230 case SouthGravity:
231 dock->x -= dock->w / 2;
232 break;
233 case NorthEastGravity:
234 case EastGravity:
235 case SouthEastGravity:
236 dock->x -= dock->w;
237 break;
238 }
239 switch(gravity) {
240 case WestGravity:
241 case CenterGravity:
242 case EastGravity:
243 dock->y -= dock->h / 2;
244 break;
245 case SouthWestGravity:
246 case SouthGravity:
247 case SouthEastGravity:
248 dock->y -= dock->h;
249 break;
250 }
251
252 if (config_dock_hide && dock->hidden) {
253 switch (config_dock_pos) {
254 case DockPos_Floating:
255 break;
256 case DockPos_TopLeft:
257 if (config_dock_horz)
258 dock->y -= dock->h - theme_bwidth;
259 else
260 dock->x -= dock->w - theme_bwidth;
261 break;
262 case DockPos_Top:
263 dock->y -= dock->h - theme_bwidth;
264 break;
265 case DockPos_TopRight:
266 if (config_dock_horz)
267 dock->y -= dock->h - theme_bwidth;
268 else
269 dock->x += dock->w - theme_bwidth;
270 break;
271 case DockPos_Left:
272 dock->x -= dock->w - theme_bwidth;
273 break;
274 case DockPos_Right:
275 dock->x += dock->w - theme_bwidth;
276 break;
277 case DockPos_BottomLeft:
278 if (config_dock_horz)
279 dock->y += dock->h - theme_bwidth;
280 else
281 dock->x -= dock->w - theme_bwidth;
282 break;
283 case DockPos_Bottom:
284 dock->y += dock->h - theme_bwidth;
285 break;
286 case DockPos_BottomRight:
287 if (config_dock_horz)
288 dock->y += dock->h - theme_bwidth;
289 else
290 dock->x += dock->w - theme_bwidth;
291 break;
292 }
293 }
294
295 /* set the strut */
296 switch (config_dock_pos) {
297 case DockPos_Floating:
298 STRUT_SET(dock_strut, 0, 0, 0, 0);
299 break;
300 case DockPos_TopLeft:
301 if (config_dock_horz)
302 STRUT_SET(dock_strut, 0, dock->h, 0, 0);
303 else
304 STRUT_SET(dock_strut, dock->w, 0, 0, 0);
305 break;
306 case DockPos_Top:
307 STRUT_SET(dock_strut, 0, dock->h, 0, 0);
308 break;
309 case DockPos_TopRight:
310 if (config_dock_horz)
311 STRUT_SET(dock_strut, 0, dock->h, 0, 0);
312 else
313 STRUT_SET(dock_strut, 0, 0, dock->w, 0);
314 break;
315 case DockPos_Left:
316 STRUT_SET(dock_strut, dock->w, 0, 0, 0);
317 break;
318 case DockPos_Right:
319 STRUT_SET(dock_strut, 0, 0, dock->w, 0);
320 break;
321 case DockPos_BottomLeft:
322 if (config_dock_horz)
323 STRUT_SET(dock_strut, 0, 0, 0, dock->h);
324 else
325 STRUT_SET(dock_strut, dock->w, 0, 0, 0);
326 break;
327 case DockPos_Bottom:
328 STRUT_SET(dock_strut, 0, 0, 0, dock->h);
329 break;
330 case DockPos_BottomRight:
331 if (config_dock_horz)
332 STRUT_SET(dock_strut, 0, 0, 0, dock->h);
333 else
334 STRUT_SET(dock_strut, 0, 0, dock->w, 0);
335 break;
336 }
337
338 /* not used for actually sizing shit */
339 dock->w -= theme_bwidth * 2;
340 dock->h -= theme_bwidth * 2;
341
342 if (dock->w > 0 && dock->h > 0) {
343 RECT_SET(dock->a_frame->area, 0, 0, dock->w, dock->h);
344 XMoveResizeWindow(ob_display, dock->frame,
345 dock->x, dock->y, dock->w, dock->h);
346
347 paint(dock->frame, dock->a_frame);
348 XMapWindow(ob_display, dock->frame);
349 } else
350 XUnmapWindow(ob_display, dock->frame);
351
352 /* but they are useful outside of this function! */
353 dock->w += theme_bwidth * 2;
354 dock->h += theme_bwidth * 2;
355
356 screen_update_struts();
357 }
358
359 void dock_app_configure(DockApp *app, int w, int h)
360 {
361 app->w = w;
362 app->h = h;
363 dock_configure();
364 }
365
366 void dock_app_drag(DockApp *app, XMotionEvent *e)
367 {
368 DockApp *over = NULL;
369 GList *it;
370 int x, y;
371 gboolean after;
372
373 x = e->x_root;
374 y = e->y_root;
375
376 /* are we on top of the dock? */
377 if (!(x >= dock->x &&
378 y >= dock->y &&
379 x < dock->x + dock->w &&
380 y < dock->y + dock->h))
381 return;
382
383 x -= dock->x;
384 y -= dock->y;
385
386 /* which dock app are we on top of? */
387 for (it = dock->dock_apps; it; it = it->next) {
388 over = it->data;
389 if (config_dock_horz) {
390 if (x >= over->x && x < over->x + over->w)
391 break;
392 } else {
393 if (y >= over->y && y < over->y + over->h)
394 break;
395 }
396 }
397 if (!it || app == over) return;
398
399 x -= over->x;
400 y -= over->y;
401
402 if (config_dock_horz)
403 after = (x > over->w / 2);
404 else
405 after = (y > over->h / 2);
406
407 /* remove before doing the it->next! */
408 dock->dock_apps = g_list_remove(dock->dock_apps, app);
409
410 if (after) it = it->next;
411
412 dock->dock_apps = g_list_insert_before(dock->dock_apps, it, app);
413 dock_configure();
414 }
415
416 static void hide_timeout(void *n)
417 {
418 /* dont repeat */
419 timer_stop(dock->hide_timer);
420 dock->hide_timer = NULL;
421
422 /* hide */
423 dock->hidden = TRUE;
424 dock_configure();
425 }
426
427 void dock_hide(gboolean hide)
428 {
429 if (dock->hidden == hide || !config_dock_hide)
430 return;
431 if (!hide) {
432 /* show */
433 dock->hidden = FALSE;
434 dock_configure();
435
436 /* if was hiding, stop it */
437 if (dock->hide_timer) {
438 timer_stop(dock->hide_timer);
439 dock->hide_timer = NULL;
440 }
441 } else {
442 g_assert(!dock->hide_timer);
443 dock->hide_timer = timer_start(config_dock_hide_timeout * 1000,
444 (TimeoutHandler)hide_timeout,
445 NULL);
446 }
447 }
This page took 0.054156 seconds and 5 git commands to generate.