From 3036ca03ab6a42973edefb665848a8a889085ff3 Mon Sep 17 00:00:00 2001 From: Bastien Dejean Date: Thu, 4 Oct 2018 18:50:55 +0200 Subject: [PATCH] Make suspending cancellable --- scripts/suspend.sh | 4 - src/app.rs | 162 ++++++++++++++++++++++++++++++----------- src/view/common.rs | 2 +- src/view/frontlight.rs | 2 +- src/view/home/mod.rs | 8 +- src/view/menu.rs | 2 +- src/view/mod.rs | 3 +- src/view/reader/mod.rs | 26 +++---- 8 files changed, 143 insertions(+), 66 deletions(-) diff --git a/scripts/suspend.sh b/scripts/suspend.sh index 4bb8fa8..9163848 100755 --- a/scripts/suspend.sh +++ b/scripts/suspend.sh @@ -1,9 +1,5 @@ #! /bin/sh -# Prevent false sleep state. -# https://github.com/koreader/koreader/commit/71afe3606ca777e4e01fcb3c9a5323cf08bdfc0c -sleep 15 - # De-activate the touch screen. echo 1 > /sys/power/state-extended diff --git a/src/app.rs b/src/app.rs index 9fc9b9f..dfde024 100644 --- a/src/app.rs +++ b/src/app.rs @@ -1,10 +1,10 @@ use std::thread; use std::fs::{self, File}; use std::path::{Path, PathBuf}; -use std::sync::mpsc; +use std::sync::mpsc::{self, Receiver, Sender}; use std::process::Command; use std::collections::VecDeque; -use std::time::{Instant, Duration}; +use std::time::Duration; use failure::{Error, ResultExt}; use fnv::FnvHashMap; use chrono::Local; @@ -16,7 +16,7 @@ use view::frontlight::FrontlightWindow; use view::menu::{Menu, MenuKind}; use input::{DeviceEvent, ButtonCode, ButtonStatus}; use input::{raw_events, device_events, usb_events}; -use gesture::{GestureEvent, gesture_events, BUTTON_HOLD_DELAY}; +use gesture::{GestureEvent, gesture_events}; use helpers::{load_json, save_json, load_toml, save_toml}; use metadata::{Metadata, METADATA_FILENAME, auto_import}; use settings::{Settings, SETTINGS_PATH}; @@ -35,6 +35,8 @@ pub const APP_NAME: &str = "Plato"; const CLOCK_REFRESH_INTERVAL: Duration = Duration::from_secs(60); const BATTERY_REFRESH_INTERVAL: Duration = Duration::from_secs(299); +const SUSPEND_WAIT_DELAY: Duration = Duration::from_secs(15); +const PREPARE_SUSPEND_WAIT_DELAY: Duration = Duration::from_secs(3); pub struct Context { pub settings: Settings, @@ -45,11 +47,10 @@ pub struct Context { pub battery: Box, pub lightsensor: Box, pub notification_index: u8, - pub resumed_at: Instant, pub inverted: bool, pub monochrome: bool, - pub suspended: bool, pub plugged: bool, + pub covered: bool, pub mounted: bool, } @@ -59,12 +60,22 @@ impl Context { frontlight: Box, lightsensor: Box) -> Context { Context { settings, metadata, filename, fonts, battery, frontlight, lightsensor, notification_index: 0, - resumed_at: Instant::now(), inverted: false, - monochrome: false, suspended: false, - plugged: false, mounted: false } + inverted: false, monochrome: false, plugged: false, + covered: false, mounted: false } } } +struct Task { + id: TaskId, + chan: Receiver<()>, +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +enum TaskId { + PrepareSuspend, + Suspend, +} + fn build_context() -> Result { let path = Path::new(SETTINGS_PATH); let settings = load_toml::(path); @@ -107,6 +118,44 @@ fn build_context() -> Result { fonts, battery, frontlight, lightsensor)) } +fn schedule_task(id: TaskId, event: Event, delay: Duration, hub: &Sender, tasks: &mut Vec) { + let (ty, ry) = mpsc::channel(); + let hub2 = hub.clone(); + tasks.push(Task { id, chan: ry }); + thread::spawn(move || { + thread::sleep(delay); + if ty.send(()).is_ok() { + hub2.send(event).unwrap(); + } + }); +} + +fn resume(id: TaskId, tasks: &mut Vec, view: &mut View, hub: &Sender, context: &mut Context) { + if id == TaskId::Suspend { + tasks.retain(|task| task.id != TaskId::Suspend); + if context.settings.frontlight { + let levels = context.settings.frontlight_levels; + context.frontlight.set_intensity(levels.intensity); + context.frontlight.set_warmth(levels.warmth); + } + if context.settings.wifi { + Command::new("scripts/wifi-enable.sh") + .spawn() + .ok(); + } + } + if id == TaskId::Suspend || id == TaskId::PrepareSuspend { + tasks.retain(|task| task.id != TaskId::PrepareSuspend); + if let Some(index) = locate::(view) { + let rect = *view.child(index).rect(); + view.children_mut().remove(index); + hub.send(Event::Expose(rect, UpdateMode::Full)).unwrap(); + } + hub.send(Event::ClockTick).unwrap(); + hub.send(Event::BatteryTick).unwrap(); + } +} + pub fn run() -> Result<(), Error> { let mut context = build_context().context("Can't build context.")?; let mut fb = KoboFramebuffer::new("/dev/fb0").context("Can't create framebuffer.")?; @@ -165,6 +214,7 @@ pub fn run() -> Result<(), Error> { context.frontlight.set_intensity(0.0); } + let mut tasks: Vec = Vec::new(); let mut history: Vec> = Vec::new(); let mut view: Box = Box::new(Home::new(fb_rect, &tx, &mut context)?); @@ -181,18 +231,50 @@ pub fn run() -> Result<(), Error> { match evt { Event::Device(de) => { match de { - DeviceEvent::Button { code: ButtonCode::Power, status: ButtonStatus::Released, .. } | + DeviceEvent::Button { code: ButtonCode::Power, status: ButtonStatus::Released, .. } => { + if context.mounted || context.covered { + continue; + } + + if tasks.iter().any(|task| task.id == TaskId::PrepareSuspend) { + resume(TaskId::PrepareSuspend, &mut tasks, view.as_mut(), &tx, &mut context); + } else if tasks.iter().any(|task| task.id == TaskId::Suspend) { + resume(TaskId::Suspend, &mut tasks, view.as_mut(), &tx, &mut context); + } else { + let interm = Intermission::new(fb_rect, "Sleeping".to_string(), false); + tx.send(Event::Render(*interm.rect(), UpdateMode::Full)).unwrap(); + schedule_task(TaskId::PrepareSuspend, Event::PrepareSuspend, + PREPARE_SUSPEND_WAIT_DELAY, &tx, &mut tasks); + view.children_mut().push(Box::new(interm) as Box); + } + }, DeviceEvent::CoverOn => { - if context.mounted || context.suspended || - context.resumed_at.elapsed() <= BUTTON_HOLD_DELAY { + context.covered = true; + + if context.mounted || tasks.iter().any(|task| task.id == TaskId::PrepareSuspend || + task.id == TaskId::Suspend) { continue; } let interm = Intermission::new(fb_rect, "Sleeping".to_string(), false); - tx.send(Event::Render(*interm.rect(), UpdateMode::Gui)).unwrap(); - tx.send(Event::Suspend).unwrap(); + tx.send(Event::Render(*interm.rect(), UpdateMode::Full)).unwrap(); + schedule_task(TaskId::PrepareSuspend, Event::PrepareSuspend, + PREPARE_SUSPEND_WAIT_DELAY, &tx, &mut tasks); view.children_mut().push(Box::new(interm) as Box); }, + DeviceEvent::CoverOff => { + context.covered = false; + + if context.mounted { + continue; + } + + if tasks.iter().any(|task| task.id == TaskId::PrepareSuspend) { + resume(TaskId::PrepareSuspend, &mut tasks, view.as_mut(), &tx, &mut context); + } else if tasks.iter().any(|task| task.id == TaskId::Suspend) { + resume(TaskId::Suspend, &mut tasks, view.as_mut(), &tx, &mut context); + } + }, DeviceEvent::NetUp => { let ip = Command::new("scripts/ip.sh").output() .map(|o| String::from_utf8_lossy(&o.stdout).trim_right().to_string()) @@ -213,6 +295,17 @@ pub fn run() -> Result<(), Error> { } context.plugged = true; + + if context.covered { + continue; + } + + if tasks.iter().any(|task| task.id == TaskId::PrepareSuspend) { + resume(TaskId::PrepareSuspend, &mut tasks, view.as_mut(), &tx, &mut context); + } else if tasks.iter().any(|task| task.id == TaskId::Suspend) { + resume(TaskId::Suspend, &mut tasks, view.as_mut(), &tx, &mut context); + } + let confirm = Confirmation::new(ViewId::ConfirmMount, Event::Mount, "Mount onboard and external cards?".to_string(), @@ -227,8 +320,8 @@ pub fn run() -> Result<(), Error> { } if context.mounted { - Command::new("scripts/usb-disable.sh").status().ok(); context.mounted = false; + Command::new("scripts/usb-disable.sh").status().ok(); let path = Path::new(SETTINGS_PATH); if let Ok(settings) = load_toml::(path) .map_err(|e| eprintln!("Can't load settings: {}", e)) { @@ -247,7 +340,7 @@ pub fn run() -> Result<(), Error> { if let Some(index) = locate::(view.as_ref()) { let rect = *view.child(index).rect(); view.children_mut().remove(index); - tx.send(Event::Expose(rect)).unwrap(); + tx.send(Event::Expose(rect, UpdateMode::Full)).unwrap(); } if Path::new("/mnt/onboard/.kobo/KoboRoot.tgz").exists() { tx.send(Event::Select(EntryId::Reboot)).unwrap(); @@ -278,8 +371,8 @@ pub fn run() -> Result<(), Error> { } } }, - Event::Suspend => { - context.suspended = true; + Event::PrepareSuspend => { + tasks.retain(|task| task.id != TaskId::PrepareSuspend); updating.retain(|tok, _| fb.wait(*tok).is_err()); let path = Path::new(SETTINGS_PATH); save_toml(&context.settings, path).map_err(|e| eprintln!("Can't save settings: {}", e)).ok(); @@ -295,36 +388,23 @@ pub fn run() -> Result<(), Error> { .status() .ok(); } + // https://github.com/koreader/koreader/commit/71afe36 + schedule_task(TaskId::Suspend, Event::Suspend, + SUSPEND_WAIT_DELAY, &tx, &mut tasks); + }, + Event::Suspend => { println!("{}", Local::now().format("Went to sleep on %B %d, %Y at %H:%M.")); Command::new("scripts/suspend.sh") .status() .ok(); println!("{}", Local::now().format("Woke up on %B %d, %Y at %H:%M.")); - context.resumed_at = Instant::now(); - if let Some(index) = locate::(view.as_ref()) { - let rect = *view.child(index).rect(); - view.children_mut().remove(index); - tx.send(Event::Expose(rect)).unwrap(); - } - context.suspended = false; Command::new("scripts/resume.sh") .status() .ok(); - if context.settings.wifi { - Command::new("scripts/wifi-enable.sh") - .spawn() - .ok(); - } - if context.settings.frontlight { - let levels = context.settings.frontlight_levels; - context.frontlight.set_intensity(levels.intensity); - context.frontlight.set_warmth(levels.warmth); - } - tx.send(Event::ClockTick).unwrap(); - tx.send(Event::BatteryTick).unwrap(); }, Event::Mount => { if !context.mounted { + tasks.clear(); while let Some(v) = history.pop() { view.handle_event(&Event::Back, &tx, &mut bus, &mut context); view = v; @@ -389,9 +469,9 @@ pub fn run() -> Result<(), Error> { updating.insert(tok, rect); } }, - Event::Expose(mut rect) => { + Event::Expose(mut rect, mode) => { fill_crack(view.as_ref(), &mut rect, &mut fb, &mut context.fonts, &mut updating); - if let Ok(tok) = fb.update(&rect, UpdateMode::Gui) { + if let Ok(tok) = fb.update(&rect, mode) { updating.insert(tok, rect); } }, @@ -419,7 +499,7 @@ pub fn run() -> Result<(), Error> { if let Some(index) = locate_by_id(view.as_ref(), ViewId::PresetMenu) { let rect = *view.child(index).rect(); view.children_mut().remove(index); - tx.send(Event::Expose(rect)).unwrap(); + tx.send(Event::Expose(rect, UpdateMode::Gui)).unwrap(); } else { let preset_menu = Menu::new(rect, ViewId::PresetMenu, MenuKind::Contextual, vec![EntryKind::Command("Remove".to_string(), @@ -441,13 +521,13 @@ pub fn run() -> Result<(), Error> { if let Some(index) = locate::(view.as_ref()) { let rect = *view.child(index).rect(); view.children_mut().remove(index); - tx.send(Event::Expose(rect)).unwrap(); + tx.send(Event::Expose(rect, UpdateMode::Gui)).unwrap(); } }, Event::Close(id) => { if let Some(index) = locate_by_id(view.as_ref(), id) { let rect = overlapping_rectangle(view.child(index)); - tx.send(Event::Expose(rect)).unwrap(); + tx.send(Event::Expose(rect, UpdateMode::Gui)).unwrap(); view.children_mut().remove(index); } }, diff --git a/src/view/common.rs b/src/view/common.rs index e466d3f..613ca3a 100644 --- a/src/view/common.rs +++ b/src/view/common.rs @@ -40,7 +40,7 @@ pub fn toggle_main_menu(view: &mut View, rect: Rectangle, enable: Option, if let Some(true) = enable { return; } - hub.send(Event::Expose(*view.child(index).rect())).unwrap(); + hub.send(Event::Expose(*view.child(index).rect(), UpdateMode::Gui)).unwrap(); view.children_mut().remove(index); } else { if let Some(false) = enable { diff --git a/src/view/frontlight.rs b/src/view/frontlight.rs index e836fe3..3b558c1 100644 --- a/src/view/frontlight.rs +++ b/src/view/frontlight.rs @@ -195,7 +195,7 @@ impl FrontlightWindow { hub.send(Event::Render(self.rect, UpdateMode::Gui)).unwrap(); } else { self.children.pop(); - hub.send(Event::Expose(self.rect)).unwrap(); + hub.send(Event::Expose(self.rect, UpdateMode::Gui)).unwrap(); shift(self, pt!(0, small_height as i32 / 2)); self.rect.max.y -= small_height as i32; } diff --git a/src/view/home/mod.rs b/src/view/home/mod.rs index e3a4a9c..56e60cd 100644 --- a/src/view/home/mod.rs +++ b/src/view/home/mod.rs @@ -585,7 +585,7 @@ impl Home { if let Some(true) = enable { return; } - hub.send(Event::Expose(*self.child(index).rect())).unwrap(); + hub.send(Event::Expose(*self.child(index).rect(), UpdateMode::Gui)).unwrap(); self.children.remove(index); if let Some(ViewId::GoToPageInput) = self.focus { self.toggle_keyboard(false, true, Some(ViewId::GoToPageInput), hub, fonts); @@ -608,7 +608,7 @@ impl Home { if let Some(true) = enable { return; } - hub.send(Event::Expose(*self.child(index).rect())).unwrap(); + hub.send(Event::Expose(*self.child(index).rect(), UpdateMode::Gui)).unwrap(); self.children.remove(index); } else { if let Some(false) = enable { @@ -652,7 +652,7 @@ impl Home { if let Some(true) = enable { return; } - hub.send(Event::Expose(*self.child(index).rect())).unwrap(); + hub.send(Event::Expose(*self.child(index).rect(), UpdateMode::Gui)).unwrap(); self.children.remove(index); } else { if let Some(false) = enable { @@ -691,7 +691,7 @@ impl Home { return; } - hub.send(Event::Expose(*self.child(index).rect())).unwrap(); + hub.send(Event::Expose(*self.child(index).rect(), UpdateMode::Gui)).unwrap(); self.children.remove(index); } else { if let Some(false) = enable { diff --git a/src/view/menu.rs b/src/view/menu.rs index 0bff4ef..82f83f1 100644 --- a/src/view/menu.rs +++ b/src/view/menu.rs @@ -272,7 +272,7 @@ impl View for Menu { }, Event::CloseSub(id) => { if let Some(index) = locate_by_id(self, id) { - hub.send(Event::Expose(*self.children[index].rect())).unwrap(); + hub.send(Event::Expose(*self.children[index].rect(), UpdateMode::Gui)).unwrap(); self.children.remove(index); } true diff --git a/src/view/mod.rs b/src/view/mod.rs index 8f6039b..fa596b4 100644 --- a/src/view/mod.rs +++ b/src/view/mod.rs @@ -190,7 +190,7 @@ pub fn fill_crack(view: &View, rect: &mut Rectangle, fb: &mut Framebuffer, fonts pub enum Event { Render(Rectangle, UpdateMode), RenderNoWait(Rectangle, UpdateMode), - Expose(Rectangle), + Expose(Rectangle, UpdateMode), Device(DeviceEvent), Gesture(GestureEvent), Keyboard(KeyboardEvent), @@ -233,6 +233,7 @@ pub enum Event { LoadPreset(usize), Save, Guess, + PrepareSuspend, Suspend, Mount, Validate, diff --git a/src/view/reader/mod.rs b/src/view/reader/mod.rs index 4bf52b1..26ec013 100644 --- a/src/view/reader/mod.rs +++ b/src/view/reader/mod.rs @@ -557,7 +557,7 @@ impl Reader { rect.absorb(self.child(index+1).rect()); } - hub.send(Event::Expose(rect)).unwrap(); + hub.send(Event::Expose(rect, UpdateMode::Gui)).unwrap(); if index == 1 { self.children.drain(index - 1 .. index + 2); @@ -640,7 +640,7 @@ impl Reader { let mut rect = *self.child(index).rect(); rect.absorb(self.child(index - 1).rect()); self.children.drain(index - 1 .. index + 1); - hub.send(Event::Expose(rect)).unwrap(); + hub.send(Event::Expose(rect, UpdateMode::Gui)).unwrap(); } else { if !enable { return; @@ -678,7 +678,7 @@ impl Reader { let mut rect = *self.child(index).rect(); rect.absorb(self.child(index - 1).rect()); self.children.drain(index - 1 .. index + 1); - hub.send(Event::Expose(rect)).unwrap(); + hub.send(Event::Expose(rect, UpdateMode::Gui)).unwrap(); } else { if !enable { return; @@ -717,7 +717,7 @@ impl Reader { self.children.drain(top_index..bottom_index+1); self.focus = None; hub.send(Event::Focus(None)).unwrap(); - hub.send(Event::Expose(self.rect)).unwrap(); + hub.send(Event::Expose(self.rect, UpdateMode::Gui)).unwrap(); } } else { if let Some(false) = enable { @@ -843,7 +843,7 @@ impl Reader { return; } - hub.send(Event::Expose(*self.child(index).rect())).unwrap(); + hub.send(Event::Expose(*self.child(index).rect(), UpdateMode::Gui)).unwrap(); self.children.remove(index); if self.focus.map(|focus_id| focus_id == input_id).unwrap_or(false) { @@ -870,7 +870,7 @@ impl Reader { return; } - hub.send(Event::Expose(*self.child(index).rect())).unwrap(); + hub.send(Event::Expose(*self.child(index).rect(), UpdateMode::Gui)).unwrap(); self.children.remove(index); } else { if let Some(false) = enable { @@ -897,7 +897,7 @@ impl Reader { return; } - hub.send(Event::Expose(*self.child(index).rect())).unwrap(); + hub.send(Event::Expose(*self.child(index).rect(), UpdateMode::Gui)).unwrap(); self.children.remove(index); } else { if let Some(false) = enable { @@ -925,7 +925,7 @@ impl Reader { return; } - hub.send(Event::Expose(*self.child(index).rect())).unwrap(); + hub.send(Event::Expose(*self.child(index).rect(), UpdateMode::Gui)).unwrap(); self.children.remove(index); } else { if let Some(false) = enable { @@ -953,7 +953,7 @@ impl Reader { return; } - hub.send(Event::Expose(*self.child(index).rect())).unwrap(); + hub.send(Event::Expose(*self.child(index).rect(), UpdateMode::Gui)).unwrap(); self.children.remove(index); } else { if let Some(false) = enable { @@ -978,7 +978,7 @@ impl Reader { return; } - hub.send(Event::Expose(*self.child(index).rect())).unwrap(); + hub.send(Event::Expose(*self.child(index).rect(), UpdateMode::Gui)).unwrap(); self.children.remove(index); } else { if let Some(false) = enable { @@ -1003,7 +1003,7 @@ impl Reader { return; } - hub.send(Event::Expose(*self.child(index).rect())).unwrap(); + hub.send(Event::Expose(*self.child(index).rect(), UpdateMode::Gui)).unwrap(); self.children.remove(index); } else { if let Some(false) = enable { @@ -1042,7 +1042,7 @@ impl Reader { return; } - hub.send(Event::Expose(*self.child(index).rect())).unwrap(); + hub.send(Event::Expose(*self.child(index).rect(), UpdateMode::Gui)).unwrap(); self.children.remove(index); } else { if let Some(false) = enable { @@ -1118,7 +1118,7 @@ impl Reader { return; } - hub.send(Event::Expose(*self.child(index).rect())).unwrap(); + hub.send(Event::Expose(*self.child(index).rect(), UpdateMode::Gui)).unwrap(); self.children.remove(index); } else { if !enable { -- 2.51.2