• Welcome to Valhalla Legends Archive.
 

Menu Mouse Notification Question (C++)

Started by LordVader, March 01, 2005, 04:06 PM

Previous topic - Next topic

LordVader

Ok, currently have my program going with a nice little icon in the system tray, uses WM_RBUTTONDOWN to display a menu to do various things(neato!)..

My problem is this:
I need to trap the mouse event when I leave the menu or move to another program or just to desktop currently tried/playing with:

WM_MOUSELEAVE
WM_NCHITTEST //(need to play with this more)
WM_MOUSEACTIVATE //(need to try this one)


Could anyone give me any idea's on which notifications to catch.
Also I'm assuming I should use:

DestroyMenu(HMENU hmenu); 

to go ahead and hide the menu is that correct?

Any idea's are appreciated.

*Update:
Just saw:

WM_CAPTURECHANGED

On msdn bout to try that ill reply if it works or not.

LordVader


WM_CAPTURECHANGED

didn't work  :P

Still goin thru msdn found:

WM_ACTIVATEAPP


Probably can use that for what I need will check/post back shortly.

LordVader

Hrmm still not having any luck, activateapp results could possibly work if i can isolate the hwnd|hdlg for the systray, but that doesn't seem to be the same hwind|hdlg as the main window|dialog..

Still trying to figure this out  ::)

MyndFyre

It seems like you're approaching the problem incorrectly.  When you load your notification icon, you can use the CreatePopupMenu function.  When you want to display the menu, you can use the TrackPopupMenuEx function.  When you are hiding your icon and want to get rid of the menu resource from memory, *then* you use DestroyMenu -- don't use it to hide the menu.  TrackPopupMenuEx should do that automatically, with the following caveat:

(from the Remarks section)
To display a context menu for a notification icon, the current window must be the foreground window before the application calls TrackPopupMenu or TrackPopupMenuEx. Otherwise, the menu will not disappear when the user clicks outside of the menu or the window that created the menu (if it is visible).

To meet the requirements of the Remarks section, which says you need your application (the owner of the notification icon) to be the foreground window, you can call the SetForegroundWindow function. 

By the way -- I know you know this because you *have* been around here for some nontrivial amount of time -- you did NOT need to post three times.  *Modify* works wonders.
QuoteEvery generation of humans believed it had all the answers it needed, except for a few mysteries they assumed would be solved at any moment. And they all believed their ancestors were simplistic and deluded. What are the odds that you are the first generation of humans who will understand reality?

After 3 years, it's on the horizon.  The new JinxBot, and BN#, the managed Battle.net Client library.

Quote from: chyea on January 16, 2009, 05:05 PM
You've just located global warming.

LordVader

#4
Ok I seem to follow what your saying, so basically something in my code that im using to handle the icon & display menu is flawed, it should be releasing the menu when the current hwnd or hdlg (menu in this case) is out of focus ..

Also, hiding the icon and deleting menu resources isn't the issue, the issue is "souly" the menu once shown (in view). Getting it to release naturally if i don't use it, or shift to a new space|program or to desktop is the trouble im having.

Currently playing with the code:

VOID SS_TrayIcon::ShowMenuAtMouse(UINT nResourceID, HWND hWnd) const
{
    if( NULL == hWnd )
        hWnd = WindowHandle();

    HMENU hMenu;
    hMenu = ::LoadMenu(Instance(), MAKEINTRESOURCE(nResourceID));
    HMENU hPopup = ::GetSubMenu(hMenu, 0);
    ASSERT(hPopup != NULL);
   
    POINT point;
    GetCursorPos( &point );
    //RECT rect;
//rect = NULL;
    ::TrackPopupMenu(hPopup, TPM_LEFTALIGN|TPM_RIGHTBUTTON, point.x, point.y, 0, hWnd, NULL);
::DestroyMenu(hMenu);
}


Which is fired up by:

m_pTrayIcon = new SS_TrayIcon( hDlgInst, 1, 1 );
m_pTrayIcon->LoadIcon( 0, 0, IDI_MAINICON );
m_pTrayIcon->ShowIcon( 0 );
m_pTrayIcon->MapMessageToFunction(WM_RBUTTONDOWN, ::OnWM_RBUTTONDOWN);


The MapMessageToFunction for WM_RBUTTONDOWN shoots to:

LRESULT CALLBACK OnWM_RBUTTONDOWN(WPARAM wParam, LPARAM lParam)
{
m_pTrayIcon->ShowMenuAtMouse(IDR_TRAYMENU, hMainDlg);
    return 0;
}


May try to shift that over to your suggestions using CreateMenu & TrackPopupMenuEX..

The input is appreciated thx.

*Edit: Added extra code snippits.

LordVader

#5
Ahh good deal that worked thanks MyndFyre,
Adding SetForegroundWindow into the function allows it to to automatically release.
Is able to keep track now because it has a valid Window associated to it I believe. which I assume was the problem.

Code from above is now:

VOID SS_TrayIcon::ShowMenuAtMouse(UINT nResourceID, HWND hWnd) const
{
    if( NULL == hWnd )
        hWnd = WindowHandle();

    HMENU hMenu;
    hMenu = ::LoadMenu(Instance(), MAKEINTRESOURCE(nResourceID));
    HMENU hPopup = ::GetSubMenu(hMenu, 0);
    ASSERT(hPopup != NULL);
   
    POINT point;
    GetCursorPos( &point );
    //RECT rect;
//rect = NULL;
::SetForegroundWindow(hWnd);
    ::TrackPopupMenuEx(hPopup, TPM_LEFTALIGN|TPM_RIGHTBUTTON, point.x, point.y, hWnd, NULL);
::DestroyMenu(hMenu);
}


That did the trick thanks alot.

*Edit: Re-worded slightly