Skip to content

Instantly share code, notes, and snippets.

@jsommr
Created November 22, 2024 11:29
Show Gist options
  • Save jsommr/6f15156999f086e277d57d58bb778bda to your computer and use it in GitHub Desktop.
Save jsommr/6f15156999f086e277d57d58bb778bda to your computer and use it in GitHub Desktop.
Waydroid on KDE: True fullscreen (KDE gestures and "reveal panel" edges disabled) and screen rotation support.
#!/bin/env bash
# Makes `waydroid show-full-ui` integrate nicely with KDE by disabling KDE gestures and
# reacting to screen rotation. Not tested with multi_windows.
#
# Run this script when signed into a wayland session, and not as root (don't use sudo).
# Re-run every time you change resolution or scaling.
#
# The Lineage OS boot animation will no longer be centered as a result of this script.
#
# IMPORTANT
# Mouse support in Waydroid gets broken by this. I believe it's because I'm marking the
# window fullscreen in KDE and re-positioning it. Touch works as expected.
# Find `waydroid.fullScreen = true` in this script and remove it if this is an issue for
# you. I haven't tried it since I only use the touch screen for Waydroid. No fullscreen
# means that KDE gestures will react to swipes, and panels are revealed when the cursor
# touches the edges of the screen.
if ! [[ -x $(command -v jq) ]]; then
echo "This command requires jq."
exit 1
fi
# No reason to let the user wait for granting sudo permission
sudo true
echo
echo "Fullscreen Waydroid on KDE"
echo
MONITORS=$(kscreen-doctor --json)
if [[ -z $MONITORS ]]; then
echo
echo "kscreen-doctor failed. This is usually a temporary thing, try running this program again a few times."
echo
exit 1
fi
MONITORS_COUNT=$(echo "$MONITORS" | jq '.outputs | length')
SELECTED_MONITOR_ID=1
if [[ $MONITORS_COUNT > 1 ]]; then
kscreen-doctor -o | sed G
echo
echo "What monitor is going to render Waydroid? Enter its \"Output: {number}\""
while true; do
read -p "Output: " SELECTED_MONITOR_ID
if [[ $SELECTED_MONITOR_ID -gt 0 && $SELECTED_MONITOR_ID -le $MONITORS_COUNT ]]; then
break
fi
echo "That output doesn't exist."
done
fi
SELECTED_MONITOR=$(echo "$MONITORS" | jq '.outputs[] | select(.id == $monitorId)' --argjson monitorId $SELECTED_MONITOR_ID)
WIDTH=$(echo "$SELECTED_MONITOR" | jq '.size.width')
HEIGHT=$(echo "$SELECTED_MONITOR" | jq '.size.height')
SCALE=$(echo "$SELECTED_MONITOR" | jq '.scale')
MAX_SIZE=$(($WIDTH > $HEIGHT ? $WIDTH : $HEIGHT))
WINDOW_SIZE=$(awk "BEGIN {print int(($MAX_SIZE/$SCALE) + 0.5)}")
echo
echo "Starting Waydroid and setting props. Expect a few retries."
echo
waydroid session start &
sleep 2
# This prop is necessary for KDE fullscreen. Something prevents the Waydroid UI from rendering without it.
waydroid prop set persist.waydroid.use_subsurface true
waydroid prop set persist.waydroid.width $WINDOW_SIZE
waydroid prop set persist.waydroid.height $WINDOW_SIZE
echo
echo "Writing script that reacts to device orientation and sets Waydroid's resolution accordingly."
echo
sudo tee /sbin/waydroid-set-resolution << EOF
#!/bin/env bash
set -e
WIDTH=$WIDTH
HEIGHT=$HEIGHT
function set_resolution {
if ! waydroid status | grep -q "Session:.*RUNNING"; then
return
fi
case \$1 in
normal|bottom-up)
waydroid shell wm size \${WIDTH}x\${HEIGHT};;
left-up|right-up)
waydroid shell wm size \${HEIGHT}x\${WIDTH};;
esac
}
while IFS='$\n' read -r line; do
rotation="\$(echo \$line | sed -En "s/.*(normal|left-up|right-up|bottom-up).*/\1/p")"
[[ ! -z \$rotation ]] && set_resolution \$rotation
done < <(stdbuf -oL monitor-sensor --accel)
EOF
sudo chmod +x /sbin/waydroid-set-resolution
echo
echo "Creating systemd service that starts the script above."
echo
sudo tee /etc/systemd/system/waydroid-set-resolution.service << EOF
[Unit]
Description=Change Waydroid resolution when device is rotated.
After=iio-sensor-proxy.service waydroid-container.service
[Service]
ExecStart=/sbin/waydroid-set-resolution
Restart=always
[Install]
WantedBy=graphical.target
EOF
sudo systemctl enable waydroid-set-resolution
sudo systemctl start waydroid-set-resolution
echo
echo "Writing KWin script that re-positions the Waydroid window when orientation is changed."
echo
sudo mkdir -p /usr/share/kwin/scripts/waydroid-fullscreen/contents
sudo tee /usr/share/kwin/scripts/waydroid-fullscreen/metadata.json << EOF
{
"KPackageStructure": "KWin/Script",
"KPlugin": {
"Authors": [{ "Name": "Jan Sommer" }],
"Description": "Run Waydroid in fullscreen (to disable KDE edge gestures). Requires waydroid-set-resolution.",
"Icon": "waydroid",
"Id": "waydroid-fullscreen",
"License": "Public Domain",
"Name": "Waydroid Fullscreen"
},
"X-Plasma-API": "javascript",
"X-Plasma-MainScript": "main.js"
}
EOF
echo
sudo tee /usr/share/kwin/scripts/waydroid-fullscreen/contents/main.js << EOF
let waydroid = undefined
function reposition() {
if (!waydroid)
return
const ps = workspace.clientArea(KWin.PrimaryScreenArea, workspace.activeScreen, 0)
const orientation = ps.width > ps.height ? "landscape" : "portrait"
const geom = Object.assign({}, waydroid.frameGeometry)
if (orientation === "landscape") {
geom.y = -Math.round((waydroid.height - ps.height) / 2)
geom.x = 0
} else {
geom.y = 0
geom.x = -Math.round((waydroid.width - ps.width) / 2)
}
waydroid.frameGeometry = geom
}
workspace.clientAdded.connect(client => {
if (client.caption !== "Waydroid")
return
waydroid = client
waydroid.fullScreen = true
reposition()
workspace.virtualScreenGeometryChanged.connect(reposition)
})
workspace.clientRemoved.connect(client => {
if (client.caption !== "Waydroid")
return
workspace.virtualScreenGeometryChanged.disconnect(reposition)
waydroid = undefined
})
EOF
waydroid session stop
echo
echo "Done."
echo "Remember to enable the Waydroid Fullscreen KWin script in settings."
echo
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment