You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Linux (native Wayland): a player now opens its window on the 3D panel by default, keeping the size it opened with, and centred for the size it gets there (#266). Opt out with DisplayXRTargetDisplay.PlaceOnPanelAtStart = false, a DisplayXRTargetDisplay with Move On Start off, or DISPLAYXR_PANEL_PLACEMENT=0.
Windows editor: fixes the editor crash on a second docked Play after a Stop (#428) and the editor not exiting after File > Exit (#429). A docked fixed-aspect Game view (e.g. 16:9 with bars) weaves with the right phase again (#420).
Windows player:DisplayXRTargetDisplay fits the window to the panel after a move to a higher-scale panel, and a full-screen window covers the panel (#266). On the transparent overlay, a drag ends where you release it and keeps following the mouse past the window's edges (#434, #437).
[2.34.0] - 2026-10-29
Changed
Linux native Wayland: the app's window opens on the 3D panel by default (#266). mutter opens a new window on the monitor under the pointer. With a screen-casting tool's virtual "extend" display up and the pointer on it, a DisplayXR app opened there, out of the user's sight; with the pointer on the laptop, it opened on the laptop and stayed 2D. The plug-in now moves the window onto the panel once, at the session's second frame (or when the window is first shown, within 5 s), centred, with the size it opened with. No component is needed.
It stands down when someone placed the window first: the app (displayxr_set_overlay_position, e.g. a saved position it restores, or DisplayXRTargetDisplay), the side-step, or the user (a drag). An app's position after it still wins. A saved position off the panel is still treated as stale (#361).
It does nothing when the window opened on the panel, when the runtime did not confirm a panel (sim display, no 3D display), for a session that starts more than 20 s after launch, for a fullscreen window, or in the editor.
Off: DisplayXRTargetDisplay.PlaceOnPanelAtStart = false before the session's second frame, a DisplayXRTargetDisplay with Move On Start off, or DISPLAYXR_PANEL_PLACEMENT=0 (off, no, false) for a run. The component turns it off from its OnEnable, so only when that runs before the session's second frame: on a GameObject that is inactive then, or in a scene loaded later, set PlaceOnPanelAtStart = false from a [RuntimeInitializeOnLoadMethod] instead (the tooltip and the API docs say so).
X11 / XWayland players, Windows and macOS are unchanged (DisplayXRTargetDisplay opts in there). Native: dxr_prov_place_window_at_start, dxr_wl_place_player_at_start (the Wayland library's ABI goes from 10 in v2.33.0 to 12 in this release, with the at-start move below); the decision is unit-tested (dxr_wl_startup_action in native~/displayxr_linux_wayland_place.h).
Fixed
Windows transparent overlay: a left drag keeps following the mouse past the window's left or top edge (#437).DisplayXRTransparentOverlay read any negative cursor coordinate as "no overlay", because displayxr_get_overlay_pointer wrote -1, -1 for that. A cursor left of or above the window has real negative coordinates, so there the injected Mouse.current state and PointerPosition froze and PointerDelta was zero: a drag-rotate stopped until the cursor came back. Past the right or bottom edge it kept working. displayxr_get_overlay_pointer now returns 1 when it read the cursor and 0 when there is no overlay window (it still writes -1, -1 then, and callers that ignore the return value compile and behave as before). The overlay injects and moves the pointer wherever the cursor is. Its hit test (hover, click, the click-through state) now runs only while the cursor is over the window on all four sides: before, a cursor past the right or bottom edge was still ray-cast, so a press released there could count as a click.
Windows transparent overlay: a left-button release outside the model no longer leaves the drag "pressed" (#434). The overlay takes no capture on a left press, so a release over the desktop or another window went to that window, and the polled button state (displayxr_get_overlay_pointer) kept the button down: a drag-rotate followed the mouse until the next click on the model. A pressed left, right or middle button whose physical button is up, with no button message waiting for the overlay, now reads as released (swapped mouse buttons included). The same clears a release lost to Alt+Tab mid-press. Click-through is unchanged, and so are Linux and macOS.
Editor (Windows): a docked fixed-aspect Game view (e.g. 16:9 with grey bars) weaves with the right phase again (#420). Since 2.33.0 the anchor sat 6-7 px below the render target (the dock's 2 pt bottom border was counted as toolbar, and #421 had removed the term that hid it), and thin top/bottom bars (up to 64 px) were taken as dock chrome (23 px off): inverted stereo on a 300 % panel. Docked anchors, Free Aspect included, now sit on the screen row that shows the render target's row 0, worked out from Unity's own placement rule. Before, they landed from 3 rows above to 3 rows below it, depending on the scale and the pane height: +2 rows on a 300 % main panel (crosstalk in the right view), -1 at 150 % for some widths. Thin left/right bars (up to 64 px) were also taken as dock chrome and centred in pixels, 1-2 px off Unity's placement in X; only the dock's 1 pt side borders count as chrome now, and at 250 % a left/right-barred RT is no longer fitted 2 px narrower than Unity draws it. Maximized and floating placements are unchanged.
Editor (Windows): a maximized fixed-aspect Game view is centred the way Unity places its RT (#420). The glue centred in pixels ((3840-2823)/2 = 508 px) while Unity rounds the target rect to whole points (510 px): 2 px off on a 300 % panel since 2.16.0 (#263).
Linux native Wayland: a window moved onto the 3D panel at start no longer shrinks at every launch (#266, #361). A move onto the panel (DisplayXRTargetDisplay, a saved position the app restores) kept the window's device size. A window that opened on a lower-scale monitor (a 133 % laptop, a casting tool's 100 % virtual display) so got a smaller logical size on a 200 % panel, which the player saved and opened with the next time: 600, 400, 267, 178 px wide over four launches in the harness. A placement made while the window is new (#361's restore window: the first 3 s the app runs with its window shown, see below; not moved by the user) now keeps the logical size the window opened with, as if it had opened there. A size the app asks for (displayxr_resize_overlay) is unaffected; X11, Windows and macOS are unchanged.
Linux native Wayland: the start-up placement keeps the window's size after a slow first frame too (#266, #361). The size rule above applied only within 3 s of the window being shown, so when the session's second frame came later than that (a slow first frame, e.g. shader warm-up), the start-up placement moved the window with its device size and a window that opened on a lower-scale monitor shrank again for that run (harness: 600x480 -> 400x320 logical px with the second frame 4.5 s after the window was shown). The start-up placement now always keeps the logical size the window opened with: it only ever moves a window that neither the app nor the user has placed. DisplayXRTargetDisplay's move at start follows the same rule (below). A saved position the app restores keeps #361's restore window (now counted in the app's running time, below), and a move the app asks for later keeps the device size, as on X11. The rule is unit-tested (dxr_wl_keeps_opening_size).
Linux native Wayland: an app that goes fullscreen before its window is first shown is no longer moved by the start-up placement (#266). A window not shown yet at the session's second frame was decided at its first show, on the Wayland library's worker thread, from the GNOME extension's window report, which does not say whether the window is fullscreen; only the second frame itself was checked. That decision is now taken on the main thread: while the window is not shown, the provider driver asks again every frame, and before each ask it re-checks Screen.fullScreenMode and PlaceOnPanelAtStart, so a fullscreen switch, or an opt-out, made in the meantime keeps the window where it is (harness: an app that went fullscreen in the frame of the second-frame decision was moved onto the panel and, by the plug-in's size keep, set back to windowed; it now stays fullscreen where it opened). The library still decides as of the window's first report (the 5 s limit is unchanged); the decision comes at most one frame later. It needs no new native entry point (dxr_prov_place_window_at_start may be called again while it answers 3).
Linux native Wayland: a window moved onto the 3D panel at start is centred for the size it gets there, and a restored saved position near the panel's edge is judged at that size (#266, #361). The size the window will have on the panel, which centring it there and the stale-saved-position check go by, was still predicted from its device size, while a move at start now keeps its logical size. A window that opened on a lower-scale monitor was so centred for a size it did not get (harness: 600x480 logical px placed at (2200,380) instead of (2100,300) on a 200 % panel at (1440,0) 1920x1080), and a saved position near the panel's edge could be judged on or off the panel at the wrong size. The prediction now follows the move: the logical size when the move keeps it, else the device size at the panel's scale, fitted into 95 % of the panel as the move itself does (dxr_wl_size_after_move, unit-tested). So the start-up placement, DisplayXRTargetDisplay and a stale saved position now put such a window at the panel's centre, not off it. A move is also sized for the monitor the window's centre lands on (where mutter puts it, and the rule the saved-position check uses), not the one under its top-left: a saved position honoured across the panel's edge (its top-left on the laptop, its centre on the panel) was sized for the laptop, then resized for the panel once there, which moved its centre back onto the laptop (dxr_wl_output_for_window, unit-tested).
Linux native Wayland: DisplayXRTargetDisplay's move at start keeps the window's size after a slow first frame too (#266, #361). Its move onto the panel once the session runs kept the logical size the window opened with only within 3 s of the window being shown, so after a slow first frame it kept the device size, and a window that opened on a lower-scale monitor shrank (harness: a 600x504 frame from the 133 % laptop became 400x344 on the 200 % panel, and the player saved 400x320). It now tells the native side that this is its move at start (dxr_prov_move_window_to_display_at_start), and every start-up move follows one rule: while neither the app nor the user has placed the window, it keeps the size the window opened with (dxr_wl_is_start_move, unit-tested). A move the app asks for later (MoveNow, DisplayXRProvider.MoveWindowToDisplay) is unchanged. The Wayland library and the main plug-in must match again (DXR_WL_LIB_ABI 12; v2.33.0 has 10); they always ship together.
Linux native Wayland, mutter's physical layout: a restored saved position across the 3D panel's edge no longer makes the window flap (#266, #361). The monitor a move sizes the window for was picked at the window's current size, while the saved-position check judges a position at the size the window will have on the panel. They differ in the physical layout (stage px = device px: a window from a 100 % monitor is twice as wide on a 200 % panel). A position the check honoured as on the panel was sized for the laptop; partly on the panel, the window got the panel's scale (mutter gives a window across monitors the highest scale of the ones it is on), shrank off the panel, got the laptop's scale back and grew onto it again, every ~0.2 s for as long as it ran (harness: 600 <-> 300 px wide). The move is now sized by the same predicted size as the check, on every output, and of the outputs the window would be on, for the one with the highest scale (dxr_wl_output_for_window, unit-tested). The logical layout (Ubuntu's default) is unaffected in practice: there the predicted size is the size the window has.
Linux native Wayland, mutter's physical layout: a window moved onto a 200 % panel no longer comes out twice the size (#266, #361). The plug-in reads the scale of the window's monitor from the GNOME extension, ahead of the fractional-scale protocol. The extension reports device px per stage px, which is the monitor's scale in the logical layout but 1 on every monitor in the physical layout. So a window that had just landed on the panel was taken to be at 100 %, the size it keeps in device px (1200x960 for a 600x480 window, since the size rule above keeps its logical size) was asked for as 1200x960 logical px, and the window ended at 2400x1920 device px when the panel's scale came (harness: in 7 of 12 start-up and stale-position runs on main). In the physical layout the window's scale is now the highest scale of the monitors it is on, which is what mutter gives it (dxr_wl_window_scale120, dxr_wl_highest_scale_under, unit-tested). The logical layout is unchanged.
Linux native Wayland: a saved position the app restores after a slow first frame counts as part of its start (#266, #361, #431).#361's restore window closed 3 s after the window was first shown, on the clock. While it is open, a restored saved position off the panel is stale (centred on the panel instead), and a placement keeps the size the window opened with. After a slow first frame the app's own start came later than that: a saved position restored on its first frame skipped the stale check and the size rule, and, as the app having placed the window, it also made DisplayXRTargetDisplay's move at start right after it keep the device size. Harness, 4.5 s slow first frame, 133 % laptop and 200 % panel: a stale position restored on the laptop and then DisplayXRTargetDisplay ended on the panel at 400x344 instead of 600x504; the stale position alone stayed on the laptop; a position on the panel shrank to 400x344. The window is now measured in the time the app has been running since the window was shown (a frame counts at most 250 ms, so a stall counts as one frame; at most 20 s on the clock), so those now keep 600x504 and the stale position is centred on the panel (dxr_wl_restore_window_open, dxr_wl_running_after_frame, unit-tested). An app that runs normally sees no difference.
Windows editor: the docked Game view's window follow no longer cuts a later subclass out of Unity's main window, or subclasses that window on top of itself (#428, #256). The docked glue subclasses the pane's top-level Unity window for the lockstep follow (#740), and Play stop put back the proc it had replaced without checking that ours was still the outermost one. When another subclass came after ours (the SR weaver's, which anchors to that same window and was measured still installed long after the session), that cut it out of the chain; when it later put back its own previous proc (ours), ours had nothing left to forward to, so Unity's own proc no longer saw the window's messages, and the next Play subclassed the window again on top of ours, which made ours its own previous proc: endless recursion on the first message. Now, as the #256 overlay teardown does, the proc is put back only while ours is the outermost one; otherwise the chain is left alone (one log line) and ours stays in it as a pass-through to the proc it replaced, kept as a property of the window. The next Play asks the window whether ours is still in its chain (a registered message only ours answers) and takes it back, or installs it afresh when another subclass's restore already took it out, as the SR weaver's does at Stop. The same rule now applies when the window is destroyed. A suspect for the editor crash on a second docked Play after a Stop (#428), not confirmed. Windows editor only.
Windows: DisplayXRTargetDisplay no longer leaves a window bigger than the panel after a move to a higher-scale panel (#266). The move kept the window's physical size and centred it for that size; Windows then rescaled the window for the panel's DPI (Unity applies WM_DPICHANGED), so a 1920x1080 player from a 150 % main display became 3848x2169 on a 300 % 3840x2160 panel and overhung onto the main display. The runtime's output-device split refuses a window larger than the panel on every frame (black panel, displayxr-runtime#1575). After the move the window is now read back: one that does not fit is reduced to the panel's work area (aspect kept) and centred, and one that fits but overhangs is re-centred, the same rule as the Linux placement (#357). A full-screen window (no title bar or sizing frame, covering its monitor before the move: Unity's FullScreenWindow, which Windows does not report as maximized) is instead made to cover the panel's whole monitor, as Screen.MoveMainWindowTo does for a full-screen window, so it stays full-screen on the panel rather than becoming a letterboxed window in the work area. A borderless window that does not cover its monitor gets the work-area fit. An ExclusiveFullScreen Windows player is not moved (MoveNow warns). Windows only; a window that is already on the panel, maximized or minimized is not touched.