Wait for configured buffers before resizing
6d7f2ee7f873bb2ccfd1de6ccc2b26040662f9a5
Open an image in imv while it is tiled: the window can flicker between two sizes and briefly expose the wallpaper. imv acknowledges a configure before attaching the matching buffer, so swm was treating pixels from the old buffer as the resize result. Keep the requested geometry pending until a commit contains the configured buffer.
1 parent
c22e5b90
swm.c
+7 -0
| 2257 | 2257 | if (c->decoration) |
|
| 2258 | 2258 | request_decoration_mode(&c->set_decoration_mode, c->decoration); |
|
| 2259 | 2259 | wlr_xdg_toplevel_set_size(c->surface.xdg->toplevel, 0, 0); |
|
| 2260 | 2260 | return; |
|
| 2261 | 2261 | } |
|
| 2262 | + | /* A configure acknowledgement may be committed before the client attaches |
|
| 2263 | + | * the matching buffer. Keep the pending layout geometry until pixels for |
|
| 2264 | + | * that configure arrive; otherwise the old buffer can trigger a resize |
|
| 2265 | + | * loop between its dimensions and the requested dimensions. */ |
|
| 2266 | + | if (c->resize && |
|
| 2267 | + | !(client_surface(c)->current.committed & WLR_SURFACE_STATE_BUFFER)) |
|
| 2268 | + | return; |
|
| 2262 | 2269 | old_geom = c->geom; |
|
| 2263 | 2270 | ||
| 2264 | 2271 | /* Floating applications may choose their own size. Applications may also |
|
| 2265 | 2272 | * round a compositor-requested size. Match the frame to the committed |
|
| 2266 | 2273 | * window geometry in both cases. */ |
test/clients.py
+43 -0
| 199 | 199 | self.toplevel.destroy() |
|
| 200 | 200 | self.xdg_surface.destroy() |
|
| 201 | 201 | self.surface.destroy() |
|
| 202 | 202 | ||
| 203 | 203 | ||
| 204 | + | class DeferredConfigureWindow(Window): |
|
| 205 | + | """A window which acknowledges post-map configures before drawing them.""" |
|
| 206 | + | ||
| 207 | + | def __init__(self, *args, **kwargs): |
|
| 208 | + | self.mapped = False |
|
| 209 | + | self.deferred = False |
|
| 210 | + | super().__init__(*args, **kwargs) |
|
| 211 | + | ||
| 212 | + | def _surface_configure(self, proxy, serial: int) -> None: |
|
| 213 | + | proxy.ack_configure(serial) |
|
| 214 | + | if self.mapped: |
|
| 215 | + | self.surface.commit() |
|
| 216 | + | self.deferred = True |
|
| 217 | + | else: |
|
| 218 | + | self.draw() |
|
| 219 | + | self.mapped = True |
|
| 220 | + | ||
| 221 | + | ||
| 222 | + | def xdg_deferred_configure(arguments: list[str]) -> None: |
|
| 223 | + | """Acknowledge a tiled resize before attaching its matching buffer.""" |
|
| 224 | + | ||
| 225 | + | if arguments: |
|
| 226 | + | raise Failure("xdg-deferred-configure takes no arguments") |
|
| 227 | + | connection = Connection(WlCompositor, WlShm, XdgWmBase) |
|
| 228 | + | window = DeferredConfigureWindow( |
|
| 229 | + | connection, |
|
| 230 | + | "deferred-configure", |
|
| 231 | + | 0xFF8844AA, |
|
| 232 | + | report=Path(os.environ["SWM_CLIENT_REPORT"]), |
|
| 233 | + | ) |
|
| 234 | + | while window.running: |
|
| 235 | + | connection.display.dispatch(block=True) |
|
| 236 | + | if window.deferred: |
|
| 237 | + | window.deferred = False |
|
| 238 | + | time.sleep(0.05) |
|
| 239 | + | window.draw() |
|
| 240 | + | connection.display.flush() |
|
| 241 | + | window.destroy() |
|
| 242 | + | connection.close() |
|
| 243 | + | ||
| 244 | + | ||
| 245 | + | ||
| 204 | 246 | def xdg_client(arguments: list[str]) -> None: |
|
| 205 | 247 | """Run one persistent XDG window.""" |
|
| 206 | 248 | ||
| 207 | 249 | color = int(arguments[0], 16) if arguments else 0xFF336699 |
|
| 208 | 250 | title = arguments[1] if len(arguments) > 1 else "swm-test" |
| 1030 | 1072 | connection.disconnect() |
|
| 1031 | 1073 | ||
| 1032 | 1074 | ||
| 1033 | 1075 | ROLES = { |
|
| 1034 | 1076 | "xdg": xdg_client, |
|
| 1077 | + | "xdg-deferred-configure": xdg_deferred_configure, |
|
| 1035 | 1078 | "xdg-resize": xdg_resize, |
|
| 1036 | 1079 | "xdg-lifecycle": xdg_lifecycle, |
|
| 1037 | 1080 | "transient": transient, |
|
| 1038 | 1081 | "keyboard": keyboard, |
|
| 1039 | 1082 | "pointer": pointer, |
test/run.py
+26 -0
| 371 | 371 | virtual_keyboard(36) |
|
| 372 | 372 | wait_title("two" if before == "one" else "one") |
|
| 373 | 373 | ||
| 374 | 374 | test("window publication and focus", publication) |
|
| 375 | 375 | ||
| 376 | + | def deferred_configure() -> None: |
|
| 377 | + | report = Path(os.environ["SWM_TEST_DIR"]) / "deferred-configure.geometry" |
|
| 378 | + | env = os.environ.copy() |
|
| 379 | + | env["SWM_CLIENT_REPORT"] = str(report) |
|
| 380 | + | client = spawn( |
|
| 381 | + | client_log("deferred-configure"), |
|
| 382 | + | *client_command("xdg-deferred-configure"), |
|
| 383 | + | env=env, |
|
| 384 | + | ) |
|
| 385 | + | wait_title("deferred-configure") |
|
| 386 | + | eventually( |
|
| 387 | + | "deferred configure buffer", |
|
| 388 | + | lambda: report.exists() and report.stat().st_size, |
|
| 389 | + | ) |
|
| 390 | + | settled = eventually( |
|
| 391 | + | "settled deferred configure geometry", |
|
| 392 | + | lambda: published_geometry("deferred-configure"), |
|
| 393 | + | ) |
|
| 394 | + | consistently( |
|
| 395 | + | "stable deferred configure geometry", |
|
| 396 | + | lambda: published_geometry("deferred-configure") == settled, |
|
| 397 | + | ) |
|
| 398 | + | terminate(client) |
|
| 399 | + | ||
| 400 | + | test("configure acknowledgement before buffer", deferred_configure) |
|
| 401 | + | ||
| 376 | 402 | def client_resize() -> None: |
|
| 377 | 403 | report = Path(os.environ["SWM_TEST_DIR"]) / "client-resize.geometry" |
|
| 378 | 404 | trigger = Path(os.environ["SWM_TEST_DIR"]) / "client-resize.trigger" |
|
| 379 | 405 | committed = Path(os.environ["SWM_TEST_DIR"]) / "client-resize.committed" |
|
| 380 | 406 | env = os.environ.copy() |