Skip to main content
Yanked

This release has been yanked by its maintainers, and will be ignored by installers, except when explicitly specified.
Consider using release 1.2.1 instead.
Reason given by maintainers: broken on Python 3.12/3.13 (SyntaxError on import)

Gnome Window Controller

GNOME: 50.4v3.14.7Email-MeLicenseTests: passing

Control GNOME window focus.

Focus changing between monitors, windows, and apps, includes multiple options

This extension uses Python, and intends to be used by mapping shortcuts or terminal commands.

Designed to use with Wayland window system protocol and GNOME desktop environment.

This extension adds terminal commands and extra features to existing extensions, but is designed to use a python backend, therefore requiring the python part install. If your usage is directional focus changing (left/right/up/down), there is the standalone gnome extension Focus Control, give it a look.

  1. Features

  2. Requirements

  3. Install

  4. Shortcuts

4.1 Example Keybindings

  1. Usage

5.1 Queries

5.2 Focus

5.3 Focus Highlight

5.4 Colored Output

  1. Acknowledgments

Features

  • Terminal commands support for every command/feature

  • Directional focus changing between monitors (left/right/up/down)

  • Highlight border uppon focusing, allowing configuration (this extension focus|any|disabled)

  • Given app name focusing

  • Same monitor app focus changing

  • Same app focus changing

  • Excluding given app name from focus changing

  • Flash highlight border on currently focused window

Requirements

  • GNOME Shell 45+ (Tested on 50.4, Wayland)

  • gnome-window-controller@eduardotcampos.hotmail.com extension (see Install)

  • glib-compile-schemas (glib2-devel)

  • Python 3.11+ (requires-python = ">=3.11").

[!NOTE] PyGObject is also a dependency, but is normally supplied by the distribution, case not, the better option is to install it from distro packages (dnf, apt, etc.) rather than letting pip to compile it.


Install

Python Package

python -m pip install gnome-window-controller

or from a checkout:

git clone https://github.com/eduardotlc/gnome_window_controller
cd gnome_window_controller
python -m pip install .

Highlight Extension

gnome-window-controller --highlight install

Log out and back in afterwards. GNOME Shell only scans for extensions at startup, and Wayland cannot restart the shell in place.

run/map the command either by

python -m gnome_window_controller [command] [flags]

or

gnome-window-controller [command] [flags]

[!NOTE] The Python package and the GNOME Shell extension are installed separately — the extension has to live under ~/.local/share/gnome-shell/extensions/

[!NOTE] python pip install gets the gnome-window-controller command in ~/.local/bin:


Shell Completions

Completion files for both shells ship inside the package, under src/gnome_window_controller/completions/ in a checkout, and beside the installed package otherwise.

Bash

mkdir -p ~/.local/share/bash-completion/completions
cp src/gnome_window_controller/completions/gnome-window-controller.bash \
   ~/.local/share/bash-completion/completions/gnome-window-controller

The target file has to be named after the command — that is how bash-completion finds and loads it on first use.

zsh

mkdir -p ~/.local/share/zsh/site-functions
cp src/gnome_window_controller/completions/_gnome-window-controller \
   ~/.local/share/zsh/site-functions/

and, in ~/.zshrc before compinit runs:

fpath=(~/.local/share/zsh/site-functions $fpath)

Both complete every flag, and the values each flag takes: --chfocus offers monitor, win, right, left, up, down and last, then narrows the second word to whatever the first one allows. --focus and --exclude complete against the wm_class of the windows currently open.

[!NOTE] Installed with pip instead of from a clone? The files are next to the installed package:

python -c 'import gnome_window_controller as m, pathlib as p;\
print(p.Path(m.__file__).parent / "completions")'

Shortcuts

Settings → Keyboard → View and Customize Shortcuts → Custom Shortcuts.

Then map commands like:

Focus right:

/home/eduardotc/.local/bin/gnome-window-controller --chfocus right

Focus left:

/home/eduardotc/.local/bin/gnome-window-controller --chfocus left

[!IMPORTANT] gnome-shell's PATH does not include ~/.local/bin, so give the absolute path (substitute /home/eduardotc above with your user home)

Back up and restore all custom shortcuts with:

dconf dump /org/gnome/settings-daemon/plugins/media-keys/ > keybindings.conf
dconf load /org/gnome/settings-daemon/plugins/media-keys/ < keybindings.conf

Example Keybindings

Keys Command
Super + L / Super + H --chfocus right / --chfocus left
Super + J / Super + K --chfocus win same_monitor / --chfocus win same_monitor_up
Super + R --chfocus last
Super + C --chfocus monitor top
Super + X --chfocus win same_app
Super + I --show-focus — outline the focused window

Usage

Running with no arguments or -h/--help prints the full help

gnome-window-controller

Queries

gnome-window-controller --list-windows            # listing
gnome-window-controller --list-windows --json     # machine readable
gnome-window-controller --details-windows         # full Details(id) per window
gnome-window-controller --list-monitors           # rectangles, order and neighbors
gnome-window-controller --list-monitors --json    # machine readable

Focus

--focus

--focus <name>
--focus <name> --scope [other-monitor|current-monitor|any]
gnome-window-controller --focus kitty
gnome-window-controller --focus kitty --scope any

--scope picks where --focus searches: other-monitor (default), current-monitor, or any.

--exclude

--exclude <name> [<name> ...]
gnome-window-controller --chfocus win --exclude floorp
gnome-window-controller --chfocus win --exclude floorp --exclude Slack

Windows whose wm_class, instance or title contains a given name are never focused — the focus command steps over them and takes the next candidate instead. Matching is a case-insensitive substring, the same rule --focus uses, so --exclude floorp covers every Floorp window and --exclude Picture-in-Picture covers one window of an app without touching its siblings.

It applies to --focus and to every --chfocus command. Listings are untouched: --list-windows still shows excluded windows, and so does the "which monitor am I on" lookup, which is what keeps things correct while an excluded app happens to hold focus.

Picture-in-Picture is excluded out of the box — a floating video overlay is virtually never what a focus shortcut is reaching for — and --exclude adds to that list rather than replacing it. To start from nothing, use the Python API:

GnomeWindowController(exclude_apps=())                  # nothing excluded
GnomeWindowController(exclude_apps=("floorp", "Slack"))  # exactly these

--chfocus

--chfocus <command> [option]
command option effect
monitor top (default) / bottom focus the top- or bottom-most window of another monitor
win same_app next window of the focused app
win same_monitor, same_monitor_down next window on this monitor
win same_monitor_up (or none) previous window on this monitor
right / left move focus one monitor right/left, wrapping
up / down move focus one monitor up/down, wrapping
last focus the previously focused window

Every one of them honours --exclude.

Monitor layouts

The four directions follow the actual monitor rectangles read from org.gnome.Mutter.DisplayConfig, so any arrangement works — a row, a vertical stack, an L, a grid, mixed resolutions, mixed scales, a screen rotated onto its side. Nothing is hard-coded to a particular desk, and Mutter's monitor indices are used as they come: they follow no geometric order of their own.

A direction with no monitor that way leaves focus alone and exits 1, rather than jumping somewhere arbitrary — on a single row, up means nothing. At the end of a row or column the search wraps, which is what makes repeated --chfocus right cycle. Where a direction has no aligned monitor but does have an off-axis one, it goes there instead, so no screen on an L-shaped desk is unreachable.

--list-monitors prints exactly what the directions will follow:

left-to-right order: [2, 1, 0]
[2] HDMI-1 1920x1080 @ 0,0     scale 1.0
[1] DP-1   2560x1440 @ 1920,0  scale 1.0 (primary) <
[0] DP-2   1920x1080 @ 4480,0  scale 1.0

neighbors (what --chfocus <direction> follows, wrapping at the edges):
   from    left   right      up    down
      2       0       1       -       -
      1       2       0       -       -
      0       1       2       -       -

Focus Highlight

gnome-window-controller --highlight           # status + current options
gnome-window-controller --highlight on
gnome-window-controller --highlight off
gnome-window-controller --highlight flash     # pulse the focused window now
gnome-window-controller --show-focus          # outline the focused window now
gnome-window-controller --highlight clear     # remove the border
gnome-window-controller --highlight uninstall

Options

gnome-window-controller --highlight on \
    --highlight-color '#fb4934' \
    --highlight-width 4 \
    --highlight-radius 8 \
    --highlight-duration 900
Flag Default Meaning
--highlight-color #993c5a any CSS color St accepts (#rgb, red, rgba(...))
--highlight-width 3 border thickness, px
--highlight-radius 12 corner radius, px
--highlight-inset 2 how far outside the frame the border sits, px
--highlight-duration 0 ms to stay visible; 0 keeps it until focus moves
--highlight-mode always always, commands or off (see above)

[!NOTE] Any --highlight-* flag applies on its own — no --highlight ACTION needed.

Settings persist to ~/.config/gnome-window-controller/highlight.json and are reloaded when the shell restarts.

Every window focused by this CLI is also flashed automatically. Pass --no-highlight to suppress that for a single invocation. When the extension is not installed the flash is skipped silently (~0.3 ms), so nothing else breaks.

Colored Output

Colors printing can be turned off with:

gnome-window-controller --list-windows --color never    # plain text
gnome-window-controller --list-windows --color always   # color even into a pipe
gnome-window-controller --list-windows                  # auto: color only a real terminal
GWC_COLORS=False gnome-window-controller --list-windows # same, from the environment

Acknowledgments

The gnome extensions from which this one wouldn't exist, huge thanks to:

TODO

  • Bundle PyPI package

  • Upload gnome-extension

  • Create documentation page

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

gnome_window_controller-1.2.0.tar.gz (73.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

gnome_window_controller-1.2.0-py3-none-any.whl (60.2 kB view details)

Uploaded Python 3

File details

Details for the file gnome_window_controller-1.2.0.tar.gz.

File metadata

  • Download URL: gnome_window_controller-1.2.0.tar.gz
  • Upload date:
  • Size: 73.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.14.7

File hashes

Hashes for gnome_window_controller-1.2.0.tar.gz
Algorithm Hash digest
SHA256 c8194e1e5153a69f03cda048df0c28228c7cc9f48fa526172e2376f181a310da
MD5 72e6776c2cdeb758c6bd4ac2357c3a27
BLAKE2b-256 2a611be663a4195e2d7cd8bf4341e561f69fd5f4047a127ce8f1b46fd3c036d6

See more details on using hashes here.

File details

Details for the file gnome_window_controller-1.2.0-py3-none-any.whl.

File metadata

File hashes

Hashes for gnome_window_controller-1.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 66f00a791439261a6c4e11120eb34658400117b8d17a0496ded33eac49fdea12
MD5 c22dc04240a0c157eeaea6727ed89b1a
BLAKE2b-256 1c916eaf8fe1d2dea0300b4c2eb87430c902e4ae0e68805078897b0de93b45c9

See more details on using hashes here.

Release history Release notifications | RSS feed

1.2.1

2 files

This release

1.2.0 This release

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page