Detailed changes
@@ -63,7 +63,9 @@ use crate::platform::linux::is_within_click_distance;
use crate::platform::linux::wayland::cursor::Cursor;
use crate::platform::linux::wayland::serial::{SerialKind, SerialTracker};
use crate::platform::linux::wayland::window::WaylandWindow;
-use crate::platform::linux::xdg_desktop_portal::{Event as XDPEvent, XDPEventSource};
+use crate::platform::linux::xdg_desktop_portal::{
+ cursor_settings, Event as XDPEvent, XDPEventSource,
+};
use crate::platform::linux::LinuxClient;
use crate::platform::PlatformWindow;
use crate::{
@@ -430,7 +432,7 @@ impl WaylandClient {
let (primary, clipboard) = unsafe { create_clipboards_from_external(display) };
- let cursor = Cursor::new(&conn, &globals, 24);
+ let mut cursor = Cursor::new(&conn, &globals, 24);
handle
.insert_source(XDPEventSource::new(&common.background_executor), {
@@ -446,10 +448,24 @@ impl WaylandClient {
}
}
}
+ XDPEvent::CursorTheme(theme) => {
+ if let Some(client) = client.0.upgrade() {
+ let mut client = client.borrow_mut();
+ client.cursor.set_theme(theme.as_str(), None);
+ }
+ }
+ XDPEvent::CursorSize(size) => {
+ if let Some(client) = client.0.upgrade() {
+ let mut client = client.borrow_mut();
+ client.cursor.set_size(size);
+ }
+ }
}
})
.unwrap();
+ let foreground = common.foreground_executor.clone();
+
let mut state = Rc::new(RefCell::new(WaylandClientState {
serial_tracker: SerialTracker::new(),
globals,
@@ -511,6 +527,18 @@ impl WaylandClient {
pending_open_uri: None,
}));
+ foreground
+ .spawn({
+ let state = state.clone();
+ async move {
+ if let Ok((theme, size)) = cursor_settings().await {
+ let mut state = state.borrow_mut();
+ state.cursor.set_theme(theme.as_str(), size);
+ }
+ }
+ })
+ .detach();
+
WaylandSource::new(conn, event_queue)
.insert(handle)
.unwrap();
@@ -1,14 +1,18 @@
use crate::Globals;
use util::ResultExt;
-use wayland_client::protocol::wl_pointer::WlPointer;
use wayland_client::protocol::wl_surface::WlSurface;
+use wayland_client::protocol::{wl_pointer::WlPointer, wl_shm::WlShm};
use wayland_client::Connection;
use wayland_cursor::{CursorImageBuffer, CursorTheme};
pub(crate) struct Cursor {
theme: Option<CursorTheme>,
+ theme_name: Option<String>,
surface: WlSurface,
+ size: u32,
+ shm: WlShm,
+ connection: Connection,
}
impl Drop for Cursor {
@@ -22,10 +26,49 @@ impl Cursor {
pub fn new(connection: &Connection, globals: &Globals, size: u32) -> Self {
Self {
theme: CursorTheme::load(&connection, globals.shm.clone(), size).log_err(),
+ theme_name: None,
surface: globals.compositor.create_surface(&globals.qh, ()),
+ shm: globals.shm.clone(),
+ connection: connection.clone(),
+ size,
}
}
+ pub fn set_theme(&mut self, theme_name: &str, size: Option<u32>) {
+ if let Some(size) = size {
+ self.size = size;
+ }
+ if let Some(theme) =
+ CursorTheme::load_from_name(&self.connection, self.shm.clone(), theme_name, self.size)
+ .log_err()
+ {
+ self.theme = Some(theme);
+ self.theme_name = Some(theme_name.to_string());
+ } else if let Some(theme) =
+ CursorTheme::load(&self.connection, self.shm.clone(), self.size).log_err()
+ {
+ self.theme = Some(theme);
+ self.theme_name = None;
+ }
+ }
+
+ pub fn set_size(&mut self, size: u32) {
+ self.size = size;
+ self.theme = self
+ .theme_name
+ .as_ref()
+ .and_then(|name| {
+ CursorTheme::load_from_name(
+ &self.connection,
+ self.shm.clone(),
+ name.as_str(),
+ self.size,
+ )
+ .log_err()
+ })
+ .or_else(|| CursorTheme::load(&self.connection, self.shm.clone(), self.size).log_err());
+ }
+
pub fn set_icon(&mut self, wl_pointer: &WlPointer, serial_id: u32, mut cursor_icon_name: &str) {
if let Some(theme) = &mut self.theme {
let mut buffer: Option<&CursorImageBuffer>;
@@ -359,6 +359,9 @@ impl X11Client {
window.window.set_appearance(appearance);
}
}
+ XDPEvent::CursorTheme(_) | XDPEvent::CursorSize(_) => {
+ // noop, X11 manages this for us.
+ }
}
})
.unwrap();
@@ -1,18 +1,18 @@
//! Provides a [calloop] event source from [XDG Desktop Portal] events
//!
-//! This module uses the [ashpd] crate and handles many async loop
-use std::future::Future;
+//! This module uses the [ashpd] crate
use ashpd::desktop::settings::{ColorScheme, Settings};
-use calloop::channel::{Channel, Sender};
+use calloop::channel::Channel;
use calloop::{EventSource, Poll, PostAction, Readiness, Token, TokenFactory};
use smol::stream::StreamExt;
-use util::ResultExt;
use crate::{BackgroundExecutor, WindowAppearance};
pub enum Event {
WindowAppearance(WindowAppearance),
+ CursorTheme(String),
+ CursorSize(u32),
}
pub struct XDPEventSource {
@@ -23,34 +23,62 @@ impl XDPEventSource {
pub fn new(executor: &BackgroundExecutor) -> Self {
let (sender, channel) = calloop::channel::channel();
- Self::spawn_observer(executor, Self::appearance_observer(sender.clone()));
+ let background = executor.clone();
- Self { channel }
- }
-
- fn spawn_observer(
- executor: &BackgroundExecutor,
- to_spawn: impl Future<Output = Result<(), anyhow::Error>> + Send + 'static,
- ) {
executor
.spawn(async move {
- to_spawn.await.log_err();
+ let settings = Settings::new().await?;
+
+ if let Ok(mut cursor_theme_changed) = settings
+ .receive_setting_changed_with_args(
+ "org.gnome.desktop.interface",
+ "cursor-theme",
+ )
+ .await
+ {
+ let sender = sender.clone();
+ background
+ .spawn(async move {
+ while let Some(theme) = cursor_theme_changed.next().await {
+ let theme = theme?;
+ sender.send(Event::CursorTheme(theme))?;
+ }
+ anyhow::Ok(())
+ })
+ .detach();
+ }
+
+ if let Ok(mut cursor_size_changed) = settings
+ .receive_setting_changed_with_args::<u32>(
+ "org.gnome.desktop.interface",
+ "cursor-size",
+ )
+ .await
+ {
+ let sender = sender.clone();
+ background
+ .spawn(async move {
+ while let Some(size) = cursor_size_changed.next().await {
+ let size = size?;
+ sender.send(Event::CursorSize(size))?;
+ }
+ anyhow::Ok(())
+ })
+ .detach();
+ }
+
+ let mut appearance_changed = settings.receive_color_scheme_changed().await?;
+ while let Some(scheme) = appearance_changed.next().await {
+ sender.send(Event::WindowAppearance(WindowAppearance::from_native(
+ scheme,
+ )))?;
+ }
+
+ anyhow::Ok(())
})
- .detach()
- }
-
- async fn appearance_observer(sender: Sender<Event>) -> Result<(), anyhow::Error> {
- let settings = Settings::new().await?;
+ .detach();
- // We observe the color change during the execution of the application
- let mut stream = settings.receive_color_scheme_changed().await?;
- while let Some(scheme) = stream.next().await {
- sender.send(Event::WindowAppearance(WindowAppearance::from_native(
- scheme,
- )))?;
- }
-
- Ok(())
+ Self { channel }
}
}
@@ -142,3 +170,16 @@ pub fn should_auto_hide_scrollbars(executor: &BackgroundExecutor) -> Result<bool
Ok(auto_hide)
})
}
+
+pub async fn cursor_settings() -> Result<(String, Option<u32>), anyhow::Error> {
+ let settings = Settings::new().await?;
+ let cursor_theme = settings
+ .read::<String>("org.gnome.desktop.interface", "cursor-theme")
+ .await?;
+ let cursor_size = settings
+ .read::<u32>("org.gnome.desktop.interface", "cursor-size")
+ .await
+ .ok();
+
+ Ok((cursor_theme, cursor_size))
+}