Use inotify to check for changes to the defaults database. Workaround for
[wmaker-crm.git] / src / shutdown.c
1 /*
2  *  Window Maker window manager
3  *
4  *  Copyright (c) 1997-2003 Alfredo K. Kojima
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 2 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
19  *  USA.
20  */
21
22 #include "wconfig.h"
23
24 #include <stdlib.h>
25 #include <signal.h>
26 #include <unistd.h>
27
28 #include <X11/Xlib.h>
29 #include <X11/Xutil.h>
30
31 #include "WindowMaker.h"
32 #include "window.h"
33 #include "client.h"
34 #include "funcs.h"
35 #include "properties.h"
36 #include "session.h"
37 #include "winspector.h"
38 #include "wmspec.h"
39
40 extern Atom _XA_WM_DELETE_WINDOW;
41 extern Time LastTimestamp;
42 extern int wScreenCount;
43
44
45 static void wipeDesktop(WScreen *scr);
46
47
48 /*
49  *----------------------------------------------------------------------
50  * Shutdown-
51  *      Exits the window manager cleanly. If mode is WSLogoutMode,
52  * the whole X session will be closed, by killing all clients if
53  * no session manager is running or by asking a shutdown to
54  * it if its present.
55  *
56  *----------------------------------------------------------------------
57  */
58 void
59 Shutdown(WShutdownMode mode)
60 {
61     int i;
62     extern int inotifyFD;
63
64     switch (mode) {
65     case WSLogoutMode:
66 #ifdef XSMP_ENABLED
67         wSessionRequestShutdown();
68         break;
69 #else
70         /* fall through */
71 #endif
72     case WSKillMode:
73     case WSExitMode:
74         /* if there is no session manager, send SAVE_YOURSELF to
75          * the clients */
76 #if 0
77 #ifdef XSMP_ENABLED
78         if (!wSessionIsManaged())
79 #endif
80             for (i = 0; i < wScreenCount; i++) {
81                 WScreen *scr;
82
83                 scr = wScreenWithNumber(i);
84                 if (scr) {
85                     wSessionSendSaveYourself(scr);
86                 }
87             }
88 #endif
89         close(inotifyFD);
90         for (i = 0; i < wScreenCount; i++) {
91             WScreen *scr;
92
93             scr = wScreenWithNumber(i);
94             if (scr) {
95                 if (scr->helper_pid)
96                     kill(scr->helper_pid, SIGKILL);
97
98                 /* if the session is not being managed, save restart info */
99 #ifdef XSMP_ENABLED
100                 if (!wSessionIsManaged())
101 #endif
102                     wSessionSaveClients(scr);
103
104                 wScreenSaveState(scr);
105
106                 if (mode == WSKillMode)
107                     wipeDesktop(scr);
108                 else
109                     RestoreDesktop(scr);
110             }
111         }
112         ExecExitScript();
113         Exit(0);
114         break;
115
116     case WSRestartPreparationMode:
117         for (i=0; i<wScreenCount; i++) {
118             WScreen *scr;
119
120             close(inotifyFD);
121             scr = wScreenWithNumber(i);
122             if (scr) {
123                 if (scr->helper_pid)
124                     kill(scr->helper_pid, SIGKILL);
125                 wScreenSaveState(scr);
126                 RestoreDesktop(scr);
127             }
128         }
129         break;
130     }
131 }
132
133
134 static void
135 restoreWindows(WMBag *bag, WMBagIterator iter)
136 {
137     WCoreWindow *next;
138     WCoreWindow *core;
139     WWindow *wwin;
140
141
142     if (iter == NULL) {
143         core = WMBagFirst(bag, &iter);
144     } else {
145         core = WMBagNext(bag, &iter);
146     }
147
148     if (core == NULL)
149         return;
150
151     restoreWindows(bag, iter);
152
153     /* go to the end of the list */
154     while (core->stacking->under)
155         core = core->stacking->under;
156
157     while (core) {
158         next = core->stacking->above;
159
160         if (core->descriptor.parent_type==WCLASS_WINDOW) {
161             Window window;
162
163             wwin = core->descriptor.parent;
164             window = wwin->client_win;
165             wUnmanageWindow(wwin, !wwin->flags.internal_window, False);
166             XMapWindow(dpy, window);
167         }
168         core = next;
169     }
170 }
171
172
173 /*
174  *----------------------------------------------------------------------
175  * RestoreDesktop--
176  *      Puts the desktop in a usable state when exiting.
177  *
178  * Side effects:
179  *      All frame windows are removed and windows are reparented
180  * back to root. Windows that are outside the screen are
181  * brought to a viable place.
182  *
183  *----------------------------------------------------------------------
184  */
185 void
186 RestoreDesktop(WScreen *scr)
187 {
188     if (scr->helper_pid > 0) {
189         kill(scr->helper_pid, SIGTERM);
190         scr->helper_pid = 0;
191     }
192
193     XGrabServer(dpy);
194     wDestroyInspectorPanels();
195
196     /* reparent windows back to the root window, keeping the stacking order */
197     restoreWindows(scr->stacking_list, NULL);
198
199     XUngrabServer(dpy);
200     XSetInputFocus(dpy, PointerRoot, RevertToParent, CurrentTime);
201     wColormapInstallForWindow(scr, NULL);
202     PropCleanUp(scr->root_win);
203     wNETWMCleanup(scr);
204     XSync(dpy, 0);
205 }
206
207
208 /*
209  *----------------------------------------------------------------------
210  * wipeDesktop--
211  *      Kills all windows in a screen. Send DeleteWindow to all windows
212  * that support it and KillClient on all windows that don't.
213  *
214  * Side effects:
215  *      All managed windows are closed.
216  *
217  * TODO: change to XQueryTree()
218  *----------------------------------------------------------------------
219  */
220 static void
221 wipeDesktop(WScreen *scr)
222 {
223     WWindow *wwin;
224
225     wwin = scr->focused_window;
226     while (wwin) {
227         if (wwin->protocols.DELETE_WINDOW)
228             wClientSendProtocol(wwin, _XA_WM_DELETE_WINDOW, LastTimestamp);
229         else
230             wClientKill(wwin);
231         wwin = wwin->prev;
232     }
233     XSync(dpy, False);
234 }
235