~ctwm/ctwm/trunk

503.1.62 by Matthew Fuller
Pull piles of occupation handling out of workmgr.c and into a new
1
/*
2
 * Occupation handling bits
503.1.97 by Matthew Fuller
Expand header comment to lampshade how tightly tied this is with
3
 *
4
 * This is in fact pretty tightly tied and extremely similar to the
5
 * handling of the WorkSpaceManager in workmgr.c, and used to be there.
6
 * It makes sense to consider them together (and indeed, many of the
7
 * configs that affect how this works are really WorkSpaceManager* or
503.1.112 by Matthew Fuller
Tpyo.
8
 * WMgr* commands.  But having them crammed together in one file is
503.1.97 by Matthew Fuller
Expand header comment to lampshade how tightly tied this is with
9
 * unwieldy.
503.1.62 by Matthew Fuller
Pull piles of occupation handling out of workmgr.c and into a new
10
 */
11
12
#include "ctwm.h"
13
14
#include <stdio.h>
15
#include <string.h>
16
#include <stdlib.h>
17
18
#include <X11/Xatom.h>
19
20
#include "add_window.h"
21
#include "ctwm_atoms.h"
22
#include "drawing.h"
23
#include "events.h"
518.1.24 by Matthew Fuller
iconmgr.h isn't needed for add_window.h. Pull it out and add it to
24
#include "iconmgr.h"
524.1.5 by Matthew Fuller
Pull list.h out of screen.h and #include it in the places that need
25
#include "list.h"
503.1.62 by Matthew Fuller
Pull piles of occupation handling out of workmgr.c and into a new
26
#include "screen.h"
524.1.1 by Matthew Fuller
Pull occupation.h out of screen.h, and include it directly in the
27
#include "occupation.h"
503.1.62 by Matthew Fuller
Pull piles of occupation handling out of workmgr.c and into a new
28
#include "otp.h"
29
#include "util.h"
524.1.3 by Matthew Fuller
Pull vscreen.h out of screen.h and #include it directly in the files
30
#include "vscreen.h"
520.1.2 by Matthew Fuller
Bust functions related to iconifying/deiconifying windows out of
31
#include "win_iconify.h"
518.1.22 by Matthew Fuller
Break the funcs for handling WindowRegion stuff out of add_window.c
32
#include "win_regions.h"
523.1.5 by Matthew Fuller
GetTwmWindow() is pretty obvious _utils fodder.
33
#include "win_utils.h"
510.1.9 by Matthew Fuller
Only stuff left in workmgr is the actual workspace manager stuff.
34
#include "workspace_manager.h"
510.1.5 by Matthew Fuller
Break the general/utility workspace functions out into their own file.
35
#include "workspace_utils.h"
503.1.62 by Matthew Fuller
Pull piles of occupation handling out of workmgr.c and into a new
36
37
38
static int GetMaskFromResource(TwmWindow *win, char *res);
39
static char *mk_nullsep_string(const char *prop, int len);
40
41
static bool CanChangeOccupation(TwmWindow **twm_winp);
42
43
int fullOccupation = 0;
44
45
/*
46
 * The window whose occupation is currently being manipulated.
47
 *
48
 * XXX Should probably be static, but currently needed in
510.1.90 by Matthew Fuller
Rename several of these funcs for adding/removing windows to the WSM
49
 * WMapRemoveWindow().  Revisit.
503.1.62 by Matthew Fuller
Pull piles of occupation handling out of workmgr.c and into a new
50
 */
51
TwmWindow *occupyWin = NULL;
52
53
503.1.98 by Matthew Fuller
Leave a comment on sharing this var.
54
/* XXX Share with captive.c? */
503.1.62 by Matthew Fuller
Pull piles of occupation handling out of workmgr.c and into a new
55
static XrmOptionDescRec table [] = {
56
	{"-xrm",            NULL,           XrmoptionResArg, (XPointer) NULL},
57
};
58
59
503.1.66 by Matthew Fuller
Comment through SetupOccupation(), localize some vars in it, leave
60
503.1.102 by Matthew Fuller
Rearrange the functions in occupation.c so they're ordered and grouped
61
62
/*
63
 ****************************************************************
64
 *
65
 * First, funcs related to setting and changing a window's occupation.
66
 *
67
 ****************************************************************
68
 */
69
70
503.1.66 by Matthew Fuller
Comment through SetupOccupation(), localize some vars in it, leave
71
/*
72
 * Setup the occupation of a TwmWindow.  Called as part of the
73
 * AddWindow() process.
556.1.50 by Matthew Fuller
Drop an XXX on this func about the confusing and maybe incorrect
74
 *
75
 * XXX The logic flow in this is kinda weird, and it's not at all clear
76
 * to what extent it's really doing the right on on what should override
77
 * what, or which things should expand/contract on others...
503.1.66 by Matthew Fuller
Comment through SetupOccupation(), localize some vars in it, leave
78
 */
503.1.62 by Matthew Fuller
Pull piles of occupation handling out of workmgr.c and into a new
79
void
80
SetupOccupation(TwmWindow *twm_win, int occupation_hint)
81
{
503.1.66 by Matthew Fuller
Comment through SetupOccupation(), localize some vars in it, leave
82
	char      **cliargv = NULL;
83
	int       cliargc;
84
	WorkSpace *ws;
503.1.62 by Matthew Fuller
Pull piles of occupation handling out of workmgr.c and into a new
85
503.1.66 by Matthew Fuller
Comment through SetupOccupation(), localize some vars in it, leave
86
	/* If there aren't any config'd workspaces, there's only 0 */
503.1.62 by Matthew Fuller
Pull piles of occupation handling out of workmgr.c and into a new
87
	if(! Scr->workSpaceManagerActive) {
88
		twm_win->occupation = 1 << 0;   /* occupy workspace #0 */
89
		/* more?... */
90
91
		return;
92
	}
93
503.1.66 by Matthew Fuller
Comment through SetupOccupation(), localize some vars in it, leave
94
	/* Workspace manager window doesn't get futzed with */
503.1.62 by Matthew Fuller
Pull piles of occupation handling out of workmgr.c and into a new
95
	if(twm_win->iswspmgr) {
96
		return;
97
	}
98
99
	/*twm_win->occupation = twm_win->iswinbox ? fullOccupation : 0;*/
100
	twm_win->occupation = 0;
101
503.1.66 by Matthew Fuller
Comment through SetupOccupation(), localize some vars in it, leave
102
	/* Specified in any Occupy{} config params? */
503.1.62 by Matthew Fuller
Pull piles of occupation handling out of workmgr.c and into a new
103
	for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) {
563.1.4 by Matthew Fuller
Mechanically translate all these full_name references to name.
104
		if(LookInList(ws->clientlist, twm_win->name, &twm_win->class)) {
503.1.62 by Matthew Fuller
Pull piles of occupation handling out of workmgr.c and into a new
105
			twm_win->occupation |= 1 << ws->number;
106
		}
107
	}
108
503.1.66 by Matthew Fuller
Comment through SetupOccupation(), localize some vars in it, leave
109
	/* OccupyAll{} */
563.1.4 by Matthew Fuller
Mechanically translate all these full_name references to name.
110
	if(LookInList(Scr->OccupyAll, twm_win->name, &twm_win->class)) {
503.1.62 by Matthew Fuller
Pull piles of occupation handling out of workmgr.c and into a new
111
		twm_win->occupation = fullOccupation;
112
	}
113
503.1.66 by Matthew Fuller
Comment through SetupOccupation(), localize some vars in it, leave
114
	/* See if it specified in -xrm stuff */
503.1.62 by Matthew Fuller
Pull piles of occupation handling out of workmgr.c and into a new
115
	if(XGetCommand(dpy, twm_win->w, &cliargv, &cliargc)) {
503.1.66 by Matthew Fuller
Comment through SetupOccupation(), localize some vars in it, leave
116
		Bool status;
117
		char *str_type;
118
		XrmValue value;
503.1.67 by Matthew Fuller
Need to initialize this to NULL, or things go bad.
119
		XrmDatabase db = NULL;
503.1.66 by Matthew Fuller
Comment through SetupOccupation(), localize some vars in it, leave
120
503.1.62 by Matthew Fuller
Pull piles of occupation handling out of workmgr.c and into a new
121
		XrmParseCommand(&db, table, 1, "ctwm", &cliargc, cliargv);
503.1.70 by Matthew Fuller
Free this list as soon as we're done with it. Not that it makes much
122
		XFreeStringList(cliargv);
503.1.66 by Matthew Fuller
Comment through SetupOccupation(), localize some vars in it, leave
123
		status = XrmGetResource(db, "ctwm.workspace", "Ctwm.Workspace",
124
		                        &str_type, &value);
503.1.62 by Matthew Fuller
Pull piles of occupation handling out of workmgr.c and into a new
125
		if((status == True) && (value.size != 0)) {
126
			/* Copy the value.addr because it's in XRM memory not ours */
127
			char wrkSpcList[512];
503.1.68 by Matthew Fuller
Use safe_strncpy() here instead of manually implementing it.
128
			safe_strncpy(wrkSpcList, value.addr, MIN(value.size, 512));
503.1.62 by Matthew Fuller
Pull piles of occupation handling out of workmgr.c and into a new
129
503.1.69 by Matthew Fuller
Use our copy, not the one in memory we don't really control.
130
			twm_win->occupation = GetMaskFromResource(twm_win, wrkSpcList);
503.1.62 by Matthew Fuller
Pull piles of occupation handling out of workmgr.c and into a new
131
		}
132
		XrmDestroyDatabase(db);
133
	}
134
503.1.66 by Matthew Fuller
Comment through SetupOccupation(), localize some vars in it, leave
135
	/* Does it have a property telling us */
503.1.62 by Matthew Fuller
Pull piles of occupation handling out of workmgr.c and into a new
136
	if(RestartPreviousState) {
503.1.66 by Matthew Fuller
Comment through SetupOccupation(), localize some vars in it, leave
137
		Atom actual_type;
138
		int actual_format;
139
		unsigned long nitems, bytesafter;
503.1.62 by Matthew Fuller
Pull piles of occupation handling out of workmgr.c and into a new
140
		unsigned char *prop;
503.1.66 by Matthew Fuller
Comment through SetupOccupation(), localize some vars in it, leave
141
503.1.62 by Matthew Fuller
Pull piles of occupation handling out of workmgr.c and into a new
142
		if(XGetWindowProperty(dpy, twm_win->w, XA_WM_OCCUPATION, 0L, 2500, False,
143
		                      XA_STRING, &actual_type, &actual_format, &nitems,
144
		                      &bytesafter, &prop) == Success) {
145
			if(nitems != 0) {
146
				twm_win->occupation = GetMaskFromProperty(prop, nitems);
147
				XFree(prop);
148
			}
149
		}
150
	}
151
152
#ifdef EWMH
503.1.66 by Matthew Fuller
Comment through SetupOccupation(), localize some vars in it, leave
153
	/* Maybe EWMH has something to tell us? */
503.1.62 by Matthew Fuller
Pull piles of occupation handling out of workmgr.c and into a new
154
	if(twm_win->occupation == 0) {
155
		twm_win->occupation = EwmhGetOccupation(twm_win);
156
	}
157
#endif /* EWMH */
158
503.1.66 by Matthew Fuller
Comment through SetupOccupation(), localize some vars in it, leave
159
	/* Icon Managers shouldn't get altered */
160
	/* XXX Should this be up near the top? */
503.1.62 by Matthew Fuller
Pull piles of occupation handling out of workmgr.c and into a new
161
	if(twm_win->isiconmgr) {
162
		return;        /* someone tried to modify occupation of icon managers */
163
	}
164
503.1.66 by Matthew Fuller
Comment through SetupOccupation(), localize some vars in it, leave
165
166
	/*
167
	 * Transient-ish things go with their parents unless
168
	 * TransientHasOccupation set in the config.
169
	 */
503.1.62 by Matthew Fuller
Pull piles of occupation handling out of workmgr.c and into a new
170
	if(! Scr->TransientHasOccupation) {
503.1.66 by Matthew Fuller
Comment through SetupOccupation(), localize some vars in it, leave
171
		TwmWindow *t;
172
503.1.62 by Matthew Fuller
Pull piles of occupation handling out of workmgr.c and into a new
173
		if(twm_win->istransient) {
174
			t = GetTwmWindow(twm_win->transientfor);
175
			if(t != NULL) {
176
				twm_win->occupation = t->occupation;
177
			}
178
		}
179
		else if(twm_win->group != 0) {
180
			t = GetTwmWindow(twm_win->group);
181
			if(t != NULL) {
182
				twm_win->occupation = t->occupation;
183
			}
184
		}
185
	}
186
187
503.1.66 by Matthew Fuller
Comment through SetupOccupation(), localize some vars in it, leave
188
	/* If we were told something specific, go with that */
503.1.62 by Matthew Fuller
Pull piles of occupation handling out of workmgr.c and into a new
189
	if(occupation_hint != 0) {
190
		twm_win->occupation = occupation_hint;
191
	}
192
503.1.66 by Matthew Fuller
Comment through SetupOccupation(), localize some vars in it, leave
193
	/* If it's apparently-nonsensical, put it in its vs's workspace */
503.1.62 by Matthew Fuller
Pull piles of occupation handling out of workmgr.c and into a new
194
	if((twm_win->occupation & fullOccupation) == 0) {
503.1.66 by Matthew Fuller
Comment through SetupOccupation(), localize some vars in it, leave
195
		twm_win->occupation = 1 << twm_win->vs->wsw->currentwspc->number;
196
	}
503.1.62 by Matthew Fuller
Pull piles of occupation handling out of workmgr.c and into a new
197
198
	/*
199
	 * If the occupation would not show it in the current vscreen,
200
	 * make it vanish.
201
	 *
202
	 * If it could be shown in one of the other vscreens, change the vscreen.
203
	 */
204
	if(!OCCUPY(twm_win, twm_win->vs->wsw->currentwspc)) {
205
206
		twm_win->vs = NULL;
207
696.1.14 by Matthew Fuller
Another "maybe show on different vscreen" case, that doesn't need to
208
#ifdef VSCREEN
503.1.62 by Matthew Fuller
Pull piles of occupation handling out of workmgr.c and into a new
209
		if(Scr->numVscreens > 1) {
696.1.14 by Matthew Fuller
Another "maybe show on different vscreen" case, that doesn't need to
210
			VirtualScreen *vs;
503.1.62 by Matthew Fuller
Pull piles of occupation handling out of workmgr.c and into a new
211
			for(vs = Scr->vScreenList; vs != NULL; vs = vs->next) {
212
				if(OCCUPY(twm_win, vs->wsw->currentwspc)) {
213
					twm_win->vs = vs;
214
					twm_win->parent_vs = vs;
215
					break;
216
				}
217
			}
218
		}
696.1.14 by Matthew Fuller
Another "maybe show on different vscreen" case, that doesn't need to
219
#endif
503.1.62 by Matthew Fuller
Pull piles of occupation handling out of workmgr.c and into a new
220
	}
221
222
511.1.9 by Matthew Fuller
Use mask_out_event{_mask}() and restore_mask() in place of manually
223
	/* Set the property for the occupation */
503.1.62 by Matthew Fuller
Pull piles of occupation handling out of workmgr.c and into a new
224
	{
503.1.66 by Matthew Fuller
Comment through SetupOccupation(), localize some vars in it, leave
225
		long eventMask;
503.1.62 by Matthew Fuller
Pull piles of occupation handling out of workmgr.c and into a new
226
		char *wsstr;
227
		int  len;
228
511.1.9 by Matthew Fuller
Use mask_out_event{_mask}() and restore_mask() in place of manually
229
		/* Ignore the PropertyChange we're about to do */
230
		if((eventMask = mask_out_event(twm_win->w, PropertyChangeMask)) < 0) {
503.1.66 by Matthew Fuller
Comment through SetupOccupation(), localize some vars in it, leave
231
			/* Window is horked, not much we can do */
232
			return;
233
		}
234
235
		/* Set the property for the occupation */
503.1.62 by Matthew Fuller
Pull piles of occupation handling out of workmgr.c and into a new
236
		len = GetPropertyFromMask(twm_win->occupation, &wsstr);
237
		XChangeProperty(dpy, twm_win->w, XA_WM_OCCUPATION, XA_STRING, 8,
238
		                PropModeReplace, (unsigned char *) wsstr, len);
239
		free(wsstr);
240
241
#ifdef EWMH
503.1.66 by Matthew Fuller
Comment through SetupOccupation(), localize some vars in it, leave
242
		EwmhSet_NET_WM_DESKTOP(twm_win);
503.1.62 by Matthew Fuller
Pull piles of occupation handling out of workmgr.c and into a new
243
#endif
503.1.66 by Matthew Fuller
Comment through SetupOccupation(), localize some vars in it, leave
244
245
		/* Restore event mask */
511.1.9 by Matthew Fuller
Use mask_out_event{_mask}() and restore_mask() in place of manually
246
		restore_mask(twm_win->w, eventMask);
503.1.66 by Matthew Fuller
Comment through SetupOccupation(), localize some vars in it, leave
247
	}
248
249
	/* Set WM_STATE prop */
250
	{
251
		int state = NormalState;
252
		Window icon;
253
254
		if(!(RestartPreviousState
255
		                && GetWMState(twm_win->w, &state, &icon)
256
		                && (state == NormalState || state == IconicState
257
		                    || state == InactiveState))) {
557.1.3 by Matthew Fuller
GC now-unnecessary NULL checks of wmhints.
258
			if(twm_win->wmhints->flags & StateHint) {
503.1.66 by Matthew Fuller
Comment through SetupOccupation(), localize some vars in it, leave
259
				state = twm_win->wmhints->initial_state;
260
			}
261
		}
262
		if(visible(twm_win)) {
263
			if(state == InactiveState) {
264
				SetMapStateProp(twm_win, NormalState);
265
			}
266
		}
267
		else {
268
			if(state == NormalState) {
269
				SetMapStateProp(twm_win, InactiveState);
270
			}
503.1.62 by Matthew Fuller
Pull piles of occupation handling out of workmgr.c and into a new
271
		}
272
	}
273
}
274
275
503.1.71 by Matthew Fuller
Comment up CanChangeOccupation().
276
/*
503.1.101 by Matthew Fuller
Expand comments a little.
277
 * Make sure a window is marked in a given workspace.  f.addtoworkspace.
278
 * Also gets called as part of the process of mapping a window; if we're
279
 * mapping it here, it should know that it's here.  And Xinerama magic
280
 * moves.
503.1.72 by Matthew Fuller
Do a bit of commenting.
281
 */
503.1.62 by Matthew Fuller
Pull piles of occupation handling out of workmgr.c and into a new
282
void
283
AddToWorkSpace(char *wname, TwmWindow *twm_win)
284
{
285
	WorkSpace *ws;
286
	int newoccupation;
287
288
	if(!CanChangeOccupation(&twm_win)) {
289
		return;
290
	}
291
	ws = GetWorkspace(wname);
292
	if(!ws) {
293
		return;
294
	}
295
296
	if(twm_win->occupation & (1 << ws->number)) {
297
		return;
298
	}
299
	newoccupation = twm_win->occupation | (1 << ws->number);
300
	ChangeOccupation(twm_win, newoccupation);
301
}
302
303
503.1.101 by Matthew Fuller
Expand comments a little.
304
/*
305
 * Converse of the above.  f.removefromworkspace, also called from
306
 * Xinerama-related magic.
307
 */
503.1.62 by Matthew Fuller
Pull piles of occupation handling out of workmgr.c and into a new
308
void
309
RemoveFromWorkSpace(char *wname, TwmWindow *twm_win)
310
{
311
	WorkSpace *ws;
312
	int newoccupation;
313
314
	if(!CanChangeOccupation(&twm_win)) {
315
		return;
316
	}
317
	ws = GetWorkspace(wname);
318
	if(!ws) {
319
		return;
320
	}
321
322
	newoccupation = twm_win->occupation & ~(1 << ws->number);
323
	if(!newoccupation) {
324
		return;
325
	}
326
	ChangeOccupation(twm_win, newoccupation);
327
}
328
329
503.1.74 by Matthew Fuller
Comment another block of functions. Do some minor code rearrangement
330
/* f.toggleoccupation - flip setting for [current] workspace */
503.1.62 by Matthew Fuller
Pull piles of occupation handling out of workmgr.c and into a new
331
void
332
ToggleOccupation(char *wname, TwmWindow *twm_win)
333
{
334
	WorkSpace *ws;
335
	int newoccupation;
336
337
	if(!CanChangeOccupation(&twm_win)) {
338
		return;
339
	}
340
	ws = GetWorkspace(wname);
341
	if(!ws) {
342
		return;
343
	}
344
345
	newoccupation = twm_win->occupation ^ (1 << ws->number);
346
	if(!newoccupation) {
503.1.74 by Matthew Fuller
Comment another block of functions. Do some minor code rearrangement
347
		/* Don't allow de-occupying _every_ ws */
503.1.62 by Matthew Fuller
Pull piles of occupation handling out of workmgr.c and into a new
348
		return;
349
	}
350
	ChangeOccupation(twm_win, newoccupation);
351
}
352
353
503.1.74 by Matthew Fuller
Comment another block of functions. Do some minor code rearrangement
354
/* f.movetonextworkspace */
503.1.62 by Matthew Fuller
Pull piles of occupation handling out of workmgr.c and into a new
355
void
356
MoveToNextWorkSpace(VirtualScreen *vs, TwmWindow *twm_win)
357
{
358
	WorkSpace *wlist1, *wlist2;
359
	int newoccupation;
360
361
	if(!CanChangeOccupation(&twm_win)) {
362
		return;
363
	}
364
365
	wlist1 = vs->wsw->currentwspc;
366
	wlist2 = wlist1->next;
367
	wlist2 = wlist2 ? wlist2 : Scr->workSpaceMgr.workSpaceList;
368
503.1.74 by Matthew Fuller
Comment another block of functions. Do some minor code rearrangement
369
	/* Out of (here), into (here+1) */
503.1.62 by Matthew Fuller
Pull piles of occupation handling out of workmgr.c and into a new
370
	newoccupation = (twm_win->occupation ^ (1 << wlist1->number))
371
	                | (1 << wlist2->number);
372
	ChangeOccupation(twm_win, newoccupation);
373
}
374
375
503.1.74 by Matthew Fuller
Comment another block of functions. Do some minor code rearrangement
376
/* f.movetonextworkspaceandfollow */
503.1.62 by Matthew Fuller
Pull piles of occupation handling out of workmgr.c and into a new
377
void
378
MoveToNextWorkSpaceAndFollow(VirtualScreen *vs, TwmWindow *twm_win)
379
{
380
	if(!CanChangeOccupation(&twm_win)) {
381
		return;
382
	}
383
384
	MoveToNextWorkSpace(vs, twm_win);
385
	GotoNextWorkSpace(vs);
386
#if 0
387
	OtpRaise(twm_win, WinWin);  /* XXX really do this? */
388
#endif
389
}
390
391
503.1.74 by Matthew Fuller
Comment another block of functions. Do some minor code rearrangement
392
/* f.movetoprevworkspaceand */
503.1.62 by Matthew Fuller
Pull piles of occupation handling out of workmgr.c and into a new
393
void
394
MoveToPrevWorkSpace(VirtualScreen *vs, TwmWindow *twm_win)
395
{
396
	WorkSpace *wlist1, *wlist2;
397
	int newoccupation;
398
399
	if(!CanChangeOccupation(&twm_win)) {
400
		return;
401
	}
402
403
	wlist1 = Scr->workSpaceMgr.workSpaceList;
404
	wlist2 = vs->wsw->currentwspc;
405
	if(wlist1 == NULL) {
406
		return;
407
	}
408
409
	while(wlist1->next != wlist2 && wlist1->next != NULL) {
410
		wlist1 = wlist1->next;
411
	}
412
503.1.74 by Matthew Fuller
Comment another block of functions. Do some minor code rearrangement
413
	/* Out of (here), into (here-1) */
503.1.62 by Matthew Fuller
Pull piles of occupation handling out of workmgr.c and into a new
414
	newoccupation = (twm_win->occupation ^ (1 << wlist2->number))
415
	                | (1 << wlist1->number);
416
	ChangeOccupation(twm_win, newoccupation);
417
}
418
419
503.1.74 by Matthew Fuller
Comment another block of functions. Do some minor code rearrangement
420
/* f.movetoprevworkspaceandfollow */
503.1.62 by Matthew Fuller
Pull piles of occupation handling out of workmgr.c and into a new
421
void
422
MoveToPrevWorkSpaceAndFollow(VirtualScreen *vs, TwmWindow *twm_win)
423
{
424
	if(!CanChangeOccupation(&twm_win)) {
425
		return;
426
	}
427
428
	MoveToPrevWorkSpace(vs, twm_win);
429
	GotoPrevWorkSpace(vs);
430
#if 0
431
	OtpRaise(twm_win, WinWin);          /* XXX really do this? */
432
#endif
433
}
434
435
503.1.74 by Matthew Fuller
Comment another block of functions. Do some minor code rearrangement
436
/*
437
 * Set the occupation based on the window name.  This is called if
438
 * AutoOccupy is set, when we get a notification about a window name
439
 * change.
440
 */
503.1.62 by Matthew Fuller
Pull piles of occupation handling out of workmgr.c and into a new
441
void
442
WmgrRedoOccupation(TwmWindow *win)
443
{
444
	WorkSpace *ws;
445
	int       newoccupation;
446
563.1.4 by Matthew Fuller
Mechanically translate all these full_name references to name.
447
	if(LookInList(Scr->OccupyAll, win->name, &win->class)) {
503.1.62 by Matthew Fuller
Pull piles of occupation handling out of workmgr.c and into a new
448
		newoccupation = fullOccupation;
449
	}
450
	else {
451
		newoccupation = 0;
452
		for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) {
563.1.4 by Matthew Fuller
Mechanically translate all these full_name references to name.
453
			if(LookInList(ws->clientlist, win->name, &win->class)) {
503.1.62 by Matthew Fuller
Pull piles of occupation handling out of workmgr.c and into a new
454
				newoccupation |= 1 << ws->number;
455
			}
456
		}
457
	}
458
	if(newoccupation != 0) {
459
		ChangeOccupation(win, newoccupation);
460
	}
461
}
462
463
503.1.74 by Matthew Fuller
Comment another block of functions. Do some minor code rearrangement
464
/* f.vanish */
503.1.62 by Matthew Fuller
Pull piles of occupation handling out of workmgr.c and into a new
465
void
466
WMgrRemoveFromCurrentWorkSpace(VirtualScreen *vs, TwmWindow *win)
467
{
468
	WorkSpace *ws;
469
	int       newoccupation;
470
471
	ws = vs->wsw->currentwspc;
472
	if(!ws) {
473
		/* Impossible? */
474
		return;
475
	}
476
	if(! OCCUPY(win, ws)) {
477
		return;
478
	}
479
480
	newoccupation = win->occupation & ~(1 << ws->number);
481
	if(newoccupation == 0) {
482
		return;
483
	}
484
485
	ChangeOccupation(win, newoccupation);
486
}
487
488
503.1.74 by Matthew Fuller
Comment another block of functions. Do some minor code rearrangement
489
/* f.warphere */
503.1.62 by Matthew Fuller
Pull piles of occupation handling out of workmgr.c and into a new
490
void
491
WMgrAddToCurrentWorkSpaceAndWarp(VirtualScreen *vs, char *winname)
492
{
493
	TwmWindow *tw;
494
	int       newoccupation;
495
503.1.74 by Matthew Fuller
Comment another block of functions. Do some minor code rearrangement
496
	/* Find named window on this screen */
503.1.62 by Matthew Fuller
Pull piles of occupation handling out of workmgr.c and into a new
497
	for(tw = Scr->FirstWindow; tw != NULL; tw = tw->next) {
563.1.4 by Matthew Fuller
Mechanically translate all these full_name references to name.
498
		if(match(winname, tw->name)) {
503.1.62 by Matthew Fuller
Pull piles of occupation handling out of workmgr.c and into a new
499
			break;
500
		}
501
	}
503.1.74 by Matthew Fuller
Comment another block of functions. Do some minor code rearrangement
502
503
	/* Didn't find it by name?  Try by class */
503.1.62 by Matthew Fuller
Pull piles of occupation handling out of workmgr.c and into a new
504
	if(!tw) {
505
		for(tw = Scr->FirstWindow; tw != NULL; tw = tw->next) {
506
			if(match(winname, tw->class.res_name)) {
507
				break;
508
			}
509
		}
503.1.74 by Matthew Fuller
Comment another block of functions. Do some minor code rearrangement
510
	}
511
	if(!tw) {
512
		for(tw = Scr->FirstWindow; tw != NULL; tw = tw->next) {
513
			if(match(winname, tw->class.res_class)) {
514
				break;
503.1.62 by Matthew Fuller
Pull piles of occupation handling out of workmgr.c and into a new
515
			}
516
		}
517
	}
503.1.74 by Matthew Fuller
Comment another block of functions. Do some minor code rearrangement
518
519
	/* Still didn't find?  Beep at the user and bail. */
503.1.62 by Matthew Fuller
Pull piles of occupation handling out of workmgr.c and into a new
520
	if(!tw) {
521
		XBell(dpy, 0);
522
		return;
523
	}
503.1.74 by Matthew Fuller
Comment another block of functions. Do some minor code rearrangement
524
525
	/* If WarpUnmapped isn't set and this isn't mapped, beep and bail */
503.1.62 by Matthew Fuller
Pull piles of occupation handling out of workmgr.c and into a new
526
	if((! Scr->WarpUnmapped) && (! tw->mapped)) {
527
		XBell(dpy, 0);
528
		return;
529
	}
503.1.74 by Matthew Fuller
Comment another block of functions. Do some minor code rearrangement
530
531
	/* Move it here if it's not */
503.1.62 by Matthew Fuller
Pull piles of occupation handling out of workmgr.c and into a new
532
	if(! OCCUPY(tw, vs->wsw->currentwspc)) {
533
		newoccupation = tw->occupation | (1 << vs->wsw->currentwspc->number);
534
		ChangeOccupation(tw, newoccupation);
535
	}
536
503.1.74 by Matthew Fuller
Comment another block of functions. Do some minor code rearrangement
537
	/* If we get here, WarpUnmapped is set, so map it if we need to */
503.1.62 by Matthew Fuller
Pull piles of occupation handling out of workmgr.c and into a new
538
	if(! tw->mapped) {
539
		DeIconify(tw);
540
	}
503.1.74 by Matthew Fuller
Comment another block of functions. Do some minor code rearrangement
541
542
	/* And go */
503.1.62 by Matthew Fuller
Pull piles of occupation handling out of workmgr.c and into a new
543
	WarpToWindow(tw, Scr->RaiseOnWarp);
544
}
545
546
503.1.102 by Matthew Fuller
Rearrange the functions in occupation.c so they're ordered and grouped
547
/* f.occupyall backend */
548
void
549
OccupyAll(TwmWindow *twm_win)
550
{
551
	IconMgr *save;
552
553
	if(!CanChangeOccupation(&twm_win)) {
554
		return;
555
	}
556
557
	/*
558
	 * Temporarily alter Scr->iconmgr because stuff down in
559
	 * ChangeOccupation winds up adding/removing bits, and that doesn't
560
	 * work right when we're setting all?  XXX Investigate further.
561
	 */
562
	save = Scr->iconmgr;
563
	Scr->iconmgr = Scr->workSpaceMgr.workSpaceList->iconmgr;
564
	ChangeOccupation(twm_win, fullOccupation);
565
	Scr->iconmgr = save;
566
}
567
568
569
570
/*
571
 ****************************************************************
572
 *
573
 * Pieces related to the Occupy window
574
 *
575
 ****************************************************************
576
 */
503.1.62 by Matthew Fuller
Pull piles of occupation handling out of workmgr.c and into a new
577
578
static ColorPair occupyButtoncp;
579
580
static char *ok_string         = "OK",
581
             *cancel_string     = "Cancel",
582
              *everywhere_string = "All";
583
584
/*
503.1.75 by Matthew Fuller
Quick comment on the last couple functions.
585
 * Create the Occupy window.  Part of startup process.
586
 *
587
 * Do not do the layout of the parts, only calculate the initial total
588
 * size. For the layout, call ResizeOccupyWindow() at the end.
589
 *
503.1.62 by Matthew Fuller
Pull piles of occupation handling out of workmgr.c and into a new
590
 * There is only one Occupy window (per Screen), it is reparented to each
591
 * virtual screen as needed.
592
 */
593
void
594
CreateOccupyWindow(void)
595
{
503.1.84 by Matthew Fuller
Most of these remaining vars are actually just shorthands for values
596
	int           width; // Caculated and altered, unlike most others
503.1.82 by Matthew Fuller
Move all the shorthand vars together and comment.
597
	int           Dummy = 1;
503.1.62 by Matthew Fuller
Pull piles of occupation handling out of workmgr.c and into a new
598
	TwmWindow     *tmp_win;
503.1.84 by Matthew Fuller
Most of these remaining vars are actually just shorthands for values
599
	/* Shorthands for the Occupy window */
600
	OccupyWindow  *occwin = Scr->workSpaceMgr.occupyWindow;
601
	Window        w; // occwin->w
602
	/* Misc other shorthands */
603
	const int lines   = Scr->workSpaceMgr.lines;
604
	const int columns = Scr->workSpaceMgr.columns;
605
	const int bwidth  = Scr->vScreenList->wsw->bwidth;
606
	const int bheight = Scr->vScreenList->wsw->bheight;
607
	const int vspace = occwin->vspace;
608
	const int hspace = occwin->hspace;
609
	const int height = ((bheight + vspace) * lines) + bheight + (2 * vspace);
610
611
	/* Struct embedded in [struct embedded in] Scr, so memory's waiting */
612
574.1.1 by Matthew Fuller
Like the workspace manager, there's no point trying to create the
613
	/* There isn't anything we should do without workspaces... */
614
	if(!Scr->workSpaceManagerActive) {
615
		return;
616
	}
617
503.1.84 by Matthew Fuller
Most of these remaining vars are actually just shorthands for values
618
	/* Initialize font and colorpair bits */
503.1.62 by Matthew Fuller
Pull piles of occupation handling out of workmgr.c and into a new
619
	occwin->font     = Scr->IconManagerFont;
620
	occwin->cp       = Scr->IconManagerC;
621
#ifdef COLOR_BLIND_USER
622
	occwin->cp.shadc = Scr->White;
623
	occwin->cp.shadd = Scr->Black;
624
#else
625
	if(!Scr->BeNiceToColormap) {
626
		GetShadeColors(&occwin->cp);
627
	}
628
#endif
503.1.83 by Matthew Fuller
name and icon_name shorthands were also only used once, so it's not
629
503.1.87 by Matthew Fuller
We know what these should be at the start of the func, so initialize
630
	/* We already know that these should be too */
631
	occwin->lines   = lines;
632
	occwin->columns = columns;
633
503.1.78 by Matthew Fuller
Localize a bunch of vars in CreateOccupyWindow().
634
503.1.86 by Matthew Fuller
Start commenting up the first block here. Eliminate unnecessary
635
	/*
636
	 * Work out the necessary size of the OK/Cancel/All buttons at the
637
	 * bottom.
638
	 */
503.1.78 by Matthew Fuller
Localize a bunch of vars in CreateOccupyWindow().
639
	{
640
		XRectangle inc_rect;
641
		XRectangle logical_rect;
503.1.86 by Matthew Fuller
Start commenting up the first block here. Eliminate unnecessary
642
		MyFont font = occwin->font;
512.1.3 by Matthew Fuller
Comment var declarations.
643
		int bbwidth;  // Bottom button width
644
		/* Window min width based on bottom vs. workspace btns */
645
		int bb_width, ws_width;
503.1.78 by Matthew Fuller
Localize a bunch of vars in CreateOccupyWindow().
646
503.1.86 by Matthew Fuller
Start commenting up the first block here. Eliminate unnecessary
647
		/* Buttons gotta be as wide as the biggest of the three strings */
503.1.78 by Matthew Fuller
Localize a bunch of vars in CreateOccupyWindow().
648
		XmbTextExtents(font.font_set, ok_string, strlen(ok_string),
649
		               &inc_rect, &logical_rect);
512.1.2 by Matthew Fuller
Use separate local vars for the min size based on the bottom buttons
650
		bbwidth = logical_rect.width;
503.1.86 by Matthew Fuller
Start commenting up the first block here. Eliminate unnecessary
651
503.1.78 by Matthew Fuller
Localize a bunch of vars in CreateOccupyWindow().
652
		XmbTextExtents(font.font_set, cancel_string, strlen(cancel_string),
653
		               &inc_rect, &logical_rect);
512.1.2 by Matthew Fuller
Use separate local vars for the min size based on the bottom buttons
654
		bbwidth = MAX(bbwidth, logical_rect.width);
503.1.86 by Matthew Fuller
Start commenting up the first block here. Eliminate unnecessary
655
503.1.78 by Matthew Fuller
Localize a bunch of vars in CreateOccupyWindow().
656
		XmbTextExtents(font.font_set, everywhere_string,
657
		               strlen(everywhere_string),
658
		               &inc_rect, &logical_rect);
512.1.2 by Matthew Fuller
Use separate local vars for the min size based on the bottom buttons
659
		bbwidth = MAX(bbwidth, logical_rect.width);
503.1.86 by Matthew Fuller
Start commenting up the first block here. Eliminate unnecessary
660
661
		/* Plus the padding width */
512.1.2 by Matthew Fuller
Use separate local vars for the min size based on the bottom buttons
662
		bbwidth += hspace;
503.1.86 by Matthew Fuller
Start commenting up the first block here. Eliminate unnecessary
663
664
		/*
503.1.88 by Matthew Fuller
Further commenting on the sizing block, and some code
665
		 * So, the final width of those bottom buttons is that, plus the
666
		 * 3d button look extra on both sides, plus a little extra.  I
667
		 * guess that extra + 2 is similar to TitlePadding or
668
		 * ButtonIndent on titlebars, but we don't have a config param
669
		 * for it on the workspace manager (which is the config used for
670
		 * the occupy window), so leave it as a magic constant for now.
671
		 */
512.1.2 by Matthew Fuller
Use separate local vars for the min size based on the bottom buttons
672
		occwin->owidth = bbwidth + 2 * Scr->WMgrButtonShadowDepth + 2;
503.1.88 by Matthew Fuller
Further commenting on the sizing block, and some code
673
674
		/*
675
		 * The whole thing has to be at least triple the min width of
512.1.1 by Matthew Fuller
Add extra hspace to the width planning here, since there's padding on
676
		 * those bottom buttons, since there are three of them.  The
677
		 * layout is "hspace button hspace button [...] hspace", to pad
678
		 * between and on both sides.
679
		 */
512.1.2 by Matthew Fuller
Use separate local vars for the min size based on the bottom buttons
680
		bb_width = 3 * (bbwidth + hspace) + hspace;
503.1.85 by Matthew Fuller
Slightly expand an inner scope so we can move these two vars into it.
681
503.1.86 by Matthew Fuller
Start commenting up the first block here. Eliminate unnecessary
682
		/*
512.1.2 by Matthew Fuller
Use separate local vars for the min size based on the bottom buttons
683
		 * It also has to be the width of our per-WS buttons.  Per-ws
684
		 * buttons are sized the same as in the button-state WSM, and
685
		 * then we add the padding to them as above.
503.1.86 by Matthew Fuller
Start commenting up the first block here. Eliminate unnecessary
686
		 */
512.1.2 by Matthew Fuller
Use separate local vars for the min size based on the bottom buttons
687
		ws_width = columns * (bwidth + hspace) + hspace;
503.1.86 by Matthew Fuller
Start commenting up the first block here. Eliminate unnecessary
688
512.1.2 by Matthew Fuller
Use separate local vars for the min size based on the bottom buttons
689
		/* So the window has to be as wide as the wider of those */
690
		width = MAX(bb_width, ws_width);
503.1.85 by Matthew Fuller
Slightly expand an inner scope so we can move these two vars into it.
691
	}
503.1.62 by Matthew Fuller
Pull piles of occupation handling out of workmgr.c and into a new
692
503.1.89 by Matthew Fuller
Start commenting making the window and buttons. Eliminate one
693
694
	/* Now we know the size, so make the window */
503.1.62 by Matthew Fuller
Pull piles of occupation handling out of workmgr.c and into a new
695
	w = occwin->w = XCreateSimpleWindow(dpy, Scr->Root, 0, 0, width, height,
503.1.79 by Matthew Fuller
This var was a shortcut for a single use; don't bother.
696
	                                    1, Scr->Black, occwin->cp.back);
503.1.89 by Matthew Fuller
Start commenting making the window and buttons. Eliminate one
697
514.1.3 by Matthew Fuller
Stash up the minimum size for the window and bail out of Resize early
698
	/* Take those base sizes as a minimum */
699
	occwin->minwidth  = width;
700
	occwin->minheight = height;
701
503.1.89 by Matthew Fuller
Start commenting making the window and buttons. Eliminate one
702
703
	/*
704
	 * Make subwindows as buttons for the workspaces.  They're laid out
705
	 * in a grid mirroring the workspace manager's.
706
	 */
503.1.78 by Matthew Fuller
Localize a bunch of vars in CreateOccupyWindow().
707
	{
708
		int i = 0, j = 0;
503.1.81 by Matthew Fuller
These two uses of ws are independent, so move one into the existing
709
		WorkSpace *ws;
710
503.1.89 by Matthew Fuller
Start commenting making the window and buttons. Eliminate one
711
		occwin->obuttonw = calloc(Scr->workSpaceMgr.count, sizeof(Window));
712
503.1.78 by Matthew Fuller
Localize a bunch of vars in CreateOccupyWindow().
713
		for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) {
503.1.89 by Matthew Fuller
Start commenting making the window and buttons. Eliminate one
714
			int idx = (j * columns) + i;
715
716
			/*
717
			 * Make and map.  Note that we're not setting the size or
718
			 * location at all here; ResizeOccupyWindow() does all that.
719
			 * We just make 'em.
720
			 */
721
			occwin->obuttonw[idx] = XCreateSimpleWindow(dpy, w,
503.1.92 by Matthew Fuller
Let make indent rejigger this.
722
			                        Dummy /* x */,
723
			                        Dummy /* y */,
724
			                        Dummy /* width */,
725
			                        Dummy /* height */,
726
			                        0, Scr->Black, ws->cp.back);
503.1.89 by Matthew Fuller
Start commenting making the window and buttons. Eliminate one
727
			XMapWindow(dpy, occwin->obuttonw[idx]);
728
729
			/* Inc around to the next location */
503.1.78 by Matthew Fuller
Localize a bunch of vars in CreateOccupyWindow().
730
			i++;
731
			if(i == columns) {
732
				i = 0;
733
				j++;
734
			}
503.1.62 by Matthew Fuller
Pull piles of occupation handling out of workmgr.c and into a new
735
		}
736
	}
503.1.78 by Matthew Fuller
Localize a bunch of vars in CreateOccupyWindow().
737
503.1.90 by Matthew Fuller
Comment up through setting various properties.
738
739
	/*
740
	 * Now start putting together the OK/Cancel/All buttons
741
	 */
742
743
	/* Background for them is hardcoded */
503.1.62 by Matthew Fuller
Pull piles of occupation handling out of workmgr.c and into a new
744
	GetColor(Scr->Monochrome, &(occupyButtoncp.back), "gray50");
503.1.90 by Matthew Fuller
Comment up through setting various properties.
745
746
	/* Foreground (not used here) is too */
503.1.62 by Matthew Fuller
Pull piles of occupation handling out of workmgr.c and into a new
747
	occupyButtoncp.fore = Scr->White;
503.1.90 by Matthew Fuller
Comment up through setting various properties.
748
749
	/* Override (probably historical */
503.1.62 by Matthew Fuller
Pull piles of occupation handling out of workmgr.c and into a new
750
	if(!Scr->BeNiceToColormap) {
751
		GetShadeColors(&occupyButtoncp);
752
	}
753
503.1.90 by Matthew Fuller
Comment up through setting various properties.
754
	/* Make 'em */
503.1.78 by Matthew Fuller
Localize a bunch of vars in CreateOccupyWindow().
755
	{
756
		Window tw;
757
758
		tw = XCreateSimpleWindow(dpy, w, Dummy, Dummy, Dummy, Dummy, 0,
759
		                         Scr->Black, occupyButtoncp.back);
760
		XMapWindow(dpy, tw);
761
		occwin->OK = tw;
762
763
		tw = XCreateSimpleWindow(dpy, w, Dummy, Dummy, Dummy, Dummy, 0,
764
		                         Scr->Black, occupyButtoncp.back);
765
		XMapWindow(dpy, tw);
766
		occwin->cancel = tw;
767
768
		tw = XCreateSimpleWindow(dpy, w, Dummy, Dummy, Dummy, Dummy, 0,
769
		                         Scr->Black, occupyButtoncp.back);
770
		XMapWindow(dpy, tw);
771
		occwin->allworkspc = tw;
772
	}
773
503.1.90 by Matthew Fuller
Comment up through setting various properties.
774
505.1.1 by Matthew Fuller
Replace XSetStandardProperties(); XSetWMHints() calls with
775
	/* Setup various window properties */
503.1.78 by Matthew Fuller
Localize a bunch of vars in CreateOccupyWindow().
776
	{
777
		XSizeHints sizehints;
505.1.1 by Matthew Fuller
Replace XSetStandardProperties(); XSetWMHints() calls with
778
		XWMHints wmhints;
503.1.90 by Matthew Fuller
Comment up through setting various properties.
779
514.1.5 by Matthew Fuller
Go ahead and set the size to max as well. Resizing the occupy window
780
		sizehints.flags       = PBaseSize | PMinSize | PMaxSize;
512.1.10 by Matthew Fuller
De-bogusize the size hints for the Occupy window. The principle
781
		sizehints.min_width   = width;
782
		sizehints.min_height  = height;
783
		sizehints.base_width  = width;
784
		sizehints.base_height = height;
514.1.5 by Matthew Fuller
Go ahead and set the size to max as well. Resizing the occupy window
785
		sizehints.max_width   = width;
786
		sizehints.max_height  = height;
503.1.90 by Matthew Fuller
Comment up through setting various properties.
787
503.1.78 by Matthew Fuller
Localize a bunch of vars in CreateOccupyWindow().
788
		wmhints.flags         = InputHint | StateHint;
789
		wmhints.input         = True;
790
		wmhints.initial_state = NormalState;
505.1.1 by Matthew Fuller
Replace XSetStandardProperties(); XSetWMHints() calls with
791
792
		XmbSetWMProperties(dpy, w, occwin->name, occwin->icon_name,
505.1.6 by Matthew Fuller
make indent
793
		                   NULL, 0, &sizehints, &wmhints, NULL);
503.1.78 by Matthew Fuller
Localize a bunch of vars in CreateOccupyWindow().
794
	}
795
503.1.91 by Matthew Fuller
Comment a little further, and move an assignment up way earlier.
796
797
	/*
798
	 * Create the TwmWindow wrapping around it, with decorations etc.  We
799
	 * do this so early in startup that we're not listening for window
800
	 * creation events yet.
801
	 */
512.1.7 by Matthew Fuller
Add a new AddWindow() type for the Occupy window.
802
	tmp_win = AddWindow(w, AWT_OCCUPY, Scr->iconmgr, Scr->currentvs);
503.1.62 by Matthew Fuller
Pull piles of occupation handling out of workmgr.c and into a new
803
	if(! tmp_win) {
804
		fprintf(stderr, "cannot create occupy window, exiting...\n");
805
		exit(1);
806
	}
807
	tmp_win->vs = NULL;
808
	tmp_win->occupation = 0;
809
503.1.91 by Matthew Fuller
Comment a little further, and move an assignment up way earlier.
810
	/* tmp_win is more convenient the rest of the func, but put in place */
811
	occwin->twm_win = tmp_win;
812
813
814
	/*
815
	 * Setup the window to have a button-pushing cursor and listen for
816
	 * clicks.
817
	 */
503.1.78 by Matthew Fuller
Localize a bunch of vars in CreateOccupyWindow().
818
	{
819
		unsigned long attrmask;
820
		XSetWindowAttributes attr;
821
		XWindowAttributes wattr;
822
823
		attr.cursor = Scr->ButtonCursor;
824
		attrmask = CWCursor;
825
		XChangeWindowAttributes(dpy, w, attrmask, &attr);
826
827
		XGetWindowAttributes(dpy, w, &wattr);
828
		attrmask = wattr.your_event_mask | KeyPressMask | KeyReleaseMask
829
		           | ExposureMask;
830
		XSelectInput(dpy, w, attrmask);
831
	}
503.1.62 by Matthew Fuller
Pull piles of occupation handling out of workmgr.c and into a new
832
503.1.93 by Matthew Fuller
Comment this setting up of events and contexts, and use macros to
833
834
	/*
835
	 * Now for each of the buttons (workspaces + OK/Cancel/All), we mark
836
	 * them as listening to click and exposure events.  We also stash
837
	 * away the screen and wrapping TwmWindow in contexts so other code
838
	 * can dredge them up.
839
	 */
840
#define EVT (ButtonPressMask | ButtonReleaseMask | ExposureMask)
841
#define BTN_IPT_CTX(win) \
842
        XSelectInput(dpy, (win), EVT); \
843
        XSaveContext(dpy, (win), TwmContext, (XPointer) tmp_win); \
844
        XSaveContext(dpy, (win), ScreenContext, (XPointer) Scr);
845
503.1.81 by Matthew Fuller
These two uses of ws are independent, so move one into the existing
846
	for(WorkSpace *ws = Scr->workSpaceMgr.workSpaceList
847
	                    ; ws != NULL ; ws = ws->next) {
503.1.93 by Matthew Fuller
Comment this setting up of events and contexts, and use macros to
848
		BTN_IPT_CTX(occwin->obuttonw[ws->number]);
503.1.62 by Matthew Fuller
Pull piles of occupation handling out of workmgr.c and into a new
849
	}
503.1.91 by Matthew Fuller
Comment a little further, and move an assignment up way earlier.
850
503.1.93 by Matthew Fuller
Comment this setting up of events and contexts, and use macros to
851
	BTN_IPT_CTX(occwin->OK);
852
	BTN_IPT_CTX(occwin->cancel);
853
	BTN_IPT_CTX(occwin->allworkspc);
854
855
#undef BTN_IPT_CTX
856
#undef EVT
503.1.62 by Matthew Fuller
Pull piles of occupation handling out of workmgr.c and into a new
857
503.1.94 by Matthew Fuller
Little commenting toward the end.
858
859
	/* Mark that we're not mapped */
503.1.62 by Matthew Fuller
Pull piles of occupation handling out of workmgr.c and into a new
860
	SetMapStateProp(tmp_win, WithdrawnState);
503.1.94 by Matthew Fuller
Little commenting toward the end.
861
862
	/* Now call that func that sizes all the buttons */
863
	ResizeOccupyWindow(tmp_win);
503.1.62 by Matthew Fuller
Pull piles of occupation handling out of workmgr.c and into a new
864
}
865
866
503.1.75 by Matthew Fuller
Quick comment on the last couple functions.
867
/*
503.1.102 by Matthew Fuller
Rearrange the functions in occupation.c so they're ordered and grouped
868
 * Slightly misleading name: layout the internals of the Occupy window
869
 * based on its current size.  That does happen when it's resized, but
870
 * also when it's initially created.  I guess you could call "creation" a
871
 * resize of a sort...
872
 */
873
void
874
ResizeOccupyWindow(TwmWindow *win)
875
{
876
	int        bwidth, bheight, owidth, oheight;
877
	int        hspace, vspace;
878
	int        lines, columns;
879
	int        neww, newh;
880
	WorkSpace  *ws;
881
	int        i, j, x, y;
882
	OccupyWindow *occwin = Scr->workSpaceMgr.occupyWindow;
883
514.1.3 by Matthew Fuller
Stash up the minimum size for the window and bail out of Resize early
884
	/* Floor at the original size */
885
	neww = MAX(win->attr.width,  occwin->minwidth);
886
	newh = MAX(win->attr.height, occwin->minheight);
503.1.102 by Matthew Fuller
Rearrange the functions in occupation.c so they're ordered and grouped
887
	if(occwin->width == neww && occwin->height == newh) {
888
		return;
889
	}
890
891
	/* Space between WS buttons.  From WMgr{Horiz,Vert}ButtonIndent. */
892
	hspace  = occwin->hspace;
893
	vspace  = occwin->vspace;
894
895
	/* Lines/cols in the layout.  Same as WorkspaceManager's */
896
	lines   = Scr->workSpaceMgr.lines;
897
	columns = Scr->workSpaceMgr.columns;
898
899
	/* Width/height of each button, based on the above and window size */
900
	bwidth  = (neww -  columns    * hspace) / columns;
901
	bheight = (newh - (lines + 2) * vspace) / (lines + 1);
902
903
	/* Width/height of the OK/Cancel/All buttons */
904
	owidth  = occwin->owidth;
905
	oheight = bheight;
906
907
908
	/*
909
	 * Lay out the workspace buttons
910
	 */
911
	i = 0;
912
	j = 0;
913
	for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) {
914
		XMoveResizeWindow(dpy, occwin->obuttonw [j * columns + i],
915
		                  i * (bwidth  + hspace) + (hspace / 2),
916
		                  j * (bheight + vspace) + (vspace / 2),
917
		                  bwidth, bheight);
918
		i++;
919
		if(i == columns) {
920
			i = 0;
921
			j++;
922
		}
923
	}
924
925
926
	/*
927
	 * Now the action buttons
928
	 */
929
	hspace = (neww - 3 * owidth) / 4;  // Padding between
930
	x = hspace;
931
	y = ((bheight + vspace) * lines) + ((3 * vspace) / 2);
932
	XMoveResizeWindow(dpy, occwin->OK, x, y, owidth, oheight);
933
	x += owidth + hspace;
934
	XMoveResizeWindow(dpy, occwin->cancel, x, y, owidth, oheight);
935
	x += owidth + hspace;
936
	XMoveResizeWindow(dpy, occwin->allworkspc, x, y, owidth, oheight);
937
938
939
	/* Save all those dimensions we figured */
940
	occwin->width   = neww;
941
	occwin->height  = newh;
942
	occwin->bwidth  = bwidth;
943
	occwin->bheight = bheight;
944
	occwin->owidth  = owidth;
945
514.1.4 by Matthew Fuller
Don't call PAintOccupyWindow() at the end of the resize operation. It
946
	/* Don't need to repaint it; it'll get expose events */
503.1.102 by Matthew Fuller
Rearrange the functions in occupation.c so they're ordered and grouped
947
}
948
949
950
/*
503.1.75 by Matthew Fuller
Quick comment on the last couple functions.
951
 * Draw the window when we need to (e.g., on expose)
952
 */
503.1.62 by Matthew Fuller
Pull piles of occupation handling out of workmgr.c and into a new
953
void
954
PaintOccupyWindow(void)
955
{
956
	WorkSpace    *ws;
957
	OccupyWindow *occwin;
958
	int          width, height;
959
960
	occwin = Scr->workSpaceMgr.occupyWindow;
961
	width  = occwin->width;
962
	height = occwin->height;
963
964
	Draw3DBorder(occwin->w, 0, 0, width, height, 2, occwin->cp, off, true, false);
965
966
	for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) {
967
		Window bw = occwin->obuttonw [ws->number];
503.1.100 by Matthew Fuller
Use intermediate vars for these states, instead of duplicating the
968
		ButtonState bs = (occwin->tmpOccupation & (1 << ws->number)) ? on : off;
969
970
		PaintWsButton(OCCUPYWINDOW, NULL, bw, ws->label, ws->cp, bs);
503.1.62 by Matthew Fuller
Pull piles of occupation handling out of workmgr.c and into a new
971
	}
972
	PaintWsButton(OCCUPYBUTTON, NULL, occwin->OK,         ok_string,
973
	              occupyButtoncp, off);
974
	PaintWsButton(OCCUPYBUTTON, NULL, occwin->cancel,     cancel_string,
975
	              occupyButtoncp, off);
976
	PaintWsButton(OCCUPYBUTTON, NULL, occwin->allworkspc, everywhere_string,
977
	              occupyButtoncp, off);
978
}
979
980
981
/*
503.1.102 by Matthew Fuller
Rearrange the functions in occupation.c so they're ordered and grouped
982
 * Somebody clicked in the Occupy window
983
 */
984
void
985
OccupyHandleButtonEvent(XEvent *event)
986
{
987
	WorkSpace    *ws;
988
	OccupyWindow *occupyW;
989
	Window       buttonW;
990
991
	/*
992
	 * Doesn't make sense that this can even happen if there are no
993
	 * workspaces...
994
	 */
995
	if(! Scr->workSpaceManagerActive) {
996
		return;
997
	}
998
999
	/* ... or if there's no Occupy window up for anything */
1000
	if(occupyWin == NULL) {
1001
		return;
1002
	}
1003
1004
	/* Which sub-window (button) was clicked */
1005
	buttonW = event->xbutton.window;
1006
	if(buttonW == 0) {
1007
		return;        /* icon */
1008
	}
1009
1010
	/* Grab onto the pointer for the duration of our action */
1011
	XGrabPointer(dpy, Scr->Root, True,
1012
	             ButtonPressMask | ButtonReleaseMask,
1013
	             GrabModeAsync, GrabModeAsync,
1014
	             Scr->Root, None, CurrentTime);
1015
1016
	/* Find the workspace button that was clicked */
1017
	occupyW = Scr->workSpaceMgr.occupyWindow;
1018
	for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) {
1019
		if(occupyW->obuttonw [ws->number] == buttonW) {
1020
			break;
1021
		}
1022
	}
1023
1024
	if(ws != NULL) {
1025
		/* If one was, toggle it */
1026
		int mask = 1 << ws->number;
1027
		ButtonState bs = (occupyW->tmpOccupation & mask) ? off : on;
1028
1029
		PaintWsButton(OCCUPYWINDOW, NULL, occupyW->obuttonw [ws->number],
1030
		              ws->label, ws->cp, bs);
1031
		occupyW->tmpOccupation ^= mask;
1032
	}
1033
	else if(buttonW == occupyW->OK) {
1034
		/* Else if we clicked OK, set things and close the window */
1035
		if(occupyW->tmpOccupation == 0) {
1036
			return;
1037
		}
1038
		ChangeOccupation(occupyWin, occupyW->tmpOccupation);
1039
		XUnmapWindow(dpy, occupyW->twm_win->frame);
1040
		occupyW->twm_win->mapped = false;
1041
		occupyW->twm_win->occupation = 0;
1042
		occupyWin = NULL;
1043
		XSync(dpy, 0);
1044
	}
1045
	else if(buttonW == occupyW->cancel) {
1046
		/* Or cancel, do nothing and close the window */
1047
		XUnmapWindow(dpy, occupyW->twm_win->frame);
1048
		occupyW->twm_win->mapped = false;
1049
		occupyW->twm_win->occupation = 0;
1050
		occupyWin = NULL;
1051
		XSync(dpy, 0);
1052
	}
1053
	else if(buttonW == occupyW->allworkspc) {
1054
		/* Or All, set 'em all */
1055
		for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) {
1056
			PaintWsButton(OCCUPYWINDOW, NULL, occupyW->obuttonw [ws->number],
1057
			              ws->label, ws->cp, on);
1058
		}
1059
		occupyW->tmpOccupation = fullOccupation;
1060
	}
1061
1062
	/* Release the pointer, if ??? */
1063
	if(ButtonPressed == -1) {
1064
		XUngrabPointer(dpy, CurrentTime);
1065
	}
1066
}
1067
1068
1069
/*
1070
 * f.occupy backend - pop up Occupy control for some window
1071
 */
1072
void
1073
Occupy(TwmWindow *twm_win)
1074
{
1075
	int          x, y;
1076
	unsigned int width, height;
1077
	Window       w;
1078
	struct OccupyWindow    *occupyWindow;
1079
	TwmWindow *occupy_twm;
1080
1081
	/* Don't pop up on stuff we can't change */
1082
	if(!CanChangeOccupation(&twm_win)) {
1083
		return;
1084
	}
1085
1086
	/* Grab our one screen-wide f.occupy window */
1087
	occupyWindow = Scr->workSpaceMgr.occupyWindow;
1088
	occupyWindow->tmpOccupation = twm_win->occupation;
1089
	w = occupyWindow->w;
1090
1091
	/* Figure where to put it so it's centered on the cursor */
1092
	XGetGeometry(dpy, w, &JunkRoot, &JunkX, &JunkY, &width, &height,
1093
	             &JunkBW, &JunkDepth);
1094
	XQueryPointer(dpy, Scr->Root, &JunkRoot, &JunkRoot, &JunkX, &JunkY,
1095
	              &x, &y, &JunkMask);
614.1.18 by Maxime Soulé
f.occupy window now uses layout
1096
1097
	occupy_twm = occupyWindow->twm_win;
1098
	occupy_twm->occupation = twm_win->occupation;
1099
1100
	width += 2 * (occupy_twm->frame_bw3D + occupy_twm->frame_bw);
1101
	height += 2 * (occupy_twm->frame_bw3D + occupy_twm->frame_bw);
503.1.102 by Matthew Fuller
Rearrange the functions in occupation.c so they're ordered and grouped
1102
	x -= (width  / 2);
1103
	y -= (height / 2);
614.1.18 by Maxime Soulé
f.occupy window now uses layout
1104
1105
	/* Clip to screen */
1106
	ConstrainByLayout(Scr->BorderedLayout, -1, &x, width, &y, height);
503.1.102 by Matthew Fuller
Rearrange the functions in occupation.c so they're ordered and grouped
1107
1108
	/* Move the occupy window to where it should be */
1109
	if(occupy_twm->parent_vs != twm_win->parent_vs) {
1110
		occupy_twm->vs = twm_win->parent_vs;
1111
		occupy_twm->frame_x = x;
1112
		occupy_twm->frame_y = y;
507.1.8 by Matthew Fuller
Leave a comment about a possibly-questionable function usage.
1113
		/*
1114
		 * XXX Should this be using DisplayWin() like everything else,
1115
		 * rather than manually grubbing beneath it?
1116
		 */
503.1.102 by Matthew Fuller
Rearrange the functions in occupation.c so they're ordered and grouped
1117
		ReparentFrameAndIcon(occupy_twm);
1118
	}
1119
	else {
1120
		XMoveWindow(dpy, occupyWindow->twm_win->frame, x, y);
1121
	}
1122
1123
	/* And show it */
1124
	SetMapStateProp(occupy_twm, NormalState);
1125
	XMapWindow(dpy, occupyWindow->w);
1126
	XMapWindow(dpy, occupy_twm->frame);
1127
1128
	/* XXX Must be a better way to express "all the way on top" */
1129
	OtpSetPriority(occupy_twm, WinWin, 0, Above);
1130
1131
	/* Mark it shown, and stash what window we're showing it for */
1132
	occupyWindow->twm_win->mapped = true;
1133
	occupyWin = twm_win;
1134
}
1135
1136
1137
1138
1139
/*
1140
 ****************************************************************
1141
 *
1142
 * Backend and misc
1143
 *
1144
 ****************************************************************
1145
 */
1146
1147
1148
/*
1149
 * The actual meat of occupation-changing; [re-]set the occupation for
1150
 * the window.  This is the func that actually sets and saves the new
1151
 * occupation, moves the window where it should be, etc.  Should maybe be
1152
 * called something more like "SetOccupation()".
1153
 */
1154
void
1155
ChangeOccupation(TwmWindow *tmp_win, int newoccupation)
1156
{
1157
	TwmWindow *t;
1158
	WorkSpace *ws;
1159
	int oldoccupation;
1160
	int changedoccupation;
1161
1162
	if((newoccupation == 0)
1163
	                || (newoccupation == tmp_win->occupation)) {
1164
		/*
1165
		 * occupation=0 we interpret as "leave it alone".  == current,
1166
		 * ditto.  Go ahead and re-set the WM_OCCUPATION property though,
1167
		 * in case it's been broken by another client.
1168
		 */
1169
		char *namelist;
1170
		int  len;
1171
		long eventMask;
1172
1173
		/* Mask out the PropertyChange events while we change the prop */
511.1.9 by Matthew Fuller
Use mask_out_event{_mask}() and restore_mask() in place of manually
1174
		eventMask = mask_out_event(tmp_win->w, PropertyChangeMask);
503.1.102 by Matthew Fuller
Rearrange the functions in occupation.c so they're ordered and grouped
1175
1176
		len = GetPropertyFromMask(tmp_win->occupation, &namelist);
1177
		XChangeProperty(dpy, tmp_win->w, XA_WM_OCCUPATION, XA_STRING, 8,
1178
		                PropModeReplace, (unsigned char *) namelist, len);
1179
		free(namelist);
1180
#ifdef EWMH
1181
		EwmhSet_NET_WM_DESKTOP(tmp_win);
1182
#endif
1183
1184
		/* Reset event mask */
511.1.9 by Matthew Fuller
Use mask_out_event{_mask}() and restore_mask() in place of manually
1185
		restore_mask(tmp_win->w, eventMask);
503.1.102 by Matthew Fuller
Rearrange the functions in occupation.c so they're ordered and grouped
1186
		return;
1187
	}
1188
1189
	/*
1190
	 * OK, there's something to change.  Stash the current state.
1191
	 */
1192
	oldoccupation = tmp_win->occupation;
1193
1194
	/*
1195
	 * Add it to IconManager in the new WS[en], remove from old.  We have
1196
	 * to do the rather odd dance because AddIconManager() loops through
1197
	 * workspaces, and will add it to any workspaces it occupies (even if
1198
	 * it's already there).  RemoveIconManager() goes over the window's
1199
	 * list of what icon managers it's on and removes it from any that
1200
	 * don't match the current occupation, so it can just be told "here's
1201
	 * where I should be".
1202
	 */
1203
	tmp_win->occupation = newoccupation & ~oldoccupation;
1204
	AddIconManager(tmp_win);
1205
	tmp_win->occupation = newoccupation;
1206
	RemoveIconManager(tmp_win);
1207
1208
	/* If it shouldn't be "here", vanish it */
1209
	if(tmp_win->vs && !OCCUPY(tmp_win, tmp_win->vs->wsw->currentwspc)) {
1210
		Vanish(tmp_win->vs, tmp_win);
1211
	}
1212
1213
	/*
1214
	 * Try to find an(other) virtual screen which shows a workspace
1215
	 * where the window has occupation, so that the window can be shown
1216
	 * there now.
1217
	 */
1218
	if(!tmp_win->vs) {
1219
		VirtualScreen *vs;
1220
		for(vs = Scr->vScreenList; vs != NULL; vs = vs->next) {
1221
			if(OCCUPY(tmp_win, vs->wsw->currentwspc)) {
1222
				DisplayWin(vs, tmp_win);
1223
				break;
1224
			}
1225
		}
1226
	}
1227
1228
	/*
1229
	 * Loop over workspaces.  Find the first one that it used to be in.
1230
	 * If it's not there anymore, take it out of the WindowRegion there
1231
	 * (RWFR() silently returns if we're not using WindowRegion's), and
1232
	 * add it the WindowRegion in the first WS it now occupies.
1233
	 *
1234
	 * XXX I'm not sure this is entirely sensible; it seems like just
1235
	 * unconditionally Remove/Place'ing would have the same effect?
1236
	 */
1237
	for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) {
1238
		int mask = 1 << ws->number;
1239
		if(oldoccupation & mask) {
1240
			if(!(newoccupation & mask)) {
1241
				int final_x, final_y;
1242
				RemoveWindowFromRegion(tmp_win);
1243
				if(PlaceWindowInRegion(tmp_win, &final_x, &final_y)) {
1244
					XMoveWindow(dpy, tmp_win->frame, final_x, final_y);
1245
				}
1246
			}
1247
			break;
1248
		}
1249
	}
1250
511.1.9 by Matthew Fuller
Use mask_out_event{_mask}() and restore_mask() in place of manually
1251
	/* Now set the WM_OCCUPATION property */
503.1.102 by Matthew Fuller
Rearrange the functions in occupation.c so they're ordered and grouped
1252
	{
1253
		char *namelist;
1254
		int  len;
1255
		long eventMask;
1256
511.1.9 by Matthew Fuller
Use mask_out_event{_mask}() and restore_mask() in place of manually
1257
		eventMask = mask_out_event(tmp_win->w, PropertyChangeMask);
503.1.102 by Matthew Fuller
Rearrange the functions in occupation.c so they're ordered and grouped
1258
1259
		len = GetPropertyFromMask(newoccupation, &namelist);
1260
		XChangeProperty(dpy, tmp_win->w, XA_WM_OCCUPATION, XA_STRING, 8,
1261
		                PropModeReplace, (unsigned char *) namelist, len);
1262
		free(namelist);
1263
#ifdef EWMH
1264
		EwmhSet_NET_WM_DESKTOP(tmp_win);
1265
#endif
1266
511.1.9 by Matthew Fuller
Use mask_out_event{_mask}() and restore_mask() in place of manually
1267
		restore_mask(tmp_win->w, eventMask);
503.1.102 by Matthew Fuller
Rearrange the functions in occupation.c so they're ordered and grouped
1268
	}
1269
1270
1271
	/*
1272
	 * Handle showing it up in the workspace map in the appropriate
1273
	 * places.
1274
	 *
1275
	 * Note that this whole block messes with the {new,old}occupation
1276
	 * vars.  That's "safe" because they're no longer used for their
1277
	 * original purposes, only for the WSmap changes, but it's still
1278
	 * kinda fugly.  Change to local vars at the drop of a hat with later
1279
	 * changes...
1280
	 */
1281
	if(!WMapWindowMayBeAdded(tmp_win)) {
1282
		/* Not showing in the map, so pretend it's nowhere */
1283
		newoccupation = 0;
1284
	}
1285
	if(Scr->workSpaceMgr.noshowoccupyall) {
1286
		/*
1287
		 * Don't show OccupyAll.  Note that this means both OccupyAll
1288
		 * window, AND windows manually set to occupy everything.  We
1289
		 * don't have to adjust newoccupation, because the above
1290
		 * conditional would have caught it, so we only need to edit old.
1291
		 */
1292
		if(oldoccupation == fullOccupation) {
1293
			oldoccupation = 0;
1294
		}
1295
	}
1296
1297
	/* Flip the ones that need flipping */
1298
	changedoccupation = oldoccupation ^ newoccupation;
1299
	for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) {
1300
		int mask = 1 << ws->number;
1301
		if(changedoccupation & mask) {
1302
			if(newoccupation & mask) {
1303
				/* Add to WS */
510.1.90 by Matthew Fuller
Rename several of these funcs for adding/removing windows to the WSM
1304
				WMapAddWindowToWorkspace(tmp_win, ws);
503.1.102 by Matthew Fuller
Rearrange the functions in occupation.c so they're ordered and grouped
1305
			}
1306
			else {
1307
				/*
1308
				 * Remove from WS.  We have to take it out of saved focus
1309
				 * if it were there.  Maybe there are other places we
1310
				 * might need to remove it from (warpring?)?
1311
				 */
510.1.90 by Matthew Fuller
Rename several of these funcs for adding/removing windows to the WSM
1312
				WMapRemoveWindowFromWorkspace(tmp_win, ws);
503.1.102 by Matthew Fuller
Rearrange the functions in occupation.c so they're ordered and grouped
1313
				if(Scr->SaveWorkspaceFocus && ws->save_focus == tmp_win) {
1314
					ws->save_focus = NULL;
1315
				}
1316
			}
1317
		}
1318
	}
1319
1320
1321
	/*
1322
	 * If transients don't have their own occupation, find any transients
1323
	 * of this window and move them with it.
1324
	 */
1325
	if(! Scr->TransientHasOccupation) {
1326
		for(t = Scr->FirstWindow; t != NULL; t = t->next) {
1327
			if(t != tmp_win &&
1328
			                ((t->istransient && t->transientfor == tmp_win->w) ||
1329
			                 t->group == tmp_win->w)) {
1330
				ChangeOccupation(t, tmp_win->occupation);
1331
			}
1332
		}
1333
	}
1334
1335
	/* All done */
1336
	return;
1337
}
1338
1339
1340
/*
1341
 * There are various reasons you might not be able to change the
1342
 * occupation of a window (either due to attributes of it, or the state
1343
 * of your session/WM), so provide a function to check them all when we
1344
 * try a change.
1345
 *
1346
 * Note that this is _not_ called from ChangeOccupation(); only from
1347
 * other things that wrap it.  Since CO() gets called from states where
1348
 * this would [falsely] fail, it would be a bad idea to put it there.
1349
 */
1350
static bool
1351
CanChangeOccupation(TwmWindow **twm_winp)
1352
{
1353
	TwmWindow *twm_win;
1354
1355
	/* No workspaces config'd?  Changing is nonsensical. */
1356
	if(!Scr->workSpaceManagerActive) {
1357
		return false;
1358
	}
1359
512.1.4 by Matthew Fuller
Fix up losing the occupation window by iconifying it.
1360
	/*
1361
	 * f.occupy window up?  Can't change in the middle of changing.
1362
	 * Though if it's not mapped, still pull it up, else iconifying the
1363
	 * occupy window breaks it forever.
1364
	 */
1365
	if(occupyWin != NULL && Scr->workSpaceMgr.occupyWindow->twm_win->mapped) {
503.1.102 by Matthew Fuller
Rearrange the functions in occupation.c so they're ordered and grouped
1366
		return false;
1367
	}
1368
1369
	/* XXX Can we jut do this in the init?  Check all callers. */
1370
	twm_win = *twm_winp;
1371
1372
	/* Don't change occupation of icon managers */
1373
	if(twm_win->isiconmgr) {
1374
		return false;
1375
	}
1376
1377
	/* XXX Should check iswspmgr here too? */
1378
1379
	/*
1380
	 * If transients don't have their own occupation, check
1381
	 * transient/group bits.
1382
	 */
1383
	if(!Scr->TransientHasOccupation) {
1384
		if(twm_win->istransient) {
1385
			return false;
1386
		}
1387
		if(twm_win->group != (Window) 0 && twm_win->group != twm_win->w) {
1388
			/*
1389
			 * When trying to modify a group member window,
1390
			 * operate on the group leader instead
1391
			 * (and thereby on all group member windows as well).
1392
			 * If we can't find the group leader, pretend it isn't set.
1393
			 */
1394
			twm_win = GetTwmWindow(twm_win->group);
1395
			if(!twm_win) {
1396
				return true;
1397
			}
1398
			*twm_winp = twm_win;
1399
		}
1400
	}
1401
1402
	/* Sure, go ahead, change it */
1403
	return true;
1404
}
1405
1406
1407
/*
1408
 * Add a client name to a list determining which workspaces it will
1409
 * occupy.  Used in handling the Occupy { } block in config file.
1410
 */
1411
bool
1412
AddToClientsList(char *workspace, char *client)
1413
{
1414
	WorkSpace *ws;
1415
1416
	/* "all" is a magic workspace value which makes it occupy anywhere */
1417
	if(strcmp(workspace, "all") == 0) {
1418
		for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) {
1419
			AddToList(&ws->clientlist, client, "");
1420
		}
1421
		return true;
1422
	}
1423
1424
	/* If prefixed with "ws:", strip the prefix and lookup by WS name */
1425
	if(strncmp(workspace, "ws:", 3) == 0) {
1426
		if((ws = GetWorkspace(workspace + 3)) != NULL) {
1427
			AddToList(&ws->clientlist, client, "");
1428
			return true;
1429
		}
1430
	}
1431
1432
	/* Else find that named workspace and all this to it */
1433
	if((ws = GetWorkspace(workspace)) != NULL) {
1434
		AddToList(&ws->clientlist, client, "");
1435
		return true;
1436
	}
1437
1438
	/* Couldn't figure where to put it */
1439
	return false;
1440
}
1441
1442
1443
/*
503.1.62 by Matthew Fuller
Pull piles of occupation handling out of workmgr.c and into a new
1444
 * Turn a ctwm.workspace resource string into an occupation mask.  n.b.;
1445
 * this changes the 'res' arg in-place.
1446
 */
1447
static int
1448
GetMaskFromResource(TwmWindow *win, char *res)
1449
{
1450
	WorkSpace *ws;
1451
	int       mask;
1452
	enum { O_SET, O_ADD, O_REM } mode;
1453
	char *wrkSpcName, *tokst;
1454
1455
	/*
1456
	 * This can set the occupation to a specific set of workspaces ("ws1
1457
	 * ws3"), add to the set it woudl have otherwise ("+ws1 ws3"), or
1458
	 * remove from the set it would otherwise ("-ws1 ws3").  The +/-
1459
	 * apply to the whole expression, not to the individual entries in
1460
	 * it.  So first, figure out what we're doing.
1461
	 */
1462
	mode = O_SET;
1463
	if(*res == '+') {
1464
		mode = O_ADD;
1465
		res++;
1466
	}
1467
	else if(*res == '-') {
1468
		mode = O_REM;
1469
		res++;
1470
	}
1471
1472
	/*
1473
	 * Walk through the string adding the workspaces specified into the
1474
	 * mask of what we're doing.
1475
	 */
1476
	mask = 0;
1477
	for(wrkSpcName = strtok_r(res, " ", &tokst) ; wrkSpcName
1478
	                ; wrkSpcName = strtok_r(NULL, " ", &tokst)) {
1479
		if(strcmp(wrkSpcName, "all") == 0) {
1480
			mask = fullOccupation;
1481
			break;
1482
		}
1483
		if(strcmp(wrkSpcName, "current") == 0) {
1484
			VirtualScreen *vs = Scr->currentvs;
1485
			if(vs) {
1486
				mask |= (1 << vs->wsw->currentwspc->number);
1487
			}
1488
			continue;
1489
		}
1490
1491
		ws = GetWorkspace(wrkSpcName);
1492
		if(ws != NULL) {
1493
			mask |= (1 << ws->number);
1494
		}
1495
		else {
1496
			fprintf(stderr, "unknown workspace : %s\n", wrkSpcName);
1497
		}
1498
	}
1499
1500
	/*
1501
	 * And return that mask, with necessary alterations depending on +/-
1502
	 * specified.
1503
	 */
1504
	switch(mode) {
1505
		case O_SET:
1506
			return (mask);
1507
		case O_ADD:
1508
			return (mask | win->occupation);
1509
		case O_REM:
1510
			return (win->occupation & ~mask);
1511
	}
1512
1513
	/* Can't get here */
1514
	fprintf(stderr, "%s(): Unreachable.\n", __func__);
1515
	return 0;
1516
}
1517
1518
1519
/*
1520
 * Turns a \0-separated buffer of workspace names into an occupation
1521
 * bitmask.
1522
 */
1523
unsigned int
1524
GetMaskFromProperty(unsigned char *_prop, unsigned long len)
1525
{
503.1.103 by Matthew Fuller
Use safe_strncpy() here to be sure we can't overflow the buffer.
1526
	char         wrkSpcName[256];
503.1.62 by Matthew Fuller
Pull piles of occupation handling out of workmgr.c and into a new
1527
	WorkSpace    *ws;
1528
	unsigned int mask;
1529
	int          l;
1530
	char         *prop;
1531
1532
	mask = 0;
1533
	l = 0;
1534
	prop = (char *) _prop;
1535
	while(l < len) {
503.1.103 by Matthew Fuller
Use safe_strncpy() here to be sure we can't overflow the buffer.
1536
		/* If you have WS names longer than 256 chars, that's just Too Bad */
1537
		safe_strncpy(wrkSpcName, prop, 256);
503.1.62 by Matthew Fuller
Pull piles of occupation handling out of workmgr.c and into a new
1538
		l    += strlen(prop) + 1;
1539
		prop += strlen(prop) + 1;
1540
		if(strcmp(wrkSpcName, "all") == 0) {
1541
			mask = fullOccupation;
1542
			break;
1543
		}
1544
1545
		ws = GetWorkspace(wrkSpcName);
1546
		if(ws != NULL) {
1547
			mask |= (1 << ws->number);
1548
		}
1549
		else {
1550
			fprintf(stderr, "unknown workspace : %s\n", wrkSpcName);
1551
		}
1552
	}
1553
1554
#if 0
1555
	{
1556
		char *dbs = mk_nullsep_string((char *)_prop, len);
1557
		fprintf(stderr, "%s('%s') -> 0x%x\n", __func__, dbs, mask);
1558
		free(dbs);
1559
	}
1560
#endif
1561
1562
	return (mask);
1563
}
1564
1565
1566
/*
1567
 * Turns an occupation mask into a \0-separated buffer (not really a
1568
 * string) of the workspace names.
1569
 */
1570
int
1571
GetPropertyFromMask(unsigned int mask, char **prop)
1572
{
1573
	WorkSpace *ws;
1574
	int       len;
1575
	char      *wss[MAXWORKSPACE];
1576
	int       i;
1577
1578
	/* If it's everything, just say 'all' */
1579
	if(mask == fullOccupation) {
1580
		*prop = strdup("all");
1581
		return 3;
1582
	}
1583
1584
	/* Stash up pointers to all the labels for WSen it's in */
1585
	memset(wss, 0, sizeof(wss));
1586
	i = 0;
1587
	len = 0;
1588
	for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) {
1589
		if(mask & (1 << ws->number)) {
1590
			wss[i++] = ws->label;
1591
			len += strlen(ws->label) + 1;
1592
		}
1593
	}
1594
1595
	/* Assemble them into \0-separated string */
1596
	*prop = malloc(len);
1597
	len = 0;
1598
	for(i = 0 ; wss[i] != NULL ; i++) {
1599
		strcpy((*prop + len), wss[i]);
1600
		len += strlen(wss[i]) + 1; // Skip past \0
1601
	}
1602
1603
#if 0
1604
	{
1605
		char *dbs = mk_nullsep_string(*prop, len);
1606
		fprintf(stderr, "%s(0x%x) -> %d:'%s'\n", __func__, mask, len, dbs);
1607
		free(dbs);
1608
	}
1609
#endif
1610
1611
	return len;
1612
}
1613
1614
1615
/*
1616
 * Generate a printable variant of the null-separated strings we use for
1617
 * stashing in XA_WM_OCCUPATION.  Used for debugging
1618
 * Get{Property,Mask}From{Mask,Property}().
1619
 */
1620
#ifdef __GNUC__
1621
# pragma GCC diagnostic push
1622
# pragma GCC diagnostic ignored "-Wunused-function"
1623
#endif
1624
static char *
1625
mk_nullsep_string(const char *prop, int len)
1626
{
1627
	char *dbs;
1628
	int i, j;
1629
1630
	/*
1631
	 * '\0' => "\\0" means we need longer than input; *2 is overkill,
1632
	 * but always sufficient, and it's cheap.
1633
	 */
1634
	dbs = malloc(len * 2);
1635
	i = j = 0;
1636
	while(i < len) {
1637
		size_t slen = strlen(prop + i);
1638
1639
		strcpy(dbs + j, (prop + i));
1640
		i += slen + 1;
1641
		strcpy(dbs + j + slen, "\\0");
1642
		j += slen + 2;
1643
	}
1644
1645
	return dbs;
1646
}
1647
#ifdef __GNUC__
1648
# pragma GCC diagnostic pop
1649
#endif