feat: reserve classroom shell and restore dock interaction

This commit is contained in:
ekklesia
2026-09-02 20:26:12 -05:00
parent 073eda61c8
commit d05f5bf909
4 changed files with 178 additions and 114 deletions
+39 -6
View File
@@ -1,11 +1,44 @@
#!/bin/bash
set -e
if pgrep -x chrome >/dev/null || pgrep -x google-chrome >/dev/null; then
swaymsg '[app_id="google-chrome"] focus' >/dev/null 2>&1 || true
APP_ID='google-chrome'
HIDDEN_WS='__ekklesia_hidden'
if ! pgrep -x chrome >/dev/null 2>&1 &&
! pgrep -x google-chrome >/dev/null 2>&1; then
exec google-chrome \
--ozone-platform=wayland \
--start-maximized \
https://app.wonderink.org/
fi
focused_app="$(
swaymsg -t get_tree -r |
python3 -c '
import json, sys
tree = json.load(sys.stdin)
def find_focused(node):
if node.get("focused"):
return node
for child in node.get("nodes", []) + node.get("floating_nodes", []):
result = find_focused(child)
if result:
return result
return None
node = find_focused(tree)
print((node or {}).get("app_id") or "")
'
)"
if [ "$focused_app" = "$APP_ID" ]; then
swaymsg '[app_id="google-chrome"] move container to workspace __ekklesia_hidden' >/dev/null
exit 0
fi
exec google-chrome \
--ozone-platform=wayland \
--start-maximized \
https://app.wonderink.org/
swaymsg '[app_id="google-chrome"] move container to workspace current' >/dev/null 2>&1 || true
swaymsg '[app_id="google-chrome"] focus' >/dev/null 2>&1 || true
swaymsg '[app_id="google-chrome"] fullscreen disable' >/dev/null 2>&1 || true
swaymsg '[app_id="google-chrome"] floating disable' >/dev/null 2>&1 || true
+135 -107
View File
@@ -1,6 +1,7 @@
#!/usr/bin/env python3
import subprocess
from datetime import datetime
from pathlib import Path
import gi
@@ -48,10 +49,7 @@ def enabled(config, key, default=False):
def launch(command):
subprocess.Popen(
command,
start_new_session=True,
)
subprocess.Popen(command, start_new_session=True)
def notify(title, message):
@@ -68,7 +66,10 @@ def themed_icon(*names):
for name in names:
if theme.has_icon(name):
return Gtk.Image.new_from_icon_name(name, Gtk.IconSize.DIALOG)
return Gtk.Image.new_from_icon_name(
name,
Gtk.IconSize.DIALOG,
)
return Gtk.Image.new_from_icon_name(
"application-x-executable",
@@ -79,21 +80,23 @@ def themed_icon(*names):
def custom_icon(filename, size):
path = ICON_DIR / filename
if path.exists():
pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_scale(
str(path),
size,
size,
True,
)
return Gtk.Image.new_from_pixbuf(pixbuf)
if not path.exists():
return None
return None
pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_scale(
str(path),
size,
size,
True,
)
return Gtk.Image.new_from_pixbuf(pixbuf)
class ClassroomDock(Gtk.Window):
class ClassroomShell(Gtk.Window):
def __init__(self):
super().__init__()
screen = self.get_screen()
visual = screen.get_rgba_visual()
@@ -101,29 +104,83 @@ class ClassroomDock(Gtk.Window):
self.set_visual(visual)
self.set_app_paintable(True)
self.config = read_device_config()
self.set_name("classroom-dock")
self.set_name("classroom-shell")
self.set_decorated(False)
self.set_resizable(False)
self.config = read_device_config()
GtkLayerShell.init_for_window(self)
GtkLayerShell.set_layer(self, GtkLayerShell.Layer.TOP)
GtkLayerShell.set_layer(
self,
GtkLayerShell.Layer.TOP,
)
GtkLayerShell.set_anchor(
self,
GtkLayerShell.Edge.BOTTOM,
True,
)
GtkLayerShell.set_margin(
GtkLayerShell.set_anchor(
self,
GtkLayerShell.Edge.BOTTOM,
12,
GtkLayerShell.Edge.LEFT,
True,
)
GtkLayerShell.set_anchor(
self,
GtkLayerShell.Edge.RIGHT,
True,
)
GtkLayerShell.set_keyboard_interactivity(self, False)
GtkLayerShell.set_exclusive_zone(self, 76)
GtkLayerShell.set_keyboard_interactivity(
self,
False,
)
layout = Gtk.Overlay()
layout.set_size_request(-1, 76)
dock = self.build_dock()
dock_align = Gtk.Alignment(
xalign=0.5,
yalign=0.5,
xscale=0,
yscale=0,
)
dock_align.add(dock)
layout.add(dock_align)
self.clock = Gtk.Label()
self.clock.get_style_context().add_class("clock")
clock_align = Gtk.Alignment(
xalign=1.0,
yalign=0.5,
xscale=0,
yscale=0,
)
clock_align.set_padding(
0,
0,
0,
20,
)
clock_align.add(self.clock)
layout.add_overlay(clock_align)
layout.set_overlay_pass_through(clock_align, True)
self.add(layout)
self.update_time()
GLib.timeout_add_seconds(
15,
self.update_time,
)
def build_dock(self):
dock = Gtk.Box(
orientation=Gtk.Orientation.HORIZONTAL,
spacing=10,
@@ -133,7 +190,6 @@ class ClassroomDock(Gtk.Window):
dock.pack_start(
self.make_button(
self.browser_icon(),
"Browser",
lambda *_: launch(
["/usr/local/bin/classroom-browser"]
),
@@ -143,11 +199,14 @@ class ClassroomDock(Gtk.Window):
0,
)
if enabled(self.config, "DVD_ENABLED", False):
if enabled(
self.config,
"DVD_ENABLED",
False,
):
dock.pack_start(
self.make_button(
self.dvd_icon(),
"DVD",
lambda *_: notify(
"DVD",
"DVD support is being prepared.",
@@ -161,7 +220,6 @@ class ClassroomDock(Gtk.Window):
dock.pack_start(
self.make_button(
self.sanctuary_icon(),
"Sanctuary",
lambda *_: notify(
"Sanctuary",
"Sanctuary live view is being prepared.",
@@ -172,19 +230,42 @@ class ClassroomDock(Gtk.Window):
0,
)
self.add(dock)
return dock
def make_button(self, image, callback):
button = Gtk.Button()
button.set_relief(Gtk.ReliefStyle.NONE)
button.get_style_context().add_class(
"dock-button"
)
button.add(image)
button.connect("clicked", callback)
return button
def browser_icon(self):
image = custom_icon("browser.svg", 28)
image = custom_icon(
"browser.svg",
28,
)
if image is not None:
return image
image = themed_icon("web-browser-symbolic", "internet-web-browser-symbolic")
image = themed_icon(
"web-browser-symbolic",
"internet-web-browser-symbolic",
)
image.set_pixel_size(28)
return image
def dvd_icon(self):
image = custom_icon("dvd.svg", 40)
image = custom_icon(
"dvd.svg",
40,
)
if image is not None:
return image
@@ -194,6 +275,7 @@ class ClassroomDock(Gtk.Window):
"media-optical",
)
image.set_pixel_size(28)
return image
def sanctuary_icon(self):
@@ -203,9 +285,16 @@ class ClassroomDock(Gtk.Window):
False,
)
filename = "live.svg" if is_live else "live-off.svg"
filename = (
"live.svg"
if is_live
else "live-off.svg"
)
image = custom_icon(filename, 38)
image = custom_icon(
filename,
38,
)
if image is not None:
return image
@@ -218,79 +307,18 @@ class ClassroomDock(Gtk.Window):
return image
def make_button(self, image, tooltip, callback):
button = Gtk.Button()
button.set_relief(Gtk.ReliefStyle.NONE)
button.get_style_context().add_class("dock-button")
button.add(image)
button.connect("clicked", callback)
return button
class ClassroomClock(Gtk.Window):
def __init__(self):
super().__init__()
screen = self.get_screen()
visual = screen.get_rgba_visual()
if visual is not None:
self.set_visual(visual)
self.set_app_paintable(True)
self.set_name("classroom-clock")
self.set_decorated(False)
self.set_resizable(False)
GtkLayerShell.init_for_window(self)
GtkLayerShell.set_layer(self, GtkLayerShell.Layer.TOP)
GtkLayerShell.set_anchor(
self,
GtkLayerShell.Edge.BOTTOM,
True,
)
GtkLayerShell.set_anchor(
self,
GtkLayerShell.Edge.RIGHT,
True,
)
GtkLayerShell.set_margin(
self,
GtkLayerShell.Edge.BOTTOM,
16,
)
GtkLayerShell.set_margin(
self,
GtkLayerShell.Edge.RIGHT,
20,
)
GtkLayerShell.set_keyboard_interactivity(self, False)
self.label = Gtk.Label()
self.label.get_style_context().add_class("clock")
self.add(self.label)
self.update_time()
GLib.timeout_add_seconds(15, self.update_time)
def update_time(self):
from datetime import datetime
self.label.set_text(
self.clock.set_text(
datetime.now().strftime("%-I:%M %p")
)
return True
def load_css():
provider = Gtk.CssProvider()
provider.load_from_path(str(CSS_FILE))
provider.load_from_path(
str(CSS_FILE)
)
screen = Gdk.Screen.get_default()
@@ -304,15 +332,15 @@ def load_css():
def main():
load_css()
dock = ClassroomDock()
dock.connect("destroy", Gtk.main_quit)
dock.show_all()
clock = ClassroomClock()
clock.show_all()
shell = ClassroomShell()
shell.connect(
"destroy",
Gtk.main_quit,
)
shell.show_all()
Gtk.main()
if __name__ == "__main__":
main()
main()