Child not visible when parent fullscreen and has focus - winapi

Working with a double-buffered window, I have a problem that when I make my parent window fullscreen (just covering the whole screen using the method in this answer, or using ChangeDisplaySettings with CDS_FULLSCREEN both show the problem), any child windows it has are not drawn/visible. However, this only happens if the window has focus / is the active window. I have been banging my head against this for a very long time (2+ years) and have finally started caring enough to try and figure this out.
Specific setup:
This is an OpenGL window, double-buffered
Parent is drawn before child is drawn and both are receiving WM_PAINT messages
Drawing is done outside WM_PAINT BeginPaint/EndPaint pairs by simply making the Device Context of the window to draw current. However, an older version of the code did confine all drawing to inside Begin-/EndPaint, and I had the same problem.
Parent window styles when fullscreen, as given by WinSpy++ (consistent with what i request in code): WS_OVERLAPPEDWINDOW, WS_VISIBLE, WSCLIPSIBLINGS, WS_CLIPCHILDREN (though caption removed by this method and is indeed not present, seems winspy doesn't show this), no active WS_EX styles
Child window: WS_CHILD, WS_VISIBLE, WSCLIPSIBLINGS, WS_CLIPCHILDREN, no WS_EX
Code handling WM_SETFOCUS: DefWindowProc() for return value of my window proc, SetActiveWindow(), UpdateWindow()
Code handling WM_KILLFOCUS: only DefWindowProc() for return value of my window proc
WM_ACTIVATE is passed to DefWindowProc().
I have seen this problem on at least windows 7 and 8, with various versions of MSVC and the windows SDK.
Is there any other info i can add?
Lastly, this concerns the code of FreeGLUT, try the resizer demo in svn trunk should you want to see the problem in action. After starting the demo, press c to open a child window, and then f to make things fullscreen.

Related

Fullscreen borderless window with 'owned' window on-top

I have two OpenGL windows: a main one and a smaller one that is set to be 'owned' by the main one (hWndParent is set in CreateWindowEx, but the WS_CHILD style is not set).
If I then convert my main window to be borderless and the same size as my desktop it will jump in front of the smaller window even though it's owned and that should not be possible (https://msdn.microsoft.com/en-us/library/windows/desktop/ms632599%28v=vs.85%29.aspx#owned_windows). This is true even if the smaller window is set to be always-on-top.
On it's own this isn't terrible, but the core issue is that I can still click-through my main window on where the smaller window is, and the smaller window will pop infront. I can go between the two windows endlessly like this by clicking on the main window, then clicking-through the main window.
If I make the main window size 1 pixel less than the full desktop size, none of these issues occur and the windows behave is as expected.
I can't find any documentation that describes this behavior. It is a feature to keep windows from going infront of content (such as a video playing back) that isn't documented, or am I just missing it?
I'll mention I'm not using layered or transparent window here, so I don't think click-through should even be possible?
Thanks
What you experience may very well be a OpenGL implementation bug that's triggered by the heuristic in which the driver switched between "windowed" and "fullscreen" rendering: You see, for OpenGL there's no special "exclusive fullscreen mode" as Direct3D has. Instead a borderless window covering the whole screen, which is not overlapped by foreign windows may trigger a "fullscreen" detection, which may the OpenGL implementation in question make switch to another code path (namely one, where all pixel ownership tests are disabled and the framebuffer flips go directly to the display scanout, bypassing the windowing compositor.
What you do there is so uncommon, that it likely may have slipped through all conformance tests. Having child windows to a OpenGL window is uncommon in the first place and them being floating is even rarer.
If you've got a minimal example showcase, you should probably report it as a bug to the driver vendor. In the meantime I propose a workaround: Make your OpenGL window a child-window to your top level window (will of course require resizing in the toplevel WM_SIZE) and make your floating window another child to the toplevel; the z-order between childs in a parent window is respected and kept. Being a child to a toplevel window should inhibit most heuristics and OpenGL drivers should not loop at the border and size of OpenGL parent windows.

How can i draw to or add a custom button to every window of all applications?

I have seen several tools adding a custom button and/or drawing on the title bar of all windows of all applications in Windows. How is that done?
Extra points for an example in Delphi.
EDIT:
I found something for dotNET that does this:
http://www.thecodeking.co.uk/2007/09/adding-caption-buttons-to-non-client.html#.VdmioEDenqQ
How I see this job:
First of all we should be able to paint this button on the our own window caption. This procedure will be used later
This part of the program enumerates the active and visible windows
This part of the program using injection attach our dll to enumerated windows
From injected dll we can draw the button on the window caption
Inside this dll we should process the click on the button
We should have mechanism to send result to our main program
I haven't done this, so the following is what I would investigate if I were to try:
For each application / each top-level window:
Create a floating window and position it over the title bar wherever you want it to sit. Set up the parent / child relationship, but this window is part of your own process. (There are occasionally problems parenting a window from one process to one from another process, but try. I'd avoid injecting into other processes if possible.)
You can investigate the window flags to see if the window has a title bar (ie if you should add a button) via GetWindowLong with GWL_STYLE looking for WS_CAPTION. The same call will also let you see the type of caption / frame, which you can combine with GetSystemMetrics with, eg, SM_CYDLGFRAME to figure out the right size for your button on this specific window's title bar.
This window is now your button: paint, handle clicks etc as appropriate.
Make it a non-focusable window so that clicks to it don't take focus away from the window is is on the title bar of. You don't want clicking it to make the title bar change colour, for example. Do this by setting the WS_EX_NOACTIVATE window flag, something like: SetWindowLong(Handle, GWL_EXSTYLE, GetWindowLong(Handle, GWL_EXSTYLE) orWS_EX_NOACTIVATE).
The main problem is to keep it positioned correctly when the window moves, is resized, etc. To do this, install a hook for the system move events. You can also hook minimize and restore via EVENT_SYSTEM_MINIMIZESTART and EVENT_SYSTEM_MINIMIZEEND. This will allow you to keep track of all windows moving around onscreen, such that you can adjust the button-window position if necessary.
That gives you a window which you can paint as a button (and respond to clicks etc), that visually is "attached" to other windows so it stays in the same place as the user drags the title bar, minimizes or maximises the app, etc, and that is in your own process without cross-process problems.

Stop being topmost window

My window should be on top of a specific "target" window that I don't have control over.
When the target window is activated, I call SetWindowPos with HWND_TOPMOST to place my window on top of it while the target can still be the active window.
When the target window is no longer the foreground window, I want my window to still be on top of the target window, but no longer topmost, so other windows are not covered by it.
Two ideas I had:
Call SetWindowPos with hWndInsertAfter to be the just activated window. This fails when the just activated window is topmost, because my window then does not lose the topmost status. Another issue with this: If the just activated window is the desktop, then my window is placed below the target window.
Call SetWindowPos with HWND_NOTOPMOST to lose the topmost status. However, this brings my window to the top of all non-topmost windows, so it covers the just activated window. To fix this I have to bring the just activated window on top again with another SetWindowPos with HWND_TOP. This feels like the wrong way to do it and may cause flicker.
Is it possible to have a window just stop being topmost and placing it below the current foreground window?
The only automatic method to make a window permanently on top of another one whether the target window is top-most or not is an owner/owned relationship. You could try using SetParent to create this relationship but note that Raymond Chen does say it's not recommended.
Assuming you're tracking window activations somehow, I think your SetWindowPos idea (the first one) is the way to do it, with the following modification:
When the target window is active, set your window to HWND_TOPMOST
When the target loses activation, insert your window after the target window's immediate predecessor in the z-order (i.e. effectively still on top of the target window, but not top-most)
Something like this psuedo-code:
if (foregroundwindow == targetwindow)
SetWindowPos(my_window, HWND_TOPMOST, ...);
else
{
HWND hwndPred = GetWindow(targetwindow, GW_HWNDPREV);
if (!hwndPred)
{
// no predecessor so my_window will still be on top, just not top-most any more
if (GetWindowLong(targetwindow, GWL_EXSTYLE) & WS_EX_TOPMOST)
hwndPred = HWND_NOTOPMOST;
}
SetWindowPos(my_window, hwndPred, ...);
}

Detect application windows

I use CBT Windows Hook to detect window creation/deletion/min-max/move-size events.
I works well, but I need to filter whose events coming from normal widgets. Practically I need to being notified by CBT hook only for those windows that the user consider windows.
The problem that I'm facing make me mad, since I continuosly get spurious events even if I filter window as follow:
BOOL FilterWindowHandle(HWND hwnd)
{
// Filtered window having WS_CHILDWINDOW style
if ((GetWindowLongPtr(hwnd, GWL_STYLE) & WS_CHILDWINDOW) != 0)
return (TRUE);
// Filtered window not having WS_CAPTION style
if ((GetWindowLongPtr(hwnd, GWL_STYLE) & WS_CAPTION) == 0)
return (TRUE);
// Not filtered
return (FALSE);
}
Those spurious events comes from shadow effects, menus and everything displayed on screen.
Is there a robust method to filter real windows from its children?
I avoid the test of WS_BORDER or similar, since some applications could create their main window without border... or am I wrong?
A good fit for "things the user considers windows" is the set of windows displayed in the Alt-Tab list (or on the Taskbar).
This OldNewThing article explains the rules (although the rules are not fixed or guaranteed to remain the same):
Which windows appear in the Alt+Tab list?
The general rule is:
For each visible window, walk up its
owner chain until you find the root
owner. Then walk back down the visible
last active popup chain until you find
a visible window. If you're back to
where you're started, then put the
window in the Alt+Tab list.
This can be overridden with explicit window styles:
A window with the WS_EX_TOOLWINDOW
extended style is treated as if it
weren't visible, even if it is. A
window with the WS_EX_APPWINDOW
extended style is treated as if it has
no owner, even if it does.
See the full OldNewThing post which those two quotes come from for more detail.
A useful criteria that I've used in the past is to test whether the window is a top-level window, i.e. its parent is NULL.

Why might WS_CLIPCHILDREN be necessary for the display of DirectShow window on XP (but not Vista or Windows 7)?

I wrote a program to play MPEG video on a window (of course, DirectShow will open its own window as the sub-window of that window). On Windows Vista and 7, the program works fine. But on XP, the video is only visible when I set the WS_CLIPCHILDREN style on the outer window (i.e. not the DirectShow one). Is this a bug in XP or some model change in Vista?
Actually, it sounds like a bug in your code...
WS_CLIPCHILDREN affects the drawing of the parent window. More specifically, it prevents it from drawing in the areas occupied by its children. So if you're re-drawing the parent on a regular basis and WS_CLIPCHILDREN isn't set, you'll end up stomping on the child window's display...
As for why this might affect XP and not Vista or Win7, well... This is just a guess, but many video players on XP used a feature provided by most video cards known as "overlays": essentially, the window was filled with a key color and this was then recognized by the hardware as indicating the area on screen where the video would be displayed. Since the window itself would not be repainted often (it would need to be filled with the key color initially and when resized, but wouldn't be repainted for every frame in the video), allowing the parent to draw over it could seriously mess up your output!
Potential solutions
Use WS_CLIPCHILDREN on your parent window. This is almost always a good idea anyway.
If you have custom painting code for your parent window, modify it to manually avoid drawing over the area occupied by the child.

Resources