Skip to content

Secondary viewports clamped to monitor boundary during drag; content shift when OS refuses position (Linux/X11) #9398

@geonheekim

Description

@geonheekim

Version/Branch of Dear ImGui:

Version 1.92.8 WIP, Branch: docking

Back-ends:

imgui_impl_glfw.cpp + imgui_impl_opengl3.cpp

Compiler, OS:

Linux Ubuntu 22.04, GCC 11.4.0, X11/GNOME Shell, kernel 6.8.0

Full config/build information:

ImGuiConfigFlags_NavEnableKeyboard | ImGuiConfigFlags_DockingEnable | ImGuiConfigFlags_ViewportsEnable

Details:

My Issue / Question:

When a window is undocked into a secondary viewport (a separate OS window), it
cannot be dragged beyond the monitor edge — it hits an invisible wall — even
though the main GLFW window and other native apps (e.g. VSCode) can freely cross
that boundary.

Additionally, while the secondary viewport is at or near the monitor edge, the
rendered content (e.g. a crosshair drawn at mouse coordinates) appears visually
offset from the actual cursor position.


Root cause (traced in source):

  1. Monitor-edge wallClampWindowPos in imgui.cpp (around the
    window->ViewportOwned branch, ~line 8257–8272) limits the window position to
    monitor->WorkPos + monitor->WorkSize expanded by -visibility_padding
    (default DisplayWindowPadding = {19, 19}). The PlatformMonitorsFullWorkRect
    path that allows straddling (#7299, #3071) is only entered when
    g.MovingWindow != NULL && window->RootWindowDockTree == g.MovingWindow->RootWindowDockTree.
    During a viewport-owned drag this condition is met, but visibility_rect is
    then expanded by -visibility_padding which still applies 19 px of clamping —
    the window can get close to the edge but not past it.

  2. Content shiftNewFrame() sets viewport->Pos to the desired position
    (cursor − grab delta, which may be beyond the monitor edge).
    TranslateWindowsInViewport has already shifted imgui child windows to
    LastPlatformPos (the actual OS position, clamped by the WM).
    So after NewFrame():

    • ImGui child-window global coordinates are based on P_actual
    • viewport->Pos (== DisplayPos) equals P_desired
    • Result: every pixel in the viewport is rendered with a
      P_actual − P_desired offset → crosshair and mouse-position overlays
      appear shifted by the "overshoot" amount.

Expected behavior:

Secondary viewports should be draggable beyond the monitor edge the same way the
main window is (the OS/WM ultimately controls whether the window actually moves).
Rendered content should never appear shifted relative to the cursor while dragging
near a monitor boundary.


Steps to reproduce:

  1. Enable ImGuiConfigFlags_ViewportsEnable.
  2. Undock any window so it becomes a secondary OS window.
  3. Drag the secondary window toward and past the monitor edge.
    → Window stops at ~19 px from the edge (the DisplayWindowPadding limit).
  4. While it is stopped at the edge, content rendered at io.MousePos (e.g. a
    crosshair) appears shifted by the amount the drag "wanted" to move the window
    further.

Screenshots/Video:

No response

Minimal, Complete and Verifiable Example code:

// Standard docking+viewports example (Dear ImGui demo is sufficient to reproduce).
// 1. Run imgui_demo with viewports enabled on Linux/X11.
// 2. Undock "Dear ImGui Demo" window (drag it out of the main window).
// 3. Draw a crosshair at io.MousePos inside the secondary window's Begin/End.
// 4. Drag the secondary window to a monitor edge.
// Observe: window stops moving before the edge; crosshair shifts from cursor.

ImGui::SetNextWindowPos(ImVec2(0, 0), ImGuiCond_Once);
ImGui::Begin("Viewport test");
ImVec2 p = ImGui::GetMousePos();
ImGui::GetForegroundDrawList()->AddLine({p.x - 10, p.y}, {p.x + 10, p.y},
IM_COL32(255, 0, 0, 255));
ImGui::GetForegroundDrawList()->AddLine({p.x, p.y - 10}, {p.x, p.y + 10},
IM_COL32(255, 0, 0, 255));
ImGui::End();

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions