]> icculus.org git repositories - dana/openbox.git/blob - openbox/slit.c
add a slit to the kernel
[dana/openbox.git] / openbox / slit.c
1 #include "slit.h"
2 #include "screen.h"
3 #include "openbox.h"
4 #include "render/theme.h"
5 #include "render/render.h"
6
7 #ifdef HAVE_LIMITS_H
8 #  include <limits.h>
9 #endif
10
11 #define SLITAPP_EVENT_MASK (StructureNotifyMask)
12
13 struct Slit {
14     Window frame;
15
16     /* user-requested position stuff */
17     SlitPosition pos;
18     int gravity;
19     int user_x, user_y;
20
21     /* actual position (when not auto-hidden) */
22     int x, y;
23     int w, h;
24
25     gboolean horz;
26
27     Appearance *a_frame;
28
29     GList *slit_apps;
30 };
31
32 GHashTable *slit_map = NULL;
33
34 static Slit *slit;
35 static int nslits;
36
37 static void slit_configure(Slit *self);
38
39 void slit_startup()
40 {
41     XSetWindowAttributes attrib;
42     int i;
43
44     slit_map = g_hash_table_new(g_int_hash, g_int_equal);
45
46     nslits = 1;
47     slit = g_new0(struct Slit, nslits);
48
49     for (i = 0; i < nslits; ++i) {
50         slit[i].horz = TRUE;
51
52         attrib.override_redirect = True;
53         slit[i].frame = XCreateWindow(ob_display, ob_root, 0, 0, 1, 1, 0,
54                                       render_depth, InputOutput, render_visual,
55                                       CWOverrideRedirect, &attrib);
56         slit[i].a_frame = appearance_copy(theme_a_unfocused_title);
57         XSetWindowBorder(ob_display, slit[i].frame, theme_b_color->pixel);
58         XSetWindowBorderWidth(ob_display, slit[i].frame, theme_bwidth);
59     }
60 }
61
62 void slit_shutdown()
63 {
64     int i;
65
66     for (i = 0; i < nslits; ++i) {
67         XDestroyWindow(ob_display, slit[i].frame);
68         appearance_free(slit[i].a_frame);
69     }
70 }
71
72 void slit_add(Window win, XWMHints *wmhints, XWindowAttributes *attrib)
73 {
74     Slit *s;
75     SlitApp *app;
76
77     /* XXX pick a slit */
78     s = &slit[0];
79
80     app = g_new0(SlitApp, 1);
81     app->slit = s;
82     app->win = win;
83     app->icon_win = (wmhints->flags & IconWindowHint) ?
84         wmhints->icon_window : win;
85     
86     app->w = attrib->width;
87     app->h = attrib->height;
88
89     s->slit_apps = g_list_append(s->slit_apps, app);
90     slit_configure(s);
91     XReparentWindow(ob_display, app->icon_win, s->frame, app->x, app->y);
92
93     /*
94       This is the same case as in frame.c for client windows. When Openbox is
95       starting, the window is already mapped so we see unmap events occur for
96       it. There are 2 unmap events generated that we see, one with the 'event'
97       member set the root window, and one set to the client, but both get
98       handled and need to be ignored.
99     */
100     if (ob_state == State_Starting)
101         app->ignore_unmaps += 2;
102
103     if (app->win != app->icon_win)
104         XMoveWindow(ob_display, app->win, 100, 100);
105     XMapWindow(ob_display, app->icon_win);
106     XSync(ob_display, False);
107
108     /* specify that if we exit, the window should not be destroyed and should
109        be reparented back to root automatically */
110     XChangeSaveSet(ob_display, app->icon_win, SetModeInsert);
111     XSelectInput(ob_display, app->icon_win, SLITAPP_EVENT_MASK);
112
113     g_hash_table_insert(slit_map, &app->icon_win, app);
114
115     g_message("Managed Slit App: 0x%lx", app->icon_win);
116 }
117
118 void slit_remove_all()
119 {
120     int i;
121
122     for (i = 0; i < nslits; ++i)
123         while (slit[i].slit_apps)
124             slit_remove(slit[i].slit_apps->data, TRUE);
125 }
126
127 void slit_remove(SlitApp *app, gboolean reparent)
128 {
129     XSelectInput(ob_display, app->icon_win, NoEventMask);
130     /* remove the window from our save set */
131     XChangeSaveSet(ob_display, app->icon_win, SetModeDelete);
132     XSync(ob_display, False);
133
134     g_hash_table_remove(slit_map, &app->icon_win);
135
136     if (reparent)
137         XReparentWindow(ob_display, app->icon_win, ob_root, app->x, app->y);
138
139     app->slit->slit_apps = g_list_remove(app->slit->slit_apps, app);
140     slit_configure(app->slit);
141
142     g_message("Unmanaged Slit App: 0x%lx", app->icon_win);
143
144     g_free(app);
145 }
146
147 void slit_configure_all()
148 {
149     int i; for (i = 0; i < nslits; ++i) slit_configure(&slit[i]);
150 }
151
152 static void slit_configure(Slit *self)
153 {
154     GList *it;
155     int spot;
156
157     self->w = self->h = spot = 0;
158
159     for (it = self->slit_apps; it; it = it->next) {
160         struct SlitApp *app = it->data;
161         if (self->horz) {
162             app->x = spot;
163             app->y = 0;
164             self->w += app->w;
165             self->h = MAX(self->h, app->h);
166             spot += app->w;
167         } else {
168             app->x = 0;
169             app->y = spot;
170             self->w = MAX(self->h, app->w);
171             self->h += app->h;
172             spot += app->h;
173         }
174
175         XMoveWindow(ob_display, app->icon_win, app->x, app->y);
176     }
177
178     /* used for calculating offsets */
179     self->w += theme_bwidth * 2;
180     self->h += theme_bwidth * 2;
181
182     switch (self->pos) {
183     case SlitPos_Floating:
184         /* calculate position */
185         self->x = self->user_x;
186         self->y = self->user_y;
187
188         switch(self->gravity) {
189         case NorthGravity:
190         case CenterGravity:
191         case SouthGravity:
192             self->x -= self->w / 2;
193             break;
194         case NorthEastGravity:
195         case EastGravity:
196         case SouthEastGravity:
197             self->x -= self->w;
198             break;
199         }
200         switch(self->gravity) {
201         case WestGravity:
202         case CenterGravity:
203         case EastGravity:
204             self->y -= self->h / 2;
205             break;
206         case SouthWestGravity:
207         case SouthGravity:
208         case SouthEastGravity:
209             self->y -= self->h;
210             break;
211         }
212         break;
213     case SlitPos_TopLeft:
214         self->x = 0;
215         self->y = 0;
216         break;
217     case SlitPos_Top:
218         self->x = (screen_physical_size.width - self->w) / 2;
219         self->y = 0;
220         break;
221     case SlitPos_TopRight:
222         self->x = screen_physical_size.width - self->w;
223         self->y = 0;
224         break;
225     case SlitPos_Left:
226         self->x = 0;
227         self->y = (screen_physical_size.height - self->h) / 2;
228         break;
229     case SlitPos_Right:
230         self->x = screen_physical_size.width - self->w;
231         self->y = (screen_physical_size.height - self->h) / 2;
232         break;
233     case SlitPos_BottomLeft:
234         self->x = 0;
235         self->y = screen_physical_size.height - self->h;
236         break;
237     case SlitPos_Bottom:
238         self->x = (screen_physical_size.width - self->w) / 2;
239         self->y = screen_physical_size.height - self->h;
240         break;
241     case SlitPos_BottomRight:
242         self->x = screen_physical_size.width - self->w;
243         self->y = screen_physical_size.height - self->h;
244         break;
245     }
246
247     /* not used for actually sizing shit */
248     self->w -= theme_bwidth * 2;
249     self->h -= theme_bwidth * 2;
250
251     if (self->w > 0 && self->h > 0) {
252         RECT_SET(self->a_frame->area, 0, 0, self->w, self->h);
253         XMoveResizeWindow(ob_display, self->frame,
254                           self->x, self->y, self->w, self->h);
255
256         paint(self->frame, self->a_frame);
257         XMapWindow(ob_display, self->frame);
258     } else
259         XUnmapWindow(ob_display, self->frame);
260 }