mirror of
https://github.com/pinnacle-comp/pinnacle.git
synced 2024-12-26 21:58:10 +01:00
Add per tag layouts
This commit is contained in:
parent
92b10121a3
commit
a6a62be446
9 changed files with 170 additions and 51 deletions
|
@ -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)
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 },
|
||||
},
|
||||
})
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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,
|
||||
},
|
||||
})
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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 },
|
||||
}
|
||||
|
|
|
@ -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(
|
||||
|
|
39
src/state.rs
39
src/state.rs
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue