Refactor screen rotation setup and GTK theme configuration in first-boot process

Update the one-shot script to set screen rotation using kanshi based on kernel command line parameters, replacing the previous wlr-randr method. The script now writes the configuration to ~/.config/kanshi/config and sets the GTK dark theme (PiXnoir or Adwaita-dark) at first login. Additionally, enhance documentation to reflect these changes and clarify the role of the new script in the first-boot process.
This commit is contained in:
nearxos
2026-02-23 09:59:32 +02:00
parent fd4e54f125
commit 8b4930d4b9
13 changed files with 488 additions and 113 deletions

5
TODO.MD Normal file
View File

@@ -0,0 +1,5 @@
- change icon on taskbar.
- fix dark theme.
- check for duplicates commands in all scripts and cloud init during deployment.

View File

@@ -1,30 +1,44 @@
#!/bin/bash
# One-shot: set reTerminal DM (labwc/Wayland) rotation to Left via wlr-randr, then remove self.
# One-shot: set screen rotation via kanshi (same as Control Center), then remove self.
# Reads video=DSI-1:rotate=N from kernel cmdline and writes ~/.config/kanshi/config.
# Runs once as user pi at first login; deletes its autostart and this script so it never runs again.
# Logs to /var/log/first-boot.log.
FIRST_BOOT_LOG="/var/log/first-boot.log"
BASE="$(basename "$0" .sh)"
log() { echo "[$(date -Iseconds)] [$BASE] $*" >> "$FIRST_BOOT_LOG" 2>/dev/null || true; }
log "started (labwc/wlr-randr)"
log "waiting 5s for compositor ..."
sleep 5
ROTATE="270"
for f in /boot/firmware/cmdline.txt /boot/cmdline.txt; do
if [[ -f "$f" ]]; then
val=$(grep -o 'video=DSI-1:rotate=[0-9]*' "$f" 2>/dev/null | head -1)
val="${val#*rotate=}"
if [[ "$val" =~ ^(90|180|270)$ ]]; then ROTATE="$val"; break; fi
fi
done
log "writing kanshi config with transform $ROTATE (from cmdline)"
OUTPUT=""
if command -v wlr-randr &>/dev/null; then
OUTPUT=$(wlr-randr 2>/dev/null | awk '/^[A-Za-z0-9_-]+ /{print $1; exit}')
fi
if [[ -z "$OUTPUT" ]]; then
OUTPUT="DSI-1"
log "using default output: $OUTPUT"
fi
KANSHI_DIR="$HOME/.config/kanshi"
KANSHI_CONFIG="$KANSHI_DIR/config"
mkdir -p "$KANSHI_DIR"
cat > "$KANSHI_CONFIG" << EOF
profile {
output DSI-1 enable scale 1.000000 mode 800x1280@60.000 position 0,0 transform $ROTATE
}
EOF
log "kanshi config written to $KANSHI_CONFIG"
if [[ -n "$OUTPUT" ]] && command -v wlr-randr &>/dev/null; then
log "applying rotation left (transform 270) on $OUTPUT"
wlr-randr --output "$OUTPUT" --transform 270 2>&1 | while read -r line; do log "$line"; done
# Set GTK dark theme (same as first-boot step 08)
GTK_THEME_NAME="PiXnoir"
[[ -d /usr/share/themes/Adwaita-dark ]] && ! [[ -d /usr/share/themes/PiXnoir ]] && GTK_THEME_NAME="Adwaita-dark"
GTK_SETTINGS="$HOME/.config/gtk-3.0/settings.ini"
mkdir -p "$(dirname "$GTK_SETTINGS")"
if [[ ! -f "$GTK_SETTINGS" ]]; then
printf '%s\n' '[Settings]' 'gtk-application-prefer-dark-theme=1' "gtk-theme-name=$GTK_THEME_NAME" > "$GTK_SETTINGS"
else
log "WARNING: wlr-randr not found or no output"
grep -q '^gtk-application-prefer-dark-theme=' "$GTK_SETTINGS" && sed -i 's/^gtk-application-prefer-dark-theme=.*/gtk-application-prefer-dark-theme=1/' "$GTK_SETTINGS" || echo 'gtk-application-prefer-dark-theme=1' >> "$GTK_SETTINGS"
grep -q '^gtk-theme-name=' "$GTK_SETTINGS" && sed -i "s/^gtk-theme-name=.*/gtk-theme-name=$GTK_THEME_NAME/" "$GTK_SETTINGS" || echo "gtk-theme-name=$GTK_THEME_NAME" >> "$GTK_SETTINGS"
fi
log "Set dark theme ($GTK_THEME_NAME) in gtk-3.0/settings.ini"
log "removing one-shot desktop and script"
rm -f "$HOME/.config/autostart/${BASE}.desktop" "$HOME/${BASE}.sh"

View File

@@ -0,0 +1,73 @@
# Taskbar (start menu) icon
The icon you see in the taskbar that opens the application menu is the **start-here** icon from the current icon theme. On Raspberry Pi OS with rpd-labwc (wf-panel-pi + wfplug-menu), that icon is resolved by name: **`start-here`** in the **places** context.
On the default PiXtrix theme, `start-here` is a symlink to the Raspberry Pi logo (`rpi.png`). To show a different icon, replace **start-here** with your own image in the same theme (or in a custom theme that overrides it).
---
## How to change it
### Option 1: Replace on the device (one-off)
After first-boot, SSH in and replace the icon files. The panel uses **PiXtrix** by default; start-here there is under **places**:
- Paths: `/usr/share/icons/PiXtrix/<size>/places/start-here.png`
- Sizes present on Raspberry Pi OS: **16, 24, 32, 48, 64, 96** (and optionally 22 for legacy).
**Steps (as root):**
```bash
# Backup originals (currently symlinks to rpi.png)
for s in 16 24 32 48 64 96; do
[ -L /usr/share/icons/PiXtrix/${s}x${s}/places/start-here.png ] && \
cp -P /usr/share/icons/PiXtrix/${s}x${s}/places/start-here.png /usr/share/icons/PiXtrix/${s}x${s}/places/start-here.png.bak
done
# Replace with your PNG (one size e.g. 32x32 then scale for others, or use a scalable SVG and generate PNGs)
# Example: copy your icon to 32x32 (panel default icon_size is 32)
cp /path/to/your-icon.png /usr/share/icons/PiXtrix/32x32/places/start-here.png
# Remove symlink first if it was a link:
rm -f /usr/share/icons/PiXtrix/32x32/places/start-here.png
cp /path/to/your-icon.png /usr/share/icons/PiXtrix/32x32/places/start-here.png
# Repeat for other sizes, or use ImageMagick to scale:
for s in 16 24 48 64 96; do
convert /path/to/your-icon.png -resize ${s}x${s} /usr/share/icons/PiXtrix/${s}x${s}/places/start-here.png
done
```
Then restart the panel (or log out and back in):
```bash
pkill wf-panel-pi
# Panel is usually restarted by the session; if not, log out and in again.
```
### Option 2: Deploy via first-boot (file server)
**first-boot.sh** (step 05) already does this: if **`start-here.png`** is present in the first-boot folder on the file server (same URL as splash.png, e.g. `http://10.20.50.1:5000/files/first-boot/start-here.png`), it is downloaded and installed as the taskbar start button icon in PiXtrix (all sizes 16, 24, 32, 48, 64, 96). If ImageMagick (`convert`) is installed, the icon is resized per size; otherwise the same image is copied to each size. Place **start-here.png** in your portal first-boot folder (e.g. next to splash.png) and re-provision or run first-boot; no extra config needed.
---
## Specs for the new icon
So that it looks correct in the taskbar and in the menu, use these specs:
| Property | Value |
|----------------|--------|
| **Icon name** | Must be installed as **start-here** (in **places** context) so the panel finds it. |
| **Format** | PNG (preferred for raster), or SVG if you generate PNGs per size. |
| **Sizes** | 16×16, 24×24, 32×32, 48×48, 64×64, 96×96 px (panel default is 32px). |
| **Aspect** | Square (11). The panel shows it in a square cell. |
| **Background** | Transparent (PNG with alpha) so it fits any panel background. |
| **Content** | Simple, recognizable at 1632 px (logo or symbol). Avoid fine detail. |
| **Theme path** | `PiXtrix/<size>x<size>/places/start-here.png` (or override via a custom theme). |
### Recommendation
- **Source asset**: One PNG at **32×32** or **64×64** (or one SVG), then generate the other sizes to avoid scaling artifacts.
- **Design**: High contrast, clear at 2432 px; works on both light and dark panel (or match your panel colour).
- **File server name**: e.g. `taskbar-icon.png` or `start-here.png`; first-boot script would download it and install to the paths above.
If you want, the next step is to add a small script (and optional first-boot wiring) that downloads `taskbar-icon.png` from the file server and installs it as **start-here** in all required sizes.

View File

@@ -0,0 +1,155 @@
# Taskbar (wf-panel-pi) editing and custom theme
You can edit the taskbar to your liking and create a custom theme. The panel is **wf-panel-pi** (GTK3); configuration is in **`~/.config/wf-panel-pi/wf-panel-pi.ini`** and optional **custom CSS** via the **css_path** option.
---
## 1. Editing the taskbar (INI config)
Config file: **`~/.config/wf-panel-pi/wf-panel-pi.ini`** (user `pi`). If the file is empty or missing, the panel uses built-in defaults. Options (from `panel-pi.xml`):
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| **css_path** | string | (empty) | Path to a custom CSS file for the panel (GTK CSS). |
| **widgets_left** | string | `smenu spacing0 spacing4 launchers spacing8 window-list` | Widget names for the left section (space-separated). |
| **widgets_center** | string | `none` | Widgets in the center. |
| **widgets_right** | string | `tray power ejecter updater ... clock ... batt squeek` | Widgets on the right. |
| **icon_size** | int | 32 | Icon size in pixels. |
| **minimal_height** | int | 24 | Panel height (min). |
| **autohide** | bool | false | Hide panel until cursor touches edge. |
| **autohide_duration** | int | 300 | Animation duration (ms) when showing/hiding. |
| **position** | string | top | `top` or `bottom`. |
| **background_color** | string | #EDECEBFF | Panel background (ARGB hex). |
| **layer** | string | bottom | `top`, `bottom`, `overlay`, `background`. |
| **monitor** | string | 0 | Monitor index. |
| **edge_offset** | int | 20 | Pixels from edge to trigger autohide. |
| **gestures_touch_only** | bool | false | Restrict gestures to touch. |
### Widget names (for widgets_left / _center / _right)
- **Left:** `smenu` (start menu), `spacing0``spacing8` (spacers), `launchers`, `window-list`
- **Right:** `tray`, `power`, `ejecter`, `updater`, `connect`, `bluetooth`, `netman`, `volumepulse`, `clock`, `batt`, `squeek`, plus `spacing2` etc.
Example: minimal left (only menu + window list), right (clock + tray only):
```ini
[panel]
widgets_left = smenu spacing4 window-list
widgets_center = none
widgets_right = spacing2 clock spacing2 tray
icon_size = 28
minimal_height = 28
position = bottom
background_color = #2D2D2DFF
```
Save as `~/.config/wf-panel-pi/wf-panel-pi.ini` for user `pi`, then restart the panel: `pkill wf-panel-pi` (session will respawn it, or log out/in).
---
## 2. Custom theme (CSS + INI)
The panel supports **GTK 3 CSS** via **css_path**. You can:
1. Set **css_path** in `wf-panel-pi.ini` to a full path to your `.css` file (e.g. `~/.config/wf-panel-pi/panel-theme.css`).
2. Use GTK CSS to style the panel window and its children (colors, borders, font, padding, etc.).
### INI
```ini
[panel]
css_path = /home/pi/.config/wf-panel-pi/panel-theme.css
background_color = #1E1E1EFF
icon_size = 28
minimal_height = 28
```
### Example CSS (panel-theme.css)
GTK panel often uses a single top-level window; you can target it and inner boxes. Example (dark, rounded, with padding):
```css
/* Custom taskbar theme dark, subtle border */
window {
background-color: transparent;
}
/* Main panel box */
window box {
background-color: rgba(30, 30, 30, 0.95);
border-radius: 12px;
margin: 4px;
padding: 2px 8px;
border: 1px solid rgba(255, 255, 255, 0.08);
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.4);
}
/* Buttons / plugin containers */
button,
button:hover,
button:active {
background: transparent;
border: none;
border-radius: 6px;
padding: 4px;
color: #e0e0e0;
}
button:hover {
background: rgba(255, 255, 255, 0.08);
}
/* Labels (e.g. clock) */
label {
color: #e0e0e0;
font-size: 11pt;
}
```
Paths: use an **absolute path** in **css_path** (e.g. `/home/pi/.config/wf-panel-pi/panel-theme.css`). Expand `~` yourself when writing the INI (the panel may not expand it).
---
## 3. Deploying a custom theme via first-boot
To apply a custom taskbar theme on every provisioned device:
1. **On the file server** (e.g. first-boot folder): add:
- **wf-panel-pi.ini** INI with your `[panel]` options and `css_path` pointing to the CSS file path on the device.
- **panel-theme.css** your GTK CSS.
2. **In first-boot** (or a one-shot script): for user `pi`:
- Create `~/.config/wf-panel-pi/` if needed.
- Copy or download **wf-panel-pi.ini** to `~/.config/wf-panel-pi/wf-panel-pi.ini`.
- Copy or download **panel-theme.css** to e.g. `~/.config/wf-panel-pi/panel-theme.css`.
- In the INI, set `css_path = /home/pi/.config/wf-panel-pi/panel-theme.css` (or use `$PI_HOME` in the script).
- `chown -R pi:pi ~/.config/wf-panel-pi`.
3. **Restart panel** after first login (or rely on next login): `pkill wf-panel-pi` (optional in script; session often restarts it).
Example first-boot snippet (run as root, after `$PI_HOME` is set):
```bash
PANEL_CONF="$PI_HOME/.config/wf-panel-pi"
mkdir -p "$PANEL_CONF"
curl -fsSL "${FILE_SERVER}/wf-panel-pi.ini" -o "$PANEL_CONF/wf-panel-pi.ini"
curl -fsSL "${FILE_SERVER}/panel-theme.css" -o "$PANEL_CONF/panel-theme.css"
sed -i "s|/home/pi|$PI_HOME|g" "$PANEL_CONF/wf-panel-pi.ini"
chown -R "$PI_USER:$PI_USER" "$PANEL_CONF"
```
Ensure the INI uses the same path as where you save the CSS (e.g. `css_path = /home/pi/.config/wf-panel-pi/panel-theme.css` or `$PI_HOME/...` if you substitute in the script).
**Example theme files** in this repo: `config-files/wf-panel-pi.ini` and `config-files/panel-theme.css` (dark, rounded panel). Host them on the file server and deploy with the snippet above.
---
## 4. Summary
| Goal | Where | How |
|------|--------|-----|
| Change layout (widgets, position, size) | `~/.config/wf-panel-pi/wf-panel-pi.ini` | Edit `[panel]` options. |
| Change colors / style | Same INI + custom CSS | Set **css_path** and write GTK CSS. |
| Custom theme on all devices | File server + first-boot | Deploy **wf-panel-pi.ini** and **panel-theme.css** and copy to `~/.config/wf-panel-pi/` for `pi`. |
After any change, restart the panel (`pkill wf-panel-pi`) or log out and back in so the new theme is applied.

View File

@@ -8,5 +8,7 @@ first-boot.sh downloads these from `FILE_SERVER` (e.g. `http://10.20.50.1:5000/f
| 99-wallpaper.conf | /etc/lightdm/lightdm.conf.d/99-wallpaper.conf |
| 99-default-session.conf | /etc/lightdm/lightdm.conf.d/99-default-session.conf (rpd-labwc) |
| maliit-keyboard.desktop | /home/pi/.config/autostart/maliit-keyboard.desktop |
| 01-set-rotation-once.desktop | /home/pi/.config/autostart/01-set-rotation-once.desktop (with 01-set-rotation-once.sh) |
| 01-set-rotation-once.desktop | /home/pi/.config/autostart/01-set-rotation-once.desktop (with 01-set-rotation-once.sh; writes kanshi config + dark theme) |
| 02-set-wallpaper-once.desktop | /home/pi/.config/autostart/02-set-wallpaper-once.desktop (with 02-set-wallpaper-once.sh). Wallpaper is also set during first-boot via pcmanfm. |
| wf-panel-pi.ini | Optional: /home/pi/.config/wf-panel-pi/wf-panel-pi.ini (custom taskbar layout and css_path). See TASKBAR-THEME.md. |
| panel-theme.css | Optional: /home/pi/.config/wf-panel-pi/panel-theme.css (custom taskbar CSS). Deploy with wf-panel-pi.ini; see TASKBAR-THEME.md. |

View File

@@ -0,0 +1,44 @@
/* Custom wf-panel-pi theme dark, rounded panel
* Place at ~/.config/wf-panel-pi/panel-theme.css
* Set css_path in wf-panel-pi.ini to this file (absolute path).
*/
/* Panel window */
window {
background-color: transparent;
}
/* Main panel box dark with slight rounding and shadow */
window box {
background-color: rgba(45, 45, 45, 0.96);
border-radius: 10px;
margin: 4px;
padding: 2px 8px;
border: 1px solid rgba(255, 255, 255, 0.06);
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.35);
}
/* Plugin / launcher buttons */
button,
button:hover,
button:active {
background: transparent;
border: none;
border-radius: 6px;
padding: 4px;
color: #e0e0e0;
}
button:hover {
background: rgba(255, 255, 255, 0.08);
}
button:active {
background: rgba(255, 255, 255, 0.12);
}
/* Labels (e.g. clock text) */
label {
color: #e0e0e0;
font-size: 11pt;
}

View File

@@ -0,0 +1,21 @@
# wf-panel-pi custom theme example
# Copy to ~/.config/wf-panel-pi/wf-panel-pi.ini (user pi)
# Optional: copy panel-theme.css to ~/.config/wf-panel-pi/panel-theme.css
# and ensure css_path below points to it. Restart panel: pkill wf-panel-pi
[panel]
# Custom CSS (use absolute path; replace /home/pi with actual $PI_HOME if different)
css_path = /home/pi/.config/wf-panel-pi/panel-theme.css
# Layout
widgets_left = smenu spacing0 spacing4 launchers spacing8 window-list
widgets_center = none
widgets_right = tray power ejecter updater spacing2 connect spacing2 bluetooth spacing2 netman spacing2 volumepulse spacing2 clock spacing2 batt spacing2 squeek
# Size and position
icon_size = 28
minimal_height = 28
position = top
# Dark background (ARGB)
background_color = #2D2D2DFF
# Optional: autohide
autohide = false
autohide_duration = 300

View File

@@ -14,7 +14,7 @@ first-boot.sh downloads from **`.../files/first-boot/`** (e.g. `http://10.20.50.
| **99-wallpaper.conf** | LightDM greeter wallpaper (from `config-files/`). |
| **99-default-session.conf** | LightDM default session rpd-labwc (from `config-files/`). |
| **maliit-keyboard.desktop** | Maliit on-screen keyboard autostart (from `config-files/`). |
| **01-set-rotation-once.sh** + **.desktop** | One-shot: wlr-randr rotation (Left) at first login. |
| **01-set-rotation-once.sh** + **.desktop** | One-shot: writes ~/.config/kanshi/config with rotation from cmdline and sets GTK dark theme at first login. |
Desktop wallpaper is set once during first-boot via pcmanfm config (first-boot.sh). Optional one-shot: **02-set-wallpaper-once.sh**.

View File

@@ -42,7 +42,8 @@
# WALLPAPER_MODE="crop"
# --- Display (reTerminal DM) ---
# Kernel cmdline: DSI rotation. 90 = 90° clockwise; use 180 or 270 for other orientations.
# Kernel cmdline: DSI rotation. 90 = 90° clockwise; 180 or 270 for other orientations.
# At login, ~/.config/kanshi/config is written with this transform (same as Control Center).
# DSI_ROTATE="270"
# Kernel cmdline: swiotlb size (for vc4-drm/DSI). Leave empty to skip.

View File

@@ -62,7 +62,7 @@ Installs the software needed for the rest of the script and for the kiosk:
| **wmctrl** | Window control; used to force Chromium into fullscreen. |
| **openssh-server** | SSH access (often also enabled in user-data). |
| **swaybg** | Wallpaper for labwc (Wayland); used by one-shot and labwc autostart. |
| **wlr-randr** | Display rotation for wlroots/labwc; one-shot sets “Left” (transform 270). |
| **kanshi** | Display rotation: ~/.config/kanshi/config is written at login with transform from cmdline (same as Control Center). The same login scripts also set GTK dark theme (~/.config/gtk-3.0/settings.ini). |
| **maliit-keyboard** | On-screen keyboard for touch input. |
| **xinput-calibrator** | Touchscreen calibration (optional; run manually if needed). |
@@ -84,7 +84,7 @@ Downloads from `FILE_SERVER` (no local creation):
Ensure the `.desktop` file on the server has `Exec=/home/pi/start-chromium.sh` (or the path you use on the device).
**Touch in Chromium:** Long-press on the touchscreen to open the context menu (right-click). This works when Chromium runs as a Wayland client (default under rpd-labwc). If you ever run under pure X11, long-press may not trigger the context menu; in that case you can use **evdev-right-click-emulation** (see e.g. [evdev-right-click-emulation](https://github.com/PeterCxy/evdev-right-click-emulation)) to inject right-click on long-press at the input layer.
**Touch long-press → right-click in Chromium:** Under Wayland (rpd-labwc), long-press may work for right-click elsewhere (e.g. desktop) but **not inside Chromium**—Chromium gets touch events directly and does not implement long-press-as-right-click. To get context menu on long-press in the browser (and everywhere), use **evdev-right-click-emulation** at the input layer so long-press is converted to right-click before any app sees it: [evdev-right-click-emulation](https://github.com/PeterCxy/evdev-right-click-emulation). Build, install the binary (e.g. to `/usr/local/bin/evdev-rce`), and run it as a systemd service at boot (works on both X11 and Wayland).
---
@@ -134,7 +134,7 @@ The reTerminal DM default is portrait. Rotation is set **persistently** via the
- **Kernel cmdline** — First-boot appends **`video=DSI-1:rotate=90`** to **`/boot/firmware/cmdline.txt`** (or `/boot/cmdline.txt`). The file must remain **one single line** with no line breaks.
- **90° clockwise** — The value `90` gives 90° clockwise rotation. Other valid values: `180`, `270` (90° counter-clockwise).
- **Effect** — Rotation is applied by the kernel at boot; no one-shot script or wlr-randr needed.
- **Effect** — Kernel cmdline rotates at boot; at login ~/.config/kanshi/config is written with the same transform (kanshi applies it; same as Control Center).
---

View File

@@ -134,8 +134,26 @@ step_02_packages() {
log "Packages installed successfully"
}
# --- Step 03: Kiosk files from file server ---
step_03_kiosk_files() {
# --- Step 03: reTerminal DM drivers (Seeed) ---
step_03_reterminal_drivers() {
if [[ -z "$RETERMINAL_REPO_URL" ]]; then
log "Skipping reTerminal drivers (RETERMINAL_REPO_URL not set)"
return 0
fi
REPO_DIR="/tmp/seeed-linux-dtoverlays"
log "Cloning seeed-linux-dtoverlays to $REPO_DIR ..."
git clone --depth 1 "$RETERMINAL_REPO_URL" "$REPO_DIR"
log "Running reTerminal.sh --device $RETERMINAL_DEVICE from $REPO_DIR ..."
if ( cd "$REPO_DIR" && "$REPO_DIR/scripts/reTerminal.sh" --device "$RETERMINAL_DEVICE" ); then
log "reTerminal DM drivers installed (reboot will apply)"
else
log "WARNING: reTerminal.sh failed (see log above). Display/touch may still work; you can retry later with: cd $REPO_DIR && sudo ./scripts/reTerminal.sh --device $RETERMINAL_DEVICE"
fi
rm -rf "$REPO_DIR"
}
# --- Step 04: Kiosk files from file server ---
step_04_kiosk_files() {
log "Creating $AUTOSTART"
mkdir -p "$AUTOSTART"
log "Downloading start-chromium.sh from ${FILE_SERVER}/start-chromium.sh"
@@ -147,8 +165,8 @@ step_03_kiosk_files() {
log "Kiosk files installed under $PI_HOME and $AUTOSTART"
}
# --- Step 04: Boot splash and wallpaper ---
step_04_splash_wallpaper() {
# --- Step 05: Boot splash and wallpaper ---
step_05_splash_wallpaper() {
log "Creating $PLYMOUTH_DIR and /usr/share/rpd-wallpaper"
mkdir -p "$PLYMOUTH_DIR" /usr/share/rpd-wallpaper
if curl -fsSL "${FILE_SERVER}/splash.png" -o "$PLYMOUTH_DIR/splash.png"; then
@@ -183,10 +201,32 @@ step_04_splash_wallpaper() {
else
log "WARNING: Could not download splash.png"
fi
# Optional: taskbar start button icon from file server (start-here.png)
if curl -fsSL "${FILE_SERVER}/start-here.png" -o /tmp/start-here.png; then
PIXTRIX_PLACES="/usr/share/icons/PiXtrix"
if [[ -d "$PIXTRIX_PLACES/32x32/places" ]]; then
for s in 16 24 32 48 64 96; do
DEST="$PIXTRIX_PLACES/${s}x${s}/places/start-here.png"
if [[ -d "$(dirname "$DEST")" ]]; then
rm -f "$DEST"
if command -v convert >/dev/null 2>&1; then
convert /tmp/start-here.png -resize "${s}x${s}" "$DEST" 2>/dev/null && true
else
cp /tmp/start-here.png "$DEST"
fi
chmod 644 "$DEST"
fi
done
log "Taskbar start button icon (start-here.png) installed from file server"
else
log "WARNING: PiXtrix theme places dir not found; skipped taskbar icon"
fi
rm -f /tmp/start-here.png
fi
}
# --- Step 05: LightDM session ---
step_05_lightdm() {
# --- Step 06: LightDM session ---
step_06_lightdm() {
mkdir -p /etc/lightdm/lightdm.conf.d
if curl -fsSL "${FILE_SERVER}/99-default-session.conf" -o /etc/lightdm/lightdm.conf.d/99-default-session.conf 2>/dev/null; then
log "99-default-session.conf installed"
@@ -198,16 +238,36 @@ step_05_lightdm() {
sed -i "s/^autologin-session=.*/autologin-session=$LIGHTDM_SESSION/" /etc/lightdm/lightdm.conf
log "Patched /etc/lightdm/lightdm.conf to use $LIGHTDM_SESSION"
fi
# Delay LightDM on first boot after provisioning so reTerminal DM DSI panel has time to init (avoids black screen on first reboot)
mkdir -p /etc/systemd/system/lightdm.service.d
cat > /etc/systemd/system/cm4-await-display.service << 'AWAITSVC'
[Unit]
Description=Wait for reTerminal DM display on first boot after provisioning
Before=lightdm.service
DefaultDependencies=no
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/bin/sh -c 'if [ -f /var/lib/cm4-provisioning/await-display ]; then echo "Waiting 18s for DSI panel..."; sleep 18; rm -f /var/lib/cm4-provisioning/await-display; fi'
[Install]
WantedBy=graphical.target
AWAITSVC
printf '%s\n' '[Unit]' 'After=cm4-await-display.service' > /etc/systemd/system/lightdm.service.d/99-await-display.conf
systemctl daemon-reload
systemctl enable cm4-await-display.service 2>/dev/null || true
log "Installed cm4-await-display.service (delays LightDM on first reboot after provisioning)"
}
# --- Step 06: Maliit on-screen keyboard ---
step_06_maliit() {
# --- Step 07: Maliit on-screen keyboard ---
step_07_maliit() {
mkdir -p "$AUTOSTART" "$PI_HOME/.config"
curl -fsSL "${FILE_SERVER}/maliit-keyboard.desktop" -o "$AUTOSTART/maliit-keyboard.desktop" 2>/dev/null && log "maliit-keyboard.desktop installed" || log "WARNING: Could not download maliit-keyboard.desktop"
}
# --- Step 07: Dark theme (GTK) ---
step_07_dark_theme() {
# --- Step 08: Dark theme (GTK) ---
step_08_dark_theme() {
GTK_SETTINGS="$PI_HOME/.config/gtk-3.0/settings.ini"
mkdir -p "$(dirname "$GTK_SETTINGS")"
if [[ ! -f "$GTK_SETTINGS" ]]; then
@@ -220,24 +280,6 @@ step_07_dark_theme() {
chown -R "$PI_USER:$PI_USER" "$PI_HOME/.config"
}
# --- Step 08: reTerminal DM drivers (Seeed) ---
step_08_reterminal_drivers() {
if [[ -z "$RETERMINAL_REPO_URL" ]]; then
log "Skipping reTerminal drivers (RETERMINAL_REPO_URL not set)"
return 0
fi
REPO_DIR="/tmp/seeed-linux-dtoverlays"
log "Cloning seeed-linux-dtoverlays to $REPO_DIR ..."
git clone --depth 1 "$RETERMINAL_REPO_URL" "$REPO_DIR"
log "Running reTerminal.sh --device $RETERMINAL_DEVICE from $REPO_DIR ..."
if ( cd "$REPO_DIR" && "$REPO_DIR/scripts/reTerminal.sh" --device "$RETERMINAL_DEVICE" ); then
log "reTerminal DM drivers installed (reboot will apply)"
else
log "WARNING: reTerminal.sh failed (see log above). Display/touch may still work; you can retry later with: cd $REPO_DIR && sudo ./scripts/reTerminal.sh --device $RETERMINAL_DEVICE"
fi
rm -rf "$REPO_DIR"
}
# --- Step 09: Re-apply splash and Plymouth theme ---
step_09_reapply_splash() {
CFG_PATH="/boot/firmware/config.txt"
@@ -277,6 +319,17 @@ step_10_cmdline() {
step_11_oneshots() {
if [[ -n "$DSI_ROTATE" ]]; then
log "Rotation is set via kernel cmdline (video=DSI-1:rotate=$DSI_ROTATE)"
# Install set-rotation-at-login to write ~/.config/kanshi/config at every login (same as Control Center)
if curl -fsSL "${FILE_SERVER}/set-rotation-at-login.sh" -o "$PI_HOME/set-rotation-at-login.sh" 2>/dev/null; then
chmod 755 "$PI_HOME/set-rotation-at-login.sh"
chown "$PI_USER:$PI_USER" "$PI_HOME/set-rotation-at-login.sh"
if curl -fsSL "${FILE_SERVER}/set-rotation-at-login.desktop" -o /tmp/set-rotation-at-login.desktop 2>/dev/null; then
sed "s|/home/pi|$PI_HOME|g" /tmp/set-rotation-at-login.desktop > "$AUTOSTART/set-rotation-at-login.desktop"
chown "$PI_USER:$PI_USER" "$AUTOSTART/set-rotation-at-login.desktop"
log "Installed set-rotation-at-login (re-applies rotation from cmdline every login)"
fi
rm -f /tmp/set-rotation-at-login.desktop
fi
fi
if [[ -n "$ONESHOT_SCRIPTS" ]]; then
for _name in $ONESHOT_SCRIPTS; do
@@ -298,6 +351,9 @@ step_13_reboot() {
DEVICE_IP="$(hostname -I 2>/dev/null | awk '{print $1}')"
report_status "done" "First-boot complete" "13" "reboot" "$DEVICE_IP"
log "Device IP: ${DEVICE_IP:-unknown}"
# Flag for cm4-await-display.service: on next boot delay LightDM so DSI panel can init (avoids black screen)
mkdir -p /var/lib/cm4-provisioning
touch /var/lib/cm4-provisioning/await-display
log "=== first-boot.sh finished, rebooting ==="
reboot
}
@@ -305,12 +361,12 @@ step_13_reboot() {
# --- Main: run steps in order ---
run_step 01 hostname
run_step 02 packages
run_step 03 kiosk_files
run_step 04 splash_wallpaper
run_step 05 lightdm
run_step 06 maliit
run_step 07 dark_theme
run_step 08 reterminal_drivers
run_step 03 reterminal_drivers
run_step 04 kiosk_files
run_step 05 splash_wallpaper
run_step 06 lightdm
run_step 07 maliit
run_step 08 dark_theme
run_step 09 reapply_splash
run_step 10 cmdline
run_step 11 oneshots

View File

@@ -1,13 +1,31 @@
#!/bin/bash
# Set reTerminal DM (labwc/Wayland) rotation to Left at every login.
# Runs from autostart when user pi logs in; does not remove itself.
# Use this when wlr-randr transform does not persist across reboots.
sleep 5
OUTPUT=""
if command -v wlr-randr &>/dev/null; then
OUTPUT=$(wlr-randr 2>/dev/null | awk '/^[A-Za-z0-9_-]+ /{print $1; exit}')
fi
[[ -z "$OUTPUT" ]] && OUTPUT="DSI-1"
if [[ -n "$OUTPUT" ]] && command -v wlr-randr &>/dev/null; then
wlr-randr --output "$OUTPUT" --transform 270
# Set screen rotation via kanshi (same as Control Center). Reads video=DSI-1:rotate=N
# from kernel cmdline and writes ~/.config/kanshi/config. Kanshi auto-reloads when the file changes.
# Also sets GTK dark theme (PiXnoir / Adwaita-dark). Runs from autostart when user pi logs in; does not remove itself.
ROTATE="270"
for f in /boot/firmware/cmdline.txt /boot/cmdline.txt; do
[[ -f "$f" ]] || continue
val=$(grep -o 'video=DSI-1:rotate=[0-9]*' "$f" 2>/dev/null | head -1)
val="${val#*rotate=}"
[[ "$val" =~ ^(90|180|270)$ ]] && ROTATE="$val" && break
done
KANSHI_DIR="$HOME/.config/kanshi"
KANSHI_CONFIG="$KANSHI_DIR/config"
mkdir -p "$KANSHI_DIR"
cat > "$KANSHI_CONFIG" << EOF
profile {
output DSI-1 enable scale 1.000000 mode 800x1280@60.000 position 0,0 transform $ROTATE
}
EOF
# Set GTK dark theme (same as first-boot step 08)
GTK_THEME_NAME="PiXnoir"
[[ -d /usr/share/themes/Adwaita-dark ]] && ! [[ -d /usr/share/themes/PiXnoir ]] && GTK_THEME_NAME="Adwaita-dark"
GTK_SETTINGS="$HOME/.config/gtk-3.0/settings.ini"
mkdir -p "$(dirname "$GTK_SETTINGS")"
if [[ ! -f "$GTK_SETTINGS" ]]; then
printf '%s\n' '[Settings]' 'gtk-application-prefer-dark-theme=1' "gtk-theme-name=$GTK_THEME_NAME" > "$GTK_SETTINGS"
else
grep -q '^gtk-application-prefer-dark-theme=' "$GTK_SETTINGS" && sed -i 's/^gtk-application-prefer-dark-theme=.*/gtk-application-prefer-dark-theme=1/' "$GTK_SETTINGS" || echo 'gtk-application-prefer-dark-theme=1' >> "$GTK_SETTINGS"
grep -q '^gtk-theme-name=' "$GTK_SETTINGS" && sed -i "s/^gtk-theme-name=.*/gtk-theme-name=$GTK_THEME_NAME/" "$GTK_SETTINGS" || echo "gtk-theme-name=$GTK_THEME_NAME" >> "$GTK_SETTINGS"
fi

View File

@@ -1,56 +1,42 @@
#!/bin/bash
# Start Chromium in app mode. Optional env vars:
# CHROMIUM_APP_URL - URL to open (default: http://127.0.0.1:8080)
# CHROMIUM_MODE - "fullscreen" or "kiosk" (default: fullscreen)
#
# Touch long-press → right-click: In Chromium on Wayland, long-press often does *not*
# open the context menu (Chromium handles touch itself). Elsewhere (e.g. desktop) it may
# work. For long-press right-click *inside* Chromium, use evdev-right-click-emulation
# at the input layer so all apps (including Chromium) receive real right-click events:
# https://github.com/PeterCxy/evdev-right-click-emulation
#
# Disable keyring prompts
export GNOME_KEYRING_CONTROL=""
# Prefer Wayland when available so touch long-press produces right-click (context menu)
# like the rest of the desktop. X11/XWayland does not get that behavior for Chromium.
USE_WAYLAND=0
if [ -n "$WAYLAND_DISPLAY" ] && [ -S "${XDG_RUNTIME_DIR:-/run/user/$(id -u)}/$WAYLAND_DISPLAY" ]; then
USE_WAYLAND=1
fi
# Wayland + labwc compositor.
export GDK_BACKEND=wayland
# Wait for compositor
for i in {1..60}; do
if [ -S "${XDG_RUNTIME_DIR:-/run/user/$(id -u)}/$WAYLAND_DISPLAY" ]; then
pgrep -x labwc >/dev/null 2>&1 && break
fi
sleep 0.5
done
# URL to open in Chromium (app mode)
#CHROMIUM_APP_URL="${CHROMIUM_APP_URL:-http://127.0.0.1:8080}"
CHROMIUM_APP_URL="${CHROMIUM_APP_URL:-https://tototheo.com}"
if [ "$USE_WAYLAND" -eq 1 ]; then
# Native Wayland: fullscreen + touch-friendly (long-press = right-click)
export GDK_BACKEND=wayland
# Wait for compositor
for i in {1..60}; do
if [ -S "${XDG_RUNTIME_DIR:-/run/user/$(id -u)}/$WAYLAND_DISPLAY" ]; then
pgrep -x labwc >/dev/null 2>&1 && break
fi
sleep 0.5
done
sleep 3
/usr/bin/chromium --start-fullscreen --noerrdialogs --disable-infobars --disable-session-crashed-bubble --disable-restore-session-state --no-first-run --password-store=basic --use-mock-keychain --ozone-platform=wayland --enable-features=WaylandWindowDecorations --disable-features=UseChromeOSDirectVideoDecoder --app=http://127.0.0.1:8080 &
else
# Fallback: X11 (e.g. no Wayland session)
export DISPLAY=:0
export GDK_BACKEND=x11
unset WAYLAND_DISPLAY
for i in {1..60}; do
if xset q >/dev/null 2>&1 || [ -n "$DISPLAY" ]; then
if pgrep -x pcmanfm >/dev/null 2>&1 || pgrep -x lxsession >/dev/null 2>&1 || pgrep -x xfdesktop >/dev/null 2>&1; then
break
fi
fi
sleep 0.5
done
sleep 5
/usr/bin/chromium --start-fullscreen --noerrdialogs --disable-infobars --disable-session-crashed-bubble --disable-restore-session-state --no-first-run --password-store=basic --use-mock-keychain --ozone-platform=x11 --disable-features=UseChromeOSDirectVideoDecoder --app=http://127.0.0.1:8080 &
sleep 3
for i in {1..10}; do
WINDOW_ID=$(wmctrl -l 2>/dev/null | grep -i chromium | head -1 | awk '{print $1}')
if [ -n "$WINDOW_ID" ]; then
wmctrl -i -r "$WINDOW_ID" -b add,fullscreen 2>/dev/null
break
fi
sleep 0.5
done
fi
# Mode: "fullscreen" or "kiosk"
CHROMIUM_MODE="${CHROMIUM_MODE:-fullscreen}"
CHROMIUM_OPTS="--noerrdialogs --disable-infobars --disable-session-crashed-bubble --disable-restore-session-state --no-first-run --password-store=basic --use-mock-keychain --ozone-platform=wayland --enable-features=WaylandWindowDecorations --disable-features=UseChromeOSDirectVideoDecoder --app=${CHROMIUM_APP_URL}"
case "${CHROMIUM_MODE}" in
kiosk) CHROMIUM_OPTS="--kiosk ${CHROMIUM_OPTS}" ;;
*) CHROMIUM_OPTS="--start-fullscreen ${CHROMIUM_OPTS}" ;;
esac
sleep 3
/usr/bin/chromium $CHROMIUM_OPTS &
# Keep script running
wait
# Kiosk mode (commented out - uncomment to use instead of fullscreen)
# /usr/bin/chromium --kiosk --noerrdialogs --disable-infobars --disable-session-crashed-bubble --disable-restore-session-state --no-first-run --password-store=basic --use-mock-keychain --ozone-platform=x11 --app=http://127.0.0.1:8080