feat: reserve classroom shell and restore dock interaction
This commit is contained in:
@@ -13,3 +13,6 @@ exec --no-startup-id /usr/local/bin/classroom-dock
|
|||||||
# Additional classroom controls are added explicitly by Ekklesia Classroom.
|
# Additional classroom controls are added explicitly by Ekklesia Classroom.
|
||||||
|
|
||||||
include /etc/sway/config.d/*
|
include /etc/sway/config.d/*
|
||||||
|
|
||||||
|
# Minimize focused window to scratchpad
|
||||||
|
bindsym $mod+m move container to workspace __ekklesia_hidden
|
||||||
|
|||||||
@@ -1,11 +1,44 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
|
||||||
if pgrep -x chrome >/dev/null || pgrep -x google-chrome >/dev/null; then
|
APP_ID='google-chrome'
|
||||||
swaymsg '[app_id="google-chrome"] focus' >/dev/null 2>&1 || true
|
HIDDEN_WS='__ekklesia_hidden'
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
exec google-chrome \
|
if ! pgrep -x chrome >/dev/null 2>&1 &&
|
||||||
|
! pgrep -x google-chrome >/dev/null 2>&1; then
|
||||||
|
exec google-chrome \
|
||||||
--ozone-platform=wayland \
|
--ozone-platform=wayland \
|
||||||
--start-maximized \
|
--start-maximized \
|
||||||
https://app.wonderink.org/
|
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
|
||||||
|
|
||||||
|
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
|
||||||
|
|||||||
+128
-100
@@ -1,6 +1,7 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
import subprocess
|
import subprocess
|
||||||
|
from datetime import datetime
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
import gi
|
import gi
|
||||||
@@ -48,10 +49,7 @@ def enabled(config, key, default=False):
|
|||||||
|
|
||||||
|
|
||||||
def launch(command):
|
def launch(command):
|
||||||
subprocess.Popen(
|
subprocess.Popen(command, start_new_session=True)
|
||||||
command,
|
|
||||||
start_new_session=True,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def notify(title, message):
|
def notify(title, message):
|
||||||
@@ -68,7 +66,10 @@ def themed_icon(*names):
|
|||||||
|
|
||||||
for name in names:
|
for name in names:
|
||||||
if theme.has_icon(name):
|
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(
|
return Gtk.Image.new_from_icon_name(
|
||||||
"application-x-executable",
|
"application-x-executable",
|
||||||
@@ -79,21 +80,23 @@ def themed_icon(*names):
|
|||||||
def custom_icon(filename, size):
|
def custom_icon(filename, size):
|
||||||
path = ICON_DIR / filename
|
path = ICON_DIR / filename
|
||||||
|
|
||||||
if path.exists():
|
if not path.exists():
|
||||||
|
return None
|
||||||
|
|
||||||
pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_scale(
|
pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_scale(
|
||||||
str(path),
|
str(path),
|
||||||
size,
|
size,
|
||||||
size,
|
size,
|
||||||
True,
|
True,
|
||||||
)
|
)
|
||||||
|
|
||||||
return Gtk.Image.new_from_pixbuf(pixbuf)
|
return Gtk.Image.new_from_pixbuf(pixbuf)
|
||||||
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
class ClassroomShell(Gtk.Window):
|
||||||
class ClassroomDock(Gtk.Window):
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
screen = self.get_screen()
|
screen = self.get_screen()
|
||||||
visual = screen.get_rgba_visual()
|
visual = screen.get_rgba_visual()
|
||||||
|
|
||||||
@@ -101,29 +104,83 @@ class ClassroomDock(Gtk.Window):
|
|||||||
self.set_visual(visual)
|
self.set_visual(visual)
|
||||||
|
|
||||||
self.set_app_paintable(True)
|
self.set_app_paintable(True)
|
||||||
self.config = read_device_config()
|
self.set_name("classroom-shell")
|
||||||
|
|
||||||
self.set_name("classroom-dock")
|
|
||||||
self.set_decorated(False)
|
self.set_decorated(False)
|
||||||
self.set_resizable(False)
|
self.set_resizable(False)
|
||||||
|
|
||||||
|
self.config = read_device_config()
|
||||||
|
|
||||||
GtkLayerShell.init_for_window(self)
|
GtkLayerShell.init_for_window(self)
|
||||||
GtkLayerShell.set_layer(self, GtkLayerShell.Layer.TOP)
|
GtkLayerShell.set_layer(
|
||||||
|
self,
|
||||||
|
GtkLayerShell.Layer.TOP,
|
||||||
|
)
|
||||||
|
|
||||||
GtkLayerShell.set_anchor(
|
GtkLayerShell.set_anchor(
|
||||||
self,
|
self,
|
||||||
GtkLayerShell.Edge.BOTTOM,
|
GtkLayerShell.Edge.BOTTOM,
|
||||||
True,
|
True,
|
||||||
)
|
)
|
||||||
|
GtkLayerShell.set_anchor(
|
||||||
GtkLayerShell.set_margin(
|
|
||||||
self,
|
self,
|
||||||
GtkLayerShell.Edge.BOTTOM,
|
GtkLayerShell.Edge.LEFT,
|
||||||
12,
|
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(
|
dock = Gtk.Box(
|
||||||
orientation=Gtk.Orientation.HORIZONTAL,
|
orientation=Gtk.Orientation.HORIZONTAL,
|
||||||
spacing=10,
|
spacing=10,
|
||||||
@@ -133,7 +190,6 @@ class ClassroomDock(Gtk.Window):
|
|||||||
dock.pack_start(
|
dock.pack_start(
|
||||||
self.make_button(
|
self.make_button(
|
||||||
self.browser_icon(),
|
self.browser_icon(),
|
||||||
"Browser",
|
|
||||||
lambda *_: launch(
|
lambda *_: launch(
|
||||||
["/usr/local/bin/classroom-browser"]
|
["/usr/local/bin/classroom-browser"]
|
||||||
),
|
),
|
||||||
@@ -143,11 +199,14 @@ class ClassroomDock(Gtk.Window):
|
|||||||
0,
|
0,
|
||||||
)
|
)
|
||||||
|
|
||||||
if enabled(self.config, "DVD_ENABLED", False):
|
if enabled(
|
||||||
|
self.config,
|
||||||
|
"DVD_ENABLED",
|
||||||
|
False,
|
||||||
|
):
|
||||||
dock.pack_start(
|
dock.pack_start(
|
||||||
self.make_button(
|
self.make_button(
|
||||||
self.dvd_icon(),
|
self.dvd_icon(),
|
||||||
"DVD",
|
|
||||||
lambda *_: notify(
|
lambda *_: notify(
|
||||||
"DVD",
|
"DVD",
|
||||||
"DVD support is being prepared.",
|
"DVD support is being prepared.",
|
||||||
@@ -161,7 +220,6 @@ class ClassroomDock(Gtk.Window):
|
|||||||
dock.pack_start(
|
dock.pack_start(
|
||||||
self.make_button(
|
self.make_button(
|
||||||
self.sanctuary_icon(),
|
self.sanctuary_icon(),
|
||||||
"Sanctuary",
|
|
||||||
lambda *_: notify(
|
lambda *_: notify(
|
||||||
"Sanctuary",
|
"Sanctuary",
|
||||||
"Sanctuary live view is being prepared.",
|
"Sanctuary live view is being prepared.",
|
||||||
@@ -172,19 +230,42 @@ class ClassroomDock(Gtk.Window):
|
|||||||
0,
|
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):
|
def browser_icon(self):
|
||||||
image = custom_icon("browser.svg", 28)
|
image = custom_icon(
|
||||||
|
"browser.svg",
|
||||||
|
28,
|
||||||
|
)
|
||||||
|
|
||||||
if image is not None:
|
if image is not None:
|
||||||
return image
|
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)
|
image.set_pixel_size(28)
|
||||||
|
|
||||||
return image
|
return image
|
||||||
|
|
||||||
def dvd_icon(self):
|
def dvd_icon(self):
|
||||||
image = custom_icon("dvd.svg", 40)
|
image = custom_icon(
|
||||||
|
"dvd.svg",
|
||||||
|
40,
|
||||||
|
)
|
||||||
|
|
||||||
if image is not None:
|
if image is not None:
|
||||||
return image
|
return image
|
||||||
@@ -194,6 +275,7 @@ class ClassroomDock(Gtk.Window):
|
|||||||
"media-optical",
|
"media-optical",
|
||||||
)
|
)
|
||||||
image.set_pixel_size(28)
|
image.set_pixel_size(28)
|
||||||
|
|
||||||
return image
|
return image
|
||||||
|
|
||||||
def sanctuary_icon(self):
|
def sanctuary_icon(self):
|
||||||
@@ -203,9 +285,16 @@ class ClassroomDock(Gtk.Window):
|
|||||||
False,
|
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:
|
if image is not None:
|
||||||
return image
|
return image
|
||||||
@@ -218,79 +307,18 @@ class ClassroomDock(Gtk.Window):
|
|||||||
|
|
||||||
return image
|
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):
|
def update_time(self):
|
||||||
from datetime import datetime
|
self.clock.set_text(
|
||||||
|
|
||||||
self.label.set_text(
|
|
||||||
datetime.now().strftime("%-I:%M %p")
|
datetime.now().strftime("%-I:%M %p")
|
||||||
)
|
)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def load_css():
|
def load_css():
|
||||||
provider = Gtk.CssProvider()
|
provider = Gtk.CssProvider()
|
||||||
provider.load_from_path(str(CSS_FILE))
|
provider.load_from_path(
|
||||||
|
str(CSS_FILE)
|
||||||
|
)
|
||||||
|
|
||||||
screen = Gdk.Screen.get_default()
|
screen = Gdk.Screen.get_default()
|
||||||
|
|
||||||
@@ -304,12 +332,12 @@ def load_css():
|
|||||||
def main():
|
def main():
|
||||||
load_css()
|
load_css()
|
||||||
|
|
||||||
dock = ClassroomDock()
|
shell = ClassroomShell()
|
||||||
dock.connect("destroy", Gtk.main_quit)
|
shell.connect(
|
||||||
dock.show_all()
|
"destroy",
|
||||||
|
Gtk.main_quit,
|
||||||
clock = ClassroomClock()
|
)
|
||||||
clock.show_all()
|
shell.show_all()
|
||||||
|
|
||||||
Gtk.main()
|
Gtk.main()
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user