remove e_comp_list(), deprecate all related functions for pending removal
[platform/upstream/enlightenment.git] / src / bin / e_sys.c
1 #include "e.h"
2
3 #define ACTION_TIMEOUT 30.0
4
5 /* local subsystem functions */
6 static Eina_Bool _e_sys_cb_timer(void *data);
7 static Eina_Bool _e_sys_cb_exit(void *data, int type, void *event);
8 static void      _e_sys_cb_logout_logout(void *data, E_Dialog *dia);
9 static void      _e_sys_cb_logout_wait(void *data, E_Dialog *dia);
10 static void      _e_sys_cb_logout_abort(void *data, E_Dialog *dia);
11 static Eina_Bool _e_sys_cb_logout_timer(void *data);
12 static void      _e_sys_logout_after(void);
13 static void      _e_sys_logout_begin(E_Sys_Action a_after, Eina_Bool raw);
14 static void      _e_sys_current_action(void);
15 static void      _e_sys_action_failed(void);
16 static int       _e_sys_action_do(E_Sys_Action a, char *param, Eina_Bool raw);
17 static void      _e_sys_dialog_cb_delete(E_Obj_Dialog *od);
18
19 static Ecore_Event_Handler *_e_sys_exe_exit_handler = NULL;
20 static Ecore_Exe *_e_sys_halt_check_exe = NULL;
21 static Ecore_Exe *_e_sys_reboot_check_exe = NULL;
22 static Ecore_Exe *_e_sys_suspend_check_exe = NULL;
23 static Ecore_Exe *_e_sys_hibernate_check_exe = NULL;
24 static int _e_sys_can_halt = 0;
25 static int _e_sys_can_reboot = 0;
26 static int _e_sys_can_suspend = 0;
27 static int _e_sys_can_hibernate = 0;
28
29 static E_Sys_Action _e_sys_action_current = E_SYS_NONE;
30 static E_Sys_Action _e_sys_action_after = E_SYS_NONE;
31 static Eina_Bool _e_sys_action_after_raw = EINA_FALSE;
32 static Ecore_Exe *_e_sys_exe = NULL;
33 static double _e_sys_begin_time = 0.0;
34 static double _e_sys_logout_begin_time = 0.0;
35 static Ecore_Timer *_e_sys_logout_timer = NULL;
36 static E_Obj_Dialog *_e_sys_dialog = NULL;
37 static E_Dialog *_e_sys_logout_confirm_dialog = NULL;
38 static Ecore_Timer *_e_sys_susp_hib_check_timer = NULL;
39 static double _e_sys_susp_hib_check_last_tick = 0.0;
40
41 static void _e_sys_systemd_handle_inhibit(void);
42 static void _e_sys_systemd_poweroff(void);
43 static void _e_sys_systemd_reboot(void);
44 static void _e_sys_systemd_suspend(void);
45 static void _e_sys_systemd_hibernate(void);
46 static void _e_sys_systemd_exists_cb(void *data, const Eldbus_Message *m, Eldbus_Pending *p);
47
48 static Eina_Bool systemd_works = EINA_FALSE;
49 static int _e_sys_systemd_inhibit_fd = -1;
50
51 static const int E_LOGOUT_AUTO_TIME = 60;
52 static const int E_LOGOUT_WAIT_TIME = 15;
53
54 static Ecore_Timer *action_timeout = NULL;
55
56 static Eldbus_Proxy *login1_manger_proxy = NULL;
57
58 EAPI int E_EVENT_SYS_SUSPEND = -1;
59 EAPI int E_EVENT_SYS_HIBERNATE = -1;
60 EAPI int E_EVENT_SYS_RESUME = -1;
61
62 static void
63 _e_sys_comp_done_cb(void *data, Evas_Object *obj, const char *sig, const char *src)
64 {
65    edje_object_signal_callback_del(obj, sig, src, _e_sys_comp_done_cb);
66    e_sys_action_raw_do((E_Sys_Action)(long)data, NULL);
67    E_FREE_FUNC(action_timeout, ecore_timer_del);
68 }
69
70 static Eina_Bool
71 _e_sys_comp_action_timeout(void *data)
72 {
73    const Eina_List *l;
74    E_Zone *zone;
75    E_Sys_Action a = (long)(intptr_t)data;
76    const char *sig = NULL;
77
78    switch (a)
79      {
80       case E_SYS_LOGOUT:
81         sig = "e,state,sys,logout,done";
82         break;
83       case E_SYS_HALT:
84         sig = "e,state,sys,halt,done";
85         break;
86       case E_SYS_REBOOT:
87         sig = "e,state,sys,reboot,done";
88         break;
89       case E_SYS_SUSPEND:
90         sig = "e,state,sys,suspend,done";
91         break;
92       case E_SYS_HIBERNATE:
93         sig = "e,state,sys,hibernate,done";
94         break;
95       default:
96         break;
97      }
98    E_FREE_FUNC(action_timeout, ecore_timer_del);
99    if (sig)
100      {
101         EINA_LIST_FOREACH(e_comp->zones, l, zone)
102           edje_object_signal_callback_del(zone->over, sig, "e", _e_sys_comp_done_cb);
103      }
104    e_sys_action_raw_do(a, NULL);
105    return EINA_FALSE;
106 }
107
108 static void
109 _e_sys_comp_emit_cb_wait(E_Sys_Action a, const char *sig, const char *rep, Eina_Bool nocomp_push)
110 {
111    const Eina_List *l;
112    E_Zone *zone;
113    Eina_Bool first = EINA_TRUE;
114
115    if (nocomp_push) e_comp_override_add(e_comp);
116    else e_comp_override_timed_pop(e_comp);
117    EINA_LIST_FOREACH(e_comp->zones, l, zone)
118      {
119         e_zone_fade_handle(zone, nocomp_push, 0.5);
120         edje_object_signal_emit(zone->base, sig, "e");
121         edje_object_signal_emit(zone->over, sig, "e");
122         if ((rep) && (first))
123           edje_object_signal_callback_add(zone->over, rep, "e", _e_sys_comp_done_cb, (void *)(long)a);
124         first = EINA_FALSE;
125      }
126    if (rep)
127      {
128         if (action_timeout) ecore_timer_del(action_timeout);
129         action_timeout = ecore_timer_add(ACTION_TIMEOUT, (Ecore_Task_Cb)_e_sys_comp_action_timeout, (intptr_t*)(long)a);
130      }
131 }
132
133 static void
134 _e_sys_comp_suspend(void)
135 {
136    _e_sys_comp_emit_cb_wait(E_SYS_SUSPEND, "e,state,sys,suspend", "e,state,sys,suspend,done", EINA_TRUE);
137 }
138
139 static void
140 _e_sys_comp_hibernate(void)
141 {
142    _e_sys_comp_emit_cb_wait(E_SYS_HIBERNATE, "e,state,sys,hibernate", "e,state,sys,hibernate,done", EINA_TRUE);
143 }
144
145 static void
146 _e_sys_comp_reboot(void)
147 {
148    _e_sys_comp_emit_cb_wait(E_SYS_REBOOT, "e,state,sys,reboot", "e,state,sys,reboot,done", EINA_TRUE);
149 }
150
151 static void
152 _e_sys_comp_shutdown(void)
153 {
154    _e_sys_comp_emit_cb_wait(E_SYS_HALT, "e,state,sys,halt", "e,state,sys,halt,done", EINA_TRUE);
155 }
156
157 static void
158 _e_sys_comp_logout(void)
159 {
160    _e_sys_comp_emit_cb_wait(E_SYS_LOGOUT, "e,state,sys,logout", "e,state,sys,logout,done", EINA_TRUE);
161 }
162
163 static void
164 _e_sys_comp_resume(void)
165 {
166    evas_damage_rectangle_add(e_comp->evas, 0, 0, e_comp->man->w, e_comp->man->h);
167    _e_sys_comp_emit_cb_wait(E_SYS_SUSPEND, "e,state,sys,resume", NULL, EINA_FALSE);
168    e_screensaver_deactivate();
169 }
170
171 /* externally accessible functions */
172 EINTERN int
173 e_sys_init(void)
174 {
175    Eldbus_Connection *conn;
176    Eldbus_Object *obj;
177
178    eldbus_init();
179    conn = eldbus_connection_get(ELDBUS_CONNECTION_TYPE_SYSTEM);
180    obj = eldbus_object_get(conn, "org.freedesktop.login1",
181                            "/org/freedesktop/login1");
182    login1_manger_proxy = eldbus_proxy_get(obj,
183                                           "org.freedesktop.login1.Manager");
184    eldbus_name_owner_get(conn, "org.freedesktop.login1",
185                          _e_sys_systemd_exists_cb, NULL);
186    _e_sys_systemd_handle_inhibit();
187    
188    E_EVENT_SYS_SUSPEND = ecore_event_type_new();
189    E_EVENT_SYS_HIBERNATE = ecore_event_type_new();
190    E_EVENT_SYS_RESUME = ecore_event_type_new();
191    /* this is not optimal - but it does work cleanly */
192    _e_sys_exe_exit_handler = ecore_event_handler_add(ECORE_EXE_EVENT_DEL,
193                                                      _e_sys_cb_exit, NULL);
194    return 1;
195 }
196
197 EINTERN int
198 e_sys_shutdown(void)
199 {
200    if (_e_sys_exe_exit_handler)
201      ecore_event_handler_del(_e_sys_exe_exit_handler);
202    _e_sys_exe_exit_handler = NULL;
203    _e_sys_halt_check_exe = NULL;
204    _e_sys_reboot_check_exe = NULL;
205    _e_sys_suspend_check_exe = NULL;
206    _e_sys_hibernate_check_exe = NULL;
207    if (login1_manger_proxy)
208      {
209          Eldbus_Connection *conn;
210          Eldbus_Object *obj;
211
212          obj = eldbus_proxy_object_get(login1_manger_proxy);
213          conn = eldbus_object_connection_get(obj);
214          eldbus_proxy_unref(login1_manger_proxy);
215          eldbus_object_unref(obj);
216          eldbus_connection_unref(conn);
217          login1_manger_proxy = NULL;
218      }
219    if (_e_sys_systemd_inhibit_fd >= 0)
220      {
221         close(_e_sys_systemd_inhibit_fd);
222         _e_sys_systemd_inhibit_fd = -1;
223      }
224    eldbus_shutdown();
225    return 1;
226 }
227
228 EAPI int
229 e_sys_action_possible_get(E_Sys_Action a)
230 {
231    switch (a)
232      {
233       case E_SYS_EXIT:
234       case E_SYS_RESTART:
235       case E_SYS_EXIT_NOW:
236         return 1;
237
238       case E_SYS_LOGOUT:
239         return 1;
240
241       case E_SYS_HALT:
242       case E_SYS_HALT_NOW:
243         return _e_sys_can_halt;
244
245       case E_SYS_REBOOT:
246         return _e_sys_can_reboot;
247
248       case E_SYS_SUSPEND:
249         return _e_sys_can_suspend;
250
251       case E_SYS_HIBERNATE:
252         return _e_sys_can_hibernate;
253
254       default:
255         return 0;
256      }
257    return 0;
258 }
259
260 EAPI int
261 e_sys_action_do(E_Sys_Action a, char *param)
262 {
263    int ret = 0;
264
265    if (_e_sys_action_current != E_SYS_NONE)
266      {
267         _e_sys_current_action();
268         return 0;
269      }
270    switch (a)
271      {
272       case E_SYS_EXIT:
273       case E_SYS_RESTART:
274       case E_SYS_EXIT_NOW:
275       case E_SYS_LOGOUT:
276       case E_SYS_SUSPEND:
277       case E_SYS_HIBERNATE:
278       case E_SYS_HALT_NOW:
279         ret = _e_sys_action_do(a, param, EINA_FALSE);
280         break;
281
282       case E_SYS_HALT:
283       case E_SYS_REBOOT:
284         if (!e_util_immortal_check())
285           ret = _e_sys_action_do(a, param, EINA_FALSE);
286         break;
287
288       default:
289         break;
290      }
291
292    if (ret) _e_sys_action_current = a;
293    else _e_sys_action_current = E_SYS_NONE;
294
295    return ret;
296 }
297
298 EAPI int
299 e_sys_action_raw_do(E_Sys_Action a, char *param)
300 {
301    int ret = 0;
302
303    if (_e_sys_action_current != E_SYS_NONE)
304      {
305         _e_sys_current_action();
306         return 0;
307      }
308    ret = _e_sys_action_do(a, param, EINA_TRUE);
309
310    if (ret) _e_sys_action_current = a;
311    else _e_sys_action_current = E_SYS_NONE;
312
313    return ret;
314 }
315
316 static Eina_List *extra_actions = NULL;
317
318 EAPI E_Sys_Con_Action *
319 e_sys_con_extra_action_register(const char *label,
320                                 const char *icon_group,
321                                 const char *button_name,
322                                 void (*func)(void *data),
323                                 const void *data)
324 {
325    E_Sys_Con_Action *sca;
326
327    sca = E_NEW(E_Sys_Con_Action, 1);
328    if (label)
329      sca->label = eina_stringshare_add(label);
330    if (icon_group)
331      sca->icon_group = eina_stringshare_add(icon_group);
332    if (button_name)
333      sca->button_name = eina_stringshare_add(button_name);
334    sca->func = func;
335    sca->data = data;
336    extra_actions = eina_list_append(extra_actions, sca);
337    return sca;
338 }
339
340 EAPI void
341 e_sys_con_extra_action_unregister(E_Sys_Con_Action *sca)
342 {
343    extra_actions = eina_list_remove(extra_actions, sca);
344    if (sca->label) eina_stringshare_del(sca->label);
345    if (sca->icon_group) eina_stringshare_del(sca->icon_group);
346    if (sca->button_name) eina_stringshare_del(sca->button_name);
347    free(sca);
348 }
349
350 EAPI const Eina_List *
351 e_sys_con_extra_action_list_get(void)
352 {
353    return extra_actions;
354 }
355
356 static void
357 _e_sys_systemd_inhibit_cb(void *data __UNUSED__, const Eldbus_Message *m, Eldbus_Pending *p __UNUSED__)
358 {
359    int fd = -1;
360    if (eldbus_message_error_get(m, NULL, NULL)) return;
361    if (!eldbus_message_arguments_get(m, "h", &fd))
362      _e_sys_systemd_inhibit_fd = fd;
363 }
364
365 static void
366 _e_sys_systemd_handle_inhibit(void)
367 {
368    Eldbus_Message *m;
369    
370    if (!login1_manger_proxy) return;
371    if (!(m = eldbus_proxy_method_call_new(login1_manger_proxy, "Inhibit")))
372      return;
373    eldbus_message_arguments_append
374      (m, "ssss",
375          "handle-power-key:"
376          "handle-suspend-key:"
377          "handle-hibernate-key:"
378          "handle-lid-switch", // what
379          "Enlightenment", // who (string)
380          "Normal Execution", // why (string)
381          "block");
382    eldbus_proxy_send(login1_manger_proxy, m, _e_sys_systemd_inhibit_cb, NULL, -1);
383 }
384
385 static void
386 _e_sys_systemd_check_cb(void *data, const Eldbus_Message *m, Eldbus_Pending *p __UNUSED__)
387 {
388    int *dest = data;
389    char *s = NULL;
390    if (!eldbus_message_arguments_get(m, "s", &s)) return;
391    if (!s) return;
392    if (!strcmp(s, "yes")) *dest = 1;
393    else *dest = 1;
394 }
395
396 static void
397 _e_sys_systemd_check(void)
398 {
399    if (!login1_manger_proxy) return;
400    if (!eldbus_proxy_call(login1_manger_proxy, "CanPowerOff",
401                           _e_sys_systemd_check_cb, &_e_sys_can_halt, -1, ""))
402      return;
403    if (!eldbus_proxy_call(login1_manger_proxy, "CanReboot",
404                           _e_sys_systemd_check_cb, &_e_sys_can_reboot, -1, ""))
405      return;
406    if (!eldbus_proxy_call(login1_manger_proxy, "CanSuspend",
407                           _e_sys_systemd_check_cb, &_e_sys_can_suspend, -1, ""))
408      return;
409    if (!eldbus_proxy_call(login1_manger_proxy, "CanHibernate",
410                           _e_sys_systemd_check_cb, &_e_sys_can_hibernate, -1, ""))
411      return;
412 }
413
414 static void
415 _e_sys_systemd_exists_cb(void *data __UNUSED__, const Eldbus_Message *m, Eldbus_Pending *p __UNUSED__)
416 {
417    const char *id = NULL;
418    
419    if (eldbus_message_error_get(m, NULL, NULL)) goto fail;
420    if (!eldbus_message_arguments_get(m, "s", &id)) goto fail;
421    if ((!id) || (id[0] != ':')) goto fail;
422    systemd_works = EINA_TRUE;
423    _e_sys_systemd_check();
424    return;
425 fail:
426    systemd_works = EINA_FALSE;
427    /* delay this for 1.0 seconds while the rest of e starts up */
428    ecore_timer_add(1.0, _e_sys_cb_timer, NULL);
429 }
430
431 static void
432 _e_sys_systemd_poweroff(void)
433 {
434    eldbus_proxy_call(login1_manger_proxy, "PowerOff", NULL, NULL, -1, "b", 0);
435 }
436
437 static void
438 _e_sys_systemd_reboot(void)
439 {
440    eldbus_proxy_call(login1_manger_proxy, "Reboot", NULL, NULL, -1, "b", 0);
441 }
442
443 static void
444 _e_sys_systemd_suspend(void)
445 {
446    eldbus_proxy_call(login1_manger_proxy, "Suspend", NULL, NULL, -1, "b", 0);
447 }
448
449 static void
450 _e_sys_systemd_hibernate(void)
451 {
452    eldbus_proxy_call(login1_manger_proxy, "Hibernate", NULL, NULL, -1, "b", 0);
453 }
454
455 static void
456 _e_sys_resume_job(void *d EINA_UNUSED)
457 {
458    ecore_event_add(E_EVENT_SYS_RESUME, NULL, NULL, NULL);
459    _e_sys_comp_resume();
460 }
461
462 static Eina_Bool
463 _e_sys_susp_hib_check_timer_cb(void *data __UNUSED__)
464 {
465    double t = ecore_time_unix_get();
466
467    if ((t - _e_sys_susp_hib_check_last_tick) > 0.2)
468      {
469         _e_sys_susp_hib_check_timer = NULL;
470         if (_e_sys_dialog)
471           {
472              e_object_del(E_OBJECT(_e_sys_dialog));
473              _e_sys_dialog = NULL;
474           }
475         ecore_job_add(_e_sys_resume_job, NULL);
476         return EINA_FALSE;
477      }
478    _e_sys_susp_hib_check_last_tick = t;
479    return EINA_TRUE;
480 }
481
482 static void
483 _e_sys_susp_hib_check(void)
484 {
485    if (_e_sys_susp_hib_check_timer)
486      ecore_timer_del(_e_sys_susp_hib_check_timer);
487    _e_sys_susp_hib_check_last_tick = ecore_time_unix_get();
488    _e_sys_susp_hib_check_timer =
489      ecore_timer_add(0.1, _e_sys_susp_hib_check_timer_cb, NULL);
490 }
491
492 /* local subsystem functions */
493 static Eina_Bool
494 _e_sys_cb_timer(void *data __UNUSED__)
495 {
496    /* exec out sys helper and ask it to test if we are allowed to do these
497     * things
498     */
499    char buf[4096];
500
501    e_init_status_set(_("Checking System Permissions"));
502    snprintf(buf, sizeof(buf),
503             "%s/enlightenment/utils/enlightenment_sys -t halt",
504             e_prefix_lib_get());
505    _e_sys_halt_check_exe = ecore_exe_run(buf, NULL);
506    snprintf(buf, sizeof(buf),
507             "%s/enlightenment/utils/enlightenment_sys -t reboot",
508             e_prefix_lib_get());
509    _e_sys_reboot_check_exe = ecore_exe_run(buf, NULL);
510    snprintf(buf, sizeof(buf),
511             "%s/enlightenment/utils/enlightenment_sys -t suspend",
512             e_prefix_lib_get());
513    _e_sys_suspend_check_exe = ecore_exe_run(buf, NULL);
514    snprintf(buf, sizeof(buf),
515             "%s/enlightenment/utils/enlightenment_sys -t hibernate",
516             e_prefix_lib_get());
517    _e_sys_hibernate_check_exe = ecore_exe_run(buf, NULL);
518    return ECORE_CALLBACK_CANCEL;
519 }
520
521 static Eina_Bool
522 _e_sys_cb_exit(void *data __UNUSED__, int type __UNUSED__, void *event)
523 {
524    Ecore_Exe_Event_Del *ev;
525
526    ev = event;
527    if ((_e_sys_exe) && (ev->exe == _e_sys_exe))
528      {
529         if (ev->exit_code != 0) _e_sys_action_failed();
530         if (((_e_sys_action_current != E_SYS_HALT) &&
531              (_e_sys_action_current != E_SYS_HALT_NOW) &&
532              (_e_sys_action_current != E_SYS_REBOOT)) ||
533             (ev->exit_code != 0))
534           {
535              if (_e_sys_dialog)
536                {
537                   e_object_del(E_OBJECT(_e_sys_dialog));
538                   _e_sys_dialog = NULL;
539                }
540           }
541         _e_sys_action_current = E_SYS_NONE;
542         _e_sys_exe = NULL;
543         return ECORE_CALLBACK_RENEW;
544      }
545    if ((_e_sys_halt_check_exe) && (ev->exe == _e_sys_halt_check_exe))
546      {
547         e_init_status_set(_("System Check Done"));
548         /* exit_code: 0 == OK, 5 == suid root removed, 7 == group id error
549          * 10 == permission denied, 20 == action undefined */
550         if (ev->exit_code == 0)
551           {
552              _e_sys_can_halt = 1;
553              _e_sys_halt_check_exe = NULL;
554           }
555      }
556    else if ((_e_sys_reboot_check_exe) && (ev->exe == _e_sys_reboot_check_exe))
557      {
558         e_init_status_set(_("System Check Done"));
559         if (ev->exit_code == 0)
560           {
561              _e_sys_can_reboot = 1;
562              _e_sys_reboot_check_exe = NULL;
563           }
564      }
565    else if ((_e_sys_suspend_check_exe) && (ev->exe == _e_sys_suspend_check_exe))
566      {
567         e_init_status_set(_("System Check Done"));
568         if (ev->exit_code == 0)
569           {
570              _e_sys_can_suspend = 1;
571              _e_sys_suspend_check_exe = NULL;
572           }
573      }
574    else if ((_e_sys_hibernate_check_exe) && (ev->exe == _e_sys_hibernate_check_exe))
575      {
576         e_init_status_set(_("System Check Done"));
577         if (ev->exit_code == 0)
578           {
579              _e_sys_can_hibernate = 1;
580              _e_sys_hibernate_check_exe = NULL;
581           }
582      }
583    return ECORE_CALLBACK_RENEW;
584 }
585
586 static void
587 _e_sys_cb_logout_logout(void *data __UNUSED__, E_Dialog *dia)
588 {
589    if (_e_sys_logout_timer)
590      {
591         ecore_timer_del(_e_sys_logout_timer);
592         _e_sys_logout_timer = NULL;
593      }
594    _e_sys_logout_begin_time = 0.0;
595    _e_sys_logout_after();
596    e_object_del(E_OBJECT(dia));
597    _e_sys_logout_confirm_dialog = NULL;
598 }
599
600 static void
601 _e_sys_cb_logout_wait(void *data __UNUSED__, E_Dialog *dia)
602 {
603    if (_e_sys_logout_timer) ecore_timer_del(_e_sys_logout_timer);
604    _e_sys_logout_timer = ecore_timer_add(0.5, _e_sys_cb_logout_timer, NULL);
605    _e_sys_logout_begin_time = ecore_time_get();
606    e_object_del(E_OBJECT(dia));
607    _e_sys_logout_confirm_dialog = NULL;
608 }
609
610 static void
611 _e_sys_cb_logout_abort(void *data __UNUSED__, E_Dialog *dia)
612 {
613    if (_e_sys_logout_timer)
614      {
615         ecore_timer_del(_e_sys_logout_timer);
616         _e_sys_logout_timer = NULL;
617      }
618    _e_sys_logout_begin_time = 0.0;
619    e_object_del(E_OBJECT(dia));
620    _e_sys_logout_confirm_dialog = NULL;
621    _e_sys_action_current = E_SYS_NONE;
622    _e_sys_action_after = E_SYS_NONE;
623    _e_sys_action_after_raw = EINA_FALSE;
624    if (_e_sys_dialog)
625      {
626         e_object_del(E_OBJECT(_e_sys_dialog));
627         _e_sys_dialog = NULL;
628      }
629 }
630
631 static void
632 _e_sys_logout_confirm_dialog_update(int remaining)
633 {
634    char txt[4096];
635
636    if (!_e_sys_logout_confirm_dialog)
637      {
638         fputs("ERROR: updating logout confirm dialog, but none exists!\n",
639               stderr);
640         return;
641      }
642
643    snprintf(txt, sizeof(txt),
644             _("Logout is taking too long.<br>"
645               "Some applications refuse to close.<br>"
646               "Do you want to finish the logout<br>"
647               "anyway without closing these<br>"
648               "applications first?<br><br>"
649               "Auto logout in %d seconds."), remaining);
650
651    e_dialog_text_set(_e_sys_logout_confirm_dialog, txt);
652 }
653
654 static Eina_Bool
655 _e_sys_cb_logout_timer(void *data __UNUSED__)
656 {
657    E_Client *ec;
658    int pending = 0;
659
660    E_CLIENT_FOREACH(e_comp, ec)
661      {
662         if (e_client_util_ignored_get(ec)) continue;
663         if (!ec->internal) pending++;
664      }
665    if (pending == 0) goto after;
666    else if (_e_sys_logout_confirm_dialog)
667      {
668         int remaining = E_LOGOUT_AUTO_TIME -
669           round(ecore_loop_time_get() - _e_sys_logout_begin_time);
670         /* it has taken 60 (E_LOGOUT_AUTO_TIME) seconds of waiting the
671          * confirm dialog and we still have apps that will not go
672          * away. Do the action as user may be far away or forgot it.
673          *
674          * NOTE: this is the behavior for many operating systems and I
675          *       guess the reason is people that hit "shutdown" and
676          *       put their laptops in their backpacks in the hope
677          *       everything will be turned off properly.
678          */
679         if (remaining > 0)
680           {
681              _e_sys_logout_confirm_dialog_update(remaining);
682              return ECORE_CALLBACK_RENEW;
683           }
684         else
685           {
686              _e_sys_cb_logout_logout(NULL, _e_sys_logout_confirm_dialog);
687              return ECORE_CALLBACK_CANCEL;
688           }
689      }
690    else
691      {
692         /* it has taken 15 seconds of waiting and we still have apps that
693          * will not go away
694          */
695         double now = ecore_loop_time_get();
696         if ((now - _e_sys_logout_begin_time) > E_LOGOUT_WAIT_TIME)
697           {
698              E_Dialog *dia;
699
700              dia = e_dialog_new(NULL, "E", "_sys_error_logout_slow");
701              if (dia)
702                {
703                   _e_sys_logout_confirm_dialog = dia;
704                   e_dialog_title_set(dia, _("Logout problems"));
705                   e_dialog_icon_set(dia, "system-log-out", 64);
706                   e_dialog_button_add(dia, _("Logout now"), NULL,
707                                       _e_sys_cb_logout_logout, NULL);
708                   e_dialog_button_add(dia, _("Wait longer"), NULL,
709                                       _e_sys_cb_logout_wait, NULL);
710                   e_dialog_button_add(dia, _("Cancel Logout"), NULL,
711                                       _e_sys_cb_logout_abort, NULL);
712                   e_dialog_button_focus_num(dia, 1);
713                   _e_sys_logout_confirm_dialog_update(E_LOGOUT_AUTO_TIME);
714                   elm_win_center(dia->win, 1, 1);
715                   e_dialog_show(dia);
716                   _e_sys_logout_begin_time = now;
717                }
718              _e_sys_comp_resume();
719              return ECORE_CALLBACK_RENEW;
720           }
721      }
722    return ECORE_CALLBACK_RENEW;
723 after:
724    switch (_e_sys_action_after)
725      {
726       case E_SYS_EXIT:
727         _e_sys_comp_logout();
728         break;
729       case E_SYS_HALT:
730       case E_SYS_HALT_NOW:
731         _e_sys_comp_shutdown();
732         break;
733       case E_SYS_REBOOT:
734         _e_sys_comp_reboot();
735         break;
736       default: break;
737      }
738    _e_sys_logout_timer = NULL;
739    return ECORE_CALLBACK_CANCEL;
740 }
741
742 static void
743 _e_sys_logout_after(void)
744 {
745    if (_e_sys_dialog)
746      {
747         e_object_del(E_OBJECT(_e_sys_dialog));
748         _e_sys_dialog = NULL;
749      }
750    _e_sys_action_current = _e_sys_action_after;
751    _e_sys_action_do(_e_sys_action_after, NULL, _e_sys_action_after_raw);
752    _e_sys_action_after = E_SYS_NONE;
753    _e_sys_action_after_raw = EINA_FALSE;
754 }
755
756 static void
757 _e_sys_logout_begin(E_Sys_Action a_after, Eina_Bool raw)
758 {
759    const Eina_List *l;
760    E_Client *ec;
761    E_Obj_Dialog *od;
762
763    /* start logout - at end do the a_after action */
764    if (!raw)
765      {
766         od = e_obj_dialog_new(e_util_comp_current_get(),
767                               _("Logout in progress"), "E", "_sys_logout");
768         e_obj_dialog_obj_theme_set(od, "base/theme/sys", "e/sys/logout");
769         e_obj_dialog_obj_part_text_set(od, "e.textblock.message",
770                                        _("Logout in progress.<br>"
771                                          "<hilight>Please wait.</hilight>"));
772         e_obj_dialog_show(od);
773         e_obj_dialog_icon_set(od, "system-log-out");
774         if (_e_sys_dialog) e_object_del(E_OBJECT(_e_sys_dialog));
775         _e_sys_dialog = od;
776      }
777    _e_sys_action_after = a_after;
778    _e_sys_action_after_raw = raw;
779    EINA_LIST_FOREACH(e_comp->clients, l, ec)
780      {
781         e_client_act_close_begin(ec);
782      }
783    /* and poll to see if all pending windows are gone yet every 0.5 sec */
784    _e_sys_logout_begin_time = ecore_time_get();
785    if (_e_sys_logout_timer) ecore_timer_del(_e_sys_logout_timer);
786    _e_sys_logout_timer = ecore_timer_add(0.5, _e_sys_cb_logout_timer, NULL);
787 }
788
789 static void
790 _e_sys_current_action(void)
791 {
792    /* display dialog that currently an action is in progress */
793    E_Dialog *dia;
794
795    dia = e_dialog_new(NULL,
796                       "E", "_sys_error_action_busy");
797    if (!dia) return;
798
799    e_dialog_title_set(dia, _("Enlightenment is busy with another request"));
800    e_dialog_icon_set(dia, "enlightenment/sys", 64);
801    switch (_e_sys_action_current)
802      {
803       case E_SYS_LOGOUT:
804         e_dialog_text_set(dia, _("Logging out.<br>"
805                                  "You cannot perform other system actions<br>"
806                                  "once a logout has begun."));
807         break;
808
809       case E_SYS_HALT:
810       case E_SYS_HALT_NOW:
811         e_dialog_text_set(dia, _("Powering off.<br>"
812                                  "You cannot do any other system actions<br>"
813                                  "once a shutdown has been started."));
814         break;
815
816       case E_SYS_REBOOT:
817         e_dialog_text_set(dia, _("Resetting.<br>"
818                                  "You cannot do any other system actions<br>"
819                                  "once a reboot has begun."));
820         break;
821
822       case E_SYS_SUSPEND:
823         e_dialog_text_set(dia, _("Suspending.<br>"
824                                  "Until suspend is complete you cannot perform<br>"
825                                  "any other system actions."));
826         break;
827
828       case E_SYS_HIBERNATE:
829         e_dialog_text_set(dia, _("Hibernating.<br>"
830                                  "You cannot perform any other system actions<br>"
831                                  "until this is complete."));
832         break;
833
834       default:
835         e_dialog_text_set(dia, _("EEK! This should not happen"));
836         break;
837      }
838    e_dialog_button_add(dia, _("OK"), NULL, NULL, NULL);
839    e_dialog_button_focus_num(dia, 0);
840    elm_win_center(dia->win, 1, 1);
841    e_dialog_show(dia);
842 }
843
844 static void
845 _e_sys_action_failed(void)
846 {
847    /* display dialog that the current action failed */
848    E_Dialog *dia;
849
850    dia = e_dialog_new(NULL,
851                       "E", "_sys_error_action_failed");
852    if (!dia) return;
853
854    e_dialog_title_set(dia, _("Enlightenment is busy with another request"));
855    e_dialog_icon_set(dia, "enlightenment/sys", 64);
856    switch (_e_sys_action_current)
857      {
858       case E_SYS_HALT:
859       case E_SYS_HALT_NOW:
860         e_dialog_text_set(dia, _("Power off failed."));
861         break;
862
863       case E_SYS_REBOOT:
864         e_dialog_text_set(dia, _("Reset failed."));
865         break;
866
867       case E_SYS_SUSPEND:
868         e_dialog_text_set(dia, _("Suspend failed."));
869         break;
870
871       case E_SYS_HIBERNATE:
872         e_dialog_text_set(dia, _("Hibernate failed."));
873         break;
874
875       default:
876         e_dialog_text_set(dia, _("EEK! This should not happen"));
877         break;
878      }
879    e_dialog_button_add(dia, _("OK"), NULL, NULL, NULL);
880    e_dialog_button_focus_num(dia, 0);
881    elm_win_center(dia->win, 1, 1);
882    e_dialog_show(dia);
883 }
884
885 static int
886 _e_sys_action_do(E_Sys_Action a, char *param __UNUSED__, Eina_Bool raw)
887 {
888    char buf[PATH_MAX];
889    E_Obj_Dialog *od;
890    int ret = 0;
891
892    switch (a)
893      {
894       case E_SYS_EXIT:
895         // XXX TODO: check for e_fm_op_registry entries and confirm
896         if (!e_util_immortal_check())
897           ecore_main_loop_quit();
898         else
899           return 0;
900         break;
901
902       case E_SYS_RESTART:
903         // XXX TODO: check for e_fm_op_registry entries and confirm
904         // FIXME: we dont   share out immortal info to restarted e. :(
905 //      if (!e_util_immortal_check())
906       {
907          restart = 1;
908          ecore_main_loop_quit();
909       }
910 //        else
911 //          return 0;
912       break;
913
914       case E_SYS_EXIT_NOW:
915         exit(0);
916         break;
917
918       case E_SYS_LOGOUT:
919         // XXX TODO: check for e_fm_op_registry entries and confirm
920         if (raw)
921           {
922              _e_sys_logout_after();
923           }
924         else
925           {
926              _e_sys_logout_begin(E_SYS_EXIT, raw);
927           }
928         break;
929
930       case E_SYS_HALT:
931       case E_SYS_HALT_NOW:
932         /* shutdown -h now */
933         if (e_util_immortal_check()) return 0;
934         snprintf(buf, sizeof(buf),
935                  "%s/enlightenment/utils/enlightenment_sys halt",
936                  e_prefix_lib_get());
937         if (_e_sys_exe)
938           {
939              if ((ecore_time_get() - _e_sys_begin_time) > 2.0)
940                _e_sys_current_action();
941              return 0;
942           }
943         else
944           {
945              if (raw)
946                {
947                   _e_sys_begin_time = ecore_time_get();
948                   if (systemd_works)
949                     _e_sys_systemd_poweroff();
950                   else
951                     {
952                        _e_sys_exe = ecore_exe_run(buf, NULL);
953                        ret = 1;
954                     }
955                }
956              else
957                {
958                   ret = 0;
959                   _e_sys_begin_time = ecore_time_get();
960
961                   od = e_obj_dialog_new(NULL,
962                                         _("Power off"), "E", "_sys_halt");
963                   e_obj_dialog_obj_theme_set(od, "base/theme/sys", "e/sys/halt");
964                   e_obj_dialog_obj_part_text_set(od, "e.textblock.message",
965                                                  _("Power off.<br>"
966                                                    "<hilight>Please wait.</hilight>"));
967                   e_obj_dialog_show(od);
968                   e_obj_dialog_icon_set(od, "system-shutdown");
969                   if (_e_sys_dialog) e_object_del(E_OBJECT(_e_sys_dialog));
970                   e_obj_dialog_cb_delete_set(od, _e_sys_dialog_cb_delete);
971                   _e_sys_dialog = od;
972                   _e_sys_logout_begin(a, EINA_TRUE);
973                }
974              /* FIXME: display halt status */
975           }
976         break;
977
978       case E_SYS_REBOOT:
979         /* shutdown -r now */
980         if (e_util_immortal_check()) return 0;
981         snprintf(buf, sizeof(buf),
982                  "%s/enlightenment/utils/enlightenment_sys reboot",
983                  e_prefix_lib_get());
984         if (_e_sys_exe)
985           {
986              if ((ecore_time_get() - _e_sys_begin_time) > 2.0)
987                _e_sys_current_action();
988              return 0;
989           }
990         else
991           {
992              if (raw)
993                {
994                   _e_sys_begin_time = ecore_time_get();
995                   if (systemd_works)
996                     _e_sys_systemd_reboot();
997                   else
998                     {
999                        _e_sys_exe = ecore_exe_run(buf, NULL);
1000                        ret = 1;
1001                     }
1002                }
1003              else
1004                {
1005                   ret = 0;
1006                   _e_sys_begin_time = ecore_time_get();
1007                   od = e_obj_dialog_new(NULL,
1008                                         _("Resetting"), "E", "_sys_reboot");
1009                   e_obj_dialog_obj_theme_set(od, "base/theme/sys", "e/sys/reboot");
1010                   e_obj_dialog_obj_part_text_set(od, "e.textblock.message",
1011                                                  _("Resetting.<br>"
1012                                                    "<hilight>Please wait.</hilight>"));
1013                   e_obj_dialog_show(od);
1014                   e_obj_dialog_icon_set(od, "system-restart");
1015                   if (_e_sys_dialog) e_object_del(E_OBJECT(_e_sys_dialog));
1016                   e_obj_dialog_cb_delete_set(od, _e_sys_dialog_cb_delete);
1017                   _e_sys_dialog = od;
1018                   _e_sys_logout_begin(a, EINA_TRUE);
1019                }
1020              /* FIXME: display reboot status */
1021           }
1022         break;
1023
1024       case E_SYS_SUSPEND:
1025         /* /etc/acpi/sleep.sh force */
1026         snprintf(buf, sizeof(buf),
1027                  "%s/enlightenment/utils/enlightenment_sys suspend",
1028                  e_prefix_lib_get());
1029         if (_e_sys_exe)
1030           {
1031              if ((ecore_time_get() - _e_sys_begin_time) > 2.0)
1032                _e_sys_current_action();
1033              return 0;
1034           }
1035         else
1036           {
1037              if (raw)
1038                {
1039                   _e_sys_susp_hib_check();
1040                   if (e_config->desklock_on_suspend)
1041                     e_desklock_show(EINA_TRUE);
1042                   _e_sys_begin_time = ecore_time_get();
1043                   if (systemd_works)
1044                     _e_sys_systemd_suspend();
1045                   else
1046                     {
1047                        _e_sys_exe = ecore_exe_run(buf, NULL);
1048                        ret = 1;
1049                     }
1050                }
1051              else
1052                {
1053                   ecore_event_add(E_EVENT_SYS_SUSPEND, NULL, NULL, NULL);
1054                   _e_sys_comp_suspend();
1055                   return 0;
1056                }
1057              /* FIXME: display suspend status */
1058           }
1059         break;
1060
1061       case E_SYS_HIBERNATE:
1062         /* /etc/acpi/hibernate.sh force */
1063         snprintf(buf, sizeof(buf),
1064                  "%s/enlightenment/utils/enlightenment_sys hibernate",
1065                  e_prefix_lib_get());
1066         if (_e_sys_exe)
1067           {
1068              if ((ecore_time_get() - _e_sys_begin_time) > 2.0)
1069                _e_sys_current_action();
1070              return 0;
1071           }
1072         else
1073           {
1074              if (raw)
1075                {
1076                   _e_sys_susp_hib_check();
1077                   if (e_config->desklock_on_suspend)
1078                     e_desklock_show(EINA_TRUE);
1079                   _e_sys_begin_time = ecore_time_get();
1080                   if (systemd_works)
1081                     _e_sys_systemd_hibernate();
1082                   else
1083                     {
1084                        _e_sys_exe = ecore_exe_run(buf, NULL);
1085                        ret = 1;
1086                     }
1087                }
1088              else
1089                {
1090                   ecore_event_add(E_EVENT_SYS_HIBERNATE, NULL, NULL, NULL);
1091                   _e_sys_comp_hibernate();
1092                   return 0;
1093                }
1094              /* FIXME: display hibernate status */
1095           }
1096         break;
1097
1098       default:
1099         return 0;
1100      }
1101    return ret;
1102 }
1103
1104 static void
1105 _e_sys_dialog_cb_delete(E_Obj_Dialog *od __UNUSED__)
1106 {
1107    /* If we don't NULL out the _e_sys_dialog, then the
1108     * ECORE_EXE_EVENT_DEL callback will trigger and segv if the window
1109     * is deleted in some other way. */
1110    _e_sys_dialog = NULL;
1111 }
1112