qtile: Recently introduced crashes

Issue description

Sometimes Qtile crashes, freezing everything (except the mouse), logging nothing obvious, and as far as I can tell it isn’t triggered by anything in particular.

cqs on IRC said they also experienced a crash (on master) with similar log output to what I see.

Qtile version

I’ve beent trying to bisect commits to identify when it was introduced. This is where I’m at so far:

146405095217428cdf5bb262978a8d92dbbb459f is bad
bb726c2cbd201383ac90d189b73250aa9ca03dfe is bad
0e9382683cffc90c1fb097f34b4d13466d709165 seems fine
d584893119bd0710c99f7ca00dc81b36a31c205e seems fine

Unfortunately without a reproducible trigger, this basically involves just waiting until a crash happens, or doesn’t after a day or so.

I’m still testing commits so I’ll keep you updated aboit how that goes.

Stack traces

I do consistently see the same log output, which at least is a lead:

logs
2021-02-09 08:41:57,590 ERROR libqtile manager.py:get_interesting_pid():L596 Got an exception in getting the window pid
Traceback (most recent call last):
  File "/usr/lib/python3.9/site-packages/xcffib/__init__.py", line 571, in wrapper
    return f(*args)
  File "/usr/lib/python3.9/site-packages/xcffib/__init__.py", line 658, in wait_for_reply
    self._process_error(error_p[0])
  File "/usr/lib/python3.9/site-packages/xcffib/__init__.py", line 645, in _process_error
    self.invalid()
  File "/usr/lib/python3.9/site-packages/xcffib/__init__.py", line 559, in invalid
    raise ConnectionException(err)
xcffib.ConnectionException: xcb connection errors because of socket, pipe and other stream errors.

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/mcol/git/qtile/libqtile/core/manager.py", line 594, in get_interesting_pid
    return win.window.get_net_wm_pid()
  File "/home/mcol/git/qtile/libqtile/backend/x11/xcbq.py", line 619, in get_net_wm_pid
    r = self.get_property("_NET_WM_PID", unpack=int)
  File "/home/mcol/git/qtile/libqtile/backend/x11/xcbq.py", line 712, in get_property
    r = self.conn.conn.core.GetProperty(
  File "/usr/lib/python3.9/site-packages/xcffib/__init__.py", line 332, in reply
    data = self.conn.wait_for_reply(self.sequence)
  File "/usr/lib/python3.9/site-packages/xcffib/__init__.py", line 573, in wrapper
    self.invalid()
  File "/usr/lib/python3.9/site-packages/xcffib/__init__.py", line 559, in invalid
    raise ConnectionException(err)
xcffib.ConnectionException: xcb connection errors because of socket, pipe and other stream errors.
2021-02-09 08:41:57,635 ERROR libqtile manager.py:get_interesting_pid():L596 Got an exception in getting the window pid
Traceback (most recent call last):
  File "/home/mcol/git/qtile/libqtile/core/manager.py", line 594, in get_interesting_pid
    return win.window.get_net_wm_pid()
  File "/home/mcol/git/qtile/libqtile/backend/x11/xcbq.py", line 619, in get_net_wm_pid
    r = self.get_property("_NET_WM_PID", unpack=int)
  File "/home/mcol/git/qtile/libqtile/backend/x11/xcbq.py", line 712, in get_property
    r = self.conn.conn.core.GetProperty(
  File "/usr/lib/python3.9/site-packages/xcffib/xproto.py", line 2720, in GetProperty
    return self.send_request(20, buf, GetPropertyCookie, is_checked=is_checked)
  File "/usr/lib/python3.9/site-packages/xcffib/__init__.py", line 391, in send_request
    seq = self.conn.send_request(flags, xcb_parts + 2, xcb_req)
  File "/usr/lib/python3.9/site-packages/xcffib/__init__.py", line 569, in wrapper
    self.invalid()
  File "/usr/lib/python3.9/site-packages/xcffib/__init__.py", line 559, in invalid
    raise ConnectionException(err)
xcffib.ConnectionException: xcb connection errors because of socket, pipe and other stream errors.
2021-02-09 08:41:57,657 ERROR libqtile core.py:_xpoll():L290 Shutting down due to X connection error XCB_CONN_ERROR (1)
Traceback (most recent call last):
  File "/home/mcol/git/qtile/libqtile/backend/x11/core.py", line 251, in _xpoll
    event = self.conn.conn.poll_for_event()
  File "/usr/lib/python3.9/site-packages/xcffib/__init__.py", line 569, in wrapper
    self.invalid()
  File "/usr/lib/python3.9/site-packages/xcffib/__init__.py", line 559, in invalid
    raise ConnectionException(err)
xcffib.ConnectionException: xcb connection errors because of socket, pipe and other stream errors.

Configuration

My config
"""
Qtile main config file
======================
"""

import os
import sys
import subprocess
from functools import partial

from libqtile.config import Key, EzKey, Screen, Group, Drag, Click, Match, ScratchPad, DropDown
from libqtile.lazy import lazy
from libqtile import layout, hook, bar, widget, qtile
from libqtile.log_utils import logger
from libqtile.widget.backlight import ChangeDirection

sys.path.append('/home/mcol/git/qtools')

HOME = os.path.expanduser('~')
DISPLAY = os.environ.get("DISPLAY")


## X resources
import qtools.xresources as xresources
default_colors = dict(
    foreground='#dfdfdf',
    background='#070611',
    color0='#0e101c',
    color8='#14172a',
    color1='#ba6767',
    color9='#e49090',
    color2='#72b978',
    color10='#92ec96',
    color3='#cec991',
    color11='#d3cd91',
    color4='#6fa3e0',
    color12='#80b0ec',
    color5='#323974',
    color13='#323974',
    color6='#72eeee',
    color14='#72eeee',
    color7='#dfdfdf',
    color15='#dfdfdf',
)

xres = xresources.get(DISPLAY, default_colors)
wm_bw = int(xres.get('wm.bw', 5))
wm_cr = int(xres.get('wm.cr', 5))
wm_colorfocused = xres.get('wm.colorfocused', '#6fa3e0')
wm_colorunfocused = xres.get('wm.colorunfocused', '#0e101c')
#wm_gapsinner = int(xres.get('wm.gapsinner', 2)) // 3
wm_gapsinner = 2
#wm_gapsouter = int(xres.get('wm.gapsouter', 10)) // 3
wm_gapsouter = 2
background = xres.get('background')
foreground = xres.get('foreground')
xcolors = [xres.get(f'color{n}') for n in range(16)]


## Keybindings
mod = "mod4"
alt = "mod1"

import qtools.focus

@lazy.function
def float_to_front(qtile):
    """ Bring all floating windows of the group to front """
    for window in qtile.current_group.windows:
        if window.floating:
            window.cmd_bring_to_front()


def shell(command):
    """ Provides ability to run abitrary shell commands from key bindings """
    @lazy.function
    def _inner(qtile):
        os.system(command)
    return _inner


keys = [EzKey(k, v, desc=d) for k, v, d in [
    #('M-A-1',        lazy.window.keep_above(),                "Close window"),
    #('M-A-2',        lazy.window.keep_below(),                "Close window"),
    #('M-A-3',        lazy.window.raise_client(),                "Close window"),
    #('M-A-4',        lazy.window.lower_client(),                "Close window"),
    #('M-A-1',        lazy.window.set_size_floating(0, 0),                "Close window"),

    # control qtile
    ('M-C-q',        lazy.window.kill(),                "Close window"),
    ('M-f',          lazy.window.toggle_fullscreen(),   "Toggle fullscreen"),
    ('M-S-<space>',  lazy.window.toggle_floating(),     "Toggle floating"),
    ('M-<space>',    float_to_front,        "Move floating windows to the front"),
    #('M-j',          lazy.traverse_down(),  "Focus down"),
    #('M-k',          lazy.traverse_up(),    "Focus up"),
    #('M-h',          lazy.traverse_left(),  "Focus left"),
    #('M-l',          lazy.traverse_right(), "Focus right"),
    ('M-j',          lazy.function(qtools.focus.down),  "Focus down"),
    ('M-k',          lazy.function(qtools.focus.up),    "Focus up"),
    ('M-h',          lazy.function(qtools.focus.left),  "Focus left"),
    ('M-l',          lazy.function(qtools.focus.right), "Focus right"),
    #('M-j',          lazy.layout.down(),  "Focus down"),
    #('M-k',          lazy.layout.up(),    "Focus up"),
    #('M-h',          lazy.layout.left(),  "Focus left"),
    #('M-l',          lazy.layout.right(), "Focus right"),
    ('M-S-j',        lazy.layout.shuffle_down(),        "Shuffle down"),
    ('M-S-k',        lazy.layout.shuffle_up(),          "Shuffle up"),
    ('M-S-h',        lazy.layout.shuffle_left(),        "Shuffle left"),
    ('M-S-l',        lazy.layout.shuffle_right(),       "Shuffle right"),
    ('M-A-j',        lazy.layout.grow_down(),           "Grow down"),
    ('M-A-k',        lazy.layout.grow_up(),             "Grow up"),
    ('M-A-h',        lazy.layout.grow_left(),           "Grow left"),
    ('M-A-l',        lazy.layout.grow_right(),          "Grow right"),
    ('M-S-r',        lazy.restart(),                    "Restart Qtile"),
    ('M-<Tab>',    lazy.next_layout(),                "Next layout"),
    ('M-C-h',        lazy.window.toggle_minimize(),     "Minimise window"),
    #('M-g',        lazy.window.static(1),                "Make window static"),

    ('<XF86AudioMute>',           lazy.widget['myvolume'].mute(),  "Mute audio"),
    ('<F10>',                     lazy.widget['myvolume'].mute(),  "Mute audio"),
    ('<XF86AudioRaiseVolume>',    lazy.widget['myvolume'].increase_vol(),  "Increase volume"),
    ('<F12>',                     lazy.widget['myvolume'].increase_vol(),  "Increase volume"),
    ('<XF86AudioLowerVolume>',    lazy.widget['myvolume'].decrease_vol(),  "Decrease volume"),
    ('<F11>',                     lazy.widget['myvolume'].decrease_vol(),  "Decrease volume"),

    ('<XF86MonBrightnessUp>',
        lazy.widget['backlight'].change_backlight(ChangeDirection.UP, 7), "Increase backlight"),
    ('<XF86MonBrightnessDown>',
        lazy.widget['backlight'].change_backlight(ChangeDirection.DOWN, 7), "Decrease backlight"),
    ('<F6>',
        lazy.widget['backlight'].change_backlight(ChangeDirection.UP, 7), "Increase backlight"),
    ('<F5>',
        lazy.widget['backlight'].change_backlight(ChangeDirection.DOWN, 7), "Decrease backlight"),

    ('M-<Return>',   lazy.spawn('urxvtc'),               "Spawn terminal"),

    ('M-S-f',        shell('wmctrl -a "Mozilla Firefox" || firefox &'), "Focus/spawn Firefox"),
    ('M-C-f',        shell('wmctrl -a "Tor Browser" || tor-browser --allow-remote &'), "Focus/spawn Tor Browser"),

    ('<Print>',     shell(f'maim -s | xclip -selection clipboard -t image/png'), "Screenshot to clipboard"),
    ('S-<Print>',  shell(f'maim -u -s {HOME}/desktop/$(date +%y%m%d-%H%M%S).png'), "Screenshot to file"),

    ('M-S-i',        lazy.spawn('slock systemctl suspend -i'),  "Suspend system and lock"),
    ('M-i',          lazy.spawn('systemctl suspend -i'),        "Suspend system"),

    #('M-d',          lazy.spawncmd(), "Run a command in the prompt widget"),
    ('M-d',          lazy.spawn('rofi -show run -theme ~/.config/rofi/common-large.rasi'), "rofi: run"),
    ('M-p',          lazy.spawn(f'{HOME}/.config/bin/get_password_rofi'), "rofi: keepass passwords"),
    #('M-S-s',        lazy.spawn('power-menu'), "rofi: power menu"),
    ('<XF86PowerOff>', lazy.spawn('power-menu'), "rofi: power menu"),

    ('<XF86TouchpadToggle>', lazy.spawn('kbd-tch'), "Disable/enable touchpad"),
    ('M-t',          lazy.spawn('kbd-tch'),         "Disable/enable touchpad"),
    ('M-S-x',        lazy.spawn('set_monitors'),    "Configure monitors"),
]]


## mouse control
mouse = [
    Drag([mod], "Button1",      lazy.window.set_position_floating(),    start=lazy.window.get_position()),
    Drag([mod, alt], "Button1", lazy.window.set_size_floating(), start=lazy.window.get_size()),
    Click([mod], "Button4",     lazy.layout.grow_up(2)),
    Click([mod], "Button5",     lazy.layout.grow_down(2)),
]


## Layouts

#border_focus = [xcolors[13], xcolors[5]]
border_focus = xcolors[13]
border_normal = xcolors[8]
border_width = 1

#import qtools.borders
#qtools.borders.enable('cde')
#border_focus = [border_focus, xcolors[5]]
#border_normal = [xcolors[0], xcolors[8]]


layouts = [
    layout.Columns(
        insert_position = 1,
        border_width = border_width,
        border_focus = border_focus,
        border_normal = border_normal,
        border_on_single = True,
        wrap_focus_columns = False,
        wrap_focus_rows = False,
        margin = wm_gapsinner,
        corner_radius = wm_cr,
    ),
    layout.Max(),
]

floating_layout = layout.Floating(
    border_width = border_width,
    border_focus = border_focus,
    border_normal = border_normal,
    corner_radius = wm_cr,
    float_rules=[
        Match(wm_class='Arandr'),
        Match(wm_class='confirm'),
        Match(wm_class='dialog'),
        Match(wm_class='download'),
        Match(wm_class='Dragon'),
        Match(wm_class='error'),
        Match(wm_class='fiji-Main'),
        Match(wm_class='file_progress'),
        Match(wm_class='fontforge'),
        Match(wm_class='imv'),
        Match(wm_class='love'),
        Match(wm_class='lxappearance'),
        Match(wm_class='mpv'),
        Match(wm_class='Nm-connection-editor'),
        Match(wm_class='notification'),
        Match(wm_class='Oomox'),
        Match(wm_class='Pavucontrol'),
        Match(wm_class='Pinentry-gtk-2'),
        Match(wm_class='qt5ct'),
        Match(wm_class='ssh-askpass'),
        Match(wm_class='tinyterm'),
        Match(wm_class='Dragon-drag-and-drop'),
        Match(wm_class='toolbar'),
        Match(wm_class='Xephyr'),
        Match(wm_type='dialog'),
        Match(role='gimp-file-export'),
    ]
)


## Screens and Bars
widget_defaults = {
    'padding': 10,
    'foreground': foreground,
    'font': 'Font Awesome 5 Free',
    'fontsize': 16,
}

trim = widget.TextBox(' ', background=xcolors[8])

groupbox_config = {
    'active': foreground,
    'highlight_method': 'line',
    'this_current_screen_border': wm_colorfocused,
    'other_current_screen_border': xcolors[5],
    'highlight_color': [background, xcolors[5]],
    'disable_drag': True,
    'padding': 8,
}

mpd2 = widget.Mpd2(
    no_connection='',
    status_format='{artist} - {title}',
    status_format_stopped='',
    foreground=xcolors[12],
    idle_format='',
    fontsize=16,
    font='TamzenForPowerline Bold',
    update_interval=10,
)

 
cpugraph = widget.CPUGraph(
    graph_color=xcolors[12],
    fill_color=wm_colorunfocused,
    border_width=0,
    margin_x=10,
    margin_y=4,
    samples=50,
    line_width=4,
    width=200,
    type='box',
    frequency=0.5,
)

bklight = widget.Backlight(
    backlight_name=os.listdir('/sys/class/backlight')[0],
    step=2,
    update_interval=None,
    format="",
    change_command=None,
    foreground=xcolors[3],
)

from libqtile.widget.volume import Volume
class MyVolume(Volume):
    def _configure(self, qtile, bar):
        Volume._configure(self, qtile, bar)
        self.volume = self.get_volume()
        self._update_drawer()
    def _update_drawer(self):
        if self.volume <= 0:
            self.text = ''
        elif self.volume <= 15:
            self.text = ''
        elif self.volume < 50:
            self.text = ''
        else:
            self.text = ''
        self.draw()

    def cmd_increase_vol(self):
        subprocess.call('amixer set PCM 4%+'.split())
        self.volume = self.get_volume()
        self._update_drawer()
    def cmd_decrease_vol(self):
        subprocess.call('amixer set PCM 4%-'.split())
        self.volume = self.get_volume()
        self._update_drawer()
    def cmd_mute(self):
        subprocess.call('amixer set Master toggle'.split())
        self.channel = 'Master'
        self.volume = self.get_volume()
        self.channel = 'PCM'
        if self.volume == 0:
            self.volume = self.get_volume()
        self._update_drawer()

volume = MyVolume(
    fontsize=18,
    channel='PCM',
    font='Font Awesome 5 Free',
    foreground=xcolors[4],
    update_interval=60,
)

import libqtile.widget.systray
class Systray(libqtile.widget.systray.Systray):
    def draw(self):
        xoffset = self.padding
        self.drawer.clear(self.background or self.bar.background)
        self.drawer.draw(offsetx=self.offset, width=self.length)
        for icon in self.icons.values():
            icon.hide()

systray = Systray()

wlan = widget.Wlan(
    format='',
    disconnected_message='',
    mouse_callbacks={
        'Button1': partial(qtile.cmd_spawn, 'urxvtc -geometry 50x20 -e nmtui'),
        'Button3': partial(qtile.cmd_spawn, 'nm-connection-editor'),
    },
    foreground=xcolors[5],
    update_interval=5,
)

from libqtile.widget.battery import Battery, BatteryState
class MyBattery(Battery):
    def build_string(self, status):
        if self.layout is not None:
            if status.state == BatteryState.DISCHARGING and status.percent < self.low_percentage:
                self.layout.colour = self.low_foreground
            else:
                self.layout.colour = self.foreground
        if status.state == BatteryState.DISCHARGING:
            if status.percent > 0.75:
                char = ''
            elif status.percent > 0.45:
                char = ''
            else:
                char = ''
        elif status.percent >= 1 or status.state == BatteryState.FULL:
            char = ''
        elif status.state == BatteryState.EMPTY or \
                (status.state == BatteryState.UNKNOWN and status.percent == 0):
            char = ''
        else:
            char = ''
        return self.format.format(char=char, percent=status.percent)

    def restore(self):
        self.format = '{char}'
        self.font = 'Font Awesome 5 Free'
        self.timer_setup()

    def button_press(self, x, y, button):
        old = self.format
        self.format = '{percent:2.0%}'
        self.font='TamzenForPowerline Bold'
        self.timer_setup()
        self.timeout_add(1, self.restore)

battery = MyBattery(
    format='{char}',
    low_foreground=xcolors[1],
    show_short_text=False,
    low_percentage=0.12,
    foreground=xcolors[6],
    notify_below=12,
)

date = widget.Clock(
    format='%e/%m/%g',
    fontsize=16,
    font='TamzenForPowerline Bold',
    foreground=xcolors[7],
    update_interval=60,
)
time = widget.Clock(
    fontsize=20,
    font='TamzenForPowerline Medium',
    update_interval=60,
)

import socket
def is_up(url):
    def _():
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        try:
            sock.connect((url, 443))
            sock.close()
            return ''
        except ConnectionRefusedError:
            return f"Down: {url}"
        except socket.gaierror as e:
            logger.exception(e)
            return ""
    return _
cakeup = widget.GenPollText(
    func=is_up('cakeandcoffee.club'),
    update_interval=300,
)

groupboxes = [
    widget.GroupBox(**groupbox_config, visible_groups=['1', '2', '3', 'q', 'w', 'e']),
    widget.GroupBox(**groupbox_config, visible_groups=['q', 'w', 'e']),
]

gaps = wm_gapsinner + wm_gapsouter
screens = [
    Screen(
        top=bar.Bar(
            [
                trim, groupboxes[0], trim, cpugraph, widget.Spacer(), mpd2,
                widget.Spacer(), cakeup, systray, bklight, volume, wlan,
                battery, trim, date, time, trim,
            ],
            40,
            background=background,
            margin=[gaps, gaps, wm_gapsouter, gaps],
        ),
        wallpaper_mode='fill',
        bottom=bar.Gap(wm_gapsouter),
        left=bar.Gap(wm_gapsouter),
        right=bar.Gap(wm_gapsouter),
        wallpaper=f'{HOME}/pictures/pixart/diver.png'
    ),
    Screen(
        top=bar.Bar(
            [
                trim, groupboxes[1], trim, cpugraph, widget.Spacer(), mpd2,
                widget.Spacer(), cakeup, bklight, volume, wlan, battery,
                trim, date, time, trim
            ],
            40,
            background=background,
            margin=[gaps, gaps, wm_gapsouter, gaps],
        ),
        wallpaper_mode='fill',
        bottom=bar.Gap(wm_gapsouter),
        left=bar.Gap(wm_gapsouter),
        right=bar.Gap(wm_gapsouter),
        wallpaper=f'{HOME}/pictures/pixart/diver.png'
    ),
]

## Groups
groups = [
    Group('1', label=''),
    Group('2', label='', matches=[Match(wm_class='Tor Browser')]),
    Group('3', label='', matches=[Match(wm_class='firefox')]),
    Group('q', label=''),
    Group('w', label='', matches=[Match(wm_class='Slack')]),
    Group('e', label='', matches=[Match(wm_class='halebird')]),
]

def _go_to_group(group):
    def _inner(qtile):
        if len(qtile.screens) > 1:
            old = qtile.current_screen.group.name
            if group in '123':
                qtile.focus_screen(0)
                if old in '123' or qtile.current_screen.group.name != group:
                    qtile.groups_map[group].cmd_toscreen()
            else:
                qtile.focus_screen(1)
                if old in 'qwe' or qtile.current_screen.group.name != group:
                    qtile.groups_map[group].cmd_toscreen()
        else:
            qtile.groups_map[group].cmd_toscreen()
    return _inner


for i in groups:
    keys.extend([
        Key([mod], i.name, lazy.function(_go_to_group(i.name))),
        Key([mod, 'shift'], i.name, lazy.window.togroup(i.name)),
    ])

def _scroll_screen(direction):
    """ Scroll next group of subset allocated to specific screen """
    def _inner(qtile):
        if len(qtile.screens) > 1:
            current = qtile.groups.index(qtile.current_group)
            if current < 3:
                destination = (current + direction) % 3
            else:
                destination = ((current - 3 + direction) % 3) + 3
            qtile.groups[destination].cmd_toscreen()
        else:
            current = qtile.groups.index(qtile.current_group)
            destination = (current + direction) % 6
            qtile.groups[destination].cmd_toscreen()
    return _inner

keys.extend([
    Key([mod], 'm', lazy.function(_scroll_screen(1))),
    Key([mod], 'n', lazy.function(_scroll_screen(-1))),
])

groups.extend([
    ScratchPad("scratchpad", [
        DropDown("tmux", "urxvt -e tmux", height=0.4,
                on_focus_lost_hide=True, opacity=1, warp_pointer=False),
        DropDown("email", f"urxvt -cd {HOME}/Downloads -e mutt",
                 x=0.1, y=0.05, width=0.8, height=0.9, opacity=1,
                 on_focus_lost_hide=False, warp_pointer=False),
        DropDown("irc", f"urxvt -b 100 --bell-command"
                        " \"mpv /usr/share/sounds/freedesktop/stereo/dialog-information.oga\""
                        " -e irc",
                 x=0.1, y=0.05, width=0.8, height=0.9, opacity=1,
                 on_focus_lost_hide=False, warp_pointer=False),
        DropDown("ncmpcpp", "urxvt -e ncmpcpp",
                 x=0.22, y=0.2, width=0.56, height=0.6, opacity=1,
                 on_focus_lost_hide=False, warp_pointer=False),
        DropDown("python", "urxvt -e python",
                 x=0.05, y=0.1, width=0.2, height=0.3, opacity=1,
                 on_focus_lost_hide=True, warp_pointer=False),
        DropDown("newsboat", "urxvt -e newsboat",
                 x=0.2, y=0.05, width=0.6, height=0.9, opacity=1,
                 on_focus_lost_hide=False, warp_pointer=False),
        ]),
])

keys.extend([
  Key([mod, 'shift'], 'Return', lazy.group['scratchpad'].dropdown_toggle('tmux')),
  Key([mod, 'control'], 'e', lazy.group['scratchpad'].dropdown_toggle('email')),
  Key([mod, 'control'], 'w', lazy.group['scratchpad'].dropdown_toggle('irc')),
  Key([mod, 'control'], 'm', lazy.group['scratchpad'].dropdown_toggle('ncmpcpp')),
  Key([mod], 'c', lazy.group['scratchpad'].dropdown_toggle('python')),
  Key([mod, 'control'], 'n', lazy.group['scratchpad'].dropdown_toggle('newsboat')),
])


## Qtools plugins
timeout = 800
import qtools.mpc as mpc
mpc_local = mpc.Client(timeout=timeout)

from qtools.rofi_searx import Searx
searx = Searx(
    instances_file=f'{HOME}/.config/searx_instances',
    theme=f'{HOME}/.config/rofi/common.rasi',
)

#from qtools.notification import Server
#x = wm_gapsouter * 2 + wm_gapsinner * 2
#y = wm_gapsouter * 4 + wm_gapsinner * 3 + 32
#notifier = Server(
#    x=x, y=y, width=192, height=64,
#    background=xcolors[0],
#    foreground=xcolors[15],
#    horizontal_padding=32,
#    vertical_padding=14,
#    border_width=4,
#    border=xcolors[4],
#    format='<b>{summary}</b>\n{body}',
#    font='monospace',
#    font_size=14,
#    line_spacing=4,
#    max_windows=3,
#    gap=wm_bw,
#)

keys.extend([EzKey(k, v) for k, v in {
    '<Pause>':              mpc_local.lazy_toggle,
    '<XF86AudioPlay>':      mpc_local.lazy_toggle,
    'M-<bracketright>':     mpc_local.lazy_next,
    '<XF86AudioNext>':      mpc_local.lazy_next,
    'M-<bracketleft>':      mpc_local.lazy_previous,
    '<XF86AudioPrev>':      mpc_local.lazy_previous,
    'S-<XF86AudioPlay>':    mpc_local.lazy_stop,
    'S-<Pause>':            mpc_local.lazy_stop,

    'M-s':      searx.lazy_search,
    'M-C-s':    searx.lazy_remove_last_used,

    #'M-<grave>':    notifier.lazy_prev,
    #'M-S-<grave>':  notifier.lazy_next,
    #'C-<space>':    notifier.lazy_close,
    #'M-S-p':        notifier.lazy_pause,
}.items()])


## bkmkfi
#from bkmkfi import Bkmkfi
#bkmks = Bkmkfi(theme='~/.config/rofi/common-large.rasi')

def bkmk_open(qtile):
    bkmks.open("tor-browser --allow-remote %s")

def bkmk_type(qtile):
    bkmks.type()

def bkmk_delete(qtile):
    bkmks.delete()

#keys.extend([
#    Key([mod], 'b', lazy.function(bkmk_open)),
#    Key([mod, 'shift'], 'b', lazy.function(bkmk_type)),
#    Key([mod, 'control'], 'b', lazy.function(bkmk_delete)),
#])


#@hook.subscribe.startup
#def start_notifier():
#    notifier.configure()


@hook.subscribe.startup
def _initial_groups():
    if len(qtile.screens) > 1:
        qtile.groups_map['1'].cmd_toscreen(0, toggle=False)
        qtile.groups_map['q'].cmd_toscreen(1, toggle=False)
        groupboxes[0].visible_groups = ['1', '2', '3']
    else:
        groupboxes[0].visible_groups = ['1', '2', '3', 'q', 'w', 'e']

    try:
        qtile.core._root.set_cursor("left_ptr")
    except Exception as e:
        logger.exception(e)


@hook.subscribe.client_new
def _floating_size_hints(window):
    hints = window.window.get_wm_normal_hints()
    if hints and 0 < hints['max_width'] < 1000:
        window.floating = True


@hook.subscribe.screen_change
def _reconfigure_groupboxes(event):
    if len(qtile.screens) > 1:
        groupboxes[0].visible_groups = ['1', '2', '3']
        qtile.groups_map['1'].cmd_toscreen(0, toggle=False)
        qtile.groups_map['q'].cmd_toscreen(1, toggle=False)
    else:
        groupboxes[0].visible_groups = ['1', '2', '3', 'q', 'w', 'e']
    groupboxes[0].bar.draw()


## General settings
follow_mouse_focus = True
bring_front_click = True
cursor_warp = False
auto_fullscreen = True
focus_on_window_activation = 'smart'
reconfigure_screens = True
wmname = 'LG3D'

However I haven’t touched my config in a month or two, so I don’t think anything I’m doing is causing it.

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Comments: 22 (21 by maintainers)

Commits related to this issue

Most upvoted comments

Oh, lol, brainfart, of course, will check that too. Running Qtile now with an interactive ipython --pdb qtile start run.