Skip to content

Instantly share code, notes, and snippets.

@nat-418
Last active November 1, 2024 10:03
Show Gist options
  • Save nat-418/1101881371c9a7b419ba5f944a7118b0 to your computer and use it in GitHub Desktop.
Save nat-418/1101881371c9a7b419ba5f944a7118b0 to your computer and use it in GitHub Desktop.
A sensible NixOS Xfce configuration

A sensible NixOS Xfce Configuration

NixOS provides good support for the Xfce desktop environment out-of-the-box, but the defaults are minimal. The files in this Gist provide a more complete experience, including a suite of basic software and plugins as well as an optional home-manager configuration for theming.

The key additions to the default Xfce provided by NixOS are:

  • Complete bluetooth / audio support with panel indicators and apps
  • LightDM with theme
  • Extra Xfce apps for calendaring, disk partitioning, etc.
  • Various quality-of-life improving non-essentials
{ config, pkgs, lib, ... }:
{
imports = [
./hardware-configuration.nix
./xfce.nix
];
# the rest of your nixos configuration
}
{ config, pkgs, lib, ... }:
{
imports = [
./xfce-home.nix
];
# the rest of your home-manager configuration
}
{ config, pkgs, lib, ... }:
{
gtk = {
enable = true;
iconTheme = {
name = "elementary-Xfce-dark";
package = pkgs.elementary-xfce-icon-theme;
};
theme = {
name = "zukitre-dark";
package = pkgs.zuki-themes;
};
gtk3.extraConfig = {
Settings = ''
gtk-application-prefer-dark-theme=1
'';
};
gtk4.extraConfig = {
Settings = ''
gtk-application-prefer-dark-theme=1
'';
};
};
programs.gpg.enable = true;
services.gpg-agent.enable = true;
}
{ pkgs, ... }:
{
environment = {
systemPackages = with pkgs; [
blueman
chromium
deja-dup
drawing
elementary-xfce-icon-theme
evince
firefox
foliate
font-manager
gimp-with-plugins
gnome.file-roller
gnome.gnome-disk-utility
inkscape-with-extensions
libqalculate
libreoffice
orca
pavucontrol
qalculate-gtk
thunderbird
wmctrl
xclip
xcolor
xcolor
xdo
xdotool
xfce.catfish
xfce.gigolo
xfce.orage
xfce.xfburn
xfce.xfce4-appfinder
xfce.xfce4-clipman-plugin
xfce.xfce4-cpugraph-plugin
xfce.xfce4-dict
xfce.xfce4-fsguard-plugin
xfce.xfce4-genmon-plugin
xfce.xfce4-netload-plugin
xfce.xfce4-panel
xfce.xfce4-pulseaudio-plugin
xfce.xfce4-systemload-plugin
xfce.xfce4-weather-plugin
xfce.xfce4-whiskermenu-plugin
xfce.xfce4-xkb-plugin
xfce.xfdashboard
xorg.xev
xsel
xtitle
xwinmosaic
zuki-themes
];
};
hardware = {
bluetooth.enable = true;
};
programs = {
dconf.enable = true;
gnupg.agent = {
enable = true;
enableSSHSupport = true;
};
thunar = {
enable = true;
plugins = with pkgs.xfce; [
thunar-archive-plugin
thunar-media-tags-plugin
thunar-volman
];
};
};
security.pam.services.gdm.enableGnomeKeyring = true;
services = {
blueman.enable = true;
gnome.gnome-keyring.enable = true;
pipewire = {
enable = true;
alsa = {
enable = true;
support32Bit = true;
};
pulse.enable = true;
};
xserver = {
enable = true;
excludePackages = with pkgs; [
xterm
];
displayManager = {
lightdm = {
enable = true;
greeters.slick = {
enable = true;
theme.name = "Zukitre-dark";
};
};
};
desktopManager.xfce.enable = true;
};
};
sound.enable = true;
}
@coderofsalvation
Copy link

coderofsalvation commented Aug 3, 2023

Just wanted to say thanks.
I got my xfce nixos up an running within 30 mins:

https://www.youtube.com/watch?v=1nkitmgCHfA&feature=youtu.be

ps. for non-homemanager folks (like me), here's how to support the standard .xinitrc way to initialize stuff during X-server boot:

services.xserver.displayManager.sessionCommands = ''
  test -f ~/.xinitrc && . ~/.xinitrc
'';

For example, I use this ~/.xinitrc on one of my systems, to initialize multiple monitors and set the bg-pictures:

# use `arandr` to export the default.sh file (menu: Layout > Save-as)
test -f ~/.screenlayout/default.sh && . ~/.screenlayout/default.sh
xfconf-query -c xfce4-desktop -l | grep last-image | while read path; do xfconf-query -c xfce4-desktop -p $path -s ~/Pictures/wallpaper.jpg; 

@nat-418
Copy link
Author

nat-418 commented Aug 3, 2023

Just wanted to say thanks. I got my xfce nixos up an running within 30 mins:

https://www.youtube.com/watch?v=1nkitmgCHfA&feature=youtu.be

ps. for non-homemanager folks (like me), here's how to support the standard .xinitrc way to initialize stuff during X-server boot:

services.xserver.displayManager.sessionCommands = ''
  test -f ~/.xinitrc && . ~/.xinitrc
'';

For example, I use this ~/.xinitrc on one of my systems, to initialize multiple monitors and set the bg-pictures:

# use `arandr` to export the default.sh file (menu: Layout > Save-as)
test -f ~/.screenlayout/default.sh && . ~/.screenlayout/default.sh
xfconf-query -c xfce4-desktop -l | grep last-image | while read path; do xfconf-query -c xfce4-desktop -p $path -s ~/Pictures/wallpaper.jpg; 

You are welcome. Thanks for adding the non-Home Manager setup.

Quick note on the video: you can just do the normal GNOME or KDE GUI easy install and then edit your configuration from there. You install Nix, change config, nixos rebuild-switch see if you like it, and repeat iteratively. The old stuff will get removed. The hardware file is generated automatically for your machine, you should leave it alone. Have fun with NixOS!

@PhilT
Copy link

PhilT commented Sep 12, 2023

Thank you for making this available. It'll help me setup my wife's computer in no time!

One thing I noticed. Is sound.mediaKeys.enable = true; needed as the doc mentions that XFCE enables this by default.

You want to leave this disabled if you run a desktop environment like KDE, Gnome, Xfce, etc, as those handle such things

@PhilT
Copy link

PhilT commented Sep 12, 2023

Also, pulseaudio is not enabled by default so this can probably be left out too but I guess it won't do any harm.

@nat-418
Copy link
Author

nat-418 commented Feb 19, 2024

Thank you for making this available. It'll help me setup my wife's computer in no time!

One thing I noticed. Is sound.mediaKeys.enable = true; needed as the doc mentions that XFCE enables this by default.

You want to leave this disabled if you run a desktop environment like KDE, Gnome, Xfce, etc, as those handle such things

thanks, removed

@nat-418
Copy link
Author

nat-418 commented Feb 19, 2024

Also, pulseaudio is not enabled by default so this can probably be left out too but I guess it won't do any harm.

thanks, removed

@Diomeh
Copy link

Diomeh commented Aug 6, 2024

Just pointing out, in systemPackages xcolor is repeated

@jaythomas
Copy link

I have a flake-based system that uses home-manager. Here's my config with a very granular xfce setup:

flake.nix
{
  description = "NixOS config flake";

  inputs = {
    #nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
    nixpkgs.url = "github:nixos/nixpkgs/nixos-24.05";

    home-manager = {
      url = "github:nix-community/home-manager/release-24.05";
      inputs.nixpkgs.follows = "nixpkgs";
    };

    sops-nix = {
      url = "github:Mic92/sops-nix";
      inputs.nixpkgs.follows = "nixpkgs";
    };
  };

  outputs = {
    self,
    nixpkgs,
    home-manager,
    ...
  } @ inputs:
  let
    primary-user = "myusername";
  in
  {
    nixosConfigurations.proxima = nixpkgs.lib.nixosSystem {
      system = "x86_64-linux";
      modules = [
        inputs.home-manager.nixosModules.home-manager
        inputs.sops-nix.nixosModules.sops
        ./hosts/proxima/configuration.nix
      ];
      specialArgs = {
        inherit inputs primary-user;
      };
    };
    nixosConfigurations.toliman = nixpkgs.lib.nixosSystem {
      system = "x86_64-linux";
      modules = [
        inputs.home-manager.nixosModules.home-manager
        inputs.sops-nix.nixosModules.sops
        ./hosts/toliman/configuration.nix
      ];
      specialArgs = {
        inherit inputs primary-user;
      };
    };
  };
}
hosts/proxima/configuration.nix
{ config, pkgs, specialArgs, ... }:

{
  imports = [
    ./hardware-configuration.nix
    ../../modules/_all-systems.nix
    ../../modules/alacritty.nix
    ../../modules/chromium.nix
    ../../modules/cups.nix
    ../../modules/direnv.nix
    ../../modules/firefox.nix
    ../../modules/fish.nix
    ../../modules/flatpak.nix
    ../../modules/git.nix
    ../../modules/gnupg.nix
    ../../modules/helix.nix
    ../../modules/imv.nix
    ../../modules/nvim.nix
    ../../modules/pijul.nix
    ../../modules/pipewire.nix
    ../../modules/ripgrep.nix
    ../../modules/rofi.nix
    ../../modules/ssh.nix
    ../../modules/steam.nix
    ../../modules/tmux.nix
    ../../modules/virtualbox.nix
    ../../modules/xfce.nix
    ../../modules/zellij.nix
  ];

  #boot.kernelPackages = pkgs.linuxPackages_latest;

  # Bootloader
  boot.loader.systemd-boot.enable = true;
  boot.loader.efi.canTouchEfiVariables = true;

  # Home Manager
  home-manager.users.${specialArgs.primary-user} = {
    home.stateVersion = "24.05";
  };
  home-manager.users.root.home.stateVersion = "24.05";

  # Networking
  networking = {
    hostName = "proxima";
    networkmanager.enable = true;
  };

  # High DPI fonts
  console.earlySetup = true;
  console.font = "${pkgs.terminus_font}/share/consolefonts/ter-u16n.psf.gz";
  environment.variables = {
    #GDK_SCALE = "0.8";
    #GDK_DPI_SCALE = "0.8";
    _JAVA_OPTIONS = "-Dsun.java2d.uiScale=2";
  };
  #services.xserver.dpi = 180;

  # Audio via Pipewire
  security.rtkit.enable = true;
  services.pipewire = {
    enable = true;
    alsa.enable = true;
    alsa.support32Bit = true;
    #jack.enable = true;
    pulse.enable = true;
  };

  users = {
    users.${specialArgs.primary-user} = {
      isNormalUser = true;
      description = specialArgs.primary-user;
      extraGroups = [ "networkmanager" "wheel" ];
      hashedPasswordFile = config.sops.secrets.passwd.path;
      packages = with pkgs; [
        # Add your packages here
      ];
    };
  };

  system.stateVersion = "24.05";
}
modules/xfce.nix
{ config, pkgs, specialArgs, ... }:

let background-image = "${pkgs.xfce.xfdesktop}/share/backgrounds/xfce/xfce-leaves.svg";
in {
  environment.systemPackages = with pkgs; [
    # Shell, window manager and x11 packages need to be installed at the
    # system level or else you will experience quirks with nixOS 24.05.
    wmctrl # workspace switcher used by /usr/bin/switch-workspace
    xclip
    xfce.mousepad
    xfce.thunar-archive-plugin
    xfce.thunar-volman
    xfce.xfce4-genmon-plugin
    xfce.xfce4-netload-plugin
    xfce.xfce4-power-manager
    xfce.xfce4-pulseaudio-plugin
    xfce.xfce4-weather-plugin
    xfce.xfwm4-themes
    xorg.xinit
  ];
  environment.xfce.excludePackages = with pkgs; [
    xfce.xfce4-appfinder
    xfce.xfce4-taskmanager
    xfce.xfce4-terminal
  ];

  home-manager.users.${specialArgs.primary-user} = { config, ... }: ({
    home.file.".config/xfce4/helpers.rc".text = "TerminalEmulator=alacritty";
    home.pointerCursor = {
      name = "Vanilla-DMZ";
      package = pkgs.vanilla-dmz;
      size = 64;
      x11.enable = true;
    };
    gtk = {
      enable = true;
      theme = {
        name = "Orchis-Orange-Dark-Compact";
        package = pkgs.orchis-theme;
      };
      iconTheme = {
        name = "Paper";
        package = pkgs.paper-icon-theme;
      };
    };
    xdg = {
      userDirs = {
        createDirectories = false;
        desktop = "${config.home.homeDirectory}/desktop";
        documents = "${config.home.homeDirectory}/documents";
        download = "${config.home.homeDirectory}/downloads";
        enable = true;
        music = "${config.home.homeDirectory}/music";
        pictures = "${config.home.homeDirectory}/pictures";
        publicShare = "${config.home.homeDirectory}/public";
        templates = "${config.home.homeDirectory}/templates";
        videos = "${config.home.homeDirectory}/videos";
      };
    };
    xfconf = {
      enable = true;
      settings = {
        keyboards = {
          "Default/Numlock" = false;
        };
        thunar = {
          "last-view" = "ThunarCompactView";
          "misc-show-delete-action" = true;
        };
        xfce4-desktop = {
          "backdrop/screen0/monitor0/workspace0/color-style" = 0;
          "backdrop/screen0/monitor0/workspace0/image-style" = 5;
          "backdrop/screen0/monitor0/workspace0/last-image" = background-image;
          "backdrop/screen0/monitor0/workspace1/color-style" = 0;
          "backdrop/screen0/monitor0/workspace1/image-style" = 5;
          "backdrop/screen0/monitor0/workspace1/last-image" = background-image;
          "backdrop/screen0/monitorDP-1/workspace0/color-style" = 0;
          "backdrop/screen0/monitorDP-1/workspace0/image-style" = 5;
          "backdrop/screen0/monitorDP-1/workspace0/last-image" = background-image;
          "backdrop/screen0/monitorDP-1/workspace1/color-style" = 0;
          "backdrop/screen0/monitorDP-1/workspace1/image-style" = 5;
          "backdrop/screen0/monitorDP-1/workspace1/last-image" = background-image;
          "backdrop/screen0/monitorDP-2/workspace0/color-style" = 0;
          "backdrop/screen0/monitorDP-2/workspace0/image-style" = 5;
          "backdrop/screen0/monitorDP-2/workspace0/last-image" = background-image;
          "backdrop/screen0/monitorDP-2/workspace1/color-style" = 0;
          "backdrop/screen0/monitorDP-2/workspace1/image-style" = 5;
          "backdrop/screen0/monitorDP-2/workspace1/last-image" = background-image;
          "desktop-icons/show-thumbnails" = false;
          "desktop-icons/style" = 0;
          "windowlist-menu/show" = false;
        };
        xfce4-keyboard-shortcuts = {
          "commands/custom/<Super>space" = "rofi -show drun";
          "commands/custom/<Super>a" = "switch-workspace left";
          "commands/custom/<Super>1" = "switch-workspace left";
          "commands/custom/<Super>s" = "switch-workspace right";
          "commands/custom/<Super>2" = "switch-workspace right";
        };
        xfce4-notifyd = {
          date-time-custom-format = "%a %H:%M:%S";
        };
        xfce4-panel = {
          "configver" = 2;
          "panels/dark-mode" = true;
          "panels/panel-1/background-style" = 2;
          "panels/panel-1/enter-opacity" = 100;
          "panels/panel-1/icon-size" = 16;
          "panels/panel-1/length" = 100;
          "panels/panel-1/plugin-ids" = [1 2 3 4 5 6 7 8 9 10 11 12 13];
          "panels/panel-1/position" = "p=6;x=0;y=0";
          "panels/panel-1/position-locked" = true;
          "panels/panel-1/size" = 26;
          "plugins/plugin-1" = "tasklist";
          "plugins/plugin-1/flat-buttons" = false;
          "plugins/plugin-1/grouping" = false;
          "plugins/plugin-1/show-handle" = false;
          "plugins/plugin-1/show-labels" = true;
          "plugins/plugin-1/show-tooltips" = false;
          "plugins/plugin-1/window-scrolling" = false;
          "plugins/plugin-2" = "separator";
          "plugins/plugin-2/expand" = true;
          "plugins/plugin-2/style" = 0;
          "plugins/plugin-3" = "netload";
          "plugins/plugin-4" = "genmon";
          "plugins/plugin-4/command" = "freemem";
          "plugins/plugin-4/enable-single-row" = true;
          "plugins/plugin-4/font" = "Sans 10";
          "plugins/plugin-4/style" = 0;
          "plugins/plugin-4/text" = "free memory";
          "plugins/plugin-4/update-period" = 30000;
          "plugins/plugin-4/use-label" = false;
          "plugins/plugin-5" = "pager";
          "plugins/plugin-5/rows" = 1;
          "plugins/plugin-6" = "weather";
          "plugins/plugin-6/cache-max-age" = 172800;
          "plugins/plugin-6/forecast/days" = 5;
          "plugins/plugin-6/forecast/layout" = 1;
          "plugins/plugin-6/labels/label0" = 3;
          "plugins/plugin-6/location/latitude" = "30.000";
          "plugins/plugin-6/location/longitude" = "-30.000";
          "plugins/plugin-6/location/name" = "My Secret Location";
          "plugins/plugin-6/msl" = 57;
          "plugins/plugin-6/offset" = "-04:00";
          "plugins/plugin-6/power-saving" = true;
          "plugins/plugin-6/round" = true;
          "plugins/plugin-6/scrollbox/animate" = "2";
          "plugins/plugin-6/scrollbox/color" = "rgba(0,0,0,0)";
          "plugins/plugin-6/scrollbox/lines" = 1;
          "plugins/plugin-6/scrollbox/show" = true;
          "plugins/plugin-6/scrollbox/use-color" = false;
          "plugins/plugin-6/single-row" = true;
          "plugins/plugin-6/timezone" = "American/New_York";
          "plugins/plugin-6/tooltip-style" = 1;
          "plugins/plugin-6/units/altitude" = 1;
          "plugins/plugin-6/units/apparent-temperature" = 0;
          "plugins/plugin-6/units/precipitation" = 1;
          "plugins/plugin-6/units/pressure" = 0;
          "plugins/plugin-6/units/temperature" = 1;
          "plugins/plugin-6/units/windspeed" = 1;
          "plugins/plugin-7" = "pulseaudio";
          "plugins/plugin-7/enable-keyboard-shortcuts" = true;
          "plugins/plugin-8" = "power-manager-plugin";
          "plugins/plugin-9" = "systray";
          "plugins/plugin-9/square-items" = true;
          "plugins/plugin-10" = "notification-plugin";
          "plugins/plugin-11" = "clock";
          "plugins/plugin-11/digital-date-font" = "Sans Bold 10";
          "plugins/plugin-11/digital-layout" = 3;
          "plugins/plugin-11/digital-time-font" = "Sans Bold 10";
          "plugins/plugin-11/digital-time-format" = "%a %d %R";
          "plugins/plugin-11/timezone" = "UTC";
          "plugins/plugin-12" = "clock";
          "plugins/plugin-12/digital-date-font" = "Sans Bold 10";
          "plugins/plugin-12/digital-layout" = 3;
          "plugins/plugin-12/digital-time-font" = "Sans Bold 10";
          "plugins/plugin-12/digital-time-format" = " %R";
          "plugins/plugin-12/mode" = 2;
          "plugins/plugin-12/tooltip-format" = "%x";
          "plugins/plugin-13" = "separator";
          "plugins/plugin-13/style" = 0;
        };
        xfce4-power-manager = {
          "xfce4-power-manager/blank-on-ac" = 30;
          "xfce4-power-manager/blank-on-battery" = 15;
          "xfce4-power-manager/dpms-enabled" = true;
          "xfce4-power-manager/dpms-on-ac-off" = 0;
          "xfce4-power-manager/dpms-on-ac-sleep" = 60;
          "xfce4-power-manager/dpms-on-battery-off" = 0;
          "xfce4-power-manager/dpms-on-battery-sleep" = 35;
        };
        xfce4-screensaver = {
          "lock/saver-activation/enabled" = false;
          "lock/user-switching/enabled" = false;
          "saver/idle-activation/enabled" = false;
          "saver/mode" = 0;
        };
        xfce4-screenshooter = {
          "imgur-custom-action-added" = false;
        };
        xfce4-session = {
          "general/SaveOnExit" = true;
        };
        xfwm4 = {
          "general/button_layout" = "O|HMC"; # titlebar minimize/maximize/close
          "general/focus_delay" = 0;
          "general/mousewheel_rollup" = false;
          "general/move_opacity" = 100;
          "general/raise_delay" = 0;
          "general/title_font" = "Sans Bold 9";
          "general/use_compositing" = true;
          "general/wrap_cycle" = true;
          "general/wrap_windows" = true;
          "general/wrap_workspaces" = false;
          "general/workspace_count" = 2;
          "general/workspace_names" = [ "1" "2" ];
        };
        xsettings = {
          "Gdk/WindowScalingFactor" = 1;
          "Gtk/ButtonImages" = false;
          "Gtk/CanChangeAccels" = false;
          "Gtk/ColorPalette" = "black:white:gray50:red:purple:blue:light blue:green:yellow:orange:lavender:brown:goldenrod4:dodger blue:pink:light green:gray10:gray30:gray75:gray90";
          "Gtk/CursorThemeName" = "Vanilla-DMZ";
          "Gtk/CursorThemeSize" = 16;
          "Gtk/DecorationLayout" = "menu:minimize,maximize,close";
          "Gtk/DialogsUseHeader" = false;
          "Gtk/FontName" = "Sans 10";
          "Gtk/MenuImages" = "1";
          "Gtk/MonospaceFontName" = "Monospace 10";
          "Gtk/TitlebarMiddleClick" = "lower";
          "Gtk/ToolbarIconSize" = 3;
          "Gtk/ToolbarStyle" = "icons";
          "Net/CursorBlink" = true;
          "Net/CursorBlinkTime" = 1200;
          "Net/DndDragThreshold" = 8;
          "Net/DoubleClickDistance" = 5;
          "Net/DoubleClickTime" = 400;
          "Net/EnableEventSounds" = false;
          "Net/EnableInputFeedbackSounds" = false;
          "Net/IconThemeName" = "Paper";
          "Net/ThemeName" = "Orchis-Orange-Dark-Compact";
        };
      };
    };
  });

  programs.thunar.plugins = with pkgs.xfce; [
    thunar-archive-plugin
    thunar-volman
  ];

  # X11
  services.xserver = {
    # Desktop environment
    desktopManager.xfce = {
      enable = true;
      noDesktop = false;
      enableXfwm = true;
    };

    displayManager = {
      lightdm = {
        enable = true;
        extraConfig = ''
          background = ${background-image}
        '';
        greeters.gtk.extraConfig = ''
          background = ${background-image}
        '';
      };
      startx.enable = true;
    };

    enable = true;

    excludePackages = with pkgs; [
      xterm
    ];

    exportConfiguration = true;

    xkb = {
      layout = "us";
      variant = "colemak";
    };
  };

  users.users.${specialArgs.primary-user}.packages = with pkgs; [
    gnome.file-roller
    orchis-theme     # gtk theme
    paper-icon-theme # xfce icons
    redshift         # blue light screen filter
    vanilla-dmz      # cursor set by home-manager
    # Genmon script to display free memory
    (writeShellApplication {
      name = "freemem";
      text = builtins.readFile ./xfce-freemem;
    })
    # Shell script to switch virtual desktops in xfce. xfce4 doesn't provide
    # the ability to create keyboard shortcuts for switching workspaces.
    (writeShellApplication {
      name = "switch-workspace";
      text = builtins.readFile ./xfce-switch-workspace;
    })
  ];

  xdg.portal = {
    enable = true;
    extraPortals = [ pkgs.xdg-desktop-portal-gtk ];
  };
}
modules/xfce-switch-workspace
#!/usr/bin/env bash

#
# Switch to workspace left, right, up, or down from current for
# workspaces arranged in `$num_rows' rows and `$num_cols'
# columns. Wraps around within the current row for left and right and
# within the current column for up and down.
#
# Usage: switch-workspace (left|right|up|down)
#

# Configuration
num_rows=1 ;
num_cols=2 ;

# Workspaces are numbered 0 .. $num_rows*$num_cols-1.

current=$( wmctrl -d | grep "\*" | cut -d ' ' -f 1 ) ;

row=$(( current / num_cols )) ;
col=$(( current % num_cols )) ;

case $1 in
  left)
    col=$(( ( col + num_cols - 1 ) % num_cols )) ;
  ;;
  right)
    col=$(( ( col + 1 ) % num_cols )) ;
  ;;
  up)
    row=$(( ( row + num_rows - 1 ) % num_rows )) ;
  ;;
  down)
    row=$(( ( row + 1 ) % num_rows )) ;
  ;;
esac ;

wmctrl -s $(( row * num_cols + col )) ;

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment