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",
"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()
tag.set_layout("1", layouts[index])
if index + 1 > #layouts then
index = 1
else
index = index + 1
local tags = output.get_focused():tags()
for _, tg in pairs(tags) do
if tg:active() then
local name = tg:name()
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)
input.keybind({ mod_key, "Shift" }, keys.space, function()
tag.set_layout("1", layouts[index])
if index - 1 < 1 then
index = #layouts
else
index = index - 1
local tags = output.get_focused():tags()
for _, tg in pairs(tags) do
if tg:active() then
local name = tg:name()
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)

View file

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

View file

@ -56,11 +56,9 @@ local output = {}
---@param name string The name of the output.
---@return Output|nil
function output.get_by_name(name)
SendMsg({
Request = {
GetOutputByName = {
name = name,
},
SendRequest({
GetOutputByName = {
name = name,
},
})
@ -82,11 +80,9 @@ end
---@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.
function output.get_by_model(model)
SendMsg({
Request = {
GetOutputsByModel = {
model = model,
},
SendRequest({
GetOutputsByModel = {
model = model,
},
})
@ -109,11 +105,9 @@ end
---@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.
function output.get_by_res(width, height)
SendMsg({
Request = {
GetOutputsByRes = {
res = { width, height },
},
SendRequest({
GetOutputsByRes = {
res = { width, height },
},
})

View file

@ -19,6 +19,7 @@ local function read_exact(socket_fd, count)
local len_to_read = count
local data = ""
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)
if bytes == nil then
@ -105,9 +106,11 @@ function pinnacle.setup(config_func)
---@type integer
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)
assert(msg_bytes)
-- print(msg_bytes)
---@type IncomingMsg
local tb = msgpack.decode(msg_bytes)

View file

@ -4,6 +4,8 @@
--
-- SPDX-License-Identifier: MPL-2.0
local tag = {}
---@alias Layout
---| "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.
@ -28,7 +30,39 @@ local function new_tag(props)
return props
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.
---
@ -183,11 +217,9 @@ end
---@param output Output
---@return Tag[]
function tag.get_on_output(output)
SendMsg({
Request = {
GetTagsByOutput = {
output = output.name,
},
SendRequest({
GetTagsByOutput = {
output = output.name,
},
})

View file

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

View file

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

View file

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

View file

@ -105,6 +105,7 @@ pub struct State<B: Backend> {
impl<B: Backend> State<B> {
pub fn handle_msg(&mut self, msg: Msg) {
// tracing::debug!("Got {msg:?}");
match msg {
Msg::SetKeybind {
key,
@ -491,6 +492,44 @@ impl<B: Backend> State<B> {
}).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();
}
}
}
},
}