Update first-boot configuration and scripts for enhanced kiosk functionality</message>

<message>Modify the first-boot configuration to include the gir1.2-gtklayershell-0.1 package for improved GTK layer shell support. Update the first-boot script to enhance the portal status reporting with connection timeouts. Additionally, implement a restart mechanism for the kanshi service in rotation scripts to ensure immediate application of configuration changes. Introduce a Chromium kiosk extension to disable text selection, improving user experience in kiosk mode. These changes streamline the setup process and enhance the overall functionality of the kiosk environment.
This commit is contained in:
nearxos
2026-02-23 18:07:14 +02:00
parent 25bf710c67
commit c91cf6dd05
15 changed files with 194 additions and 31 deletions

View File

@@ -1,6 +1,8 @@
#!/usr/bin/env python3
# 5 taps in the top-right corner of the screen close Chromium (kiosk).
# Run from session autostart. Requires: python3, PyGObject (Gtk), Wayland or X11.
# Uses wlr-layer-shell to create an overlay surface above all windows (including fullscreen).
# Falls back to a regular GTK window on X11.
# Run from session autostart. Requires: python3, PyGObject (Gtk3), gir1.2-gtklayershell-0.1.
import logging
import subprocess
@@ -23,25 +25,19 @@ except Exception as e:
log.error("need PyGObject Gtk: %s", e)
sys.exit(1)
HAS_LAYER_SHELL = False
try:
gi.require_version("GtkLayerShell", "0.1")
from gi.repository import GtkLayerShell
HAS_LAYER_SHELL = True
except Exception:
log.warning("GtkLayerShell not available, falling back to regular window")
CORNER_SIZE = 80
TAP_WINDOW_SEC = 2.0
CHROMIUM_KILL_CMD = ["pkill", "-f", "chromium"]
def get_screen_size():
display = Gdk.Display.get_default()
if not display:
log.warning("no display found, using fallback 800x1280")
return 800, 1280
monitor = display.get_monitor(0) if display.get_n_monitors() else None
if monitor:
geom = monitor.get_geometry()
log.info("screen size: %dx%d", geom.width, geom.height)
return geom.width, geom.height
log.warning("no monitor found, using fallback 800x1280")
return 800, 1280
def on_button_press(widget, event, data):
count, reset_timer = data
count[0] += 1
@@ -69,6 +65,40 @@ def on_button_press(widget, event, data):
return False
def get_screen_size():
display = Gdk.Display.get_default()
if not display:
log.warning("no display found, using fallback 800x1280")
return 800, 1280
monitor = display.get_monitor(0) if display.get_n_monitors() else None
if monitor:
geom = monitor.get_geometry()
log.info("screen size: %dx%d", geom.width, geom.height)
return geom.width, geom.height
log.warning("no monitor found, using fallback 800x1280")
return 800, 1280
def make_window_layer_shell(win):
"""Anchor an overlay surface to the top-right corner via wlr-layer-shell."""
GtkLayerShell.init_for_window(win)
GtkLayerShell.set_layer(win, GtkLayerShell.Layer.OVERLAY)
GtkLayerShell.set_anchor(win, GtkLayerShell.Edge.TOP, True)
GtkLayerShell.set_anchor(win, GtkLayerShell.Edge.RIGHT, True)
GtkLayerShell.set_keyboard_mode(win, GtkLayerShell.KeyboardMode.NONE)
log.info("layer-shell overlay anchored top-right (%dx%d)", CORNER_SIZE, CORNER_SIZE)
def make_window_fallback(win):
"""X11 fallback: position with move() and hope keep-above works."""
win.set_keep_above(True)
win.realize()
w, _h = get_screen_size()
x = max(0, w - CORNER_SIZE)
win.move(x, 0)
log.info("X11 fallback: window positioned at x=%d y=0", x)
def main():
win = Gtk.Window()
win.set_decorated(False)
@@ -76,27 +106,33 @@ def main():
win.set_default_size(CORNER_SIZE, CORNER_SIZE)
win.set_skip_taskbar_hint(True)
win.set_skip_pager_hint(True)
win.set_keep_above(True)
win.set_opacity(0.01)
win.set_accept_focus(False)
win.set_focus_on_map(False)
# Allow closing from compositor / taskbar
# Make the window nearly invisible
screen = win.get_screen()
visual = screen.get_rgba_visual()
if visual:
win.set_visual(visual)
win.set_app_paintable(True)
win.connect("draw", lambda w, cr: (cr.set_source_rgba(0, 0, 0, 0.01), cr.paint()))
if HAS_LAYER_SHELL and GtkLayerShell.is_supported():
make_window_layer_shell(win)
else:
make_window_fallback(win)
win.connect("destroy", Gtk.main_quit)
# Count 5 taps
count = [0]
reset_timer = [None]
win.connect("button-press-event", on_button_press, (count, reset_timer))
# Touch events often come as button-press with button=1
win.set_events(
win.get_events()
| Gdk.EventMask.BUTTON_PRESS_MASK
| Gdk.EventMask.TOUCH_MASK
)
win.realize()
w, h = get_screen_size()
x = max(0, w - CORNER_SIZE)
win.move(x, 0)
log.info("window %dx%d positioned at x=%d y=0", CORNER_SIZE, CORNER_SIZE, x)
win.show_all()
log.info("listening for taps (5 within %.1fs to kill chromium)", TAP_WINDOW_SEC)
Gtk.main()