Professional UI Solutions
Site Map   /  Register
 
 

Forum

Please Log In to post a new message or reply to an existing one. If you are not registered, please register.

NOTE: Some forums may be read-only if you are not currently subscribed to our technical support services.

Forums » Prof-UIS Tech Support » WM_MOUSEACTIVATE not sent in Prof-uis controls Collapse All
Subject Author Date
Raffaele Cappelli Feb 19, 2006 - 3:18 AM

It seems a bug: steps to reproduce the behaviour:


1) Modify the MDI sample by adding two buttons in CChildView:


CExtButton m_wndButton1;


CButton m_wndButton2;


2) Create the two controls at the end of CChildView::OnCreate:


m_wndButton1.Create("test",WS_CHILD|WS_VISIBLE,CRect(10,10,200,30),this,1001);


m_wndButton2.Create("test",WS_CHILD|WS_VISIBLE,CRect(10,40,200,60),this,1002);


 


3)

Raffaele Cappelli Feb 19, 2006 - 3:21 AM

3) Run the app and open two MDI child wnd: if you click on the traditional cbutton of the non-active child, it is activated as expected, but if you click on the cextbutton, the mdi child is not activated.


The same happens with other controls (toolbar, tabwnd, ...)


 

Technical Support Feb 19, 2006 - 11:00 AM

We tried to reproduce the problem with buttons inside the CChidView window of the MDI sample application in the way you desscribed. Here are the source code and executable of this modified app. We did not come across the problem with activating the inactive MDI child frame window by clicking any button.

We confirm the problems with MDI child frame activation when clicking a toolbar button or a tab item. To fix this, please update the source code of the CExtControlBar::_ActivateOnClick() method in the ExtControlBar.cpp file and the source code of the CExtTabWnd::_ProcessMouseClick() method in the ExtTabWnd.cpp file:

void CExtControlBar::_ActivateOnClick()
{
    ASSERT_VALID( this );
HWND hWndOwn = GetSafeHwnd();
    if(     hWndOwn == NULL
        ||  (! ::IsWindow(hWndOwn) )
        )
        return;
HWND hWndActivate = NULL;
    if( m_bPresubclassDialogMode )
        hWndActivate = ::GetParent( hWndOwn );
    else
        hWndActivate = _GetDockingFrameImpl()->GetSafeHwnd();
    if( hWndActivate == NULL )
    {
        ::SetFocus( hWndOwn );
        return;
    }
CWnd * pWndPermanent = CWnd::FromHandlePermanent( hWndActivate );
    if( pWndPermanent != NULL )
    {
        CMDIChildWnd * pWndMDIChild =
            DYNAMIC_DOWNCAST( CMDIChildWnd, pWndPermanent );
        if( pWndMDIChild != NULL )
        {
            CFrameWnd * pWndFrame =
                pWndMDIChild->GetParentFrame();
            if( pWndFrame != NULL )
            {
                CMDIFrameWnd * pWndMDIFrame =
                    DYNAMIC_DOWNCAST( CMDIFrameWnd, pWndFrame );
                if( pWndMDIFrame != NULL )
                {
                    CMDIChildWnd * pActive =
                        pWndMDIFrame->MDIGetActive();
                    if( pWndMDIChild != pActive )
                        pWndMDIChild->MDIActivate();
                    return;
                }
            }
        }
    }
HWND hWndFocus = ::GetFocus();
    if( hWndFocus == NULL )
    {
        ::SetFocus( hWndActivate );
        return;
    }
    if(     hWndActivate != hWndFocus
        ||  (! ::IsChild( hWndActivate, hWndFocus ) )
        )
    {
        if( ! CExtPopupMenuWnd::TestHoverEnabledFromActiveHWND( hWndOwn ) )
            ::SetFocus( hWndActivate );
    }
}
 
bool CExtTabWnd::_ProcessMouseClick(
    CPoint point,
    bool bButtonPressed,
    INT nMouseButton, // MK_... values
    UINT nMouseEventFlags
    )
{
    ASSERT_VALID( this );
    if( GetSafeHwnd() == NULL )
        return false;
    if( bButtonPressed )
    {
        CWnd * pWndTestChildFrame = GetParentFrame();
        if(        pWndTestChildFrame != NULL
            &&    pWndTestChildFrame->IsKindOf( RUNTIME_CLASS( CMDIChildWnd ) )
            )
        {
            CFrameWnd * pWndFrame =
                pWndTestChildFrame->GetParentFrame();
            if( pWndFrame != NULL )
            {
                CMDIFrameWnd * pWndMDIFrame =
                    DYNAMIC_DOWNCAST( CMDIFrameWnd, pWndFrame );
                if( pWndMDIFrame != NULL )
                {
                    CMDIChildWnd * pActive =
                        pWndMDIFrame->MDIGetActive();
                    if( pWndTestChildFrame != pActive )
                        ((CMDIChildWnd*)pWndTestChildFrame)->MDIActivate();
                }
            }
        }
    } // if( bButtonPressed )
 
LONG nHitTest = ItemHitTest( point );
    switch( nHitTest )
    {
    case __ETWH_BUTTON_LEFTUP:
    case __ETWH_BUTTON_RIGHTDOWN:
    case __ETWH_BUTTON_SCROLL_HOME:
    case __ETWH_BUTTON_SCROLL_END:
    case __ETWH_BUTTON_HELP:
    case __ETWH_BUTTON_CLOSE:
    case __ETWH_BUTTON_TAB_LIST:
        return
            OnTabWndClickedButton(
                nHitTest,
                bButtonPressed,
                nMouseButton,
                nMouseEventFlags
                );
    default:
        if( nHitTest < __ETWH_TAB_FIRST )
        {
            OnTabWndMouseTrackingPushedStop();
            Invalidate();
            UpdateWindow();
            return false; //true;
        }
    break;
    }
    ASSERT( nHitTest >= 0 && nHitTest < ItemGetCount() );
    if( bButtonPressed )
        m_ptStartDrag = point;
    return
        OnTabWndClickedItem(
            nHitTest,
            bButtonPressed,
            nMouseButton,
            nMouseEventFlags
            );
}

Raffaele Cappelli Feb 19, 2006 - 5:10 PM

Thank you for the prompt reply. Yes, in the modified MDI sample you provided the problem does not occur, but you created the two buttons in the CChildFrm and not in the CChildView, please try to create the buttons in the CChildView (at the end of OnCreate() ).

Technical Support Feb 20, 2006 - 9:34 AM

Your report is really interesting. We have modified the CExtButton::OnLButtonDown() method in the ExtButton.cpp file to let the parent MDI child frame window be activated when the CExtButton window is clicked:

void CExtButton::OnLButtonDown(UINT nFlags, CPoint point) 
{
    if( m_bKeyTracking )
        return;
    CButton::OnLButtonDown( nFlags, point );
HWND hWndOwn = m_hWnd;
    if( IsWindowEnabled() )
    {
        CFrameWnd * pParentFrame = GetParentFrame();
        if(        pParentFrame != NULL
            &&    pParentFrame->IsKindOf( RUNTIME_CLASS(CMDIChildWnd) )
            )
        {
            CFrameWnd * pMDIFrame = pParentFrame->GetParentFrame();
            if(        pMDIFrame != NULL
                &&    pMDIFrame->IsKindOf( RUNTIME_CLASS(CMDIFrameWnd) )
                )
            {
                CMDIChildWnd * pActive = ((CMDIFrameWnd*)pMDIFrame)->MDIGetActive();
                if( LPVOID(pParentFrame) != LPVOID(pActive) )
                    ((CMDIChildWnd*)pParentFrame)->MDIActivate();
            }
        }
        if( ! ::IsWindow( hWndOwn ) )
            return;
        if( ::GetFocus() != hWndOwn )
            ::SetFocus( hWndOwn );
    } // if( IsWindowEnabled() )
    if( ! ::IsWindow( hWndOwn ) )
        return;
    _DoClick();
}


Raffaele Cappelli Feb 20, 2006 - 10:46 AM

Thank you for being so quick in providing the fix. However, I have a question: why instead of manually handling the activation for the MDIChild case, don’t you send the WM_MOUSEACTIVATE message as normal controls do? Is there any side effect that you want to avoid, or any other problem that may prevent the normal approach from working?


 

Technical Support Feb 21, 2006 - 1:24 AM

There are several types of button types supported by the button common control. The most often used are the push button, default push button, check box and radio button. When the CExtButton (or CExtColorButton or CExtCheckBox or CExtRadioButton or CExtHyperlink) class subclasses the button common control, it remembers the type of the subclassed button for further behavior and appearance implementation and changes the real type of the button common control to the owner draw button. This is the single way to redraw any type of the button correctly. The owner drawn button type is the absolutely stand alone mode of the button common control which have no predefined appearance nor behavior implementation. As you can see, the CExtButton::OnLButtonDown() method invokes the CButton::OnLButtonDown() method. This means the WM_LBUTTONDOWN standard Windows message is delivered to the original window procedure of the button common control. The WM_MOUSEACTIVATE standard Windows message is also delivered to there. We guess, the buggy MDI child frame activation is caused by undefined behavior implementation of the owner draw button type.

Raffaele Cappelli Feb 21, 2006 - 1:13 PM

I made some tests and it seems that the problem is related to the mouse capture. In OnMouseMove you capture the mouse (I guess to detect the mouse leave) and it seems that the default button implementation does not send WM_MOUSEACTIVATE when there is a capture active (which may be reasonable): if you comment out

CExtMouseCaptureSink::SetCapture( GetSafeHwnd() ); in OnMouseMove, it should work. Of course this is not a fix, I will keep the one you proposed, unless you find something better with this further information.

Technical Support Feb 22, 2006 - 11:36 AM

Thank you for the information but you are comparing the standard push button with the owner draw button (the CExtButton class). These two types cannot be compared directly.