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