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/rs…
==============================================================================
--- 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/rs…
==============================================================================
--- 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/rs…
==============================================================================
--- 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__)