Tutorial and example on how to create a Kotlin Desktop Compose app running on Raspberry Pi 5 in kiosk mode.
To create the jar file from scratch, open Intellij IDEA and click on the New_Project button. Choose Compose Desktop as a project type. It would create the Hello World app automatically. To create a fat jar file, click on the gradle button on the right side of IDE to open the Gradle panel. Expand on Tasks/compose_desktop/ scroll down and right-click on "packageUberJarForCurrentOS" and select Run. This will produce the "build/compose/jars/PiKiosk-linux-x64-1.0.0.jar" file.
You can build the project on RPi from sources with this command:
./gradlew build
But before running a Compose app on RPi, run this command first:
export MESA_EXTENSION_OVERRIDE="-GL_ARB_invalidate_subdata"
Otherwise you'll get an error. For explanation see: https://www.reddit.com/r/Kotlin/comments/1c5jikl/how_do_i_get_compose_working_on_my_raspberry_pi/
Then run it with:
./gradlew run
You can build fat jar on RPi with:
./gradlew packageUberJarForCurrentOS
- Use Raspberry Pi Imager
to flash Raspberry Pi OS 64-bit to a microSD card
- Click the ⚙️ icon for Advanced Options
- Check
Enable SSH
-
Select
Use password authentication
OR
-
Select
Allow public-key authentication only
(more secure)-
Set authorized_keys for '<username>'
-
-
- Check
Set username and password
- Enter
Username
andPassword
in the respective fields
- Enter
- Check
Configure Wireless LAN
- Enter
SSID
andPassword
for your Wi-Fi network - Select
Wireless LAN Country
- Enter
- Check
Set locale settings
- Select
Time zone
andKeyboard layout
- Select
- Click
Save
- Check
- Select
RASPBERRY PI OS(64-BIT)
asOperating System
- Click
CHOOSE STORAGE
and select the microSD card - Click
WRITE
- Click the ⚙️ icon for Advanced Options
If you need to change any of these settings later, run sudo raspi-config
in a
terminal on the Pi 5.
- Connect the following h/w with the Pi 5
- a monitor/screen
- a keyboard
- and a mouse
- Insert the microSD card into the Pi 5
- Connect Pi 5 to the power supply
Pi 5 will boot up and show the desktop environment.
ssh
into the Pi 5 with the username and password you set during the OS installation.
ssh <username>@<hostname/IP>
Follow the steps below to install cage
on Pi 5.
-
Make sure our OS is up-to-date
sudo apt-get update && sudo apt-get -y upgrade
-
Install dependencies for
cage
:sudo apt-get -y install cmake libvulkan-dev libwlroots-dev
Optional: Building man pages
Append `scdoc` to above command if you need cage man pages.Notes
Without the dependencies, `meson setup build` will fail with the following error message(s)/warning(s):Found CMake: NO Run-time dependency wlroots found: NO (tried pkgconfig and cmake) Build-time dependency scdoc found: NO (tried pkgconfig and cmake)
-
Build and install
cage
# our workspace mkdir ~/devel && cd ~/devel # master branch of cage requires a higher version of libwlroots-dev # whereas Debian bookworm has an older version(v0.1.4). We build v0.1.5 # here, which is the latest release at the time this writing git clone https://github.com/cage-kiosk/cage.git -b v0.1.5 cd cage # Configure meson setup build --buildtype=release -Dxwayland=true -Dprefix=/usr # Build ninja -C build # Install sudo ninja -C build install
-
Clone this repository
cd ~/devel git clone https://github.com/SergeySn/PiKiosk.git cd PiKiosk
-
Start
cage
on boot-
Install the systemd unit file for
cage
from this repository to the system.The systemd unit file template is set up to run
galculator
by default as it is available in stock Pi OS.sudo cp files/cage-template.service /etc/systemd/system/[email protected]
Notes
This is the same template as in the cage wikiThe only difference is that the following line
ExecStart=/usr/bin/cage /usr/bin/gtk3-widget-factory
has been replaced with
ExecStart=/usr/bin/cage /usr/bin/galculator
-
Add
cage
user. This is required by[email protected]
sudo useradd -m cage
Set a password for
cage
usersudo passwd cage
-
Disable the default display manager(
lightdm
)sudo systemctl disable display-manager
-
Enable an instantiated service of
cage
sudo ln -s /etc/systemd/system/[email protected] \ /etc/systemd/system/graphical.target.wants/[email protected]
-
Change systemd's default target to the graphical target
sudo systemctl set-default graphical.target
-
PAM configuration
Copy the PAM configuration file for
cage
sudo cp files/cage-pam-cfg /etc/pam.d/cage
Notes
This is the same PAM config as in thecage wiki
-
-
Reboot the Pi 5
sudo reboot
After reboot, cage
will start the galculator
app in kiosk mode.
-
SSH into Pi again
ssh <user>@<hostname/IP>
-
Install JRE, required to run compose app
sudo apt-get update && sudo apt-get -y install default-jre
-
Optional: Force a specific resolution in Compose app
As of https://github.com/SergeySn/PiKiosk/commit/d4b8842c9770020d417a28ebe111b171a65eb67c, the Compose app is forced to use 1920x1080 resolution. To force a different resolution replace
WindowSize(1920.dp, 1080.dp)
in Main.kt with the desired values for width and height. -
Build the sample app
cd ~/devel/PiKiosk ./gradlew packageUberJarForCurrentOS
This will produce a JAR file at
${HOME}/devel/PiKiosk/build/compose/jars/PiKiosk-linux-arm64-1.0.0.jar
.As this .jar is supposed to be accessible by the
cage
user, copy it to/home/cage
.sudo cp \ ${HOME}/devel/PiKiosk/build/compose/jars/PiKiosk-linux-arm64-1.0.0.jar \ /home/cage/
sudo chown cage:cage /home/cage/PiKiosk-linux-arm64-1.0.0.jar
-
Update
cage
's systemd unit file (/etc/systemd/system/[email protected]
) to run your compose app instead ofgalculator
#JAR=</path/to/jar> # replcae </path/to/jar> with actual path of the JAR file that you want to # run with cage #. e.g. if you want to run the JAR file created in the # previous step do: JAR=/home/cage/PiKiosk-linux-arm64-1.0.0.jar sudo sed -i -e \ "s@^ExecStart=.*@ExecStart=/usr/bin/cage -- java -jar ${JAR}@" \ /etc/systemd/system/[email protected]
-
Workaround JetBrains/skiko#649
sudo sed -i -e \ 's@^#Environment=.*@Environment="MESA_EXTENSION_OVERRIDE=-GL_ARB_invalidate_subdata"@' \ /etc/systemd/system/[email protected]
Please see the discussion here for more info.
-
Restart
cage
service for the changes to take effect# Required when /etc/systemd/system/[email protected] is updated. sudo systemctl daemon-reload # Required when /etc/systemd/system/[email protected] or .jar is updated. sudo systemctl restart [email protected]
-
Optional: Force
cage
to use a specific resolution# Replace 1920x1080@60 with desired <width>x<height>x<refresh-rate>. # For the app to appear fullscreen, make sure to use the same values as in # step 3. # Also replace HDMI-A-2 with the output <name> of your display. You can list # the displays using the `wlr-randr` command. JAR=/home/cage/PiKiosk-linux-arm64-1.0.0.jar WLR_RANDR_CMD="wlr-randr --output HDMI-A-2 --mode 1920x1080@60" sudo sed -i -e \ "s|^ExecStart=.*|ExecStart=/usr/bin/cage -- sh -c '${WLR_RANDR_CMD} \&\& java -jar ${JAR}'|" \ /etc/systemd/system/[email protected] sudo systemctl daemon-reload && sudo systemctl restart cage@tty1
# To experiment with different output modes of your display, you need to # login as cage user su cage export XDG_RUNTIME_DIR=/run/user/${UID} wlr-randr # display available outputs and modes wlr-randr --output HDMI-A-2 --mode 1920x1080@60 # select desired output/mode
⚠️ wlr-randr
only works whencage
is running.
The following steps are optional and are for hardening the kiosk setup.
-
Disable splash screen
sudo raspi-config
- Select
System Options
- Select
Splash Screen
- Select
No
- Select
Ok
- Select
Finish
- Select
-
Append
fbcon=map:1
to/boot/firmware/cmdline.txt
tells fbcon not to take over the console. This takes care of the messages that appear when the splash screen is disabled. See: https://www.kernel.org/doc/Documentation/fb/fbcon.txt
-
Alternatively, you can replace the splash screen image by replacing file:
/usr/share/plymouth/themes/pix/splash.png
with your own image. And then running
sudo plymouth-set-default-theme --rebuild-initrd pix
command to persist it.