diff --git a/api/lua/examples/default/default_config.lua b/api/lua/examples/default/default_config.lua index 77aabbe..90a77a9 100644 --- a/api/lua/examples/default/default_config.lua +++ b/api/lua/examples/default/default_config.lua @@ -54,6 +54,7 @@ require("pinnacle").setup(function(Pinnacle) local focused = Window.get_focused() if focused then focused:toggle_floating() + focused:raise() end end) @@ -62,6 +63,7 @@ require("pinnacle").setup(function(Pinnacle) local focused = Window.get_focused() if focused then focused:toggle_fullscreen() + focused:raise() end end) @@ -70,6 +72,7 @@ require("pinnacle").setup(function(Pinnacle) local focused = Window.get_focused() if focused then focused:toggle_maximized() + focused:raise() end end) diff --git a/api/lua/pinnacle/window.lua b/api/lua/pinnacle/window.lua index c7c49bb..8f276a5 100644 --- a/api/lua/pinnacle/window.lua +++ b/api/lua/pinnacle/window.lua @@ -19,6 +19,7 @@ local rpc_types = { SetFocused = {}, MoveToTag = {}, SetTag = {}, + Raise = {}, MoveGrab = {}, ResizeGrab = {}, Get = { @@ -633,6 +634,21 @@ function WindowHandle:toggle_tag(tag) ) end +---Raise a window. +--- +---This will raise a window all the way to the top of the z-stack. +--- +---### Example +---```lua +---local focused = Window.get_focused() +---if focused then +--- focused:raise() +---end +---``` +function WindowHandle:raise() + client.unary_request(build_grpc_request_params("Raise", { window_id = self.id })) +end + ---@class WindowProperties ---@field geometry { x: integer?, y: integer?, width: integer?, height: integer? }? The location and size of the window ---@field class string? The window's class diff --git a/api/protocol/pinnacle/window/v0alpha1/window.proto b/api/protocol/pinnacle/window/v0alpha1/window.proto index a591c8d..5e131ec 100644 --- a/api/protocol/pinnacle/window/v0alpha1/window.proto +++ b/api/protocol/pinnacle/window/v0alpha1/window.proto @@ -46,6 +46,12 @@ message SetTagRequest { optional .pinnacle.v0alpha1.SetOrToggle set_or_toggle = 3; } +// Raise a window. +message RaiseRequest { + // The id of the window to raise. + optional uint32 window_id = 1; +} + message MoveGrabRequest { optional uint32 button = 1; } @@ -54,6 +60,7 @@ message ResizeGrabRequest { optional uint32 button = 1; } + message GetRequest {} message GetResponse { repeated uint32 window_ids = 1; @@ -115,6 +122,7 @@ service WindowService { rpc SetFocused(SetFocusedRequest) returns (google.protobuf.Empty); rpc MoveToTag(MoveToTagRequest) returns (google.protobuf.Empty); rpc SetTag(SetTagRequest) returns (google.protobuf.Empty); + rpc Raise(RaiseRequest) returns (google.protobuf.Empty); rpc MoveGrab(MoveGrabRequest) returns (google.protobuf.Empty); rpc ResizeGrab(ResizeGrabRequest) returns (google.protobuf.Empty); diff --git a/api/rust/examples/default_config/main.rs b/api/rust/examples/default_config/main.rs index 9793e63..9f8dcc5 100644 --- a/api/rust/examples/default_config/main.rs +++ b/api/rust/examples/default_config/main.rs @@ -69,6 +69,7 @@ async fn main() { input.keybind([mod_key, Mod::Alt], Keysym::space, || { if let Some(window) = window.get_focused() { window.toggle_floating(); + window.raise(); } }); @@ -76,6 +77,7 @@ async fn main() { input.keybind([mod_key], 'f', || { if let Some(window) = window.get_focused() { window.toggle_fullscreen(); + window.raise(); } }); @@ -83,6 +85,7 @@ async fn main() { input.keybind([mod_key], 'm', || { if let Some(window) = window.get_focused() { window.toggle_maximized(); + window.raise(); } }); diff --git a/api/rust/src/window.rs b/api/rust/src/window.rs index 56c62ef..831a306 100644 --- a/api/rust/src/window.rs +++ b/api/rust/src/window.rs @@ -20,8 +20,9 @@ use pinnacle_api_defs::pinnacle::{ self, v0alpha1::{ window_service_client::WindowServiceClient, AddWindowRuleRequest, CloseRequest, - GetRequest, MoveGrabRequest, MoveToTagRequest, ResizeGrabRequest, SetFloatingRequest, - SetFocusedRequest, SetFullscreenRequest, SetMaximizedRequest, SetTagRequest, + GetRequest, MoveGrabRequest, MoveToTagRequest, RaiseRequest, ResizeGrabRequest, + SetFloatingRequest, SetFocusedRequest, SetFullscreenRequest, SetMaximizedRequest, + SetTagRequest, }, }, }; @@ -502,6 +503,24 @@ impl WindowHandle { .unwrap(); } + /// Raise this window. + /// + /// This will raise this window all the way to the top of the z-stack. + /// + /// # Examples + /// + /// ``` + /// window.get_focused()?.raise(); + /// ``` + pub fn raise(&self) { + let mut client = self.window_client.clone(); + + block_on_tokio(client.raise(RaiseRequest { + window_id: Some(self.id), + })) + .unwrap(); + } + /// Get all properties of this window. /// /// # Examples diff --git a/src/api/window.rs b/src/api/window.rs index 194ff5c..69461ff 100644 --- a/src/api/window.rs +++ b/src/api/window.rs @@ -6,7 +6,7 @@ use pinnacle_api_defs::pinnacle::{ self, v0alpha1::{ window_service_server, AddWindowRuleRequest, CloseRequest, FullscreenOrMaximized, - MoveGrabRequest, MoveToTagRequest, ResizeGrabRequest, SetFloatingRequest, + MoveGrabRequest, MoveToTagRequest, RaiseRequest, ResizeGrabRequest, SetFloatingRequest, SetFocusedRequest, SetFullscreenRequest, SetGeometryRequest, SetMaximizedRequest, SetTagRequest, WindowRule, WindowRuleCondition, }, @@ -433,6 +433,26 @@ impl window_service_server::WindowService for WindowService { .await } + async fn raise(&self, request: Request) -> Result, Status> { + let request = request.into_inner(); + + let window_id = WindowId( + request + .window_id + .ok_or_else(|| Status::invalid_argument("no window specified"))?, + ); + + run_unary_no_response(&self.sender, move |state| { + let Some(window) = window_id.window(state) else { + warn!("`raise` was called on a nonexistent window"); + return; + }; + + state.raise_window(window, false); + }) + .await + } + async fn move_grab(&self, request: Request) -> Result, Status> { let request = request.into_inner(); diff --git a/src/handlers.rs b/src/handlers.rs index ab3ada8..ec4e4a4 100644 --- a/src/handlers.rs +++ b/src/handlers.rs @@ -56,6 +56,7 @@ use smithay::{ }, xwayland::{X11Wm, XWaylandClientData}, }; +use tracing::error; use crate::{ focus::{keyboard::KeyboardFocusTarget, pointer::PointerFocusTarget}, @@ -504,14 +505,15 @@ impl WlrLayerShellHandler for State { .or_else(|| self.space.outputs().next().cloned()); let Some(output) = output else { - tracing::error!("New layer surface, but there was no output to map it on"); + error!("New layer surface, but there was no output to map it on"); return; }; - let mut map = layer_map_for_output(&output); - map.map_layer(&desktop::LayerSurface::new(surface, namespace)) - .expect("failed to map layer surface"); - drop(map); // wow i really love refcells haha + if let Err(err) = + layer_map_for_output(&output).map_layer(&desktop::LayerSurface::new(surface, namespace)) + { + error!("Failed to map layer surface: {err}"); + } self.loop_handle.insert_idle(move |state| { state.request_layout(&output);