Tip: Gaining Foreground Window Access


#1

In the hope it will be helpful, I’d like to share some findings and code with you that solves a common problem: Correct stacking of windows and dialogues when multiple processes are involved. I had quite a struggle to get the windows of background processes and plugins to the foreground without blocking system alerts and host dialogues.

On Windows, a background process (e.g. some 32/64 bit bridge or other service that you run as a slave) is not allowed to take foreground access unless it received a permission for that. Simply using setAlwaysOnTop() doesn’t cut it, because that would force all other windows to the background, which can lead to serious deadlock situations (e.g. when a 3rd party plugin opens a file dialogue or alert message).

I found a simple and reliable solution that works for Windows and Mac. It consists of three functions:

[code]** Allow other processes to steal the foreground on the desktop. Call this
before you launch the child process or make the IPC call that opens a
window in the child process. Return true on success.
*/
bool giveAwayForegroundAccess (bool allow);

/** Request that the current process eventually wants to take foreground
access on the desktop. Call this in the application startup of your child
process once.
*/
void setWantForegroundAccess (bool want);

/** Call this immediately after opening a window in the child process
that wants to gain foreground access. The best place is immediately
after setVisible (true). Return true on success.
/
bool takeForegroundAccessNow (DocumentWindow
window);[/code]

The implementation for Windows is:

[code]bool giveAwayForegroundAccess (bool allow)
{
/** @todo This currently enables the feature only, should also allow for disablement */
LockSetForegroundWindow (LSFW_UNLOCK);
return AllowSetForegroundWindow (ASFW_ANY);
}

void setWantForegroundAccess (bool want)
{
}

bool takeForegroundAccessNow (DocumentWindow* window)
{
HWND nativeWindow = (HWND)(window->getWindowHandle());
SetForegroundWindow (nativeWindow);
return true;
}[/code]

The implementation for Mac is:

[code]bool giveAwayForegroundAccess (bool allow)
{
return true;
}

void setWantForegroundAccess (bool want)
{
[NSApp activateIgnoringOtherApps:YES];
}

bool takeForegroundAccessNow (DocumentWindow* window)
{
NSWindow* nsWindow = [((NSView*)(window->getWindowHandle())) window];
[NSApp activateIgnoringOtherApps:YES];
[nsWindow orderFrontRegardless];
return true;
}[/code]

Jules, feel free to add this to the library if you like. DocumentWindow would probably be a good place. With all methods being static, except takeForegroundAccessNow().


#2

Just what I needed, thanks Ans!


#3

The Windows version of takeForegroundAccessNow didn’t work until I added this to the top: