Skip to content

Commit

Permalink
Windows: setting right Z order for dialog windows
Browse files Browse the repository at this point in the history
  • Loading branch information
sadko4u committed Jun 29, 2024
1 parent 1b193d3 commit 38d13ab
Show file tree
Hide file tree
Showing 6 changed files with 131 additions and 50 deletions.
1 change: 1 addition & 0 deletions include/private/win/WinDDSurface.h
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,7 @@ namespace lsp

public:
void sync_size();
void invalidate();
};

} /* namespace win */
Expand Down
1 change: 1 addition & 0 deletions include/private/win/WinDisplay.h
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ namespace lsp
WinDisplay *pNextHandler; // Next hook handler in the chain of handlers
lltl::parray<WinWindow> vGrab[__GRAB_TOTAL]; // Grab queue according to the priority
lltl::parray<WinWindow> sTargets; // Targets for event delivery
lltl::parray<WinWindow> vWindows; // All registered windows
HWND hClipWnd; // Clipboard window
IDataSource *pClipData; // Data source for clipboard
lltl::parray<void> vClipMemory; // Memory chunks allocated for the clipboard
Expand Down
4 changes: 4 additions & 0 deletions include/private/win/WinWindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,9 @@ namespace lsp
void handle_mouse_leave();
void handle_mouse_enter(const ws::event_t *ev);
status_t set_geomety_impl();
void place_above(HWND wnd);
HWND placement_window(HWND wnd);
static HWND wrapping_window(HWND wnd);

public:
explicit WinWindow(WinDisplay *dpy, HWND wnd, IEventHandler *handler, bool wrapper);
Expand Down Expand Up @@ -189,6 +192,7 @@ namespace lsp
HWND win_handle();
WinDisplay *win_display();
WinDNDTarget *dnd_target();
void idle();
};
} /* namespace win */
} /* namespace ws */
Expand Down
7 changes: 7 additions & 0 deletions src/main/win/WinDDSurface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,13 @@ namespace lsp
}
}

void WinDDSurface::invalidate()
{
if (pShared != NULL)
pShared->Invalidate();
safe_release(pDC);
}

void WinDDSurface::sync_size()
{
if ((pShared == NULL) || (pShared->hWindow == NULL))
Expand Down
7 changes: 7 additions & 0 deletions src/main/win/WinDisplay.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1987,6 +1987,13 @@ namespace lsp
{
ws::timestamp_t ts = system::get_time_millis();
dpy->process_pending_tasks(ts);
for (lltl::iterator<WinWindow> it = dpy->vWindows.values(); it; ++it)
{
WinWindow *wnd = it.get();
if (wnd != NULL)
wnd->idle();
}

atomic_add(&dpy->nIdlePending, -1);
return 0;
}
Expand Down
161 changes: 111 additions & 50 deletions src/main/win/WinWindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,17 @@ namespace lsp
{
namespace win
{
// static void dump_window(const char *id, HWND wnd)
// {
// WCHAR caption[256];
// LSPString text;
//
// GetWindowTextW(wnd, caption, sizeof(caption)/sizeof(WCHAR));
// text.set_utf16(caption);
// bool visible = IsWindowVisible(wnd);
// lsp_trace(" %s=%p, caption=%s, visible=%s", id, wnd, text.get_native(), (visible) ? "true" : "false");
// }

WinWindow::WinWindow(WinDisplay *dpy, HWND wnd, IEventHandler *handler, bool wrapper):
ws::IWindow(dpy, handler)
{
Expand Down Expand Up @@ -99,6 +110,7 @@ namespace lsp

WinWindow::~WinWindow()
{
pWinDisplay = NULL;
pDisplay = NULL;
}

Expand Down Expand Up @@ -170,11 +182,17 @@ namespace lsp
// Enable all keyboard and mouse input for the window
EnableWindow(hWindow, TRUE);

// Add window to display
pWinDisplay->vWindows.add(this);

return STATUS_OK;
}

void WinWindow::destroy()
{
if (pWinDisplay != NULL)
pWinDisplay->vWindows.qpremove(this);

if (hWindow == NULL)
return;

Expand Down Expand Up @@ -612,49 +630,25 @@ namespace lsp
return 0;
}

case WM_WINDOWPOSCHANGED:
{
WINDOWPOS *p = reinterpret_cast<WINDOWPOS *>(lParam);
lsp_trace("windowposchanged wnd=%p (%p) flags=0x%x transient_for=%p", hWindow, p->hwnd, p->flags, hTransientFor);
break;
}

case WM_WINDOWPOSCHANGING:
{
if ((hTransientFor == NULL) || (hTransientFor == HWND_TOP))
break;

// WCHAR caption[256];
// LSPString tmp;
//
// lsp_trace("Order for hWnd = %p, hTransientFor = %p:", hWindow, hTransientFor);
// HWND hIter = GetWindow(hWindow, GW_HWNDFIRST);
// while (hIter != NULL)
// {
// caption[0] = 0;
// GetWindowTextW(hIter, caption, sizeof(caption)/sizeof(WCHAR));
// tmp.set_utf16(caption);
// lsp_trace(" hWnd=%p (%s)", hIter, tmp.get_native());
//
// hIter = GetWindow(hIter, GW_HWNDNEXT);
// }

HWND hPrev = GetWindow(hWindow, GW_HWNDFIRST);
// lsp_trace("hPrev = %p", hPrev);
while (hPrev != NULL)
WINDOWPOS *p = reinterpret_cast<WINDOWPOS *>(lParam);
HWND placement = placement_window(hTransientFor);
if (placement != NULL)
{
HWND hCurr = GetWindow(hPrev, GW_HWNDNEXT);
// lsp_trace("hCurr = %p", hCurr);

// We are already at the top?
if (hCurr == hWindow)
break;
if (hCurr == hTransientFor)
{
// lsp_trace("overriding hwndInsertAfter with %p", hPrev);
WINDOWPOS *p = reinterpret_cast<WINDOWPOS *>(lParam);
p->hwndInsertAfter = hPrev;
p->flags &= ~SWP_NOZORDER;
break;
}

// Update pointer
hPrev = hCurr;
p->hwndInsertAfter = placement;
p->flags &= ~SWP_NOZORDER;
}

break;
}

Expand Down Expand Up @@ -922,15 +916,18 @@ namespace lsp
return STATUS_BAD_STATE;

hTransientFor = NULL;
SetWindowPos(
hWindow, // hWnd
HWND_TOPMOST, // hWndInsertAfter
sSize.nLeft, // X
sSize.nTop, // Y
sSize.nWidth, // nWidth
sSize.nHeight, // nHeight
SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE // uFlags
);
if (!has_parent())
{
SetWindowPos(
hWindow, // hWnd
HWND_TOPMOST, // hWndInsertAfter
sSize.nLeft, // X
sSize.nTop, // Y
sSize.nWidth, // nWidth
sSize.nHeight, // nHeight
SWP_NOSIZE | SWP_NOMOVE // uFlags
);
}
ShowWindow(hWindow, SW_SHOW);
return STATUS_OK;
}
Expand All @@ -952,18 +949,82 @@ namespace lsp
bTransientOn = !EnableWindow(hTransientFor, FALSE);
}

if (!has_parent())
{
place_above(hTransientFor);
// HWND topmost = placement_window(hTransientFor);
// SetWindowPos(
// hWindow, // hWnd
// topmost, // hWndInsertAfter
// sSize.nLeft, // X
// sSize.nTop, // Y
// sSize.nWidth, // nWidth
// sSize.nHeight, // nHeight
// SWP_NOSIZE | SWP_NOMOVE // uFlags
// );
}

ShowWindow(hWindow, SW_SHOW);

return STATUS_OK;
}

void WinWindow::idle()
{
// Update window order
if ((hTransientFor != NULL) && (!has_parent()))
{
place_above(hTransientFor);
}
}

HWND WinWindow::wrapping_window(HWND window)
{
HWND parent;
while ((parent = GetParent(window)) != NULL)
window = parent;

return window;
}

void WinWindow::place_above(HWND wnd)
{
HWND window = placement_window(wnd);

// Nope, we need to find the window to place after
lsp_trace("Placing window %p above %p", hWindow, window);

SetWindowPos(
hWindow, // hWnd
hTransientFor, // hWndInsertAfter
window, // hWndInsertAfter
sSize.nLeft, // X
sSize.nTop, // Y
sSize.nWidth, // nWidth
sSize.nHeight, // nHeight
SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE // uFlags
SWP_NOSIZE | SWP_NOMOVE // uFlags
);
ShowWindow(hWindow, SW_SHOW);
}

return STATUS_OK;
HWND WinWindow::placement_window(HWND window)
{
HWND desktop = GetDesktopWindow();
window = wrapping_window(window);

// Check that the window is placed before the passed in arguments
HWND current = GetTopWindow(desktop);
while (true)
{
current = GetWindow(current, GW_HWNDNEXT);
if (current == NULL)
return HWND_TOPMOST;
if (current == window)
break;
if (current == hWindow)
return NULL;
}

// Nope, we need to find the window to place after
return GetWindow(current, GW_HWNDPREV);
}

status_t WinWindow::take_focus()
Expand Down Expand Up @@ -1195,7 +1256,7 @@ namespace lsp
{
case BS_DIALOG:
style = WS_OVERLAPPED | WS_CAPTION | WS_THICKFRAME | WS_SYSMENU;
ex_style = WS_EX_ACCEPTFILES;
ex_style = WS_EX_ACCEPTFILES | WS_EX_DLGMODALFRAME;
break;
case BS_SINGLE:
style = WS_OVERLAPPED | WS_CAPTION | WS_THICKFRAME | WS_SYSMENU;
Expand Down

0 comments on commit 38d13ab

Please sign in to comment.