Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(Krohnkite): init Krohnkite kwin script #420

Open
wants to merge 15 commits into
base: trunk
Choose a base branch
from
Open
2 changes: 1 addition & 1 deletion modules/kwin.nix
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
pkgs,
...
}:

let
cfg = config.programs.plasma;
validTitlebarButtons = {
Expand Down Expand Up @@ -132,6 +131,7 @@ in
"animation"
]
)
./scripts/tiling/krohnkite.nix
];

options.programs.plasma.kwin = {
Expand Down
310 changes: 310 additions & 0 deletions modules/scripts/tiling/krohnkite.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,310 @@
{
config,
lib,
pkgs,
...
}:
let
cfg = config.programs.plasma;

krohnkiteGaps = lib.types.submodule {
options =
let
mkGapOption =
name:
lib.mkOption {
type = with lib.types; nullOr (ints.between 0 999);
default = null;
example = 8;
description = "${name} gap for Krohnkite.";
};
in
{
top = mkGapOption "Top screen";
left = mkGapOption "Left screen";
right = mkGapOption "Right screen";
bottom = mkGapOption "Bottom screen";
tiles = mkGapOption "Gap between tiles";
};
};

krohnkiteSupportedLayouts = [
{
value = "btree";
label = "BTreeLayout";
}
{
value = "monocle";
label = "MonocleLayout";
}
{
value = "column";
label = "ColumnsLayout";
}
{
value = "floating";
label = "FloatingLayout";
}
{
value = "quarter";
label = "QuarterLayout";
}
{
value = "spiral";
label = "SpiralLayout";
}
{
value = "threeColumn";
label = "ThreeColumnLayout";
}
{
value = "tile";
label = "TileLayout";
}
{
value = "stacked";
label = "StackedLayout";
}
{
value = "spread";
label = "SpreadLayout";
}
{
value = "stair";
label = "StairLayout";
}
];

krohnkiteLayouts = lib.types.submodule {
options = {
name = lib.mkOption {
type = with lib.types; enum (lib.lists.forEach krohnkiteSupportedLayouts (x: x.value));
description = "The name of the layout.";
};

options = lib.mkOption {
type = with lib.types; nullOr (attrsOf (with lib.types; anything));
default = null;
example = {
maximize = true;
};
description = ''
Layout-specific options. Supported options depend on the layout:
- `column`: `{ balanced = true; }`
- `monocle`: `{ maximize = true; minimizeRest = true; }`
- `stair`: `{ reverse = true; }`
'';
};
};
};

mkNullableOption =
type: description: example:
lib.mkOption {
type = with lib.types; nullOr type;
default = null;
example = example;
description = description;
};

convertListToString = list: if list == null then null else builtins.concatStringsSep "," list;

mkFilterOption =
description: default: example:
lib.mkOption {
type = with lib.types; nullOr (listOf str);
default = default;
example = example;
description = description;
apply = convertListToString;
};

checkIfString = v: if lib.isString v then v else v.name;

isLayoutEnabled =
name: lib.any (l: (checkIfString l) == name) cfg.kwin.scripts.krohnkite.settings.layouts.enabled;

generateOptionsConfig =
layoutObj:
if layoutObj.name == "monocle" then
{
monocleMaximize = lib.attrByPath [
"options"
"maximize"
] false layoutObj;
monocleMinimizeRest = lib.attrByPath [
"options"
"minimizeRest"
] false layoutObj;
}
else if layoutObj.name == "column" then
{
columnsBalanced = lib.attrByPath [
"options"
"balanced"
] false layoutObj;
}
else if layoutObj.name == "stair" then
{
stairReverse = lib.attrByPath [
"options"
"reverse"
] false layoutObj;
}
else
{ };

serializeLayouts =
layouts:
let
toLayoutEntry =
layout:
let
layoutEnabled = isLayoutEnabled layout.value;
layoutObj = lib.findFirst (l: (checkIfString l) == layout.value) { } layouts;
in
{
"enable${layout.label}" = layoutEnabled;
}
// (if layoutEnabled && !lib.isString layoutObj then generateOptionsConfig layoutObj else { });
in
lib.foldl' lib.recursiveUpdate { } (lib.map toLayoutEntry krohnkiteSupportedLayouts);
in
{
options.programs.plasma.kwin.scripts.krohnkite = with lib.types; {
enable = mkNullableOption bool "Whether to enable Krohnkite." true;

settings = {
gaps =
mkNullableOption krohnkiteGaps
"Gaps configuration for Krohnkite, e.g., top, bottom, left, right, and tiles."
{
top = 8;
bottom = 8;
left = 8;
right = 8;
tiles = 8;
};

tileWidthLimit = {
enable = mkNullableOption bool "Whether to limit tile width for Krohnkite." true;

ratio = lib.mkOption {
type = with lib.types; nullOr (numbers.between 0 99);
default = null;
example = 1.6;
description = "Tile width limiting ratio for Krohnkite. Must be a float between 0 and 99.";
};
};

layouts = {
enabled = lib.mkOption {
type =
with lib.types;
listOf (either (enum (lib.lists.forEach krohnkiteSupportedLayouts (x: x.value))) krohnkiteLayouts);
default = [ ];
example = [
"floating"
{
name = "monocle";
options = {
maximize = true;
};
}
];
description = ''
List of layout configurations for Krohnkite. This can be:
- An array of strings representing valid layout names, like `["floating" "monocle"]`. Valid values include:
${lib.concatStringsSep ", " (lib.lists.forEach krohnkiteSupportedLayouts (x: x.value))}.
- An array of objects with layout-specific options:
```
[
{ name = "monocle"; options = { maximize = true; }; }
{ name = "column"; options = { balanced = true; }; }
]
```
Mixed types are also supported.
'';
};
};

# Tiling options
maximizeSoleTile = mkNullableOption bool "Whether to maximize the sole window" true;
keepFloatAbove = mkNullableOption bool "Whether to keep floating windows above tiled windows" true;
keepTilingOnDrag =
mkNullableOption bool "Always preserve the tiling status of the window upon dragging"
true;
preventMinimize = mkNullableOption bool "Prevent windows from minimizing" true;
preventProtrusion = mkNullableOption bool "Prevent window from protruding from its screen" true;
noTileBorders = mkNullableOption bool "Remove borders of tiled windows" true;
floatUtility = mkNullableOption bool "Float utility windows" true;

# Filter rules
ignoreRoles = mkFilterOption "Ignore windows by role" [ "quake" ] [ "quake" ];
ignoreTitles = mkFilterOption "Ignore windows by title" null [ "firefox" ];
ignoreClasses = mkFilterOption "Ignore windows by class" [
"krunner"
"yakuake"
"spectacle"
"kded5"
"xwaylandvideobridge"
"plasmashell"
"ksplashqml"
"org.kde.plasmashell"
"org.kde.polkit-kde-authentication-agent-1"
"org.kde.kruler"
] [ "dialog" ];
ignoreActivities = mkFilterOption "Disable tiling on activities" null [ "Activity1" ];
ignoreScreens = mkFilterOption "Disable tiling on screens" null [ "Screen1" ];
ignoreVirtualDesktops = mkFilterOption "Disable tiling on virtual desktops" null [ "Desktop_1" ];
floatWindowsByClass = mkFilterOption "Float windows by class" null [ "dialog" ];
floatWindowsByTitle = mkFilterOption "Float windows by title" null [ "firefox" ];
};
};

config = lib.mkIf cfg.enable {
home.packages =
with pkgs;
lib.optionals (cfg.kwin.scripts.krohnkite.enable != null) [ kdePackages.krohnkite ];

programs.plasma.configFile."kwinrc" = lib.mkIf (cfg.kwin.scripts.krohnkite.enable != null) {
Plugins.krohnkiteEnabled = cfg.kwin.scripts.krohnkite.enable;
Script-krohnkite =
let
settings = cfg.kwin.scripts.krohnkite.settings;
gaps = settings.gaps;
tileWidthLimit = settings.tileWidthLimit;
in
serializeLayouts cfg.kwin.scripts.krohnkite.settings.layouts.enabled
// {
screenGapTop = gaps.top;
screenGapLeft = gaps.left;
screenGapRight = gaps.right;
screenGapBottom = gaps.bottom;
tileLayoutGap = gaps.tiles;

limitTileWidth = tileWidthLimit.enable;
limitTileWidthRatio = tileWidthLimit.ratio;

# Tiling options
maximizeSoleTile = settings.maximizeSoleTile;
keepFloatAbove = settings.keepFloatAbove;
keepTilingOnDrag = settings.keepTilingOnDrag;
preventMinimize = settings.preventMinimize;
preventProtrusion = settings.preventProtrusion;
noTileBorders = settings.noTileBorders;
floatUtility = settings.floatUtility;

# Filter rules
ignoreRole = settings.ignoreRoles;
ignoreTitle = settings.ignoreTitles;
ignoreClass = settings.ignoreClasses;
ignoreActivity = settings.ignoreActivities;
ignoreScreen = settings.ignoreScreens;
ignoreVDesktop = settings.ignoreVirtualDesktops;
floatingClass = settings.floatWindowsByClass;
floatingTitle = settings.floatWindowsByTitle;
};
};
};
}
Loading