pinnacle/api/lua/output.lua

373 lines
12 KiB
Lua
Raw Normal View History

2023-08-01 18:06:35 +02:00
-- SPDX-License-Identifier: GPL-3.0-or-later
2023-07-11 18:59:38 +02:00
2023-07-22 04:02:02 +02:00
---@class OutputModule
local output_module = {}
2023-07-11 18:59:38 +02:00
---@class Output A display.
2023-07-20 22:22:22 +02:00
---@field private _name string The name of this output (or rather, of its connector).
local output = {}
2023-07-11 18:59:38 +02:00
2023-07-22 04:02:02 +02:00
---Create a new output object from a name.
---The name is the unique identifier for each output.
---@param name string
---@return Output
local function create_output(name)
---@type Output
local o = { _name = name }
-- Copy functions over
for k, v in pairs(output) do
o[k] = v
end
return o
end
2023-07-20 22:22:22 +02:00
---Get this output's name. This is something like "eDP-1" or "HDMI-A-0".
---@return string
function output:name()
2023-07-20 22:22:22 +02:00
return self._name
end
2023-07-22 04:02:02 +02:00
---Get all tags on this output.
2023-07-18 17:31:08 +02:00
---@return Tag[]
2023-07-22 04:44:56 +02:00
---@see OutputModule.tags — The corresponding module function
function output:tags()
2023-07-22 04:02:02 +02:00
return output_module.tags(self)
2023-07-18 17:31:08 +02:00
end
2023-07-22 04:02:02 +02:00
---Add tags to this output.
---@param ... string The names of the tags you want to add. You can also pass in a table.
2023-07-20 23:54:26 +02:00
---@overload fun(self: self, tag_names: string[])
2023-07-22 04:44:56 +02:00
---@see OutputModule.add_tags — The corresponding module function
function output:add_tags(...)
2023-07-22 04:02:02 +02:00
output_module.add_tags(self, ...)
2023-07-18 17:31:08 +02:00
end
2023-07-20 01:55:22 +02:00
---Get this output's make.
---@return string|nil
2023-07-22 04:44:56 +02:00
---@see OutputModule.make — The corresponding module function
function output:make()
2023-07-22 04:02:02 +02:00
return output_module.make(self)
2023-07-20 01:55:22 +02:00
end
---Get this output's model.
---@return string|nil
2023-07-22 04:44:56 +02:00
---@see OutputModule.model — The corresponding module function
function output:model()
2023-07-22 04:02:02 +02:00
return output_module.model(self)
2023-07-20 01:55:22 +02:00
end
2023-07-22 04:02:02 +02:00
---Get this output's location in the global space, in pixels.
2023-07-20 01:55:22 +02:00
---@return { x: integer, y: integer }|nil
2023-07-22 04:44:56 +02:00
---@see OutputModule.loc — The corresponding module function
function output:loc()
2023-07-22 04:02:02 +02:00
return output_module.loc(self)
2023-07-20 01:55:22 +02:00
end
---Get this output's resolution in pixels.
---@return { w: integer, h: integer }|nil
2023-07-22 04:44:56 +02:00
---@see OutputModule.res — The corresponding module function
function output:res()
2023-07-22 04:02:02 +02:00
return output_module.res(self)
2023-07-20 01:55:22 +02:00
end
---Get this output's refresh rate in millihertz.
---For example, 60Hz will be returned as 60000.
---@return integer|nil
2023-07-22 04:44:56 +02:00
---@see OutputModule.refresh_rate — The corresponding module function
function output:refresh_rate()
2023-07-22 04:02:02 +02:00
return output_module.refresh_rate(self)
2023-07-20 01:55:22 +02:00
end
---Get this output's physical size in millimeters.
---@return { w: integer, h: integer }|nil
2023-07-22 04:44:56 +02:00
---@see OutputModule.physical_size — The corresponding module function
function output:physical_size()
2023-07-22 04:02:02 +02:00
return output_module.physical_size(self)
2023-07-20 01:55:22 +02:00
end
---Get whether or not this output is focused. This is currently defined as having the cursor on it.
---@return boolean|nil
2023-07-22 04:44:56 +02:00
---@see OutputModule.focused — The corresponding module function
function output:focused()
2023-07-22 04:02:02 +02:00
return output_module.focused(self)
2023-07-11 18:59:38 +02:00
end
------------------------------------------------------
---Get an output by its name.
---
---"Name" in this sense does not mean its model or manufacturer;
---rather, "name" is the name of the connector the output is connected to.
---This should be something like "HDMI-A-0", "eDP-1", or similar.
---
2023-07-18 22:12:23 +02:00
---### Example
2023-07-11 18:59:38 +02:00
---```lua
---local monitor = output.get_by_name("DP-1")
---print(monitor.name) -- should print `DP-1`
---```
---@param name string The name of the output.
2023-07-19 04:10:43 +02:00
---@return Output|nil output The output, or nil if none have the provided name.
2023-07-22 04:02:02 +02:00
function output_module.get_by_name(name)
2023-07-21 22:04:39 +02:00
local response = Request("GetOutputs")
2023-07-20 01:55:22 +02:00
local output_names = response.RequestResponse.response.Outputs.output_names
2023-07-11 18:59:38 +02:00
2023-07-20 01:55:22 +02:00
for _, output_name in pairs(output_names) do
if output_name == name then
2023-07-22 04:02:02 +02:00
return create_output(output_name)
2023-07-20 01:55:22 +02:00
end
2023-07-11 18:59:38 +02:00
end
2023-07-20 01:55:22 +02:00
return nil
2023-07-11 18:59:38 +02:00
end
2023-07-18 17:31:08 +02:00
---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.
2023-07-11 18:59:38 +02:00
---
---Get outputs by their model.
---This is something like "DELL E2416H" or whatever gibberish monitor manufacturers call their displays.
---@param model string The model of the output(s).
2023-07-19 04:10:43 +02:00
---@return Output[] outputs All outputs with this model.
2023-07-22 04:02:02 +02:00
function output_module.get_by_model(model)
2023-07-21 22:04:39 +02:00
local response = Request("GetOutputs")
2023-07-18 22:12:23 +02:00
local output_names = response.RequestResponse.response.Outputs.output_names
2023-07-11 18:59:38 +02:00
2023-07-20 01:55:22 +02:00
---@type Output[]
2023-07-11 18:59:38 +02:00
local outputs = {}
2023-07-20 01:55:22 +02:00
for _, output_name in pairs(output_names) do
2023-07-22 04:02:02 +02:00
local o = create_output(output_name)
2023-07-20 01:55:22 +02:00
if o:model() == model then
table.insert(outputs, o)
end
2023-07-11 18:59:38 +02:00
end
return outputs
end
---Get outputs by their resolution.
---
---@param width integer The width of the outputs, in pixels.
---@param height integer The height of the outputs, in pixels.
2023-07-19 04:10:43 +02:00
---@return Output[] outputs All outputs with this resolution.
2023-07-22 04:02:02 +02:00
function output_module.get_by_res(width, height)
2023-07-21 22:04:39 +02:00
local response = Request("GetOutputs")
2023-07-11 18:59:38 +02:00
2023-07-18 22:12:23 +02:00
local output_names = response.RequestResponse.response.Outputs.output_names
2023-07-11 18:59:38 +02:00
2023-07-23 00:43:36 +02:00
---@type Output[]
2023-07-11 18:59:38 +02:00
local outputs = {}
2023-07-18 22:12:23 +02:00
for _, output_name in pairs(output_names) do
2023-07-22 04:02:02 +02:00
local o = create_output(output_name)
2023-07-20 01:55:22 +02:00
if o:res() and o:res().w == width and o:res().h == height then
table.insert(outputs, o)
end
2023-07-11 18:59:38 +02:00
end
return outputs
end
2023-07-12 04:07:51 +02:00
---Get the currently focused output. This is currently implemented as the one with the cursor on it.
2023-07-18 17:31:08 +02:00
---
---This function may return nil, which means you may get a warning if you try to use it without checking for nil.
---Usually this function will not be nil unless you unplug all monitors, so instead of checking,
---you can ignore the warning by either forcing the type to be non-nil with an inline comment:
---```lua
---local op = output.get_focused() --[[@as Output]]
---```
---or by disabling nil check warnings for the line:
---```lua
---local op = output.get_focused()
------@diagnostic disable-next-line:need-check-nil
---local tags_on_output = op:tags()
---```
---Type checking done by Lua LS isn't perfect.
---Note that directly using the result of this function inline will *not* raise a warning, so be careful.
---```lua
---local tags = output.get_focused():tags() -- will NOT warn for nil
---```
---@return Output|nil output The output, or nil if none are focused.
2023-07-22 04:02:02 +02:00
function output_module.get_focused()
2023-07-21 22:04:39 +02:00
local response = Request("GetOutputs")
2023-07-20 01:55:22 +02:00
local output_names = response.RequestResponse.response.Outputs.output_names
2023-07-20 01:55:22 +02:00
for _, output_name in pairs(output_names) do
2023-07-22 04:02:02 +02:00
local o = create_output(output_name)
2023-07-20 01:55:22 +02:00
if o:focused() then
return o
end
end
2023-07-20 01:55:22 +02:00
return nil
end
2023-07-11 18:59:38 +02:00
---Connect a function to be run on all current and future outputs.
---
---When called, `connect_for_all` will immediately run `func` with all currently connected outputs.
---If a new output is connected, `func` will also be called with it.
---
---Please note: this function will be run *after* Pinnacle processes your entire config.
---For example, if you define tags in `func` but toggle them directly after `connect_for_all`, nothing will happen as the tags haven't been added yet.
2023-07-11 18:59:38 +02:00
---@param func fun(output: Output) The function that will be run.
2023-07-22 04:02:02 +02:00
function output_module.connect_for_all(func)
2023-07-11 18:59:38 +02:00
---@param args Args
table.insert(CallbackTable, function(args)
local args = args.ConnectForAllOutputs
2023-07-22 04:02:02 +02:00
func(create_output(args.output_name))
2023-07-11 18:59:38 +02:00
end)
SendMsg({
ConnectForAllOutputs = {
callback_id = #CallbackTable,
},
})
end
2023-07-20 22:22:22 +02:00
---Get the output the specified tag is on.
---@param tag Tag
---@return Output|nil
2023-07-22 04:44:56 +02:00
---@see TagModule.output — A global method for fully qualified syntax (for you Rustaceans out there)
2023-07-22 04:02:02 +02:00
---@see Tag.output — The corresponding object method
function output_module.get_for_tag(tag)
2023-07-21 22:04:39 +02:00
local response = Request({
2023-07-20 23:05:26 +02:00
GetTagProps = {
2023-07-20 22:22:22 +02:00
tag_id = tag:id(),
},
2023-07-21 22:04:39 +02:00
})
2023-07-20 23:05:26 +02:00
local output_name = response.RequestResponse.response.TagProps.output_name
2023-07-20 22:22:22 +02:00
if output_name == nil then
return nil
else
2023-07-22 04:02:02 +02:00
return create_output(output_name)
end
end
---Get the specified output's make.
---@param op Output
---@return string|nil
---@see Output.make — The corresponding object method
function output_module.make(op)
local response = Request({
GetOutputProps = {
output_name = op:name(),
},
})
local props = response.RequestResponse.response.OutputProps
return props.make
end
---Get the specified output's model.
---@param op Output
---@return string|nil
---@see Output.model — The corresponding object method
function output_module.model(op)
local response = Request({
GetOutputProps = {
output_name = op:name(),
},
})
local props = response.RequestResponse.response.OutputProps
return props.model
end
---Get the specified output's location in the global space, in pixels.
---@param op Output
---@return { x: integer, y: integer }|nil
---@see Output.loc — The corresponding object method
function output_module.loc(op)
local response = Request({
GetOutputProps = {
output_name = op:name(),
},
})
local props = response.RequestResponse.response.OutputProps
if props.loc == nil then
return nil
else
return { x = props.loc[1], y = props.loc[2] }
2023-07-20 22:22:22 +02:00
end
end
2023-07-22 04:02:02 +02:00
---Get the specified output's resolution in pixels.
---@param op Output
---@return { w: integer, h: integer }|nil
---@see Output.res — The corresponding object method
function output_module.res(op)
local response = Request({
GetOutputProps = {
output_name = op:name(),
},
})
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 the specified output's refresh rate in millihertz.
---For example, 60Hz will be returned as 60000.
---@param op Output
---@return integer|nil
---@see Output.refresh_rate — The corresponding object method
function output_module.refresh_rate(op)
local response = Request({
GetOutputProps = {
output_name = op:name(),
},
})
local props = response.RequestResponse.response.OutputProps
return props.refresh_rate
end
---Get the specified output's physical size in millimeters.
---@param op Output
---@return { w: integer, h: integer }|nil
---@see Output.physical_size — The corresponding object method
function output_module.physical_size(op)
local response = Request({
GetOutputProps = {
output_name = op:name(),
},
})
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 the specified output is focused. This is currently defined as having the cursor on it.
---@param op Output
---@return boolean|nil
---@see Output.focused — The corresponding object method
function output_module.focused(op)
local response = Request({
GetOutputProps = {
output_name = op:name(),
},
})
local props = response.RequestResponse.response.OutputProps
return props.focused
end
---Get the specified output's tags.
---@param op Output
2023-07-22 04:44:56 +02:00
---@see TagModule.get_on_output — The called function
2023-07-22 04:02:02 +02:00
---@see Output.tags — The corresponding object method
function output_module.tags(op)
return require("tag").get_on_output(op)
end
---Add tags to the specified output.
---@param op Output
---@param ... string The names of the tags you want to add. You can also pass in a table.
---@overload fun(op: Output, tag_names: string[])
2023-07-22 04:44:56 +02:00
---@see TagModule.add — The called function
2023-07-22 04:02:02 +02:00
---@see Output.add_tags — The corresponding object method
function output_module.add_tags(op, ...)
require("tag").add(op, ...)
end
return output_module