Splash + Layout-Skip-Revert
User-Bug: Layout-Skip-Optimierung war zu aggressiv — Mac Rhino haelt die Panel-Anordnung zwischen Sessions doch nicht im internen State, also wurden Panels falsch platziert nach Quick-Restart. Skip-Logik raus, der ~3s _-WindowLayout-Apply laeuft wieder jedes Mal. Das ist OK weil der Splash diese Wartezeit jetzt optisch abdeckt. Splash verbessert: - _try_borderless_mac(): direkter NSWindow-Zugriff via Eto.ControlObject + ObjC-Methoden (setStyleMask_, setOpaque_, setHasShadow_, setBackgroundColor_, setMovableByWindowBackground_) — produziert echten borderless Mac-Look wie der Launcher-Splash - Form-BackgroundColor auf transparent damit das gradient des WebView- HTMLs durchscheint (rounded petrol gradient mit weichem Verlauf) - WebView selber transparenter Hintergrund - Closeable/Minimizable/Maximizable/Resizable alle False - [SPLASH] visible log fuer Debug-Sichtbarkeit
This commit is contained in:
+79
-12
@@ -83,41 +83,97 @@ html, body { margin:0; padding:0; width:100%; height:100%; background:transparen
|
|||||||
'''
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
def _try_borderless_mac(form):
|
||||||
|
"""Mac-spezifisch: direkter NSWindow-Zugriff via Eto.ControlObject um
|
||||||
|
titlebar/Decorations komplett zu killen + rounded corners zu setzen.
|
||||||
|
Auf Mac ist Eto.Forms.Form.WindowStyle.None inkonsistent — der echte
|
||||||
|
Borderless-Effekt geht nur ueber AppKit. Probiert verschiedene Wege,
|
||||||
|
keiner ist fatal wenn er nicht klappt."""
|
||||||
|
nswindow = None
|
||||||
|
try:
|
||||||
|
# Eto auf Mac: Form.ControlObject ist die NSWindow-Instanz
|
||||||
|
nswindow = getattr(form, "ControlObject", None)
|
||||||
|
except Exception: pass
|
||||||
|
if nswindow is None: return False
|
||||||
|
|
||||||
|
# NSBorderlessWindowMask = 0, NSFullSizeContentViewWindowMask = 1<<15
|
||||||
|
# NSWindowStyleMaskTitled = 1
|
||||||
|
BORDERLESS = 0
|
||||||
|
FULL_SIZE = 1 << 15
|
||||||
|
|
||||||
|
def _try(method_name, *args):
|
||||||
|
try:
|
||||||
|
m = getattr(nswindow, method_name, None)
|
||||||
|
if m is None: return False
|
||||||
|
m(*args)
|
||||||
|
return True
|
||||||
|
except Exception: return False
|
||||||
|
|
||||||
|
ok = False
|
||||||
|
# 1) Style-Mask auf borderless (entfernt Titlebar/Border)
|
||||||
|
if _try("setStyleMask_", BORDERLESS):
|
||||||
|
ok = True
|
||||||
|
# 2) Hintergrund transparent damit WebView's eigene rounded box scheint
|
||||||
|
if _try("setOpaque_", False): ok = True
|
||||||
|
if _try("setHasShadow_", True): ok = True
|
||||||
|
# 3) Background color clear
|
||||||
|
try:
|
||||||
|
from AppKit import NSColor as _NSColor # type: ignore
|
||||||
|
clear = _NSColor.clearColor()
|
||||||
|
if _try("setBackgroundColor_", clear): ok = True
|
||||||
|
except Exception: pass
|
||||||
|
# 4) Bewegbar via background-drag
|
||||||
|
if _try("setMovableByWindowBackground_", True): ok = True
|
||||||
|
return ok
|
||||||
|
|
||||||
|
|
||||||
def show():
|
def show():
|
||||||
"""Zeigt den Splash. Idempotent — zweiter Aufruf bringt das bestehende
|
"""Zeigt den Splash. Idempotent — zweiter Aufruf bringt das bestehende
|
||||||
Fenster nur in den Vordergrund. Auto-Hide nach _SAFETY_TIMEOUT_SEC
|
Fenster nur in den Vordergrund. Auto-Hide nach _SAFETY_TIMEOUT_SEC
|
||||||
als Fallback falls hide() vergessen wird."""
|
als Fallback falls hide() vergessen wird."""
|
||||||
if sc.sticky.get(_SPLASH_KEY) is not None:
|
if sc.sticky.get(_SPLASH_KEY) is not None:
|
||||||
return
|
print("[SPLASH] schon offen — skip"); return
|
||||||
try:
|
try:
|
||||||
import Eto.Forms as ef
|
import Eto.Forms as ef
|
||||||
import Eto.Drawing as ed
|
import Eto.Drawing as ed
|
||||||
|
except Exception as ex:
|
||||||
|
print("[SPLASH] Eto-Import:", ex); return
|
||||||
|
try:
|
||||||
form = ef.Form()
|
form = ef.Form()
|
||||||
form.Title = "Dossier"
|
form.Title = "" # leerer Titel hilft bei Mac-Titlebar-Reduktion
|
||||||
# WindowStyle.None — "None" ist Python-keyword, daher via getattr
|
# Versuche WindowStyle.None (Eto-API, funktioniert nicht immer auf Mac)
|
||||||
try: form.WindowStyle = getattr(ef.WindowStyle, "None")
|
try: form.WindowStyle = getattr(ef.WindowStyle, "None")
|
||||||
except Exception: pass
|
except Exception: pass
|
||||||
try: form.Resizable = False
|
# Alle Window-Chrome-Optionen aus
|
||||||
except Exception: pass
|
for attr, val in (
|
||||||
try: form.Topmost = True
|
("Resizable", False), ("Minimizable", False),
|
||||||
except Exception: pass
|
("Maximizable", False), ("Closeable", False),
|
||||||
try: form.ShowInTaskbar = False
|
("ShowInTaskbar", False), ("Topmost", True),
|
||||||
|
):
|
||||||
|
try: setattr(form, attr, val)
|
||||||
except Exception: pass
|
except Exception: pass
|
||||||
try: form.Size = ed.Size(420, 160)
|
try: form.Size = ed.Size(420, 160)
|
||||||
except Exception: pass
|
except Exception: pass
|
||||||
|
# Transparent so dass WebView's eigene rounded gradient sichtbar wird
|
||||||
try:
|
try:
|
||||||
# Hintergrund weiss, das WebView-content hat seine eigene
|
form.BackgroundColor = ed.Colors.Transparent
|
||||||
# gerundete Petrol-Box — Form muss nur kein graues Border zeigen
|
except Exception:
|
||||||
form.BackgroundColor = ed.Color(0.18, 0.50, 0.45)
|
try: form.BackgroundColor = ed.Color(0.37, 0.66, 0.59)
|
||||||
except Exception: pass
|
except Exception: pass
|
||||||
|
|
||||||
wv = ef.WebView()
|
wv = ef.WebView()
|
||||||
|
try:
|
||||||
|
# WebView selber transparent damit das Form-Hintergrund durchscheint
|
||||||
|
wv.BackgroundColor = ed.Colors.Transparent
|
||||||
|
except Exception: pass
|
||||||
try:
|
try:
|
||||||
wv.LoadHtml(_SPLASH_HTML)
|
wv.LoadHtml(_SPLASH_HTML)
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
print("[SPLASH] LoadHtml:", ex)
|
print("[SPLASH] LoadHtml:", ex)
|
||||||
form.Content = wv
|
form.Content = wv
|
||||||
try:
|
|
||||||
# Center on screen
|
# Center on screen
|
||||||
|
try:
|
||||||
screen = ef.Screen.PrimaryScreen
|
screen = ef.Screen.PrimaryScreen
|
||||||
sb = screen.Bounds
|
sb = screen.Bounds
|
||||||
x = int(sb.X + (sb.Width - form.Size.Width) / 2)
|
x = int(sb.X + (sb.Width - form.Size.Width) / 2)
|
||||||
@@ -125,10 +181,21 @@ def show():
|
|||||||
form.Location = ed.Point(x, y)
|
form.Location = ed.Point(x, y)
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
print("[SPLASH] center:", ex)
|
print("[SPLASH] center:", ex)
|
||||||
|
|
||||||
try: form.Show()
|
try: form.Show()
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
print("[SPLASH] Show:", ex); return
|
print("[SPLASH] Show:", ex); return
|
||||||
|
|
||||||
|
# Mac-spezifischer Borderless-Hack — MUSS nach Show() laufen damit
|
||||||
|
# die NSWindow existiert
|
||||||
|
try:
|
||||||
|
if _try_borderless_mac(form):
|
||||||
|
print("[SPLASH] Borderless (Mac NSWindow) angewendet")
|
||||||
|
except Exception as ex:
|
||||||
|
print("[SPLASH] borderless-mac:", ex)
|
||||||
|
|
||||||
sc.sticky[_SPLASH_KEY] = form
|
sc.sticky[_SPLASH_KEY] = form
|
||||||
|
print("[SPLASH] visible")
|
||||||
# Safety-Timeout — wenn nach 8s niemand hide() ruft, automatisch weg
|
# Safety-Timeout — wenn nach 8s niemand hide() ruft, automatisch weg
|
||||||
try:
|
try:
|
||||||
import threading
|
import threading
|
||||||
|
|||||||
+4
-13
@@ -1353,26 +1353,17 @@ class OberleisteBridge(panel_base.BaseBridge):
|
|||||||
# Default-Window-Layout anwenden, wenn aktiviert und noch nicht in
|
# Default-Window-Layout anwenden, wenn aktiviert und noch nicht in
|
||||||
# DIESER Rhino-Session geschehen (sticky-flag = process-lifetime).
|
# DIESER Rhino-Session geschehen (sticky-flag = process-lifetime).
|
||||||
# Mac Rhino persistiert die Window-Anordnung zwischen Sessions
|
# Mac Rhino persistiert die Window-Anordnung zwischen Sessions
|
||||||
# NICHT zuverlaessig — der Cold-Start-Apply lief bisher jedes Mal
|
# NICHT zuverlaessig — der Cold-Start-Apply muss jedes Mal laufen.
|
||||||
# (= ~3s _-WindowLayout RunScript-Blocker).
|
# Die 3s Wartezeit verdeckt jetzt der Splash-Screen optisch.
|
||||||
# Optimierung: Marker-File mit Timestamp + Name. Wenn der letzte
|
|
||||||
# erfolgreiche Apply < 10 min her ist UND derselbe Layout-Name → skip
|
|
||||||
# (Rhino "remembers" wahrscheinlich noch). Bei langem Abstand
|
|
||||||
# (Pause, neuer Tag, Reboot) → apply normal.
|
|
||||||
try:
|
try:
|
||||||
cfg = _settings_load()
|
cfg = _settings_load()
|
||||||
if not sc.sticky.get("_dossier_layout_applied"):
|
if not sc.sticky.get("_dossier_layout_applied"):
|
||||||
layout_name = cfg.get("windowLayout") or cfg.get("defaultLayout")
|
layout_name = cfg.get("windowLayout") or cfg.get("defaultLayout")
|
||||||
if cfg.get("autoApplyLayout") and layout_name:
|
if cfg.get("autoApplyLayout") and layout_name:
|
||||||
sc.sticky["_dossier_layout_applied"] = True
|
sc.sticky["_dossier_layout_applied"] = True
|
||||||
if _is_layout_recently_applied(layout_name, max_age_sec=600):
|
|
||||||
print("[OBERLEISTE] Layout '{}' wurde vor < 10min "
|
|
||||||
"appliziert — skip (~3s gespart). Manuell neu "
|
|
||||||
"anwenden via Oberleiste-Einstellungen wenn noetig.".format(
|
|
||||||
layout_name))
|
|
||||||
else:
|
|
||||||
_apply_window_layout(layout_name)
|
_apply_window_layout(layout_name)
|
||||||
_mark_layout_applied(layout_name)
|
try: _mark_layout_applied(layout_name)
|
||||||
|
except Exception: pass
|
||||||
# Viewport-Colors einmalig pro Session auto-applien (wenn aktiviert)
|
# Viewport-Colors einmalig pro Session auto-applien (wenn aktiviert)
|
||||||
if (cfg.get("autoApplyViewColors") and
|
if (cfg.get("autoApplyViewColors") and
|
||||||
not sc.sticky.get("_dossier_view_colors_applied")):
|
not sc.sticky.get("_dossier_view_colors_applied")):
|
||||||
|
|||||||
Reference in New Issue
Block a user