]> git.decadent.org.uk Git - ion3.git/blob - ioncore/exec.c
[svn-upgrade] Integrating new upstream version, ion3 (20070608)
[ion3.git] / ioncore / exec.c
1 /*
2  * ion/ioncore/exec.c
3  *
4  * Copyright (c) Tuomo Valkonen 1999-2007. 
5  *
6  * See the included file LICENSE for details.
7  */
8
9 #include <limits.h>
10 #include <string.h>
11 #include <stdlib.h>
12 #include <stdio.h>
13
14 #include <libmainloop/select.h>
15 #include <libmainloop/exec.h>
16
17 #include "common.h"
18 #include "exec.h"
19 #include "property.h"
20 #include "global.h"
21 #include "ioncore.h"
22 #include "saveload.h"
23
24
25 /*{{{ Exec */
26
27
28 void ioncore_setup_display(int xscr)
29 {
30     char *tmp, *ptr;
31     char *display;
32
33     /* Set up $DISPLAY */
34     
35     display=XDisplayName(ioncore_g.display);
36     
37     /* %ui, UINT_MAX is used to ensure there is enough space for the screen
38      * number
39      */
40     libtu_asprintf(&tmp, "DISPLAY=%s.0123456789a", display);
41
42     if(tmp==NULL)
43         return;
44
45     ptr=strchr(tmp, ':');
46     if(ptr!=NULL){
47         ptr=strchr(ptr, '.');
48         if(ptr!=NULL)
49             *ptr='\0';
50     }
51
52     if(xscr>=0)
53         snprintf(tmp+strlen(tmp), 11, ".%u", (unsigned)xscr);
54     
55     putenv(tmp);
56         
57     /* No need to free it, we'll execve soon */
58     /*free(tmp);*/
59
60     /*XFree(display);*/
61 }
62
63
64 void ioncore_setup_environ(const WExecP *p)
65 {
66     /* Set up $DISPLAY */
67     
68     ioncore_setup_display(p->target!=NULL 
69                           ? region_rootwin_of(p->target)->xscr
70                           : -1);
71     
72     /* Set up working directory */
73     
74     if(p->wd!=NULL){
75         if(chdir(p->wd)!=0)
76             warn_err_obj(p->wd);
77     }
78 }
79
80
81 WHook *ioncore_exec_environ_hook=NULL;
82
83
84 static void setup_exec(void *execp)
85 {
86     hook_call_p(ioncore_exec_environ_hook, execp, NULL);
87     
88 #ifndef CF_NO_SETPGID
89     setpgid(0, 0);
90 #endif
91     
92     ioncore_g.dpy=NULL;
93 }
94
95
96 EXTL_EXPORT
97 int ioncore_do_exec_on(WRegion *reg, const char *cmd, const char *wd,
98                        ExtlFn errh)
99 {
100     WExecP p;
101     
102     p.target=reg;
103     p.cmd=cmd;
104     p.wd=wd;
105     
106     return mainloop_popen_bgread(cmd, setup_exec, (void*)&p, 
107                                  extl_fn_none(), errh);
108 }
109
110
111 /*EXTL_DOC
112  * Run \var{cmd} with the environment variable DISPLAY set to point to the
113  * X display the WM is running on. No specific screen is set unlike with
114  * \fnref{WRootWin.exec_on}. The PID of the (shell executing the) new 
115  * process is returned.
116  */
117 EXTL_SAFE
118 EXTL_EXPORT
119 int ioncore_exec(const char *cmd)
120 {
121     return ioncore_do_exec_on(NULL, cmd, NULL, extl_fn_none());
122 }
123
124
125 /*EXTL_DOC
126  * Run \var{cmd} with a read pipe connected to its stdout and stderr.
127  * When data is received through one of these pipes, \var{h} or \var{errh} 
128  * is called with that data. When the pipe is closed, the handler is called
129  * with \code{nil} argument. The PID of the new process is returned, or
130  * -1 on error.
131  */
132 EXTL_SAFE
133 EXTL_EXPORT
134 int ioncore_popen_bgread(const char *cmd, ExtlFn h, ExtlFn errh)
135 {
136     WExecP p;
137     
138     p.target=NULL;
139     p.wd=NULL;
140     p.cmd=cmd;
141     
142     return mainloop_popen_bgread(cmd, setup_exec, (void*)&p, h, errh);
143 }
144
145
146
147 /*}}}*/
148
149
150 /*{{{ Exit, restart, snapshot */
151
152
153 static void (*smhook)(int what);
154
155 bool ioncore_set_smhook(void (*fn)(int what))
156 {
157     smhook=fn;
158     return TRUE;
159 }
160
161
162 void ioncore_do_exit()
163 {
164     ioncore_deinit();
165     exit(0);
166 }
167
168
169 bool ioncore_do_snapshot()
170 {
171     if(!ioncore_save_layout())
172         return FALSE;
173
174     extl_protect(NULL);
175     hook_call_v(ioncore_snapshot_hook);
176     extl_unprotect(NULL);
177     
178     return TRUE;
179 }
180
181
182 void ioncore_emergency_snapshot()
183 {
184     if(smhook!=NULL)
185         warn(TR("Not saving state: running under session manager."));
186     else
187         ioncore_do_snapshot();
188 }
189
190
191
192 static char *other=NULL;
193
194 static void set_other(const char *s)
195 {
196     if(other!=NULL)
197         free(other);
198     other=(s==NULL ? NULL : scopy(s));
199 }
200
201
202 void ioncore_do_restart()
203 {
204     ioncore_deinit();
205     if(other!=NULL){
206         if(ioncore_g.display!=NULL)
207             ioncore_setup_display(-1);
208         mainloop_do_exec(other);
209         warn_err_obj(other);
210     }
211     execvp(ioncore_g.argv[0], ioncore_g.argv);
212     die_err_obj(ioncore_g.argv[0]);
213 }
214
215
216 /*EXTL_DOC
217  * Causes the window manager to simply exit without saving
218  * state/session.
219  */
220 EXTL_EXPORT
221 void ioncore_resign()
222 {
223     if(smhook!=NULL){
224         smhook(IONCORE_SM_RESIGN);
225     }else{
226         ioncore_do_exit();
227     }
228 }
229
230
231 /*EXTL_DOC
232  * End session saving it first.
233  */
234 EXTL_EXPORT
235 void ioncore_shutdown()
236 {
237     if(smhook!=NULL){
238         smhook(IONCORE_SM_SHUTDOWN);
239     }else{
240         ioncore_do_snapshot();
241         ioncore_do_exit();
242     }
243 }
244
245
246 /*EXTL_DOC
247  * Restart, saving session first.
248  */
249 EXTL_EXPORT
250 void ioncore_restart()
251 {
252     set_other(NULL);
253     
254     if(smhook!=NULL){
255         smhook(IONCORE_SM_RESTART);
256     }else{
257         ioncore_do_snapshot();
258         ioncore_do_restart();
259     }
260 }
261
262
263 /*EXTL_DOC
264  * Attempt to restart another window manager \var{cmd}.
265  */
266 EXTL_EXPORT
267 void ioncore_restart_other(const char *cmd)
268 {
269     set_other(cmd);
270     
271     if(smhook!=NULL){
272         smhook(IONCORE_SM_RESTART_OTHER);
273     }else{
274         ioncore_do_snapshot();
275         ioncore_do_restart();
276     }
277 }
278
279
280 /*EXTL_DOC
281  * Save session.
282  */
283 EXTL_EXPORT
284 void ioncore_snapshot()
285 {
286     if(smhook!=NULL)
287         smhook(IONCORE_SM_SNAPSHOT);
288     else
289         ioncore_do_snapshot();
290 }
291
292
293 /*}}}*/
294