Merge branch 'saver' into 'master'

popover: Deactivate settings button when lock screen is on

See merge request World/Phosh/squeekboard!582
This commit is contained in:
dcz
2023-01-02 12:21:23 +00:00
13 changed files with 208 additions and 33 deletions

View File

@ -1,5 +1,6 @@
# Dependencies which change based on build flags # Dependencies and tools which change based on build flags
# For the newer-than-Byzantium config # For the newer-than-Byzantium config
bitflags = "1.3.*" bitflags = "1.3.*"
clap = { version = "3.2.*", features=["std"], default-features = false } clap = { version = "3.2.*", features=["std"], default-features = false }
zbus = "1.9.*" zbus = "1.9.*"

View File

@ -23,6 +23,7 @@ path = "@path@/examples/find_orphan_layouts.rs"
[features] [features]
glib_v0_14 = [] glib_v0_14 = []
zbus_v1_5 = []
# Dependencies which don't change based on build flags # Dependencies which don't change based on build flags
[dependencies] [dependencies]

View File

@ -99,7 +99,7 @@ cargo_toml_base = configure_file(
cargo_patch = [] cargo_patch = []
if get_option('newer') == true if get_option('newer') == true
cargo_build_flags += ['--features', 'glib_v0_14'] cargo_build_flags += ['--features', 'glib_v0_14,zbus_v1_5']
cargo_deps = files('Cargo.deps.newer') cargo_deps = files('Cargo.deps.newer')
cargo_lock = files('Cargo.lock.newer') cargo_lock = files('Cargo.lock.newer')
else else

View File

@ -3,12 +3,13 @@
* *
* SPDX-License-Identifier: GPL-3.0-or-later * SPDX-License-Identifier: GPL-3.0-or-later
*/ */
use std::thread;
use zbus::{Connection, ObjectServer, dbus_interface, fdo};
use crate::main; use crate::main;
use crate::state; use crate::state;
use std::thread;
use zbus::{Connection, ObjectServer, dbus_interface, fdo};
use super::Void;
use std::convert::TryInto; use std::convert::TryInto;
@ -37,7 +38,7 @@ impl Manager {
} }
} }
fn start(mgr: Manager) -> Result<(), Box<dyn std::error::Error>> { fn start(mgr: Manager) -> Result<Void, Box<dyn std::error::Error>> {
let connection = Connection::new_session()?; let connection = Connection::new_session()?;
fdo::DBusProxy::new(&connection)?.request_name( fdo::DBusProxy::new(&connection)?.request_name(
"sm.puri.SqueekDebug", "sm.puri.SqueekDebug",

14
src/actors/external/mod.rs vendored Normal file
View File

@ -0,0 +1,14 @@
/*
* Copyright (C) 2022 Purism SPC
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
/*! Contains actors with custom event loops, not based off of the event_loop module. */
pub mod debug;
#[cfg(feature = "zbus_v1_5")]
pub mod screensaver;
/// The uninhabited type. Cannot be created or returned; means "will never return" as return type. Useful for infinite loops.
enum Void {}

57
src/actors/external/screensaver.rs vendored Normal file
View File

@ -0,0 +1,57 @@
/*
* Copyright (C) 2022 Purism SPC
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
use crate::actors::Destination;
use crate::actors::popover;
use crate::logging;
use std::thread;
use zbus::{Connection, dbus_proxy};
use super::Void;
#[dbus_proxy(
interface = "org.freedesktop.ScreenSaver",
default_service = "org.freedesktop.ScreenSaver",
default_path = "/org/freedesktop/ScreenSaver"
)]
pub trait Manager {
#[dbus_proxy(signal)]
fn active_changed(&self, active: bool) -> fdo::Result<()>;
}
/// Listens to screensaver (screen lock) changes
pub fn init(destination: popover::Destination) {
thread::spawn(move || {
if let Err(e) = start(destination) {
log_print!(
logging::Level::Surprise,
"Could not track screensaver status, giving up: {:?}",
e,
);
}
});
}
fn start(destination: popover::Destination) -> Result<Void, zbus::Error> {
let conn = Connection::new_session()?;
let manager = ManagerProxy::new(&conn)?;
manager.connect_active_changed(move |m| {
destination.send(popover::Event::ScreensaverActive(m));
Ok(())
})?;
loop {
match manager.next_signal() {
Ok(None) => {}
other => log_print!(
logging::Level::Bug,
"Encountered unhandled event: {:?}",
other,
),
}
}
}

View File

@ -20,4 +20,14 @@ and by receiving updates from it.
// Panel contains state and logic to protect the main state from getting flooded // Panel contains state and logic to protect the main state from getting flooded
// with low-level wayland and gtk sizing events. // with low-level wayland and gtk sizing events.
pub mod popover; pub mod external;
pub mod popover;
/// The implementing actor is able to receive and handle messages.
/// Typically, it's the sending end of the channel,
/// whose other end is inside an event loop.
// TODO: implement for remaning actors and make the event loop refer to this.
pub trait Destination {
type Event;
fn send(&self, event: Self::Event);
}

View File

@ -11,30 +11,66 @@ but it cannot get the user-selected overlay, because it's stored in state.
To solve this, overlay will be cached in the popover actor, To solve this, overlay will be cached in the popover actor,
and updated by main state every time it changes. and updated by main state every time it changes.
*/ */
use crate::logging;
use std::borrow::BorrowMut;
use std::sync::{Arc, Mutex};
pub mod c { pub mod c {
use super::*; use super::*;
use crate::util::c::Wrapped; use crate::util::c::ArcWrapped;
/// The mutable instance of state /// The mutable instance of state.
pub type Actor = Wrapped<State>; /// Thread-safe because this actor does not get its own event loop,
/// and therefore can't have a channel to receive messages,
/// so instead messages will be passed directly to the mutexed actor.
pub type Actor = ArcWrapped<State>;
} }
#[derive(Clone)] pub type Destination = Arc<Mutex<State>>;
pub struct State {
pub overlay: Option<String>, #[derive(Debug)]
pub enum Event {
Overlay(Option<String>),
ScreensaverActive(bool),
} }
impl State { impl super::Destination for Destination {
pub fn new() -> Self { type Event = Event;
Self { overlay: None } fn send(&self, event: Self::Event) {
let actor = self.lock();
match actor {
Ok(mut actor) => {
let actor = actor.borrow_mut();
**actor = actor.clone().handle_event(event);
},
Err(e) => log_print!(
logging::Level::Bug,
"Cannot lock popover state: {:?}",
e,
),
}
} }
} }
pub fn set_overlay( #[derive(Clone, Debug)]
actor: &c::Actor, pub struct State {
overlay: Option<String>, pub overlay: Option<String>,
) { /// Settings button active
let actor = actor.clone_ref(); pub settings_active: bool,
let mut actor = actor.borrow_mut(); }
actor.overlay = overlay;
} impl State {
pub fn new(settings_active: bool) -> Self {
Self {
overlay: None,
settings_active,
}
}
fn handle_event(mut self, event: Event) -> Self {
match event {
Event::Overlay(overlay) => { self.overlay = overlay; },
Event::ScreensaverActive(lock_active) => { self.settings_active = !lock_active; },
};
self
}
}

View File

@ -23,10 +23,9 @@ mod assert_matches;
mod logging; mod logging;
mod action; mod action;
mod actors; pub mod actors;
mod animation; mod animation;
pub mod data; pub mod data;
mod debug;
mod drawing; mod drawing;
mod event_loop; mod event_loop;
pub mod float_ord; pub mod float_ord;

View File

@ -4,8 +4,8 @@
/*! Glue for the main loop. */ /*! Glue for the main loop. */
use crate::actors; use crate::actors;
use crate::actors::external::debug;
use crate::animation; use crate::animation;
use crate::debug;
use crate::data::loading; use crate::data::loading;
use crate::event_loop; use crate::event_loop;
use crate::panel; use crate::panel;
@ -21,6 +21,8 @@ mod c {
use std::rc::Rc; use std::rc::Rc;
use std::time::Instant; use std::time::Instant;
use crate::actors::Destination;
use crate::actors::popover;
use crate::event_loop::driver; use crate::event_loop::driver;
use crate::imservice::IMService; use crate::imservice::IMService;
use crate::imservice::c::InputMethod; use crate::imservice::c::InputMethod;
@ -28,7 +30,7 @@ mod c {
use crate::outputs::Outputs; use crate::outputs::Outputs;
use crate::state; use crate::state;
use crate::submission::Submission; use crate::submission::Submission;
use crate::util::c::Wrapped; use crate::util::c::{ArcWrapped, Wrapped};
use crate::vkeyboard::c::ZwpVirtualKeyboardV1; use crate::vkeyboard::c::ZwpVirtualKeyboardV1;
/// DbusHandler* /// DbusHandler*
@ -121,12 +123,17 @@ mod c {
}; };
let submission = Submission::new(vk, imservice); let submission = Submission::new(vk, imservice);
let popover = ArcWrapped::new(actors::popover::State::new(true));
#[cfg(feature = "zbus_v1_5")]
crate::actors::external::screensaver::init(popover.clone_ref());
RsObjects { RsObjects {
submission: Wrapped::new(submission), submission: Wrapped::new(submission),
state_manager: Wrapped::new(state_manager), state_manager: Wrapped::new(state_manager),
receiver: Wrapped::new(receiver), receiver: Wrapped::new(receiver),
wayland: Box::into_raw(wayland), wayland: Box::into_raw(wayland),
popover: Wrapped::new(actors::popover::State::new()), popover,
} }
} }
@ -152,7 +159,7 @@ mod c {
main_loop_handle_message( main_loop_handle_message(
msg, msg,
panel_manager.clone(), panel_manager.clone(),
&popover, &popover.clone_ref(),
hint_manager, hint_manager,
dbus_handler, dbus_handler,
); );
@ -170,7 +177,7 @@ mod c {
fn main_loop_handle_message( fn main_loop_handle_message(
msg: Commands, msg: Commands,
panel_manager: Wrapped<panel::Manager>, panel_manager: Wrapped<panel::Manager>,
popover: &actors::popover::c::Actor, popover: &actors::popover::Destination,
hint_manager: HintManager, hint_manager: HintManager,
dbus_handler: *const DBusHandler, dbus_handler: *const DBusHandler,
) { ) {
@ -191,7 +198,7 @@ mod c {
overlay_name, overlay_name,
purpose, purpose,
} = description; } = description;
actors::popover::set_overlay(popover, overlay_name.clone()); popover.send(popover::Event::Overlay(overlay_name.clone()));
let layout = loading::load_layout(&name, kind, purpose, &overlay_name); let layout = loading::load_layout(&name, kind, purpose, &overlay_name);
let layout = Box::into_raw(Box::new(layout)); let layout = Box::into_raw(Box::new(layout));
// CSS can't express "+" in the class // CSS can't express "+" in the class

View File

@ -364,6 +364,7 @@ pub fn show(
}; };
let settings_action = gio::SimpleAction::new("settings", None); let settings_action = gio::SimpleAction::new("settings", None);
settings_action.set_enabled(popover.settings_active);
settings_action.connect_activate(move |_, _| { settings_action.connect_activate(move |_, _| {
let s = CString::new("region").unwrap(); let s = CString::new("region").unwrap();
unsafe { c::popover_open_settings_panel(s.as_ptr()) }; unsafe { c::popover_open_settings_panel(s.as_ptr()) };

View File

@ -5,8 +5,8 @@
/*! Application-wide state is stored here. /*! Application-wide state is stored here.
* It's driven by the loop defined in the loop module. */ * It's driven by the loop defined in the loop module. */
use crate::actors::external::debug;
use crate::animation; use crate::animation;
use crate::debug;
use crate::event_loop; use crate::event_loop;
use crate::event_loop::ActorState; use crate::event_loop::ActorState;
use crate::imservice::{ ContentHint, ContentPurpose }; use crate::imservice::{ ContentHint, ContentPurpose };

View File

@ -15,6 +15,7 @@ pub mod c {
use std::os::raw::c_char; use std::os::raw::c_char;
use std::rc::Rc; use std::rc::Rc;
use std::str::Utf8Error; use std::str::Utf8Error;
use std::sync::{Arc, Mutex};
// traits // traits
@ -128,6 +129,53 @@ pub mod c {
} }
impl<T> COpaquePtr for Wrapped<T> {} impl<T> COpaquePtr for Wrapped<T> {}
/// Similar to Wrapped, except thread-safe.
#[repr(transparent)]
pub struct ArcWrapped<T>(*const Mutex<T>);
impl<T> ArcWrapped<T> {
pub fn new(value: T) -> Self {
Self::wrap(Arc::new(Mutex::new(value)))
}
pub fn wrap(state: Arc<Mutex<T>>) -> Self {
Self(Arc::into_raw(state))
}
/// Extracts the reference to the data.
/// It may cause problems if attempted in more than one place
pub unsafe fn unwrap(self) -> Arc<Mutex<T>> {
Arc::from_raw(self.0)
}
/// Creates a new Rc reference to the same data.
/// Use for accessing the underlying data as a reference.
pub fn clone_ref(&self) -> Arc<Mutex<T>> {
// A bit dangerous: the Rc may be in use elsewhere
let used_rc = unsafe { Arc::from_raw(self.0) };
let rc = used_rc.clone();
Arc::into_raw(used_rc); // prevent dropping the original reference
rc
}
}
impl<T> Clone for ArcWrapped<T> {
fn clone(&self) -> Self {
Self::wrap(self.clone_ref())
}
}
/// ToOwned won't work here
impl<T: Clone> CloneOwned for ArcWrapped<T> {
type Owned = T;
fn clone_owned(&self) -> T {
let rc = self.clone_ref();
// FIXME: this panic here is inelegant.
// It will only happen in case of crashes elsewhere, but still.
let r = rc.lock().unwrap();
r.to_owned()
}
}
} }
/// Clones the underlying data structure, like ToOwned. /// Clones the underlying data structure, like ToOwned.