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