~ctwm/ctwm/trunk

648.1.1 by Matthew Fuller
Extract the funcs relating to shutting down ctwm ('restart' is a kind
1
/*
2
 * Shutdown (/restart) bits
3
 */
4
5
#include "ctwm.h"
6
7
#include <stdlib.h>
8
#include <stdio.h>
9
#include <unistd.h>
10
11
#include "animate.h"
692.1.6 by Matthew Fuller
Conditionalize including captive.h.
12
#ifdef CAPTIVE
648.1.1 by Matthew Fuller
Extract the funcs relating to shutting down ctwm ('restart' is a kind
13
#include "captive.h"
692.1.6 by Matthew Fuller
Conditionalize including captive.h.
14
#endif
648.1.1 by Matthew Fuller
Extract the funcs relating to shutting down ctwm ('restart' is a kind
15
#include "colormaps.h"
16
#include "ctwm_atoms.h"
17
#include "ctwm_shutdown.h"
18
#include "screen.h"
19
#include "session.h"
20
#ifdef SOUNDS
21
# include "sound.h"
22
#endif
23
#include "otp.h"
24
#include "win_ops.h"
25
#include "win_utils.h"
26
27
648.1.18 by Matthew Fuller
Rename these restore-config funcs so the names are a little less
28
static void RestoreForShutdown(Time mytime);
648.1.1 by Matthew Fuller
Extract the funcs relating to shutting down ctwm ('restart' is a kind
29
30
31
/**
648.1.15 by Matthew Fuller
Comment up RestoreWithdrawnLocation() and drop a mark on one caller.
32
 * Put a window back where it should be if we don't (any longer) control
652.1.39 by Matthew Fuller
Update comment a bit.
33
 * it and reparent it back up to the root.  This leaves it where it was
34
 * before we started (well, adjusted by any moves we've made to it
35
 * since), and placed so that if we restart and take it back over, it'll
36
 * wind up right where it is now, so restarting doesn't shift windows all
37
 * over the place.
648.1.1 by Matthew Fuller
Extract the funcs relating to shutting down ctwm ('restart' is a kind
38
 */
39
void
648.1.18 by Matthew Fuller
Rename these restore-config funcs so the names are a little less
40
RestoreWinConfig(TwmWindow *tmp)
648.1.1 by Matthew Fuller
Extract the funcs relating to shutting down ctwm ('restart' is a kind
41
{
652.1.38 by Matthew Fuller
Reindent due to elimination of a block, move the vars up to the top of
42
	int gravx, gravy;
43
	int newx, newy;
44
45
	// Things adjusting by the border have to move our border size, but
46
	// subtract away from that the old border we're restoring.
47
	const int borders = tmp->frame_bw + tmp->frame_bw3D - tmp->old_bw;
48
648.1.15 by Matthew Fuller
Comment up RestoreWithdrawnLocation() and drop a mark on one caller.
49
	// If this window is "unmapped" by moving it way offscreen, and is in
50
	// that state, move it back onto the window.
648.1.1 by Matthew Fuller
Extract the funcs relating to shutting down ctwm ('restart' is a kind
51
	if(tmp->UnmapByMovingFarAway && !visible(tmp)) {
52
		XMoveWindow(dpy, tmp->frame, tmp->frame_x, tmp->frame_y);
53
	}
648.1.15 by Matthew Fuller
Comment up RestoreWithdrawnLocation() and drop a mark on one caller.
54
55
	// If it's squeezed, unsqueeze it.
648.1.1 by Matthew Fuller
Extract the funcs relating to shutting down ctwm ('restart' is a kind
56
	if(tmp->squeezed) {
57
		Squeeze(tmp);
58
	}
648.1.15 by Matthew Fuller
Comment up RestoreWithdrawnLocation() and drop a mark on one caller.
59
652.1.37 by Matthew Fuller
Invert this condition; just exit out early, instead of
60
	// This is apparently our standard "is this window still around?"
61
	// idiom.
652.1.36 by Matthew Fuller
We're no longer using the XGetGeometry returns, so just use junk for
62
	if(XGetGeometry(dpy, tmp->w, &JunkRoot, &JunkX, &JunkY,
652.1.37 by Matthew Fuller
Invert this condition; just exit out early, instead of
63
	                &JunkWidth, &JunkHeight, &JunkBW, &JunkDepth) == 0) {
64
		// Well, give up...
65
		return;
66
	}
652.1.38 by Matthew Fuller
Reindent due to elimination of a block, move the vars up to the top of
67
68
	// Get gravity bits to know how to move stuff around when we take
69
	// away the decorations.
70
	GetGravityOffsets(tmp, &gravx, &gravy);
71
72
	// We want to move the window to where it should be "outside" of our
73
	// frame.  This varies depending on the window gravity detail, and we
74
	// have to account for that, since on re-startup we'll be doing it to
75
	// resposition it after we re-wrap it.
76
	//
77
	// e.g., in simple "NorthWest" gravity, we just made the frame start
78
	// where the window did, and shifted the app window right (by the
79
	// border width) and down (by the border width + titlebar).  However,
80
	// "SouthEast" gravity means the bottom right of the frame is where
652.1.42 by Matthew Fuller
Fixup some tpyos and slightly improve some verbiage in comments.
81
	// the windows' was, and the window itself shifted left/up by the
82
	// border.  Compare e.g. an xterm with -geometry "+0+0" with one
83
	// using "-0-0" as an easy trick to make windows with different
84
	// geoms.
652.1.38 by Matthew Fuller
Reindent due to elimination of a block, move the vars up to the top of
85
	newx = tmp->frame_x;
86
	newy = tmp->frame_y;
87
88
89
	// So, first consider the north/south gravity.  If gravity is North,
90
	// we put the top of the frame where the window was and shifted
91
	// everything inside down, so the top of the frame now is where the
92
	// window should be put.  With South-y gravity, the window should
93
	// wind up at the bottom of the frame, which means we need to shift
94
	// it down by the titlebar height, plus twice the border width.  But
95
	// if the vertical gravity is neutral, then the window needs to wind
96
	// up staying right where it is, because we built the frame around it
97
	// without moving it.
98
	//
99
	// Previous code here (and code elsewhere) expressed this calculation
100
	// by the rather confusing idiom ((gravy + 1) * border_width), which
101
	// gives the right answer, but is confusing as hell...
102
	if(gravy < 0) {
103
		// North; where the frame starts (already set)
104
	}
105
	else if(gravy > 0) {
106
		// South; shift down title + 2*border
107
		newy += tmp->title_height + 2 * borders;
108
	}
109
	else {
110
		// Neutral; down by the titlebar + border.
111
		newy += tmp->title_height + borders;
112
	}
113
114
652.1.42 by Matthew Fuller
Fixup some tpyos and slightly improve some verbiage in comments.
115
	// Now east/west.  West means align with the frame start, east means
652.1.38 by Matthew Fuller
Reindent due to elimination of a block, move the vars up to the top of
116
	// align with the frame right edge, neutral means where it already
117
	// is.
118
	if(gravx < 0) {
652.1.42 by Matthew Fuller
Fixup some tpyos and slightly improve some verbiage in comments.
119
		// West; it's already correct
652.1.38 by Matthew Fuller
Reindent due to elimination of a block, move the vars up to the top of
120
	}
121
	else if(gravx > 0) {
122
		// East; shift over by 2*border
123
		newx += 2 * borders;
124
	}
125
	else {
126
		// Neutral; over by the left border
127
		newx += borders;
128
	}
129
130
700.1.11 by Matthew Fuller
Hide these TwmWindow winbox-related fields behind an ifdef along with
131
#ifdef WINBOX
652.1.38 by Matthew Fuller
Reindent due to elimination of a block, move the vars up to the top of
132
	// If it's in a WindowBox, reparent the frame back up to our real root
133
	if(tmp->winbox && tmp->winbox->twmwin && tmp->frame) {
134
		int xbox, ybox;
135
		unsigned int j_bw;
136
137
		// XXX This isn't right, right?  This will give coords relative
138
		// to the window box, but we're using them relative to the real
139
		// screen root?
140
		if(XGetGeometry(dpy, tmp->frame, &JunkRoot, &xbox, &ybox,
141
		                &JunkWidth, &JunkHeight, &j_bw, &JunkDepth)) {
142
			ReparentWindow(dpy, tmp, WinWin, Scr->Root, xbox, ybox);
143
		}
144
	}
700.1.11 by Matthew Fuller
Hide these TwmWindow winbox-related fields behind an ifdef along with
145
#endif
652.1.38 by Matthew Fuller
Reindent due to elimination of a block, move the vars up to the top of
146
147
148
	// Restore the original window border if there were one
149
	if(tmp->old_bw) {
150
		XSetWindowBorderWidth(dpy, tmp->w, tmp->old_bw);
151
	}
152
153
	// Reparent and move back to where it otter be
154
	XReparentWindow(dpy, tmp->w, Scr->Root, newx, newy);
155
156
	// If it came with a pre-made icon window, hide it
157
	if(tmp->wmhints->flags & IconWindowHint) {
158
		XUnmapWindow(dpy, tmp->wmhints->icon_window);
159
	}
648.1.15 by Matthew Fuller
Comment up RestoreWithdrawnLocation() and drop a mark on one caller.
160
161
	// Done
162
	return;
648.1.1 by Matthew Fuller
Extract the funcs relating to shutting down ctwm ('restart' is a kind
163
}
164
165
166
/**
167
 * Restore some window positions/etc in preparation for going away.
168
 */
169
static void
648.1.18 by Matthew Fuller
Rename these restore-config funcs so the names are a little less
170
RestoreForShutdown(Time mytime)
648.1.1 by Matthew Fuller
Extract the funcs relating to shutting down ctwm ('restart' is a kind
171
{
648.1.16 by Matthew Fuller
Comment up Reborder().
172
	ScreenInfo *savedScr = Scr;  // We need Scr flipped around...
648.1.1 by Matthew Fuller
Extract the funcs relating to shutting down ctwm ('restart' is a kind
173
174
	XGrabServer(dpy);
648.1.16 by Matthew Fuller
Comment up Reborder().
175
176
	for(int scrnum = 0; scrnum < NumScreens; scrnum++) {
648.1.1 by Matthew Fuller
Extract the funcs relating to shutting down ctwm ('restart' is a kind
177
		if((Scr = ScreenList[scrnum]) == NULL) {
178
			continue;
179
		}
180
648.1.16 by Matthew Fuller
Comment up Reborder().
181
		// Force reinstalling any colormaps
182
		InstallColormaps(0, &Scr->RootColormaps);
183
652.1.26 by Matthew Fuller
Replace RestoreWinConfig() calls with explicit Reparent's in our
184
		// Pull all the windows out of their frames and reposition them
652.1.41 by Matthew Fuller
Slightly improve comment.
185
		// where the frame was, with approprate adjustments for gravity.
186
		// This will preserve their positions when we restart, or put
187
		// them back where they were before we started.  Do it from the
188
		// bottom up of our stacking order to preserve the stacking.
652.1.26 by Matthew Fuller
Replace RestoreWinConfig() calls with explicit Reparent's in our
189
		for(TwmWindow *tw = OtpBottomWin() ; tw != NULL
190
		                ; tw = OtpNextWinUp(tw)) {
652.1.31 by Matthew Fuller
It turns out we really do need to do reworking of the coordinates to
191
			if(tw->isiconmgr || tw->iswspmgr || tw->isoccupy) {
192
				// Don't bother with internals...
193
				continue;
194
			}
195
			RestoreWinConfig(tw);
648.1.1 by Matthew Fuller
Extract the funcs relating to shutting down ctwm ('restart' is a kind
196
		}
197
	}
648.1.16 by Matthew Fuller
Comment up Reborder().
198
648.1.1 by Matthew Fuller
Extract the funcs relating to shutting down ctwm ('restart' is a kind
199
	XUngrabServer(dpy);
648.1.16 by Matthew Fuller
Comment up Reborder().
200
201
	// Restore
202
	Scr = savedScr;
203
204
	// Focus away from any windows
648.1.1 by Matthew Fuller
Extract the funcs relating to shutting down ctwm ('restart' is a kind
205
	SetFocus(NULL, mytime);
206
}
207
208
209
/**
648.1.19 by Matthew Fuller
Done() -> DoShutdown(). Imperative form is more descriptive, and it's
210
 * Cleanup and exit ctwm
648.1.1 by Matthew Fuller
Extract the funcs relating to shutting down ctwm ('restart' is a kind
211
 */
212
void
648.1.19 by Matthew Fuller
Done() -> DoShutdown(). Imperative form is more descriptive, and it's
213
DoShutdown(void)
648.1.1 by Matthew Fuller
Extract the funcs relating to shutting down ctwm ('restart' is a kind
214
{
648.1.20 by Matthew Fuller
Comment through shutdown/restart funcs, and note how weird things are
215
648.1.1 by Matthew Fuller
Extract the funcs relating to shutting down ctwm ('restart' is a kind
216
#ifdef SOUNDS
648.1.20 by Matthew Fuller
Comment through shutdown/restart funcs, and note how weird things are
217
	// Denounce ourselves
648.1.1 by Matthew Fuller
Extract the funcs relating to shutting down ctwm ('restart' is a kind
218
	play_exit_sound();
219
#endif
648.1.20 by Matthew Fuller
Comment through shutdown/restart funcs, and note how weird things are
220
221
	// Restore windows/colormaps for our absence.
648.1.18 by Matthew Fuller
Rename these restore-config funcs so the names are a little less
222
	RestoreForShutdown(CurrentTime);
648.1.20 by Matthew Fuller
Comment through shutdown/restart funcs, and note how weird things are
223
648.1.1 by Matthew Fuller
Extract the funcs relating to shutting down ctwm ('restart' is a kind
224
#ifdef EWMH
648.1.20 by Matthew Fuller
Comment through shutdown/restart funcs, and note how weird things are
225
	// Clean up EWMH properties
648.1.1 by Matthew Fuller
Extract the funcs relating to shutting down ctwm ('restart' is a kind
226
	EwmhTerminate();
648.1.20 by Matthew Fuller
Comment through shutdown/restart funcs, and note how weird things are
227
#endif
228
229
	// Clean up our list of workspaces
648.1.1 by Matthew Fuller
Extract the funcs relating to shutting down ctwm ('restart' is a kind
230
	XDeleteProperty(dpy, Scr->Root, XA_WM_WORKSPACESLIST);
648.1.20 by Matthew Fuller
Comment through shutdown/restart funcs, and note how weird things are
231
692.1.5 by Matthew Fuller
Add ifdef's around references to Screen and CLargs members that are
232
#ifdef CAPTIVE
648.1.20 by Matthew Fuller
Comment through shutdown/restart funcs, and note how weird things are
233
	// Shut down captive stuff
648.1.1 by Matthew Fuller
Extract the funcs relating to shutting down ctwm ('restart' is a kind
234
	if(CLarg.is_captive) {
235
		RemoveFromCaptiveList(Scr->captivename);
236
	}
692.1.5 by Matthew Fuller
Add ifdef's around references to Screen and CLargs members that are
237
#endif
648.1.20 by Matthew Fuller
Comment through shutdown/restart funcs, and note how weird things are
238
239
	// Close up shop
648.1.1 by Matthew Fuller
Extract the funcs relating to shutting down ctwm ('restart' is a kind
240
	XCloseDisplay(dpy);
241
	exit(0);
242
}
243
244
245
/**
246
 * exec() ourself to restart.
247
 */
248
void
249
DoRestart(Time t)
250
{
648.1.20 by Matthew Fuller
Comment through shutdown/restart funcs, and note how weird things are
251
	// Don't try to do any further animating
648.1.1 by Matthew Fuller
Extract the funcs relating to shutting down ctwm ('restart' is a kind
252
	StopAnimation();
253
	XSync(dpy, 0);
648.1.20 by Matthew Fuller
Comment through shutdown/restart funcs, and note how weird things are
254
255
	// Replace all the windows/colormaps as if we were going away.  'cuz
256
	// we are.
648.1.18 by Matthew Fuller
Rename these restore-config funcs so the names are a little less
257
	RestoreForShutdown(t);
648.1.1 by Matthew Fuller
Extract the funcs relating to shutting down ctwm ('restart' is a kind
258
	XSync(dpy, 0);
259
648.1.20 by Matthew Fuller
Comment through shutdown/restart funcs, and note how weird things are
260
	// Shut down session management connection cleanly.
648.1.1 by Matthew Fuller
Extract the funcs relating to shutting down ctwm ('restart' is a kind
261
	if(smcConn) {
262
		SmcCloseConnection(smcConn, 0, NULL);
263
	}
264
648.1.20 by Matthew Fuller
Comment through shutdown/restart funcs, and note how weird things are
265
	// Re-run ourself
266
	fprintf(stderr, "%s:  restarting:  %s\n", ProgramName, *Argv);
648.1.1 by Matthew Fuller
Extract the funcs relating to shutting down ctwm ('restart' is a kind
267
	execvp(*Argv, Argv);
648.1.20 by Matthew Fuller
Comment through shutdown/restart funcs, and note how weird things are
268
269
	// Uh oh, we shouldn't get here...
648.1.1 by Matthew Fuller
Extract the funcs relating to shutting down ctwm ('restart' is a kind
270
	fprintf(stderr, "%s:  unable to restart:  %s\n", ProgramName, *Argv);
648.1.20 by Matthew Fuller
Comment through shutdown/restart funcs, and note how weird things are
271
272
	// We should probably un-RestoreForShutdown() etc.  If that exec
273
	// fails, we're in a really weird state...
648.1.21 by Matthew Fuller
At least add a XBell call if restart fails, so maybe we'll get a
274
	XBell(dpy, 0);
648.1.1 by Matthew Fuller
Extract the funcs relating to shutting down ctwm ('restart' is a kind
275
}