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