ShowWindowAsync doesn't activate a hidden+minimized window? - winapi

A given external (not owned by the current process) window (hWnd) is first minimized, then hidden:
ShowWindowAsync(hWnd, SW_MINIMIZE);
// wait loop inserted here
ShowWindowAsync(hWnd, SW_HIDE);
The following call properly restores it to the un-minimized (restored) state:
ShowWindow(hWnd, SW_RESTORE);
However, this call does not:
ShowWindowAsync(hWnd, SW_RESTORE);
In the second instance with ShowWindowAsync(), the window is un-minimized and no longer hidden, but it is not activated (remains behind other existing windows). Conversely, the first ShowWindow() call correctly activates the window.
Is this expected behavior? How can I restore the window (to the foreground) without relying on ShowWindow(), which is synchronous (blocking)? (The wait loop in the example can have a timeout, while ShowWindow() does not allow specification of a timeout.)
(WinXP SP3)

ShowWindowAsync posts a show-window event to the message queue of the given window. In particular, the window is shown by its thread, rather than your thread. And the difference is that your thread is the foreground thread, and can therefore activate another window, which it can't do itself.

Here's the solution as used:
ShowWindowAsync(hWnd, SW_SHOW);
// wait loop inserted here
ShowWindowAsync(hWnd, SW_RESTORE);
This is essentially an inversion of the snippet used to hide the window:
ShowWindowAsync(hWnd, SW_MINIMIZE);
// wait loop inserted here
ShowWindowAsync(hWnd, SW_HIDE);

Related

MFC: Show or minimize (to hide) window on startup

In CWinApp::InitInstance() I have:
if (!ProcessShellCommand(cmdInfo))
return FALSE;
m_pMainWnd->ShowWindow(m_MinimizeOnStartup ? SW_SHOWMINIMIZED : SW_SHOWNORMAL);
m_pMainWnd->UpdateWindow();
But my ShowWindow call is not resulting in an OnSize() or OnShowWindow() callback? During the ProcessShellCommand() those are called a few times as the first OnShowWindow() restores the window size when last shutdown via SetWindowPlacement(). That all works good, restoring to last state, but ProcessShellCommand() afterwards calls ShowWindow with SW_SHOW which causes a my hidden when minimized window to show on the taskbar. Where is the proper place to either show the window or minimize it (to hide it). Basically what happens is the minimize comes in (on SetWindowPlacement(), window is hidden, MFC later calls SW_SHOW which makes it minimized on the taskbar instead of hidden, my forced ShowWindow() doesn't do anything.
TIA!!
There is no OnSize() nor OnShowWindow() callback on ShowWindow() when already in those states. Set m_nCmdShow=SW_HIDE in CAppWnd then at the end of the InitInstance() call the SetWindowPlacement()

SendMessage(WM_SYSCOMMAND) failed when mouse captured

I'm using the win32sdk, but some messages would never work as expected while mouse was captured by calling SetCapture(), such as:
case WM_LBUTTONDOWN:
SetCapture(hWnd);
SendMessage(hWnd, WM_SYSCOMMAND, SC_MAXIMIZE, 0);
ReleaseCapture();
return 0;
The Window won't be maximized. but why?
Additional,
1. if I use PostMessage() instead, it works.
2. if I use PostMessage() instead and remove the ReleaseCapture(); statement, it doesn't work again.
In general:
PostMessage is asynchronous and you call ReleaseCapture() before WM_SYSCOMMAND is processed. So you have only one question: Why you can't maximize if mouse is captured?
I haven't found any info on this but read here:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms646262(v=vs.85).aspx
"When the mouse is captured, menu hotkeys and other keyboard accelerators do not work." I suppose WM_SYSCOMMAND is not processed also because of this restriction. May be it was done like this to keep coords consistent.
As norekhov said menu hotkeys don't work when the mouse is captured. When the mouse is captured the the only action a user can take that will result in the WM_SYSCOMMAND message being sent is to use a system menu hotkey.
Note that the WM_SYSCOMMAND message is only meant to be used to notify a window of a user initiated action. When you send it to a window, you're in essence trying to mimic a user's action. In this case you don't need to do this. You can tell the window to maximize itself directly:
ShowWindow(hWnd, SW_SHOWMAXIMIZED);
In this case it won't appear to be a user command, so it won't be ignored because the mouse has been captured.

XLIB Decoration questions

I'm writing a small window manager, that add a basic decoration around a window, but actually i have several question about adding/remove decoration of a window.
First Question
Actually the decoration is added during MapNotify event, but it seems to be not a good idea, because it add decoration also to a menu opened by an application everytime the mapnotify is fired with a new window, but i want only to add decoration to main window. Maybe i have to check if the current window is a child of another window ? Actually my code just create the decoration window with a specific name, so at every MapNotify request i give the decoration window a dummy name (Parent) to distinguish it from all other windows in that way if the MapNotify event is launched on a decoration window, at least it doesn't add another decoration.
But i don't understand if MapNotify is launched not only for parent window but also for childrend probably the risk is that i add more than one decoration window.
The actual code is the following:
void map_notify_handler(XEvent local_event, Display* display, ScreenInfos infos){
printf("Map Notify\n");
XWindowAttributes win_attr;
char *child_name;
XGetWindowAttributes(display, local_event.xmap.window, &win_attr);
XFetchName(display, local_event.xmap.window, &child_name);
printf("Attributes: W: %d - H: %d - Name: %s\n", win_attr.width, win_attr.height, child_name);
if(child_name!=NULL){
if(strcmp(child_name, "Parent")){
Window new_win = draw_window_with_name(display, RootWindow(display, infos.screen_num), "Parent", infos.screen_num,
win_attr.x, win_attr.y, win_attr.width, win_attr.height+DECORATION_HEIGHT, 0,
BlackPixel(display, infos.screen_num));
XMapWindow(display, new_win);
XReparentWindow(display,local_event.xmap.window, new_win,0, DECORATION_HEIGHT);
XSelectInput(display, local_event.xmap.window, SubstructureNotifyMask);
put_text(display, new_win, child_name, "9x15", 10, 10, BlackPixel(display,infos.screen_num), WhitePixel(display, infos.screen_num));
}
}
XFree(child_name);
}
So how to avoid adding of decoration on every window except the main application window (or the popup windows, there is a way to distinguish the type of window? How can i figure it out?)
Second Question
WHen i exit a program the window that is destroyed is just the application window not the parent decoration, how to destroy the current window and also the decoration?
I tried with the following:
void destroy_notify_handler(XEvent local_event, Display *display){
Window window = local_event.xdestroywindow.event;
XDestroyWindow(display, window);
}
But i receive the following error:
Error occurred: BadWindow (invalid Window parameter)
I use event instead of window because it seems that it contains the parent window (i read it from there: http://tronche.com/gui/x/xlib/events/window-state-change/destroy.html)
But even if i use window i have the same problem.
Or maybe i have to destroy the parent window earlier? Maybe during UnMapNotify? But how to understand if the event is launched just because the window is going to be closed or for some other reasons?
Thanks for the help :)
Read EWMH spec and you'll find answers to all questions.
Check "override redirect" window flag
You are trying
to destroy window which is already destroyed. Instead of using
event.xdestroywindow.event window id just delete your decoration
window.
Don't forget to add client window to save set if you are
writing reparenting WM. That way if you kill wm application windows
are not destroyed but reparented back to root window

Win32 prevent window "snap"

How can I disable the snap feature of Windows 7 for my application (progmatically)? Or is there any way to detect if the application has been snapped, and specifically call an API function to unsnap it?
Calling SetWindowPos() or ShowWindow() does not unsnap it correctly *(SW_MAXIMIZE does). Calling SetWindowPos() actually causes strange behavior in future calls to SetWindowPos() and MoveWindow(). The same inconsistencies do not apply to a window that is maximized.
I figured out a way to unsnap, by calling ShowWindow() with SW_MAXIMIZE. This is odd since no other values unsnap with this call, even though the window can be moved away, it is still anchored to the side of the screen. Maximizing it fixes the problem, whereafter I can move the window where it needs to be.
#define WM_RESTOREORIGINALSTYLE WM_USER+... /* your first free USER message */
case WM_SYSCOMMAND:
{
if(wParam==(SC_MOVE|2)) wParam=SC_SIZE|9;
if((wParam&0xFFE0)==SC_SIZE && (wParam&0x000F)) // handles MOVE and SIZE in one "if"
{
long int oldStyle=GetWindowLongW(hwnd,GWL_STYLE);
PostMessageW(hwnd,WM_RESTOREORIGINALSTYLE,GWL_STYLE,oldStyle);
SetWindowLongW(hwnd,GWL_STYLE,oldStyle &0xFEFEFFFF); // disable WS_MAXIMIZE and WS_MAXIMIZEBOX
DefWindowProcW(hwnd,WM_SYSCOMMAND,wParam,lParam);
return 0;
}
return DefWindowProcW(hwnd,WM_SYSCOMMAND,wParam,lParam);
}
case WM_RESTOREORIGINALSTYLE:
{
if((long int)wParam==GWL_STYLE)
SetWindowLongW(hwnd,GWL_STYLE,lParam);
return 0;
}
The PostMessage will be processed in subsequent message loop - it means ASAP after entering into move-size loop.
If you use own drawing method of frame, please do not forget to redraw your frame correctly on WM_STYLECHANGED message, internally store oldStyle in your class.
Why it works? Windows check snap condition at start of move/size action. If WS_MAXIMIZE and WS_MAXIMIZEBOX are disabled at start, the snap behaviour is disabled.
The SC_SIZE|9 is equivalent of SC_MOVE|2 without blocking redrawing for half a second.
If you don't want to enable dragging maximized windows if they are fully maximized, check state of SC_MOVE item in system menu and if it is enabled, directly return 0 in WM_SYSCOMMAND.
Verified on Windows 8.1.

How can I stop window rendering and later resume?

I'd like to prevent my window from being updated until I finish receiving data from the server and render it. Can I hook on the WM_PAINT event, or better still call some Win32API method to prevent the window from being updated and unfreeze it later?
More info:
In the context of an MMC snapin written in C#, our application suffers from annoying flickering and double sorting behaviour:
We use MMC's listViews, but since we subscribe to the sort event.
MMC does it's own magic and sorts the page being displayed (and we can't override that), and when we receive a reply from our server we change the listView again.
each row change is done sequentially, there's no beginUpdate etc. (AFAIK).
Normally hooking into WM_PAINT is the way to go, but make sure you also ignore all WM_ERASEBKGND notifcations, otherwise you'll still get flicker, because Windows erases the Windows area for you. (Return non-zero to prevent Windows from doing that)
One other possibility is to use the LockWindowUpdate function, but it has some drawbacks:
Only one window can be locked
Upon unlock the whole desktop and all sub-windows (i.e. everything) is repainted, resulting in short flash of the whole desktop. (It's worse on XP than on Vista)
Some controls have BeginUpdate and EndUpdate APIs for this purpose.
If you do something (e.g. hook and ignore paint events) do disable painting, then a way to force a repaint later is to call the Invalidate method.
OK, after all searching and checking I've found that LockUpdateWindow is bad idea - see for example articles of Raimond Chen OldNewThing. But even to implement the idea of SetRedrawWindow wasn't so simple - because what I had was only received from IConsole2* pConsole->GetMainWindow() HWND handler of main window. By setting it to SetRedraw = FALSE it was disappeared in very strange manner. Though to make the procedure run only for the TreeView and not for the whole application (ours left panel) I ran
EnumChildWindows(hWnd, SetChildRedraw, FALSE); //stopping redraw
//... here you do your operations
EnumChildWindows(hWnd, SetChildRedraw, TRUE); //restarting redraw
where SetChildRedraw callback was defined in next way:
#define DECLARE_STRING(str) TCHAR str[MAX_PATH]; ZeroMemory(str, sizeof(str));
BOOL CALLBACK SetChildRedraw(HWND hwndChild, LPARAM lParam)
{
RECT rcChildRect; ZeroMemory(&rcChildRect, sizeof(rcChildRect));
DECLARE_STRING(sText)
GetClassName(hwndChild, sText, MAX_PATH);
if (wcsstr(sText, L"SysTreeView32") != NULL)
{
SetWindowRedraw(hwndChild, lParam);
if (lParam == TRUE)
{
GetWindowRect(hwndChild, &rcChildRect);
InvalidateRect(hwndChild, &rcChildRect, TRUE);
}
}
return TRUE;
}

Resources