diff --git a/src/bin/e_comp.c b/src/bin/e_comp.c index 0e1e56c1b..01e8d4d51 100644 --- a/src/bin/e_comp.c +++ b/src/bin/e_comp.c @@ -893,6 +893,7 @@ _e_comp_screensaver_on(void *data EINA_UNUSED, int type EINA_UNUSED, void *event edje_object_signal_emit(zone->base, "e,state,screensaver,on", "e"); edje_object_signal_emit(zone->over, "e,state,screensaver,on", "e"); } + e_comp_screen_suspend(); return ECORE_CALLBACK_PASS_ON; } @@ -906,6 +907,7 @@ _e_comp_screensaver_off(void *data EINA_UNUSED, int type EINA_UNUSED, void *even ecore_animator_frametime_set(ecore_frametime); if (!e_comp->saver) return ECORE_CALLBACK_RENEW; + e_comp_screen_resume(); e_comp_override_del(); e_comp->saver = EINA_FALSE; if (!e_comp->nocomp) @@ -1800,3 +1802,100 @@ e_comp_util_object_is_above_nocomp(Evas_Object *obj) return EINA_TRUE; return EINA_FALSE; } + +#ifndef HAVE_WAYLAND_ONLY +static void +_e_comp_pointer_grab(void) +{ + if (e_comp->suspend_grabbed) ecore_x_window_free(e_comp->suspend_grabbed); + e_comp->suspend_grabbed = ecore_x_window_input_new(e_comp->root, 0, 0, 1, 1); + ecore_x_window_show(e_comp->suspend_grabbed); + if (!e_grabinput_get(e_comp->suspend_grabbed, 0, e_comp->suspend_grabbed)) + { + ecore_x_window_free(e_comp->suspend_grabbed); + e_comp->suspend_grabbed = 0; + } +} + +static void +_e_comp_pointer_ungrab(void) +{ + if (e_comp->comp_type == E_PIXMAP_TYPE_X) + { + e_grabinput_release(e_comp->suspend_grabbed, e_comp->suspend_grabbed); + ecore_x_window_free(e_comp->suspend_grabbed); + } +} + +static void +_e_comp_cb_pointer_suspend_resume_done(void *data, Evas_Object *obj, const char *emission, const char *source) +{ + edje_object_signal_callback_del(obj, emission, source, + _e_comp_cb_pointer_suspend_resume_done); + if (!data) _e_comp_pointer_ungrab(); +} +#endif + +E_API void +e_comp_screen_suspend(void) +{ +#ifndef HAVE_WAYLAND_ONLY + if (e_comp->comp_type != E_PIXMAP_TYPE_X) return; + _e_comp_pointer_ungrab(); + _e_comp_pointer_grab(); + if (!e_comp->suspend_grabbed) return; + if ((e_comp->pointer) && (e_comp->pointer->o_ptr)) + { + const char *s = edje_object_data_get(e_comp->pointer->o_ptr, + "can_suspend"); + if ((s) && (atoi(s) == 1)) + { + edje_object_signal_callback_del(e_comp->pointer->o_ptr, + "e,state,mouse,suspend,done", "e", + _e_comp_cb_pointer_suspend_resume_done); + edje_object_signal_callback_del(e_comp->pointer->o_ptr, + "e,state,mouse,resume,done", "e", + _e_comp_cb_pointer_suspend_resume_done); + edje_object_signal_callback_add(e_comp->pointer->o_ptr, + "e,state,mouse,suspend,done", + "e", + _e_comp_cb_pointer_suspend_resume_done, + e_comp); + edje_object_signal_emit(e_comp->pointer->o_ptr, + "e,state,mouse,suspend", "e"); + } + } +#endif +} + +E_API void +e_comp_screen_resume(void) +{ +#ifndef HAVE_WAYLAND_ONLY + if (e_comp->comp_type != E_PIXMAP_TYPE_X) return; + _e_comp_pointer_ungrab(); + _e_comp_pointer_grab(); + if (!e_comp->suspend_grabbed) return; + if ((e_comp->pointer) && (e_comp->pointer->o_ptr)) + { + const char *s = edje_object_data_get(e_comp->pointer->o_ptr, + "can_suspend"); + if ((s) && (atoi(s) == 1)) + { + edje_object_signal_callback_del(e_comp->pointer->o_ptr, + "e,state,mouse,suspend,done", "e", + _e_comp_cb_pointer_suspend_resume_done); + edje_object_signal_callback_del(e_comp->pointer->o_ptr, + "e,state,mouse,resume,done", "e", + _e_comp_cb_pointer_suspend_resume_done); + edje_object_signal_callback_add(e_comp->pointer->o_ptr, + "e,state,mouse,resume,done", + "e", + _e_comp_cb_pointer_suspend_resume_done, + NULL); + edje_object_signal_emit(e_comp->pointer->o_ptr, + "e,state,mouse,resume", "e"); + } + } +#endif +} diff --git a/src/bin/e_comp.h b/src/bin/e_comp.h index 745550d22..c991088ea 100644 --- a/src/bin/e_comp.h +++ b/src/bin/e_comp.h @@ -97,6 +97,7 @@ struct _E_Comp Ecore_Window win; // input overlay Ecore_Window root; //x11 root window + Ecore_Window suspend_grabbed; // window grabber for suspending pointer Ecore_Evas *ee; //canvas Ecore_Window ee_win; //canvas window E_Comp_Canvas *canvas; @@ -232,6 +233,8 @@ EINTERN Evas_Object *e_comp_style_selector_create(Evas *evas, const char **sourc E_API E_Config_Dialog *e_int_config_comp(Evas_Object *parent, const char *params); E_API E_Config_Dialog *e_int_config_comp_match(Evas_Object *parent, const char *params); +E_API void e_comp_screen_suspend(void); +E_API void e_comp_screen_resume(void); E_API Eina_Bool e_comp_util_kbd_grabbed(void); E_API Eina_Bool e_comp_util_mouse_grabbed(void); diff --git a/src/bin/e_comp_x.c b/src/bin/e_comp_x.c index e097a4d9f..a039862d1 100644 --- a/src/bin/e_comp_x.c +++ b/src/bin/e_comp_x.c @@ -4939,6 +4939,7 @@ _e_comp_x_screensaver_eval_cb(void *d EINA_UNUSED) static Eina_Bool _e_comp_x_screensaver_notify_cb(void *data EINA_UNUSED, int type EINA_UNUSED, Ecore_X_Event_Screensaver_Notify *ev) { + if (e_screensaver_ignore_get()) return ECORE_CALLBACK_PASS_ON; if ((ev->on) && (!saver_on)) { saver_on = EINA_TRUE; diff --git a/src/bin/e_config.c b/src/bin/e_config.c index 7e4350c38..293dd83fe 100644 --- a/src/bin/e_config.c +++ b/src/bin/e_config.c @@ -627,6 +627,8 @@ _e_config_edd_init(Eina_Bool old) E_CONFIG_VAL(D, T, screensaver_wake_on_notify, INT); E_CONFIG_VAL(D, T, screensaver_wake_on_urgent, INT); + E_CONFIG_VAL(D, T, suspend_connected_standby, UCHAR); + E_CONFIG_VAL(D, T, screensaver_suspend, UCHAR); E_CONFIG_VAL(D, T, screensaver_suspend_on_ac, UCHAR); E_CONFIG_VAL(D, T, screensaver_suspend_delay, DOUBLE); diff --git a/src/bin/e_config.h b/src/bin/e_config.h index 00eb90d62..275283977 100644 --- a/src/bin/e_config.h +++ b/src/bin/e_config.h @@ -225,6 +225,8 @@ struct _E_Config int screensaver_wake_on_notify; // GUI int screensaver_wake_on_urgent; // GUI + unsigned char suspend_connected_standby; // GUI + unsigned char screensaver_suspend; // GUI unsigned char screensaver_suspend_on_ac; // GUI double screensaver_suspend_delay; // GUI diff --git a/src/bin/e_screensaver.c b/src/bin/e_screensaver.c index 2db7b947a..506e13284 100644 --- a/src/bin/e_screensaver.c +++ b/src/bin/e_screensaver.c @@ -30,6 +30,8 @@ static Ecore_Timer *_e_screensaver_timer; static Eina_Bool _e_screensaver_inhibited = EINA_FALSE; #endif +static Eina_Bool _screensaver_ignore = EINA_FALSE; + E_API int E_EVENT_SCREENSAVER_ON = -1; E_API int E_EVENT_SCREENSAVER_OFF = -1; E_API int E_EVENT_SCREENSAVER_OFF_PRE = -1; @@ -68,6 +70,24 @@ e_screensaver_timeout_get(Eina_Bool use_idle) return timeout; } +E_API void +e_screensaver_ignore(void) +{ + _screensaver_ignore = EINA_TRUE; +} + +E_API void +e_screensaver_unignore(void) +{ + _screensaver_ignore = EINA_FALSE; +} + +E_API Eina_Bool +e_screensaver_ignore_get(void) +{ + return _screensaver_ignore; +} + E_API void e_screensaver_update(void) { @@ -504,19 +524,25 @@ e_screensaver_eval(Eina_Bool saver_on) if (t < 1.0) t = 1.0; E_FREE_FUNC(screensaver_idle_timer, ecore_timer_del); - if (e_config->screensaver_enable) - screensaver_idle_timer = ecore_timer_loop_add - (t, _e_screensaver_idle_timer_cb, NULL); - if (e_backlight_mode_get(NULL) != E_BACKLIGHT_MODE_DIM) + if (!_screensaver_ignore) { - e_backlight_mode_set(NULL, E_BACKLIGHT_MODE_DIM); - screensaver_dimmed = EINA_TRUE; + if (e_config->screensaver_enable) + screensaver_idle_timer = ecore_timer_loop_add + (t, _e_screensaver_idle_timer_cb, NULL); + if (e_backlight_mode_get(NULL) != E_BACKLIGHT_MODE_DIM) + { + e_backlight_mode_set(NULL, E_BACKLIGHT_MODE_DIM); + screensaver_dimmed = EINA_TRUE; + } } } else { - if (!e_screensaver_on_get()) - ecore_event_add(E_EVENT_SCREENSAVER_ON, NULL, NULL, NULL); + if (!_screensaver_ignore) + { + if (!e_screensaver_on_get()) + ecore_event_add(E_EVENT_SCREENSAVER_ON, NULL, NULL, NULL); + } } return; } @@ -536,8 +562,11 @@ e_screensaver_eval(Eina_Bool saver_on) e_backlight_mode_set(NULL, E_BACKLIGHT_MODE_NORMAL); screensaver_dimmed = EINA_FALSE; } - if (e_screensaver_on_get()) - ecore_event_add(E_EVENT_SCREENSAVER_OFF, NULL, NULL, NULL); + if (!_screensaver_ignore) + { + if (e_screensaver_on_get()) + ecore_event_add(E_EVENT_SCREENSAVER_OFF, NULL, NULL, NULL); + } } E_API void diff --git a/src/bin/e_screensaver.h b/src/bin/e_screensaver.h index 35e94cbfb..9c26afc98 100644 --- a/src/bin/e_screensaver.h +++ b/src/bin/e_screensaver.h @@ -7,6 +7,10 @@ EINTERN void e_screensaver_preinit(void); EINTERN int e_screensaver_init(void); EINTERN int e_screensaver_shutdown(void); +E_API void e_screensaver_ignore(void); +E_API void e_screensaver_unignore(void); +E_API Eina_Bool e_screensaver_ignore_get(void); + E_API void e_screensaver_update(void); E_API int e_screensaver_timeout_get(Eina_Bool use_idle); diff --git a/src/bin/e_sys.c b/src/bin/e_sys.c index c75ce1653..d323ea60b 100644 --- a/src/bin/e_sys.c +++ b/src/bin/e_sys.c @@ -36,6 +36,8 @@ static E_Dialog *_e_sys_logout_confirm_dialog = NULL; static Ecore_Timer *_e_sys_susp_hib_check_timer = NULL; static double _e_sys_susp_hib_check_last_tick = 0.0; +static Ecore_Event_Handler *_e_sys_acpi_handler = NULL; + static void _e_sys_systemd_handle_inhibit(void); static void _e_sys_systemd_poweroff(void); static void _e_sys_systemd_reboot(void); @@ -55,16 +57,46 @@ static Eldbus_Proxy *login1_manger_proxy = NULL; static int _e_sys_comp_waiting = 0; +static Ecore_Timer *_e_sys_screensaver_unignore_timer = NULL; + E_API int E_EVENT_SYS_SUSPEND = -1; E_API int E_EVENT_SYS_HIBERNATE = -1; E_API int E_EVENT_SYS_RESUME = -1; +static Eina_Bool +_e_sys_comp_done2_cb(void *data) +{ + e_sys_action_raw_do((E_Sys_Action)(long)data, NULL); + return EINA_FALSE; +} + static void _e_sys_comp_done_cb(void *data, Evas_Object *obj, const char *sig, const char *src) { if (_e_sys_comp_waiting == 1) _e_sys_comp_waiting--; edje_object_signal_callback_del(obj, sig, src, _e_sys_comp_done_cb); - e_sys_action_raw_do((E_Sys_Action)(long)data, NULL); + if (_e_sys_screensaver_unignore_timer) + { + ecore_timer_del(_e_sys_screensaver_unignore_timer); + _e_sys_screensaver_unignore_timer = NULL; + } + e_screensaver_ignore(); + ecore_evas_manual_render_set(e_comp->ee, EINA_TRUE); +#ifndef HAVE_WAYLAND_ONLY + if (e_comp->comp_type == E_PIXMAP_TYPE_X) + { + ecore_x_screensaver_suspend(); + ecore_x_dpms_force(EINA_TRUE); + } +#endif +#ifdef HAVE_WAYLAND + if (e_comp->comp_type != E_PIXMAP_TYPE_X) + { + if (e_comp->screen && e_comp->screen->dpms) + e_comp->screen->dpms(3); + } +#endif + ecore_timer_add(0.5, _e_sys_comp_done2_cb, data); E_FREE_FUNC(action_timeout, ecore_timer_del); } @@ -128,9 +160,9 @@ _e_sys_comp_emit_cb_wait(E_Sys_Action a, const char *sig, const char *rep, Eina_ if (_e_sys_comp_waiting == 0) _e_sys_comp_waiting++; if (nocomp_push) e_comp_override_add(); else e_comp_override_timed_pop(); - printf("_e_sys_comp_emit_cb_wait - [%x] %s %s\n", a, sig, rep); _e_sys_comp_zones_fade(sig, nocomp_push); + e_comp_screen_suspend(); if (rep) { @@ -171,16 +203,53 @@ _e_sys_comp_logout(void) _e_sys_comp_emit_cb_wait(E_SYS_LOGOUT, "e,state,sys,logout", "e,state,sys,logout,done", EINA_TRUE); } -static void -_e_sys_comp_resume(void) +static Eina_Bool +_e_sys_screensaver_unignore_delay(void *data EINA_UNUSED) +{ + _e_sys_screensaver_unignore_timer = NULL; + e_screensaver_unignore(); + return EINA_FALSE; +} + +static Eina_Bool +_e_sys_comp_resume2(void *data EINA_UNUSED) { Eina_List *l; E_Zone *zone; - evas_damage_rectangle_add(e_comp->evas, 0, 0, e_comp->w, e_comp->h); + + e_comp_screen_resume(); EINA_LIST_FOREACH(e_comp->zones, l, zone) e_backlight_level_set(zone, e_config->backlight.normal, -1.0); _e_sys_comp_zones_fade("e,state,sys,resume", EINA_FALSE); + return EINA_FALSE; +} + +static void +_e_sys_comp_resume(void) +{ + ecore_evas_manual_render_set(e_comp->ee, EINA_FALSE); + evas_damage_rectangle_add(e_comp->evas, 0, 0, e_comp->w, e_comp->h); +#ifndef HAVE_WAYLAND_ONLY + if (e_comp->comp_type == E_PIXMAP_TYPE_X) + { + ecore_x_dpms_force(EINA_FALSE); + ecore_x_screensaver_resume(); + ecore_x_screensaver_reset(); + } +#endif +#ifdef HAVE_WAYLAND + if (e_comp->comp_type != E_PIXMAP_TYPE_X) + { + if (e_comp->screen && e_comp->screen->dpms) + e_comp->screen->dpms(0); + } +#endif e_screensaver_deactivate(); + if (_e_sys_screensaver_unignore_timer) + ecore_timer_del(_e_sys_screensaver_unignore_timer); + _e_sys_screensaver_unignore_timer = + ecore_timer_add(0.5, _e_sys_screensaver_unignore_delay, NULL); + ecore_timer_add(1.5, _e_sys_comp_resume2, NULL); } /* externally accessible functions */ @@ -211,8 +280,14 @@ e_sys_init(void) EINTERN int e_sys_shutdown(void) { + if (_e_sys_screensaver_unignore_timer) + ecore_timer_del(_e_sys_screensaver_unignore_timer); + if (_e_sys_acpi_handler) + ecore_event_handler_del(_e_sys_acpi_handler); if (_e_sys_exe_exit_handler) ecore_event_handler_del(_e_sys_exe_exit_handler); + _e_sys_screensaver_unignore_timer = NULL; + _e_sys_acpi_handler = NULL; _e_sys_exe_exit_handler = NULL; _e_sys_halt_check_exe = NULL; _e_sys_reboot_check_exe = NULL; @@ -467,11 +542,12 @@ _e_sys_systemd_hibernate(void) eldbus_proxy_call(login1_manger_proxy, "Hibernate", NULL, NULL, -1, "b", 0); } -static void -_e_sys_resume_job(void *d EINA_UNUSED) +static Eina_Bool +_e_sys_resume_delay(void *d EINA_UNUSED) { ecore_event_add(E_EVENT_SYS_RESUME, NULL, NULL, NULL); _e_sys_comp_resume(); + return EINA_FALSE; } static Eina_Bool @@ -479,10 +555,10 @@ _e_sys_susp_hib_check_timer_cb(void *data EINA_UNUSED) { double t = ecore_time_unix_get(); - if ((t - _e_sys_susp_hib_check_last_tick) > 0.2) + if ((t - _e_sys_susp_hib_check_last_tick) > 0.5) { _e_sys_susp_hib_check_timer = NULL; - ecore_job_add(_e_sys_resume_job, NULL); + ecore_timer_add(0.2, _e_sys_resume_delay, NULL); return EINA_FALSE; } _e_sys_susp_hib_check_last_tick = t; @@ -860,6 +936,32 @@ _e_sys_action_failed(void) e_dialog_show(dia); } +static Eina_Bool +_e_sys_cb_acpi_event(void *data EINA_UNUSED, int type EINA_UNUSED, void *event) +{ + E_Event_Acpi *ev = event; + + if (e_powersave_mode_get() == E_POWERSAVE_MODE_FREEZE) + { + if (((ev->type == E_ACPI_TYPE_LID) && + (ev->status == E_ACPI_LID_OPEN)) || + (ev->type == E_ACPI_TYPE_POWER) || + (ev->type == E_ACPI_TYPE_SLEEP)) + { + if (_e_sys_acpi_handler) + { + ecore_event_handler_del(_e_sys_acpi_handler); + _e_sys_acpi_handler = NULL; + } + e_powersave_mode_unforce(); + ecore_timer_add(1.0, _e_sys_resume_delay, NULL); + // XXX: need some way of, at the system level, restoring + // system and devices back to running normally + } + } + return ECORE_CALLBACK_PASS_ON; +} + static int _e_sys_action_do(E_Sys_Action a, char *param EINA_UNUSED, Eina_Bool raw) { @@ -990,16 +1092,36 @@ _e_sys_action_do(E_Sys_Action a, char *param EINA_UNUSED, Eina_Bool raw) { if (raw) { - _e_sys_susp_hib_check(); if (e_config->desklock_on_suspend) + // XXX: this desklock - ensure its instant e_desklock_show(EINA_TRUE); _e_sys_begin_time = ecore_time_get(); - if (systemd_works) - _e_sys_systemd_suspend(); + if (e_config->suspend_connected_standby == 0) + { + _e_sys_susp_hib_check(); + if (systemd_works) + _e_sys_systemd_suspend(); + else + { + _e_sys_exe = ecore_exe_run(buf, NULL); + ret = 1; + } + } else { - _e_sys_exe = ecore_exe_run(buf, NULL); - ret = 1; + if (_e_sys_acpi_handler) + ecore_event_handler_del(_e_sys_acpi_handler); + _e_sys_acpi_handler = + ecore_event_handler_add(E_EVENT_ACPI, + _e_sys_cb_acpi_event, + NULL); + e_powersave_mode_force(E_POWERSAVE_MODE_FREEZE); + // XXX: need some system way of forcing the system + // into a very lowe power level with as many + // devices suspended as possible. below is a simple + // "freeze the cpu/kernel" which is not what we + // want actually + // ecore_exe_run("sleep 2 && echo freeze | sudo tee /sys/power/state", NULL); } } else diff --git a/src/modules/conf_performance/e_int_config_powermanagement.c b/src/modules/conf_performance/e_int_config_powermanagement.c index 01e3bf816..8b3e14d13 100644 --- a/src/modules/conf_performance/e_int_config_powermanagement.c +++ b/src/modules/conf_performance/e_int_config_powermanagement.c @@ -21,6 +21,7 @@ struct _E_Config_Dialog_Data double powersave_extreme; E_Powersave_Mode powersave_min; E_Powersave_Mode powersave_max; + int suspend_connected_standby; }; E_Config_Dialog * @@ -56,6 +57,7 @@ _create_data(E_Config_Dialog *cfd EINA_UNUSED) cfdata->powersave_medium = e_config->powersave.medium; cfdata->powersave_high = e_config->powersave.high; cfdata->powersave_extreme = e_config->powersave.extreme; + cfdata->suspend_connected_standby = e_config->suspend_connected_standby; return cfdata; } @@ -70,6 +72,7 @@ _free_data(E_Config_Dialog *cfd EINA_UNUSED, E_Config_Dialog_Data *cfdata) static int _basic_apply(E_Config_Dialog *cfd EINA_UNUSED, E_Config_Dialog_Data *cfdata) { + e_config->suspend_connected_standby = cfdata->suspend_connected_standby; e_config->powersave.none = cfdata->powersave_none; e_config->powersave.low = cfdata->powersave_low; e_config->powersave.medium = cfdata->powersave_medium; @@ -92,7 +95,8 @@ _basic_apply(E_Config_Dialog *cfd EINA_UNUSED, E_Config_Dialog_Data *cfdata) static int _basic_check_changed(E_Config_Dialog *cfd EINA_UNUSED, E_Config_Dialog_Data *cfdata) { - return ((e_config->powersave.min != cfdata->powersave_min) || + return ((e_config->suspend_connected_standby != cfdata->suspend_connected_standby) || + (e_config->powersave.min != cfdata->powersave_min) || (e_config->powersave.max != cfdata->powersave_max) || (!EINA_DBL_EQ(e_config->powersave.none, cfdata->powersave_none)) || (!EINA_DBL_EQ(e_config->powersave.low, cfdata->powersave_low)) || @@ -367,6 +371,16 @@ _basic_create(E_Config_Dialog *cfd EINA_UNUSED, Evas *evas, E_Config_Dialog_Data 0.0, 0.5 //align ); + y++; + ob = e_widget_check_add(evas, _("Connected standby instead of suspend"), + &(cfdata->suspend_connected_standby)); + e_widget_table_object_align_append(ol, ob, + 0, y, //place + 4, 1, //span + 1, 1, //fill + 1, 0, //expand + 0.0, 0.5 //align + ); return ol; }