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