Author: dquintana Date: Sat Feb 22 22:59:28 2014 New Revision: 62295
URL: http://svn.reactos.org/svn/reactos?rev=62295&view=rev Log: [RSHELL] * Take "DbgPrint" function from explorer-new. * CMenuBand: Show placeholder if the band gets an empty IShellFolder. Added what I guess is a hack, to allow CMenuDeskBar to get the submenu popup from the band. * CMenuDeskBar: Use WM_ACTIVATE and WM_ACTIVATEAPP to detect when the menu should be closed. Uses the hack above for the exception of showing a submenu. CORE-7886
Modified: branches/shell-experiments/base/shell/rshell/CMenuBand.cpp branches/shell-experiments/base/shell/rshell/CMenuDeskBar.cpp branches/shell-experiments/base/shell/rshell/precomp.h
Modified: branches/shell-experiments/base/shell/rshell/CMenuBand.cpp URL: http://svn.reactos.org/svn/reactos/branches/shell-experiments/base/shell/rsh... ============================================================================== --- branches/shell-experiments/base/shell/rshell/CMenuBand.cpp [iso-8859-1] (original) +++ branches/shell-experiments/base/shell/rshell/CMenuBand.cpp [iso-8859-1] Sat Feb 22 22:59:28 2014 @@ -332,6 +332,11 @@ }
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 @@ 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<MSG*>(lParam); - if (nCode == HC_ACTION) { + BOOL callNext = TRUE; + MSG* msg = reinterpret_cast<MSG*>(lParam); + // Do whatever is necessary here
switch (msg->message) @@ -452,9 +450,6 @@ // PostMessage(m_currentFocus, WM_SYSCHAR, wParam, lParam); //} break; - case WM_ACTIVATE: - break; - }
if (!callNext) @@ -481,24 +476,26 @@ HRESULT UpdateFocus(CMenuBand * newBand) { HRESULT hr; - - hr = RemoveHooks(m_currentFocus); - - if (FAILED(hr) || !newBand) - { + HWND newFocus; + + 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 @@ } 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<LPARAM>(&tbb)); + + return S_OK; + } + return hr; }
@@ -1829,7 +1842,15 @@
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 @@ return S_OK; }
- HRESULT CMenuBand::_OnPopupSubMenu(IMenuPopup * popup, POINTL * pAt, RECTL * pExclude) { if (m_subMenuChild)
Modified: branches/shell-experiments/base/shell/rshell/CMenuDeskBar.cpp URL: http://svn.reactos.org/svn/reactos/branches/shell-experiments/base/shell/rsh... ============================================================================== --- branches/shell-experiments/base/shell/rshell/CMenuDeskBar.cpp [iso-8859-1] (original) +++ branches/shell-experiments/base/shell/rshell/CMenuDeskBar.cpp [iso-8859-1] Sat Feb 22 22:59:28 2014 @@ -56,6 +56,8 @@
INT m_Level;
+ BOOL m_Shown; + public: CMenuDeskBar(); ~CMenuDeskBar(); @@ -68,8 +70,9 @@ 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 @@ // 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,13 +165,19 @@ CMenuDeskBar::CMenuDeskBar() : m_Client(NULL), m_Banner(NULL), - m_Level(deskBarCount++) + m_Level(deskBarCount++), + m_Shown(FALSE) { }
CMenuDeskBar::~CMenuDeskBar() { deskBarCount--; +} + +HRESULT STDMETHODCALLTYPE CMenuDeskBar::Initialize(THIS) +{ + return S_OK; }
HRESULT STDMETHODCALLTYPE CMenuDeskBar::GetWindow(HWND *lphwnd) @@ -320,12 +331,16 @@ { if (prc == NULL) return E_POINTER; + return S_OK; }
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;
@@ -340,88 +355,6 @@ return E_FAIL;
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<IWinEventHandler> 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) @@ -502,6 +435,8 @@
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 @@
UIActivateIO(TRUE, NULL);
+ return S_OK; }
@@ -555,78 +491,9 @@ return S_OK; }
-HRESULT STDMETHODCALLTYPE CMenuDeskBar::OnSelect( - DWORD dwSelectType) -{ - /* As far as I can tell, the submenu hierarchy looks like this: - - The DeskBar's Child is the Band it contains. - The DeskBar's Parent is the SID_SMenuPopup of the Site. - - The Band's Child is the IMenuPopup of the child submenu. - The Band's Parent is the SID_SMenuPopup of the Site (the DeskBar). - - When the DeskBar receives a selection event: - If it requires closing the window, it will notify the Child (Band) using CancelLevel. - If it has to spread upwards (everything but CancelLevel), it will notify the Parent. - - When the Band receives a selection event, this is where it gets fuzzy: - In which cases does it call the Parent? Probably not CancelLevel. - In which cases does it call the Child? - How does it react to calls? - - */ - - switch (dwSelectType) - { - case MPOS_EXECUTE: - case MPOS_FULLCANCEL: - case MPOS_CANCELLEVEL: - - _CloseBar(); - - if (dwSelectType == MPOS_CANCELLEVEL) - return S_OK; - - case MPOS_SELECTLEFT: - case MPOS_SELECTRIGHT: - case MPOS_CHILDTRACKING: - if (m_SubMenuParent) - return m_SubMenuParent->OnSelect(dwSelectType); - break; - } - - return S_OK; -} - -HRESULT CMenuDeskBar::_CloseBar() -{ - CComPtr<IDeskBarClient> dbc; - HRESULT hr; - - if (m_SubMenuChild) - { - hr = m_SubMenuChild->OnSelect(MPOS_CANCELLEVEL); - if (FAILED(hr)) - return hr; - } - - hr = m_Client->QueryInterface(IID_PPV_ARG(IDeskBarClient, &dbc)); - if (FAILED(hr)) - return hr; - - hr = dbc->UIActivateDBC(FALSE); - if (FAILED(hr)) - return hr; - - SetWindowPos(m_hWnd, 0, 0, 0, 0, SWP_HIDEWINDOW | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER); - - return UIActivateIO(FALSE, NULL); -} - HRESULT STDMETHODCALLTYPE CMenuDeskBar::SetSubMenu(IMenuPopup *pmp, BOOL fSet) { - // Called by the CHILD to notify the parent of the submenu object + // Called by the MenuBand to assign itself as the logical child of the DeskBar
if (fSet) { @@ -645,8 +512,220 @@ return S_OK; }
- -HRESULT STDMETHODCALLTYPE CMenuDeskBar::Initialize(THIS) -{ - return S_OK; -} +HRESULT STDMETHODCALLTYPE CMenuDeskBar::OnSelect(DWORD dwSelectType) +{ + /* As far as I can tell, the submenu hierarchy looks like this: + + The DeskBar's Child is the Band it contains. + The DeskBar's Parent is the SID_SMenuPopup of the Site. + + The Band's Child is the IMenuPopup of the child submenu. + The Band's Parent is the SID_SMenuPopup of the Site (the DeskBar). + + When the DeskBar receives a selection event: + If it requires closing the window, it will notify the Child (Band) using CancelLevel. + If it has to spread upwards (everything but CancelLevel), it will notify the Parent. + + When the Band receives a selection event, this is where it gets fuzzy: + In which cases does it call the Parent? Probably not CancelLevel. + In which cases does it call the Child? + How does it react to calls? + + */ + + switch (dwSelectType) + { + case MPOS_EXECUTE: + case MPOS_FULLCANCEL: + case MPOS_CANCELLEVEL: + + _CloseBar(); + + if (dwSelectType == MPOS_CANCELLEVEL) + return S_OK; + + case MPOS_SELECTLEFT: + case MPOS_SELECTRIGHT: + case MPOS_CHILDTRACKING: + if (m_SubMenuParent) + return m_SubMenuParent->OnSelect(dwSelectType); + break; + } + + return S_OK; +} + +HRESULT CMenuDeskBar::_CloseBar() +{ + CComPtr<IDeskBarClient> dbc; + HRESULT hr; + + m_Shown = false; + + if (m_SubMenuChild) + { + hr = m_SubMenuChild->OnSelect(MPOS_CANCELLEVEL); + if (FAILED(hr)) + return hr; + } + + hr = m_Client->QueryInterface(IID_PPV_ARG(IDeskBarClient, &dbc)); + if (FAILED(hr)) + return hr; + + hr = dbc->UIActivateDBC(FALSE); + if (FAILED(hr)) + return hr; + + SetWindowPos(m_hWnd, 0, 0, 0, 0, SWP_HIDEWINDOW | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER); + + return UIActivateIO(FALSE, NULL); +} + +BOOL CMenuDeskBar::_IsSubMenuParent(HWND hwnd) +{ + CComPtr<IMenuPopup> popup = m_SubMenuParent; + + while (popup) + { + HRESULT hr; + CComPtr<IOleWindow> 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; + } + + return FALSE; +} + +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) +{ + if (!m_Client) + return 0; + + CComPtr<IWinEventHandler> 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<IDeskBar> db; + HRESULT hr = IUnknown_QueryService(m_Client, SID_SMenuBandChild, IID_PPV_ARG(IDeskBar, &db)); + if (FAILED(hr)) + return 0; + + CComPtr<IUnknown> punk; + + hr = db->GetClient(&punk); + if (FAILED(hr)) + return 0; + + if (!punk && m_Shown) + { + if (!_IsSubMenuParent(reinterpret_cast<HWND>(lParam))) + { + OnSelect(MPOS_FULLCANCEL); + } + } + + return 0; +} + +LRESULT CMenuDeskBar::_OnAppActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) +{ + if (wParam == 0) + { + OnSelect(MPOS_FULLCANCEL); + } + return 0; +}
Modified: branches/shell-experiments/base/shell/rshell/precomp.h URL: http://svn.reactos.org/svn/reactos/branches/shell-experiments/base/shell/rsh... ============================================================================== --- branches/shell-experiments/base/shell/rshell/precomp.h [iso-8859-1] (original) +++ branches/shell-experiments/base/shell/rshell/precomp.h [iso-8859-1] Sat Feb 22 22:59:28 2014 @@ -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 <stdio.h> #include <tchar.h> @@ -44,3 +44,39 @@ 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__)