I created a CEF browser within a borderless window (WS_POPUP style).
The CEF renderer overlaps my window's client area.
The problem is that I'd like to allow the user to resize the window but I can't
handle the WM_NCHITTEST message.
I found many topics on the Internet but there was no actual solution.
Of course, I could create a 1px border with WM_NCCALCSIZE but I don't want to, as I would need to change the color of the border depending on the browser's content.
Is there a way to subclass the renderer's window (used internally by CEF)?
Do I really need to handle the WM_NCHITTEST message? Is there another way of doing that?
Any help would be greatly appreciated.
winapiwrapper
Related
This is a screenshot of Steam's client window being resized.
Steam's client window has two cool features.
Custom window which is very responsive.
Cool glass resize effect, different from standard windows (Thought it might be a side effect strongly related to 1)
Let's say I wanna create similar window using winapi. How can I do it?
I don't ask about widget-management related stuff, but about technical winapi tricks.
Basically, you can do almost anything with your window. But most of the tricks are to be implemented manually.
What is 'very responsive' I don't know. If you mean that the window has no standart border, it is easy to implement: do not specify WS_BORDER and WS_CAPTION when creating a WS_POPUP window. After that you will have to draw a border and a caption yourself. Handle WM_ERASEBKGND and WM_PAINT messages, draw background, menus, all as usual.
This effect seems to me more like a bug. It happens this way: the window is resized, it gets a WM_SIZE message, processes it, Windows sends a WM_ERASEBKGND message which the window ignores. Thus, the system draws a new shadow around new window frame which is not yet filled with new window image. And here we get this cool glass effect: old image of underlaying windows with a windows aero shadow. You can try to disable windows shadows and look at this effect.
In order to create a custom resizing border, you might find useful these functions: LoadCursor, SetCursor, MoveWindow.
In order to draw your custom borders, you can use standart GDI functions. Also you can create a handful of child windows and delegate drawing to them. This is basics of winapi.
I inherited an MFC app, and it has a window that has several owner-draw widgets that respond to OnPaint and do various drawing.
I noticed that in order to force the controls to redraw in response to various user actions, there was the following code:
CRect rect;
m_myControl.GetWindowRect(&rect);
ScreenToClient(&rect);
InvalidateRect(&rect, FALSE);
I thought this could be simplified like so:
m_myControl.Invalidate(FALSE);
But, in practice, when I do it this way, the control paints sometimes but not others. Specifically, when I'm interacting with controls in the window, sometimes myControl ends up just painting as solid gray. I changed the code back to the more-complicated InvalidateRect style and it's working great again.
Why would there be a difference here?
When you invalidate a window, you don't invalidate the window underneath it. If the parent window is responsible for drawing the control it won't get triggered because you didn't tell it that it needed updating. The original code does the right thing in that case.
How would I draw outside the client area of a window, and on the title bar. I know it can be done, but I am unsure of how to implement this effectively. Think google chrome, where the tabs are on the title bar.
When Windows asks you to draw the portion of the window that is outside your client area, it will send you an WM_NCPAINT message. Handle that message and draw whatever you want the non-client portion of your window to be. See the page I linked for an example of how to get a device context you can draw upon.
It may be worth mentioning WM_NCHITTEST also, if you plan on customizing where non-client elements are located.
Drawing a custom window caption DrawCaption
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.
Normally, the thickness of a window is 4 pixels, which can be retrieved by GetSystemMetrics method. Can I change its value, for example 2 pixels?
Thank you very much!
Simple answer: No. Not for a specific window.
Complicated answer: The border is drawn as part of the "non-client" region of the window. This is all handled (under the hood) by the default processing (i.e. DefWindowProc), along with the caption, minimize, maximize buttons, etc. You can override this by handling the WM_NCPAINT message. You'll then be responsible for drawing the entire non-client area of your window. You'll also want to handle the WM_NCCALCSIZE message, so that Windows knows how much of the remaining space to give to your client area.
Alternatively, you can set the border style of your window to none. This will allow Windows to draw the caption for you, although it'll probably look slightly different. Unfortunately, by doing this, you lose the drag-to-resize functionality. For that, you'll need to handle the WM_NCHITTEST message.