From 017ef8f09da294e576ea84ffd4060dedc3f0b4a3 Mon Sep 17 00:00:00 2001 From: Ottatop Date: Fri, 21 Jul 2023 21:02:02 -0500 Subject: [PATCH] Restructure API, add doc comments --- api/lua/input.lua | 10 +- api/lua/keys.lua | 6 +- api/lua/output.lua | 279 +++++++++++++++++++++------------ api/lua/process.lua | 11 +- api/lua/tag.lua | 175 ++++++++++++++------- api/lua/window.lua | 364 ++++++++++++++++++++++++++++++++------------ 6 files changed, 586 insertions(+), 259 deletions(-) diff --git a/api/lua/input.lua b/api/lua/input.lua index 8170446..f8eccfa 100644 --- a/api/lua/input.lua +++ b/api/lua/input.lua @@ -4,7 +4,8 @@ -- -- SPDX-License-Identifier: MPL-2.0 -local input = { +---@class InputModule +local input_module = { keys = require("keys"), } @@ -13,8 +14,7 @@ local input = { ---### Example --- ---```lua ------ The following sets Super + Return to open Alacritty ---- +----- Set `Super + Return` to open Alacritty ---input.keybind({ "Super" }, input.keys.Return, function() --- process.spawn("Alacritty") ---end) @@ -22,7 +22,7 @@ local input = { ---@param key Keys The key for the keybind. ---@param modifiers (Modifier)[] Which modifiers need to be pressed for the keybind to trigger. ---@param action fun() What to do. -function input.keybind(modifiers, key, action) +function input_module.keybind(modifiers, key, action) table.insert(CallbackTable, action) SendMsg({ SetKeybind = { @@ -33,4 +33,4 @@ function input.keybind(modifiers, key, action) }) end -return input +return input_module diff --git a/api/lua/keys.lua b/api/lua/keys.lua index 41113ec..6bd89c5 100644 --- a/api/lua/keys.lua +++ b/api/lua/keys.lua @@ -4,7 +4,11 @@ -- -- SPDX-License-Identifier: MPL-2.0 ----@alias Modifier "Alt" | "Ctrl" | "Shift" | "Super" +---@alias Modifier +---| "Alt" # The "Alt" key +---| "Ctrl" # The "Control" key +---| "Shift" # The "Shift" key +---| "Super" # The "Super" key, aka "Meta", "Mod4" in X11, the Windows key, etc. ---@enum Keys local keys = { diff --git a/api/lua/output.lua b/api/lua/output.lua index a80a52c..70431d6 100644 --- a/api/lua/output.lua +++ b/api/lua/output.lua @@ -4,141 +4,97 @@ -- -- SPDX-License-Identifier: MPL-2.0 ----@class OutputGlobal -local output_global = {} +---@class OutputModule +local output_module = {} ---@class Output A display. ---@field private _name string The name of this output (or rather, of its connector). local output = {} +---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 + ---Get this output's name. This is something like "eDP-1" or "HDMI-A-0". ---@return string function output:name() return self._name end ----Get all tags on this output. See `tag.get_on_output`. +---Get all tags on this output. ---@return Tag[] +---@see OutputGlobal.tags — The corresponding module function function output:tags() - return require("tag").get_on_output(self) + return output_module.tags(self) end ----Add tags to this output. See `tag.add`. ----@param ... string The names of the tags you want to add. +---Add tags to this output. +---@param ... string The names of the tags you want to add. You can also pass in a table. ---@overload fun(self: self, tag_names: string[]) +---@see OutputGlobal.add_tags — The corresponding module function function output:add_tags(...) - require("tag").add(self, ...) + output_module.add_tags(self, ...) end ---Get this output's make. ---@return string|nil +---@see OutputGlobal.make — The corresponding module function function output:make() - local response = Request({ - GetOutputProps = { - output_name = self._name, - }, - }) - local props = response.RequestResponse.response.OutputProps - return props.make + return output_module.make(self) end ---Get this output's model. ---@return string|nil +---@see OutputGlobal.model — The corresponding module function function output:model() - local response = Request({ - GetOutputProps = { - output_name = self._name, - }, - }) - local props = response.RequestResponse.response.OutputProps - return props.model + return output_module.model(self) end ----Get this output's location in the global space. +---Get this output's location in the global space, in pixels. ---@return { x: integer, y: integer }|nil +---@see OutputGlobal.loc — The corresponding module function function output:loc() - local response = Request({ - GetOutputProps = { - output_name = self._name, - }, - }) - local props = response.RequestResponse.response.OutputProps - if props.loc == nil then - return nil - else - return { x = props.loc[1], y = props.loc[2] } - end + return output_module.loc(self) end ---Get this output's resolution in pixels. ---@return { w: integer, h: integer }|nil +---@see OutputGlobal.res — The corresponding module function function output:res() - local response = Request({ - GetOutputProps = { - output_name = self._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 + return output_module.res(self) end ---Get this output's refresh rate in millihertz. ---For example, 60Hz will be returned as 60000. ---@return integer|nil +---@see OutputGlobal.refresh_rate — The corresponding module function function output:refresh_rate() - local response = Request({ - GetOutputProps = { - output_name = self._name, - }, - }) - local props = response.RequestResponse.response.OutputProps - return props.refresh_rate + return output_module.refresh_rate(self) end ---Get this output's physical size in millimeters. ---@return { w: integer, h: integer }|nil +---@see OutputGlobal.physical_size — The corresponding module function function output:physical_size() - local response = Request({ - GetOutputProps = { - output_name = self._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 + return output_module.physical_size(self) end ---Get whether or not this output is focused. This is currently defined as having the cursor on it. ---@return boolean|nil +---@see OutputGlobal.focused — The corresponding module function function output:focused() - local response = Request({ - GetOutputProps = { - output_name = self._name, - }, - }) - 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 output_name string The name of the output. ----@return Output -local function new_output(output_name) - ---@type Output - local o = { _name = output_name } - -- Copy functions over - for k, v in pairs(output) do - o[k] = v - end - - return o + return output_module.focused(self) end ------------------------------------------------------ @@ -156,13 +112,13 @@ end ---``` ---@param name string The name of the output. ---@return Output|nil output The output, or nil if none have the provided name. -function output_global.get_by_name(name) +function output_module.get_by_name(name) local response = Request("GetOutputs") local output_names = response.RequestResponse.response.Outputs.output_names for _, output_name in pairs(output_names) do if output_name == name then - return new_output(output_name) + return create_output(output_name) end end @@ -175,14 +131,14 @@ end ---This is something like "DELL E2416H" or whatever gibberish monitor manufacturers call their displays. ---@param model string The model of the output(s). ---@return Output[] outputs All outputs with this model. -function output_global.get_by_model(model) +function output_module.get_by_model(model) local response = Request("GetOutputs") local output_names = response.RequestResponse.response.Outputs.output_names ---@type Output[] local outputs = {} for _, output_name in pairs(output_names) do - local o = new_output(output_name) + local o = create_output(output_name) if o:model() == model then table.insert(outputs, o) end @@ -196,7 +152,7 @@ end ---@param width integer The width of the outputs, in pixels. ---@param height integer The height of the outputs, in pixels. ---@return Output[] outputs All outputs with this resolution. -function output_global.get_by_res(width, height) +function output_module.get_by_res(width, height) local response = Request("GetOutputs") local output_names = response.RequestResponse.response.Outputs.output_names @@ -204,7 +160,7 @@ function output_global.get_by_res(width, height) ---@type Output local outputs = {} for _, output_name in pairs(output_names) do - local o = new_output(output_name) + local o = create_output(output_name) if o:res() and o:res().w == width and o:res().h == height then table.insert(outputs, o) end @@ -233,12 +189,12 @@ end ---local tags = output.get_focused():tags() -- will NOT warn for nil ---``` ---@return Output|nil output The output, or nil if none are focused. -function output_global.get_focused() +function output_module.get_focused() local response = Request("GetOutputs") local output_names = response.RequestResponse.response.Outputs.output_names for _, output_name in pairs(output_names) do - local o = new_output(output_name) + local o = create_output(output_name) if o:focused() then return o end @@ -255,11 +211,11 @@ end ---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. ---@param func fun(output: Output) The function that will be run. -function output_global.connect_for_all(func) +function output_module.connect_for_all(func) ---@param args Args table.insert(CallbackTable, function(args) local args = args.ConnectForAllOutputs - func(new_output(args.output_name)) + func(create_output(args.output_name)) end) SendMsg({ ConnectForAllOutputs = { @@ -271,7 +227,9 @@ end ---Get the output the specified tag is on. ---@param tag Tag ---@return Output|nil -function output_global.get_for_tag(tag) +---@see TagGlobal.output — A global method for fully qualified syntax (for you Rustaceans out there) +---@see Tag.output — The corresponding object method +function output_module.get_for_tag(tag) local response = Request({ GetTagProps = { tag_id = tag:id(), @@ -282,8 +240,137 @@ function output_global.get_for_tag(tag) if output_name == nil then return nil else - return new_output(output_name) + return create_output(output_name) end end -return output_global +---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] } + end +end + +---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 +---@see TagGlobal.get_on_output — The called function +---@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[]) +---@see TagGlobal.add — The called function +---@see Output.add_tags — The corresponding object method +function output_module.add_tags(op, ...) + require("tag").add(op, ...) +end + +return output_module diff --git a/api/lua/process.lua b/api/lua/process.lua index a04fdd6..001eb77 100644 --- a/api/lua/process.lua +++ b/api/lua/process.lua @@ -6,7 +6,8 @@ ---@diagnostic disable: redefined-local -local process = {} +---@class ProcessModule +local process_module = {} ---Spawn a process with an optional callback for its stdout, stderr, and exit information. --- @@ -17,7 +18,7 @@ local process = {} --- - `exit_msg`: The process exited with this message. ---@param command string|string[] The command as one whole string or a table of each of its arguments ---@param callback fun(stdout: string|nil, stderr: string|nil, exit_code: integer|nil, exit_msg: string|nil)? A callback to do something whenever the process's stdout or stderr print a line, or when the process exits. -function process.spawn(command, callback) +function process_module.spawn(command, callback) ---@type integer|nil local callback_id = nil @@ -58,7 +59,7 @@ end ---`spawn_once` checks for the process using `pgrep`. If your system doesn't have `pgrep`, this won't work properly. ---@param command string|string[] The command as one whole string or a table of each of its arguments ---@param callback fun(stdout: string|nil, stderr: string|nil, exit_code: integer|nil, exit_msg: string|nil)? A callback to do something whenever the process's stdout or stderr print a line, or when the process exits. -function process.spawn_once(command, callback) +function process_module.spawn_once(command, callback) local proc = "" if type(command) == "string" then proc = command:match("%S+") @@ -71,7 +72,7 @@ function process.spawn_once(command, callback) if procs:len() ~= 0 then -- if process exists, return return end - process.spawn(command, callback) + process_module.spawn(command, callback) end -return process +return process_module diff --git a/api/lua/tag.lua b/api/lua/tag.lua index 845334d..5fd2e38 100644 --- a/api/lua/tag.lua +++ b/api/lua/tag.lua @@ -4,8 +4,8 @@ -- -- SPDX-License-Identifier: MPL-2.0 ----@class TagGlobal -local tag_global = {} +---@class TagModule +local tag_module = {} ---@alias Layout ---| "MasterStack" # One master window on the left with all other windows stacked to the right. @@ -20,11 +20,13 @@ local tag_global = {} ---@field private _id integer The internal id of this tag. local tag = {} ----@param tag_id integer +---Create a tag from an id. +---The id is the unique identifier for each tag. +---@param id TagId ---@return Tag -local function new_tag(tag_id) +local function create_tag(id) ---@type Tag - local t = { _id = tag_id } + local t = { _id = id } -- Copy functions over for k, v in pairs(tag) do t[k] = v @@ -34,6 +36,7 @@ local function new_tag(tag_id) end ---Get this tag's internal id. +---***You probably won't need to use this.*** ---@return integer function tag:id() return self._id @@ -41,61 +44,49 @@ end ---Get this tag's active status. ---@return boolean|nil active `true` if the tag is active, `false` if not, and `nil` if the tag doesn't exist. +---@see TagGlobal.active — The corresponding module function function tag:active() - local response = Request({ - GetTagProps = { - tag_id = self._id, - }, - }) - local active = response.RequestResponse.response.TagProps.active - return active + return tag_module.active(self) end ---Get this tag's name. ---@return string|nil name The name of this tag, or nil if it doesn't exist. +---@see TagGlobal.name — The corresponding module function function tag:name() - local response = Request({ - GetTagProps = { - tag_id = self._id, - }, - }) - local name = response.RequestResponse.response.TagProps.name - return name + return tag_module.name(self) end ---Get this tag's output. ---@return Output|nil output The output this tag is on, or nil if the tag doesn't exist. +---@see TagGlobal.output — The corresponding module function function tag:output() - return require("output").get_for_tag(self) + return tag_module.output(self) end ---Switch to this tag. +---@see TagGlobal.switch_to — The corresponding module function function tag:switch_to() - tag_global.switch_to(self) + tag_module.switch_to(self) end ---Toggle this tag. +---@see TagGlobal.toggle — The corresponding module function function tag:toggle() - tag_global.toggle(self) + tag_module.toggle(self) end ---Set this tag's layout. ---@param layout Layout +---@see TagGlobal.set_layout — The corresponding module function function tag:set_layout(layout) - local name = self:name() - if name ~= nil then - tag_global.set_layout(name, layout) - end + tag_module.set_layout(self, layout) end ----------------------------------------------------------- ---Add tags to the specified output. --- ----You can also do `output_object:add_tags(...)`. ---- ---### Examples ---- ---```lua ---local op = output.get_by_name("DP-1") ---if op ~= nil then @@ -110,7 +101,8 @@ end ---@param output Output The output you want these tags to be added to. ---@param ... string The names of the new tags you want to add. ---@overload fun(output: Output, tag_names: string[]) -function tag_global.add(output, ...) +---@see Output.add_tags — The corresponding object method +function tag_module.add(output, ...) local varargs = { ... } if type(varargs[1]) == "string" then local tag_names = varargs @@ -148,7 +140,8 @@ end ---@param name string The name of the tag. ---@param output Output? The output. ---@overload fun(t: Tag) -function tag_global.toggle(name, output) +---@see Tag.toggle — The corresponding object method +function tag_module.toggle(name, output) if type(name) == "table" then SendMsg({ ToggleTag = { @@ -165,7 +158,7 @@ function tag_global.toggle(name, output) end print("before tag_global.get_by_name") - local tags = tag_global.get_by_name(name) + local tags = tag_module.get_by_name(name) print("after tag_global.get_by_name") for _, t in pairs(tags) do if t:output() and t:output():name() == output:name() then @@ -185,15 +178,18 @@ end --- ---This is used to replicate what a traditional workspace is on some other Wayland compositors. --- ----### Example ---- +---### Examples ---```lua ----tag.switch_to("3") -- Switches to and displays *only* windows on tag 3 +----- Switches to and displays *only* windows on tag `3` on the focused output. +---tag.switch_to("3") +--- +---local ---``` ---@param name string The name of the tag. ---@param output Output? The output. ---@overload fun(t: Tag) -function tag_global.switch_to(name, output) +---@see Tag.switch_to — The corresponding object method +function tag_module.switch_to(name, output) if type(name) == "table" then SendMsg({ SwitchToTag = { @@ -209,7 +205,7 @@ function tag_global.switch_to(name, output) return end - local tags = tag_global.get_by_name(name) + local tags = tag_module.get_by_name(name) for _, t in pairs(tags) do if t:output() and t:output():name() == output:name() then SendMsg({ @@ -224,11 +220,22 @@ end ---Set a layout for the tag on the specified output. If no output is provided, set it for the tag on the currently focused one. ---Alternatively, provide a tag object instead of a name and output. +--- +---### Examples +---```lua +----- Set tag `1` on `DP-1` to the `Dwindle` layout +---tag.set_layout("1", "Dwindle", output.get_by_name("DP-1")) +--- +----- Do the same as above. Note: if you have more than one tag named `1` then this picks the first one. +---local t = tag.get_by_name("1")[1] +---tag.set_layout(t, "Dwindle") +---``` ---@param name string The name of the tag. ---@param layout Layout The layout. ---@param output Output? The output. ---@overload fun(t: Tag, layout: Layout) -function tag_global.set_layout(name, layout, output) +---@see Tag.set_layout — The corresponding object method +function tag_module.set_layout(name, layout, output) if type(name) == "table" then SendMsg({ SetLayout = { @@ -245,7 +252,7 @@ function tag_global.set_layout(name, layout, output) return end - local tags = tag_global.get_by_name(name) + local tags = tag_module.get_by_name(name) for _, t in pairs(tags) do if t:output() and t:output():name() == output:name() then SendMsg({ @@ -261,15 +268,18 @@ end ---Get all tags on the specified output. --- ----You can also use `output_obj:tags()`, which delegates to this function: +---### Example ---```lua ----local tags_on_output = output.get_focused():tags() ------ This is the same as ------ local tags_on_output = tag.get_on_output(output.get_focused()) +---local op = output.get_focused() +---if op ~= nil then +--- local tags = tag.get_on_output(op) -- All tags on the focused output +---end ---``` ---@param output Output ---@return Tag[] -function tag_global.get_on_output(output) +--- +---@see Output.tags — The corresponding object method +function tag_module.get_on_output(output) local response = Request({ GetOutputProps = { output_name = output:name(), @@ -286,17 +296,26 @@ function tag_global.get_on_output(output) end for _, tag_id in pairs(tag_ids) do - table.insert(tags, new_tag(tag_id)) + table.insert(tags, create_tag(tag_id)) end return tags end ---Get all tags with this name across all outputs. ----@param name string The name of the tags you want. +--- +---### Example +---```lua +----- Given one monitor with the tags "OBS", "OBS", "VSCode", and "Spotify"... +---local tags = tag.get_by_name("OBS") +----- ...will have 2 tags in `tags`, while... +---local no_tags = tag.get_by_name("Firefox") +----- ...will have `no_tags` be empty. +---``` +---@param name string The name of the tag(s) you want. ---@return Tag[] -function tag_global.get_by_name(name) - local t_s = tag_global.get_all() +function tag_module.get_by_name(name) + local t_s = tag_module.get_all() ---@type Tag[] local tags = {} @@ -310,11 +329,17 @@ function tag_global.get_by_name(name) return tags end ----Get all tags across all ouptuts. +---Get all tags across all outputs. +--- +---### Example +---```lua +----- With two monitors with the same tags: "1", "2", "3", "4", and "5"... +---local tags = tag.get_all() +----- ...`tags` should have 10 tags, with 5 pairs of those names across both outputs. +---``` ---@return Tag[] -function tag_global.get_all() +function tag_module.get_all() local response = Request("GetTags") - RPrint(response) local tag_ids = response.RequestResponse.response.Tags.tag_ids @@ -322,10 +347,54 @@ function tag_global.get_all() local tags = {} for _, tag_id in pairs(tag_ids) do - table.insert(tags, new_tag(tag_id)) + table.insert(tags, create_tag(tag_id)) end return tags end -return tag_global +---Get the specified tag's name. +--- +---### Example +---```lua +----- Assuming the tag `Terminal` exists... +---print(tag.name(tag.get_by_name("Terminal")[1])) +----- ...should print `Terminal`. +---``` +---@param t Tag +---@return string|nil +---@see Tag.name — The corresponding object method +function tag_module.name(t) + local response = Request({ + GetTagProps = { + tag_id = t:id(), + }, + }) + local name = response.RequestResponse.response.TagProps.name + return name +end + +---Get whether or not the specified tag is active. +---@param t Tag +---@return boolean|nil +---@see Tag.active — The corresponding object method +function tag_module.active(t) + local response = Request({ + GetTagProps = { + tag_id = t:id(), + }, + }) + local active = response.RequestResponse.response.TagProps.active + return active +end + +---Get the output the specified tag is on. +---@param t Tag +---@return Output|nil +---@see OutputGlobal.get_for_tag — The called function +---@see Tag.output — The corresponding object method +function tag_module.output(t) + return require("output").get_for_tag(t) +end + +return tag_module diff --git a/api/lua/window.lua b/api/lua/window.lua index 2d3b86d..36415f1 100644 --- a/api/lua/window.lua +++ b/api/lua/window.lua @@ -4,8 +4,8 @@ -- -- SPDX-License-Identifier: MPL-2.0 ----@class WindowGlobal -local window_global = {} +---@class WindowModule +local window_module = {} ---@class Window ---@field private _id integer The internal id of this window @@ -13,7 +13,7 @@ local window = {} ---@param window_id WindowId ---@return Window -local function new_window(window_id) +local function create_window(window_id) ---@type Window local w = { _id = window_id } -- Copy functions over @@ -24,7 +24,15 @@ local function new_window(window_id) return w end ----Set a window's size. +---Get this window's unique id. +--- +---***You will probably not need to use this.*** +---@return WindowId +function window:id() + return self._id +end + +---Set this window's size. --- ---### Examples ---```lua @@ -33,17 +41,12 @@ end ---window.get_focused():set_size({}) -- do absolutely nothing useful ---``` ---@param size { w: integer?, h: integer? } +---@see WindowGlobal.set_size — The corresponding module function function window:set_size(size) - SendMsg({ - SetWindowSize = { - window_id = self._id, - width = size.w, - height = size.h, - }, - }) + window_module.set_size(self, size) end ----Move a window to a tag, removing all other ones. +---Move this window to a tag, removing all other ones. --- ---### Example ---```lua @@ -54,8 +57,9 @@ end ---@param name string ---@param output Output? ---@overload fun(self: self, t: Tag) +---@see WindowGlobal.move_to_tag — The corresponding module function function window:move_to_tag(name, output) - window_global.move_to_tag(self, name, output) + window_module.move_to_tag(self, name, output) end ---Toggle the specified tag for this window. @@ -71,8 +75,9 @@ end ---@param name string ---@param output Output? ---@overload fun(self: self, t: Tag) +---@see WindowGlobal.toggle_tag — The corresponding module function function window:toggle_tag(name, output) - window_global.toggle_tag(self, name, output) + window_module.toggle_tag(self, name, output) end ---Close this window. @@ -84,12 +89,9 @@ end ---```lua ---window.get_focused():close() -- close the currently focused window ---``` +---@see WindowGlobal.close — The corresponding module function function window:close() - SendMsg({ - CloseWindow = { - window_id = self._id, - }, - }) + window_module.close(self) end ---Toggle this window's floating status. @@ -98,15 +100,12 @@ end ---```lua ---window.get_focused():toggle_floating() -- toggles the focused window between tiled and floating ---``` +---@see WindowGlobal.toggle_floating — The corresponding module function function window:toggle_floating() - SendMsg({ - ToggleFloating = { - window_id = self._id, - }, - }) + window_module.toggle_floating(self) end ----Get a window's size. +---Get this window's size. --- ---### Example ---```lua @@ -115,21 +114,9 @@ end ----- ...should have size equal to `{ w = 3840, h = 2160 }`. ---``` ---@return { w: integer, h: integer }|nil size The size of the window, or nil if it doesn't exist. +---@see WindowGlobal.size — The corresponding module function function window:size() - local response = Request({ - GetWindowProps = { - window_id = self._id, - }, - }) - local size = response.RequestResponse.response.WindowProps.size - if size == nil then - return nil - else - return { - w = size[1], - h = size[2], - } - end + return window_module.size(self) end ---Get this window's location in the global space. @@ -146,21 +133,9 @@ end ----- ...should have loc equal to `{ x = 1920, y = 0 }`. ---``` ---@return { x: integer, y: integer }|nil loc The location of the window, or nil if it's not on-screen or alive. +---@see WindowGlobal.loc — The corresponding module function function window:loc() - local response = Request({ - GetWindowProps = { - window_id = self._id, - }, - }) - local loc = response.RequestResponse.response.WindowProps.loc - if loc == nil then - return nil - else - return { - x = loc[1], - y = loc[2], - } - end + return window_module.loc(self) end ---Get this window's class. This is usually the name of the application. @@ -172,14 +147,9 @@ end ----- ...should print "Alacritty". ---``` ---@return string|nil class This window's class, or nil if it doesn't exist. +---@see WindowGlobal.class — The corresponding module function function window:class() - local response = Request({ - GetWindowProps = { - window_id = self._id, - }, - }) - local class = response.RequestResponse.response.WindowProps.class - return class + return window_module.class(self) end ---Get this window's title. @@ -191,14 +161,9 @@ end ----- ...should print the directory Alacritty is in or what it's running (what's in its title bar). ---``` ---@return string|nil title This window's title, or nil if it doesn't exist. +---@see WindowGlobal.title — The corresponding module function function window:title() - local response = Request({ - GetWindowProps = { - window_id = self._id, - }, - }) - local title = response.RequestResponse.response.WindowProps.title - return title + return window_module.title(self) end ---Get this window's floating status. @@ -210,14 +175,9 @@ end ----- ...should print `true`. ---``` ---@return boolean|nil floating `true` if it's floating, `false` if it's tiled, or nil if it doesn't exist. +---@see WindowGlobal.floating — The corresponding module function function window:floating() - local response = Request({ - GetWindowProps = { - window_id = self._id, - }, - }) - local floating = response.RequestResponse.response.WindowProps.floating - return floating + return window_module.floating(self) end ---Get whether or not this window is focused. @@ -227,19 +187,9 @@ end ---print(window.get_focused():focused()) -- should print `true`. ---``` ---@return boolean|nil floating `true` if it's floating, `false` if it's tiled, or nil if it doesn't exist. +---@see WindowGlobal.focused — The corresponding module function function window:focused() - local response = Request({ - GetWindowProps = { - window_id = self._id, - }, - }) - local focused = response.RequestResponse.response.WindowProps.focused - return focused -end - ----@return WindowId -function window:id() - return self._id + return window_module.focused(self) end ------------------------------------------------------------------- @@ -247,8 +197,8 @@ end ---Get all windows with the specified class (usually the name of the application). ---@param class string The class. For example, Alacritty's class is "Alacritty". ---@return Window[] -function window_global.get_by_class(class) - local windows = window_global.get_all() +function window_module.get_by_class(class) + local windows = window_module.get_all() ---@type Window[] local windows_ret = {} @@ -264,8 +214,8 @@ end ---Get all windows with the specified title. ---@param title string The title. ---@return Window[] -function window_global.get_by_title(title) - local windows = window_global.get_all() +function window_module.get_by_title(title) + local windows = window_module.get_all() ---@type Window[] local windows_ret = {} @@ -280,8 +230,8 @@ end ---Get the currently focused window. ---@return Window|nil -function window_global.get_focused() - local windows = window_global.get_all() +function window_module.get_focused() + local windows = window_module.get_all() for _, w in pairs(windows) do if w:focused() then @@ -294,21 +244,24 @@ end ---Get all windows. ---@return Window[] -function window_global.get_all() +function window_module.get_all() local window_ids = Request("GetWindows").RequestResponse.response.Windows.window_ids ---@type Window[] local windows = {} for _, window_id in pairs(window_ids) do - table.insert(windows, new_window(window_id)) + table.insert(windows, create_window(window_id)) end return windows end ----comment +---Toggle the tag with the given name and (optional) output for the specified window. +---You can also provide a tag object instead of a name and output. ---@param w Window ---@param name string ---@param output Output? -function window_global.toggle_tag(w, name, output) +---@overload fun(w: Window, t: Tag) +---@see WindowGlobal.toggle_tag — The corresponding object method +function window_module.toggle_tag(w, name, output) if type(name) == "table" then SendMsg({ ToggleTagOnWindow = { @@ -339,12 +292,14 @@ function window_global.toggle_tag(w, name, output) end end ----comment +---Move the specified window to the tag with the given name and (optional) output. +---You can also provide a tag object instead of a name and output. ---@param w Window ---@param name string ---@param output Output? ---@overload fun(w: Window, t: Tag) -function window_global.move_to_tag(w, name, output) +---@see WindowGlobal.move_to_tag — The corresponding object method +function window_module.move_to_tag(w, name, output) if type(name) == "table" then SendMsg({ MoveWindowToTag = { @@ -375,4 +330,215 @@ function window_global.move_to_tag(w, name, output) end end -return window_global +---Set the specified window's size. +--- +---### Examples +---```lua +---local win = window.get_focused() +---if win ~= nil then +--- window.set_size(win, { w = 500, h = 500 }) -- make the window square and 500 pixels wide/tall +--- window.set_size(win, { h = 300 }) -- keep the window's width but make it 300 pixels tall +--- window.set_size(win, {}) -- do absolutely nothing useful +---end +---``` +---@param win Window +---@param size { w: integer?, h: integer? } +---@see WindowGlobal.set_size — The corresponding object method +function window_module.set_size(win, size) + SendMsg({ + SetWindowSize = { + window_id = win:id(), + width = size.w, + height = size.h, + }, + }) +end + +---Close the specified window. +--- +---This only sends a close *event* to the window and is the same as just clicking the X button in the titlebar. +---This will trigger save prompts in applications like GIMP. +--- +---### Example +---```lua +---local win = window.get_focused() +---if win ~= nil then +--- window.close(win) -- close the currently focused window +---end +---``` +---@param win Window +---@see WindowGlobal.close — The corresponding object method +function window_module.close(win) + SendMsg({ + CloseWindow = { + window_id = win:id(), + }, + }) +end + +---Toggle the specified window between tiled and floating. +---@param win Window +---@see WindowGlobal.toggle_floating — The corresponding object method +function window_module.toggle_floating(win) + SendMsg({ + ToggleFloating = { + window_id = win:id(), + }, + }) +end + +---Get the specified window's size. +--- +---### Example +---```lua +----- With a 4K monitor, given a focused fullscreen window `win`... +---local size = window.size(win) +----- ...should have size equal to `{ w = 3840, h = 2160 }`. +---``` +---@param win Window +---@return { w: integer, h: integer }|nil size The size of the window, or nil if it doesn't exist. +---@see WindowGlobal.size — The corresponding object method +function window_module.size(win) + local response = Request({ + GetWindowProps = { + window_id = win:id(), + }, + }) + local size = response.RequestResponse.response.WindowProps.size + if size == nil then + return nil + else + return { + w = size[1], + h = size[2], + } + end +end + +---Get the specified window's location in the global space. +--- +---Think of your monitors as being laid out on a big sheet. +---The top left of the sheet if you trim it down is (0, 0). +---The location of this window is relative to that point. +--- +---### Example +---```lua +----- With two 1080p monitors side by side and set up as such, +----- if a window `win` is fullscreen on the right one... +---local loc = window.loc(win) +----- ...should have loc equal to `{ x = 1920, y = 0 }`. +---``` +---@param win Window +---@return { x: integer, y: integer }|nil loc The location of the window, or nil if it's not on-screen or alive. +---@see WindowGlobal.loc — The corresponding object method +function window_module.loc(win) + local response = Request({ + GetWindowProps = { + window_id = win:id(), + }, + }) + local loc = response.RequestResponse.response.WindowProps.loc + if loc == nil then + return nil + else + return { + x = loc[1], + y = loc[2], + } + end +end + +---Get the specified window's class. This is usually the name of the application. +--- +---### Example +---```lua +----- With Alacritty focused... +---local win = window.get_focused() +---if win ~= nil then +--- print(window.class(win)) +---end +----- ...should print "Alacritty". +---``` +---@param win Window +---@return string|nil class This window's class, or nil if it doesn't exist. +---@see WindowGlobal.class — The corresponding object method +function window_module.class(win) + local response = Request({ + GetWindowProps = { + window_id = win:id(), + }, + }) + local class = response.RequestResponse.response.WindowProps.class + return class +end + +---Get the specified window's title. +--- +---### Example +---```lua +----- With Alacritty focused... +---local win = window.get_focused() +---if win ~= nil then +--- print(window.title(win)) +---end +----- ...should print the directory Alacritty is in or what it's running (what's in its title bar). +---``` +---@param win Window +---@return string|nil title This window's title, or nil if it doesn't exist. +---@see WindowGlobal.title — The corresponding object method +function window_module.title(win) + local response = Request({ + GetWindowProps = { + window_id = win:id(), + }, + }) + local title = response.RequestResponse.response.WindowProps.title + return title +end + +---Get this window's floating status. +--- +---### Example +---```lua +----- With the focused window floating... +---local win = window.get_focused() +---if win ~= nil then +--- print(window.floating(win)) +---end +----- ...should print `true`. +---``` +---@param win Window +---@return boolean|nil floating `true` if it's floating, `false` if it's tiled, or nil if it doesn't exist. +---@see WindowGlobal.floating — The corresponding object method +function window_module.floating(win) + local response = Request({ + GetWindowProps = { + window_id = win:id(), + }, + }) + local floating = response.RequestResponse.response.WindowProps.floating + return floating +end + +---Get whether or not this window is focused. +--- +---### Example +---```lua +---local win = window.get_focused() +---if win ~= nil then +--- print(window.focused(win)) -- Should print `true` +---end +---``` +---@param win Window +---@return boolean|nil floating `true` if it's floating, `false` if it's tiled, or nil if it doesn't exist. +---@see WindowGlobal.focused — The corresponding object method +function window_module.focused(win) + local response = Request({ + GetWindowProps = { + window_id = win:id(), + }, + }) + local focused = response.RequestResponse.response.WindowProps.focused + return focused +end +return window_module