From 3dce4eef68870c8bc57ac84cb5d22397f4af62ae Mon Sep 17 00:00:00 2001 From: deb84 <56758812+Deb84@users.noreply.github.com> Date: Sat, 25 Jul 2026 08:04:48 +0200 Subject: [PATCH 1/2] refactoring: everything (architecture and logic) --- .vscode/settings.json | 8 ++ miaout/DOC.md | 5 + miaout/config.lua | 35 ++++++ miaout/init.lua | 41 +++++-- miaout/layout.lua | 82 -------------- miaout/log.lua | 33 ++++++ miaout/types/config.types.lua | 25 +++++ miaout/types/hl.types.lua | 7 ++ miaout/types/miaout.types.lua | 57 ++++++++++ miaout/types/window.types.lua | 93 ++++++++++++++++ miaout/types/workspace.types.lua | 90 ++++++++++++++++ miaout/utils/layout.lua | 35 ++++++ miaout/utils/monitor.lua | 71 ++++++++++++ miaout/utils/utils.lua | 23 ++++ miaout/utils/window.lua | 7 ++ miaout/utils/workspace.lua | 71 ++++++++++++ miaout/window.lua | 103 ------------------ miaout/window/events.lua | 35 ++++++ miaout/window/facade.lua | 142 ++++++++++++++++++++++++ miaout/window/logic.lua | 115 ++++++++++++++++++++ miaout/window/manager.lua | 74 +++++++++++++ miaout/window/window.lua | 69 ++++++++++++ miaout/workspace.lua | 178 ------------------------------- miaout/workspace/events.lua | 22 ++++ miaout/workspace/facade.lua | 118 ++++++++++++++++++++ miaout/workspace/logic.lua | 103 ++++++++++++++++++ miaout/workspace/manager.lua | 74 +++++++++++++ miaout/workspace/workspace.lua | 81 ++++++++++++++ 28 files changed, 1423 insertions(+), 374 deletions(-) create mode 100644 .vscode/settings.json create mode 100644 miaout/DOC.md create mode 100644 miaout/config.lua delete mode 100644 miaout/layout.lua create mode 100644 miaout/log.lua create mode 100644 miaout/types/config.types.lua create mode 100644 miaout/types/hl.types.lua create mode 100644 miaout/types/miaout.types.lua create mode 100644 miaout/types/window.types.lua create mode 100644 miaout/types/workspace.types.lua create mode 100644 miaout/utils/layout.lua create mode 100644 miaout/utils/monitor.lua create mode 100644 miaout/utils/utils.lua create mode 100644 miaout/utils/window.lua create mode 100644 miaout/utils/workspace.lua delete mode 100644 miaout/window.lua create mode 100644 miaout/window/events.lua create mode 100644 miaout/window/facade.lua create mode 100644 miaout/window/logic.lua create mode 100644 miaout/window/manager.lua create mode 100644 miaout/window/window.lua delete mode 100644 miaout/workspace.lua create mode 100644 miaout/workspace/events.lua create mode 100644 miaout/workspace/facade.lua create mode 100644 miaout/workspace/logic.lua create mode 100644 miaout/workspace/manager.lua create mode 100644 miaout/workspace/workspace.lua diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..4fe5936 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,8 @@ +{ + "Lua.workspace.library": [ + "/usr/share/hypr/stubs" + ], + "Lua.diagnostics.globals": [ + "changeFullscreen" + ] +} \ No newline at end of file diff --git a/miaout/DOC.md b/miaout/DOC.md new file mode 100644 index 0000000..9358375 --- /dev/null +++ b/miaout/DOC.md @@ -0,0 +1,5 @@ +#### il y a 3 types d'abstractions : +*par exemple pour window* +le module window est la gestion de fenĂȘtre avec son manager et repo +le module facade est le module qui expose l'api publique +init est le module qui permet d'initialiser le tout \ No newline at end of file diff --git a/miaout/config.lua b/miaout/config.lua new file mode 100644 index 0000000..47a03fd --- /dev/null +++ b/miaout/config.lua @@ -0,0 +1,35 @@ +local Config = {} ---@class MiaoutConfig +Config.__index = Config + +function Config.new() + local self = setmetatable({}, Config) + + Config.window = { + default = {client = 0, internal = 0}, + maximise = {client = 1, internal = 1}, + fullscreen = {client = 1, internal = 2}, + } + + Config.workspace = { + nextWorkspaceSelector = "e+1", + prevWorkspaceSelector = "e-1", + nextMonitorWorkspaceSelector = "m+1", + prevMonitorWorkspaceSelector = "m-1" , + defaultLayout = hl.get_config("general.layout"), + layouts = { + "dwindle", + "master", + "scrolling", + "monocle" + } + } + + Config.notifications = { + prefix = "MIAOUT ", + displayTimeMs = 3000, + } + + return self +end + +return Config \ No newline at end of file diff --git a/miaout/init.lua b/miaout/init.lua index b48b51c..5900d24 100644 --- a/miaout/init.lua +++ b/miaout/init.lua @@ -1,17 +1,36 @@ -local workspace = require("miaout.workspace") -local layout = require("miaout.layout") -local window = require("miaout.window") +local Log = require("miaout.log") ---@class Log +local Config = require("miaout.config") ---@class MiaoutConfig -local M = {} +local WindowManager = require("miaout.window.manager") ---@class WindowManager +local WindowLogic = require("miaout.window.logic") ---@class WindowLogic +local WindowFacade = require("miaout.window.facade") ---@class WindowFacade -function M.Init() - local Instances = {} +local WorkspaceManager = require("miaout.workspace.manager") ---@class WorkspaceManager +local WorkspaceLogic = require("miaout.workspace.logic") ---@class WorkspaceLogic +local WorkspaceFacade = require("miaout.workspace.facade") ---@class WorkspaceFacade - Instances.layout = layout.new() - Instances.window = window.new() - Instances.workspace = workspace.new(Instances.layout, Instances.window) - return Instances +local Miaout = {} + +---@return Modules +function Miaout.Init() + local config = Config.new() + local log = Log.new(config) + + local workspaceManager = WorkspaceManager.new() + local workspaceLogic = WorkspaceLogic.new(log, config, workspaceManager) + local workspaceFacade = WorkspaceFacade.new(log, workspaceLogic, workspaceManager) + + local windowManager = WindowManager.new() + local windowLogic = WindowLogic.new(log, config, windowManager, workspaceManager) + local windowFacade = WindowFacade.new(log, windowLogic, windowManager) + + local Modules = {} + + Modules.window = windowFacade + Modules.workspace = workspaceFacade + + return Modules end -return M \ No newline at end of file +return Miaout \ No newline at end of file diff --git a/miaout/layout.lua b/miaout/layout.lua deleted file mode 100644 index e21ec0f..0000000 --- a/miaout/layout.lua +++ /dev/null @@ -1,82 +0,0 @@ -local Instance = {} -Instance.__index = Instance - -function Instance.new() - local defaultLayout = hl.get_config("general.layout") - - local layouts = { - [1] = "dwindle", - [2] = "master", - [3] = "scrolling", - [4] = "monocle", - } - - local layoutIndex = {} - - for i, v in ipairs(layouts) do - layoutIndex[v] = i - end - - local self = setmetatable({}, Instance) - self.layouts = layouts - self.layoutIndex = layoutIndex - - self.defaultLayout = defaultLayout - self.lastLayout = defaultLayout - - return self -end - -function Instance:GetCurrentLayout() - return hl.get_config("general.layout") -end - -function Instance:UpdateLayout(newLayout) - hl.config({ - general = {layout = newLayout} - }) -end - -function Instance:SwitchLayout(step) - self.lastLayout = self:GetCurrentLayout() - local currentIndex = self.layoutIndex[self.lastLayout] - local layoutLength = #self.layouts - - local nextIndex =((currentIndex - 1 + step) % layoutLength) + 1 - - self:UpdateLayout(self.layouts[nextIndex]) -end - -function Instance:SwitchNextLayout() - self:SwitchLayout(1) -end - -function Instance:SwitchPrevLayout() - self:SwitchLayout(-1) -end - -function Instance:SwitchLastLayout() - local currentLayout = self:GetCurrentLayout() - - self:UpdateLayout(self.lastLayout) - - self.lastLayout = currentLayout -end - -function Instance:SwitchDefaultLayout() - local currentLayout = self:GetCurrentLayout() - local newLayout - - if currentLayout ~= self.defaultLayout then - - newLayout = self.defaultLayout - self.lastLayout = currentLayout - else - newLayout = self.lastLayout - self.lastLayout = currentLayout - end - - self:UpdateLayout(newLayout) -end - -return Instance \ No newline at end of file diff --git a/miaout/log.lua b/miaout/log.lua new file mode 100644 index 0000000..ead6ea7 --- /dev/null +++ b/miaout/log.lua @@ -0,0 +1,33 @@ + + +---@class Log +local Log = {} +Log.__index = Log + +function Log.new(config) + local self = setmetatable({}, Log) + + self.config = config.notifications + + return self +end + + +---@param level string +---@param ... string +function Log:format(level, ...) + local text = string.format("%s %s", self.config.prefix, level, ...) + return text +end + +function Log:Error(...) + local text = self:format(...) + hl.notification.create({text = text, timeout = self.config.displayTimeMs, color = "0xffff0000"}) +end + +function Log:Info(...) + local text = self:format(...) + hl.notification.create({text = text, timeout = self.config.displayTimeMs}) +end + +return Log \ No newline at end of file diff --git a/miaout/types/config.types.lua b/miaout/types/config.types.lua new file mode 100644 index 0000000..4fd3fce --- /dev/null +++ b/miaout/types/config.types.lua @@ -0,0 +1,25 @@ +---@meta + +-- Config +---@class MiaoutConfig +---@field new fun(): MiaoutConfig +---@field window WindowConfig +---@field workspace WorkspaceConfig +---@field notifications NotificationConfig + +---@class WindowConfig +---@field default FullscreenState +---@field maximise FullscreenState +---@field fullscreen FullscreenState + +---@class WorkspaceConfig +---@field nextWorkspaceSelector HL.WorkspaceSelector +---@field prevWorkspaceSelector HL.WorkspaceSelector +---@field nextMonitorWorkspaceSelector HL.WorkspaceSelector +---@field prevMonitorWorkspaceSelector HL.WorkspaceSelector +---@field defaultLayout string +---@field layouts string[] + +---@class NotificationConfig +---@field prefix string +---@field displayTimeMs integer diff --git a/miaout/types/hl.types.lua b/miaout/types/hl.types.lua new file mode 100644 index 0000000..9226c2b --- /dev/null +++ b/miaout/types/hl.types.lua @@ -0,0 +1,7 @@ +---@meta + +---@alias Fullscreen 0|1|2|3 + +---@class FullscreenState +---@field internal Fullscreen +---@field client Fullscreen \ No newline at end of file diff --git a/miaout/types/miaout.types.lua b/miaout/types/miaout.types.lua new file mode 100644 index 0000000..9173011 --- /dev/null +++ b/miaout/types/miaout.types.lua @@ -0,0 +1,57 @@ +---@meta + +---@class Log +---@field new fun(config: MiaoutConfig): Log +---@field private config NotificationConfig +---@field private format fun(self: Log, level: string, ...: string): string +---@field Error fun(self: Log, ...: string) +---@field Info fun(self: Log, ...: string) + +-- Utils + +---@generic CopyTableT +---@alias CopyTable fun(t: CopyTableT): CopyTableT + +---@class Utils +---@field CopyTable CopyTable +---@field TableLength fun(t: table): integer + +---@alias GetMonitorLambda fun(monitorId: integer, monitorsLen: integer): integer + +---@class MonitorUtils +---@field GetMonitorsOrdered fun(): HL.Monitor[], integer +---@field GetMonitorOrderedId fun(monitorId: integer): integer|nil +---@field GetMonitorFromOrderedId fun(monitorId: integer): HL.Monitor|nil +---@field GetTargetMonitor fun(self: MonitorUtils, func: GetMonitorLambda): HL.Monitor? +---@field GetNextMonitor fun(self: MonitorUtils): HL.Monitor? +---@field GetPrevMonitor fun(self: MonitorUtils): HL.Monitor? + +---@alias GetLayoutLambda fun(layoutId: integer, layoutsLen: integer): integer + +---@class LayoutUtils +---@field GetTargetLayout fun(layouts: string[], layout: string, func: GetLayoutLambda): string +---@field GetNextLayout fun(self: LayoutUtils, layouts: string[], layout: string): string +---@field GetPrevLayout fun(self: LayoutUtils, layouts: string[], layout: string): string + +---@class WindowUtils +---@field CompareFullscreenState fun(a: FullscreenState, b:FullscreenState): boolean + +---@alias GetWorkspaceLambda fun(workspaceIndex: integer, workspaceLen: integer): integer + +---@class WorkspaceUtils +---@field private GetTargetedWorkspace fun(workspaces: HL.Workspace[]|nil, func: GetWorkspaceLambda, workspace: Workspace): HL.Workspace|nil +---@field private CalculateNextWorksace GetWorkspaceLambda +---@field private CalculatePrevWorkspace GetWorkspaceLambda +---@field GetNextWorkspace fun(self: WorkspaceUtils, workspace: Workspace): HL.Workspace|nil +---@field GetPrevWorkspace fun(self: WorkspaceUtils, workspace: Workspace): HL.Workspace|nil +---@field GetMonitorWorkspaces fun(monitor: HL.Monitor): HL.Workspace[]|nil +---@field GetNextMonitorWorkspace fun(self: WorkspaceUtils, workspace: Workspace, monitor: HL.Monitor): HL.Workspace|nil +---@field GetPrevMonitorWorkspace fun(self: WorkspaceUtils, workspace: Workspace, monitor: HL.Monitor): HL.Workspace|nil + +-- Miaout Init +---@class Modules +---@field window WindowFacade +---@field workspace WorkspaceFacade + +---@class Miaout +---@field Init fun(): Modules diff --git a/miaout/types/window.types.lua b/miaout/types/window.types.lua new file mode 100644 index 0000000..fb431b2 --- /dev/null +++ b/miaout/types/window.types.lua @@ -0,0 +1,93 @@ +---@meta + +---@class WindowState +---@field fullscreenState FullscreenState +---@field size integer|table + +---@class WindowRepo +---@field new fun(): WindowRepo +---@field private windowStates table +---@field SaveState fun(self: WindowRepo, windowId: integer, state: WindowState) +---@field GetState fun(self: WindowRepo, windowId: integer): WindowState? +---@field RemoveState fun(self: WindowRepo, windowId: integer) + +---@class WindowManager +---@field new fun(): WindowManager +---@field private repo WindowRepo +---@field private windows Window[] +---@field NewWindow fun(self: WindowManager, hlw: HL.Window): Window +---@field GetWindow fun(self: WindowManager, windowId: integer): Window? +---@field GetOrNewWindow fun(self: WindowManager, hlw: HL.Window): Window +---@field RemoveWindow fun(self: WindowManager, windowId: integer) + +---@class Window +---@field new fun(repo: WindowRepo, hlWindow: HL.Window): Window +---@field private repo WindowRepo +---@field private hlw HL.Window +---@field id integer +---@field GetHlObject fun(self: Window): HL.Window +---@field UpdateState fun(self: Window) +---@field LoadState fun(self: Window) +---@field Focus fun(self: Window) +---@field SetFullscreenState fun(self: Window, state: FullscreenState) +---@field GetFullscreenState fun(self: Window): FullscreenState +---@field SwapWindow fun(self: Window, window: Window) +---@field MoveToWorkspace fun(self: Window, workspace: Workspace) +---@field MoveToMonitor fun(self: Window, monitor: HL.Monitor) + +---@alias MoveToWorkspaceLambda fun(self: WorkspaceUtils, workspace: Workspace, monitor: HL.Monitor?) + +---@class WindowLogic +---@field new fun(log: Log, config: MiaoutConfig, windowManager: WindowManager, workspaceManager: WorkspaceManager): WindowLogic +---@field private log Log +---@field private config MiaoutConfig +---@field private windowManager WindowManager +---@field private workspaceManager WorkspaceManager +---@field private MoveToMonitor fun(self:WindowLogic, window: Window, monitor: HL.Monitor?) +---@field private MoveToWorkspace fun(self: WindowLogic, window: Window, func: MoveToWorkspaceLambda) +---@field MoveToNextWorkspace fun(self:WindowLogic, window: Window) +---@field MoveToPrevWorkspace fun(self:WindowLogic, window: Window) +---@field MoveToNextMonitorWorkspace fun(self:WindowLogic, window: Window) +---@field MoveToPrevMonitorWorkspace fun(self:WindowLogic, window: Window) +---@field MoveToNextMonitor fun(self:WindowLogic, window: Window) +---@field MoveToPrevMonitor fun(self:WindowLogic, window: Window) +---@field private ChangeScreenState fun(self: WindowLogic, window: Window, state: FullscreenState, toggle: FullscreenState?) +---@field SetScreenDefault fun(self: WindowLogic, window: Window) +---@field Maximise fun(self: WindowLogic, window: Window) +---@field SetFullscreen fun(self: WindowLogic, window: Window) +---@field SwapWindows fun(self: WindowLogic, activeWindow: Window, lastWindow: Window) + + +---@alias WindowFacadeMethod fun(self: WindowFacade, hlWindow: HL.Window) + +---@class WindowFacade +---@field new fun(log: Log, windowLogic: WindowLogic, windowManager: WindowManager): WindowFacade +---@field private log Log +---@field private windowLogic WindowLogic +---@field private windowManager WindowManager +---@field public current CurrentWindowFacade +---@field MoveToNextWorkspace WindowFacadeMethod +---@field MoveToPrevWorkspace WindowFacadeMethod +---@field MoveToNextMonitorWorkspace WindowFacadeMethod +---@field MoveToPrevMonitorWorkspace WindowFacadeMethod +---@field DefaultScreen WindowFacadeMethod +---@field Maximise WindowFacadeMethod +---@field Fullscreen WindowFacadeMethod +---@field SwapWindows fun(self: WindowFacade, hlWindowA: HL.Window, hlWindowA: HL.Window) + +---@alias CurrentWindowFacadeMethod fun(self: CurrentWindowFacade) +---@alias WithActiveWindowCallback fun(self: WindowFacade, hlWindow: HL.Window, ...: any?) + +---@class CurrentWindowFacade +---@field new fun(windowFacade: WindowFacade, log: Log): CurrentWindowFacade +---@field private log Log +---@field private facade WindowFacade +---@field private withActiveWindow fun(self: CurrentWindowFacade, func: WithActiveWindowCallback, ...: any?) +---@field MoveToNextWorkspace CurrentWindowFacadeMethod +---@field MoveToPrevWorkspace CurrentWindowFacadeMethod +---@field MoveToNextMonitorWorkspace CurrentWindowFacadeMethod +---@field MoveToPrevMonitorWorkspace CurrentWindowFacadeMethod +---@field DefaultScreen CurrentWindowFacadeMethod +---@field Maximise CurrentWindowFacadeMethod +---@field Fullscreen CurrentWindowFacadeMethod + diff --git a/miaout/types/workspace.types.lua b/miaout/types/workspace.types.lua new file mode 100644 index 0000000..1705eb5 --- /dev/null +++ b/miaout/types/workspace.types.lua @@ -0,0 +1,90 @@ +---@meta + + +---@class WorkspaceState: table +---@field layout string + +---@class WorkspaceRepo +---@field new fun(): WorkspaceRepo +---@field private workspaceStates table +---@field RemoveState fun(self: WorkspaceRepo, workspaceId: integer) +---@field SaveState fun(self: WorkspaceRepo, workspaceId: integer, workspaceState: WorkspaceState) +---@field GetState fun(self: WorkspaceRepo, workspaceId: integer): WorkspaceState? + +---@class WorkspaceManager +---@field new fun(): WorkspaceManager +---@field private repo WorkspaceRepo +---@field private workspaces Workspace[] +---@field NewWorkspace fun(self: WorkspaceManager, hlw: HL.Workspace): Workspace +---@field GetWorkspace fun(self: WorkspaceManager, workspaceId: integer): Workspace? +---@field GetOrNewWorkspace fun(self: WorkspaceManager, hlw: HL.Workspace): Workspace +---@field RemoveWorkspace fun(self: WorkspaceManager, workspaceId: integer) + +---@class Workspace +---@field new fun(repo: WorkspaceRepo, hlWorkspace: HL.Workspace): Workspace +---@field private repo WorkspaceRepo +---@field private hlw HL.Workspace? +---@field public id integer +---@field GetHlObject fun(self: Workspace): HL.Workspace? +---@field UpdateState fun(self: Workspace, state: WorkspaceState?) +---@field LoadState fun(self: Workspace) +---@field Focus fun(self: Workspace) +---@field MoveToMonitor fun(self: Workspace, monitor: HL.Monitor) +---@field ChangeLayout fun(self: Workspace, layout: string) +---@field GetLayout fun(self: Workspace): string + +---@alias ChangeLayoutLambda fun(layouts: string[], string): string + +---@class WorkspaceLogic +---@field new fun(log: Log, config: MiaoutConfig, manager: WorkspaceManager): WorkspaceLogic +---@field private config MiaoutConfig +---@field private log Log +---@field private manager WorkspaceManager +---@field NewWorkspace fun(self: WorkspaceLogic) +---@field SwitchToWorkspace fun(self: WorkspaceLogic, workspace: Workspace|HL.WorkspaceSelector) +---@field NextWorkspace fun(self: WorkspaceLogic) +---@field PrevWorkspace fun(self: WorkspaceLogic) +---@field NextMonitorWorkspace fun(self: WorkspaceLogic) +---@field PrevMonitorWorkspace fun(self: WorkspaceLogic) +---@field MoveToMonitor fun(self: WorkspaceLogic, workspace: Workspace, monitor: HL.Monitor?) +---@field MoveToNextMonitor fun(self: WorkspaceLogic, workspace: Workspace) +---@field MoveToPrevMonitor fun(self: WorkspaceLogic, workspace: Workspace) +---@field private ChangeLayout fun(self: WorkspaceLogic, workspace: Workspace, func: ChangeLayoutLambda) +---@field NextLayout fun(self: WorkspaceLogic, workspace: Workspace) +---@field PrevLayout fun(self: WorkspaceLogic, workspace: Workspace) +---@field DefaultLayout fun(self: WorkspaceLogic, workspace: Workspace) + +---@alias WorkspaceFacadeMethod fun(self: WorkspaceFacade) + +---@class WorkspaceFacade +---@field new fun(log: Log, workspaceLogic: WorkspaceLogic, workspaceManager: WorkspaceManager): WorkspaceFacade +---@field private log Log +---@field private workspaceLogic WorkspaceLogic +---@field private workspaceManager WorkspaceManager +---@field public current CurrentWorkspaceFacade +---@field NewWorkspace WorkspaceFacadeMethod +---@field NextWorkspace WorkspaceFacadeMethod +---@field PrevWorkspace WorkspaceFacadeMethod +---@field NextMonitorWorkspace WorkspaceFacadeMethod +---@field PrevMonitorWorkspace WorkspaceFacadeMethod +---@field MoveToMonitor fun(self: WorkspaceFacade, hlWorkspace: HL.Workspace, monitor: HL.Monitor) +---@field MoveToNextMonitor fun(self: WorkspaceFacade, hlWorkspace: HL.Workspace) +---@field MoveToPrevMonitor fun(self: WorkspaceFacade, hlWorkspace: HL.Workspace) +---@field NextLayout fun(self: WorkspaceFacade, hlWorkspace: HL.Workspace) +---@field PrevLayout fun(self: WorkspaceFacade, hlWorkspace: HL.Workspace) +---@field DefaultLayout fun(self: WorkspaceFacade, hlWorkspace: HL.Workspace) + +---@alias CurrentWorkspaceFacadeMethod fun(self: CurrentWorkspaceFacade) +---@alias WithActiveWorkspaceCallback fun(self: WorkspaceFacade, hlWindow: HL.Workspace, ...: any?) + +---@class CurrentWorkspaceFacade +---@field new fun(workspaceFacade: WorkspaceFacade, log: Log): CurrentWorkspaceFacade +---@field private log Log +---@field private facade WorkspaceFacade +---@field private WithActiveWorkspaceCallback +---@field MoveToMonitor fun(self: CurrentWorkspaceFacade, monitor: HL.Monitor) +---@field MoveToNextMonitor CurrentWorkspaceFacadeMethod +---@field MoveToPrevMonitor CurrentWorkspaceFacadeMethod +---@field NextLayout CurrentWorkspaceFacadeMethod +---@field PrevLayout CurrentWorkspaceFacadeMethod +---@field DefaultLayout CurrentWorkspaceFacadeMethod \ No newline at end of file diff --git a/miaout/utils/layout.lua b/miaout/utils/layout.lua new file mode 100644 index 0000000..746204c --- /dev/null +++ b/miaout/utils/layout.lua @@ -0,0 +1,35 @@ +local Layout = {} ---@class LayoutUtils + + +function Layout.GetTargetLayout(layouts, layout, func) + local layoutId + + for i, v in ipairs(layouts) do + if v == layout then + layoutId = i + end + end + + local nextLayoutId = func(layoutId, #layouts) + + return layouts[nextLayoutId] +end + +function Layout:GetNextLayout(layouts, layout) + local func = function (layoutId, layoutsLen) + return ((layoutId - 1 + 1) % layoutsLen) + 1 + end + + return self.GetTargetLayout(layouts, layout, func) +end + +function Layout:GetPrevLayout(layouts, layout) + local func = function (layoutId, layoutsLen) + return ((layoutId - 1 - 1) % layoutsLen) + 1 + end + + return self.GetTargetLayout(layouts, layout, func) +end + + +return Layout \ No newline at end of file diff --git a/miaout/utils/monitor.lua b/miaout/utils/monitor.lua new file mode 100644 index 0000000..d2230ef --- /dev/null +++ b/miaout/utils/monitor.lua @@ -0,0 +1,71 @@ +local Utils = require("miaout.utils.utils") + +local Monitor = {} ---@class MonitorUtils + + +function Monitor.GetMonitorsOrdered() + local monitors = hl.get_monitors() + local monitorsAscending = Utils.CopyTable(monitors) + + table.sort(monitorsAscending, function (a, b) + return a.id < b.id + end) + + return monitorsAscending, #monitors +end + +function Monitor.GetMonitorOrderedId(monitorId) + local monitors = Monitor.GetMonitorsOrdered() + + for id, monitor in ipairs(monitors) do + if monitor.id == monitorId then + return id + end + end + + return nil +end + +function Monitor.GetMonitorFromOrderedId(monitorId) + local monitors = Monitor.GetMonitorsOrdered() + + return monitors[monitorId] +end + +function Monitor:GetTargetMonitor(func) + local monitor = hl.get_active_monitor() + if not monitor then return end + + local monitorsLen = #hl.get_monitors() + if monitorsLen == 0 then return end + + local monitorId = self.GetMonitorOrderedId(monitor.id) + if not monitorId then return end + + local nextMonitorId = func(monitorId, monitorsLen) + local nextMonitor = self.GetMonitorFromOrderedId(nextMonitorId) + + return nextMonitor +end + +function Monitor:GetNextMonitor() + local func = function (monitorId, monitorsLen) + return ((monitorId + 1 + 1) % monitorsLen) + 1 + end + + return self:GetTargetMonitor(func) +end + +function Monitor:GetPrevMonitor() + local func = function (monitorId, monitorsLen) + return ((monitorId + 1 - 1) % monitorsLen) + 1 + end + + return self:GetTargetMonitor(func) +end + + + + + +return Monitor \ No newline at end of file diff --git a/miaout/utils/utils.lua b/miaout/utils/utils.lua new file mode 100644 index 0000000..3c25ff8 --- /dev/null +++ b/miaout/utils/utils.lua @@ -0,0 +1,23 @@ +local Utils = {} ---@class Utils + +function Utils.CopyTable(t) + local new = {} + + for i, v in ipairs(t) do + new[i] = v + end + + return new +end + +function Utils.TableLength(t) + local count = 0 + + for _ in pairs(t) do + count = count + 1 + end + + return count +end + +return Utils \ No newline at end of file diff --git a/miaout/utils/window.lua b/miaout/utils/window.lua new file mode 100644 index 0000000..e0aa8a3 --- /dev/null +++ b/miaout/utils/window.lua @@ -0,0 +1,7 @@ +local WindowUtils = {} ---@class WindowUtils + +function WindowUtils.CompareFullscreenState(a, b) + return a.internal == b.internal and a.client == b.client +end + +return WindowUtils \ No newline at end of file diff --git a/miaout/utils/workspace.lua b/miaout/utils/workspace.lua new file mode 100644 index 0000000..708f01b --- /dev/null +++ b/miaout/utils/workspace.lua @@ -0,0 +1,71 @@ +local Utils = require("miaout.utils.utils") + +local WorkspaceUtils = {} ---@class WorkspaceUtils + + +function WorkspaceUtils.GetTargetedWorkspace(workspaces, func, workspace) + if not workspaces then return end + + table.sort(workspaces, function (a, b) + return a.id < b.id + end) + + local currentIndex + + for i, w in ipairs(workspaces) do + if w.id == workspace.id then + currentIndex = i + break + end + end + if not currentIndex then return end + + local nextWorkspaceId = func(currentIndex, #workspaces) + + return workspaces[nextWorkspaceId] +end + +function WorkspaceUtils.CalculateNextWorksace(workspaceIndex, workspaceLen) + return ((workspaceIndex - 1 + 1) % workspaceLen) + 1 +end + +function WorkspaceUtils.CalculatePrevWorkspace(workspaceIndex, workspaceLen) + return ((workspaceIndex - 1 - 1) % workspaceLen) + 1 +end + +function WorkspaceUtils:GetNextWorkspace(workspace) + local workspaces = hl.get_workspaces() + return self.GetTargetedWorkspace(workspaces, self.CalculateNextWorksace, workspace) +end + +function WorkspaceUtils:GetPrevWorkspace(workspace) + local workspaces = hl.get_workspaces() + return self.GetTargetedWorkspace(workspaces, self.CalculatePrevWorkspace, workspace) +end + +function WorkspaceUtils.GetMonitorWorkspaces(monitor) + local workspaces = hl.get_workspaces() + local monitorWorkspaces = {} + + for _, v in ipairs(workspaces) do + if v.monitor.id == monitor.id then + table.insert(monitorWorkspaces, v) + end + end + + if not next(monitorWorkspaces) then return end + return monitorWorkspaces +end + +function WorkspaceUtils:GetNextMonitorWorkspace(workspace, monitor) + local workspaces = self.GetMonitorWorkspaces(monitor) + return self.GetTargetedWorkspace(workspaces, self.CalculateNextWorksace, workspace) +end + +function WorkspaceUtils:GetPrevMonitorWorkspace(workspace, monitor) + local workspaces = self.GetMonitorWorkspaces(monitor) + return self.GetTargetedWorkspace(workspaces, self.CalculatePrevWorkspace, workspace) +end + + +return WorkspaceUtils \ No newline at end of file diff --git a/miaout/window.lua b/miaout/window.lua deleted file mode 100644 index 1d1c53a..0000000 --- a/miaout/window.lua +++ /dev/null @@ -1,103 +0,0 @@ -local Instance = {} -Instance.__index = Instance - -function Instance.new() - local self = setmetatable({}, Instance) - - -- memory - self.windowInitialFullscreenState = {} - - return self -end - -function Instance:MoveToNextWorkspace() - local workspaceMove = "e+1" - hl.dispatch(hl.dsp.window.move({ workspace = workspaceMove})) -end - -function Instance:MoveToPrevWorkspace() - local workspaceMove = "e-1" - hl.dispatch(hl.dsp.window.move({ workspace = workspaceMove})) -end - -function Instance:SwapWindows() - local last = hl.get_last_window() - - hl.dispatch(hl.dsp.window.swap({target = last})) - hl.dispatch(hl.dsp.window.bring_to_top()) -end - -function Instance:MoveWindowMonitor() - local monitors = hl.get_monitors() - local monitorsPerId = {} - - local maxId = 0 - for _, v in ipairs(monitors) do - monitorsPerId[v.id] = v - if v.id > maxId then - maxId = v.id - end - end - - local currentMonitor = hl.get_active_window().monitor - if not currentMonitor then return end - - local nextMonitorId = currentMonitor.id - 1 - local nextMonitor = monitorsPerId[nextMonitorId] - - - if not nextMonitor then - local id = 0 - while id <= maxId do - id = id +1 - nextMonitor = monitorsPerId[id] - if nextMonitor then break end - end - end - - - hl.dispatch(hl.dsp.window.move({monitor = nextMonitor.name })) -end - -local function changeFullscreenState(self, internal, client) - local window = hl.get_active_window() - if not window then return end - - local initalState = self.windowInitialFullscreenState[window.stable_id] - self.windowInitialFullscreenState[window.stable_id] = {internal = window.fullscreen, client = window.fullscreen_client} - - if not initalState or initalState.internal > 1 then - initalState = {internal = 0, client = 1} - end - - local state - if window.fullscreen ~= internal then - state = {internal = internal, client = client} - else - state = initalState - end - - hl.dispatch(hl.dsp.window.fullscreen_state(state)) -end - -function Instance:Fullscreen() - changeFullscreenState(self, 2, 1) -end - -function Instance:Maximise() - changeFullscreenState(self, 1, 1) -end - -function Instance:Default() - changeFullscreenState(self, 0, 0) -end - -function Instance:FocusWindow(window) - hl.dispatch(hl.dsp.focus({ window = window})) -end - -function Instance:SetFullscreenState(state) - hl.dispatch(hl.dsp.window.fullscreen_state(state)) -end - -return Instance \ No newline at end of file diff --git a/miaout/window/events.lua b/miaout/window/events.lua new file mode 100644 index 0000000..2018eb5 --- /dev/null +++ b/miaout/window/events.lua @@ -0,0 +1,35 @@ +local Events = {} + +---@param wm WindowManager +function Events.Subscribe(wm) + hl.on("window.active", function(hlw) ---@param hlw HL.Window + -- Hl trigger this event two time, first without an stable_id, second with id + if not hlw.stable_id then + return + end + + wm:GetOrNewWindow(hlw):LoadState() + end) + + hl.on("window.close", function(hlw) ---@param hlw HL.Window + wm:RemoveWindow(hlw.stable_id) + end) + + hl.on("window.fullscreen", function(hlw) ---@param hlw HL.Window + wm:GetOrNewWindow(hlw):UpdateState() + end) + + hl.on("window.open", function(hlw) ---@param hlw HL.Window + wm:GetOrNewWindow(hlw):UpdateState() + end) + + hl.on("window.pin", function(hlw) ---@param hlw HL.Window + wm:GetOrNewWindow(hlw):UpdateState() + end) + + hl.on("window.update_rules", function(hlw) ---@param hlw HL.Window + wm:GetOrNewWindow(hlw):UpdateState() + end) +end + +return Events diff --git a/miaout/window/facade.lua b/miaout/window/facade.lua new file mode 100644 index 0000000..2866d2f --- /dev/null +++ b/miaout/window/facade.lua @@ -0,0 +1,142 @@ +local WindowFacade = {} ---@class WindowFacade +WindowFacade.__index = WindowFacade + +local Current = {} ---@class CurrentWindowFacade +Current.__index = Current + +function Current.new(windowFacade, log) + local self = setmetatable({}, Current) + + self.log = log + self.facade = windowFacade + + return self +end + +function Current:withActiveWindow(func, ...) + local window = hl.get_active_window() + + if not window then + self.log:Error("Unable to get the current window") + return + end + + func(self.facade, window, ...) +end + +function Current:MoveToNextWorkspace() + self:withActiveWindow(self.facade.MoveToNextWorkspace) +end + +function Current:MoveToPrevWorkspace() + self:withActiveWindow(self.facade.MoveToPrevWorkspace) +end + +function Current:MoveToNextMonitorWorkspace() + self:withActiveWindow(self.facade.MoveToNextMonitorWorkspace) +end + +function Current:MoveToPrevMonitorWorkspace() + self:withActiveWindow(self.facade.MoveToPrevMonitorWorkspace) +end + +function Current:MoveToNextMonitor() + self:withActiveWindow(self.facade.MoveToNextMonitor) +end + +function Current:MoveToPrevMonitor() + self:withActiveWindow(self.facade.MoveToPrevMonitor) +end + +function Current:DefaultScreen() + self:withActiveWindow(self.facade.DefaultScreen) +end + +function Current:Maximise() + self:withActiveWindow(self.facade.Maximise) +end + +function Current:Fullscreen() + self:withActiveWindow(self.facade.Fullscreen) +end + +function Current:SwapWithLastWindow() + local last = hl.get_last_window() + if not last then + self.log:Error("Unable to get the last window") + return + end + + self:withActiveWindow(self.facade.SwapWindows, last) +end + + +--- WindowFacade +function WindowFacade.new(log, windowLogic, windowManager) + local self = setmetatable({}, WindowFacade) + + self.log = log + self.windowLogic = windowLogic + self.windowManager = windowManager + + self.current = Current.new(self, log) + + return self +end + +function WindowFacade:MoveToNextWorkspace(hlWindow) + local window = self.windowManager:NewWindow(hlWindow) + self.windowLogic:MoveToNextWorkspace(window) +end + +function WindowFacade:MoveToPrevWorkspace(hlWindow) + local window = self.windowManager:NewWindow(hlWindow) + self.windowLogic:MoveToPrevWorkspace(window) +end + +function WindowFacade:MoveToNextMonitorWorkspace(hlWindow) + local window = self.windowManager:NewWindow(hlWindow) + self.windowLogic:MoveToNextMonitorWorkspace(window) +end + +function WindowFacade:MoveToPrevMonitorWorkspace(hlWindow) + local window = self.windowManager:NewWindow(hlWindow) + self.windowLogic:MoveToPrevMonitorWorkspace(window) +end + +function WindowFacade:MoveToNextMonitor(hlWindow) + local window = self.windowManager:NewWindow(hlWindow) + self.windowLogic:MoveToNextMonitor(window) +end + +function WindowFacade:MoveToPrevMonitor(hlWindow) + local window = self.windowManager:NewWindow(hlWindow) + self.windowLogic:MoveToPrevMonitor(window) +end + +function WindowFacade:DefaultScreen(hlWindow) + local window = self.windowManager:NewWindow(hlWindow) + self.windowLogic:SetScreenDefault(window) +end + +function WindowFacade:Maximise(hlWindow) + local window = self.windowManager:NewWindow(hlWindow) + self.windowLogic:Maximise(window) +end + +function WindowFacade:Fullscreen(hlWindow) + local window = self.windowManager:NewWindow(hlWindow) + self.windowLogic:SetFullscreen(window) +end + +function WindowFacade:SwapWindows(hlWindowA, hlWindowB) + local activeWindow = self.windowManager:GetOrNewWindow(hlWindowA) + local lastWindow = self.windowManager:GetOrNewWindow(hlWindowB) + + self.windowLogic:SwapWindows(activeWindow, lastWindow) +end + +return WindowFacade + + + diff --git a/miaout/window/logic.lua b/miaout/window/logic.lua new file mode 100644 index 0000000..f5b15d4 --- /dev/null +++ b/miaout/window/logic.lua @@ -0,0 +1,115 @@ +local Workspace = require("miaout.workspace.workspace") ---@class Workspace +local MonitorUtils = require("miaout.utils.monitor") ---@class MonitorUtils +local WindowUtils = require("miaout.utils.window") ---@class WindowUtils +local WorkspaceUtils = require("miaout.utils.workspace") ---@class WorkspaceUtils + + +-- TODO +-- GetWorkspace (workspace miaout obj) + +---@class WindowLogic +local WindowLogic = {} +WindowLogic.__index = WindowLogic + +function WindowLogic.new(log, config, windowManager, workspaceManager) + local self = setmetatable({}, WindowLogic) + + self.config = config + self.log = log + self.windowManager = windowManager + self.workspaceManager = workspaceManager + + return self +end + +function WindowLogic:MoveToWorkspace(window, func) + local hlWindow = window:GetHlObject() + + hl.notification.create({text = self.config.notifications.prefix, timeout = 3000}) + + local currentWorkspace = self.workspaceManager:GetOrNewWorkspace(hlWindow.workspace) + + local nextHlWorkspace = func(WorkspaceUtils, currentWorkspace, hlWindow.monitor) + if not nextHlWorkspace then return end + + local nextWorkspace = self.workspaceManager:GetOrNewWorkspace(nextHlWorkspace) + + window:MoveToWorkspace(nextWorkspace) + window:Focus() +end + +function WindowLogic:MoveToNextWorkspace(window) + self:MoveToWorkspace(window, WorkspaceUtils.GetNextWorkspace) +end + +function WindowLogic:MoveToPrevWorkspace(window) + self:MoveToWorkspace(window, WorkspaceUtils.GetPrevWorkspace) +end + +function WindowLogic:MoveToNextMonitorWorkspace(window) + self:MoveToWorkspace(window, WorkspaceUtils.GetNextMonitorWorkspace) +end + +function WindowLogic:MoveToPrevMonitorWorkspace(window) + self:MoveToWorkspace(window, WorkspaceUtils.GetPrevMonitorWorkspace) +end + +function WindowLogic:MoveToMonitor(window, monitor) + if not monitor then + self.log:Error("Unable to find the next monitor") + return + end + + window:MoveToMonitor(monitor) + window:Focus() +end + +function WindowLogic:MoveToNextMonitor(window) + local nextMonitor = MonitorUtils:GetNextMonitor() + + self:MoveToMonitor(window, nextMonitor) +end + +function WindowLogic:MoveToPrevMonitor(window) + local prevMonitor = MonitorUtils:GetPrevMonitor() + + self:MoveToMonitor(window, prevMonitor) +end + +function WindowLogic:ChangeScreenState(window, state, toggle) + if toggle then + local fullscreenState = window:GetFullscreenState() + + if WindowUtils.CompareFullscreenState(fullscreenState, state) then + window:SetFullscreenState(toggle) + return + end + end + + window:SetFullscreenState(state) + window:UpdateState() +end + +function WindowLogic:SetScreenDefault(window) + self:ChangeScreenState(window, self.config.window.default) +end + +function WindowLogic:Maximise(window) + self:ChangeScreenState(window, self.config.window.maximise, self.config.window.default) +end + +function WindowLogic:SetFullscreen(window) + self:ChangeScreenState(window, self.config.window.fullscreen, self.config.window.default) +end + +function WindowLogic:SwapWindows(activeWindow, lastWindow) + activeWindow:SwapWindow(lastWindow) + lastWindow:UpdateState() + activeWindow:UpdateState() +end + + +return WindowLogic + + + diff --git a/miaout/window/manager.lua b/miaout/window/manager.lua new file mode 100644 index 0000000..db3380b --- /dev/null +++ b/miaout/window/manager.lua @@ -0,0 +1,74 @@ +local Window = require("miaout.window.window") ---@type Window +local Events = require("miaout.window.events") + +---@class WindowRepo +local WindowRepo = {} +WindowRepo.__index = WindowRepo + +---@class WindowManager +local WindowManager = {} +WindowManager.__index = WindowManager + +-- WindowRepo +function WindowRepo.new() + local self = setmetatable({}, WindowRepo) + + self.windowStates = {} + + return self +end + +function WindowRepo:RemoveState(windowId) + self.windowStates[windowId] = nil +end + +function WindowRepo:SaveState(windowId, windowState) + self.windowStates[windowId] = windowState +end + +function WindowRepo:GetState(windowId) + return self.windowStates[windowId] +end + + +-- WindowManager +function WindowManager.new() + local self = setmetatable({}, WindowManager) + + self.repo = WindowRepo.new() + + self.windows = {} + + Events.Subscribe(self) + + return self +end + +function WindowManager:NewWindow(hlw) + local window = Window.new(self.repo, hlw) + + self.windows[window.id] = window + + return window +end + +function WindowManager:GetWindow(windowId) + return self.windows[windowId] +end + +function WindowManager:GetOrNewWindow(hlw) + local window = self:GetWindow(hlw.stable_id) + + if window then + return window + end + + return self:NewWindow(hlw) +end + +function WindowManager:RemoveWindow(windowId) + self.windows[windowId] = nil + self.repo:RemoveState(windowId) +end + +return WindowManager \ No newline at end of file diff --git a/miaout/window/window.lua b/miaout/window/window.lua new file mode 100644 index 0000000..1a110db --- /dev/null +++ b/miaout/window/window.lua @@ -0,0 +1,69 @@ + +---@class Window +local Window = {} +Window.__index = Window + +-- TODO +-- GetWorkspace (workspace miaout obj) + +function Window.new(repo, hlWindow) + local self = setmetatable({}, Window) + + self.repo = repo + self.hlw = hlWindow + self.id = hlWindow.stable_id + + return self +end + +function Window:GetHlObject() + return self.hlw +end + +function Window:UpdateState() + local state = { + fullscreenState = { + internal = self.hlw.fullscreen, + client = self.hlw.fullscreen_client + }, + size = self.hlw.size + } + + self.repo:SaveState(self.id, state) +end + +function Window:LoadState() + local state = self.repo:GetState(self.id) + + if not state then return end + + self:SetFullscreenState(state.fullscreenState) +end + +function Window:Focus() + hl.dispatch(hl.dsp.focus({ + window = self.hlw + })) +end + +function Window:SetFullscreenState(state) + hl.dispatch(hl.dsp.window.fullscreen_state(state)) +end + +function Window:GetFullscreenState() + return {internal = self.hlw.fullscreen, client = self.hlw.fullscreen_client} +end + +function Window:SwapWindow(window) + hl.dispatch(hl.dsp.window.swap({target = window:GetHlObject()})) +end + +function Window:MoveToWorkspace(workspace) + hl.dispatch(hl.dsp.window.move({ workspace = workspace:GetHlObject() })) +end + +function Window:MoveToMonitor(monitor) + hl.dispatch(hl.dsp.window.move({ monitor = monitor.name, window = self.hlw })) +end + +return Window \ No newline at end of file diff --git a/miaout/workspace.lua b/miaout/workspace.lua deleted file mode 100644 index f0a8623..0000000 --- a/miaout/workspace.lua +++ /dev/null @@ -1,178 +0,0 @@ -local Instance = {} -Instance.__index = Instance - -local function subscribleEvents(self) - - -- the behaviour is weird here, active workspace is actually the last workspace - hl.on("monitor.focused", function (monitor) - local lastWorkspace = hl.get_active_workspace() -- dont ask me how but it works - self:SaveWorkspaceState(lastWorkspace) - - local workspace = monitor.active_workspace - - self:LoadWorkspaceState(workspace) - end) - - hl.on("workspace.active", function (workspace) - local lastWorkspace = hl.get_last_workspace() - self:SaveWorkspaceState(lastWorkspace) - - self:LoadWorkspaceState(workspace) - end) - - hl.on("window.move_to_workspace", function (window, workspace) - for id, ws in ipairs(self.workspaceStates) do - if workspace.id == id then return end - if ws.activeWindowState.window.stable_id ~= window.stable_id then return end - self.workspaceStates[id].activeWindowState = nil - end - end) - - hl.on("window.close", function (window) - local workspaceState = self.workspaceStates[window.workspace.id] - if not workspaceState then return end - self.workspaceStates[window.workspace.id].activeWindowState = nil - end) - - hl.on("workspace.removed", function (workspace) - local workspaceState = self.workspaceStates[workspace.id] - if not workspaceState then return end - self.workspaceStates[workspace.id] = nil - end) -end - -function Instance.new(layout, window) - local self = setmetatable({}, Instance) - self.layout = layout - self.window = window - self.workspaceStates = {} - self.lock = 0 - - subscribleEvents(self) - - return self -end - -function Instance:SaveWorkspaceState(workspace) - local lastWindow = workspace.last_window - - local activeWindowState = nil - if lastWindow then - activeWindowState = { - window = lastWindow; - fullscreen = lastWindow.fullscreen, - fullscreen_client = lastWindow.fullscreen_client, - size = lastWindow.size, - } - end - - self.workspaceStates[workspace.id] = { - layout = hl.get_config("general.layout"), - activeWindowState = activeWindowState - } -end - -function timer(fun, timeout) - hl.timer(function(...) - fun(...) - end, { timeout = timeout, type = "oneshot" }) -end - -function Instance:LoadWindowState(windowState) - if windowState.window.stable_id == hl.get_active_window().stable_id then return end - self.window:FocusWindow(windowState.window) - self.window:SetFullscreenState({internal = windowState.fullscreen, client = windowState.fullscreen_client}) - -end - -function Instance:LazyLoadWindowState(windowState) - self.lock = self.lock + 1 - local lock = self.lock - - timer(function () - if self.lock ~= lock then return end - self:LoadWindowState(windowState) - end, 1) -end - -function Instance:LoadWorkspaceState(workspace) - local workspaceState = self.workspaceStates[workspace.id] - if not workspaceState then return end - - if workspaceState.activeWindowState then - self:LazyLoadWindowState(workspaceState.activeWindowState) -- need to load window state after the workspace loading - hl.notification.create({text = workspace.id, timeout = 3000}) - end - - self.layout:UpdateLayout(workspaceState.layout) -end - -function Instance:SwitchToWorkspace(workspaceSelector) - hl.dispatch(hl.dsp.focus({workspace = workspaceSelector})) - - - local workspace = hl.get_active_workspace() - return workspace -end - -function Instance:NewWorkspace() - local max = 0 - - for _, ws in ipairs(hl.get_workspaces()) do - if ws.id > max then - max = ws.id - end - end - return self:SwitchToWorkspace(max + 1) -end - -function Instance:MoveWorkspaceMonitor() - - local monitors = hl.get_monitors() - local monitorsPerId = {} - - local maxId = 0 - for _, v in ipairs(monitors) do - monitorsPerId[v.id] = v - if v.id > maxId then - maxId = v.id - end - end - - local currentMonitor = hl.get_active_window().monitor - if not currentMonitor then return end - - local nextMonitorId = currentMonitor.id - 1 - local nextMonitor = monitorsPerId[nextMonitorId] - - - if not nextMonitor then - local id = 0 - while id <= maxId do - id = id +1 - nextMonitor = monitorsPerId[id] - if nextMonitor then break end - end - end - - - hl.dispatch(hl.dsp.workspace.move({monitor = nextMonitor.name })) -end - -function Instance:SwitchNextWorkspace() - self:SwitchToWorkspace("e+1") -end - -function Instance:SwitchPreviousWorkspace() - self:SwitchToWorkspace("e-1") -end - -function Instance:SwitchNextMonitorWorkspace() - self:SwitchToWorkspace("m+1") -end - -function Instance:SwitchPrevMonitorWorkspace() - self:SwitchToWorkspace("m-1") -end - -return Instance \ No newline at end of file diff --git a/miaout/workspace/events.lua b/miaout/workspace/events.lua new file mode 100644 index 0000000..796aee2 --- /dev/null +++ b/miaout/workspace/events.lua @@ -0,0 +1,22 @@ +local Events = {} + +---@param wm WorkspaceManager +function Events.Subscribe(wm) + hl.on("workspace.active", function(hlw) ---@param hlw HL.Workspace + wm:GetOrNewWorkspace(hlw):LoadState() + end) + + hl.on("workspace.removed", function(hlw) ---@param hlw HL.Workspace + wm:RemoveWorkspace(hlw.id) + end) + + hl.on("workspace.move_to_monitor", function(hlw) ---@param hlw HL.Workspace + wm:GetOrNewWorkspace(hlw):LoadState() + end) + + hl.on("workspace.created", function(hlw) ---@param hlw HL.Workspace + wm:GetOrNewWorkspace(hlw):UpdateState() + end) +end + +return Events diff --git a/miaout/workspace/facade.lua b/miaout/workspace/facade.lua new file mode 100644 index 0000000..2d28826 --- /dev/null +++ b/miaout/workspace/facade.lua @@ -0,0 +1,118 @@ +local WorkspaceFacade = {} ---@class WorkspaceFacade +WorkspaceFacade.__index = WorkspaceFacade + +local Current = {} ---@class CurrentWorkspaceFacade +Current.__index = Current + +function Current.new(workspaceFacade, log) + local self = setmetatable({}, Current) + + self.log = log + self.facade = workspaceFacade + + return self +end + +function Current:withActiveWorkspace(func, ...) + local hlWorkspace = hl.get_active_workspace() + + if not hlWorkspace then + self.log:Error("Unable to get the current workspace") + return + end + + func(self.facade, hlWorkspace, ...) +end + +function Current:MoveToMonitor(monitor) + self:withActiveWorkspace(self.facade.MoveToMonitor, monitor) +end + +function Current:MoveToNextMonitor() + self:withActiveWorkspace(self.facade.MoveToNextMonitor) +end + +function Current:MoveToPrevMonitor() + self:withActiveWorkspace(self.facade.MoveToPrevMonitor) +end + +function Current:NextLayout() + self:withActiveWorkspace(self.facade.NextLayout) +end + +function Current:PrevLayout() + self:withActiveWorkspace(self.facade.PrevLayout) +end + +function Current:DefaultLayout() + self:withActiveWorkspace(self.facade.DefaultLayout) +end + + +--- WindowFacade +function WorkspaceFacade.new(log, workspaceLogic, workspaceManager) + local self = setmetatable({}, WorkspaceFacade) + + self.log = log + self.workspaceLogic = workspaceLogic + self.workspaceManager = workspaceManager + + self.current = Current.new(self, log) + + return self +end + + +function WorkspaceFacade:NewWorkspace() + self.workspaceLogic:NewWorkspace() +end + +function WorkspaceFacade:NextWorkspace() + self.workspaceLogic:NextWorkspace() +end + +function WorkspaceFacade:PrevWorkspace() + self.workspaceLogic:PrevWorkspace() +end + +function WorkspaceFacade:NextMonitorWorkspace() + self.workspaceLogic:NextMonitorWorkspace() +end + +function WorkspaceFacade:PrevMonitorWorkspace() + self.workspaceLogic:PrevMonitorWorkspace() +end + +function WorkspaceFacade:MoveToMonitor(hlWorkspace, monitor) + local workspace = self.workspaceManager:GetOrNewWorkspace(hlWorkspace) + self.workspaceLogic:MoveToMonitor(workspace, monitor) +end + +function WorkspaceFacade:MoveToNextMonitor(hlWorkspace) + local workspace = self.workspaceManager:GetOrNewWorkspace(hlWorkspace) + self.workspaceLogic:MoveToNextMonitor(workspace) +end + +function WorkspaceFacade:MoveToPrevMonitor(hlWorkspace) + local workspace = self.workspaceManager:GetOrNewWorkspace(hlWorkspace) + self.workspaceLogic:MoveToPrevMonitor(workspace) +end + +function WorkspaceFacade:NextLayout(hlWorkspace) + local workspace = self.workspaceManager:GetOrNewWorkspace(hlWorkspace) + self.workspaceLogic:NextLayout(workspace) +end + +function WorkspaceFacade:PrevLayout(hlWorkspace) + local workspace = self.workspaceManager:GetOrNewWorkspace(hlWorkspace) + self.workspaceLogic:PrevLayout(workspace) +end + +function WorkspaceFacade:DefaultLayout(hlWorkspace) + local workspace = self.workspaceManager:GetOrNewWorkspace(hlWorkspace) + self.workspaceLogic:DefaultLayout(workspace) +end + + + +return WorkspaceFacade \ No newline at end of file diff --git a/miaout/workspace/logic.lua b/miaout/workspace/logic.lua new file mode 100644 index 0000000..40009d6 --- /dev/null +++ b/miaout/workspace/logic.lua @@ -0,0 +1,103 @@ +local Workspace = require("miaout.workspace.workspace") ---@class Workspace +local MonitorUtils = require("miaout.utils.monitor") ---@class MonitorUtils +local LayoutUtils = require("miaout.utils.layout") ---@class LayoutUtils + + +---@class WorkspaceLogic +local WorkspaceLogic = {} +WorkspaceLogic.__index = WorkspaceLogic + +function WorkspaceLogic.new(log, config, manager) + local self = setmetatable({}, WorkspaceLogic) + + self.config = config + self.log = log + self.manager = manager + + return self +end + +function WorkspaceLogic:NewWorkspace() + local workspacesLen = #hl.get_workspaces() + self:SwitchToWorkspace(workspacesLen + 1) +end + +function WorkspaceLogic:SwitchToWorkspace(workspaceRef) + if getmetatable(workspaceRef) == Workspace then + ---@cast workspaceRef Workspace + workspaceRef:Focus() + else + ---@cast workspaceRef HL.WorkspaceSelector + hl.dispatch(hl.dsp.focus({workspace = workspaceRef})) + end +end + +function WorkspaceLogic:NextWorkspace() + self:SwitchToWorkspace(self.config.workspace.nextWorkspaceSelector) +end + +function WorkspaceLogic:PrevWorkspace() + self:SwitchToWorkspace(self.config.workspace.prevWorkspaceSelector) +end + +function WorkspaceLogic:NextMonitorWorkspace() + self:SwitchToWorkspace(self.config.workspace.nextMonitorWorkspaceSelector) +end + +function WorkspaceLogic:PrevMonitorWorkspace() + self:SwitchToWorkspace(self.config.workspace.prevMonitorWorkspaceSelector) +end + +function WorkspaceLogic:MoveToMonitor(workspace, monitor) + if not monitor then + self.log:Error("Unable to find the next monitor") + return + end + + workspace:MoveToMonitor(monitor) + workspace:Focus() +end + +function WorkspaceLogic:MoveToNextMonitor(workspace) + local nextMonitor = MonitorUtils:GetNextMonitor() + + self:MoveToMonitor(workspace, nextMonitor) +end + +function WorkspaceLogic:MoveToPrevMonitor(workspace) + local prevMonitor = MonitorUtils:GetPrevMonitor() + + self:MoveToMonitor(workspace, prevMonitor) +end + +function WorkspaceLogic:ChangeLayout(workspace, func) + local layouts = self.config.workspace.layouts + local layout = workspace:GetLayout() + + local nextLayout = func(layouts, layout) + if not nextLayout then return end + + workspace:ChangeLayout(nextLayout) + workspace:LoadState() +end + +function WorkspaceLogic:NextLayout(workspace) + self:ChangeLayout(workspace, function (layouts, layout) + return LayoutUtils:GetNextLayout(layouts, layout) + end) +end + +function WorkspaceLogic:PrevLayout(workspace) + self:ChangeLayout(workspace, function (layouts, layout) + return LayoutUtils:GetPrevLayout(layouts, layout) + end) +end + +function WorkspaceLogic:DefaultLayout(workspace) + workspace:ChangeLayout(self.config.workspace.defaultLayout) + workspace:LoadState() +end + + + +return WorkspaceLogic \ No newline at end of file diff --git a/miaout/workspace/manager.lua b/miaout/workspace/manager.lua new file mode 100644 index 0000000..71ba220 --- /dev/null +++ b/miaout/workspace/manager.lua @@ -0,0 +1,74 @@ +local Workspace = require("miaout.workspace.workspace") ---@type Workspace +local Events = require("miaout.workspace.events") + +---@class WorkspaceRepo +local WorkspaceRepo = {} +WorkspaceRepo.__index = WorkspaceRepo + +---@class WorkspaceManager +local WorkspaceManager = {} +WorkspaceManager.__index = WorkspaceManager + +-- WorkspaceRepo +function WorkspaceRepo.new() + local self = setmetatable({}, WorkspaceRepo) ---@type WorkspaceRepo + + self.workspaceStates = {} + + return self +end + +function WorkspaceRepo:RemoveState(workspaceId) + self.workspaceStates[workspaceId] = nil +end + +function WorkspaceRepo:SaveState(workspaceId, workspaceState) + self.workspaceStates[workspaceId] = workspaceState +end + +function WorkspaceRepo:GetState(workspaceId) + return self.workspaceStates[workspaceId] +end + + +-- WorkspaceManager +function WorkspaceManager.new() + local self = setmetatable({}, WorkspaceManager) ---@type WorkspaceManager + + self.repo = WorkspaceRepo.new() + + self.workspaces = {} + + Events.Subscribe(self) + + return self +end + +function WorkspaceManager:NewWorkspace(hlw) + local workspace = Workspace.new(self.repo, hlw) + + self.workspaces[workspace.id] = workspace + + return workspace +end + +function WorkspaceManager:GetWorkspace(workspaceId) + return self.workspaces[workspaceId] +end + +function WorkspaceManager:GetOrNewWorkspace(hlw) + local workspace = self:GetWorkspace(hlw.id) + + if workspace then + return workspace + end + + return self:NewWorkspace(hlw) +end + +function WorkspaceManager:RemoveWorkspace(workspaceId) + self.workspaces[workspaceId] = nil + self.repo:RemoveState(workspaceId) +end + +return WorkspaceManager \ No newline at end of file diff --git a/miaout/workspace/workspace.lua b/miaout/workspace/workspace.lua new file mode 100644 index 0000000..051d25a --- /dev/null +++ b/miaout/workspace/workspace.lua @@ -0,0 +1,81 @@ +local Utils = require("miaout.utils.utils") + +---@class Workspace +local Workspace = {} +Workspace.__index = Workspace + +-- TODO +-- GetWorkspace (workspace miaout obj) + +function Workspace.new(repo, hlWorkspace) + local self = setmetatable({}, Workspace) + + self.repo = repo + self.hlw = hlWorkspace + self.id = hlWorkspace.id + + if not self.repo:GetState(self.id) then + self:UpdateState() + end + + return self +end + +function Workspace:GetHlObject() + return self.hlw +end + +function Workspace:UpdateState(state) + if not state then + state = { + layout = self.hlw.tiled_layout + } + end + + self.repo:SaveState(self.id, state) +end + +function Workspace:LoadState() + local state = self.repo:GetState(self.id) + + if not state then + return + end + + hl.workspace_rule({workspace = self.hlw.name, layout = state.layout}) + + self:Focus() +end + +function Workspace:Focus() + local selector = self.hlw or self.id + + hl.dispatch(hl.dsp.focus({ + workspace = selector + })) +end + +function Workspace:MoveToMonitor(monitor) + hl.dispatch(hl.dsp.workspace.move({monitor = monitor.name, workspace = self.hlw})) +end + +function Workspace:ChangeLayout(layout) + local _state = self.repo:GetState(self.id) + local state + + if _state then + state = Utils.CopyTable(_state) + else + state.layout = layout + end + + state.layout = layout + + self:UpdateState(state) +end + +function Workspace:GetLayout() + return self.repo:GetState(self.id).layout +end + +return Workspace \ No newline at end of file From a289c7b9bfa7e17f1ff77888b5b1bc1ca418fd66 Mon Sep 17 00:00:00 2001 From: deb84 <56758812+Deb84@users.noreply.github.com> Date: Wed, 29 Jul 2026 11:39:26 +0200 Subject: [PATCH 2/2] doc: udpated README to feat with the refactoring --- README.md | 129 +++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 90 insertions(+), 39 deletions(-) diff --git a/README.md b/README.md index 01a0a6a..41e9910 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # Miaout -A really simple layout/workspace/window "manager" for hyprland lua config +A really simple *overengeeneried* workspace/window "manager" for hyprland lua config ## Setup ```lua @@ -10,7 +10,10 @@ local miaout = require("miaout") miaout = miaout.Init() ``` > [!IMPORTANT] -> **`hl.config({general = {layout = ...}})` need to be set before `miaout = miaout.Init()`** +> **`hl.config({...})` need to be set before `miaout = miaout.Init()`** + +## Config +See config docs [Here](./Docs/CONFIG.md) ## Bind usage ```lua @@ -19,80 +22,128 @@ hl.bind("KEY(S)", function() end) ``` -## Functions +## Methods + +### Workspace -### Layout +**Some methods need a HL.Workspace as argument, to use the current workspace:** ```lua -miaout.layout:SwitchNextLayout() +miaout.workspace.current:method() ``` -Switch to the next layout + ```lua -miaout.layout:SwitchLastLayout() +miaout.workspace:NewWorkspace() ``` -Switch to the last layout +Create a new workspace + +#### Navigation + ```lua -miaout.layout:SwitchPrevLayout() +miaout.workspace:NextWorkspace() ``` -Switch to the previous layout +Focus the next workspace (e+1) ```lua -miaout.layout:SwitchDefaultLayout() +miaout.workspace:PrevWorkspace() ``` -Switch to your default layout (see the the note above) +Focus the next workspace (e-1) -### Workspace ```lua -miaout.workspace:NewWorkspace() +miaout.workspace:NextMonitorWorkspace() ``` -Create a new workspace +Focus the next monitor workspace (m+1) + +```lua +miaout.workspace:PrevMonitorWorkspace() +``` +Focus the next monitor workspace (m-1) + +```lua +miaout.workspace:MoveToNextMonitor(workspace) +``` +Move the workspace to the next monitor + ```lua -miaout.workspace:SwitchNextWorkspace() +miaout.workspace:MoveToPrevMonitor(workspace) ``` -Switch to the next workspace (e+1) +Move the workspace to the previous monitor + ```lua -miaout.workspace:SwitchPreviousWorkspace() +miaout.workspace:MoveToMonitor(workspace, monitor) ``` -Switch to the next workspace (e-1) +Move the workspace to a monitor + +#### Layouts + ```lua -miaout.workspace:SwitchNextMonitorWorkspace() +miaout.workspace:NextLayout(workspace) ``` -Switch to the next monitor workspace (m+1) +Apply next layout to a workspace + ```lua -miaout.workspace:SwitchPrevMonitorWorkspace() +miaout.workspace:PrevLayout(workspace) ``` -Switch to the next monitor workspace (m-1) +Apply previous layout to a workspace + ```lua -miaout.workspace:MoveWorkspaceMonitor() +miaout.workspace:DefaultLayout(workspace) ``` -Move the workspace to the next Monitor +Apply the default layout to a workspace ### Window + +**Some methods need a HL.Winfow as argument, to use the current window:** ```lua -miaout.window:MoveToNextWorkspace() +miaout.window.current:method() ``` -Move the active window to the next workspace +#### Navigation + ```lua -miaout.window:MoveToPrevWorkspace() +miaout.window:MoveToNextWorkspace(window) ``` -Move the active window to the previous workspace +Move the window to the next workspace ```lua -miaout.window:SwapWindows() +miaout.window:MoveToPrevWorkspace(window) ``` -Swap the active window with the last active window +Move the window to the previous workspace + ```lua -miaout.window:SwapWindowMonitor() +miaout.window:MoveToNextMonitorWorkspace(window) ``` -Swap the active window to the next monitor +Move the window to the next monitor workspace + ```lua -miaout.window:Fullscreen() +miaout.window:MoveToPrevMonitorWorkspace(window) ``` -Puts the active window in full screen (toggle switch) +Move the window to the previous monitor workspace + ```lua -miaout.window:Maximise() +miaout.window:MoveToNextMonitor(window) ``` -Maximise the active window (toggle switch) +Move the window to the next monitor + ```lua -miaout.window:Default() +miaout.window:MoveToPrevMonitor(window) ``` -Reset the window fullscreen state to the default value +Move the window to the previous monitor +```lua +miaout.window:SwapWindows(windowA, windowB) +``` +Swap `windowA` with `windowB` (with current, swap with the last active window) +#### Fullscreen States + +```lua +miaout.window:Fullscreen(window) +``` +Puts the window in full screen (toggle switch) + +```lua +miaout.window:Maximise(window) +``` +Maximise the window (toggle switch) + +```lua +miaout.window:Default(window) +``` +Reset the window fullscreen state to the default value