How do I seamlessly call MoveWindow on a maximized window in Windows? - c#

I have a C# application that is attempting to create a customizable version of Windows's Snap functionality. I primarily use the native functions MoveWindow and ShowWindowAsync. I also use GetWindowPlacement to determine maximized/normal/minimized state.
I can seamlessly snap a "normal" window around to my user definable frames. The window instantly snaps to new desired position and size.
The problem is when I transition from maximized to normal. If I only call MoveWindow then the window snaps to my desired position and size. However the window still thinks it's "maximized" which causes attempts to re-maximize to fail.
However if I call ShowWindowAsync(wnd, SW_SHOWNORMAL) followed by MoveWindow(wnd, x, y, width, height, true) it causes the maximized window to animate to it's old position then snap to its new position. This is very jarring and unpleasant. Attempting to flip the call order or use ShowWindow instead of ShowWindowAsync does not help.
The answer to this question might be to disable the animation. I have not found a clean way to do that.

Solution found!
The fix is to call SetWindowPlacement instead of MoveWindow. SetWindowPlacement takes a WINDOWPLACEMENT structure which allows setting both position/size and showCmd state at the same time.

Related

How to resize a window with a certain key-combo + mouse move? (like Alt+F8 in Linux) Not click and drag

In a C# winform app, I'm trying to implement some of Linux window manager features.
I already did a lot of stuff, but right now, I'm trying to do the re-sizing part, where you press a certain combo at a window, then move your mouse to the right/left, the width of the window increases to the right/left, move it diagonally, the window will increase in both directions.
Now I already know how to register the hotkeys, get/set mouse cursor pos, move a window, etc. All in winapi.
The thing that I can't seem to get that much, is how can I increase the window's, say width, in one direction? if I normally increase it, it will span in both directions. I gave this a thought, and I think that: the window will increase in both directions, but if we want to just increase it's width to the right, we keep re-positioning/moving it at it's start point, so that the left side of it will remain fixed, will the right one will span.
What is the right and easy way to do this? Am I right about my guess?
And please note that I don't just want this to work only in my form, but on any window.
Any C++/C#/Winapi code would help.
Any ideas/thoughts of some sort would also be great.
Thanks a lot.
Any Windows window:
Alt+Space - brings up the standard Windows menu
S - selects Size
Arrow keys (Or Mouse) - Resizes the window
Enter - commits the operation

Get which process/window is actually visible in C#

I have a list of all open windows, the ones in the windows taskbar. What I want to do is to remove the ones that are not visible from the list.
What I mean is, if a window is hidden by another one, it should not be in my list.
I've been searching google for the past two days without success...
Any ideas?
PS: I can get the location and size of each process, so getting the last time a process was used/idle time would work too...
You need to use regions, what's still visible of the window can be a complex set of rectangles. Start with the window you want to check, GetWindowRect and CreateRectRegion to create a region for the window rectangle.
Call GetWindow() in a loop, passing GW_HWNDPREV. Which returns the previous window in the Z-order so it could overlap. GetWindowRect() to get its rectangle, CreateRectRegion() and combine that with the original window region using CombineRgn() with RGN_DIFF.
When GetWindow returns NULL you've found all possible overlapping windows. Use GetRgnBox to check if there's anything left of the region. If there is, at least one part of the window wasn't overlapped.

Get a window by coordinates

I have a point in screen coordinates and I need to find which window it "falls" onto. I.e. find the window (hWND) that is foremost of all windows containing the point. Pinvoke and WinApi is fine...
PS. I actually need to detect, which window is my mouse cursor currently "over", to put it another way.
Use WindowFromPoint.

Implement sticky overlays in .NET

I'm looking for a nice way to render overlays over a native Windows form not owned by myself preferably using a library available for .NET (WinForms, GTK#, ...). Precisely, I'd like to display a few labels or text boxes at a given location on the window.
Device Context & System.Drawing: What I'm currently doing is drawing directly onto the other windows' device context, which causes flickering, as parts of the other application are redrawn in unpredictable intervals. I therefore would have to catch its WM_PAINT event using hook magic, but that's actually not as far down as I'd like to go unless there's no simpler way.
Transparent window overlay with visible child labels: another technique I tried was creating a Windows.Forms.Form with the other windows' size, using TransparencyKey to make only the children visible. This seems pretty hard to get correct, as I don't want the window to be the upper-most one but only exactly one Z-level above the foreign window. The upside would be, that I could add more behaviour to it, as I could actually handle click events, etc.
How would you implement it / deal with the problems in the two techniques described above?
Definitely go with the transparent window approach as that should be simpler to implement. Creating a transparent form is very easy. You already know how to use the TransparenyKey to get the background to not drawn. Also remove the border from the window and remove the min/max/close buttons so you do not have any chrome showing.
Create your window as owned by the window of interest and it will always be on top of the target and act like a modeless dialog. I.e. it is visible only when the owning window is visible.
Thanks for your answer, but I'm still a little confused. How exactly would you set the owner of a window to anything not owned by your own application? I guess that's not even possible when the other application is unmanaged, is it?
Edit:
I now got a little step closer. The example code is in Boo.
[DllImport("user32.dll", SetLastError: true, CharSet: CharSet.Auto)]
public def SetParent(child as IntPtr, parent as IntPtr):
pass
def createAttachedForm(parentHandle as IntPtr):
f = Form()
f.Text = "My overlay"
f.Show()
SetParent(f.Handle, parentHandle)
Application.Run(f)
Now only the TransparencyKey thing doesn't seem to work. Instead the form is completely invisible when the value is set.
Setting the owner of a form can be done with
Form.Show(IWin32Window w)
where w exposes the Handle to the parent window.

How to restore minimized window without flicker

I've made an expose-clone for Vista that sometimes need to restore a minimized window.
I've managed to do this with the SetWindowPlacement function.
The problem is that this also repaints the window which looks like crap after the window nicely has slided into the screen.
This is the code i use to bring a window to the top and give it focus:
private static void ActivateWindow(IntPtr windowToShow)
{
RectAPI r = new RectAPI();
Win32.GetWindowRect(windowToShow, ref r);
if (r.top == -32000) //r.top is -32000 if the window is in minimized state
{
WINDOWPLACEMENT wp = new WINDOWPLACEMENT();
Win32.GetWindowPlacement(windowToShow, ref wp);
if (wp.flags == WindowPlacementFlags.WPF_RESTORETOMAXIMIZED)
wp.showCmd = cmdShow.SW_SHOWMAXIMIZED;
else
wp.showCmd = cmdShow.SW_RESTORE;
Win32.SetWindowPlacement(windowToShow, ref wp);
}
Win32.SetForegroundWindow(windowToShow);
}
If i use it on a window that is already restored it will only call SetForegroundWindow and the window will get to the top of the z-order and get focus without any flicker.
But if i call it on a minimized window I also have to use SetWindowPlacement to bring back the window to restored state. This is what causes the window to repaint and flicker :/
There has to be a way to restore a minimized window without the flicker because the built in window manager does this.
One way to do it is to use double-buffering technique: paint to an off-screen bitmap, then restore, then blit the bitmap to the screen. But it seems like overkill if restoring a minimized window is the only scenario where it's needed. Maybe others will have better ideas?..
Also, if you paint entire window client area, you can disable WM_ERASEBKGND (or rather, say that you processed it but don't do anything) to avoid unneeded fill-with-background-then-redraw sequence.
This link on MSDN will explain how you would want to handle the window painting in your case. Window events like window refresh or minimize/maximize will require repainting of your window or a region of the window.
Happy Coding!!
I'm OP...accidentaly ate my cookie.
Studied how windows flip3d and the taskbar manages this a bit closer and they actually repaint the window before they start the animation of the thumb.
Try to minimize a window and then restore it with flip3d, you will see a small blink on the 3d-window before it get restored.
Tried the same thing with my app and it looks alot better, not perfect but acceptable :/

Categories

Resources