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
bitflags = "1.3.*"
clap = { version = "3.2.*", features=["std"], default-features = false }
zbus = "1.9.*"

View File

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

View File

@ -99,7 +99,7 @@ cargo_toml_base = configure_file(
cargo_patch = []
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_lock = files('Cargo.lock.newer')
else

View File

@ -3,12 +3,13 @@
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
use std::thread;
use zbus::{Connection, ObjectServer, dbus_interface, fdo};
use crate::main;
use crate::state;
use std::thread;
use zbus::{Connection, ObjectServer, dbus_interface, fdo};
use super::Void;
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()?;
fdo::DBusProxy::new(&connection)?.request_name(
"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
// with low-level wayland and gtk sizing events.
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,
and updated by main state every time it changes.
*/
use crate::logging;
use std::borrow::BorrowMut;
use std::sync::{Arc, Mutex};
pub mod c {
use super::*;
use crate::util::c::Wrapped;
/// The mutable instance of state
pub type Actor = Wrapped<State>;
use crate::util::c::ArcWrapped;
/// The mutable instance of 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 struct State {
pub overlay: Option<String>,
pub type Destination = Arc<Mutex<State>>;
#[derive(Debug)]
pub enum Event {
Overlay(Option<String>),
ScreensaverActive(bool),
}
impl State {
pub fn new() -> Self {
Self { overlay: None }
impl super::Destination for Destination {
type Event = Event;
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(
actor: &c::Actor,
overlay: Option<String>,
) {
let actor = actor.clone_ref();
let mut actor = actor.borrow_mut();
actor.overlay = overlay;
#[derive(Clone, Debug)]
pub struct State {
pub overlay: Option<String>,
/// Settings button active
pub settings_active: bool,
}
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 action;
mod actors;
pub mod actors;
mod animation;
pub mod data;
mod debug;
mod drawing;
mod event_loop;
pub mod float_ord;

View File

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

View File

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

View File

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

View File

@ -15,6 +15,7 @@ pub mod c {
use std::os::raw::c_char;
use std::rc::Rc;
use std::str::Utf8Error;
use std::sync::{Arc, Mutex};
// traits
@ -128,6 +129,53 @@ pub mod c {
}
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.