#!/usr/bin/env python """ Djarea Desktop — PyWebView + Django local RPC. Starts a local Django ASGI server and opens a native desktop window. All communication between the UI and backend uses Djarea server functions. """ import os import sys import threading import time os.environ.setdefault("DJANGO_SETTINGS_MODULE", "backend.settings") # Work around Qt WebEngine GPU crashes on some systems os.environ.setdefault("QTWEBENGINE_CHROMIUM_FLAGS", "--disable-gpu") def start_server(host: str, port: int): """Start the Django ASGI server in a background thread.""" import django django.setup() # Run migrations on first launch from django.core.management import call_command call_command("migrate", "--run-syncdb", verbosity=0) import uvicorn uvicorn.run( "backend.asgi:application", host=host, port=port, log_level="warning", ) def wait_for_server(url: str, timeout: float = 10.0): """Poll until the server responds.""" from urllib.request import urlopen from urllib.error import URLError deadline = time.time() + timeout while time.time() < deadline: try: urlopen(url, timeout=1) return True except (URLError, OSError): time.sleep(0.1) return False def main(): host = "127.0.0.1" port = 8765 # Start Django in a daemon thread server = threading.Thread(target=start_server, args=(host, port), daemon=True) server.start() base_url = f"http://{host}:{port}" if not wait_for_server(f"{base_url}/api/djarea/session/"): print("ERROR: Django server failed to start", file=sys.stderr) sys.exit(1) print(f"Backend running at {base_url}") # Check if --headless flag is passed (for testing) if "--headless" in sys.argv: print("Headless mode — server running. Press Ctrl+C to stop.") try: while True: time.sleep(1) except KeyboardInterrupt: pass return # Open native window import webview window = webview.create_window( title="Djarea Desktop", url=base_url, width=1024, height=768, min_size=(640, 480), ) webview.start() if __name__ == "__main__": main()