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