9
votes

I am building a Win7/8/10 x64 Direct3D11 desktop application that allows the user to switch between windowed and fullscreen mode (proper dedicated fullscreen mode, not just a maximized window*). On a dual-monitor setup I am encountering some issues.

The switch itself is performed manually using IDXGISwapChain::SetFullscreenState and works as intended: The monitor that houses the lion's share of the window area (let's call it monitor A) goes into dedicated fullscreen mode while leaving the other (monitor B) as it was, allowing the user to interact normally with windows on B as well as the fullscreen application on A.

However, if a window on B is dragged or resized so that it crosses over to A, the application's fullscreen state gets disturbed: Sometimes it just reverts back to windowed mode (leaving the application's internal tracking variable out of sync), sometimes it stays in a quasi fullscreen mode where it seemingly refuses further mode switches, and so on. The same thing happens if a window that overlapped both A and B before the application went into fullscreen mode gets focus.

Is there any way to prevent this?

I wish the OS would honor my application's dedicated fullscreen mode and keep it in a robust state even if other windows are dragged onto that monitor. I'd want the behavior to be similar to having an "always-on-top, maximized borderless window" in its stead, i.e. have other windows just "disappear behind it" and not affect the state of my fullscreen window at all.

I have tried some workarounds, like responding to WM_KILLFOCUS and temporarily switching my application into a "maximixed borderless window" until it receives WM_SETFOCUS again, but the WM_KILLFOCUS message has a lag during which there is time for a user to drag another window into the area that is then still in fullscreen mode, thereby setting me back to square one.


*The reason I want this feature rather than simply using a maximized borderless window (which is also a supported mode, btw) has to do with it allowing for much lower mouse-movement-to-rendering latency, vsync control (ON/OFF) etc.. all of which are - in short - important to the nature of this application (which is not a game).

1

1 Answers

2
votes

Although not ideal (ideal would be that there was a way to have the OS itself handle this properly), I have found a reasonable workaround that I suppose I can live with for now. It is a variation of the concept mentioned in the question ("..like responding to WM_KILLFOCUS and temporarily switching my application into a maximixed borderless window.."), but without the crippling delay problem:

Whenever the application enters dedicated fullscreen mode, it also captures the mouse with a call to SetCapture. This will not affect the user's ability to interact with other windows on monitor B, but it will ensure that any such de/activating interaction - like a mouse click in another application - will send a WM_LBUTTONDOWN to my application before it loses focus. Importantly, this happens immediately, unlike the WM_KILLFOCUS message that has significant latency.

When such a WM_LBUTTONDOWN message is received (while in fullscreen), the application checks whether the click happened outside its screen area. If so, it means it is about to lose focus and thus expose itself to all the complications brought up in the original question. So it temporarily exits dedicated fullscreen mode and "replaces" it with a (visually identical) borderless maximized window. When the application regains focus, it goes back into dedicated fullscreen.

This works OK, since you don't really care about the application's responsiveness when you're not interacting with it anyway. The biggest inconvenience here is the mode switch flickering that occurs on these focus transfers, but given the alternatives, I find it an acceptable price to pay for what I want to accomplish (but by all means - I'd be very interested in a better solution).


Edit 1: It is worth noting that since there are other ways for an application to lose focus than through mouse clicks, WM_KILLFOCUS is also handled.


Edit 2: I recently realized that handling the WM_BUTTONDOWN message is redundant. SetCapture alone will ensure that the WM_KILLFOCUS message is received quickly enough.