1 /*
2  * Copyright (C) 2000-2007 Carsten Haitzler, Geoff Harrison and various contributors
3  * Copyright (C) 2004-2021 Kim Woelders
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a copy
6  * of this software and associated documentation files (the "Software"), to
7  * deal in the Software without restriction, including without limitation the
8  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
9  * sell copies of the Software, and to permit persons to whom the Software is
10  * furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in
13  * all copies of the Software, its documentation and marketing & publicity
14  * materials, and acknowledgment shall be given in the documentation, materials
15  * and software packages that this Software was used.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20  * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23  */
24 #include "E.h"
25 #include "dialog.h"
26 #include "emodule.h"
27 #include "events.h"
28 #include "ewins.h"
29 #include "session.h"
30 #include "settings.h"
31 #include "snaps.h"
32 #include "user.h"
33 #include "xwin.h"
34 
35 #ifdef USE_EXT_INIT_WIN
36 static EX_Window    new_init_win_ext = NoXID;
37 #endif
38 
39 /* True if we are saving state for a doExit("restart") */
40 static char         restarting = 0;
41 
42 #if USE_SM
43 
44 #include <fcntl.h>
45 #include <X11/SM/SMlib.h>
46 
47 /*
48  * NB! If the discard property is revived, the dual use of buf must be fixed.
49  */
50 #define USE_DISCARD_PROPERTY 0
51 
52 static char        *sm_client_id = NULL;
53 static SmcConn      sm_conn = NULL;
54 
55 static int          sm_efd = 0;
56 
57 static void
set_save_props(SmcConn smc_conn,int master_flag)58 set_save_props(SmcConn smc_conn, int master_flag)
59 {
60    const char         *s;
61    const char         *user;
62    const char         *program;
63    char                priority = 10;
64    char                style;
65    int                 i, n;
66    SmPropValue         programVal;
67    SmPropValue         userIDVal;
68 
69 #if USE_DISCARD_PROPERTY
70    const char         *sh = "sh";
71    const char         *c = "-c";
72    const char         *sm_file;
73    SmPropValue         discardVal[3];
74    SmProp              discardProp;
75 #endif
76 #ifdef USE_EXT_INIT_WIN
77    char                bufx[32];
78 #endif
79    SmPropValue         restartVal[32];
80    SmPropValue         styleVal;
81    SmPropValue         priorityVal;
82    SmProp              programProp;
83    SmProp              userIDProp;
84    SmProp              restartProp;
85    SmProp              cloneProp;
86    SmProp              styleProp;
87    SmProp              priorityProp;
88    SmProp             *props[7];
89    char                bufs[32], bufm[32];
90 
91    if (EDebug(EDBUG_TYPE_SESSION))
92       Eprintf("%s\n", __func__);
93 
94    programProp.name = (char *)SmProgram;
95    programProp.type = (char *)SmARRAY8;
96    programProp.num_vals = 1;
97    programProp.vals = &programVal;
98 
99    userIDProp.name = (char *)SmUserID;
100    userIDProp.type = (char *)SmARRAY8;
101    userIDProp.num_vals = 1;
102    userIDProp.vals = &userIDVal;
103 
104 #if USE_DISCARD_PROPERTY
105    discardProp.name = (char *)SmDiscardCommand;
106    discardProp.type = (char *)SmLISTofARRAY8;
107    discardProp.num_vals = 3;
108    discardProp.vals = discardVal;
109 #endif
110 
111    restartProp.name = (char *)SmRestartCommand;
112    restartProp.type = (char *)SmLISTofARRAY8;
113    restartProp.vals = restartVal;
114 
115    cloneProp.name = (char *)SmCloneCommand;
116    cloneProp.type = (char *)SmLISTofARRAY8;
117    cloneProp.vals = restartVal;
118 
119    styleProp.name = (char *)SmRestartStyleHint;
120    styleProp.type = (char *)SmCARD8;
121    styleProp.num_vals = 1;
122    styleProp.vals = &styleVal;
123 
124    priorityProp.name = (char *)"_GSM_Priority";
125    priorityProp.type = (char *)SmCARD8;
126    priorityProp.num_vals = 1;
127    priorityProp.vals = &priorityVal;
128 
129    if (master_flag)
130       /* Master WM restarts immediately for a doExit("restart") */
131       style = restarting ? SmRestartImmediately : SmRestartIfRunning;
132    else
133       /* Slave WMs never restart */
134       style = SmRestartNever;
135 
136    user = username();
137    /* The SM specs state that the SmProgram should be the argument passed
138     * to execve. Passing argv[0] is close enough. */
139    program = Mode.wm.exec_name;
140 
141    userIDVal.length = (user) ? strlen(user) : 0;
142    userIDVal.value = (char *)user;
143    programVal.length = strlen(program);
144    programVal.value = (char *)program;
145    styleVal.length = 1;
146    styleVal.value = &style;
147    priorityVal.length = 1;
148    priorityVal.value = &priority;
149 
150 #if USE_DISCARD_PROPERTY
151    /* Tell session manager how to clean up our old data */
152    sm_file = EGetSavePrefix();
153    Esnprintf(buf, sizeof(buf), "rm %s*.clients.*", sm_file);
154 
155    discardVal[0].length = strlen(sh);
156    discardVal[0].value = sh;
157    discardVal[1].length = strlen(c);
158    discardVal[1].value = c;
159    discardVal[2].length = strlen(buf);
160    discardVal[2].value = buf;	/* ??? Also used in restartVal ??? */
161 #endif
162 
163    n = 0;
164    restartVal[n++].value = (char *)program;
165    if (Mode.wm.single)
166      {
167 	Esnprintf(bufs, sizeof(bufs), "%i", Mode.wm.master_screen);
168 	restartVal[n++].value = (char *)"-s";
169 	restartVal[n++].value = (char *)bufs;
170      }
171    else if (restarting && !Mode.wm.master)
172      {
173 	Esnprintf(bufm, sizeof(bufm), "%i", Mode.wm.master_screen);
174 	restartVal[n++].value = (char *)"-m";
175 	restartVal[n++].value = bufm;
176      }
177 #ifdef USE_EXT_INIT_WIN
178    if (restarting)
179      {
180 	Esnprintf(bufx, sizeof(bufx), "%#x", new_init_win_ext);
181 	restartVal[n++].value = (char *)"-X";
182 	restartVal[n++].value = bufx;
183      }
184 #endif
185 #if 0
186    restartVal[n++].value = (char *)smfile;
187    restartVal[n++].value = (char *)sm_file;
188 #endif
189    s = Mode.conf.name;
190    if (s)
191      {
192 	restartVal[n++].value = (char *)"-p";
193 	restartVal[n++].value = (char *)s;
194      }
195    s = EDirUserConf();
196    if (s)
197      {
198 	restartVal[n++].value = (char *)"-P";
199 	restartVal[n++].value = (char *)s;
200      }
201    s = EDirUserCache();
202    if (s)
203      {
204 	restartVal[n++].value = (char *)"-Q";
205 	restartVal[n++].value = (char *)s;
206      }
207    s = sm_client_id;
208    restartVal[n++].value = (char *)"-S";
209    restartVal[n++].value = (char *)s;
210 
211    for (i = 0; i < n; i++)
212       restartVal[i].length = strlen((const char *)restartVal[i].value);
213 
214    restartProp.num_vals = n;
215 
216    /* SM specs require SmCloneCommand excludes "--sm-client-id" option */
217    cloneProp.num_vals = restartProp.num_vals - 2;
218 
219    if (EDebug(EDBUG_TYPE_SESSION))
220       for (i = 0; i < restartProp.num_vals; i++)
221 	 Eprintf("restartVal[i]: %2d: %s\n", restartVal[i].length,
222 		 (char *)restartVal[i].value);
223 
224    n = 0;
225    props[n++] = &programProp;
226    props[n++] = &userIDProp;
227 #if USE_DISCARD_PROPERTY
228    props[n++] = &discardProp;
229 #endif
230    props[n++] = &restartProp;
231    props[n++] = &cloneProp;
232    props[n++] = &styleProp;
233    props[n++] = &priorityProp;
234 
235    SmcSetProperties(smc_conn, n, props);
236 }
237 
238 /* This function is usually exclusively devoted to saving data.
239  * However, E sometimes wants to save state and exit immediately afterwards
240  * so that the SM will restart it in a different theme. Therefore, we include
241  * a suicide clause at the end.
242  */
243 static void
callback_save_yourself2(SmcConn smc_conn,SmPointer client_data __UNUSED__)244 callback_save_yourself2(SmcConn smc_conn, SmPointer client_data __UNUSED__)
245 {
246    if (EDebug(EDBUG_TYPE_SESSION))
247       Eprintf("%s\n", __func__);
248 
249    set_save_props(smc_conn, Mode.wm.master);
250    SmcSaveYourselfDone(smc_conn, True);
251    if (restarting)
252       EExit(0);
253 }
254 
255 static void
callback_save_yourself(SmcConn smc_conn,SmPointer client_data __UNUSED__,int save_style __UNUSED__,Bool shutdown __UNUSED__,int interact_style __UNUSED__,Bool fast __UNUSED__)256 callback_save_yourself(SmcConn smc_conn, SmPointer client_data __UNUSED__,
257 		       int save_style __UNUSED__, Bool shutdown __UNUSED__,
258 		       int interact_style __UNUSED__, Bool fast __UNUSED__)
259 {
260    if (EDebug(EDBUG_TYPE_SESSION))
261       Eprintf("%s\n", __func__);
262 
263    SmcRequestSaveYourselfPhase2(smc_conn, callback_save_yourself2, NULL);
264 }
265 
266 static void
callback_die(SmcConn smc_conn __UNUSED__,SmPointer client_data __UNUSED__)267 callback_die(SmcConn smc_conn __UNUSED__, SmPointer client_data __UNUSED__)
268 {
269    if (EDebug(EDBUG_TYPE_SESSION))
270       Eprintf("%s\n", __func__);
271 
272    SessionExit(EEXIT_EXIT, NULL);
273 }
274 
275 static void
callback_save_complete(SmcConn smc_conn __UNUSED__,SmPointer client_data __UNUSED__)276 callback_save_complete(SmcConn smc_conn __UNUSED__,
277 		       SmPointer client_data __UNUSED__)
278 {
279    if (EDebug(EDBUG_TYPE_SESSION))
280       Eprintf("%s\n", __func__);
281 }
282 
283 static void
callback_shutdown_cancelled(SmcConn smc_conn,SmPointer client_data __UNUSED__)284 callback_shutdown_cancelled(SmcConn smc_conn, SmPointer client_data __UNUSED__)
285 {
286    if (EDebug(EDBUG_TYPE_SESSION))
287       Eprintf("%s\n", __func__);
288 
289    SmcSaveYourselfDone(smc_conn, False);
290 }
291 
292 static IceConn      ice_conn;
293 
294 static void
ice_io_error_handler(IceConn connection __UNUSED__)295 ice_io_error_handler(IceConn connection __UNUSED__)
296 {
297    if (EDebug(EDBUG_TYPE_SESSION))
298       Eprintf("%s\n", __func__);
299 
300    /* The less we do here the better - the default handler does an
301     * exit(1) instead of closing the losing connection. */
302 }
303 
304 static void
ice_exit(void)305 ice_exit(void)
306 {
307    SmcCloseConnection(sm_conn, 0, NULL);
308    sm_conn = NULL;
309    EventFdUnregister(sm_efd);
310 }
311 
312 static void
ice_msgs_process(void)313 ice_msgs_process(void)
314 {
315    IceProcessMessagesStatus status;
316 
317    status = IceProcessMessages(ice_conn, NULL, NULL);
318    if (status == IceProcessMessagesIOError)
319      {
320 	/* Less of the hope.... E survives */
321 	Alert(_("ERROR!\n" "\n"
322 		"Lost the Session Manager that was there?\n"
323 		"Here here session manager... come here... want a bone?\n"
324 		"Oh come now! Stop sulking! Bugger. Oh well. "
325 		"Will continue without\n" "a session manager.\n" "\n"
326 		"I'll survive somehow.\n" "\n" "\n" "... I hope.\n"));
327 	ice_exit();
328      }
329 }
330 
331 static void
ice_init(void)332 ice_init(void)
333 {
334    static SmPointer    context;
335    SmcCallbacks        callbacks;
336    char                error_string_ret[4096];
337    char               *client_id;
338    char                style[2];
339    SmPropValue         styleVal;
340    SmProp              styleProp;
341    SmProp             *props[1];
342    int                 sm_fd;
343 
344    if (!getenv("SESSION_MANAGER"))
345       return;
346 
347    IceSetIOErrorHandler(ice_io_error_handler);
348 
349    callbacks.save_yourself.callback = callback_save_yourself;
350    callbacks.die.callback = callback_die;
351    callbacks.save_complete.callback = callback_save_complete;
352    callbacks.shutdown_cancelled.callback = callback_shutdown_cancelled;
353 
354    callbacks.save_yourself.client_data = callbacks.die.client_data =
355       callbacks.save_complete.client_data =
356       callbacks.shutdown_cancelled.client_data = (SmPointer) NULL;
357 
358    client_id = Estrdup(sm_client_id);
359 
360    error_string_ret[0] = '\0';
361 
362    sm_conn =
363       SmcOpenConnection(NULL, &context, SmProtoMajor, SmProtoMinor,
364 			SmcSaveYourselfProcMask | SmcDieProcMask |
365 			SmcSaveCompleteProcMask |
366 			SmcShutdownCancelledProcMask, &callbacks,
367 			client_id, &sm_client_id, 4096, error_string_ret);
368    Efree(client_id);
369 
370    if (error_string_ret[0])
371       Eprintf("While connecting to session manager: %s.", error_string_ret);
372 
373    if (!sm_conn)
374       return;
375 
376    style[0] = SmRestartIfRunning;
377    style[1] = 0;
378 
379    styleVal.length = 1;
380    styleVal.value = style;
381 
382    styleProp.name = (char *)SmRestartStyleHint;
383    styleProp.type = (char *)SmCARD8;
384    styleProp.num_vals = 1;
385    styleProp.vals = &styleVal;
386 
387    props[0] = &styleProp;
388 
389    ice_conn = SmcGetIceConnection(sm_conn);
390    sm_fd = IceConnectionNumber(ice_conn);
391    /* Just in case we are a copy of E created by a doExit("restart") */
392    SmcSetProperties(sm_conn, 1, props);
393    fcntl(sm_fd, F_SETFD, fcntl(sm_fd, F_GETFD, 0) | FD_CLOEXEC);
394 
395    sm_efd = EventFdRegister(sm_fd, ice_msgs_process);
396 }
397 
398 #endif /* USE_SM */
399 
400 void
SessionInit(void)401 SessionInit(void)
402 {
403    if (!Conf.session.script)
404       Conf.session.script = Estrdup("$EROOT/scripts/session.sh");
405    if (!Conf.session.cmd_reboot)
406       Conf.session.cmd_reboot = Estrdup("reboot");
407    if (!Conf.session.cmd_halt)
408       Conf.session.cmd_halt = Estrdup("poweroff");
409 
410    if (Mode.wm.window)
411       return;
412 
413 #if USE_SM
414    ice_init();
415 #endif
416 }
417 
418 #if USE_SM
419 void
SetSMID(const char * smid)420 SetSMID(const char *smid)
421 {
422    sm_client_id = Estrdup(smid);
423 }
424 #else
425 void
SetSMID(const char * smid __UNUSED__)426 SetSMID(const char *smid __UNUSED__)
427 {
428 }
429 #endif /* USE_SM */
430 
431 static void
SessionSave(int shutdown)432 SessionSave(int shutdown)
433 {
434    if (EDebug(EDBUG_TYPE_SESSION))
435       Eprintf("%s: %d\n", __func__, shutdown);
436 
437    SnapshotsSaveReal();
438 
439 #if USE_SM
440    if (shutdown && sm_conn)
441       ice_exit();
442 #endif /* USE_SM */
443 }
444 
445 /*
446  * Normally, the SM will throw away all the session data for a client
447  * that breaks its connection unexpectedly. In order to avoid this we
448  * have to let the SM handle the restart (by setting a SmRestartStyleHint
449  * of SmRestartImmediately). Rather than forcing all SM clients to do a
450  * checkpoint (which would be a bit cleaner) we just save our own state
451  * and then restore it on restart. We grab X input via the ext_init_win
452  * so the our clients remain frozen while we are down.
453  */
454 __NORETURN__ static void
doSMExit(int mode,const char * params)455 doSMExit(int mode, const char *params)
456 {
457    int                 l;
458    char                s[1024];
459    const char         *ss;
460 
461    if (EDebug(EDBUG_TYPE_SESSION))
462       Eprintf("%s: mode=%d prm=%p\n", __func__, mode, params);
463 
464    restarting = 1;
465 
466    SessionSave(1);
467 
468    if (mode != EEXIT_THEME && mode != EEXIT_RESTART)
469       SessionHelper(ESESSION_STOP);
470 
471    LangExit();
472 
473    if (disp)
474      {
475 	/* We may get here from HandleXIOError */
476 	EwinsSetFree();
477 	ESelectInput(VROOT, 0);
478 	ExtInitWinKill();
479 	ESync(0);
480 
481 	/* Forget about cleaning up if no disp */
482 	ModulesSignal(ESIGNAL_EXIT, NULL);
483      }
484 
485    ss = NULL;
486    switch (mode)
487      {
488      case EEXIT_EXEC:
489 	SoundPlay(SOUND_EXIT);
490 	EDisplayClose();
491 
492 	if (EDebug(EDBUG_TYPE_SESSION))
493 	   Eprintf("%s: exec %s\n", __func__, params);
494 	Eexec(params);
495 	break;
496 
497      case EEXIT_THEME:
498 	ss = params;
499 	/* FALLTHROUGH */
500      case EEXIT_RESTART:
501 	SoundPlay(SOUND_WAIT);
502 #ifdef USE_EXT_INIT_WIN
503 	if (disp)
504 	   new_init_win_ext = ExtInitWinCreate();
505 #endif
506 	EDisplayClose();
507 
508 	l = 0;
509 	l += Esnprintf(s + l, sizeof(s) - l, "%s -f", Mode.wm.exec_name);
510 	if (Mode.wm.single)
511 	   l += Esnprintf(s + l, sizeof(s) - l, " -s %d", Dpy.screen);
512 	else if (!Mode.wm.master)
513 	   l +=
514 	      Esnprintf(s + l, sizeof(s) - l, " -m %d", Mode.wm.master_screen);
515 	if (Mode.wm.window)
516 	   l += Esnprintf(s + l, sizeof(s) - l, " -w %dx%d",
517 			  WinGetW(VROOT), WinGetH(VROOT));
518 #if USE_SM
519 	if (sm_client_id)
520 	   l += Esnprintf(s + l, sizeof(s) - l, " -S %s", sm_client_id);
521 #endif
522 #ifdef USE_EXT_INIT_WIN
523 	if (new_init_win_ext != NoXID)
524 	   l += Esnprintf(s + l, sizeof(s) - l, " -X %#x", new_init_win_ext);
525 #endif
526 	if (ss)
527 	   Esnprintf(s + l, sizeof(s) - l, " -t %s", ss);
528 
529 	if (EDebug(EDBUG_TYPE_SESSION))
530 	   Eprintf("%s: exec %s\n", __func__, s);
531 
532 	Eexec(s);
533 	break;
534      }
535 
536    restarting = 0;
537    SoundPlay(SOUND_EXIT);
538    EExit(0);
539 }
540 
541 static void
SessionLogout(void)542 SessionLogout(void)
543 {
544 #if USE_SM
545    if (sm_conn)
546      {
547 	SmcRequestSaveYourself(sm_conn, SmSaveBoth, True, SmInteractStyleAny,
548 			       False, True);
549      }
550    else
551 #endif /* USE_SM */
552      {
553 	SessionExit(EEXIT_EXIT, NULL);
554      }
555 }
556 
557 #if ENABLE_DIALOGS
558 static void
LogoutCB(Dialog * d,int val,void * data __UNUSED__)559 LogoutCB(Dialog * d, int val, void *data __UNUSED__)
560 {
561 #if USE_SM
562    if (sm_conn)
563      {
564 	SessionLogout();
565      }
566    else
567 #endif /* USE_SM */
568      {
569 	/* 0:LogOut -: No    -or-        */
570 	/* 0:Halt 1:Reboot 2:LogOut -:No */
571 	switch (val)
572 	  {
573 	  default:
574 	     break;
575 	  case 1:
576 	     SessionExit(EEXIT_EXIT, NULL);
577 	     break;
578 	  case 2:
579 	     SessionExit(EEXIT_EXEC, Conf.session.cmd_reboot);
580 	     break;
581 	  case 3:
582 	     SessionExit(EEXIT_EXEC, Conf.session.cmd_halt);
583 	     break;
584 	  }
585      }
586 
587    DialogClose(d);
588 }
589 
590 static void
SessionLogoutConfirm(void)591 SessionLogoutConfirm(void)
592 {
593    Dialog             *d;
594    DItem              *table, *di;
595 
596    d = DialogFind("LOGOUT_DIALOG");
597    if (!d)
598      {
599 	SoundPlay(SOUND_LOGOUT);
600 	d = DialogCreate("LOGOUT_DIALOG");
601 	table = DialogInitItem(d);
602 	DialogSetTitle(d, _("Are you sure?"));
603 	di = DialogAddItem(table, DITEM_TEXT);
604 	DialogItemSetText(di, _("Are you sure you wish to log out ?"));
605 	table = DialogAddItem(table, DITEM_TABLE);
606 	DialogItemSetAlign(table, 512, 0);
607 	DialogItemSetFill(table, 0, 0);
608 	DialogItemTableSetOptions(table, 2, 0, 1, 0);
609 	if (Conf.session.enable_reboot_halt)
610 	  {
611 	     DialogItemTableSetOptions(table, 4, 0, 1, 0);
612 	     DialogItemAddButton(table, _("Yes, Shut Down"), LogoutCB, 3,
613 				 1, DLG_BUTTON_OK);
614 	     DialogItemAddButton(table, _("Yes, Reboot"), LogoutCB, 2,
615 				 1, DLG_BUTTON_OK);
616 	  }
617 	DialogItemAddButton(table, _("Yes, Log Out"), LogoutCB, 1,
618 			    1, DLG_BUTTON_OK);
619 	DialogItemAddButton(table, _("No"), NULL, 0, 1, DLG_BUTTON_CANCEL);
620 	DialogBindKey(d, "Escape", DialogCallbackClose, 0, NULL);
621 	DialogBindKey(d, "Return", LogoutCB, 1, NULL);
622      }
623 
624    DialogShowCentered(d);
625 }
626 #endif /* ENABLE_DIALOGS */
627 
628 void
SessionExit(int mode,const char * param)629 SessionExit(int mode, const char *param)
630 {
631    /* We do not want to be exited by children. */
632    if (getpid() != Mode.wm.pid)
633       return;
634 
635    if (EDebug(EDBUG_TYPE_SESSION))
636       Eprintf("%s: mode=%d(%d) prm=%s\n", __func__, mode, Mode.wm.exit_mode,
637 	      param ? param : "(none)");
638 
639    if (Mode.wm.exiting)
640       return;
641 
642    if (Mode.wm.startup || Mode.wm.exit_now)
643       goto done;
644 
645    switch (mode)
646      {
647      default:
648 	/* In event loop - Set exit mode */
649 	Mode.wm.exit_mode = mode;
650 	Mode.wm.exit_param = Estrdup(param);
651 	return;
652 
653      case EEXIT_QUIT:
654 	mode = Mode.wm.exit_mode;
655 	param = Mode.wm.exit_param;
656 	break;
657 
658      case EEXIT_ERROR:
659 	if (!Mode.wm.exiting)
660 	   break;
661 	/* This may be possible during nested signal handling */
662 	Eprintf("%s: already in progress ... now exiting\n", __func__);
663 	exit(1);
664 	break;
665 
666      case EEXIT_LOGOUT:
667 #if ENABLE_DIALOGS
668 	if (Conf.session.enable_logout_dialog)
669 	   SessionLogoutConfirm();
670 	else
671 #endif
672 	   SessionLogout();
673 	return;
674      }
675 
676  done:
677    Mode.wm.exiting++;
678    doSMExit(mode, param);
679 }
680 
681 static void
SessionRunProg(const char * prog,const char * params)682 SessionRunProg(const char *prog, const char *params)
683 {
684    if (EDebug(EDBUG_TYPE_SESSION))
685       Eprintf("%s: %s %s\n", __func__, prog, params);
686    Esystem("%s %s", prog, params);
687 }
688 
689 void
SessionHelper(int when)690 SessionHelper(int when)
691 {
692    switch (when)
693      {
694      case ESESSION_INIT:
695 	if (Conf.session.enable_script && Conf.session.script)
696 	   SessionRunProg(Conf.session.script, "init");
697 	break;
698      case ESESSION_START:
699 	if (Conf.session.enable_script && Conf.session.script)
700 	   SessionRunProg(Conf.session.script, "start");
701 	break;
702      case ESESSION_STOP:
703 	if (Conf.session.enable_script && Conf.session.script)
704 	   SessionRunProg(Conf.session.script, "stop");
705 	break;
706      }
707 }
708 
709 #if ENABLE_DIALOGS
710 /*
711  * Session dialog
712  */
713 static char         tmp_session_script;
714 static char         tmp_logout_dialog;
715 static char         tmp_reboot_halt;
716 
717 static void
_DlgApplySession(Dialog * d __UNUSED__,int val __UNUSED__,void * data __UNUSED__)718 _DlgApplySession(Dialog * d __UNUSED__, int val __UNUSED__,
719 		 void *data __UNUSED__)
720 {
721    Conf.session.enable_script = tmp_session_script;
722    Conf.session.enable_logout_dialog = tmp_logout_dialog;
723    Conf.session.enable_reboot_halt = tmp_reboot_halt;
724    autosave();
725 }
726 
727 static void
_DlgFillSession(Dialog * d __UNUSED__,DItem * table,void * data __UNUSED__)728 _DlgFillSession(Dialog * d __UNUSED__, DItem * table, void *data __UNUSED__)
729 {
730    DItem              *di;
731 
732    tmp_session_script = Conf.session.enable_script;
733    tmp_logout_dialog = Conf.session.enable_logout_dialog;
734    tmp_reboot_halt = Conf.session.enable_reboot_halt;
735 
736    DialogItemTableSetOptions(table, 2, 0, 0, 0);
737 
738    di = DialogAddItem(table, DITEM_CHECKBUTTON);
739    DialogItemSetColSpan(di, 2);
740    DialogItemSetText(di, _("Enable Session Script"));
741    DialogItemCheckButtonSetPtr(di, &tmp_session_script);
742 
743    di = DialogAddItem(table, DITEM_CHECKBUTTON);
744    DialogItemSetColSpan(di, 2);
745    DialogItemSetText(di, _("Enable Logout Dialog"));
746    DialogItemCheckButtonSetPtr(di, &tmp_logout_dialog);
747 
748    di = DialogAddItem(table, DITEM_CHECKBUTTON);
749    DialogItemSetColSpan(di, 2);
750    DialogItemSetText(di, _("Enable Reboot/Halt on Logout"));
751    DialogItemCheckButtonSetPtr(di, &tmp_reboot_halt);
752 }
753 
754 const DialogDef     DlgSession = {
755    "CONFIGURE_SESSION",
756    N_("Session"), N_("Session Settings"),
757    0,
758    SOUND_SETTINGS_SESSION,
759    "pix/miscellaneous.png",
760    N_("Enlightenment Session\n" "Settings Dialog"),
761    _DlgFillSession,
762    DLG_OAC, _DlgApplySession, NULL
763 };
764 #endif /* ENABLE_DIALOGS */
765