From b51d10649f2de5dd659b45edd0e6fb304babc8b4 Mon Sep 17 00:00:00 2001 From: Ottatop Date: Fri, 21 Jun 2024 18:34:54 -0500 Subject: [PATCH] Add API calls for xcursor settings --- api/lua/pinnacle/grpc/defs.lua | 11 +++++ api/lua/pinnacle/input.lua | 24 +++++++++++ .../pinnacle/input/v0alpha1/input.proto | 7 ++++ api/rust/src/input.rs | 42 ++++++++++++++++++- src/api.rs | 27 +++++++++++- src/cursor.rs | 28 +++++++++---- 6 files changed, 130 insertions(+), 9 deletions(-) diff --git a/api/lua/pinnacle/grpc/defs.lua b/api/lua/pinnacle/grpc/defs.lua index 7c00f27..5bb9309 100644 --- a/api/lua/pinnacle/grpc/defs.lua +++ b/api/lua/pinnacle/grpc/defs.lua @@ -350,6 +350,10 @@ local pinnacle_input_v0alpha1_SetLibinputSettingRequest_TapButtonMap = { ---@field tap_drag_lock boolean? ---@field tap boolean? +---@class SetXcursorRequest +---@field theme string? +---@field size integer? + -- Process ---@class pinnacle.process.v0alpha1.SpawnRequest @@ -770,6 +774,13 @@ defs.pinnacle = { request = "pinnacle.input.v0alpha1.SetLibinputSettingRequest", response = "google.protobuf.Empty", }, + ---@type GrpcRequestArgs + SetXcursor = { + service = "pinnacle.input.v0alpha1.InputService", + method = "SetXcursor", + request = "pinnacle.input.v0alpha1.SetXcursorRequest", + response = "google.protobuf.Empty", + }, }, }, }, diff --git a/api/lua/pinnacle/input.lua b/api/lua/pinnacle/input.lua index 1f178a5..86f983d 100644 --- a/api/lua/pinnacle/input.lua +++ b/api/lua/pinnacle/input.lua @@ -352,4 +352,28 @@ function input.set_libinput_settings(settings) end end +---Sets the current xcursor theme. +--- +---Pinnacle reads `$XCURSOR_THEME` on startup to set the theme. +---This allows you to set it at runtime. +--- +---@param theme string +function input.set_xcursor_theme(theme) + client.unary_request(input_service.SetXcursor, { + theme = theme, + }) +end + +---Sets the current xcursor size. +--- +---Pinnacle reads `$XCURSOR_SIZE` on startup to set the cursor size. +---This allows you to set it at runtime. +--- +---@param size integer +function input.set_xcursor_size(size) + client.unary_request(input_service.SetXcursor, { + size = size, + }) +end + return input diff --git a/api/protocol/pinnacle/input/v0alpha1/input.proto b/api/protocol/pinnacle/input/v0alpha1/input.proto index 0ad65d3..a2e6ae3 100644 --- a/api/protocol/pinnacle/input/v0alpha1/input.proto +++ b/api/protocol/pinnacle/input/v0alpha1/input.proto @@ -143,6 +143,11 @@ message SetLibinputSettingRequest { } } +message SetXcursorRequest { + optional string theme = 1; + optional uint32 size = 2; +} + service InputService { rpc SetKeybind(SetKeybindRequest) returns (stream SetKeybindResponse); rpc SetMousebind(SetMousebindRequest) returns (stream SetMousebindResponse); @@ -153,4 +158,6 @@ service InputService { rpc SetRepeatRate(SetRepeatRateRequest) returns (google.protobuf.Empty); rpc SetLibinputSetting(SetLibinputSettingRequest) returns (google.protobuf.Empty); + + rpc SetXcursor(SetXcursorRequest) returns (google.protobuf.Empty); } diff --git a/api/rust/src/input.rs b/api/rust/src/input.rs index 0804499..ae80ada 100644 --- a/api/rust/src/input.rs +++ b/api/rust/src/input.rs @@ -16,7 +16,7 @@ use pinnacle_api_defs::pinnacle::input::{ input_service_client::InputServiceClient, set_libinput_setting_request::{CalibrationMatrix, Setting}, KeybindDescriptionsRequest, SetKeybindRequest, SetLibinputSettingRequest, - SetMousebindRequest, SetRepeatRateRequest, SetXkbConfigRequest, + SetMousebindRequest, SetRepeatRateRequest, SetXcursorRequest, SetXkbConfigRequest, }, }; use tokio::sync::mpsc::UnboundedSender; @@ -402,6 +402,46 @@ impl Input { })) .unwrap(); } + + /// Set the xcursor theme. + /// + /// Pinnacle reads `$XCURSOR_THEME` on startup to determine the theme. + /// This allows you to set it at runtime. + /// + /// # Examples + /// + /// ``` + /// input.set_xcursor_theme("Adwaita"); + /// ``` + pub fn set_xcursor_theme(&self, theme: impl ToString) { + let mut client = self.create_input_client(); + + block_on_tokio(client.set_xcursor(SetXcursorRequest { + theme: Some(theme.to_string()), + size: None, + })) + .unwrap(); + } + + /// Set the xcursor size. + /// + /// Pinnacle reads `$XCURSOR_SIZE` on startup to determine the cursor size. + /// This allows you to set it at runtime. + /// + /// # Examples + /// + /// ``` + /// input.set_xcursor_size(64); + /// ``` + pub fn set_xcursor_size(&self, size: u32) { + let mut client = self.create_input_client(); + + block_on_tokio(client.set_xcursor(SetXcursorRequest { + theme: None, + size: Some(size), + })) + .unwrap(); + } } /// A trait that designates anything that can be converted into a [`Keysym`]. diff --git a/src/api.rs b/src/api.rs index 33934a3..671587a 100644 --- a/src/api.rs +++ b/src/api.rs @@ -11,7 +11,7 @@ use pinnacle_api_defs::pinnacle::{ set_mousebind_request::MouseEdge, KeybindDescription, KeybindDescriptionsRequest, KeybindDescriptionsResponse, Modifier, SetKeybindRequest, SetKeybindResponse, SetLibinputSettingRequest, SetMousebindRequest, - SetMousebindResponse, SetRepeatRateRequest, SetXkbConfigRequest, + SetMousebindResponse, SetRepeatRateRequest, SetXcursorRequest, SetXkbConfigRequest, }, output::{ self, @@ -586,6 +586,31 @@ impl input_service_server::InputService for InputService { }) .await } + + async fn set_xcursor( + &self, + request: Request, + ) -> Result, Status> { + let request = request.into_inner(); + + let theme = request.theme; + let size = request.size; + + run_unary_no_response(&self.sender, move |state| { + if let Some(theme) = theme { + state.pinnacle.cursor_state.set_theme(&theme); + } + + if let Some(size) = size { + state.pinnacle.cursor_state.set_size(size); + } + + if let Some(output) = state.pinnacle.focused_output().cloned() { + state.schedule_render(&output) + } + }) + .await + } } pub struct ProcessService { diff --git a/src/cursor.rs b/src/cursor.rs index 5051d14..a17c6ae 100644 --- a/src/cursor.rs +++ b/src/cursor.rs @@ -32,20 +32,32 @@ pub struct CursorState { impl CursorState { pub fn new() -> Self { - let (theme, size) = load_xcursor_theme(); + let (theme, size) = load_xcursor_theme_from_env(); + + std::env::set_var("XCURSOR_THEME", &theme); + std::env::set_var("XCURSOR_SIZE", size.to_string()); Self { start_time: Instant::now(), current_cursor_image: CursorImageStatus::default_named(), - theme, + theme: CursorTheme::load(&theme), size, mem_buffer_cache: Default::default(), loaded_images: Default::default(), } } - pub fn set_theme_and_size(&mut self, theme: CursorTheme, size: u32) { - self.theme = theme; + pub fn set_theme(&mut self, theme: &str) { + std::env::set_var("XCURSOR_THEME", theme); + + self.theme = CursorTheme::load(theme); + self.mem_buffer_cache.clear(); + self.loaded_images.clear(); + } + + pub fn set_size(&mut self, size: u32) { + std::env::set_var("XCURSOR_SIZE", size.to_string()); + self.size = size; self.mem_buffer_cache.clear(); self.loaded_images.clear(); @@ -186,15 +198,17 @@ fn nearest_size_images(size: u32, images: &[Image]) -> impl Iterator (CursorTheme, u32) { +/// Loads a theme and size from $XCURSOR_THEME and $XCURSOR_SIZE. +/// +/// Defaults to "default" and 24 respectively. +fn load_xcursor_theme_from_env() -> (String, u32) { let theme = std::env::var("XCURSOR_THEME").unwrap_or_else(|_| "default".into()); let size = std::env::var("XCURSOR_SIZE") .ok() .and_then(|size| size.parse::().ok()) .unwrap_or(24); - (CursorTheme::load(&theme), size) + (theme, size) } /// Load xcursor images for the given theme and icon.