CCE

KDE is a Base for my Emacs Desktop

Contents
emacs-lisp:tangle ~/nix/lisp/kde-desktop.el
(provide 'cce/kde-desktop)

Since I first started using Linux from a live-image collection DVD in the back of Fry's Electronics magazine, I have been a use of the various KDE desktop environments, or more specifically the KDE desktop's various incarnations over the years from KDE 3.5.9.

I've spent time exploring basically every other Desktop Environment under the sun over the years, but KDE is the right balance of smart design choices, and malleable user-choices. This is one of the few desktop environments that still, for example, make it easy to swap your window manager software easily.

If I wanted to install EXWM as my default window manager, rather than allowing it to kill kwin when EXWM is ready to load, I could simply place this in ~/.config/plasma-workspace/env/ and KDE will read the file, and use it.

shell
KDEWM=/usr/bin/emacs

And EXWM works really well with most of the KDE Plasma system. I don't really see my desktop of course, but the panel which has my list of X11 applications, my "system tray", etc, are still fully functional, once I learned that EXWM [can and] should ignore Plasma notifications.

I have a simple function M-x logout that will signal to KDE's Session Manager via D-BUS to trigger a desktop logout, as though I'd hit the logout button on the Application Launcher:

emacs-lisp:tangle ~/nix/lisp/kde-desktop.el
(defun logout-kde ()
  (interactive)
  (background-shell-command "qdbus org.kde.ksmserver /KSMServer logout -1 2 3"))

Installing KDE on My NixOS configuration

This is the bare-minimum for me; most of the applications are arbitrarily managed in home-manager e.g. Applications I Use so that they're available on home-manager+linux systems.

I customize my KDE installation a fair bit both within home-manager and without. Look at my use of Plasma Manager, and How I use KDE Plasma (Primarily) with a Keyboard.

nix:tangle ~/nix/nixos/kde.nix
{ config, pkgs, ... }:
{
  environment.variables = {
    QT_LOGGING_RULES = "kwin_*.debug=true";
  };
    
  security.pam.services.login = {
    enableKwallet = true;
    startSession = true;
  };

  # use plasma5
  services.desktopManager.plasma6.enable = true;

  environment.systemPackages = (with pkgs.kdePackages; [
    breeze-gtk
    kde-gtk-config
    breeze
    kdesu

    plasma-systemmonitor
    kio-extras
    # kipi-plugins
    plasma-browser-integration

    xdg-desktop-portal-kde
    systemsettings
    bluedevil
    
    ark
    dolphin
    filelight
    gwenview
    konsole
    okular
    partitionmanager
  ]) ++ (with pkgs; [
    # core kde applications
    libreoffice-qt
    gparted
  ]) ++ (with pkgs; [
    # extra utilities to make desktop bearable
    wl-clipboard-x11 
  ]);

  environment.sessionVariables = {
    QT_LOGGING_CONFIG = "kwin_xwl.debug=true";
  };

  # auto login
  services.xserver.enable = true;
  services.displayManager = {
    autoLogin.enable = true;
    autoLogin.user = "rrix";
    # defaultSession = "plasma";
  };
  # services.xserver.displayManager.lightdm.enable = true;
}

How I use KDE Plasma (Primarily) with a Keyboard

look ma, no pointer!

Driving A Laptop with Krohnkite

When I used X11 one of the window managers I preferred the most was XMonad. I can't claim to "know haskell", but I can copy and customize haskell I find on wiki pages and from friends, so when my friend Tor showed me his linux tiling WM setup and tossed me his config I was hooked. It allowed me to move really quickly through my windows, roughly organized with a few workspaces for swapping between code, docs, reference code, communications apps, media players... all in their own little place just a single keychord away from me. For years meta-s has taken me to a virtual desktop with my communication methods, a mere muscle twitch away. Double-edged sword dark laughter

And having an auto-tiler, boy howdy. Windows just show up and get out of the way, you can move things around without taking your hands off the keyboard, have them reorganized with separate organization strategies for each virtual desktop. things just zoom around and then stay where you want them to be.

For years I could just run XMonad with Plasma under X11 and that was great. Now I run Wayland. I tried RiverWM, I used a few KWin Scripts krohnkite, bismuth, etc, but Plasma 6 temporarily broke a lot of them and I was happy enough with Karousel especially on my laptop and on the ultra-wide monitor, but it was a bummer that it doesn't support multimonitor. I meant to get around asking some folks to give me a nudge toward fixing that for myself, but Krohnkite works again, and it's a great option for managing your desktop windows with only a tiny little keyboard like The Monticello Drive or a Framework Laptop

nix:tangle ~/nix/hm/kde-config-shortcuts-krohnkite.nix:noweb tangle
{ pkgs, config, ... }:

{
  # home.packages = [ pkgs.kdePackages.krohnkite pkgs.kwin-effects-forceblur pkgs.karess ];

  programs.plasma.shortcuts = {
    <<shortcuts_str(shortcuts_tbl_krohnkite)>>
    <<shortcuts_str(shortcuts_tbl_common)>>
    <<unset_str()>>
  };
}

Now this set of tables is used to generate shortcuts suitable for using the Karousel tiling WM on The Monticello Drive and Framework Laptop.

All keys here use the Windows/Meta/Super key...

  • Use asdf to switch between four virtual desktops, use those with the Shift key ASDF to move a window to that desktop.

  • Use jk to move to the next/previous windows. Use shifted JK to move the window up and down the stack.

  • Use um to increase the number of windows in the primary part of the split

  • Use HL to move the primary split left/right

  • Use r to rotate the layout

And, also, but:

group key value
kwin KrohnkiteShrinkWidth Meta+H,
kwin KrohnkiteFocusNext Meta+J,
kwin KrohnkiteFocusPrev Meta+K,
kwin KrohnkitegrowWidth Meta+L,
kwin KrohnkiteGrowHeight Meta+Shift+H,
kwin KrohnkiteShiftDown Meta+Shift+J,
kwin KrohnkiteShiftUp Meta+Shift+K,
kwin KrohnkiteShrinkHeight Meta+Shift+L,
kwin KrohnkiteIncrease Meta+U,
kwin KrohnkiteDecrease Meta+M,
kwin KrohnkiteRotate Meta+R,
kwin KrohnkiteRotatePart Meta+Shift+R,
kwin KrohnkiteSetMaster Meta+Return,
kwin Expose Meta+X,
kwin ExposeClass Meta+Shift+X,
kwin Switch to Next Screen Meta+I,
kwin Switch to Previous Screen Meta+\\,,,
kwin Window to Next Screen Meta+Ctrl+I,
kwin Window to Previous Screen Meta+Ctrl+\\,,,
file group key value note
kwinrc Plugins krohnkiteEnabled true
kwinrc Script-krohnkite directionalKeyDwm true
kwinrc Script-krohnkite directionalKeyFocus false
kwinrc Script-krohnkite screenGapBetween 3
kwinrc Script-krohnkite screenGapBottom 5
kwinrc Script-krohnkite screenGapLeft 5
kwinrc Script-krohnkite screenGapRight 5
kwinrc Script-krohnkite screenGapTop 5
kwinrc Script-krohnkite binaryTreeLayoutOrder 0
kwinrc Script-krohnkite cascadeLayoutOrder 0
kwinrc Script-krohnkite floatingLayoutOrder 0
kwinrc Script-krohnkite spiralLayoutOrder 0
kwinrc Script-krohnkite spreadLayoutOrder 0
kwinrc Script-krohnkite stairLayoutOrder 0
kwinrc Script-krohnkite limitTileWidth true

Common Keybindings

group key value
kwin Window On All Desktops Meta+Z,
kwin Window Close Alt+F4,Meta+Backspace,
kwin Kill Window Meta+Ctrl+Esc,
kwin Overview Meta+G,
kwin ExposeAll Launch (C),Meta+T,
kwin Show Desktop Meta+Q,
plasmashell show-on-mouse-pos Meta+V,
kwin Activate Window Demanding Attention Meta+Ctrl+A,
kwin Cube Meta+C,
kwin Window Maximize Meta+N,
kwin MoveMouseToCenter Meta+[,
kwin MoveMouseToFocus Meta+],
yakuake toggle-window-state Meta+Y,
kwin Switch to Desktop 1 Meta+A,
kwin Switch to Desktop 2 Meta+S,
kwin Switch to Desktop 3 Meta+D,
kwin Switch to Desktop 4 Meta+F,
kwin Window to Desktop 1 Meta+Shift+A,
kwin Window to Desktop 2 Meta+Shift+S,
kwin Window to Desktop 3 Meta+Shift+D,
kwin Window to Desktop 4 Meta+Shift+F,
kwin view_actual_size Meta+0,
kwin view_zoom_in Meta++, Meta+=,
kwin view_zoom_out Meta+-,

Panels and Desktop Widgets

configuration example

nix:tangle ~/nix/hm/kde-config-plasma-workspace.nix:noweb tangle
{ ... }:
{
  programs.plasma.panels = [
    {
      alignment = "center";
      floating = true;
      lengthMode = "fit";
      location = "top";
      height = 48;
      hiding = "autohide";
      widgets = [
        "org.kde.plasma.digitalclock"
        { name = "org.kde.plasma.fuzzyclock";
          config.Appearance.fuzzyness = 2; }
        { name = "org.kde.plasma.fuzzyclock";
          config.Appearance.fuzzyness = 3; }
        { name = "org.kde.plasma.fuzzyclock";
          config.Appearance.fuzzyness = 4; }
        { name = "org.kde.plasma.fuzzyclock";
          config.Appearance.fuzzyness = 5; }
      ];
    }
    {
      alignment = "center";
      floating = true;
      lengthMode = "fill";
      location = "bottom";
      height = 32;
      widgets = [
        "org.kde.plasma.pager"
        "org.kde.plasma.panelspacer"
        "org.kde.plasma.kickoff"
        { name = "org.kde.plasma.fuzzyclock";
          config.Appearance.fuzzyness = 2; }
        { name = "org.kde.plasma.icontasks";
          config.General = {
            launchers="preferred://browser,applications:emacs.desktop";
            showOnlyCurrentDesktop="false";
            groupingStrategy="0"; # disable grouping
            sortingStrategy="3"; # by desktop
          };
        }
        "org.kde.plasma.panelspacer"
        "org.kde.plasma.marginsseparator"
        {
          systemTray.items = {
            # We explicitly show bluetooth and battery
            # shown = [
            #   "org.kde.plasma.battery"
            #   "org.kde.plasma.bluetooth"
            # ];
            hidden = [
              "chrome_status_icon_1" # electron apps lol sob
              "Syncthing Tray"
              "org.kde.plasma.bluetooth"
              "Yakuake"
            ];
          };
        }
      ];
    }
  ];

  programs.plasma.workspace = {
    clickItemTo = "select";
    lookAndFeel = "org.kde.breezedark.desktop";
    colorScheme = "Breeze Dark Evo";
    # wallpaperPictureOfTheDay.provider = "apod";
  };
}

Desktop and Lockscreen Wallpapers

nix:tangle ~/nix/hm/kde-config-plasma-wallpapers.nix:noweb tangle
{ ... }:


let
  wpssc = {
    interval = 180;
    path = [
      "/home/rrix/sync/wallpapers/"
      "/home/rrix/Pictures/Backgrounds/"
      "/home/rrix/Pictures/Incoming/Game Captures/art of rally/"
      "/home/rrix/.nix-profile/share/wallpapers/"
      "/run/current-system/sw/share/wallpapers/"
    ];
  };
in
{
  programs.plasma.kscreenlocker.appearance.wallpaperSlideShow = wpssc;
  programs.plasma.workspace.wallpaperSlideShow = wpssc;
}

KWin effects configuration

file group key value note
kwinrc Desktops Name_1 🂱 Hearts
kwinrc Desktops Name_2 🃁 Diamonds
kwinrc Desktops Name_3 🃑 Clubs
kwinrc Desktops Name_4 🂡 Spades
kwinrc Desktops Id_1 ea4af40e-ac2e-47a6-a7fe-d8c96fe19498
kwinrc Desktops Id_2 6b27887c-168b-47c0-afec-1e2c4fb7569c
kwinrc Desktops Id_3 5fad8a00-140c-48b9-bce8-e387e1897532
kwinrc Desktops Id_4 a16fda83-8a7c-4abf-a525-f6cad58b173e
kwinrc Effect-PresentWindows LayoutMode 2 Layout Mode = Closest
kwinrc Effect-overview LayoutMode 0 Layout Mode = Closest
kwinrc ModifierOnlyShortcuts Meta Disable Meta/Super/Windows "start button" behavior.
kwinrc NightColor Active true Enable night color temperatures
kwinrc NightColor Mode Times I had issues with the location-based changing...
kwinrc NightColor MorningBeginFixed 0700
kwinrc NightColor EveningBeginFixed 2000
kwinrc NightColor NightTemperature 3600 Change to 3600k at night
kwinrc Xwayland Scale 1 X11 Apps will scale themselves
kwinrc Xwayland XwaylandEavesdrops Combinations "All keys, but only while Meta, Ctrl, Alt, or Shift keys are pressed"
kwinrc ModifierOnlyShortcuts Meta Disable Meta/Super/Windows "start button" behavior.
breezerc Windeco ButtonSize ButtonSmall
nix:tangle ~/nix/hm/kde-config-kwin.nix:noweb tangle
{ ... }:

{
  programs.plasma.kwin = {
    borderlessMaximizedWindows = false;
    effects = {
      blur.enable = true;
      cube.enable = true;
      desktopSwitching.animation = "fade";
      dimAdminMode.enable = true;
      minimization.animation = "magiclamp";
      minimization.duration = 150;
      shakeCursor.enable = true;
      slideBack.enable = false;
      snapHelper.enable = true;
      translucency.enable = true;
      windowOpenClose.animation = "glide";
      wobblyWindows.enable = true;
    };

    nightLight = {
      enable = true;
      mode = "location";
      location.latitude = "44.0";
      location.longitude = "-123.1";
      transitionTime = 30;
    };

    virtualDesktops.number = 4;
    virtualDesktops.rows = 2;
  };
}

NEXT Draft programs.plasma.window-rules

nix:tangle ~/nix/hm/kde-config-window-rules.nix:noweb tangle
{ ... }:

{
  programs.plasma.window-rules = [
    # {
    #   description = "Cantata -> D2";
    #   match.window-class = {
    #     value = "cantata";
    #     type = "substring";
    #   };
    #   match.window-types = ["normal" ];
    #   apply.desktops = {
    #     value = "";
    #     apply = "initially";
    #   };
    # }
  ];
}

CANCELLED Temporarily having gnome-shell fall-back session

I've been experiencing a desktop crash for like 3 months now. I have to do my job.

: #+ARROYO_NIXOS_MODULE: nixos/gnome.nix

nix:tangle ~/nix/nixos/gnome.nix
{ pkgs, lib, ... }:

{
  # services.xserver.desktopManager.gnome.enable = true;
  # services.gnome.gnome-browser-connector.enable = true;
  # hardware.pulseaudio.enable = false;
  # programs.ssh.askPassword = lib.mkForce "${pkgs.ksshaskpass}/bin/ksshaskpass";
  # services.xserver.displayManager.defaultSession = lib.mkForce "gnome";

  # programs.kdeconnect.package = pkgs.gnomeExtensions.gsconnect;

  # environment.systemPackages = with pkgs.gnomeExtensions; [
  #   activate-window-by-title
  #   appindicator
  #   paperwm
  #   pixel-saver
  #   yakuake
  # ];
}

CANCELLED Package for Karousel kwin script [and maybe a plasma-manager module]

: no longer needed, this is in nixpkgs

The Karousel source is pulled in as a flake input pinned by flake.lock:

nix:tangle ~/nix/snippets/karousel-input.nix:mkdirp yes
karousel = {
  url = "github:peterfajdiga/karousel";
  flake = false;
};

Available in rixpkgs.

nix:tangle ~/nix/pkgs/karousel.nix
{ inputs,
  lib,
  callPackage,
  mkDerivation,
  plasma-framework,
  typescript,
  nodejs,
  kwindowsystem
}:

mkDerivation rec {
  pname = "karousel";
  version = "0.0.1";

  src = inputs.karousel;

  postPatch = ''
    patchShebangs --build .
  '';

  buildInputs = [
    typescript
    nodejs
    plasma-framework
  ];

  # 1. --global still installs to $HOME/.local/share so we use --packageroot
  # 2. plasmapkg2 doesn't copy metadata.desktop into place, so we do that manually
  installPhase = ''
    runHook preInstall

    plasmapkg2 --type kwinscript --install ./package --packageroot $out/share/kwin/scripts

    runHook postInstall
  '';

  meta = with lib; {
    description = "Scrollable tiling script for kwin";
    license = licenses.gpl2;
    inherit (src.meta) homepage;
    inherit (kwindowsystem.meta) platforms;
  };
}

DONE put this in Nix Version Pins so that it's up to date.

Package for KWin Better Blur

You know the drill...

The kwin-effects-forceblur source is pulled in as a flake input pinned by flake.lock:

nix:tangle ~/nix/snippets/kwin-force-blur-input.nix:mkdirp yes
kwin-force-blur = {
  url = "github:taj-ny/kwin-effects-forceblur";
  flake = false;
};
nix:tangle ~/nix/pkgs/kwin-effects-forceblur.nix
{ inputs,
  lib,
  stdenv,
  callPackage,
  cmake,
  extra-cmake-modules,
  kwin,
  wrapQtAppsHook,
  qttools
}:

stdenv.mkDerivation rec {
  pname = "kwin-better-blur";
  version = "1.3.2";

  src = inputs.kwin-force-blur;

  nativeBuildInputs = [
    cmake
    extra-cmake-modules
    wrapQtAppsHook
  ];

  buildInputs = [
    kwin
    qttools
  ];

  meta = with lib; {
    description = "Fork of the KWin Blur effect for KDE Plasma 6 with additional features (including force blur) and bug fixes";
    license = licenses.gpl3;
    homepage = "https://github.com/taj-ny/kwin-effects-forceblur";
  };
}

CANCELLED Package for Karess

It lets u set up ur computer to have shortcuts bound to touchpad gestures

In to rixpkgs with u.

The karess source is pulled in as a flake input pinned by flake.lock:

nix:tangle ~/nix/snippets/karess-input.nix:mkdirp yes
karess = {
  url = "github:lavafroth/karess";
  flake = false;
};
nix:tangle ~/nix/pkgs/karess.nix
{ inputs,
  lib,
  callPackage,
  stdenv,
  plasma-framework,
  kwin
}:

stdenv.mkDerivation (finalAttrs: {
  pname = "karess";
  version = "0.0.1";

  src = inputs.karess;

  buildInputs = [
    kwin 
    plasma-framework
  ];
  dontWrapQtApps = true;

  installPhase = ''
    runHook preInstall

    plasmapkg2 --type kwinscript --install ./src --packageroot $out/share/kwin/scripts

    runHook postInstall
  '';

  meta = {
    description = "KWin Effect to enable touchpad gestures with Karousel";
    homepage = "https://github.com/lavafroth/karess";
    license = lib.licenses.mit;
    maintainers = with lib.maintainers; [ rrix ];
    platforms = lib.platforms.all;
  };
})