diff --git a/src/gui_x/__init__.py b/src/gui_x/__init__.py index 0884ef1..3a41143 100644 --- a/src/gui_x/__init__.py +++ b/src/gui_x/__init__.py @@ -18,8 +18,33 @@ def main(): root = tk.Tk() root.title("Codex Launcher X") - root.geometry("750x1010") - root.minsize(750, 600) + + # Pick a sensible default size based on the display, then center. + # Using a smaller default that fits on every screen (incl. laptops with + # docks/panels) so the UI is never cut off. Launcher is resizable. + try: + sw = root.winfo_screenwidth() + sh = root.winfo_screenheight() + except Exception: + sw, sh = 1920, 1080 + + # Default: 80% of screen, capped to a comfortable max, with a sane + # minimum so it never overflows a small laptop display. + w = min(1400, max(900, int(sw * 0.80))) + h = min(900, max(600, int(sh * 0.85))) + + # Center on screen + x = max(0, (sw - w) // 2) + y = max(0, (sh - h) // 2) + root.geometry(f"{w}x{h}+{x}+{y}") + # Smaller minsize so the window can shrink for tiny displays + root.minsize(720, 520) + + # Force the window to be visible by processing pending geometry events. + # Required on Ubuntu/GNOME where the window otherwise appears as an + # empty grey block until the user clicks. + root.update_idletasks() + root.deiconify() # Apply the X Edition dark theme before creating widgets from gui_x.theme import apply_theme diff --git a/src/gui_x/launcher.py b/src/gui_x/launcher.py index e4e4202..9aa6a93 100644 --- a/src/gui_x/launcher.py +++ b/src/gui_x/launcher.py @@ -200,20 +200,31 @@ def __init__(self, root): recover_config_if_needed() # ── Custom title bar (Linux only) ─────────────────────────── - self._use_custom_titlebar = not IS_WINDOWS - if self._use_custom_titlebar: + # DISABLED: overrideredirect causes Ubuntu/GNOME to render an + # empty grey block because the WM can't track the undecorated + # window's content properly. Using the native decorations + # gives a reliable, visible result on every Linux DE. + self._use_custom_titlebar = False + try: + # Pick a default size that fits every screen (including + # laptops with top bars + docks) and never overflows. + root.update_idletasks() + sw = root.winfo_screenwidth() + sh = root.winfo_screenheight() + # 80% of screen width, capped at 1400 (4K gets same as 1440p) + w = min(1400, max(900, int(sw * 0.80))) + # 85% of screen height, capped at 900 + h = min(900, max(600, int(sh * 0.85))) + x = max(0, (sw - w) // 2) + y = max(0, (sh - h) // 2) + root.geometry(f"{w}x{h}+{x}+{y}") + # Allow the user to shrink further if their display is tiny try: - root.overrideredirect(True) - # Center the window - root.update_idletasks() - sw = root.winfo_screenwidth() - sh = root.winfo_screenheight() - x = (sw - 750) // 2 - y = (sh - 1010) // 2 - root.geometry(f"750x1010+{x}+{y}") + root.minsize(720, 520) except Exception: - self._use_custom_titlebar = False - root.overrideredirect(False) + pass + except Exception: + pass # ── Main container ────────────────────────────────────────── main = tk.Frame(root, bg=self.C["base"]) diff --git a/src/gui_x/titlebar.py b/src/gui_x/titlebar.py index 740d908..37e1a19 100644 --- a/src/gui_x/titlebar.py +++ b/src/gui_x/titlebar.py @@ -91,10 +91,21 @@ def __init__(self, root, version="", **kwargs): self.bind("", self._start_drag) self.bind("", self._on_drag) # Also bind to child labels so dragging works everywhere - for child in self.winfo_children(): - for widget in child.winfo_children(): - widget.bind("", self._start_drag) - widget.bind("", self._on_drag) + # Note: on Python 3.14+, winfo_children() raises TypeError on + # certain widget types — use try/except to skip safely. + try: + for child in self.winfo_children(): + try: + for widget in child.winfo_children(): + try: + widget.bind("", self._start_drag) + widget.bind("", self._on_drag) + except Exception: + pass + except Exception: + pass + except Exception: + pass def _make_control_btn(self, parent, text, command): """Create a window control button (min/max) with hover effect."""