518.1.22
by Matthew Fuller
Break the funcs for handling WindowRegion stuff out of add_window.c |
1 |
/*
|
2 |
* WindowRegion handling
|
|
3 |
*/
|
|
4 |
||
5 |
#include "ctwm.h" |
|
6 |
||
7 |
#include <stdlib.h> |
|
8 |
||
524.1.5
by Matthew Fuller
Pull list.h out of screen.h and #include it in the places that need |
9 |
#include "list.h" |
518.1.22
by Matthew Fuller
Break the funcs for handling WindowRegion stuff out of add_window.c |
10 |
#include "screen.h" |
11 |
#include "win_regions.h" |
|
614.1.24
by Maxime Soulé
Icon{Region,Manager{s,Geometry} accept monitor relative geometries |
12 |
#include "xparsegeometry.h" |
518.1.22
by Matthew Fuller
Break the funcs for handling WindowRegion stuff out of add_window.c |
13 |
|
14 |
||
15 |
static void splitWindowRegionEntry(WindowEntry *we, |
|
16 |
RegGravity grav1, RegGravity grav2, |
|
17 |
int w, int h); |
|
18 |
static WindowEntry *findWindowEntry(WorkSpace *wl, |
|
518.1.27
by Matthew Fuller
make indent |
19 |
TwmWindow *tmp_win, WindowRegion **wrp); |
518.1.22
by Matthew Fuller
Break the funcs for handling WindowRegion stuff out of add_window.c |
20 |
static WindowEntry *prevWindowEntry(WindowEntry *we, WindowRegion *wr); |
21 |
static void mergeWindowEntries(WindowEntry *old, WindowEntry *we); |
|
22 |
||
23 |
||
24 |
||
25 |
/*
|
|
26 |
* Backend for the parser when it hits WindowRegion
|
|
27 |
*/
|
|
28 |
name_list ** |
|
29 |
AddWindowRegion(char *geom, RegGravity grav1, RegGravity grav2) |
|
30 |
{
|
|
31 |
WindowRegion *wr; |
|
32 |
int mask; |
|
33 |
||
34 |
wr = malloc(sizeof(WindowRegion)); |
|
35 |
wr->next = NULL; |
|
36 |
||
37 |
if(!Scr->FirstWindowRegion) { |
|
38 |
Scr->FirstWindowRegion = wr; |
|
39 |
}
|
|
40 |
||
41 |
wr->entries = NULL; |
|
42 |
wr->clientlist = NULL; |
|
43 |
wr->grav1 = grav1; |
|
44 |
wr->grav2 = grav2; |
|
45 |
wr->x = wr->y = wr->w = wr->h = 0; |
|
46 |
||
614.1.24
by Maxime Soulé
Icon{Region,Manager{s,Geometry} accept monitor relative geometries |
47 |
mask = RLayoutXParseGeometry(Scr->Layout, geom, &wr->x, &wr->y, |
48 |
(unsigned int *) &wr->w, |
|
49 |
(unsigned int *) &wr->h); |
|
518.1.22
by Matthew Fuller
Break the funcs for handling WindowRegion stuff out of add_window.c |
50 |
|
51 |
if(mask & XNegative) { |
|
52 |
wr->x += Scr->rootw - wr->w; |
|
53 |
}
|
|
54 |
if(mask & YNegative) { |
|
55 |
wr->y += Scr->rooth - wr->h; |
|
56 |
}
|
|
57 |
||
58 |
return (&(wr->clientlist)); |
|
59 |
}
|
|
60 |
||
61 |
||
62 |
/*
|
|
63 |
* Called during startup after the config parsing (which would hit
|
|
64 |
* AddWindowRegion() above) to do some further setup.
|
|
65 |
*/
|
|
66 |
void
|
|
67 |
CreateWindowRegions(void) |
|
68 |
{
|
|
69 |
WindowRegion *wr, *wr1 = NULL, *wr2 = NULL; |
|
70 |
WorkSpace *wl; |
|
71 |
||
72 |
for(wl = Scr->workSpaceMgr.workSpaceList; wl != NULL; wl = wl->next) { |
|
73 |
wl->FirstWindowRegion = NULL; |
|
74 |
wr2 = NULL; |
|
75 |
for(wr = Scr->FirstWindowRegion; wr != NULL; wr = wr->next) { |
|
76 |
wr1 = malloc(sizeof(WindowRegion)); |
|
77 |
*wr1 = *wr; |
|
78 |
wr1->entries = calloc(1, sizeof(WindowEntry)); |
|
79 |
wr1->entries->x = wr1->x; |
|
80 |
wr1->entries->y = wr1->y; |
|
81 |
wr1->entries->w = wr1->w; |
|
82 |
wr1->entries->h = wr1->h; |
|
83 |
if(wr2) { |
|
84 |
wr2->next = wr1; |
|
85 |
}
|
|
86 |
else { |
|
87 |
wl->FirstWindowRegion = wr1; |
|
88 |
}
|
|
89 |
wr2 = wr1; |
|
90 |
}
|
|
91 |
if(wr1) { |
|
92 |
wr1->next = NULL; |
|
93 |
}
|
|
94 |
}
|
|
95 |
}
|
|
96 |
||
97 |
||
98 |
/*
|
|
99 |
* Funcs for putting windows into and taking them out of regions.
|
|
100 |
* Similarly to icons in IconRegion's, this writes the coordinates into
|
|
101 |
* final_[xy] after setting up the Window Region/Entry structures and
|
|
102 |
* stashing them in tmp_win as necessary. Or it doesn't have anything to
|
|
103 |
* do (like if the user doesn't have WindowRegion's config'd), and it
|
|
104 |
* doesn't touch anything and returns false.
|
|
105 |
*/
|
|
106 |
bool
|
|
107 |
PlaceWindowInRegion(TwmWindow *tmp_win, int *final_x, int *final_y) |
|
108 |
{
|
|
109 |
WindowRegion *wr; |
|
110 |
WindowEntry *we; |
|
111 |
int w, h; |
|
112 |
WorkSpace *wl; |
|
113 |
||
114 |
if(!Scr->FirstWindowRegion) { |
|
115 |
return false; |
|
116 |
}
|
|
117 |
for(wl = Scr->workSpaceMgr.workSpaceList; wl != NULL; wl = wl->next) { |
|
118 |
if(OCCUPY(tmp_win, wl)) { |
|
119 |
break; |
|
120 |
}
|
|
121 |
}
|
|
122 |
if(!wl) { |
|
123 |
return false; |
|
124 |
}
|
|
125 |
w = tmp_win->frame_width; |
|
126 |
h = tmp_win->frame_height; |
|
127 |
we = NULL; |
|
128 |
for(wr = wl->FirstWindowRegion; wr; wr = wr->next) { |
|
563.1.4
by Matthew Fuller
Mechanically translate all these full_name references to name. |
129 |
if(LookInList(wr->clientlist, tmp_win->name, &tmp_win->class)) { |
518.1.22
by Matthew Fuller
Break the funcs for handling WindowRegion stuff out of add_window.c |
130 |
for(we = wr->entries; we; we = we->next) { |
131 |
if(we->used) { |
|
132 |
continue; |
|
133 |
}
|
|
134 |
if(we->w >= w && we->h >= h) { |
|
135 |
break; |
|
136 |
}
|
|
137 |
}
|
|
138 |
if(we) { |
|
139 |
break; |
|
140 |
}
|
|
141 |
}
|
|
142 |
}
|
|
143 |
tmp_win->wr = NULL; |
|
144 |
if(!we) { |
|
145 |
return false; |
|
146 |
}
|
|
147 |
||
148 |
splitWindowRegionEntry(we, wr->grav1, wr->grav2, w, h); |
|
149 |
we->used = true; |
|
150 |
we->twm_win = tmp_win; |
|
151 |
*final_x = we->x; |
|
152 |
*final_y = we->y; |
|
153 |
tmp_win->wr = wr; |
|
154 |
return true; |
|
155 |
}
|
|
156 |
||
157 |
||
158 |
/*
|
|
159 |
* Taking a window out of a region. Doesn't do anything with the
|
|
160 |
* _window_, just disconnects it from the data structures describing the
|
|
161 |
* regions and entries.
|
|
162 |
*/
|
|
163 |
void
|
|
164 |
RemoveWindowFromRegion(TwmWindow *tmp_win) |
|
165 |
{
|
|
166 |
WindowEntry *we, *wp, *wn; |
|
167 |
WindowRegion *wr; |
|
168 |
WorkSpace *wl; |
|
169 |
||
170 |
if(!Scr->FirstWindowRegion) { |
|
171 |
return; |
|
172 |
}
|
|
173 |
we = NULL; |
|
174 |
for(wl = Scr->workSpaceMgr.workSpaceList; wl != NULL; wl = wl->next) { |
|
175 |
we = findWindowEntry(wl, tmp_win, &wr); |
|
176 |
if(we) { |
|
177 |
break; |
|
178 |
}
|
|
179 |
}
|
|
180 |
if(!we) { |
|
181 |
return; |
|
182 |
}
|
|
183 |
||
184 |
we->twm_win = NULL; |
|
185 |
we->used = false; |
|
186 |
wp = prevWindowEntry(we, wr); |
|
187 |
wn = we->next; |
|
188 |
for(;;) { |
|
189 |
if(wp && wp->used == false && |
|
190 |
((wp->x == we->x && wp->w == we->w) || |
|
191 |
(wp->y == we->y && wp->h == we->h))) { |
|
192 |
wp->next = we->next; |
|
193 |
mergeWindowEntries(we, wp); |
|
194 |
free(we); |
|
195 |
we = wp; |
|
196 |
wp = prevWindowEntry(wp, wr); |
|
197 |
}
|
|
198 |
else if(wn && wn->used == false && |
|
199 |
((wn->x == we->x && wn->w == we->w) || |
|
200 |
(wn->y == we->y && wn->h == we->h))) { |
|
201 |
we->next = wn->next; |
|
202 |
mergeWindowEntries(wn, we); |
|
203 |
free(wn); |
|
204 |
wn = we->next; |
|
205 |
}
|
|
206 |
else { |
|
207 |
break; |
|
208 |
}
|
|
209 |
}
|
|
210 |
}
|
|
211 |
||
212 |
||
213 |
/*
|
|
214 |
* Creating a new space inside a region.
|
|
215 |
*
|
|
216 |
* x-ref comment on splitIconRegionEntry() for grodiness.
|
|
217 |
*/
|
|
218 |
static void |
|
219 |
splitWindowRegionEntry(WindowEntry *we, RegGravity grav1, RegGravity grav2, |
|
220 |
int w, int h) |
|
221 |
{
|
|
222 |
switch(grav1) { |
|
223 |
case GRAV_NORTH: |
|
224 |
case GRAV_SOUTH: |
|
225 |
if(w != we->w) { |
|
226 |
splitWindowRegionEntry(we, grav2, grav1, w, we->h); |
|
227 |
}
|
|
228 |
if(h != we->h) { |
|
229 |
WindowEntry *new = calloc(1, sizeof(WindowEntry)); |
|
230 |
new->next = we->next; |
|
231 |
we->next = new; |
|
232 |
new->x = we->x; |
|
233 |
new->h = (we->h - h); |
|
234 |
new->w = we->w; |
|
235 |
we->h = h; |
|
236 |
if(grav1 == GRAV_SOUTH) { |
|
237 |
new->y = we->y; |
|
238 |
we->y = new->y + new->h; |
|
239 |
}
|
|
240 |
else { |
|
241 |
new->y = we->y + we->h; |
|
242 |
}
|
|
243 |
}
|
|
244 |
break; |
|
245 |
case GRAV_EAST: |
|
246 |
case GRAV_WEST: |
|
247 |
if(h != we->h) { |
|
248 |
splitWindowRegionEntry(we, grav2, grav1, we->w, h); |
|
249 |
}
|
|
250 |
if(w != we->w) { |
|
251 |
WindowEntry *new = calloc(1, sizeof(WindowEntry)); |
|
252 |
new->next = we->next; |
|
253 |
we->next = new; |
|
254 |
new->y = we->y; |
|
255 |
new->w = (we->w - w); |
|
256 |
new->h = we->h; |
|
257 |
we->w = w; |
|
258 |
if(grav1 == GRAV_EAST) { |
|
259 |
new->x = we->x; |
|
260 |
we->x = new->x + new->w; |
|
261 |
}
|
|
262 |
else { |
|
263 |
new->x = we->x + we->w; |
|
264 |
}
|
|
265 |
}
|
|
266 |
break; |
|
267 |
}
|
|
268 |
}
|
|
269 |
||
270 |
||
271 |
/*
|
|
272 |
* Utils for finding and merging various WindowEntry's
|
|
273 |
*/
|
|
274 |
static WindowEntry * |
|
275 |
findWindowEntry(WorkSpace *wl, TwmWindow *tmp_win, WindowRegion **wrp) |
|
276 |
{
|
|
277 |
WindowRegion *wr; |
|
278 |
WindowEntry *we; |
|
279 |
||
280 |
for(wr = wl->FirstWindowRegion; wr; wr = wr->next) { |
|
281 |
for(we = wr->entries; we; we = we->next) { |
|
282 |
if(we->twm_win == tmp_win) { |
|
283 |
if(wrp) { |
|
284 |
*wrp = wr; |
|
285 |
}
|
|
286 |
return we; |
|
287 |
}
|
|
288 |
}
|
|
289 |
}
|
|
290 |
return NULL; |
|
291 |
}
|
|
292 |
||
293 |
||
294 |
static WindowEntry * |
|
295 |
prevWindowEntry(WindowEntry *we, WindowRegion *wr) |
|
296 |
{
|
|
297 |
WindowEntry *wp; |
|
298 |
||
299 |
if(we == wr->entries) { |
|
300 |
return 0; |
|
301 |
}
|
|
302 |
for(wp = wr->entries; wp->next != we; wp = wp->next); |
|
303 |
return wp; |
|
304 |
}
|
|
305 |
||
306 |
||
307 |
static void |
|
308 |
mergeWindowEntries(WindowEntry *old, WindowEntry *we) |
|
309 |
{
|
|
310 |
if(old->y == we->y) { |
|
311 |
we->w = old->w + we->w; |
|
312 |
if(old->x < we->x) { |
|
313 |
we->x = old->x; |
|
314 |
}
|
|
315 |
}
|
|
316 |
else { |
|
317 |
we->h = old->h + we->h; |
|
318 |
if(old->y < we->y) { |
|
319 |
we->y = old->y; |
|
320 |
}
|
|
321 |
}
|
|
322 |
}
|