Ubuntu Budgie 20.04 Fractional HiDPI for x11

Fractional HiDPI may work better under Wayland - however if the applications you use works best under X11 vs Wayland then this guide may be for you!

(Also to note - I completely ignore the fractional scaling options in the Display menu because they do not work for my system.)

If you apply fractional HiDPI under X11 and suspend your laptop by closing your lid then you will quickly find out that Ubuntu Budgie 20.04 does not keep your xrandr scaling settings. This guide will fix that issue.

The issue appears to be caused by Mutter removing any fractional scaling that is being applied via xrandr. The reason(s) for this is unknown and may be an unintentional bug. There appears to be no method, that I found, that can remove this functionality so working around it is what this guide is all about.

Also this guide explains this type of solution perfectly, and that even Apple takes a similar approach to their scaling as well. They also indicate that scaling broke in Mutter as of 3.32.

https://wilfredwee.github.io/entry/how-to-xrandr

So here’s my setup - I have a cheap $150 used laptop that has a 13" screen, intel gpu, and 1920x1080 resolution. It’s wonderfully sharp, but also wonderfully tiny on Linux at this native resolution, so how do we fix this? Also can we make it similar to an Apple retina screen of 2880x1800 resolution that the MacBook Pro 15" has?

If you do the math and multiply 1920x1080 by 1.5 then you will get 2880x1620!

So to get straight into it you will need to scale your Budgie DE to 2x so that we can later scale that back down.

Scale Budgie Up 2x

gsettings set org.gnome.settings-daemon.plugins.xsettings overrides "[{'Gdk/WindowScalingFactor', <2>}]"
gsettings set org.gnome.desktop.interface scaling-factor 2

Scale Budgie back down to 1.5x

xrandr --output eDP-1 --scale 1.5x1.5

Everything should look perfectly sharp and better than ever, but everything is not perfect as you may soon find out. If you close your lid and come back you will find that you are scaled backup to 2x and the xrandr scaling has been wiped out. You will also find out that if you suspend manually before closing the lid then the scaling will not be lost - but that’s annoying you want to close your lid like a sane person, right?

The next steps are not for the faint of heart but it will get you where you want to to go. So lets layout what we want to do.

A.) Apply the scaling when you first login.
B.) Disable the normal lid close suspend
C.) Configure your custom lid close suspend, so you can re-apply scaling
D.) Optional Fix screen tearing for Intel GPUs

I will tell you right now that steps 1 & 2… they’re pretty easy step 3 is not. Why? What issues are you going to run into? Well it may vary with your GPU &/or driver but if your system is like mine you will have graphical glitches that will leave literal transparent holes in your windows after rescaling so we will need to clean that up.

Also to ensure that your custom suspend method is working we will play sounds to help you know that your laptop has indeed gone to sleep correctly. You can comment these out later if you would like once you are comfortable with the setup.

Let’s Begin

Section A.) Apply the scaling when you first login.

We will create 2 files to quickly get up and running.

1.) Get your connect display name (this may slightly change if you later add an xorg.conf file, so be prepared to possibly come back to this.)

xrandr | grep " connected " | awk '{ print$1 }'

My result was eDP-1, but later becomes eDP1 due ot my xorg.conf file for Intel - to try and lessen any tearing.

  1. Create directory for the scripts
mkdir ~/.config/scripts/
  1. Create the script
    nano ~/.config/scripts/startup.sh
#!/bin/bash
until [ xrandr ]; do sleep 1; done
xrandr --output eDP1 --scale 1.5x1.5

chmod +x ~/.config/scripts/startup.sh

Optional - I also added the following to startup.sh as it resolves an issue that I have with my touchpad to make it more sensitive. (Also installed a synaptics driver)

synclient MinSpeed=1.8 MaxSpeed=4 AccelFactor=0.0997009
xinput set-prop 10 "Device Accel Velocity Scaling" 50
xinput set-prop 10 "Synaptics Coasting Speed" 30 50
  1. Create the desktop shortcut file in your autostart directory
    nano ~/.config/autostart/startup.desktop
[Desktop Entry]
Name=Startup
GenericName=Path
Comment=Startup Patches
Exec=/bin/bash -c "/home/{username}/.config/scripts/startup.sh"
Terminal=false
Type=Application
X-GNOME-Autostart-enabled=true

This completes section A. Your resolution and other fixes ought to be applied on login.

Section B) Disable the normal lid close suspend

1.) Ignore Lid Close Events (by changing suspend to ignore)

sudo nano /etc/systemd/logind.conf

...
HandleLidSwitch=ignore
HandleLidSwitchExternalPower=ignore
HandleLidSwitchDocked=ignore
...

systemctl restart systemd-logind

Note: Only for testing you can also set IgnoreLid=false in /etc/UPower/UPower.conf to witness Mutter screwing up your scaling graphics on lid close events as it ignores these type of settings and does its own thing. service upower restart

Now you are ready for what was the longest and most difficult part of this tutorial to get right.

C.) Configure your custom lid close suspend, so you can re-apply scaling.

Note: This largely follows the advice here 18.04 - How to run a script when the lid is closed? - Ask Ubuntu .

We will create these 4 files
/etc/acpi/events/laptop-lid
/etc/acpi/laptop-lid.sh
~/.Xdbus
~/.config/scripts/monitor.sh

sudo nano /etc/acpi/events/laptop-lid

event=button/lid.*
action=/etc/acpi/laptop-lid.sh

update all {username} to simply your username (no brackets)
sudo nano /etc/acpi/laptop-lid.sh

#!/bin/bash

DISPLAY=:0
sleep 1

source /home/{username}/.Xdbus
grep -q closed /proc/acpi/button/lid/*/state
if [ $? = 0 ]
then
        killall dbus-monitor
        killall monitor.sh
        # close action
        aplay /usr/share/sounds/sound-icons/percussion-50.wav
        su {username} -c "gnome-screensaver-command -l"
        sleep 1
        systemctl suspend
        sleep 10
        # You should not hear this 2nd noise on sleep, but only on resume!
        aplay /usr/share/sounds/sound-icons/percussion-50.wav
else
        su {username} -c "/usr/bin/bash -c '/home/{username}/.config/scripts/monitor.sh'" &
        aplay /usr/share/sounds/sound-icons/piano-3.wav
fi

sudo chmod +x /etc/acpi/laptop-lid.sh

nano ~/.Xdbus

export XDG_SEAT_PATH=/org/freedesktop/DisplayManager/Seat0

nano ~/.config/scripts/monitor.sh

#!/bin/bash

dbus-monitor --session "type='signal',interface='org.gnome.ScreenSaver'" | \
(
  while true; do
    read X
    if echo $X | grep "boolean true" &> /dev/null; then
      echo `date` - SCREEN_LOCKED;
    elif echo $X | grep "boolean false" &> /dev/null; then
      #echo `date` - SCREEN_UNLOCKED;
      DISPLAY=:0 xrandr --output eDP1 --scale 1.5x1.5
      sleep 2
      DISPLAY=:0 wmctrl -l|awk '{$3=""; $2=""; $1=""; print $0}'| xargs -I % sh -c '{ DISPLAY=:0 wmctrl -r "%" -b toggle,shaded; sleep 0.1; DISPLAY=:0 wmctrl -r "%" -b toggle,shaded; }'
      sleep 1
      killall dbus-monitor
      killall monitor.sh
      break
    fi
  done
)

D.) Optional Fix screen tearing for Intel GPUs

sudo vi /etc/X11/xorg.conf.d/20-intel.conf

Section "Monitor"
    Identifier "Intel Graphics"
EndSection

Section "Device"
  Identifier  "Intel Graphics"
  Driver      "intel"
  Option      "TearFree" "true"
EndSection

And that’s it! You should now have a working Fractional HiDPI laptop running Ubuntu Budgie 20.04 under X11.

Also that line there is a little bit hackish as it simply toggles the window shade for all of your applications to clean up a graphical glitchy mess that would normally appear when you re-apply your scaling after a lid close suspend event.

Also it might be better to modify that line to actually slightly resize every window instead of toggling the shade. If anyone wants to work that out then I will add that as the primary method to clean up the graphical artifacts or inconjuction with toggling the window shade.

On a different note you can possibly use the normal suspend method, and just use a solution like below to play sounds or initiate the dbus monitor script as well, but I have not retested it since I worked this method out. (Just retested this and it would not initiate the monitor script for some reason - so the lid event script was still needed in the end - at which point there is no point in configuring this because if you suspend without closing the lid there will not be a scaling issue to begin with.)

Also trying to fix the scaling issues just before it goes to sleep, but after unscaling is applied, is a bad idea - the scaling is un-applied both on suspend and resume and doing such an action back to back like that risks more graphical glitches, artifacts and system instability.

Unapply → Apply scaling → Unapply → Apply scaling = Bad
Unappy → Unapply (practically nothing) → Apply scaling = Good

It is much safer and more reliable to only rescale on login unless you fix this issue in the source code of mutter and recompile it imo.

1 Like

The fix for resizing a specific program’s windows, in this case Waterfox, a fork of Firefox, but this same logic can be applied to other applications - just break this command apart and make sure it works for the specific program you want to use it for.

Also note that I had to add in a strange offset of 28 and 132 on the x & y positioning of the windows, I am not sure why but I did have to do that. May vary on other systems as I have not tested it against others than this one. The grep command can likely be extended to other applications as well. Updated the command from the initial post to properly pull in the right wm_class name vs the title name - this should work 100% reliably now across any app as far as I know.

DISPLAY=:0 wmctrl -lGx | awk '{print $1 " " $3 " " $4 " " $5 " " $6 " " $7}' | grep Waterfox | awk '{ system("DISPLAY=:0 wmctrl -ir " $1 " -e 0,"$2-28","$3-132","$4-10","$5-10";sleep 0.5;DISPLAY=:0 wmctrl -ir  "$1" -e 0,"$2-28","$3-132","$4","$5)}'