Provided by: qtile_0.31.0-1_all bug

NAME

       qtile - Qtile [image]

       Qtile is a full-featured, hackable tiling window manager written and configured in Python. It's available
       both as an X11 window manager and also as a Wayland compositor.

       This  documentation  is designed to help you install and configure Qtile. Once it's up and running you'll
       probably want to start adding your own customisations to have it running exactly the way you want.

       You'll find a lot of what you need within these docs but, if you still have some questions, you can  find
       support in the following places:

       IRC    irc://irc.oftc.net:6667/qtile

       Discord
              https://discord.gg/ehh233wCrC (Bridged with IRC)

       Q&A    https://github.com/qtile/qtile/discussions/categories/q-a

       Mailing List
              https://groups.google.com/group/qtile-dev

INSTALLATION

   Distro Guides
       Below  are  the  preferred  installation methods for specific distros. If you are running something else,
       please see Installing From Source.

   Installing on Arch Linux
       Stable versions of Qtile are currently packaged for Arch Linux. To install this package, run:

          pacman -S qtile

       Please see the ArchWiki for more information on Qtile.

   Installing on Fedora 40 or later.
       Both Qtile X11 and Wayland stable versions can be installed via the DNF Package Manager.

       If you want to pick a specific version(Such as the wayland version) then double-click Tab after "qtile".

          dnf install qtile

   Installing on Funtoo
       Latest versions of Qtile are available on Funtoo. To install it, run:

          emerge -av x11-wm/qtile

       You can also install the development version from GitHub:

          echo "x11-wm/qtile-9999 **" >> /etc/portage/package.accept_keywords
          emerge -av qtile

   Customize
       You can customize your installation with the following useflags:

       • dbus

       • widget-khal-calendar

       • widget-imap

       • widget-keyboardkbdd

       • widget-launchbar

       • widget-mpd

       • widget-mpris

       • widget-wlan

       The dbus useflag is enabled by default. Disable it only if you  know  what  it  is  and  know  you  don't
       use/need it.

       All widget-* useflags are disabled by default because these widgets require additional dependencies while
       not  everyone  will  use  them.  Enable only widgets you need to avoid extra dependencies thanks to these
       useflags.

       Visit Funtoo Qtile documentation for more details on Qtile installation on Funtoo.

   Installing on Ubuntu or Debian 11 (bullseye) or greater
       Ubuntu and Debian >=11 comes with the necessary packages for installing Qtile.  Starting from  a  minimal
       Debian installation, the following packages are required:

          sudo apt install xserver-xorg xinit
          sudo apt install libpangocairo-1.0-0
          sudo apt install python3-pip python3-xcffib python3-cairocffi

       Either  Qtile  can  then  be  downloaded from the package index or the Github repository can be used, see
       Installing From Source:

          pip install qtile

   Installing on Slackware
       Qtile is available on the SlackBuilds.org as:
                                      ┌──────────────┬─────────────────────────┐
                                      │ Package Name │ Description             │
                                      ├──────────────┼─────────────────────────┤
                                      │ qtile        │ stable branch (release) │
                                      └──────────────┴─────────────────────────┘

   Using slpkg (third party package manager)
       The easy way to install Qtile is with slpkg. For example:

          slpkg -s sbo qtile

   Manual installation
       Download dependencies first and install them.  The order in which you need to install is:

       • pycparser

       • cffi

       • futures

       • python-xcffib

       • trollius

       • cairocffi

       • qtile

       Please see the HOWTO for more information on SlackBuild Usage HOWTO.

   Installing on FreeBSD
       Qtile is available via FreeBSD Ports. It can be installed with

          pkg install qtile

   Installing on NixOS
       Qtile is available in the NixOS repos.  To set qtile  as  your  window  manager,  include  this  in  your
       configuration.nix file:

          services.xserver.windowManager.qtile.enable = true;

       Other options for qtile can be declared within the services.xserver.windowManager.qtile attribute set.

       You may add extra packages in the qtile python environment by putting them in the extraPackages list.

          services.xserver.windowManager.qtile = {
            enable = true;
            extraPackages = python3Packages: with python3Packages; [
              qtile-extras
            ];
          };

       The  Qtile  package creates desktop files for both X11 and Wayland, to use one of the backends choose the
       right session in your display manager.

       The configuration file can be changed from its default location ($XDG_CONFIG/qtile/config.py) by  setting
       the configFile attribute:

          qtile = {
            enable = true;
            configFile = ./my_qtile_config.py;
          };

       NOTE:
          Some  options  may  change  over  time,  please  refer to see all the options for the latest stable: ‐
          search.nixos.org if you have any doubt

   Home manager
       If you are using home-manager, you can copy your qtile configuration by using the following:

          xdg.configFile."qtile/config.py".source = ./my_qtile_config.py;

       or, if you have a directory containing multiple python files:

          xdg.configFile."qtile" = {
            source = ./src;
            recursive = true;
          };

   Flake
       Qtile also has a flake in the repository. This can be used for the following use cases:

       • Run a bleeding edge version of Qtile by using it as an overlay in your flake config

       • Hack on Qtile with a Nix develop shell

       Note that flakes are an experimental NixOS feature but they are already  widely  used.  This  section  is
       meant for users that already use flakes.

       To  run a bleeding edge version of Qtile with the flake, add the Qtile repo to your inputs and define the
       overlay. An example flake is the following:

          {
             description = "A very basic flake";
             inputs = {
               nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable";

               qtile-flake = {
                 url = "github:qtile/qtile";
                 inputs.nixpkgs.follows = "nixpkgs";
               };
             };

             outputs = { self, nixpkgs, qtile-flake }: {
               nixosConfigurations.demo = nixpkgs.lib.nixosSystem {
                 system = "x86_64-linux";

                 modules = [
                   (_: { nixpkgs.overlays = [ qtile-flake.overlays.default ]; })
                   ({ config, pkgs, lib, ...}: {
                     services.xserver = {
                       enable = true;
                       windowManager.qtile.enable = true;
                     };

                     # make qtile X11 the default session
                     services.displayManager.defaultSession = lib.mkForce "qtile";

                     # rest of your NixOS config
                   })
                 ];
               };
             };
          }

       This flake can also be tested with a vm:

          sudo nixos-rebuild build-vm --flake .#demo

       Gives you a script to run that runs Qemu to test your config. For this to work you have  to  set  a  user
       with a password.

       To  hack  on Qtile with Nix, simply run nix develop in a checkout of the repo.  In the development shell,
       there are a few useful things:

       • qtile-run-tests-wayland: Run all Wayland tests

       • qtile-run-tests-x11: Run all X11 tests

   Installing From Source
   Python interpreters
       We aim to always support the last three versions of CPython, the reference Python interpreter. We usually
       support the latest stable version of PyPy as well.  You  can  check  the  versions  and  interpreters  we
       currently run our test suite against in our tox configuration file.

       There  are not many differences between versions aside from Python features you may or may not be able to
       use in your config. PyPy should be faster at runtime than any corresponding CPython  version  under  most
       circumstances, especially for bits of Python code that are run many times. CPython should start up faster
       than PyPy and has better compatibility for external libraries.

   Core Dependencies
       Here  are  Qtile's core runtime dependencies and the package names that provide them in Ubuntu. Note that
       Qtile can run with one of two backends -- X11 and Wayland -- so only the dependencies of one of these  is
       required.
                      ┌───────────────────┬─────────────────────┬──────────────────────────────┐
                      │ Dependency        │ Ubuntu Package      │ Needed for                   │
                      ├───────────────────┼─────────────────────┼──────────────────────────────┤
                      │ Core Dependencies │                     │                              │
                      ├───────────────────┼─────────────────────┼──────────────────────────────┤
                      │ CFFI              │ python3-cffi        │ Bars and popups              │
                      ├───────────────────┼─────────────────────┼──────────────────────────────┤
                      │ cairocffi         │ python3-cairocffi   │ Drawing on bars and popups   │
                      ├───────────────────┼─────────────────────┼──────────────────────────────┤
                      │ libpangocairo     │ libpangocairo-1.0-0 │ Writing on bars and popups   │
                      ├───────────────────┼─────────────────────┼──────────────────────────────┤
                      │ dbus-fast         │ --                  │ Sending  notifications  with │
                      │                   │                     │ dbus (optional).             │
                      ├───────────────────┼─────────────────────┼──────────────────────────────┤
                      │ X11               │                     │                              │
                      ├───────────────────┼─────────────────────┼──────────────────────────────┤
                      │ X server          │ xserver-xorg        │ X11 backends                 │
                      ├───────────────────┼─────────────────────┼──────────────────────────────┤
                      │ xcffib            │ python3-xcffib      │ required for X11 backend     │
                      ├───────────────────┼─────────────────────┼──────────────────────────────┤
                      │ Wayland           │                     │                              │
                      ├───────────────────┼─────────────────────┼──────────────────────────────┤
                      │ wlroots           │ libwlroots-dev      │ Wayland backend (see below)  │
                      ├───────────────────┼─────────────────────┼──────────────────────────────┤
                      │ pywlroots         │ --                  │ python  bindings   for   the │
                      │                   │                     │ wlroots library              │
                      ├───────────────────┼─────────────────────┼──────────────────────────────┤
                      │ pywayland         │ --                  │ python   bindings   for  the │
                      │                   │                     │ wayland library              │
                      ├───────────────────┼─────────────────────┼──────────────────────────────┤
                      │ python-xkbcommon  │ --                  │ required for wayland backeds │
                      └───────────────────┴─────────────────────┴──────────────────────────────┘

   Qtile
       With the dependencies in place, you can now install the stable version of qtile from PyPI:

          pip install qtile

       Or with sets of dependencies:

          pip install qtile[wayland]  # for Wayland dependencies
          pip install qtile[widgets]  # for all widget dependencies
          pip install qtile[all]      # for all dependencies

       Or install qtile-git with:

          git clone https://github.com/qtile/qtile.git
          cd qtile
          pip install .
          pip install --config-setting backend=wayland .  # adds wayland dependencies

   Starting Qtile
       There are several ways to start Qtile. The most common way is via an entry in your  X  session  manager's
       menu. The default Qtile behavior can be invoked by creating a qtile.desktop file in /usr/share/xsessions.

       A  second  way  to  start  Qtile  is  a custom X session. This way allows you to invoke Qtile with custom
       arguments, and also allows you to do any setup you want (e.g. special keyboard bindings like mapping caps
       lock to control, setting your desktop background, etc.) before Qtile starts. If you're using an X session
       manager, you still may need to create a custom.desktop file similar to the qtile.desktop file above,  but
       with  Exec=/etc/X11/xsession.  Then,  create  your  own  ~/.xsession.  There are several examples of user
       defined xsession s in the qtile-examples repository.

       If there is no display manager such as SDDM, LightDM or other and there is need to start  Qtile  directly
       from ~/.xinitrc do that by adding exec qtile start at the end.

       In  very  special  cases,  ex. Qtile crashing during session, then suggestion would be to start through a
       loop to save running applications:

          while true; do
              qtile
          done

   Wayland
       Qtile can be run as a Wayland compositor rather than an X11 window manager. For this, Qtile uses wlroots,
       a compositor library which is undergoing fast development.  Be  aware  that  some  distributions  package
       outdated  versions  of  wlroots.  More up-to-date distributions such as Arch Linux may package pywayland,
       pywlroots and python-xkbcommon. Also note that we may not have yet caught  up  with  the  latest  wlroots
       release ourselves.

       NOTE:
          We currently support wlroots>=0.17.0,<0.18.0, pywlroots>=0.17.0,<0.18.0 and pywayland >= 0.4.17.

       With  the Wayland dependencies in place, Qtile can be run either from a TTY, or within an existing X11 or
       Wayland session where it will run inside a nested window:

          qtile start -b wayland

       See the Wayland page for more information on running Qtile as a Wayland compositor.

       Similar to the xsession example above, a wayland session file can be used to start  qtile  from  a  login
       manager. To use this, you should create a qtile-wayland.desktop file in /usr/share/wayland-sessions.

   udev rules
       Qtile  has  widgets  that  support managing various kinds of hardware (LCD backlight, keyboard backlight,
       battery charge thresholds) via the kernel's exposed sysfs endpoints. However, to make  this  work,  Qtile
       needs  permission to write to these files. There is a udev rules file at /resources/99-qtile.rules in the
       tree, which users installing from source will want to install at /etc/udev/rules.d/ on their  system.  By
       default,  this rules file changes the group of the relevant files to the sudo group, and changes the file
       mode to be g+w (i.e. writable by all members of the sudo group). The theory here  is  that  most  systems
       qtile  is installed on will also have the primary user in the sudo group. However, you can change this to
       whatever you like with the --group argument; see the sample udev rules.

       Note that this file invokes Qtile's hidden udev from udevd, so udevd will need qtile in  its  $PATH.  For
       distro  packaging this shouldn't be a problem, since /usr/bin is typically in udev's path. Alternatively,
       users can install from source using uv, which will do all the right $PYTHONPATH setup etc., so  you  only
       need to change the path to the final executable in the udev rules:

          # copy the in-tree udev rules file to the right place to make udev see it,
          # and change the rules to point at our wrapper script above.
          sed "s,qtile,$HOME/.local/bin/qtile,g" ./resources/99-qtile.rules | sudo tee /etc/udev/rules.d/99-qtile.rules

RUNNING QTILE AS A WAYLAND COMPOSITOR

       Some  functionality  may  not yet be implemented in the Wayland compositor.  Please see the Wayland To Do
       List discussion for the current state of development.   Also  checkout  the  unresolved  Wayland-specific
       issues and troubleshooting for tips on how to debug Wayland problems.

       NOTE:
          We currently support wlroots>=0.17.0,<0.18.0 and pywlroots>=0.17.0,<0.18.0.

   Backend-Specific Configuration
       If  you  want  your config file to work with different backends but want some options set differently per
       backend, you can check the name of the current backend in your config as follows:

          from libqtile import qtile

          if qtile.core.name == "x11":
              term = "urxvt"
          elif qtile.core.name == "wayland":
              term = "foot"

   Running X11-Only Programs
       Qtile supports XWayland but requires that wlroots and pywlroots were built  with  XWayland  support,  and
       that  XWayland  is  installed  on  the system from startup. XWayland will be started the first time it is
       needed.

   XWayland windows sometimes don't receive mouse events
       There is currently a known bug (https://github.com/qtile/qtile/issues/3675) which causes  pointer  events
       (hover/click/scroll) to propagate to the wrong window when switching focus.

   Input Device Configuration
       If  you  want  to change keyboard configuration during runtime, you can use the core's set_keymap command
       (see below).

   Core Commands
       See the Wayland backend section in the API Commands documentation.

TROUBLESHOOTING

   So something has gone wrong... what do you do?
       When Qtile is running, it logs error messages (and other messages) to its log  file.  This  is  found  at
       ~/.local/share/qtile/qtile.log.  This  is  the  first  place to check to see what is going on. If you are
       getting unexpected errors from normal usage or your configuration (and you're not doing something  wacky)
       and believe you have found a bug, then please report a bug.

       If  you  are  hacking  on Qtile and you want to debug your changes, this log is your best friend. You can
       send messages to the log from within libqtile by using the logger:

          from libqtile.log_utils import logger

          logger.warning("Your message here")
          logger.warning(variable_you_want_to_print)

          try:
              # some changes here that might error
          except Exception:
              logger.exception("Uh oh!")

       logger.warning is convenient because its messages will always be visibile in the log. logger.exception is
       helpful because it will print the full traceback of an error to the log. By sticking these  amongst  your
       changes you can look more closely at the effects of any changes you made to Qtile's internals.

   X11: Capturing an xtrace
       Occasionally,  a  bug  will  be low level enough to require an xtrace of Qtile's conversations with the X
       server. To capture one of these, create an xinitrc or similar file with:

          exec xtrace qtile >> ~/qtile.log

       This will put the xtrace output in Qtile's logfile as well. You can then demonstrate the bug,  and  paste
       the contents of this file into the bug report.

       Note that xtrace may be named x11trace on some platforms, for example, on Fedora and Arch.

   Debugging in Wayland
       To  get  incredibly  verbose  output  of  communications  between  clients  and  the  server, you can set
       WAYLAND_DEBUG=1 in the environment before starting the process. This applies to the server itself, so  be
       aware  that  running  qtile  with this set will generate lots of output for Qtile and all clients that it
       launches. If you're including this output with a bug report please try  to  cut  out  just  the  relevant
       portions.

       If you're hacking on Qtile and would like this debug log output for it rather than any clients, it can be
       helpful  to  run the helper script at scripts/wephyr in the source from an existing session. You can then
       run clients from another terminal using the WAYLAND_DISPLAY value printed by Qtile,  so  that  the  debug
       logs printed by Qtile are only the server's.

       If you suspect a client may be responsible for a bug, it can be helpful to look at the issue trackers for
       other  compositors, such as sway. Similarly if you're hacking on Qtile's internals and think you've found
       an unexpected quirk it may be helpful to search the issue tracker for wlroots.

ENTRY POINTS

       Qtile uses a subcommand structure;  various  subcommands  are  listed  below.   Additionally,  two  other
       commands available in the scripts/ section of the repository are also documented below.

   qtile start
       This  is  the entry point for the window manager, and what you should run from your .xsession or similar.
       This will make an attempt to detect if qtile is already running and fail if it is. See qtile start --help
       for more details.

   qtile shell
       The Qtile command shell is a command-line shell interface that provides access to the full complement  of
       Qtile  command  functions. The shell features command name completion, and full command documentation can
       be accessed from the shell itself. The shell uses GNU Readline when it's available, so the interface  can
       be  configured  to,  for  example,  obey  VI  keybindings  with an appropriate .inputrc file. See the GNU
       Readline documentation for more information.

   Navigating the Object Graph
       The shell presents a filesystem-like interface to the command graph - the builtin "cd" and "ls"  commands
       act like their familiar shell counterparts:

          > ls
          layout/  widget/  screen/  bar/     window/  group/

          > cd screen
          layout/  window/  bar/  widget/

          > cd ..
          /

          > ls
          layout/  widget/  screen/  bar/     window/  group/

       If you try to access an object that has no "default" value then you will see an error message:

          > ls
          layout/  widget/  screen/  bar/     window/  group/

          > cd bar
          Item required for bar

          > ls bar
          bar[bottom]/

          > cd bar/bottom
          bar['bottom']> ls
          screen/  widget/

       Please refer to Navigating the command graph for a summary of which objects need a specified selector and
       the type of selector required. Using ls will show which selectors are available for an object. Please see
       below for an explanation about how Qtile displays shell paths.

       Alternatively, the items() command can be run on the parent object to show which selectors are available.
       The  first  value  shows whether a selector is optional (False means that a selector is required) and the
       second value is a list of selectors:

          > ls
          layout/  widget/  screen/  bar/     window/  group/

          > items(bar)
          (False, ['bottom'])

   Displaying the shell path
       Note that the shell provides a "short-hand" for specifying  node  keys  (as  opposed  to  children).  The
       following is a valid shell path:

          > cd group/4/window/31457314

       The  command prompt will, however, always display the Python node path that should be used in scripts and
       key bindings:

          group['4'].window[31457314]>

   Live Documentation
       The shell help command provides the canonical documentation for the Qtile API:

          > cd layout/1

          layout[1]> help
          help command   -- Help for a specific command.

          Builtins
          ========
          cd    exit  help  ls    q     quit

          Commands for this object
          ========================
          add           commands      current       delete        doc
          down          get_info      items         next          previous
          rotate        shuffle_down  shuffle_up    toggle_split  up

          layout[1]> help previous
          previous()
          Focus previous stack.

   qtile migrate
       qtile migrate is a tool to help users update their configs to reflect any  breaking  changes/deprecations
       introduced in later versions.

       The  tool  can  automatically apply updates but it can also be used to highlight impacted lines, allowing
       users to update their configs manually.

       The tool can take a number of options when running:
             ┌────────────────────────────┬──────────────────────────────┬──────────────────────────────┐
             │ Argument                   │ Description                  │ Default                      │
             ├────────────────────────────┼──────────────────────────────┼──────────────────────────────┤
             │ -c, --config               │ Sets the path to the  config │ ~/.config/qtile/config.py    │
             │                            │ file                         │                              │
             ├────────────────────────────┼──────────────────────────────┼──────────────────────────────┤
             │ --list-migrations          │ Lists   all   the  available │ n/a                          │
             │                            │ migrations that can  be  run │                              │
             │                            │ by the tool.                 │                              │
             ├────────────────────────────┼──────────────────────────────┼──────────────────────────────┤
             │ --info ID                  │ Show  more  detail about the │ n/a                          │
             │                            │ migration implement by ID.   │                              │
             ├────────────────────────────┼──────────────────────────────┼──────────────────────────────┤
             │ --after-version VERSION    │ Only     runs     migrations │ Not   set   (i.e.  runs  all │
             │                            │ relating      to     changes │ migrations).                 │
             │                            │ implemented  after   release │                              │
             │                            │ VERSION.                     │                              │
             ├────────────────────────────┼──────────────────────────────┼──────────────────────────────┤
             │ -r ID, --run-migrations ID │ Run   selected    migrations │ Not   set   (i.e.  runs  all │
             │                            │ identified   by   ID.  Comma │ migrations).                 │
             │                            │ separated  list   if   using │                              │
             │                            │ multiple values.             │                              │
             ├────────────────────────────┼──────────────────────────────┼──────────────────────────────┤
             │ --yes                      │ Automatically apply  changes │ Not  set  (i.e.  users  will │
             │                            │ without   asking   user  for │ need  to confirm application │
             │                            │ confirmation.                │ of changes).                 │
             ├────────────────────────────┼──────────────────────────────┼──────────────────────────────┤
             │ --show-diff                │ When used  with  --yes  will │ Not set.                     │
             │                            │ cause   diffs  to  still  be │                              │
             │                            │ shown    for     information │                              │
             │                            │ purposes only.               │                              │
             ├────────────────────────────┼──────────────────────────────┼──────────────────────────────┤
             │ --no-colour                │ Disables  colour  output for │ Not set                      │
             │                            │ diff.                        │                              │
             ├────────────────────────────┼──────────────────────────────┼──────────────────────────────┤
             │ --lint                     │ Outputs    linting     lines │ Not set.                     │
             │                            │ showing location of changes. │                              │
             │                            │ No  changes  are made to the │                              │
             │                            │ config.                      │                              │
             └────────────────────────────┴──────────────────────────────┴──────────────────────────────┘

   Available migrations
       The following migrations are currently available.

   Running migrations
       Assuming your config file is in the default location, running qtile migrate is sufficient  to  start  the
       migration process.

       Let's say you had a config file with the following contents:

          import libqtile.command_client

          keys = [
              KeyChord(
                  [mod],
                  "x",
                  [Key([], "Up", lazy.layout.grow()), Key([], "Down", lazy.layout.shrink())],
                  mode="Resize layout",
              )
          ]

          qtile.cmd_spawn("alacritty")

       Running qtile migrate will run each available migration and, where the migration would result in changes,
       a diff will be shown and you will be asked whether you wish to apply the changes.

          UpdateKeychordArgs: Updates ``KeyChord`` argument signature.

          --- original
          +++ modified
          @@ -5,7 +5,8 @@

                  [mod],
                  "x",
                  [Key([], "Up", lazy.layout.grow()), Key([], "Down", lazy.layout.shrink())],
          -        mode="Resize layout",
          +        name="Resize layout",
          +    mode=True,
              )
          ]

          Apply changes? (y)es, (n)o, (s)kip file, (q)uit.

       You  will  see  from  the output above that you are shown the name of the migration being applied and its
       purpose, along with the changes that will be implemented.

       If you select quit the migration will be stopped and any applied changes will be reversed.

       Once all migrations have been run on a file, you will then be asked whether you want to save  changes  to
       the file:

          Save all changes to config.py? (y)es, (n)o.

       At  the  end  of  the  migration, backups of your original config will still be in your config folder. NB
       these will be overwritten if you re-run qtile migrate.

   Linting
       If you don't want the script to modify your config directly, you can use the --lint option  to  show  you
       where changes are required.

       Running qtile migrate --lint on the same config as shown above will result in the following output:

          config.py:
          [Ln 1, Col 7]: The 'libqtile.command_*' modules have been moved to 'libqtile.command.*'. (ModuleRenames)
          [Ln 8, Col 8]: The use of mode='mode name' for KeyChord is deprecated. Use mode=True and value='mode name'. (UpdateKeychordArgs)
          [Ln 12, Col 6]: Use of 'cmd_' prefix is deprecated. 'cmd_spawn' should be replaced with 'spawn' (RemoveCmdPrefix)

   Explanations of migrations
       The table below provides more detail of the available migrations.

   qtile cmd-obj
       This  is a simple tool to expose qtile.command functionality to shell.  This can be used standalone or in
       other shell scripts.

   How it works
       qtile cmd-obj works by selecting a command object and calling a specified function of that object.

       As per Architecture, Qtile's command graph has seven nodes: layout, window, group, bar,  widget,  screen,
       and a special root node. These are the objects that can be accessed via qtile cmd-obj.

       Running  the command against a selected object without a function (-f) will run the help command and list
       the commands available to the object. Commands shown with an  asterisk  ("*")  require  arguments  to  be
       passed via the -a flag.

   Selecting an object
       With the exception of cmd, all objects need an identifier so the correct object can be selected. Refer to
       Navigating the command graph for more information.

       NOTE:
          You  will  see from the graph on Architecture that certain objects can be accessed from other objects.
          For example, qtile cmd-obj -o group term layout will list the commands for the current layout  on  the
          term group.

   Information on functions
       Running a function with the -i flag will provide additional detail about that function (i.e. what it does
       and what arguments it expects).

   Passing arguments to functions
       Arguments  can  be  passed  to  a function by using the -a flag. For example, to change the label for the
       group named "1" to "A", you would run qtile cmd-obj -o group 1 -f set_label -a A.

       WARNING:
          It is not currently possible to pass non-string arguments to functions via  qtile  cmd-obj.  Doing  so
          will result in an error.

   Examples:
   Output of qtile cmd-obj -h
          usage: qtile cmd-obj [-h] [--object OBJ_SPEC [OBJ_SPEC ...]]
                           [--function FUNCTION] [--args ARGS [ARGS ...]] [--info]

          Simple tool to expose qtile.command functionality to shell.

          optional arguments:
            -h, --help            show this help message and exit
            --object OBJ_SPEC [OBJ_SPEC ...], -o OBJ_SPEC [OBJ_SPEC ...]
                                  Specify path to object (space separated). If no
                                  --function flag display available commands.
            --function FUNCTION, -f FUNCTION
                                  Select function to execute.
            --args ARGS [ARGS ...], -a ARGS [ARGS ...]
                                  Set arguments supplied to function.
            --info, -i            With both --object and --function args prints
                                  documentation for function.

          Examples:
           qtile cmd-obj
           qtile cmd-obj -o root  # same as above, root node is default
           qtile cmd-obj -o root -f prev_layout -i
           qtile cmd-obj -o root -f prev_layout -a 3 # prev_layout on group 3
           qtile cmd-obj -o group 3 -f focus_back
           qtile cmd-obj -o widget textbox -f update -a "New text"
           qtile cmd-obj -f restart # restart qtile

   Output of qtile cmd-obj -o group 3
          -o group 3 -f commands            Returns a list of possible commands for this object
          -o group 3 -f doc               * Returns the documentation for a specified command name
          -o group 3 -f eval              * Evaluates code in the same context as this function
          -o group 3 -f focus_back          Focus the window that had focus before the current one got it.
          -o group 3 -f focus_by_name     * Focus the first window with the given name. Do nothing if the name is
          -o group 3 -f function          * Call a function with current object as argument
          -o group 3 -f info                Returns a dictionary of info for this group
          -o group 3 -f info_by_name      * Get the info for the first window with the given name without giving it
          -o group 3 -f items             * Returns a list of contained items for the specified name
          -o group 3 -f next_window         Focus the next window in group.
          -o group 3 -f prev_window         Focus the previous window in group.
          -o group 3 -f set_label         * Set the display name of current group to be used in GroupBox widget.
          -o group 3 -f setlayout
          -o group 3 -f switch_groups     * Switch position of current group with name
          -o group 3 -f toscreen          * Pull a group to a specified screen.
          -o group 3 -f unminimize_all      Unminimise all windows in this group

   Output of qtile cmd-obj -o root
          -o root -f add_rule              * Add a dgroup rule, returns rule_id needed to remove it
          -o root -f addgroup              * Add a group with the given name
          -o root -f commands                Returns a list of possible commands for this object
          -o root -f critical                Set log level to CRITICAL
          -o root -f debug                   Set log level to DEBUG
          -o root -f delgroup              * Delete a group with the given name
          -o root -f display_kb            * Display table of key bindings
          -o root -f doc                   * Returns the documentation for a specified command name
          -o root -f error                   Set log level to ERROR
          -o root -f eval                  * Evaluates code in the same context as this function
          -o root -f findwindow            * Launch prompt widget to find a window of the given name
          -o root -f focus_by_click        * Bring a window to the front
          -o root -f function              * Call a function with current object as argument
          -o root -f get_info                Prints info for all groups
          -o root -f get_state               Get pickled state for restarting qtile
          -o root -f get_test_data           Returns any content arbitrarily set in the self.test_data attribute.
          -o root -f groups                  Return a dictionary containing information for all groups
          -o root -f hide_show_bar         * Toggle visibility of a given bar
          -o root -f info                    Set log level to INFO
          -o root -f internal_windows        Return info for each internal window (bars, for example)
          -o root -f items                 * Returns a list of contained items for the specified name
          -o root -f list_widgets            List of all addressible widget names
          -o root -f next_layout           * Switch to the next layout.
          -o root -f next_screen             Move to next screen
          -o root -f next_urgent             Focus next window with urgent hint
          -o root -f pause                   Drops into pdb
          -o root -f prev_layout           * Switch to the previous layout.
          -o root -f prev_screen             Move to the previous screen
          -o root -f qtile_info              Returns a dictionary of info on the Qtile instance
          -o root -f qtilecmd              * Execute a Qtile command using the client syntax
          -o root -f remove_rule           * Remove a dgroup rule by rule_id
          -o root -f restart                 Restart qtile
          -o root -f run_extension         * Run extensions
          -o root -f run_external          * Run external Python script
          -o root -f screens                 Return a list of dictionaries providing information on all screens
          -o root -f shutdown                Quit Qtile
          -o root -f simulate_keypress     * Simulates a keypress on the focused window.
          -o root -f spawn                 * Run cmd in a shell.
          -o root -f spawncmd              * Spawn a command using a prompt widget, with tab-completion.
          -o root -f status                  Return "OK" if Qtile is running
          -o root -f switch_groups         * Switch position of groupa to groupb
          -o root -f switchgroup           * Launch prompt widget to switch to a given group to the current screen
          -o root -f sync                    Sync the X display. Should only be used for development
          -o root -f to_layout_index       * Switch to the layout with the given index in self.layouts.
          -o root -f to_screen             * Warp focus to screen n, where n is a 0-based screen number
          -o root -f togroup               * Launch prompt widget to move current window to a given group
          -o root -f tracemalloc_dump        Dump tracemalloc snapshot
          -o root -f tracemalloc_toggle      Toggle tracemalloc status
          -o root -f warning                 Set log level to WARNING
          -o root -f windows                 Return info for each client window

   qtile run-cmd
       Run  a command applying rules to the new windows, ie, you can start a window in a specific group, make it
       floating, intrusive, etc.

       The Windows must have NET_WM_PID.

          # run xterm floating on group "test-group"
          qtile run-cmd -g test-group -f xterm

   qtile top
       qtile top is a top-like tool to measure memory usage of Qtile's internals.

       NOTE:
          To use qtile shell you need to have tracemalloc enabled. You can do this by setting the  environmental
          variable  PYTHONTRACEMALLOC=1  before  starting qtile.  Alternatively, you can force start tracemalloc
          but you will lose early traces:

              >>> from libqtile.command.client import InteractiveCommandClient
              >>> i=InteractiveCommandClient()
              >>> i.eval("import tracemalloc;tracemalloc.start()")

   dqtile-cmd
       A Rofi/dmenu interface to qtile-cmd. Accepts all arguments of qtile-cmd.

   Examples:
   Output of dqtile-cmd -o cmd
       [image]

   Output of dqtile-cmd -h
          dqtile-cmd

              A Rofi/dmenu interface to qtile-cmd. Excepts all arguments of qtile-cmd
              (see below).

          usage: dqtile-cmd [-h] [--object OBJ_SPEC [OBJ_SPEC ...]]
                            [--function FUNCTION] [--args ARGS [ARGS ...]] [--info]

          Simple tool to expose qtile.command functionality to shell.

          optional arguments:
            -h, --help            show this help message and exit
            --object OBJ_SPEC [OBJ_SPEC ...], -o OBJ_SPEC [OBJ_SPEC ...]
                                  Specify path to object (space separated). If no
                                  --function flag display available commands.
            --function FUNCTION, -f FUNCTION
                                  Select function to execute.
            --args ARGS [ARGS ...], -a ARGS [ARGS ...]
                                  Set arguments supplied to function.
            --info, -i            With both --object and --function args prints
                                  documentation for function.

          Examples:
           dqtile-cmd
           dqtile-cmd -o cmd
           dqtile-cmd -o cmd -f prev_layout -i
           dqtile-cmd -o cmd -f prev_layout -a 3 # prev_layout on group 3
           dqtile-cmd -o group 3 -f focus_back

          If both rofi and dmenu are present rofi will be selected as default, to change this us --force-dmenu as the first argument.

   iqshell
       In addition to the standard qtile shell shell interface, we provide a kernel capable of  running  through
       Jupyter that hooks into the qshell client.  The command structure and syntax is the same as qshell, so it
       is recommended you read that for more information about that.

   Dependencies
       In  order  to run iqshell, you must have ipykernel and jupyter_console.  You can install the dependencies
       when you are installing qtile by running:

          $ pip install qtile[ipython]

       Otherwise, you can just install these two packages  separately,  either  through  PyPI  or  through  your
       distribution package manager.

   Installing and Running the Kernel
       Once you have the required dependencies, you can run the kernel right away by running:

          $ python3 -m libqtile.interactive.iqshell_kernel

       However, this will merely spawn a kernel instance, you will have to run a separate frontend that connects
       to this kernel.

       A  more  convenient  way  to  run  the kernel is by registering the kernel with Jupyter.  To register the
       kernel itself, run:

          $ python3 -m libqtile.interactive.iqshell_install

       If you run this as a non-root user, or pass the --user flag, this will install to the user Jupyter kernel
       directory.  You can now invoke the kernel directly when starting a Jupyter frontend, for example:

          $ jupyter console --kernel qshell

       The iqshell script will launch a Jupyter terminal console with the qshell kernel.

   iqshell vs qtile shell
       One of the main drawbacks of running through a Jupyter kernel is the frontend has no  way  to  query  the
       current  node of the kernel, and as such, there is no way to set a custom prompt.  In order to query your
       current node, you can call pwd.

       This, however, enables many of the benefits of running in a Jupyter frontend,  including  being  able  to
       save, run, and re-run code cells in frontends such as the Jupyter notebook.

       The  Jupyter  kernel  also  enables  more  advanced help, text completion, and introspection capabilities
       (however, these are currently not implemented at a level much beyond what is available  in  the  standard
       qtile shell).

DEFAULT CONFIG FILE

       The  below  default config file is included with the Qtile package and will be copied to your home config
       folder (~/.config/qtile/config.py) if no config file exists when you start Qtile for the first time.

          # Copyright (c) 2010 Aldo Cortesi
          # Copyright (c) 2010, 2014 dequis
          # Copyright (c) 2012 Randall Ma
          # Copyright (c) 2012-2014 Tycho Andersen
          # Copyright (c) 2012 Craig Barnes
          # Copyright (c) 2013 horsik
          # Copyright (c) 2013 Tao Sauvage
          #
          # Permission is hereby granted, free of charge, to any person obtaining a copy
          # of this software and associated documentation files (the "Software"), to deal
          # in the Software without restriction, including without limitation the rights
          # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
          # copies of the Software, and to permit persons to whom the Software is
          # furnished to do so, subject to the following conditions:
          #
          # The above copyright notice and this permission notice shall be included in
          # all copies or substantial portions of the Software.
          #
          # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
          # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
          # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
          # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
          # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
          # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
          # SOFTWARE.

          from libqtile import bar, layout, qtile, widget
          from libqtile.config import Click, Drag, Group, Key, Match, Screen
          from libqtile.lazy import lazy
          from libqtile.utils import guess_terminal

          mod = "mod4"
          terminal = guess_terminal()

          keys = [
              # A list of available commands that can be bound to keys can be found
              # at https://docs.qtile.org/en/latest/manual/config/lazy.html
              # Switch between windows
              Key([mod], "h", lazy.layout.left(), desc="Move focus to left"),
              Key([mod], "l", lazy.layout.right(), desc="Move focus to right"),
              Key([mod], "j", lazy.layout.down(), desc="Move focus down"),
              Key([mod], "k", lazy.layout.up(), desc="Move focus up"),
              Key([mod], "space", lazy.layout.next(), desc="Move window focus to other window"),
              # Move windows between left/right columns or move up/down in current stack.
              # Moving out of range in Columns layout will create new column.
              Key([mod, "shift"], "h", lazy.layout.shuffle_left(), desc="Move window to the left"),
              Key([mod, "shift"], "l", lazy.layout.shuffle_right(), desc="Move window to the right"),
              Key([mod, "shift"], "j", lazy.layout.shuffle_down(), desc="Move window down"),
              Key([mod, "shift"], "k", lazy.layout.shuffle_up(), desc="Move window up"),
              # Grow windows. If current window is on the edge of screen and direction
              # will be to screen edge - window would shrink.
              Key([mod, "control"], "h", lazy.layout.grow_left(), desc="Grow window to the left"),
              Key([mod, "control"], "l", lazy.layout.grow_right(), desc="Grow window to the right"),
              Key([mod, "control"], "j", lazy.layout.grow_down(), desc="Grow window down"),
              Key([mod, "control"], "k", lazy.layout.grow_up(), desc="Grow window up"),
              Key([mod], "n", lazy.layout.normalize(), desc="Reset all window sizes"),
              # Toggle between split and unsplit sides of stack.
              # Split = all windows displayed
              # Unsplit = 1 window displayed, like Max layout, but still with
              # multiple stack panes
              Key(
                  [mod, "shift"],
                  "Return",
                  lazy.layout.toggle_split(),
                  desc="Toggle between split and unsplit sides of stack",
              ),
              Key([mod], "Return", lazy.spawn(terminal), desc="Launch terminal"),
              # Toggle between different layouts as defined below
              Key([mod], "Tab", lazy.next_layout(), desc="Toggle between layouts"),
              Key([mod], "w", lazy.window.kill(), desc="Kill focused window"),
              Key(
                  [mod],
                  "f",
                  lazy.window.toggle_fullscreen(),
                  desc="Toggle fullscreen on the focused window",
              ),
              Key([mod], "t", lazy.window.toggle_floating(), desc="Toggle floating on the focused window"),
              Key([mod, "control"], "r", lazy.reload_config(), desc="Reload the config"),
              Key([mod, "control"], "q", lazy.shutdown(), desc="Shutdown Qtile"),
              Key([mod], "r", lazy.spawncmd(), desc="Spawn a command using a prompt widget"),
          ]

          # Add key bindings to switch VTs in Wayland.
          # We can't check qtile.core.name in default config as it is loaded before qtile is started
          # We therefore defer the check until the key binding is run by using .when(func=...)
          for vt in range(1, 8):
              keys.append(
                  Key(
                      ["control", "mod1"],
                      f"f{vt}",
                      lazy.core.change_vt(vt).when(func=lambda: qtile.core.name == "wayland"),
                      desc=f"Switch to VT{vt}",
                  )
              )

          groups = [Group(i) for i in "123456789"]

          for i in groups:
              keys.extend(
                  [
                      # mod + group number = switch to group
                      Key(
                          [mod],
                          i.name,
                          lazy.group[i.name].toscreen(),
                          desc=f"Switch to group {i.name}",
                      ),
                      # mod + shift + group number = switch to & move focused window to group
                      Key(
                          [mod, "shift"],
                          i.name,
                          lazy.window.togroup(i.name, switch_group=True),
                          desc=f"Switch to & move focused window to group {i.name}",
                      ),
                      # Or, use below if you prefer not to switch to that group.
                      # # mod + shift + group number = move focused window to group
                      # Key([mod, "shift"], i.name, lazy.window.togroup(i.name),
                      #     desc="move focused window to group {}".format(i.name)),
                  ]
              )

          layouts = [
              layout.Columns(border_focus_stack=["#d75f5f", "#8f3d3d"], border_width=4),
              layout.Max(),
              # Try more layouts by unleashing below layouts.
              # layout.Stack(num_stacks=2),
              # layout.Bsp(),
              # layout.Matrix(),
              # layout.MonadTall(),
              # layout.MonadWide(),
              # layout.RatioTile(),
              # layout.Tile(),
              # layout.TreeTab(),
              # layout.VerticalTile(),
              # layout.Zoomy(),
          ]

          widget_defaults = dict(
              font="sans",
              fontsize=12,
              padding=3,
          )
          extension_defaults = widget_defaults.copy()

          screens = [
              Screen(
                  bottom=bar.Bar(
                      [
                          widget.CurrentLayout(),
                          widget.GroupBox(),
                          widget.Prompt(),
                          widget.WindowName(),
                          widget.Chord(
                              chords_colors={
                                  "launch": ("#ff0000", "#ffffff"),
                              },
                              name_transform=lambda name: name.upper(),
                          ),
                          widget.TextBox("default config", name="default"),
                          widget.TextBox("Press &lt;M-r&gt; to spawn", foreground="#d75f5f"),
                          # NB Systray is incompatible with Wayland, consider using StatusNotifier instead
                          # widget.StatusNotifier(),
                          widget.Systray(),
                          widget.Clock(format="%Y-%m-%d %a %I:%M %p"),
                          widget.QuickExit(),
                      ],
                      24,
                      # border_width=[2, 0, 2, 0],  # Draw top and bottom borders
                      # border_color=["ff00ff", "000000", "ff00ff", "000000"]  # Borders are magenta
                  ),
                  # You can uncomment this variable if you see that on X11 floating resize/moving is laggy
                  # By default we handle these events delayed to already improve performance, however your system might still be struggling
                  # This variable is set to None (no cap) by default, but you can set it to 60 to indicate that you limit it to 60 events per second
                  # x11_drag_polling_rate = 60,
              ),
          ]

          # Drag floating layouts.
          mouse = [
              Drag([mod], "Button1", lazy.window.set_position_floating(), start=lazy.window.get_position()),
              Drag([mod], "Button3", lazy.window.set_size_floating(), start=lazy.window.get_size()),
              Click([mod], "Button2", lazy.window.bring_to_front()),
          ]

          dgroups_key_binder = None
          dgroups_app_rules = []  # type: list
          follow_mouse_focus = True
          bring_front_click = False
          floats_kept_above = True
          cursor_warp = False
          floating_layout = layout.Floating(
              float_rules=[
                  # Run the utility of `xprop` to see the wm class and name of an X client.
                  *layout.Floating.default_float_rules,
                  Match(wm_class="confirmreset"),  # gitk
                  Match(wm_class="makebranch"),  # gitk
                  Match(wm_class="maketag"),  # gitk
                  Match(wm_class="ssh-askpass"),  # ssh-askpass
                  Match(title="branchdialog"),  # gitk
                  Match(title="pinentry"),  # GPG key password entry
              ]
          )
          auto_fullscreen = True
          focus_on_window_activation = "smart"
          reconfigure_screens = True

          # If things like steam games want to auto-minimize themselves when losing
          # focus, should we respect this or not?
          auto_minimize = True

          # When using the Wayland backend, this can be used to configure input devices.
          wl_input_rules = None

          # xcursor theme (string or None) and size (integer) for Wayland backend
          wl_xcursor_theme = None
          wl_xcursor_size = 24

          # XXX: Gasp! We're lying here. In fact, nobody really uses or cares about this
          # string besides java UI toolkits; you can see several discussions on the
          # mailing lists, GitHub issues, and other WM documentation that suggest setting
          # this string if your java app doesn't work correctly. We may as well just lie
          # and say that we're a working one by default.
          #
          # We choose LG3D to maximize irony: it is a 3D non-reparenting WM written in
          # java that happens to be on java's whitelist.
          wmname = "LG3D"

THE CONFIG FILE

       Qtile is configured in Python. A script (~/.config/qtile/config.py by default) is evaluated, and a  small
       set of configuration variables are pulled from its global namespace.

   Configuration lookup order
       Qtile looks in the following places for a configuration file, in order:

       • The location specified by the -c argument.

       • $XDG_CONFIG_HOME/qtile/config.py, if it is set

       • ~/.config/qtile/config.py

       • first qtile/config.py found in $XDG_CONFIG_DIRS (defaults to /etc/xdg)

       • It   reads   the  module  libqtile.resources.default_config,  included  by  default  with  every  Qtile
         installation.

       Qtile will try to create the configuration file as a copy of the default config, if it doesn't exist yet,
       this one will be placed inside of $XDG_CONFIG_HOME/qtile/config.py (if set) or ~/.config/qtile/config.py.

   Default Configuration
       The default configuration is invoked when qtile cannot find a configuration file. In addition,  if  qtile
       is  restarted  or the config is reloaded, qtile will load the default configuration if the config file it
       finds has some kind of error in it. The documentation below describes the configuration  lookup  process,
       as well as what the key bindings are in the default config.

       The  default  config  is  not intended to be suitable for all users; it's mostly just there so qtile does
       /something/ when fired up, and so that it doesn't crash and cause you to lose all your work if you reload
       a bad config.

   Configuration variables
       A Qtile configuration consists of a file with a bunch of variables in it, which qtile  imports  and  then
       runs  as  a  Python  file  to derive its final configuration.  The documentation below describes the most
       common  configuration  variables;  more  advanced  configuration  can  be  found  in  the  qtile-examples
       repository,  which includes a number of real-world configurations that demonstrate how you can tune Qtile
       to your liking. (Feel free to issue a pull request to add your own configuration to the mix!)

   Lazy objects
       Lazy objects are a way of executing any of the commands available in Qtile's commands API.

       The name "lazy" refers to the fact that the commands are not executed at the time of the  call.  Instead,
       the  lazy  object creates a reference to the relevant command and this is only executed when the relevant
       event is triggered (e.g. on a keypress).

       Typically, for config files, the commands are used to manipulate windows,  layouts  and  groups  as  well
       application commands like exiting, restarting, reloading the config file etc.

   Example
          from libqtile.config import Key
          from libqtile.lazy import lazy

          keys = [
              Key(
                  ["mod1"], "k",
                  lazy.layout.down()
              ),
              Key(
                  ["mod1"], "j",
                  lazy.layout.up()
              )
          ]

       NOTE:
          As  noted  above, lazy calls do not call the relevant command but only create a reference to it. While
          this makes it ideal for binding commands to key presses and mouse_callbacks for widgets, it also means
          that lazy calls cannot be included in user-defined functions.

   Lazy functions
       This is overview of the commonly used functions for the key bindings.  These functions can be called from
       commands on the REPLACE object or on another object in the command tree.

       Some examples are given below. For a complete list of available commands, please refer to Commands API.

   General functions
                        ┌───────────────────────────┬───────────────────────────────────────┐
                        │ function                  │ description                           │
                        ├───────────────────────────┼───────────────────────────────────────┤
                        │ lazy.spawn("application") │ Run the application                   │
                        ├───────────────────────────┼───────────────────────────────────────┤
                        │ lazy.spawncmd()           │ Open command prompt on the  bar.  See │
                        │                           │ prompt widget.                        │
                        ├───────────────────────────┼───────────────────────────────────────┤
                        │ lazy.reload_config()      │ Reload the config.                    │
                        ├───────────────────────────┼───────────────────────────────────────┤
                        │ lazy.restart()            │ Restart Qtile. In X11, it won't close │
                        │                           │ your windows.                         │
                        ├───────────────────────────┼───────────────────────────────────────┤
                        │ lazy.shutdown()           │ Close the whole Qtile                 │
                        └───────────────────────────┴───────────────────────────────────────┘

   Group functions
                   ┌─────────────────────────────────────┬───────────────────────────────────────┐
                   │ function                            │ description                           │
                   ├─────────────────────────────────────┼───────────────────────────────────────┤
                   │ lazy.next_layout()                  │ Use next layout on the actual group   │
                   ├─────────────────────────────────────┼───────────────────────────────────────┤
                   │ lazy.prev_layout()                  │ Use  previous  layout  on  the actual │
                   │                                     │ group                                 │
                   ├─────────────────────────────────────┼───────────────────────────────────────┤
                   │ lazy.screen.next_group()            │ Move to the group on the right        │
                   ├─────────────────────────────────────┼───────────────────────────────────────┤
                   │ lazy.screen.prev_group()            │ Move to the group on the left         │
                   ├─────────────────────────────────────┼───────────────────────────────────────┤
                   │ lazy.screen.toggle_group()          │ Move to the last visited group        │
                   ├─────────────────────────────────────┼───────────────────────────────────────┤
                   │ lazy.group.next_window()            │ Switch window focus to next window in │
                   │                                     │ group                                 │
                   ├─────────────────────────────────────┼───────────────────────────────────────┤
                   │ lazy.group.prev_window()            │ Switch  window  focus   to   previous │
                   │                                     │ window in group                       │
                   ├─────────────────────────────────────┼───────────────────────────────────────┤
                   │ lazy.group["group_name"].toscreen() │ Move  to the group called group_name. │
                   │                                     │ Takes an  optional  toggle  parameter │
                   │                                     │ (defaults  to  False).  If this group │
                   │                                     │ is already on  the  screen,  it  does │
                   │                                     │ nothing  by  default;  to toggle with │
                   │                                     │ the  last  used  group  instead,  use │
                   │                                     │ toggle=True.                          │
                   ├─────────────────────────────────────┼───────────────────────────────────────┤
                   │ lazy.layout.increase_ratio()        │ Increase  the space for master window │
                   │                                     │ at the expense of slave windows       │
                   ├─────────────────────────────────────┼───────────────────────────────────────┤
                   │ lazy.layout.decrease_ratio()        │ Decrease the space for master  window │
                   │                                     │ in the advantage of slave windows     │
                   └─────────────────────────────────────┴───────────────────────────────────────┘

   Window functions
                    ┌───────────────────────────────────┬───────────────────────────────────────┐
                    │ function                          │ description                           │
                    ├───────────────────────────────────┼───────────────────────────────────────┤
                    │ lazy.window.kill()                │ Close the focused window              │
                    ├───────────────────────────────────┼───────────────────────────────────────┤
                    │ lazy.layout.next()                │ Switch  window focus to other pane(s) │
                    │                                   │ of stack                              │
                    ├───────────────────────────────────┼───────────────────────────────────────┤
                    │ lazy.window.togroup("group_name") │ Move  focused  window  to  the  group │
                    │                                   │ called group_name                     │
                    ├───────────────────────────────────┼───────────────────────────────────────┤
                    │ lazy.window.toggle_floating()     │ Put   the   focused   window  to/from │
                    │                                   │ floating mode                         │
                    ├───────────────────────────────────┼───────────────────────────────────────┤
                    │ lazy.window.toggle_fullscreen()   │ Put  the   focused   window   to/from │
                    │                                   │ fullscreen mode                       │
                    ├───────────────────────────────────┼───────────────────────────────────────┤
                    │ lazy.window.move_up()             │ Move the window above the next window │
                    │                                   │ in the stack.                         │
                    ├───────────────────────────────────┼───────────────────────────────────────┤
                    │ lazy.window.move_down()           │ Move  the  window  below the previous │
                    │                                   │ window in the stack.                  │
                    ├───────────────────────────────────┼───────────────────────────────────────┤
                    │ lazy.window.move_to_top()         │ Move  the  window  above  all   other │
                    │                                   │ windows with similar priority (i.e. a │
                    │                                   │ "normal"  window  will  not  be moved │
                    │                                   │ above a kept_above window).           │
                    ├───────────────────────────────────┼───────────────────────────────────────┤
                    │ lazy.window.move_to_bottom()      │ Move  the  window  below  all   other │
                    │                                   │ windows with similar priority (i.e. a │
                    │                                   │ "normal"  window  will  not  be moved │
                    │                                   │ below a kept_below window).           │
                    ├───────────────────────────────────┼───────────────────────────────────────┤
                    │ lazy.window.keep_above()          │ Keep window above other windows.      │
                    ├───────────────────────────────────┼───────────────────────────────────────┤
                    │ lazy.window.keep_below()          │ Keep window below other windows.      │
                    ├───────────────────────────────────┼───────────────────────────────────────┤
                    │ lazy.window.bring_to_front()      │ Bring window above all other windows. │
                    │                                   │ Ignores kept_above priority.          │
                    └───────────────────────────────────┴───────────────────────────────────────┘

   Screen functions
                     ┌─────────────────────────────────┬───────────────────────────────────────┐
                     │ function                        │ description                           │
                     ├─────────────────────────────────┼───────────────────────────────────────┤
                     │ lazy.screen.set_wallpaper(path, │ Set the wallpaper to the  specificied │
                     │ mode=None)                      │ image.   Possible   modes:   None  no │
                     │                                 │ resizing, 'fill' centre and resize to │
                     │                                 │ fill  screen,  'stretch'  stretch  to │
                     │                                 │ fill screen.                          │
                     └─────────────────────────────────┴───────────────────────────────────────┘

   ScratchPad DropDown functions
          ┌───────────────────────────────────────────────────────┬───────────────────────────────────────┐
          │ function                                              │ description                           │
          ├───────────────────────────────────────────────────────┼───────────────────────────────────────┤
          │ lazy.group["group_name"].dropdown_toggle("name")      │ Toggles   the   visibility   of   the │
          │                                                       │ specified DropDown window.  On  first │
          │                                                       │ use,   the   configured   process  is │
          │                                                       │ spawned.                              │
          ├───────────────────────────────────────────────────────┼───────────────────────────────────────┤
          │ lazy.group["group_name"].hide_all()                   │ Hides all DropDown windows.           │
          ├───────────────────────────────────────────────────────┼───────────────────────────────────────┤
          │ lazy.group["group_name"].dropdown_reconfigure("name", │ Update the configuration of the named │
          │ **configuration)                                      │ DropDown.                             │
          └───────────────────────────────────────────────────────┴───────────────────────────────────────┘

   User-defined functions
                   ┌──────────────────────────────────────┬───────────────────────────────────────┐
                   │ function                             │ description                           │
                   ├──────────────────────────────────────┼───────────────────────────────────────┤
                   │ lazy.function(func, *args, **kwargs) │ Calls func(qtile,  *args,  **kwargs). │
                   │                                      │ NB. the qtile object is automatically │
                   │                                      │ passed as the first argument.         │
                   └──────────────────────────────────────┴───────────────────────────────────────┘

   Examples
       lazy.function can also be used as a decorator for functions.

          from libqtile.config import Key
          from libqtile.lazy import lazy

          @lazy.function
          def my_function(qtile):
              ...

          keys = [
              Key(
                  ["mod1"], "k",
                  my_function
              )
          ]

       Additionally, you can pass arguments to user-defined function in one of two ways:

       1. In-line definition

       Arguments can be added to the lazy.function call.

          from libqtile.config import Key
          from libqtile.lazy import lazy
          from libqtile.log_utils import logger

          def multiply(qtile, value, multiplier=10):
              logger.warning(f"Multiplication results: {value * multiplier}")

          keys = [
              Key(
                  ["mod1"], "k",
                  lazy.function(multiply, 10, multiplier=2)
              )
          ]

       2. Decorator

       Arguments can also be passed to the decorated function.

          from libqtile.config import Key
          from libqtile.lazy import lazy
          from libqtile.log_utils import logger

          @lazy.function
          def multiply(qtile, value, multiplier=10):
              logger.warning(f"Multiplication results: {value * multiplier}")

          keys = [
              Key(
                  ["mod1"], "k",
                  multiply(10, multiplier=2)
              )
          ]

   Groups
       A  group  is  a  container for a bunch of windows, analogous to workspaces in other window managers. Each
       client window managed by the window manager belongs to exactly one group. The groups config file variable
       should be initialized to a list of Group objects.

       Group objects provide several options for group configuration. Groups can be configured to show and  hide
       themselves  when  they're  not  empty, spawn applications for them when they start, automatically acquire
       certain groups, and various other options.

   Example
          from libqtile.config import Group, Match

          groups = [
              Group("a"),
              Group("b"),
              Group("c", matches=[Match(wm_class="Firefox")]),
          ]

          # allow mod3+1 through mod3+0 to bind to groups; if you bind your groups
          # by hand in your config, you don't need to do this.
          from libqtile.dgroups import simple_key_binder

          dgroups_key_binder = simple_key_binder("mod3")

   Reference
   Group Matching
   ScratchPad and DropDown
       ScratchPad is a special -  by  default  invisible  -  group  which  acts  as  a  container  for  DropDown
       configurations.  A  DropDown can be configured to spawn a defined process and bind that's process' window
       to it. The associated window can then be shown and hidden by the lazy command dropdown_toggle() (see Lazy
       objects) from the ScratchPad group.  Thus - for example - your favorite terminal emulator  turns  into  a
       quake-like terminal by the control of Qtile.

       If  the  DropDown  window turns visible it is placed as a floating window on top of the current group. If
       the DropDown is hidden, it is simply switched back to the ScratchPad group.

   Example
          from libqtile.config import Group, ScratchPad, DropDown, Key
          from libqtile.lazy import lazy

          groups = [
              ScratchPad("scratchpad", [
                  # define a drop down terminal.
                  # it is placed in the upper third of screen by default.
                  DropDown("term", "urxvt", opacity=0.8),

                  # define another terminal exclusively for ``qtile shell` at different position
                  DropDown("qtile shell", "urxvt -hold -e 'qtile shell'",
                           x=0.05, y=0.4, width=0.9, height=0.6, opacity=0.9,
                           on_focus_lost_hide=True) ]),
              Group("a"),
          ]

          keys = [
            # toggle visibiliy of above defined DropDown named "term"
            Key([], 'F11', lazy.group['scratchpad'].dropdown_toggle('term')),
            Key([], 'F12', lazy.group['scratchpad'].dropdown_toggle('qtile shell')),
          ]

       Note that if the window is set to not floating, it is detached from DropDown and ScratchPad,  and  a  new
       process is spawned next time the DropDown is set visible.

       Some  programs  run in a server-like mode where the spawned process does not directly own the window that
       is created, which is instead created by a background process.  In  this  case,  the  window  may  not  be
       correctly  caught  in  the  scratchpad  group.  To  work  around this, you can pass a Match object to the
       corresponding DropDown. See below.

   Reference
   Keys
       The keys variable defines Qtile's key bindings.

   Default Key Bindings
       The mod key for the default config is mod4, which is typically bound  to  the  "Super"  keys,  which  are
       things like the windows key and the mac command key. The basic operation is:

       • mod + k or mod + j: switch windows on the current stack

       • mod + <space>: put focus on the other pane of the stack (when in stack layout)

       • mod + <tab>: switch layouts

       • mod + w: close window

       • mod + <ctrl> + r: reload the config

       • mod + <group name>: switch to that group

       • mod + <shift> + <group name>: send a window to that group

       • mod + <enter>: start terminal guessed by libqtile.utils.guess_terminalmod + r: start a little prompt in the bar so users can run arbitrary commands

       The  default  config  defines  one  screen  and 8 groups, one for each letter in asdfuiop. It has a basic
       bottom bar that includes a group box, the current window name, a little text reminder that  you're  using
       the default config, a system tray, and a clock.

       The  default configuration has several more advanced key combinations, but the above should be enough for
       basic usage of qtile.

       See Keybindings in images for visual keybindings in keyboard layout.

   Defining key bindings
       Individual key bindings are defined with Key as demonstrated in the following example. Note that you  may
       specify more than one callback functions.

          from libqtile.config import Key

          keys = [
             # Pressing "Meta + Shift + a".
             Key(["mod4", "shift"], "a", callback, ...),

             # Pressing "Control + p".
             Key(["control"], "p", callback, ...),

             # Pressing "Meta + Tab".
             Key(["mod4", "mod1"], "Tab", callback, ...),
          ]

       The  above  may  also  be  written  more concisely with the help of the EzKey helper class. The following
       example is functionally equivalent to the above:

          from libqtile.config import EzKey as Key

          keys = [
             Key("M-S-a", callback, ...),
             Key("C-p",   callback, ...),
             Key("M-A-<Tab>", callback, ...),
          ]

       The EzKey modifier keys (i.e. MASC) can be overwritten through the  EzKey.modifier_keys  dictionary.  The
       defaults are:

          modifier_keys = {
             'M': 'mod4',
             'A': 'mod1',
             'S': 'shift',
             'C': 'control',
          }

       Callbacks  can  also  be  configured  to  work  only under certain conditions by using the when() method.
       Currently, the following conditions are supported:

          from libqtile.config import Key

          keys = [
              # Only trigger callback for a specific layout
              Key(
                  [mod, 'shift'],
                  "j",
                  lazy.layout.grow().when(layout='verticaltile'),
                  lazy.layout.grow_down().when(layout='columns')
              ),

              # Limit action to when the current window is not floating
              Key([mod], "f", lazy.window.toggle_fullscreen().when(when_floating=False))

              # Limit action to when the current window is floating
              Key([mod], "f", lazy.window.toggle_fullscreen().when(when_floating=True))

              # Also matches are supported on the current window
              # For example to match on the wm_class for fullscreen do the following
              Key([mod], "f", lazy.window.toggle_fullscreen().when(focused=Match(wm_class="yourclasshere"))
          ]

   KeyChords
       Qtile also allows sequences of keys to trigger callbacks. These sequences are known  as  chords  and  are
       defined with KeyChord. Chords are added to the keys section of the config file.

          from libqtile.config import Key, KeyChord

          keys = [
              KeyChord([mod], "z", [
                  Key([], "x", lazy.spawn("xterm"))
              ])
          ]

       The above code will launch xterm when the user presses Mod + z, followed by x.

       WARNING:
          Users  should note that key chords are aborted by pressing <escape>. In the above example, if the user
          presses Mod + z, any following key presses will still be sent to the  currently  focussed  window.  If
          <escape> has not been pressed, the next press of x will launch xterm.

   Modes
       Chords  can optionally persist until a user presses <escape>. This can be done by setting mode=True. This
       can be useful for configuring a subset of commands for a  particular  situations  (i.e.  similar  to  vim
       modes).

          from libqtile.config import Key, KeyChord

          keys = [
              KeyChord([mod], "z", [
                  Key([], "g", lazy.layout.grow()),
                  Key([], "s", lazy.layout.shrink()),
                  Key([], "n", lazy.layout.normalize()),
                  Key([], "m", lazy.layout.maximize())],
                  mode=True,
                  name="Windows"
              )
          ]

       In the above example, pressing Mod + z triggers the "Windows" mode. Users can then resize windows by just
       pressing  g  (to  grow  the window), s to shrink it etc. as many times as needed. To exit the mode, press
       <escape>.

       NOTE:
          The Chord widget (Chord) will display the name of the active chord (as set  by  the  name  parameter).
          This  is  particularly  useful  where  the  chord  is a persistent mode as this will indicate when the
          chord's mode is still active.

   Chains
       Chords can also be chained to make even longer sequences.

          from libqtile.config import Key, KeyChord

          keys = [
              KeyChord([mod], "z", [
                  KeyChord([], "x", [
                      Key([], "c", lazy.spawn("xterm"))
                  ])
              ])
          ]

       Modes can also be added to chains if required. The following  example  demonstrates  the  behaviour  when
       using the mode argument in chains:

          from libqtile.config import Key, KeyChord

          keys = [
              KeyChord([mod], "z", [
                  KeyChord([], "y", [
                      KeyChord([], "x", [
                          Key([], "c", lazy.spawn("xterm"))
                      ], mode=True, name="inner")
                  ])
              ], mode=True, name="outer")
          ]

       After pressing Mod+z y x c, the "inner" mode will remain active. When pressing <escape>, the "inner" mode
       is  exited.  Since  the  mode in between does not have mode set, it is also left. Arriving at the "outer"
       mode (which has this argument set) stops the "leave" action and "outer" now becomes the active mode.

       NOTE:
          If you want to bind a custom key to leave the current mode (e.g. Control + G in addition to <escape>),
          you can specify lazy.ungrab_chord() as the key action. To leave all  modes  and  return  to  the  root
          bindings, use lazy.ungrab_all_chords().

   Modifiers
       On  most  systems mod1 is the Alt key - you can see which modifiers, which are enclosed in a list, map to
       which keys on your system by running the xmodmap command. This example binds Alt-k to the "down"  command
       on  the  current  layout.  This command is standard on all the included layouts, and switches to the next
       window (where "next" is defined differently in different layouts). The matching "up" command switches  to
       the previous window.

       Modifiers  include:  "shift",  "lock", "control", "mod1", "mod2", "mod3", "mod4", and "mod5". They can be
       used in combination by appending more than one modifier to the list:

          Key(
              ["mod1", "control"], "k",
              lazy.layout.shuffle_down()
          )

   Special keys
       These are most commonly used special keys. For complete  list  please  see  the  code.   You  can  create
       bindings on them just like for the regular keys. For example Key(["mod1"], "F4", lazy.window.kill()).
                                              ┌───────────────────────┐
                                              │ Return                │
                                              ├───────────────────────┤
                                              │ BackSpace             │
                                              ├───────────────────────┤
                                              │ Tab                   │
                                              ├───────────────────────┤
                                              │ space                 │
                                              ├───────────────────────┤
                                              │ Home, End             │
                                              ├───────────────────────┤
                                              │ Left, Up, Right, Down │
                                              ├───────────────────────┤
                                              │ F1, F2, F3, ...       │
                                              ├───────────────────────┤
                                              │                       │
                                              ├───────────────────────┤
                                              │ XF86AudioRaiseVolume  │
                                              ├───────────────────────┤
                                              │ XF86AudioLowerVolume  │
                                              ├───────────────────────┤
                                              │ XF86AudioMute         │
                                              ├───────────────────────┤
                                              │ XF86AudioNext         │
                                              ├───────────────────────┤
                                              │ XF86AudioPrev         │
                                              ├───────────────────────┤
                                              │ XF86MonBrightnessUp   │
                                              ├───────────────────────┤
                                              │ XF86MonBrightnessDown │
                                              └───────────────────────┘

   Reference
   Layouts
       A  layout  is  an  algorithm  for  laying out windows in a group on your screen.  Since Qtile is a tiling
       window manager, this usually means that we try to use space as efficiently as possible, and give the user
       ample commands that can be bound to keys to interact with layouts.

       The layouts variable defines the list of layouts you will use with Qtile.  The first layout in  the  list
       is the default. If you define more than one layout, you will probably also want to define key bindings to
       let you switch to the next and previous layouts.

       See Built-in Layouts for a listing of available layouts.

   Example
          from libqtile import layout

          layouts = [
              layout.Max(),
              layout.Stack(stacks=2)
          ]

   Mouse
       The  mouse  config  file  variable defines a set of global mouse actions, and is a list of Click and Drag
       objects, which define what to do when a window is clicked or dragged.

   Default Mouse Bindings
       By default, holding your mod key and left-clicking (and holding) a window  will  allow  you  to  drag  it
       around  as  a floating window. Holding your mod key and right-clicking (and holding) a window will resize
       the window (and also make it float if it is not already floating).

   Example
          from libqtile.config import Click, Drag
          mouse = [
              Drag([mod], "Button1", lazy.window.set_position_floating(),
                  start=lazy.window.get_position()),
              Drag([mod], "Button3", lazy.window.set_size_floating(),
                  start=lazy.window.get_size()),
              Click([mod], "Button2", lazy.window.bring_to_front())
          ]

       The above example can also be written more concisely with the help of the EzClick and EzDrag helpers:

          from libqtile.config import EzClick as Click, EzDrag as Drag

          mouse = [
              Drag("M-1", lazy.window.set_position_floating(),
                  start=lazy.window.get_position()),
              Drag("M-3", lazy.window.set_size_floating(),
                  start=lazy.window.get_size()),
              Click("M-2", lazy.window.bring_to_front())
          ]

   Reference
   Screens
       The screens configuration variable is where the physical screens, their associated bars, and the  widgets
       contained within the bars are defined (see Built-in Widgets for a listing of available widgets).

   Example
       Tying together screens, bars and widgets, we get something like this:

          from libqtile.config import Screen
          from libqtile import bar, widget

          window_name = widget.WindowName()

          screens = [
              Screen(
                  bottom=bar.Bar([
                      widget.GroupBox(),
                      window_name,
                      ], 30),
                  ),
              Screen(
                  bottom=bar.Bar([
                      widget.GroupBox(),
                      window_name,
                      ], 30),
                  )
              ]

       Note  that  a  widget  can  be passed to multiple bars (and likewise multiple times to the same bar). Its
       contents is mirrored across all copies so this is useful where you want identical content (e.g. the  name
       of the focussed window, like in this example).

       Bars  support  both  solid  background  colors and gradients by supplying a list of colors that make up a
       linear gradient. For example, bar.Bar(..., background="#000000") will give you a black back  ground  (the
       default),  while  bar.Bar(...,  background=["#000000",  "#FFFFFF"]) will give you a background that fades
       from black to white.

       Bars (and widgets) also support transparency by adding an alpha value to the desired color. For  example,
       bar.Bar(...,  background="#00000000") will result in a fully transparent bar. Widget contents will not be
       impacted i.e.  this is different to the opacity parameter which  sets  the  transparency  of  the  entire
       window.

       NOTE:
          In X11 backends, transparency will be disabled in a bar if the background color is fully opaque.

       Users  can  add  borders  to  the  bar by using the border_width and border_color parameters. Providing a
       single value sets the value for all four sides while sides can be customised individually by setting four
       values in a list (top, right, bottom, left) e.g. border_width=[2, 0, 2, 0] would draw a border  2  pixels
       thick on the top and bottom of the bar.

   Multiple Screens
       You will see from the example above that screens is a list of individual Screen objects. The order of the
       screens in this list should match the order of screens as seen by your display server.

   X11
       You can view the current order of your screens by running xrandr --listmonitors.

       Examples of how to set the order of your screens can be found on the Arch wiki.

   Wayland
       The  Wayland  backend  supports  the wlr-output-management protocol for configuration of outputs by tools
       such as Kanshi.

   Fake Screens
       instead of using the variable screens the variable fake_screens can be  used  to  set  split  a  physical
       monitor into multiple screens.  They can be used like this:

          from libqtile.config import Screen
          from libqtile import bar, widget

          # screens look like this
          #     600         300
          #  |-------------|-----|
          #  |          480|     |580
          #  |   A         |  B  |
          #  |----------|--|     |
          #  |       400|--|-----|
          #  |   C      |        |400
          #  |----------|   D    |
          #     500     |--------|
          #                 400
          #
          # Notice there is a hole in the middle
          # also D goes down below the others

          fake_screens = [
            Screen(
                bottom=bar.Bar(
                    [
                        widget.Prompt(),
                        widget.Sep(),
                        widget.WindowName(),
                        widget.Sep(),
                        widget.Systray(),
                        widget.Sep(),
                        widget.Clock(format='%H:%M:%S %d.%m.%Y')
                    ],
                    24,
                    background="#555555"
                ),
                x=0,
                y=0,
                width=600,
                height=480
            ),
            Screen(
                top=bar.Bar(
                    [
                        widget.GroupBox(),
                        widget.WindowName(),
                        widget.Clock()
                    ],
                    30,
                ),
                x=600,
                y=0,
                width=300,
                height=580
            ),
            Screen(
                top=bar.Bar(
                    [
                        widget.GroupBox(),
                        widget.WindowName(),
                        widget.Clock()
                    ],
                    30,
                ),
                x=0,
                y=480,
                width=500,
                height=400
            ),
            Screen(
                top=bar.Bar(
                    [
                        widget.GroupBox(),
                        widget.WindowName(),
                        widget.Clock()
                    ],
                    30,
                ),
                x=500,
                y=580,
                width=400,
                height=400
            ),
          ]

   Third-party bars
       There  might  be  some  reasons  to  use  third-party bars. For instance you can come from another window
       manager and you have already configured dzen2, xmobar, or something else. They  definitely  can  be  used
       with  Qtile  too.  In  fact, any additional configurations aren't needed. Just run the bar and qtile will
       adapt.

   Reference
   Hooks
       Qtile provides a mechanism for subscribing to certain events in libqtile.hook.  To subscribe to a hook in
       your configuration, simply decorate a function with the hook you wish to subscribe to.

       See Built-in Hooks for a listing of available hooks.

   Examples
   Automatic floating dialogs
       Let's say we wanted to automatically float all dialog windows (this code is not actually necessary; Qtile
       floats all dialogs by default). We would subscribe to the client_new hook to tell us when  a  new  window
       has  opened  and,  if  the type is "dialog", as can set the window to float. In our configuration file it
       would look something like this:

          from libqtile import hook

          @hook.subscribe.client_new
          def floating_dialogs(window):
              dialog = window.window.get_wm_type() == 'dialog'
              transient = window.window.get_wm_transient_for()
              if dialog or transient:
                  window.floating = True

       A list of available hooks can be found in the Built-in Hooks reference.

   Autostart
       If you want to run commands or spawn some applications when Qtile starts, you'll  want  to  look  at  the
       startup  and startup_once hooks. startup is emitted every time Qtile starts (including restarts), whereas
       startup_once is only emitted on the very first startup.

       Let's create an executable file ~/.config/qtile/autostart.sh that will start a few  programs  when  Qtile
       first runs. Remember to chmod +x ~/.config/qtile/autostart.sh so that it can be executed.

          #!/bin/sh
          pidgin &
          dropbox start &

       We can then subscribe to startup_once to run this script:

          import os
          import subprocess

          from libqtile import hook

          @hook.subscribe.startup_once
          def autostart():
              home = os.path.expanduser('~/.config/qtile/autostart.sh')
              subprocess.call(home)

   Accessing the qtile object
       If  you  want to do something with the Qtile manager instance inside a hook, it can be imported into your
       config:

          from libqtile import qtile

   Async hooks
       Hooks can also be defined as coroutine functions using async def, which will run them  asynchronously  in
       the event loop:

          @hook.subscribe.focus_change
          async def _():
              ...

   Matching windows
       Qtile's config provides a number of situations where the behaviour depends on whether the relevant window
       matches some specified criteria.

       These situations include:

          • Defining which windows should be floated by default

          • Assigning windows to specific groups

          • Assigning window to a master section of a layout

       In  each  instance,  the  criteria  are  defined via a Match object. The properties of the object will be
       compared to a Window to determine if its properties  match.  It  can  match  by  title,  wm_class,  role,
       wm_type,  wm_instance_class,  net_wm_pid,  or wid. Additionally, a function may be passed, which takes in
       the Window to be compared against and returns a boolean.

       A basic rule would therefore look something like:

          Match(wm_class="mpv")

       This would match against any window whose class was mpv.

       Where a string is provided as an argument then the value must match  exactly.  More  flexibility  can  be
       achieved by using regular expressions. For example:

          import re

          Match(wm_class=re.compile(r"mpv"))

       This  would  still match a window whose class was mpv but it would also match any class starting with mpv
       e.g. mpvideo.

       NOTE:
          When providing a regular expression, qtile applies the .match method.  This matches from the start  of
          the  string  so,  if  you  want  to match any substring, you will need to adapt the regular expression
          accordingly e.g.

              import re

              Match(wm_class=re.compile(r".*mpv"))

          This would match any string containing mpv

   Creating advanced rules
       While the func parameter allows users to create more  complex  matches,  this  requires  a  knowledge  of
       qtile's  internal  objects. An alternative is to combine Match objects using logical operators & (and), |
       (or), ~ (not) and ^ (xor).

       For example, to create rule that matches all windows with a fixed aspect ratio except  for  mpv  windows,
       you would provide the following:

          Match(func=lambda c: c.has_fixed_ratio()) & ~Match(wm_class="mpv")

       It  is  also  possible  to  use  wrappers  for Match objects if you do not want to use the operators. The
       following wrappers are available:

          • MatchAll(Match(...), ...) equivalent to "and" test. All matches must match.

          • MatchAny(Match(...), ...) equivalent to "or" test. At least one match must match.

          • MatchOnlyOne(Match(...), Match(...)) equivalent to "xor". Only one match must match.

          • InvertMatch(Match(...)) equivalent to "not". Inverts the result of the match.

       So, to recreate the above rule using the wrappers, you would write the following:

          from libqtile.config import InvertMatch, Match, MatchAll

          MatchAll(Match(func=lambda c: c.has_fixed_ratio()), InvertMatch(Match(wm_class="mpv")))

       In addition to the above variables, there are several other boolean configuration variables that  control
       specific aspects of Qtile's behavior:
          ┌────────────────────────────┬────────────────────────────────────┬──────────────────────────────┐
          │ variable                   │ default                            │ description                  │
          ├────────────────────────────┼────────────────────────────────────┼──────────────────────────────┤
          │ auto_fullscreenTrue                               │ If  a  window requests to be │
          │                            │                                    │ fullscreen,      it       is │
          │                            │                                    │ automatically  fullscreened. │
          │                            │                                    │ Set this  to  false  if  you │
          │                            │                                    │ only   want  windows  to  be │
          │                            │                                    │ fullscreen if you  ask  them │
          │                            │                                    │ to be.                       │
          ├────────────────────────────┼────────────────────────────────────┼──────────────────────────────┤
          │ bring_front_clickFalse                              │ When   clicked,  should  the │
          │                            │                                    │ window  be  brought  to  the │
          │                            │                                    │ front or not. If this is set │
          │                            │                                    │ to   "floating_only",   only │
          │                            │                                    │ floating  windows  will  get │
          │                            │                                    │ affected  (This  sets  the X │
          │                            │                                    │ Stack Mode to Above.).  This │
          │                            │                                    │ will   ignore  the  layering │
          │                            │                                    │ rules  and  will   therefore │
          │                            │                                    │ bring  windows  above  other │
          │                            │                                    │ windows, even if  they  have │
          │                            │                                    │ been  set  as  "kept_above". │
          │                            │                                    │ This may cause  issues  with │
          │                            │                                    │ docks and other similar apps │
          │                            │                                    │ as  these  may end up hidden │
          │                            │                                    │ behind    other     windows. │
          │                            │                                    │ Setting  this  to  False  or │
          │                            │                                    │ "floating_only"          may │
          │                            │                                    │ therefore  be  required when │
          │                            │                                    │ using these apps.            │
          ├────────────────────────────┼────────────────────────────────────┼──────────────────────────────┤
          │ cursor_warpFalse                              │ If true, the cursor  follows │
          │                            │                                    │ the focus as directed by the │
          │                            │                                    │ keyboard,   warping  to  the │
          │                            │                                    │ center   of   the    focused │
          │                            │                                    │ window. When switching focus │
          │                            │                                    │ between  screens,  If  there │
          │                            │                                    │ are  no   windows   in   the │
          │                            │                                    │ screen, the cursor will warp │
          │                            │                                    │ to the center of the screen. │
          ├────────────────────────────┼────────────────────────────────────┼──────────────────────────────┤
          │ dgroups_key_binderNone                               │ A  function  which generates │
          │                            │                                    │ group  binding  hotkeys.  It │
          │                            │                                    │ takes a single argument, the │
          │                            │                                    │ DGroups  object, and can use │
          │                            │                                    │ that to set up  dynamic  key │
          │                            │                                    │ bindings.                    │
          │                            │                                    │                              │
          │                            │                                    │ A  sample  implementation is │
          │                            │                                    │ available        in        ‐ │
          │                            │                                    │ libqtile/dgroups.py   called │
          │                            │                                    │ simple_key_binder(),   which │
          │                            │                                    │ will    bind    groups    to │
          │                            │                                    │ mod+shift+0-10 by default.   │
          ├────────────────────────────┼────────────────────────────────────┼──────────────────────────────┤
          │ dgroups_app_rules[]                                 │ A list of Rule objects which │
          │                            │                                    │ can send windows to  various │
          │                            │                                    │ groups   based  on  matching │
          │                            │                                    │ criteria.                    │
          ├────────────────────────────┼────────────────────────────────────┼──────────────────────────────┤
          │ extension_defaults         │ same as widget_defaults            │ Default     settings     for │
          │                            │                                    │ extensions.                  │
          ├────────────────────────────┼────────────────────────────────────┼──────────────────────────────┤
          │ floating_layoutlayout.Floating(float_rules=[...]) │ The  default floating layout │
          │                            │                                    │ to use. This allows  you  to │
          │                            │                                    │ set  custom  floating  rules │
          │                            │                                    │ among other  things  if  you │
          │                            │                                    │ wish.                        │
          │                            │                                    │                              │
          │                            │                                    │ See  the  configuration file │
          │                            │                                    │ for the default float_rules. │
          ├────────────────────────────┼────────────────────────────────────┼──────────────────────────────┤
          │ floats_kept_aboveTrue                               │ Floating  windows  are  kept │
          │                            │                                    │ above      tiled     windows │
          │                            │                                    │ (Currently x11 only. Wayland │
          │                            │                                    │ support coming soon.)        │
          ├────────────────────────────┼────────────────────────────────────┼──────────────────────────────┤
          │ focus_on_window_activation'smart'                            │ Behavior       of        the │
          │                            │                                    │ _NET_ACTIVE_WINDOW   message │
          │                            │                                    │ sent by applications         │
          │                            │                                    │                              │
          │                            │                                    │        • urgent: urgent flag │
          │                            │                                    │          is  set   for   the │
          │                            │                                    │          window              │
          │                            │                                    │                              │
          │                            │                                    │        • focus:              │
          │                            │                                    │          automatically focus │
          │                            │                                    │          the window          │
          │                            │                                    │                              │
          │                            │                                    │        • smart:              │
          │                            │                                    │          automatically focus │
          │                            │                                    │          if the window is in │
          │                            │                                    │          the current group   │
          │                            │                                    │                              │
          │                            │                                    │        • never:        never │
          │                            │                                    │          automatically focus │
          │                            │                                    │          any   window   that │
          │                            │                                    │          requests it         │
          │                            │                                    │                              │
          │                            │                                    │        •                     │
          │                            │                                    │                              │
          │                            │                                    │          can also be a       │
          │                            │                                    │          function which      │
          │                            │                                    │          takes the window as │
          │                            │                                    │          an argument:        │
          │                            │                                    │                              │
          │                            │                                    │                 • returns    │
          │                            │                                    │                   True:      │
          │                            │                                    │                   focus      │
          │                            │                                    │                   window     │
          │                            │                                    │                              │
          │                            │                                    │                 • returns    │
          │                            │                                    │                   False:     │
          │                            │                                    │                   doesn't do │
          │                            │                                    │                   anything   │
          ├────────────────────────────┼────────────────────────────────────┼──────────────────────────────┤
          │ follow_mouse_focusTrue                               │ Controls   whether   or  not │
          │                            │                                    │ focus  follows   the   mouse │
          │                            │                                    │ around  as  it  moves across │
          │                            │                                    │ windows   in    a    layout. │
          │                            │                                    │ Otherwise    set   this   to │
          │                            │                                    │ "click_or_drag_only"      to │
          │                            │                                    │ change focus only when doing │
          │                            │                                    │ a Click or Drag action.      │
          ├────────────────────────────┼────────────────────────────────────┼──────────────────────────────┤
          │ widget_defaultsdict(font='sans',     fontsize=12, │ Default  settings  for   bar │
          │                            │ padding=3)                         │ widgets.                     │
          ├────────────────────────────┼────────────────────────────────────┼──────────────────────────────┤
          │ reconfigure_screensTrue                               │ Controls  whether  or not to │
          │                            │                                    │ automatically    reconfigure │
          │                            │                                    │ screens   when   there   are │
          │                            │                                    │ changes  in   randr   output │
          │                            │                                    │ configuration.               │
          ├────────────────────────────┼────────────────────────────────────┼──────────────────────────────┤
          │ wmname'LG3D'                             │ Gasp!  We're  lying here. In │
          │                            │                                    │ fact, nobody really uses  or │
          │                            │                                    │ cares   about   this  string │
          │                            │                                    │ besides  java  UI  toolkits; │
          │                            │                                    │ you    can    see    several │
          │                            │                                    │ discussions on  the  mailing │
          │                            │                                    │ lists,  GitHub  issues,  and │
          │                            │                                    │ other WM documentation  that │
          │                            │                                    │ suggest  setting this string │
          │                            │                                    │ if  your  java  app  doesn't │
          │                            │                                    │ work  correctly.  We  may as │
          │                            │                                    │ well just lie and  say  that │
          │                            │                                    │ we're   a   working  one  by │
          │                            │                                    │ default. We choose  LG3D  to │
          │                            │                                    │ maximize  irony:  it is a 3D │
          │                            │                                    │ non-reparenting  WM  written │
          │                            │                                    │ in  java  that happens to be │
          │                            │                                    │ on java's whitelist.         │
          ├────────────────────────────┼────────────────────────────────────┼──────────────────────────────┤
          │ auto_minimizeTrue                               │ If things like  steam  games │
          │                            │                                    │ want     to    auto-minimize │
          │                            │                                    │ themselves    when    losing │
          │                            │                                    │ focus,   should  we  respect │
          │                            │                                    │ this or not?                 │
          └────────────────────────────┴────────────────────────────────────┴──────────────────────────────┘

   Testing your configuration
       The best way to test changes to your configuration is with the provided scripts at ./scripts/xephyr (X11)
       or ./scripts/wephyr (Wayland). This will run Qtile with your config.py inside a nested window and prevent
       your running instance of Qtile from crashing if something goes wrong.

       See Hacking Qtile for more information on using Xephyr.

BUILT-IN LAYOUTS

BUILT-IN WIDGETS

BUILT-IN HOOKS

BUILT-IN EXTENSIONS

KEYBINDINGS IN IMAGES

   Default configuration
       [image] [image] [image]

   Generate your own images
       Qtile provides a tiny helper script to generate keybindings images from a config file. In the repository,
       the script is located under scripts/gen-keybinding-img.

       This script accepts a configuration file and an output directory. If no argument is  given,  the  default
       configuration will be used and files will be placed in same directory where the command has been run.

          usage: gen-keybinding-img [-h] [-c CONFIGFILE] [-o OUTPUT_DIR]

          Qtile keybindings image generator

          optional arguments:
              -h, --help          show this help message and exit
              -c CONFIGFILE, --config CONFIGFILE
                                  use specified configuration file. If no presented
                                  default will be used
              -o OUTPUT_DIR, --output-dir OUTPUT_DIR
                                  set directory to export all images to

WINDOW STACKING

       A  number  of  window  commands  (move_up/down(),  bring_to_front() etc.) relate to the stacking order of
       windows.

       The aim of this page is to provide more details as to how stacking is implemented in Qtile.

       IMPORTANT:
          Currently, stacking is only implemented in the X11 background. Support will be added  to  the  Wayland
          backend in future and this page will be updated accordingly.

   Layer priority groups
       We  have  tried  to  adhere  to  the  EWMH specification. Windows are therefore stacked, from the bottom,
       according to the following priority rules:

       • windows of type _NET_WM_TYPE_DESKTOP

       • windows having state _NET_WM_STATE_BELOW

       • windows not belonging in any other layer

       • windows of type _NET_WM_TYPE_DOCK (unless they have state _NET_WM_TYPE_BELOW) and windows having  state
         _NET_WM_STATE_ABOVE

       • focused windows having state _NET_WM_STATE_FULLSCREEN

       Qtile had then added an additional layer so that Scratchpad windows are placed above everything else.

       Tiled  windows  will  open  in  the  default,  "windows  not  belonging  in  any  other layer", layer. If
       floats_kept_above  is  set  to  True  in  the  config  then  new   floating   windows   will   have   the
       _NET_WM_STATE_ABOVE property set which will ensure they remain above tiled windows.

   Moving windows
       Imagine you have four tiled windows stacked (from the top) as follows:

          "One"
          "Two"
          "Three"
          "Four"

       If you call move_up() on window "Four", the result will be:

          "One"
          "Two"
          "Four"
          "Three"

       If you now call move_to_top() on window "Three", the result will be:

          "Three"
          "One"
          "Two"
          "Four"

       NOTE:
          bring_to_front()  has  a special behaviour in Qtile. This will bring any window to the very top of the
          stack, disregarding the priority rules set out above.  When  that  window  loses  focus,  it  will  be
          restacked in the appropriate location.

          This  can  cause undesirable results if the config contains bring_front_click=True and the user has an
          app like a dock which is activated by mousing over the window. In this situation, tiled  windows  will
          be  displayed  above  the  dock making it difficult to activate. To fix this, set bring_front_click to
          False to disable the behaviour completely, or "floating_only" to only have  this  behaviour  apply  to
          floating windows.

ARCHITECTURE

       This  page  explains how Qtile's API works and how it can be accessed. Users who just want to find a list
       of commands can jump to the API commands page.

       Qtile's command API is based on a graph of objects, where each object has a set of  associated  commands,
       combined with a number of interfaces that are used to navigate the graph and execute associated commands.

       This  page  gives  an  overview  of the command graph and the various interfaces accessible by users. The
       documentation also contains details of all the commands that are exposed by objects on the graph.

       NOTE:
          While users are able to access the internal python objects (e.g. via a qtile instance),  this  is  not
          part  of  the "official" API. These objects and method are not currently included in the documentation
          but can be viewed by looking at the source code on github. Changes to commonly-used  internal  objects
          will be kept to a minimum.

       The graph and object commands are used in a number of different places:

       • Commands can be bound to keys in the Qtile configuration file using the lazy interface.

       • Commands  can  be  called  from a script using one of the various available interfaces to interact with
         Qtile from Python or shell scripts.

       A couple of additional options are available if you are looking for more interactive access:

       • Commands can be called through qtile shell, the Qtile shell.

       • The shell can also be hooked into a Jupyter kernel called  iqshell  (NB  this  interface  is  currently
         broken).

       If the explanations in the pages below seems a bit complex, please take a moment to explore the API using
       the  qtile  shell  command shell. The shell provides a way to navigate the graph, allowing you to see how
       nodes are connected. Available nodes can be displayed  with  the  ls  command  while  command  lists  and
       detailed documentation can be accessed from the built-in help command. Commands can also be executed from
       this shell.

   The Command Graph
       The  objects  in Qtile's command graph come in eight flavours, matching the eight basic components of the
       window manager: layouts, windows, groups, bars, widgets, screens, core, and a special root node.  Objects
       are addressed by a path specification that starts at the root and follows  the  available  paths  in  the
       graph. This is what the graph looks like:

       Each  arrow  can be read as "holds a reference to". So, we can see that a widget object holds a reference
       to objects of type bar, screen and group. Let's start with some simple examples  of  how  the  addressing
       works.  Which particular objects we hold reference to depends on the context - for instance, widgets hold
       a reference to the screen that they appear on, and the bar they are attached to.

       Let's look at an example, starting at the root node. The following script runs the status command on  the
       root node, which, in this case, is represented by the InteractiveCommandClient object:

          from libqtile.command.client import InteractiveCommandClient
          c = InteractiveCommandClient()
          print(c.status())

       The  InteractiveCommandClient is a class that allows us to traverse the command graph using attributes to
       select child nodes or commands.  In this example, we have resolved  the  status()  command  on  the  root
       object.   The interactive command client will automatically find and connect to a running Qtile instance,
       and which it will use to dispatch the call and print out the return.

       An alternative is to use the CommandClient, which allows for a more precise resolution of  command  graph
       objects, but is not as easy to interact with from a REPL:

          from libqtile.command.client import CommandClient
          c = CommandClient()
          print(c.call("status")())

       Like  the  interactive client, the command client will automatically connect to a running Qtile instance.
       Here, we first resolve the status() command with the .call("status"), which simply located the  function,
       then we can invoke the call with no arguments.

       For  the  rest  of  this example, we will use the interactive command client.  From the graph, we can see
       that the root node holds a reference to group nodes.  We can access the "info"  command  on  the  current
       group like so:

          c.group.info()

       To  access a specific group, regardless of whether or not it is current, we use the Python mapping lookup
       syntax. This command sends group "b" to screen 1 (by the libqtile.config.Group.toscreen() method):

          c.group["b"].toscreen(1)

       In different contexts, it is possible to access a default object,  where  in  other  contexts  a  key  is
       required.   From  the  root of the graph, the current group, layout, screen and window can be accessed by
       simply leaving the key specifier out. The key specifier is mandatory for widget and bar nodes.

       With this context, we can now drill down deeper in the graph, following the edges in the  graphic  above.
       To access the screen currently displaying group "b", we can do this:

          c.group["b"].screen.info()

       Be  aware,  however,  that group "b" might not currently be displayed. In that case, it has no associated
       screen, the path resolves to a non-existent node, and we get an exception:

          libqtile.command.CommandError: No object screen in path 'group['b'].screen'

       The graph is not a tree, since it can  contain  cycles.  This  path  (redundantly)  specifies  the  group
       belonging to the screen that belongs to group "b":

          c.group["b"].screen.group

       This amount of connectivity makes it easy to reach out from a given object when callbacks and events fire
       on that object to related objects.

   Navigating the command graph
       As noted previously, some objects require a selector to ensure that the correct object is selected, while
       other nodes provide a default object without a selector.

       The  table  below  shows  what selectors are required for the different nodes and whether the selector is
       optional (i.e. if it can be omitted to select the default object).
 ┌────────┬─────────────────────────────────────────────────────────────────────┬───────────┬────────────────────────┐
 │ Object │ Key                                                                 │ Optional? │ Example                │
 ├────────┼─────────────────────────────────────────────────────────────────────┼───────────┼────────────────────────┤
 │ bar    │ "top", "bottom"                                                     │ No        │ c.screen.bar["bottom"] │
 │        │ (Note: if accessing this node from the root, users on multi-monitor │           │                        │
 │        │ setups may wish to navigate via a screen node to ensure that they   │           │                        │
 │        │ select the correct object.)                                         │           │                        │
 ├────────┼─────────────────────────────────────────────────────────────────────┼───────────┼────────────────────────┤
 │ group  │ Name string                                                         │ Yes       │ c.group["one"]         │
 │        │                                                                     │           │ c.group                │
 ├────────┼─────────────────────────────────────────────────────────────────────┼───────────┼────────────────────────┤
 │ layout │ Integer index                                                       │ Yes       │ c.layout[2]            │
 │        │                                                                     │           │ c.layout               │
 ├────────┼─────────────────────────────────────────────────────────────────────┼───────────┼────────────────────────┤
 │ screen │ Integer index                                                       │ Yes       │ c.screen[1]            │
 │        │                                                                     │           │ c.screen               │
 ├────────┼─────────────────────────────────────────────────────────────────────┼───────────┼────────────────────────┤
 │ widget │ Widget name                                                         │ No        │ c.widget["textbox"]    │
 │        │ (This is usually the name of the widget class in lower case but can │           │                        │
 │        │ be set by passing the name parameter to the widget.)                │           │                        │
 ├────────┼─────────────────────────────────────────────────────────────────────┼───────────┼────────────────────────┤
 │ window │ Integer window ID                                                   │ Yes       │ c.window[123456]       │
 │        │                                                                     │           │ c.window               │
 ├────────┼─────────────────────────────────────────────────────────────────────┼───────────┼────────────────────────┤
 │ core   │ No                                                                  │ n/a       │ c.core                 │
 └────────┴─────────────────────────────────────────────────────────────────────┴───────────┴────────────────────────┘

   Command graph development
       This page provides further detail on how Qtile's command graph works.  If you just want  to  script  your
       Qtile  window manager the earlier information, in addition to the documentation on the available commands
       should be enough to get started.

       To develop the Qtile manager itself, we can dig into how Qtile represents these objects, which will  lead
       to the way the commands are dispatched.

   Client-Server Scripting Model
       Qtile  has  a  client-server  control model - the main Qtile instance listens on a named pipe, over which
       marshalled command calls and response data is passed.  This allows Qtile  to  be  controlled  fully  from
       external     scripts.     Remote     interaction     occurs     through     an     instance     of    the
       libqtile.command.interface.IPCCommandInterface  class.  This  class  establishes  a  connection  to   the
       currently  running  instance  of  Qtile.  A libqtile.command.client.InteractiveCommandClient can use this
       connection to dispatch commands to the running instance.   Commands  then  appear  as  methods  with  the
       appropriate  signature  on the InteractiveCommandClient object.  The object hierarchy is described in the
       Architecture section of this manual. Full command documentation is available through the Qtile Shell.

   Digging Deeper: Command Objects
       All of the configured objects setup by Qtile are CommandObject subclasses.  These objects  are  so  named
       because  we  can  issue commands against them using the command scripting API.  Looking through the code,
       the commands that are exposed are commands that are decorated with the @expose_command() decorator.  When
       writing custom layouts, widgets, or any other object, you can add your own custom functions and, once you
       add the decorator, they will be callable using the standard command infrastructure. An available  command
       can be extracted by calling .command() with the name of the command.

       In  addition  to  having a set of associated commands, each command object also has a collection of items
       associated with it.  This is what forms the graph that is shown above.  For  a  given  object  type,  the
       items()  method  returns all of the names of the associated objects of that type and whether or not there
       is a defaultable value.  For example, from the root, .items("group") returns  the  name  of  all  of  the
       groups and that there is a default value, the currently focused group.

       To  navigate  from  one command object to the next, the .select() method is used.  This method resolves a
       requested object from the command graph by iteratively selecting objects.   A  selector  like  [("group",
       "b"), ("screen", None)] would be to first resolve group "b", then the screen associated to the group.

   The Command Graph
       In  order  to  help  in  specifying  command objects, there is the abstract command graph structure.  The
       command graph structure allows us to address any valid command object and issue any  command  against  it
       without  needing  to have any Qtile instance running or have anything to resolve the objects to.  This is
       particularly useful when constructing lazy calls, where the Qtile instance does not exist to specify  the
       path  that  will be resolved when the command is executed.  The only limitation of traversing the command
       graph is that it must follow the allowed edges specified in the first section above.

       Every object in the command graph is represented by a CommandGraphNode.  Any call can be resolved from  a
       given  node.   In addition, each node knows about all of the children objects that can be reached from it
       and have the ability to .navigate() to the other nodes in the command graph.  Each of  the  object  types
       are  represented  as  CommandGraphObject  types  and  the  root  node  of the graph, the CommandGraphRoot
       represents the Qtile instance.  When a call is performed on an object,  it  returns  a  CommandGraphCall.
       Each  call  will know its own name as well as be able to resolve the path through the command graph to be
       able to find itself.

       Note that the command graph itself can standalone, there is no other functionality within Qtile  that  it
       relies  on.   While we could have started here and built up, it is helpful to understand the objects that
       the graph is meant to represent, as the graph is just a representation of a traversal of the real objects
       in a running Qtile window manager.  In order to tie the running Qtile instance to  the  abstract  command
       graph, we move on to the command interface.

   Executing graph commands: Command Interface
       The  CommandInterface is what lets us take an abstract call on the command graph and resolve it against a
       running   command   object.    Put   another   way,   this   is   what   takes   the   graph    traversal
       .group["b"].screen.info()   and  executes  the  info()  command  against  the  addressed  screen  object.
       Additional functionality can be used to check that a given traversal resolves to actual objcets and  that
       the  requested  command  actually exists.  Note that by construction of the command graph, the traversals
       here must be feasible, even if they cannot be resolved for a given configuration state.  For example,  it
       is possible to check the screen assoctiated to a group, even though the group may not be on a screen, but
       it is not possible to check the widget associated to a group.

       The  simplest  form  of  the command interface is the QtileCommandInterface, which can take an in-process
       Qtile instance as the root CommandObject and execute requested commands.  This is typically  how  we  run
       the unit tests for Qtile.

       The  other  primary  example  of  this  is  the IPCCommandInterface which is able to then route all calls
       through an IPC client connected to a running Qtile instance.  In this case, the command graph call can be
       constructed on the client side without having to dispatch to Qtile and once the call is  constructed  and
       deemed valid, the call can be executed.

       In  both  of  these cases, executing a command on a command interface will return the result of executing
       the command on a running Qtile instance.  To support lazy  execution,  the  LazyCommandInterface  instead
       returns a LazyCall which is able to be resolved later by the running Qtile instance when it is configured
       to fire.

   Tying it together: Command Client
       So  far, we have our running Command Objects and the Command Interface to dispatch commands against these
       objects as well as the Command Graph structure itself which  encodes  how  to  traverse  the  connections
       between  the  objects.   The  final component which ties everything together is the Command Client, which
       allows us to navigate through the graph to resolve objects, find their associated commands,  and  execute
       the commands against the held command interface.

       The  idea  of  the  command  client  is  that it is created with a reference into the command graph and a
       command interface.  All navigation can be done against the  command  graph,  and  traversal  is  done  by
       creating  a  new  command  client starting from the new node.  When a command is executed against a node,
       that command is dispatched to the held command interface.  The key decision here is how  to  perform  the
       traversal.   The  command  client  exists  in  two different flavors: the standard CommandClient which is
       useful for handling more programmatic traversal of the graph, calling methods to traverse the graph,  and
       the  InteractiveCommandClient  which  behaves more like a standard Python object, traversing by accessing
       properties and performing key lookups.

       Returning to our examples above, we now have the full context to see what is going on when we call:

          from libqtile.command.client import CommandClient
          c = CommandClient()
          print(c.call("status")())
          from libqtile.command.client import InteractiveCommandClient
          c = InteractiveCommandClient()
          print(c.status())

       In both cases, the command clients are constructed with the default command interface, which sets  up  an
       IPC  connection  to  the  running  Qtile instance, and starts the client at the graph root.  When we call
       c.call("status") or c.status, we navigate the command client to the status  command  on  the  root  graph
       object.   When  these  are invoked, the commands graph calls are dispatched via the IPC command interface
       and the results then sent back and printed on the local command line.

       The power that can be realized by separating out the traversal and resolution of objects in  the  command
       graph  from  actually invoking or looking up any objects within the graph can be seen in the lazy module.
       By creating a lazy evaluated command client, we can expose the  graph  traversal  and  object  resolution
       functionality via the same InteractiveCommandClient that is used to perform live command execution in the
       Qtile prompt.

INTERFACES

   Introduction
       This  page  provides  an  overview  of  the various interfaces available to interact with Qtile's command
       graph.

       • lazy calls

       • when running qtile shell

       • when running qtile cmd-obj

       • when using CommandClient or InteractiveCommandClient in python

       The way that these commands are called  varies  depending  on  which  option  you  select.  However,  all
       interfaces  follow the same, basic approach: navigate to the desired object and then execute a command on
       that object. The following examples illustrate this principle by showing how  the  same  command  can  be
       accessed by the various interfaces:

          Lazy call:
          lazy.widget["volume"].increase_volume()

          qtile shell:
          > cd widget/volume
          widget[volume] > increase_volume()

          qtile cmd-obj:
          qtile cmd-obj -o widget volume -f increase_volume

          CommandClient:
          >>> from libqtile.command.client import CommandClient
          >>> c = CommandClient()
          >>> c.navigate("widget", "volume").call("increase_volume")

          InteractiveCommandClient:
          >>> from libqtile.command.client import InteractiveCommandClient
          >>> c = InteractiveCommandClient()
          >>> c.widget["volume"].increase_volume()

   The Interfaces
       From  the  examples  above, you can see that there are five main interfaces which can be used to interact
       with Qtile's command graph. Which one you choose will depend  on  how  you  intend  to  use  it  as  each
       interface is suited to different scenarios.

       • The lazy interface is used in config scripts to bind commands to keys and mouse callbacks.

       • The  qtile  shell  is  a  tool  for exploring the graph by presenting it as a file structure. It is not
         designed to be used for scripting.

       • For users creating shell scripts, the qtile cmd-obj interface would be the recommended choice.

       • For users wanting  to  control  Qtile  from  a  python  script,  there  are  two  available  interfaces
         libqtile.command.client.CommandClient  and  libqtile.command.client.InteractiveCommandClient. Users are
         advised to use the InteractiveCommandClient as this simplifies the syntax for navigating the graph  and
         calling commands.

   The Lazy interface
       The  lazy.lazy  object  is a special helper object to specify a command for later execution. Lazy objects
       are typically users' first exposure to Qtile's command graph  but  they  may  not  realise  it.  However,
       understanding this will help users when they try using some of the other interfaces listed on this page.

       The basic syntax for a lazy command is:

          lazy.node[selector].command(arguments)

       No  node  is  required  when  accessing  commands  on  the  root node. In addition, multiple nodes can be
       sequenced if required to navigate to a specific object. For example, bind a key that would focus the next
       window on the active group on screen 2, you would create a lazy object as follows:

          lazy.screen[1].group.next_window()

       NOTE:
          As noted above, lazy calls do not call the relevant command but only create a reference to  it.  While
          this makes it ideal for binding commands to key presses and mouse_callbacks for widgets, it also means
          that lazy calls cannot be included in user-defined functions.

   qtile shell
       The  qtile  shell  maps the command graph to a virtual filesystem that can be navigated in a similar way.
       While it is unlikely to be used for scripting, the qtile shell interface provides an excellent means  for
       users to navigate and familiarise themselves with the command graph.

       For more information, please refer to qtile shell

   qtile cmd-obj
       qtile  cmd-obj is a command line interface for executing commands on the command graph. It can be used as
       a standalone command (e.g. executed directly from the terminal) or incorporated into shell scripts.

       For more information, please refer to qtile cmd-obj

   CommandClient
       The CommandClient interface is a low-level python interface for  accessing  and  navigating  the  command
       graph.  The  low-level  nature  means  that navigation steps must be called explicitly, rather than being
       inferred from the body of the calling command.

       For example:

          from libqtile.command.client import CommandClient

          c = CommandClient()

          # Call info command on clock widget
          info = c.navigate("widget", "clock").call("info")

          # Call info command on the screen displaying the clock widget
          info = c.navigate("widget", "clock").navigate("screen", None).call("info")

       Note from the last example that each navigation step must be called separately. The arguments  passed  to
       navigate()  are  node  and  selector. selector is None when you wish to access the default object on that
       node (e.g. the current screen).

       More technical explanation about the python command clients can be found  at  Executing  graph  commands:
       Command Interface.

   InteractiveCommandClient
       The  InteractiveCommandClient  is likely to be the more popular interface for users wishing to access the
       command   graph   via   external   python   scripts.   One   of   the   key   differences   between   the
       InteractiveCommandClient  and  the  above  CommandClient is that the InteractiveCommandClient removes the
       need to call navigate and call explicitly. Instead, the syntax mimics that of the lazy interface.

       For example, to call the same commands in the above example:

          from libqtile.command.client import InteractiveCommandClient

          c = InteractiveCommandClient()

          # Call info command on clock widget
          info = c.widget["clock"].info()

          # Call info command on the screen displaying the clock widget
          info = c.widget["clock"].screen.info()

COMMANDS API

       The following pages list all the commands that are exposed by Qtile's command graph. As a result, all  of
       these commands are accessible by any of the various interfaces provided by Qtile (e.g. the lazy interface
       for keybindings and mouse callbacks).

   Qtile root object
       The root node represents the main Qtile manager instance. Many of the commands on this node are therefore
       related to the running of the application itself.

       The  root  can  access  every  other node in the command graph. Certain objects can be accessed without a
       selector resulting in the current object being selected (e.g. current group, screen, layout, window).

   Layout objects
       Layouts position windows according to their specific rules.  Layout  commands  typically  include  moving
       windows around the layout and changing the size of windows.

       Layouts  can  access  the windows being displayed, the group holding the layout and the screen displaying
       the layout.

   Window objects
       The size and position of windows is determined by the current layout.  Nevertheless,  windows  can  still
       change their appearance in multiple ways (toggling floating state, fullscreen, opacity).

       Windows can access objects relevant to the display of the window (i.e.  the screen, group and layout).

   Group objects
       Groups are Qtile's workspaces. Groups are not responsible for the positioning of windows (that is handled
       by the layouts) so the available commands are somewhat more limited in scope.

       Groups  have  access to the layouts in that group, the windows in the group and the screen displaying the
       group.

   Bar objects
       The bar is primarily used to display widgets on the screen. As a result, the bar does not  need  many  of
       its own commands.

       To  select a bar on the command graph, you must use a selector (as there is no default bar). The selector
       is the position of the bar on the screen i.e. "top", "bottom", "left" or "right".

       The bar can access the screen it's on and the widgets it contains via the command graph.

   Widget objects
       Widgets are small scripts that are used to provide content or add functionality to the bar. Some  widgets
       will expose commands in order for functionality to be triggered indirectly (e.g. via a keypress).

       Widgets can access the parent bar and screen via the command graph.

   Screen objects
       Screens  are  the  display area that holds bars and an active group. Screen commands include changing the
       current group and changing the wallpaper.

       Screens can access objects displayed on that screen e.g. bar, widgets, groups, layouts and windows.

   Backend core objects
       The backend core is the link between the Qtile objects (windows, layouts, groups etc.)  and the  specific
       backend  (X11 or Wayland). This core should be largely invisible to users and, as a result, these objects
       do not expose many commands.

       Nevertheless, both backends do contain important commands, notably set_keymap on X11 and  change_vt  used
       to change to a different TTY on Wayland.

       The backend core has no access to other nodes on the command graph.

   X11 backend
   Wayland backend

HACKING ON QTILE

   Requirements
       Here are Qtile's additional dependencies that may be required for tests:

   Backends
       The test suite can be run using the X11 or Wayland backend, or both.  By default, only the X11 backend is
       used for tests. To test a single backend or both backends, specify as arguments to pytest:

          pytest --backend wayland  # Test just Wayland backend
          pytest --backend x11 --backend wayland  # Test both

       Testing  with  the  X11  backend  requires  Xephyr  (and  xvfb for headless mode) in addition to the core
       dependencies.

   Building cffi module
       Qtile ships with a small in-tree pangocairo binding built using cffi, pangocffi.py,  and  also  binds  to
       xcursor  with  cffi.   The bindings are not built at run time and will have to be generated manually when
       the code is downloaded or when any changes are made to the cffi library.  This can be done by calling:

          ./scripts/ffibuild

   Setting up the environment
       In the root of the project, run ./dev.sh.  It will create a virtualenv called venv.

       Activate this virtualenv with . venv/bin/activate.  Deactivate it with the deactivate command.

   Building the documentation
       To build the documentation, you will also need to install graphviz.

       Go into the docs/ directory and run pip install -r requirements.txt.

       Build the documentation with make html.

       Check the result by opening _build/html/index.html in your browser.

       NOTE:
          To speed up local testing, screenshots are not generated each time the documentation is built.

          You can enable screenshots by setting the QTILE_BUILD_SCREENSHOTS environmental variable at build time
          e.g. QTILE_BUILD_SCREENSHOTS=1 make html. You can also export the variable so it  will  apply  to  all
          local  builds  export QTILE_BUILD_SCREENSHOTS=1 (but remember to unset it if you want to skip building
          screenshots).

   Development and testing
       In practice, the development cycle looks something like this:

       1. make minor code change

       2. run appropriate test: pytest tests/test_module.py or pytest -k PATTERN

       3. GOTO 1, until hackage is complete

       4. run entire test suite to make sure you didn't break anything else: pytest

       5. try to commit, get changes and feedback from the pre-commit hooks

       6. GOTO 5, until your changes actually get committed

       Tests and pre-commit hooks will be run by our CI on every pull request as well so you can see whether  or
       not your contribution passes.

   Coding style
       While  not all of our code follows PEP8, we do try to adhere to it where possible. All new code should be
       PEP8 compliant.

       The make lint command (or pre-commit run -a) will run our linters and formatters with  our  configuration
       over  the  whole  libqtile  to ensure your patch complies with reasonable formatting constraints. We also
       request that git commit messages follow the standard format.

   Logging
       Logs are important to us because they are our best way to see what Qtile is doing when something abnormal
       happens. However, our goal is not to have as many logs as possible, as this hinders readability. What  we
       want are relevant logs.

       To decide which log level to use, refer to the following scenarios:

       • ERROR:  a  problem  affects  the  behavior of Qtile in a way that is noticeable to the end user, and we
         can't work around it.

       • WARNING: a problem causes Qtile to operate in a suboptimal manner.

       • INFO: the state of Qtile has changed.

       • DEBUG: information is worth giving to help the developer better understand which branch the process  is
         in.

       Be  careful  not  to  overuse DEBUG and clutter the logs. No information should be duplicated between two
       messages.

       Also, keep in mind that any other level than DEBUG is aimed at users who don't necessarily have  advanced
       programming  knowledge;  adapt  your  message  accordingly.  If it can't make sense to your grandma, it's
       probably meant to be a DEBUG message.

   Using Xephyr
       Qtile has a very extensive test suite, using the Xephyr nested X server. When tests are run, a  nested  X
       server  with  a  nested  instance  of  Qtile is fired up, and then tests interact with the Qtile instance
       through the client API. The fact that we can do this is a great  demonstration  of  just  how  completely
       scriptable  Qtile  is. In fact, Qtile is designed expressly to be scriptable enough to allow unit testing
       in a nested environment.

       The Qtile repo includes a tiny helper script to let you quickly pull up a nested  instance  of  Qtile  in
       Xephyr, using your current configuration.  Run it from the top-level of the repository, like this:

          ./scripts/xephyr

       Change the screen size by setting the SCREEN_SIZE environment variable.  Default: 800x600. Example:

          SCREEN_SIZE=1920x1080 ./scripts/xephyr

       Change the log level by setting the LOG_LEVEL environment variable.  Default: INFO. Example:

          LOG_LEVEL=DEBUG ./scripts/xephyr

       The  script  will  also  pass  any  additional  options  to  Qtile.  For  example, you can use a specific
       configuration file like this:

          ./scripts/xephyr -c ~/.config/qtile/other_config.py

       Once the Xephyr window is running and focused, you can enable capturing the keyboard shortcuts by hitting
       Control+Shift. Hitting them again will disable the  capture  and  let  you  use  your  personal  keyboard
       shortcuts again.

       You  can  close  the  Xephyr window by enabling the capture of keyboard shortcuts and hit Mod4+Control+Q.
       Mod4 (or Mod) is usually the Super key (or Windows key).  You can also close the Xephyr window by running
       qtile cmd-obj -o cmd -f shutdown in a terminal (from inside the Xephyr window of course).

       You don't need to run the Xephyr script in order to run the tests as the test runner will launch its  own
       Xephyr instances.

   Second X Session
       Some  users prefer to test Qtile in a second, completely separate X session: Just switch to a new tty and
       run startx normally to use the ~/.xinitrc X startup script.

       It's likely though that you want to use a different, customized startup script for testing purposes,  for
       example ~/.config/qtile/xinitrc. You can do so by launching X with:

          startx ~/.config/qtile/xinitrc

       startx  deals with multiple X sessions automatically. If you want to use xinit instead, you need to first
       copy /etc/X11/xinit/xserverrc to ~/.xserverrc; when launching it, you  have  to  specify  a  new  session
       number:

          xinit ~/.config/qtile/xinitrc -- :1

       Examples of custom X startup scripts are available in qtile-examples.

   Debugging in PyCharm
       Make sure to have all the requirements installed and your development environment setup.

       PyCharm  should  automatically  detect  the  venv  virtualenv when opening the project.  If you are using
       another viirtualenv, just  instruct  PyCharm  to  use  it  in  Settings  ->  Project:  qtile  ->  Project
       interpreter.

       In  the  project tree, on the left, right-click on the libqtile folder, and click on Mark Directory as ->
       Sources Root.

       Next, add a Configuration using a Python template with these fields:

       • Script path: bin/qtile, or the absolute path to it

       • Parameters: -c libqtile/resources/default_config.py, or nothing if you want to use your own config file
         in ~/.config/qtile/config.py

       • Environment variables: PYTHONUNBUFFERED=1;DISPLAY=:1

       • Working directory: the root of the project

       • Add contents root to PYTHONPATH: yes

       • Add source root to PYTHONPATH: yes

       Then, in a terminal, run:
          Xephyr +extension RANDR -screen 1920x1040 :1 -ac &

       Note that we used the same display, :1, in both  the  terminal  command  and  the  PyCharm  configuration
       environment variables.  Feel free to change the screen size to fit your own screen.

       Finally, place your breakpoints in the code and click on Debug!

       Once  you  finished debugging, you can close the Xephyr window with kill PID (use the jobs builtin to get
       its PID).

   Debugging in VSCode
       Make sure to have all the requirements installed and your development environment setup.

       Open the root of the repo in VSCode.  If you have created it, VSCode should detect the  venv  virtualenv,
       if not, select it.

       Create a launch.json file with the following lines.

          {
            "version": "0.2.0",
            "configurations": [
                {
                    "name": "Python: Qtile",
                    "type": "python",
                    "request": "launch",
                    "program": "${workspaceFolder}/bin/qtile",
                    "cwd": "${workspaceFolder}",
                    "args": ["-c", "libqtile/resources/default_config.py"],
                    "console": "integratedTerminal",
                    "env": {"PYTHONUNBUFFERED":"1", "DISPLAY":":1"}
                }
            ]
          }

       Then, in a terminal, run:
          Xephyr +extension RANDR -screen 1920x1040 :1 -ac &

       Note  that  we  used  the  same  display,  :1,  in both the terminal command and the VSCode configuration
       environment variables.  Then debug usually in VSCode. Feel free to change the screen size to fit your own
       screen.

   Resources
       Here are a number of resources that may come in handy:

       • Inter-Client Conventions ManualExtended Window Manager HintsA reasonable basic Xlib Manual

CONTRIBUTING

   Reporting bugs
       Perhaps the easiest way to contribute to Qtile is to report any bugs you run into  on  the  GitHub  issue
       tracker.

       Useful bug reports are ones that get bugs fixed. A useful bug report normally has two qualities:

       1. Reproducible. If your bug is not reproducible it will never get fixed.  You should clearly mention the
          steps  to  reproduce  the  bug.  Do  not  assume  or  skip  any  reproducing step. Describe the issue,
          step-by-step, so that it is easy to reproduce and fix.

       2. Specific. Do not write an essay about the problem. Be specific and to the point. Try to summarize  the
          problem  in a succinct manner. Do not combine multiple problems even if they seem to be similar. Write
          different reports for each problem.

       Ensure  to   include   any   appropriate   log   entries   from   ~/.local/share/qtile/qtile.log   and/or
       ~/.xsession-errors!   Sometimes,  an  xtrace  is  requested.  If  that is the case, refer to capturing an
       xtrace.

   Writing code
       To get started writing code for Qtile, check out our guide to Hacking on Qtile.  A more detailed page  on
       creating widgets is available here.

       IMPORTANT:
          Use   a   separate   git   branch   to  make  rebasing  easy.  Ideally,  you  would  git  checkout  -b
          <my_feature_branch_name> before starting your work.

          See also: using git.

   Submit a pull request
       You've done your hacking and are ready to submit your patch to Qtile. Great!  Now it's time to submit a ‐
       pull request to our issue tracker on GitHub.

       IMPORTANT:
          Pull requests are not considered complete until they include all of the following:

          • Code that conforms to our linters and formatters.  Run  pre-commit  install  to  install  pre-commit
            hooks that will make sure your code is compliant before any commit.

          • Unit  tests  that  pass  locally  and  in our CI environment (More below).  Please add unit tests to
            ensure that your code works and stays working!

          • Documentation updates on an as needed basis.

          • A qtile migrate migration is required for config-breaking changes.  See here for current  migrations
            and see below for further information.

          • Code  that  does  not include unrelated changes. Examples for this are formatting changes, replacing
            quotes or whitespace in other parts of the code or "fixing"  linter  warnings  popping  up  in  your
            editor on existing code. Do not include anything like the above!Widgets don't need to catch their own exceptions, or introduce their own polling infrastructure. The
            code  in libqtile.widget.base.* does all of this. Your widget should generally only include whatever
            parsing/rendering code is necessary, any other changes should go at the framework level.  Make  sure
            to double-check that you are not re-implementing parts of libqtile.widget.base.

          • Commit messages are more important that Github PR notes, since this is what people see when they are
            spelunking  via  git  blame.  Please  include  all  relevant detail in the actual git commit message
            (things like  exact  stack  traces,  copy/pastes  of  discussion  in  IRC/mailing  lists,  links  to
            specifications  or  other  API docs are all good). If your PR fixes a Github issue, it might also be
            wise to link to it with #1234 in the commit message.

          • PRs with multiple commits should not introduce code in one patch to then change it in a later patch.
            Please do a patch-by-patch review of your PR, and make sure each commit passes CI and makes  logical
            sense  on  its  own. In other words: do introduce your feature in one commit and maybe add the tests
            and documentation in a separate commit. Don't push commits that partially implement  a  feature  and
            are basically broken.

       NOTE:
          Others  might  ban force-pushes, we allow them and prefer them over incomplete commits or commits that
          have a bad and meaningless commit description.

       Feel free to add your contribution (no matter how small) to the appropriate place  in  the  CHANGELOG  as
       well!

   Unit testing
       We  must  test  each  unit  of  code  to  ensure  that  new  changes  to  the  code do not break existing
       functionality. The framework we use to test Qtile is pytest. How pytest works is outside of the scope  of
       this documentation, but there are tutorials online that explain how it is used.

       Our  tests  are written inside the test folder at the top level of the repository. Reading through these,
       you can get a feel for the approach we take to test a given unit. Most of the  tests  involve  an  object
       called manager.  This is the test manager (defined in test/helpers.py), which exposes a command client at
       manager.c that we use to test a Qtile instance running in a separate thread as if we were using a command
       client from within a running Qtile session.

       For  any  Qtile-specific  question on testing, feel free to ask on our issue tracker or on IRC (#qtile on
       irc.oftc.net).

   Running tests locally
       This section gives an overview about tox so that you don't have to search its documentation just  to  get
       started.

       Checks  are  grouped  in so-called environments. Some of them are configured to check that the code works
       (the usual unit test, e.g. py39, pypy3), others make sure that your code  conforms  to  the  style  guide
       (pep8,  codestyle,  mypy).  A  third kind of test verifies that the documentation and packaging processes
       work (docs, docstyle, packaging).

       We have configured tox to run the full suite of tests whenever a pull request  is  submitted/updated.  To
       reduce  the  amount  of  time taken by these tests, we have created separate environments for both python
       versions and backends (e.g. tests for x11 and wayland run in parallel for each  python  version  that  we
       currently support).

       These  environments  were  designed with automation in mind so there are separate test environments which
       should be used for running qtile's tests locally. By default, tests will only run on x11 backend (but see
       below for information on how to set the backend).

       The following examples show how to run tests locally:

              • To run the functional tests, use tox -e test. You can specify to only run a specific  test  file
                or even a specific test within that file with the following commands:

                   tox -e test # Run all tests in default python version
                   tox -e test -- -x test/widgets/test_widgetbox.py  # run a single file
                   tox -e test -- -x test/widgets/test_widgetbox.py::test_widgetbox_widget
                   tox -e test -- --backend=wayland --backend=x11  # run tests on both backends
                   tox -e test-both  # same as above
                   tox -e test-wayland  # Just run tests on wayland backend

              • To  run  style  and building checks, use tox -e docs,packaging,pep8,....  You can use -p auto to
                run the environments in parallel.

                IMPORTANT:
                   The CI is configured to run all the environments. Hence it can be time- consuming to make all
                   the tests pass. As stated above, pull requests that  don't  pass  the  tests  are  considered
                   incomplete.  Don't  forget  that this does not only include the functionality, but the style,
                   typing annotations (if necessary) and documentation as well!

   Writing migrations
       Migrations are needed when a commit introduces a change which makes a breaking change to a user's config.
       Examples include renaming classes, methods, arguments and moving modules or class definitions.

       Where these changes are made, it is strongly encouraged to support the old syntax where possible and warn
       the user about the deprecations.

       Whether or not a deprecation warning is provided, a migration script should be provided that will  modify
       the user's config when they run qtile migrate.

       Click here for detailed instructions on How to write a migration script.

   How to write a migration script
       Qtile's migration scripts should provide two functions:

       • Update config files to fix any breaking changes introduced by a commit

       • Provide linting summary of errors in existing configs

       To  do this, we use LibCST to parse the config file and make changes as appropriate. Basic tips for using
       LibCST are included below but it is recommended that you read their documentation to familiarise yourself
       with the available functionalities.

   Structure of a migration file
       Migrations should be saved as a new file in libqtile/scripts/migrations.

       A basic migration will look like this:

          from libqtile.scripts.migrations._base import MigrationTransformer, _QtileMigrator, add_migration

          class MyMigration(MigrationTransformer):
              """The class that actually modifies the code."""
              ...

          class Migrator(_QtileMigrator):
              ID = "MyMigrationName"

              SUMMARY = "Summary of migration."

              HELP = """
              Longer text explaining purpose of the migration and, ideally,
              giving code examples.

              """

              AFTER_VERSION = "0.22.1"

              TESTS = []

              visitor = MyMigration

          add_migration(Migrator)

   Providing details about the migration
       The purpose of Migrator class in the code above is to provide the information about the migration.

       It is important that the information is as helpful as possible as it is used in multiple places.

       • The ID attribute is a short, unique name to  identify  the  migration.  This  allows  users  to  select
         specific migrations to run via qtile migrate --run-migrations ID.

       • The  SUMMARY attribute is used to provide a brief summary of the migration and is used when a user runs
         qtile migrate --list-migrations. It is also used in the documentation.

       • Similarly, the HELP attribute is used for the script (qtie migrate --info ID)  and  the  documentation.
         This  text should be longer and can include example code. As it is used in the documentation, it should
         use RST syntax (e.g. .. code:: python for codeblocks etc.).

       • AFTER_VERSION should be set the name of the current release. This allows users to filter migrations  to
         those that were added after the last release.

       • The  visitor  attribute  is  a  link  to  the  class definition (not and instance of the class) for the
         transformer that you wish to use.

       • The add_migration call at the end is required to ensure the  migration  is  loaded  into  the  list  of
         available migrations.

       • See below for details on TESTS.

   How migrations are run
       You  are pretty much free to transform the code as you see fit. By default, the script will run the visit
       method on the parsed code and will pass  the  visitor  attribute  of  the  _QtileMigrator  class  object.
       Therefore,  if  all  your transformations can be performed in a single visitor, it is not necessary to do
       anything further in the Migrator class.

       However, if you want to run multiple visitors, transformers, codemods, this is possible by overriding the
       run method of the _QtileMigrator class. For example, the RemoveCmdPrefix migrator has the following code:

          def run(self, original):
              # Run the base migrations
              transformer = CmdPrefixTransformer()
              updated = original.visit(transformer)
              self.update_lint(transformer)

              # Check if we need to add an import line
              if transformer.needs_import:
                  # We use the built-in visitor to add the import
                  context = codemod.CodemodContext()
                  AddImportsVisitor.add_needed_import(
                      context, "libqtile.command.base", "expose_command"
                  )
                  visitor = AddImportsVisitor(context)

                  # Run the visitor over the updated code
                  updated = updated.visit(visitor)

              return original, updated

       In this migration, it may be required to add an import statement. LibCST has  a  built-in  transformation
       for doing this so we can run that after our own transformation has been performed.

       IMPORTANT:
          The run method must return a tuple of the original code and the updated code.

   Transforming the code
       It  is recommended that you use a transformed to update the code. For convenience, a MigrationTransformer
       class is defined in libqtile.scripts.migrations._base.  This  class  definition  includes  some  metadata
       information and a lint method for outputting details of errors.

       Let's  look  at an example transformer to understand how the migration works. The code below shows how to
       change a positional argument to a keyword argument in the WidgetBox widget.

          class WidgetboxArgsTransformer(MigrationTransformer):
              @m.call_if_inside(
                  m.Call(func=m.Name("WidgetBox")) | m.Call(func=m.Attribute(attr=m.Name("WidgetBox")))
              )
              @m.leave(m.Arg(keyword=None))
              def update_widgetbox_args(self, original_node, updated_node) -> cst.Arg:
                  """Changes positional  argumentto 'widgets' kwargs."""
                  self.lint(
                      original_node,
                      "The positional argument should be replaced with a keyword argument named 'widgets'.",
                  )
                  return updated_node.with_changes(keyword=cst.Name("widgets"), equal=EQUALS_NO_SPACE)

       Our  class  (which  inherits  from  MigrationTransformer)  defines  a  single  method  to   perform   the
       transformation.  We  take  advantage  of  LibCST  and  its  Matchers  to  narrow  the  scope  of when the
       transformation is run.

       We are looking to modify an argument so we use the @m.leave(m.Arg()) decorator to call  the  function  at
       end of parsing an argument. We can restrict when this is called by specify m.Arg(keyword=None) so that it
       is  only  called  for  positional  arguments.   Furthermore,  as  we  only want this called for WidgetBox
       instantiation lines, we add an additional decorator @m.call_if_inside(m.Call()). This ensures the  method
       is  only called when we're in a call. On its own, that's not helpful as args would  almost always be part
       of a call. However, we can say we only want to match calls to WidgetBox. The reason for the  long  syntax
       above  is  that LibCST parses WidgetBox() and widget.WidgetBox() differently. In the first one, WidgetBox
       is in the func property of the call.  However, in the second, the func is an Attribute as it is a  dotted
       name and so we need to check the attr property.

       The  decorated method takes two arguments, original_mode and updated_node (note: The original_node should
       not be modified).  The method should also confirm the return type.

       The above method provides a linting message by calling self.lint and passing  the  original  node  and  a
       helpful message.

       Finally,  the  method updates the code by calling updated_node.with_changes(). In this instance, we add a
       keyword ("widgets") to the argument. We also remove spaces around the equals sign as these are  added  by
       default by LibCST. The updated node is returned.

   Helper classes
       Helper classes are provided for common transformations.

       • RenamerTransformer  will update all instances of a name, replacing it with another. The class will also
         handle the necessary linting.

            class RenameHookTransformer(RenamerTransformer):
                from_to = ("window_name_change", "client_name_updated")

   Testing the migration
       All migrations must be tested, ideally with a number of scenarios to confirm that the migration works  as
       expected.

       Unlike other tests, the tests for the migrations are defined within the TESTS attribute.

       This  is  a  list  that  should  take  a  Check,  Change  or  NoChange  object  (all  are  imported  from
       libqtile.scripts.migrations._base).

       A Change object needs two parameters, the input code and the expected  output.  A  NoChange  object  just
       defines the input (as the output should be the same).

       A  Check  object  is  identical to Change however, when running the test suite, the migrated code will be
       verified with qtile check. The code will therefore need to include all relevant imports etc.

       Based on the above, the following is recommended as best practice:

       • Define one Check test which addresses every situation anticipated by the migration

       • Use as many Change tests as required to test individual scenarios in a minimal way

       • Use NoChange tests where there are specific cases that should not be modified

       • Depending on the simplicity of the migration, a single Check may be all that is required

       For example, the RemoveCmdPrefix migration has the following TESTS:

          TESTS = [
              Change("""qtile.cmd_spawn("alacritty")""", """qtile.spawn("alacritty")"""),
              Change("""qtile.cmd_groups()""", """qtile.get_groups()"""),
              Change("""qtile.cmd_screens()""", """qtile.get_screens()"""),
              Change("""qtile.current_window.cmd_hints()""", """qtile.current_window.get_hints()"""),
              Change(
                  """qtile.current_window.cmd_opacity(0.5)""",
                  """qtile.current_window.set_opacity(0.5)""",
              ),
              Change(
                  """
                  class MyWidget(widget.Clock):
                      def cmd_my_command(self):
                          pass
                  """,
                  """
                  from libqtile.command.base import expose_command

                  class MyWidget(widget.Clock):
                      @expose_command
                      def my_command(self):
                          pass
                  """
              ),
              NoChange(
                  """
                  def cmd_some_other_func():
                      pass
                  """
              ),
              Check(
                  """
                  from libqtile import qtile, widget

                  class MyClock(widget.Clock):
                      def cmd_my_exposed_command(self):
                          pass

                  def my_func(qtile):
                      qtile.cmd_spawn("rickroll")
                      hints = qtile.current_window.cmd_hints()
                      groups = qtile.cmd_groups()
                      screens = qtile.cmd_screens()
                      qtile.current_window.cmd_opacity(0.5)

                  def cmd_some_other_func():
                      pass
                  """,
                  """
                  from libqtile import qtile, widget
                  from libqtile.command.base import expose_command

                  class MyClock(widget.Clock):
                      @expose_command
                      def my_exposed_command(self):
                          pass

                  def my_func(qtile):
                      qtile.spawn("rickroll")
                      hints = qtile.current_window.get_hints()
                      groups = qtile.get_groups()
                      screens = qtile.get_screens()
                      qtile.current_window.set_opacity(0.5)

                  def cmd_some_other_func():
                      pass
                  """
              )
          ]

       The tests check:

       • cmd_ prefix is removed on method calls, updating specific changes as required

       • Exposed methods in a class should use the expose_command decorator  (adding  the  import  if  it's  not
         already included)

       • No change is made to a function definition (as it's not part of a class definition)

       NOTE:
          Tests will fail in the following scenarios:

          • If no tests are defined

          • If a Change test does not result in linting output

          • If no Check test is defined

       You  can  check  your tests by running pytest -k <YourMigrationID>. Note, mpypy must be installed for the
       Check tests to be run.

   Deprecation Policy
       Interfaces that have been deprecated for at least two  years  after  the  first  release  containing  the
       deprecation  notice can be deleted. Since all new breaking changes should have a migration, users can use
       qtile migrate to bootstrap across versions when migrations are deleted if necessary.

       Deprecated interfaces that do not have a migration (i.e. whose deprecation was noted before the migration
       feature was introduced) are all fair game to be deleted, since the migration feature  is  more  than  two
       years old.

FREQUENTLY ASKED QUESTIONS

   Why the name Qtile?
       Users  often  wonder,  why the Q? Does it have something to do with Qt? No. Below is an IRC excerpt where
       cortesi explains the great trial that ultimately brought Qtile into existence, thanks to the  benevolence
       of the Open Source Gods. Praise be to the OSG!

          ramnes:  what does Qtile mean?
          ramnes:  what's the Q?
          @tych0:  ramnes: it doesn't :)
          @tych0:  cortesi was just looking for the first letter that wasn't registered
                   in a domain name with "tile" as a suffix
          @tych0:  qtile it was :)
          cortesi: tych0, dx: we really should have something more compelling to
                   explain the name. one day i was swimming at manly beach in sydney,
                   where i lived at the time. suddenly, i saw an enormous great white
                   right beside me. it went for my leg with massive, gaping jaws, but
                   quick as a flash, i thumb-punched it in both eyes. when it reared
                   back in agony, i saw that it had a jagged, gnarly scar on its
                   stomach... a scar shaped like the letter "Q".
          cortesi: while it was distracted, i surfed a wave to shore. i knew that i
                   had to dedicate my next open source project to the ocean gods, in
                   thanks for my lucky escape. and thus, qtile got its name...

   When  I  first  start  xterm/urxvt/rxvt containing an instance of Vim, I see text and layout corruption. What
       gives?
       Vim is not handling terminal resizes correctly. You can fix the problem by starting your xterm  with  the
       "-wf" option, like so:

          xterm -wf -e vim

       Alternatively, you can just cycle through your layouts a few times, which usually seems to fix it.

   How do I know which modifier specification maps to which key?
       To  see  a  list  of  modifier  names and their matching keys, use the xmodmap command. On my system, the
       output looks like this:

          $ xmodmap
          xmodmap:  up to 3 keys per modifier, (keycodes in parentheses):

          shift       Shift_L (0x32),  Shift_R (0x3e)
          lock        Caps_Lock (0x9)
          control     Control_L (0x25),  Control_R (0x69)
          mod1        Alt_L (0x40),  Alt_R (0x6c),  Meta_L (0xcd)
          mod2        Num_Lock (0x4d)
          mod3
          mod4        Super_L (0xce),  Hyper_L (0xcf)
          mod5        ISO_Level3_Shift (0x5c),  Mode_switch (0xcb)

   My "pointer mouse cursor" isn't the one I expect it to be!
       Qtile should set the default cursor to left_ptr, you must install xcb-util-cursor if you want support for
       themed cursors.

   LibreOffice menus don't appear or don't stay visible
       A  workaround  for  problem  with  the  mouse  in  libreoffice  is  setting  the   environment   variable
       »SAL_USE_VCLPLUGIN=gen«.   It  is  dependent  on  your  system configuration as to where to do this. e.g.
       ArchLinux with libreoffice-fresh in /etc/profile.d/libreoffice-fresh.sh.

   How can I get my groups to stick to screens?
       This behaviour can be replicated by configuring your keybindings to not move groups between screens.  For
       example  if you want groups "1", "2" and "3" on one screen and "q", "w", and "e" on the other, instead of
       binding keys to lazy.group[name].toscreen(), use this:

          groups = [
              # Screen affinity here is used to make
              # sure the groups startup on the right screens
              Group(name="1", screen_affinity=0),
              Group(name="2", screen_affinity=0),
              Group(name="3", screen_affinity=0),
              Group(name="q", screen_affinity=1),
              Group(name="w", screen_affinity=1),
              Group(name="e", screen_affinity=1),
          ]

          def go_to_group(name: str):
              def _inner(qtile):
                  if len(qtile.screens) == 1:
                      qtile.groups_map[name].toscreen()
                      return

                  if name in '123':
                      qtile.focus_screen(0)
                      qtile.groups_map[name].toscreen()
                  else:
                      qtile.focus_screen(1)
                      qtile.groups_map[name].toscreen()

              return _inner

          for i in groups:
              keys.append(Key([mod], i.name, lazy.function(go_to_group(i.name))))

       To be able to move windows across these groups which switching groups, a similar function can be used:

          def go_to_group_and_move_window(name: str):
              def _inner(qtile):
                  if len(qtile.screens) == 1:
                      qtile.current_window.togroup(name, switch_group=True)
                      return

                  if name in "123":
                      qtile.current_window.togroup(name, switch_group=False)
                      qtile.focus_screen(0)
                      qtile.groups_map[name].toscreen()
                  else:
                      qtile.current_window.togroup(name, switch_group=False)
                      qtile.focus_screen(1)
                      qtile.groups_map[name].toscreen()

              return _inner

          for i in groups:
              keys.append(Key([mod, "shift"], i.name, lazy.function(go_to_group_and_move_window(i.name))))

       If you use the GroupBox widget you can make it reflect this behaviour:

          groupbox1 = widget.GroupBox(visible_groups=['1', '2', '3'])
          groupbox2 = widget.GroupBox(visible_groups=['q', 'w', 'e'])

       And if you jump between having single and double screens then modifying the visible groups on the fly may
       be useful:

          @hook.subscribe.screens_reconfigured
          async def _():
              if len(qtile.screens) > 1:
                  groupbox1.visible_groups = ['1', '2', '3']
              else:
                  groupbox1.visible_groups = ['1', '2', '3', 'q', 'w', 'e']
              if hasattr(groupbox1, 'bar'):
                  groupbox1.bar.draw()

   Where can I find example configurations and other scripts?
       Please visit our qtile-examples repo which contains examples of users' configurations, scripts and  other
       useful links.

   Where are the log files for Qtile?
       The log files for qtile are at ~/.local/share/qtile/qtile.log.

   How can I match the bar with picom?
       You  can  use "QTILE_INTERNAL:32c = 1" in your picom.conf to match the bar.  This will match all internal
       Qtile windows, so if you want to avoid that or to target bars individually, you can set a custom property
       and match that:

          mybar = Bar(...)

          @hook.subscribe.startup
          def _():
              mybar.window.window.set_property("QTILE_BAR", 1, "CARDINAL", 32)

       This would enable matching on mybar's window using "QTILE_BAR:32c = 1".   See  2526  and  1515  for  more
       discussion.

   Why do get a warning that fonts cannot be loaded?
       When   installing   Qtile   on  a  new  system,  when  running  the  test  suite  or  the  Xephyr  script
       (./scripts/xephyr), you might see errors in the output like the following or similar:

       • Xephyr script:

            xterm: cannot load font "-Misc-Fixed-medium-R-*-*-13-120-75-75-C-120-ISO10646-1"
            xterm: cannot load font "-misc-fixed-medium-r-semicondensed--13-120-75-75-c-60-iso10646-1"

       • pytest:

            ---------- Captured stderr call ----------
            Warning: Cannot convert string "8x13" to type FontStruct
            Warning: Unable to load any usable ISO8859 font
            Warning: Unable to load any usable ISO8859 font
            Error: Aborting: no font found

            -------- Captured stderr teardown --------
            Qtile exited with exitcode: -9

       If it happens, it might be because you're missing fonts on your system.

       On ArchLinux, you can fix this by installing xorg-fonts-misc:

          sudo pacman -S xorg-fonts-misc

       Try to search for "xorg fonts misc" with your distribution name on the internet to find  how  to  install
       them.

   I've upgraded and Qtile's broken. What do I do?
       If you've recently upgraded, the first thing to do is check the changelog and see if any breaking changes
       were made.

       Next, check your log file (see above) to see if any error messages explain what the problem is.

       If you're still stuck, come and ask for help on Discord, IRC or GitHub.

HOW TO CREATE A WIDGET

       The  aim  of this page is to explain the main components of qtile widgets, how they work, and how you can
       use them to create your own widgets.

       NOTE:
          This page is not meant to be an exhaustive summary of everything needed to make a widget.

          It is highly recommended  that  users  wishing  to  create  their  own  widget  refer  to  the  source
          documentation of existing widgets to familiarise themselves with the code.

          However, the detail below may prove helpful when read in conjunction with the source code.

   What is a widget?
       In  Qtile,  a widget is a small drawing that is displayed on the user's bar. The widget can display text,
       images and drawings. In addition, the widget  can  be  configured  to  update  based  on  timers,  hooks,
       dbus_events etc. and can also respond to mouse events (clicks, scrolls and hover).

   Widget base classes
       Qtile  provides  a  number  of  base  classes for widgets than can be used to implement commonly required
       features (e.g. display text).

       Your widget should inherit one of these classes. Whichever base class you inherit for your widget, if you
       override either the __init__ and/or _configure methods, you should make sure that your widget  calls  the
       equivalent method from the superclass.

          class MyCustomWidget(base._TextBox):

              def __init__(self, **config):
                  super().__init__("", **config)
                  # My widget's initialisation code here

       The functions of the various base classes are explained further below.

   _Widget
       This  is  the  base  widget class that defines the core components required for a widget.  All other base
       classes are based off this class.

       This is like a blank canvas so you're free to do what you want but  you  don't  have  any  of  the  extra
       functionality provided by the other base classes.

       The  base._Widget  class is therefore typically used for widgets that want to draw graphics on the widget
       as opposed to displaying text.

   _TextBox
       The base._TextBox class builds on the bare widget and adds a drawer.TextLayout which  is  accessible  via
       the self.layout property. The widget will adjust its size to fit the amount of text to be displayed.

       Text  can  be  updated  via the self.text property but note that this does not trigger a redrawing of the
       widget.

       Parameters including font, fontsize, fontshadow, padding and foreground (font colour) can be  configured.
       It is recommended not to hard-code these parameters as users may wish to have consistency across units.

   InLoopPollText
       The  base.InLoopPollText  class builds on the base._TextBox by adding a timer to periodically refresh the
       displayed text.

       Widgets using this class should override the poll method to include a function that returns the  required
       text.

       NOTE:
          This  loop  runs in the event loop so it is important that the poll method does not call some blocking
          function. If this is required, widgets should inherit the base.ThreadPoolText class (see below).

   ThreadPoolText
       The base.ThreadPoolText class is very similar to the base.InLoopPollText class.  The  key  difference  is
       that  the  poll  method  is  run asynchronously and triggers a callback once the function completes. This
       allows widgets to get text from long-running functions without blocking Qtile.

   Mixins
       As well as inheriting from one of the base classes above, widgets can also inherit one or more mixins  to
       provide some additional functionality to the widget.

   PaddingMixin
       This provides the padding(_x|_y|) attributes which can be used to change the appearance of the widget.

       If you use this mixin in your widget, you need to add the following line to your __init__ method:

          self.add_defaults(base.PaddingMixin.defaults)

   MarginMixin
       The MarginMixin is essentially effectively exactly the same as the PaddingMixin but, instead, it provides
       the margin(_x|_y|) attributes.

       As  above,  if  you  use  this  mixin in your widget, you need to add the following line to your __init__
       method:

          self.add_defaults(base.MarginMixin.defaults)

   Configuration
       Now you know which class to base your widget on, you need to know how the widget gets configured.

   Defining Parameters
       Each widget will likely have a number of parameters that users can change to customise the look and  feel
       and/or behaviour of the widget for their own needs.

       The  widget  should  therefore provide the default values of these parameters as a class attribute called
       defaults. The format of this attribute is a list of tuples.

          defaults = [
              ("parameter_name",
               default_parameter_value,
               "Short text explaining what parameter does")
          ]

       Users can override the default value when creating their config.py file.

          MyCustomWidget(parameter_name=updated_value)

       Once the widget is initialised, these parameters are available at self.parameter_name.

   The __init__ method
       Parameters that should not be changed by users can be defined in the __init__ method.

       This method is run when the widgets are initially created.  This  happens  before  the  qtile  object  is
       available.

   The _configure method
       The  _configure method is called by the bar object and sets the self.bar and self.qtile attributes of the
       widget. It also creates the self.drawer attribute which is necessary for displaying any content.

       Once this method has been run, your widget should be ready to display content as the bar will  draw  once
       it has finished its configuration.

       Calls  to  methods  required  to  prepare  the content for your widget should therefore be made from this
       method rather than __init__.

   Displaying output
       A Qtile widget is just a drawing that is displayed at a certain location the user's bar. The widget's job
       is therefore to create a small drawing surface that can be placed in the appropriate location on the bar.

   The "draw" method
       The draw method is called when the widget needs to update its appearance.  This can be triggered  by  the
       widget itself (e.g. if the content has changed) or by the bar (e.g. if the bar needs to redraw its entire
       contents).

       This  method therefore needs to contain all the relevant code to draw the various components that make up
       the widget. Examples of displaying text, icons and drawings are set out below.

       It is important to note that the bar controls the placing of the widget by assigning  the  offsetx  value
       (for horizontal positioning) and offsety value (for vertical positioning). Widgets should use this at the
       end  of  the  draw method. Both offsetx and offsety are required as both values will be set if the bar is
       drawing a border.

          self.drawer.draw(offsetx=self.offsetx, offsety=self.offsety, width=self.width)

       NOTE:
          If you need to trigger a redrawing of your widget, you should call self.draw() if the  width  of  your
          widget  is  unchanged.  Otherwise  you  need  to  call  self.bar.draw()  as  this method means the bar
          recalculates the position of all widgets.

   Displaying text
       Text is displayed by using a drawer.TextLayout object. If all you are doing is displaying text then  it's
       highly recommended that you use the base._TextBox superclass as this simplifies adding and updating text.

       If  you  wish  to  implement  this manually then you can create a your own drawer.TextLayout by using the
       self.drawer.textlayout method of the widget (only available after the _configure method  has  been  run).
       object to include in your widget.

       Some  additional formatting of Text can be displayed using pango markup and ensuring the markup parameter
       is set to True.

          self.textlayout = self.drawer.textlayout(
                               "Text",
                               "fffff",       # Font colour
                               "sans",        # Font family
                               12,            # Font size
                               None,          # Font shadow
                               markup=False,  # Pango markup (False by default)
                               wrap=True      # Wrap long lines (True by default)
                               )

   Displaying icons and images
       Qtile provides a helper library to convert images to a surface that can be drawn by the  widget.  If  the
       images are static then you should only load them once when the widget is configured. Given the small size
       of the bar, this is most commonly used to draw icons but the same method applies to other images.

          from libqtile import images

          def setup_images(self):

              self.surfaces = {}

              # File names to load (will become keys to the `surfaces` dictionary)
              names = (
                  "audio-volume-muted",
                  "audio-volume-low",
                  "audio-volume-medium",
                  "audio-volume-high"
              )

              d_images = images.Loader(self.imagefolder)(*names)  # images.Loader can take more than one folder as an argument

              for name, img in d_images.items():
                  new_height = self.bar.height - 1
                  img.resize(height=new_height)   # Resize images to fit widget
                  self.surfaces[name] = img.pattern  # Images added to the `surfaces` dictionary

       Drawing the image is then just a matter of painting it to the relevant surface:

          def draw(self):
              self.drawer.ctx.set_source(self.surfaces[img_name])  # Use correct key here for your image
              self.drawer.ctx.paint()
              self.drawer.draw(offsetx=self.offset, width=self.length)

   Drawing shapes
       It  is  possible  to draw shapes directly to the widget. The Drawer class (available in your widget after
       configuration  as  self.drawer)  provides  some  basic  functions  rounded_rectangle,   rounded_fillrect,
       rectangle and fillrect.

       In addition, you can access the Cairo context drawing functions via self.drawer.ctx.

       For example, the following code can draw a wifi icon showing signal strength:

          import math

          ...

          def to_rads(self, degrees):
              return degrees * math.pi / 180.0

          def draw_wifi(self, percentage):

              WIFI_HEIGHT = 12
              WIFI_ARC_DEGREES = 90

              y_margin = (self.bar.height - WIFI_HEIGHT) / 2
              half_arc = WIFI_ARC_DEGREES / 2

              # Draw grey background
              self.drawer.ctx.new_sub_path()
              self.drawer.ctx.move_to(WIFI_HEIGHT, y_margin + WIFI_HEIGHT)
              self.drawer.ctx.arc(WIFI_HEIGHT,
                                  y_margin + WIFI_HEIGHT,
                                  WIFI_HEIGHT,
                                  self.to_rads(270 - half_arc),
                                  self.to_rads(270 + half_arc))
              self.drawer.set_source_rgb("666666")
              self.drawer.ctx.fill()

              # Draw white section to represent signal strength
              self.drawer.ctx.new_sub_path()
              self.drawer.ctx.move_to(WIFI_HEIGHT, y_margin + WIFI_HEIGHT)
              self.drawer.ctx.arc(WIFI_HEIGHT
                                  y_margin + WIFI_HEIGHT,
                                  WIFI_HEIGHT * percentage,
                                  self.to_rads(270 - half_arc),
                                  self.to_rads(270 + half_arc))
              self.drawer.set_source_rgb("ffffff")
              self.drawer.ctx.fill()

       This creates something looking like this: [image: wifi_image] [image] .

   Background
       At  the  start  of the draw method, the widget should clear the drawer by drawing the background. Usually
       this is done by including the following line at the start of the method:

          self.drawer.clear(self.background or self.bar.background)

       The background can be a single colour or a list of colours which will result in a  linear  gradient  from
       top to bottom.

   Updating the widget
       Widgets  will usually need to update their content periodically. There are numerous ways that this can be
       done. Some of the most common ones are summarised below.

   Timers
       A non-blocking timer can be called by using the self.timeout_add method.

          self.timeout_add(delay_in_seconds, method_to_call, (method_args))

       NOTE:
          Consider using the  ThreadPoolText  superclass  where  you  are  calling  a  function  repeatedly  and
          displaying its output as text.

   Hooks
       Qtile has a number of hooks built in which are triggered on certain events.

       The  WindowCount  widget  is  a good example of using hooks to trigger updates. It includes the following
       method which is run when the widget is configured:

          from libqtile import hook

          ...

          def _setup_hooks(self):
              hook.subscribe.client_killed(self._win_killed)
              hook.subscribe.client_managed(self._wincount)
              hook.subscribe.current_screen_change(self._wincount)
              hook.subscribe.setgroup(self._wincount)

       Read the Built-in Hooks page for details of which hooks are available and which arguments are  passed  to
       the callback function.

   Using dbus
       Qtile uses dbus-fast for interacting with dbus.

       If  you  just  want  to listen for signals then Qtile provides a helper method called add_signal_receiver
       which can subscribe to a signal and trigger a callback whenever that signal is broadcast.

       NOTE:
          Qtile uses the asyncio based functions of dbus-fast so your widget must make  sure,  where  necessary,
          calls to dbus are made via coroutines.

          There  is  a  _config_async  coroutine  in the base widget class which can be overridden to provide an
          entry point for asyncio calls in your widget.

       For example, the Mpris2 widget uses the following code:

          from libqtile.utils import add_signal_receiver

          ...

          async def _config_async(self):
              subscribe = await add_signal_receiver(
                              self.message,  # Callback function
                              session_bus=True,
                              signal_name="PropertiesChanged",
                              bus_name=self.objname,
                              path="/org/mpris/MediaPlayer2",
                              dbus_interface="org.freedesktop.DBus.Properties")

       dbus-fast can also be used to query properties, call methods etc. on dbus  interfaces.  Refer  to  the  ‐
       dbus-fast documentation for more information on how to use the module.

   Mouse events
       By  default,  widgets handle button presses and will call any function that is bound to the button in the
       mouse_callbacks dictionary. The dictionary keys are as follows:

          • Button1: Left click

          • Button2: Middle click

          • Button3: Right click

          • Button4: Scroll up

          • Button5: Scroll down

          • Button6: Scroll left

          • Button7: Scroll right

       You can then define your button bindings in your widget (e.g. in __init__):

          class MyWidget(widget.TextBox)

              def __init__(self, *args, **config):
                  widget.TextBox.__init__(self, *args, **kwargs)
                  self.add_callbacks(
                      {
                          "Button1": self.left_click_method,
                          "Button3": self.right_click_method
                      }
                  )

       NOTE:
          As well as functions, you can also bind LazyCall objects to button presses.  For example:

              self.add_callbacks(
                  {
                      "Button1": lazy.spawn("xterm"),
                  }
              )

       In addition to button presses, you can also respond to mouse enter and leave  events.   For  example,  to
       make a clock show a longer date when you put your mouse over it, you can do the following:

          class MouseOverClock(widget.Clock):
              defaults = [
                  (
                      "long_format",
                      "%A %d %B %Y | %H:%M",
                      "Format to show when mouse is over widget."
                  )
              ]

              def __init__(self, **config):
                  widget.Clock.__init__(self, **config)
                  self.add_defaults(MouseOverClock.defaults)
                  self.short_format = self.format

              def mouse_enter(self, *args, **kwargs):
                  self.format = self.long_format
                  self.bar.draw()

              def mouse_leave(self, *args, **kwargs):
                  self.format = self.short_format
                  self.bar.draw()

   Exposing commands to the IPC interface
       If  you want to control your widget via lazy or scripting commands (such as qtile cmd-obj), you will need
       to expose the relevant methods in your widget. Exposing commands is done by adding the  @expose_command()
       decorator to your method. For example:

          from libqtile.command.base import expose_command
          from libqtile.widget import TextBox

          class ExposedWidget(TextBox):

              @expose_command()
              def uppercase(self):
                  self.update(self.text.upper())

       Text     in    the    ExposedWidget    can    now    be    made    into    upper    case    by    calling
       lazy.widget["exposedwidget"].uppercase() or qtile cmd-onj -o widget exposedwidget -f uppercase.

       If you want to expose a method under  multiple  names,  you  can  pass  these  additional  names  to  the
       decorator. For example, decorating a method with:

          @expose_command(["extra", "additional"])
          def mymethod(self):
              ...

       will make make the method visible under mymethod, extra and additional.

   Debugging
       You can use the logger object to record messages in the Qtile log file to help debug your development.

          from libqtile.log_utils import logger

          ...

          logger.debug("Callback function triggered")

       NOTE:
          The  default  log level for the Qtile log is INFO so you may either want to change this when debugging
          or use logger.info instead.

          Debugging messages should be removed from your code before submitting pull requests.

   Submitting the widget to the official repo
       The following sections are only relevant for users who wish for their widgets to be submitted as a PR for
       inclusion in the main Qtile repo.

   Including the widget in libqtile.widget
       You should include your widget in the widgets dict in libqtile.widget.__init__.py.  The  relevant  format
       is {"ClassName": "modulename"}.

       This has a number of benefits:

       • Lazy imports

       • Graceful handling of import errors (useful where widget relies on third party modules)

       • Inclusion in basic unit testing (see below)

   Testing
       Any new widgets should include an accompanying unit test.

       Basic   initialisation   and   configurations   (using   defaults)   will   automatically  be  tested  by
       test/widgets/test_widget_init_configure.py if the widget has been included in libqtile.widget.__init__.py
       (see above).

       However, where possible, it is strongly encouraged that widgets include additional unit tests  that  test
       specific functionality of the widget (e.g. reaction to hooks).

       See Unit testing for more.

   Documentation
       It  is  really  important  that  we maintain good documentation for Qtile. Any new widgets must therefore
       include sufficient documentation in order for users to understand how to use/configure the widget.

       The majority of the documentation is generated automatically from your  module.  The  widget's  docstring
       will  be used as the description of the widget. Any parameters defined in the widget's defaults attribute
       will also be displayed. It is essential that there is a clear explanation of each new  parameter  defined
       by the widget.

   Screenshots
       While not essential, it is strongly recommended that the documentation includes one or more screenshots.

       Screenshots  can be generated automatically with a minimal amount of coding by using the fixtures created
       by Qtile's test suite.

       A screenshot file must satisfy the following criteria:

          • Be named ss_[widgetname].py

          • Any function that takes a screenshot must be prefixed with ss_

          • Define a pytest fixture named widget

       An example screenshot file is below:

          import pytest

          from libqtile.widget import wttr
          from test.widgets.docs_screenshots.conftest import vertical_bar, widget_config

          RESPONSE = "London: +17°C"

          @pytest.fixture
          def widget(monkeypatch):
              def result(self):
                  return RESPONSE

              monkeypatch.setattr("libqtile.widget.wttr.Wttr.fetch", result)
              yield wttr.Wttr

          @widget_config([{"location": {"London": "Home"}}])
          def ss_wttr(screenshot_manager):
              screenshot_manager.take_screenshot()

          @vertical_bar
          def ss_wttr_vertical(screenshot_manager):
              screenshot_manager.take_screenshot()

       The widget fixture returns the widget class (not an instance of the widget). Any  monkeypatching  of  the
       widget should be included in this fixture.

       The  screenshot  function  (here,  called  ss_wttr) must take an argument called screenshot_manager.  The
       function can also be parameterized, in which case, each dict object will be used to configure the  widget
       for  the  screenshot  (and  the  configuration  will  be  displayed  in the docs). If you want to include
       parameterizations but also want to show the default configuration, you should include an empty dict  ({})
       as the first object in the list.

       Taking  a screenshot is then as simple as calling screenshot_manager.take_screenshot(). The method can be
       called multiple times in the same function.

       Screenshots can also be taken in a vertical bar orientation by using the @vertical_bar decorator as shown
       in the above example.

       screenshot_manager.take_screenshot() only takes a picture of the widget. If you need to take a screenshot
       of the bar then you need a few extra steps:

          def ss_bar_screenshot(screenshot_manager):
              # Generate a filename for the screenshot
              target = screenshot_manager.target()

              # Get the bar object
              bar = screenshot_manager.c.bar["top"]

              # Take a screenshot. Will take screenshot of whole bar unless
              # a `width` parameter is set.
              bar.take_screenshot(target, width=width)

   Getting help
       If you still need help with developing your widget then please submit a question in the  qtile-dev  group
       or submit an issue on the github page if you believe there's an error in the codebase.

HOW TO CREATE A LAYOUT

       The  aim  of this page is to explain the main components of qtile layouts, how they work, and how you can
       use them to create your own layouts or hack existing layouts to make them work the way you want them.

       NOTE:
          It is highly recommended  that  users  wishing  to  create  their  own  layout  refer  to  the  source
          documentation of existing layouts to familiarise themselves with the code.

   What is a layout?
       In  Qtile,  a  layout is essentially a set of rules that determine how windows should be displayed on the
       screen. The layout is responsible for positioning all  windows  other  than  floating  windows,  "static"
       windows,  internal windows (e.g. the bar) and windows that have requested not to be managed by the window
       manager.

   Base classes
       To simplify the creation of layouts, a couple of base classes are available to users.

   The Layout class
       As a bare minimum, all layouts should inherit the base Layout class object as this class defines a number
       of methods required for basic usage  and  will  also  raise  errors  if  the  required  methods  are  not
       implemented. Further information on these required methods is set out below.

   The _SimpleLayoutBase class
       This  class  implements  everything needed for a basic layout with the exception of the configure method.
       Therefore, unless your layout requires special logic for updating and navigating the list of clients,  it
       is strongly recommended that your layout inherits this base class

   The _ClientList class
       This class defines a list of clients and the current client.

       The  collection  is  meant  as a base or utility class for special layouts, which need to maintain one or
       several collections of windows, for example Columns or Stack, which use this  class  as  base  for  their
       internal helper.

       The  property  current_index get and set the index to the current client, whereas current_client property
       can be used with clients directly.

   Required methods
       To create a minimal, functioning layout your layout must include the methods listed below:

       • __init__configureadd_clientremovefocus_firstfocus_lastfocus_nextfocus_previousnextprevious

       As noted above, if you create a layout based on the _SimpleLayoutBase class, you will only need to define
       configure (and _init__, if you have custom parameters). However, for the purposes of  this  document,  we
       will show examples of all required methods.

   __init__
       Initialise  your  layout's  variables  here.  The  main  use  of  this method will be to load any default
       parameters defined by layout. These are defined in a class attribute called defaults. The format of  this
       attribute is a list of tuples.

          from libqtile.layout import base

          class TwoByTwo(base.Layout):
              """
              A simple layout with a fixed two by two grid.

              By default, unfocused windows are smaller than the focused window.
              """
              defaults = [
                  ("border_width", 5, "Window border width"),
                  ("border_colour", "00ff00", "Window border colour"),
                  ("margin_focused", 5, "Margin width for focused windows"),
                  ("margin_unfocused", 50, "Margin width for unfocused windows")
              ]

              def __init__(self, **config):
                  base.Layout.__init__(self, **config)
                  self.add_defaults(TwoByTwo.defaults)
                  self.clients = []
                  self.current_client = None

       Once the layouts is initialised, these parameters are available at self.border_width etc.

   configure
       This  is  where the magic happens! This method is responsible for determining how to position a window on
       the screen.

       This method should therefore configure the dimensions and borders of a window using the window's .place()
       method. The layout can also call either hide() or .unhide() on the window.

          def configure(self, client: Window, screen_rect: ScreenRect) -> None:
              """Simple example breaking screen into four quarters."""
              try:
                  index = self.clients.index(client)
              except ValueError:
                  # Layout not expecting this window so ignore it
                  return

              # We're only showing first 4 windows
              if index > 3:
                  client.hide()
                  return

              # Unhide the window in case it was hiddent before
              client.unhide()

              # List to help us calculate x and y values of
              quarters = [
                  (0, 0),
                  (0.5, 0),
                  (0, 0.5),
                  (0.5, 0.5)
              ]

              # Calculate size and position for each window
              xpos, ypos = quarters[index]

              x = int(screen_rect.width * xpos) + screen_rect.x
              y = int(screen_rect.height * ypos) + screen_rect.y
              w = screen_rect.width // 2
              h = screen_rect.height // 2

              if client is self.current_client:
                  margin = self.margin_focused
              else:
                  margin = self.margin_unfocused

              client.place(
                  x,
                  y,
                  w - self.border_width * 2,
                  h - self.border_width * 2,
                  self.border_width,
                  self.border_colour,
                  margin=[margin] * 4,
              )

   add_client
       This method is called whenever a window is added to the  group,  regardless  of  whether  the  layout  is
       current  or not. The layout should just add the window to its internal datastructures, without mapping or
       configuring/displaying.

          def add_client(self, client: Window) -> None:
              # Assumes self.clients is simple list
              self.clients.insert(0, client)
              self.current_client = client

   remove
       This method is called whenever a window is removed from the group, regardless of whether  the  layout  is
       current or not. The layout should just de-register the window from its data structures, without unmapping
       the window.

       The  method  must  also  return  the  "next"  window that should gain focus or None if there are no other
       windows.

          def remove(self, client: Window) -> Window | None:
              # Assumes self.clients is a simple list
              # Client already removed so ignore this
              if client not in self.clients:
                  return None
              # Client is only window in the list
              elif len(self.clients) == 1:
                  self.clients.remove(client)
                  self.current_client = None
                  # There are no other windows so return None
                  return None
              else:
                  # Find position of client in our list
                  index = self.clients.index(client)
                  # Remove client
                  self.clients.remove(client)
                  # Ensure the index value is not greater than list size
                  # i.e. if we closed the last window in the list, we need to return
                  # the first one (index 0).
                  index %= len(self.clients)
                  next_client = self.clients[index]
                  self.current_client = next_client
                  return next_client

   focus_first
       This method is called when the first client in the layout should be focused.

       This method should just return the first client in the layout, if any. NB the method should not focus the
       client itself, this is done by caller.

          def focus_first(self) -> Window | None:
              if not self.clients:
                  return None

              return self.client[0]

   focus_last
       This method is called when the last client in the layout should be focused.

       This method should just return the last client in the layout, if any. NB the method should not focus  the
       client itself, this is done by caller.

          def focus_last(self) -> Window | None:
              if not self.clients:
                  return None

              return self.client[-1]

   focus_next
       This method is called the next client in the layout should be focused.

       This  method  should return the next client in the layout, if any. NB the layout should not cycle clients
       when reaching the end of the list as there are other method in the group for cycling windows which  focus
       floating windows once the the end of the tiled client list is reached.

       In addition, the method should not focus the client.

          def focus_next(self, win: Window) -> Window | None:
              try:
                  return self.clients[self.clients.index(win) + 1]
              except IndexError:
                  return None

   focus_previous
       This method is called the previous client in the layout should be focused.

       This  method  should  return  the  previous  client in the layout, if any. NB the layout should not cycle
       clients when reaching the end of the list as there are other method in  the  group  for  cycling  windows
       which focus floating windows once the the end of the tiled client list is reached.

       In addition, the method should not focus the client.

          def focus_previous(self, win: Window) -> Window | None:
              if not self.clients or self.clients.index(win) == 0
                  return None

              try:
                  return self.clients[self.clients.index(win) - 1]
              except IndexError:
                  return None

   next
       This method focuses the next tiled window and can cycle back to the beginning of the list.

          def next(self) -> None:
              if self.current_client is None:
                  return
              # Get the next client or, if at the end of the list, get the first
              client = self.focus_next(self.current_client) or self.focus_first()
              self.group.focus(client, True)

   previous
       This method focuses the previous tiled window and can cycle back to the end of the list.

          def previous(self) -> None:
              if self.current_client is None:
                  return
              # Get the previous client or, if at the end of the list, get the last
              client = self.focus_previous(self.current_client) or self.focus_last()
              self.group.focus(client, True)

   Additional methods
       While not essential to implement, the following methods can also be defined:

       • cloneshowhideswapfocusblur

   clone
       Each  group  gets  a  copy  of  the  layout.  The  clone  method is used to create this copy. The default
       implementation in Layout is as follows:

          def clone(self, group: _Group) -> Self:
              c = copy.copy(self)
              c._group = group
              return c

   show
       This method can be used to run code when the layout is being displayed. The method receives one argument,
       the ScreenRect for the screen showing the layout.

       The default implementation is a no-op:

          def show(self, screen_rect: ScreenRect) -> None:
              pass

   hide
       This method can be used to run code when the layout is being hidden.

       The default implementation is a no-op:

          def hide(self) -> None:
              pass

   swap
       This method is used to change the position of two windows in the layout.

          def swap(self, c1: Window, c2: Window) -> None:
              if c1 not in self.clients and c2 not in self.clients:
                  return

              index1 = self.clients.index(c1)
              index2 = self.clients.index(c2)

              self.clients[index1], self.clients[index2] = self.clients[index2], self.clients[index1]

   focus
       This method is called when a given window is being focused.

          def focus(self, client: Window) -> None:
              if client not in self.clients:
                  self.current_client = None
                  return

              index = self.clients.index(client)

              # Check if window is not visible
              if index > 3:
                  c = self.clients.pop(index)
                  self.clients.insert(0, c)

              self.current_client = client

   blur
       This method is called when the layout loses focus.

          def blur(self) -> None:
              self.current_client = None

   Adding commands
       Adding commands allows users to modify the behaviour of the layout. To make commands  available  via  the
       command interface (e.g. via lazy.layout calls), the layout must include the following import:

          from libqtile.command.base import expose_command

       Commands are then decorated with @expose_command. For example:

          @expose_command
          def rotate(self, clockwise: bool = True) -> None:
              if not self.clients:
                  return

              if clockwise:
                  client = self.clients.pop(-1)
                  self.clients.insert(0, client)
              else:
                  client = self.clients.pop(0)
                  self.clients.append(client)

              # Check if current client has been rotated off the screen
              if self.current_client and self.clients.index(self.current_client) > 3:
                  if clockwise:
                      self.current_client = self.clients[3]
                  else:
                      self.current_client = self.clients[0]

              # Redraw the layout
              self.group.layout_all()

   The info command
       Layouts should also implement an info method to provide information about the layout.

       As a minimum, the test suite (see below) will expect a layout to return the following information:

       • Its name

       • Its group

       • The clients managed by the layout

       NB  the  last  item  is  not included in Layout's implementation of the method so it should be added when
       defining a class that inherits that base.

          @expose_command
          def info(self) -> dict[str, Any]:
              inf = base.Layout.info(self)
              inf["clients"] = self.clients
              return inf

   Adding layout to main repo
       If you think your layout is amazing and you want to share with other users by including it  in  the  main
       repo then there are a couple of extra steps that you need to take.

   Add to list of layouts
       You  must  save  the  layout  in  libqtile/layout  and then add a line importing the layout definition to
       libqtile/layout/__init__.py e.g.

          from libqtile.layout.twobytwo import TwoByTwo

   Add tests
       Basic functionality for all layouts is handled automatically by the core test suite. However, you  should
       create tests for any custom functionality of your layout (e.g. testing the rotate command defined above).

   Full example
       The full code for the example layout is as follows:

          from __future__ import annotations

          from typing import TYPE_CHECKING

          from libqtile.command.base import expose_command
          from libqtile.layout import base

          if TYPE_CHECKING:
              from libqtile.backend.base import Window
              from libqtile.config import ScreenRect
              from libqtile.group import _Group

          class TwoByTwo(base.Layout):
              """
              A simple layout with a fixed two by two grid.

              By default, unfocused windows are smaller than the focused window.
              """
              defaults = [
                  ("border_width", 5, "Window border width"),
                  ("border_colour", "00ff00", "Window border colour"),
                  ("margin_focused", 5, "Margin width for focused windows"),
                  ("margin_unfocused", 50, "Margin width for unfocused windows")
              ]

              def __init__(self, **config):
                  base.Layout.__init__(self, **config)
                  self.add_defaults(TwoByTwo.defaults)
                  self.clients = []
                  self.current_client = None

              def configure(self, client: Window, screen_rect: ScreenRect) -> None:
                  """Simple example breaking screen into four quarters."""
                  try:
                      index = self.clients.index(client)
                  except ValueError:
                      # Layout not expecting this window so ignore it
                      return

                  # We're only showing first 4 windows
                  if index > 3:
                      client.hide()
                      return

                  # Unhide the window in case it was hiddent before
                  client.unhide()

                  # List to help us calculate x and y values of
                  quarters = [
                      (0, 0),
                      (0.5, 0),
                      (0, 0.5),
                      (0.5, 0.5)
                  ]

                  # Calculate size and position for each window
                  xpos, ypos = quarters[index]

                  x = int(screen_rect.width * xpos) + screen_rect.x
                  y = int(screen_rect.height * ypos) + screen_rect.y
                  w = screen_rect.width // 2
                  h = screen_rect.height // 2

                  if client is self.current_client:
                      margin = self.margin_focused
                  else:
                      margin = self.margin_unfocused

                  client.place(
                      x,
                      y,
                      w - self.border_width * 2,
                      h - self.border_width * 2,
                      self.border_width,
                      self.border_colour,
                      margin=[margin] * 4,
                  )

              def add_client(self, client: Window) -> None:
                  # Assumes self.clients is simple list
                  self.clients.insert(0, client)
                  self.current_client = client

              def remove(self, client: Window) -> Window | None:
                  # Assumes self.clients is a simple list
                  # Client already removed so ignore this
                  if client not in self.clients:
                      return None
                  # Client is only window in the list
                  elif len(self.clients) == 1:
                      self.clients.remove(client)
                      self.current_client = None
                      # There are no other windows so return None
                      return None
                  else:
                      # Find position of client in our list
                      index = self.clients.index(client)
                      # Remove client
                      self.clients.remove(client)
                      # Ensure the index value is not greater than list size
                      # i.e. if we closed the last window in the list, we need to return
                      # the first one (index 0).
                      index %= len(self.clients)
                      next_client = self.clients[index]
                      self.current_client = next_client
                      return next_client

              def focus_first(self) -> Window | None:
                  if not self.clients:
                      return None

                  return self.client[0]

              def focus_last(self) -> Window | None:
                  if not self.clients:
                      return None

                  return self.client[-1]

              def focus_next(self, win: Window) -> Window | None:
                  try:
                      return self.clients[self.clients.index(win) + 1]
                  except IndexError:
                      return None

              def focus_previous(self, win: Window) -> Window | None:
                  if not self.clients or self.clients.index(win) == 0:
                      return None

                  try:
                      return self.clients[self.clients.index(win) - 1]
                  except IndexError:
                      return None

              def next(self) -> None:
                  if self.current_client is None:
                      return
                  # Get the next client or, if at the end of the list, get the first
                  client = self.focus_next(self.current_client) or self.focus_first()
                  self.group.focus(client, True)

              def previous(self) -> None:
                  if self.current_client is None:
                      return
                  # Get the previous client or, if at the end of the list, get the last
                  client = self.focus_previous(self.current_client) or self.focus_last()
                  self.group.focus(client, True)

              def swap(self, c1: Window, c2: Window) -> None:
                  if c1 not in self.clients and c2 not in self.clients:
                      return

                  index1 = self.clients.index(c1)
                  index2 = self.clients.index(c2)

                  self.clients[index1], self.clients[index2] = self.clients[index2], self.clients[index1]

              def focus(self, client: Window) -> None:
                  if client not in self.clients:
                      self.current_client = None
                      return

                  index = self.clients.index(client)

                  # Check if window is not visible
                  if index > 3:
                      c = self.clients.pop(index)
                      self.clients.insert(0, c)

                  self.current_client = client

              def blur(self) -> None:
                  self.current_client = None

              @expose_command
              def rotate(self, clockwise: bool = True) -> None:
                  if not self.clients:
                      return

                  if clockwise:
                      client = self.clients.pop(-1)
                      self.clients.insert(0, client)
                  else:
                      client = self.clients.pop(0)
                      self.clients.append(client)

                  # Check if current client has been rotated off the screen
                  if self.current_client and self.clients.index(self.current_client) > 3:
                      if clockwise:
                          self.current_client = self.clients[3]
                      else:
                          self.current_client = self.clients[0]

                  # Redraw the layout
                  self.group.layout_all()

              @expose_command
              def info(self) -> dict[str, Any]:
                  inf = base.Layout.info(self)
                  inf["clients"] = self.clients
                  return inf

       This should result in a layout looking like this: [image: layout_image] [image] .

   Getting help
       If  you  still need help with developing your widget then please submit a question in the qtile-dev group
       or submit an issue on the github page if you believe there's an error in the codebase.

USING GIT

       git is the version control system that is used to manage all of the source code. It is very powerful, but
       might be frightening at first.  This page should give you a quick overview, but for a complete guide  you
       will  have  to  search  the  web  on your own.  Another great resource to get started practically without
       having to try out the newly-learned commands on a pre-existing repository is learn  git  branching.   You
       should  probably  learn  the basic git vocabulary and then come back to find out how you can use all that
       practically. This guide will be oriented on how to create a  pull  request  and  things  might  be  in  a
       different order compared to the introductory guides.

       WARNING:
          This  guide  is  not complete and never will be. If something isn't clear, consult other sources until
          you are confident you know what you are doing.

   I want to try out a feature somebody is working on
       If you see a pull request on GitHub that you want to try out, have a look at the line where it says:

          user wants to merge n commits into qtile:master from user:branch

       Right now you probably have one remote from which you can  fetch  changes,  the  origin.  If  you  cloned
       qtile/qtile,  git  remote  show  origin  will  spit out the upstream url. If you cloned your fork, origin
       points to it and you probably want to git remote add upstream https://www.github.com/qtile/qtile.  To try
       out somebody's work, you can add their fork as a new remote:

          git remote add <user> https://www.github.com/user/qtile

       where you fill in the username from the line we asked you to search for before.  Then you can  load  data
       from  that  remote  with  git  fetch  and  then  ultimately  check  out  the  branch  with  git  checkout
       <user>/<branch>.

       Alternatively, it is also possible to fetch and checkout pull  requests  without  needing  to  add  other
       remotes. The upstream remote is sufficient:

          git fetch upstream pull/<id>/head:pr<id>
          git checkout pr<id>

       The numeric pull request id can be found in the url or next to the title (preceded by a # symbol).

       NOTE:
          Having  the  feature  branch checked out doesn't mean that it is installed and will be loaded when you
          restart qtile. You might still need to install it with pip.

   I committed changes and the tests failed
       You can easily change your last commit: After you have done your work, git add everything  you  need  and
       use  git commit --amend to change your last commit. This causes the git history of your local clone to be
       diverged from your fork on GitHub, so you need to force-push your changes with:

          git push -f <origin> <feature-branch>

       where origin might be your user name or origin if you cloned  your  fork  and  feature-branch  is  to  be
       replaced by the name of the branch you are working on.

       Assuming  the  feature  branch  is  currently  checked  out, you can usually omit it and just specify the
       origin.

   I was told to rebase my work
       If upstream/master is changed and you happened to change the same files as the commits  that  were  added
       upstream,  you  should  rebase your work onto the most recent upstream/master. Checkout your master, pull
       from upstream, checkout your branch again and then rebase it:

          git checkout master
          git pull upstream/master
          git checkout <feature-branch>
          git rebase upstream/master

       You will be asked to solve conflicts where your diff cannot be applied with confidence to the  work  that
       was  pushed  upstream.  If that is the case, open the files in your text editor and resolve the conflicts
       manually. You possibly need to git rebase --continue after you have resolved conflicts for one commit  if
       you are rebasing multiple commits.

       Note  that  the  above  doesn't  work  if  you  didn't create a branch. In that case you will find guides
       elsewhere to fix this problem, ideally by creating a branch and resetting your master branch to where  it
       should be.

   I was told to squash some commits
       If  you introduce changes in one commit and replace them in another, you are told to squash these changes
       into one single commit without the intermediate step:

          git rebase -i master

       opens a text editor with your commits and a comment block  reminding  you  what  you  can  do  with  your
       commits.  You  can  reword  them to change the commit message, reorder them or choose fixup to squash the
       changes of a commit into the commit on the line above.

       This also changes your git history and you will need to force-push your changes afterwards.

       Note that interactive rebasing also allows you to split, reorder and edit commits.

   I was told to edit a commit message
       If you need to edit the commit message of the last commit you did, use:

          git commit --amend

       to open an editor giving you the possibility to reword the message. If you want to reword the message  of
       an older commit or multiple commits, use git rebase -i as above with the reword command in the editor.

LICENSE

       This project is distributed under the MIT license.

       Copyright (c) 2008, Aldo Cortesi All rights reserved.

       Permission  is  hereby  granted,  free  of  charge,  to  any person obtaining a copy of this software and
       associated documentation files (the "Software"), to deal in the Software without  restriction,  including
       without  limitation  the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
       copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to  the
       following conditions:

       The  above  copyright  notice  and  this permission notice shall be included in all copies or substantial
       portions of the Software.

       THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR  IMPLIED,  INCLUDING  BUT  NOT
       LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
       EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
       IN  AN  ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
       THE USE OR OTHER DEALINGS IN THE SOFTWARE.

CHANGELOG

          Qtile x.xx.x, released xxxx-xx-xx:
              * features
              * bugfixes

          Qtile 0.31.0, released 2025-03-07:
              !!! breaking changes !!!
                  - Spiral layout: `shuffle_up` and `shuffle_down` commands now shuffle the focused window instead of rotating all windows.
              * features
                  - Add TunedManager Widget to show the currently active power profile and cycle through a list of configurable power profiles
              * bugfixes
                  - Fix StatusNotifier displaying wrong icon when icon changes too quickly (e.g. nm-applet)
                  - PulseVolume widget: fix breakage with xrandr/wlr-randr + reload config #5111

          Qtile 0.30.0, released 2025-01-06:
              !!! breaking changes !!!
                - dbus-fast is now required for dbus support.
                  dbus-next was removed as the package is unmaintained.
              * features
                  - Add `SwayNC` widget to interact with Sway Notification Centre (wayland only)
                  - Add `swap` method to Plasma layout
                  - New `click_or_drag_only` option for follow_mouse_focus to change the focus to the window under the mouse when click or drag
                  - Customize battery widget "Full" and "Empty" short text with `full_short_text` and `empty_short_text`
              * bugfixes
                  - Make MonadWide layout up/down focus navigation behave like MonadTall's left/right

          Qtile 0.29.0, released 2024-10-19:
              * features
                  - A Nix flake has been added which can be used by Nix(OS) users to update to the latest version easily
                  - Add `group_window_remove` hook when window is removed from group
                  - Switched to ruff for formatting
              * bugfixes
                  - Add returns to lazy.function and qtile.core.function
                  - Fix a bug with newer versions of cairo breaking the bar
                  - Fix a few TreeTab rendering bugs
                  - Fix a TaskList crash
                  - Fix a scratchpad window size bug

          Qtile 0.28.1, released 2024-08-12:
              * bugfixes
                  - fix a crash in the StatusNotifier widget #4959 #4960

          Qtile 0.28.0, released 2024-08-11:
              * bugfixes
                  - various bug fixes to widgets from previous releases
                  - fix xrandr commands racing with qtile startup

          Qtile 0.27.0, released 2024-07-12:
              * features
                  - Make default `Plasma` add mode dynamic
                  - Add `background` parameter to `Screen` to paint a solid colour background
                  - Add ability to use key codes to bind keys. Will benefit users who change keyboard layouts but
                    wish to retain same bindings, irrespective of layout.
                  - Wayland: Add support for idle-notify-v1 protocol needed by swayidle.
                  - Wayland: Make keybinds repeat according to the keyboard's repeat rate and delay. Previously the keybinds did not repeat.

              * bugfixes
                - Fix `Plasma` layout with `ScreenSplit` by implementing `get_windows`
                - Fix border bug in fullscreening/maximizing wayland windows
                - Fix automatic fullscreening for many XWayland applications (e.g. games) by checking if they want to fullscreen on map

          Qtile 0.26.0, released 2024-05-21:
              !!! breaking changes !!!
                - this release drops support for python 3.9
                - deleted the (very old) libqtile/command_* deprecation wrappers
                - SIGUSR2 no longer restarts qtile, instead it dumps stack traces
                - lazy.<object>.when(when_floating=X) now behaves differently: the lazy call will be executed
                  independently of the current window's float state by default, and can be limited to when it
                  is floating or tiled by passing when_floating as True or False respectively.
                - Dropped support for KDE idle protocol on Wayland
              !!! Notice for packagers - Wayland backend !!!
                - Qtile's Wayland backend now requires wlroots 0.17.x, pywlroots 0.17.x and pywayland >= 0.4.17.
              !!! Notice for pip package - Pypy !!!
                - We currently do not build for pypy-3.10 as there seems to be a resolution error in either pypy or pip (https://github.com/pypy/pypy/issues/4956)
              * features
                - For Wayland you can now set the cursor theme and size to forcefully use in Qtile,
                  set `wl_xcursor_theme` and `wl_xcursor_size` in the configuration
                - automatically lift types to their annotated type when specified via
                  the `qtile cmd-obj` command line
                - Add `Plasma` layout. The original layout (https://github.com/numirias/qtile-plasma) appears to be unmaintained
                  so we have added this to the main codebase.
                - Add ability to specify muted and unmuted formats for `Volume` and `PulseVolume` widgets.
                - Add back server-side opacity support for Wayland backend
              * bugfixes

          Qtile 0.25.0, released 2024-04-06:
              * features
                - The Battery widget now supports dynamic charge control, allowing for
                  protecting battery life.
                - To support the above (plus the other widgets that modify sysfs), qtile
                  now ships with its own udev rules, located at
                  /resources/99-qtile.rules; distro packagers will probably want to
                  install this rule set.
              * bugfixes
                - Fix groups marked with `persist=False` not being deleted when their last window is moved to another group.
                - Fallback icon in StatusNotifier widget

          Qtile 0.24.0, released 2024-01-20:
              !!! config breakage/changes !!!
                - Matches no longer use "include/substring" style matching. But match the string exactly. Previously on X11, if the WM_TYPE of a spawned window is e.g. dialog a match with wm_type dialognoonereadschangelogs would return true. Additionally a window with an empty WM_CLASS (which can happen) would match anything. If you rely this style of substring matching, pass a regex to your match or use a function with func=.
                  Using a list of strings inside Match with role, title, wm_class, wm_instance_class, wm_type are also deprecated, use a regex. Right now we replace the property with a regex if it's a list and warn with a deprecation message. You can use "qtile migrate" to migrate your config to this.
              * features
                - Change how `tox` runs tests. See https://docs.qtile.org/en/latest/manual/contributing.html#running-tests-locally
                for more information on how to run tests locally.
                - Add `ScreenSplit` layout which allows multiple layouts per screen. Also adds `ScreenSplit`
                  widget to display name of active split.
                - Updated `Bluetooth` widget which allows users to manage multiple devices in a single widget
                - Add `align` option to `Columns` layout so new windows can be added to left or right column.
                - `.when()` have two new parameters:
                  - `func: Callable`: Enable call when the result of the callable evaluates to True
                  - `condition: bool`: a boolean value to determine whether the lazy object should be run. Unlike `func`, the
                    condition is evaluated once when the config file is first loaded.
                - Add ability to have bar drawns over windows by adding `reserve=False` to bar's config to
                  stop the bar reserving screen space.
                - Add ability for third-party code (widgets, layouts) to create hooks
                - Add ability to create user-defined hooks which can be fired from external scripts
              * bugfixes
                - Fix two bugs in stacking transient windows in X11
                - Checking configs containing `qtile.core.name` with `python config.py` don't fail anymore (but `qtile.core.name`
                  will be `None`)
                - Fix an error if a wayland xwindow has unknown wm_type

          Qtile 0.23.0, released 2023-09-24:
              !!! Dependency Changes !!!
                - xcffib must be upgraded to >= 1.4.0
                - cairocffi must be upgraded to >= 1.6.0
                - New optional dependency `pulsectl-asyncio` required for `PulseVolume` widget
              !!! Notice for packagers - wlroots (optional dependency) bump !!!
                - Qtile's wayland backend now requires on wlroots 0.16 (and pywlroots 0.16)
              !!! config breakage/changes !!!
                - The `cmd_` prefix has been dropped from all commands (this means command names are common when accessed
                  via the command interface or internal python objects).
                - Custom widgets should now expose command methods with the `@expose_command` decorator (available via
                  `from libqtile.command.base import expose_command`).
                - Some commands have been renamed (in addition to dropping the 'cmd_' prefix):
                    `hints` -> `get_hints`
                    `groups` -> `get_groups`
                    `screens` -> `get_screens`
                - Layouts need to rename some methods:
                  - `add` to `add_client`
                  - `cmd_next` to `next`
                  - `cmd_previous` to `previous`
                - Layouts or widgets that redefine the `commands` property need to update the signature:
                    `@expose_command()`
                    `def commands(self) -> list[str]:`
                - `Window.getsize` has been renamed `Window.get_size` (i.e. merged with the get_size command).
                - `Window.getposition` has been renamed `Window.get_position` (i.e. merged with the get_position command).
                - The `StockTicker` widget `function` option is being deprecated: rename it to `func`.
                - The formatting of `NetWidget` has changed, if you use the `format` parameter in your config include
                  `up_suffix`, `total_suffix` and `down_suffix` to display the respective units.
                - The `Notify` widget now has separate `default_timeout` properties for differenct urgency levels. Previously,
                  `default_timeout` was `None` which meant that there was no timeout for all notifications (unless this had been
                  set by the client sending the notification). Now, `default_timeout` is for normal urgency notifications and this
                  has been set to a default of 10 seconds. `default_timeout_urgent`, for critical notifications, has a timeout of `None`.
                - The `PulseVolume` widget now depends on a third party library, `pulsectl-asyncio`, to interact with the pulse audio
                  server. Users will now see an `ImportError` until they install that library.
              * features
                  - Add ability to set icon size in `LaunchBar` widget.
                  - Add 'warp_pointer' option to `Drag` that when set will warp the pointer to the bottom right of
                    the window when dragging begins.
                  - Add `currentsong` status to `Mpd2` widget.
                  - Add ability to disable group toggling in `GroupBox` widget
                  - Add ability to have different border color when windows are stacked in Stack layout. Requires
                    setting `border_focus_stack` and `border_normal_stack` variables.
                  - Add ability to have different single border width for Columns layout by setting 'single_border_width' key.
                  - Add ability to have different border and margin widths when VerticalTile layout only contains 1 window by
                    setting 'single_border_width' and 'single_margin' keys.
                  - New widget: GenPollCommand
                  - Add `format` and `play_icon` parameters for styling cmus widget.
                  - Add ability to add a group at a specified index
                  - Add ability to spawn the `WidgetBox` widget opened.
                  - Add ability to swap focused window based on index, and change the order of windows inside current group
                  - Add ability to update the widget only once if `update_interval` is None.
                  - Add `move_to_slice` command to move current window to single layout in `Slice` layout
                  - Made the `NetWidget` text formattable.
                  - Qtile no longer floods the log following X server disconnection, instead handling those errors.
                  - `Key` and `KeyChord` bindings now have another argument `swallow`.
                    It indicates whether or not the pressed keys should be passed on to the focused client.
                    By default the keys are not passed (swallowed), so this argument is set to `True`.
                    When set to `False`, the keys are passed to the focused client. A key is never swallowed if the
                    function is not executed, e.g. due to failing the `.when()` check.
                  - Add ability to set custom "Undefined" status key value to `Mpd2Widget`.
                  - `Mpd2Widget` now searches for artist name in all similar keys (i.e `albumartist`, `performer`, etc.).
                  - Add svg support to `CustomLayoutIcon`
                  - added layering controls for X11 (Wayland support coming soon!):
                    - `lazy.window.keep_above()/keep_below()` marks windows to be kept above/below other windows permanently.
                       Calling the functions with no arguments toggles the state, otherwise pass `enable=True` or `enable=False`.
                    - `lazy.window.move_up()/move_down()` moves windows up and down the z axis.
                    - added `only_focused` setting to Max layout, allowing to draw multiple clients on top of each other when
                      set to False
                  - Add `suspend` hook to run functions before system goes to sleep.
              * bugfixes
                  - Fix bug where Window.center() centers window on the wrong screen when using multiple monitors.
                  - Fix `Notify` bug when apps close notifications.
                  - Fix `CPU` precision bug with specific version of `psutil`
                  - Fix config being reevaluated twice during reload (e.g. all hooks from config were doubled)
                  - Fix `PulseVolume` high CPU usage when update_interval set to 0.
                  - Fix `Battery` widget on FreeBSD without explicit `battery` index given.
                  - Fix XMonad layout faulty call to nonexistent _shrink_up
                  - Fix setting tiled position by mouse for layouts using _SimpleLayoutBase. To support this in other layouts, add a swap method taking two windows.
                  - Fix unfullscreening bug in conjunction with Chromium based clients when auto_fullscreen is set to `False`.
                  - Ensure `CurrentLayoutIcon` expands paths for custom folders.
                  - Fix vertical alignment of icons in `TaskList` widget
                  - Fix laggy resize/positioning of floating windows in X11 by handling motion notify events later. We also introduced a cap setting if you want to limit these events further, e.g. for limiting resource usage. This is configurable with the x11_drag_polling_rate variable for each `Screen` which is set to None by default, indicating no cap.
              * python version support
                  - We have added support for python 3.11 and pypy 3.9.
                  - python 3.7, 3.8 and pypy 3.7 are not longer supported.
                  - Fix bug where `StatusNotifier` does not update icons

          Qtile 0.22.0, released 2022-09-22:
              !!! Config breakage !!!
                  - lazy.qtile.display_kb() no longer receives any arguments. If you passed it any arguments
                    (which were ignored previously), remove them.
                  - If you have a custom startup Python script that you use instead of `qtile start` and run init_log
                    manually, the signature has changed. Please check the source for the updated arguments.
                  - `KeyChord`'s signature has changed. ``mode`` is now a boolean to indicate whether the mode should persist.
                    The ``name`` parameter should be used to name the chord (e.g. for the ``Chord`` widget).
              * features
                  - Add ability to draw borders and add margins to the `Max` layout.
                  - The default XWayland cursor is now set at startup to left_ptr, so an xsetroot call is not needed to
                    avoid the ugly X cursor.
                  - Wayland: primary clipboard should now behave same way as with X after selecting something it
                    should be copied into clipboard
                  - Add `resume` hook when computer resumes from sleep/suspend/hibernate.
                  - Add `text_only` option for `LaunchBar` widget.
                  - Add `force_update` command to `ThreadPoolText` widgets to simplify updating from key bindings
                  - Add scrolling ability to `_TextBox`-based widgets.
                  - Add player controls (via mouse callbacks) to `Mpris2` widget.
                  - Wayland: input inhibitor protocol support added (pywayland>=0.4.14 & pywlroots>=0.15.19)
                  - Add commands to control Pomodoro widget.
                  - Add icon theme support to `TaskList` widget (available on X11 and Wayland backends).
                  - Wayland: Use `qtile cmd-obj -o core -f get_inputs` to get input device identifiers for
                    configuring inputs. Also input configs will be updated by config reloads (pywlroots>=0.15.21)
              * bugfixes
                  - Widgets that are incompatible with a backend (e.g. Systray on Wayland) will no longer show
                    as a ConfigError in the bar. Instead the widget is silently removed from the bar and a message
                    included in the logs.
                  - Reduce error messages in `StatusNotifier` widget from certain apps.
                  - Reset colours in `Chord` widget
                  - Prevent crash in `LaunchBar` when using SVG icons
                  - Improve scrolling in `Mpris2` widget (options to repeat scrolling etc.)

          Qtile 0.21.0, released 2022-03-23:
              * features
                  - Add `lazy.window.center()` command to center a floating window on the screen.
                  - Wayland: added power-output-management-v1 protocol support, added idle protocol,
                    added idle inhibit protocol
                  - Add MonadThreeCol layout based on XMonad's ThreeColumns.
                  - Add `lazy.screen.set_wallpaper` command.
                  - Added ability to scale the battery icon's size
                  - Add Spiral layout
                  - Add `toggle` argument to `Window.togroup` with the same functionality as in `Group.toscreen`.
                  - Added `margin_on_single` and `border_on_single` to Bsp layout
              * bugfixes
                  - Fix `Systray` crash on `reconfigure_screens`.
                  - Fix bug where widgets can't be mirrored in same bar.
                  - Fix various issues with setting fullscreen windows floating and vice versa.
                  - Fix a bug where a .when() check for lazy functions errors out when matching
                    on focused windows when none is focused. By default we do not match on focused windows,
                    to change this set `if_no_focused` to True.
                  - Widget with duplicate names will be automatically renamed by appending numeric suffixes
                  - Fix resizing of wallpaper when screen scale changes (X11)
                  - Two small bugfixes for `StatusNotifier` - better handling of Ayatana indicators
                  - Fix bug where StatusNotifierItem crashes due to invalid object paths (e.g. Zoom)

          Qtile 0.20.0, released 2022-01-24:
              * features
                  - Add `place_right` option in the TreeTab layout to place the tab panel on the right side
                  - X11: Add support for _NET_DESKTOP_VIEWPORT. E.g. can be used by rofi to map on current output.
                  - Wayland: Bump wlroots version. 0.15.x wlroots and 0.15.2+ pywlroots are required.
                  - Add XWayland support to the Wayland backend. XWayland will start up as needed, if it is installed.
              * bugfixes
                  - Remove non-commandable windows from IPC. Fixes bug where IPC would fail when trying to get info
                    on all windows but Systray has icons (which are non-commandable `_Window`s.)
                  - Fix bug where bars were not reconfigured correctly when screen layout changes.
                  - Fix a Wayland bug where layer-shell surface like dunst would freeze up and stop updating.
                  - Change timing of `screens_reconfigured` hook. Will now be called ONLY if `cmd_reconfigure_screens`
                    has been called and completed.
                  - Fix order of icons in Systray widget when restarting/reloading config.
                  - Fix rounding error in PulseVolume widget's reported volume.
                  - Fix bug where Volume widget did not load images where `theme_path` had been set in `widget_defaults`.
                  - Remove ability to have multiple `Systray` widgets. Additional `Systray` widgets will result in a
                    ConfigError.
                  - Release notification name from dbus when finalising `Notify` widget. This allows other notification
                    managers to request the name.
                  - Fix bug where `Battery` widget did not retrieve `background` from `widget_defaults`.
                  - Fix bug where widgets in a `WidgetBox` are rendered on top of bar borders.

                  - Add ability to swap focused window based on index, and change the order of windows inside current group
          Qtile 0.19.0, released 2021-12-22:
              * features
                  - Add ability to draw borders to the Bar. Can customise size and colour per edge.
                  - Add `StatusNotifier` widget implementing the `StatusNotifierItem` specification.
                    NB Widget does not provide context menus.
                  - Add `total` bandwidth format value to the Net widget.
                  - Scratchpad groups could be defined as single so that only one of the scratchpad in the group is visible
                    at a given time.
                  - All scratchpads in a Scratchpad group can be hidden with hide_all() function.
                  - For saving states of scratchpads during restart, we use wids instead of pids.
                  - Scratchpads can now be defined with an optional matcher to match with window properties.
                  - `Qtile.cmd_reload_config` is added for reloading the config without completely restarting.
                  - Window.cmd_togroup's argument `groupName` should be changed to
                    `group_name`. For the time being a log warning is in place and a
                    migration is added. In the future `groupName` will fail.
                  - Add `min/max_ratio` to Tile layout and fix bug where windows can extend offscreen.
                  - Add ability for widget `mouse_callbacks` to take `lazy` calls (similar to keybindings)
                  - Add `aliases` to `lazy.spawncmd()` which takes a dictionary mapping convenient aliases
                    to full command lines.
                  - Add a new 'prefix' option to the net widget to display speeds with a static unit (e.g. MB).
                  - `lazy.group.toscreen()` now does not toggle groups by default. To get this behaviour back, use
                    `lazy.group.toscreen(toggle=True)`
                  - Tile layout has new `margin_on_single` and `border_on_single` option to specify
                    whether to draw margin and border when there is only one window.
                  - Thermal zone widget.
                  - Allow TextBox-based widgets to display in vertical bars.
                  - Added a focused attribute to `lazy.function.when` which can be used to Match on focused windows.
                  - Allow one to update Image widget with update() function by giving a new path.
              * bugfixes
                  - Windows are now properly re-ordered in the layouts when toggled on and off fullscreen

          Qtile 0.18.1, released 2021-09-16:
              * features
                  - All layouts will accept a list of colors for border_* options with which
                    they will draw multiple borders on the appropriate windows.

          Qtile 0.18.0, released 2021-07-04:
              !!! Config breakage !!!
                  - The `qtile` entry point doesn't run `qtile start` by default anymore
                  - New optional dependency for dbus related features: dbus-next.
                    Replaces previous reliance on dbus/Glib and allows qtile to use async
                    dbus calls within asyncio's eventloop.
                  - widget.BatteryIcon no longer has a fallback text mode; use
                    widget.Battery instead
                  - MonadX layout key new_at_current is deprecated, use new_client_position.
                  - `libqtile.window` has been moved to `libqtile.backend.x11.window`; a migration has been added for this.
              !!! deprecation warning !!!
                  - 'main' config functions, deprecated in 0.16.1, will no longer be executed.
              !!! Notice for packagers - new dependencies !!!
                  - Tests now require the 'dbus-next' python module plus 'dbus-launch' and 'notify-send' applications
              * features
                  - added transparency in x11 and wayland backends
                  - added measure_mem and measure_swap attributes to memory widget to allow user to choose measurement units.
                  - memory widget can now be displayed with decimal values
                  - new "qtile migrate" command, which will attempt to upgrade previous
                    configs to the current version in the case of qtile API breaks.
                  - A new `reconfigure_screens` config setting. When `True` (default) it
                    hooks `Qtile.reconfigure_screens` to the `screen_change` hook,
                    reconfiguring qtile's screens in response to randr events. This
                    removes the need to restart qtile when adding/removing external
                    monitors.
                  - improved key chord / sequence functionality. Leaving a chord with `mode`
                    set brings you to a named mode you activated before, see #2264.
                    A new command, `lazy.ungrab_all_chords`, was introduced to return to the root bindings.
                    The `enter_chord` hook is now always called with a string argument.
                    The third argument to `KeyChord` was renamed from `submaping` to `submapping` (typo fix).
                  - added new argument for CheckUpdates widget: `custom_command_modify` which allows user to modify the
                    the line count of the output of `custom_command` with a lambda function (i.e. `lambda x: x-3`).
                    Argument defaults to `lambda x: x` and is overridden by `distro` argument's internal lambda.
                  - added new argument for the WindowName, WindowTabs and Tasklist widgets: `parse_text` which allows users to
                    define a function that takes a window name as an input, modify it in some way (e.g. str.replace(), str.upper() or regex)
                    and show that modification on screen.
                  - A Wayland backend has been added which can be used by calling `qtile start -b wayland` directly in your TTY.
                    It requires the latest releases of wlroots, python-xkbcommon, pywayland and pywlroots. It is expected to be
                    unstable so please let us know if you find any bugs!
                  - The 'focus` argument to `Click` and `Drag` objects in your config are no longer necessary (and are ignored).

          Qtile 0.17.0, released 2021-02-13:
              !!! Python version breakage !!!
                  - Python 3.5 and 3.6 are no longer supported
              !!! Config breakage !!!
                  - Pacman widget has been removed. Use CheckUpdates instead.
                  - Mpris widget has been removed. Use Mpris2 instead.
                  - property "masterWindows" of Tile layout renamed to master_length
                  - Match objects now only allow one string argument for their wm
                    name/class/etc. properties. to update your config, do e.g.
                             Group('www', spawn='firefox', layout='xmonad',
                        -          matches=[Match(wm_class=['Firefox', 'google-chrome', 'Google-chrome'])]),
                        +          matches=[Match(wm_class='Firefox'), Match(wm_class='google-chrome'), Match(wm_class='Google-chrome')]),
                  - properties wname, wmclass and role of Slice-layout replaced by Match-
                    type property "match"
                  - rules specified in `layout.Floating`'s `float_rules` are now evaluated with
                    AND-semantics instead of OR-semantics, i.e. if you specify 2 different
                    property rules, both have to match
                  - check the new `float_rules` for `floating_layout` in the default config and
                    extend your own rules appropriately: some non-configurable auto-floating rules
                    were made explicit and added to the default config
                  - using `dict`s for `layout.Floating`'s `float_rules` is now deprecated, please
                    use `config.Match` objects instead
                  - `no_reposition_match` in `layout.Floating` has been removed; use the list of
                    `config.Match`-objects `no_reposition_rules` instead
                  - Command line has been modernized to a single entry point, the `qtile`
                    binary. Translations are below:
                          qtile     -> qtile start
                          qtile-cmd -> qtile cmd-obj
                          qtile-run -> qtile run-cmd
                          qtile-top -> qtile top
                          qshell    -> qtile shell
                    iqshell and dqtile-cmd are no longer distributed with the
                    package, as they were either user or developer scripts. Both are
                    still available in the qtile repo in /scripts.

                    Running `qtile` without arguments will continue to work for the
                    foreseeable future, but will be eventually deprecated. qtile prints a
                    warning when run in this configuration.
                  - Qtile.cmd_focus_by_click is no longer an available command.
                  - Qtile.cmd_get_info is no longer an available command.
                  - libqtile.command_* has been deprecated, it has been moved to
                    libqtile.command.*
                  - libqtile.widget.base.ThreadedPollText has been removed; out of tree
                    widgets can use ThreadPoolText in the same package instead.
                  - the YahooWeather widget was removed since Yahoo retired their free
                    tier of the weather API
                  - Deprecated hook `window_name_change` got removed, use
                    `client_name_updated` instead.
                  - show_state attribute from WindowName widget has been removed. Use format attribute instead.
                          show_state = True  -> format = '{state}{name}'
                          show_state = False -> format = '{name}'
                  - mouse_callbacks no longer receives the qtile object as an argument
                    (they receive no arguments); import it via `from libqtile import
                    qtile` instead.
              * features
                  - new WidgetBox widget
                  - new restart and shutdown hooks
                  - rules specified in `layout.Floating`'s `float_rules` are now evaluated with
                    AND-semantics, allowing for more complex and specific rules
                  - Python 3.9 support
                  - switch to Github Actions for CI
                  - Columns layout has new `margin_on_single` option to specify margin
                    size when there is only one window (default -1: use `margin` option).
                  - new OpenWeather widget to replace YahooWeather
                  - new format attribute for WindowName widget
                  - new max_chars attribute for WindowName widget
                  - libqtile now exports type information
                  - add a new `qtile check` subcommand, which will check qtile configs
                    for various things:
                        - validates configs against the newly exported type information
                          if mypy is present in the environment
                        - validates that qtile can import the config file (e.g. that
                          syntax is correct, ends in a .py extension, etc.)
                        - validates Key and Mouse mod/keysym arguments are ok.
                  - Columns layout now enables column swapping by using swap_column_left and swap_column_right
              !!! warning !!!
                  - When (re)starting, Qtile passes its state to the new process in a
                    file now, where previously it passed state directly as a string. This
                    fixes a bug where some character encodings (i.e. in group names) were
                    getting messed up in the conversion to/from said string. This change
                    will cause issues if you update Qtile then restart it, causing the
                    running old version to pass state in the previous format to the new
                    process which recognises the new.

          Qtile 0.16.1, released 2020-08-11:
              !!! Config breakage !!!
                  - Hooks 'addgroup', 'delgroup' and 'screen_change' will no longer
                    receive the qtile object as an argument. It can be accessed directly
                    at libqtile.qtile.
              !!! deprecation warning !!!
                  - defining a main function in your config is deprecated. You should use
                    @hook.subscribe.startup_complete instead. If you need access to the
                    qtile object, import it from libqtile directly.
              * bugfixes
                  - include tests in the release for distros to consume
                  - don't resize 0th screen incorrectly on root ConfigureNotify
                  - expose qtile object as libqtile.qtile (note that we still consider
                    anything not prefixed with cmd_ to be a private API)
                  - fix transparent borders
                  - MonadTall, MonadWide, and TreeTab now work with Slice

          Qtile 0.16.0, released 2020-07-20:
              !!! Config breakage !!!
                  - Imports from libqtile.widget are now made through a function
                    proxy to avoid the side effects of importing all widgets at
                    once. If you subclass a widget in your config, import it from
                    its own module.
                    e.g. from libqtile.widget.pomodoro import Pomodoro
              * features
                  - added `guess_terminal` in utils
                  - added keybinding cheet sheet image generator
                  - custom keyboardlayout display
                  - added native support for key chords
                  - validate config before restart and refuse to restart with a bad
                    config
                  - added a bunch of type annotations to config objects (more to come)
              * bugfixes
                  - major focus rework; Java-based IDEs such as PyCharm, NetBrains, etc.
                    now focus correctly
                  - fix a bug where spotify (or any window with focus-to=parent) was
                    closed, nothing would be focused and no hotkeys would work
                  - support windows unsetting the input hint
                  - respects window's/user's location setting if present (WM_SIZE_HINTS)
                  - fixed YahooWeather widget for new API
                  - fix a bug where _NET_WM_DESKTOPS wasn't correctly updated when
                    switching screens in some cases
                  - fix a crash in the BSP layout
                  - fix a stacktrace when unknown keysyms are encounted
                  - make qtile --version output more sane
                  - fix a rendering issue with special characters in window names
                  - keyboard widget no longer re-sets the keyboard settings every second
                  - fix qtile-top with the new IPC model
                  - Image widget respects its background setting now
                  - correctly re-draw non-focused screens on qtile restart
                  - fix a crash when decoding images
                  - fix the .when() constraint for lazy objects

          Qtile 0.15.1, released 2020-04-14
              * bugfixes
                  - fix qtile reload (it was crashing)

          Qtile 0.15.0, released 2020-04-12:
              !!! Config breakage !!!
                  - removed the mpd widget, which depended on python-mpd.
                  - the Clock widget now requires pytz to handle timezones that are
                    passed as string
                  - libqtile.command.Client does not exist anymore and has been
                    replaced by libqtile.command_client.CommandClient
              !!! deprecation warning !!!
                  - libqtile.command.lazy is deprecated in favor of libqtile.lazy.lazy
              * features
                  - Python 3.8 support
                  - `wallpaper` and `wallpaper_mode` for screens
                  - bars can now have margins
                  - `lazy.toscreen` called twice will now toggle the groups
                    (optional with the `toggle` parameter)
                  - `lazy.window.togroup` now has `switch_group` parameter to follow
                    the window to the group it is sent to
                  - qtile now copies the default config if the config file does not exist
                  - all widgets now use Pango markup by default
                  - add an `fmt` option for all textbox widgets
                  - new PulseVolume widget for controlling PulseAudio
                  - new QuickExit widget, mainly for the default config
                  - new non-graph CPU widget
                  - KeyboardLayout widget: new `options` parameter
                  - CheckUpdates widget: support ArchLinux yay
                  - GroupBox widget: new `block_highlight_text_color` parameter
                  - Mpd2 widget: new `color_progress` parameter
                  - Maildir widget can now display the inbox grand total
                  - the Net widget can now use bits as unit
                  - Spacer widget: new `background_color` parameter
                  - More consistent resize behavior in Columns layout
                  - various improvements of the default config
                  - large documentation update and improvements (e.g. widget
                    dependencies)
              * bugfixes
                  - qtile binary: don't fail if we can't set the locale
                  - don't print help if qtile-cmd function returns nothing
                  - Monad layout: fix margins when flipped

          Qtile 0.14.2, released 2019-06-19:
              * bugfixes
                  - previous release still exhibited same issues with package data,
                    really fix it this time

          Qtile 0.14.1, released 2019-06-19:
              * bugfixes
                  - properly include png files in the package data to install included
                    icons

          Qtile 0.14.0, released 2019-06-19:
              !!! Python version breakage !!!
                  - Python 2 is no longer supported
                  - Python 3.4 and older is no longer supported
              !!! Config breakage !!!
                  - Many internal things were renamed from camel case to snake case. If
                    your config uses main(), or any lazy.function() invocations that
                    interact directly with the qtile object, you may need to forward port
                    them. Also note that we do *not* consider the qtile object to be a
                    stable api, so you will need to continue forward porting these things
                    for future refactorings (for wayland, etc.). A better approach may be
                    to add an upstream API for what you want to do ;)
                  - Maildir's subFolder and maildirPath changed to maildir_path and
                    sub_folder.
                  - the graph widget requires the psutil library to be installed
              * features
                  - add custom `change_command` to backlight widget
                  - add CommandSet extension to list available commands
                  - simplify battery monitoring widget interface and add freebsd
                    compatible battery widget implementation
                  - track last known mouse coordinates on the qtile manager
                  - allow configuration of warping behavior in columns layout
              * bugfixes
                  - with cursor warp enabled, the cursor is warped on screen change
                  - fix stepping groups to skip the scratch pad group
                  - fix stack layout to properly shuffle
                  - silence errors when unmapping windows

          Qtile 0.13.0, released 2018-12-23:
              !!! deprecation warning !!!
                  - wmii layout is deprecated in terms of columns layout, which has the
                    same behavior with different defaults, see the wmii definition for
                    more details
              * features
                  - add svg handling for images
                  - allow addgroup command to set the layout
                  - add command to get current log level
                  - allow groupbox to hide unused groups
                  - add caps lock indicator widget
                  - add custom_command to check_update widget
              * bugfixes
                  - better shutdown handling
                  - fix clientlist current client tracking
                  - fix typo in up command on ratiotile layout
                  - various fixes to check_update widget
                  - fix 0 case for resize screen

          Qtile 0.12.0, released 2018-07-20:
              !!! Config breakage !!!
                  - Tile layout commands up/down/shuffle_up/shuffle_down changed to be
                    more consistent with other layouts
                  - move qcmd to qtile-cmd because of conflict with renameutils, move
                    dqcmd to dqtile-cmd for symmetry
              * features
                  - add `add_after_last` option to Tile layout to add windows to the end
                    of the list.
                  - add new formatting options to TaskList
                  - allow Volume to open app on right click
              * bugfixes
                  - fix floating of file transfer windows and java drop-downs
                  - fix exception when calling `cmd_next` and `cmd_previous` on layout
                    without windows
                  - fix caps lock affected behaviour of key bindings
                  - re-create cache dir if it is deleted while qtile is running
                  - fix CheckUpdates widget color when no updates
                  - handle cases where BAT_DIR does not exist
                  - fix the wallpaper widget when using `wallpaper_command`
                  - fix Tile layout order to not reverse on reset
                  - fix calling `focus_previous/next` with no windows
                  - fix floating bug is BSP layout

          Qtile 0.11.1, released 2018-03-01:
              * bug fix
                  - fixed pip install of qtile

          Qtile 0.11.0, released 2018-02-28:
              !!! Completely changed extension configuration, see the documentation !!!
              !!! `extention` subpackage renamed to `extension` !!!
              !!! `extentions` configuration variable changed to `extension_defaults` !!!
              * features
                  - qshell improvements
                  - new MonadWide layout
                  - new Bsp layout
                  - new pomodoro widget
                  - new stock ticker widget
                  - new `client_name_updated` hook
                  - new RunCommand and J4DmenuDesktop extension
                  - task list expands to fill space, configurable via `spacing` parameter
                  - add group.focus_by_name() and group.info_by_name()
                  - add disk usage ratio to df widget
                  - allow displayed group name to differ from group name
                  - enable custom TaskList icon size
                  - add qcmd and dqcmd to extend functionality around qtile.command
                    functionality
                  - add ScratchPad group that has configurable drop downs
              * bugfixes
                  - fix race condition in Window.fullscreen
                  - fix for string formatting in qtile_top
                  - fix unicode literal in tasklist
                  - move mpris2 initialization out of constructor
                  - fix wlan widget variable naming and division
                  - normalize behavior of layouts on various commands
                  - add better fallback to default config
                  - update btc widget to use coinbase
                  - fix cursor warp when using default layout implementation
                  - don't crash when using widget with unmet dependencies
                  - fix floating window default location

          Qtile 0.10.7, released 2017-02-14:
              * features
                  - new MPD widget, widget.MPD2, based on `mpd2` library
                  - add option to ignore duplicates in prompt widget
                  - add additional margin options to GroupBox widget
                  - add option to ignore mouse wheel to GroupBox widget
                  - add `watts` formatting string option to Battery widgets
                  - add volume commands to Volume widget
                  - add Window.focus command
              * bugfixes
                  - place transient windows in the middle of their parents
                  - fix TreeTab layout
                  - fix CurrentLayoutIcon in Python 3
                  - fix xcb handling for xcffib 0.5.0
                  - fix bug in Screen.resize
                  - fix Qtile.display_kb command

          Qtile 0.10.6, released 2016-05-24:
              !!! qsh renamed to qshell !!!
                  This avoids name collision with other packages
              * features
                  - Test framework changed to pytest
                  - Add `startup_complete` hook
              * bugfixes
                  - Restore dynamic groups on restart
                  - Correct placement of transient_for windows
                  - Major bug fixes with floating window handling
              * file path changes (XDG Base Directory specification)
                  - the default log file path changed from ~/.qtile.log to
                    ~/.local/share/qtile/qtile.log
                  - the cache directory changed from ~/.cache to ~/.cache/qtile
                  - the prompt widget's history file changed from ~/.qtile_history to
                    ~/.cache/qtile/prompt_history

          Qtile 0.10.5, released 2016-03-06:
              !!! Python 3.2 support dropped !!!
              !!! GoogleCalendar widget dropped for KhalCalendar widget !!!
              !!! qtile-session script removed in favor of qtile script !!!
              * features
                  - new Columns layout, composed of dynamic and configurable columns of
                    windows
                  - new iPython kernel for qsh, called iqsh, see docs for installing
                  - new qsh command `display_kb` to show current key binding
                  - add json interface to IPC server
                  - add commands for resizing MonadTall main panel
                  - wlan widget shows when you are disconnected and uses a configurable
                    format
              * bugfixes
                  - fix path handling in PromptWidget
                  - fix KeyboardLayout widget cycling keyboard
                  - properly guard against setting screen to too large screen index

          Qtile 0.10.4, released 2016-01-19:
              !!! Config breakage !!!
                  - positional arguments to Slice layout removed, now `side` and `width`
                    must be passed in as keyword arguments
              * features
                  - add alt coin support to BitcoinTracker widget
              * bugfixes
                  - don't use six.moves assignment (fix for >=setuptools-19.3)
                  - improved floating and fullscreen handling
                  - support empty or non-charging secondary battery in BatteryWidget
                  - fix GoogleCalendar widget crash

          Qtile 0.10.3, released 2015-12-25:
              * features
                  - add wmii layout
                  - add BSD support to graph widgets
              * bugfixes
                  - fix (some) fullscreen problems
                  - update google calendar widget to latest google api
                  - improve multiple keyboard layout support
                  - fix displaying Systray widget on secondary monitor
                  - fix spawn file descriptor handling in Python 3
                  - remove duplicate assert code in test_verticaltile.py
                  - allow padding_{x,y} and margin_{x,y} widget attrs to be set to 0

          Qtile 0.10.2, released 2015-10-19:
              * features
                  - add qtile-top memory monitoring
                  - GroupBox can set visible groups
                  - new GroupBox highlighting, line
                  - allow window state to be hidden on WindowName widget
                  - cmd_togroup can move to current group when None sent
                  - added MOC playback widget
                  - added memory usage widget
                  - log truncation, max log size, and number of log backups configurable
                  - add a command to change to specific layout index
                    (lazy.to_layout_index(index))
              * bugfixes
                  - fixed memory leak in dgroups
                  - margin fixes for MonalTall layout
                  - improved cursor warp
                  - remove deprecated imp for Python >= 3.3
                  - properly close file for NetGraph
                  - fix MondadTall layout grow/shrink secondary panes for Python 2
                  - Clock widget uses datetime.now() rather than .fromtimestamp()
                  - fix Python 3 compatibility of ThermalSensor widget
                  - various Systray fixes, including implementing XEMBED protocol
                  - print exception to log during loading config
                  - fixed xmonad layout margins between main and secondary panes
                  - clear last window name from group widgets when closed
                  - add toggleable window border to single xmonad layout
              * config breakage
                  - layouts.VerticalTile `windows` is now `clients`
                  - layouts.VerticalTile focus_next/focus_previous now take a single
                    argument, similar to other layouts

          Qtile 0.10.1, released 2015-07-08:
              This release fixes a problem that made the PyPI package uninstallable,
              qtile will work with a pip install now

          Qtile 0.10.0, released 2015-07-07:
              !!! Config breakage !!!
                  - various deprecated commands have been removed:
                      Screen.cmd_nextgroup: use cmd_next_group
                      Screen.cmd_prevgroup: use cmd_prev_group
                      Qtile.cmd_nextlayout: use cmd_next_layout
                      Qtile.cmd_prevlayout: use cmd_prev_layout
                      Qtile.cmd_to_next_screen: use cmd_next_screen
                      Qtile.cmd_to_prev_screen: use cmd_prev_screen
                  - Clock widget: remove fmt kwarg, use format kwarg
                  - GmailChecker widget: remove settings parameter
                  - Maildir widget: remove maildirPath, subFolders, and separator kwargs
              * Dependency updates
                  - cffi>=1.1 is now required, along with xcffib>=0.3 and cairocffi>=0.7
                    (the cffi 1.0 compatible versions of each)
                  - Care must be taken that xcffib is installed *before* cairocffi
              * features
                  - add support for themed cursors using xcb-cursor if available
                  - add CheckUpdate widget, for checking package updates, this deprecates
                    the Pacman widget
                  - add KeyboardKbdd widget, for changing keyboard layouts
                  - add Cmus widget, for showing song playing in cmus
                  - add Wallpaper widget, for showing and cycling wallpaper
                  - add EzConfig classes allowing shortcuts to define key bindings
                  - allow GroupBox urgent highlighting through text
                  - Bar can be placed vertically on sides of screens (widgets must be
                    adapted for vertical viewing)
                  - add recognizing brightness keys
              * bugfixes
                  - deprecation warnings were not printing to logs, this has been fixed
                  - fix calculation of y property of Gap
                  - fix focus after closing floating windows and floating windows
                  - fix various Python 3 related int/float problems
                  - remember screen focus across restarts
                  - handle length 1 list passed to Drawer.set_source_rgb without raising
                    divide by zero error
                  - properly close files opened in Graph widget
                  - handle _NET_WM_STATE_DEMANDS_ATTENTION as setting urgency
                  - fix get_wm_transient_for, request WINDOW, not ATOM

          Qtile 0.9.1, released 2015-02-13:
              This is primarily a unicode bugfix release for 0.9.0; there were several
              nits related to the python2/3 unicode conversion that were simply wrong.
              This release also adds license headers to each file, which is necessary for
              distro maintainers to package Qtile.
              * bugfixes
                  - fix python2's importing of gobject
                  - fix unicode handling in several places

          Qtile 0.9.0, released 2015-01-20:
              * !!! Dependency Changes !!!
                New dependencies will need to be installed for Qtile to work
                  - drop xpyb for xcffib (XCB bindings)
                  - drop py2cairo for cairocffi (Cairo bindings)
                  - drop PyGTK for asyncio (event loop, pangocairo bindings managed
                    internally)
                  - Qtile still depends on gobject if you want to use anything that uses
                    dbus (e.g. the mpris widgets or the libnotify widget)
              * features
                  - add Python 3 and pypy support (made possible by dependency changes)
                  - new layout for vertical monitors
                  - add startup_once hook, which is called exactly once per session (i.e.
                    it is not called when qtile is restarted via lazy.restart()). This
                    eliminates the need for the execute_once() function found in lots of
                    user configs.
                  - add a command for showing/hiding the bar (lazy.hide_show_bar())
                  - warn when a widget's dependencies cannot be imported
                  - make qtile.log more useful via better warnings in general, including
                    deprecation and various other warnings that were previously
                    nonexistent
                  - new text-polling widget super classes, which enable easy
                    implementation of various widgets that need to poll things outside
                    the event loop.
                  - add man pages
                  - large documentation update, widget/layout documentation is now
                    autogenerated from the docstrings
                  - new ImapWidget for checking imap mailboxes
              * bugfixes
                  - change default wmname to "LG3D" (this prevents some java apps from
                    not working out of the box)
                  - all code passes flake8
                  - default log level is now WARNING
                  - all widgets now use our config framework
                  - windows with the "About" role float by default
                  - got rid of a bunch of unnecessary bare except: clauses

          Qtile 0.8.0, released 2014-08-18:
              * features
                  - massive widget/layout documentation update
                  - new widget debuginfo for use in Qtile development
                  - stack has new autosplit, fair options
                  - matrix, ratiotile, stack, xmonad, zoomy get 'margin' option
                  - new launchbar widget
                  - support for matching WM_CLASS and pid in Match
                  - add support for adding dgroups rules dynamically and via ipc
                  - Clock supports non-system timezones
                  - new mpris2 widget
                  - volume widget can use emoji instead of numbers
                  - add an 'eval' function to qsh at every object level
                  - bar gradients support more colors
                  - new Clipboard widget (very handy!)
              * bugfixes
                  - bitcoin ticker widget switched from MtGox (dead) to btc-e
                  - all widgets now use Qtile's defaults system, so their defaults are
                    settable globally, etc.
                  - fix behavior when screens are cloned
                  - all widgets use a unified polling framework
                  - "dialog" WM_TYPEs float by default
                  - respect xrandr --primary
                  - use a consistent font size in the default config
                  - default config supports mouse movements and floating
                  - fix a bug where the bar was not redrawn correctly in some multiscreen
                    environments
                  - add travis-ci support and make tests vastly more robust
              * config breakage
                  - libqtile.layout.Stack's `stacks` parameter is now `num_stacks`

          Qtile 0.7.0, released 2014-03-30:
              * features
                  - new disk free percentage widget
                  - new widget to display static image
                  - per core CPU graphs
                  - add "screen affinity" in dynamic groups
                  - volume widget changes volume linear-ly instead of log-ly
                  - only draw bar when idle, vastly reducing the number of bar draws and
                    speeding things up
                  - new Gmail widget
                  - Tile now supports automatically managing master windows via the
                    `master_match` parameter.
                  - include support for minimum height, width, size increment hints
              * bugfixes
                  - don't crash on any exception in main loop
                  - don't crash on exceptions in hooks
                  - fix a ZeroDivisionError in CPU graph
                  - remove a lot of duplicate and unused code
                  - Steam windows are placed more correctly
                  - Fixed several crashes in qsh
                  - performance improvements for some layouts
                  - keyboard layout widget behaves better with multiple keyboard
                    configurations
              * config breakage
                  - Tile's shuffleMatch is renamed to resetMaster

          Qtile 0.6, released 2013-05-11:
              !!! Config breakage !!!
              This release breaks your config file in several ways:
                  - The Textbox widget no longer takes a ``name'' positional parameter,
                    since it was redundant; you can use the ``name'' kwarg to define it.
                  - manager.Group (now _Group) is not used to configure groups any more;
                    config.Group replaces it. For simple configurations (i.e.
                    Group("a") type configs), this should be a drop in replacement.
                    config.Group also provides many more options for showing and hiding
                    groups, assigning windows to groups by default, etc.
                  - The Key, Screen, Drag, and Click objects have moved from the manager
                    module to the config module.
                  - The Match object has moved from the dgroups module to the config
                    module.
                  - The addgroup hook now takes two parameters: the qtile object and the
                    name of the group added:
                        @hook.subscribe
                        def addgroup_hook(qtile, name):
                            pass
                  - The nextgroup and prevgroup commands are now on Screen instead of
                    Group.
              For most people, you should be able to just:
                  sed -i -e 's/libqtile.manager/libqtile.config' config.py
              ...dgroups users will need to go to a bit more work, but hopefully
              configuration will be much simpler now for new users.
              * features
                  - New widgets: task list,
                  - New layout: Matrix
                  - Added ability to drag and drop groups on GroupBox
                  - added "next urgent window" command
                  - added font shadowing on widgets
                  - maildir widget supports multiple folders
                  - new config option log_level to set logging level (any of
                    logging.{DEBUG, INFO, WARNING, ERROR, CRITICAL})
                  - add option to battery widget to hide while level is above a certain
                    amount
                  - vastly simplify configuration of dynamic groups
                  - MPD widget now supports lots of metadata options
              * bugfixes
                  - don't crash on restart when the config has errors
                  - save layout and selected group state on restart
                  - varous EWMH properties implemented correctly
                  - fix non-black systray icon backgrounds
                  - drastically reduce the number of timeout_add calls in most widgets
                  - restart on RandR attach events to allow for new screens
                  - log level defaults to ERROR
                  - default config options are no longer initialized when users define
                    their corresponding option (preventing duplicate widgets, etc.)
                  - don't try to load config in qsh (not used)
                  - fix font alignment across Textbox based widgets

          Qtile 0.5, released 2012-11-11:
              (Note, this is not complete! Many, many changes have gone in to 0.5, by a
              large number of contributors. Thanks to everyone who reported a bug or
              fixed one!)
              * features
                  - Test framework is now nose
                  - Documentation is now in sphinx
                  - Several install guides for various OSes
                  - New widgets: battery based icon, MPRIS1, canto, current layout, yahoo
                    weather, sensors, screen brightness, notify, pacman, windowtabs,
                    she, crashme, wifi.
                  - Several improvements to old widgets (e.g. battery widget displays low
                    battery in red, GroupBox now has a better indication of which screen
                    has focus in multi-screen setups, improvements to Prompt, etc.)
                  - Desktop notification service.
                  - More sane way to handle configuration files
                  - Promote dgroups to a first class entity in libqtile
                  - Allow layouts to be named on an instance level, so you can:
                      layouts = [
                          # a layout just for gimp
                          layout.Slice('left', 192, name='gimp', role='gimp-toolbox',
                              fallback=layout.Slice('right', 256, role='gimp-dock',
                              fallback=layout.Stack(stacks=1, **border_args)))
                      ]
                      ...

                      dynamic_groups = { 'gimp': {'layout': 'gimp'} }

                      Dgroups(..., dynamic_groups, ...)
                  - New Layout: Zoomy
                  - Add a session manager to re-exec qtile if things go south
                  - Support for WM_TAKE_FOCUS protocol
                  - Basic .desktop file for support in login managers
                  - Qsh reconnects after qtile is restarted from within it
                  - Textbox supports pango markup
                  - Examples moved to qtile-examples repository.

              * bugfixes
                  - Fix several classes of X races in a more sane way
                  - Minor typo fixes to most widgets
                  - Fix several crashes when drawing systray icons too early
                  - Create directories for qtile socket as necessary
                  - PEP8 formatting updates (though we're not totally there yet)
                  - All unit tests pass
                  - Lots of bugfixes to MonadTall
                  - Create IPC socket directory if necessary
                  - Better error if two widgets have STRETCH length
                  - Autofloat window classes can now be overridden
                  - xkeysyms updated

          # vim :set ts=4 sw=4 sts=4 et :

AUTHOR

       Author name not set

                                                  Mar 15, 2025                                          QTILE(1)