add dbus osk and session support

The D-Bus interfaces used by Phosh are org.gnome.SessionManager for
recovering critical services from crashes and sm.puri.OSK0 for manual
on-screen keyboard activation. Add support for them.
This commit is contained in:
Richard Acayan 2024-07-24 22:39:16 -04:00
parent 397323b582
commit 4fd0c82997
6 changed files with 283 additions and 30 deletions

7
src/dbus/mod.rs Normal file
View file

@ -0,0 +1,7 @@
// SPDX-License-Identifier: GPL-3.0-only
/*
* Copyright (c) 2024, Richard Acayan. All rights reserved.
*/
pub mod osk;
pub mod session;

99
src/dbus/osk.rs Normal file
View file

@ -0,0 +1,99 @@
// SPDX-License-Identifier: GPL-3.0-only
/*
* Copyright (c) 2024, Richard Acayan. All rights reserved.
*/
use crate::core::Graphics;
use crate::wayland::Surface;
use crate::wayland::fractional_scale_v1::wp_fractional_scale_v1::WpFractionalScaleV1;
use crate::wayland::viewporter::wp_viewport::WpViewport;
use crate::wayland::wlr_layer_shell_unstable_v1::zwlr_layer_surface_v1::ZwlrLayerSurfaceV1;
use std::sync::Arc;
use std::sync::Mutex;
use std::sync::atomic::AtomicBool;
use std::sync::atomic::Ordering;
use wayland_client::Dispatch;
use wayland_client::protocol::wl_buffer::WlBuffer;
use wayland_client::protocol::wl_shm_pool::WlShmPool;
use wayland_client::protocol::wl_surface::WlSurface;
use zbus::Connection;
use zbus::InterfaceRef;
use zbus::Result;
use zbus::SignalContext;
use zbus::interface;
pub struct OSK0<T: Dispatch<WlBuffer, u32>
+ Dispatch<WlShmPool, u32>
+ Dispatch<WlSurface, ()>
+ Dispatch<ZwlrLayerSurfaceV1, ()>
+ Dispatch<WpFractionalScaleV1, ()>
+ Dispatch<WpViewport, ()>
+ 'static> {
visible: AtomicBool,
gfx: Arc<Mutex<Graphics<Surface<T>>>>,
sigctx: SignalContext<'static>,
conn_wl: Arc<wayland_client::Connection>,
}
#[interface(name = "sm.puri.OSK0")]
impl<T: Dispatch<WlBuffer, u32>
+ Dispatch<WlShmPool, u32>
+ Dispatch<WlSurface, ()>
+ Dispatch<ZwlrLayerSurfaceV1, ()>
+ Dispatch<WpFractionalScaleV1, ()>
+ Dispatch<WpViewport, ()>
+ 'static> OSK0<T> {
fn get_visible(&self) -> bool
{
self.visible.load(Ordering::Relaxed)
}
pub async fn set_visible(&self, visible: bool)
{
self.visible.store(visible, Ordering::Relaxed);
self.visible_changed(&self.sigctx).await.unwrap();
let mut gfx = self.gfx.lock().unwrap();
let disp = gfx.display_mut();
if visible {
disp.show();
} else {
disp.hide();
}
self.conn_wl.flush().unwrap();
}
#[zbus(property)]
fn visible(&self) -> bool
{
self.visible.load(Ordering::Relaxed)
}
}
impl<T: Dispatch<WlBuffer, u32>
+ Dispatch<WlShmPool, u32>
+ Dispatch<WlSurface, ()>
+ Dispatch<ZwlrLayerSurfaceV1, ()>
+ Dispatch<WpFractionalScaleV1, ()>
+ Dispatch<WpViewport, ()>
+ 'static> OSK0<T> {
pub async fn start(conn: &Connection,
gfx: Arc<Mutex<Graphics<Surface<T>>>>,
conn_wl: Arc<wayland_client::Connection>)
-> Result<InterfaceRef<OSK0<T>>>
{
let sigctx = SignalContext::new(conn, "/sm/puri/OSK0")?;
let visible = AtomicBool::new(false);
let osk = OSK0 { visible, gfx, sigctx, conn_wl };
let server = conn.object_server();
server.at("/sm/puri/OSK0", osk).await?;
conn.request_name("sm.puri.OSK0").await?;
let osk = server.interface("/sm/puri/OSK0").await?;
Ok(osk)
}
}

70
src/dbus/session.rs Normal file
View file

@ -0,0 +1,70 @@
// SPDX-License-Identifier: GPL-3.0-only
/*
* Copyright (c) 2024, Richard Acayan. All rights reserved.
*/
use std::convert::TryFrom;
use std::env;
use std::sync::Arc;
use tokio::task;
use zbus::Connection;
use zbus::Result;
use zbus::export::futures_util::stream::StreamExt;
use zbus::fdo::DBusProxy;
use zbus::names::BusName;
use zbus::proxy;
use zbus::zvariant::OwnedObjectPath;
#[proxy(interface = "org.gnome.SessionManager",
default_service = "org.gnome.SessionManager",
default_path = "/org/gnome/SessionManager")]
trait SessionManager {
fn register_client(&self, app_id: &str, client_startup_id: &str) -> Result<OwnedObjectPath>;
}
#[proxy(interface = "org.gnome.SessionManager.ClientPrivate")]
trait ClientPrivate {
fn end_session_response(&self, is_ok: bool, reason: &str) -> Result<()>;
#[zbus(signal)]
fn query_end_session(&self, flags: u32);
}
pub async fn register(conn: &Connection) -> Result<()>
{
let manager = SessionManagerProxy::new(conn).await?;
let autostart_id = env::var("DESKTOP_AUTOSTART_ID").unwrap_or(String::new());
let path = manager.register_client("sm.puri.OSK0", &autostart_id).await?;
let dbus = DBusProxy::new(conn).await?;
let name = BusName::try_from("org.gnome.SessionManager")?;
let id = dbus.get_name_owner(name).await?;
let client_priv = ClientPrivateProxy::new(conn, id, path).await?;
let client_priv = Arc::new(client_priv);
{
let client_priv = client_priv.clone();
let mut stream_qes = client_priv.receive_query_end_session().await?;
task::spawn(async move {
while stream_qes.next().await.is_some() {
let _ = client_priv.end_session_response(true, "").await;
}
});
}
{
let client_priv = client_priv.clone();
let mut stream_es = client_priv.receive_query_end_session().await?;
task::spawn(async move {
while stream_es.next().await.is_some() {
let _ = client_priv.end_session_response(true, "").await;
}
});
}
Ok(())
}