Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 73 additions & 0 deletions swift/kioskapp/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# Stage 1: Build the Swift GTK application
FROM swift:6.2-jammy AS builder

# Install GTK4 development dependencies
RUN apt-get update && apt-get install -y \
libgtk-4-dev \
pkg-config \
&& rm -rf /var/lib/apt/lists/*

WORKDIR /app
COPY Package.swift ./

# Resolve dependencies first (cached unless Package.swift changes)
RUN swift package resolve

COPY Sources/ ./Sources/

# Build the application
RUN swift build

# Stage 2: Runtime with Cage compositor
FROM ubuntu:22.04

# Install runtime dependencies
RUN apt-get update && apt-get install -y \
# Cage Wayland compositor
cage \
# Seat management daemon
seatd \
# GTK4 runtime
libgtk-4-1 \
# Wayland and graphics
libwayland-client0 \
libwayland-server0 \
libegl1 \
libgles2 \
libgbm1 \
libdrm2 \
libinput10 \
libxkbcommon0 \
# Mesa DRI drivers (required for EGL/GPU rendering)
libgl1-mesa-dri \
# Fonts
fonts-dejavu-core \
# D-Bus (required for GTK)
dbus \
&& rm -rf /var/lib/apt/lists/*

# Create a non-root user (cage refuses to run as root)
# Add to video group for DRM access
RUN groupadd -f render && useradd -m -s /bin/bash -G video,render kioskuser

WORKDIR /app

# Copy Swift runtime libraries from builder
COPY --from=builder /usr/lib/swift/linux /usr/lib/swift/linux
ENV LD_LIBRARY_PATH=/usr/lib/swift/linux

# Copy the built binary from builder stage
COPY --from=builder /app/.build/debug/KioskApp ./app

# Environment variables for Wayland/GTK
ENV GDK_BACKEND=wayland
ENV GTK_THEME=Adwaita

# Entrypoint: start seatd, then run cage as kioskuser
CMD ["/bin/sh", "-c", "\
mkdir -p /run/user/1000 && chown kioskuser:kioskuser /run/user/1000 && chmod 700 /run/user/1000 && \
chmod 666 /dev/dri/* && \
seatd -g video &\
sleep 0.5 && \
runuser -u kioskuser -- env XDG_RUNTIME_DIR=/run/user/1000 LIBSEAT_BACKEND=seatd WLR_BACKENDS=drm WLR_DRM_DEVICES=/dev/dri/card1 cage -ds -- /app/app \
"]
21 changes: 21 additions & 0 deletions swift/kioskapp/Package.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// swift-tools-version:6.1
import PackageDescription

let package = Package(
name: "KioskApp",
platforms: [
.macOS(.v14)
],
dependencies: [
.package(url: "https://github.com/stackotter/swift-cross-ui", revision: "main")
],
targets: [
.executableTarget(
name: "KioskApp",
dependencies: [
.product(name: "SwiftCrossUI", package: "swift-cross-ui"),
.product(name: "GtkBackend", package: "swift-cross-ui")
]
)
]
)
39 changes: 39 additions & 0 deletions swift/kioskapp/Sources/KioskApp/main.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import SwiftCrossUI
import GtkBackend

@main
struct KioskApp: App {
var body: some Scene {
WindowGroup("Kiosk App") {
ContentView()
}
}
}

struct ContentView: View {
@State private var count = 0

var body: some View {
VStack(spacing: 20) {
Text("Swift GTK Kiosk App")
.font(.largeTitle)

Text("Running in Cage Wayland Compositor")
.font(.body)

Text("Count: \(count)")
.font(.title)

HStack(spacing: 10) {
Button("Decrement") {
count -= 1
}

Button("Increment") {
count += 1
}
}
}
.padding(40)
}
}
37 changes: 37 additions & 0 deletions swift/kioskapp/wendy.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{
"appId" : "com.example.kioskapp",
"entitlements" : [
{
"type" : "audio"
},
{
"mode" : "bluez",
"type" : "bluetooth"
},
{
"mode" : "host",
"type" : "network"
},
{
"allowlist" : [

],
"mode" : "all",
"type" : "video"
},
{
"name" : "app-com.example.kioskapp",
"path" : "\/mnt\/app",
"type" : "persist"
},
{
"name" : "wendy-shared",
"path" : "\/mnt\/shared",
"type" : "persist"
},
{
"type" : "gpu"
}
],
"version" : "0.0.1"
}