e laptop lid fixes to bring back behavior and trim down glitches

so i spent a few days lopening and closing the lids of a few laptops,
plugging and unplugging external screens in, plugging and unplugging
ac power and doing lots of combinations of these. this led to a whole
slew of interrealted issues that were pretty hard to detangle into
just single issues, so this is all one blob.

this fixes:

1. if a lid close gets a monitor unplug from x or e's randr wants to
unplug then this lead to slow unsuspend or lid open times as e was
reconfirguring the screens entireluy on lid open. dont do that. just
keep things as is, unless we have an external display, then reconfigure.

2. we had 2 systems monitoring for a wake. a poller and a systemd
event. this was redundant and lead to interesting things in the debug
output, so clean that up and on systemd systsems use the systemd wake
events

3. some systems dont shut down their screens on lid close, so they
stay open until screensaver timeouts kick in. bad. so also force the
screen to go off on lid close (if the lid screen is the only one we
have).

4. x seems to have a bug where if you force dpms off etc. to turn the
screen on, it still thinks it's of and wont dpms off again after that
until you eother give some input to have the wake event make the dpms
system in x think its now time to go on, or you toggle dpms on and
off, so i found toggling tricks x into thinking the right thing.

this makes some debugging also be consistent with printfs.

all in all i have a pretty well supported laptop doing swimmingly with
e and a not so well designed (acpi dsdt - missing many events like
acpi battery ones, ac power change acpi events, missing logic to power
off a closed screen in firmware or hardware and leaving it to sw...
not this laptop has a tocuh panel and extra fun points awarded since
the touch panel doesnt shut off on lid close... AND it reprots touch
events when it closes  as it touches the keys/case... hooray! that has
another work-around local to my system, as efl has no mechanism to do
this).

@fix
This commit is contained in:
Carsten Haitzler 2018-05-15 15:40:00 +09:00
parent b00477c1e5
commit 5a1e9a995c
6 changed files with 204 additions and 18 deletions

View File

@ -344,7 +344,7 @@ _e_acpi_cb_server_data(void *data EINA_UNUSED, int type EINA_UNUSED, void *event
case E_ACPI_TYPE_LID:
acpi_event->status =
_e_acpi_lid_status_get(device, bus);
printf("RRR: acpi event\n");
printf("RRR: acpi event @%1.8f\n", ecore_time_get());
/* no change in lid state */
if (lid_is_closed == (acpi_event->status == E_ACPI_LID_CLOSED)) break;
lid_is_closed = (acpi_event->status == E_ACPI_LID_CLOSED);

View File

@ -2394,7 +2394,6 @@ ACT_FN_GO(suspend, )
static Eina_Bool
_have_lid_and_external_screens_on(void)
{
#ifndef HAVE_WAYLAND_ONLY
Eina_List *l;
E_Randr2_Screen *s;
int lids = 0;
@ -2409,7 +2408,6 @@ _have_lid_and_external_screens_on(void)
ext_screens++;
}
if ((lids > 0) && (ext_screens > 0)) return EINA_TRUE;
#endif
return EINA_FALSE;
}

View File

@ -582,8 +582,10 @@ _screens_fingerprint(E_Randr2 *r)
eina_strbuf_append(buf, ":");
eina_strbuf_append(buf, s->id);
eina_strbuf_append(buf, ":");
if (s->info.lid_closed) eina_strbuf_append(buf, ":LC:");
else eina_strbuf_append(buf, ":LO:");
// Don't do this asbecause this forces a screen replug when you open and
// close your laptop lid and if that is the only thing you open or close...
// if (s->info.lid_closed) eina_strbuf_append(buf, ":LC:");
// else eina_strbuf_append(buf, ":LO:");
}
}
str = eina_strbuf_string_steal(buf);
@ -598,6 +600,7 @@ _screens_differ(E_Randr2 *r1, E_Randr2 *r2)
Eina_Bool changed = EINA_FALSE;
Eina_List *l, *ll;
E_Randr2_Screen *s, *ss;
int r1_screen_num = 0, r2_screen_num = 0;
// check monitor outputs and edids, plugged in things
s1 = _screens_fingerprint(r1);
@ -609,6 +612,26 @@ _screens_differ(E_Randr2 *r1, E_Randr2 *r2)
free(s1);
free(s2);
// check screen config
printf("RRR: screens lists %i -> %i\n", eina_list_count(r1->screens), eina_list_count(r2->screens));
printf("RRR: --------\n");
EINA_LIST_FOREACH(r1->screens, l, s)
{
if (!s->id) continue;
if ((s->info.connected) &&
(!((s->info.is_lid) && (s->info.lid_closed))))
r1_screen_num++;
}
printf("RRR: --------\n");
EINA_LIST_FOREACH(r2->screens, l, s)
{
if (!s->id) continue;
if ((s->info.connected) &&
(!((s->info.is_lid) && (s->info.lid_closed))))
r2_screen_num++;
}
printf("RRR: --------\n");
printf("RRR: screens %i -> %i\n", r1_screen_num, r2_screen_num);
printf("RRR: --------\n");
EINA_LIST_FOREACH(r2->screens, l, s)
{
if (!s->id) continue;
@ -625,14 +648,62 @@ _screens_differ(E_Randr2 *r1, E_Randr2 *r2)
(s->config.mode.w != ss->config.mode.w) ||
(s->config.mode.h != ss->config.mode.h) ||
(s->config.enabled != ss->config.enabled) ||
(s->config.rotation != ss->config.rotation) ||
(s->info.lid_closed != ss->info.lid_closed))
(s->config.rotation != ss->config.rotation))
changed = EINA_TRUE;
else
{
if (r1_screen_num != r2_screen_num)
{
printf("RRR: do change because screen count changed\n");
changed = EINA_TRUE;
}
else
{
if ((r2_screen_num != 1) &&
(s->info.lid_closed != ss->info.lid_closed))
{
printf("RRR: change because laptop lid open/close and number of screens > 1\n");
changed = EINA_TRUE;
}
else
printf("RRR: skip change because of single laptop lid\n");
}
}
}
printf("RRR: --------\n");
printf("RRR: changed = %i\n", changed);
return changed;
}
static Eina_Bool
_cb_deferred_suspend_screen_change(void *data EINA_UNUSED)
{
Eina_List *l;
E_Randr2_Screen *s;
int lids = 0;
int ext_screens = 0;
EINA_LIST_FOREACH(e_randr2->screens, l, s)
{
if (s->info.is_lid) lids++;
else if ((s->config.enabled) &&
(s->config.geom.w > 0) &&
(s->config.geom.h > 0))
ext_screens++;
}
printf("RRR: =========================== deferred suspend.... %i %i\n", lids, ext_screens);
if ((lids > 0) && (ext_screens == 0))
{
if ((e_config->screensaver_suspend_on_ac) ||
(e_powersave_mode_get() > E_POWERSAVE_MODE_LOW))
{
printf("RRR: =========================== powermd low / suspend on ac");
e_sys_action_do(E_SYS_SUSPEND, NULL);
}
}
return EINA_FALSE;
}
static Eina_Bool
_cb_screen_change_delay(void *data EINA_UNUSED)
{
@ -642,6 +713,11 @@ _cb_screen_change_delay(void *data EINA_UNUSED)
// if we had a screen plug/unplug etc. event and we shouldnt ignore it...
if ((event_screen) && (!event_ignore))
{
Eina_List *l;
E_Randr2_Screen *s;
int lid_screens = 0;
int close_lid_screens = 0;
int external_screens = 0;
E_Randr2 *rtemp;
printf("RRR: reconfigure screens due to event...\n");
@ -658,12 +734,74 @@ _cb_screen_change_delay(void *data EINA_UNUSED)
change = EINA_TRUE;
}
}
EINA_LIST_FOREACH(rtemp->screens, l, s)
{
// if (!s->id) continue;
if (s->info.is_lid)
{
lid_screens++;
if (s->info.lid_closed) close_lid_screens++;
}
else
{
if ((s->info.connected) && (s->config.enabled))
external_screens++;
}
}
printf("RRR: lids=%i closed=%i ext=%i\n", lid_screens, close_lid_screens, external_screens);
_info_free(rtemp);
}
printf("RRR: change = %i\n", change);
// we plugged or unplugged some monitor - re-apply config so
// known screens can be configured
if (change) e_randr2_config_apply();
if (change)
{
if ((lid_screens > 0) && (close_lid_screens == lid_screens) &&
(external_screens == 0))
{
printf("RRR: skip change with all lids closed and no ext\n");
change = EINA_FALSE;
e_screensaver_now_set(EINA_TRUE);
e_screensaver_attrs_set
(1, e_config->screensaver_blanking,
e_config->screensaver_expose);
e_screensaver_update();
e_dpms_force_update();
e_screensaver_activate();
e_screensaver_eval(EINA_TRUE);
// force dpms...
}
if ((lid_screens > 0) && (close_lid_screens < lid_screens) &&
(external_screens == 0))
{
printf("RRR: skip change with lid screens open and no ext\n");
change = EINA_FALSE;
e_screensaver_now_set(EINA_FALSE);
e_screensaver_attrs_set
(e_config->screensaver_timeout,
e_config->screensaver_blanking,
e_config->screensaver_expose);
e_screensaver_update();
e_dpms_force_update();
e_screensaver_deactivate();
}
if (change)
e_randr2_config_apply();
}
if (change)
{
if ((lid_screens > 0) && (close_lid_screens == lid_screens) &&
(external_screens == 0))
{
printf("RRR: have all closed laptop screens and no external\n");
if ((e_config->screensaver_suspend_on_ac) ||
(e_powersave_mode_get() > E_POWERSAVE_MODE_LOW))
{
printf("RRR: we should try and suspend now because on ac or suspend on ac is on\n");
ecore_timer_add(1.0, _cb_deferred_suspend_screen_change, NULL);
}
}
}
}
// update screen info after the above apply or due to external changes
e_randr2_screeninfo_update();

View File

@ -31,6 +31,7 @@ static Eina_Bool _e_screensaver_inhibited = EINA_FALSE;
#endif
static Eina_Bool _screensaver_ignore = EINA_FALSE;
static Eina_Bool _screensaver_now = EINA_FALSE;
E_API int E_EVENT_SCREENSAVER_ON = -1;
E_API int E_EVENT_SCREENSAVER_OFF = -1;
@ -51,6 +52,7 @@ e_screensaver_timeout_get(Eina_Bool use_idle)
{
int timeout = 0, count = (1 + _e_screensaver_ask_presentation_count);
if (_screensaver_now) return 1;
if ((e_config->screensaver_enable) && (!e_config->mode.presentation))
{
if ((e_desklock_state_get()) &&
@ -138,8 +140,24 @@ e_screensaver_update(void)
if (e_comp->comp_type != E_PIXMAP_TYPE_WL)
{
if (changed)
{
// this toggling of dpms is a bug workaround in x that i found
// where if we change screensaver timeouts and force a manual
// wake of the screen e.g. on lid open/close we have to toggle
// it for x to stop thinking the monitor is off when it's
// actually on and this causes later dpms issues where the
// screen doesnt turn off at all because x thinks interanlly
// that the monitor is still off... so this is odd, but it's
// necessary on some hardware.
int enabled;
enabled = ((e_config->screensaver_enable) &&
(!e_config->mode.presentation));
ecore_x_dpms_enabled_set(!enabled);
ecore_x_dpms_enabled_set(enabled);
ecore_x_screensaver_set(timeout, interval, blanking, expose);
}
}
#endif
#ifdef HAVE_WAYLAND
if (changed && (e_comp->comp_type == E_PIXMAP_TYPE_WL))
@ -518,6 +536,12 @@ e_screensaver_deactivate(void)
#endif
}
E_API void
e_screensaver_now_set(Eina_Bool now)
{
_screensaver_now = now;
}
E_API void
e_screensaver_eval(Eina_Bool saver_on)
{
@ -529,6 +553,7 @@ e_screensaver_eval(Eina_Bool saver_on)
e_config->backlight.timer;
if (t < 1.0) t = 1.0;
if (_screensaver_now) t = 1.0;
E_FREE_FUNC(screensaver_idle_timer, ecore_timer_del);
if (!_screensaver_ignore)
{

View File

@ -19,6 +19,7 @@ E_API Eina_Bool e_screensaver_on_get(void);
E_API void e_screensaver_activate(void);
E_API void e_screensaver_deactivate(void);
E_API void e_screensaver_now_set(Eina_Bool now);
E_API void e_screensaver_eval(Eina_Bool saver_on);
E_API void e_screensaver_notidle(void);
E_API void e_screensaver_inhibit_toggle(Eina_Bool inhibit);

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_Timer *_e_sys_phantom_wake_check_timer = NULL;
static Ecore_Timer *_e_sys_resume_delay_timer = NULL;
static Eina_Bool _e_sys_suspended = EINA_FALSE;
static Ecore_Event_Handler *_e_sys_acpi_handler = NULL;
@ -254,6 +256,7 @@ _e_sys_comp_resume2(void *data EINA_UNUSED)
_e_sys_phantom_wake_check_timer =
ecore_timer_add(1.0, _e_sys_phantom_wake_check_cb, NULL);
}
printf("SSS: sys resume2 @ %1.8f\n", ecore_time_get());
return EINA_FALSE;
}
@ -284,6 +287,7 @@ _e_sys_comp_resume(void)
_e_sys_screensaver_unignore_timer =
ecore_timer_add(0.3, _e_sys_screensaver_unignore_delay, NULL);
ecore_timer_add(0.6, _e_sys_comp_resume2, NULL);
printf("SSS: sys resume @ %1.8f\n", ecore_time_get());
}
static void
@ -293,7 +297,7 @@ _e_sys_systemd_signal_prepare_shutdown(void *data EINA_UNUSED, const Eldbus_Mess
Eina_Bool b = EINA_FALSE;
if (!eldbus_message_arguments_get(msg, "b", &b)) return;
fprintf(stderr, "SSS: systemd said to prepare for shutdown! bool=%i @%1.8f\n", (int)b, ecore_time_get());
printf("SSS: systemd said to prepare for shutdown! bool=%i @%1.8f\n", (int)b, ecore_time_get());
}
static void
@ -305,12 +309,17 @@ _e_sys_systemd_signal_prepare_sleep(void *data EINA_UNUSED, const Eldbus_Message
if (!eldbus_message_arguments_get(msg, "b", &b)) return;
// b == 1 -> suspending
// b == 0 -> resuming
fprintf(stderr, "SSS: systemd said to prepare for sleep! bool=%i @%1.8f\n", (int)b, ecore_time_get());
printf("SSS: systemd said to prepare for sleep! bool=%i @%1.8f\n", (int)b, ecore_time_get());
if (b == EINA_FALSE)
{
if (_e_sys_suspended)
{
_e_sys_suspended = EINA_FALSE;
ecore_event_add(E_EVENT_SYS_RESUME, NULL, NULL, NULL);
_e_sys_comp_resume();
}
}
else _e_sys_suspended = EINA_TRUE;
}
/* externally accessible functions */
@ -347,12 +356,15 @@ e_sys_init(void)
EINTERN int
e_sys_shutdown(void)
{
if (_e_sys_resume_delay_timer)
ecore_timer_del(_e_sys_resume_delay_timer);
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_resume_delay_timer = NULL;
_e_sys_screensaver_unignore_timer = NULL;
_e_sys_acpi_handler = NULL;
_e_sys_exe_exit_handler = NULL;
@ -612,8 +624,13 @@ _e_sys_systemd_hibernate(void)
static Eina_Bool
_e_sys_resume_delay(void *d EINA_UNUSED)
{
_e_sys_resume_delay_timer = NULL;
if (_e_sys_suspended)
{
_e_sys_suspended = EINA_FALSE;
ecore_event_add(E_EVENT_SYS_RESUME, NULL, NULL, NULL);
_e_sys_comp_resume();
}
return EINA_FALSE;
}
@ -622,9 +639,13 @@ _e_sys_susp_hib_check_timer_cb(void *data EINA_UNUSED)
{
double t = ecore_time_unix_get();
printf("SSS: hib check @%1.8f (unix %1.8f, delt %1.8f)\n", ecore_time_get(), t, t - _e_sys_susp_hib_check_last_tick);
if ((t - _e_sys_susp_hib_check_last_tick) > 0.5)
{
_e_sys_susp_hib_check_timer = NULL;
if (_e_sys_resume_delay_timer)
ecore_timer_del(_e_sys_resume_delay_timer);
_e_sys_resume_delay_timer =
ecore_timer_add(0.2, _e_sys_resume_delay, NULL);
return EINA_FALSE;
}
@ -640,6 +661,7 @@ _e_sys_susp_hib_check(void)
_e_sys_susp_hib_check_last_tick = ecore_time_unix_get();
_e_sys_susp_hib_check_timer =
ecore_timer_loop_add(0.1, _e_sys_susp_hib_check_timer_cb, NULL);
printf("SSS: hib check begin @%1.8f (unix %1.8f)\n", ecore_time_get(), _e_sys_susp_hib_check_last_tick);
}
/* local subsystem functions */
@ -1163,17 +1185,18 @@ _e_sys_action_do(E_Sys_Action a, char *param EINA_UNUSED, Eina_Bool raw)
_e_sys_phantom_wake_check_timer = NULL;
if (raw)
{
_e_sys_suspended = EINA_TRUE;
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 (e_config->suspend_connected_standby == 0)
{
_e_sys_susp_hib_check();
if (systemd_works)
_e_sys_systemd_suspend();
else
{
_e_sys_susp_hib_check();
_e_sys_exe = ecore_exe_run(buf, NULL);
ret = 1;
}
@ -1223,7 +1246,7 @@ _e_sys_action_do(E_Sys_Action a, char *param EINA_UNUSED, Eina_Bool raw)
_e_sys_phantom_wake_check_timer = NULL;
if (raw)
{
_e_sys_susp_hib_check();
_e_sys_suspended = EINA_TRUE;
if (e_config->desklock_on_suspend)
// XXX: this desklock - ensure its instant
e_desklock_show(EINA_TRUE);
@ -1232,6 +1255,7 @@ _e_sys_action_do(E_Sys_Action a, char *param EINA_UNUSED, Eina_Bool raw)
_e_sys_systemd_hibernate();
else
{
_e_sys_susp_hib_check();
_e_sys_exe = ecore_exe_run(buf, NULL);
ret = 1;
}