Add per tag layouts

This commit is contained in:
Ottatop 2023-07-18 12:37:40 -05:00
parent 92b10121a3
commit a6a62be446
9 changed files with 170 additions and 51 deletions

View file

@ -69,22 +69,46 @@ require("pinnacle").setup(function(pinnacle)
"CornerBottomLeft", "CornerBottomLeft",
"CornerBottomRight", "CornerBottomRight",
} }
local index = 1 local indices = {}
-- Layout cycling
-- Yes, this is very complicated and yes, I'll cook up a way to make it less complicated.
input.keybind({ mod_key }, keys.space, function() input.keybind({ mod_key }, keys.space, function()
tag.set_layout("1", layouts[index]) local tags = output.get_focused():tags()
if index + 1 > #layouts then for _, tg in pairs(tags) do
index = 1 if tg:active() then
else local name = tg:name()
index = index + 1 tg:set_layout(layouts[indices[name] or 1])
if indices[name] == nil then
indices[name] = 2
else
if indices[name] + 1 > #layouts then
indices[name] = 1
else
indices[name] = indices[name] + 1
end
end
break
end
end end
end) end)
input.keybind({ mod_key, "Shift" }, keys.space, function() input.keybind({ mod_key, "Shift" }, keys.space, function()
tag.set_layout("1", layouts[index]) local tags = output.get_focused():tags()
if index - 1 < 1 then for _, tg in pairs(tags) do
index = #layouts if tg:active() then
else local name = tg:name()
index = index - 1 tg:set_layout(layouts[indices[name] or #layouts])
if indices[name] == nil then
indices[name] = #layouts - 1
else
if indices[name] - 1 < 1 then
indices[name] = #layouts
else
indices[name] = indices[name] - 1
end
end
break
end
end end
end) end)

View file

@ -40,6 +40,8 @@
---@field GetOutputsByModel { model: string } ---@field GetOutputsByModel { model: string }
---@field GetOutputsByRes { res: integer[] } ---@field GetOutputsByRes { res: integer[] }
---@field GetTagsByOutput { output: string } ---@field GetTagsByOutput { output: string }
---@field GetTagActive { tag_id: integer }
---@field GetTagName { tag_id: integer }
---@alias Request _Request | "GetWindowByFocus" | "GetAllWindows" | "GetOutputByFocus" ---@alias Request _Request | "GetWindowByFocus" | "GetAllWindows" | "GetOutputByFocus"
@ -56,6 +58,8 @@
---@field GetAllWindows { windows: WindowProperties[] } ---@field GetAllWindows { windows: WindowProperties[] }
---@field Outputs { names: string[] } ---@field Outputs { names: string[] }
---@field Tags { tags: TagProperties[] } ---@field Tags { tags: TagProperties[] }
---@field TagActive { active: boolean }
---@field TagName { name: string }
---@class WindowProperties ---@class WindowProperties
---@field id integer ---@field id integer

View file

@ -56,11 +56,9 @@ local output = {}
---@param name string The name of the output. ---@param name string The name of the output.
---@return Output|nil ---@return Output|nil
function output.get_by_name(name) function output.get_by_name(name)
SendMsg({ SendRequest({
Request = { GetOutputByName = {
GetOutputByName = { name = name,
name = name,
},
}, },
}) })
@ -82,11 +80,9 @@ end
---@param model string The model of the output(s). ---@param model string The model of the output(s).
---@return Output[] outputs All outputs with this model. If there are none, the returned table will be empty. ---@return Output[] outputs All outputs with this model. If there are none, the returned table will be empty.
function output.get_by_model(model) function output.get_by_model(model)
SendMsg({ SendRequest({
Request = { GetOutputsByModel = {
GetOutputsByModel = { model = model,
model = model,
},
}, },
}) })
@ -109,11 +105,9 @@ end
---@param height integer The height of the outputs, in pixels. ---@param height integer The height of the outputs, in pixels.
---@return Output[] outputs All outputs with this resolution. If there are none, the returned table will be empty. ---@return Output[] outputs All outputs with this resolution. If there are none, the returned table will be empty.
function output.get_by_res(width, height) function output.get_by_res(width, height)
SendMsg({ SendRequest({
Request = { GetOutputsByRes = {
GetOutputsByRes = { res = { width, height },
res = { width, height },
},
}, },
}) })

View file

@ -19,6 +19,7 @@ local function read_exact(socket_fd, count)
local len_to_read = count local len_to_read = count
local data = "" local data = ""
while len_to_read > 0 do while len_to_read > 0 do
-- print("need to read " .. tostring(len_to_read) .. " bytes")
local bytes, err_msg, errnum = socket.recv(socket_fd, len_to_read) local bytes, err_msg, errnum = socket.recv(socket_fd, len_to_read)
if bytes == nil then if bytes == nil then
@ -105,9 +106,11 @@ function pinnacle.setup(config_func)
---@type integer ---@type integer
local msg_len = string.unpack("=I4", msg_len_bytes) local msg_len = string.unpack("=I4", msg_len_bytes)
-- print(msg_len)
local msg_bytes, err_msg2, err_num2 = read_exact(socket_fd, msg_len) local msg_bytes, err_msg2, err_num2 = read_exact(socket_fd, msg_len)
assert(msg_bytes) assert(msg_bytes)
-- print(msg_bytes)
---@type IncomingMsg ---@type IncomingMsg
local tb = msgpack.decode(msg_bytes) local tb = msgpack.decode(msg_bytes)

View file

@ -4,6 +4,8 @@
-- --
-- SPDX-License-Identifier: MPL-2.0 -- SPDX-License-Identifier: MPL-2.0
local tag = {}
---@alias Layout ---@alias Layout
---| "MasterStack" # One master window on the left with all other windows stacked to the right. ---| "MasterStack" # One master window on the left with all other windows stacked to the right.
---| "Dwindle" # Windows split in half towards the bottom right corner. ---| "Dwindle" # Windows split in half towards the bottom right corner.
@ -28,7 +30,39 @@ local function new_tag(props)
return props return props
end end
local tag = {} ---Get this tag's active status.
---@return boolean active True if the tag is active, otherwise false.
function tg:active()
SendRequest({
GetTagActive = {
tag_id = self.id,
},
})
local response = ReadMsg()
local active = response.RequestResponse.response.TagActive.active
return active
end
function tg:name()
SendRequest({
GetTagName = {
tag_id = self.id,
},
})
local response = ReadMsg()
local name = response.RequestResponse.response.TagName.name
return name
end
---Set this tag's layout.
---@param layout Layout
function tg:set_layout(layout) -- TODO: output param
tag.set_layout(self:name(), layout)
end
-----------------------------------------------------------
---Add tags. ---Add tags.
--- ---
@ -183,11 +217,9 @@ end
---@param output Output ---@param output Output
---@return Tag[] ---@return Tag[]
function tag.get_on_output(output) function tag.get_on_output(output)
SendMsg({ SendRequest({
Request = { GetTagsByOutput = {
GetTagsByOutput = { output = output.name,
output = output.name,
},
}, },
}) })

View file

@ -112,6 +112,7 @@ pub fn send_to_client(
stream: &mut UnixStream, stream: &mut UnixStream,
msg: &OutgoingMsg, msg: &OutgoingMsg,
) -> Result<(), rmp_serde::encode::Error> { ) -> Result<(), rmp_serde::encode::Error> {
// tracing::debug!("Sending {msg:?}");
let msg = rmp_serde::to_vec_named(msg)?; let msg = rmp_serde::to_vec_named(msg)?;
let msg_len = msg.len() as u32; let msg_len = msg.len() as u32;
let bytes = msg_len.to_ne_bytes(); let bytes = msg_len.to_ne_bytes();

View file

@ -9,7 +9,7 @@
use crate::{ use crate::{
layout::Layout, layout::Layout,
tag::TagProperties, tag::{TagId, TagProperties},
window::{window_state::WindowId, WindowProperties}, window::{window_state::WindowId, WindowProperties},
}; };
@ -111,6 +111,8 @@ pub enum Request {
GetOutputsByRes { res: (u32, u32) }, GetOutputsByRes { res: (u32, u32) },
GetOutputByFocus, GetOutputByFocus,
GetTagsByOutput { output: String }, GetTagsByOutput { output: String },
GetTagActive { tag_id: TagId },
GetTagName { tag_id: TagId },
} }
#[derive(Debug, PartialEq, Eq, Copy, Clone, serde::Serialize, serde::Deserialize)] #[derive(Debug, PartialEq, Eq, Copy, Clone, serde::Serialize, serde::Deserialize)]
@ -192,4 +194,6 @@ pub enum RequestResponse {
GetAllWindows { windows: Vec<WindowProperties> }, GetAllWindows { windows: Vec<WindowProperties> },
Outputs { names: Vec<String> }, Outputs { names: Vec<String> },
Tags { tags: Vec<TagProperties> }, Tags { tags: Vec<TagProperties> },
TagActive { active: bool },
TagName { name: String },
} }

View file

@ -167,8 +167,10 @@ impl Layout {
Slice::Right => { Slice::Right => {
let width_partition = win1_size.w / 2; let width_partition = win1_size.w / 2;
win1.toplevel().with_pending_state(|state| { win1.toplevel().with_pending_state(|state| {
state.size = state.size = Some(
Some((win1_size.w - width_partition, win1_size.h).into()); (win1_size.w - width_partition, i32::max(win1_size.h, 40))
.into(),
);
}); });
win1.with_state(|state| { win1.with_state(|state| {
state.resize_state = WindowResizeState::Requested( state.resize_state = WindowResizeState::Requested(
@ -177,7 +179,8 @@ impl Layout {
); );
}); });
win2.toplevel().with_pending_state(|state| { win2.toplevel().with_pending_state(|state| {
state.size = Some((width_partition, win1_size.h).into()); state.size =
Some((width_partition, i32::max(win1_size.h, 40)).into());
}); });
win2.with_state(|state| { win2.with_state(|state| {
state.resize_state = WindowResizeState::Requested( state.resize_state = WindowResizeState::Requested(
@ -190,8 +193,10 @@ impl Layout {
Slice::Below => { Slice::Below => {
let height_partition = win1_size.h / 2; let height_partition = win1_size.h / 2;
win1.toplevel().with_pending_state(|state| { win1.toplevel().with_pending_state(|state| {
state.size = state.size = Some(
Some((win1_size.w, win1_size.h - height_partition).into()); (win1_size.w, i32::max(win1_size.h - height_partition, 40))
.into(),
);
}); });
win1.with_state(|state| { win1.with_state(|state| {
state.resize_state = WindowResizeState::Requested( state.resize_state = WindowResizeState::Requested(
@ -200,7 +205,8 @@ impl Layout {
); );
}); });
win2.toplevel().with_pending_state(|state| { win2.toplevel().with_pending_state(|state| {
state.size = Some((win1_size.w, height_partition).into()); state.size =
Some((win1_size.w, i32::max(height_partition, 40)).into());
}); });
win2.with_state(|state| { win2.with_state(|state| {
state.resize_state = WindowResizeState::Requested( state.resize_state = WindowResizeState::Requested(
@ -273,8 +279,10 @@ impl Layout {
Slice::Above => { Slice::Above => {
let height_partition = win1_size.h / 2; let height_partition = win1_size.h / 2;
win1.toplevel().with_pending_state(|state| { win1.toplevel().with_pending_state(|state| {
state.size = state.size = Some(
Some((win1_size.w, win1_size.h - height_partition).into()); (win1_size.w, i32::max(win1_size.h - height_partition, 40))
.into(),
);
}); });
win1.with_state(|state| { win1.with_state(|state| {
state.resize_state = WindowResizeState::Requested( state.resize_state = WindowResizeState::Requested(
@ -283,7 +291,8 @@ impl Layout {
); );
}); });
win2.toplevel().with_pending_state(|state| { win2.toplevel().with_pending_state(|state| {
state.size = Some((win1_size.w, height_partition).into()); state.size =
Some((win1_size.w, i32::max(height_partition, 40)).into());
}); });
win2.with_state(|state| { win2.with_state(|state| {
state.resize_state = WindowResizeState::Requested( state.resize_state = WindowResizeState::Requested(
@ -295,8 +304,10 @@ impl Layout {
Slice::Below => { Slice::Below => {
let height_partition = win1_size.h / 2; let height_partition = win1_size.h / 2;
win1.toplevel().with_pending_state(|state| { win1.toplevel().with_pending_state(|state| {
state.size = state.size = Some(
Some((win1_size.w, win1_size.h - height_partition).into()); (win1_size.w, win1_size.h - i32::max(height_partition, 40))
.into(),
);
}); });
win1.with_state(|state| { win1.with_state(|state| {
state.resize_state = WindowResizeState::Requested( state.resize_state = WindowResizeState::Requested(
@ -305,7 +316,8 @@ impl Layout {
); );
}); });
win2.toplevel().with_pending_state(|state| { win2.toplevel().with_pending_state(|state| {
state.size = Some((win1_size.w, height_partition).into()); state.size =
Some((win1_size.w, i32::max(height_partition, 40)).into());
}); });
win2.with_state(|state| { win2.with_state(|state| {
state.resize_state = WindowResizeState::Requested( state.resize_state = WindowResizeState::Requested(
@ -318,8 +330,10 @@ impl Layout {
Slice::Left => { Slice::Left => {
let width_partition = win1_size.w / 2; let width_partition = win1_size.w / 2;
win1.toplevel().with_pending_state(|state| { win1.toplevel().with_pending_state(|state| {
state.size = state.size = Some(
Some((win1_size.w - width_partition, win1_size.h).into()); (win1_size.w - width_partition, i32::max(win1_size.h, 40))
.into(),
);
}); });
win1.with_state(|state| { win1.with_state(|state| {
state.resize_state = WindowResizeState::Requested( state.resize_state = WindowResizeState::Requested(
@ -328,7 +342,8 @@ impl Layout {
); );
}); });
win2.toplevel().with_pending_state(|state| { win2.toplevel().with_pending_state(|state| {
state.size = Some((width_partition, win1_size.h).into()); state.size =
Some((width_partition, i32::max(win1_size.h, 40)).into());
}); });
win2.with_state(|state| { win2.with_state(|state| {
state.resize_state = WindowResizeState::Requested( state.resize_state = WindowResizeState::Requested(
@ -340,8 +355,10 @@ impl Layout {
Slice::Right => { Slice::Right => {
let width_partition = win1_size.w / 2; let width_partition = win1_size.w / 2;
win1.toplevel().with_pending_state(|state| { win1.toplevel().with_pending_state(|state| {
state.size = state.size = Some(
Some((win1_size.w - width_partition, win1_size.h).into()); (win1_size.w - width_partition, i32::max(win1_size.h, 40))
.into(),
);
}); });
win1.with_state(|state| { win1.with_state(|state| {
state.resize_state = WindowResizeState::Requested( state.resize_state = WindowResizeState::Requested(
@ -350,7 +367,8 @@ impl Layout {
); );
}); });
win2.toplevel().with_pending_state(|state| { win2.toplevel().with_pending_state(|state| {
state.size = Some((width_partition, win1_size.h).into()); state.size =
Some((width_partition, i32::max(win1_size.h, 40)).into());
}); });
win2.with_state(|state| { win2.with_state(|state| {
state.resize_state = WindowResizeState::Requested( state.resize_state = WindowResizeState::Requested(

View file

@ -105,6 +105,7 @@ pub struct State<B: Backend> {
impl<B: Backend> State<B> { impl<B: Backend> State<B> {
pub fn handle_msg(&mut self, msg: Msg) { pub fn handle_msg(&mut self, msg: Msg) {
// tracing::debug!("Got {msg:?}");
match msg { match msg {
Msg::SetKeybind { Msg::SetKeybind {
key, key,
@ -491,6 +492,44 @@ impl<B: Backend> State<B> {
}).unwrap(); }).unwrap();
} }
} }
Request::GetTagActive { tag_id } => {
let tag = self
.space
.outputs()
.flat_map(|op| {
op.with_state(|state| state.tags.clone())
})
.find(|tag| tag.id() == tag_id);
if let Some(tag) = tag {
crate::api::send_to_client(
&mut stream,
&OutgoingMsg::RequestResponse {
response: RequestResponse::TagActive {
active: tag.active()
}
})
.unwrap();
}
}
Request::GetTagName { tag_id } => {
let tag = self
.space
.outputs()
.flat_map(|op| {
op.with_state(|state| state.tags.clone())
})
.find(|tag| tag.id() == tag_id);
if let Some(tag) = tag {
crate::api::send_to_client(
&mut stream,
&OutgoingMsg::RequestResponse {
response: RequestResponse::TagName {
name: tag.name()
}
})
.unwrap();
}
}
} }
}, },
} }