prasannavl / WinApi

A simple, direct, ultra-thin CLR library for high-performance Win32 Native Interop
Apache License 2.0
823 stars 101 forks source link

What is the purpose of ScreenToClient and ClientToScreen in NativeWindow.cs? #22

Open mpolicki opened 6 years ago

mpolicki commented 6 years ago

I tried using the ScreenToClient and ClientToScreen methods in WinApi/WinApi/Windows/NativeWindow.cs because I thought they did the same thing as the Windows functions of the same name. But, after getting unexpected results, I noticed that the methods had AdjustWindowRectEx/InverseAdjustWindowRectEx calls in them as well, which results in something other than a simple client/screen coordinate transformation. This left me confused as to the purpose of the methods, so could you please clarify whether the intent really is something other than a simple client/screen coordinate transformation?

prasannavl commented 6 years ago

Hi, thanks for bringing this up.

Intent

This does the conversion in relation to the window (i.e, taking the NonClient area, based on the style of the Window - It may have a title bar, it may not. It may be borderless, it may not. It relieves the user of the API from thinking about these complexities). This is very useful when the window has children (which it usually does). Say, have a native window that is drawing a bunch of DirectX items. Now, you can just pass their co-ordinates onto these methods to get them in correct relation to the window. The adjustment is done with AdjustWindowRectEx/InverseAdjustWindowRectEx, while the ScreenToClient/ClientToScreen (which by the way you are probably better off not using in most cases - MapWindowPoints is the correct replacement for it) is correctly done by MapWindowPoints.

prasannavl commented 6 years ago

Also adding to that, it exposes a public virtual method, that's in turn called by the methods that just take a single argument this.ClientToScreen(clientRect) to facilitate exactly that. If in a case your window has a more complex implementation - then you can manually override it to provide the correct transformation. So, say you have an usual NC Client implementation, you can just do the transformation in here, so all it's children of external items can get a correct adjusted value.

You will have to do this at some point to build a correct layout with a set of children. This just facilitates that.

Please have a look at the DwmWindow for it's uses: https://github.com/prasannavl/WinApi/blob/master/WinApi.Utils/DwmWindow.cs

Non normal NC windows are in most cases notoriously complicated and hard to implement. This is one of those things that help in implementing such so effortlessly.

mpolicki commented 6 years ago

Right, thanks for elaborating. I'm sure the default implementation is useful for the purposes you describe, however for the basic case of having a regular overlapped window, it does the wrong thing, at least from the perspective of someone coming from a WinAPI background. So it would be useful if the different semantics of these methods were somehow indicated.

prasannavl commented 6 years ago

From the perspective of the Window, this client area (not the non client area) is the client. From the perspective of Windows, the entire Window is the client. Hopefully, that makes sense to you.

May be WindowClientToScreen/ScreenToWindowClient to clear the confusion? Or perhaps just document it properly and leave it. Any feedback would be welcome.

mpolicki commented 6 years ago

From the perspective of the Window, this client area (not the non client area) is the client. From the perspective of Windows, the entire Window is the client. Hopefully, that makes sense to you.

It does, but I'm not quite sure why taking the perspective of Windows is relevant. Using the word "client" in the sense of "client area" for anything other than the client area of a window as defined by the API docs is confusing, and at the very least should be explicitly documented.

May be WindowClientToScreen/ScreenToWindowClient to clear the confusion? Or perhaps just document it properly and leave it. Any feedback would be welcome.

Frankly, I'm not sure what to call it. Take ClientToScreen for example; it takes a rectangle in coordinates relative to the client area of the window, translates them to screen coordinates, enlarges the rectangle by the size of the non-client area, and returns the enlarged rectangle. I honestly don't know what to call this operation...ClientToScreenAndAdjust maybe?

weltkante commented 6 years ago

How about LocalClientToScreen or just LocalToScreen to avoid confusion with the established ClientToScreen semantics of the Windows API?