From 5a1e9a995ca691139405b6a9bc2edc6ec427fe54 Mon Sep 17 00:00:00 2001 From: "Carsten Haitzler (Rasterman)" Date: Tue, 15 May 2018 15:40:00 +0900 Subject: [PATCH] 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 --- src/bin/e_acpi.c | 2 +- src/bin/e_actions.c | 2 - src/bin/e_randr2.c | 148 ++++++++++++++++++++++++++++++++++++++-- src/bin/e_screensaver.c | 27 +++++++- src/bin/e_screensaver.h | 1 + src/bin/e_sys.c | 42 +++++++++--- 6 files changed, 204 insertions(+), 18 deletions(-) diff --git a/src/bin/e_acpi.c b/src/bin/e_acpi.c index fff5b7fb0..e8e5fcfa2 100644 --- a/src/bin/e_acpi.c +++ b/src/bin/e_acpi.c @@ -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); diff --git a/src/bin/e_actions.c b/src/bin/e_actions.c index 2913cc36d..1e3f525f1 100644 --- a/src/bin/e_actions.c +++ b/src/bin/e_actions.c @@ -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; } diff --git a/src/bin/e_randr2.c b/src/bin/e_randr2.c index fc0375a8c..c90b2fa6e 100644 --- a/src/bin/e_randr2.c +++ b/src/bin/e_randr2.c @@ -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(); diff --git a/src/bin/e_screensaver.c b/src/bin/e_screensaver.c index 89bca5e28..da0ea2d3a 100644 --- a/src/bin/e_screensaver.c +++ b/src/bin/e_screensaver.c @@ -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,7 +140,23 @@ e_screensaver_update(void) if (e_comp->comp_type != E_PIXMAP_TYPE_WL) { if (changed) - ecore_x_screensaver_set(timeout, interval, blanking, expose); + { + // 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 @@ -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) { diff --git a/src/bin/e_screensaver.h b/src/bin/e_screensaver.h index 9c26afc98..5b1cd6187 100644 --- a/src/bin/e_screensaver.h +++ b/src/bin/e_screensaver.h @@ -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); diff --git a/src/bin/e_sys.c b/src/bin/e_sys.c index 6781a9b5a..5dc7754cc 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_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) { - ecore_event_add(E_EVENT_SYS_RESUME, NULL, NULL, NULL); - _e_sys_comp_resume(); + 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) { - ecore_event_add(E_EVENT_SYS_RESUME, NULL, NULL, NULL); - _e_sys_comp_resume(); + _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,10 +639,14 @@ _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; - ecore_timer_add(0.2, _e_sys_resume_delay, 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; } _e_sys_susp_hib_check_last_tick = t; @@ -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; }