Customizing Your Workspace with Qtile: A Look at My Configuration File

Customizing Your Workspace with Qtile: A Look at My Configuration File

As a programmer, having an efficient and well-organized workspace is crucial for getting work done. That's why I was always on the lookout for tools that could help me customize and optimize my development environment.

When I stumbled upon Qtile, a tiling window manager written in Python, I knew I had to give it a try. In this blog post, I'll be sharing my Qtile configuration file and talking about how it has helped me streamline my workflow.

TLDR: gist.github.com/neerajadhav/17c6fb3ec6f856e..

What I like about Qtile.

One of the things I love about Qtile is its highly customizable nature. With just a few lines of code in the configuration file, I was able to set up my workspace exactly how I wanted it.

Whether it's adjusting the layout of my windows, creating custom keybindings, or setting up workspaces for specific projects, Qtile has made it all possible. And because it's a tiling window manager, I no longer have to spend time manually resizing and arranging windows – Qtile takes care of that for me, saving me valuable time and energy. In the following paragraphs, I'll be diving into the specifics of my Qtile configuration and explaining how it all works.

Imports

import os
import re
import socket
import subprocess
from typing import List  # noqa: F401
from libqtile import layout, bar, widget, hook, extension
from libqtile.config import Click, Drag, Group, Key, Match, Screen, Rule
from libqtile.command import lazy
#import arcobattery

This is a Python script that imports several modules and functions that are used in a Qtile window manager configuration.

The os module provides functions for interacting with the operating system, such as reading or writing to the filesystem.

The re (regular expression) module provides functions for searching and manipulating strings using regular expressions.

The socket module provides functions for creating and using network sockets, which are used for communication between programs on the same or different computers.

The subprocess module allows you to spawn new processes, connect to their input/output/error pipes, and obtain their return codes.

The typing module is used for type hinting, which allows you to annotate variables and function signatures with their expected types. This can make your code more readable and help catch type-related bugs.

The libqtile module is a Python library that provides classes and functions for creating and configuring a Qtile window manager.

The Click, Drag, Group, Key, Match, Screen, and Rule classes from the libqtile.config module are used to define the behavior of the window manager in response to various events, such as mouse clicks or key presses.

The lazy decorator from the libqtile.command module is used to delay the execution of a function until it is needed, which can be useful for optimizing the performance of the window manager.

Variables

mod = "mod4"
mod1 = "alt"
mod2 = "control"
home = os.path.expanduser('~')

browser = "firefox"
terminal = "xfce4-terminal"
fileManager = "thunar"

These lines of code define some variables that are used to configure the behavior of the window manager.

The mod variable is assigned the string "mod4", which is probably the name of a key on the keyboard that is used as a modifier key for creating keyboard shortcuts.

The mod1 and mod2 variables are assigned the strings "alt" and "control", which are also likely names of modifier keys.

The home variable is assigned the path to the user's home directory, as determined by the os.path.expanduser function.

The browser, terminal, and fileManager variables are assigned the strings "firefox", "xfce4-terminal", and "thunar", which are the names of executables for launching a web browser, terminal emulator, and file manager, respectively.

Colors

def init_colors():
    return[["#282c34", "#282c34"],
          ["#1c1f24", "#1c1f24"],
          ["#dfdfdf", "#dfdfdf"],
          ["#ff6c6b", "#ff6c6b"],
          ["#98be65", "#98be65"],
          ["#da8548", "#da8548"],
          ["#51afef", "#51afef"],
          ["#c678dd", "#c678dd"],
          ["#46d9ff", "#46d9ff"],
          ["#a9a1e1", "#a9a1e1"]]
colors = init_colors()

These lines of code define a function named init_colors that returns a list of lists, where each inner list contains two strings representing colors. It looks like the function is intended to initialize the colors variable with a set of default color values.

The colors variable is then assigned the return value of the init_colors function. This will initialize colors with the default set of color values defined in the function.

Lazy Functions

@lazy.function
def window_to_prev_group(qtile):
    if qtile.currentWindow is not None:
        i = qtile.groups.index(qtile.currentGroup)
        qtile.currentWindow.togroup(qtile.groups[i - 1].name)

@lazy.function
def window_to_next_group(qtile):
    if qtile.currentWindow is not None:
        i = qtile.groups.index(qtile.currentGroup)
        qtile.currentWindow.togroup(qtile.groups[i + 1].name)

These are two functions that are decorated with the @lazy.function decorator. This decorator is provided by the libqtile.command module and is used to delay the execution of a function until it is needed, which can be useful for optimizing the performance of the window manager.

The window_to_prev_group function takes a single argument, qtile, which is an instance of the libqtile.command.CommandObject class. This function moves the current window to the previous group (workspace) in the list of groups managed by the window manager.

The window_to_next_group function is similar to window_to_prev_group, but moves the current window to the next group in the list instead of the previous one.

Both functions use the togroup method of the currentWindow attribute of the qtile object to move the current window to a new group. The togroup method takes a string argument representing the name of the group to move the window to. The index of the current group in the list of groups is determined using the index method and the groups attribute of the qtile object. The name of the group to move the window to is constructed by either selecting the group at the previous index (for the window_to_prev_group function) or the next index (for the window_to_next_group function) in the list.

Key Bindings

keys = [

# SUPER + FUNCTION KEYS

    Key([mod], "f", lazy.window.toggle_fullscreen()),
    Key([mod], "q", lazy.window.kill()),

    Key([mod], "f", lazy.spawn(browser)),
    Key([mod], "return", lazy.spawn(terminal)),
    Key([mod, "shift"], "return", lazy.spawn(fileManager)),
    Key([mod], "x", lazy.spawn("archlinux-logout")),
    Key([], "print", lazy.spawn("scrot 'ArcoLinux-%Y-%m-%d-%s_screenshot_$wx$h.jpg' -e 'mv $f $$(xdg-user-dir PICTURES)'")),
    Key([mod], "a", lazy.spawn("xfce4-appfinder")),

# SUPER + SHIFT KEYS

    Key([mod, "shift"], "q", lazy.window.kill()),
    Key([mod, "shift"], "r", lazy.restart()),


# QTILE LAYOUT KEYS
    Key([mod], "n", lazy.layout.normalize()),
    Key([mod], "space", lazy.next_layout()),

# CHANGE FOCUS
    Key([mod], "Up", lazy.layout.up()),
    Key([mod], "Down", lazy.layout.down()),
    Key([mod], "Left", lazy.layout.left()),
    Key([mod], "Right", lazy.layout.right()),
    Key([mod], "k", lazy.layout.up()),
    Key([mod], "j", lazy.layout.down()),
    Key([mod], "h", lazy.layout.left()),
    Key([mod], "l", lazy.layout.right()),


# RESIZE UP, DOWN, LEFT, RIGHT
    Key([mod, "control"], "l",
        lazy.layout.grow_right(),
        lazy.layout.grow(),
        lazy.layout.increase_ratio(),
        lazy.layout.delete(),
        ),
    Key([mod, "control"], "Right",
        lazy.layout.grow_right(),
        lazy.layout.grow(),
        lazy.layout.increase_ratio(),
        lazy.layout.delete(),
        ),
    Key([mod, "control"], "h",
        lazy.layout.grow_left(),
        lazy.layout.shrink(),
        lazy.layout.decrease_ratio(),
        lazy.layout.add(),
        ),
    Key([mod, "control"], "Left",
        lazy.layout.grow_left(),
        lazy.layout.shrink(),
        lazy.layout.decrease_ratio(),
        lazy.layout.add(),
        ),
    Key([mod, "control"], "k",
        lazy.layout.grow_up(),
        lazy.layout.grow(),
        lazy.layout.decrease_nmaster(),
        ),
    Key([mod, "control"], "Up",
        lazy.layout.grow_up(),
        lazy.layout.grow(),
        lazy.layout.decrease_nmaster(),
        ),
    Key([mod, "control"], "j",
        lazy.layout.grow_down(),
        lazy.layout.shrink(),
        lazy.layout.increase_nmaster(),
        ),
    Key([mod, "control"], "Down",
        lazy.layout.grow_down(),
        lazy.layout.shrink(),
        lazy.layout.increase_nmaster(),
        ),


# FLIP LAYOUT FOR MONADTALL/MONADWIDE
    Key([mod, "shift"], "f", lazy.layout.flip()),

# FLIP LAYOUT FOR BSP
    Key([mod, "mod1"], "k", lazy.layout.flip_up()),
    Key([mod, "mod1"], "j", lazy.layout.flip_down()),
    Key([mod, "mod1"], "l", lazy.layout.flip_right()),
    Key([mod, "mod1"], "h", lazy.layout.flip_left()),

# MOVE WINDOWS UP OR DOWN BSP LAYOUT
    Key([mod, "shift"], "k", lazy.layout.shuffle_up()),
    Key([mod, "shift"], "j", lazy.layout.shuffle_down()),
    Key([mod, "shift"], "h", lazy.layout.shuffle_left()),
    Key([mod, "shift"], "l", lazy.layout.shuffle_right()),

# MOVE WINDOWS UP OR DOWN MONADTALL/MONADWIDE LAYOUT
    Key([mod, "shift"], "Up", lazy.layout.shuffle_up()),
    Key([mod, "shift"], "Down", lazy.layout.shuffle_down()),
    Key([mod, "shift"], "Left", lazy.layout.swap_left()),
    Key([mod, "shift"], "Right", lazy.layout.swap_right()),

# TOGGLE FLOATING LAYOUT
    Key([mod, "shift"], "space", lazy.window.toggle_floating()),

 # Key([mod], "r", lazy.spawncmd(), desc="Spawn a command using a prompt widget"),
    Key(['mod4'], 'd', lazy.run_extension(extension.DmenuRun(
        dmenu_prompt="Run:",
        dmenu_font="sans",
        dmenu_lines=10,
    ))),

# Brightness controls
    Key([], "XF86MonBrightnessUp", lazy.spawn(
        'lux -a 10'), desc="Brightness Up"),
    Key([], "XF86MonBrightnessDown", lazy.spawn(
        'lux -s 10'), desc="Brightness Down"),
    ]

def window_to_previous_screen(qtile, switch_group=False, switch_screen=False):
    i = qtile.screens.index(qtile.current_screen)
    if i != 0:
        group = qtile.screens[i - 1].group.name
        qtile.current_window.togroup(group, switch_group=switch_group)
        if switch_screen == True:
            qtile.cmd_to_screen(i - 1)

def window_to_next_screen(qtile, switch_group=False, switch_screen=False):
    i = qtile.screens.index(qtile.current_screen)
    if i + 1 != len(qtile.screens):
        group = qtile.screens[i + 1].group.name
        qtile.current_window.togroup(group, switch_group=switch_group)
        if switch_screen == True:
            qtile.cmd_to_screen(i + 1)

keys.extend([
    # MOVE WINDOW TO NEXT SCREEN
    Key([mod,"shift"], "Right", lazy.function(window_to_next_screen, switch_screen=True)),
    Key([mod,"shift"], "Left", lazy.function(window_to_previous_screen, switch_screen=True)),
])

These lines of code define a list of keybindings for the window manager. Each keybinding consists of a key combination and an action that should be taken when the key combination is pressed.

The key combinations are specified using the Key class from the libqtile.config module, which takes a list of modifier keys as its first argument and a key as its second argument. The action that should be taken is specified as a function or method call, which is passed as the third argument to the Key constructor.

The lazy decorator is used to wrap many of the function and method calls, which delays their execution until they are needed. This can be useful for optimizing the performance of the window manager.

Some examples of the keybindings defined in this list include:

  • Pressing Mod4+F (Mod4 is the key specified by the mod variable, which is likely the name of a modifier key) will toggle the current window between fullscreen and windowed mode.

  • Pressing Mod4+Q will close the current window.

  • Pressing Mod4+F will launch a web browser.

  • Pressing Mod4+Return will launch a terminal emulator.

  • Pressing Mod4+Shift+Return will launch a file manager.

  • Pressing Mod4+X will log out of the system.

  • Pressing Print will take a screenshot of the entire screen and save it to the user's Pictures directory.

  • Pressing Mod4+A will launch an appfinder.

  • Pressing Mod4+Shift+Q will close the current window.

  • Pressing Mod4+Shift+R will restart the window manager.

  • Pressing Mod4+N will normalize the window size and position.

  • Pressing Mod4+Space will switch to the next layout.

  • Pressing Mod4+Up, Mod4+Down, Mod4+Left, or Mod4+Right will change the focus to the window in the specified direction.

  • Pressing Mod4+Control+Right, Mod4+Control+Left, Mod4+Control+Up, or Mod4+Control+Down will resize the current window in the specified direction.

  • Pressing Mod4+Shift+F will flip the layout for the current group.

  • Pressing Mod4+Mod1+Up, Mod4+Mod1+Down, Mod4+Mod1+Left, or Mod4+Mod1+Right will flip the layout in the specified direction for the current group.

  • Pressing Mod4+Shift+Up, Mod4+Shift+Down, Mod4+Shift+Left, or Mod4+Shift+Right will move the current window in the specified direction for the current group.

There are many more keybindings defined in this list, but these are just a few examples.

Groups

groups = []
#["", "", "", "", "", "", "", "", "", "",]
groups = [
        Group(name="1"),
        Group(name="2"),
        Group(name="3"),
        Group(name="4"),
        Group(name="5"),
        Group(name="6"),
        ]

for i in groups:
    keys.extend([

#CHANGE WORKSPACES
        Key([mod], i.name, lazy.group[i.name].toscreen()),
        Key([mod], "Tab", lazy.screen.next_group()),
        Key([mod, "shift" ], "Tab", lazy.screen.prev_group()),
        Key(["mod1"], "Tab", lazy.screen.next_group()),
        Key(["mod1", "shift"], "Tab", lazy.screen.prev_group()),

# MOVE WINDOW TO SELECTED WORKSPACE 1-10 AND STAY ON WORKSPACE
        #Key([mod, "shift"], i.name, lazy.window.togroup(i.name)),
# MOVE WINDOW TO SELECTED WORKSPACE 1-10 AND FOLLOW MOVED WINDOW TO WORKSPACE
        Key([mod, "shift"], i.name, lazy.window.togroup(i.name) , lazy.group[i.name].toscreen()),
    ])

These lines of code define a list of groups for the window manager and extend the list of keybindings with additional keybindings for changing and moving windows between these groups.

The groups list is initialized with a list of Group objects, each of which represents a workspace managed by the window manager. The name attribute of each Group object specifies the name of the group, which is used to identify the group and is displayed in the window manager's user interface.

The keys list is then extended with additional keybindings that allow the user to switch between the different groups, move windows between groups, and follow moved windows to their new group.

Some examples of the keybindings added to the keys list include:

  • Pressing Mod4+1, Mod4+2, Mod4+3, etc. will switch to the group with the corresponding name.

  • Pressing Mod4+Tab will switch to the next group.

  • Pressing Mod4+Shift+Tab will switch to the previous group.

  • Pressing Mod1+Tab will switch to the next group.

  • Pressing Mod1+Shift+Tab will switch to the previous group.

  • Pressing Mod4+Shift+1, Mod4+Shift+2, Mod4+Shift+3, etc. will move the current window to the group with the corresponding name and follow the moved window to that group.

Note that the commented out keybinding Key([mod, "shift"], i.name, lazy.window.togroup(i.name)) is identical to the keybinding that follows it, except that it does not include the lazy.group[i.name].toscreen() call. This means that the commented out keybinding will move the current window to the group with the corresponding name, but will not switch to that group.

Layouts

def init_layout_theme():
    return {"margin":10,
            "border_width":2,
            "border_focus": colors[8],
            "border_normal": colors[9]
            }

layout_theme = init_layout_theme()


layouts = [
    # layout.MonadTall(margin=8, border_width=2, border_focus="#5e81ac", border_normal="#4c566a"),
    layout.MonadTall(**layout_theme),
    # layout.Columns(**layout_theme),
    # layout.MonadWide(margin=8, border_width=2, border_focus="#5e81ac", border_normal="#4c566a"),
    layout.MonadWide(**layout_theme),
    layout.Matrix(**layout_theme),
    # layout.Bsp(**layout_theme),
    # layout.Floating(**layout_theme),
    # layout.RatioTile(**layout_theme),
    # layout.Max(**layout_theme)
]

These lines of code define a function named init_layout_theme that returns a dictionary containing layout theme options for the window manager. It looks like the function is intended to initialize the layout_theme variable with a set of default layout theme values.

The layout_theme variable is then initialized with the return value of the init_layout_theme function. This will initialize layout_theme with the default set of layout theme options defined in the function.

The layouts list is then defined as a list of layout objects that the window manager can use to arrange windows on the screen. Each layout object is created using the layout module and is passed the layout theme options contained in the layout_theme dictionary using the ** operator. This allows the layout theme options to be passed to the layout constructor as keyword arguments.

The available layout objects include:

  • MonadTall: A tiling layout with a main window and a stack of windows on the right.

  • MonadWide: A tiling layout with a main window and a stack of windows below.

  • Matrix: A tiling layout that arranges windows in a grid.

  • Bsp: A binary space partitioning layout that arranges windows in a tree structure.

  • Floating: A layout that allows windows to be freely moved and resized.

  • RatioTile: A tiling layout that adjusts the size of windows based on their ratios.

  • Max: A layout that displays only one window at a time and hides all others.

Note that some of the layout objects are commented out, which means that they will not be available to the window manager.

Widgets

# WIDGETS FOR THE BAR
def init_widgets_defaults():
    return dict(
                font="sans",
                fontsize=14,
                padding=4,
                background=colors[1])

widget_defaults = init_widgets_defaults()

def init_widgets_list():
    widgets_list = [
                widget.Sep(
                    linewidth=0,
                    padding=6,
                    foreground=colors[2],
                    background=colors[0],
                ),
                widget.Image(
                    filename="~/.config/qtile/icons/.face",
                    scale="False",
                    margin=5,
                    foreground=colors[2],
                    background=colors[0],
                    mouse_callbacks={'Button1': lazy.spawn('dmenu_run')},
                ),
                widget.Sep(
                    linewidth=0,
                    padding=6,
                    foreground=colors[2],
                    background=colors[0]
                ),
                widget.GroupBox(
                    font="Ubuntu Bold",
            fontsize=10,
                    margin_y=3,
                    margin_x=0,
                    padding_y=5,
                    padding_x=3,
                    borderwidth=3,
                    active=colors[8],
                    inactive=colors[2],
                    rounded=True,
                    highlight_color=colors[1],
                    highlight_method="line",
                    this_current_screen_border=colors[6],
                    this_screen_border=colors[4],
                    other_current_screen_border=colors[6],
                    other_screen_border=colors[4],
                    foreground=colors[2],
                    background=colors[0]
                ),
                widget.TextBox(
                    text='|',
                    font="Ubuntu Mono",
                    background=colors[0],
                    foreground=colors[1],
                    padding=0,
                    fontsize=50
                ),
                widget.CurrentLayoutIcon(
                    custom_icon_paths=[os.path.expanduser(
                        "~/.config/qtile/icons")],
                    foreground=colors[9],
                    background=colors[0],
                    padding=0,
                    scale=0.45,
                ),
                widget.CurrentLayout(
                    foreground=colors[9],
                    background=colors[0],
                    padding=5,
                ),
                widget.TextBox(
                    text='|',
                    font="Ubuntu Mono",
                    background=colors[0],
                    foreground=colors[1],
                    padding=2,
                    fontsize=50
                ),
                widget.WindowName(
                    foreground=colors[2],
                    background=colors[0],
                    padding=0,
                ),
                #####
                 widget.TextBox(
                    text='|',
                    font="Ubuntu Mono",
                    background=colors[0],
                    foreground=colors[1],
                    padding=0,
                    fontsize=50
                ),
                widget.Net(
                    foreground=colors[2],
                    background=colors[0],
                    format = ' {down}    {up} ',
                ),
                #####
                widget.TextBox(
                    text='',
                    background=colors[0],
                    foreground=colors[1],
                    padding=0,
                    fontsize=50,
                ),
                widget.Systray(
                    foreground=colors[7],
                    background=colors[1],
                    padding=5,
                    icon_size=17,
                ),
                widget.Volume(
                    foreground=colors[2],
                    background=colors[1],
                    fmt='{}',
                    padding=4,
                    fontsize=10,
                ),
                widget.Sep(
                    linewidth=0,
                    padding=6,
                    background=colors[1]
                ),
                #####
                widget.TextBox(
                    text='',
                    background=colors[1],
                    foreground=colors[0],
                    padding=0,
                    fontsize=50,
                ),
                widget.ThermalSensor(
                    foreground=colors[2],
                    background=colors[0],
                    format = '  {temp:.1f}{unit} ',
                ),
                widget.Sep(
                    linewidth=0,
                    padding=6,
                    background=colors[0]
                ),
                #####
                widget.TextBox(
                    text='',
                    background=colors[0],
                    foreground=colors[1],
                    padding=0,
                    fontsize=50,
                ),
                widget.Battery(
                    format = '   {percent:2.0%} {char} {hour:d}:{min:02d}',
                    charge_char='AC',
                    discharge_char='DC',
                    foreground=colors[4],
                    background=colors[1],
                    update_interval=1,
                    low_percentage=0.3,
                    low_foreground=colors[3]
                ),
                widget.Sep(
                    linewidth=0,
                    padding=6,
                    background=colors[1]
                ),
                #####
                widget.TextBox(
                    text='',
                    background=colors[1],
                    foreground=colors[0],
                    padding=0,
                    fontsize=50,
                ),
                widget.Clock(
                    foreground=colors[2],
                    background=colors[0],
                    format="    %d %b, %a %I:%M %p"
                ),
                widget.Sep(
                    linewidth=0,
                    padding=6,
                    background=colors[0]
                ),
            ]
    return widgets_list

widgets_list = init_widgets_list()

Screens

def init_widgets_screen1():
    widgets_screen1 = init_widgets_list()
    return widgets_screen1

def init_widgets_screen2():
    widgets_screen2 = init_widgets_list()
    return widgets_screen2

widgets_screen1 = init_widgets_screen1()
widgets_screen2 = init_widgets_screen2()


def init_screens():
    return [
            Screen(top=bar.Bar(widgets=init_widgets_screen1(), size=30, opacity=0.9)),
            Screen(top=bar.Bar(widgets=init_widgets_screen2(), size=30, opacity=0.9))
        ]
screens = init_screens()

This block of code is defining a number of widgets that can be displayed on the bar at the top of the screen by the window manager.

The init_widgets_defaults function is defined to return a dictionary containing default options for the widgets. The widget_defaults variable is then initialized with the return value of this function, which will set the default options for the widgets.

The init_widgets_list function is then defined to return a list of widget objects. Each widget object is created using the widget module and is passed the default options contained in the widget_defaults dictionary using the ** operator. This allows the default options to be passed to the widget constructor as keyword arguments.

The available widget objects include:

  • Sep: A separator widget that displays a line or other separator between other widgets.

  • Image: A widget that displays an image file.

  • GroupBox: A widget that displays a box containing the names of the groups and the windows they contain.

  • TextBox: A widget that displays a block of text.

  • CurrentLayoutIcon: A widget that displays an icon representing the current layout.

  • CurrentLayout: A widget that displays the name of the current layout.

  • WindowName: A widget that displays the name of the currently focused window.

  • Net: A widget that displays network usage information.

  • Systray: A widget that displays icons for system tray applications.

  • Volume: A widget that displays the current volume level.

  • Battery: A widget that displays battery information.

  • Clock: A widget that displays the current time and date.

The widgets will be displayed on the bar in the order they appear in the list.

Mouse Configuration

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())
]

dgroups_key_binder = None
dgroups_app_rules = []

This block of code is defining some mouse binding and application rules for the window manager.

The mouse list contains two Drag objects, which define mouse binding rules for dragging windows around the screen. The first Drag object binds the left mouse button to the window.set_position_floating method, which allows the window to be moved to any position on the screen by clicking and dragging the window. The second Drag object binds the right mouse button to the window.set_size_floating method, which allows the window to be resized by clicking and dragging the window's edges or corners.

The dgroups_key_binder variable is set to None, which means that there are no key bindings defined for dynamic groups (groups that can be created and destroyed at runtime).

The dgroups_app_rules variable is set to an empty list, which means that there are no rules defined for dynamically assigning windows to dynamic groups.

Hooks

main = None

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

@hook.subscribe.startup
def start_always():
    # Set the cursor to something sane in X
    subprocess.Popen(['xsetroot', '-cursor_name', 'left_ptr'])

@hook.subscribe.client_new
def set_floating(window):
    if (window.window.get_wm_transient_for()
            or window.window.get_wm_type() in floating_types):
        window.floating = True

This block of code defines three hook functions and a main function. Hook functions are functions that are called at specific points in the window manager's lifecycle.

The start_once hook function is called only once, when the window manager starts up. It expands the ~ character in the home variable to the user's home directory, and then runs the autostart.sh script located in the ~/.config/qtile/scripts directory.

The start_always hook function is called every time the window manager starts up. It sets the cursor to the left pointer using the xsetroot command.

The set_floating hook function is called whenever a new client (application window) is created. It sets the floating attribute of the window object to True if the window is a transient window (a window that is dependent on another window) or if the window's type is in the floating_types list. This causes the window to be treated as a floating window, which means that it will not be managed by the tiling layout and will be allowed to be positioned and resized manually.

The main function is set to None, which means that it is not being used in this configuration.

Floating Layout Configuration

floating_types = ["notification", "toolbar", "splash", "dialog"]


follow_mouse_focus = True
bring_front_click = False
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
    Match(wm_class='Arcolinux-welcome-app.py'),
    Match(wm_class='Arcolinux-calamares-tool.py'),
    Match(wm_class='confirm'),
    Match(wm_class='dialog'),
    Match(wm_class='download'),
    Match(wm_class='error'),
    Match(wm_class='file_progress'),
    Match(wm_class='notification'),
    Match(wm_class='splash'),
    Match(wm_class='toolbar'),
    Match(wm_class='Arandr'),
    Match(wm_class='feh'),
    Match(wm_class='Galculator'),
    Match(wm_class='archlinux-logout'),
],  fullscreen_border_width = 0, border_width = 0)
auto_fullscreen = True

focus_on_window_activation = "focus" # or smart

wmname = "LG3D"

The floating_types list specifies the types of windows that should be treated as floating windows. These are windows that should not be tiled with other windows, but should instead be allowed to be moved and resized freely.

The follow_mouse_focus setting determines whether the focus should automatically be moved to the window under the mouse cursor when the mouse is moved.

The bring_front_click setting determines whether clicking on a window should bring it to the front of all other windows.

The cursor_warp setting determines whether the mouse cursor should be moved to the center of the window when it is focused.

The floating_layout variable specifies the layout that should be used for floating windows. In this case, it is set to a Floating layout with a number of rules for specific window types and titles that should be treated as floating.

The auto_fullscreen setting determines whether a window should be automatically set to fullscreen mode when it is opened in a floating layout.

The focus_on_window_activation setting determines the behavior of the window focus when a window is activated (e.g. when it is clicked on or given focus by another window). The possible values are "focus", which means the window should be given focus, and "smart", which means the focus should be given to the window unless it is already focused, in which case the focus should be left unchanged.

Final Words

In conclusion, the configuration file for the Qtile window manager is a powerful tool for customizing and organizing your desktop experience. It allows you to specify keybindings, define groups of workspaces, customize the look and behavior of the bar and widgets and set rules for how windows should behave. With a little bit of scripting knowledge, the possibilities are endless. I hope this blog has helped me understand the structure and purpose of the Qtile configuration file. Happy desktop customization! And as always, Keep Reading, Keep Exploring and Keep Learning.