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