diff --git a/backend/display.py b/backend/display.py index 7747cdc..f5c79e2 100644 --- a/backend/display.py +++ b/backend/display.py @@ -187,6 +187,8 @@ class ManagedGuiApp: pass return + # Maximize the window to fill the Xvfb display and activate it + await self._maximize_window() log.info("Capture loop started for app %s window %d", self.app_id, self.window_id) while self.alive: @@ -357,6 +359,25 @@ class ManagedGuiApp: grandchildren.extend(ManagedGuiApp._get_descendant_pids(cpid)) return children + grandchildren + async def _maximize_window(self): + """Activate the window, resize it to fill the Xvfb display, and move to origin.""" + if not self.window_id or not XDOTOOL_BIN: + return + env = self._display_env() + wid = str(self.window_id) + try: + # Activate (focus) the window + await self._xdotool("windowactivate", "--sync", wid, env=env) + # Move to origin + await self._xdotool("windowmove", "--sync", wid, "0", "0", env=env) + # Resize to fill display (Xvfb is 1280x1024) + await self._xdotool("windowsize", "--sync", wid, "1280", "1024", env=env) + # Some apps need a moment to redraw after resize + await asyncio.sleep(0.3) + log.debug("Maximized window %s to 1280x1024 for %s", wid, self.app_id) + except Exception as e: + log.debug("Failed to maximize window %s: %s", wid, e) + async def _xdotool_search(self, *args, env=None) -> Optional[int]: """Run xdotool search and return first window ID, or None.""" try: @@ -399,6 +420,7 @@ class ManagedGuiApp: if action == "click": btn = str(msg.get("button", 1)) await self._xdotool( + "windowactivate", "--sync", wid, "mousemove", "--window", wid, x, y, "click", "--window", wid, btn, env=env, @@ -406,6 +428,7 @@ class ManagedGuiApp: elif action == "dblclick": btn = str(msg.get("button", 1)) await self._xdotool( + "windowactivate", "--sync", wid, "mousemove", "--window", wid, x, y, "click", "--window", wid, "--repeat", "2", btn, env=env, @@ -449,7 +472,11 @@ class ManagedGuiApp: wid = str(self.window_id) if action == "press": - await self._xdotool("key", "--window", wid, xkey, env=env) + await self._xdotool( + "windowfocus", "--sync", wid, + "key", "--window", wid, xkey, + env=env, + ) # release events handled implicitly by xdotool key async def _xdotool(self, *args, env=None): diff --git a/frontend/css/apps/display.css b/frontend/css/apps/display.css index 42ed64b..e96886e 100644 --- a/frontend/css/apps/display.css +++ b/frontend/css/apps/display.css @@ -9,18 +9,17 @@ .gui-canvas-wrap { flex: 1; display: flex; - align-items: center; - justify-content: center; overflow: hidden; position: relative; } .gui-canvas { - max-width: 100%; - max-height: 100%; + width: 100%; + height: 100%; cursor: default; outline: none; image-rendering: auto; + object-fit: contain; } /* Status overlays */