mirror of
https://github.com/pinnacle-comp/pinnacle.git
synced 2024-12-25 09:59:21 +01:00
Add docs to new Lua API
1000% sure I'm gonna have to rewrite my LDoc generation tool to actually work
This commit is contained in:
parent
7fe56ed949
commit
a8239f171e
11 changed files with 910 additions and 127 deletions
|
@ -12,47 +12,46 @@ require("pinnacle").setup(function(Pinnacle)
|
|||
|
||||
local terminal = "alacritty"
|
||||
|
||||
Input:set_mousebind({ mod_key }, "left", "press", function()
|
||||
Window:begin_move("left")
|
||||
Input:mousebind({ mod_key }, "btn_left", "press", function()
|
||||
Window:begin_move("btn_left")
|
||||
end)
|
||||
|
||||
Input:set_mousebind({ mod_key }, "right", "press", function()
|
||||
Window:begin_resize("right")
|
||||
Input:mousebind({ mod_key }, "btn_right", "press", function()
|
||||
Window:begin_resize("btn_right")
|
||||
end)
|
||||
|
||||
------
|
||||
|
||||
Input:set_keybind({ mod_key, "alt" }, "q", function()
|
||||
print("GOT QUIT")
|
||||
Input:keybind({ mod_key, "alt" }, "q", function()
|
||||
Pinnacle:quit()
|
||||
end)
|
||||
|
||||
Input:set_keybind({ mod_key, "alt" }, "c", function()
|
||||
Input:keybind({ mod_key, "alt" }, "c", function()
|
||||
local focused = Window:get_focused()
|
||||
if focused then
|
||||
focused:close()
|
||||
end
|
||||
end)
|
||||
|
||||
Input:set_keybind({ mod_key }, key.Return, function()
|
||||
Input:keybind({ mod_key }, key.Return, function()
|
||||
Process:spawn(terminal)
|
||||
end)
|
||||
|
||||
Input:set_keybind({ mod_key, "alt" }, key.space, function()
|
||||
Input:keybind({ mod_key, "alt" }, key.space, function()
|
||||
local focused = Window:get_focused()
|
||||
if focused then
|
||||
focused:toggle_floating()
|
||||
end
|
||||
end)
|
||||
|
||||
Input:set_keybind({ mod_key }, "f", function()
|
||||
Input:keybind({ mod_key }, "f", function()
|
||||
local focused = Window:get_focused()
|
||||
if focused then
|
||||
focused:toggle_fullscreen()
|
||||
end
|
||||
end)
|
||||
|
||||
Input:set_keybind({ mod_key }, "m", function()
|
||||
Input:keybind({ mod_key }, "m", function()
|
||||
local focused = Window:get_focused()
|
||||
if focused then
|
||||
focused:toggle_maximized()
|
||||
|
@ -78,14 +77,14 @@ require("pinnacle").setup(function(Pinnacle)
|
|||
"corner_bottom_right",
|
||||
})
|
||||
|
||||
Input:set_keybind({ mod_key }, key.space, function()
|
||||
Input:keybind({ mod_key }, key.space, function()
|
||||
local focused_op = Output:get_focused()
|
||||
if focused_op then
|
||||
layout_cycler.next(focused_op)
|
||||
end
|
||||
end)
|
||||
|
||||
Input:set_keybind({ mod_key, "shift" }, key.space, function()
|
||||
Input:keybind({ mod_key, "shift" }, key.space, function()
|
||||
local focused_op = Output:get_focused()
|
||||
if focused_op then
|
||||
layout_cycler.prev(focused_op)
|
||||
|
@ -94,19 +93,19 @@ require("pinnacle").setup(function(Pinnacle)
|
|||
|
||||
for _, tag_name in ipairs(tag_names) do
|
||||
-- nil-safety: tags are guaranteed to be on the outputs due to connect_for_all above
|
||||
Input:set_keybind({ mod_key }, tag_name, function()
|
||||
Input:keybind({ mod_key }, tag_name, function()
|
||||
Tag:get(tag_name):switch_to()
|
||||
end)
|
||||
Input:set_keybind({ mod_key, "shift" }, tag_name, function()
|
||||
Input:keybind({ mod_key, "shift" }, tag_name, function()
|
||||
Tag:get(tag_name):toggle_active()
|
||||
end)
|
||||
Input:set_keybind({ mod_key, "alt" }, tag_name, function()
|
||||
Input:keybind({ mod_key, "alt" }, tag_name, function()
|
||||
local focused = Window:get_focused()
|
||||
if focused then
|
||||
focused:move_to_tag(Tag:get(tag_name) --[[@as TagHandle]])
|
||||
end
|
||||
end)
|
||||
Input:set_keybind({ mod_key, "shift", "alt" }, tag_name, function()
|
||||
Input:keybind({ mod_key, "shift", "alt" }, tag_name, function()
|
||||
local focused = Window:get_focused()
|
||||
if focused then
|
||||
focused:toggle_tag(Tag:get(tag_name) --[[@as TagHandle]])
|
||||
|
|
|
@ -68,23 +68,13 @@ function Client:unary_request(grpc_request_params)
|
|||
stream:write_headers(create_request_headers(service, method), false)
|
||||
stream:write_chunk(body, true)
|
||||
|
||||
-- for chunk in stream:each_chunk() do
|
||||
-- print(chunk, ":", pb.tohex(chunk))
|
||||
-- os.exit(1)
|
||||
-- end
|
||||
|
||||
local response_headers = stream:get_headers()
|
||||
-- TODO: check headers for errors
|
||||
|
||||
local response_body = stream:get_next_chunk()
|
||||
print("unary body", response_body, "end")
|
||||
print(pb.tohex(response_body))
|
||||
print("--------------------------------")
|
||||
|
||||
local trailers = stream:get_headers()
|
||||
print("trailers", trailers)
|
||||
print("------------------------------")
|
||||
if trailers then
|
||||
if trailers then -- idk if im big dummy or not but there are never any trailers
|
||||
for name, value, never_index in trailers:each() do
|
||||
print(name, value, never_index)
|
||||
end
|
||||
|
@ -134,18 +124,10 @@ function Client:server_streaming_request(grpc_request_params, callback)
|
|||
stream:write_chunk(body, true)
|
||||
|
||||
local response_headers = stream:get_headers()
|
||||
for name, value, never_index in response_headers:each() do
|
||||
print(name, value, never_index)
|
||||
end
|
||||
-- local chunk = stream:get_next_chunk()
|
||||
-- print(chunk, chunk:len())
|
||||
-- TODO: check headers for errors
|
||||
|
||||
self.loop:wrap(function()
|
||||
for response_body in stream:each_chunk() do
|
||||
print("stream chunk", response_body, "end")
|
||||
print(pb.tohex(response_body))
|
||||
print("-----------------------------------")
|
||||
-- Skip the 1-byte compressed flag and the 4-byte message length
|
||||
local response_body = response_body:sub(6)
|
||||
|
||||
|
|
|
@ -32,6 +32,8 @@ function protobuf.build_protos()
|
|||
pinnacle_pb:close()
|
||||
|
||||
assert(pb.load(pinnacle_pb_data), "failed to load .pb file")
|
||||
|
||||
pb.option("enum_as_value")
|
||||
end
|
||||
|
||||
return protobuf
|
||||
|
|
|
@ -34,6 +34,8 @@ local function build_grpc_request_params(method, data)
|
|||
}
|
||||
end
|
||||
|
||||
-- This is an @enum and not an @alias because with an @alias the completion replaces tables with a string,
|
||||
-- which is annoying
|
||||
---@enum (key) Modifier
|
||||
local modifier_values = {
|
||||
shift = 1,
|
||||
|
@ -42,7 +44,6 @@ local modifier_values = {
|
|||
super = 4,
|
||||
}
|
||||
|
||||
---@enum (key) MouseButton
|
||||
local mouse_button_values = {
|
||||
--- Left
|
||||
[1] = 0x110,
|
||||
|
@ -58,20 +59,38 @@ local mouse_button_values = {
|
|||
[6] = 0x115,
|
||||
--- Back
|
||||
[7] = 0x116,
|
||||
left = 0x110,
|
||||
right = 0x111,
|
||||
middle = 0x112,
|
||||
side = 0x113,
|
||||
extra = 0x114,
|
||||
forward = 0x115,
|
||||
back = 0x116,
|
||||
btn_left = 0x110,
|
||||
btn_right = 0x111,
|
||||
btn_middle = 0x112,
|
||||
btn_side = 0x113,
|
||||
btn_extra = 0x114,
|
||||
btn_forward = 0x115,
|
||||
btn_back = 0x116,
|
||||
}
|
||||
-- This alias is because I can't get @enum completion to work
|
||||
---@alias MouseButton
|
||||
---| 1 Left
|
||||
---| 2 Right
|
||||
---| 3 Middle
|
||||
---| 4 Side
|
||||
---| 5 Extra
|
||||
---| 6 Forward
|
||||
---| 7 Back,
|
||||
---| "btn_left"
|
||||
---| "btn_right"
|
||||
---| "btn_middle"
|
||||
---| "btn_side"
|
||||
---| "btn_extra"
|
||||
---| "btn_forward"
|
||||
---| "btn_back"
|
||||
|
||||
---@enum (key) MouseEdge
|
||||
local mouse_edge_values = {
|
||||
press = 1,
|
||||
release = 2,
|
||||
}
|
||||
---@alias MouseEdge
|
||||
---| "press" Trigger on mouse button press
|
||||
---| "release" Trigger on mouse button release
|
||||
|
||||
---@class InputModule
|
||||
---@field private btn table
|
||||
|
@ -84,10 +103,44 @@ local Input = {
|
|||
key = require("pinnacle.input.keys"),
|
||||
}
|
||||
|
||||
---@param mods Modifier[]
|
||||
---@param key Key | string
|
||||
---@param action fun()
|
||||
function Input:set_keybind(mods, key, action)
|
||||
---Set a keybind. If called with an already existing keybind, it gets replaced.
|
||||
---
|
||||
---You must provide three arguments:
|
||||
---
|
||||
--- - `mods`: An array of `Modifier`s. If you don't want any, provide an empty table.
|
||||
--- - `key`: The key that will trigger `action`. You can provide three types of key:
|
||||
--- - Something from the `Key` table in `Input.key`, which lists every xkbcommon key. The naming pattern is the xkbcommon key without the `KEY_` prefix, unless that would make it start with a number or the reserved lua keyword `function`, in which case the `KEY_` prefix is included.
|
||||
--- - A single character representing your key. This can be something like "g", "$", "~", "1", and so on.
|
||||
--- - A string of the key's name. This is the name of the xkbcommon key without the `KEY_` prefix.
|
||||
--- - `action`: The function that will be run when the keybind is pressed.
|
||||
---
|
||||
---It is important to note that `"a"` is different than `"A"`. Similarly, `key.a` is different than `key.A`.
|
||||
---Usually, it's best to use the non-modified key to prevent confusion and unintended behavior.
|
||||
---
|
||||
---```lua
|
||||
---Input:keybind({ "shift" }, "a", function() end) -- This is preferred
|
||||
---Input:keybind({ "shift" }, "A", function() end) -- over this
|
||||
---
|
||||
--- -- This keybind will only work with capslock on.
|
||||
---Input:keybind({}, "A", function() end)
|
||||
---
|
||||
--- -- This keybind won't work at all because to get `@` you need to hold shift,
|
||||
--- -- which this keybind doesn't accept.
|
||||
---Input:keybind({ "ctrl" }, "@", function() end)
|
||||
---```
|
||||
---
|
||||
---### Example
|
||||
---```lua
|
||||
--- -- Set `super + Return` to open Alacritty
|
||||
---Input:keybind({ "super" }, Input.key.Return, function()
|
||||
--- Process:spawn("alacritty")
|
||||
---end)
|
||||
---```
|
||||
---
|
||||
---@param mods Modifier[] The modifiers that need to be held down for the bind to trigger
|
||||
---@param key Key | string The key used to trigger the bind
|
||||
---@param action fun() The function to run when the bind is triggered
|
||||
function Input:keybind(mods, key, action)
|
||||
local raw_code = nil
|
||||
local xkb_name = nil
|
||||
|
||||
|
@ -112,13 +165,23 @@ function Input:set_keybind(mods, key, action)
|
|||
)
|
||||
end
|
||||
|
||||
---Set a mousebind.
|
||||
---Set a mousebind. If called with an already existing mousebind, it gets replaced.
|
||||
---
|
||||
---@param mods Modifier[]
|
||||
---@param button MouseButton
|
||||
---@param edge MouseEdge
|
||||
---@param action fun()
|
||||
function Input:set_mousebind(mods, button, edge, action)
|
||||
---You must specify whether the keybind happens on button press or button release.
|
||||
---
|
||||
---### Example
|
||||
---```lua
|
||||
--- -- Set `super + left mouse button` to move a window on press
|
||||
---Input:mousebind({ "super" }, "btn_left", "press", function()
|
||||
--- Window:begin_move("btn_left")
|
||||
---end)
|
||||
---```
|
||||
---
|
||||
---@param mods Modifier[] The modifiers that need to be held down for the bind to trigger
|
||||
---@param button MouseButton The mouse button used to trigger the bind
|
||||
---@param edge MouseEdge "press" or "release" to trigger on button press or release
|
||||
---@param action fun() The function to run when the bind is triggered
|
||||
function Input:mousebind(mods, button, edge, action)
|
||||
local edge = mouse_edge_values[edge]
|
||||
|
||||
local mod_values = {}
|
||||
|
@ -145,15 +208,32 @@ end
|
|||
|
||||
---Set the xkbconfig for your keyboard.
|
||||
---
|
||||
---@param xkb_config XkbConfig
|
||||
---Fields not present will be set to their default values.
|
||||
---
|
||||
---Read `xkeyboard-config(7)` for more information.
|
||||
---
|
||||
---### Example
|
||||
---```lua
|
||||
---Input:set_xkb_config({
|
||||
--- layout = "us,fr,ge",
|
||||
--- options = "ctrl:swapcaps,caps:shift"
|
||||
---})
|
||||
---```
|
||||
---
|
||||
---@param xkb_config XkbConfig The new xkbconfig
|
||||
function Input:set_xkb_config(xkb_config)
|
||||
self.config_client:unary_request(build_grpc_request_params("SetXkbConfig", xkb_config))
|
||||
end
|
||||
|
||||
---Set the keyboard's repeat rate and delay.
|
||||
---
|
||||
---@param rate integer The time between repeats, in milliseconds
|
||||
---@param delay integer The duration a key needs to be held down before repeating starts, in milliseconds
|
||||
---### Example
|
||||
---```lua
|
||||
---Input:set_repeat_rate(100, 1000) -- Key must be held down for 1 second, then repeats 10 times per second.
|
||||
---```
|
||||
---
|
||||
---@param rate integer The time between repeats in milliseconds
|
||||
---@param delay integer The duration a key needs to be held down before repeating starts in milliseconds
|
||||
function Input:set_repeat_rate(rate, delay)
|
||||
self.config_client:unary_request(build_grpc_request_params("SetRepeatRate", {
|
||||
rate = rate,
|
||||
|
|
|
@ -54,6 +54,11 @@ local Output = {}
|
|||
|
||||
---Get all outputs.
|
||||
---
|
||||
---### Example
|
||||
---```lua
|
||||
---local outputs = Output:get_all()
|
||||
---```
|
||||
---
|
||||
---@return OutputHandle[]
|
||||
function Output:get_all()
|
||||
local response = self.config_client:unary_request(build_grpc_request_params("Get", {}))
|
||||
|
@ -68,7 +73,14 @@ function Output:get_all()
|
|||
return handles
|
||||
end
|
||||
|
||||
---@param name string The name of the port the output is connected to
|
||||
---Get an output by its name (the connector it's plugged into).
|
||||
---
|
||||
---### Example
|
||||
---```lua
|
||||
---local output = Output:get_by_name("eDP-1")
|
||||
---```
|
||||
---
|
||||
---@param name string The name of the connector the output is connected to
|
||||
---@return OutputHandle | nil
|
||||
function Output:get_by_name(name)
|
||||
local handles = self:get_all()
|
||||
|
@ -82,6 +94,15 @@ function Output:get_by_name(name)
|
|||
return nil
|
||||
end
|
||||
|
||||
---Get the currently focused output.
|
||||
---
|
||||
---This is currently defined as the most recent one that has had pointer motion.
|
||||
---
|
||||
---### Example
|
||||
---```lua
|
||||
---local output = Output:get_focused()
|
||||
---```
|
||||
---
|
||||
---@return OutputHandle | nil
|
||||
function Output:get_focused()
|
||||
local handles = self:get_all()
|
||||
|
@ -95,6 +116,25 @@ function Output:get_focused()
|
|||
return nil
|
||||
end
|
||||
|
||||
---Connect a function to be run with all current and future outputs.
|
||||
---
|
||||
---This method does two things:
|
||||
---1. Immediately runs `callback` with all currently connected outputs.
|
||||
---2. Calls `callback` whenever a new output is plugged in.
|
||||
---
|
||||
---This will *not* run `callback` with an output that has been unplugged and replugged
|
||||
---to prevent duplicate setup. Instead, the compositor keeps track of the tags and other
|
||||
---state associated with that output and restores it when replugged.
|
||||
---
|
||||
---### Example
|
||||
---```lua
|
||||
--- -- Add tags "1" through "5" to all outputs
|
||||
---Output:connect_for_all(function(output)
|
||||
--- local tags = Tag:add(output, "1", "2", "3", "4", "5")
|
||||
--- tags[1]:toggle_active()
|
||||
---end)
|
||||
---```
|
||||
---
|
||||
---@param callback fun(output: OutputHandle)
|
||||
function Output:connect_for_all(callback)
|
||||
local handles = self:get_all()
|
||||
|
@ -109,7 +149,39 @@ function Output:connect_for_all(callback)
|
|||
end)
|
||||
end
|
||||
|
||||
---Set the location of this output in the global space.
|
||||
---
|
||||
---On startup, Pinnacle will lay out all connected outputs starting at (0, 0)
|
||||
---and going to the right, with their top borders aligned.
|
||||
---
|
||||
---This method allows you to move outputs where necessary.
|
||||
---
|
||||
---Note: If you have space between two outputs when setting their locations,
|
||||
---the pointer will not be able to move between them.
|
||||
---
|
||||
---### Example
|
||||
---```lua
|
||||
--- -- Assume two monitors in order, "DP-1" and "HDMI-1", with the following dimensions:
|
||||
--- -- - "DP-1": ┌─────┐
|
||||
--- -- │ │1920x1080
|
||||
--- -- └─────┘
|
||||
--- -- - "HDMI-1": ┌───────┐
|
||||
--- -- │ 2560x │
|
||||
--- -- │ 1440 │
|
||||
--- -- └───────┘
|
||||
---Output:get_by_name("DP-1"):set_location({ x = 0, y = 0 })
|
||||
---Output:get_by_name("HDMI-1"):set_location({ x = 1920, y = -360 })
|
||||
--- -- Results in:
|
||||
--- -- ┌───────┐
|
||||
--- -- ┌─────┤ │
|
||||
--- -- │DP-1 │HDMI-1 │
|
||||
--- -- └─────┴───────┘
|
||||
--- -- Notice that x = 0 aligns with the top of "DP-1", and the top of "HDMI-1" is at x = -360.
|
||||
---```
|
||||
---
|
||||
---@param loc { x: integer?, y: integer? }
|
||||
---
|
||||
---@see OutputHandle.set_loc_adj_to
|
||||
function OutputHandle:set_location(loc)
|
||||
self.config_client:unary_request(build_grpc_request_params("SetLocation", {
|
||||
output_name = self.name,
|
||||
|
@ -119,19 +191,47 @@ function OutputHandle:set_location(loc)
|
|||
end
|
||||
|
||||
---@alias Alignment
|
||||
---| "top_align_left"
|
||||
---| "top_align_center"
|
||||
---| "top_align_right"
|
||||
---| "bottom_align_left"
|
||||
---| "bottom_align_center"
|
||||
---| "bottom_align_right"
|
||||
---| "left_align_top"
|
||||
---| "left_align_center"
|
||||
---| "left_align_bottom"
|
||||
---| "right_align_top"
|
||||
---| "right_align_center"
|
||||
---| "right_align_bottom"
|
||||
---| "top_align_left" Set above, align left borders
|
||||
---| "top_align_center" Set above, align centers
|
||||
---| "top_align_right" Set above, align right borders
|
||||
---| "bottom_align_left" Set below, align left borders
|
||||
---| "bottom_align_center" Set below, align centers
|
||||
---| "bottom_align_right" Set below, align right border
|
||||
---| "left_align_top" Set to left, align top borders
|
||||
---| "left_align_center" Set to left, align centers
|
||||
---| "left_align_bottom" Set to left, align bottom borders
|
||||
---| "right_align_top" Set to right, align top borders
|
||||
---| "right_align_center" Set to right, align centers
|
||||
---| "right_align_bottom" Set to right, align bottom borders
|
||||
|
||||
---Set the location of this output adjacent to another one.
|
||||
---
|
||||
---`alignment` is how you want this output to be placed.
|
||||
---For example, "top_align_left" will place this output above `other` and align the left borders.
|
||||
---Similarly, "right_align_center" will place this output to the right of `other` and align their centers.
|
||||
---
|
||||
---### Example
|
||||
---```lua
|
||||
--- -- Assume two monitors in order, "DP-1" and "HDMI-1", with the following dimensions:
|
||||
--- -- - "DP-1": ┌─────┐
|
||||
--- -- │ │1920x1080
|
||||
--- -- └─────┘
|
||||
--- -- - "HDMI-1": ┌───────┐
|
||||
--- -- │ 2560x │
|
||||
--- -- │ 1440 │
|
||||
--- -- └───────┘
|
||||
---Output:get_by_name("DP-1"):set_loc_adj_to(Output:get_by_name("HDMI-1"), "bottom_align_right")
|
||||
--- -- Results in:
|
||||
--- -- ┌───────┐
|
||||
--- -- │ │
|
||||
--- -- │HDMI-1 │
|
||||
--- -- └──┬────┤
|
||||
--- -- │DP-1│
|
||||
--- -- └────┘
|
||||
--- -- Notice that "DP-1" now has the coordinates (2280, 1440) because "DP-1" is getting moved, not "HDMI-1".
|
||||
--- -- "HDMI-1" was placed at (1920, 0) during the compositor's initial output layout.
|
||||
---```
|
||||
---
|
||||
---@param other OutputHandle
|
||||
---@param alignment Alignment
|
||||
function OutputHandle:set_loc_adj_to(other, alignment)
|
||||
|
@ -203,15 +303,16 @@ end
|
|||
---@field physical_width integer?
|
||||
---@field physical_height integer?
|
||||
---@field focused boolean?
|
||||
---@field tags TagHandle[]
|
||||
---@field tags TagHandle[]?
|
||||
|
||||
---Get all properties of this output.
|
||||
---
|
||||
---@return OutputProperties
|
||||
function OutputHandle:props()
|
||||
local response =
|
||||
self.config_client:unary_request(build_grpc_request_params("GetProperties", { output_name = self.name }))
|
||||
|
||||
local handles = require("pinnacle.tag").handle.new_from_table(self.config_client, response.tag_ids)
|
||||
local handles = require("pinnacle.tag").handle.new_from_table(self.config_client, response.tag_ids or {})
|
||||
|
||||
response.tags = handles
|
||||
response.tag_ids = nil
|
||||
|
@ -219,6 +320,113 @@ function OutputHandle:props()
|
|||
return response
|
||||
end
|
||||
|
||||
---Get this output's make.
|
||||
---
|
||||
---Note: make and model detection are currently somewhat iffy and may not work.
|
||||
---
|
||||
---Shorthand for `handle:props().make`.
|
||||
---
|
||||
---@return string?
|
||||
function OutputHandle:make()
|
||||
return self:props().make
|
||||
end
|
||||
|
||||
---Get this output's model.
|
||||
---
|
||||
---Note: make and model detection are currently somewhat iffy and may not work.
|
||||
---
|
||||
---Shorthand for `handle:props().model`.
|
||||
---
|
||||
---@return string?
|
||||
function OutputHandle:model()
|
||||
return self:props().model
|
||||
end
|
||||
|
||||
---Get this output's x-coordinate in the global space.
|
||||
---
|
||||
---Shorthand for `handle:props().x`.
|
||||
---
|
||||
---@return integer?
|
||||
function OutputHandle:x()
|
||||
return self:props().x
|
||||
end
|
||||
|
||||
---Get this output's y-coordinate in the global space.
|
||||
---
|
||||
---Shorthand for `handle:props().y`.
|
||||
---
|
||||
---@return integer?
|
||||
function OutputHandle:y()
|
||||
return self:props().y
|
||||
end
|
||||
|
||||
---Get this output's width in pixels.
|
||||
---
|
||||
---Shorthand for `handle:props().pixel_width`.
|
||||
---
|
||||
---@return integer?
|
||||
function OutputHandle:pixel_width()
|
||||
return self:props().pixel_width
|
||||
end
|
||||
|
||||
---Get this output's height in pixels.
|
||||
---
|
||||
---Shorthand for `handle:props().pixel_height`.
|
||||
---
|
||||
---@return integer?
|
||||
function OutputHandle:pixel_height()
|
||||
return self:props().pixel_height
|
||||
end
|
||||
|
||||
---Get this output's refresh rate in millihertz.
|
||||
---
|
||||
---For example, 144Hz is returned as 144000.
|
||||
---
|
||||
---Shorthand for `handle:props().refresh_rate`.
|
||||
---
|
||||
---@return integer?
|
||||
function OutputHandle:refresh_rate()
|
||||
return self:props().refresh_rate
|
||||
end
|
||||
|
||||
---Get this output's physical width in millimeters.
|
||||
---
|
||||
---Shorthand for `handle:props().physical_width`.
|
||||
---
|
||||
---@return integer?
|
||||
function OutputHandle:physical_width()
|
||||
return self:props().physical_width
|
||||
end
|
||||
|
||||
---Get this output's physical height in millimeters.
|
||||
---
|
||||
---Shorthand for `handle:props().physical_height`.
|
||||
---
|
||||
---@return integer?
|
||||
function OutputHandle:physical_height()
|
||||
return self:props().physical_height
|
||||
end
|
||||
|
||||
---Get whether or not this output is focused.
|
||||
---
|
||||
---The focused output is currently implemented as the one that last had pointer motion.
|
||||
---
|
||||
---Shorthand for `handle:props().focused`.
|
||||
---
|
||||
---@return boolean?
|
||||
function OutputHandle:focused()
|
||||
return self:props().focused
|
||||
end
|
||||
|
||||
---Get the tags this output has.
|
||||
---
|
||||
---Shorthand for `handle:props().tags`.
|
||||
---
|
||||
---@return TagHandle[]?
|
||||
function OutputHandle:tags()
|
||||
return self:props().tags
|
||||
end
|
||||
|
||||
---@return Output
|
||||
function output.new(config_client)
|
||||
---@type Output
|
||||
|
|
|
@ -67,8 +67,21 @@ local function spawn_inner(config_client, args, callbacks, once)
|
|||
)
|
||||
end
|
||||
|
||||
---@param args string | string[]
|
||||
---@param callbacks { stdout: fun(line: string)?, stderr: fun(line: string)?, exit: fun(code: integer, msg: string)? }?
|
||||
---Spawn a program with optional callbacks for its stdout, stderr, and exit information.
|
||||
---
|
||||
---`callbacks` is an optional table with the following optional fields:
|
||||
--- - `stdout`: function(line: string)
|
||||
--- - `stderr`: function(line: string)
|
||||
--- - `exit`: function(code: integer, msg: string)
|
||||
---
|
||||
---Note: if `args` is a string then it will be wrapped in a table and sent to the compositor.
|
||||
---If you need multiple arguments, use a string array instead.
|
||||
---
|
||||
---Note 2: If you spawn a window before tags are added it will spawn without any tags and
|
||||
---won't be displayed in the compositor. TODO: Do what awesome does and display on all tags instead
|
||||
---
|
||||
---@param args string | string[] The program arguments; a string instead of an array should be for only 1 argument
|
||||
---@param callbacks { stdout: fun(line: string)?, stderr: fun(line: string)?, exit: fun(code: integer, msg: string)? }? Callbacks that will be run whenever the program outputs to stdout, stderr, or exits.
|
||||
function Process:spawn(args, callbacks)
|
||||
if type(args) == "string" then
|
||||
args = { args }
|
||||
|
@ -77,8 +90,12 @@ function Process:spawn(args, callbacks)
|
|||
spawn_inner(self.config_client, args, callbacks, false)
|
||||
end
|
||||
|
||||
---Like `Process:spawn` but will only spawn the program if it isn't already running.
|
||||
---
|
||||
---@param args string | string[]
|
||||
---@param callbacks { stdout: fun(line: string)?, stderr: fun(line: string)?, exit: fun(code: integer, msg: string)? }?
|
||||
---
|
||||
---@see Process.spawn
|
||||
function Process:spawn_once(args, callbacks)
|
||||
if type(args) == "string" then
|
||||
args = { args }
|
||||
|
|
|
@ -71,8 +71,24 @@ function Tag:get_all()
|
|||
return handles
|
||||
end
|
||||
|
||||
---Get the tag with the given name and output.
|
||||
---
|
||||
---If `output` is not specified, this uses the focused output.
|
||||
---
|
||||
---If an output has more than one tag with the same name, this returns the first.
|
||||
---
|
||||
---### Example
|
||||
---```lua
|
||||
--- -- Get tags on the focused output
|
||||
---local tag = Tag:get("Tag")
|
||||
---
|
||||
--- -- Get tags on a specific output
|
||||
---local tag_on_hdmi1 = Tag:get("Tag", Output:get_by_name("HDMI-1"))
|
||||
---```
|
||||
---
|
||||
---@param name string
|
||||
---@param output OutputHandle?
|
||||
---
|
||||
---@return TagHandle | nil
|
||||
function Tag:get(name, output)
|
||||
output = output or require("pinnacle.output").new(self.config_client):get_focused()
|
||||
|
@ -97,10 +113,19 @@ end
|
|||
---
|
||||
---Returns handles to the created tags.
|
||||
---
|
||||
---### Example
|
||||
---```lua
|
||||
---local tags = Tag:add(Output:get_by_name("HDMI-1"), "1", "2", "Buckle", "Shoe")
|
||||
---
|
||||
--- -- With a table
|
||||
---local tag_names = { "1", "2", "Buckle", "Shoe" }
|
||||
---local tags = Tag:add(Output:get_by_name("HDMI-1"), tag_names)
|
||||
---```
|
||||
---
|
||||
---@param output OutputHandle
|
||||
---@param ... string
|
||||
---
|
||||
---@return TagHandle[]
|
||||
---@return TagHandle[] tags Handles to the created tags
|
||||
---
|
||||
---@overload fun(self: self, output: OutputHandle, tag_names: string[])
|
||||
function Tag:add(output, ...)
|
||||
|
@ -126,6 +151,13 @@ end
|
|||
|
||||
---Remove the given tags.
|
||||
---
|
||||
---### Example
|
||||
---```lua
|
||||
---local tags = Tag:add(Output:get_by_name("HDMI-1"), "1", "2", "Buckle", "Shoe")
|
||||
---
|
||||
---Tag:remove(tags) -- "HDMI-1" no longer has those tags
|
||||
---```
|
||||
---
|
||||
---@param tags TagHandle[]
|
||||
function Tag:remove(tags)
|
||||
---@type integer[]
|
||||
|
@ -139,10 +171,44 @@ function Tag:remove(tags)
|
|||
end
|
||||
|
||||
---@class LayoutCycler
|
||||
---@field next fun(output: OutputHandle)
|
||||
---@field prev fun(output: OutputHandle)
|
||||
---@field next fun(output: OutputHandle?)
|
||||
---@field prev fun(output: OutputHandle?)
|
||||
|
||||
--- TODO: docs
|
||||
---Create a layout cycler that will cycle layouts on the given output.
|
||||
---
|
||||
---This returns a `LayoutCycler` table with two fields, both functions that take in an optional `OutputHandle`:
|
||||
--- - `next`: Cycle to the next layout on the given output
|
||||
--- - `prev`: Cycle to the previous layout on the given output
|
||||
---
|
||||
---If the output isn't specified then the focused one will be used.
|
||||
---
|
||||
---Internally, this will only change the layout of the first active tag on the output
|
||||
---because that is the one that determines the layout.
|
||||
---
|
||||
---### Example
|
||||
---```lua
|
||||
--- ---@type LayoutCycler[]
|
||||
---local layouts = {
|
||||
--- "master_stack",
|
||||
--- "dwindle",
|
||||
--- "corner_top_left",
|
||||
--- "corner_top_right".
|
||||
---} -- Only cycle between these four layouts
|
||||
---
|
||||
---local layout_cycler = Tag:new_layout_cycler()
|
||||
---
|
||||
--- -- Assume the focused output starts with the "master_stack" layout
|
||||
---layout_cycler.next() -- Layout is now "dwindle"
|
||||
---layout_cycler.next() -- Layout is now "corner_top_left"
|
||||
---layout_cycler.next() -- Layout is now "corner_top_right"
|
||||
---layout_cycler.next() -- Layout is now "dwindle"
|
||||
---layout_cycler.next() -- Layout is now "corner_top_right"
|
||||
---
|
||||
--- -- Cycling on another output
|
||||
---layout_cycler.next(Output:get_by_name("eDP-1"))
|
||||
---layout_cycler.prev(Output:get_by_name("HDMI-1"))
|
||||
---```
|
||||
---
|
||||
---@param layouts Layout[]
|
||||
---
|
||||
---@return LayoutCycler
|
||||
|
@ -159,6 +225,11 @@ function Tag:new_layout_cycler(layouts)
|
|||
---@type LayoutCycler
|
||||
return {
|
||||
next = function(output)
|
||||
local output = output or require("pinnacle.output").new(self.config_client):get_focused()
|
||||
if not output then
|
||||
return
|
||||
end
|
||||
|
||||
local tags = output:props().tags
|
||||
|
||||
for _, tg in ipairs(tags) do
|
||||
|
@ -182,6 +253,11 @@ function Tag:new_layout_cycler(layouts)
|
|||
end
|
||||
end,
|
||||
prev = function(output)
|
||||
local output = output or require("pinnacle.output").new(self.config_client):get_focused()
|
||||
if not output then
|
||||
return
|
||||
end
|
||||
|
||||
local tags = output:props().tags
|
||||
|
||||
for _, tg in ipairs(tags) do
|
||||
|
@ -209,11 +285,19 @@ function Tag:new_layout_cycler(layouts)
|
|||
end
|
||||
|
||||
---Remove this tag.
|
||||
---
|
||||
---### Example
|
||||
---```lua
|
||||
---local tags = Tag:add(Output:get_by_name("HDMI-1"), "1", "2", "Buckle", "Shoe")
|
||||
---
|
||||
---tags[2]:remove()
|
||||
---tags[4]:remove()
|
||||
--- -- "HDMI-1" now only has tags "1" and "Buckle"
|
||||
---```
|
||||
function TagHandle:remove()
|
||||
self.config_client:unary_request(build_grpc_request_params("Remove", { tag_ids = { self.id } }))
|
||||
end
|
||||
|
||||
---@enum (key) Layout
|
||||
local _layouts = {
|
||||
master_stack = 1,
|
||||
dwindle = 2,
|
||||
|
@ -223,7 +307,25 @@ local _layouts = {
|
|||
corner_bottom_left = 6,
|
||||
corner_bottom_right = 7,
|
||||
}
|
||||
---@alias Layout
|
||||
---| "master_stack" # One master window on the left with all other windows stacked to the right.
|
||||
---| "dwindle" # Windows split in half towards the bottom right corner.
|
||||
---| "spiral" # Windows split in half in a spiral.
|
||||
---| "corner_top_left" # One main corner window in the top left with a column of windows on the right and a row on the bottom.
|
||||
---| "corner_top_right" # One main corner window in the top right with a column of windows on the left and a row on the bottom.
|
||||
---| "corner_bottom_left" # One main corner window in the bottom left with a column of windows on the right and a row on the top.
|
||||
---| "corner_bottom_right" # One main corner window in the bottom right with a column of windows on the left and a row on the top.
|
||||
|
||||
---Set this tag's layout.
|
||||
---
|
||||
---If this is the first active tag on its output, its layout will be used to tile windows.
|
||||
---
|
||||
---### Example
|
||||
---```lua
|
||||
--- -- Assume the focused output has tag "Tag"
|
||||
---Tag:get("Tag"):set_layout("dwindle")
|
||||
---```
|
||||
---
|
||||
---@param layout Layout
|
||||
function TagHandle:set_layout(layout)
|
||||
local layout = _layouts[layout]
|
||||
|
@ -235,26 +337,57 @@ function TagHandle:set_layout(layout)
|
|||
end
|
||||
|
||||
---Activate this tag and deactivate all other ones on the same output.
|
||||
---
|
||||
---### Example
|
||||
---```lua
|
||||
--- -- Assume the focused output has the following inactive tags and windows:
|
||||
--- -- - "1": Alacritty
|
||||
--- -- - "2": Firefox, Discord
|
||||
--- -- - "3": Steam
|
||||
---Tag:get("2"):switch_to() -- Displays Firefox and Discord
|
||||
---Tag:get("3"):switch_to() -- Displays Steam
|
||||
---```
|
||||
function TagHandle:switch_to()
|
||||
self.config_client:unary_request(build_grpc_request_params("SwitchTo", { tag_id = self.id }))
|
||||
end
|
||||
|
||||
---Set whether or not this tag is active.
|
||||
---
|
||||
---### Example
|
||||
---```lua
|
||||
--- -- Assume the focused output has the following inactive tags and windows:
|
||||
--- -- - "1": Alacritty
|
||||
--- -- - "2": Firefox, Discord
|
||||
--- -- - "3": Steam
|
||||
---Tag:get("2"):set_active(true) -- Displays Firefox and Discord
|
||||
---Tag:get("3"):set_active(true) -- Displays Firefox, Discord, and Steam
|
||||
---Tag:get("2"):set_active(false) -- Displays Steam
|
||||
---```
|
||||
---
|
||||
---@param active boolean
|
||||
function TagHandle:set_active(active)
|
||||
self.config_client:unary_request(build_grpc_request_params("SetActive", { tag_id = self.id, set = active }))
|
||||
end
|
||||
|
||||
---Toggle this tag's active state.
|
||||
---
|
||||
---### Example
|
||||
---```lua
|
||||
--- -- Assume the focused output has the following inactive tags and windows:
|
||||
--- -- - "1": Alacritty
|
||||
--- -- - "2": Firefox, Discord
|
||||
--- -- - "3": Steam
|
||||
---Tag:get("2"):toggle_active() -- Displays Firefox and Discord
|
||||
---Tag:get("2"):toggle_active() -- Displays nothing
|
||||
---```
|
||||
function TagHandle:toggle_active()
|
||||
self.config_client:unary_request(build_grpc_request_params("SetActive", { tag_id = self.id, toggle = {} }))
|
||||
end
|
||||
|
||||
---@class TagProperties
|
||||
---@field active boolean?
|
||||
---@field name string?
|
||||
---@field output OutputHandle?
|
||||
---@field active boolean? Whether or not the tag is currently being displayed
|
||||
---@field name string? The name of the tag
|
||||
---@field output OutputHandle? The output the tag is on
|
||||
|
||||
---Get all properties of this tag.
|
||||
---
|
||||
|
@ -270,6 +403,33 @@ function TagHandle:props()
|
|||
}
|
||||
end
|
||||
|
||||
---Get whether or not this tag is being displayed.
|
||||
---
|
||||
---Shorthand for `handle:props().active`.
|
||||
---
|
||||
---@return boolean?
|
||||
function TagHandle:active()
|
||||
return self:props().active
|
||||
end
|
||||
|
||||
---Get this tag's name.
|
||||
---
|
||||
---Shorthand for `handle:props().name`.
|
||||
---
|
||||
---@return string?
|
||||
function TagHandle:name()
|
||||
return self:props().name
|
||||
end
|
||||
|
||||
---Get the output this tag is on.
|
||||
---
|
||||
---Shorthand for `handle:props().output`.
|
||||
---
|
||||
---@return OutputHandle?
|
||||
function TagHandle:output()
|
||||
return self:props().output
|
||||
end
|
||||
|
||||
---@return Tag
|
||||
function tag.new(config_client)
|
||||
---@type Tag
|
||||
|
|
|
@ -60,7 +60,14 @@ local Window = {}
|
|||
|
||||
---Get all windows.
|
||||
---
|
||||
---@return WindowHandle[]
|
||||
---### Example
|
||||
---```lua
|
||||
---local windows = Window:get_all()
|
||||
---for _, window in ipairs(windows) do
|
||||
--- print(window:props().class)
|
||||
---end
|
||||
---```
|
||||
---@return WindowHandle[] windows Handles to all windows
|
||||
function Window:get_all()
|
||||
local response = self.config_client:unary_request(build_grpc_request_params("Get", {}))
|
||||
|
||||
|
@ -69,7 +76,16 @@ function Window:get_all()
|
|||
return handles
|
||||
end
|
||||
|
||||
---@return WindowHandle | nil
|
||||
---Get the currently focused window.
|
||||
---
|
||||
---### Example
|
||||
---```lua
|
||||
---local focused = Window:get_focused()
|
||||
---if focused then
|
||||
--- print(focused:props().class)
|
||||
---end
|
||||
---```
|
||||
---@return WindowHandle | nil window A handle to the currently focused window
|
||||
function Window:get_focused()
|
||||
local handles = self:get_all()
|
||||
|
||||
|
@ -82,15 +98,35 @@ function Window:get_focused()
|
|||
return nil
|
||||
end
|
||||
|
||||
--- TODO: docs
|
||||
---@param button MouseButton
|
||||
---Begin moving this window using the specified mouse button.
|
||||
---
|
||||
---The button must be pressed at the time this method is called.
|
||||
---If the button is lifted, the move will end.
|
||||
---
|
||||
---### Example
|
||||
---```lua
|
||||
---Input:mousebind({ "super" }, "btn_left", function()
|
||||
--- Window:begin_move("btn_left")
|
||||
---end)
|
||||
---```
|
||||
---@param button MouseButton The button that will initiate the move
|
||||
function Window:begin_move(button)
|
||||
local button = require("pinnacle.input").btn[button]
|
||||
self.config_client:unary_request(build_grpc_request_params("MoveGrab", { button = button }))
|
||||
end
|
||||
|
||||
--- TODO: docs
|
||||
---@param button MouseButton
|
||||
---Begin resizing this window using the specified mouse button.
|
||||
---
|
||||
---The button must be pressed at the time this method is called.
|
||||
---If the button is lifted, the resize will end.
|
||||
---
|
||||
---### Example
|
||||
---```lua
|
||||
---Input:mousebind({ "super" }, "btn_right", function()
|
||||
--- Window:begin_resize("btn_right")
|
||||
---end)
|
||||
---```
|
||||
---@param button MouseButton The button that will initiate the resize
|
||||
function Window:begin_resize(button)
|
||||
local button = require("pinnacle.input").btn[button]
|
||||
self.config_client:unary_request(build_grpc_request_params("ResizeGrab", { button = button }))
|
||||
|
@ -126,7 +162,95 @@ local _fullscreen_or_maximized_keys = {
|
|||
[3] = "maximized",
|
||||
}
|
||||
|
||||
---@param rule { cond: WindowRuleCondition, rule: WindowRule }
|
||||
---Add a window rule.
|
||||
---
|
||||
---A window rule defines what properties a window will spawn with given certain conditions.
|
||||
---For example, if Firefox is spawned, you can set it to open on a specific tag.
|
||||
---
|
||||
---This method takes in a table with two keys:
|
||||
---
|
||||
--- - `cond`: The condition for `rule` to apply to a new window.
|
||||
--- - `rule`: What gets applied to the new window if `cond` is true.
|
||||
---
|
||||
---There are some important mechanics you should know when using window rules:
|
||||
---
|
||||
--- - All children inside an `all` block must be true for the block to be true.
|
||||
--- - At least one child inside an `any` block must be true for the block to be true.
|
||||
--- - The outermost block of a window rule condition is implicitly an `all` block.
|
||||
--- - Within an `all` block, all items in each array must be true for the attribute to be true.
|
||||
--- - Within an `any` block, only one item in each array needs to be true for the attribute to be true.
|
||||
---
|
||||
---`cond` can be a bit confusing and quite table heavy. Examples are shown below for guidance.
|
||||
---
|
||||
---### Examples
|
||||
---```lua
|
||||
--- -- A simple window rule. This one will cause Firefox to open on tag "Browser".
|
||||
---Window:add_window_rule({
|
||||
--- cond = { classes = { "firefox" } },
|
||||
--- rule = { tags = { "Browser" } },
|
||||
---})
|
||||
---
|
||||
--- -- To apply rules when *all* provided conditions are true, use `all`.
|
||||
--- -- `all` takes an array of conditions and checks if all are true.
|
||||
--- -- The following will open Steam fullscreen only if it opens on tag "5".
|
||||
---Window:add_window_rule({
|
||||
--- cond = {
|
||||
--- all = {
|
||||
--- {
|
||||
--- class = "steam",
|
||||
--- tag = Tag:get("5"),
|
||||
--- }
|
||||
--- }
|
||||
--- },
|
||||
--- rule = { fullscreen_or_maximized = "fullscreen" },
|
||||
---})
|
||||
---
|
||||
--- -- The outermost block of a `cond` is implicitly an `all` block.
|
||||
--- -- Thus, the above can be shortened to:
|
||||
---Window:add_window_rule({
|
||||
--- cond = {
|
||||
--- class = "steam",
|
||||
--- tag = Tag:get("5"),
|
||||
--- },
|
||||
--- rule = { fullscreen_or_maximized = "fullscreen" },
|
||||
---})
|
||||
---
|
||||
--- -- `any` also exists to allow at least one provided condition to match.
|
||||
--- -- The following will open either xterm or Alacritty floating.
|
||||
---Window:add_window_rule({
|
||||
--- cond = {
|
||||
--- any = { { classes = { "xterm", "Alacritty" } } }
|
||||
--- },
|
||||
--- rule = { floating = true },
|
||||
---})
|
||||
---
|
||||
--- -- You can arbitrarily nest `any` and `all` to achieve desired logic.
|
||||
--- -- The following will open Discord, Thunderbird, or Firefox floating if they
|
||||
--- -- open on either *all* of tags "A", "B", and "C" or both tags "1" and "2".
|
||||
---Window:add_window_rule({
|
||||
--- cond = {
|
||||
--- all = { -- This `all` block is needed because the outermost block cannot be an array.
|
||||
--- { any = {
|
||||
--- { class = { "firefox", "thunderbird", "discord" } }
|
||||
--- } },
|
||||
--- { any = {
|
||||
--- -- Because `tag` is inside an `all` block,
|
||||
--- -- the window must have all these tags for this to be true.
|
||||
--- -- If it was in an `any` block, only one tag would need to match.
|
||||
--- { all = {
|
||||
--- { tag = { "A", "B", "C" } }
|
||||
--- } },
|
||||
--- { all = {
|
||||
--- { tag = { "1", "2" } }
|
||||
--- } },
|
||||
--- } }
|
||||
--- }
|
||||
--- },
|
||||
--- rule = { floating = true },
|
||||
---})
|
||||
---```
|
||||
---
|
||||
---@param rule { cond: WindowRuleCondition, rule: WindowRule } The condition and rule
|
||||
function Window:add_window_rule(rule)
|
||||
if rule.cond.tags then
|
||||
local ids = {}
|
||||
|
@ -159,18 +283,57 @@ function Window:add_window_rule(rule)
|
|||
end
|
||||
|
||||
---Send a close request to this window.
|
||||
---
|
||||
---### Example
|
||||
---```lua
|
||||
---local focused = Window:get_focused()
|
||||
---if focused then focused:close() end
|
||||
---```
|
||||
function WindowHandle:close()
|
||||
self.config_client:unary_request(build_grpc_request_params("Close", { window_id = self.id }))
|
||||
end
|
||||
|
||||
---Set this window's location and/or size.
|
||||
---
|
||||
---@param geo { x: integer?, y: integer, width: integer?, height: integer? }
|
||||
---The coordinate system has the following axes:
|
||||
---```
|
||||
--- ^ -y
|
||||
--- |
|
||||
--- -x <--+--> +x
|
||||
--- |
|
||||
--- v +y
|
||||
---```
|
||||
---
|
||||
---*Tiled windows will not reflect these changes.*
|
||||
---This method only applies to this window's floating geometry.
|
||||
---
|
||||
---### Example
|
||||
---```lua
|
||||
---local focused = Window:get_focused()
|
||||
---if focused then
|
||||
--- focused:set_floating(true) -- `set_geometry` only applies to floating geometry.
|
||||
---
|
||||
--- focused:set_geometry({ x = 50, y = 300 }) -- Move this window to (50, 300)
|
||||
--- focused:set_geometry({ y = 0, height = 1080 }) -- Move this window to y = 0 and make its height 1080 pixels
|
||||
--- focused:set_geometry({}) -- Do nothing useful
|
||||
---end
|
||||
---```
|
||||
---@param geo { x: integer?, y: integer, width: integer?, height: integer? } The new location and/or size
|
||||
function WindowHandle:set_geometry(geo)
|
||||
self.config_client:unary_request(build_grpc_request_params("SetGeometry", { window_id = self.id, geometry = geo }))
|
||||
end
|
||||
|
||||
---Set this window to fullscreen or not.
|
||||
---
|
||||
---### Example
|
||||
---```lua
|
||||
---local focused = Window:get_focused()
|
||||
---if focused then
|
||||
--- focused:set_fullscreen(true)
|
||||
--- focused:set_fullscreen(false)
|
||||
---end
|
||||
---```
|
||||
---
|
||||
---@param fullscreen boolean
|
||||
function WindowHandle:set_fullscreen(fullscreen)
|
||||
self.config_client:unary_request(
|
||||
|
@ -178,35 +341,114 @@ function WindowHandle:set_fullscreen(fullscreen)
|
|||
)
|
||||
end
|
||||
|
||||
---Toggle this window to and from fullscreen.
|
||||
---
|
||||
---### Example
|
||||
---```lua
|
||||
---local focused = Window:get_focused()
|
||||
---if focused then
|
||||
--- focused:toggle_fullscreen()
|
||||
---end
|
||||
---```
|
||||
function WindowHandle:toggle_fullscreen()
|
||||
self.config_client:unary_request(build_grpc_request_params("SetFullscreen", { window_id = self.id, toggle = {} }))
|
||||
end
|
||||
|
||||
---Set this window to maximized or not.
|
||||
---
|
||||
---### Example
|
||||
---```lua
|
||||
---local focused = Window:get_focused()
|
||||
---if focused then
|
||||
--- focused:set_maximized(true)
|
||||
--- focused:set_maximized(false)
|
||||
---end
|
||||
---```
|
||||
---
|
||||
---@param maximized boolean
|
||||
function WindowHandle:set_maximized(maximized)
|
||||
self.config_client:unary_request(
|
||||
build_grpc_request_params("SetMaximized", { window_id = self.id, set = maximized })
|
||||
)
|
||||
end
|
||||
|
||||
---Toggle this window to and from maximized.
|
||||
---
|
||||
---### Example
|
||||
---```lua
|
||||
---local focused = Window:get_focused()
|
||||
---if focused then
|
||||
--- focused:toggle_maximized()
|
||||
---end
|
||||
---```
|
||||
function WindowHandle:toggle_maximized()
|
||||
self.config_client:unary_request(build_grpc_request_params("SetMaximized", { window_id = self.id, toggle = {} }))
|
||||
end
|
||||
|
||||
---Set this window to floating or not.
|
||||
---
|
||||
---### Example
|
||||
---```lua
|
||||
---local focused = Window:get_focused()
|
||||
---if focused then
|
||||
--- focused:set_floating(true)
|
||||
--- focused:set_floating(false)
|
||||
---end
|
||||
---```
|
||||
---
|
||||
---@param floating boolean
|
||||
function WindowHandle:set_floating(floating)
|
||||
self.config_client:unary_request(build_grpc_request_params("SetFloating", { window_id = self.id, set = floating }))
|
||||
end
|
||||
|
||||
---Toggle this window to and from floating.
|
||||
---
|
||||
---### Example
|
||||
---```lua
|
||||
---local focused = Window:get_focused()
|
||||
---if focused then
|
||||
--- focused:toggle_floating()
|
||||
---end
|
||||
---```
|
||||
function WindowHandle:toggle_floating()
|
||||
self.config_client:unary_request(build_grpc_request_params("SetFloating", { window_id = self.id, toggle = {} }))
|
||||
end
|
||||
|
||||
---@param tag TagHandle
|
||||
---Move this window to the specified tag.
|
||||
---
|
||||
---This will remove all tags from this window and tag it with `tag`.
|
||||
---
|
||||
---### Example
|
||||
---```lua
|
||||
--- -- Assume the focused output has the tag "Tag"
|
||||
---local focused = Window:get_focused()
|
||||
---if focused then
|
||||
--- focused:move_to_tag(Tag:get("Tag"))
|
||||
---end
|
||||
---```
|
||||
---
|
||||
---@param tag TagHandle The tag to move this window to
|
||||
function WindowHandle:move_to_tag(tag)
|
||||
self.config_client:unary_request(build_grpc_request_params("MoveToTag", { window_id = self.id, tag_id = tag.id }))
|
||||
end
|
||||
|
||||
---Tag or untag the given tag on this window.
|
||||
---@param tag TagHandle
|
||||
---
|
||||
---### Example
|
||||
---```lua
|
||||
--- -- Assume the focused output has the tag "Tag"
|
||||
---local focused = Window:get_focused()
|
||||
---if focused then
|
||||
--- local tag = Tag:get("Tag")
|
||||
---
|
||||
--- focused:set_tag(tag, true)
|
||||
--- -- `focused` now has tag "Tag"
|
||||
--- focused:set_tag(tag, false)
|
||||
--- -- `focused` no longer has tag "Tag"
|
||||
---end
|
||||
---```
|
||||
---
|
||||
---@param tag TagHandle The tag to set or unset
|
||||
---@param set boolean
|
||||
function WindowHandle:set_tag(tag, set)
|
||||
self.config_client:unary_request(
|
||||
|
@ -215,7 +457,23 @@ function WindowHandle:set_tag(tag, set)
|
|||
end
|
||||
|
||||
---Toggle the given tag on this window.
|
||||
---@param tag TagHandle
|
||||
---
|
||||
---### Example
|
||||
---```lua
|
||||
--- -- Assume the focused output has the tag "Tag"
|
||||
---local focused = Window:get_focused()
|
||||
---if focused then
|
||||
--- local tag = Tag:get("Tag")
|
||||
--- focused:set_tag(tag, false)
|
||||
---
|
||||
--- focused:toggle_tag(tag)
|
||||
--- -- `focused` now has tag "Tag"
|
||||
--- focused:toggle_tag(tag)
|
||||
--- -- `focused` no longer has tag "Tag"
|
||||
---end
|
||||
---```
|
||||
---
|
||||
---@param tag TagHandle The tag to toggle
|
||||
function WindowHandle:toggle_tag(tag)
|
||||
self.config_client:unary_request(
|
||||
build_grpc_request_params("SetTag", { window_id = self.id, tag_id = tag.id, toggle = {} })
|
||||
|
@ -223,13 +481,16 @@ function WindowHandle:toggle_tag(tag)
|
|||
end
|
||||
|
||||
---@class WindowProperties
|
||||
---@field geometry { x: integer?, y: integer?, width: integer?, height: integer? }?
|
||||
---@field class string?
|
||||
---@field title string?
|
||||
---@field focused boolean?
|
||||
---@field floating boolean?
|
||||
---@field fullscreen_or_maximized FullscreenOrMaximized?
|
||||
---@field geometry { x: integer?, y: integer?, width: integer?, height: integer? }? The location and size of the window
|
||||
---@field class string? The window's class
|
||||
---@field title string? The window's title
|
||||
---@field focused boolean? Whether or not the window is focused
|
||||
---@field floating boolean? Whether or not the window is floating
|
||||
---@field fullscreen_or_maximized FullscreenOrMaximized? Whether the window is fullscreen, maximized, or neither
|
||||
---@field tags TagHandle[]? The tags the window has
|
||||
|
||||
---Get all the properties of this window.
|
||||
---
|
||||
---@return WindowProperties
|
||||
function WindowHandle:props()
|
||||
local response =
|
||||
|
@ -237,9 +498,76 @@ function WindowHandle:props()
|
|||
|
||||
response.fullscreen_or_maximized = _fullscreen_or_maximized_keys[response.fullscreen_or_maximized]
|
||||
|
||||
response.tags = response.tag_ids
|
||||
and require("pinnacle.tag").handle.new_from_table(self.config_client, response.tag_ids)
|
||||
response.tag_ids = nil
|
||||
|
||||
return response
|
||||
end
|
||||
|
||||
---Get this window's location and size.
|
||||
---
|
||||
---Shorthand for `handle:props().geometry`.
|
||||
---
|
||||
---@return { x: integer?, y: integer?, width: integer?, height: integer? }?
|
||||
function WindowHandle:geometry()
|
||||
return self:props().geometry
|
||||
end
|
||||
|
||||
---Get this window's class.
|
||||
---
|
||||
---Shorthand for `handle:props().class`.
|
||||
---
|
||||
---@return string?
|
||||
function WindowHandle:class()
|
||||
return self:props().class
|
||||
end
|
||||
|
||||
---Get this window's title.
|
||||
---
|
||||
---Shorthand for `handle:props().title`.
|
||||
---
|
||||
---@return string?
|
||||
function WindowHandle:title()
|
||||
return self:props().title
|
||||
end
|
||||
|
||||
---Get whether or not this window is focused.
|
||||
---
|
||||
---Shorthand for `handle:props().focused`.
|
||||
---
|
||||
---@return boolean?
|
||||
function WindowHandle:focused()
|
||||
return self:props().focused
|
||||
end
|
||||
|
||||
---Get whether or not this window is floating.
|
||||
---
|
||||
---Shorthand for `handle:props().floating`.
|
||||
---
|
||||
---@return boolean?
|
||||
function WindowHandle:floating()
|
||||
return self:props().floating
|
||||
end
|
||||
|
||||
---Get whether this window is fullscreen, maximized, or neither.
|
||||
---
|
||||
---Shorthand for `handle:props().fullscreen_or_maximized`.
|
||||
---
|
||||
---@return FullscreenOrMaximized?
|
||||
function WindowHandle:fullscreen_or_maximized()
|
||||
return self:props().fullscreen_or_maximized
|
||||
end
|
||||
|
||||
---Get all tags on this window.
|
||||
---
|
||||
---Shorthand for `handle:props().tags`.
|
||||
---
|
||||
---@return TagHandle[]?
|
||||
function WindowHandle:tags()
|
||||
return self:props().tags
|
||||
end
|
||||
|
||||
---@param config_client Client
|
||||
---@return Window
|
||||
function window.new(config_client)
|
||||
|
|
|
@ -1,29 +1,18 @@
|
|||
require("pinnacle").setup(function(pinnacle)
|
||||
local input = pinnacle.input
|
||||
local process = pinnacle.process
|
||||
local output = pinnacle.output
|
||||
local tag = pinnacle.tag
|
||||
local window = pinnacle.window
|
||||
require("pinnacle").setup(function(Pinnacle)
|
||||
local Input = Pinnacle.input
|
||||
local Process = Pinnacle.process
|
||||
local Output = Pinnacle.output
|
||||
local Tag = Pinnacle.tag
|
||||
local Window = Pinnacle.window
|
||||
|
||||
local mods = input.mod
|
||||
|
||||
input:set_keybind({ mods.SHIFT }, "A", function()
|
||||
process:spawn({ "alacritty" }, {
|
||||
stdout = function(line)
|
||||
print("stdout")
|
||||
print(line)
|
||||
end,
|
||||
stderr = function(line)
|
||||
print("stderr")
|
||||
print(line)
|
||||
end,
|
||||
exit = function(code, msg)
|
||||
print(code, msg)
|
||||
end,
|
||||
})
|
||||
end)
|
||||
|
||||
input:set_keybind({ 1 }, "Q", function()
|
||||
pinnacle:quit()
|
||||
Input:keybind({ "shift" }, "f", function()
|
||||
local focused = Window:get_focused()
|
||||
if focused then
|
||||
print(focused:fullscreen_or_maximized())
|
||||
-- assert(focused:fullscreen_or_maximized() == "neither")
|
||||
focused:set_fullscreen(true)
|
||||
print(focused:fullscreen_or_maximized())
|
||||
-- assert(focused:fullscreen_or_maximized() == "fullscreen")
|
||||
end
|
||||
end)
|
||||
end)
|
||||
|
|
|
@ -77,6 +77,7 @@ message GetPropertiesResponse {
|
|||
optional bool focused = 4;
|
||||
optional bool floating = 5;
|
||||
optional .pinnacle.window.rules.v0alpha1.FullscreenOrMaximized fullscreen_or_maximized = 6;
|
||||
repeated uint32 tag_ids = 7;
|
||||
}
|
||||
|
||||
service WindowService {
|
||||
|
|
|
@ -1217,7 +1217,7 @@ impl pinnacle_api_defs::pinnacle::window::v0alpha1::window_service_server::Windo
|
|||
window_size.h = height.unwrap_or(window_size.h);
|
||||
|
||||
let rect = Rectangle::from_loc_and_size(window_loc, window_size);
|
||||
window.change_geometry(rect);
|
||||
// window.change_geometry(rect);
|
||||
window.with_state(|state| {
|
||||
use crate::window::window_state::FloatingOrTiled;
|
||||
state.floating_or_tiled = match state.floating_or_tiled {
|
||||
|
@ -1727,6 +1727,22 @@ impl pinnacle_api_defs::pinnacle::window::v0alpha1::window_service_server::Windo
|
|||
}
|
||||
} as i32);
|
||||
|
||||
let tag_ids = window
|
||||
.as_ref()
|
||||
.map(|win| {
|
||||
win.with_state(|state| {
|
||||
state
|
||||
.tags
|
||||
.iter()
|
||||
.map(|tag| match tag.id() {
|
||||
TagId::Some(id) => id,
|
||||
TagId::None => unreachable!(),
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
})
|
||||
})
|
||||
.unwrap_or_default();
|
||||
|
||||
let _ = sender.send(
|
||||
pinnacle_api_defs::pinnacle::window::v0alpha1::GetPropertiesResponse {
|
||||
geometry,
|
||||
|
@ -1735,6 +1751,7 @@ impl pinnacle_api_defs::pinnacle::window::v0alpha1::window_service_server::Windo
|
|||
focused,
|
||||
floating,
|
||||
fullscreen_or_maximized,
|
||||
tag_ids,
|
||||
},
|
||||
);
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue