~ctwm/ctwm/trunk

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
}