diff --git a/src/main.py b/src/main.py index e12c681..0a48a3d 100644 --- a/src/main.py +++ b/src/main.py @@ -1,10 +1,7 @@ -import atexit import os # App-capture typelib path (built via meson in src/window/switcher/app-capture/builddir) # Must be set before gi is imported so the typelib search path includes it. -# Note: LD_LIBRARY_PATH does not take effect in the current process, so the -# .so is preloaded via ctypes in window/switcher/main.py instead. _app_capture_builddir = os.path.join( os.path.dirname(__file__), "window", "switcher", "app-capture", "builddir" ) @@ -18,18 +15,11 @@ if os.path.isdir(_app_capture_builddir): from fabric import Application from fabric.utils import get_relative_path, logger, monitor_file -for log in [ - "fabric", - "services", - "window", - "utils", - "window.globalmenu", -]: - logger.disable(log) - +from services.config import config from services.keyboard_layout import KeyboardLayout from shared.data import APP_NAME, load_config from utils.functions import set_process_name +from utils.gtk_utils import generate_colors_from_wallpaper from window.desktop.widget import Deskwidgets from window.dock import Dock from window.lock import LockScreenWrapper @@ -42,25 +32,19 @@ from window.spotlight.main import SpotlightWindow from window.switcher import ApplicationSwitcher -def main(): - - # Generate colors.css if it doesn't exist - colors_css_path = get_relative_path("styles/colors.css") - if not os.path.exists(colors_css_path): - from utils.gtk_utils import generate_colors_from_wallpaper - - default_wallpaper = get_relative_path("assets/wallpaper_example/example-1.png") - if os.path.exists(default_wallpaper): - generate_colors_from_wallpaper(default_wallpaper) - - set_process_name(APP_NAME) - - load_config() - - from services.config import config +def setup_logger(): + for log in [ + "fabric", + "services", + "window", + "utils", + "window.globalmenu", + "LIBDBUSMENU-GLIB", + "libdbusmenu-glib", + ]: + logger.disable(log) _debug = config().get("debug", False) - if not _debug: logger.disable("modus_plugin_builtin_emoji") else: @@ -70,6 +54,48 @@ def main(): logger.enable("utils") logger.enable("window.globalmenu") + +def setup_css(app): + # Generate colors.css if it doesn't exist + colors_css_path = get_relative_path("styles/colors.css") + if not os.path.exists(colors_css_path): + default_wallpaper = get_relative_path("assets/wallpaper_example/example-1.png") + if os.path.exists(default_wallpaper): + generate_colors_from_wallpaper(default_wallpaper) + + def set_css(): + app.set_stylesheet_from_file(get_relative_path("styles/main.css")) + + app.set_css = set_css + app.set_css() + + css_monitors = [] + for root, dirs, files in os.walk(get_relative_path("styles/")): + monitor = monitor_file(root) + monitor.connect("changed", lambda *_: set_css()) + css_monitors.append(monitor) + + def cleanup_css_monitors(*args): + for m in css_monitors: + try: + m.cancel() + except Exception as e: + logger.warning(f"[main] m.cancel() failed: {e}") + + app.connect("shutdown", cleanup_css_monitors) + + +def main(): + set_process_name(APP_NAME) + load_config() + setup_logger() + + # Initialize the Application first so it can manage styles globally + app = Application(f"{APP_NAME}") + + # Set up styling before creating windows to prevent unstyled flashes + setup_css(app) + switcher = ApplicationSwitcher() panel = Panel() modusnoti = ModusNoti() @@ -81,15 +107,8 @@ def main(): screencapture = ScreenCaptureWindow() settings = get_settings_window() - # Monitor CSS files and subdirectories for changes - css_monitors = [] - for root, dirs, files in os.walk(get_relative_path("styles/")): - monitor = monitor_file(root) - monitor.connect("changed", lambda *_: set_css()) - css_monitors.append(monitor) - - app = Application( - f"{APP_NAME}", + # Register windows with the application + for w in [ panel, modusnoti, deskwidget.top_left, @@ -99,25 +118,10 @@ def main(): dock, screencapture, spotlight, - ) - - def set_css(): - app.set_stylesheet_from_file(get_relative_path("styles/main.css")) - - app.set_css = set_css - app.set_css() - - def cleanup_css_monitors(): - for m in css_monitors: - try: - m.cancel() - except Exception as e: - logger.warning(f"[main] m.cancel() failed: {e}") - - atexit.register(cleanup_css_monitors) + ]: + app.add_window(w) # Inject into the executing module's namespace (__main__) - # to emulate what happened when this file was run directly. # This allows fabric-cli exec to execute commands flawlessly. import __main__ diff --git a/start.py b/start.py index 30720a7..77817bf 100644 --- a/start.py +++ b/start.py @@ -1,66 +1,72 @@ import os import sys -# Ensure the 'src' directory is in the python path -# This allows 'import main' and other src-relative imports to work from the root -src_path = os.path.join(os.path.dirname(__file__), "src") -if src_path not in sys.path: - sys.path.insert(0, src_path) -# App-capture library paths (built via meson in src/window/switcher/app-capture/builddir) -_app_capture_builddir = os.path.join( - src_path, "window", "switcher", "app-capture", "builddir" -) -if os.path.isdir(_app_capture_builddir): - for env_var in ("GI_TYPELIB_PATH", "LD_LIBRARY_PATH"): - current = os.environ.get(env_var, "") - if _app_capture_builddir not in current.split(os.pathsep): - os.environ[env_var] = ( - f"{_app_capture_builddir}{os.pathsep}{current}" - if current - else _app_capture_builddir - ) +def setup_environment(): + """Ensure the src directory is in sys.path and configure C library paths.""" + src_path = os.path.join(os.path.dirname(__file__), "src") + if src_path not in sys.path: + sys.path.insert(0, src_path) + + # App-capture library paths (built via meson in src/window/switcher/app-capture/builddir) + app_capture_builddir = os.path.join( + src_path, "window", "switcher", "app-capture", "builddir" + ) + + if os.path.isdir(app_capture_builddir): + for env_var in ("GI_TYPELIB_PATH", "LD_LIBRARY_PATH"): + current = os.environ.get(env_var, "") + if app_capture_builddir not in current.split(os.pathsep): + os.environ[env_var] = ( + f"{app_capture_builddir}{os.pathsep}{current}" + if current + else app_capture_builddir + ) -# Apply monkey patch for hyprland lua dispatcher def run_app(): + """Start the main Modus application.""" from main import main as app_main app_main() def run_lock(): + """Start the lock screen.""" from window.lock import main as lock_main lock_main() def run_spotlight(argv): + """Start the spotlight search interface.""" from window.spotlight.app import main as spotlight_main - command = "" - text = "" - external = False + external = "--external" in argv + positional = [arg for arg in argv if arg != "--external"] - positional = [] - for arg in argv: - if arg == "--external": - external = True - else: - positional.append(arg) - - if positional: - command = positional[0] - if len(positional) > 1: - text = " ".join(positional[1:]) + command = positional[0] if positional else "" + text = " ".join(positional[1:]) if len(positional) > 1 else "" spotlight_main(command=command, text=text, external=external) +def main(): + setup_environment() + + # Route the command based on arguments + if len(sys.argv) > 1: + command = sys.argv[1] + if command == "lock": + run_lock() + return + elif command == "spotlight": + run_spotlight(sys.argv[2:]) + return + + # Default to running the main app + run_app() + + if __name__ == "__main__": - if len(sys.argv) > 1 and sys.argv[1] == "lock": - run_lock() - elif len(sys.argv) > 1 and sys.argv[1] == "spotlight": - run_spotlight(sys.argv[2:]) - else: - run_app() + main()