api: Add new window state stuff

This commit is contained in:
Ottatop 2024-06-27 18:42:23 -05:00
parent 621f2779d6
commit f4f61a9d1f
7 changed files with 280 additions and 28 deletions

View file

@ -180,6 +180,7 @@ local pinnacle_output_v0alpha1_Transform = {
---@field floating boolean?
---@field fullscreen_or_maximized pinnacle.window.v0alpha1.FullscreenOrMaximized?
---@field tag_ids integer[]?
---@field state pinnacle.window.v0alpha1.WindowState?
---@enum pinnacle.window.v0alpha1.FullscreenOrMaximized
local pinnacle_window_v0alpha1_FullscreenOrMaximized = {
@ -200,6 +201,15 @@ local pinnacle_window_v0alpha1_FullscreenOrMaximized = {
---@field titles string[]?
---@field tags integer[]?
---@enum pinnacle.window.v0alpha1.WindowState
local pinnacle_window_v0alpha1_WindowState = {
WINDOW_STATE_UNSPECIFIED = 0,
WINDOW_STATE_TILED = 1,
WINDOW_STATE_FLOATING = 2,
WINDOW_STATE_FULLSCREEN = 3,
WINDOW_STATE_MAXIMIZED = 4,
}
---@class pinnacle.window.v0alpha1.WindowRule
---@field output string?
---@field tags integer[]?
@ -210,6 +220,7 @@ local pinnacle_window_v0alpha1_FullscreenOrMaximized = {
---@field width integer?
---@field height integer?
---@field ssd boolean?
---@field state pinnacle.window.v0alpha1.WindowState?
-- Tag
@ -560,6 +571,7 @@ defs.pinnacle = {
FullscreenOrMaximized = util.bijective_table(
pinnacle_window_v0alpha1_FullscreenOrMaximized
),
WindowState = util.bijective_table(pinnacle_window_v0alpha1_WindowState),
WindowService = {
---@type GrpcRequestArgs
Close = {

View file

@ -133,16 +133,23 @@ end
---@field titles string[]?
---@field tags TagHandle[]?
---@alias WindowState
---| "tiled"
---| "floating"
---| "fullscreen"
---| "maximized"
---@class WindowRule
---@field output OutputHandle?
---@field tags TagHandle[]?
---@field floating boolean?
---@field fullscreen_or_maximized FullscreenOrMaximized?
---@field floating boolean? -- Deprecated; use `state` with "floating" or "tiled" instead
---@field fullscreen_or_maximized FullscreenOrMaximized? -- Deprecated; use `state` with "fullscreen" or "maximized" instead
---@field x integer?
---@field y integer?
---@field width integer?
---@field height integer?
---@field decoration_mode ("client_side" | "server_side")?
---@field state WindowState?
---@enum (key) FullscreenOrMaximized
local _fullscreen_or_maximized = {
@ -185,6 +192,23 @@ local function process_window_rule(rule)
rule.ssd = true
end
end
if rule.state then
local WindowState = require("pinnacle.grpc.defs").pinnacle.window.v0alpha1.WindowState
if rule.state == "tiled" then
---@diagnostic disable-next-line: assign-type-mismatch
rule.state = WindowState.WINDOW_STATE_TILED
elseif rule.state == "floating" then
---@diagnostic disable-next-line: assign-type-mismatch
rule.state = WindowState.WINDOW_STATE_FLOATING
elseif rule.state == "fullscreen" then
---@diagnostic disable-next-line: assign-type-mismatch
rule.state = WindowState.WINDOW_STATE_FULLSCREEN
elseif rule.state == "maximized" then
---@diagnostic disable-next-line: assign-type-mismatch
rule.state = WindowState.WINDOW_STATE_MAXIMIZED
end
end
end
---@param cond WindowRuleCondition
@ -655,6 +679,7 @@ end
---@field floating boolean? Whether or not the window is floating
---@field fullscreen_or_maximized FullscreenOrMaximized? Whether the window is fullscreen, maximized, or neither
---@field tags TagHandle[]? The tags the window has
---@field state WindowState?
---Get all the properties of this window.
---
@ -670,6 +695,22 @@ function WindowHandle:props()
and require("pinnacle.tag").handle.new_from_table(response.tag_ids)
response.tag_ids = nil
if response.state then
local WindowState = require("pinnacle.grpc.defs").pinnacle.window.v0alpha1.WindowState
---@type WindowState?
local state = nil
if response.state == WindowState.WINDOW_STATE_TILED then
state = "tiled"
elseif response.state == WindowState.WINDOW_STATE_FLOATING then
state = "floating"
elseif response.state == WindowState.WINDOW_STATE_FULLSCREEN then
state = "fullscreen"
elseif response.state == WindowState.WINDOW_STATE_MAXIMIZED then
state = "maximized"
end
response.state = state
end
return response
end
@ -713,16 +754,40 @@ end
---
---Shorthand for `handle:props().floating`.
---
---@return boolean?
---@return boolean
function WindowHandle:floating()
return self:props().floating
return self:props().state == "floating"
end
---Get whether this window is tiled.
---
---@return boolean
function WindowHandle:tiled()
return self:props().state == "tiled"
end
---Get whether this window is fullscreen.
---
---@return boolean
function WindowHandle:fullscreen()
return self:props().state == "fullscreen"
end
---Get whether this window is maximized.
---
---@return boolean
function WindowHandle:maximized()
return self:props().state == "maximized"
end
---Deprecated; use the `fullscreen` or `maximized` methods instead.
---
---Get whether this window is fullscreen, maximized, or neither.
---
---Shorthand for `handle:props().fullscreen_or_maximized`.
---
---@return FullscreenOrMaximized?
---@deprecated
function WindowHandle:fullscreen_or_maximized()
return self:props().fullscreen_or_maximized
end

View file

@ -74,9 +74,10 @@ message GetPropertiesResponse {
optional string class = 2;
optional string title = 3;
optional bool focused = 4;
optional bool floating = 5;
optional FullscreenOrMaximized fullscreen_or_maximized = 6;
optional bool floating = 5 [deprecated = true];
optional FullscreenOrMaximized fullscreen_or_maximized = 6 [deprecated = true];
repeated uint32 tag_ids = 7;
optional WindowState state = 8;
}
enum FullscreenOrMaximized {
@ -99,12 +100,25 @@ message WindowRuleCondition {
repeated uint32 tags = 5;
}
enum WindowState {
WINDOW_STATE_UNSPECIFIED = 0;
WINDOW_STATE_TILED = 1;
WINDOW_STATE_FLOATING = 2;
WINDOW_STATE_FULLSCREEN = 3;
WINDOW_STATE_MAXIMIZED = 4;
}
message WindowRule {
optional string output = 1;
repeated uint32 tags = 2;
// DEPRECATED
// TODO: remove in 0.1/0.2
// `true` for floating, `false` for tiled
optional bool floating = 3;
// DEPRECATED
// TODO: remove in 0.1/0.2
optional FullscreenOrMaximized fullscreen_or_maximized = 4;
optional int32 x = 5;
@ -113,6 +127,8 @@ message WindowRule {
optional int32 height = 8;
// true to force ssd, false to force csd, null to not force anything
optional bool ssd = 9;
optional WindowState state = 10;
}
service WindowService {

View file

@ -234,6 +234,20 @@ pub enum FullscreenOrMaximized {
Maximized,
}
/// A window's current display state.
#[repr(i32)]
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, TryFromPrimitive)]
pub enum WindowState {
/// The window is tiled.
Tiled = 1,
/// The window is floating.
Floating,
/// The window is fullscreen.
Fullscreen,
/// The window is maximized.
Maximized,
}
/// Properties of a window.
#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)]
pub struct WindowProperties {
@ -249,11 +263,15 @@ pub struct WindowProperties {
///
/// Note that a window can still be floating even if it's fullscreen or maximized; those two
/// states will just override the floating state.
#[deprecated = "use `state` instead"]
pub floating: Option<bool>,
/// Whether the window is fullscreen, maximized, or neither
#[deprecated = "use `state` instead"]
pub fullscreen_or_maximized: Option<FullscreenOrMaximized>,
/// All the tags on the window
pub tags: Vec<TagHandle>,
/// The state of the window.
pub state: Option<WindowState>,
}
impl WindowHandle {
@ -569,6 +587,15 @@ impl WindowHandle {
}
};
let state = match response.state() {
window::v0alpha1::WindowState::Unspecified => None,
window::v0alpha1::WindowState::Tiled => Some(WindowState::Tiled),
window::v0alpha1::WindowState::Floating => Some(WindowState::Floating),
window::v0alpha1::WindowState::Fullscreen => Some(WindowState::Fullscreen),
window::v0alpha1::WindowState::Maximized => Some(WindowState::Maximized),
};
#[allow(deprecated)]
let fullscreen_or_maximized = response
.fullscreen_or_maximized
.unwrap_or_default()
@ -582,6 +609,7 @@ impl WindowHandle {
height: geo.height() as u32,
});
#[allow(deprecated)]
WindowProperties {
geometry,
class: response.class,
@ -594,6 +622,7 @@ impl WindowHandle {
.into_iter()
.map(|id| self.api.tag.new_handle(id))
.collect(),
state,
}
}
@ -649,24 +678,82 @@ impl WindowHandle {
///
/// Shorthand for `self.props().floating`.
pub fn floating(&self) -> Option<bool> {
self.props().floating
self.props()
.state
.map(|state| state == WindowState::Floating)
}
/// The async version of [`floating`][Self::floating]
pub async fn floating_async(&self) -> Option<bool> {
self.props_async().await.floating
self.props_async()
.await
.state
.map(|state| state == WindowState::Floating)
}
/// Get whether this window is fullscreen, maximized, or neither.
///
/// Shorthand for `self.props().fullscreen_or_maximized`.
#[deprecated = "use the `fullscreen` or `maximized` methods instead"]
pub fn fullscreen_or_maximized(&self) -> Option<FullscreenOrMaximized> {
self.props().fullscreen_or_maximized
self.props().state.map(|state| match state {
WindowState::Tiled | WindowState::Floating => FullscreenOrMaximized::Neither,
WindowState::Fullscreen => FullscreenOrMaximized::Fullscreen,
WindowState::Maximized => FullscreenOrMaximized::Maximized,
})
}
/// The async version of [`fullscreen_or_maximized`][Self::fullscreen_or_maximized].
#[deprecated = "use the `fullscreen_async` or `maximized_async` methods instead"]
pub async fn fullscreen_or_maximized_async(&self) -> Option<FullscreenOrMaximized> {
self.props_async().await.fullscreen_or_maximized
self.props_async().await.state.map(|state| match state {
WindowState::Tiled | WindowState::Floating => FullscreenOrMaximized::Neither,
WindowState::Fullscreen => FullscreenOrMaximized::Fullscreen,
WindowState::Maximized => FullscreenOrMaximized::Maximized,
})
}
/// Get whether or not this window is tiled.
pub fn tiled(&self) -> Option<bool> {
self.props().state.map(|state| state == WindowState::Tiled)
}
/// The async version of [`tiled`][Self::tiled].
pub async fn tiled_async(&self) -> Option<bool> {
self.props_async()
.await
.state
.map(|state| state == WindowState::Tiled)
}
/// Get whether or not this window is fullscreen.
pub fn fullscreen(&self) -> Option<bool> {
self.props()
.state
.map(|state| state == WindowState::Fullscreen)
}
/// The async version of [`fullscreen`][Self::fullscreen].
pub async fn fullscreen_async(&self) -> Option<bool> {
self.props_async()
.await
.state
.map(|state| state == WindowState::Fullscreen)
}
/// Get whether or not this window is maximized.
pub fn maximized(&self) -> Option<bool> {
self.props()
.state
.map(|state| state == WindowState::Maximized)
}
/// The async version of [`maximized`][Self::maximized].
pub async fn maximized_async(&self) -> Option<bool> {
self.props_async()
.await
.state
.map(|state| state == WindowState::Maximized)
}
/// Get all the tags on this window.

View file

@ -412,7 +412,7 @@ impl WindowRule {
self
}
/// This rule will force windows to open either floating or not.
/// This rule will force windows to open either floating if true or tiled if false.
///
/// # Examples
///
@ -426,7 +426,10 @@ impl WindowRule {
/// let rule = WindowRule::new().floating(false);
/// ```
pub fn floating(mut self, floating: bool) -> Self {
self.0.floating = Some(floating);
self.0.set_state(match floating {
true => window::v0alpha1::WindowState::Floating,
false => window::v0alpha1::WindowState::Tiled,
});
self
}
@ -447,6 +450,7 @@ impl WindowRule {
/// // Force the window to open not fullscreen nor maximized
/// let rule = WindowRule::new().fullscreen_or_maximized(FullscreenOrMaximized::Neither);
/// ```
#[deprecated = "use the `fullscreen` or `maximized` methods instead"]
pub fn fullscreen_or_maximized(
mut self,
fullscreen_or_maximized: FullscreenOrMaximized,
@ -455,6 +459,36 @@ impl WindowRule {
self
}
/// This rule will force windows to open fullscreen.
///
/// # Examples
///
/// ```
/// use pinnacle_api::window::rules::WindowRule;
///
/// // Force the window to open fullscreen
/// let rule = WindowRule::new().fullscreen();
/// ```
pub fn fullscreen(mut self) -> Self {
self.0.set_state(window::v0alpha1::WindowState::Fullscreen);
self
}
/// This rule will force windows to open maximized.
///
/// # Examples
///
/// ```
/// use pinnacle_api::window::rules::WindowRule;
///
/// // Force the window to open fullscreen
/// let rule = WindowRule::new().maximized();
/// ```
pub fn maximized(mut self) -> Self {
self.0.set_state(window::v0alpha1::WindowState::Maximized);
self
}
/// This rule will force windows to open at a specific x-coordinate.
///
/// This will only actually be visible if the window is also floating.

View file

@ -666,6 +666,17 @@ impl window_service_server::WindowService for WindowService {
})
.unwrap_or_default();
let state = window.as_ref().map(|win| {
let state = win.with_state(|state| state.window_state);
(match state {
WindowState::Tiled => window::v0alpha1::WindowState::Tiled,
WindowState::Floating => window::v0alpha1::WindowState::Floating,
WindowState::Maximized { .. } => window::v0alpha1::WindowState::Maximized,
WindowState::Fullscreen { .. } => window::v0alpha1::WindowState::Fullscreen,
}) as i32
});
#[allow(deprecated)]
window::v0alpha1::GetPropertiesResponse {
geometry,
class,
@ -674,6 +685,7 @@ impl window_service_server::WindowService for WindowService {
floating,
fullscreen_or_maximized,
tag_ids,
state,
}
})
.await
@ -763,6 +775,19 @@ impl From<WindowRule> for crate::window::rules::WindowRule {
Some(crate::window::window_state::FullscreenOrMaximized::Maximized)
}
};
let window_state = match rule.state() {
window::v0alpha1::WindowState::Unspecified => None,
window::v0alpha1::WindowState::Tiled => Some(WindowState::Tiled),
window::v0alpha1::WindowState::Floating => Some(WindowState::Floating),
window::v0alpha1::WindowState::Fullscreen => Some(WindowState::Fullscreen {
previous_state: crate::window::window_state::FloatingOrTiled::Tiled,
}),
window::v0alpha1::WindowState::Maximized => Some(WindowState::Fullscreen {
previous_state: crate::window::window_state::FloatingOrTiled::Tiled,
}),
};
let output = rule.output.map(OutputName);
let tags = match rule.tags.is_empty() {
true => None,
@ -794,6 +819,7 @@ impl From<WindowRule> for crate::window::rules::WindowRule {
size,
location,
decoration_mode,
window_state,
}
}
}

View file

@ -14,7 +14,7 @@ use crate::{
window::window_state::FloatingOrTiled,
};
use super::WindowElement;
use super::{window_state::WindowState, WindowElement};
use std::num::NonZeroU32;
@ -162,6 +162,7 @@ pub struct WindowRule {
/// when set to floating.
pub location: Option<(i32, i32)>,
pub decoration_mode: Option<DecorationMode>,
pub window_state: Option<WindowState>,
}
impl Pinnacle {
@ -177,6 +178,7 @@ impl Pinnacle {
size,
location, // FIXME: make f64
decoration_mode,
window_state,
} = rule;
// TODO: If both `output` and `tags` are specified, `tags` will apply over
@ -200,23 +202,33 @@ impl Pinnacle {
window.with_state_mut(|state| state.tags.clone_from(&tags));
}
if let Some(floating_or_tiled) = floating_or_tiled {
window.with_state_mut(|state| {
state.window_state.set_floating(match floating_or_tiled {
FloatingOrTiled::Floating => true,
FloatingOrTiled::Tiled => false,
})
if let Some(window_state) = window_state {
window.with_state_mut(|state| match window_state {
WindowState::Tiled => state.window_state.set_floating(false),
WindowState::Floating => state.window_state.set_floating(true),
WindowState::Maximized { .. } => state.window_state.set_maximized(true),
WindowState::Fullscreen { .. } => state.window_state.set_fullscreen(true),
});
}
} else {
if let Some(floating_or_tiled) = floating_or_tiled {
window.with_state_mut(|state| {
state.window_state.set_floating(match floating_or_tiled {
FloatingOrTiled::Floating => true,
FloatingOrTiled::Tiled => false,
})
});
}
if let Some(fs_or_max) = fullscreen_or_maximized {
match fs_or_max {
FullscreenOrMaximized::Neither => (), // TODO:
FullscreenOrMaximized::Fullscreen => {
window.with_state_mut(|state| state.window_state.set_fullscreen(true));
}
FullscreenOrMaximized::Maximized => {
window.with_state_mut(|state| state.window_state.set_maximized(true))
if let Some(fs_or_max) = fullscreen_or_maximized {
match fs_or_max {
FullscreenOrMaximized::Neither => (), // TODO:
FullscreenOrMaximized::Fullscreen => {
window.with_state_mut(|state| {
state.window_state.set_fullscreen(true)
});
}
FullscreenOrMaximized::Maximized => window
.with_state_mut(|state| state.window_state.set_maximized(true)),
}
}
}