From af18536ae024fe00293fd0151a1f7716a806657e Mon Sep 17 00:00:00 2001 From: Heitor Augusto Date: Mon, 23 Dec 2024 23:20:42 -0300 Subject: [PATCH] feat: add COSMIC panel configuration support (#4) - Add panel configuration module with comprehensive settings - Support panel positioning, autohide behavior, and appearance - Add plugin configuration for center and wings sections - Include panel size and output display options - Implement panel background and opacity controls --- lib/types.nix | 42 ++++--- modules/default.nix | 1 + modules/panels.nix | 281 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 306 insertions(+), 18 deletions(-) create mode 100644 modules/panels.nix diff --git a/lib/types.nix b/lib/types.nix index 2b9b74b..3efe14c 100644 --- a/lib/types.nix +++ b/lib/types.nix @@ -127,7 +127,9 @@ "one of the following RON enum variants: ${lib.concatMapStringsSep ", " show variants}"; descriptionClass = if builtins.length variants < 2 then "noun" else "conjunction"; functor = lib.defaultFunctor name // { - payload = { inherit variants; }; + payload = { + inherit variants; + }; type = payload: ronEnum' payload.variants; binOp = a: b: { variants = lib.unique (a.variants + b.variants); }; }; @@ -159,7 +161,7 @@ value = { }; }; }; - merge = loc: defs: { + merge = _loc: defs: { __type = "map"; value = builtins.foldl' (first: def: lib.recursiveUpdate first def.value.value) { } defs; }; @@ -200,14 +202,14 @@ functor = lib.defaultFunctor name // { wrapped = elemType; }; - getSubModules = elemType.getSubModules; + inherit (elemType) getSubModules; getSubOptions = prefix: elemType.getSubOptions (prefix ++ [ "" ]); merge = loc: defs: let pushPositions = map ( def: - builtins.mapAttrs (n: v: { + builtins.mapAttrs (_n: v: { inherit (def) file; value = v; }) def.value.value @@ -215,9 +217,9 @@ in { __type = "map"; - value = builtins.mapAttrs (n: v: v.value) ( - lib.filterAttrs (n: v: v ? value) ( - lib.zipAttrsWith ( + value = builtins.mapAttrs (_n: v: v.value) ( + lib.filterAttrs (_n: v: v ? value) ( + builtins.zipAttrsWith ( name: defs: (lib.mergeDefinitions (loc ++ [ name ]) elemType defs).optionalValue ) (pushPositions defs) ) @@ -298,14 +300,14 @@ functor = lib.defaultFunctor name // { wrapped = elemType; }; - getSubModules = elemType.getSubModules; + inherit (elemType) getSubModules; getSubOptions = prefix: elemType.getSubOptions (prefix ++ [ "" ]); merge = loc: defs: let pushPositions = map ( def: - builtins.mapAttrs (n: v: { + builtins.mapAttrs (_n: v: { inherit (def) file; value = v; }) def.value.value @@ -330,9 +332,9 @@ else first.value.__name ) (builtins.head defs) (builtins.tail defs); - value = builtins.mapAttrs (n: v: v.value) ( - lib.filterAttrs (n: v: v ? value) ( - lib.zipAttrsWith ( + value = builtins.mapAttrs (_n: v: v.value) ( + lib.filterAttrs (_n: v: v ? value) ( + builtins.zipAttrsWith ( name: defs: (lib.mergeDefinitions (loc ++ [ name ]) elemType defs).optionalValue ) (pushPositions defs) ) @@ -395,7 +397,7 @@ functor = lib.defaultFunctor name // { wrapped = elemType; }; - getSubModules = elemType.getSubModules; + inherit (elemType) getSubModules; getSubOptions = prefix: elemType.getSubOptions (prefix ++ [ "" ]); merge = loc: defs: { __type = "optional"; @@ -436,7 +438,7 @@ value = [ ]; }; }; - merge = loc: defs: { + merge = _loc: defs: { __type = "tuple"; value = builtins.concatLists (map (x: x.value.value) defs); }; @@ -481,7 +483,9 @@ } with a value"; descriptionClass = if builtins.length variants < 2 then "noun" else "conjunction"; functor = lib.defaultFunctor name // { - payload = { inherit variants; }; + payload = { + inherit variants; + }; type = payload: ronTupleEnum' payload.variants; binOp = a: b: { variants = lib.unique (a.variants + b.variants); }; }; @@ -533,14 +537,16 @@ } value"; descriptionClass = if builtins.length variants < 2 then "noun" else "conjunction"; functor = lib.defaultFunctor name // { - payload = { inherit elemType variants; }; + payload = { + inherit elemType variants; + }; type = payload: ronTupleEnumOf' payload.elemType payload.variants; binOp = a: b: { variants = lib.unique (a.variants + b.variants); elemType = a.elemType.typeMerge b.elemType.functor; }; }; - getSubModules = elemType.getSubModules; + inherit (elemType) getSubModules; getSubOptions = prefix: elemType.getSubOptions (prefix ++ [ "*" ]); merge = loc: defs: { __type = "enum"; @@ -622,7 +628,7 @@ functor = lib.defaultFunctor name // { wrapped = elemType; }; - getSubModules = elemType.getSubModules; + inherit (elemType) getSubModules; getSubOptions = prefix: elemType.getSubOptions (prefix ++ [ "*" ]); merge = loc: defs: { __type = "tuple"; diff --git a/modules/default.nix b/modules/default.nix index cc10da2..bb2dbe5 100644 --- a/modules/default.nix +++ b/modules/default.nix @@ -17,6 +17,7 @@ in [ ./files.nix + ./panels.nix ] ++ lib.foldlAttrs ( prev: name: type: diff --git a/modules/panels.nix b/modules/panels.nix new file mode 100644 index 0000000..8c19118 --- /dev/null +++ b/modules/panels.nix @@ -0,0 +1,281 @@ +{ config, lib, ... }: +let + inherit (lib.cosmic.options) mkNullOrOption; + + cfg = config.wayland.desktopManager.cosmic; +in +{ + options.wayland.desktopManager.cosmic.panels = + let + panelSubmodule = lib.types.submodule { + freeformType = with lib.types; attrsOf cosmicEntryValue; + options = { + anchor = mkNullOrOption { + type = lib.types.ronEnum [ + "Bottom" + "Left" + "Right" + "Top" + ]; + example = { + __type = "enum"; + variant = "Bottom"; + }; + description = '' + The position of the panel on the screen. + ''; + }; + anchor_gap = mkNullOrOption { + type = lib.types.bool; + example = true; + description = '' + Whether there should be a gap between the panel and the screen edge. + ''; + }; + autohide = mkNullOrOption { + type = lib.types.ronOptionalOf ( + lib.types.submodule { + freeformType = with lib.types; attrsOf cosmicEntryValue; + options = { + handle_size = mkNullOrOption { + type = + with lib.types; + (addCheck lib.types.ints.u32 (x: x > 0)) + // { + description = "32 bit unsigned integer; must be greater than 0"; + }; + example = 4; + description = '' + The size of the handle in pixels. + ''; + }; + transition_time = lib.mkOption { + type = lib.types.ints.u32; + example = 200; + description = '' + The time in milliseconds it should take to transition the panel hiding. + ''; + }; + wait_time = lib.mkOption { + type = lib.types.ints.u32; + example = 1000; + description = '' + The time in milliseconds without pointer focus before the panel hides. + ''; + }; + }; + } + ); + example = { + __type = "optional"; + value = { + handle_size = 4; + transition_time = 200; + wait_time = 1000; + }; + }; + description = '' + Whether the panel should autohide and the settings for autohide. + If set the `value` is set to `null`, the panel will not autohide. + ''; + }; + background = mkNullOrOption { + type = + with lib.types; + either (ronEnum [ + "Dark" + "Light" + "ThemeDefault" + ]) (ronTupleEnumOf (listOf float) [ "Color" ]); + example = { + __type = "enum"; + variant = "Dark"; + }; + description = '' + The appearance of the panel. + ''; + }; + expand_to_edges = mkNullOrOption { + type = lib.types.bool; + example = true; + description = '' + Whether the panel should expand to the edges of the screen. + ''; + }; + name = lib.mkOption { + type = lib.types.str; + example = "Panel"; + description = '' + The name of the panel. + ''; + }; + opacity = mkNullOrOption { + type = lib.types.numbers.between 0 1; + example = 1.0; + description = '' + The opacity of the panel. + ''; + }; + output = mkNullOrOption { + type = + with lib.types; + either (ronEnum [ + "Active" + "All" + ]) (ronTupleEnumOf str [ "Name" ]); + example = { + __type = "enum"; + variant = "Name"; + value = "Virtual-1"; + }; + description = '' + The output(s) the panel should be displayed on. + ''; + }; + plugins_center = mkNullOrOption { + type = with lib.types; ronOptionalOf (listOf str); + example = { + __type = "optional"; + value = [ "com.system76.CosmicAppletTime" ]; + }; + description = '' + The center plugins of the panel. + ''; + }; + plugins_wings = mkNullOrOption { + type = with lib.types; ronOptionalOf (ronTupleOf (listOf str)); + example = { + __type = "optional"; + value = { + __type = "tuple"; + value = [ + [ + "com.system76.CosmicPanelWorkspacesButton" + "com.system76.CosmicPanelAppButton" + "com.system76.CosmicAppletWorkspaces" + ] + [ + "com.system76.CosmicAppletInputSources" + "com.system76.CosmicAppletStatusArea" + "com.system76.CosmicAppletTiling" + "com.system76.CosmicAppletAudio" + "com.system76.CosmicAppletNetwork" + "com.system76.CosmicAppletBattery" + "com.system76.CosmicAppletNotifications" + "com.system76.CosmicAppletBluetooth" + "com.system76.CosmicAppletPower" + ] + ]; + }; + }; + description = '' + The plugins that will be displayed on the right and left sides of the panel, respectively. + ''; + }; + size = mkNullOrOption { + type = lib.types.ronEnum [ + "XS" + "S" + "M" + "L" + "XL" + ]; + example = { + __type = "enum"; + variant = "M"; + }; + description = '' + The size of the panel. + ''; + }; + }; + }; + in + mkNullOrOption { + type = lib.types.listOf panelSubmodule; + example = [ + { + anchor = { + __type = "enum"; + variant = "Bottom"; + }; + anchor_gap = true; + autohide = { + __type = "optional"; + value = { + handle_size = 4; + transition_time = 200; + wait_time = 1000; + }; + }; + background = { + __type = "enum"; + variant = "Dark"; + }; + expand_to_edges = true; + name = "Panel"; + opacity = 1.0; + output = { + __type = "enum"; + variant = "Name"; + value = "Virtual-1"; + }; + plugins_center = { + __type = "optional"; + value = [ "com.system76.CosmicAppletTime" ]; + }; + plugins_wings = { + __type = "optional"; + value = { + __type = "tuple"; + value = [ + [ + "com.system76.CosmicPanelWorkspacesButton" + "com.system76.CosmicPanelAppButton" + "com.system76.CosmicAppletWorkspaces" + ] + [ + "com.system76.CosmicAppletInputSources" + "com.system76.CosmicAppletStatusArea" + "com.system76.CosmicAppletTiling" + "com.system76.CosmicAppletAudio" + "com.system76.CosmicAppletNetwork" + "com.system76.CosmicAppletBattery" + "com.system76.CosmicAppletNotifications" + "com.system76.CosmicAppletBluetooth" + "com.system76.CosmicAppletPower" + ] + ]; + }; + }; + size = { + __type = "enum"; + variant = "M"; + }; + } + ]; + }; + + config = + let + version = 1; + in + lib.mkIf (cfg.enable && cfg.panels != null) { + wayland.desktopManager.cosmic.configFile = lib.mkMerge ( + [ + { + "com.system76.CosmicPanel" = { + entries.entries = map (panel: panel.name) cfg.panels; + inherit version; + }; + } + ] + ++ (map (panel: { + "com.system76.CosmicPanel.${panel.name}" = { + entries = panel; + inherit version; + }; + }) cfg.panels) + ); + }; +}