Repository: qtile/qtile

Issue:
Qt apps regression: window area is not repainted on group switch
# Issue description

When there is a Qt application open (qBittorrent, KeePassXC, etc) and group is switched to the other one and back, the whole area of Qt application is painted with whatever was visible on the previous group.

This is a regression in Qtile 0.17.0 that I just upgraded to from 0.16.1 to the best of my knowledge. It happened in the past if Qt apps were starting minimized, but now it happens on group switch as well and is very annoying.

Screencast demonstrating the issue: https://nextcloud.mokrynskyi.com/s/DEHnMyDZpiyjTWP

# Qtile version

0.17.0 as installed from pip.

# Stack traces

Only this, but it prints during startup and doesn't happen afterwards:
```
2021-05-22 10:04:47,416 ERROR libqtile core.py:_xpoll():L305 Got an exception in poll loop
Traceback (most recent call last):
  File "/home/nazar-pc/.local/lib/python3.8/site-packages/libqtile/backend/x11/core.py", line 258, in _xpoll
    event = self.conn.conn.poll_for_event()
  File "/home/nazar-pc/.local/lib/python3.8/site-packages/xcffib/__init__.py", line 571, in wrapper
    return f(*args)
  File "/home/nazar-pc/.local/lib/python3.8/site-packages/xcffib/__init__.py", line 612, in poll_for_event
    return self.hoist_event(e)
  File "/home/nazar-pc/.local/lib/python3.8/site-packages/xcffib/__init__.py", line 685, in hoist_event
    return self._process_error(ffi.cast("xcb_generic_error_t *", e))
  File "/home/nazar-pc/.local/lib/python3.8/site-packages/xcffib/__init__.py", line 648, in _process_error
    raise error(buf)
xcffib.xproto.ValueError
```

# Configuration

<details>

```python
from libqtile.command import lazy
from libqtile.config import EzDrag, EzKey, EzClick, Screen, Group, Match
from libqtile.layout import Floating, Max, Matrix, Tile
from libqtile import hook
#from plasma import Plasma
from xcffib.xproto import StackMode
import subprocess
import os

@hook.subscribe.startup_once
def dbus_register ():
	id = os.environ.get('DESKTOP_AUTOSTART_ID')
	if not id:
		return
	subprocess.Popen([
		'dbus-send',
		'--session',
		'--print-reply',
		'--dest=org.gnome.SessionManager',
		'/org/gnome/SessionManager',
		'org.gnome.SessionManager.RegisterClient',
		'string:qtile',
		'string:' + id
	])

tint2_instance = None

@hook.subscribe.client_managed
def register_and_bring_to_front_tint2_instance (window):
	global tint2_instance
	if window.name == 'tint2':
		tint2_instance = window
	elif tint2_instance is not None:
		tint2_instance.window.configure(stackmode=StackMode.Above)

@hook.subscribe.client_killed
def unregister_tint2_instance (window):
	global tint2_instance
	if window.name == 'tint2':
		tint2_instance = None

mod = 'mod4'

keymap = {
	'M-<Left>'        : lazy.layout.left(),
	'M-<Down>'        : lazy.layout.down(),
	'M-<Up>'          : lazy.layout.up(),
	'M-<Right>'       : lazy.layout.right(),
	'M-S-<Left>'      : [lazy.layout.move_left(), lazy.layout.shuffle_up(), lazy.layout.swap_column_left()],
	'M-S-<Down>'      : [lazy.layout.move_down(), lazy.layout.shuffle_down(), lazy.layout.swap_column_right()],
	'M-S-<Up>'        : [lazy.layout.move_up(), lazy.layout.shuffle_up(), lazy.layout.swap_column_left()],
	'M-S-<Right>'     : [lazy.layout.move_right(), lazy.layout.shuffle_down(), lazy.layout.swap_column_right()],
	'M-C-<Left>'      : lazy.layout.integrate_left(),
	'M-C-<Down>'      : lazy.layout.integrate_down(),
	'M-C-<Up>'        : lazy.layout.integrate_up(),
	'M-C-<Right>'     : lazy.layout.integrate_right(),
	'A-S-<Tab>'       : lazy.layout.previous(),
	'A-<Tab>'         : lazy.layout.next(),
	'M-h'             : lazy.layout.mode_horizontal(),
	'M-v'             : lazy.layout.mode_vertical(),
	'M-S-h'           : lazy.layout.mode_horizontal_split(),
	'M-S-v'           : lazy.layout.mode_vertical_split(),
	'M-<End>'         : [lazy.layout.increase_ratio(), lazy.layout.grow_width(30)],
	'M-<Home>'        : [lazy.layout.decrease_ratio(), lazy.layout.grow_width(-30)],
	'M-<equal>'       : lazy.layout.increase_nmaster(),
	'M-<minus>'       : lazy.layout.decrease_nmaster(),
	'M-<KP_Add>'      : lazy.layout.increase_nmaster(),
	'M-<KP_Subtract>' : lazy.layout.decrease_nmaster(),
	'M-<Page_Up>'     : lazy.layout.grow_height(30),
	'M-<Page_Down>'   : lazy.layout.grow_height(-30),
	'M-<Tab>'         : lazy.next_layout(),
	'C-A-<Up>'        : lazy.screen.prev_group(),
	'C-A-<Down>'      : lazy.screen.next_group(),
	'M-r'             : lazy.layout.reset_size(),
	'M-w'             : lazy.window.kill(),
	'C-A-t'           : lazy.spawn('terminator'),
	'C-A-c'           : lazy.spawn('gnome-calculator'),
	'C-A-s'           : lazy.spawn('env XDG_CURRENT_DESKTOP=GNOME gnome-system-monitor'),
	'M-f'             : lazy.spawn('spacefm'),
	'M-s'             : lazy.spawn('synapse'),
	'<XF86Tools>'     : lazy.spawn('clementine'),
	'<Print>'         : lazy.spawn('gnome-screenshot'),
	'A-<Print>'       : lazy.spawn('gnome-screenshot --window'),
	'S-<Print>'       : lazy.spawn('gnome-screenshot --area'),
	'M-l'             : [lazy.group['0'].toscreen(), lazy.spawn('i3lock -c 000000')],
	'M-C-r'           : lazy.restart(),
}

mouse = [
	EzDrag('M-1', lazy.window.set_position_floating(), start = lazy.window.get_position()),
	EzDrag('M-3', lazy.window.set_size_floating(), start = lazy.window.get_size()),
	EzClick('M-2', lazy.window.bring_to_front()),
	EzClick('9', lazy.screen.prev_group()),
	EzClick('8', lazy.screen.next_group()),
]

borders = {
	'border_width': 1,
	'border_normal': '#000000',
	'border_focus': '#318d00'
}

layouts = [
	Max(name = 'Max'),
	Matrix(columns = 3, name = 'Matrix', **borders),
#	Plasma(name = 'Plasma', **borders),
	Tile(
		name = 'Tile',
		expand = False,
		add_after_last = True,
		shift_windows = True,
		ratio = 0.5,
		**borders
	),
	Tile(
		name = 'Tile1',
		expand = False,
		add_after_last = True,
		shift_windows = True,
		ratio = 0.5,
		master_match = Match(wm_class = 'Thunderbird'),
		**borders
	),
	Tile(
		name = 'Tile2',
		expand = False,
		add_after_last = True,
		shift_windows = True,
		ratio = 0.5,
		master_match = Match(wm_class = 'Nightly'),
		**borders
	),
]

floating_layout = Floating(
#	no_reposition_match = Match(wm_class = 'Synapse'),
	**borders
)

groups = [
	Group('1', layout = 'Tile1', matches = [Match(wm_class = 'Thunderbird')]),
	Group('2', layout = 'Tile2', matches = [Match(wm_class = 'Nightly'), Match(wm_class = 'qBittorrent'), Match(wm_class = 'KeePassXC')]),
	Group('3', layout = 'Tile', matches = [Match(wm_class = 'jetbrains-idea')]),
	Group('4', layout = 'Matrix', matches = [Match(wm_class = 'Clementine'), Match(wm_class = 'Pavucontrol'), Match(wm_class = 'Synaptic')]),
	Group('5', layout = 'Tile'),
	Group('6', layout = 'Tile'),
	Group('7', layout = 'Tile'),
	Group('8', layout = 'Tile'),
	Group('9', layout = 'Tile'),
	Group('0', layout = 'Tile'),
]

for i in groups:
	keymap['M-' + i.name] = [
		lazy.group[i.name].toscreen()
	]
	keymap['M-S-' + i.name] = [
		lazy.window.togroup(i.name),
		lazy.group[i.name].toscreen()
	]

keys = []
for k, v in keymap.items():
	if type(v) is list:
		keys.append(EzKey(k, *v))
	else:
		keys.append(EzKey(k, v))

screens = [Screen()]

follow_mouse_focus = True
bring_front_click = False
cursor_warp = False
auto_fullscreen = True
focus_on_window_activation = 'smart'

wmname = 'LG3D'
```

</details>


Discussion:

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
@@ -708,7 +708,6 @@ def hide(self):
         # We don't want to get the UnmapNotify for this unmap
         with self.disable_mask(EventMask.StructureNotify):
             self.window.unmap()
-        self.state = IconicState
         self.hidden = True
 
     def unhide(self):
@@ -1314,6 +1313,7 @@ def getposition(self):
 
     def _reconfigure_floating(self, new_float_state=FloatStates.FLOATING):
         if new_float_state == FloatStates.MINIMIZED:
+            self.state = IconicState
             self.hide()
         else:
             width = self.width


Test patch: