diff --git a/base/shell/rshell/CMenuBand.cpp b/base/shell/rshell/CMenuBand.cpp index 4e2c799ce8a..7641ad075aa 100644 --- a/base/shell/rshell/CMenuBand.cpp +++ b/base/shell/rshell/CMenuBand.cpp @@ -332,6 +332,11 @@ private: } private: + CMenuBand * m_currentBand; + HWND m_currentFocus; + HHOOK m_hHook; + DWORD m_threadId; + // TODO: make dynamic #define MAX_RECURSE 20 CMenuBand* m_bandStack[MAX_RECURSE]; @@ -399,23 +404,16 @@ public: BEGIN_COM_MAP(CMenuFocusManager) END_COM_MAP() -private: - CMenuBand * m_currentBand; - HWND m_currentFocus; - HHOOK m_hHook; - DWORD m_threadId; - LRESULT GetMsgHook(INT nCode, WPARAM wParam, LPARAM lParam) { if (nCode < 0) return CallNextHookEx(m_hHook, nCode, wParam, lParam); - BOOL callNext = TRUE; - BOOL fRemoved = wParam; - MSG* msg = reinterpret_cast(lParam); - if (nCode == HC_ACTION) { + BOOL callNext = TRUE; + MSG* msg = reinterpret_cast(lParam); + // Do whatever is necessary here switch (msg->message) @@ -452,9 +450,6 @@ private: // PostMessage(m_currentFocus, WM_SYSCHAR, wParam, lParam); //} break; - case WM_ACTIVATE: - break; - } if (!callNext) @@ -481,24 +476,26 @@ private: HRESULT UpdateFocus(CMenuBand * newBand) { HRESULT hr; + HWND newFocus; - hr = RemoveHooks(m_currentFocus); - - if (FAILED(hr) || !newBand) + if (newBand == NULL) { + hr = RemoveHooks(m_currentFocus); m_currentFocus = NULL; m_currentBand = NULL; return S_OK; } - HWND newFocus; hr = newBand->_GetTopLevelWindow(&newFocus); if (FAILED(hr)) return hr; - hr = PlaceHooks(m_currentFocus); - if (FAILED(hr)) - return hr; + if (!m_currentBand) + { + hr = PlaceHooks(newFocus); + if (FAILED(hr)) + return hr; + } m_currentFocus = newFocus; m_currentBand = newBand; @@ -1147,6 +1144,22 @@ HRESULT CMenuSFToolbar::FillToolbar() } CoTaskMemFree(item); + // If no items were added, show the "empty" placeholder + if (i == 0) + { + TBBUTTON tbb = { 0 }; + PWSTR MenuString = L"(Empty)"; + + tbb.fsState = 0/*TBSTATE_DISABLED*/; + tbb.fsStyle = 0; + tbb.iString = (INT_PTR) MenuString; + tbb.iBitmap = -1; + + SendMessageW(m_hwnd, TB_ADDBUTTONS, 1, reinterpret_cast(&tbb)); + + return S_OK; + } + return hr; } @@ -1829,7 +1842,15 @@ HRESULT STDMETHODCALLTYPE CMenuBand::SetClient(IUnknown *punkClient) HRESULT STDMETHODCALLTYPE CMenuBand::GetClient(IUnknown **ppunkClient) { - UNIMPLEMENTED; + // HACK, so I can test for a submenu in the DeskBar + //UNIMPLEMENTED; + if (ppunkClient) + { + if (m_subMenuChild) + *ppunkClient = m_subMenuChild; + else + *ppunkClient = NULL; + } return S_OK; } @@ -2209,7 +2230,6 @@ HRESULT CMenuBand::_MenuItemHotTrack(DWORD changeType) return S_OK; } - HRESULT CMenuBand::_OnPopupSubMenu(IMenuPopup * popup, POINTL * pAt, RECTL * pExclude) { if (m_subMenuChild) diff --git a/base/shell/rshell/CMenuDeskBar.cpp b/base/shell/rshell/CMenuDeskBar.cpp index f5f92f72be0..2ffed5dd70c 100644 --- a/base/shell/rshell/CMenuDeskBar.cpp +++ b/base/shell/rshell/CMenuDeskBar.cpp @@ -56,6 +56,8 @@ private: INT m_Level; + BOOL m_Shown; + public: CMenuDeskBar(); ~CMenuDeskBar(); @@ -68,8 +70,9 @@ public: BEGIN_MSG_MAP(CMenuDeskBar) MESSAGE_HANDLER(WM_SIZE, _OnSize) MESSAGE_HANDLER(WM_NOTIFY, _OnNotify) - MESSAGE_HANDLER(WM_WINDOWPOSCHANGED, _OnWindowPosChanged) MESSAGE_HANDLER(WM_PAINT, _OnPaint) + MESSAGE_HANDLER(WM_ACTIVATE, _OnActivate) + MESSAGE_HANDLER(WM_ACTIVATEAPP, _OnAppActivate) END_MSG_MAP() BEGIN_COM_MAP(CMenuDeskBar) @@ -131,9 +134,11 @@ private: // message handlers LRESULT _OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); LRESULT _OnNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); - LRESULT _OnWindowPosChanged(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); LRESULT _OnPaint(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); + LRESULT _OnActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); + LRESULT _OnAppActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); + BOOL _IsSubMenuParent(HWND hwnd); HRESULT _CloseBar(); }; @@ -160,7 +165,8 @@ INT deskBarCount=0; CMenuDeskBar::CMenuDeskBar() : m_Client(NULL), m_Banner(NULL), - m_Level(deskBarCount++) + m_Level(deskBarCount++), + m_Shown(FALSE) { } @@ -169,6 +175,11 @@ CMenuDeskBar::~CMenuDeskBar() deskBarCount--; } +HRESULT STDMETHODCALLTYPE CMenuDeskBar::Initialize(THIS) +{ + return S_OK; +} + HRESULT STDMETHODCALLTYPE CMenuDeskBar::GetWindow(HWND *lphwnd) { if (lphwnd == NULL) @@ -320,6 +331,7 @@ HRESULT STDMETHODCALLTYPE CMenuDeskBar::OnPosRectChangeDB(LPRECT prc) { if (prc == NULL) return E_POINTER; + return S_OK; } @@ -327,6 +339,9 @@ HRESULT STDMETHODCALLTYPE CMenuDeskBar::SetSite(IUnknown *pUnkSite) { // Windows closes the bar if this is called when the bar is shown + if (m_Shown) + _CloseBar(); + m_Site = pUnkSite; IUnknown_QueryService(m_Site, SID_SMenuPopup, IID_PPV_ARG(IMenuPopup, &m_SubMenuParent)); @@ -342,88 +357,6 @@ HRESULT STDMETHODCALLTYPE CMenuDeskBar::GetSite(REFIID riid, void **ppvSite) return m_Site->QueryInterface(riid, ppvSite); } -LRESULT CMenuDeskBar::_OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) -{ - if (m_Client) - { - RECT rc; - - GetClientRect(&rc); - - if (m_Banner != NULL) - { - BITMAP bm; - ::GetObject(m_Banner, sizeof(bm), &bm); - rc.left += bm.bmWidth; - } - - ::SetWindowPos(m_ClientWindow, NULL, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, 0); - } - - return 0; -} - -LRESULT CMenuDeskBar::_OnNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) -{ - CComPtr winEventHandler; - LRESULT result; - HRESULT hr; - - result = 0; - if (m_Client.p != NULL) - { - hr = m_Client->QueryInterface(IID_PPV_ARG(IWinEventHandler, &winEventHandler)); - if (SUCCEEDED(hr) && winEventHandler.p != NULL) - hr = winEventHandler->OnWinEvent(NULL, uMsg, wParam, lParam, &result); - } - return result; -} - -LRESULT CMenuDeskBar::_OnWindowPosChanged(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) -{ - return 0; -} - -LRESULT CMenuDeskBar::_OnPaint(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) -{ - bHandled = FALSE; - - if (m_Banner && !m_IconSize) - { - BITMAP bm; - PAINTSTRUCT ps; - HDC hdc = BeginPaint(&ps); - - HDC hdcMem = ::CreateCompatibleDC(hdc); - HGDIOBJ hbmOld = ::SelectObject(hdcMem, m_Banner); - - ::GetObject(m_Banner, sizeof(bm), &bm); - - RECT rc; - if (!GetClientRect(&rc)) - WARN("GetClientRect failed\n"); - - const int bx = bm.bmWidth; - const int by = bm.bmHeight; - const int cy = rc.bottom; - - TRACE("Painting banner: %d by %d\n", bm.bmWidth, bm.bmHeight); - - if (!::StretchBlt(hdc, 0, 0, bx, cy - by, hdcMem, 0, 0, bx, 1, SRCCOPY)) - WARN("StretchBlt failed\n"); - - if (!::BitBlt(hdc, 0, cy - by, bx, by, hdcMem, 0, 0, SRCCOPY)) - WARN("BitBlt failed\n"); - - ::SelectObject(hdcMem, hbmOld); - ::DeleteDC(hdcMem); - - EndPaint(&ps); - } - - return TRUE; -} - HRESULT STDMETHODCALLTYPE CMenuDeskBar::Popup(POINTL *ppt, RECTL *prcExclude, MP_POPUPFLAGS dwFlags) { HRESULT hr; @@ -502,6 +435,8 @@ HRESULT STDMETHODCALLTYPE CMenuDeskBar::Popup(POINTL *ppt, RECTL *prcExclude, MP this->SetWindowPos(HWND_TOPMOST, x, y, cx, cy, SWP_SHOWWINDOW); + m_Shown = true; + // HACK: The bar needs to be notified of the size AFTER it is shown. // Quick & dirty way of getting it done. BOOL bHandled; @@ -509,6 +444,7 @@ HRESULT STDMETHODCALLTYPE CMenuDeskBar::Popup(POINTL *ppt, RECTL *prcExclude, MP UIActivateIO(TRUE, NULL); + return S_OK; } @@ -555,8 +491,28 @@ HRESULT STDMETHODCALLTYPE CMenuDeskBar::GetBitmap(THIS_ HBITMAP* phBitmap) return S_OK; } -HRESULT STDMETHODCALLTYPE CMenuDeskBar::OnSelect( - DWORD dwSelectType) +HRESULT STDMETHODCALLTYPE CMenuDeskBar::SetSubMenu(IMenuPopup *pmp, BOOL fSet) +{ + // Called by the MenuBand to assign itself as the logical child of the DeskBar + + if (fSet) + { + m_SubMenuChild = pmp; + } + else + { + if (m_SubMenuChild) + { + if (SHIsSameObject(pmp, m_SubMenuChild)) + { + m_SubMenuChild = NULL; + } + } + } + return S_OK; +} + +HRESULT STDMETHODCALLTYPE CMenuDeskBar::OnSelect(DWORD dwSelectType) { /* As far as I can tell, the submenu hierarchy looks like this: @@ -604,6 +560,8 @@ HRESULT CMenuDeskBar::_CloseBar() CComPtr dbc; HRESULT hr; + m_Shown = false; + if (m_SubMenuChild) { hr = m_SubMenuChild->OnSelect(MPOS_CANCELLEVEL); @@ -624,29 +582,150 @@ HRESULT CMenuDeskBar::_CloseBar() return UIActivateIO(FALSE, NULL); } -HRESULT STDMETHODCALLTYPE CMenuDeskBar::SetSubMenu(IMenuPopup *pmp, BOOL fSet) +BOOL CMenuDeskBar::_IsSubMenuParent(HWND hwnd) { - // Called by the CHILD to notify the parent of the submenu object + CComPtr popup = m_SubMenuParent; - if (fSet) + while (popup) { - m_SubMenuChild = pmp; + HRESULT hr; + CComPtr window; + + hr = popup->QueryInterface(IID_PPV_ARG(IOleWindow, &window)); + if (FAILED(hr)) + return FALSE; + + HWND parent; + + hr = window->GetWindow(&parent); + if (SUCCEEDED(hr) && hwnd == parent) + return TRUE; + + popup = NULL; + hr = IUnknown_GetSite(window, IID_PPV_ARG(IMenuPopup, &popup)); + if (FAILED(hr)) + return FALSE; } - else + + return FALSE; +} + +LRESULT CMenuDeskBar::_OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) +{ + if (m_Client) { - if (m_SubMenuChild) + RECT rc; + + GetClientRect(&rc); + + if (m_Banner != NULL) { - if (SHIsSameObject(pmp, m_SubMenuChild)) - { - m_SubMenuChild = NULL; - } + BITMAP bm; + ::GetObject(m_Banner, sizeof(bm), &bm); + rc.left += bm.bmWidth; + } + + ::SetWindowPos(m_ClientWindow, NULL, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, 0); + } + + return 0; +} + +LRESULT CMenuDeskBar::_OnNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) +{ + if (!m_Client) + return 0; + + CComPtr winEventHandler; + HRESULT hr = m_Client->QueryInterface(IID_PPV_ARG(IWinEventHandler, &winEventHandler)); + if (FAILED(hr)) + return 0; + + if (winEventHandler) + { + LRESULT result; + hr = winEventHandler->OnWinEvent(NULL, uMsg, wParam, lParam, &result); + if (FAILED(hr)) + return 0; + return result; + } + + return 0; +} + +LRESULT CMenuDeskBar::_OnPaint(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) +{ + bHandled = FALSE; + + if (m_Banner && !m_IconSize) + { + BITMAP bm; + PAINTSTRUCT ps; + HDC hdc = BeginPaint(&ps); + + HDC hdcMem = ::CreateCompatibleDC(hdc); + HGDIOBJ hbmOld = ::SelectObject(hdcMem, m_Banner); + + ::GetObject(m_Banner, sizeof(bm), &bm); + + RECT rc; + if (!GetClientRect(&rc)) + WARN("GetClientRect failed\n"); + + const int bx = bm.bmWidth; + const int by = bm.bmHeight; + const int cy = rc.bottom; + + TRACE("Painting banner: %d by %d\n", bm.bmWidth, bm.bmHeight); + + if (!::StretchBlt(hdc, 0, 0, bx, cy - by, hdcMem, 0, 0, bx, 1, SRCCOPY)) + WARN("StretchBlt failed\n"); + + if (!::BitBlt(hdc, 0, cy - by, bx, by, hdcMem, 0, 0, SRCCOPY)) + WARN("BitBlt failed\n"); + + ::SelectObject(hdcMem, hbmOld); + ::DeleteDC(hdcMem); + + EndPaint(&ps); + } + + return TRUE; +} + +LRESULT CMenuDeskBar::_OnActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) +{ + if (wParam != 0) + return 0; + + // HACK! I just want it to work !!! + CComPtr db; + HRESULT hr = IUnknown_QueryService(m_Client, SID_SMenuBandChild, IID_PPV_ARG(IDeskBar, &db)); + if (FAILED(hr)) + return 0; + + CComPtr punk; + + hr = db->GetClient(&punk); + if (FAILED(hr)) + return 0; + + if (!punk && m_Shown) + { + if (!_IsSubMenuParent(reinterpret_cast(lParam))) + { + OnSelect(MPOS_FULLCANCEL); } } - return S_OK; + + return 0; } - -HRESULT STDMETHODCALLTYPE CMenuDeskBar::Initialize(THIS) +LRESULT CMenuDeskBar::_OnAppActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) { - return S_OK; + if (wParam == 0) + { + OnSelect(MPOS_FULLCANCEL); + } + return 0; } diff --git a/base/shell/rshell/precomp.h b/base/shell/rshell/precomp.h index 5715aaaf572..4b1652f5800 100644 --- a/base/shell/rshell/precomp.h +++ b/base/shell/rshell/precomp.h @@ -3,9 +3,9 @@ #define USE_SYSTEM_MENUSITE 0 #define USE_SYSTEM_MENUBAND 0 -#define WRAP_MENUDESKBAR 1 -#define WRAP_MENUSITE 1 -#define WRAP_MENUBAND 1 +#define WRAP_MENUDESKBAR 0 +#define WRAP_MENUSITE 0 +#define WRAP_MENUBAND 0 #include #include @@ -44,3 +44,39 @@ extern "C" HRESULT CMenuBand_Constructor(REFIID riid, LPVOID *ppv); extern "C" HRESULT CMenuDeskBar_Wrapper(IDeskBar * db, REFIID riid, LPVOID *ppv); extern "C" HRESULT CMenuSite_Wrapper(IBandSite * bs, REFIID riid, LPVOID *ppv); extern "C" HRESULT CMenuBand_Wrapper(IShellMenu * sm, REFIID riid, LPVOID *ppv); + +static __inline ULONG +Win32DbgPrint(const char *filename, int line, const char *lpFormat, ...) +{ + char szMsg[512]; + char *szMsgStart; + const char *fname; + va_list vl; + ULONG uRet; + + fname = strrchr(filename, '\\'); + if (fname == NULL) + { + fname = strrchr(filename, '/'); + if (fname != NULL) + fname++; + } + else + fname++; + + if (fname == NULL) + fname = filename; + + szMsgStart = szMsg + sprintf(szMsg, "%s:%d: ", fname, line); + + va_start(vl, lpFormat); + uRet = (ULONG) vsprintf(szMsgStart, lpFormat, vl); + va_end(vl); + + OutputDebugStringA(szMsg); + + return uRet; +} + +#define DbgPrint(fmt, ...) \ + Win32DbgPrint(__FILE__, __LINE__, fmt, ##__VA_ARGS__)