How to check if my window gets hidden/visible? - c++

If i press the "show desktop" button in Windows7, my program will still think its not minimized, and if i press WIN+D while my program is focused, only then my program will catch this minimize command. How can i check for 100% sure that my program is visible or not?
Here is my main loop:
while(!done){
if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)){
if(msg.message == WM_QUIT){
done = TRUE;
}else{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}else if(active){
render();
}
}
Edit3: Is this good? looks like its working:
case WM_WINDOWPOSCHANGED:
{
flags = ((PWINDOWPOS)lParam)->flags;
if((flags & 0x8000) && (flags & SWP_NOCOPYBITS) && (flags & SWP_FRAMECHANGED)){
active = !(flags & SWP_NOACTIVATE);
}
if((flags & 0x1000) && (flags & 0x0800) && (flags & SWP_NOMOVE) && (flags & SWP_NOSIZE)){
active = 1;
}
}
case WM_ACTIVATE:
{
active = !HIWORD(wParam);
return 0;
}

WM_ACTIVATE is sent when another window becomes active. When you say show desktop, no other window becomes active, so technically, your app is still active, even though it has been minimized.
You probably want to watch for WM_WINDOWPOSCHANGED. You can look at the flags to see what type of position event it was, or you can check IsIconic and IsWindowVisible whenever the window position changes.

There are a variety of potential functions that may get you the information you need depending on exactly what you want to do:
GetForegroundWindow() : Gets the window the user is currently "working" with. You could use this if you only wanted to draw things when a user is using your application but not another one.
GetActiveWindow() : Returns the active window within the calling thread which is probably not what you want. This might be useful if you wish to enable/disable drawing depending on which window was active within your own application.
GetFocus() : Returns the window with the current keyboard focus in the calling thread. Probably not what you want and use GetForegorundWindow() instead.
IsWindowVisible(): Returns whether the show/hide flag of the window is set to visible. This doesn't actually tell you whether the window is actually visible on the screen.
GetTopWindow(): Tells you the highest window in the z-order but not whether it actually has the focus/foreground. It may be possible for your window to be focused/activate/foreground but not have the highest z-order (I think anyways).
From your comments, however, you seem to actually want to see if there is at least one pixel of your window actually visible on the screen. For that I would probably use the technique mentioned in this SO question using the strangely named GetRandomRgn() although a simpler check may be to use GetClipBox() and check the return code for NULLREGION.

With Windows 8/10, there's another window visibility flag which is separate from IsWindowVisible. Check DwmGetWindowAttribute and the DWMWA_CLOAKED attribute.
Additionally, windows can be semitransparent, and GetLayeredWindowAttributes can tell you what the alpha level of a window is.

IsWindowVisible tells you if your window is visible. GetTopWindow tells you if it is the uppermost one in the Z order.

Try WM_ACTIVATEAPP.
wParam will be false if a window from any other app is getting focus. This includes pressing the "show desktop" button.

Related

Gtk app on Windows, how to disable the Control-Win-Left/Right/Up/Down keybindings?

Windows 10/11 defines the following key bindings for all applications by default:
Win+Left/Right : split view mode (i.e. dock window against left or right side of screen);
Ctrl+Win+Left/Right : scroll to previous/next workspace.
Gtk 3.x also by default associates Ctrl+Win+Left/Right with split view actions. Thus pressing Ctrl+Win+Left/Right with a Gtk 3.x application in focus on Windows 10 causes both the application window to go into split view mode and a workspace switch. This is confusing. By comparison, non-Gtk apps ignore the Ctrl+Win+arrow combinations.
I tried hooking a signal handler to intercept key press events in my application window, that I would then use to block the unwanted key combinations, i.e. (C++):
add_events( Gdk::EventMask::ALL_EVENTS_MASK );
signal_event().connect(
[&] ( GdkEvent* pEvent ) -> bool
{
// Return 'true' if match, do not propagate the event further:
if( pEvent->type == Gdk::KEY_PRESS && pEvent->key.keyval == GDK_KEY_Left )
{
return true;
}
else
{
return false;
}
} );
This does block the Left arrow key (with any combination of modifier keys)... but the particular Win+anything combinations are handled at a lower lever and never reach the handler.
Then I did find the documentation on GtkBindingSet and added definitions in my gtk.css file to unbind Ctrl+Win+Left/Right in the application, but it also had no effect. I know that the binding set is loaded in the app because I can define other keybindings that do work (i.e. I successfully changed the behavior of the Left/Right keys in GtkEntry widgets).
This is the CSS that I added which does not work. The syntax appears correct since other definitions in the same file do take effect, just not my binding set:
#binding-set ms-keys {
unbind "<Control><Super>Left";
unbind "<Control><Super>Right";
unbind "<Control><Super>Up";
unbind "<Control><Super>Down"; }
Window { -gtk-key-bindings: ms-keys; }
I'm not a CSS expert, perhaps I'm doing something wrong? I've run out of ideas to try, any help appreciated.

Change cursor when hovering a child window

I have a window that asks for Login/Password with five child windows:
An editable one: Login
Another editable one: Password
An OK button
A "forgot your password" one
And a "Register" one.
Basically, when you click on either of the last two, you are sent to a website where you can perform the appropriate actions.
It's all fine and dandy, but I would love to know how it's possible to check (with messages I guess) if the mouse cursor is hovering over one of the two links, and if that's the case, to change it to a hand cursor.
I'd especially like to know how to detect it! I can figure out how to change the cursor afterwards with SetCursor and such!
EDIT: I actually found out that WM_SETCURSOR is a really easy message to handle. Basically, you check if the wParam is equal to the handle of the child window it's hovering over and voilĂ !
But I actually find the SetCursor to be a bigger issue.
Here's what I did:
The declaration of my cursors:
static HCURSOR hCursorHand;
static HCURSOR hCursorArrow;
The value is set here (in the handle for WM_CREATE):
hCursorHand = LoadCursor( NULL, IDC_HAND );
hCursorArrow = LoadCursor( NULL, IDC_ARROW );
And here's where I set it:
else if (msg == WM_SETCURSOR)
{
if ((HWND)wParam == hwndLinkFPasswd || (HWND)wParam == hwndLinkSignUp)
SetCursor(hCursorHand);
else
SetCursor(hCursorArrow);
}
I know the cursor is properly detected (thank you breakpoints), but it doesn't seem to do anything. The cursor stays an arrow...
So! As I said, I figured it out! (I just couldn't answer my question within the first 8 hours!)
Here's what I missed: (for anyone having the same problem)
else if (msg == WM_SETCURSOR)
{
if ((HWND)wParam == hwndLinkFPasswd || (HWND)wParam == hwndLinkSignUp)
{
SetCursor(hCursorHand);
return(TRUE);
}
}
I find the documentation on this API awful, so I hope my contribution will one day help someone in my situation! ;)

How to reinstate ClipCursor constriction after alt-tab switching away and back

I'm trying to restrict the mouse pointer (with a custom cursor) to the client area of the window for my app which works initially but runs into problems when I switch away from the app and back. I'm using ClipCursor() to restrict the cursor and using a couple of different cursors which are situation dependant so I'm using SetCursor() instead of setting the window's class cursor.
I've got the cursor reinstating itself correctly when Alt-Tabbing away from the app and back (which I want to allow) by checking for the WM_SETCURSOR message in my WndProc:
case WM_SETCURSOR:
{
if (mIsMouseGrabOn) // a bool that indicates if the mouse should be restricted to the cient area or not
SetCursor(gmInstance->m_cursorTargetGreen);
else
SetCursor(gmInstance->m_cursorTargetRed);
return 0; // prevent DefWndProc from resetting it
}
but on switching back the cursor is no longer clipped to the client area of my app's window. I've tried checking for WM_ACTIVATEAPP (as shown below) with no luck and tried checking for WM_ACTIVATE with the same code and the same result.
case WM_ACTIVATEAPP:
{
if(wParam == TRUE) // When we are activated
{
if (mIsMouseGrabOn)
GrabMouse(); // function to determine client area and call ClipCusor with the results
else
ClipCusor(NULL); // make the sure cursor is freed
}
else if(wParam == FALSE) // When we are deactivated
{
ClipCursor(NULL);
}
//return 0; // Let DefWndProc handle anything else
}
With the above code in place, the cursor changes correctly but doesn't get captured regardless of the state of mIsMouseGrabOn.
How do I get my cursor to be bound correctly when switching away from the app and back? What message(s) should I be watching for instead of WM_ACTIVATEAPP?
You can watch lost focus and got focus messages
1) WA_ACTIVE or WA_CLICKACTIVE - window got focus
2) WA_INACTIVE - window lost focus
and you should watch if your app run in fullscreen mode:
3) WM_DISPLAYCHANGE - when Windows changing desktop resolution
and resize message
WM_SIZE - if wparam equals SIZE_MINIMIZED,SIZE_MAXIMIZED or SIZE_RESTORED you can clip or unclip cursor
WM_SETFOCUS is sent after the Window receives keyboard focus, which allows ClipCursor to work.

C++ subclassing a form to trap F1 - F12 keys

The main form opens a child form that has a handful of button CONTROLs on it. I need to trap keyboard events so I subclassed one of the controls. All is good until the control loses focus of course.
Ideally, as long as this child form is open I would like to assign the focus to this control and thus trap all the keystrokes, no matter where the user clicks.
I suspect superclassing might be a better way to go but I am not as familiar with it.
Perhaps what I should do is use accelerators on the main form?
ADDED:
I should mention that the main form has a large listview control that is subclassed to recover up/down arrows and mousewheel etc.
The traditional way is to install a keyboard hook (SetWindowsHookEx), but you need to inject it into every application, and it doesn't work across 32/64 bit boundaries.
What you can do however, and quite easily at that, is to poll the keyboard with GetKeyboardState on a timer and check whether your f1-f12 keys are activated. The timer can be as slow ticking as 100ms and it will catch almost everything while using virtually no resources.
Assuming that this is within Windows and the Win32 API, one option is to look for messages in your main GetMessage, TranslateMessage, DispatchMessage loop. You can special-case any message within this loop, irrespective of which window it's aimed at.
You should probably use IsChild to check that the message is intended for a control on your main window (as opposed to some dialog box or message box that might be displayed separately). Getting the logic right can be fiddly, too. It would be best to only intercept messages when you know your control has lost the focus, and only intercept the exact messages you need to.
Years ago, I wrote a library message loop with a lot of this built in. I had a simple manager class that held pointers to instances of my own little window class. The loop knew the difference between dialogs and normal windows, gave each window class a chance to spy on its childrens messages, and so on. You won't be able to run this directly and the conventions are a bit strange, but you might find this useful...
int c_Window_List::Message_Loop (void)
{
MSG msg;
bool l_Handled;
while (GetMessage (&msg, NULL, 0, 0))
{
l_Handled = false;
c_Windows::c_Cursor l_Cursor;
bool ok;
for (ok = l_Cursor.Find_First (g_Windows); ok; ok = l_Cursor.Step_Next ())
{
if (IsChild (l_Cursor.Key (), msg.hwnd))
{
if (l_Cursor.Data ().f_Accelerators != NULL)
{
l_Handled = TranslateAccelerator (l_Cursor.Key (), l_Cursor.Data ().f_Accelerators, &msg);
if (l_Handled) break;
}
if (l_Cursor.Data ().f_Manager != 0)
{
l_Handled = l_Cursor.Data ().f_Manager->Spy_Msg (l_Cursor.Key (), msg);
}
if (l_Handled) break;
if (l_Cursor.Data ().f_Is_Dialog)
{
l_Handled = IsDialogMessage (l_Cursor.Key (), &msg);
if (l_Handled) break;
}
}
}
if (!l_Handled)
{
TranslateMessage (&msg);
DispatchMessage (&msg);
}
if (g_Windows.Size () == 0)
{
// When all windows have closed, exit
PostQuitMessage (0);
}
}
return msg.wParam;
}
The f_ prefixes mean field - I picked up the m_ convention later, but this code hasn't been revisited in a very long time. f_Manager in particular points to an instance of my c_Window_Base class. The c_Cursor class is a kind of iterator, used to step through all the windows stored in the g_Windows variable (actually a static class member rather than a global).

Finding a window and setting focus on it

1.I want to find a window and set focus on it , but window is not taking the focus.
2.If i use HWND_TOP then it does not make the window active and if i use HWND_TOPMOST then it make window always on top.
Can anyone help me ??
HWND hwndAppDlg = ::FindWindowEx(hwndDesktop,NULL,lpszClass,lpszWindow);
if(hwndAppDlg && IsWindow(hwndAppDlg))
{
CRect rcAppDlg;
if( 0 == ::GetWindowRect(hwndAppDlg,rcAppDlg))
{
OutputDebugString(L"\n GetWindowRect failed...");
return FALSE;
}
if(0 == ::SetWindowPos(hwndAppDlg,HWND_TOPMOST,rcAppDlg.left,rcAppDlg.top,rcAppDlg.Width(),rcAppDlg.Height(),SWP_SHOWWINDOW))
{
OutputDebugString(L"\n SetWindowPos failed...");
return FALSE;
}
if(0 == ::PostMessage(hwndAppDlg,WM_SETFOCUS,0,0))
{
OutputDebugString(L"\n WM_SETFOCUS failed");
return FALSE;
}
return TRUE;
}
You're sending WM_SETFOCUS, but that does not set the focus. That message is sent to a control if it gained or lost the focus, but when that message is sent/received, the focus change has already happened.
To actually set the focus (you don't need to send the WM_SETFOCUS message), use SetFocus() if you know which control in the dialog should get the focus, or SetForegroundWindow() to set the focus to the dialog itself and let the dialog determine which subcontrol actually will get the focus.
Both of these APIs will send WM_SETFOCUS automatically.
How about ShowWindow( hwndAppDlg, SW_SHOW );
I have used ::SetForegroundWindow(hwndAppDlg) to activate and set focus on the dialog and it works cool.