mirror of
https://github.com/pinnacle-comp/pinnacle.git
synced 2024-12-26 21:58:10 +01:00
Add to and simplify output in API
This commit is contained in:
parent
f2b54be2fc
commit
53f29086b6
8 changed files with 391 additions and 160 deletions
|
@ -66,14 +66,28 @@ require("pinnacle").setup(function(pinnacle)
|
|||
|
||||
-- Just testing stuff
|
||||
input.keybind({ mod_key }, keys.h, function()
|
||||
local win = window.get_focused()
|
||||
if win ~= nil then
|
||||
print("loc: " .. (win:loc() and win:loc().x or "nil") .. ", " .. (win:loc() and win:loc().y or "nil"))
|
||||
print("size: " .. (win:size() and win:size().w or "nil") .. ", " .. (win:size() and win:size().h or "nil"))
|
||||
print("class: " .. (win:class() or "nil"))
|
||||
print("title: " .. (win:title() or "nil"))
|
||||
print("float: " .. tostring(win:floating()))
|
||||
end
|
||||
-- local win = window.get_focused()
|
||||
-- if win ~= nil then
|
||||
-- print("loc: " .. (win:loc() and win:loc().x or "nil") .. ", " .. (win:loc() and win:loc().y or "nil"))
|
||||
-- print("size: " .. (win:size() and win:size().w or "nil") .. ", " .. (win:size() and win:size().h or "nil"))
|
||||
-- print("class: " .. (win:class() or "nil"))
|
||||
-- print("title: " .. (win:title() or "nil"))
|
||||
-- print("float: " .. tostring(win:floating()))
|
||||
-- end
|
||||
|
||||
local op = output.get_focused() --[[@as Output]]
|
||||
print("res: " .. (op:res() and (op:res().w .. ", " .. op:res().h) or "nil"))
|
||||
print("loc: " .. (op:loc() and (op:loc().x .. ", " .. op:loc().y) or "nil"))
|
||||
print("rr: " .. (op:refresh_rate() or "nil"))
|
||||
print("make: " .. (op:make() or "nil"))
|
||||
print("model: " .. (op:model() or "nil"))
|
||||
print("focused: " .. (tostring(op:focused())))
|
||||
|
||||
-- local tags = tag.get_on_output(output.get_focused())
|
||||
-- for _, tg in pairs(tags) do
|
||||
-- print(tg:name())
|
||||
-- print(tg:output() and tg:output().name or "nil output")
|
||||
-- end
|
||||
end)
|
||||
|
||||
-- Tags ---------------------------------------------------------------------------
|
||||
|
@ -103,6 +117,9 @@ require("pinnacle").setup(function(pinnacle)
|
|||
for _, tg in pairs(tags) do
|
||||
if tg:active() then
|
||||
local name = tg:name()
|
||||
if name == nil then
|
||||
return
|
||||
end
|
||||
tg:set_layout(layouts[indices[name] or 1])
|
||||
if indices[name] == nil then
|
||||
indices[name] = 2
|
||||
|
@ -122,6 +139,9 @@ require("pinnacle").setup(function(pinnacle)
|
|||
for _, tg in pairs(tags) do
|
||||
if tg:active() then
|
||||
local name = tg:name()
|
||||
if name == nil then
|
||||
return
|
||||
end
|
||||
tg:set_layout(layouts[indices[name] or #layouts])
|
||||
if indices[name] == nil then
|
||||
indices[name] = #layouts - 1
|
||||
|
|
|
@ -41,14 +41,15 @@
|
|||
---@field GetWindowClass { window_id: WindowId }
|
||||
---@field GetWindowTitle { window_id: WindowId }
|
||||
--Outputs
|
||||
---@field GetOutputByName { output_name: OutputName }
|
||||
---@field GetOutputsByModel { model: string }
|
||||
---@field GetOutputsByRes { res: integer[] }
|
||||
---@field GetOutputProps { output_name: string }
|
||||
--Tags
|
||||
---@field GetTagsByOutput { output_name: string }
|
||||
---@field GetTagsByName { tag_name: string }
|
||||
---@field GetTagOutput { tag_id: TagId }
|
||||
---@field GetTagActive { tag_id: TagId }
|
||||
---@field GetTagName { tag_id: TagId }
|
||||
|
||||
---@alias Request _Request | "GetWindowByFocus" | "GetAllWindows" | "GetOutputByFocus"
|
||||
---@alias Request _Request | "GetWindowByFocus" | "GetAllWindows" | "GetOutputs"
|
||||
|
||||
---@class IncomingMsg
|
||||
---@field CallCallback { callback_id: integer, args: Args }
|
||||
|
@ -66,15 +67,16 @@
|
|||
--Windows
|
||||
---@field Window { window_id: WindowId|nil }
|
||||
---@field Windows { window_ids: WindowId[] }
|
||||
---@field WindowSize { size: (integer[])? }
|
||||
---@field WindowLocation { loc: (integer[])? }
|
||||
---@field WindowSize { size: integer[]? }
|
||||
---@field WindowLocation { loc: integer[]? }
|
||||
---@field WindowClass { class: string? }
|
||||
---@field WindowTitle { title: string? }
|
||||
---@field WindowFloating { floating: boolean? }
|
||||
--Outputs
|
||||
---@field Output { output_name: OutputName? }
|
||||
---@field Outputs { output_names: OutputName[] }
|
||||
---@field OutputProps { make: string?, model: string?, loc: integer[]?, res: integer[]?, refresh_rate: integer?, physical_size: integer[]?, focused: boolean? }
|
||||
--Tags
|
||||
---@field Tags { tag_ids: TagId[] }
|
||||
---@field TagActive { active: boolean }
|
||||
---@field TagName { name: string }
|
||||
---@field TagActive { active: boolean? }
|
||||
---@field TagName { name: string? }
|
||||
|
|
|
@ -26,10 +26,121 @@ function op:add_tags_table(names)
|
|||
require("tag").add_table(self, names)
|
||||
end
|
||||
|
||||
---Add methods to this output.
|
||||
---Get this output's make.
|
||||
---@return string|nil
|
||||
function op:make()
|
||||
SendRequest({
|
||||
GetOutputProps = {
|
||||
output_name = self.name,
|
||||
},
|
||||
})
|
||||
|
||||
local response = ReadMsg()
|
||||
local props = response.RequestResponse.response.OutputProps
|
||||
return props.make
|
||||
end
|
||||
|
||||
---Get this output's model.
|
||||
---@return string|nil
|
||||
function op:model()
|
||||
SendRequest({
|
||||
GetOutputProps = {
|
||||
output_name = self.name,
|
||||
},
|
||||
})
|
||||
|
||||
local response = ReadMsg()
|
||||
local props = response.RequestResponse.response.OutputProps
|
||||
return props.model
|
||||
end
|
||||
|
||||
---Get this output's location in the global space.
|
||||
---@return { x: integer, y: integer }|nil
|
||||
function op:loc()
|
||||
SendRequest({
|
||||
GetOutputProps = {
|
||||
output_name = self.name,
|
||||
},
|
||||
})
|
||||
|
||||
local response = ReadMsg()
|
||||
local props = response.RequestResponse.response.OutputProps
|
||||
if props.loc == nil then
|
||||
return nil
|
||||
else
|
||||
return { x = props.loc[1], y = props.loc[2] }
|
||||
end
|
||||
end
|
||||
|
||||
---Get this output's resolution in pixels.
|
||||
---@return { w: integer, h: integer }|nil
|
||||
function op:res()
|
||||
SendRequest({
|
||||
GetOutputProps = {
|
||||
output_name = self.name,
|
||||
},
|
||||
})
|
||||
|
||||
local response = ReadMsg()
|
||||
local props = response.RequestResponse.response.OutputProps
|
||||
if props.res == nil then
|
||||
return nil
|
||||
else
|
||||
return { w = props.res[1], h = props.res[2] }
|
||||
end
|
||||
end
|
||||
|
||||
---Get this output's refresh rate in millihertz.
|
||||
---For example, 60Hz will be returned as 60000.
|
||||
---@return integer|nil
|
||||
function op:refresh_rate()
|
||||
SendRequest({
|
||||
GetOutputProps = {
|
||||
output_name = self.name,
|
||||
},
|
||||
})
|
||||
|
||||
local response = ReadMsg()
|
||||
local props = response.RequestResponse.response.OutputProps
|
||||
return props.refresh_rate
|
||||
end
|
||||
|
||||
---Get this output's physical size in millimeters.
|
||||
---@return { w: integer, h: integer }|nil
|
||||
function op:physical_size()
|
||||
SendRequest({
|
||||
GetOutputProps = {
|
||||
output_name = self.name,
|
||||
},
|
||||
})
|
||||
|
||||
local response = ReadMsg()
|
||||
local props = response.RequestResponse.response.OutputProps
|
||||
if props.physical_size == nil then
|
||||
return nil
|
||||
else
|
||||
return { w = props.physical_size[1], h = props.physical_size[2] }
|
||||
end
|
||||
end
|
||||
|
||||
---Get whether or not this output is focused. This is currently defined as having the cursor on it.
|
||||
---@return boolean|nil
|
||||
function op:focused()
|
||||
SendRequest({
|
||||
GetOutputProps = {
|
||||
output_name = self.name,
|
||||
},
|
||||
})
|
||||
|
||||
local response = ReadMsg()
|
||||
local props = response.RequestResponse.response.OutputProps
|
||||
return props.focused
|
||||
end
|
||||
|
||||
---This is an internal global function used to create an output object from an output name.
|
||||
---@param props Output
|
||||
---@return Output
|
||||
local function new_output(props)
|
||||
function NewOutput(props)
|
||||
-- Copy functions over
|
||||
for k, v in pairs(op) do
|
||||
props[k] = v
|
||||
|
@ -40,6 +151,7 @@ end
|
|||
|
||||
------------------------------------------------------
|
||||
|
||||
---@class OutputGlobal
|
||||
local output = {}
|
||||
|
||||
---Get an output by its name.
|
||||
|
@ -56,21 +168,17 @@ local output = {}
|
|||
---@param name string The name of the output.
|
||||
---@return Output|nil output The output, or nil if none have the provided name.
|
||||
function output.get_by_name(name)
|
||||
SendRequest({
|
||||
GetOutputByName = {
|
||||
output_name = name,
|
||||
},
|
||||
})
|
||||
|
||||
SendRequest("GetOutputs")
|
||||
local response = ReadMsg()
|
||||
local output_names = response.RequestResponse.response.Outputs.output_names
|
||||
|
||||
local output_name = response.RequestResponse.response.Output.output_name
|
||||
|
||||
if output_name ~= nil then
|
||||
return new_output({ name = output_name })
|
||||
else
|
||||
return nil
|
||||
for _, output_name in pairs(output_names) do
|
||||
if output_name == name then
|
||||
return NewOutput({ name = output_name })
|
||||
end
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
---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.
|
||||
|
@ -80,20 +188,17 @@ end
|
|||
---@param model string The model of the output(s).
|
||||
---@return Output[] outputs All outputs with this model.
|
||||
function output.get_by_model(model)
|
||||
SendRequest({
|
||||
GetOutputsByModel = {
|
||||
model = model,
|
||||
},
|
||||
})
|
||||
|
||||
SendRequest("GetOutputs")
|
||||
local response = ReadMsg()
|
||||
|
||||
local output_names = response.RequestResponse.response.Outputs.output_names
|
||||
|
||||
---@type Output
|
||||
---@type Output[]
|
||||
local outputs = {}
|
||||
for _, v in pairs(output_names) do
|
||||
table.insert(outputs, new_output({ name = v }))
|
||||
for _, output_name in pairs(output_names) do
|
||||
local o = NewOutput({ name = output_name })
|
||||
if o:model() == model then
|
||||
table.insert(outputs, o)
|
||||
end
|
||||
end
|
||||
|
||||
return outputs
|
||||
|
@ -105,11 +210,7 @@ end
|
|||
---@param height integer The height of the outputs, in pixels.
|
||||
---@return Output[] outputs All outputs with this resolution.
|
||||
function output.get_by_res(width, height)
|
||||
SendRequest({
|
||||
GetOutputsByRes = {
|
||||
res = { width, height },
|
||||
},
|
||||
})
|
||||
SendRequest("GetOutputs")
|
||||
|
||||
local response = ReadMsg()
|
||||
|
||||
|
@ -118,7 +219,10 @@ function output.get_by_res(width, height)
|
|||
---@type Output
|
||||
local outputs = {}
|
||||
for _, output_name in pairs(output_names) do
|
||||
table.insert(outputs, new_output({ name = output_name }))
|
||||
local o = NewOutput({ name = output_name })
|
||||
if o:res() and o:res().w == width and o:res().h == height then
|
||||
table.insert(outputs, o)
|
||||
end
|
||||
end
|
||||
|
||||
return outputs
|
||||
|
@ -145,17 +249,18 @@ end
|
|||
---```
|
||||
---@return Output|nil output The output, or nil if none are focused.
|
||||
function output.get_focused()
|
||||
SendRequest("GetOutputByFocus")
|
||||
|
||||
SendRequest("GetOutputs")
|
||||
local response = ReadMsg()
|
||||
local output_names = response.RequestResponse.response.Outputs.output_names
|
||||
|
||||
local output_name = response.RequestResponse.response.Output.output_name
|
||||
|
||||
if output_name ~= nil then
|
||||
return new_output({ name = output_name })
|
||||
else
|
||||
return nil
|
||||
for _, output_name in pairs(output_names) do
|
||||
local o = NewOutput({ name = output_name })
|
||||
if o:focused() then
|
||||
return o
|
||||
end
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
---Connect a function to be run on all current and future outputs.
|
||||
|
@ -170,7 +275,7 @@ function output.connect_for_all(func)
|
|||
---@param args Args
|
||||
table.insert(CallbackTable, function(args)
|
||||
local args = args.ConnectForAllOutputs
|
||||
func(new_output({ name = args.output_name }))
|
||||
func(NewOutput({ name = args.output_name }))
|
||||
end)
|
||||
SendMsg({
|
||||
ConnectForAllOutputs = {
|
||||
|
|
|
@ -82,6 +82,7 @@ function pinnacle.setup(config_func)
|
|||
---@type fun(args: table?)[]
|
||||
CallbackTable = {}
|
||||
|
||||
---This is an internal global function used to send serialized messages to the Pinnacle server.
|
||||
---@param data Msg
|
||||
function SendMsg(data)
|
||||
local encoded = msgpack.encode(data)
|
||||
|
@ -92,6 +93,7 @@ function pinnacle.setup(config_func)
|
|||
socket.send(socket_fd, encoded)
|
||||
end
|
||||
|
||||
---This is an internal global function used to send requests to the Pinnacle server for information.
|
||||
---@param data Request
|
||||
function SendRequest(data)
|
||||
SendMsg({
|
||||
|
@ -99,6 +101,8 @@ function pinnacle.setup(config_func)
|
|||
})
|
||||
end
|
||||
|
||||
---This is an internal global function used to read messages sent from the server.
|
||||
---These are used to call user-defined functions and provide requested information.
|
||||
function ReadMsg()
|
||||
local msg_len_bytes, err_msg, err_num = read_exact(socket_fd, 4)
|
||||
assert(msg_len_bytes)
|
||||
|
|
|
@ -31,7 +31,7 @@ local function new_tag(props)
|
|||
end
|
||||
|
||||
---Get this tag's active status.
|
||||
---@return boolean active True if the tag is active, otherwise false.
|
||||
---@return boolean|nil active `true` if the tag is active, `false` if not, and `nil` if the tag doesn't exist.
|
||||
function tg:active()
|
||||
SendRequest({
|
||||
GetTagActive = {
|
||||
|
@ -44,6 +44,8 @@ function tg:active()
|
|||
return active
|
||||
end
|
||||
|
||||
---Get this tag's name.
|
||||
---@return string|nil name The name of this tag, or nil if it doesn't exist.
|
||||
function tg:name()
|
||||
SendRequest({
|
||||
GetTagName = {
|
||||
|
@ -56,10 +58,32 @@ function tg:name()
|
|||
return name
|
||||
end
|
||||
|
||||
---Get this tag's output.
|
||||
---@return Output|nil output The output this tag is on, or nil if the tag doesn't exist.
|
||||
function tg:output()
|
||||
SendRequest({
|
||||
GetTagOutput = {
|
||||
tag_id = self.id,
|
||||
},
|
||||
})
|
||||
|
||||
local response = ReadMsg()
|
||||
local output_name = response.RequestResponse.response.Output.output_name
|
||||
|
||||
if output_name == nil then
|
||||
return nil
|
||||
else
|
||||
return NewOutput({ name = output_name })
|
||||
end
|
||||
end
|
||||
|
||||
---Set this tag's layout.
|
||||
---@param layout Layout
|
||||
function tg:set_layout(layout) -- TODO: output param
|
||||
tag.set_layout(self:name(), layout)
|
||||
local name = self:name()
|
||||
if name ~= nil then
|
||||
tag.set_layout(name, layout)
|
||||
end
|
||||
end
|
||||
|
||||
-----------------------------------------------------------
|
||||
|
@ -68,12 +92,14 @@ end
|
|||
---
|
||||
---If you need to add the names as a table, use `tag.add_table` instead.
|
||||
---
|
||||
---You can also do `op:add_tags(...)`.
|
||||
---
|
||||
---### Example
|
||||
---
|
||||
---```lua
|
||||
---local output = output.get_by_name("DP-1")
|
||||
---if output ~= nil then
|
||||
--- tag.add(output, "1", "2", "3", "4", "5") -- Add tags with names 1-5
|
||||
---local op = output.get_by_name("DP-1")
|
||||
---if op ~= nil then
|
||||
--- tag.add(op, "1", "2", "3", "4", "5") -- Add tags with names 1-5
|
||||
---end
|
||||
---```
|
||||
---@param output Output The output you want these tags to be added to.
|
||||
|
@ -237,4 +263,28 @@ function tag.get_on_output(output)
|
|||
return tags
|
||||
end
|
||||
|
||||
---Get all tags with this name across all outputs.
|
||||
---@param name string The name of the tags you want.
|
||||
---@return Tag[]
|
||||
function tag.get_by_name(name)
|
||||
SendRequest({
|
||||
GetTagsByName = {
|
||||
tag_name = name,
|
||||
},
|
||||
})
|
||||
|
||||
local response = ReadMsg()
|
||||
|
||||
local tag_ids = response.RequestResponse.response.Tags.tag_ids
|
||||
|
||||
---@type Tag[]
|
||||
local tags = {}
|
||||
|
||||
for _, tag_id in pairs(tag_ids) do
|
||||
table.insert(tags, new_tag({ id = tag_id }))
|
||||
end
|
||||
|
||||
return tags
|
||||
end
|
||||
|
||||
return tag
|
||||
|
|
|
@ -110,12 +110,12 @@ pub enum Request {
|
|||
GetWindowClass { window_id: WindowId },
|
||||
GetWindowTitle { window_id: WindowId },
|
||||
// Outputs
|
||||
GetOutputByName { output_name: String },
|
||||
GetOutputsByModel { model: String },
|
||||
GetOutputsByRes { res: (u32, u32) },
|
||||
GetOutputByFocus,
|
||||
GetOutputs,
|
||||
GetOutputProps { output_name: String },
|
||||
// Tags
|
||||
GetTagsByOutput { output_name: String },
|
||||
GetTagsByName { tag_name: String },
|
||||
GetTagOutput { tag_id: TagId },
|
||||
GetTagActive { tag_id: TagId },
|
||||
GetTagName { tag_id: TagId },
|
||||
}
|
||||
|
@ -196,16 +196,56 @@ pub enum Args {
|
|||
|
||||
#[derive(Debug, serde::Serialize, serde::Deserialize)]
|
||||
pub enum RequestResponse {
|
||||
Window { window_id: Option<WindowId> },
|
||||
Windows { window_ids: Vec<WindowId> },
|
||||
WindowSize { size: Option<(i32, i32)> },
|
||||
WindowLocation { loc: Option<(i32, i32)> },
|
||||
WindowClass { class: Option<String> },
|
||||
WindowTitle { title: Option<String> },
|
||||
WindowFloating { floating: Option<bool> },
|
||||
Output { output_name: Option<String> },
|
||||
Outputs { output_names: Vec<String> },
|
||||
Tags { tag_ids: Vec<TagId> },
|
||||
TagActive { active: bool },
|
||||
TagName { name: String },
|
||||
Window {
|
||||
window_id: Option<WindowId>,
|
||||
},
|
||||
Windows {
|
||||
window_ids: Vec<WindowId>,
|
||||
},
|
||||
WindowSize {
|
||||
size: Option<(i32, i32)>,
|
||||
},
|
||||
WindowLocation {
|
||||
loc: Option<(i32, i32)>,
|
||||
},
|
||||
WindowClass {
|
||||
class: Option<String>,
|
||||
},
|
||||
WindowTitle {
|
||||
title: Option<String>,
|
||||
},
|
||||
WindowFloating {
|
||||
floating: Option<bool>,
|
||||
},
|
||||
Output {
|
||||
output_name: Option<String>,
|
||||
},
|
||||
Outputs {
|
||||
output_names: Vec<String>,
|
||||
},
|
||||
OutputProps {
|
||||
/// The make of the output.
|
||||
make: Option<String>,
|
||||
/// The model of the output.
|
||||
model: Option<String>,
|
||||
/// The location of the output in the space.
|
||||
loc: Option<(i32, i32)>,
|
||||
/// The resolution of the output.
|
||||
res: Option<(i32, i32)>,
|
||||
/// The refresh rate of the output.
|
||||
refresh_rate: Option<i32>,
|
||||
/// The size of the output, in millimeters.
|
||||
physical_size: Option<(i32, i32)>,
|
||||
/// Whether the output is focused or not.
|
||||
focused: Option<bool>,
|
||||
},
|
||||
Tags {
|
||||
tag_ids: Vec<TagId>,
|
||||
},
|
||||
TagActive {
|
||||
active: Option<bool>,
|
||||
},
|
||||
TagName {
|
||||
name: Option<String>,
|
||||
},
|
||||
}
|
||||
|
|
132
src/state.rs
132
src/state.rs
|
@ -471,74 +471,63 @@ impl<B: Backend> State<B> {
|
|||
)
|
||||
.expect("failed to send to client");
|
||||
}
|
||||
Request::GetOutputByName { output_name } => {
|
||||
// TODO: name better
|
||||
let name = self
|
||||
Request::GetOutputs => {
|
||||
let output_names = self
|
||||
.space
|
||||
.outputs()
|
||||
.find(|output| output.name() == output_name)
|
||||
.map(|output| output.name());
|
||||
crate::api::send_to_client(
|
||||
&mut stream,
|
||||
&OutgoingMsg::RequestResponse {
|
||||
response: RequestResponse::Output { output_name: name },
|
||||
},
|
||||
)
|
||||
.expect("failed to send to client");
|
||||
}
|
||||
Request::GetOutputsByModel { model } => {
|
||||
let names = self
|
||||
.space
|
||||
.outputs()
|
||||
.filter(|output| output.physical_properties().model == model)
|
||||
.map(|output| output.name())
|
||||
.collect::<Vec<_>>();
|
||||
crate::api::send_to_client(
|
||||
&mut stream,
|
||||
&OutgoingMsg::RequestResponse {
|
||||
response: RequestResponse::Outputs {
|
||||
output_names: names,
|
||||
},
|
||||
response: RequestResponse::Outputs { output_names },
|
||||
},
|
||||
)
|
||||
.expect("failed to send to client");
|
||||
}
|
||||
Request::GetOutputsByRes { res } => {
|
||||
let names = self
|
||||
Request::GetOutputProps { output_name } => {
|
||||
let output = self
|
||||
.space
|
||||
.outputs()
|
||||
.filter_map(|output| {
|
||||
if let Some(mode) = output.current_mode() {
|
||||
if mode.size == (res.0 as i32, res.1 as i32).into() {
|
||||
Some(output.name())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
crate::api::send_to_client(
|
||||
&mut stream,
|
||||
&OutgoingMsg::RequestResponse {
|
||||
response: RequestResponse::Outputs {
|
||||
output_names: names,
|
||||
},
|
||||
},
|
||||
.find(|output| output.name() == output_name);
|
||||
let res = output.as_ref().and_then(|output| {
|
||||
output.current_mode().map(|mode| (mode.size.w, mode.size.h))
|
||||
});
|
||||
let refresh_rate = output
|
||||
.as_ref()
|
||||
.and_then(|output| output.current_mode().map(|mode| mode.refresh));
|
||||
let model = output
|
||||
.as_ref()
|
||||
.map(|output| output.physical_properties().model);
|
||||
let physical_size = output.as_ref().map(|output| {
|
||||
(
|
||||
output.physical_properties().size.w,
|
||||
output.physical_properties().size.h,
|
||||
)
|
||||
.expect("failed to send to client");
|
||||
}
|
||||
Request::GetOutputByFocus => {
|
||||
let name = self
|
||||
});
|
||||
let make = output
|
||||
.as_ref()
|
||||
.map(|output| output.physical_properties().make);
|
||||
let loc = output
|
||||
.as_ref()
|
||||
.map(|output| (output.current_location().x, output.current_location().y));
|
||||
let focused = self
|
||||
.focus_state
|
||||
.focused_output
|
||||
.as_ref()
|
||||
.map(|output| output.name());
|
||||
.and_then(|foc_op| output.map(|op| op == foc_op));
|
||||
crate::api::send_to_client(
|
||||
&mut stream,
|
||||
&OutgoingMsg::RequestResponse {
|
||||
response: RequestResponse::Output { output_name: name },
|
||||
response: RequestResponse::OutputProps {
|
||||
make,
|
||||
model,
|
||||
loc,
|
||||
res,
|
||||
refresh_rate,
|
||||
physical_size,
|
||||
focused,
|
||||
},
|
||||
},
|
||||
)
|
||||
.expect("failed to send to client");
|
||||
|
@ -558,42 +547,57 @@ impl<B: Backend> State<B> {
|
|||
.expect("failed to send to client");
|
||||
}
|
||||
}
|
||||
Request::GetTagActive { tag_id } => {
|
||||
let tag = self
|
||||
Request::GetTagsByName { tag_name } => {
|
||||
let tag_ids = self
|
||||
.space
|
||||
.outputs()
|
||||
.flat_map(|op| op.with_state(|state| state.tags.clone()))
|
||||
.find(|tag| tag.id() == tag_id);
|
||||
if let Some(tag) = tag {
|
||||
.filter(|tag| tag.name() == tag_name)
|
||||
.map(|tag| tag.id())
|
||||
.collect::<Vec<_>>();
|
||||
crate::api::send_to_client(
|
||||
&mut stream,
|
||||
&OutgoingMsg::RequestResponse {
|
||||
response: RequestResponse::TagActive {
|
||||
active: tag.active(),
|
||||
},
|
||||
response: RequestResponse::Tags { tag_ids },
|
||||
},
|
||||
)
|
||||
.expect("failed to send to client");
|
||||
}
|
||||
Request::GetTagOutput { tag_id } => {
|
||||
let output_name = tag_id
|
||||
.tag(self)
|
||||
.and_then(|tag| tag.output(self))
|
||||
.map(|output| output.name());
|
||||
crate::api::send_to_client(
|
||||
&mut stream,
|
||||
&OutgoingMsg::RequestResponse {
|
||||
response: RequestResponse::Output { output_name },
|
||||
},
|
||||
)
|
||||
.expect("failed to send to client");
|
||||
}
|
||||
Request::GetTagActive { tag_id } => {
|
||||
let active = tag_id.tag(self).map(|tag| tag.active());
|
||||
crate::api::send_to_client(
|
||||
&mut stream,
|
||||
&OutgoingMsg::RequestResponse {
|
||||
response: RequestResponse::TagActive { active },
|
||||
},
|
||||
)
|
||||
.expect("failed to send to client");
|
||||
}
|
||||
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 {
|
||||
let name = tag_id.tag(self).map(|tag| tag.name());
|
||||
crate::api::send_to_client(
|
||||
&mut stream,
|
||||
&OutgoingMsg::RequestResponse {
|
||||
response: RequestResponse::TagName { name: tag.name() },
|
||||
response: RequestResponse::TagName { name },
|
||||
},
|
||||
)
|
||||
.expect("failed to send to client");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handle_spawn(&self, command: Vec<String>, callback_id: Option<CallbackId>) {
|
||||
let mut command = command.into_iter();
|
||||
|
@ -752,7 +756,7 @@ impl<B: Backend> State<B> {
|
|||
state
|
||||
.tags
|
||||
.iter()
|
||||
.any(|tag| self.output_for_tag(tag).is_some_and(|op| &op == output))
|
||||
.any(|tag| tag.output(self).is_some_and(|op| &op == output))
|
||||
})
|
||||
})
|
||||
.cloned()
|
||||
|
|
18
src/tag.rs
18
src/tag.rs
|
@ -28,6 +28,14 @@ impl TagId {
|
|||
fn next() -> Self {
|
||||
Self(TAG_ID_COUNTER.fetch_add(1, Ordering::Relaxed))
|
||||
}
|
||||
|
||||
pub fn tag<B: Backend>(&self, state: &State<B>) -> Option<Tag> {
|
||||
state
|
||||
.space
|
||||
.outputs()
|
||||
.flat_map(|op| op.with_state(|state| state.tags.clone()))
|
||||
.find(|tag| &tag.id() == self)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -88,13 +96,11 @@ impl Tag {
|
|||
layout: Layout::MasterStack, // TODO: get from config
|
||||
})))
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: Backend> State<B> {
|
||||
pub fn output_for_tag(&self, tag: &Tag) -> Option<Output> {
|
||||
self.space
|
||||
pub fn output<B: Backend>(&self, state: &State<B>) -> Option<Output> {
|
||||
state
|
||||
.space
|
||||
.outputs()
|
||||
.find(|output| output.with_state(|state| state.tags.iter().any(|tg| tg == tag)))
|
||||
.find(|output| output.with_state(|state| state.tags.iter().any(|tg| tg == self)))
|
||||
.cloned()
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue