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.

2 Likes

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)}'

If I want to try this on my laptop, 13" with 2560*1600 resolution, should I disable scaling in Settings > Display first?

Because I have set it to 125% and it works just fine. My #1 issue is really that you need per-application fixes, like Spotify. Usually done by editing the .desktop file.

I also have the issue of blown up screen when I close the lid and reopen later. To prevent that from happening, I suspend first.

I like that there is a workaround now, but it seems like a lot of work to solve the “close lid” issue?

Yea, I believe you will need to unapply any scaling you have done via the UI first.

It is a bit of work yes - but I will be working to port this over into my Kairos repo - which will be rename it once this fix makes it into that repo along with 1 or 2 other more minor fixes. Karios already sets a lot up now and in about 3 minutes (7-9 w/ homebrew, but I commented that out now) . I also want to extend it sorta so that people can contribute other yaml configs for any distro. I really only care about Budgie and XFCE as usable DE’s and have no intention on dog fooding any of the others, but I still want the overall concept and idea to be applicable to any distro current, or future and give people the chance to send me PRs for anything I don’t support or test personally.

I am not sure why you need other individual dpi fixes, although linux doesn’t always handle hidpi well, the joy of this fix though is that that largely does not matter for the way it both upscales and downscales it seems to work well, at least on a single monitor. Less of sure of different monitors at different DPI but I can test that in about a week. Sadly I am not in a position right not to test it right now.

If you want to try this in a VM or don’t mind running something risky then you can try out my Kairos project, just be aware that I consider it alpha-beta quality as I am still working through it.

You can try it yourself, for example install Spotify, Anydesk etc. QT applications usually require this.

Still the fractional scaling of Budgie itself seems like something that should be fixed by Budgie… although I appreciate your workaround.

I only have an issue where the login screen is shown blown up (200%) when I have enabled fractional scaling (125%). This happens not just on lid close but anytime the display goes to sleep (strangely it doesn’t always happen).
How to solve that? Your solution only solves it for lid close, but the laptop might have already put the display or the whole device to sleep, without me closing the lid.

The biggest issue is there is no password input window anymore, even if I just “guess” and type my password/hit enter, I can’t get passed the login screen anymore.
I don’t understand why release after release no solution has been provided by Ubuntu. Lot’s of devices need fractional scaling 125% or 150%.

Actually with 21.04 the issue with fractional scaling has become even worse with regards to the lock screen:

Please see this video (I used WhatsApp as a quick hack to make the video file smaller).

@fossfreedom

budgie-screensaver, mate-screensaver, xfce4-screensaver all have issues since they are ultimately a fork of gnome-screensaver which we use in 21.04.

In reality the only real solution here is a native in-built lock screen written specifically for budgie-wm.

@fossfreedom I’d like to better toggle between these 2 states without needing to logoff and back on for everything to appear correctly. Do you have any thoughts? Because restarting budgie-wm and replacing budgie-panel does not appear to be enough for me.

For retina

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

Normal

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

not all apps will respond to scaling changes - where you may notice issues is because the apps pick up their scaling factors on startup and don’t cater for scaling changes after the app has started.

@fossfreedom The thing that bothers me most - or in particular though is the launcher menu component of the budgie-panel, can I at least restart that one too w/o logging off and back on? I literally have to type logout for that option to appear, otherwise it gets cut off and I know other users may just not ever find it, get frustrated or annoyed.

Generally speaking most things rescale just fine or I can restart them, that launcher though has been a mystery.

picture of what you are seeing?

Note that this only happens when you have logged in under the scaling of 1 and increase it to 2, but if you had originally logged in under 2 then you can in fact switch between 2 to 1 and 1 to 2 again without this odd behavior. I assume some type of reserved canvas space is created at the larger size and is kept throughout, but when it is set small it is never increased.

… and you say that a restart of the panel doesn’t resolve? How odd.

Crap… it just worked and I restarted that panel again -.-. I am sorry, feel like I have wasted your time… I could have sworn that restarting that panel with replace did not in fact work previously… Maybe I had scripted the changes too fast in secession and need to slow that down.

Well I guess I am pretty happy now… because I should be able to switch scaling pretty easily without needing to actually log off if this is the case.

Looks like what I was trying to do won’t work any ways… xrdp is just too odd in how it behaves - once you log into an xrdp session with a user you may have difficulty logging into that user locally after that (maybe a reboot would fix it?). The budgie-desktop just doesn’t start right locally after setting it up to work with xrdp, my main account works fine - but I don’t xrdp into that one, only the 2nd profile. I may just have to create a 3rd profile so that I can switch locally to a different user account when I need to and share files btwn the 2nd and 3rd account so that I can retain the xrdp capabilities I have setup.

Not as seamless as what I can do with Windows - but I prefer an xRDP/NoMachine combination over VNC. It is simply too fast and performs too well for me to ignore it. Also the dynamic changing of screen resolutions is perfect, I would not get that with VNC which bases its resolutions on my local monitors, unless I setup virtual ones and again… that is a lot of work. Not even sure how I would toggle btwn virtual and actual screens either.

I better understand what needs to happen now so that users generally should not need to log off and back on imo when changing scaling.

After changing btwn scale states of 1 and 2 the gnome-shell ought to be restarted, then the budgie-wm, if they are done in that order then the panel doesn’t even need to be reloaded. So ideally I think the account should always login with a Scale of 2, even if they want 1 so that the memory or canvas is more or less set for it already and then you can easily toggle btwn the two. I say that - short of updating the source so that it allocates more than it needs, but maybe it is easier to just restart the shell and wm processes.

To sum it up though these commands are what worked for me and while the launch menu was ok afterall - the cursor was not and was stuck at a large size when going to 1 and menu titles would be too large or tiny in some cases until the proper commands were ran in the right order.

Avoid the need for logoff and logon

# fixes some odd window sizing cursor size issues
gnome-shell --replace&
# may also fix window sizing issues
budgie-wm --replace&
# If you logged in starting with 1x then this too
budgie-panel --replace&
# Also should restart plank
pkill -9 plank
plank&