From ad81b553c8542e0cc5dfba166d48c61b9203b558 Mon Sep 17 00:00:00 2001 From: Ottatop Date: Tue, 4 Jun 2024 10:48:34 -0500 Subject: [PATCH] lua-api: Add custom modelines --- Cargo.lock | 1 + Cargo.toml | 6 +-- api/lua/pinnacle/grpc/defs.lua | 21 +++++++++ api/lua/pinnacle/output.lua | 48 ++++++++++++++++++++ api/lua/pinnacle/util.lua | 83 ++++++++++++++++++++++++++++++++++ 5 files changed, 156 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8fb6133..71171e5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2388,6 +2388,7 @@ checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c" [[package]] name = "smithay" version = "0.3.0" +source = "git+https://github.com/Smithay/smithay?rev=900b938#900b938970081cb525dc94ff083d76aa07c60e54" dependencies = [ "appendlist", "ash", diff --git a/Cargo.toml b/Cargo.toml index 3782a89..b6d71d0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,9 +34,9 @@ dircpy = "0.3.16" tempfile = "3.10.1" [workspace.dependencies.smithay] -# git = "https://github.com/Smithay/smithay" -# rev = "900b938" -path = "../../git/smithay" +git = "https://github.com/Smithay/smithay" +rev = "900b938" +# path = "../../git/smithay" default-features = false features = [ "desktop", diff --git a/api/lua/pinnacle/grpc/defs.lua b/api/lua/pinnacle/grpc/defs.lua index 8010c7f..2f07610 100644 --- a/api/lua/pinnacle/grpc/defs.lua +++ b/api/lua/pinnacle/grpc/defs.lua @@ -65,6 +65,20 @@ local pinnacle_output_v0alpha1_Transform = { ---@field pixel_height integer? ---@field refresh_rate_millihz integer? +---@class pinnacle.output.v0alpha1.SetModelineRequest +---@field output_name string? +---@field clock number? +---@field hdisplay integer? +---@field hsync_start integer? +---@field hsync_end integer? +---@field htotal integer? +---@field vdisplay integer? +---@field vsync_start integer? +---@field vsync_end integer? +---@field vtotal integer? +---@field hsync_pos boolean? +---@field vsync_pos boolean? + ---@class pinnacle.output.v0alpha1.SetScaleRequest ---@field output_name string? ---@field absolute number? @@ -476,6 +490,13 @@ defs.pinnacle = { response = "google.protobuf.Empty", }, ---@type GrpcRequestArgs + SetModeline = { + service = "pinnacle.output.v0alpha1.OutputService", + method = "SetModeline", + request = "pinnacle.output.v0alpha1.SetModelineRequest", + response = "google.protobuf.Empty", + }, + ---@type GrpcRequestArgs SetScale = { service = "pinnacle.output.v0alpha1.OutputService", method = "SetScale", diff --git a/api/lua/pinnacle/output.lua b/api/lua/pinnacle/output.lua index 552daa4..2ba57fb 100644 --- a/api/lua/pinnacle/output.lua +++ b/api/lua/pinnacle/output.lua @@ -813,6 +813,54 @@ function OutputHandle:set_mode(pixel_width, pixel_height, refresh_rate_millihz) }) end +---@class Modeline +---@field clock number +---@field hdisplay integer +---@field hsync_start integer +---@field hsync_end integer +---@field htotal integer +---@field vdisplay integer +---@field vsync_start integer +---@field vsync_end integer +---@field vtotal integer +---@field hsync boolean +---@field vsync boolean + +---Set a custom modeline for this output. +--- +---This accepts a `Modeline` table or a string of the modeline. +--- +---@param modeline string|Modeline +function OutputHandle:set_modeline(modeline) + if type(modeline) == "string" then + local ml, err = require("pinnacle.util").output.parse_modeline(modeline) + if ml then + modeline = ml + else + print("invalid modeline: " .. tostring(err)) + return + end + end + + ---@type pinnacle.output.v0alpha1.SetModelineRequest + local request = { + output_name = self.name, + clock = modeline.clock, + hdisplay = modeline.hdisplay, + hsync_start = modeline.hsync_start, + hsync_end = modeline.hsync_end, + htotal = modeline.htotal, + vdisplay = modeline.vdisplay, + vsync_start = modeline.vsync_start, + vsync_end = modeline.vsync_end, + vtotal = modeline.vtotal, + hsync_pos = modeline.hsync, + vsync_pos = modeline.vsync, + } + + client.unary_request(output_service.SetModeline, request) +end + ---Set this output's scaling factor. --- ---@param scale number diff --git a/api/lua/pinnacle/util.lua b/api/lua/pinnacle/util.lua index 07327a2..88fa8c7 100644 --- a/api/lua/pinnacle/util.lua +++ b/api/lua/pinnacle/util.lua @@ -118,10 +118,93 @@ function rectangle.new(x, y, width, height) return self end +---Parse a modeline string. +--- +---@param modeline string +--- +---@return Modeline|nil modeline A modeline if successful +---@return string|nil error An error message if any +local function parse_modeline(modeline) + local args = modeline:gmatch("[^%s]+") + + local targs = {} + + for arg in args do + table.insert(targs, arg) + end + + local clock = tonumber(targs[1]) + local hdisplay = tonumber(targs[2]) + local hsync_start = tonumber(targs[3]) + local hsync_end = tonumber(targs[4]) + local htotal = tonumber(targs[5]) + local vdisplay = tonumber(targs[6]) + local vsync_start = tonumber(targs[7]) + local vsync_end = tonumber(targs[8]) + local vtotal = tonumber(targs[9]) + local hsync = targs[10] + local vsync = targs[11] + + if + not ( + clock + and hdisplay + and hsync_start + and hsync_end + and htotal + and vdisplay + and vsync_start + and vsync_end + and vtotal + and hsync + and vsync + ) + then + return nil, "one or more fields was missing" + end + + local hsync_lower = string.lower(hsync) + local vsync_lower = string.lower(vsync) + + if hsync_lower == "+hsync" then + hsync = true + elseif hsync_lower == "-hsync" then + hsync = false + else + return nil, "invalid hsync: " .. hsync + end + + if vsync_lower == "+vsync" then + vsync = true + elseif vsync_lower == "-vsync" then + vsync = false + else + return nil, "invalid vsync: " .. vsync + end + + ---@type Modeline + return { + clock = clock, + hdisplay = hdisplay, + hsync_start = hsync_start, + hsync_end = hsync_end, + htotal = htotal, + vdisplay = vdisplay, + vsync_start = vsync_start, + vsync_end = vsync_end, + vtotal = vtotal, + hsync = hsync, + vsync = vsync, + } +end + ---Utility functions. ---@class Util local util = { rectangle = rectangle, + output = { + parse_modeline = parse_modeline, + }, } ---Batch a set of requests that will be sent to the compositor all at once.