Repository: qtile/qtile

Issue:
Multiple borders not drawn on Firefox in X

# Issue description

Using the x11 backend, multiple borders fail to get drawn on Firefox windows, instead keeping whatever borders they had before or no borders.

# Qtile version

Current master add6e136ce5d7f046d560979bd58a7f3b085e4d2

# Stack traces

`MatchError`s get logged when the border drawing is attempted e.g. when moving focus to a FF window. This makes me suspect it's a mismatch between window and border depth/visual or one of those other X things (haven't looked deeper).

```
2021-09-08 23:02:21,385 ERROR libqtile core.py:_xpoll():L330 Got an exception in poll loop
Traceback (most recent call last):
  File "/home/mcol/git/qtile/libqtile/backend/x11/core.py", line 284, in _xpoll
    event = self.conn.conn.poll_for_event()
  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 612, in poll_for_event
    return self.hoist_event(e)
  File "/usr/lib/python3.9/site-packages/xcffib/__init__.py", line 686, in hoist_event
    return self._process_error(ffi.cast("xcb_generic_error_t *", e))
  File "/usr/lib/python3.9/site-packages/xcffib/__init__.py", line 649, in _process_error
    raise error(buf)
xcffib.xproto.MatchError
2021-09-08 23:02:21,402 ERROR libqtile core.py:_xpoll():L330 Got an exception in poll loop
Traceback (most recent call last):
  File "/home/mcol/git/qtile/libqtile/backend/x11/core.py", line 284, in _xpoll
    event = self.conn.conn.poll_for_event()
  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 612, in poll_for_event
    return self.hoist_event(e)
  File "/usr/lib/python3.9/site-packages/xcffib/__init__.py", line 686, in hoist_event
    return self._process_error(ffi.cast("xcb_generic_error_t *", e))
  File "/usr/lib/python3.9/site-packages/xcffib/__init__.py", line 649, in _process_error
    raise error(buf)
xcffib.xproto.MatchError
```

# Configuration

Default config, just open up firefox and either switch the `Column`s column to stack mode, or just rename the default `border_focus_stack` option to `border_focus`.



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
@@ -89,6 +89,7 @@ def get_attr(self):
             self.y = g.y
             self.width = g.width
             self.height = g.height
+            self.depth = g.depth
         return getattr(self, "_" + attr)
     return get_attr
 
@@ -427,7 +428,7 @@ def query_tree(self):
             parent = XWindow(self.conn, q.parent)
         return root, parent, [XWindow(self.conn, i) for i in q.children]
 
-    def paint_borders(self, colors, borderwidth, width, height):
+    def paint_borders(self, depth, colors, borderwidth, width, height):
         """
         This method is used only by the managing Window class.
         """
@@ -447,7 +448,7 @@ def paint_borders(self, colors, borderwidth, width, height):
         with PixmapID(self.conn.conn) as pixmap:
             with GContextID(self.conn.conn) as gc:
                 core.CreatePixmap(
-                    self.conn.default_screen.root_depth, pixmap, self.wid, outer_w, outer_h
+                    depth, pixmap, self.wid, outer_w, outer_h
                 )
                 core.CreateGC(gc, pixmap, 0, None)
                 borders = len(colors)
@@ -464,15 +465,15 @@ def paint_borders(self, colors, borderwidth, width, height):
                     )
                     core.PolyFillRectangle(pixmap, gc, 1, [rect])
                     coord += borderwidths[i]
-                self._set_borderpixmap(pixmap, gc, borderwidth, width, height)
+                self._set_borderpixmap(depth, pixmap, gc, borderwidth, width, height)
 
-    def _set_borderpixmap(self, pixmap, gc, borderwidth, width, height):
+    def _set_borderpixmap(self, depth, pixmap, gc, borderwidth, width, height):
         core = self.conn.conn.core
         outer_w = width + borderwidth * 2
         outer_h = height + borderwidth * 2
         with PixmapID(self.conn.conn) as border:
             core.CreatePixmap(
-                self.conn.default_screen.root_depth, border, self.wid, outer_w, outer_h
+                depth, border, self.wid, outer_w, outer_h
             )
             most_w = outer_w - borderwidth
             most_h = outer_h - borderwidth
@@ -500,6 +501,7 @@ def __init__(self, window, qtile):
             self._y = g.y
             self._width = g.width
             self._height = g.height
+            self._depth = g.depth
         except xcffib.xproto.DrawableError:
             # Whoops, we were too early, so let's ignore it for now and get the
             # values on demand.
@@ -507,6 +509,7 @@ def __init__(self, window, qtile):
             self._y = None
             self._width = None
             self._height = None
+            self._depth = None
 
         self.float_x: Optional[int] = None
         self.float_y: Optional[int] = None
@@ -545,6 +548,10 @@ def __init__(self, window, qtile):
         fset=_geometry_setter("height"),
         fget=_geometry_getter("height"),
     )
+    depth = property(
+        fset=_geometry_setter("depth"),
+        fget=_geometry_getter("depth"),
+    )
 
     @property
     def wid(self):
@@ -869,7 +876,7 @@ def paint_borders(self, color, width):
         self.borderwidth = width
         self.bordercolor = color
         self.window.configure(borderwidth=width)
-        self.window.paint_borders(color, width, self.width, self.height)
+        self.window.paint_borders(self.depth, color, width, self.width, self.height)
 
     def send_configure_notify(self, x, y, width, height):
         """Send a synthetic ConfigureNotify"""


Test patch: