Index: dll/win32/shell32/startmenu.cpp =================================================================== --- dll/win32/shell32/startmenu.cpp (revision 57871) +++ dll/win32/shell32/startmenu.cpp (working copy) @@ -2,6 +2,7 @@ * Start menu object * * Copyright 2009 Andrew Hill + * Copyright 2012 Katayama Hirofumi MZ * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -22,10 +23,270 @@ WINE_DEFAULT_DEBUG_CHANNEL(shell32start); +static const +TCHAR szStartMenuWndClass[] = TEXT("DV2ControlHost"); + +static INT +StartMenu_HitTest(HWND hwnd, CStartMenu *pMenu, POINT pt) +{ + RECT rcBanner, rcClient; + + if (pMenu->m_hBitmap != NULL) + { + GetClientRect(hwnd, &rcClient); + SetRect(&rcBanner, + 0, 0, + pMenu->m_sizBitmap.cx, rcClient.bottom - rcClient.top); + if (PtInRect(&rcBanner, pt)) + return -1; /* Clicked the banner */ + } + + /* FIXME: Return hit item index */ + return 0; +} + +static VOID +StartMenu_CalcClientSize(CStartMenu *pMenu, LPSIZE psiz) +{ + /* FIXME */ + psiz->cx = 180; + psiz->cy = 400; +} + +static VOID +StartMenu_OnPaint(HWND hwnd, CStartMenu *pMenu) +{ + PAINTSTRUCT ps; + HDC hdc, hdcMem; + RECT rcClient; + HGDIOBJ hbmOld; + HBRUSH hbr; + + GetClientRect(hwnd, &rcClient); + + hdc = BeginPaint(hwnd, &ps); + if (hdc != NULL) + { + if (pMenu->m_hBitmap != NULL) + { + /* fill the banner background */ + hbr = CreateSolidBrush(RGB(138, 178, 219)); + if (hbr != NULL) + { + rcClient.right = rcClient.left + pMenu->m_sizBitmap.cx; + FillRect(hdc, &rcClient, hbr); + DeleteObject(hbr); + } + GetClientRect(hwnd, &rcClient); + + /* draw the banner */ + hdcMem = CreateCompatibleDC(hdc); + if (hdcMem != NULL) + { + hbmOld = SelectObject(hdcMem, pMenu->m_hBitmap); + BitBlt(hdc, + 0, rcClient.bottom - pMenu->m_sizBitmap.cy, + pMenu->m_sizBitmap.cx, pMenu->m_sizBitmap.cy, + hdcMem, 0, 0, SRCCOPY); + SelectObject(hdcMem, hbmOld); + GdiFlush(); + DeleteDC(hdcMem); + } + } + + /* FIXME: Draw icons and texts */ + + EndPaint(hwnd, &ps); + } +} + +static BOOL +StartMenu_OnCreate(CStartMenu *pMenu) +{ + /* FIXME: Load icons and texts */ + return TRUE; +} + +static VOID +StartMenu_OnKeyDown(HWND hwnd, CStartMenu *pMenu, UINT vk) +{ + POINT pt; + RECT rc; + + GetCursorPos(&pt); + GetWindowRect(hwnd, &rc); + + /* FIXME: Change menu item status */ + switch(vk) + { + case VK_ESCAPE: + ShowWindow(hwnd, SW_HIDE); + break; + + case VK_UP: + if (PtInRect(&rc, pt)) + return; + break; + + case VK_DOWN: + if (PtInRect(&rc, pt)) + return; + break; + + case VK_LEFT: + if (PtInRect(&rc, pt)) + return; + break; + + case VK_RIGHT: + if (PtInRect(&rc, pt)) + return; + break; + + case VK_SPACE: + break; + + case VK_RETURN: /* [Enter] key */ + break; + } + + InvalidateRect(hwnd, NULL, FALSE); +} + +static LRESULT CALLBACK +StartMenu_WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + static CStartMenu *pMenu = NULL; + + switch(uMsg) + { + case WM_CREATE: + pMenu = (CStartMenu *)((LPCREATESTRUCT)lParam)->lpCreateParams; + pMenu->m_hWnd = hwnd; + if (!StartMenu_OnCreate(pMenu)) + return -1; + return 0; + + case WM_SHOWWINDOW: + /* NOTE: WM_MOUSEMOVE doesn't work, so we use WM_TIMER instead */ + if (wParam) + { + SetTimer(hwnd, 0xDEADBEEF, 400, NULL); + SetCapture(hwnd); + } + else + { + KillTimer(hwnd, 0xDEADBEEF); + } + pMenu->m_iMenuSelected = pMenu->m_iMenuHot = -1; + break; + + case WM_TIMER: + InvalidateRect(hwnd, NULL, FALSE); + break; + + case WM_PAINT: + StartMenu_OnPaint(hwnd, pMenu); + break; + + case WM_KEYDOWN: + StartMenu_OnKeyDown(hwnd, pMenu, (UINT)wParam); + break; + + case WM_LBUTTONDOWN: + case WM_RBUTTONDOWN: + { + POINT pt; + pt.x = (short)LOWORD(lParam); + pt.y = (short)HIWORD(lParam); + INT i = StartMenu_HitTest(hwnd, pMenu, pt); + if (i != -1) + pMenu->m_iMenuSelected = i; + InvalidateRect(hwnd, NULL, FALSE); + break; + } + + case WM_LBUTTONUP: + case WM_RBUTTONUP: + ReleaseCapture(); + break; + + case WM_KILLFOCUS: + lParam = wParam; + /* FALL THRU */ + + case WM_CAPTURECHANGED: + { + TCHAR szClsName[32]; + GetClassName((HWND)lParam, szClsName, 32); + if (lstrcmpi(szClsName, TEXT("BUTTON")) == 0) + { + DWORD PID; + GetWindowThreadProcessId((HWND)lParam, &PID); + if (GetCurrentProcessId() == PID) + break; + } + ShowWindow(hwnd, SW_HIDE); + break; + } + + default: + return DefWindowProc(hwnd, uMsg, wParam, lParam); + } + + return 0; +} + +static BOOL +StartMenu_Register(VOID) +{ + WNDCLASSEX wcx; + + wcx.cbSize = sizeof(wcx); + wcx.style = CS_DBLCLKS; + wcx.lpfnWndProc = StartMenu_WndProc; + wcx.cbClsExtra = 0; + wcx.cbWndExtra = sizeof(CStartMenu*); + wcx.hInstance = GetModuleHandle(NULL); + wcx.hIcon = LoadIcon(NULL, IDI_WINLOGO); + wcx.hCursor = LoadCursor(NULL, IDC_ARROW); + wcx.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1); + wcx.lpszMenuName = NULL; + wcx.lpszClassName = szStartMenuWndClass; + wcx.hIconSm = (HICON)LoadImage(NULL, IDI_WINLOGO, IMAGE_ICON, + GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), 0); + + return RegisterClassEx(&wcx) != 0; +} + +static HWND +StartMenu_Create(CStartMenu *pMenu) +{ + RECT rc; + SIZE siz; + DWORD dwStyle, dwExStyle; + + StartMenu_CalcClientSize(pMenu, &siz); + rc.left = rc.top = 0; + rc.right = siz.cx; rc.bottom = siz.cy; + dwStyle = WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_DLGFRAME | WS_POPUP; + dwExStyle = WS_EX_TOPMOST | WS_EX_WINDOWEDGE; + AdjustWindowRectEx(&rc, dwStyle, FALSE, dwExStyle); + + return CreateWindowEx(dwExStyle, szStartMenuWndClass, NULL, dwStyle, + 0, 0, rc.right - rc.top, rc.bottom - rc.top, + NULL, NULL, GetModuleHandle(NULL), pMenu); +} + CStartMenu::CStartMenu() { m_pBandSite = NULL; m_pUnkSite = NULL; + m_hWnd = NULL; + m_iIcon = 32; + m_hBitmap = NULL; + m_sizBitmap.cx = m_sizBitmap.cy = 0; + m_iMenuSelected = m_iMenuHot = -1; } CStartMenu::~CStartMenu() @@ -40,8 +301,10 @@ HRESULT STDMETHODCALLTYPE CStartMenu::GetWindow(HWND *phwnd) { - UNIMPLEMENTED; - return E_NOTIMPL; + if (phwnd == NULL) + return E_POINTER; + *phwnd = m_hWnd; + return S_OK; } HRESULT STDMETHODCALLTYPE CStartMenu::GetClient(IUnknown **ppunkClient) @@ -73,8 +336,25 @@ HRESULT STDMETHODCALLTYPE CStartMenu::Popup(POINTL *ppt, RECTL *prcExclude, MP_POPUPFLAGS dwFlags) { - UNIMPLEMENTED; - return E_NOTIMPL; + RECT rc, rcWorkArea; + + GetWindowRect(m_hWnd, &rc); + SystemParametersInfo(SPI_GETWORKAREA, 0, &rcWorkArea, 0); + + /* FIXME: Check ppt and prcExclude */ + MoveWindow(m_hWnd, + 0, rcWorkArea.bottom - (rc.bottom - rc.top), + rc.right - rc.left, rc.bottom - rc.top, + TRUE); + + if (IsWindowVisible(m_hWnd)) + ShowWindow(m_hWnd, SW_HIDE); + else + ShowWindow(m_hWnd, SW_SHOW); + + InvalidateRect(m_hWnd, NULL, FALSE); + + return S_OK; } HRESULT STDMETHODCALLTYPE CStartMenu::SetSubMenu(IMenuPopup *pmp, BOOL fSet) @@ -112,6 +392,9 @@ TRACE("(%p)\n", this); + if (!StartMenu_Register() || !StartMenu_Create(this)) + return E_FAIL; + //pBandSiteObj = new CComObject(); ATLTRY (pBandSiteObj = new CComObject); if (pBandSiteObj == NULL) @@ -119,23 +402,84 @@ hr = pBandSiteObj->QueryInterface(IID_IBandSite, (VOID**)&m_pBandSite); if (FAILED(hr)) - return NULL; + return E_FAIL; return m_pBandSite->AddBand((IMenuBand*)this); } HRESULT STDMETHODCALLTYPE CStartMenu::IsMenuMessage(MSG *pmsg) { + if (pmsg->message == WM_CREATE) + return S_OK; + + if (IsWindow(m_hWnd) && pmsg->hwnd == m_hWnd) + { + if (PeekMessage(pmsg, m_hWnd, 0, 0, PM_REMOVE)) + { + TranslateMessage(pmsg); + DispatchMessage(pmsg); + return S_OK; + } + } + + return E_FAIL; +} + +HRESULT STDMETHODCALLTYPE CStartMenu::TranslateMenuMessage(MSG *pmsg, LRESULT *plRet) +{ + if (plRet == NULL) + return S_FALSE; + + if (pmsg->message == WM_CREATE) + return S_OK; + + if (IsWindow(m_hWnd) && pmsg->hwnd == m_hWnd) + { + if (PeekMessage(pmsg, m_hWnd, 0, 0, PM_REMOVE)) + { + TranslateMessage(pmsg); + DispatchMessage(pmsg); + *plRet = 0; + return S_OK; + } + } + + return E_FAIL; +} + +HRESULT STDMETHODCALLTYPE CStartMenu::SetIconSize(DWORD iIcon) +{ UNIMPLEMENTED; return E_NOTIMPL; } -HRESULT STDMETHODCALLTYPE CStartMenu::TranslateMenuMessage(MSG *pmsg, LRESULT *plRet) +HRESULT STDMETHODCALLTYPE CStartMenu::GetIconSize(DWORD* piIcon) { UNIMPLEMENTED; return E_NOTIMPL; } +HRESULT STDMETHODCALLTYPE CStartMenu::SetBitmap(HBITMAP hBitmap) +{ + BITMAP bm; + if (GetObject(hBitmap, sizeof(BITMAP), &bm)) + { + m_hBitmap = hBitmap; + m_sizBitmap.cx = bm.bmWidth; + m_sizBitmap.cy = bm.bmHeight; + return S_OK; + } + return E_FAIL; +} + +HRESULT STDMETHODCALLTYPE CStartMenu::GetBitmap(HBITMAP* phBitmap) +{ + if (phBitmap == NULL) + return E_FAIL; + *phBitmap = m_hBitmap; + return S_OK; +} + CMenuBandSite::CMenuBandSite() { m_pObjects = NULL; Index: dll/win32/shell32/startmenu.h =================================================================== --- dll/win32/shell32/startmenu.h (revision 57871) +++ dll/win32/shell32/startmenu.h (working copy) @@ -27,16 +27,25 @@ public IMenuPopup, public IObjectWithSite, public IInitializeObject, - public IMenuBand // FIXME + public IMenuBand, // FIXME + public IBanneredBar { private: IBandSite *m_pBandSite; IUnknown *m_pUnkSite; public: - CStartMenu(); - ~CStartMenu(); + HWND m_hWnd; + DWORD m_iIcon; + HBITMAP m_hBitmap; + SIZE m_sizBitmap; + INT m_iMenuSelected; + INT m_iMenuHot; +public: + CStartMenu(); + ~CStartMenu(); + // *** IOleWindow methods *** virtual HRESULT STDMETHODCALLTYPE ContextSensitiveHelp(BOOL fEnterMode); virtual HRESULT STDMETHODCALLTYPE GetWindow(HWND *phwnd); @@ -62,6 +71,13 @@ virtual HRESULT STDMETHODCALLTYPE IsMenuMessage(MSG *pmsg); virtual HRESULT STDMETHODCALLTYPE TranslateMenuMessage(MSG *pmsg, LRESULT *plRet); + // *** IBanneredBar methods *** + virtual HRESULT STDMETHODCALLTYPE SetIconSize(DWORD iIcon); + virtual HRESULT STDMETHODCALLTYPE GetIconSize(DWORD* piIcon); + virtual HRESULT STDMETHODCALLTYPE SetBitmap(HBITMAP hBitmap); + virtual HRESULT STDMETHODCALLTYPE GetBitmap(HBITMAP* phBitmap); + + DECLARE_REGISTRY_RESOURCEID(IDR_STARTMENU) DECLARE_NOT_AGGREGATABLE(CStartMenu) @@ -74,6 +90,7 @@ COM_INTERFACE_ENTRY_IID(IID_IObjectWithSite, IObjectWithSite) COM_INTERFACE_ENTRY_IID(IID_IInitializeObject, IInitializeObject) COM_INTERFACE_ENTRY_IID(IID_IMenuBand, IMenuBand) // FIXME: Win does not export it + COM_INTERFACE_ENTRY_IID(IID_IBanneredBar, IBanneredBar) END_COM_MAP() };