mirror of
https://github.com/pinnacle-comp/pinnacle.git
synced 2024-12-26 21:58:10 +01:00
Update output in API, modify tag tracking
This commit is contained in:
parent
d91c06dbe9
commit
3efdb9d73f
13 changed files with 251 additions and 94 deletions
|
@ -62,8 +62,8 @@ require("pinnacle").setup(function(pinnacle)
|
|||
|
||||
output.connect_for_all(function(op)
|
||||
tag.add(op, "1", "2", "3", "4", "5")
|
||||
tag.toggle("1", op)
|
||||
end)
|
||||
tag.toggle("1")
|
||||
|
||||
input.keybind({ mod_key }, keys.KEY_1, function()
|
||||
tag.switch_to("1")
|
||||
|
|
|
@ -19,8 +19,8 @@
|
|||
---@field Spawn { command: string[], callback_id: integer? }
|
||||
---@field Request Request
|
||||
--Tags
|
||||
---@field ToggleTag { tag_id: string }
|
||||
---@field SwitchToTag { tag_id: string }
|
||||
---@field ToggleTag { output_name: string, tag_name: string }
|
||||
---@field SwitchToTag { output_name: string, tag_name: string }
|
||||
---@field AddTags { output_name: string, tags: string[] }
|
||||
---@field RemoveTags { output_name: string, tags: string[] }
|
||||
--Outputs
|
||||
|
@ -39,7 +39,7 @@
|
|||
---@field GetOutputsByModel { model: string }
|
||||
---@field GetOutputsByRes { res: integer[] }
|
||||
|
||||
---@alias Request _Request | "GetWindowByFocus" | "GetAllWindows"
|
||||
---@alias Request _Request | "GetWindowByFocus" | "GetAllWindows" | "GetOutputByFocus"
|
||||
|
||||
---@class IncomingMsg
|
||||
---@field CallCallback { callback_id: integer, args: Args }
|
||||
|
|
|
@ -57,7 +57,7 @@ function output.get_by_name(name)
|
|||
end
|
||||
end
|
||||
|
||||
---NOTE: This may or may not be what is reported by other monitor listing utilities. One of my monitors fails to report itself in Smithay when it is correctly picked up by tools like wlr-randr. I'll fix this in the future.
|
||||
---NOTE: This may or may not be what is reported by other monitor listing utilities. Pinnacle currently fails to pick up one of my monitors' models when it is correctly picked up by tools like wlr-randr. I'll fix this in the future.
|
||||
---
|
||||
---Get outputs by their model.
|
||||
---This is something like "DELL E2416H" or whatever gibberish monitor manufacturers call their displays.
|
||||
|
@ -112,10 +112,31 @@ function output.get_by_res(width, height)
|
|||
return outputs
|
||||
end
|
||||
|
||||
---Get the currently focused output. This is currently the one with the cursor on it.
|
||||
---@return Output|nil output The output, or nil if none are focused.
|
||||
function output.get_focused()
|
||||
SendMsg({
|
||||
Request = "GetOutputByFocus",
|
||||
})
|
||||
|
||||
local response = ReadMsg()
|
||||
|
||||
local names = response.RequestResponse.response.Outputs.names
|
||||
|
||||
if names[1] ~= nil then
|
||||
return new_output({ name = names[1] })
|
||||
else
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
---Connect a function to be run on all current and future outputs.
|
||||
---
|
||||
---When called, `connect_for_all` will immediately run `func` with all currently connected outputs.
|
||||
---If a new output is connected, `func` will also be called with it.
|
||||
---
|
||||
---Please note: this function will be run *after* Pinnacle processes your entire config.
|
||||
---For example, if you define tags in `func` but toggle them directly after `connect_for_all`, nothing will happen as the tags haven't been added yet.
|
||||
---@param func fun(output: Output) The function that will be run.
|
||||
function output.connect_for_all(func)
|
||||
---@param args Args
|
||||
|
|
|
@ -54,26 +54,42 @@ function tag.add_table(output, tags)
|
|||
})
|
||||
end
|
||||
|
||||
---Toggle a tag on the currently focused output.
|
||||
---Toggle a tag on the specified output. If `output` isn't specified, toggle it on the currently focused output instead.
|
||||
---
|
||||
---# Example
|
||||
---
|
||||
---```lua
|
||||
----- Assuming all tags are toggled off...
|
||||
---tag.toggle("1")
|
||||
---tag.toggle("2")
|
||||
---local op = output.get_by_name("DP-1")
|
||||
---tag.toggle("1", op)
|
||||
---tag.toggle("2", op)
|
||||
----- will cause windows on both tags 1 and 2 to be displayed at the same time.
|
||||
---```
|
||||
---@param name string The name of the tag.
|
||||
function tag.toggle(name)
|
||||
---@param output Output? The output.
|
||||
function tag.toggle(name, output)
|
||||
if output ~= nil then
|
||||
SendMsg({
|
||||
ToggleTag = {
|
||||
tag_id = name,
|
||||
output_name = output.name,
|
||||
tag_name = name,
|
||||
},
|
||||
})
|
||||
else
|
||||
local op = require("output").get_focused()
|
||||
if op ~= nil then
|
||||
SendMsg({
|
||||
ToggleTag = {
|
||||
output_name = op.name,
|
||||
tag_name = name,
|
||||
},
|
||||
})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
---Switch to a tag on the currently focused output, deactivating any other active tags on that output.
|
||||
---Switch to a tag on the specified output, deactivating any other active tags on it.
|
||||
---If `output` is not specified, this uses the currently focused output instead.
|
||||
---
|
||||
---This is used to replicate what a traditional workspace is on some other Wayland compositors.
|
||||
---
|
||||
|
@ -83,12 +99,26 @@ end
|
|||
---tag.switch_to("3") -- Switches to and displays *only* windows on tag 3
|
||||
---```
|
||||
---@param name string The name of the tag.
|
||||
function tag.switch_to(name)
|
||||
---@param output Output? The output.
|
||||
function tag.switch_to(name, output)
|
||||
if output ~= nil then
|
||||
SendMsg({
|
||||
SwitchToTag = {
|
||||
tag_id = name,
|
||||
output_name = output.name,
|
||||
tag_name = name,
|
||||
},
|
||||
})
|
||||
else
|
||||
local op = require("output").get_focused()
|
||||
if op ~= nil then
|
||||
SendMsg({
|
||||
SwitchToTag = {
|
||||
output_name = op.name,
|
||||
tag_name = name,
|
||||
},
|
||||
})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return tag
|
||||
|
|
|
@ -49,11 +49,13 @@ pub enum Msg {
|
|||
// Tag management
|
||||
// FIXME: tag_id should not be a string
|
||||
ToggleTag {
|
||||
tag_id: String,
|
||||
output_name: String,
|
||||
tag_name: String,
|
||||
},
|
||||
// FIXME: tag_id should not be a string
|
||||
SwitchToTag {
|
||||
tag_id: String,
|
||||
output_name: String,
|
||||
tag_name: String,
|
||||
},
|
||||
AddTags {
|
||||
/// The name of the output you want these tags on.
|
||||
|
@ -99,6 +101,7 @@ pub enum Request {
|
|||
GetOutputByName { name: String },
|
||||
GetOutputsByModel { model: String },
|
||||
GetOutputsByRes { res: (u32, u32) },
|
||||
GetOutputByFocus,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Copy, Clone, serde::Serialize, serde::Deserialize)]
|
||||
|
|
|
@ -219,7 +219,7 @@ pub fn run_winit() -> Result<(), Box<dyn Error>> {
|
|||
None,
|
||||
None,
|
||||
);
|
||||
state.re_layout();
|
||||
state.re_layout(&output);
|
||||
}
|
||||
WinitEvent::Focus(_) => {}
|
||||
WinitEvent::Input(input_evt) => {
|
||||
|
|
|
@ -232,12 +232,12 @@ impl<B: Backend> XdgShellHandler for State<B> {
|
|||
(Some(output), _) | (None, Some(output)) => output.with_state(|state| {
|
||||
let output_tags = state
|
||||
.focused_tags()
|
||||
.map(|tag| tag.id.clone())
|
||||
.map(|tag| tag.clone())
|
||||
.collect::<Vec<_>>();
|
||||
if !output_tags.is_empty() {
|
||||
output_tags
|
||||
} else if let Some(first_tag) = state.tags.first() {
|
||||
vec![first_tag.id.clone()]
|
||||
vec![first_tag.clone()]
|
||||
} else {
|
||||
vec![]
|
||||
}
|
||||
|
@ -267,7 +267,10 @@ impl<B: Backend> XdgShellHandler for State<B> {
|
|||
focused_output.with_state(|state| {
|
||||
data.state
|
||||
.windows
|
||||
.to_master_stack(state.focused_tags().map(|tag| tag.id.clone()).collect())
|
||||
.to_master_stack(
|
||||
focused_output,
|
||||
state.focused_tags().map(|tag| tag.clone()).collect(),
|
||||
)
|
||||
.layout(&data.state.space, focused_output);
|
||||
});
|
||||
}
|
||||
|
@ -280,7 +283,10 @@ impl<B: Backend> XdgShellHandler for State<B> {
|
|||
if let Some(focused_output) = self.focus_state.focused_output.as_ref() {
|
||||
focused_output.with_state(|state| {
|
||||
self.windows
|
||||
.to_master_stack(state.focused_tags().map(|tag| tag.id.clone()).collect())
|
||||
.to_master_stack(
|
||||
focused_output,
|
||||
state.focused_tags().map(|tag| tag.clone()).collect(),
|
||||
)
|
||||
.layout(&self.space, focused_output);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ use smithay::{
|
|||
use crate::{
|
||||
backend::Backend,
|
||||
state::{State, WithState},
|
||||
tag::TagId,
|
||||
tag::Tag,
|
||||
window::window_state::WindowResizeState,
|
||||
};
|
||||
|
||||
|
@ -30,6 +30,7 @@ pub trait Layout<S: SpaceElement> {
|
|||
|
||||
pub struct MasterStack<S: SpaceElement> {
|
||||
inner: Vec<S>,
|
||||
output: Output,
|
||||
}
|
||||
|
||||
impl MasterStack<Window> {
|
||||
|
@ -49,6 +50,8 @@ impl MasterStack<Window> {
|
|||
return;
|
||||
};
|
||||
|
||||
let output_loc = output.current_location();
|
||||
|
||||
let height = output_geo.size.h / stack_count as i32;
|
||||
|
||||
for (i, win) in self.stack().enumerate() {
|
||||
|
@ -59,7 +62,11 @@ impl MasterStack<Window> {
|
|||
win.with_state(|state| {
|
||||
state.resize_state = WindowResizeState::WaitingForAck(
|
||||
win.toplevel().send_configure(),
|
||||
(output_geo.size.w / 2, i as i32 * height).into(),
|
||||
(
|
||||
output_geo.size.w / 2 + output_loc.x,
|
||||
i as i32 * height + output_loc.y,
|
||||
)
|
||||
.into(),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
@ -77,6 +84,8 @@ impl Layout<Window> for MasterStack<Window> {
|
|||
return;
|
||||
};
|
||||
|
||||
let output_loc = output.current_location();
|
||||
|
||||
if self.stack().count() == 0 {
|
||||
// one window
|
||||
master.toplevel().with_pending_state(|state| {
|
||||
|
@ -86,7 +95,7 @@ impl Layout<Window> for MasterStack<Window> {
|
|||
master.with_state(|state| {
|
||||
state.resize_state = WindowResizeState::WaitingForAck(
|
||||
master.toplevel().send_configure(),
|
||||
(0, 0).into(),
|
||||
(output_loc.x, output_loc.y).into(),
|
||||
);
|
||||
});
|
||||
} else {
|
||||
|
@ -98,7 +107,7 @@ impl Layout<Window> for MasterStack<Window> {
|
|||
master.with_state(|state| {
|
||||
state.resize_state = WindowResizeState::WaitingForAck(
|
||||
master.toplevel().send_configure(),
|
||||
(0, 0).into(),
|
||||
(output_loc.x, output_loc.y).into(),
|
||||
);
|
||||
});
|
||||
|
||||
|
@ -109,6 +118,7 @@ impl Layout<Window> for MasterStack<Window> {
|
|||
|
||||
pub struct Dwindle<S: SpaceElement> {
|
||||
inner: Vec<S>,
|
||||
output: Output,
|
||||
}
|
||||
|
||||
impl Layout<Window> for Dwindle<Window> {
|
||||
|
@ -119,32 +129,34 @@ impl Layout<Window> for Dwindle<Window> {
|
|||
|
||||
pub trait LayoutVec<S: SpaceElement> {
|
||||
/// Interpret this vec as a master-stack layout.
|
||||
fn to_master_stack(&self, tags: Vec<TagId>) -> MasterStack<S>;
|
||||
fn to_dwindle(&self, tags: Vec<TagId>) -> Dwindle<S>;
|
||||
fn to_master_stack(&self, output: &Output, tags: Vec<Tag>) -> MasterStack<S>;
|
||||
fn to_dwindle(&self, output: &Output, tags: Vec<Tag>) -> Dwindle<S>;
|
||||
}
|
||||
|
||||
impl LayoutVec<Window> for Vec<Window> {
|
||||
fn to_master_stack(&self, tags: Vec<TagId>) -> MasterStack<Window> {
|
||||
fn to_master_stack(&self, output: &Output, tags: Vec<Tag>) -> MasterStack<Window> {
|
||||
MasterStack {
|
||||
inner: filter_windows(self, tags),
|
||||
output: output.clone(), // TODO: get rid of?
|
||||
}
|
||||
}
|
||||
|
||||
fn to_dwindle(&self, tags: Vec<TagId>) -> Dwindle<Window> {
|
||||
fn to_dwindle(&self, output: &Output, tags: Vec<Tag>) -> Dwindle<Window> {
|
||||
Dwindle {
|
||||
inner: filter_windows(self, tags),
|
||||
output: output.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn filter_windows(windows: &[Window], tags: Vec<TagId>) -> Vec<Window> {
|
||||
fn filter_windows(windows: &[Window], tags: Vec<Tag>) -> Vec<Window> {
|
||||
windows
|
||||
.iter()
|
||||
.filter(|window| {
|
||||
window.with_state(|state| {
|
||||
state.floating.is_tiled() && {
|
||||
for tag_id in state.tags.iter() {
|
||||
if tags.iter().any(|tag| tag == tag_id) {
|
||||
for tag in state.tags.iter() {
|
||||
if tags.iter().any(|tg| tg == tag) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,9 @@ use smithay::output::Output;
|
|||
|
||||
use crate::{state::WithState, tag::Tag};
|
||||
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, PartialEq, Eq)]
|
||||
pub struct OutputName(pub String);
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct OutputState {
|
||||
pub tags: Vec<Tag>,
|
||||
|
@ -36,6 +39,6 @@ impl WithState for Output {
|
|||
|
||||
impl OutputState {
|
||||
pub fn focused_tags(&mut self) -> impl Iterator<Item = &mut Tag> {
|
||||
self.tags.iter_mut().filter(|tag| tag.active)
|
||||
self.tags.iter_mut().filter(|tag| tag.active())
|
||||
}
|
||||
}
|
||||
|
|
114
src/state.rs
114
src/state.rs
|
@ -162,15 +162,16 @@ impl<B: Backend> State<B> {
|
|||
.as_ref()
|
||||
.unwrap()
|
||||
.with_state(|op_state| {
|
||||
let tag = op_state.tags.iter().find(|tag| tag.name == tag_id);
|
||||
let tag = op_state.tags.iter().find(|tag| tag.name() == tag_id);
|
||||
if let Some(tag) = tag {
|
||||
state.tags = vec![tag.id.clone()];
|
||||
state.tags = vec![tag.clone()];
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
self.re_layout();
|
||||
let output = self.focus_state.focused_output.clone().unwrap();
|
||||
self.re_layout(&output);
|
||||
}
|
||||
Msg::ToggleTagOnWindow { window_id, tag_id } => {
|
||||
if let Some(window) = self
|
||||
|
@ -184,64 +185,66 @@ impl<B: Backend> State<B> {
|
|||
.as_ref()
|
||||
.unwrap()
|
||||
.with_state(|op_state| {
|
||||
let tag = op_state.tags.iter().find(|tag| tag.name == tag_id);
|
||||
let tag = op_state.tags.iter().find(|tag| tag.name() == tag_id);
|
||||
if let Some(tag) = tag {
|
||||
if state.tags.contains(&tag.id) {
|
||||
state.tags.retain(|id| id != &tag.id);
|
||||
if state.tags.contains(&tag) {
|
||||
state.tags.retain(|tg| tg != tag);
|
||||
} else {
|
||||
state.tags.push(tag.id.clone());
|
||||
state.tags.push(tag.clone());
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
self.re_layout();
|
||||
let output = self.focus_state.focused_output.clone().unwrap();
|
||||
self.re_layout(&output);
|
||||
}
|
||||
}
|
||||
Msg::ToggleTag { tag_id } => {
|
||||
self.focus_state
|
||||
.focused_output
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.with_state(|state| {
|
||||
if let Some(tag) = state.tags.iter_mut().find(|tag| tag.name == tag_id) {
|
||||
tag.active = !tag.active;
|
||||
Msg::ToggleTag { output_name, tag_name } => {
|
||||
tracing::debug!("ToggleTag");
|
||||
|
||||
let output = self.space.outputs().find(|op| op.name() == output_name).cloned();
|
||||
if let Some(output) = output {
|
||||
|
||||
output.with_state(|state| {
|
||||
if let Some(tag) = state.tags.iter_mut().find(|tag| tag.name() == tag_name) {
|
||||
tracing::debug!("Setting tag {tag:?} to {}", !tag.active());
|
||||
tag.set_active(!tag.active());
|
||||
}
|
||||
});
|
||||
|
||||
self.re_layout();
|
||||
self.re_layout(&output);
|
||||
}
|
||||
Msg::SwitchToTag { tag_id } => {
|
||||
self.focus_state
|
||||
.focused_output
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.with_state(|state| {
|
||||
if !state.tags.iter().any(|tag| tag.name == tag_id) {
|
||||
}
|
||||
Msg::SwitchToTag { output_name, tag_name } => {
|
||||
let output = self.space.outputs().find(|op| op.name() == output_name).cloned();
|
||||
if let Some(output) = output {
|
||||
|
||||
output.with_state(|state| {
|
||||
if !state.tags.iter().any(|tag| tag.name() == tag_name) {
|
||||
// TODO: notify error
|
||||
return;
|
||||
}
|
||||
for tag in state.tags.iter_mut() {
|
||||
tag.active = false;
|
||||
tag.set_active(false);
|
||||
}
|
||||
|
||||
let Some(tag) = state.tags.iter_mut().find(|tag| tag.name == tag_id) else {
|
||||
let Some(tag) = state.tags.iter_mut().find(|tag| tag.name() == tag_name) else {
|
||||
unreachable!()
|
||||
};
|
||||
tag.active = true;
|
||||
tag.set_active(true);
|
||||
|
||||
tracing::debug!(
|
||||
"focused tags: {:?}",
|
||||
state
|
||||
.tags
|
||||
.iter()
|
||||
.filter(|tag| tag.active)
|
||||
.map(|tag| &tag.name)
|
||||
.filter(|tag| tag.active())
|
||||
.map(|tag| tag.name())
|
||||
.collect::<Vec<_>>()
|
||||
);
|
||||
});
|
||||
|
||||
self.re_layout();
|
||||
self.re_layout(&output);
|
||||
}
|
||||
}
|
||||
// TODO: add output
|
||||
Msg::AddTags { output_name, tags } => {
|
||||
|
@ -251,7 +254,10 @@ impl<B: Backend> State<B> {
|
|||
.find(|output| output.name() == output_name)
|
||||
{
|
||||
output.with_state(|state| {
|
||||
state.tags.extend(tags.iter().cloned().map(Tag::new));
|
||||
state
|
||||
.tags
|
||||
.extend(tags.iter().cloned().map(Tag::new));
|
||||
tracing::debug!("tags added, are now {:?}", state.tags);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -262,7 +268,7 @@ impl<B: Backend> State<B> {
|
|||
.find(|output| output.name() == output_name)
|
||||
{
|
||||
output.with_state(|state| {
|
||||
state.tags.retain(|tag| !tags.contains(&tag.name));
|
||||
state.tags.retain(|tag| !tags.contains(&tag.name()));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -456,6 +462,28 @@ impl<B: Backend> State<B> {
|
|||
)
|
||||
.unwrap();
|
||||
}
|
||||
Request::GetOutputByFocus => {
|
||||
let names = self
|
||||
.focus_state
|
||||
.focused_output
|
||||
.as_ref()
|
||||
.map(|output| output.name())
|
||||
.into_iter()
|
||||
.collect::<Vec<_>>();
|
||||
let stream = self
|
||||
.api_state
|
||||
.stream
|
||||
.as_ref()
|
||||
.expect("Stream doesn't exist");
|
||||
let mut stream = stream.lock().expect("Couldn't lock stream");
|
||||
crate::api::send_to_client(
|
||||
&mut stream,
|
||||
&OutgoingMsg::RequestResponse {
|
||||
response: RequestResponse::Outputs { names },
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -608,19 +636,25 @@ impl<B: Backend> State<B> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn re_layout(&mut self) {
|
||||
let output = self.focus_state.focused_output.as_ref().unwrap();
|
||||
pub fn re_layout(&mut self, output: &Output) {
|
||||
let windows = self.windows.iter().filter(|win| {
|
||||
win.with_state(|state| state.tags.iter().any(|tag| self.output_for_tag(tag).is_some_and(|op| &op == output)))
|
||||
}).cloned().collect::<Vec<_>>();
|
||||
let (render, do_not_render) = output.with_state(|state| {
|
||||
self.windows
|
||||
.to_master_stack(state.focused_tags().map(|tag| tag.id.clone()).collect())
|
||||
.to_master_stack(
|
||||
output,
|
||||
state.focused_tags().map(|tag| tag.clone()).collect(),
|
||||
)
|
||||
.layout(&self.space, output);
|
||||
self.windows.iter().cloned().partition::<Vec<_>, _>(|win| {
|
||||
|
||||
windows.iter().cloned().partition::<Vec<_>, _>(|win| {
|
||||
win.with_state(|win_state| {
|
||||
if win_state.floating.is_floating() {
|
||||
return true;
|
||||
}
|
||||
for tag_id in win_state.tags.iter() {
|
||||
if state.focused_tags().any(|tag| &tag.id == tag_id) {
|
||||
for tag in win_state.tags.iter() {
|
||||
if state.focused_tags().any(|tg| tg == tag) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
59
src/tag.rs
59
src/tag.rs
|
@ -5,13 +5,22 @@
|
|||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
use std::{
|
||||
cell::RefCell,
|
||||
hash::Hash,
|
||||
rc::Rc,
|
||||
sync::atomic::{AtomicU32, Ordering},
|
||||
};
|
||||
|
||||
use smithay::output::Output;
|
||||
|
||||
use crate::{
|
||||
backend::Backend,
|
||||
state::{State, WithState},
|
||||
};
|
||||
|
||||
static TAG_ID_COUNTER: AtomicU32 = AtomicU32::new(0);
|
||||
|
||||
#[derive(Debug, Hash, PartialEq, Eq, Clone, serde::Serialize, serde::Deserialize)]
|
||||
#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy, serde::Serialize, serde::Deserialize)]
|
||||
pub struct TagId(u32);
|
||||
|
||||
impl TagId {
|
||||
|
@ -21,22 +30,60 @@ impl TagId {
|
|||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Tag {
|
||||
struct TagInner {
|
||||
/// The internal id of this tag.
|
||||
pub id: TagId,
|
||||
id: TagId,
|
||||
/// The name of this tag.
|
||||
pub name: String,
|
||||
name: String,
|
||||
/// Whether this tag is active or not.
|
||||
pub active: bool,
|
||||
active: bool,
|
||||
// TODO: layout
|
||||
}
|
||||
|
||||
impl PartialEq for TagInner {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.id == other.id
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for TagInner {}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct Tag(Rc<RefCell<TagInner>>);
|
||||
|
||||
impl Tag {
|
||||
pub fn id(&self) -> TagId {
|
||||
self.0.borrow().id
|
||||
}
|
||||
|
||||
pub fn name(&self) -> String {
|
||||
self.0.borrow().name.clone()
|
||||
}
|
||||
|
||||
pub fn active(&self) -> bool {
|
||||
self.0.borrow().active
|
||||
}
|
||||
|
||||
pub fn set_active(&mut self, active: bool) {
|
||||
self.0.borrow_mut().active = active;
|
||||
}
|
||||
}
|
||||
|
||||
impl Tag {
|
||||
pub fn new(name: String) -> Self {
|
||||
Self {
|
||||
Self(Rc::new(RefCell::new(TagInner {
|
||||
id: TagId::next(),
|
||||
name,
|
||||
active: false,
|
||||
})))
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: Backend> State<B> {
|
||||
pub fn output_for_tag(&self, tag: &Tag) -> Option<Output> {
|
||||
self.space
|
||||
.outputs()
|
||||
.find(|output| output.with_state(|state| state.tags.iter().any(|tg| tg == tag)))
|
||||
.cloned()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -62,7 +62,8 @@ pub fn toggle_floating<B: Backend>(state: &mut State<B>, window: &Window) {
|
|||
}
|
||||
});
|
||||
|
||||
state.re_layout();
|
||||
let output = state.focus_state.focused_output.clone().unwrap();
|
||||
state.re_layout(&output);
|
||||
|
||||
let output = state.focus_state.focused_output.as_ref().unwrap();
|
||||
let render = output.with_state(|op_state| {
|
||||
|
@ -75,8 +76,8 @@ pub fn toggle_floating<B: Backend>(state: &mut State<B>, window: &Window) {
|
|||
if win_state.floating.is_floating() {
|
||||
return true;
|
||||
}
|
||||
for tag_id in win_state.tags.iter() {
|
||||
if op_state.focused_tags().any(|tag| &tag.id == tag_id) {
|
||||
for tag in win_state.tags.iter() {
|
||||
if op_state.focused_tags().any(|tg| tg == tag) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ use smithay::{
|
|||
utils::{Logical, Point, Serial, Size},
|
||||
};
|
||||
|
||||
use crate::{state::WithState, tag::TagId};
|
||||
use crate::{state::WithState, tag::Tag};
|
||||
|
||||
#[derive(Debug, Hash, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
|
||||
pub struct WindowId(u32);
|
||||
|
@ -36,7 +36,7 @@ pub struct WindowState {
|
|||
/// The window's resize state. See [WindowResizeState] for more.
|
||||
pub resize_state: WindowResizeState,
|
||||
/// What tags the window is currently on.
|
||||
pub tags: Vec<TagId>,
|
||||
pub tags: Vec<Tag>,
|
||||
}
|
||||
|
||||
/// The state of a window's resize operation.
|
||||
|
|
Loading…
Reference in a new issue