mirror of
https://github.com/pinnacle-comp/pinnacle.git
synced 2025-02-06 20:46:37 +01:00
Rework fullscreen tracking again
Lots of stuff needs cleaning up
This commit is contained in:
parent
947ccdf464
commit
dbde8545c3
14 changed files with 389 additions and 335 deletions
|
@ -53,11 +53,7 @@ require("pinnacle").setup(function(pinnacle)
|
||||||
input.keybind({ mod_key, "Alt" }, keys.space, function()
|
input.keybind({ mod_key, "Alt" }, keys.space, function()
|
||||||
local win = window.get_focused()
|
local win = window.get_focused()
|
||||||
if win ~= nil then
|
if win ~= nil then
|
||||||
if win:status() == "Tiled" then
|
win:toggle_floating()
|
||||||
win:set_status("Floating")
|
|
||||||
elseif win:status() == "Floating" then
|
|
||||||
win:set_status("Tiled")
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
@ -70,21 +66,14 @@ require("pinnacle").setup(function(pinnacle)
|
||||||
input.keybind({ mod_key }, keys.f, function()
|
input.keybind({ mod_key }, keys.f, function()
|
||||||
local win = window.get_focused()
|
local win = window.get_focused()
|
||||||
if win ~= nil then
|
if win ~= nil then
|
||||||
win:set_status("Fullscreen")
|
win:toggle_fullscreen()
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
input.keybind({ mod_key }, keys.m, function()
|
input.keybind({ mod_key }, keys.m, function()
|
||||||
local win = window.get_focused()
|
local win = window.get_focused()
|
||||||
if win ~= nil then
|
if win ~= nil then
|
||||||
win:set_status("Maximized")
|
win:toggle_maximized()
|
||||||
end
|
|
||||||
end)
|
|
||||||
|
|
||||||
input.keybind({ mod_key }, keys.t, function()
|
|
||||||
local win = window.get_focused()
|
|
||||||
if win ~= nil then
|
|
||||||
win:set_status("Tiled")
|
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,9 @@
|
||||||
---@field SetWindowSize { window_id: WindowId, width: integer?, height: integer? }?
|
---@field SetWindowSize { window_id: WindowId, width: integer?, height: integer? }?
|
||||||
---@field MoveWindowToTag { window_id: WindowId, tag_id: TagId }?
|
---@field MoveWindowToTag { window_id: WindowId, tag_id: TagId }?
|
||||||
---@field ToggleTagOnWindow { window_id: WindowId, tag_id: TagId }?
|
---@field ToggleTagOnWindow { window_id: WindowId, tag_id: TagId }?
|
||||||
---@field SetStatus { window_id: WindowId, status: StatusName }?
|
---@field ToggleFloating { window_id: WindowId }?
|
||||||
|
---@field ToggleFullscreen { window_id: WindowId }?
|
||||||
|
---@field ToggleMaximized { window_id: WindowId }?
|
||||||
--
|
--
|
||||||
---@field Spawn { command: string[], callback_id: integer? }?
|
---@field Spawn { command: string[], callback_id: integer? }?
|
||||||
---@field Request Request?
|
---@field Request Request?
|
||||||
|
@ -26,9 +28,8 @@
|
||||||
|
|
||||||
---@alias Msg _Msg | "Quit"
|
---@alias Msg _Msg | "Quit"
|
||||||
|
|
||||||
---@alias StatusName
|
---@alias FullscreenOrMaximized
|
||||||
---| "Floating"
|
---| "Neither"
|
||||||
---| "Tiled"
|
|
||||||
---| "Fullscreen"
|
---| "Fullscreen"
|
||||||
---| "Maximized"
|
---| "Maximized"
|
||||||
|
|
||||||
|
@ -62,7 +63,7 @@
|
||||||
--Windows
|
--Windows
|
||||||
---@field Window { window_id: WindowId|nil }?
|
---@field Window { window_id: WindowId|nil }?
|
||||||
---@field Windows { window_ids: WindowId[] }?
|
---@field Windows { window_ids: WindowId[] }?
|
||||||
---@field WindowProps { size: integer[]?, loc: integer[]?, class: string?, title: string?, status: StatusName?, focused: boolean? }?
|
---@field WindowProps { size: integer[]?, loc: integer[]?, class: string?, title: string?, focused: boolean?, floating: boolean?, fullscreen_or_maximized: FullscreenOrMaximized? }?
|
||||||
--Outputs
|
--Outputs
|
||||||
---@field Output { output_name: OutputName? }?
|
---@field Output { output_name: OutputName? }?
|
||||||
---@field Outputs { output_names: OutputName[] }?
|
---@field Outputs { output_names: OutputName[] }?
|
||||||
|
|
|
@ -90,12 +90,6 @@ function window:close()
|
||||||
window_module.close(self)
|
window_module.close(self)
|
||||||
end
|
end
|
||||||
|
|
||||||
---Set this window's status. Yes, this isn't a great name.
|
|
||||||
---@param status StatusName
|
|
||||||
function window:set_status(status)
|
|
||||||
window_module.set_status(self, status)
|
|
||||||
end
|
|
||||||
|
|
||||||
---Get this window's size.
|
---Get this window's size.
|
||||||
---
|
---
|
||||||
---### Example
|
---### Example
|
||||||
|
@ -158,10 +152,48 @@ function window:title()
|
||||||
end
|
end
|
||||||
|
|
||||||
---Get this window's status.
|
---Get this window's status.
|
||||||
---@return StatusName|nil
|
---@return boolean|nil
|
||||||
---@see WindowModule.status — The corresponding module function
|
---@see WindowModule.status — The corresponding module function
|
||||||
function window:status()
|
function window:floating()
|
||||||
return window_module.status(self)
|
return window_module.floating(self)
|
||||||
|
end
|
||||||
|
|
||||||
|
---Get this window's status.
|
||||||
|
---@return boolean|nil
|
||||||
|
---@see WindowModule.status — The corresponding module function
|
||||||
|
function window:fullscreen()
|
||||||
|
return window_module.fullscreen(self)
|
||||||
|
end
|
||||||
|
|
||||||
|
---Get this window's status.
|
||||||
|
---@return boolean|nil
|
||||||
|
---@see WindowModule.status — The corresponding module function
|
||||||
|
function window:maximized()
|
||||||
|
return window_module.maximized(self)
|
||||||
|
end
|
||||||
|
|
||||||
|
function window:toggle_floating()
|
||||||
|
SendMsg({
|
||||||
|
ToggleFloating = {
|
||||||
|
window_id = self:id(),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
function window:toggle_fullscreen()
|
||||||
|
SendMsg({
|
||||||
|
ToggleFullscreen = {
|
||||||
|
window_id = self:id(),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
function window:toggle_maximized()
|
||||||
|
SendMsg({
|
||||||
|
ToggleMaximized = {
|
||||||
|
window_id = self:id(),
|
||||||
|
},
|
||||||
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
---Get whether or not this window is focused.
|
---Get whether or not this window is focused.
|
||||||
|
@ -361,18 +393,6 @@ function window_module.close(win)
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
---Set `win`'s status. Yes, this is not a great name for the function.
|
|
||||||
---@param win Window
|
|
||||||
---@param status StatusName
|
|
||||||
function window_module.set_status(win, status)
|
|
||||||
SendMsg({
|
|
||||||
SetStatus = {
|
|
||||||
window_id = win:id(),
|
|
||||||
status = status,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
end
|
|
||||||
|
|
||||||
---Get the specified window's size.
|
---Get the specified window's size.
|
||||||
---
|
---
|
||||||
---### Example
|
---### Example
|
||||||
|
@ -482,18 +502,48 @@ function window_module.title(win)
|
||||||
return title
|
return title
|
||||||
end
|
end
|
||||||
|
|
||||||
---Get this window's status.
|
---Get this window's floating status.
|
||||||
---@param win Window
|
---@param win Window
|
||||||
---@return StatusName|nil
|
---@return boolean|nil
|
||||||
---@see Window.status — The corresponding object method
|
---@see Window.status — The corresponding object method
|
||||||
function window_module.status(win)
|
function window_module.floating(win)
|
||||||
local response = Request({
|
local response = Request({
|
||||||
GetWindowProps = {
|
GetWindowProps = {
|
||||||
window_id = win:id(),
|
window_id = win:id(),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
local status = response.RequestResponse.response.WindowProps.status
|
local floating = response.RequestResponse.response.WindowProps.floating
|
||||||
return status
|
return floating
|
||||||
|
end
|
||||||
|
|
||||||
|
---Get this window's fullscreen status.
|
||||||
|
---@param win Window
|
||||||
|
---@return boolean|nil
|
||||||
|
---@see Window.status — The corresponding object method
|
||||||
|
function window_module.fullscreen(win)
|
||||||
|
local response = Request({
|
||||||
|
GetWindowProps = {
|
||||||
|
window_id = win:id(),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
local fom =
|
||||||
|
response.RequestResponse.response.WindowProps.fullscreen_or_maximized
|
||||||
|
return fom == "Fullscreen"
|
||||||
|
end
|
||||||
|
|
||||||
|
---Get this window's maximized status.
|
||||||
|
---@param win Window
|
||||||
|
---@return boolean|nil
|
||||||
|
---@see Window.status — The corresponding object method
|
||||||
|
function window_module.maximized(win)
|
||||||
|
local response = Request({
|
||||||
|
GetWindowProps = {
|
||||||
|
window_id = win:id(),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
local fom =
|
||||||
|
response.RequestResponse.response.WindowProps.fullscreen_or_maximized
|
||||||
|
return fom == "Maximized"
|
||||||
end
|
end
|
||||||
|
|
||||||
---Get whether or not this window is focused.
|
---Get whether or not this window is focused.
|
||||||
|
|
|
@ -7,7 +7,7 @@ use crate::{
|
||||||
layout::Layout,
|
layout::Layout,
|
||||||
output::OutputName,
|
output::OutputName,
|
||||||
tag::TagId,
|
tag::TagId,
|
||||||
window::window_state::{StatusName, WindowId},
|
window::window_state::{FullscreenOrMaximized, WindowId},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, serde::Serialize, serde::Deserialize, Clone, Copy)]
|
#[derive(Debug, serde::Serialize, serde::Deserialize, Clone, Copy)]
|
||||||
|
@ -44,9 +44,14 @@ pub enum Msg {
|
||||||
window_id: WindowId,
|
window_id: WindowId,
|
||||||
tag_id: TagId,
|
tag_id: TagId,
|
||||||
},
|
},
|
||||||
SetStatus {
|
ToggleFloating {
|
||||||
|
window_id: WindowId,
|
||||||
|
},
|
||||||
|
ToggleFullscreen {
|
||||||
|
window_id: WindowId,
|
||||||
|
},
|
||||||
|
ToggleMaximized {
|
||||||
window_id: WindowId,
|
window_id: WindowId,
|
||||||
status: StatusName,
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// Tag management
|
// Tag management
|
||||||
|
@ -207,7 +212,8 @@ pub enum RequestResponse {
|
||||||
class: Option<String>,
|
class: Option<String>,
|
||||||
title: Option<String>,
|
title: Option<String>,
|
||||||
focused: Option<bool>,
|
focused: Option<bool>,
|
||||||
status: Option<StatusName>,
|
floating: Option<bool>,
|
||||||
|
fullscreen_or_maximized: Option<FullscreenOrMaximized>,
|
||||||
},
|
},
|
||||||
Output {
|
Output {
|
||||||
output_name: Option<String>,
|
output_name: Option<String>,
|
||||||
|
|
|
@ -20,7 +20,7 @@ use crate::{
|
||||||
backend::Backend,
|
backend::Backend,
|
||||||
state::{State, WithState},
|
state::{State, WithState},
|
||||||
window::{
|
window::{
|
||||||
window_state::{LocationRequestState, Status},
|
window_state::{FloatingOrTiled, LocationRequestState},
|
||||||
WindowElement,
|
WindowElement,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -60,7 +60,9 @@ impl<B: Backend> PointerGrab<State<B>> for MoveSurfaceGrab<State<B>> {
|
||||||
// tracing::info!("window geo is: {:?}", self.window.geometry());
|
// tracing::info!("window geo is: {:?}", self.window.geometry());
|
||||||
// tracing::info!("loc is: {:?}", data.space.element_location(&self.window));
|
// tracing::info!("loc is: {:?}", data.space.element_location(&self.window));
|
||||||
|
|
||||||
let tiled = self.window.with_state(|state| state.status.is_tiled());
|
let tiled = self
|
||||||
|
.window
|
||||||
|
.with_state(|state| state.floating_or_tiled.is_tiled());
|
||||||
|
|
||||||
if tiled {
|
if tiled {
|
||||||
// INFO: this is being used instead of space.element_under(event.location) because that
|
// INFO: this is being used instead of space.element_under(event.location) because that
|
||||||
|
@ -85,7 +87,8 @@ impl<B: Backend> PointerGrab<State<B>> for MoveSurfaceGrab<State<B>> {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let is_floating = window_under.with_state(|state| state.status.is_floating());
|
let is_floating =
|
||||||
|
window_under.with_state(|state| state.floating_or_tiled.is_floating());
|
||||||
|
|
||||||
if is_floating {
|
if is_floating {
|
||||||
return;
|
return;
|
||||||
|
@ -113,10 +116,12 @@ impl<B: Backend> PointerGrab<State<B>> for MoveSurfaceGrab<State<B>> {
|
||||||
.size;
|
.size;
|
||||||
|
|
||||||
self.window.with_state(|state| {
|
self.window.with_state(|state| {
|
||||||
if state.status.is_floating() {
|
if state.floating_or_tiled.is_floating() {
|
||||||
state.status = Status::Floating(Rectangle::from_loc_and_size(new_loc, size));
|
state.floating_or_tiled =
|
||||||
|
FloatingOrTiled::Floating(Rectangle::from_loc_and_size(new_loc, size));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if let WindowElement::X11(surface) = &self.window {
|
if let WindowElement::X11(surface) = &self.window {
|
||||||
let geo = surface.geometry();
|
let geo = surface.geometry();
|
||||||
let new_geo = Rectangle::from_loc_and_size(new_loc, geo.size);
|
let new_geo = Rectangle::from_loc_and_size(new_loc, geo.size);
|
||||||
|
|
|
@ -18,7 +18,7 @@ use smithay::{
|
||||||
use crate::{
|
use crate::{
|
||||||
backend::Backend,
|
backend::Backend,
|
||||||
state::{State, WithState},
|
state::{State, WithState},
|
||||||
window::{window_state::Status, WindowElement},
|
window::{window_state::FloatingOrTiled, WindowElement},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
@ -332,8 +332,9 @@ pub fn handle_commit<B: Backend>(state: &mut State<B>, surface: &WlSurface) -> O
|
||||||
.size;
|
.size;
|
||||||
|
|
||||||
window.with_state(|state| {
|
window.with_state(|state| {
|
||||||
if state.status.is_floating() {
|
if state.floating_or_tiled.is_floating() {
|
||||||
state.status = Status::Floating(Rectangle::from_loc_and_size(window_loc, size));
|
state.floating_or_tiled =
|
||||||
|
FloatingOrTiled::Floating(Rectangle::from_loc_and_size(window_loc, size));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -365,7 +366,8 @@ pub fn resize_request_client<B: Backend>(
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
if window.with_state(|state| state.status.is_tiled()) {
|
// TODO: check for fullscreen/maximized (probably shouldn't matter)
|
||||||
|
if window.with_state(|state| state.floating_or_tiled.is_tiled()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -412,7 +414,7 @@ pub fn resize_request_server<B: Backend>(
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
if window.with_state(|state| state.status.is_tiled()) {
|
if window.with_state(|state| state.floating_or_tiled.is_tiled()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,10 +30,7 @@ use crate::{
|
||||||
backend::Backend,
|
backend::Backend,
|
||||||
focus::FocusTarget,
|
focus::FocusTarget,
|
||||||
state::{State, WithState},
|
state::{State, WithState},
|
||||||
window::{
|
window::{window_state::LocationRequestState, WindowElement, BLOCKER_COUNTER},
|
||||||
window_state::{LocationRequestState, StatusName},
|
|
||||||
WindowElement, BLOCKER_COUNTER,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
impl<B: Backend> XdgShellHandler for State<B> {
|
impl<B: Backend> XdgShellHandler for State<B> {
|
||||||
|
@ -42,9 +39,14 @@ impl<B: Backend> XdgShellHandler for State<B> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_toplevel(&mut self, surface: ToplevelSurface) {
|
fn new_toplevel(&mut self, surface: ToplevelSurface) {
|
||||||
let window = WindowElement::Wayland(Window::new(surface.clone()));
|
surface.with_pending_state(|state| {
|
||||||
|
state.states.set(xdg_toplevel::State::TiledTop);
|
||||||
|
state.states.set(xdg_toplevel::State::TiledBottom);
|
||||||
|
state.states.set(xdg_toplevel::State::TiledLeft);
|
||||||
|
state.states.set(xdg_toplevel::State::TiledRight);
|
||||||
|
});
|
||||||
|
|
||||||
window.set_status(StatusName::Tiled);
|
let window = WindowElement::Wayland(Window::new(surface.clone()));
|
||||||
|
|
||||||
window.with_state(|state| {
|
window.with_state(|state| {
|
||||||
state.tags = match (
|
state.tags = match (
|
||||||
|
@ -323,7 +325,9 @@ impl<B: Backend> XdgShellHandler for State<B> {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
window.set_status(StatusName::Fullscreen);
|
if !window.with_state(|state| state.fullscreen_or_maximized.is_fullscreen()) {
|
||||||
|
window.toggle_fullscreen();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
surface.send_configure();
|
surface.send_configure();
|
||||||
|
@ -351,8 +355,9 @@ impl<B: Backend> XdgShellHandler for State<B> {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: remember the last status instead of tiled
|
if window.with_state(|state| state.fullscreen_or_maximized.is_fullscreen()) {
|
||||||
window.set_status(StatusName::Tiled);
|
window.toggle_fullscreen();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn maximize_request(&mut self, surface: ToplevelSurface) {
|
fn maximize_request(&mut self, surface: ToplevelSurface) {
|
||||||
|
@ -360,8 +365,9 @@ impl<B: Backend> XdgShellHandler for State<B> {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
window.set_status(StatusName::Maximized);
|
if !window.with_state(|state| state.fullscreen_or_maximized.is_maximized()) {
|
||||||
|
window.toggle_maximized();
|
||||||
|
}
|
||||||
// TODO: might need to update_windows here
|
// TODO: might need to update_windows here
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -370,8 +376,9 @@ impl<B: Backend> XdgShellHandler for State<B> {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: remember last status
|
if window.with_state(|state| state.fullscreen_or_maximized.is_maximized()) {
|
||||||
window.set_status(StatusName::Tiled);
|
window.toggle_maximized();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// fn minimize_request(&mut self, surface: ToplevelSurface) {
|
// fn minimize_request(&mut self, surface: ToplevelSurface) {
|
||||||
|
|
|
@ -28,10 +28,7 @@ use crate::{
|
||||||
backend::Backend,
|
backend::Backend,
|
||||||
focus::FocusTarget,
|
focus::FocusTarget,
|
||||||
state::{CalloopData, WithState},
|
state::{CalloopData, WithState},
|
||||||
window::{
|
window::{window_state::FloatingOrTiled, WindowBlocker, WindowElement, BLOCKER_COUNTER},
|
||||||
window_state::{Status, StatusName},
|
|
||||||
WindowBlocker, WindowElement, BLOCKER_COUNTER,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
impl<B: Backend> XwmHandler for CalloopData<B> {
|
impl<B: Backend> XwmHandler for CalloopData<B> {
|
||||||
|
@ -131,7 +128,7 @@ impl<B: Backend> XwmHandler for CalloopData<B> {
|
||||||
|
|
||||||
if should_float(surface) {
|
if should_float(surface) {
|
||||||
window.with_state(|state| {
|
window.with_state(|state| {
|
||||||
state.status = Status::Floating(bbox);
|
state.floating_or_tiled = FloatingOrTiled::Floating(bbox);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -279,11 +276,9 @@ impl<B: Backend> XwmHandler for CalloopData<B> {
|
||||||
self.state
|
self.state
|
||||||
.windows
|
.windows
|
||||||
.retain(|elem| win.wl_surface() != elem.wl_surface());
|
.retain(|elem| win.wl_surface() != elem.wl_surface());
|
||||||
if win.with_state(|state| state.status.is_tiled()) {
|
|
||||||
if let Some(output) = win.output(&self.state) {
|
if let Some(output) = win.output(&self.state) {
|
||||||
self.state.update_windows(&output);
|
self.state.update_windows(&output);
|
||||||
// self.state.re_layout(&output);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tracing::debug!("destroyed x11 window");
|
tracing::debug!("destroyed x11 window");
|
||||||
|
@ -341,7 +336,10 @@ impl<B: Backend> XwmHandler for CalloopData<B> {
|
||||||
let Some(window) = (|| self.state.window_for_surface(&window.wl_surface()?))() else {
|
let Some(window) = (|| self.state.window_for_surface(&window.wl_surface()?))() else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
window.set_status(StatusName::Maximized);
|
|
||||||
|
if !window.with_state(|state| state.fullscreen_or_maximized.is_maximized()) {
|
||||||
|
window.toggle_maximized();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unmaximize_request(&mut self, _xwm: XwmId, window: X11Surface) {
|
fn unmaximize_request(&mut self, _xwm: XwmId, window: X11Surface) {
|
||||||
|
@ -351,8 +349,10 @@ impl<B: Backend> XwmHandler for CalloopData<B> {
|
||||||
let Some(window) = (|| self.state.window_for_surface(&window.wl_surface()?))() else {
|
let Some(window) = (|| self.state.window_for_surface(&window.wl_surface()?))() else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
// TODO: remember previous status
|
|
||||||
window.set_status(StatusName::Tiled);
|
if window.with_state(|state| state.fullscreen_or_maximized.is_maximized()) {
|
||||||
|
window.toggle_maximized();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fullscreen_request(&mut self, _xwm: XwmId, window: X11Surface) {
|
fn fullscreen_request(&mut self, _xwm: XwmId, window: X11Surface) {
|
||||||
|
@ -363,9 +363,10 @@ impl<B: Backend> XwmHandler for CalloopData<B> {
|
||||||
let Some(window) = (|| self.state.window_for_surface(&window.wl_surface()?))() else {
|
let Some(window) = (|| self.state.window_for_surface(&window.wl_surface()?))() else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
window.set_status(StatusName::Fullscreen);
|
|
||||||
|
|
||||||
// TODO: do i need to update_windows here?
|
if !window.with_state(|state| state.fullscreen_or_maximized.is_fullscreen()) {
|
||||||
|
window.toggle_fullscreen();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unfullscreen_request(&mut self, _xwm: XwmId, window: X11Surface) {
|
fn unfullscreen_request(&mut self, _xwm: XwmId, window: X11Surface) {
|
||||||
|
@ -375,8 +376,10 @@ impl<B: Backend> XwmHandler for CalloopData<B> {
|
||||||
let Some(window) = (|| self.state.window_for_surface(&window.wl_surface()?))() else {
|
let Some(window) = (|| self.state.window_for_surface(&window.wl_surface()?))() else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
// TODO: remember previous status
|
|
||||||
window.set_status(StatusName::Tiled);
|
if window.with_state(|state| state.fullscreen_or_maximized.is_fullscreen()) {
|
||||||
|
window.toggle_fullscreen();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resize_request(
|
fn resize_request(
|
||||||
|
|
|
@ -75,7 +75,8 @@ impl<B: Backend> State<B> {
|
||||||
|
|
||||||
let top_fullscreen_window = self.focus_state.focus_stack.iter().rev().find(|win| {
|
let top_fullscreen_window = self.focus_state.focus_stack.iter().rev().find(|win| {
|
||||||
win.with_state(|state| {
|
win.with_state(|state| {
|
||||||
state.status.is_fullscreen() && state.tags.iter().any(|tag| tag.active())
|
state.fullscreen_or_maximized.is_fullscreen()
|
||||||
|
&& state.tags.iter().any(|tag| tag.active())
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ use crate::{
|
||||||
state::{State, WithState},
|
state::{State, WithState},
|
||||||
tag::Tag,
|
tag::Tag,
|
||||||
window::{
|
window::{
|
||||||
window_state::{LocationRequestState, Status},
|
window_state::{FullscreenOrMaximized, LocationRequestState},
|
||||||
WindowElement,
|
WindowElement,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -70,7 +70,11 @@ impl<B: Backend> State<B> {
|
||||||
|
|
||||||
let tiled_windows = windows_on_foc_tags
|
let tiled_windows = windows_on_foc_tags
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|win| win.with_state(|state| state.status.is_tiled()))
|
.filter(|win| {
|
||||||
|
win.with_state(|state| {
|
||||||
|
state.floating_or_tiled.is_tiled() && state.fullscreen_or_maximized.is_neither()
|
||||||
|
})
|
||||||
|
})
|
||||||
.cloned()
|
.cloned()
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
@ -78,11 +82,11 @@ impl<B: Backend> State<B> {
|
||||||
|
|
||||||
let output_geo = self.space.output_geometry(output).expect("no output geo");
|
let output_geo = self.space.output_geometry(output).expect("no output geo");
|
||||||
for window in windows_on_foc_tags.iter() {
|
for window in windows_on_foc_tags.iter() {
|
||||||
match window.with_state(|state| state.status) {
|
match window.with_state(|state| state.fullscreen_or_maximized) {
|
||||||
Status::Fullscreen(_) => {
|
FullscreenOrMaximized::Fullscreen => {
|
||||||
window.change_geometry(output_geo);
|
window.change_geometry(output_geo);
|
||||||
}
|
}
|
||||||
Status::Maximized(_) => {
|
FullscreenOrMaximized::Maximized => {
|
||||||
let map = layer_map_for_output(output);
|
let map = layer_map_for_output(output);
|
||||||
let geo = if map.layers().peekable().peek().is_none() {
|
let geo = if map.layers().peekable().peek().is_none() {
|
||||||
// INFO: Sometimes the exclusive zone is some weird number that doesn't match the
|
// INFO: Sometimes the exclusive zone is some weird number that doesn't match the
|
||||||
|
@ -96,7 +100,7 @@ impl<B: Backend> State<B> {
|
||||||
};
|
};
|
||||||
window.change_geometry(geo);
|
window.change_geometry(geo);
|
||||||
}
|
}
|
||||||
_ => (),
|
FullscreenOrMaximized::Neither => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -474,7 +478,7 @@ fn corner(layout: &Layout, windows: Vec<WindowElement>, rect: Rectangle<i32, Log
|
||||||
fn filter_windows(windows: &[WindowElement], tags: Vec<Tag>) -> Vec<WindowElement> {
|
fn filter_windows(windows: &[WindowElement], tags: Vec<Tag>) -> Vec<WindowElement> {
|
||||||
windows
|
windows
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|window| window.with_state(|state| state.status.is_tiled()))
|
.filter(|window| window.with_state(|state| state.floating_or_tiled.is_tiled()))
|
||||||
.filter(|window| {
|
.filter(|window| {
|
||||||
window.with_state(|state| {
|
window.with_state(|state| {
|
||||||
for tag in state.tags.iter() {
|
for tag in state.tags.iter() {
|
||||||
|
|
|
@ -181,7 +181,7 @@ where
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
state.status.is_fullscreen()
|
state.fullscreen_or_maximized.is_fullscreen()
|
||||||
&& state.tags.iter().any(|tag| tag.active())
|
&& state.tags.iter().any(|tag| tag.active())
|
||||||
&& is_wayland_actually_fullscreen
|
&& is_wayland_actually_fullscreen
|
||||||
})
|
})
|
||||||
|
|
115
src/state.rs
115
src/state.rs
|
@ -20,10 +20,7 @@ use crate::{
|
||||||
focus::FocusState,
|
focus::FocusState,
|
||||||
grab::resize_grab::ResizeSurfaceState,
|
grab::resize_grab::ResizeSurfaceState,
|
||||||
tag::Tag,
|
tag::Tag,
|
||||||
window::{
|
window::{window_state::LocationRequestState, WindowElement},
|
||||||
window_state::{LocationRequestState, Status, StatusName},
|
|
||||||
WindowElement,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
use calloop::futures::Scheduler;
|
use calloop::futures::Scheduler;
|
||||||
use futures_lite::AsyncBufReadExt;
|
use futures_lite::AsyncBufReadExt;
|
||||||
|
@ -201,15 +198,26 @@ impl<B: Backend> State<B> {
|
||||||
self.update_windows(&output);
|
self.update_windows(&output);
|
||||||
// self.re_layout(&output);
|
// self.re_layout(&output);
|
||||||
}
|
}
|
||||||
Msg::SetStatus { window_id, status } => {
|
Msg::ToggleFloating { window_id } => {
|
||||||
let Some(window) = window_id.window(self) else { return };
|
let Some(window) = window_id.window(self) else { return };
|
||||||
window.set_status(status);
|
window.toggle_floating();
|
||||||
let outputs = self.space.outputs_for_element(&window);
|
|
||||||
self.focus_state.set_focus(window);
|
|
||||||
|
|
||||||
if let Some(output) = outputs.into_iter().next() {
|
let Some(output) = window.output(self) else { return };
|
||||||
self.update_windows(&output);
|
self.update_windows(&output);
|
||||||
}
|
}
|
||||||
|
Msg::ToggleFullscreen { window_id } => {
|
||||||
|
let Some(window) = window_id.window(self) else { return };
|
||||||
|
window.toggle_fullscreen();
|
||||||
|
|
||||||
|
let Some(output) = window.output(self) else { return };
|
||||||
|
self.update_windows(&output);
|
||||||
|
}
|
||||||
|
Msg::ToggleMaximized { window_id } => {
|
||||||
|
let Some(window) = window_id.window(self) else { return };
|
||||||
|
window.toggle_maximized();
|
||||||
|
|
||||||
|
let Some(output) = window.output(self) else { return };
|
||||||
|
self.update_windows(&output);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tags ----------------------------------------
|
// Tags ----------------------------------------
|
||||||
|
@ -369,19 +377,17 @@ impl<B: Backend> State<B> {
|
||||||
}
|
}
|
||||||
WindowElement::X11(surface) => (Some(surface.class()), Some(surface.title())),
|
WindowElement::X11(surface) => (Some(surface.class()), Some(surface.title())),
|
||||||
});
|
});
|
||||||
let status = window.as_ref().map(|win| {
|
|
||||||
win.with_state(|state| match state.status {
|
|
||||||
Status::Floating(_) => StatusName::Floating,
|
|
||||||
Status::Tiled(_) => StatusName::Tiled,
|
|
||||||
Status::Fullscreen(_) => StatusName::Fullscreen,
|
|
||||||
Status::Maximized(_) => StatusName::Maximized,
|
|
||||||
})
|
|
||||||
});
|
|
||||||
let focused = window.as_ref().and_then(|win| {
|
let focused = window.as_ref().and_then(|win| {
|
||||||
self.focus_state
|
self.focus_state
|
||||||
.current_focus() // TODO: actual focus
|
.current_focus() // TODO: actual focus
|
||||||
.map(|foc_win| win == &foc_win)
|
.map(|foc_win| win == &foc_win)
|
||||||
});
|
});
|
||||||
|
let floating = window
|
||||||
|
.as_ref()
|
||||||
|
.map(|win| win.with_state(|state| state.floating_or_tiled.is_floating()));
|
||||||
|
let fullscreen_or_maximized = window
|
||||||
|
.as_ref()
|
||||||
|
.map(|win| win.with_state(|state| state.fullscreen_or_maximized));
|
||||||
crate::api::send_to_client(
|
crate::api::send_to_client(
|
||||||
&mut stream,
|
&mut stream,
|
||||||
&OutgoingMsg::RequestResponse {
|
&OutgoingMsg::RequestResponse {
|
||||||
|
@ -392,7 +398,8 @@ impl<B: Backend> State<B> {
|
||||||
class,
|
class,
|
||||||
title,
|
title,
|
||||||
focused,
|
focused,
|
||||||
status,
|
floating,
|
||||||
|
fullscreen_or_maximized,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
@ -661,78 +668,6 @@ impl<B: Backend> State<B> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn re_layout(&mut self, output: &Output) {
|
|
||||||
let windows = self
|
|
||||||
.windows
|
|
||||||
.iter()
|
|
||||||
.filter(|win| {
|
|
||||||
win.with_state(|state| {
|
|
||||||
state
|
|
||||||
.tags
|
|
||||||
.iter()
|
|
||||||
.any(|tag| tag.output(self).is_some_and(|op| &op == output))
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.cloned()
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
let (render, do_not_render) = output.with_state(|state| {
|
|
||||||
let first_tag = state.focused_tags().next();
|
|
||||||
if let Some(first_tag) = first_tag {
|
|
||||||
first_tag.layout().layout(
|
|
||||||
self.windows.clone(),
|
|
||||||
state.focused_tags().cloned().collect(),
|
|
||||||
&mut self.space,
|
|
||||||
output,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
windows.iter().cloned().partition::<Vec<_>, _>(|win| {
|
|
||||||
win.with_state(|win_state| {
|
|
||||||
win_state
|
|
||||||
.tags
|
|
||||||
.iter()
|
|
||||||
.any(|tag| state.focused_tags().any(|tg| tag == tg))
|
|
||||||
})
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
tracing::debug!(
|
|
||||||
"{} to render, {} to not render",
|
|
||||||
render.len(),
|
|
||||||
do_not_render.len()
|
|
||||||
);
|
|
||||||
|
|
||||||
let clone = render.clone();
|
|
||||||
self.loop_handle.insert_idle(|data| {
|
|
||||||
schedule_on_commit(data, clone.clone(), |dt| {
|
|
||||||
for win in do_not_render {
|
|
||||||
dt.state.space.unmap_elem(&win);
|
|
||||||
if let WindowElement::X11(surface) = win {
|
|
||||||
if !surface.is_override_redirect() {
|
|
||||||
surface.set_mapped(false).expect("failed to unmap x11 win");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (win, rect) in
|
|
||||||
clone
|
|
||||||
.into_iter()
|
|
||||||
.filter_map(|win| match win.with_state(|state| state.status) {
|
|
||||||
Status::Floating(loc) => Some((win, loc)),
|
|
||||||
_ => None,
|
|
||||||
})
|
|
||||||
{
|
|
||||||
if let WindowElement::X11(surface) = &win {
|
|
||||||
if !surface.is_override_redirect() {
|
|
||||||
surface.set_mapped(true).expect("failed to map x11 win");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
dt.state.space.map_element(win, rect.loc, false);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Schedule something to be done when windows have finished committing and have become
|
/// Schedule something to be done when windows have finished committing and have become
|
||||||
|
|
119
src/window.rs
119
src/window.rs
|
@ -20,10 +20,7 @@ use smithay::{
|
||||||
},
|
},
|
||||||
output::Output,
|
output::Output,
|
||||||
reexports::{
|
reexports::{
|
||||||
wayland_protocols::{
|
wayland_protocols::wp::presentation_time::server::wp_presentation_feedback,
|
||||||
wp::presentation_time::server::wp_presentation_feedback,
|
|
||||||
xdg::shell::server::xdg_toplevel,
|
|
||||||
},
|
|
||||||
wayland_server::protocol::wl_surface::WlSurface,
|
wayland_server::protocol::wl_surface::WlSurface,
|
||||||
},
|
},
|
||||||
utils::{user_data::UserDataMap, IsAlive, Logical, Point, Rectangle, Serial, Size},
|
utils::{user_data::UserDataMap, IsAlive, Logical, Point, Rectangle, Serial, Size},
|
||||||
|
@ -40,7 +37,7 @@ use crate::{
|
||||||
state::{State, WithState},
|
state::{State, WithState},
|
||||||
};
|
};
|
||||||
|
|
||||||
use self::window_state::{LocationRequestState, Status, StatusName, WindowElementState};
|
use self::window_state::{LocationRequestState, WindowElementState};
|
||||||
|
|
||||||
pub mod window_state;
|
pub mod window_state;
|
||||||
|
|
||||||
|
@ -184,6 +181,8 @@ impl WindowElement {
|
||||||
/// configures to Wayland windows.
|
/// configures to Wayland windows.
|
||||||
///
|
///
|
||||||
/// Xwayland windows will still receive a configure.
|
/// Xwayland windows will still receive a configure.
|
||||||
|
///
|
||||||
|
/// This method uses a [`RefCell`].
|
||||||
// TODO: ^ does that make things flicker?
|
// TODO: ^ does that make things flicker?
|
||||||
pub fn change_geometry(&self, new_geo: Rectangle<i32, Logical>) {
|
pub fn change_geometry(&self, new_geo: Rectangle<i32, Logical>) {
|
||||||
match self {
|
match self {
|
||||||
|
@ -268,116 +267,6 @@ impl WindowElement {
|
||||||
pub fn is_x11(&self) -> bool {
|
pub fn is_x11(&self) -> bool {
|
||||||
matches!(self, Self::X11(..))
|
matches!(self, Self::X11(..))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_status(&self, status: StatusName) {
|
|
||||||
let prev_status = self.with_state(|state| state.status);
|
|
||||||
let geo = match prev_status {
|
|
||||||
Status::Floating(rect)
|
|
||||||
| Status::Tiled(Some(rect))
|
|
||||||
| Status::Fullscreen(Some(rect))
|
|
||||||
| Status::Maximized(Some(rect)) => rect,
|
|
||||||
_ => self.geometry(),
|
|
||||||
};
|
|
||||||
|
|
||||||
match status {
|
|
||||||
StatusName::Floating => {
|
|
||||||
self.with_state(|state| state.status = Status::Floating(geo));
|
|
||||||
|
|
||||||
match self {
|
|
||||||
WindowElement::Wayland(window) => {
|
|
||||||
window.toplevel().with_pending_state(|state| {
|
|
||||||
state.states.unset(xdg_toplevel::State::Maximized);
|
|
||||||
state.states.unset(xdg_toplevel::State::Fullscreen);
|
|
||||||
state.states.unset(xdg_toplevel::State::TiledTop);
|
|
||||||
state.states.unset(xdg_toplevel::State::TiledBottom);
|
|
||||||
state.states.unset(xdg_toplevel::State::TiledLeft);
|
|
||||||
state.states.unset(xdg_toplevel::State::TiledRight);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
WindowElement::X11(surface) => {
|
|
||||||
surface
|
|
||||||
.set_fullscreen(false)
|
|
||||||
.expect("failed to set x11 win to not fullscreen");
|
|
||||||
surface
|
|
||||||
.set_maximized(false)
|
|
||||||
.expect("failed to set x11 win to not maximized");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
StatusName::Tiled => {
|
|
||||||
self.with_state(|state| state.status = Status::Tiled(Some(geo)));
|
|
||||||
|
|
||||||
match self {
|
|
||||||
WindowElement::Wayland(window) => {
|
|
||||||
window.toplevel().with_pending_state(|state| {
|
|
||||||
state.states.unset(xdg_toplevel::State::Maximized);
|
|
||||||
state.states.unset(xdg_toplevel::State::Fullscreen);
|
|
||||||
state.states.set(xdg_toplevel::State::TiledTop);
|
|
||||||
state.states.set(xdg_toplevel::State::TiledBottom);
|
|
||||||
state.states.set(xdg_toplevel::State::TiledLeft);
|
|
||||||
state.states.set(xdg_toplevel::State::TiledRight);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
WindowElement::X11(surface) => {
|
|
||||||
surface
|
|
||||||
.set_fullscreen(false)
|
|
||||||
.expect("failed to set x11 win to not fullscreen");
|
|
||||||
surface
|
|
||||||
.set_maximized(false)
|
|
||||||
.expect("failed to set x11 win to not maximized");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
StatusName::Fullscreen => {
|
|
||||||
self.with_state(|state| state.status = Status::Fullscreen(Some(geo)));
|
|
||||||
|
|
||||||
match self {
|
|
||||||
WindowElement::Wayland(window) => {
|
|
||||||
window.toplevel().with_pending_state(|state| {
|
|
||||||
state.states.unset(xdg_toplevel::State::Maximized);
|
|
||||||
state.states.set(xdg_toplevel::State::Fullscreen);
|
|
||||||
state.states.set(xdg_toplevel::State::TiledTop);
|
|
||||||
state.states.set(xdg_toplevel::State::TiledBottom);
|
|
||||||
state.states.set(xdg_toplevel::State::TiledLeft);
|
|
||||||
state.states.set(xdg_toplevel::State::TiledRight);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
WindowElement::X11(surface) => {
|
|
||||||
surface
|
|
||||||
.set_fullscreen(true)
|
|
||||||
.expect("failed to set x11 win to fullscreen");
|
|
||||||
surface
|
|
||||||
.set_maximized(false)
|
|
||||||
.expect("failed to set x11 win to not maximzied");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
StatusName::Maximized => {
|
|
||||||
self.with_state(|state| state.status = Status::Maximized(Some(geo)));
|
|
||||||
|
|
||||||
match self {
|
|
||||||
WindowElement::Wayland(window) => {
|
|
||||||
window.toplevel().with_pending_state(|state| {
|
|
||||||
state.states.unset(xdg_toplevel::State::Fullscreen);
|
|
||||||
state.states.set(xdg_toplevel::State::Maximized);
|
|
||||||
state.states.set(xdg_toplevel::State::TiledTop);
|
|
||||||
state.states.set(xdg_toplevel::State::TiledBottom);
|
|
||||||
state.states.set(xdg_toplevel::State::TiledLeft);
|
|
||||||
state.states.set(xdg_toplevel::State::TiledRight);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
WindowElement::X11(surface) => {
|
|
||||||
surface
|
|
||||||
.set_fullscreen(false)
|
|
||||||
.expect("failed to set x11 win to not fullscreen");
|
|
||||||
surface
|
|
||||||
.set_maximized(true)
|
|
||||||
.expect("failed to set x11 win to maximized");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IsAlive for WindowElement {
|
impl IsAlive for WindowElement {
|
||||||
|
|
|
@ -6,7 +6,8 @@ use std::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use smithay::{
|
use smithay::{
|
||||||
desktop::Window,
|
desktop::{space::SpaceElement, Window},
|
||||||
|
reexports::wayland_protocols::xdg::shell::server::xdg_toplevel,
|
||||||
utils::{Logical, Point, Rectangle, Serial},
|
utils::{Logical, Point, Rectangle, Serial},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -66,12 +67,12 @@ impl WithState for Window {
|
||||||
pub struct WindowElementState {
|
pub struct WindowElementState {
|
||||||
/// The id of this window.
|
/// The id of this window.
|
||||||
pub id: WindowId,
|
pub id: WindowId,
|
||||||
/// Whether the window is floating, tiled, fullscreen, or maximized.
|
|
||||||
pub status: Status,
|
|
||||||
/// The window's resize state. See [WindowResizeState] for more.
|
/// The window's resize state. See [WindowResizeState] for more.
|
||||||
pub loc_request_state: LocationRequestState,
|
pub loc_request_state: LocationRequestState,
|
||||||
/// What tags the window is currently on.
|
/// What tags the window is currently on.
|
||||||
pub tags: Vec<Tag>,
|
pub tags: Vec<Tag>,
|
||||||
|
pub floating_or_tiled: FloatingOrTiled,
|
||||||
|
pub fullscreen_or_maximized: FullscreenOrMaximized,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The state of a window's resize operation.
|
/// The state of a window's resize operation.
|
||||||
|
@ -114,55 +115,215 @@ pub enum LocationRequestState {
|
||||||
Acknowledged(Point<i32, Logical>),
|
Acknowledged(Point<i32, Logical>),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Whether the window is floating, tiled, fullscreen, or maximized.
|
impl WindowElement {
|
||||||
|
/// This method uses a [`RefCell`].
|
||||||
|
pub fn toggle_floating(&self) {
|
||||||
|
match self.with_state(|state| state.floating_or_tiled) {
|
||||||
|
FloatingOrTiled::Floating(current_rect) => {
|
||||||
|
self.with_state(|state| {
|
||||||
|
state.floating_or_tiled = FloatingOrTiled::Tiled(Some(current_rect))
|
||||||
|
});
|
||||||
|
self.set_tiled_states();
|
||||||
|
}
|
||||||
|
FloatingOrTiled::Tiled(prev_rect) => {
|
||||||
|
let prev_rect = prev_rect.unwrap_or_else(|| self.geometry());
|
||||||
|
|
||||||
|
self.with_state(|state| {
|
||||||
|
state.floating_or_tiled = FloatingOrTiled::Floating(prev_rect);
|
||||||
|
});
|
||||||
|
|
||||||
|
// TODO: maybe move this into update_windows
|
||||||
|
self.change_geometry(prev_rect);
|
||||||
|
self.set_floating_states();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This method uses a [`RefCell`].
|
||||||
|
pub fn toggle_fullscreen(&self) {
|
||||||
|
self.with_state(|state| match state.fullscreen_or_maximized {
|
||||||
|
FullscreenOrMaximized::Neither | FullscreenOrMaximized::Maximized => {
|
||||||
|
state.fullscreen_or_maximized = FullscreenOrMaximized::Fullscreen;
|
||||||
|
|
||||||
|
match self {
|
||||||
|
WindowElement::Wayland(window) => {
|
||||||
|
window.toplevel().with_pending_state(|state| {
|
||||||
|
state.states.unset(xdg_toplevel::State::Maximized);
|
||||||
|
state.states.set(xdg_toplevel::State::Fullscreen);
|
||||||
|
state.states.set(xdg_toplevel::State::TiledTop);
|
||||||
|
state.states.set(xdg_toplevel::State::TiledLeft);
|
||||||
|
state.states.set(xdg_toplevel::State::TiledBottom);
|
||||||
|
state.states.set(xdg_toplevel::State::TiledRight);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
WindowElement::X11(surface) => {
|
||||||
|
surface
|
||||||
|
.set_maximized(false)
|
||||||
|
.expect("failed to set x11 win to maximized");
|
||||||
|
surface
|
||||||
|
.set_fullscreen(true)
|
||||||
|
.expect("failed to set x11 win to not fullscreen");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
FullscreenOrMaximized::Fullscreen => {
|
||||||
|
state.fullscreen_or_maximized = FullscreenOrMaximized::Neither;
|
||||||
|
|
||||||
|
match state.floating_or_tiled {
|
||||||
|
FloatingOrTiled::Floating(current_rect) => {
|
||||||
|
self.change_geometry(current_rect);
|
||||||
|
self.set_floating_states();
|
||||||
|
}
|
||||||
|
FloatingOrTiled::Tiled(_) => self.set_tiled_states(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This method uses a [`RefCell`].
|
||||||
|
pub fn toggle_maximized(&self) {
|
||||||
|
self.with_state(|state| match state.fullscreen_or_maximized {
|
||||||
|
FullscreenOrMaximized::Neither | FullscreenOrMaximized::Fullscreen => {
|
||||||
|
state.fullscreen_or_maximized = FullscreenOrMaximized::Maximized;
|
||||||
|
|
||||||
|
match self {
|
||||||
|
WindowElement::Wayland(window) => {
|
||||||
|
window.toplevel().with_pending_state(|state| {
|
||||||
|
state.states.set(xdg_toplevel::State::Maximized);
|
||||||
|
state.states.unset(xdg_toplevel::State::Fullscreen);
|
||||||
|
state.states.set(xdg_toplevel::State::TiledTop);
|
||||||
|
state.states.set(xdg_toplevel::State::TiledLeft);
|
||||||
|
state.states.set(xdg_toplevel::State::TiledBottom);
|
||||||
|
state.states.set(xdg_toplevel::State::TiledRight);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
WindowElement::X11(surface) => {
|
||||||
|
surface
|
||||||
|
.set_maximized(true)
|
||||||
|
.expect("failed to set x11 win to maximized");
|
||||||
|
surface
|
||||||
|
.set_fullscreen(false)
|
||||||
|
.expect("failed to set x11 win to not fullscreen");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
FullscreenOrMaximized::Maximized => {
|
||||||
|
state.fullscreen_or_maximized = FullscreenOrMaximized::Neither;
|
||||||
|
|
||||||
|
match state.floating_or_tiled {
|
||||||
|
FloatingOrTiled::Floating(current_rect) => {
|
||||||
|
self.change_geometry(current_rect);
|
||||||
|
self.set_floating_states();
|
||||||
|
}
|
||||||
|
FloatingOrTiled::Tiled(_) => self.set_tiled_states(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_floating_states(&self) {
|
||||||
|
match self {
|
||||||
|
WindowElement::Wayland(window) => {
|
||||||
|
window.toplevel().with_pending_state(|state| {
|
||||||
|
state.states.unset(xdg_toplevel::State::Maximized);
|
||||||
|
state.states.unset(xdg_toplevel::State::Fullscreen);
|
||||||
|
state.states.unset(xdg_toplevel::State::TiledTop);
|
||||||
|
state.states.unset(xdg_toplevel::State::TiledLeft);
|
||||||
|
state.states.unset(xdg_toplevel::State::TiledBottom);
|
||||||
|
state.states.unset(xdg_toplevel::State::TiledRight);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
WindowElement::X11(surface) => {
|
||||||
|
surface
|
||||||
|
.set_maximized(false)
|
||||||
|
.expect("failed to set x11 win to maximized");
|
||||||
|
surface
|
||||||
|
.set_fullscreen(false)
|
||||||
|
.expect("failed to set x11 win to not fullscreen");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_tiled_states(&self) {
|
||||||
|
match self {
|
||||||
|
WindowElement::Wayland(window) => {
|
||||||
|
window.toplevel().with_pending_state(|state| {
|
||||||
|
state.states.unset(xdg_toplevel::State::Maximized);
|
||||||
|
state.states.unset(xdg_toplevel::State::Fullscreen);
|
||||||
|
state.states.set(xdg_toplevel::State::TiledTop);
|
||||||
|
state.states.set(xdg_toplevel::State::TiledLeft);
|
||||||
|
state.states.set(xdg_toplevel::State::TiledBottom);
|
||||||
|
state.states.set(xdg_toplevel::State::TiledRight);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
WindowElement::X11(surface) => {
|
||||||
|
surface
|
||||||
|
.set_maximized(false)
|
||||||
|
.expect("failed to set x11 win to maximized");
|
||||||
|
surface
|
||||||
|
.set_fullscreen(false)
|
||||||
|
.expect("failed to set x11 win to not fullscreen");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// You know what they say, the two hardest things in computer science are
|
||||||
|
// cache invalidation and naming things (and off by one errors).
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub enum Status {
|
pub enum FloatingOrTiled {
|
||||||
Floating(Rectangle<i32, Logical>),
|
Floating(Rectangle<i32, Logical>),
|
||||||
Tiled(Option<Rectangle<i32, Logical>>),
|
Tiled(Option<Rectangle<i32, Logical>>),
|
||||||
Fullscreen(Option<Rectangle<i32, Logical>>),
|
|
||||||
Maximized(Option<Rectangle<i32, Logical>>),
|
|
||||||
}
|
|
||||||
// TODO: couple these somehow
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, serde::Serialize, serde::Deserialize)]
|
|
||||||
pub enum StatusName {
|
|
||||||
Floating,
|
|
||||||
Tiled,
|
|
||||||
Fullscreen,
|
|
||||||
Maximized,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Status {
|
impl FloatingOrTiled {
|
||||||
/// Returns `true` if the float is [`Tiled`].
|
/// Returns `true` if the floating or tiled is [`Floating`].
|
||||||
///
|
///
|
||||||
/// [`Tiled`]: Float::Tiled
|
/// [`Floating`]: FloatingOrTiled::Floating
|
||||||
|
#[must_use]
|
||||||
|
pub fn is_floating(&self) -> bool {
|
||||||
|
matches!(self, Self::Floating(..))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns `true` if the floating or tiled is [`Tiled`].
|
||||||
|
///
|
||||||
|
/// [`Tiled`]: FloatingOrTiled::Tiled
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn is_tiled(&self) -> bool {
|
pub fn is_tiled(&self) -> bool {
|
||||||
matches!(self, Self::Tiled(..))
|
matches!(self, Self::Tiled(..))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns `true` if the float is [`Floating`].
|
#[derive(Debug, Clone, Copy, serde::Serialize, serde::Deserialize)]
|
||||||
|
pub enum FullscreenOrMaximized {
|
||||||
|
Neither,
|
||||||
|
Fullscreen,
|
||||||
|
Maximized,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FullscreenOrMaximized {
|
||||||
|
/// Returns `true` if the fullscreen or maximized is [`Neither`].
|
||||||
///
|
///
|
||||||
/// [`Floating`]: Float::Floating
|
/// [`Neither`]: FullscreenOrMaximized::Neither
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn is_floating(&self) -> bool {
|
pub fn is_neither(&self) -> bool {
|
||||||
matches!(self, Self::Floating(_))
|
matches!(self, Self::Neither)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns `true` if the status is [`Fullscreen`].
|
/// Returns `true` if the fullscreen or maximized is [`Fullscreen`].
|
||||||
///
|
///
|
||||||
/// [`Fullscreen`]: Status::Fullscreen
|
/// [`Fullscreen`]: FullscreenOrMaximized::Fullscreen
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn is_fullscreen(&self) -> bool {
|
pub fn is_fullscreen(&self) -> bool {
|
||||||
matches!(self, Self::Fullscreen(..))
|
matches!(self, Self::Fullscreen)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns `true` if the status is [`Maximized`].
|
/// Returns `true` if the fullscreen or maximized is [`Maximized`].
|
||||||
///
|
///
|
||||||
/// [`Maximized`]: Status::Maximized
|
/// [`Maximized`]: FullscreenOrMaximized::Maximized
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn is_maximized(&self) -> bool {
|
pub fn is_maximized(&self) -> bool {
|
||||||
matches!(self, Self::Maximized(..))
|
matches!(self, Self::Maximized)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -178,9 +339,10 @@ impl Default for WindowElementState {
|
||||||
Self {
|
Self {
|
||||||
// INFO: I think this will assign the id on use of the state, not on window spawn.
|
// INFO: I think this will assign the id on use of the state, not on window spawn.
|
||||||
id: WindowId::next(),
|
id: WindowId::next(),
|
||||||
status: Status::Tiled(None),
|
|
||||||
loc_request_state: LocationRequestState::Idle,
|
loc_request_state: LocationRequestState::Idle,
|
||||||
tags: vec![],
|
tags: vec![],
|
||||||
|
floating_or_tiled: FloatingOrTiled::Tiled(None),
|
||||||
|
fullscreen_or_maximized: FullscreenOrMaximized::Neither,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue