Fix cursors on some GNOME installations (#12914)
This PR adds support for `org.gnome.desktop.interface`'s `cursor-theme` setting on Wayland. This should fix cursors not showing up on some GNOME installs. This PR also adds the wiring to watch the current cursor theme value. Thanks to @apricotbucket28 for helping debug the issue. Release Notes: - N/A
This commit is contained in:
parent
4cb8d6f40e
commit
ab41eddd8b
4 changed files with 145 additions and 30 deletions
|
@ -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();
|
||||
})
|
||||
.detach()
|
||||
}
|
||||
|
||||
async fn appearance_observer(sender: Sender<Event>) -> Result<(), anyhow::Error> {
|
||||
let settings = Settings::new().await?;
|
||||
|
||||
// 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 {
|
||||
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,
|
||||
)))?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
anyhow::Ok(())
|
||||
})
|
||||
.detach();
|
||||
|
||||
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))
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue