Repository: qtile/qtile

Issue:
Wallpaper not resizing when display scaled
Hello, first of all thank you for the amazing job you are doing. Qtile is amazing!

I have an issue I am not able to solve. Not sure if it is a bug in qtile or just an issue related to my config. 

From time to time, I connect a secondary monitor to my laptop. I want to set a refresh rate for this monitor of 120 and scale it by 10%. When I am on Gnome, I do not have any issues. When on Qtile, I cannot seem to make it work. I have tried the following:

1) make qtile run an autostart file with an xrandr command in it:
 
```
@hook.subscribe.startup
def autostart():
    home = os.path.expanduser('~/.config/qtile/autostart.sh')
    subprocess.run([home])
```
```
#!/usr/bin/sh
sh /home/eugenio/.local/bin/auto-screen-rotate.sh eDP-1 "Wacom HID 4956 Finger touch" &
picom &
xrandr --output eDP-1 --primary --output DP-1 --scale 1.1x1.1 --right-of eDP-1 --mode 1920x1280 --rate 120 &
sleep 1 &&
feh --no-fehbg --bg-scale /home/eugenio/Sync/Sfondi/wallhaven-vg6dqp.jpg --bg-scale /home/eugenio/Sync/Sfondi/1245752.jpg &
sleep 10 && xinput map-to-output 'Wacom HID 4956 Finger touch' eDP-1 &

```
While the other commands are working correctly, the xrandr command is ineffective.

2) start qtile from an xsession:
```
#!/usr/bin/bash

xsetroot -solid gray 
xrandr --output eDP-1 --primary --output DP-1 --scale 1.1x1.1 --right-of eDP-1 --mode 1920x1280 --rate 120 
qtile start
```
As in the previous case, qtile starts but the xrandr command is not working.

What I am doing wrong? Or is this a problem with qtile setting xrandr on its own and overriding my configuration?

Thank you very much.




Discussion:
Does the xrandr command work if you just run it in a terminal after qtile has started?
Sorry, I forgot to mention it. Yes, it works.
If you run your autostart script from a terminal, does the xrandr command work?
Thank you, that was a very good suggestion. I am not sure why I had not thought about it. 

The results get weirder to me, as the output in the terminal says:
`xrandr: cannot find mode 1920x1280`
But when I run the same command in the terminal alone
`xrandr --output DP-1 --scale 1.10x1.10 --right-of eDP-1 --mode 1920x1080 --rate 120`
it works. And the output of the xrandr command is:
```
Screen 0: minimum 320 x 200, current 4032 x 1188, maximum 16384 x 16384
eDP-1 connected primary 1920x1080+0+0 (normal left inverted right x axis y axis) 309mm x 174mm
   1920x1080     59.99*+  59.97    59.96    59.93    47.99  
   1680x1050     59.95    59.88  
   1600x1024     60.17  
   1400x1050     59.98  
   1600x900      59.99    59.94    59.95    59.82  
   1280x1024     60.02  
   1440x900      59.89  
   1400x900      59.96    59.88  
   1280x960      60.00  
   1440x810      60.00    59.97  
   1368x768      59.88    59.85  
   1360x768      59.80    59.96  
   1280x800      59.99    59.97    59.81    59.91  
   1152x864      60.00  
   1280x720      60.00    59.99    59.86    59.74  
   1024x768      60.04    60.00  
   960x720       60.00  
   928x696       60.05  
   896x672       60.01  
   1024x576      59.95    59.96    59.90    59.82  
   960x600       59.93    60.00  
   960x540       59.96    59.99    59.63    59.82  
   800x600       60.00    60.32    56.25  
   840x525       60.01    59.88  
   864x486       59.92    59.57  
   800x512       60.17  
   700x525       59.98  
   800x450       59.95    59.82  
   640x512       60.02  
   720x450       59.89  
   700x450       59.96    59.88  
   640x480       60.00    59.94  
   720x405       59.51    58.99  
   684x384       59.88    59.85  
   680x384       59.80    59.96  
   640x400       59.88    59.98  
   576x432       60.06  
   640x360       59.86    59.83    59.84    59.32  
   512x384       60.00  
   512x288       60.00    59.92  
   480x270       59.63    59.82  
   400x300       60.32    56.34  
   432x243       59.92    59.57  
   320x240       60.05  
   360x202       59.51    59.13  
   320x180       59.84    59.32  
DP-1 connected 2112x1188+1920+0 (normal left inverted right x axis y axis) 543mm x 302mm
   1920x1080     60.00 + 165.00   143.98   120.00*  119.88    50.00    59.94    24.00    23.98  
   3840x2160     30.00    24.00    29.97    23.98  
   1680x1050     59.88  
   1280x1024     75.02    60.02  
   1440x900      59.90  
   1280x960      60.00  
   1280x800      59.91  
   1152x864      75.00  
   1280x720      60.00    50.00    59.94  
   1024x768      75.03    70.07    60.00  
   832x624       74.55  
   800x600       72.19    75.00    60.32    56.25  
   720x576       50.00  
   720x480       60.00    59.94  
   640x480       75.00    72.81    66.67    60.00    59.94  
   720x400       70.08  
HDMI-1 disconnected (normal left inverted right x axis y axis)
DP-2 disconnected (normal left inverted right x axis y axis)
HDMI-2 disconnected (normal left inverted right x axis y axis)
```
They're not the same command. You're using `1920x1280`  in one and `1920x1080` in another.
Ok I am really that stupid then! Sorry about this and thank you for your help.

One last issue: the bar on the secondary monitor crashes at startup. Nothing that cannot be solved with a restart but nevertheless annoying. Any suggestions? Is qtile loading too soon? 
No problem.

As for the other issue, I'm guessing you're on v0.20 and not running the latest git version. There were some bugs with bars not reconfiguring properly when using programs like xrandr. These have been fixed so you should see those changes once we push a new bugfix release and this gets packaged by your distro.
I tried with the latest git. It was not working out well at first when I tried with the qtile wallpaper option, but then eventually I got it right in this way under startup_once:

```
#!/usr/bin/sh
dunst &
notmuch new  &
picom &
sh /home/eugenio/.local/bin/auto-screen-rotate.sh eDP-1 "Wacom HID 4956 Finger touch" &
$HOME/.local/bin/touchpad_toggle.sh  &
$HOME/.config/eww/scripts/daemon_eww.sh  &
$HOME/.local/bin/cal_alarms.py  &
$HOME/.local/bin/dropbox start  &
setxkbmap -layout us,it -variant qwerty -option grp:rshift_toggle,compose:rctrl &
setxkbmap -device 10 -layout us,it -variant qwerty -option grp:rshift_toggle,compose:rctrl &
xrdb ~/.Xresources &
sleep 5 &&
xrandr --output DP-1 --scale 1.10x1.10 --right-of eDP-1 --mode 1920x1080 --rate 120 &&
feh --no-fehbg --bg-scale /home/eugenio/Sync/Sfondi/wallhaven-vg6dqp.jpg --bg-scale /home/eugenio/Sync/Sfondi/1245752.jpg &
sleep 10 && xinput map-to-output 'Wacom HID 4956 Finger touch' eDP-1 &
```
Qtile has to load before I make xrandr run and before setting the wallpaper apparently.

Thank you again.
Wallpaper should work. 

Can you take some screenshots?
Here it is. The first screen looks fine. The second one does not, as the image is clearly not centered even if I set it up with the "fill" option. Is it because xrandr starts after the wallpaper is already set?

![22_02_22_13_13_57](https://user-images.githubusercontent.com/58224469/155130460-e343eeb4-07fe-4f34-a7a3-ac591d935bf2.png)

Ah yes. This is an issue to do with scaling. I've seen it before but haven't had a chance to fix it.

Will take a look.

Resolving patch:
diff --git a/libqtile/backend/x11/xcbq.py b/libqtile/backend/x11/xcbq.py
--- a/libqtile/backend/x11/xcbq.py
+++ b/libqtile/backend/x11/xcbq.py
@@ -686,6 +686,8 @@ def __init__(self, display):
         self.default_screen = self.screens[self.conn.pref_screen]
         self.conn.core.SetCloseDownMode(xcffib.xproto.CloseDown.RetainPermanent)
         self.atoms = AtomCache(self)
+        self.width = -1
+        self.height = -1
 
     def paint(self, screen, image_path, mode=None):
         try:
@@ -695,6 +697,14 @@ def paint(self, screen, image_path, mode=None):
             logger.error("Wallpaper: %s" % e)
             return
 
+        # Querying the screen dimensions via the xcffib connection does not
+        # take account of any screen scaling. We can therefore work out the
+        # necessary size of the root window by looking at the
+        # pseudoscreens attribute and calculating the max x and y extents.
+        root_windows = screen.qtile.core.conn.pseudoscreens
+        width = max((win.x + win.width for win in root_windows))
+        height = max((win.y + win.height for win in root_windows))
+
         root_pixmap = self.default_screen.root.get_property(
             "_XROOTPMAP_ID", xcffib.xproto.Atom.PIXMAP, int
         )
@@ -702,16 +712,18 @@ def paint(self, screen, image_path, mode=None):
             root_pixmap = self.default_screen.root.get_property(
                 "ESETROOT_PMAP_ID", xcffib.xproto.Atom.PIXMAP, int
             )
-        if root_pixmap:
+        if root_pixmap and (self.width == width and self.height == height):
             root_pixmap = root_pixmap[0]
         else:
+            self.width = width
+            self.height = height
             root_pixmap = self.conn.generate_id()
             self.conn.core.CreatePixmap(
                 self.default_screen.root_depth,
                 root_pixmap,
                 self.default_screen.root.wid,
-                self.default_screen.width_in_pixels,
-                self.default_screen.height_in_pixels,
+                self.width,
+                self.height,
             )
 
         for depth in self.default_screen.allowed_depths:
@@ -721,11 +733,7 @@ def paint(self, screen, image_path, mode=None):
                     break
 
         surface = cairocffi.xcb.XCBSurface(
-            self.conn,
-            root_pixmap,
-            root_visual,
-            self.default_screen.width_in_pixels,
-            self.default_screen.height_in_pixels,
+            self.conn, root_pixmap, root_visual, self.width, self.height
         )
 
         context = cairocffi.Context(surface)
@@ -772,14 +780,7 @@ def paint(self, screen, image_path, mode=None):
         self.conn.core.ChangeWindowAttributes(
             self.default_screen.root.wid, CW.BackPixmap, [root_pixmap]
         )
-        self.conn.core.ClearArea(
-            0,
-            self.default_screen.root.wid,
-            0,
-            0,
-            self.default_screen.width_in_pixels,
-            self.default_screen.height_in_pixels,
-        )
+        self.conn.core.ClearArea(0, self.default_screen.root.wid, 0, 0, self.width, self.height)
         self.conn.flush()
 
     def __del__(self):


Test patch: