How to update the screen once it has lost focus - c++

I'm working on a program that requires WM_ERASEBKGND to be disabled (to avoid flickering).
The problem comes in when my main window loses focus, and another window (another program) gains the focus.
The window that has the focus (not my program) invalidates MY program's window every time it passes over it! The result is, my window's screen turns white everywhere that another window has passed by it, leaving it almost totally blank afterward. Obviously, I cannot have a program where the screen turns white every time it loses focus.
Is there any way to continue my window's drawing operations, (continue calling wm_paint, for example) even after my window has lost focus (WM_KILLFOCUS)?

First of all, from the comments above, never send the WM_PAINT manually with SendMessage or PostMessage. Use InvalidateRect to instruct the window to be repainted.
About the WM_ERASEBKGND, the return value is used to indicate the WM_PAINT handler that the background has been erased, in case the paint procedure can be optimized. To actually prevent the background from being erased, simply do not call DefWndProc() for that message. Or even easier, set the hbrBackground to NULL in the window class.
As others mentioned the focus has nothing to do with repainting, and your window should paint normally even while in the background.

Related

What is the difference of MouseInputs and KeyInputs (To get the window in the foreground)

Good day everybody.
It is so that one with SendInputs to send keys only has to call SetForegroundWindow() in order to bring the window into the foreground. This also works without problems.
Now it is so that one could think that with the mouse inputs the same procedure can be applied. But this was not possible. First you had to use the function AttachThreadInput() to get the window really in the foreground.
It is very confusing that it works with keys simply but with the mouse so cumbersome to be done. Can someone explain to me briefly why this is so?
Sorry for the title and the bad english, unfortunately, no other words have occurred to me.
Since it is too much code, I simply show the relevant for my question.
Keys:
if(SetForegroundWindow(window[id]))
{
//SENDINPUT for key, works without any problems. (Not with Mouse)
}
Mouse:
AttachThreadInput(dwCurID, dwMyID, TRUE);
SetWindowPos(window, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
SetWindowPos(window, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
SetForegroundWindow(window);
AttachThreadInput(dwCurID, dwMyID, FALSE);
//The Window is now on foreground, now use SendInput for Mouse. This way works
So I wonder really why not both works in the way of the key example. So the reason I know since the window is not really in the foreground and this is necessary for the MouseInputs. One might think that it would also be necessary for the Keyevents. Hence my confusion.
I wish you happy day!
If I understand the question correctly ... Yes, the keyboard and mouse input models are different.
But I think the real issue is that calling SetForegroundWindow on the window of another application is complicated. Windows has a long list of rules of when you can and cannot set the foreground window. (The intent is to make it hard for programs to push their windows in the user's face when the user wants to do something else.) What seems to work when you're testing might not actually work reliably in real life. For example, some of the rules depend on whether the current foreground window is owned by a process attached to a debugger. My guess is that you got lucky when you tested the keyboard case and you found a way around the rules when you worked on the mouse case.
Keyboard input is directed to the window with the keyboard focus. The window with keyboard focus is either the foreground window or a child of the foreground window. So to direct keyboard messages with SendInput to a particular application, you only have to make sure it has focus, which you can do by bringing its window to the foreground.
If you succeed, then the window you just brought to the foreground will make sure the window focus is set appropriate (e.g., by calling SetFocus on one of its children). If you were to try to call SetFocus yourself, on a window that belonged to another thread or process, you would first have to use AttachThreadInput just as you've done in the case for the mouse. (This is explained in SetFocus.)
Mouse input is (generally) directed to the window under the mouse, even if that window is not the foreground window. The big exception is when a window has "captured" the mouse, then all mouse input goes to that window, even if the mouse is over a different window. But the other exception is also the mouse scroll wheel messages, which seem to follow the window with keyboard focus.
I'm not entirely sure why (or whether) it's important to set the foreground window to send mouse input, unless it's because you're trying to make sure it gets the mouse scroll wheel messages.

Does SetWindowPos paint immediately

On every mouse move event, I am moving my window. From the documentation it appears that if the move is successful SetWindowPos return a non-zero value.
I wanted to confirm my inference that every time SetWindowPos returns a non-zero value, the move has already happened. Which means, the window has actually been re-painted at the new position and only then does the function return. It is NOT the case that move will happen a little while later (when some kind of message is processed) after the function has returned.
I wanted to confirm my inference that every time SetWindowPos returns a non-zero value, the move has already happened. Which means, the window has actually been re-painted
This is false assumption. Successful move and non-zero return has nothing to do with painting.
The API changes position and non-zero returned value confirm that new values were accepted. The API does not promise, does not do the complete repaint cycle as a part of its execution. More to that, change in position, Z-order etc. is likely to affect visibility of other windows too, which in turn need repaint, which in turn has to happen on respective threads. The repaints are scheduled, they are not synchronized with SetWindowPos return. Documentation on MSDN does not have any promises regarding repaints/updates. Then zero return from the API is an indication that your arguments are not accepted at all (esp. invalid window handle).
Bonus reading:
When you call the Set­Window­Pos function, the window manager updates the window size, position, whatever, and then it goes around repainting the windows that were affected by the operation. By default, the Set­Window­Pos function does a quick-repaint of the windows before returning. After the function returns, the normal WM_PAINT message does the real work of painting the window. The quick-repaint is done so that there is immediate feedback that the window did change its size, position, whatever.
SetWindowPos returns immediately after it has done its job.
But the main painting is deferred until WM_NCPAINT and WM_PAINT are received by the window. From my experience, I can say that changes to the frame are often drawn directly by SetWindowPos.
If you want the window completely redrawn call UpdateWindow or RedrawWindow (with appropriate flags) after the call to SetWindowPos

content (or background) remains when draggin the splitter bar to resize two panels

I have a main window with 3 child: hwndTocBox (left panel), hwndSplitter and hwndCanvas (right panel).
hwndTocBox has a child hwndTreeView, which is a TreeView control. When I drag hwndSplitter to the right (i.e want to make hwndTocBox and hence hwndTreeView bigger), the content (and background?) of hwndCanvas and hwndSplitter will remain for a while. (When I drag the splitter to the left, there is no problem at all.)
When hwndSplitter is draged, it uses DeferWindowPos() to resize and move hwndTocBox, hwndSplitter and hwndCanvas. When hwndTocBox is resized, in WM_SIZE case of its windows procedure, it resizes hwndTreeView (still using DeferWindowPos(), since it resizes not only hwndTreeView but also others).
I have tried to use CLIPCHILDREN and WS_CLIPSIBLINGS in several places, but it doesn't solve the problem.
Why the contents remain there for a while and erased later?
Could you indicate me how to solve this issue, please.
You'll need to repaint the portions of the window that you've resized, otherwise you'll get these strange artifacts. There's a reason they look like smears, because that's almost exactly what they are. A certain portion of the content was painted and appeared on screen normally. Then you resized the window. The portion that had already been painted was not repainted because you didn't invalidate it, but the newly-exposed portion had to be repainted because there was nothing there before.
The fix is simple: add a call to the InvalidateRect() function at the bottom of your resizing code to ensure that the portion of the window you're resizing gets redrawn the next time that the window processes a WM_PAINT message.
If you want to make sure that a WM_PAINT message gets processed immediately (resulting in the immediate redrawing of your window's affected regions), follow up with a call to the UpdateWindow() function. But this really shouldn't be necessary. It's much more efficient to postpone all of the redrawing to later when everything is finalized, rather than doing it incrementally. Relatively speaking, repainting a window is an expensive operation.

Constraining window position to desktop working area

I want to allow a user to drag my Win32 window around only inside the working area of the desktop. In other words, they shouldn't be able to have any part of the window extend outside the monitor(s) nor should the window overlap the taskbar.
I'd like to do it in a way that does cause any stuttering. Handling WM_MOVE messages and calling MoveWindow() to reposition the window if it goes off works, but I don't like the flickering effect that's caused by MoveWindow().
I also tried handling WM_MOVING which prevents the need to call MoveWindow() by altering the destination rectangle before the move actually happens. This resolves the flickering problem, but another issue I run into is that the cursor some times gets aways from the window when a drag occurs allowing the user to drag the window around while the cursor is not even inside the window.
How do I constrain my window without running into these issues?
Windows are, ultimately, positioned via the SetWindowPos API.
SetWindowPos starts by validating its parameters by sending the window being sized or moved a WM_WINDOWPOSCHANGING message, and then a WM_WINDOWPOSCHANGED message notifying the window proc of the changed size and/or position.
DefWindowProc handling of these messages is to, in turn, send WM_GETMINMAXINFO and then WM_SIZE or WM_MOVE messages.
Anyway, handle WM_WINDOWPOSCHANGING to filter both user, and code, based attempts to position a window out of bounds.
Keep in mind that users with multi-monitor setups may have a desktop that extends into negative x- and y-coordinates, or that is not rectangular. Also, some users use alternative window managers such as LiteStep, which implement virtual desktops by moving them off-screen; if you try to fight this, your application will break for these users.
You can do this by handling the WM_MOVING message and changing the RECT pointed to by the lParam.
lParam: Pointer to a RECT structure with the current position of the window, in screen coordinates. To change the position of the drag rectangle, an application must change the members of this structure.
you may also want to handle WM_ENTERSIZEMOVE to know when the window is beginning to move, and WM_EXITSIZEMOVE
WM_GETMINMAXINFO is what you seem to be looking for.

Difference between InvalidateRect and RedrawWindow

When I want to redraw a window, is there any preferred function to call between InvalidateRect and RedrawWindow?
For instance, are these two calls equal: (win would be a HWND)
RedrawWindow(win, NULL, NULL, RDW_INVALIDATE);
InvalidateRect(win, NULL, NULL);
The main question(s): When should I use one or the other? Are there any differences that happen in the background? (different WM_messages / focus / order / priorities..)
The reason that I want to redraw the window is because I send a new image to it that I want it to display, meaning the content of the window is no longer valid.
InvalidateRect does not immediately redraw the window. It simply "schedules" a future redraw for a specific rectangular area of the window. Using InvalidateRect you may schedule as many areas as you want, making them accumulate in some internal buffer. The actual redrawing for all accumulated scheduled areas will take place later, when the window has nothing else to do. (Of course, if the window is idle at the moment when you issue the InvalidateRect call, the redrawing will take place immediately).
You can also force an immediate redraw for all currently accumulated invalidated areas by calling UpdateWindow. But, again, if you are not in a hurry, explicitly calling UpdateWindow is not necessary, since once the window is idle it will perform a redraw for all currently invalidated areas automatically.
RedrawWindow, on the other hand, is a function with a much wider and flexible set of capabilities. It can be used to perform invalidation scheduling (i.e. the same thing InvalidateRect does) or it can be used to forcefully perform immediate redrawing of the specified area, without doing any "scheduling". In the latter case calling RedrawWindow is virtually equivalent to calling InvalidateRect and then immediately calling UpdateWindow.
RedrawWindow(win, NULL, NULL, RDW_INVALIDATE); and InvalidateRect(win, NULL, NULL); are equivalent. Both functions invalidate the window. The WM_PAINT occurs at the normal time (no other messages in the application queue) in both cases.
If you want the paint to be done immediately then calling either RedrawWindow(win, NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW) or InvalidateRect followed by an UpdateWindow will do that.
RedrawWindow simply gives more options with the RDW_* bits. If all you want is to invalidate the window without the immediate paint then calling InvalidateRect seems cleaner.
I don't like just giving links, but the MSDN gives you all the information you need and it would be a waste of time to re-type it all here.
RedrawWindow
InvalidateRect
In short, yes there are differences. The question is, why do you want to redraw the window? Is it because the contents are no longer valid? If so, use InvalidateRect, otherwise use RedrawWindow.
RedrawWindow repaints the window immediately. InvalidateRect only marks the window to be repainted on the next WM_PAINT message. But WM_PAINT messages have lower priority than other messages, so the repainting won't be immediately if your app is busy handling other messages.