[RSHELL]
[reactos.git] / base / shell / rshell / CMenuBand.cpp
index 229cb1e..a9979b9 100644 (file)
@@ -35,27 +35,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(CMenuBand);
 extern "C"
 HRESULT WINAPI CMenuBand_Constructor(REFIID riid, LPVOID *ppv)
 {
-    HRESULT hr;
-#if USE_SYSTEM_MENUBAND
-    hr = CoCreateInstance(CLSID_MenuBand,
-        NULL,
-        CLSCTX_INPROC_SERVER,
-        riid, ppv);
-#else
-    *ppv = NULL;
-
-    CMenuBand * site = new CComObject<CMenuBand>();
-
-    if (!site)
-        return E_OUTOFMEMORY;
-
-    hr = site->QueryInterface(riid, ppv);
-
-    if (FAILED_UNEXPECTEDLY(hr))
-        delete site;
-#endif
-
-    return hr;
+    return ShellObjectCreator<CMenuBand>(riid, ppv);
 }
 
 CMenuBand::CMenuBand() :
@@ -75,7 +55,10 @@ CMenuBand::CMenuBand() :
     m_hotItem(-1),
     m_popupBar(NULL),
     m_popupItem(-1),
-    m_Show(FALSE)
+    m_Show(FALSE),
+    m_shellBottom(FALSE),
+    m_trackedPopup(NULL),
+    m_trackedHwnd(NULL)
 {
     m_focusManager = CMenuFocusManager::AcquireManager();
 }
@@ -89,6 +72,9 @@ CMenuBand::~CMenuBand()
 
     if (m_SFToolbar)
         delete m_SFToolbar;
+
+    if (m_hmenu)
+        DestroyMenu(m_hmenu);
 }
 
 HRESULT STDMETHODCALLTYPE  CMenuBand::Initialize(
@@ -121,7 +107,10 @@ HRESULT STDMETHODCALLTYPE  CMenuBand::GetMenuInfo(
         return E_INVALIDARG;
 
     if (ppsmc)
+    {
+        m_psmc->AddRef();
         *ppsmc = m_psmc;
+    }
 
     if (puId)
         *puId = m_uId;
@@ -143,6 +132,12 @@ HRESULT STDMETHODCALLTYPE  CMenuBand::SetMenu(
 
     BOOL created = FALSE;
 
+    if (m_hmenu)
+    {
+        DestroyMenu(m_hmenu);
+        m_hmenu = NULL;
+    }
+
     if (m_staticToolbar == NULL)
     {
         m_staticToolbar = new CMenuStaticToolbar(this);
@@ -292,21 +287,43 @@ HRESULT STDMETHODCALLTYPE CMenuBand::OnPosRectChangeDB(RECT *prc)
     int syStatic = maxStatic.cy;
     int syShlFld = sy - syStatic;
 
-    if (m_SFToolbar)
+    if (m_shellBottom)
     {
-        m_SFToolbar->SetPosSize(
-            prc->left,
-            prc->top,
-            prc->right - prc->left,
-            syShlFld);
+        if (m_SFToolbar)
+        {
+            m_SFToolbar->SetPosSize(
+                prc->left,
+                prc->top + syStatic,
+                prc->right - prc->left,
+                syShlFld);
+        }
+        if (m_staticToolbar)
+        {
+            m_staticToolbar->SetPosSize(
+                prc->left,
+                prc->top,
+                prc->right - prc->left,
+                syStatic);
+        }
     }
-    if (m_staticToolbar)
+    else // shell menu on top
     {
-        m_staticToolbar->SetPosSize(
-            prc->left,
-            prc->top + syShlFld,
-            prc->right - prc->left,
-            syStatic);
+        if (m_SFToolbar)
+        {
+            m_SFToolbar->SetPosSize(
+                prc->left,
+                prc->top,
+                prc->right - prc->left,
+                syShlFld);
+        }
+        if (m_staticToolbar)
+        {
+            m_staticToolbar->SetPosSize(
+                prc->left,
+                prc->top + syShlFld,
+                prc->right - prc->left,
+                syStatic);
+        }
     }
 
     return S_OK;
@@ -368,6 +385,8 @@ HRESULT STDMETHODCALLTYPE  CMenuBand::ShowDW(BOOL fShow)
     if (m_Show == fShow)
         return S_OK;
 
+    m_Show = fShow;
+
     if (m_staticToolbar != NULL)
     {
         hr = m_staticToolbar->ShowWindow(fShow);
@@ -408,31 +427,34 @@ HRESULT STDMETHODCALLTYPE  CMenuBand::ShowDW(BOOL fShow)
             hr = m_focusManager->PopMenuBar(this);
     }
 
-    m_Show = fShow;
-
     return S_OK;
 }
 
 HRESULT STDMETHODCALLTYPE CMenuBand::CloseDW(DWORD dwReserved)
 {
+    if (m_subMenuChild)
+    {
+        m_subMenuChild->OnSelect(MPOS_CANCELLEVEL);
+    }
+
+    if (m_subMenuChild)
+    {
+        DbgPrint("Child object should have removed itself.\n");
+    }
+
     ShowDW(FALSE);
 
     if (m_staticToolbar != NULL)
     {
         m_staticToolbar->Close();
-        delete m_staticToolbar;
-        m_staticToolbar = NULL;
     }
 
     if (m_SFToolbar != NULL)
     {
         m_SFToolbar->Close();
-        delete m_staticToolbar;
-        m_staticToolbar = NULL;
     }
 
     if (m_site) m_site.Release();
-    if (m_psmc) m_psmc.Release();
     if (m_subMenuChild) m_subMenuChild.Release();
     if (m_subMenuParent) m_subMenuParent.Release();
     if (m_childBand) m_childBand.Release();
@@ -581,7 +603,7 @@ HRESULT CMenuBand::_SetParentBand(CMenuBand * parent)
 
 HRESULT CMenuBand::_IsPopup()
 {
-    return m_subMenuParent ? S_OK : S_FALSE;
+    return !(m_dwFlags & SMINIT_VERTICAL);
 }
 
 HRESULT CMenuBand::_IsTracking()
@@ -591,28 +613,37 @@ HRESULT CMenuBand::_IsTracking()
 
 HRESULT STDMETHODCALLTYPE CMenuBand::SetClient(IUnknown *punkClient)
 {
+    CComPtr<IMenuPopup> child = m_subMenuChild;
+
     m_subMenuChild = NULL;
+        
+    if (child)
+    {
+        IUnknown_SetSite(child, NULL);
+        child.Release();
+    }
 
     if (!punkClient)
     {
         return S_OK;
     }
 
-    HRESULT hr = punkClient->QueryInterface(IID_PPV_ARG(IMenuPopup, &m_subMenuChild));
-
-    return hr;
+    return punkClient->QueryInterface(IID_PPV_ARG(IMenuPopup, &m_subMenuChild));
 }
 
 HRESULT STDMETHODCALLTYPE CMenuBand::GetClient(IUnknown **ppunkClient)
 {
     // HACK, so I can test for a submenu in the DeskBar
-    if (ppunkClient)
+    if (!ppunkClient)
+        return E_POINTER;
+    *ppunkClient = NULL;
+
+    if (m_subMenuChild)
     {
-        if (m_subMenuChild)
-            *ppunkClient = m_subMenuChild;
-        else
-            *ppunkClient = NULL;
+        m_subMenuChild->AddRef();
+        *ppunkClient = m_subMenuChild;
     }
+
     return S_OK;
 }
 
@@ -637,6 +668,8 @@ HRESULT STDMETHODCALLTYPE CMenuBand::SetShellFolder(IShellFolder *psf, LPCITEMID
     if (FAILED_UNEXPECTEDLY(hr))
         return hr;
 
+    m_shellBottom = (dwFlags & SMSET_BOTTOM) != 0;
+
     if (m_site)
     {
         HWND hwndParent;
@@ -733,10 +766,16 @@ HRESULT CMenuBand::_TrackSubMenu(HMENU popup, INT x, INT y, RECT& rcExclude)
     UINT      flags  = TPM_VERPOSANIMATION | TPM_VERTICAL | TPM_LEFTALIGN;
     HWND      hwnd   = m_menuOwner ? m_menuOwner : m_topLevelWindow;
 
+    m_trackedPopup = popup;
+    m_trackedHwnd = hwnd;
+
     m_focusManager->PushTrackedPopup(popup);
     ::TrackPopupMenuEx(popup, flags, x, y, hwnd, &params);
     m_focusManager->PopTrackedPopup(popup);
 
+    m_trackedPopup = NULL;
+    m_trackedHwnd = NULL;
+
     _DisableMouseTrack(FALSE);
 
     return S_OK;
@@ -762,9 +801,13 @@ HRESULT CMenuBand::_TrackContextMenu(IContextMenu * contextMenu, INT x, INT y)
 
     HWND hwnd = m_menuOwner ? m_menuOwner : m_topLevelWindow;
 
+    m_focusManager->PushTrackedPopup(popup);
+
     TRACE("Before Tracking\n");
     uCommand = ::TrackPopupMenuEx(popup, TPM_RETURNCMD, x, y, hwnd, NULL);
 
+    m_focusManager->PopTrackedPopup(popup);
+
     if (uCommand != 0)
     {
         TRACE("Before InvokeCommand\n");
@@ -867,6 +910,7 @@ HRESULT  CMenuBand::_KeyboardItemChange(DWORD change)
 
 HRESULT CMenuBand::_MenuItemHotTrack(DWORD changeType)
 {
+    CComPtr<CMenuBand> safeThis = this;
     HRESULT hr;
 
     if (m_dwFlags & SMINIT_VERTICAL)
@@ -905,9 +949,18 @@ HRESULT CMenuBand::_MenuItemHotTrack(DWORD changeType)
     switch (changeType)
     {
     case MPOS_EXECUTE:
-        m_hotBar->ExecuteItem(m_hotItem);
+    {
+        CMenuToolbarBase * tb = m_hotBar;
+        int item = m_hotItem;
+        tb->PrepareExecuteItem(item);
+        if (m_subMenuParent)
+        {
+            m_subMenuParent->OnSelect(changeType);
+        }
+        TRACE("Menu closed, executing item...\n");
+        tb->ExecuteItem();
         break;
-
+    }
     case MPOS_SELECTLEFT:
         if (m_parentBand && m_parentBand->_IsPopup()==S_FALSE)
             return m_parentBand->_MenuItemHotTrack(VK_LEFT);
@@ -937,25 +990,47 @@ HRESULT CMenuBand::_MenuItemHotTrack(DWORD changeType)
 
 HRESULT CMenuBand::_CancelCurrentPopup()
 {
-    if (!m_subMenuChild)
-        return S_FALSE;
+    if (m_subMenuChild)
+    {
+        HRESULT hr = m_subMenuChild->OnSelect(MPOS_CANCELLEVEL);
+        return hr;
+    }
 
-    HRESULT hr = m_subMenuChild->OnSelect(MPOS_CANCELLEVEL);
-    return hr;
+    if (m_trackedPopup)
+    {
+        ::SendMessage(m_trackedHwnd, WM_CANCELMODE, 0, 0);
+        return S_OK;
+    }
+
+    return S_FALSE;
 }
 
 HRESULT CMenuBand::_OnPopupSubMenu(IShellMenu * childShellMenu, POINTL * pAt, RECTL * pExclude, BOOL keyInitiated)
 {
     HRESULT hr = 0;
-    IBandSite* pBandSite;
-    IDeskBar* pDeskBar;
+    CComPtr<IBandSite> pBandSite;
+    CComPtr<IDeskBar> pDeskBar;
 
     // Create the necessary objects
+#if USE_SYSTEM_MENUSITE
+    hr = CoCreateInstance(CLSID_MenuBandSite,
+        NULL,
+        CLSCTX_INPROC_SERVER,
+        IID_PPV_ARG(IBandSite, &pBandSite));
+#else
     hr = CMenuSite_Constructor(IID_PPV_ARG(IBandSite, &pBandSite));
+#endif
     if (FAILED_UNEXPECTEDLY(hr))
         return hr;
 
+#if USE_SYSTEM_MENUDESKBAR
+    hr = CoCreateInstance(CLSID_MenuDeskBar,
+        NULL,
+        CLSCTX_INPROC_SERVER,
+        IID_PPV_ARG(IDeskBar, &pDeskBar));
+#else
     hr = CMenuDeskBar_Constructor(IID_PPV_ARG(IDeskBar, &pDeskBar));
+#endif
     if (FAILED_UNEXPECTEDLY(hr))
         return hr;
 
@@ -1013,6 +1088,29 @@ HRESULT CMenuBand::_KillPopupTimers()
     return hr;
 }
 
+HRESULT CMenuBand::_MenuBarMouseDown(HWND hwnd, INT item)
+{
+    if (m_staticToolbar && m_staticToolbar->IsWindowOwner(hwnd) == S_OK)
+        m_staticToolbar->MenuBarMouseDown(item);
+    if (m_SFToolbar && m_SFToolbar->IsWindowOwner(hwnd) == S_OK)
+        m_SFToolbar->MenuBarMouseDown(item);
+    return S_OK;
+}
+
+HRESULT CMenuBand::_MenuBarMouseUp(HWND hwnd, INT item)
+{
+    if (m_staticToolbar && m_staticToolbar->IsWindowOwner(hwnd) == S_OK)
+        m_staticToolbar->MenuBarMouseUp(item);
+    if (m_SFToolbar && m_SFToolbar->IsWindowOwner(hwnd) == S_OK)
+        m_SFToolbar->MenuBarMouseUp(item);
+    return S_OK;
+}
+
+HRESULT CMenuBand::_HasSubMenu()
+{
+    return m_popupBar ? S_OK : S_FALSE;
+}
+
 HRESULT STDMETHODCALLTYPE CMenuBand::InvalidateItem(LPSMDATA psmd, DWORD dwFlags)
 {
     UNIMPLEMENTED;