support connected standby (non-s3 sleep/freeze) that new lpatops sport

this requires we have to force dpms on to reduce power. to avoid
glitches with the pointer staying around in x we need to support
suspending it too so it hides cleanly like the screen dims or undims.
also use the new powersave freeze mode to do this.

note that i've tested this on s3 supporting laptops and non-s3 and it
"works for me". it may require more testing and work. there is more to
power saving than just this as well but for now that's out of scope as
you have to mess with linux device autosuspend timeouts and a bunch
more (wowlan ... blahblah).

i need to find the source of the intermittent wakeups too in e. there
is a long lived timeout (8-ish seconds?) but more specifically e keeps
waking up from fd's and then reading /sys stuff about battery - some
event is causing us to do this... maybe to suspend this or make
battery checking very rare when in freeze mode (or screen off) etc.

so this fixes some glitches as well as supports a new way of sleeping
"alive" when hardware literally doesnt support normal s3 sleep... so
kind of a fix with a feature.
This commit is contained in:
Carsten Haitzler 2017-07-10 09:08:25 +09:00
parent 7caf5c8ff4
commit d0c5fb465b
9 changed files with 301 additions and 25 deletions

View File

@ -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
}

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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;
}