Repository: qtile/qtile

Issue:
Qtile causes problems with apps that use EWMH.
I changed xmonad to qtile recently.
I use windows in QEMU and use looking-glass for display it.
Looking-glass can send host keyboard and mouse action to guest VM through spice and did not show cursor.
I could do it using xmonad but could not do it using qtile.
I installed xmonad again and changed it, I could send these action to guest VM and showed cursor.
However, qtile never do it.
Qtile don't have error.
I don't change startup process between qtile and xmonad. (I wrote startup process in .xprofile, .xinitrc and .Xresources.)
Do you have any solutions?

I show my config.

<details>
<summary>my config</summary>

```
from typing import List  # noqa: F401
from pathlib import Path
import subprocess
import asyncio
import time

from libqtile import bar, layout, widget, hook
from libqtile.config import Click, Drag, Group, Key, Match, Screen
from libqtile.lazy import lazy
from libqtile.utils import guess_terminal
from libqtile.log_utils import logger
from libqtile.core.manager import Qtile
from libqtile import qtile

colors = {
        'BGbase': '#222d32', 'FGbase': '#475359',
        'black': '#01060e', 'red': 'ff5252',
        'green': '#4db69f', 'yellow': '#c9bc0e',
        'blue': '#008fc2', 'magenta': '#cf00ac',
        'cyan': '#02adc7', 'white': '#cfd8dc',
        'clear': '#00000000'
        }
colors2 = {
        'bblack': "#475359", 'bred': "#ff4f4d",
        'bgreen': "#56d6ba", 'byellow': "#c9c30e",
        'bblue': "#c9c30e", 'bmagenta': "#9c0082",
        'bcyan': "#02b7c7", 'bwhite': "#a7b0b5"
        }
screan_size = [2560-5, 1440]
pinp_size = [800, 450]
pinp_pos = [s-p for s, p in zip(screan_size, pinp_size)]

mod = 'mod4' # super key
terminal = 'kitty'
browser = 'vivaldi-stable'
home = Path.home()
capture_path = home.joinpath('Pictures', 'screenshot')
wallpapers = list(home.joinpath('Pictures', 'wallpapers').glob('*.jpg'))
wallpapers.sort()


num_screen = 2
laptop = False

pinp_window = None


monitor1=0
monitor2=0

@hook.subscribe.setgroup
def change_wallpaper():
    global monitor1
    global monitor2
    group = qtile.current_screen.group
    gidx = qtile.groups.index(group)
    if qtile.current_screen in qtile.screens:
        idx = qtile.screens.index(qtile.current_screen)
        n_groups = len(qtile.groups) // len(qtile.screens)
        if gidx >= n_groups:
            gidx -= n_groups
        if idx == 0:
            monitor1 = gidx
        else:
            monitor2 = gidx
        subprocess.run('feh --bg-fill {} --bg-fill {}'.format(str(wallpapers[monitor1]), str(wallpapers[monitor2])), shell=True)
        

@hook.subscribe.startup_once
def autostart():
    subprocess.run('feh --bg-fill {} --bg-fill {}'.format(str(wallpapers[0]), str(wallpapers[0])), shell=True)
    subprocess.run('blueman-applet', shell=True)


@hook.subscribe.client_new
async def move_spotify(window):
    await asyncio.sleep(0.005)
    if window.name == 'Spotify':
        window.togroup('0-media')
    elif window.name == 'ピクチャー イン ピクチャー':
        _pinp_pos = pinp_pos.copy()
        global pinp_window
        pinp_window = window
        idx = qtile.screens.index(qtile.current_screen)
        if idx == 1:
            _pinp_pos[0] += screan_size[0]
        window.cmd_place(*_pinp_pos, *pinp_size, borderwidth=2,
                         bordercolor=colors['cyan'], above=False, margin=None)
    else:
        pass


@hook.subscribe.client_killed
def remove_pinp(window):
    if window.name == 'ピクチャー イン ピクチャー':
        global pinp_window
        pinp_window = None


@hook.subscribe.focus_change
def float_always_show_front_focus_change():
    for window in qtile.current_group.windows:
        if window.floating:
            window.cmd_bring_to_front()


floating_window_index = 0
def float_cycle(qtile, forward: bool):
    global floating_window_index
    floating_windows = []
    for window in qtile.current_group.windows:
        if window.floating:
            floating_windows.append(window)
    if not floating_windows:
        return
    floating_window_index = min(floating_window_index, len(floating_windows) -1)
    if forward:
        floating_window_index += 1
    else:
        floating_window_index += 1
    if floating_window_index >= len(floating_windows):
        floating_window_index = 0
    if floating_window_index < 0:
        floating_window_index = len(floating_windows) - 1
    win = floating_windows[floating_window_index]
    win.cmd_bring_to_front()
    win.cmd_focus()


@lazy.function
def float_cycle_backward(qtile):
    float_cycle(qtile, False)


@lazy.function
def float_cycle_forward(qtile):
    float_cycle(qtile, True)


@lazy.function
def keep_pinp(qtile):
    if pinp_window is not None:
        n_screen = len(qtile.screens)
        now_pinp_screen = qtile.groups.index(pinp_window.group) // (len(qtile.groups) // n_screen)
        idx = qtile.screens.index(qtile.current_screen)
        if now_pinp_screen == idx:
            pinp_window.togroup(qtile.current_screen.group.name)
            for window in qtile.current_group.windows:
                if not window.floating:
                    break
            window.cmd_focus(warp=True)


def check_screen(idx, min_idx, max_idx):
    return min_idx <= idx < max_idx

def calc_range_idx(current_screen_idx, num_group):
    n_screen = len(qtile.screens)
    group_per_s = num_group // n_screen
    min_idx = group_per_s * current_screen_idx
    max_idx = group_per_s*(current_screen_idx + 1)
    return min_idx, max_idx

@lazy.function
def focus_previous_group(qtile):
    group = qtile.current_screen.group
    group_index = qtile.groups.index(group)

    previous_group = group.get_previous_group(skip_empty=True)
    previous_group_index = qtile.groups.index(previous_group)

    idx = qtile.screens.index(qtile.current_screen)
    min_idx, max_idx = calc_range_idx(idx, len(qtile.groups))
    check = check_screen(previous_group_index, min_idx, max_idx)

    if previous_group_index < group_index and check:
        qtile.current_screen.set_group(previous_group)


@lazy.function
def focus_next_group(qtile):
    group = qtile.current_screen.group
    group_index = qtile.groups.index(group)

    next_group = group.get_next_group(skip_empty=True)
    next_group_index = qtile.groups.index(next_group)

    idx = qtile.screens.index(qtile.current_screen)
    min_idx, max_idx = calc_range_idx(idx, len(qtile.groups))
    check = check_screen(next_group_index, min_idx, max_idx)

    if next_group_index > group_index and check:
        qtile.current_screen.set_group(next_group)
        

@lazy.function
def window_to_previous_group(qtile):
    group = qtile.current_screen.group
    group_index = qtile.groups.index(group)

    previous_group = group.get_previous_group(skip_empty=False)
    previous_group_index = qtile.groups.index(previous_group)

    idx = qtile.screens.index(qtile.current_screen)
    min_idx, max_idx = calc_range_idx(idx, len(qtile.groups))
    check = check_screen(previous_group_index, min_idx, max_idx)

    if previous_group_index < group_index and check:
        qtile.current_window.togroup(previous_group.name, switch_group=True)


@lazy.function
def window_to_next_group(qtile):
    group = qtile.current_screen.group
    group_index = qtile.groups.index(group)

    next_group = group.get_next_group(skip_empty=False)
    next_group_index = qtile.groups.index(next_group)

    idx = qtile.screens.index(qtile.current_screen)
    min_idx, max_idx = calc_range_idx(idx, len(qtile.groups))
    check = check_screen(next_group_index, min_idx, max_idx)
    if next_group_index > group_index and check:
        qtile.current_window.togroup(next_group.name, switch_group=True)


@lazy.function
def focus_n_screen_group(qtile, idx, g_per_s):
    groups = qtile.groups
    s_idx = qtile.screens.index(qtile.current_screen)
    if idx < g_per_s:
        qtile.current_screen.set_group(groups[int(idx + g_per_s*s_idx)])


@lazy.function
def move_n_screen_group(qtile, idx, g_per_s):
    groups = qtile.groups
    s_idx = qtile.screens.index(qtile.current_screen)
    if idx < g_per_s:
        qtile.current_window.togroup(groups[int(idx + g_per_s*s_idx)].name, switch_group=True)


@lazy.function
def focus_prev_screen(qtile,):
    n_screen = len(qtile.screens)
    idx = qtile.screens.index(qtile.current_screen)
    prev_idx = idx - 1
    if prev_idx >= 0:
        qtile.cmd_to_screen(prev_idx)


@lazy.function
def focus_next_screen(qtile,):
    n_screen = len(qtile.screens)
    idx = qtile.screens.index(qtile.current_screen)
    next_idx = idx + 1
    if next_idx < n_screen:
        qtile.cmd_to_screen(next_idx)


@lazy.function
def focus_cycle_screen(qtile, backward=False):
    n_screen = len(qtile.screens)
    idx = qtile.screens.index(qtile.current_screen)
    if backward:
        to_idx = n_screen - 1 if idx == 0 else idx - 1
        qtile.cmd_to_screen(to_idx)
    else:
        to_idx = 0 if idx + 1 == n_screen else idx + 1
        qtile.cmd_to_screen(to_idx)


@lazy.function
def move_cycle_screen(qtile, backward=False):
    n_screen = len(qtile.screens)
    idx = qtile.screens.index(qtile.current_screen)
    if backward:
        to_idx = n_screen - 1 if idx == 0 else idx - 1
        group = qtile.screens[to_idx].group.name
        qtile.current_window.togroup(group)
    else:
        to_idx = 0 if idx + 1 == n_screen else idx + 1
        group = qtile.screens[to_idx].group.name
        qtile.current_window.togroup(group)


@lazy.function
def window_to_previous_screen(qtile):
    i = qtile.screens.index(qtile.current_screen)
    if i != 0:
        group = qtile.screens[i - 1].group.name
        qtile.current_window.togroup(group)


@lazy.function
def window_to_next_screen(qtile):
    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)


keys = [
    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, 'shift'], 'h',
        lazy.layout.shuffle_left(),
        lazy.layout.move_left(),
        desc='Move window to the left'),
    Key([mod, 'shift'], 'l',
        lazy.layout.shuffle_right(),
        lazy.layout.move_right(),
        desc='Move window to the right'),
    Key([mod, 'shift'], 'j', 
        lazy.layout.shuffle_down(),
        lazy.layout.section_down(),
        desc='Move window down'),
    Key([mod, 'shift'], 'k',
        lazy.layout.shuffle_up(),
        lazy.layout.section_up(),
        desc='Move window up'),
    Key([mod, 'control'], 'h',
        focus_previous_group(),
        keep_pinp(),
        desc='focus prev group'),
    Key([mod, 'control'], 'l',
        focus_next_group(),
        keep_pinp(),
        desc='focus next group'),

    Key([mod, 'shift', 'control'], 'h', 
        window_to_previous_group(), keep_pinp(), desc='win to prev group'),
    Key([mod, 'shift', 'control'], 'l',
        window_to_next_group(), keep_pinp(), desc='win to next group'),

    Key([mod], 'n', focus_cycle_screen(),  desc='focus next screen'),
    Key([mod], 'm', focus_cycle_screen(backward=True),  desc='focus next screen'),
    Key([mod, 'shift'], 'n', move_cycle_screen(), keep_pinp()),
    Key([mod, 'shift'], 'm', move_cycle_screen(backward=True), keep_pinp()),

    Key([mod], 'space', lazy.window.toggle_maximize()),
    Key([mod, 'shift'], 'space', lazy.window.toggle_minimize()),

    Key([mod], 'f', lazy.window.toggle_fullscreen()),
    Key([mod, 'shift'], 'f', lazy.window.toggle_floating()),

    Key([mod], 'Tab', lazy.next_layout(),
        desc='Move window focus to other window'),


    Key([mod], 's', lazy.layout.toggle_split(), desc='Launch terminal'),
    Key([mod, 'shift'], 'Return', lazy.spawn(terminal), desc='Launch terminal'),

    Key([mod, 'shift'], 'c', lazy.window.kill(), desc='Kill focused window'),

    Key([mod, 'control'], 'r', lazy.reload_config(), desc='Reload the config'),
    Key([mod, 'control'], 'e', lazy.shutdown(), desc='Shutdown Qtile'),

    Key([mod], 'p', lazy.spawn('rofi -modi combi -show combi -combi-modi window,drun -show-icons'), desc='show rofi'),
    Key([mod, 'shift'], 'p', lazy.spawn('rofi -show run'), desc='run rofi script mode'),
    Key([mod, 'control'], 'p', lazy.spawn('rofi -show power-menu -modi power-menu:rofi-power-menu -show-icons'), desc='run rofi script mode'),

    Key([], 'Print', lazy.spawn('flameshot full -p {}'.format(str(capture_path)))),
    Key([mod], 'Print', lazy.spawn('flameshot screen -p {}'.format(str(capture_path)))),
    Key([mod, 'shift'], 'Print', lazy.spawn('flameshot screen -c')),
    Key([mod], "period", float_cycle_forward()),
    Key([mod], "comma", float_cycle_backward()),

    Key([mod], 'q', lazy.spawn('copyq show')),
    Key([mod], 'b', lazy.spawn(browser)),

    Key([], 'XF86AudioRaiseVolume', lazy.spawn('pactl set-sink-volume @DEFAULT_SINK@ +5%')),
    Key([], 'XF86AudioLowerVolume', lazy.spawn('pactl set-sink-volume @DEFAULT_SINK@ -5%')),
    Key([], 'XF86AudioMute', lazy.spawn('pactl set-sink-mute @DEFAULT_SINK@ toggle')),
    Key([], 'XF86AudioMicMute', lazy.spawn('pactl set-source-mute @DEFAULT_SINK@ toggle')),
    Key([], 'XF86AudioPause', lazy.spawn('playerctl play-pause')),
    Key([], 'XF86AudioPlay', lazy.spawn('playerctl play-pause')),
    Key([], 'XF86AudioNext', lazy.spawn('playerctl next')),
    Key([], 'XF86AudioPrev', lazy.spawn('playerctl previous')),
    Key([], 'XF86MonBrightnessUp', lazy.spawn('light -A 5')),
    Key([], 'XF86MonBrightnessDown', lazy.spawn('light -U 5')),
    Key([], 'XF86KbdBrightnessUp', lazy.spawn('light -Ars {} 1'.format('sysfs/leds/asus::kbd_backlight'))),
    Key([], 'XF86KbdBrightnessDown', lazy.spawn('light -Urs {} 1'.format('sysfs/leds/asus::kbd_backlight'))),
    Key([], 'XF86Launch4', lazy.spawn('asusctl profile -n'))

]

default_settings = {'border_width': 2,
                  'border_focus': colors['blue'],
                  'border_normal': colors['BGbase']}
margin = 14
layouts = [
    layout.Columns(**default_settings,
                   border_focus_stack=colors['cyan'],
                   border_normal_stack=colors['BGbase'],
                   border_on_single=True, fair=False,
                   num_columns=2, insert_position=1,
                   margin=margin, margin_on_single=margin,
                   split=False),
    layout.TreeTab(active_bg=colors2['bblack'],
                   bg_color=colors['BGbase'],
                   font='Noto Sans CJK JP',
                   sections=['WS{}'.format(i) for i in range(1, 4)],
                   level_shift=20,
                   fontsize=14,
                   section_fontsize=16,
                   ),
]
layouts2 = [
    layout.MonadWide(**default_settings,
                     ratio=0.6,
                     new_client_position='bottom',
                     single_border_width=2,
                     margin=margin, single_margin=margin
                     ),
        ]
layouts3 = [
    layout.TreeTab(active_bg=colors2['bblack'],
                   bg_color=colors['BGbase'],
                   font='Noto Sans CJK JP',
                   sections=['WS{}'.format(i) for i in range(1, 6)],
                   level_shift=20,
                   fontsize=14,
                   section_fontsize=16,
                   ),
    ]
layouts4 = [
    layout.Slice(match=Match(wm_class='pavucontrol'), width=350, side='bottom',
                 fallback=layouts[0]),
    ]

match_code = [Match(wm_class='code')]
match_browse = [Match(wm_class='vivaldi-stable'), Match(wm_class='firefox'),
                Match(wm_class='virt-manager')]
match_paper = [Match(wm_class='zathura')]
match_analyze = [Match(title='WaveSurfer 1.8.8p5'), Match(wm_class='thunar'),
                 Match(wm_class='mpv')]
match_full = [Match(wm_class='Steam'), Match(wm_class='krita'),
              Match(wm_class='Gimp'), Match(wm_class='Blender'),
              Match(wm_class='unityhub'), Match(wm_class='Unity'),
              Match(wm_class='obs'), Match(wm_class='audacity'),
              Match(wm_class='looking-glass')]
match_sns = [Match(wm_class='slack'), Match(wm_class='discord')]
match_media = [Match(wm_class='pavucontrol')]

groups = list()
_groups = {'code': ('', layouts2, match_code),
           'browse': ('', layouts, match_browse),
           'paper': ('', layouts, match_paper),
           'analyze': ('', layouts, match_analyze),
           'full': ('', layouts3, match_full),
           'sns': ('', layouts, match_sns),
           'media': ('', layouts4, match_media)}

if laptop:
    for k, (label, layouts, matches) in _groups.items():
        groups.append(Group('{}-{}'.format(0, k), layouts=layouts, matches=matches, label=label))
else:
    for n in range(num_screen):
        for k, (label, layouts, matches) in _groups.items():
            groups.append(Group('{}-{}'.format(n, k), layouts=layouts, matches=matches, label=label))

for n, i in enumerate(groups, 1):
    keys.extend([
        Key([mod], str(n), focus_n_screen_group(n-1, len(_groups)), keep_pinp,
            desc='Switch to group {}'.format(i.name)),

        Key([mod, 'shift'], str(n), move_n_screen_group(n-1, len(_groups)), keep_pinp,
            desc='Switch to & move focused window to group {}'.format(i.name)),
    ])
    if n == len(_groups):
        break


@hook.subscribe.screen_change
def attach_screen(notify):
    out = subprocess.check_output('xrandr --listmonitors', shell=True)
    n_monitor = int(out.decode('utf-8').split('\n')[0].split(' ')[-1])
    time.sleep(0.1)
    subprocess.run('xrandr --output eDP --auto --output HDMI-A-0 --auto --right-of eDP', shell=True)
    for k, (label, layouts, matches) in _groups.items():
        qtile.add_group('{}-{}'.format(1, k), layouts=layouts, label=label)


widget_defaults = dict(
    font='Noto Sans CJK JP',
    fontsize=18,
    padding=3,
)
extension_defaults = widget_defaults.copy()
colorset1 = {'background': colors['BGbase'], 'foreground': colors['cyan']}
colorset2 = {'background': colors['cyan'], 'foreground': colors['BGbase']}
colorset3 = {'background': colors['blue'], 'foreground': colors['BGbase']}
colorset4 = {'background': colors['BGbase'], 'foreground': colors['blue']}
colorset5 = {'background': colors['clear'], 'foreground': colors['BGbase']}
colorset6 = {'background': colors['BGbase'], 'foreground': colors['white']}

def left_corner(background, foreground):
    return widget.TextBox(
        foreground = foreground,
        background = background,
        text = "\ue0b6",
        fontsize = 36,
        padding=0
    )

def right_corner(background, foreground):
    return widget.TextBox(
        foreground = foreground,
        background = background,
        text = "\ue0b4",
        fontsize = 36,
        padding=0
    )

def separator():
    return widget.Sep(
        linewidth = 0,
        padding = 10
    )

gaps = 15
screens = [
    Screen(
        top=bar.Bar(
            [
                left_corner(**colorset1),
                widget.CurrentScreen(active_color=colors['magenta'],
                                     inactive_color=colors['BGbase'],
                                     inactive_text='N', **colorset2),
                right_corner(**colorset1),
                separator(),
                left_corner(**colorset1),
                widget.CurrentLayout(fmt='{:.3}', **colorset2),
                right_corner(**colorset1),
                separator(),
                left_corner(**colorset4),
                widget.GroupBox(this_current_screen_border=colors['cyan'], borderwidth=2, **colorset3,
                                active=colors['white']),
                right_corner(**colorset4),
                separator(),
                left_corner(**colorset1),
                widget.CPU(format=' {load_percent}%', **colorset2),
                right_corner(**colorset1),
                widget.Memory(format=' {MemUsed: .1f}{mm}/{MemTotal: .1f}{mm}',
                              measure_mem='G', measure_swap='G', **colorset1),
                right_corner(**colorset2),
                widget.DF(format = " {f} GB ({r:.0f}%)", visible_on_warn=False,
                          partition='/home', **colorset2),
                right_corner(**colorset1),
                widget.Spacer(),
                left_corner(**colorset1),
                widget.Clock(format='%Y-%m-%d %a %I:%M:%S %p', **colorset2),
                right_corner(**colorset1),
                separator(),
                separator(),
                left_corner(**colorset4),
                widget.TaskList(border=colors['BGbase'], borderwidth=2, max_title_width=120, **colorset3),
                right_corner(**colorset4),
                separator(),
                left_corner(**colorset1),
                widget.Net(format='{down} ↓↑ {up}', **colorset2),
                right_corner(**colorset1),
                widget.PulseVolume(fmt=' {}', limit_max_volume=True, volume_app='pavucontrol',
                                   update_interval=0.1, **colorset1),
                right_corner(**colorset2),
                widget.CheckUpdates(display_format=' {updates}', distro='Arch_paru',
                                    colour_have_updates=colors['magenta'], colour_no_updates=colors['BGbase'],
                                    update_interval=60*60, no_update_string='  0', **colorset2),
                right_corner(**colorset1),
                separator(),
                left_corner(**colorset4),
                widget.Systray(**colorset3),
                right_corner(**colorset4),
                separator(),
                     
            ],
            32,
            background=colors['BGbase'],
            border_color=colors['cyan']
        ),
    ),
    Screen(
        top=bar.Bar(
            [
                left_corner(**colorset1),
                widget.CurrentScreen(active_color=colors['magenta'],
                                     inactive_color=colors['BGbase'], 
                                     inactive_text='N',**colorset2),
                right_corner(**colorset1),
                separator(),
                left_corner(**colorset1),
                widget.CurrentLayout(fmt='{:.3}', **colorset2),
                right_corner(**colorset1),
                separator(),
                left_corner(**colorset4),
                widget.GroupBox(this_current_screen_border=colors['cyan'], borderwidth=2, **colorset3,
                                active=colors['white']),
                right_corner(**colorset4),
                separator(),
                left_corner(**colorset1),
                widget.CPU(format=' {load_percent}%', **colorset2),
                right_corner(**colorset1),
                widget.Memory(format=' {MemUsed: .1f}{mm}/{MemTotal: .1f}{mm}',
                              measure_mem='G', measure_swap='G', **colorset1),
                right_corner(**colorset2),
                widget.DF(format = " {f} GB ({r:.0f}%)", visible_on_warn=False,
                          partition='/home', **colorset2),
                right_corner(**colorset1),
                widget.Spacer(),
                left_corner(**colorset1),
                widget.Clock(format='%Y-%m-%d %a %I:%M:%S %p', **colorset2),
                right_corner(**colorset1),
                separator(),
                separator(),
                left_corner(**colorset4),
                widget.TaskList(border=colors['BGbase'], borderwidth=2, max_title_width=120, **colorset3),
                right_corner(**colorset4),
                separator(),
                left_corner(**colorset1),
                widget.Net(format='{down} ↓↑ {up}', **colorset2),
                right_corner(**colorset1),
                widget.PulseVolume(fmt=' {}', limit_max_volume=True, volume_app='pavucontrol',
                                   update_interval=0.1, **colorset1),
                right_corner(**colorset2),
                widget.CheckUpdates(display_format=' {updates}', distro='Arch_paru',
                                    colour_have_updates=colors['magenta'], colour_no_updates=colors['BGbase'],
                                    update_interval=60*60, no_update_string='  0', **colorset2),
                right_corner(**colorset1),
                     
            ],
            32,
            background=colors['BGbase'],
            border_color=colors['cyan']
        ),
    ),
]

mouse = [
    Drag([mod], 'Button1', lazy.window.set_position_floating(),
         start=lazy.window.get_position()),
    Drag([mod, 'shift'], 'Button1', lazy.window.set_size_floating(),
         start=lazy.window.get_size()),
]

dgroups_key_binder = None
dgroups_app_rules = []  # type: List
follow_mouse_focus = False
bring_front_click = True
cursor_warp = False
floating_layout = layout.Floating(float_rules=[
    *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
], **default_settings)
auto_fullscreen = True
focus_on_window_activation = 'smart'
reconfigure_screens = True

auto_minimize = True

wmname = 'Qtile'
```
</details>



Discussion:
The developers of LookingGlass say that the problem occurs when they assume that EWMH is supported when it is not.
According to the discussion, qtile does not support ewmh, is there any way to explicitly turn this off?
Do you know which hints are required? We could possibly add them. We support some EWMH but generally only add support for hints when they are needed - but we are happy to if that is preferable, depending on what work is required.
According to maintainer of LG, this probrem maybe cause by failing to set _NET_WM_STATE_FOCUSED in _NET_WM_STATE or in _NET_WM_SUPPORTED.
I want to check it but I don't know how do I check it.
Sorry...
Great, that's helpful. Here are a couple notes for myself/someone, if anybody is interested in implementing this. If nobody is then I will get to it within a week or two.

i3's PR adding support: https://github.com/i3/i3/pull/3178
The spec where it is described: https://specifications.freedesktop.org/wm-spec/wm-spec-latest.html


Resolving patch:
diff --git a/libqtile/backend/x11/window.py b/libqtile/backend/x11/window.py
--- a/libqtile/backend/x11/window.py
+++ b/libqtile/backend/x11/window.py
@@ -999,15 +999,19 @@ def focus(self, warp: bool) -> None:
         if warp and self.qtile.config.cursor_warp:
             self.window.warp_pointer(self.width // 2, self.height // 2)
 
+        # update net wm state
+        state = list(self.window.get_property("_NET_WM_STATE", "ATOM", unpack=int))
+        state_focused = self.qtile.core.conn.atoms["_NET_WM_STATE_FOCUSED"]
+        state.append(state_focused)
+
         if self.urgent:
             self.urgent = False
-
             atom = self.qtile.core.conn.atoms["_NET_WM_STATE_DEMANDS_ATTENTION"]
-            state = list(self.window.get_property("_NET_WM_STATE", "ATOM", unpack=int))
 
             if atom in state:
                 state.remove(atom)
-                self.window.set_property("_NET_WM_STATE", state)
+
+        self.window.set_property("_NET_WM_STATE", state)
 
         # re-grab button events on the previously focussed window
         old = self.qtile.core._root.get_property("_NET_ACTIVE_WINDOW", "WINDOW", unpack=int)
@@ -1015,6 +1019,10 @@ def focus(self, warp: bool) -> None:
             old_win = self.qtile.windows_map[old[0]]
             if not isinstance(old_win, base.Internal):
                 old_win._grab_click()
+                state = list(old_win.window.get_property("_NET_WM_STATE", "ATOM", unpack=int))
+                if state_focused in state:
+                    state.remove(state_focused)
+                    old_win.window.set_property("_NET_WM_STATE", state)
         self.qtile.core._root.set_property("_NET_ACTIVE_WINDOW", self.window.wid)
         self._ungrab_click()
 


Test patch:
diff --git a/test/backend/x11/test_window.py b/test/backend/x11/test_window.py
--- a/test/backend/x11/test_window.py
+++ b/test/backend/x11/test_window.py
@@ -763,3 +763,26 @@ def assert_frame(wid, frame):
     xmanager.c.window.enable_floating()
     assert_frame(wid, (6, 6, 6, 6))
     xmanager.kill_window(pid)
+
+
+def test_net_wm_state_focused(xmanager):
+    conn = xcbq.Connection(xmanager.display)
+    atom = conn.atoms["_NET_WM_STATE_FOCUSED"]
+
+    def assert_state_focused(wid, has_state):
+        r = conn.conn.core.GetProperty(
+            False, wid, conn.atoms["_NET_WM_STATE"], conn.atoms["ATOM"], 0, (2**32) - 1
+        ).reply()
+        assert (atom in r.value.to_atoms()) == has_state
+
+    one = xmanager.test_window("one")
+    wid1 = xmanager.c.window.info()["id"]
+    assert_state_focused(wid1, True)
+
+    two = xmanager.test_window("two")
+    wid2 = xmanager.c.window.info()["id"]
+    assert_state_focused(wid1, False)
+    assert_state_focused(wid2, True)
+    xmanager.kill_window(two)
+    assert_state_focused(wid1, True)
+    xmanager.kill_window(one)