diff --git a/base/shell/explorer-new/CMakeLists.txt b/base/shell/explorer-new/CMakeLists.txt index 2672ce321dd..821d88fa17e 100644 --- a/base/shell/explorer-new/CMakeLists.txt +++ b/base/shell/explorer-new/CMakeLists.txt @@ -1,28 +1,34 @@ - PROJECT(SHELL) -add_definitions(-DWIN32) +set_cpp(WITH_RUNTIME) + +include_directories(${REACTOS_SOURCE_DIR}/lib/atl) list(APPEND SOURCE - desktop.c - dragdrop.c - explorer.c - rshell.c - settings.c - shellservice.c - startmnu.c - startup.c - taskband.c - taskswnd.c - tbsite.c - trayntfy.c - trayprop.c - traywnd.c + desktop.cpp + dragdrop.cpp + explorer.cpp + rshell.cpp + settings.cpp + shellservice.cpp + startmnu.cpp + startup.cpp + taskband.cpp + taskswnd.cpp + tbsite.cpp + trayntfy.cpp + trayprop.cpp + traywnd.cpp + util.cpp precomp.h) add_executable(explorer ${SOURCE} explorer.rc) -target_link_libraries(explorer uuid wine) + +target_link_libraries(explorer uuid atlnew wine) + set_module_type(explorer win32gui UNICODE) add_importlibs(explorer advapi32 gdi32 user32 comctl32 ole32 oleaut32 shell32 browseui shlwapi shdocvw version uxtheme msvcrt kernel32 ntdll) + add_pch(explorer precomp.h SOURCE) + add_cd_file(TARGET explorer DESTINATION reactos FOR all) diff --git a/base/shell/explorer-new/desktop.c b/base/shell/explorer-new/desktop.cpp similarity index 88% rename from base/shell/explorer-new/desktop.c rename to base/shell/explorer-new/desktop.cpp index 2ccebb3fc51..99c71d44d94 100644 --- a/base/shell/explorer-new/desktop.c +++ b/base/shell/explorer-new/desktop.cpp @@ -27,30 +27,29 @@ typedef struct _DESKCREATEINFO HANDLE hDesktop; } DESKCREATEINFO, *PDESKCREATEINFO; +HANDLE WINAPI _SHCreateDesktop(IShellDesktopTray *ShellDesk); +BOOL WINAPI _SHDesktopMessageLoop(HANDLE hDesktop); + static DWORD CALLBACK DesktopThreadProc(IN OUT LPVOID lpParameter) { volatile DESKCREATEINFO *DeskCreateInfo = (volatile DESKCREATEINFO *)lpParameter; - IShellDesktopTray *pSdt; + CComPtr pSdt; HANDLE hDesktop; HRESULT hRet; OleInitialize(NULL); - hRet = ITrayWindow_QueryInterface(DeskCreateInfo->Tray, - &IID_IShellDesktopTray, - (PVOID*)&pSdt); + hRet = DeskCreateInfo->Tray->QueryInterface(IID_PPV_ARG(IShellDesktopTray, &pSdt)); if (!SUCCEEDED(hRet)) return 1; - hDesktop = SHCreateDesktop(pSdt); + hDesktop = _SHCreateDesktop(pSdt); - IShellDesktopTray_Release(pSdt); if (hDesktop == NULL) return 1; - (void)InterlockedExchangePointer(&DeskCreateInfo->hDesktop, - hDesktop); + (void)InterlockedExchangePointer(&DeskCreateInfo->hDesktop, hDesktop); if (!SetEvent(DeskCreateInfo->hEvent)) { @@ -59,7 +58,7 @@ DesktopThreadProc(IN OUT LPVOID lpParameter) return 1; } - SHDesktopMessageLoop(hDesktop); + _SHDesktopMessageLoop(hDesktop); /* FIXME: Properly rundown the main thread! */ ExitProcess(0); diff --git a/base/shell/explorer-new/dragdrop.c b/base/shell/explorer-new/dragdrop.c deleted file mode 100644 index ae1cb640160..00000000000 --- a/base/shell/explorer-new/dragdrop.c +++ /dev/null @@ -1,411 +0,0 @@ -/* - * ReactOS Explorer - * - * Copyright 2006 - 2007 Thomas Weidenmueller - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "precomp.h" - -static const IDropTargetVtbl IDropTargetImpl_Vtbl; - -/* - * IDropTarget - */ - -typedef struct -{ - const IDropTargetVtbl *lpVtbl; - LONG Ref; - HWND hwndTarget; - IDropTargetHelper *DropTargetHelper; - PVOID Context; - BOOL CanDrop; - DROPTARGET_CALLBACKS Callbacks; - DWORD FormatsCount; - FORMATETC Formats[0]; -} IDropTargetImpl; - -static IUnknown * -IUnknown_from_impl(IDropTargetImpl *This) -{ - return (IUnknown *)&This->lpVtbl; -} - -static IDropTarget * -IDropTarget_from_impl(IDropTargetImpl *This) -{ - return (IDropTarget *)&This->lpVtbl; -} - -static IDropTargetImpl * -impl_from_IDropTarget(IDropTarget *iface) -{ - return (IDropTargetImpl *)((ULONG_PTR)iface - FIELD_OFFSET(IDropTargetImpl, - lpVtbl)); -} - -static VOID -IDropTargetImpl_Free(IDropTargetImpl *This) -{ - IDropTargetHelper_Release(This->DropTargetHelper); - HeapFree(hProcessHeap, - 0, - This); -} - -static ULONG STDMETHODCALLTYPE -IDropTargetImpl_Release(IN OUT IDropTarget *iface) -{ - IDropTargetImpl *This = impl_from_IDropTarget(iface); - ULONG Ret; - - Ret = InterlockedDecrement(&This->Ref); - if (Ret == 0) - IDropTargetImpl_Free(This); - - return Ret; -} - -static ULONG STDMETHODCALLTYPE -IDropTargetImpl_AddRef(IN OUT IDropTarget *iface) -{ - IDropTargetImpl *This = impl_from_IDropTarget(iface); - - return InterlockedIncrement(&This->Ref); -} - -static HRESULT STDMETHODCALLTYPE -IDropTargetImpl_QueryInterface(IN OUT IDropTarget *iface, - IN REFIID riid, - OUT LPVOID *ppvObj) -{ - IDropTargetImpl *This; - - if (ppvObj == NULL) - return E_POINTER; - - This = impl_from_IDropTarget(iface); - - if (IsEqualIID(riid, - &IID_IUnknown)) - { - *ppvObj = IUnknown_from_impl(This); - } - else if (IsEqualIID(riid, - &IID_IDropTarget)) - { - *ppvObj = IDropTarget_from_impl(This); - } - else - { - *ppvObj = NULL; - return E_NOINTERFACE; - } - - IDropTargetImpl_AddRef(iface); - return S_OK; -} - -IDropTarget * -CreateDropTarget(IN HWND hwndTarget, - IN DWORD nSupportedFormats, - IN const FORMATETC *Formats OPTIONAL, - IN PVOID Context OPTIONAL, - IN const DROPTARGET_CALLBACKS *Callbacks OPTIONAL) -{ - IDropTargetImpl *This; - HRESULT hr; - - This = HeapAlloc(hProcessHeap, - HEAP_ZERO_MEMORY, - FIELD_OFFSET(IDropTargetImpl, - Formats[nSupportedFormats])); - if (This != NULL) - { - This->lpVtbl = &IDropTargetImpl_Vtbl; - This->Ref = 1; - This->hwndTarget = hwndTarget; - This->FormatsCount = nSupportedFormats; - if (nSupportedFormats != 0) - { - CopyMemory(This->Formats, - Formats, - sizeof(Formats[0]) * nSupportedFormats); - } - - This->Context = Context; - if (Callbacks != NULL) - { - CopyMemory(&This->Callbacks, - Callbacks, - sizeof(*Callbacks)); - } - - hr = CoCreateInstance(&CLSID_DragDropHelper, - NULL, - CLSCTX_INPROC_SERVER, - &IID_IDropTargetHelper, - (PVOID *)&This->DropTargetHelper); - - if (!SUCCEEDED(hr)) - { - HeapFree(hProcessHeap, - 0, - This); - return NULL; - } - - return IDropTarget_from_impl(This); - } - - return NULL; -} - -static const FORMATETC * -IDropTargetImpl_FindSupportedFormat(IN OUT IDropTargetImpl *This, - IN IDataObject *pDataObject) -{ - FORMATETC *Current, *Last; - HRESULT hr; - - /* NOTE: we could use IDataObject::EnumFormatEtc(), - but this appears to be a lot easier! */ - Last = This->Formats + This->FormatsCount; - for (Current = This->Formats; - Current != Last; - Current++) - { - hr = IDataObject_QueryGetData(pDataObject, - Current); - if (SUCCEEDED(hr)) - return Current; - } - - return NULL; -} - -static HRESULT STDMETHODCALLTYPE -IDropTargetImpl_DragEnter(IN OUT IDropTarget *iface, - IN IDataObject *pDataObject, - IN DWORD grfKeyState, - IN POINTL pt, - IN OUT DWORD *pdwEffect) -{ - IDropTargetImpl *This = impl_from_IDropTarget(iface); - const FORMATETC *Format; - HRESULT hr; - - if (pDataObject == NULL) - return E_INVALIDARG; - - This->CanDrop = FALSE; - - hr = IDropTargetHelper_DragEnter(This->DropTargetHelper, - This->hwndTarget, - pDataObject, - (POINT *)&pt, - *pdwEffect); - - if (SUCCEEDED(hr)) - { - Format = IDropTargetImpl_FindSupportedFormat(This, - pDataObject); - if (Format != NULL) - { - /* We found a format that we support! */ - if (This->Callbacks.OnDragEnter != NULL) - { - hr = This->Callbacks.OnDragEnter(iface, - This->Context, - Format, - grfKeyState, - pt, - pdwEffect); - if (SUCCEEDED(hr)) - { - if (hr == S_OK) - This->CanDrop = TRUE; - else - { - /* Special return value by the callback routine, - doesn't want to allow dragging */ - *pdwEffect = DROPEFFECT_NONE; - } - - hr = S_OK; - } - else - { - *pdwEffect = DROPEFFECT_NONE; - hr = S_OK; - } - } - else - *pdwEffect = DROPEFFECT_NONE; - } - else - *pdwEffect = DROPEFFECT_NONE; - } - - return hr; -} - -static HRESULT STDMETHODCALLTYPE -IDropTargetImpl_DragOver(IN OUT IDropTarget *iface, - IN DWORD grfKeyState, - IN POINTL pt, - IN OUT DWORD *pdwEffect) -{ - IDropTargetImpl *This = impl_from_IDropTarget(iface); - HRESULT hr; - - hr = IDropTargetHelper_DragOver(This->DropTargetHelper, - (POINT *)&pt, - *pdwEffect); - - if (SUCCEEDED(hr)) - { - if (This->CanDrop) - { - if (This->Callbacks.OnDragOver != NULL) - { - hr = This->Callbacks.OnDragOver(iface, - This->Context, - grfKeyState, - pt, - pdwEffect); - if (SUCCEEDED(hr)) - { - if (hr != S_OK) - { - /* Special return value by the callback routine, - doesn't want to allow dropping here */ - *pdwEffect = DROPEFFECT_NONE; - } - - hr = S_OK; - } - else - { - *pdwEffect = DROPEFFECT_NONE; - hr = S_OK; - } - } - else - *pdwEffect = DROPEFFECT_NONE; - } - else - *pdwEffect = DROPEFFECT_NONE; - } - - return hr; -} - -static HRESULT STDMETHODCALLTYPE -IDropTargetImpl_DragLeave(IN OUT IDropTarget *iface) -{ - IDropTargetImpl *This = impl_from_IDropTarget(iface); - HRESULT hr; - - hr = IDropTargetHelper_DragLeave(This->DropTargetHelper); - if (SUCCEEDED(hr)) - { - if (This->Callbacks.OnDragLeave != NULL) - { - hr = This->Callbacks.OnDragLeave(iface, - This->Context); - } - } - - return hr; -} - -static HRESULT STDMETHODCALLTYPE -IDropTargetImpl_Drop(IN OUT IDropTarget *iface, - IN IDataObject *pDataObject, - IN DWORD grfKeyState, - IN POINTL pt, - IN OUT DWORD *pdwEffect) -{ - IDropTargetImpl *This = impl_from_IDropTarget(iface); - const FORMATETC *Format; - HRESULT hr; - - if (pDataObject == NULL) - return E_INVALIDARG; - - hr = IDropTargetHelper_Drop(This->DropTargetHelper, - pDataObject, - (POINT *)&pt, - *pdwEffect); - - if (SUCCEEDED(hr) && This->CanDrop) - { - Format = IDropTargetImpl_FindSupportedFormat(This, - pDataObject); - if (Format != NULL) - { - /* We found a format that we support! */ - if (This->Callbacks.OnDrop != NULL) - { - hr = This->Callbacks.OnDrop(iface, - This->Context, - Format, - grfKeyState, - pt, - pdwEffect); - if (SUCCEEDED(hr)) - { - if (hr == S_OK) - This->CanDrop = TRUE; - else - { - /* Special return value by the callback routine, - doesn't want to allow dragging */ - *pdwEffect = DROPEFFECT_NONE; - } - - hr = S_OK; - } - else - { - *pdwEffect = DROPEFFECT_NONE; - hr = S_OK; - } - } - else - *pdwEffect = DROPEFFECT_NONE; - } - else - *pdwEffect = DROPEFFECT_NONE; - } - - return hr; -} - -static const IDropTargetVtbl IDropTargetImpl_Vtbl = -{ - /* IUnknown */ - IDropTargetImpl_QueryInterface, - IDropTargetImpl_AddRef, - IDropTargetImpl_Release, - /* IDropTarget */ - IDropTargetImpl_DragEnter, - IDropTargetImpl_DragOver, - IDropTargetImpl_DragLeave, - IDropTargetImpl_Drop -}; diff --git a/base/shell/explorer-new/dragdrop.cpp b/base/shell/explorer-new/dragdrop.cpp new file mode 100644 index 00000000000..d9c21e6f42a --- /dev/null +++ b/base/shell/explorer-new/dragdrop.cpp @@ -0,0 +1,314 @@ +/* + * ReactOS Explorer + * + * Copyright 2006 - 2007 Thomas Weidenmueller + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "precomp.h" + +class CDropTarget : + public CComCoClass, + public CComObjectRootEx, + public IDropTarget +{ + HWND hwndTarget; + CComPtr DropTargetHelper; + PVOID Context; + BOOL CanDrop; + DROPTARGET_CALLBACKS Callbacks; + DWORD FormatsCount; + FORMATETC* Formats; + + const FORMATETC * + FindSupportedFormat(IN IDataObject *pDataObject) + { + FORMATETC *Current, *Last; + HRESULT hr; + + /* NOTE: we could use IDataObject::EnumFormatEtc(), + but this appears to be a lot easier! */ + Last = Formats + FormatsCount; + for (Current = Formats; + Current != Last; + Current++) + { + hr = pDataObject->QueryGetData(Current); + if (SUCCEEDED(hr)) + return Current; + } + + return NULL; + } + +public: + CDropTarget() : + hwndTarget(NULL), + Context(NULL), + CanDrop(FALSE), + FormatsCount(0), + Formats(NULL) + { + ZeroMemory(&Callbacks, sizeof(Callbacks)); + } + + virtual ~CDropTarget() { } + + HRESULT Initialize(IN HWND hwndTarget, + IN DWORD nSupportedFormats, + IN const FORMATETC *formats OPTIONAL, + IN PVOID Context OPTIONAL, + IN const DROPTARGET_CALLBACKS *Callbacks OPTIONAL) + { + this->hwndTarget = hwndTarget; + FormatsCount = nSupportedFormats; + if (nSupportedFormats != 0) + { + Formats = new FORMATETC[nSupportedFormats]; + CopyMemory(Formats, + formats, + sizeof(formats[0]) * nSupportedFormats); + } + + this->Context = Context; + if (Callbacks != NULL) + { + CopyMemory(&this->Callbacks, + Callbacks, + sizeof(*Callbacks)); + } + + HRESULT hr = CoCreateInstance(CLSID_DragDropHelper, + NULL, + CLSCTX_INPROC_SERVER, + IID_PPV_ARG(IDropTargetHelper, &DropTargetHelper)); + + return hr; + } + + virtual HRESULT STDMETHODCALLTYPE DragEnter( + IN IDataObject *pDataObject, + IN DWORD grfKeyState, + IN POINTL pt, + IN OUT DWORD *pdwEffect) + { + const FORMATETC *Format; + HRESULT hr; + + if (pDataObject == NULL) + return E_INVALIDARG; + + CanDrop = FALSE; + + hr = DropTargetHelper->DragEnter( + hwndTarget, + pDataObject, + (POINT *) &pt, + *pdwEffect); + + if (SUCCEEDED(hr)) + { + Format = FindSupportedFormat( + pDataObject); + if (Format != NULL) + { + /* We found a format that we support! */ + if (Callbacks.OnDragEnter != NULL) + { + hr = Callbacks.OnDragEnter(this, + Context, + Format, + grfKeyState, + pt, + pdwEffect); + if (SUCCEEDED(hr)) + { + if (hr == S_OK) + CanDrop = TRUE; + else + { + /* Special return value by the callback routine, + doesn't want to allow dragging */ + *pdwEffect = DROPEFFECT_NONE; + } + + hr = S_OK; + } + else + { + *pdwEffect = DROPEFFECT_NONE; + hr = S_OK; + } + } + else + *pdwEffect = DROPEFFECT_NONE; + } + else + *pdwEffect = DROPEFFECT_NONE; + } + + return hr; + } + + virtual HRESULT STDMETHODCALLTYPE DragOver( + IN DWORD grfKeyState, + IN POINTL pt, + IN OUT DWORD *pdwEffect) + { + HRESULT hr; + + hr = DropTargetHelper->DragOver( + (POINT *) &pt, + *pdwEffect); + + if (SUCCEEDED(hr)) + { + if (CanDrop) + { + if (Callbacks.OnDragOver != NULL) + { + hr = Callbacks.OnDragOver(this, + Context, + grfKeyState, + pt, + pdwEffect); + if (SUCCEEDED(hr)) + { + if (hr != S_OK) + { + /* Special return value by the callback routine, + doesn't want to allow dropping here */ + *pdwEffect = DROPEFFECT_NONE; + } + + hr = S_OK; + } + else + { + *pdwEffect = DROPEFFECT_NONE; + hr = S_OK; + } + } + else + *pdwEffect = DROPEFFECT_NONE; + } + else + *pdwEffect = DROPEFFECT_NONE; + } + + return hr; + } + + virtual HRESULT STDMETHODCALLTYPE DragLeave() + { + HRESULT hr; + + hr = DropTargetHelper->DragLeave(); + if (SUCCEEDED(hr)) + { + if (Callbacks.OnDragLeave != NULL) + { + hr = Callbacks.OnDragLeave(this, + Context); + } + } + + return hr; + } + + virtual HRESULT STDMETHODCALLTYPE Drop( + IN IDataObject *pDataObject, + IN DWORD grfKeyState, + IN POINTL pt, + IN OUT DWORD *pdwEffect) + { + const FORMATETC *Format; + HRESULT hr; + + if (pDataObject == NULL) + return E_INVALIDARG; + + hr = DropTargetHelper->Drop( + pDataObject, + (POINT *) &pt, + *pdwEffect); + + if (SUCCEEDED(hr) && CanDrop) + { + Format = FindSupportedFormat(pDataObject); + if (Format != NULL) + { + /* We found a format that we support! */ + if (Callbacks.OnDrop != NULL) + { + hr = Callbacks.OnDrop(this, + Context, + Format, + grfKeyState, + pt, + pdwEffect); + if (SUCCEEDED(hr)) + { + if (hr == S_OK) + CanDrop = TRUE; + else + { + /* Special return value by the callback routine, + doesn't want to allow dragging */ + *pdwEffect = DROPEFFECT_NONE; + } + + hr = S_OK; + } + else + { + *pdwEffect = DROPEFFECT_NONE; + hr = S_OK; + } + } + else + *pdwEffect = DROPEFFECT_NONE; + } + else + *pdwEffect = DROPEFFECT_NONE; + } + + return hr; + } + + DECLARE_NOT_AGGREGATABLE(CDropTarget) + + DECLARE_PROTECT_FINAL_CONSTRUCT() + BEGIN_COM_MAP(CDropTarget) + COM_INTERFACE_ENTRY_IID(IID_IDropTarget, IDropTarget) + END_COM_MAP() +}; + +IDropTarget * +CreateDropTarget(IN HWND hwndTarget, + IN DWORD nSupportedFormats, + IN const FORMATETC *Formats OPTIONAL, + IN PVOID Context OPTIONAL, + IN const DROPTARGET_CALLBACKS *Callbacks OPTIONAL) +{ + IDropTarget *dt; + + HRESULT hr = ShellObjectCreatorInit(hwndTarget, nSupportedFormats, Formats, Context, Callbacks, IID_IDropTarget, &dt); + if (FAILED_UNEXPECTEDLY(hr)) + return NULL; + + return dt; +} diff --git a/base/shell/explorer-new/explorer.c b/base/shell/explorer-new/explorer.c deleted file mode 100644 index fe30d620352..00000000000 --- a/base/shell/explorer-new/explorer.c +++ /dev/null @@ -1,485 +0,0 @@ -/* - * ReactOS Explorer - * - * Copyright 2006 - 2007 Thomas Weidenmueller - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "precomp.h" -#include -#include - -HINSTANCE hExplorerInstance; -HMODULE hUser32; -HANDLE hProcessHeap; -HKEY hkExplorer = NULL; -DRAWCAPTEMP DrawCapTemp = NULL; - -typedef struct _LANGCODEPAGE -{ - WORD wLanguage; - WORD wCodePage; -} LANGCODEPAGE, *PLANGCODEPAGE; - -LONG -SetWindowStyle(IN HWND hWnd, - IN LONG dwStyleMask, - IN LONG dwStyle) -{ - LONG PrevStyle, Style; - - ASSERT((~dwStyleMask & dwStyle) == 0); - - PrevStyle = GetWindowLong(hWnd, - GWL_STYLE); - if (PrevStyle != 0 && - (PrevStyle & dwStyleMask) != dwStyle) - { - Style = PrevStyle & ~dwStyleMask; - Style |= dwStyle; - - PrevStyle = SetWindowLong(hWnd, - GWL_STYLE, - Style); - } - - return PrevStyle; -} - -LONG -SetWindowExStyle(IN HWND hWnd, - IN LONG dwStyleMask, - IN LONG dwStyle) -{ - LONG PrevStyle, Style; - - ASSERT((~dwStyleMask & dwStyle) == 0); - - PrevStyle = GetWindowLong(hWnd, - GWL_EXSTYLE); - if (PrevStyle != 0 && - (PrevStyle & dwStyleMask) != dwStyle) - { - Style = PrevStyle & ~dwStyleMask; - Style |= dwStyle; - - PrevStyle = SetWindowLong(hWnd, - GWL_EXSTYLE, - Style); - } - - return PrevStyle; -} - -HMENU -LoadPopupMenu(IN HINSTANCE hInstance, - IN LPCTSTR lpMenuName) -{ - HMENU hMenu, hSubMenu = NULL; - - hMenu = LoadMenu(hInstance, - lpMenuName); - - if (hMenu != NULL) - { - hSubMenu = GetSubMenu(hMenu, - 0); - if (hSubMenu != NULL && - !RemoveMenu(hMenu, - 0, - MF_BYPOSITION)) - { - hSubMenu = NULL; - } - - DestroyMenu(hMenu); - } - - return hSubMenu; -} - -HMENU -FindSubMenu(IN HMENU hMenu, - IN UINT uItem, - IN BOOL fByPosition) -{ - MENUITEMINFO mii; - - mii.cbSize = sizeof(mii); - mii.fMask = MIIM_SUBMENU; - - if (GetMenuItemInfo(hMenu, - uItem, - fByPosition, - &mii)) - { - return mii.hSubMenu; - } - - return NULL; -} - -BOOL -GetCurrentLoggedOnUserName(OUT LPTSTR szBuffer, - IN DWORD dwBufferSize) -{ - DWORD dwType; - DWORD dwSize; - - /* Query the user name from the registry */ - dwSize = (dwBufferSize * sizeof(TCHAR)) - 1; - if (RegQueryValueEx(hkExplorer, - TEXT("Logon User Name"), - 0, - &dwType, - (LPBYTE)szBuffer, - &dwSize) == ERROR_SUCCESS && - (dwSize / sizeof(TCHAR)) > 1 && - szBuffer[0] != _T('\0')) - { - szBuffer[dwSize / sizeof(TCHAR)] = _T('\0'); - return TRUE; - } - - /* Fall back to GetUserName() */ - dwSize = dwBufferSize; - if (!GetUserName(szBuffer, - &dwSize)) - { - szBuffer[0] = _T('\0'); - return FALSE; - } - - return TRUE; -} - -BOOL -FormatMenuString(IN HMENU hMenu, - IN UINT uPosition, - IN UINT uFlags, - ...) -{ - va_list vl; - MENUITEMINFO mii; - TCHAR szBuf[128]; - TCHAR szBufFmt[128]; - - /* Find the menu item and read the formatting string */ - mii.cbSize = sizeof(mii); - mii.fMask = MIIM_STRING; - mii.dwTypeData = (LPTSTR)szBufFmt; - mii.cch = sizeof(szBufFmt) / sizeof(szBufFmt[0]); - if (GetMenuItemInfo(hMenu, - uPosition, - uFlags, - &mii)) - { - /* Format the string */ - va_start(vl, uFlags); - _vsntprintf(szBuf, - (sizeof(szBuf) / sizeof(szBuf[0])) - 1, - szBufFmt, - vl); - va_end(vl); - szBuf[(sizeof(szBuf) / sizeof(szBuf[0])) - 1] = _T('\0'); - - /* Update the menu item */ - mii.dwTypeData = (LPTSTR)szBuf; - if (SetMenuItemInfo(hMenu, - uPosition, - uFlags, - &mii)) - { - return TRUE; - } - } - - return FALSE; -} - -BOOL -GetExplorerRegValueSet(IN HKEY hKey, - IN LPCTSTR lpSubKey, - IN LPCTSTR lpValue) -{ - TCHAR szBuffer[MAX_PATH]; - HKEY hkSubKey; - DWORD dwType, dwSize; - BOOL Ret = FALSE; - - StringCbCopy(szBuffer, sizeof(szBuffer), - TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer")); - if (FAILED(StringCbCat(szBuffer, sizeof(szBuffer), - _T("\\")))) - return FALSE; - if (FAILED(StringCbCat(szBuffer, sizeof(szBuffer), - lpSubKey))) - return FALSE; - - dwSize = sizeof(szBuffer); - if (RegOpenKeyEx(hKey, - szBuffer, - 0, - KEY_QUERY_VALUE, - &hkSubKey) == ERROR_SUCCESS) - { - ZeroMemory(szBuffer, - sizeof(szBuffer)); - - if (RegQueryValueEx(hkSubKey, - lpValue, - 0, - &dwType, - (LPBYTE)szBuffer, - &dwSize) == ERROR_SUCCESS) - { - if (dwType == REG_DWORD && dwSize == sizeof(DWORD)) - Ret = *((PDWORD)szBuffer) != 0; - else if (dwSize > 0) - Ret = *((PUCHAR)szBuffer) != 0; - } - - RegCloseKey(hkSubKey); - } - return Ret; -} - - -static BOOL -SetShellReadyEvent(IN LPCTSTR lpEventName) -{ - HANDLE hEvent; - - hEvent = OpenEvent(EVENT_MODIFY_STATE, - FALSE, - lpEventName); - if (hEvent != NULL) - { - SetEvent(hEvent); - - CloseHandle(hEvent); - return TRUE; - } - - return FALSE; -} - -BOOL -GetVersionInfoString(IN TCHAR *szFileName, - IN TCHAR *szVersionInfo, - OUT TCHAR *szBuffer, - IN UINT cbBufLen) -{ - LPVOID lpData = NULL; - TCHAR szSubBlock[128]; - TCHAR *lpszLocalBuf = NULL; - LANGID UserLangId; - PLANGCODEPAGE lpTranslate = NULL; - DWORD dwLen; - DWORD dwHandle; - UINT cbTranslate; - UINT cbLen; - BOOL bRet = FALSE; - unsigned int i; - - dwLen = GetFileVersionInfoSize(szFileName, &dwHandle); - - if (dwLen > 0) - { - lpData = HeapAlloc(hProcessHeap, 0, dwLen); - - if (lpData != NULL) - { - if (GetFileVersionInfo(szFileName, - 0, - dwLen, - lpData) != 0) - { - UserLangId = GetUserDefaultLangID(); - - VerQueryValue(lpData, - TEXT("\\VarFileInfo\\Translation"), - (LPVOID *)&lpTranslate, - &cbTranslate); - - for (i = 0; i < cbTranslate / sizeof(LANGCODEPAGE); i++) - { - /* If the bottom eight bits of the language id's - match, use this version information (since this - means that the version information and the users - default language are the same). */ - if ((lpTranslate[i].wLanguage & 0xFF) == - (UserLangId & 0xFF)) - { - wnsprintf(szSubBlock, - sizeof(szSubBlock) / sizeof(szSubBlock[0]), - TEXT("\\StringFileInfo\\%04X%04X\\%s"), - lpTranslate[i].wLanguage, - lpTranslate[i].wCodePage, - szVersionInfo); - - if (VerQueryValue(lpData, - szSubBlock, - (LPVOID *)&lpszLocalBuf, - &cbLen) != 0) - { - _tcsncpy(szBuffer, lpszLocalBuf, cbBufLen / sizeof(*szBuffer)); - - bRet = TRUE; - break; - } - } - } - } - HeapFree(hProcessHeap, 0, lpData); - lpData = NULL; - } - } - - return bRet; -} - -static VOID -HideMinimizedWindows(IN BOOL bHide) -{ - MINIMIZEDMETRICS mm; - - mm.cbSize = sizeof(mm); - if (!SystemParametersInfo(SPI_GETMINIMIZEDMETRICS, sizeof(mm), &mm, 0)) - { - ERR("SystemParametersInfo failed with %lu\n", GetLastError()); - return; - } - if (bHide) - mm.iArrange |= ARW_HIDE; - else - mm.iArrange &= ~ARW_HIDE; - if (!SystemParametersInfo(SPI_SETMINIMIZEDMETRICS, sizeof(mm), &mm, 0)) - ERR("SystemParametersInfo failed with %lu\n", GetLastError()); -} - -INT WINAPI -_tWinMain(IN HINSTANCE hInstance, - IN HINSTANCE hPrevInstance, - IN LPTSTR lpCmdLine, - IN INT nCmdShow) -{ - ITrayWindow *Tray = NULL; - HANDLE hShellDesktop = NULL; - BOOL CreateShellDesktop = FALSE; - - DbgPrint("Explorer starting... Commandline: %S\n", lpCmdLine); - - /* - * Set our shutdown parameters: we want to shutdown the very last, - * but before any TaskMgr instance (which has a shutdown level of 1). - */ - SetProcessShutdownParameters(2, 0); - - if (GetShellWindow() == NULL) - CreateShellDesktop = TRUE; - - if (!CreateShellDesktop) - { - EXPLORER_CMDLINE_PARSE_RESULTS parseResults = { 0 }; - - if (SHExplorerParseCmdLine(&parseResults)) - return SHCreateFromDesktop(&parseResults); - - if (parseResults.strPath) - SHFree(parseResults.strPath); - - if (parseResults.pidlPath) - ILFree(parseResults.pidlPath); - - if (parseResults.pidlRoot) - ILFree(parseResults.pidlRoot); - - } - - if (RegOpenKey(HKEY_CURRENT_USER, - TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer"), - &hkExplorer) != ERROR_SUCCESS) - { - TCHAR Message[256]; - LoadString(hInstance, IDS_STARTUP_ERROR, Message, 256); - MessageBox(NULL, Message, NULL, MB_ICONERROR); - return 1; - } - - hExplorerInstance = hInstance; - hProcessHeap = GetProcessHeap(); - LoadAdvancedSettings(); - - hUser32 = GetModuleHandle(TEXT("USER32.DLL")); - if (hUser32 != NULL) - { - DrawCapTemp = (DRAWCAPTEMP)GetProcAddress(hUser32, - PROC_NAME_DRAWCAPTIONTEMP); - } - - InitCommonControls(); - OleInitialize(NULL); - - ProcessStartupItems(); - - /* Initialize shell dde support */ - ShellDDEInit(TRUE); - - /* Initialize shell icons */ - FileIconInit(TRUE); - - /* Initialize CLSID_ShellWindows class */ - WinList_Init(); - - if (RegisterTrayWindowClass() && RegisterTaskSwitchWndClass()) - { - Tray = CreateTrayWindow(); - /* This not only hides the minimized window captions in the bottom - left screen corner, but is also needed in order to receive - HSHELL_* notification messages (which are required for taskbar - buttons to work right) */ - HideMinimizedWindows(TRUE); - - if (Tray != NULL) - hShellDesktop = DesktopCreateWindow(Tray); - } - - /* WinXP: Notify msgina to hide the welcome screen */ - if (!SetShellReadyEvent(TEXT("msgina: ShellReadyEvent"))) - SetShellReadyEvent(TEXT("Global\\msgina: ShellReadyEvent")); - - if (Tray != NULL) - { - RegisterHotKey(NULL, IDHK_RUN, MOD_WIN, 'R'); - TrayMessageLoop(Tray); - HideMinimizedWindows(FALSE); - ITrayWindow_Release(Tray); - UnregisterTrayWindowClass(); - } - - if (hShellDesktop != NULL) - DesktopDestroyShellWindow(hShellDesktop); - - /* FIXME - shutdown SSO Thread */ - - OleUninitialize(); - - RegCloseKey(hkExplorer); - hkExplorer = NULL; - - return 0; -} diff --git a/base/shell/explorer-new/explorer.cpp b/base/shell/explorer-new/explorer.cpp new file mode 100644 index 00000000000..bd40c3db135 --- /dev/null +++ b/base/shell/explorer-new/explorer.cpp @@ -0,0 +1,239 @@ +/* + * ReactOS Explorer + * + * Copyright 2006 - 2007 Thomas Weidenmueller + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "precomp.h" +#include + +DWORD WINAPI _WinList_Init(void); +void WINAPI _ShellDDEInit(BOOL bInit); + +HINSTANCE hExplorerInstance; +HMODULE hUser32; +HANDLE hProcessHeap; +HKEY hkExplorer = NULL; +DRAWCAPTEMP DrawCapTemp = NULL; + +class CExplorerModule : public CComModule +{ +public: +}; + +BEGIN_OBJECT_MAP(ObjectMap) +END_OBJECT_MAP() + +CExplorerModule gModule; +CAtlWinModule gWinModule; + +void *operator new (size_t, void *buf) +{ + return buf; +} + +static VOID InitializeAtlModule(HINSTANCE hInstance, BOOL bInitialize) +{ + if (bInitialize) + { + /* HACK - the global constructors don't run, so I placement new them here */ + new (&gModule) CExplorerModule; + new (&gWinModule) CAtlWinModule; + new (&_AtlBaseModule) CAtlBaseModule; + new (&_AtlComModule) CAtlComModule; + + gModule.Init(ObjectMap, hInstance, NULL); + } + else + { + gModule.Term(); + } +} + +#if !WIN7_COMPAT_MODE +static BOOL +SetShellReadyEvent(IN LPCTSTR lpEventName) +{ + HANDLE hEvent; + + hEvent = OpenEvent(EVENT_MODIFY_STATE, FALSE, lpEventName); + if (hEvent != NULL) + { + SetEvent(hEvent); + + CloseHandle(hEvent); + return TRUE; + } + + return FALSE; +} + +static VOID +HideMinimizedWindows(IN BOOL bHide) +{ + MINIMIZEDMETRICS mm; + + mm.cbSize = sizeof(mm); + if (!SystemParametersInfo(SPI_GETMINIMIZEDMETRICS, sizeof(mm), &mm, 0)) + { + ERR("SystemParametersInfo failed with %lu\n", GetLastError()); + return; + } + if (bHide) + mm.iArrange |= ARW_HIDE; + else + mm.iArrange &= ~ARW_HIDE; + if (!SystemParametersInfo(SPI_SETMINIMIZEDMETRICS, sizeof(mm), &mm, 0)) + ERR("SystemParametersInfo failed with %lu\n", GetLastError()); +} + +static INT +StartWithCommandLine(IN HINSTANCE hInstance) +{ + BOOL b = FALSE; + EXPLORER_CMDLINE_PARSE_RESULTS parseResults = { 0 }; + + if (SHExplorerParseCmdLine(&parseResults)) + b = SHCreateFromDesktop(&parseResults); + + if (parseResults.strPath) + SHFree(parseResults.strPath); + + if (parseResults.pidlPath) + ILFree(parseResults.pidlPath); + + if (parseResults.pidlRoot) + ILFree(parseResults.pidlRoot); + + return b; +} +#endif + +static INT +StartWithDesktop(IN HINSTANCE hInstance) +{ + InitializeAtlModule(hInstance, TRUE); + + if (RegOpenKey(HKEY_CURRENT_USER, + L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer", + &hkExplorer) != ERROR_SUCCESS) + { + WCHAR Message[256]; + LoadString(hInstance, IDS_STARTUP_ERROR, Message, 256); + MessageBox(NULL, Message, NULL, MB_ICONERROR); + return 1; + } + + hExplorerInstance = hInstance; + hProcessHeap = GetProcessHeap(); + LoadAdvancedSettings(); + + hUser32 = GetModuleHandle(TEXT("USER32.DLL")); + if (hUser32 != NULL) + { + DrawCapTemp = (DRAWCAPTEMP) GetProcAddress(hUser32, PROC_NAME_DRAWCAPTIONTEMP); + } + + InitCommonControls(); + OleInitialize(NULL); + +#if !WIN7_COMPAT_MODE + ProcessStartupItems(); + + /* Initialize shell dde support */ + _ShellDDEInit(TRUE); +#endif + + /* Initialize shell icons */ + FileIconInit(TRUE); + + /* Initialize CLSID_ShellWindows class */ + _WinList_Init(); + + CComPtr Tray; + CreateTrayWindow(&Tray); + +#if !WIN7_COMPAT_MODE + /* This not only hides the minimized window captions in the bottom + left screen corner, but is also needed in order to receive + HSHELL_* notification messages (which are required for taskbar + buttons to work right) */ + HideMinimizedWindows(TRUE); + + HANDLE hShellDesktop = NULL; + if (Tray != NULL) + hShellDesktop = DesktopCreateWindow(Tray); + + /* WinXP: Notify msgina to hide the welcome screen */ + if (!SetShellReadyEvent(TEXT("msgina: ShellReadyEvent"))) + SetShellReadyEvent(TEXT("Global\\msgina: ShellReadyEvent")); +#endif + + if (Tray != NULL) + { +#if !WIN7_COMPAT_MODE + RegisterHotKey(NULL, IDHK_RUN, MOD_WIN, 'R'); +#endif + TrayMessageLoop(Tray); +#if !WIN7_COMPAT_MODE + HideMinimizedWindows(FALSE); +#endif + } + +#if !WIN7_COMPAT_MODE + if (hShellDesktop != NULL) + DesktopDestroyShellWindow(hShellDesktop); +#endif + + OleUninitialize(); + + RegCloseKey(hkExplorer); + hkExplorer = NULL; + + InitializeAtlModule(hInstance, FALSE); + + return 0; +} + +INT WINAPI +_tWinMain(IN HINSTANCE hInstance, + IN HINSTANCE hPrevInstance, + IN LPTSTR lpCmdLine, + IN INT nCmdShow) +{ +#if !WIN7_COMPAT_MODE + BOOL CreateShellDesktop = FALSE; + + DbgPrint("Explorer starting... Commandline: %S\n", lpCmdLine); + + /* + * Set our shutdown parameters: we want to shutdown the very last, + * but before any TaskMgr instance (which has a shutdown level of 1). + */ + SetProcessShutdownParameters(2, 0); + + if (GetShellWindow() == NULL) + CreateShellDesktop = TRUE; + + if (!CreateShellDesktop) + { + return StartWithCommandLine(hInstance); + } +#endif + + return StartWithDesktop(hInstance); +} diff --git a/base/shell/explorer-new/precomp.h b/base/shell/explorer-new/precomp.h index 56571d2cb39..e9e6c26771d 100644 --- a/base/shell/explorer-new/precomp.h +++ b/base/shell/explorer-new/precomp.h @@ -1,6 +1,8 @@ #ifndef _EXPLORER_PRECOMP__H_ #define _EXPLORER_PRECOMP__H_ +#define WIN7_COMPAT_MODE 0 + #include #include @@ -16,6 +18,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -24,6 +29,7 @@ #include #include #include +#include #include "tmschema.h" #include "resource.h" @@ -34,62 +40,26 @@ WINE_DEFAULT_DEBUG_CHANNEL(explorernew); /* dynamic imports due to lack of support in msvc linker libs */ -typedef INT (APIENTRY *REGSHELLHOOK)(HWND, DWORD); +typedef INT(APIENTRY *REGSHELLHOOK)(HWND, DWORD); #ifdef UNICODE #define PROC_NAME_DRAWCAPTIONTEMP "DrawCaptionTempW" -typedef BOOL (APIENTRY *DRAWCAPTEMP)(HWND, HDC, const RECT*, HFONT, HICON, LPCWSTR, UINT); +typedef BOOL(APIENTRY *DRAWCAPTEMP)(HWND, HDC, const RECT*, HFONT, HICON, LPCWSTR, UINT); #else #define PROC_NAME_DRAWCAPTIONTEMP "DrawCaptionTempA" typedef BOOL (APIENTRY *DRAWCAPTEMP)(HWND, HDC, const RECT*, HFONT, HICON, LPCSTR, UINT); #endif -typedef HRESULT (APIENTRY *SHINVDEFCMD)(HWND, IShellFolder*, LPCITEMIDLIST); +typedef HRESULT(APIENTRY *SHINVDEFCMD)(HWND, IShellFolder*, LPCITEMIDLIST); typedef void (APIENTRY *RUNFILEDLG)(HWND, HICON, LPCWSTR, LPCWSTR, LPCWSTR, UINT); typedef void (APIENTRY *EXITWINDLG)(HWND); -typedef HRESULT (APIENTRY *SHWINHELP)(HWND, LPWSTR, UINT, DWORD); +typedef HRESULT(APIENTRY *SHWINHELP)(HWND, LPWSTR, UINT, DWORD); /* Constants for RunFileDlg */ #define RFF_CALCDIRECTORY 0x04 /* Calculates the working directory from the file name. */ -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 ASSERT(cond) \ do if (!(cond)) { \ Win32DbgPrint(__FILE__, __LINE__, "ASSERTION %s FAILED!\n", #cond); \ - } while (0) - -#define DbgPrint(fmt, ...) \ - Win32DbgPrint(__FILE__, __LINE__, fmt, ##__VA_ARGS__) + } while (0) extern HINSTANCE hExplorerInstance; extern HMODULE hUser32; @@ -103,33 +73,33 @@ extern DRAWCAPTEMP DrawCapTemp; typedef struct _DROPTARGET_CALLBACKS { - HRESULT (*OnDragEnter)(IN IDropTarget *pDropTarget, - IN PVOID Context, - IN const FORMATETC *Format, - IN DWORD grfKeyState, - IN POINTL pt, - IN OUT DWORD *pdwEffect); - HRESULT (*OnDragOver)(IN IDropTarget *pDropTarget, + HRESULT(*OnDragEnter)(IN IDropTarget *pDropTarget, IN PVOID Context, + IN const FORMATETC *Format, IN DWORD grfKeyState, IN POINTL pt, IN OUT DWORD *pdwEffect); - HRESULT (*OnDragLeave)(IN IDropTarget *pDropTarget, - IN PVOID Context); - HRESULT (*OnDrop)(IN IDropTarget *pDropTarget, - IN PVOID Context, - IN const FORMATETC *Format, - IN DWORD grfKeyState, - IN POINTL pt, - IN OUT DWORD *pdwEffect); + HRESULT(*OnDragOver)(IN IDropTarget *pDropTarget, + IN PVOID Context, + IN DWORD grfKeyState, + IN POINTL pt, + IN OUT DWORD *pdwEffect); + HRESULT(*OnDragLeave)(IN IDropTarget *pDropTarget, + IN PVOID Context); + HRESULT(*OnDrop)(IN IDropTarget *pDropTarget, + IN PVOID Context, + IN const FORMATETC *Format, + IN DWORD grfKeyState, + IN POINTL pt, + IN OUT DWORD *pdwEffect); } DROPTARGET_CALLBACKS, *PDROPTARGET_CALLBACKS; IDropTarget * CreateDropTarget(IN HWND hwndTarget, - IN DWORD nSupportedFormats, - IN const FORMATETC *Formats OPTIONAL, - IN PVOID Context OPTIONAL, - IN const DROPTARGET_CALLBACKS *Callbacks OPTIONAL); +IN DWORD nSupportedFormats, +IN const FORMATETC *Formats OPTIONAL, +IN PVOID Context OPTIONAL, +IN const DROPTARGET_CALLBACKS *Callbacks OPTIONAL); /* * explorer.c @@ -139,46 +109,44 @@ CreateDropTarget(IN HWND hwndTarget, LONG SetWindowStyle(IN HWND hWnd, - IN LONG dwStyleMask, - IN LONG dwStyle); +IN LONG dwStyleMask, +IN LONG dwStyle); LONG SetWindowExStyle(IN HWND hWnd, - IN LONG dwStyleMask, - IN LONG dwStyle); +IN LONG dwStyleMask, +IN LONG dwStyle); HMENU LoadPopupMenu(IN HINSTANCE hInstance, - IN LPCTSTR lpMenuName); +IN LPCTSTR lpMenuName); HMENU FindSubMenu(IN HMENU hMenu, - IN UINT uItem, - IN BOOL fByPosition); +IN UINT uItem, +IN BOOL fByPosition); BOOL GetCurrentLoggedOnUserName(OUT LPTSTR szBuffer, - IN DWORD dwBufferSize); +IN DWORD dwBufferSize); BOOL FormatMenuString(IN HMENU hMenu, - IN UINT uPosition, - IN UINT uFlags, - ...); +IN UINT uPosition, +IN UINT uFlags, +...); BOOL GetExplorerRegValueSet(IN HKEY hKey, - IN LPCTSTR lpSubKey, - IN LPCTSTR lpValue); +IN LPCTSTR lpSubKey, +IN LPCTSTR lpValue); /* * rshell.c */ -HRESULT -CStartMenu_Constructor( - REFIID riid, - void **ppv); +HRESULT WINAPI +_CStartMenu_Constructor(REFIID riid, void **ppv); /* * traywnd.c @@ -186,13 +154,13 @@ CStartMenu_Constructor( #define TWM_OPENSTARTMENU (WM_USER + 260) -typedef HMENU (*PCREATECTXMENU)(IN HWND hWndOwner, - IN PVOID *ppcmContext, - IN PVOID Context OPTIONAL); -typedef VOID (*PCTXMENUCOMMAND)(IN HWND hWndOwner, - IN UINT uiCmdId, - IN PVOID pcmContext OPTIONAL, - IN PVOID Context OPTIONAL); +typedef HMENU(*PCREATECTXMENU)(IN HWND hWndOwner, + IN PVOID *ppcmContext, + IN PVOID Context OPTIONAL); +typedef VOID(*PCTXMENUCOMMAND)(IN HWND hWndOwner, + IN UINT uiCmdId, + IN PVOID pcmContext OPTIONAL, + IN PVOID Context OPTIONAL); typedef struct _TRAYWINDOW_CTXMENU { @@ -203,22 +171,22 @@ typedef struct _TRAYWINDOW_CTXMENU extern const GUID IID_IShellDesktopTray; #define INTERFACE ITrayWindow -DECLARE_INTERFACE_(ITrayWindow,IUnknown) +DECLARE_INTERFACE_(ITrayWindow, IUnknown) { /*** IUnknown methods ***/ - STDMETHOD_(HRESULT,QueryInterface) (THIS_ REFIID riid, void** ppvObject) PURE; - STDMETHOD_(ULONG,AddRef) (THIS) PURE; - STDMETHOD_(ULONG,Release) (THIS) PURE; + STDMETHOD_(HRESULT, QueryInterface) (THIS_ REFIID riid, void** ppvObject) PURE; + STDMETHOD_(ULONG, AddRef) (THIS) PURE; + STDMETHOD_(ULONG, Release) (THIS) PURE; /*** ITrayWindow methods ***/ - STDMETHOD_(HRESULT,Open) (THIS) PURE; - STDMETHOD_(HRESULT,Close) (THIS) PURE; - STDMETHOD_(HWND,GetHWND) (THIS) PURE; - STDMETHOD_(BOOL,IsSpecialHWND) (THIS_ HWND hWnd) PURE; - STDMETHOD_(BOOL,IsHorizontal) (THIS) PURE; - STDMETHOD_(HFONT,GetCaptionFonts) (THIS_ HFONT *phBoldCaption) PURE; - STDMETHOD_(HWND,DisplayProperties) (THIS) PURE; - STDMETHOD_(BOOL,ExecContextMenuCmd) (THIS_ UINT uiCmd) PURE; - STDMETHOD_(BOOL,Lock) (THIS_ BOOL bLock) PURE; + STDMETHOD_(HRESULT, Open) (THIS) PURE; + STDMETHOD_(HRESULT, Close) (THIS) PURE; + STDMETHOD_(HWND, GetHWND) (THIS) PURE; + STDMETHOD_(BOOL, IsSpecialHWND) (THIS_ HWND hWnd) PURE; + STDMETHOD_(BOOL, IsHorizontal) (THIS) PURE; + STDMETHOD_(HFONT, GetCaptionFonts) (THIS_ HFONT *phBoldCaption) PURE; + STDMETHOD_(HWND, DisplayProperties) (THIS) PURE; + STDMETHOD_(BOOL, ExecContextMenuCmd) (THIS_ UINT uiCmd) PURE; + STDMETHOD_(BOOL, Lock) (THIS_ BOOL bLock) PURE; }; #undef INTERFACE @@ -245,8 +213,7 @@ RegisterTrayWindowClass(VOID); VOID UnregisterTrayWindowClass(VOID); -ITrayWindow * -CreateTrayWindow(VOID); +HRESULT CreateTrayWindow(ITrayWindow ** ppTray); VOID TrayProcessMessages(IN OUT ITrayWindow *Tray); @@ -259,20 +226,21 @@ TrayMessageLoop(IN OUT ITrayWindow *Tray); */ /* Structure to hold non-default options*/ -typedef struct _ADVANCED_SETTINGS { +typedef struct _ADVANCED_SETTINGS +{ BOOL bShowSeconds; } ADVANCED_SETTINGS, *PADVANCED_SETTINGS; extern ADVANCED_SETTINGS AdvancedSettings; -extern const TCHAR szAdvancedSettingsKey[]; +extern const TCHAR szAdvancedSettingsKey []; VOID LoadAdvancedSettings(VOID); BOOL SaveSettingDword(IN PCTSTR pszKeyName, - IN PCTSTR pszValueName, - IN DWORD dwValue); +IN PCTSTR pszValueName, +IN DWORD dwValue); /* * startup.c @@ -305,14 +273,14 @@ DesktopDestroyShellWindow(IN HANDLE hDesktop); extern const GUID CLSID_ITaskBand; #define INTERFACE ITaskBand -DECLARE_INTERFACE_(ITaskBand,IUnknown) +DECLARE_INTERFACE_(ITaskBand, IUnknown) { /*** IUnknown methods ***/ - STDMETHOD_(HRESULT,QueryInterface) (THIS_ REFIID riid, void** ppvObject) PURE; - STDMETHOD_(ULONG,AddRef) (THIS) PURE; - STDMETHOD_(ULONG,Release) (THIS) PURE; + STDMETHOD_(HRESULT, QueryInterface) (THIS_ REFIID riid, void** ppvObject) PURE; + STDMETHOD_(ULONG, AddRef) (THIS) PURE; + STDMETHOD_(ULONG, Release) (THIS) PURE; /*** ITaskBand methods ***/ - STDMETHOD_(HRESULT,GetRebarBandID)(THIS_ DWORD *pdwBandID) PURE; + STDMETHOD_(HRESULT, GetRebarBandID)(THIS_ DWORD *pdwBandID) PURE; }; #undef INTERFACE @@ -333,20 +301,20 @@ CreateTaskBand(IN OUT ITrayWindow *Tray); */ #define INTERFACE ITrayBandSite -DECLARE_INTERFACE_(ITrayBandSite,IUnknown) +DECLARE_INTERFACE_(ITrayBandSite, IUnknown) { /*** IUnknown methods ***/ - STDMETHOD_(HRESULT,QueryInterface) (THIS_ REFIID riid, void** ppvObject) PURE; - STDMETHOD_(ULONG,AddRef) (THIS) PURE; - STDMETHOD_(ULONG,Release) (THIS) PURE; + STDMETHOD_(HRESULT, QueryInterface) (THIS_ REFIID riid, void** ppvObject) PURE; + STDMETHOD_(ULONG, AddRef) (THIS) PURE; + STDMETHOD_(ULONG, Release) (THIS) PURE; /*** IBandSiteStreamCallback ***/ - STDMETHOD_(HRESULT,OnLoad)(THIS_ IStream *pStm, REFIID riid, PVOID *pvObj) PURE; - STDMETHOD_(HRESULT,OnSave)(THIS_ IUnknown *pUnk, IStream *pStm) PURE; + STDMETHOD_(HRESULT, OnLoad)(THIS_ IStream *pStm, REFIID riid, PVOID *pvObj) PURE; + STDMETHOD_(HRESULT, OnSave)(THIS_ IUnknown *pUnk, IStream *pStm) PURE; /*** ITrayBandSite methods ***/ - STDMETHOD_(HRESULT,IsTaskBand) (THIS_ IUnknown *punk) PURE; - STDMETHOD_(HRESULT,ProcessMessage) (THIS_ HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *plResult) PURE; - STDMETHOD_(HRESULT,AddContextMenus) (THIS_ HMENU hmenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags, IContextMenu **ppcm) PURE; - STDMETHOD_(HRESULT,Lock) (THIS_ BOOL bLock) PURE; + STDMETHOD_(HRESULT, IsTaskBand) (THIS_ IUnknown *punk) PURE; + STDMETHOD_(HRESULT, ProcessMessage) (THIS_ HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *plResult) PURE; + STDMETHOD_(HRESULT, AddContextMenus) (THIS_ HMENU hmenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags, IContextMenu **ppcm) PURE; + STDMETHOD_(HRESULT, Lock) (THIS_ BOOL bLock) PURE; }; #undef INTERFACE @@ -367,8 +335,8 @@ DECLARE_INTERFACE_(ITrayBandSite,IUnknown) ITrayBandSite * CreateTrayBandSite(IN OUT ITrayWindow *Tray, - OUT HWND *phWndRebar, - OUT HWND *phWndTaskSwitch); +OUT HWND *phWndRebar, +OUT HWND *phWndTaskSwitch); /* * startmnu.c @@ -377,12 +345,12 @@ CreateTrayBandSite(IN OUT ITrayWindow *Tray, extern const TRAYWINDOW_CTXMENU StartMenuBtnCtxMenu; #define INTERFACE IStartMenuSite -DECLARE_INTERFACE_(IStartMenuSite,IUnknown) +DECLARE_INTERFACE_(IStartMenuSite, IUnknown) { /*** IUnknown methods ***/ - STDMETHOD_(HRESULT,QueryInterface) (THIS_ REFIID riid, void** ppvObject) PURE; - STDMETHOD_(ULONG,AddRef) (THIS) PURE; - STDMETHOD_(ULONG,Release) (THIS) PURE; + STDMETHOD_(HRESULT, QueryInterface) (THIS_ REFIID riid, void** ppvObject) PURE; + STDMETHOD_(ULONG, AddRef) (THIS) PURE; + STDMETHOD_(ULONG, Release) (THIS) PURE; /*** IStartMenuSite ***/ }; #undef INTERFACE @@ -397,14 +365,14 @@ DECLARE_INTERFACE_(IStartMenuSite,IUnknown) IMenuPopup* CreateStartMenu(IN ITrayWindow *Tray, - OUT IMenuBand **ppMenuBand, - IN HBITMAP hbmBanner OPTIONAL, - IN BOOL bSmallIcons); +OUT IMenuBand **ppMenuBand, +IN HBITMAP hbmBanner OPTIONAL, +IN BOOL bSmallIcons); HRESULT UpdateStartMenu(IN OUT IMenuPopup *pMenuPopup, - IN HBITMAP hbmBanner OPTIONAL, - IN BOOL bSmallIcons); +IN HBITMAP hbmBanner OPTIONAL, +IN BOOL bSmallIcons); /* * trayntfy.c @@ -431,16 +399,14 @@ UnregisterTrayNotifyWndClass(VOID); HWND CreateTrayNotifyWnd(IN OUT ITrayWindow *TrayWindow, - IN BOOL bHideClock); +IN BOOL bHideClock); VOID -TrayNotify_NotifyMsg(IN HWND hwnd, - IN WPARAM wParam, - IN LPARAM lParam); +TrayNotify_NotifyMsg(IN WPARAM wParam, +IN LPARAM lParam); BOOL -TrayNotify_GetClockRect(IN HWND hwnd, - OUT PRECT rcClock); +TrayNotify_GetClockRect(OUT PRECT rcClock); /* * taskswnd.c @@ -457,9 +423,12 @@ UnregisterTaskSwitchWndClass(VOID); HWND CreateTaskSwitchWnd(IN HWND hWndParent, - IN OUT ITrayWindow *Tray); +IN OUT ITrayWindow *Tray); HRESULT Tray_OnStartMenuDismissed(); +HRESULT +IsSameObject(IN IUnknown *punk1, IN IUnknown *punk2); + #endif /* _EXPLORER_PRECOMP__H_ */ diff --git a/base/shell/explorer-new/rshell.c b/base/shell/explorer-new/rshell.cpp similarity index 93% rename from base/shell/explorer-new/rshell.c rename to base/shell/explorer-new/rshell.cpp index 1ea863ab7ba..49e2352153c 100644 --- a/base/shell/explorer-new/rshell.c +++ b/base/shell/explorer-new/rshell.cpp @@ -24,7 +24,7 @@ static HINSTANCE hRShell = NULL; typedef HRESULT(WINAPI * PSTARTMENU_CONSTRUCTOR)(REFIID riid, void **ppv); -HRESULT CStartMenu_Constructor(REFIID riid, void **ppv) +HRESULT WINAPI _CStartMenu_Constructor(REFIID riid, void **ppv) { if (!hRShell) { @@ -40,7 +40,7 @@ HRESULT CStartMenu_Constructor(REFIID riid, void **ppv) } } - return CoCreateInstance(&CLSID_StartMenu, + return CoCreateInstance(CLSID_StartMenu, NULL, CLSCTX_INPROC_SERVER, riid, @@ -49,7 +49,7 @@ HRESULT CStartMenu_Constructor(REFIID riid, void **ppv) typedef HANDLE(WINAPI * PSHCREATEDESKTOP)(IShellDesktopTray *ShellDesk); -HANDLE WINAPI SHCreateDesktop(IShellDesktopTray *ShellDesk) +HANDLE WINAPI _SHCreateDesktop(IShellDesktopTray *ShellDesk) { HINSTANCE hFallback; @@ -83,7 +83,7 @@ HANDLE WINAPI SHCreateDesktop(IShellDesktopTray *ShellDesk) typedef BOOL(WINAPI *PSHDESKTOPMESSAGELOOP)(HANDLE hDesktop); -BOOL WINAPI SHDesktopMessageLoop(HANDLE hDesktop) +BOOL WINAPI _SHDesktopMessageLoop(HANDLE hDesktop) { HINSTANCE hFallback; @@ -117,7 +117,7 @@ BOOL WINAPI SHDesktopMessageLoop(HANDLE hDesktop) typedef DWORD(WINAPI* PWINLIST_INIT)(void); -DWORD WINAPI WinList_Init(void) +DWORD WINAPI _WinList_Init(void) { HINSTANCE hFallback; @@ -151,7 +151,7 @@ DWORD WINAPI WinList_Init(void) typedef void (WINAPI *PSHELLDDEINIT)(BOOL bInit); -void WINAPI ShellDDEInit(BOOL bInit) +void WINAPI _ShellDDEInit(BOOL bInit) { HINSTANCE hFallback; diff --git a/base/shell/explorer-new/settings.c b/base/shell/explorer-new/settings.cpp similarity index 96% rename from base/shell/explorer-new/settings.c rename to base/shell/explorer-new/settings.cpp index b982c9aec3f..149645717ae 100644 --- a/base/shell/explorer-new/settings.c +++ b/base/shell/explorer-new/settings.cpp @@ -21,8 +21,7 @@ #include "precomp.h" ADVANCED_SETTINGS AdvancedSettings; -const TCHAR szAdvancedSettingsKey[] = TEXT("Software\\ReactOS\\Features\\Explorer"); - +const WCHAR szAdvancedSettingsKey[] = TEXT("Software\\ReactOS\\Features\\Explorer"); VOID LoadAdvancedSettings(VOID) diff --git a/base/shell/explorer-new/shellservice.c b/base/shell/explorer-new/shellservice.cpp similarity index 82% rename from base/shell/explorer-new/shellservice.c rename to base/shell/explorer-new/shellservice.cpp index 02d3600a2f4..39a83cb91b0 100644 --- a/base/shell/explorer-new/shellservice.c +++ b/base/shell/explorer-new/shellservice.cpp @@ -25,26 +25,26 @@ extern HRESULT ShutdownShellServices(HDPA hdpa); static int CALLBACK InitializeAllCallback(void* pItem, void* pData) { - IOleCommandTarget * pOct = pItem; - HRESULT * phr = pData; + IOleCommandTarget * pOct = reinterpret_cast(pItem); + HRESULT * phr = reinterpret_cast(pData); TRACE("Initializing SSO %p\n", pOct); - *phr = IOleCommandTarget_Exec(pOct, &CGID_ShellServiceObject, OLECMDID_NEW, OLECMDEXECOPT_DODEFAULT, NULL, NULL); + *phr = pOct->Exec(&CGID_ShellServiceObject, OLECMDID_NEW, OLECMDEXECOPT_DODEFAULT, NULL, NULL); return SUCCEEDED(*phr); } static int CALLBACK ShutdownAllCallback(void* pItem, void* pData) { - IOleCommandTarget * pOct = pItem; + IOleCommandTarget * pOct = reinterpret_cast(pItem); TRACE("Shutting down SSO %p\n", pOct); - IOleCommandTarget_Exec(pOct, &CGID_ShellServiceObject, OLECMDID_SAVE, OLECMDEXECOPT_DODEFAULT, NULL, NULL); + pOct->Exec(&CGID_ShellServiceObject, OLECMDID_SAVE, OLECMDEXECOPT_DODEFAULT, NULL, NULL); return TRUE; } static int CALLBACK DeleteAllEnumCallback(void* pItem, void* pData) { - IOleCommandTarget * pOct = pItem; + IOleCommandTarget * pOct = reinterpret_cast(pItem); TRACE("Releasing SSO %p\n", pOct); - IUnknown_Release(pOct); + pOct->Release(); return TRUE; } @@ -92,14 +92,14 @@ HRESULT InitShellServices(HDPA * phdpa) } hr = CLSIDFromString(value, &clsid); - if (FAILED(hr)) + if (FAILED_UNEXPECTEDLY(hr)) { ERR("CLSIDFromString failed %08x.\n", hr); goto cleanup; } - hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IOleCommandTarget, (VOID**) &pOct); - if (FAILED(hr)) + hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IOleCommandTarget, &pOct)); + if (FAILED_UNEXPECTEDLY(hr)) { ERR("CoCreateInstance failed %08x.\n", hr); goto cleanup; @@ -122,7 +122,7 @@ HRESULT InitShellServices(HDPA * phdpa) /* Initialize */ DPA_EnumCallback(hdpa, InitializeAllCallback, &hr); - if (FAILED(hr)) + if (FAILED_UNEXPECTEDLY(hr)) goto cleanup; *phdpa = hdpa; diff --git a/base/shell/explorer-new/startmnu.c b/base/shell/explorer-new/startmnu.c deleted file mode 100644 index 36ffaef1a97..00000000000 --- a/base/shell/explorer-new/startmnu.c +++ /dev/null @@ -1,1063 +0,0 @@ -/* - * ReactOS Explorer - * - * Copyright 2006 - 2007 Thomas Weidenmueller - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "precomp.h" - -/* - * Start menu button context menu - */ - -typedef struct _STARTMNU_CTMENU_CTX -{ - IContextMenu *pcm; - LPITEMIDLIST pidl; -} STARTMNU_CTMENU_CTX, *PSTARTMNU_CTMENU_CTX; - -static HMENU -CreateStartContextMenu(IN HWND hWndOwner, - IN PVOID *ppcmContext, - IN PVOID Context OPTIONAL); - -static VOID -OnStartContextMenuCommand(IN HWND hWndOwner, - IN UINT uiCmdId, - IN PVOID pcmContext OPTIONAL, - IN PVOID Context OPTIONAL); - -const TRAYWINDOW_CTXMENU StartMenuBtnCtxMenu = { - CreateStartContextMenu, - OnStartContextMenuCommand -}; - -static HMENU -CreateContextMenuFromShellFolderPidl(IN HWND hWndOwner, - IN OUT IShellFolder *psf, - IN OUT LPITEMIDLIST pidl, - OUT IContextMenu **ppcm) -{ - IContextMenu *pcm; - HRESULT hRet; - HMENU hPopup; - - hRet = IShellFolder_GetUIObjectOf(psf, - hWndOwner, - 1, - (LPCITEMIDLIST *)&pidl, - &IID_IContextMenu, - NULL, - (PVOID *)&pcm); - if (SUCCEEDED(hRet)) - { - hPopup = CreatePopupMenu(); - - if (hPopup != NULL) - { - hRet = IContextMenu_QueryContextMenu(pcm, - hPopup, - 0, - ID_SHELL_CMD_FIRST, - ID_SHELL_CMD_LAST, - CMF_VERBSONLY); - - if (SUCCEEDED(hRet)) - { - *ppcm = pcm; - return hPopup; - } - - DestroyMenu(hPopup); - } - - IContextMenu_Release(pcm); - } - - return NULL; -} - -static VOID -OnStartContextMenuCommand(IN HWND hWndOwner, - IN UINT uiCmdId, - IN PVOID pcmContext OPTIONAL, - IN PVOID Context OPTIONAL) -{ - PSTARTMNU_CTMENU_CTX psmcmc = pcmContext; - - if (uiCmdId != 0) - { - if ((uiCmdId >= ID_SHELL_CMD_FIRST) && (uiCmdId <= ID_SHELL_CMD_LAST)) - { - CMINVOKECOMMANDINFO cmici = {0}; - CHAR szDir[MAX_PATH]; - - /* Setup and invoke the shell command */ - cmici.cbSize = sizeof(cmici); - cmici.hwnd = hWndOwner; - cmici.lpVerb = (LPCSTR)MAKEINTRESOURCE(uiCmdId - ID_SHELL_CMD_FIRST); - cmici.nShow = SW_NORMAL; - - /* FIXME: Support Unicode!!! */ - if (SHGetPathFromIDListA(psmcmc->pidl, - szDir)) - { - cmici.lpDirectory = szDir; - } - - IContextMenu_InvokeCommand(psmcmc->pcm, - &cmici); - } - else - { - ITrayWindow_ExecContextMenuCmd((ITrayWindow *)Context, - uiCmdId); - } - } - - IContextMenu_Release(psmcmc->pcm); - - HeapFree(hProcessHeap, - 0, - psmcmc); -} - -static VOID -AddStartContextMenuItems(IN HWND hWndOwner, - IN HMENU hPopup) -{ - TCHAR szBuf[MAX_PATH]; - HRESULT hRet; - - /* Add the "Open All Users" menu item */ - if (LoadString(hExplorerInstance, - IDS_PROPERTIES, - szBuf, - sizeof(szBuf) / sizeof(szBuf[0]))) - { - AppendMenu(hPopup, - MF_STRING, - ID_SHELL_CMD_PROPERTIES, - szBuf); - } - - if (!SHRestricted(REST_NOCOMMONGROUPS)) - { - /* Check if we should add menu items for the common start menu */ - hRet = SHGetFolderPath(hWndOwner, - CSIDL_COMMON_STARTMENU, - NULL, - SHGFP_TYPE_CURRENT, - szBuf); - if (SUCCEEDED(hRet) && hRet != S_FALSE) - { - /* The directory exists, but only show the items if the - user can actually make any changes to the common start - menu. This is most likely only the case if the user - has administrative rights! */ - if (IsUserAnAdmin()) - { - AppendMenu(hPopup, - MF_SEPARATOR, - 0, - NULL); - - /* Add the "Open All Users" menu item */ - if (LoadString(hExplorerInstance, - IDS_OPEN_ALL_USERS, - szBuf, - sizeof(szBuf) / sizeof(szBuf[0]))) - { - AppendMenu(hPopup, - MF_STRING, - ID_SHELL_CMD_OPEN_ALL_USERS, - szBuf); - } - - /* Add the "Explore All Users" menu item */ - if (LoadString(hExplorerInstance, - IDS_EXPLORE_ALL_USERS, - szBuf, - sizeof(szBuf) / sizeof(szBuf[0]))) - { - AppendMenu(hPopup, - MF_STRING, - ID_SHELL_CMD_EXPLORE_ALL_USERS, - szBuf); - } - } - } - } -} - -static HMENU -CreateStartContextMenu(IN HWND hWndOwner, - IN PVOID *ppcmContext, - IN PVOID Context OPTIONAL) -{ - LPITEMIDLIST pidlStart, pidlLast; - IShellFolder *psfStart, *psfDesktop; - IContextMenu *pcm; - HRESULT hRet; - HMENU hPopup; - - pidlStart = SHCloneSpecialIDList(hWndOwner, - CSIDL_STARTMENU, - TRUE); - - if (pidlStart != NULL) - { - pidlLast = ILClone(ILFindLastID(pidlStart)); - ILRemoveLastID(pidlStart); - - if (pidlLast != NULL) - { - hRet = SHGetDesktopFolder(&psfDesktop); - if (SUCCEEDED(hRet)) - { - hRet = IShellFolder_BindToObject(psfDesktop, - pidlStart, - NULL, - &IID_IShellFolder, - (PVOID*)&psfStart); - if (SUCCEEDED(hRet)) - { - hPopup = CreateContextMenuFromShellFolderPidl(hWndOwner, - psfStart, - pidlLast, - &pcm); - - if (hPopup != NULL) - { - PSTARTMNU_CTMENU_CTX psmcmc; - - psmcmc = HeapAlloc(hProcessHeap, - 0, - sizeof(*psmcmc)); - if (psmcmc != NULL) - { - psmcmc->pcm = pcm; - psmcmc->pidl = pidlLast; - - AddStartContextMenuItems(hWndOwner, - hPopup); - - *ppcmContext = psmcmc; - return hPopup; - } - else - { - IContextMenu_Release(pcm); - - DestroyMenu(hPopup); - hPopup = NULL; - } - } - - IShellFolder_Release(psfStart); - } - - IShellFolder_Release(psfDesktop); - } - - ILFree(pidlLast); - } - - ILFree(pidlStart); - } - - return NULL; -} - -/***************************************************************************** - ** IStartMenuSite *********************************************************** - *****************************************************************************/ - -static const IStartMenuSiteVtbl IStartMenuSiteImpl_Vtbl; -static const IServiceProviderVtbl IServiceProviderImpl_Vtbl; -static const ITrayPrivVtbl ITrayPrivImpl_Vtbl; -static const IOleCommandTargetVtbl IOleCommandTargetImpl_Vtbl; -static const IMenuPopupVtbl IMenuPopupImpl_Vtbl; - -typedef struct -{ - const IStartMenuSiteVtbl *lpVtbl; - const IServiceProviderVtbl *lpServiceProviderVtbl; - const ITrayPrivVtbl *lpStartMenuCallbackVtbl; - const IOleCommandTargetVtbl *lpOleCommandTargetVtbl; - const IMenuPopupVtbl *lpMenuPopupVtbl; - LONG Ref; - - ITrayWindow *Tray; - - IMenuPopup * StartMenuPopup; -} IStartMenuSiteImpl; - -static IUnknown * -IUnknown_from_IStartMenuSiteImpl(IStartMenuSiteImpl *This) -{ - return (IUnknown *)&This->lpVtbl; -} - -IMPL_CASTS(IStartMenuSite, IStartMenuSite, lpVtbl) -IMPL_CASTS(IServiceProvider, IStartMenuSite, lpServiceProviderVtbl) -IMPL_CASTS(ITrayPriv, IStartMenuSite, lpStartMenuCallbackVtbl) -IMPL_CASTS(IOleCommandTarget, IStartMenuSite, lpOleCommandTargetVtbl) -IMPL_CASTS(IDeskBar, IStartMenuSite, lpMenuPopupVtbl) -IMPL_CASTS(IMenuPopup, IStartMenuSite, lpMenuPopupVtbl) - -/*******************************************************************/ - -static ULONG STDMETHODCALLTYPE -IStartMenuSiteImpl_AddRef(IN OUT IStartMenuSite *iface) -{ - IStartMenuSiteImpl *This = IStartMenuSiteImpl_from_IStartMenuSite(iface); - - return InterlockedIncrement(&This->Ref); -} - -static VOID -IStartMenuSiteImpl_Free(IN OUT IStartMenuSiteImpl *This) -{ - HeapFree(hProcessHeap, - 0, - This); -} - -static ULONG STDMETHODCALLTYPE -IStartMenuSiteImpl_Release(IN OUT IStartMenuSite *iface) -{ - IStartMenuSiteImpl *This = IStartMenuSiteImpl_from_IStartMenuSite(iface); - ULONG Ret; - - Ret = InterlockedDecrement(&This->Ref); - - if (Ret == 0) - IStartMenuSiteImpl_Free(This); - - return Ret; -} - -static HRESULT STDMETHODCALLTYPE -IStartMenuSiteImpl_QueryInterface(IN OUT IStartMenuSite *iface, - IN REFIID riid, - OUT LPVOID *ppvObj) -{ - IStartMenuSiteImpl *This; - - if (ppvObj == NULL) - return E_POINTER; - - This = IStartMenuSiteImpl_from_IStartMenuSite(iface); - - if (IsEqualIID(riid, - &IID_IUnknown)) - { - *ppvObj = IUnknown_from_IStartMenuSiteImpl(This); - } - else if (IsEqualIID(riid, - &IID_IServiceProvider)) - { - *ppvObj = IServiceProvider_from_IStartMenuSiteImpl(This); - } - else if (IsEqualIID(riid, - &IID_ITrayPriv) || - IsEqualIID(riid, - &IID_IOleWindow)) - { - *ppvObj = ITrayPriv_from_IStartMenuSiteImpl(This); - } - else if (IsEqualIID(riid, - &IID_IOleCommandTarget)) - { - *ppvObj = IOleCommandTarget_from_IStartMenuSiteImpl(This); - } - else if (IsEqualIID(riid, - &IID_IDeskBar)) - { - *ppvObj = IDeskBar_from_IStartMenuSiteImpl(This); - } - else if (IsEqualIID(riid, - &IID_IMenuPopup)) - { - *ppvObj = IMenuPopup_from_IStartMenuSiteImpl(This); - } - else - { - TRACE("IStartMenuSite::QueryInterface queried unsupported interface: " - "{0x%8x,0x%4x,0x%4x,{0x%2x,0x%2x,0x%2x,0x%2x,0x%2x,0x%2x,0x%2x,0x%2x}}\n", - riid->Data1, riid->Data2, riid->Data3, riid->Data4[0], riid->Data4[1], - riid->Data4[2], riid->Data4[3], riid->Data4[4], riid->Data4[5], - riid->Data4[6], riid->Data4[7]); - *ppvObj = NULL; - return E_NOINTERFACE; - } - - IStartMenuSiteImpl_AddRef(iface); - return S_OK; -} - -static const IStartMenuSiteVtbl IStartMenuSiteImpl_Vtbl = -{ - /*** IUnknown methods ***/ - IStartMenuSiteImpl_QueryInterface, - IStartMenuSiteImpl_AddRef, - IStartMenuSiteImpl_Release, - /*** IStartMenuSite methods ***/ -}; - -/*******************************************************************/ - -METHOD_IUNKNOWN_INHERITED_ADDREF(IServiceProvider, IStartMenuSite) -METHOD_IUNKNOWN_INHERITED_RELEASE(IServiceProvider, IStartMenuSite) -METHOD_IUNKNOWN_INHERITED_QUERYINTERFACE(IServiceProvider, IStartMenuSite) - -static HRESULT STDMETHODCALLTYPE -IStartMenuSiteImpl_QueryService(IN OUT IServiceProvider *iface, - IN REFGUID guidService, - IN REFIID riid, - OUT PVOID *ppvObject) -{ - IStartMenuSiteImpl *This = IStartMenuSiteImpl_from_IServiceProvider(iface); - - if (IsEqualGUID(guidService, - &SID_SMenuPopup)) - { - return IStartMenuSiteImpl_QueryInterface(IStartMenuSite_from_IStartMenuSiteImpl(This), - riid, - ppvObject); - } - - return E_NOINTERFACE; -} - -static const IServiceProviderVtbl IServiceProviderImpl_Vtbl = -{ - /*** IUnknown methods ***/ - METHOD_IUNKNOWN_INHERITED_QUERYINTERFACE_NAME(IServiceProvider, IStartMenuSite), - METHOD_IUNKNOWN_INHERITED_ADDREF_NAME(IServiceProvider, IStartMenuSite), - METHOD_IUNKNOWN_INHERITED_RELEASE_NAME(IServiceProvider, IStartMenuSite), - /*** IServiceProvider methods ***/ - IStartMenuSiteImpl_QueryService -}; - -/*******************************************************************/ - -METHOD_IUNKNOWN_INHERITED_ADDREF(ITrayPriv, IStartMenuSite) -METHOD_IUNKNOWN_INHERITED_RELEASE(ITrayPriv, IStartMenuSite) -METHOD_IUNKNOWN_INHERITED_QUERYINTERFACE(ITrayPriv, IStartMenuSite) - -static HRESULT STDMETHODCALLTYPE -IStartMenuSiteImpl_GetWindow(IN OUT ITrayPriv *iface, - OUT HWND *phwnd) -{ - IStartMenuSiteImpl *This = IStartMenuSiteImpl_from_ITrayPriv(iface); - TRACE("ITrayPriv::GetWindow\n"); - - *phwnd = ITrayWindow_GetHWND(This->Tray); - if (*phwnd != NULL) - return S_OK; - - return E_FAIL; -} - -static HRESULT STDMETHODCALLTYPE -IStartMenuSiteImpl_ContextSensitiveHelp(IN OUT ITrayPriv *iface, - IN BOOL fEnterMode) -{ - TRACE("ITrayPriv::ContextSensitiveHelp\n"); - return E_NOTIMPL; -} - -static HRESULT STDMETHODCALLTYPE -IStartMenuSiteImpl_Execute(IN OUT ITrayPriv *iface, - IN IShellFolder *pShellFolder, - IN LPCITEMIDLIST pidl) -{ - HMODULE hShlwapi; - HRESULT ret = S_FALSE; - - IStartMenuSiteImpl *This = IStartMenuSiteImpl_from_ITrayPriv(iface); - - TRACE("ITrayPriv::Execute\n"); - - hShlwapi = GetModuleHandle(TEXT("SHLWAPI.DLL")); - if (hShlwapi != NULL) - { - SHINVDEFCMD SHInvokeDefCmd; - - /* SHInvokeDefaultCommand */ - SHInvokeDefCmd = (SHINVDEFCMD)GetProcAddress(hShlwapi, - (LPCSTR)((LONG)279)); - if (SHInvokeDefCmd != NULL) - { - ret = SHInvokeDefCmd(ITrayWindow_GetHWND(This->Tray), - pShellFolder, - pidl); - } - } - - return ret; -} - -static HRESULT STDMETHODCALLTYPE -IStartMenuSiteImpl_Unknown(IN OUT ITrayPriv *iface, - IN PVOID Unknown1, - IN PVOID Unknown2, - IN PVOID Unknown3, - IN PVOID Unknown4) -{ - TRACE("ITrayPriv::Unknown(0x%p,0x%p,0x%p,0x%p)\n", Unknown1, Unknown2, Unknown3, Unknown4); - return E_NOTIMPL; -} - -static BOOL -ShowUndockMenuItem(VOID) -{ - TRACE("ShowUndockMenuItem() not implemented!\n"); - /* FIXME: How do we detect this?! */ - return FALSE; -} - -static BOOL -ShowSynchronizeMenuItem(VOID) -{ - TRACE("ShowSynchronizeMenuItem() not implemented!\n"); - /* FIXME: How do we detect this?! */ - return FALSE; -} - -static HRESULT STDMETHODCALLTYPE -IStartMenuSiteImpl_AppendMenu(IN OUT ITrayPriv *iface, - OUT HMENU* phMenu) -{ - HMENU hMenu, hSettingsMenu; - DWORD dwLogoff; - BOOL bWantLogoff; - UINT uLastItemsCount = 5; /* 5 menu items below the last separator */ - TCHAR szUser[128]; - - TRACE("ITrayPriv::AppendMenu\n"); - - hMenu = LoadPopupMenu(hExplorerInstance, - MAKEINTRESOURCE(IDM_STARTMENU)); - *phMenu = hMenu; - if (hMenu == NULL) - return E_FAIL; - - /* Remove menu items that don't apply */ - - dwLogoff = SHRestricted(REST_STARTMENULOGOFF); - bWantLogoff = (dwLogoff == 2 || - SHRestricted(REST_FORCESTARTMENULOGOFF) || - GetExplorerRegValueSet(HKEY_CURRENT_USER, - TEXT("Advanced"), - TEXT("StartMenuLogoff"))); - - /* Favorites */ - if (!GetExplorerRegValueSet(HKEY_CURRENT_USER, - TEXT("Advanced"), - TEXT("StartMenuFavorites"))) - { - DeleteMenu(hMenu, - IDM_FAVORITES, - MF_BYCOMMAND); - } - - /* Documents */ - if (SHRestricted(REST_NORECENTDOCSMENU)) - { - DeleteMenu(hMenu, - IDM_DOCUMENTS, - MF_BYCOMMAND); - } - - /* Settings */ - hSettingsMenu = FindSubMenu(hMenu, - IDM_SETTINGS, - FALSE); - if (hSettingsMenu != NULL) - { - if (SHRestricted(REST_NOSETFOLDERS)) - { - /* Control Panel */ - if (SHRestricted(REST_NOCONTROLPANEL)) - { - DeleteMenu(hSettingsMenu, - IDM_CONTROLPANEL, - MF_BYCOMMAND); - - /* Delete the separator below it */ - DeleteMenu(hSettingsMenu, - 0, - MF_BYPOSITION); - } - - /* Network Connections */ - if (SHRestricted(REST_NONETWORKCONNECTIONS)) - { - DeleteMenu(hSettingsMenu, - IDM_NETWORKCONNECTIONS, - MF_BYCOMMAND); - } - - /* Printers and Faxes */ - DeleteMenu(hSettingsMenu, - IDM_PRINTERSANDFAXES, - MF_BYCOMMAND); - } - - /* Security */ - if (GetSystemMetrics(SM_REMOTECONTROL) == 0 || - SHRestricted(REST_NOSECURITY)) - { - DeleteMenu(hSettingsMenu, - IDM_SECURITY, - MF_BYCOMMAND); - } - - if (GetMenuItemCount(hSettingsMenu) == 0) - { - DeleteMenu(hMenu, - IDM_SETTINGS, - MF_BYCOMMAND); - } - } - - /* Search */ - /* FIXME: Enable after implementing */ - /* if (SHRestricted(REST_NOFIND)) */ - { - DeleteMenu(hMenu, - IDM_SEARCH, - MF_BYCOMMAND); - } - - /* FIXME: Help */ - - /* Run */ - if (SHRestricted(REST_NORUN)) - { - DeleteMenu(hMenu, - IDM_RUN, - MF_BYCOMMAND); - } - - /* Synchronize */ - if (!ShowSynchronizeMenuItem()) - { - DeleteMenu(hMenu, - IDM_SYNCHRONIZE, - MF_BYCOMMAND); - uLastItemsCount--; - } - - /* Log off */ - if (dwLogoff != 1 && bWantLogoff) - { - /* FIXME: We need a more sophisticated way to determine whether to show - or hide it, it might be hidden in too many cases!!! */ - - /* Update Log Off menu item */ - if (!GetCurrentLoggedOnUserName(szUser, - sizeof(szUser) / sizeof(szUser[0]))) - { - szUser[0] = _T('\0'); - } - - if (!FormatMenuString(hMenu, - IDM_LOGOFF, - MF_BYCOMMAND, - szUser)) - { - /* We couldn't update the menu item, delete it... */ - DeleteMenu(hMenu, - IDM_LOGOFF, - MF_BYCOMMAND); - } - } - else - { - DeleteMenu(hMenu, - IDM_LOGOFF, - MF_BYCOMMAND); - uLastItemsCount--; - } - - - /* Disconnect */ - if (GetSystemMetrics(SM_REMOTECONTROL) == 0) - { - DeleteMenu(hMenu, - IDM_DISCONNECT, - MF_BYCOMMAND); - uLastItemsCount--; - } - - /* Undock computer */ - if (!ShowUndockMenuItem()) - { - DeleteMenu(hMenu, - IDM_UNDOCKCOMPUTER, - MF_BYCOMMAND); - uLastItemsCount--; - } - - /* Shut down */ - if (SHRestricted(REST_NOCLOSE)) - { - DeleteMenu(hMenu, - IDM_SHUTDOWN, - MF_BYCOMMAND); - uLastItemsCount--; - } - - if (uLastItemsCount == 0) - { - /* Remove the separator at the end of the menu */ - DeleteMenu(hMenu, - IDM_LASTSTARTMENU_SEPARATOR, - MF_BYCOMMAND); - } - - return S_OK; -} - -static const ITrayPrivVtbl ITrayPrivImpl_Vtbl = -{ - /*** IUnknown methods ***/ - METHOD_IUNKNOWN_INHERITED_QUERYINTERFACE_NAME(ITrayPriv, IStartMenuSite), - METHOD_IUNKNOWN_INHERITED_ADDREF_NAME(ITrayPriv, IStartMenuSite), - METHOD_IUNKNOWN_INHERITED_RELEASE_NAME(ITrayPriv, IStartMenuSite), - /*** IOleWindow methods ***/ - IStartMenuSiteImpl_GetWindow, - IStartMenuSiteImpl_ContextSensitiveHelp, - /*** ITrayPriv methods ***/ - IStartMenuSiteImpl_Execute, - IStartMenuSiteImpl_Unknown, - IStartMenuSiteImpl_AppendMenu -}; - -/*******************************************************************/ - -METHOD_IUNKNOWN_INHERITED_ADDREF(IOleCommandTarget, IStartMenuSite) -METHOD_IUNKNOWN_INHERITED_RELEASE(IOleCommandTarget, IStartMenuSite) -METHOD_IUNKNOWN_INHERITED_QUERYINTERFACE(IOleCommandTarget, IStartMenuSite) - -static HRESULT STDMETHODCALLTYPE -IStartMenuSiteImpl_QueryStatus(IN OUT IOleCommandTarget *iface, - IN const GUID *pguidCmdGroup OPTIONAL, - IN ULONG cCmds, - IN OUT OLECMD *prgCmds, - IN OUT OLECMDTEXT *pCmdText OPTIONAL) -{ - return E_NOTIMPL; -} - -static HRESULT STDMETHODCALLTYPE -IStartMenuSiteImpl_Exec(IN OUT IOleCommandTarget *iface, - IN const GUID *pguidCmdGroup OPTIONAL, - IN DWORD nCmdID, - IN DWORD nCmdExecOpt, - IN VARIANTARG *pvaIn OPTIONAL, - IN VARIANTARG *pvaOut OPTIONAL) -{ - return E_NOTIMPL; -} - -static const IOleCommandTargetVtbl IOleCommandTargetImpl_Vtbl = -{ - /*** IUnknown methods ***/ - METHOD_IUNKNOWN_INHERITED_QUERYINTERFACE_NAME(IOleCommandTarget, IStartMenuSite), - METHOD_IUNKNOWN_INHERITED_ADDREF_NAME(IOleCommandTarget, IStartMenuSite), - METHOD_IUNKNOWN_INHERITED_RELEASE_NAME(IOleCommandTarget, IStartMenuSite), - /*** IOleCommandTarget ***/ - IStartMenuSiteImpl_QueryStatus, - IStartMenuSiteImpl_Exec -}; - -/*******************************************************************/ - -METHOD_IUNKNOWN_INHERITED_ADDREF(IMenuPopup, IStartMenuSite) -METHOD_IUNKNOWN_INHERITED_RELEASE(IMenuPopup, IStartMenuSite) -METHOD_IUNKNOWN_INHERITED_QUERYINTERFACE(IMenuPopup, IStartMenuSite) - -static HRESULT STDMETHODCALLTYPE -IStartMenuSiteImpl_IMenuPopup_GetWindow(IN OUT IMenuPopup *iface, OUT HWND *phwnd) -{ - IStartMenuSiteImpl * This = IStartMenuSiteImpl_from_IMenuPopup(iface); - ITrayPriv * tp = ITrayPriv_from_IStartMenuSiteImpl(This); - return IStartMenuSiteImpl_GetWindow(tp, phwnd); -} - -static HRESULT STDMETHODCALLTYPE -IStartMenuSiteImpl_IMenuPopup_ContextSensitiveHelp(IN OUT IMenuPopup *iface, IN BOOL fEnterMode) -{ - IStartMenuSiteImpl * This = IStartMenuSiteImpl_from_IMenuPopup(iface); - ITrayPriv * tp = ITrayPriv_from_IStartMenuSiteImpl(This); - return IStartMenuSiteImpl_ContextSensitiveHelp(tp, fEnterMode); -} - -static HRESULT STDMETHODCALLTYPE -IStartMenuSiteImpl_SetClient(IN OUT IMenuPopup *iface, IUnknown *punkClient) -{ - return E_NOTIMPL; -} - -static HRESULT STDMETHODCALLTYPE -IStartMenuSiteImpl_GetClient(IN OUT IMenuPopup *iface, IUnknown ** ppunkClient) -{ - return E_NOTIMPL; -} - -static HRESULT STDMETHODCALLTYPE -IStartMenuSiteImpl_OnPosRectChangeDB(IN OUT IMenuPopup *iface, RECT *prc) -{ - return E_NOTIMPL; -} - -static HRESULT STDMETHODCALLTYPE -IStartMenuSiteImpl_Popup(IN OUT IMenuPopup *iface, POINTL *ppt, RECTL *prcExclude, MP_POPUPFLAGS dwFlags) -{ - return E_NOTIMPL; -} - -static HRESULT STDMETHODCALLTYPE -IStartMenuSiteImpl_OnSelect(IN OUT IMenuPopup *iface, DWORD dwSelectType) -{ - return E_NOTIMPL; -} - -static HRESULT STDMETHODCALLTYPE -IStartMenuSiteImpl_SetSubMenu(IN OUT IMenuPopup *iface, IMenuPopup *pmp, BOOL fSet) -{ - if (!fSet) - { - return Tray_OnStartMenuDismissed(); - } - - return S_OK; -} - -static const IMenuPopupVtbl IMenuPopupImpl_Vtbl = -{ - /*** IUnknown methods ***/ - METHOD_IUNKNOWN_INHERITED_QUERYINTERFACE_NAME(IMenuPopup, IStartMenuSite), - METHOD_IUNKNOWN_INHERITED_ADDREF_NAME(IMenuPopup, IStartMenuSite), - METHOD_IUNKNOWN_INHERITED_RELEASE_NAME(IMenuPopup, IStartMenuSite), - /*** IOleWindow methods ***/ - IStartMenuSiteImpl_IMenuPopup_GetWindow, - IStartMenuSiteImpl_IMenuPopup_ContextSensitiveHelp, - /*** IDeskBar methods ***/ - IStartMenuSiteImpl_SetClient, - IStartMenuSiteImpl_GetClient, - IStartMenuSiteImpl_OnPosRectChangeDB, - /*** IMenuPopup ***/ - IStartMenuSiteImpl_Popup, - IStartMenuSiteImpl_OnSelect, - IStartMenuSiteImpl_SetSubMenu -}; - - -/*******************************************************************/ - -static IStartMenuSiteImpl* -IStartMenuSiteImpl_Construct(IN ITrayWindow *Tray) -{ - IStartMenuSiteImpl *This; - - This = HeapAlloc(hProcessHeap, - HEAP_ZERO_MEMORY, - sizeof(*This)); - if (This == NULL) - return NULL; - - This->lpVtbl = &IStartMenuSiteImpl_Vtbl; - This->lpServiceProviderVtbl = &IServiceProviderImpl_Vtbl; - This->lpStartMenuCallbackVtbl = &ITrayPrivImpl_Vtbl; - This->lpOleCommandTargetVtbl = &IOleCommandTargetImpl_Vtbl; - This->lpMenuPopupVtbl = &IMenuPopupImpl_Vtbl; - This->Ref = 1; - - This->Tray = Tray; - - return This; -} - -static IStartMenuSite* -CreateStartMenuSite(IN ITrayWindow *Tray) -{ - IStartMenuSiteImpl *This; - - This = IStartMenuSiteImpl_Construct(Tray); - if (This != NULL) - { - return IStartMenuSite_from_IStartMenuSiteImpl(This); - } - - return NULL; -} - -HRESULT -UpdateStartMenu(IN OUT IMenuPopup *pMenuPopup, - IN HBITMAP hbmBanner OPTIONAL, - IN BOOL bSmallIcons) -{ - IBanneredBar *pbb; - HRESULT hRet; - - hRet = IMenuPopup_QueryInterface(pMenuPopup, - &IID_IBanneredBar, - (PVOID *)&pbb); - if (SUCCEEDED(hRet)) - { - hRet = IBanneredBar_SetBitmap(pbb, hbmBanner); - - /* Update the icon size */ - hRet = IBanneredBar_SetIconSize(pbb, - bSmallIcons ? BMICON_SMALL : BMICON_LARGE); - - IBanneredBar_Release(pbb); - } - - return hRet; -} - -IMenuPopup * -CreateStartMenu(IN ITrayWindow *Tray, - OUT IMenuBand **ppMenuBand, - IN HBITMAP hbmBanner OPTIONAL, - IN BOOL bSmallIcons) -{ - HRESULT hr; - IObjectWithSite *pOws = NULL; - IMenuPopup *pMp = NULL; - IStartMenuSite *pSms = NULL; - IMenuBand *pMb = NULL; - IInitializeObject *pIo; - IUnknown *pUnk = NULL; - IBandSite *pBs = NULL; - DWORD dwBandId = 0; - - pSms = CreateStartMenuSite(Tray); - if (pSms == NULL) - return NULL; - -#if 0 - hr = CoCreateInstance(&CLSID_StartMenu, - NULL, - CLSCTX_INPROC_SERVER, - &IID_IMenuPopup, - (PVOID *)&pMp); -#else - hr = CStartMenu_Constructor(&IID_IMenuPopup,(PVOID *)&pMp); -#endif - if (FAILED(hr)) - { - TRACE("CoCreateInstance failed: %x\n", hr); - goto cleanup; - } - - hr = IMenuPopup_QueryInterface(pMp, - &IID_IObjectWithSite, - (PVOID *)&pOws); - if (FAILED(hr)) - { - TRACE("IMenuPopup_QueryInterface failed: %x\n", hr); - goto cleanup; - } - - /* Set the menu site so we can handle messages */ - hr = IObjectWithSite_SetSite(pOws, (IUnknown *)pSms); - if (FAILED(hr)) - { - TRACE("IObjectWithSite_SetSite failed: %x\n", hr); - goto cleanup; - } - - /* Initialize the menu object */ - hr = IMenuPopup_QueryInterface(pMp, &IID_IInitializeObject, (PVOID*)&pIo); - if (SUCCEEDED(hr)) - { - hr = IInitializeObject_Initialize(pIo); - IInitializeObject_Release(pIo); - } - else - hr = S_OK; - - /* Everything is initialized now. Let's get the IMenuBand interface. */ - if (FAILED(hr)) - { - TRACE("IMenuPopup_QueryInterface failed: %x\n", hr); - goto cleanup; - } - - hr = IMenuPopup_GetClient(pMp, &pUnk); - if (FAILED(hr)) - { - TRACE("IMenuPopup_GetClient failed: %x\n", hr); - goto cleanup; - } - - hr = IUnknown_QueryInterface(pUnk, &IID_IBandSite, (PVOID *)&pBs); - if (FAILED(hr)) - { - TRACE("IUnknown_QueryInterface pBs failed: %x\n", hr); - goto cleanup; - } - - /* Finally we have the IBandSite interface, there's only one - band in it that apparently provides the IMenuBand interface */ - hr = IBandSite_EnumBands(pBs, 0, &dwBandId); - if (FAILED(hr)) - { - TRACE("IBandSite_EnumBands failed: %x\n", hr); - goto cleanup; - } - - hr = IBandSite_GetBandObject(pBs, dwBandId, &IID_IMenuBand, (PVOID *)&pMb); - if (FAILED(hr)) - { - TRACE("IBandSite_GetBandObject failed: %x\n", hr); - goto cleanup; - } - - UpdateStartMenu(pMp, - hbmBanner, - bSmallIcons); - -cleanup: - if (SUCCEEDED(hr)) - *ppMenuBand = pMb; - else if (pMb != NULL) - IMenuBand_Release(pMb); - - if (pBs != NULL) - IBandSite_Release(pBs); - if (pUnk != NULL) - IUnknown_Release(pUnk); - if (pOws != NULL) - IObjectWithSite_Release(pOws); - if (pMp != NULL) - IMenuPopup_Release(pMp); - if (pSms != NULL) - IStartMenuSite_Release(pSms); - - if (FAILED(hr)) - return NULL; - return pMp; -} diff --git a/base/shell/explorer-new/startmnu.cpp b/base/shell/explorer-new/startmnu.cpp new file mode 100644 index 00000000000..950a3309ffb --- /dev/null +++ b/base/shell/explorer-new/startmnu.cpp @@ -0,0 +1,796 @@ +/* + * ReactOS Explorer + * + * Copyright 2006 - 2007 Thomas Weidenmueller + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "precomp.h" + +/* + * Start menu button context menu + */ + +typedef struct _STARTMNU_CTMENU_CTX +{ + IContextMenu *pcm; + LPITEMIDLIST pidl; +} STARTMNU_CTMENU_CTX, *PSTARTMNU_CTMENU_CTX; + +static HMENU +CreateStartContextMenu(IN HWND hWndOwner, + IN PVOID *ppcmContext, + IN PVOID Context OPTIONAL); + +static VOID +OnStartContextMenuCommand(IN HWND hWndOwner, + IN UINT uiCmdId, + IN PVOID pcmContext OPTIONAL, + IN PVOID Context OPTIONAL); + +const TRAYWINDOW_CTXMENU StartMenuBtnCtxMenu = { + CreateStartContextMenu, + OnStartContextMenuCommand +}; + +static HMENU +CreateContextMenuFromShellFolderPidl(IN HWND hWndOwner, + IN OUT IShellFolder *psf, + IN OUT LPITEMIDLIST pidl, + OUT IContextMenu **ppcm) +{ + CComPtr pcm; + HRESULT hRet; + HMENU hPopup; + + hRet = psf->GetUIObjectOf(hWndOwner, 1, (LPCITEMIDLIST *)&pidl, IID_NULL_PPV_ARG(IContextMenu, &pcm)); + if (SUCCEEDED(hRet)) + { + hPopup = CreatePopupMenu(); + + if (hPopup != NULL) + { + hRet = pcm->QueryContextMenu( + hPopup, + 0, + ID_SHELL_CMD_FIRST, + ID_SHELL_CMD_LAST, + CMF_VERBSONLY); + + if (SUCCEEDED(hRet)) + { + *ppcm = pcm; + return hPopup; + } + + DestroyMenu(hPopup); + } + } + + return NULL; +} + +static VOID +OnStartContextMenuCommand(IN HWND hWndOwner, + IN UINT uiCmdId, + IN PVOID pcmContext OPTIONAL, + IN PVOID Context OPTIONAL) +{ + PSTARTMNU_CTMENU_CTX psmcmc = (PSTARTMNU_CTMENU_CTX) pcmContext; + + if (uiCmdId != 0) + { + if ((uiCmdId >= ID_SHELL_CMD_FIRST) && (uiCmdId <= ID_SHELL_CMD_LAST)) + { + CMINVOKECOMMANDINFO cmici = {0}; + CHAR szDir[MAX_PATH]; + + /* Setup and invoke the shell command */ + cmici.cbSize = sizeof(cmici); + cmici.hwnd = hWndOwner; + cmici.lpVerb = (LPCSTR)MAKEINTRESOURCE(uiCmdId - ID_SHELL_CMD_FIRST); + cmici.nShow = SW_NORMAL; + + /* FIXME: Support Unicode!!! */ + if (SHGetPathFromIDListA(psmcmc->pidl, + szDir)) + { + cmici.lpDirectory = szDir; + } + + psmcmc->pcm->InvokeCommand(&cmici); + } + else + { + ITrayWindow * TrayWnd = (ITrayWindow *) Context; + TrayWnd->ExecContextMenuCmd(uiCmdId); + } + } + + psmcmc->pcm->Release(); + + HeapFree(hProcessHeap, 0, psmcmc); +} + +static VOID +AddStartContextMenuItems(IN HWND hWndOwner, + IN HMENU hPopup) +{ + WCHAR szBuf[MAX_PATH]; + HRESULT hRet; + + /* Add the "Open All Users" menu item */ + if (LoadString(hExplorerInstance, + IDS_PROPERTIES, + szBuf, + sizeof(szBuf) / sizeof(szBuf[0]))) + { + AppendMenu(hPopup, + MF_STRING, + ID_SHELL_CMD_PROPERTIES, + szBuf); + } + + if (!SHRestricted(REST_NOCOMMONGROUPS)) + { + /* Check if we should add menu items for the common start menu */ + hRet = SHGetFolderPath(hWndOwner, + CSIDL_COMMON_STARTMENU, + NULL, + SHGFP_TYPE_CURRENT, + szBuf); + if (SUCCEEDED(hRet) && hRet != S_FALSE) + { + /* The directory exists, but only show the items if the + user can actually make any changes to the common start + menu. This is most likely only the case if the user + has administrative rights! */ + if (IsUserAnAdmin()) + { + AppendMenu(hPopup, + MF_SEPARATOR, + 0, + NULL); + + /* Add the "Open All Users" menu item */ + if (LoadString(hExplorerInstance, + IDS_OPEN_ALL_USERS, + szBuf, + sizeof(szBuf) / sizeof(szBuf[0]))) + { + AppendMenu(hPopup, + MF_STRING, + ID_SHELL_CMD_OPEN_ALL_USERS, + szBuf); + } + + /* Add the "Explore All Users" menu item */ + if (LoadString(hExplorerInstance, + IDS_EXPLORE_ALL_USERS, + szBuf, + sizeof(szBuf) / sizeof(szBuf[0]))) + { + AppendMenu(hPopup, + MF_STRING, + ID_SHELL_CMD_EXPLORE_ALL_USERS, + szBuf); + } + } + } + } +} + +static HMENU +CreateStartContextMenu(IN HWND hWndOwner, + IN PVOID *ppcmContext, + IN PVOID Context OPTIONAL) +{ + LPITEMIDLIST pidlStart, pidlLast; + CComPtr psfStart; + CComPtr psfDesktop; + CComPtr pcm; + HRESULT hRet; + HMENU hPopup; + + pidlStart = SHCloneSpecialIDList(hWndOwner, + CSIDL_STARTMENU, + TRUE); + + if (pidlStart != NULL) + { + pidlLast = ILClone(ILFindLastID(pidlStart)); + ILRemoveLastID(pidlStart); + + if (pidlLast != NULL) + { + hRet = SHGetDesktopFolder(&psfDesktop); + if (SUCCEEDED(hRet)) + { + hRet = psfDesktop->BindToObject(pidlStart, NULL, IID_PPV_ARG(IShellFolder, &psfStart)); + if (SUCCEEDED(hRet)) + { + hPopup = CreateContextMenuFromShellFolderPidl(hWndOwner, + psfStart, + pidlLast, + &pcm); + + if (hPopup != NULL) + { + PSTARTMNU_CTMENU_CTX psmcmc; + + psmcmc = (PSTARTMNU_CTMENU_CTX) HeapAlloc(hProcessHeap, 0, sizeof(*psmcmc)); + if (psmcmc != NULL) + { + psmcmc->pcm = pcm; + psmcmc->pidl = pidlLast; + + AddStartContextMenuItems(hWndOwner, + hPopup); + + *ppcmContext = psmcmc; + return hPopup; + } + else + { + DestroyMenu(hPopup); + hPopup = NULL; + } + } + } + } + + ILFree(pidlLast); + } + + ILFree(pidlStart); + } + + return NULL; +} + +/***************************************************************************** + ** IStartMenuSite *********************************************************** + *****************************************************************************/ + +class IStartMenuSiteImpl : + public CComCoClass, + public CComObjectRootEx, + public IStartMenuSite, + public IServiceProvider, + public ITrayPriv, + public IOleCommandTarget, + public IMenuPopup +{ + CComPtr Tray; + CComPtr StartMenuPopup; + +public: + IStartMenuSiteImpl() + { + } + + virtual ~IStartMenuSiteImpl() { } + + /*******************************************************************/ + + virtual HRESULT STDMETHODCALLTYPE QueryService( + IN REFGUID guidService, + IN REFIID riid, + OUT PVOID *ppvObject) + { + if (IsEqualGUID(guidService, SID_SMenuPopup)) + { + return QueryInterface(riid, ppvObject); + } + + return E_NOINTERFACE; + } + + /*******************************************************************/ + + virtual HRESULT STDMETHODCALLTYPE GetWindow( + OUT HWND *phwnd) + { + TRACE("ITrayPriv::GetWindow\n"); + + *phwnd = Tray->GetHWND(); + if (*phwnd != NULL) + return S_OK; + + return E_FAIL; + } + + virtual HRESULT STDMETHODCALLTYPE ContextSensitiveHelp( + IN BOOL fEnterMode) + { + TRACE("ITrayPriv::ContextSensitiveHelp\n"); + return E_NOTIMPL; + } + + virtual HRESULT STDMETHODCALLTYPE Execute( + IN IShellFolder *pShellFolder, + IN LPCITEMIDLIST pidl) + { + HMODULE hShlwapi; + HRESULT ret = S_FALSE; + + TRACE("ITrayPriv::Execute\n"); + + hShlwapi = GetModuleHandle(TEXT("SHLWAPI.DLL")); + if (hShlwapi != NULL) + { + SHINVDEFCMD SHInvokeDefCmd; + + /* SHInvokeDefaultCommand */ + SHInvokeDefCmd = (SHINVDEFCMD) GetProcAddress(hShlwapi, + (LPCSTR) ((LONG) 279)); + if (SHInvokeDefCmd != NULL) + { + ret = SHInvokeDefCmd(Tray->GetHWND(), + pShellFolder, + pidl); + } + } + + return ret; + } + + virtual HRESULT STDMETHODCALLTYPE Unknown( + IN PVOID Unknown1, + IN PVOID Unknown2, + IN PVOID Unknown3, + IN PVOID Unknown4) + { + TRACE("ITrayPriv::Unknown(0x%p,0x%p,0x%p,0x%p)\n", Unknown1, Unknown2, Unknown3, Unknown4); + return E_NOTIMPL; + } + + virtual BOOL + ShowUndockMenuItem(VOID) + { + TRACE("ShowUndockMenuItem() not implemented!\n"); + /* FIXME: How do we detect this?! */ + return FALSE; + } + + virtual BOOL + ShowSynchronizeMenuItem(VOID) + { + TRACE("ShowSynchronizeMenuItem() not implemented!\n"); + /* FIXME: How do we detect this?! */ + return FALSE; + } + + virtual HRESULT STDMETHODCALLTYPE AppendMenu( + OUT HMENU* phMenu) + { + HMENU hMenu, hSettingsMenu; + DWORD dwLogoff; + BOOL bWantLogoff; + UINT uLastItemsCount = 5; /* 5 menu items below the last separator */ + WCHAR szUser[128]; + + TRACE("ITrayPriv::AppendMenu\n"); + + hMenu = LoadPopupMenu(hExplorerInstance, + MAKEINTRESOURCE(IDM_STARTMENU)); + *phMenu = hMenu; + if (hMenu == NULL) + return E_FAIL; + + /* Remove menu items that don't apply */ + + dwLogoff = SHRestricted(REST_STARTMENULOGOFF); + bWantLogoff = (dwLogoff == 2 || + SHRestricted(REST_FORCESTARTMENULOGOFF) || + GetExplorerRegValueSet(HKEY_CURRENT_USER, + TEXT("Advanced"), + TEXT("StartMenuLogoff"))); + + /* Favorites */ + if (!GetExplorerRegValueSet(HKEY_CURRENT_USER, + TEXT("Advanced"), + TEXT("StartMenuFavorites"))) + { + DeleteMenu(hMenu, + IDM_FAVORITES, + MF_BYCOMMAND); + } + + /* Documents */ + if (SHRestricted(REST_NORECENTDOCSMENU)) + { + DeleteMenu(hMenu, + IDM_DOCUMENTS, + MF_BYCOMMAND); + } + + /* Settings */ + hSettingsMenu = FindSubMenu(hMenu, + IDM_SETTINGS, + FALSE); + if (hSettingsMenu != NULL) + { + if (SHRestricted(REST_NOSETFOLDERS)) + { + /* Control Panel */ + if (SHRestricted(REST_NOCONTROLPANEL)) + { + DeleteMenu(hSettingsMenu, + IDM_CONTROLPANEL, + MF_BYCOMMAND); + + /* Delete the separator below it */ + DeleteMenu(hSettingsMenu, + 0, + MF_BYPOSITION); + } + + /* Network Connections */ + if (SHRestricted(REST_NONETWORKCONNECTIONS)) + { + DeleteMenu(hSettingsMenu, + IDM_NETWORKCONNECTIONS, + MF_BYCOMMAND); + } + + /* Printers and Faxes */ + DeleteMenu(hSettingsMenu, + IDM_PRINTERSANDFAXES, + MF_BYCOMMAND); + } + + /* Security */ + if (GetSystemMetrics(SM_REMOTECONTROL) == 0 || + SHRestricted(REST_NOSECURITY)) + { + DeleteMenu(hSettingsMenu, + IDM_SECURITY, + MF_BYCOMMAND); + } + + if (GetMenuItemCount(hSettingsMenu) == 0) + { + DeleteMenu(hMenu, + IDM_SETTINGS, + MF_BYCOMMAND); + } + } + + /* Search */ + /* FIXME: Enable after implementing */ + /* if (SHRestricted(REST_NOFIND)) */ + { + DeleteMenu(hMenu, + IDM_SEARCH, + MF_BYCOMMAND); + } + + /* FIXME: Help */ + + /* Run */ + if (SHRestricted(REST_NORUN)) + { + DeleteMenu(hMenu, + IDM_RUN, + MF_BYCOMMAND); + } + + /* Synchronize */ + if (!ShowSynchronizeMenuItem()) + { + DeleteMenu(hMenu, + IDM_SYNCHRONIZE, + MF_BYCOMMAND); + uLastItemsCount--; + } + + /* Log off */ + if (dwLogoff != 1 && bWantLogoff) + { + /* FIXME: We need a more sophisticated way to determine whether to show + or hide it, it might be hidden in too many cases!!! */ + + /* Update Log Off menu item */ + if (!GetCurrentLoggedOnUserName(szUser, + sizeof(szUser) / sizeof(szUser[0]))) + { + szUser[0] = _T('\0'); + } + + if (!FormatMenuString(hMenu, + IDM_LOGOFF, + MF_BYCOMMAND, + szUser)) + { + /* We couldn't update the menu item, delete it... */ + DeleteMenu(hMenu, + IDM_LOGOFF, + MF_BYCOMMAND); + } + } + else + { + DeleteMenu(hMenu, + IDM_LOGOFF, + MF_BYCOMMAND); + uLastItemsCount--; + } + + + /* Disconnect */ + if (GetSystemMetrics(SM_REMOTECONTROL) == 0) + { + DeleteMenu(hMenu, + IDM_DISCONNECT, + MF_BYCOMMAND); + uLastItemsCount--; + } + + /* Undock computer */ + if (!ShowUndockMenuItem()) + { + DeleteMenu(hMenu, + IDM_UNDOCKCOMPUTER, + MF_BYCOMMAND); + uLastItemsCount--; + } + + /* Shut down */ + if (SHRestricted(REST_NOCLOSE)) + { + DeleteMenu(hMenu, + IDM_SHUTDOWN, + MF_BYCOMMAND); + uLastItemsCount--; + } + + if (uLastItemsCount == 0) + { + /* Remove the separator at the end of the menu */ + DeleteMenu(hMenu, + IDM_LASTSTARTMENU_SEPARATOR, + MF_BYCOMMAND); + } + + return S_OK; + } + + /*******************************************************************/ + + virtual HRESULT STDMETHODCALLTYPE QueryStatus( + IN const GUID *pguidCmdGroup OPTIONAL, + IN ULONG cCmds, + IN OUT OLECMD *prgCmds, + IN OUT OLECMDTEXT *pCmdText OPTIONAL) + { + return E_NOTIMPL; + } + + virtual HRESULT STDMETHODCALLTYPE Exec( + IN const GUID *pguidCmdGroup OPTIONAL, + IN DWORD nCmdID, + IN DWORD nCmdExecOpt, + IN VARIANTARG *pvaIn OPTIONAL, + IN VARIANTARG *pvaOut OPTIONAL) + { + return E_NOTIMPL; + } + + /*******************************************************************/ + + virtual HRESULT STDMETHODCALLTYPE SetClient(IUnknown *punkClient) + { + return E_NOTIMPL; + } + + virtual HRESULT STDMETHODCALLTYPE GetClient(IUnknown ** ppunkClient) + { + return E_NOTIMPL; + } + + virtual HRESULT STDMETHODCALLTYPE OnPosRectChangeDB(RECT *prc) + { + return E_NOTIMPL; + } + + virtual HRESULT STDMETHODCALLTYPE Popup(POINTL *ppt, RECTL *prcExclude, MP_POPUPFLAGS dwFlags) + { + return E_NOTIMPL; + } + + virtual HRESULT STDMETHODCALLTYPE OnSelect(DWORD dwSelectType) + { + return E_NOTIMPL; + } + + virtual HRESULT STDMETHODCALLTYPE SetSubMenu(IMenuPopup *pmp, BOOL fSet) + { + if (!fSet) + { + return Tray_OnStartMenuDismissed(); + } + + return S_OK; + } + + /*******************************************************************/ + + HRESULT Initialize(IN ITrayWindow *tray) + { + Tray = tray; + return S_OK; + } + + DECLARE_NOT_AGGREGATABLE(IStartMenuSiteImpl) + + DECLARE_PROTECT_FINAL_CONSTRUCT() + BEGIN_COM_MAP(IStartMenuSiteImpl) + COM_INTERFACE_ENTRY_IID(IID_IServiceProvider, IServiceProvider) + COM_INTERFACE_ENTRY_IID(IID_ITrayPriv, ITrayPriv) + COM_INTERFACE_ENTRY_IID(IID_IOleCommandTarget, IOleCommandTarget) + COM_INTERFACE_ENTRY_IID(IID_IMenuPopup, IMenuPopup) + COM_INTERFACE_ENTRY_IID(IID_IOleWindow, IOleWindow) + END_COM_MAP() +}; + +HRESULT CreateStartMenuSite(IN OUT ITrayWindow *Tray, const IID & riid, PVOID * ppv) +{ + return ShellObjectCreatorInit(Tray, riid, ppv); +} + +HRESULT +UpdateStartMenu(IN OUT IMenuPopup *pMenuPopup, + IN HBITMAP hbmBanner OPTIONAL, + IN BOOL bSmallIcons) +{ + CComPtr pbb; + HRESULT hRet; + + hRet = pMenuPopup->QueryInterface(IID_PPV_ARG(IBanneredBar, &pbb)); + if (SUCCEEDED(hRet)) + { + hRet = pbb->SetBitmap( hbmBanner); + + /* Update the icon size */ + hRet = pbb->SetIconSize(bSmallIcons ? BMICON_SMALL : BMICON_LARGE); + } + + return hRet; +} + +IMenuPopup * +CreateStartMenu(IN ITrayWindow *Tray, + OUT IMenuBand **ppMenuBand, + IN HBITMAP hbmBanner OPTIONAL, + IN BOOL bSmallIcons) +{ + HRESULT hr; + IObjectWithSite *pOws = NULL; + IMenuPopup *pMp = NULL; + IUnknown *pSms = NULL; + IMenuBand *pMb = NULL; + IInitializeObject *pIo; + IUnknown *pUnk = NULL; + IBandSite *pBs = NULL; + DWORD dwBandId = 0; + + hr = CreateStartMenuSite(Tray, IID_PPV_ARG(IUnknown, &pSms)); + if (FAILED_UNEXPECTEDLY(hr)) + return NULL; + +#if 0 + hr = CoCreateInstance(&CLSID_StartMenu, + NULL, + CLSCTX_INPROC_SERVER, + &IID_IMenuPopup, + (PVOID *)&pMp); +#else + hr = _CStartMenu_Constructor(IID_PPV_ARG(IMenuPopup, &pMp)); +#endif + if (FAILED_UNEXPECTEDLY(hr)) + { + TRACE("CoCreateInstance failed: %x\n", hr); + goto cleanup; + } + + hr = pMp->QueryInterface(IID_PPV_ARG(IObjectWithSite, &pOws)); + if (FAILED_UNEXPECTEDLY(hr)) + { + TRACE("IMenuPopup_QueryInterface failed: %x\n", hr); + goto cleanup; + } + + /* Set the menu site so we can handle messages */ + hr = pOws->SetSite(pSms); + if (FAILED_UNEXPECTEDLY(hr)) + { + TRACE("IObjectWithSite_SetSite failed: %x\n", hr); + goto cleanup; + } + + /* Initialize the menu object */ + hr = pMp->QueryInterface(IID_PPV_ARG(IInitializeObject, &pIo)); + if (SUCCEEDED(hr)) + { + hr = pIo->Initialize(); + pIo->Release(); + } + else + hr = S_OK; + + /* Everything is initialized now. Let's get the IMenuBand interface. */ + if (FAILED_UNEXPECTEDLY(hr)) + { + TRACE("IMenuPopup_QueryInterface failed: %x\n", hr); + goto cleanup; + } + + hr = pMp->GetClient( &pUnk); + if (FAILED_UNEXPECTEDLY(hr)) + { + TRACE("IMenuPopup_GetClient failed: %x\n", hr); + goto cleanup; + } + + hr = pUnk->QueryInterface(IID_PPV_ARG(IBandSite, &pBs)); + if (FAILED_UNEXPECTEDLY(hr)) + { + TRACE("IUnknown_QueryInterface pBs failed: %x\n", hr); + goto cleanup; + } + + /* Finally we have the IBandSite interface, there's only one + band in it that apparently provides the IMenuBand interface */ + hr = pBs->EnumBands( 0, &dwBandId); + if (FAILED_UNEXPECTEDLY(hr)) + { + TRACE("IBandSite_EnumBands failed: %x\n", hr); + goto cleanup; + } + + hr = pBs->GetBandObject( dwBandId, IID_PPV_ARG(IMenuBand, &pMb)); + if (FAILED_UNEXPECTEDLY(hr)) + { + TRACE("IBandSite_GetBandObject failed: %x\n", hr); + goto cleanup; + } + + UpdateStartMenu(pMp, + hbmBanner, + bSmallIcons); + +cleanup: + if (SUCCEEDED(hr)) + *ppMenuBand = pMb; + else if (pMb != NULL) + pMb->Release(); + + if (pBs != NULL) + pBs->Release(); + if (pUnk != NULL) + pUnk->Release(); + if (pOws != NULL) + pOws->Release(); + if (pMp != NULL) + pMp->Release(); + if (pSms != NULL) + pSms->Release(); + + if (FAILED_UNEXPECTEDLY(hr)) + return NULL; + return pMp; +} diff --git a/base/shell/explorer-new/startup.c b/base/shell/explorer-new/startup.cpp similarity index 99% rename from base/shell/explorer-new/startup.c rename to base/shell/explorer-new/startup.cpp index 4de2ef33e4b..d1ae7ee39cc 100644 --- a/base/shell/explorer-new/startup.c +++ b/base/shell/explorer-new/startup.cpp @@ -176,7 +176,7 @@ static BOOL ProcessRunKeys(HKEY hkRoot, LPCWSTR szKeyName, BOOL bDelete, goto end; } - szCmdLine = HeapAlloc(hProcessHeap, + szCmdLine = (WCHAR*)HeapAlloc(hProcessHeap, 0, cbMaxCmdLine); if (szCmdLine == NULL) @@ -188,7 +188,7 @@ static BOOL ProcessRunKeys(HKEY hkRoot, LPCWSTR szKeyName, BOOL bDelete, } ++cchMaxValue; - szValue = HeapAlloc(hProcessHeap, + szValue = (WCHAR*)HeapAlloc(hProcessHeap, 0, cchMaxValue * sizeof(*szValue)); if (szValue == NULL) diff --git a/base/shell/explorer-new/taskband.c b/base/shell/explorer-new/taskband.c deleted file mode 100644 index 299a7fa22d6..00000000000 --- a/base/shell/explorer-new/taskband.c +++ /dev/null @@ -1,660 +0,0 @@ -/* - * ReactOS Explorer - * - * Copyright 2006 - 2007 Thomas Weidenmueller - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "precomp.h" - -/***************************************************************************** - ** ITaskBand **************************************************************** - *****************************************************************************/ - -const GUID CLSID_ITaskBand = {0x68284FAA,0x6A48,0x11D0,{0x8C,0x78,0x00,0xC0,0x4F,0xD9,0x18,0xB4}}; - -static const ITaskBandVtbl ITaskBandImpl_Vtbl; -static const IDeskBandVtbl IDeskBandImpl_Vtbl; -static const IObjectWithSiteVtbl IObjectWithSiteImpl_Vtbl; -static const IDeskBarVtbl IDeskBarImpl_Vtbl; -static const IPersistStreamVtbl IPersistStreamImpl_Vtbl; -static const IWinEventHandlerVtbl IWinEventHandlerImpl_Vtbl; - -typedef struct -{ - const ITaskBandVtbl *lpVtbl; - const IDeskBandVtbl *lpDeskBandVtbl; - const IObjectWithSiteVtbl *lpObjectWithSiteVtbl; - const IDeskBarVtbl *lpDeskBarVtbl; - const IPersistStreamVtbl *lpPersistStreamVtbl; - const IWinEventHandlerVtbl *lpWindowEventHandlerVtbl; - /* FIXME: Implement IOleCommandTarget */ - LONG Ref; - - ITrayWindow *Tray; - IUnknown *punkSite; - - HWND hWnd; - DWORD dwBandID; -} ITaskBandImpl; - -static IUnknown * -IUnknown_from_ITaskBandImpl(ITaskBandImpl *This) -{ - return (IUnknown *)&This->lpVtbl; -} - -IMPL_CASTS(ITaskBand, ITaskBand, lpVtbl) -IMPL_CASTS(IDeskBand, ITaskBand, lpDeskBandVtbl) -IMPL_CASTS(IObjectWithSite, ITaskBand, lpObjectWithSiteVtbl) -IMPL_CASTS(IDeskBar, ITaskBand, lpDeskBarVtbl) -IMPL_CASTS(IPersistStream, ITaskBand, lpPersistStreamVtbl) -IMPL_CASTS(IWinEventHandler, ITaskBand, lpWindowEventHandlerVtbl) - -static ULONG STDMETHODCALLTYPE -ITaskBandImpl_AddRef(IN OUT ITaskBand *iface) -{ - ITaskBandImpl *This = ITaskBandImpl_from_ITaskBand(iface); - - return InterlockedIncrement(&This->Ref); -} - -static VOID -ITaskBandImpl_Free(IN OUT ITaskBandImpl *This) -{ - if (This->punkSite != NULL) - { - IUnknown_Release(This->punkSite); - This->punkSite = NULL; - } - - HeapFree(hProcessHeap, - 0, - This); -} - -static ULONG STDMETHODCALLTYPE -ITaskBandImpl_Release(IN OUT ITaskBand *iface) -{ - ITaskBandImpl *This = ITaskBandImpl_from_ITaskBand(iface); - ULONG Ret; - - Ret = InterlockedDecrement(&This->Ref); - - if (Ret == 0) - ITaskBandImpl_Free(This); - - return Ret; -} - -static HRESULT STDMETHODCALLTYPE -ITaskBandImpl_QueryInterface(IN OUT ITaskBand *iface, - IN REFIID riid, - OUT LPVOID *ppvObj) -{ - ITaskBandImpl *This; - - if (ppvObj == NULL) - return E_POINTER; - - This = ITaskBandImpl_from_ITaskBand(iface); - - if (IsEqualIID(riid, - &IID_IUnknown)) - { - *ppvObj = IUnknown_from_ITaskBandImpl(This); - } - else if (IsEqualIID(riid, - &IID_IDeskBand) || - IsEqualIID(riid, - &IID_IOleWindow) || - IsEqualIID(riid, - &IID_IDockingWindow)) - { - *ppvObj = IDeskBand_from_ITaskBandImpl(This); - } - else if (IsEqualIID(riid, - &IID_IObjectWithSite)) - { - *ppvObj = IObjectWithSite_from_ITaskBandImpl(This); - } - else if (IsEqualIID(riid, - &IID_IDeskBar)) - { - *ppvObj = IDeskBar_from_ITaskBandImpl(This); - } - else if (IsEqualIID(riid, - &IID_IWinEventHandler)) - { - /* When run on Windows the system queries this interface, which is completely - undocumented :( It's queried during initialization of the tray band site. - The system apparently uses this interface to forward messages to be handled - by the band child window. This interface appears to be implemented by a number - of classes provided by the shell, including the IBandSite interface. In that - we (the host application) forward messages to the default message handler (in - our case the IBandSite default message handler for the Rebar control)! This - interface in the ITaskBand implementation is only actually used if we use - the same interface to forward messages to the IBandSite implementation of - the shell! */ - *ppvObj = IWinEventHandler_from_ITaskBandImpl(This); - } -#if 0 - else if (IsEqualIID(riid, - &IID_IPersistStream) || - IsEqualIID(riid, - &IID_IPersist)) - { - *ppvObj = IPersistStream_from_ITaskBandImpl(This); - } -#endif - else - { - *ppvObj = NULL; - return E_NOINTERFACE; - } - - ITaskBandImpl_AddRef(iface); - return S_OK; -} - -static HRESULT STDMETHODCALLTYPE -ITaskBandImpl_GetRebarBandID(IN OUT ITaskBand *iface, - OUT DWORD *pdwBandID) -{ - ITaskBandImpl *This = ITaskBandImpl_from_ITaskBand(iface); - - if (This->dwBandID != (DWORD)-1) - { - if (pdwBandID != NULL) - *pdwBandID = This->dwBandID; - - return S_OK; - } - - return E_FAIL; -} - -static const ITaskBandVtbl ITaskBandImpl_Vtbl = -{ - /*** IUnknown methods ***/ - ITaskBandImpl_QueryInterface, - ITaskBandImpl_AddRef, - ITaskBandImpl_Release, - /*** ITaskBand methods ***/ - ITaskBandImpl_GetRebarBandID -}; - -/*****************************************************************************/ - -METHOD_IUNKNOWN_INHERITED_ADDREF(IDeskBand, ITaskBand) -METHOD_IUNKNOWN_INHERITED_RELEASE(IDeskBand, ITaskBand) -METHOD_IUNKNOWN_INHERITED_QUERYINTERFACE(IDeskBand, ITaskBand) - -static HRESULT STDMETHODCALLTYPE -ITaskBandImpl_GetWindow(IN OUT IDeskBand *iface, - OUT HWND *phwnd) -{ - ITaskBandImpl *This = ITaskBandImpl_from_IDeskBand(iface); - - /* NOTE: We have to return the tray window here so that ITaskBarClient - knows the parent window of the Rebar control it creates when - calling ITaskBarClient::SetDeskBarSite()! However, once we - created a window we return the task switch window! */ - if (This->hWnd != NULL) - *phwnd = This->hWnd; - else - *phwnd = ITrayWindow_GetHWND(This->Tray); - - TRACE("ITaskBand::GetWindow(0x%p->0x%p)\n", phwnd, *phwnd); - - if (*phwnd != NULL) - return S_OK; - - return E_FAIL; -} - -static HRESULT STDMETHODCALLTYPE -ITaskBandImpl_ContextSensitiveHelp(IN OUT IDeskBand *iface, - IN BOOL fEnterMode) -{ - /* FIXME: Implement */ - return E_NOTIMPL; -} - -static HRESULT STDMETHODCALLTYPE -ITaskBandImpl_ShowDW(IN OUT IDeskBand *iface, - IN BOOL bShow) -{ - /* We don't do anything... */ - return S_OK; -} - -static HRESULT STDMETHODCALLTYPE -ITaskBandImpl_CloseDW(IN OUT IDeskBand *iface, - IN DWORD dwReserved) -{ - /* We don't do anything... */ - return S_OK; -} - -static HRESULT STDMETHODCALLTYPE -ITaskBandImpl_ResizeBoderDW(IN OUT IDeskBand *iface, - IN LPCRECT prcBorder, - IN IUnknown *punkToolbarSite, - IN BOOL fReserved) -{ - /* No need to implement this method */ - return E_NOTIMPL; -} - -static HRESULT STDMETHODCALLTYPE -ITaskBandImpl_GetBandInfo(IN OUT IDeskBand *iface, - IN DWORD dwBandID, - IN DWORD dwViewMode, - IN OUT DESKBANDINFO *pdbi) -{ - ITaskBandImpl *This = ITaskBandImpl_from_IDeskBand(iface); - TRACE("ITaskBand::GetBandInfo(0x%x,0x%x,0x%p) hWnd=0x%p\n", dwBandID, dwViewMode, pdbi, This->hWnd); - - /* NOTE: We could save dwBandID in the instance in case we need it later... */ - - if (This->hWnd != NULL) - { - /* The task band never has a title */ - pdbi->dwMask &= ~DBIM_TITLE; - - /* NOTE: We don't return DBIMF_UNDELETEABLE here, the band site will - handle us differently and add this flag for us. The reason for - this is future changes that might allow it to be deletable. - We want the band site to be in charge of this decision rather - the band itself! */ - /* FIXME: What about DBIMF_NOGRIPPER and DBIMF_ALWAYSGRIPPER */ - pdbi->dwModeFlags = DBIMF_VARIABLEHEIGHT; - - if (dwViewMode & DBIF_VIEWMODE_VERTICAL) - { - pdbi->ptIntegral.y = 1; - pdbi->ptMinSize.y = 1; - /* FIXME: Get the button metrics from the task bar object!!! */ - pdbi->ptMinSize.x = (3 * GetSystemMetrics(SM_CXEDGE) / 2) + /* FIXME: Might be wrong if only one column! */ - GetSystemMetrics(SM_CXSIZE) + (2 * GetSystemMetrics(SM_CXEDGE)); /* FIXME: Min button size, query!!! */ - } - else - { - pdbi->ptMinSize.y = GetSystemMetrics(SM_CYSIZE) + (2 * GetSystemMetrics(SM_CYEDGE)); /* FIXME: Query */ - pdbi->ptIntegral.y = pdbi->ptMinSize.y + (3 * GetSystemMetrics(SM_CYEDGE) / 2); /* FIXME: Query metrics */ - /* We're not going to allow task bands where not even the minimum button size fits into the band */ - pdbi->ptMinSize.x = pdbi->ptIntegral.y; - } - - /* Ignored: pdbi->ptMaxSize.x */ - pdbi->ptMaxSize.y = -1; - - /* FIXME: We should query the height from the task bar object!!! */ - pdbi->ptActual.y = GetSystemMetrics(SM_CYSIZE) + (2 * GetSystemMetrics(SM_CYEDGE)); - - /* Save the band ID for future use in case we need to check whether a given band - is the task band */ - This->dwBandID = dwBandID; - - TRACE("H: %d, Min: %d,%d, Integral.y: %d Actual: %d,%d\n", (dwViewMode & DBIF_VIEWMODE_VERTICAL) == 0, - pdbi->ptMinSize.x, pdbi->ptMinSize.y, pdbi->ptIntegral.y, - pdbi->ptActual.x,pdbi->ptActual.y); - - return S_OK; - } - - return E_FAIL; -} - -static const IDeskBandVtbl IDeskBandImpl_Vtbl = -{ - /*** IUnknown methods ***/ - METHOD_IUNKNOWN_INHERITED_QUERYINTERFACE_NAME(IDeskBand, ITaskBand), - METHOD_IUNKNOWN_INHERITED_ADDREF_NAME(IDeskBand, ITaskBand), - METHOD_IUNKNOWN_INHERITED_RELEASE_NAME(IDeskBand, ITaskBand), - /*** IOleWindow methods ***/ - ITaskBandImpl_GetWindow, - ITaskBandImpl_ContextSensitiveHelp, - /*** IDockingWindow methods ***/ - ITaskBandImpl_ShowDW, - ITaskBandImpl_CloseDW, - ITaskBandImpl_ResizeBoderDW, - /*** IDeskBand methods ***/ - ITaskBandImpl_GetBandInfo -}; - -/*****************************************************************************/ - -METHOD_IUNKNOWN_INHERITED_ADDREF(IDeskBar, ITaskBand) -METHOD_IUNKNOWN_INHERITED_RELEASE(IDeskBar, ITaskBand) -METHOD_IUNKNOWN_INHERITED_QUERYINTERFACE(IDeskBar, ITaskBand) - -static HRESULT STDMETHODCALLTYPE -IDeskBarImpl_GetWindow(IN OUT IDeskBar *iface, - OUT HWND *phwnd) -{ - ITaskBandImpl *This = ITaskBandImpl_from_IDeskBar(iface); - IDeskBand *DeskBand = IDeskBand_from_ITaskBandImpl(This); - - /* Proxy to IDeskBand interface */ - return IDeskBand_GetWindow(DeskBand, - phwnd); -} - -static HRESULT STDMETHODCALLTYPE -IDeskBarImpl_ContextSensitiveHelp(IN OUT IDeskBar *iface, - IN BOOL fEnterMode) -{ - ITaskBandImpl *This = ITaskBandImpl_from_IDeskBar(iface); - IDeskBand *DeskBand = IDeskBand_from_ITaskBandImpl(This); - - /* Proxy to IDeskBand interface */ - return IDeskBand_ContextSensitiveHelp(DeskBand, - fEnterMode); -} - -static HRESULT STDMETHODCALLTYPE -IDeskBarImpl_SetClient(IN OUT IDeskBar *iface, - IN IUnknown *punkClient) -{ - TRACE("IDeskBar::SetClient(0x%p)\n", punkClient); - return E_NOTIMPL; -} - -static HRESULT STDMETHODCALLTYPE -IDeskBarImpl_GetClient(IN OUT IDeskBar *iface, - OUT IUnknown **ppunkClient) -{ - TRACE("IDeskBar::GetClient(0x%p)\n", ppunkClient); - return E_NOTIMPL; -} - -static HRESULT STDMETHODCALLTYPE -IDeskBarImpl_OnPosRectChangeDB(IN OUT IDeskBar *iface, - IN RECT *prc) -{ - TRACE("IDeskBar::OnPosRectChangeDB(0x%p=(%d,%d,%d,%d))\n", prc, prc->left, prc->top, prc->right, prc->bottom); - if (prc->bottom - prc->top == 0) - return S_OK; - - return S_FALSE; -} - -static const IDeskBarVtbl IDeskBarImpl_Vtbl = -{ - /*** IUnknown methods ***/ - METHOD_IUNKNOWN_INHERITED_QUERYINTERFACE_NAME(IDeskBar, ITaskBand), - METHOD_IUNKNOWN_INHERITED_ADDREF_NAME(IDeskBar, ITaskBand), - METHOD_IUNKNOWN_INHERITED_RELEASE_NAME(IDeskBar, ITaskBand), - /*** IOleWindow methods ***/ - IDeskBarImpl_GetWindow, - IDeskBarImpl_ContextSensitiveHelp, - /*** IDeskBar methods ***/ - IDeskBarImpl_SetClient, - IDeskBarImpl_GetClient, - IDeskBarImpl_OnPosRectChangeDB -}; - -/*****************************************************************************/ - -METHOD_IUNKNOWN_INHERITED_ADDREF(IPersistStream, ITaskBand) -METHOD_IUNKNOWN_INHERITED_RELEASE(IPersistStream, ITaskBand) -METHOD_IUNKNOWN_INHERITED_QUERYINTERFACE(IPersistStream, ITaskBand) - -static HRESULT STDMETHODCALLTYPE -ITaskBandImpl_GetClassID(IN OUT IPersistStream *iface, - OUT CLSID *pClassID) -{ - TRACE("ITaskBand::GetClassID(0x%p)\n", pClassID); - /* We're going to return the (internal!) CLSID of the task band interface */ - *pClassID = CLSID_ITaskBand; - return S_OK; -} - -static HRESULT STDMETHODCALLTYPE -ITaskBandImpl_IsDirty(IN OUT IPersistStream *iface) -{ - /* The object hasn't changed since the last save! */ - return S_FALSE; -} - -static HRESULT STDMETHODCALLTYPE -ITaskBandImpl_Load(IN OUT IPersistStream *iface, - IN IStream *pStm) -{ - TRACE("ITaskBand::Load called\n"); - /* Nothing to do */ - return S_OK; -} - -static HRESULT STDMETHODCALLTYPE -ITaskBandImpl_Save(IN OUT IPersistStream *iface, - IN IStream *pStm, - IN BOOL fClearDirty) -{ - /* Nothing to do */ - return S_OK; -} - -static HRESULT STDMETHODCALLTYPE -ITaskBandImpl_GetSizeMax(IN OUT IPersistStream *iface, - OUT ULARGE_INTEGER *pcbSize) -{ - TRACE("ITaskBand::GetSizeMax called\n"); - /* We don't need any space for the task band */ - pcbSize->QuadPart = 0; - return S_OK; -} - -static const IPersistStreamVtbl IPersistStreamImpl_Vtbl = -{ - /*** IUnknown methods ***/ - METHOD_IUNKNOWN_INHERITED_QUERYINTERFACE_NAME(IPersistStream, ITaskBand), - METHOD_IUNKNOWN_INHERITED_ADDREF_NAME(IPersistStream, ITaskBand), - METHOD_IUNKNOWN_INHERITED_RELEASE_NAME(IPersistStream, ITaskBand), - /*** IPersist methods ***/ - ITaskBandImpl_GetClassID, - /*** IPersistStream methods ***/ - ITaskBandImpl_IsDirty, - ITaskBandImpl_Load, - ITaskBandImpl_Save, - ITaskBandImpl_GetSizeMax -}; - -/*****************************************************************************/ - -METHOD_IUNKNOWN_INHERITED_ADDREF(IObjectWithSite, ITaskBand) -METHOD_IUNKNOWN_INHERITED_RELEASE(IObjectWithSite, ITaskBand) -METHOD_IUNKNOWN_INHERITED_QUERYINTERFACE(IObjectWithSite, ITaskBand) - -static HRESULT STDMETHODCALLTYPE -ITaskBandImpl_SetSite(IN OUT IObjectWithSite *iface, - IN IUnknown* pUnkSite) -{ - ITaskBandImpl *This = ITaskBandImpl_from_IObjectWithSite(iface); - HRESULT hRet = E_FAIL; - - TRACE("ITaskBand::SetSite(0x%p)\n", pUnkSite); - - /* Release the current site */ - if (This->punkSite != NULL) - { - IUnknown_Release(This->punkSite); - } - - This->punkSite = NULL; - This->hWnd = NULL; - - if (pUnkSite != NULL) - { - IOleWindow *OleWindow; - - /* Check if the site supports IOleWindow */ - hRet = IUnknown_QueryInterface(pUnkSite, - &IID_IOleWindow, - (PVOID *)&OleWindow); - if (SUCCEEDED(hRet)) - { - HWND hWndParent = NULL; - - hRet = IOleWindow_GetWindow(OleWindow, - &hWndParent); - if (SUCCEEDED(hRet)) - { - /* Attempt to create the task switch window */ - - TRACE("CreateTaskSwitchWnd(Parent: 0x%p)\n", hWndParent); - This->hWnd = CreateTaskSwitchWnd(hWndParent, - This->Tray); - if (This->hWnd != NULL) - { - This->punkSite = pUnkSite; - hRet = S_OK; - } - else - { - TRACE("CreateTaskSwitchWnd() failed!\n"); - IUnknown_Release(OleWindow); - hRet = E_FAIL; - } - } - else - IUnknown_Release(OleWindow); - } - else - TRACE("Querying IOleWindow failed: 0x%x\n", hRet); - } - - return hRet; -} - -static HRESULT STDMETHODCALLTYPE -ITaskBandImpl_GetSite(IN OUT IObjectWithSite *iface, - IN REFIID riid, - OUT VOID **ppvSite) -{ - ITaskBandImpl *This = ITaskBandImpl_from_IObjectWithSite(iface); - TRACE("ITaskBand::GetSite(0x%p,0x%p)\n", riid, ppvSite); - - if (This->punkSite != NULL) - { - return IUnknown_QueryInterface(This->punkSite, - riid, - ppvSite); - } - - *ppvSite = NULL; - return E_FAIL; -} - -static const IObjectWithSiteVtbl IObjectWithSiteImpl_Vtbl = -{ - /*** IUnknown methods ***/ - METHOD_IUNKNOWN_INHERITED_QUERYINTERFACE_NAME(IObjectWithSite, ITaskBand), - METHOD_IUNKNOWN_INHERITED_ADDREF_NAME(IObjectWithSite, ITaskBand), - METHOD_IUNKNOWN_INHERITED_RELEASE_NAME(IObjectWithSite, ITaskBand), - /*** IObjectWithSite methods ***/ - ITaskBandImpl_SetSite, - ITaskBandImpl_GetSite -}; - - -/*****************************************************************************/ - -METHOD_IUNKNOWN_INHERITED_ADDREF(IWinEventHandler, ITaskBand) -METHOD_IUNKNOWN_INHERITED_RELEASE(IWinEventHandler, ITaskBand) -METHOD_IUNKNOWN_INHERITED_QUERYINTERFACE(IWinEventHandler, ITaskBand) - -static HRESULT STDMETHODCALLTYPE -IWinEventHandlerImpl_ProcessMessage(IN OUT IWinEventHandler *iface, - IN HWND hWnd, - IN UINT uMsg, - IN WPARAM wParam, - IN LPARAM lParam, - OUT LRESULT *plrResult) -{ - TRACE("ITaskBand: IWinEventHandler::ProcessMessage(0x%p, 0x%x, 0x%p, 0x%p, 0x%p)\n", hWnd, uMsg, wParam, lParam, plrResult); - return E_NOTIMPL; -} - -static HRESULT STDMETHODCALLTYPE -IWinEventHandlerImpl_ContainsWindow(IN OUT IWinEventHandler *iface, - IN HWND hWnd) -{ - ITaskBandImpl *This = ITaskBandImpl_from_IWinEventHandler(iface); - - if (This->hWnd == hWnd || - IsChild(This->hWnd, hWnd)) - { - TRACE("ITaskBand::ContainsWindow(0x%p) returns S_OK\n", hWnd); - return S_OK; - } - - return S_FALSE; -} - -static const IWinEventHandlerVtbl IWinEventHandlerImpl_Vtbl = -{ - /*** IUnknown methods ***/ - METHOD_IUNKNOWN_INHERITED_QUERYINTERFACE_NAME(IWinEventHandler, ITaskBand), - METHOD_IUNKNOWN_INHERITED_ADDREF_NAME(IWinEventHandler, ITaskBand), - METHOD_IUNKNOWN_INHERITED_RELEASE_NAME(IWinEventHandler, ITaskBand), - /*** IWinEventHandler methods ***/ - IWinEventHandlerImpl_ProcessMessage, - IWinEventHandlerImpl_ContainsWindow -}; - -/*****************************************************************************/ - -static ITaskBandImpl * -ITaskBandImpl_Construct(IN OUT ITrayWindow *Tray) -{ - ITaskBandImpl *This; - - This = HeapAlloc(hProcessHeap, - HEAP_ZERO_MEMORY, - sizeof(*This)); - if (This == NULL) - return NULL; - - This->lpVtbl = &ITaskBandImpl_Vtbl; - This->lpDeskBandVtbl = &IDeskBandImpl_Vtbl; - This->lpObjectWithSiteVtbl = &IObjectWithSiteImpl_Vtbl; - This->lpDeskBarVtbl = &IDeskBarImpl_Vtbl; - This->lpPersistStreamVtbl = &IPersistStreamImpl_Vtbl; - This->lpWindowEventHandlerVtbl = &IWinEventHandlerImpl_Vtbl; - This->Ref = 1; - - This->Tray = Tray; - This->dwBandID = (DWORD)-1; - - return This; -} - -ITaskBand * -CreateTaskBand(IN OUT ITrayWindow *Tray) -{ - ITaskBandImpl *This; - - This = ITaskBandImpl_Construct(Tray); - if (This != NULL) - { - return ITaskBand_from_ITaskBandImpl(This); - } - - return NULL; -} diff --git a/base/shell/explorer-new/taskband.cpp b/base/shell/explorer-new/taskband.cpp new file mode 100644 index 00000000000..3c0df861933 --- /dev/null +++ b/base/shell/explorer-new/taskband.cpp @@ -0,0 +1,420 @@ +/* + * ReactOS Explorer + * + * Copyright 2006 - 2007 Thomas Weidenmueller + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "precomp.h" + +/***************************************************************************** + ** ITaskBand **************************************************************** + *****************************************************************************/ + +const GUID CLSID_ITaskBand = { 0x68284FAA, 0x6A48, 0x11D0, { 0x8C, 0x78, 0x00, 0xC0, 0x4F, 0xD9, 0x18, 0xB4 } }; + +class ITaskBandImpl : + public CComCoClass, + public CComObjectRootEx, + public IObjectWithSite, + public ITaskBand, + public IDeskBand, + public IDeskBar, + public IPersistStream, + public IWinEventHandler, + public IOleCommandTarget +{ + CComPtr Tray; + CComPtr punkSite; + + HWND hWnd; + DWORD dwBandID; + +public: + ITaskBandImpl() : + hWnd(NULL), + dwBandID(0) + { + + } + + virtual ~ITaskBandImpl() { } + + virtual HRESULT STDMETHODCALLTYPE GetRebarBandID( + OUT DWORD *pdwBandID) + { + if (dwBandID != (DWORD) -1) + { + if (pdwBandID != NULL) + *pdwBandID = dwBandID; + + return S_OK; + } + + return E_FAIL; + } + + /*****************************************************************************/ + + virtual HRESULT STDMETHODCALLTYPE GetWindow( + OUT HWND *phwnd) + { + + /* NOTE: We have to return the tray window here so that ITaskBarClient + knows the parent window of the Rebar control it creates when + calling ITaskBarClient::SetDeskBarSite()! However, once we + created a window we return the task switch window! */ + if (hWnd != NULL) + *phwnd = hWnd; + else + *phwnd = Tray->GetHWND(); + + TRACE("ITaskBand::GetWindow(0x%p->0x%p)\n", phwnd, *phwnd); + + if (*phwnd != NULL) + return S_OK; + + return E_FAIL; + } + + virtual HRESULT STDMETHODCALLTYPE ContextSensitiveHelp( + IN BOOL fEnterMode) + { + /* FIXME: Implement */ + return E_NOTIMPL; + } + + virtual HRESULT STDMETHODCALLTYPE ShowDW( + IN BOOL bShow) + { + /* We don't do anything... */ + return S_OK; + } + + virtual HRESULT STDMETHODCALLTYPE CloseDW( + IN DWORD dwReserved) + { + /* We don't do anything... */ + return S_OK; + } + + virtual HRESULT STDMETHODCALLTYPE ResizeBorderDW( + LPCRECT prcBorder, + IUnknown *punkToolbarSite, + BOOL fReserved) + { + /* No need to implement this method */ + return E_NOTIMPL; + } + + virtual HRESULT STDMETHODCALLTYPE GetBandInfo( + IN DWORD dwBandID, + IN DWORD dwViewMode, + IN OUT DESKBANDINFO *pdbi) + { + TRACE("ITaskBand::GetBandInfo(0x%x,0x%x,0x%p) hWnd=0x%p\n", dwBandID, dwViewMode, pdbi, hWnd); + + if (hWnd != NULL) + { + /* The task band never has a title */ + pdbi->dwMask &= ~DBIM_TITLE; + + /* NOTE: We don't return DBIMF_UNDELETEABLE here, the band site will + handle us differently and add this flag for us. The reason for + this is future changes that might allow it to be deletable. + We want the band site to be in charge of this decision rather + the band itself! */ + /* FIXME: What about DBIMF_NOGRIPPER and DBIMF_ALWAYSGRIPPER */ + pdbi->dwModeFlags = DBIMF_VARIABLEHEIGHT; + + if (dwViewMode & DBIF_VIEWMODE_VERTICAL) + { + pdbi->ptIntegral.y = 1; + pdbi->ptMinSize.y = 1; + /* FIXME: Get the button metrics from the task bar object!!! */ + pdbi->ptMinSize.x = (3 * GetSystemMetrics(SM_CXEDGE) / 2) + /* FIXME: Might be wrong if only one column! */ + GetSystemMetrics(SM_CXSIZE) + (2 * GetSystemMetrics(SM_CXEDGE)); /* FIXME: Min button size, query!!! */ + } + else + { + pdbi->ptMinSize.y = GetSystemMetrics(SM_CYSIZE) + (2 * GetSystemMetrics(SM_CYEDGE)); /* FIXME: Query */ + pdbi->ptIntegral.y = pdbi->ptMinSize.y + (3 * GetSystemMetrics(SM_CYEDGE) / 2); /* FIXME: Query metrics */ + /* We're not going to allow task bands where not even the minimum button size fits into the band */ + pdbi->ptMinSize.x = pdbi->ptIntegral.y; + } + + /* Ignored: pdbi->ptMaxSize.x */ + pdbi->ptMaxSize.y = -1; + + /* FIXME: We should query the height from the task bar object!!! */ + pdbi->ptActual.y = GetSystemMetrics(SM_CYSIZE) + (2 * GetSystemMetrics(SM_CYEDGE)); + + /* Save the band ID for future use in case we need to check whether a given band + is the task band */ + this->dwBandID = dwBandID; + + TRACE("H: %d, Min: %d,%d, Integral.y: %d Actual: %d,%d\n", (dwViewMode & DBIF_VIEWMODE_VERTICAL) == 0, + pdbi->ptMinSize.x, pdbi->ptMinSize.y, pdbi->ptIntegral.y, + pdbi->ptActual.x, pdbi->ptActual.y); + + return S_OK; + } + + return E_FAIL; + } + + /*****************************************************************************/ + // *** IOleCommandTarget methods *** + virtual HRESULT STDMETHODCALLTYPE QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD prgCmds [], OLECMDTEXT *pCmdText) + { + UNIMPLEMENTED; + return E_NOTIMPL; + } + + virtual HRESULT STDMETHODCALLTYPE Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut) + { + if (IsEqualIID(*pguidCmdGroup, IID_IBandSite)) + { + return S_OK; + } + + if (IsEqualIID(*pguidCmdGroup, IID_IDeskBand)) + { + return S_OK; + } + + UNIMPLEMENTED; + return E_NOTIMPL; + } + + /*****************************************************************************/ + + virtual HRESULT STDMETHODCALLTYPE SetClient( + IN IUnknown *punkClient) + { + TRACE("IDeskBar::SetClient(0x%p)\n", punkClient); + return E_NOTIMPL; + } + + virtual HRESULT STDMETHODCALLTYPE GetClient( + OUT IUnknown **ppunkClient) + { + TRACE("IDeskBar::GetClient(0x%p)\n", ppunkClient); + return E_NOTIMPL; + } + + virtual HRESULT STDMETHODCALLTYPE OnPosRectChangeDB( + IN RECT *prc) + { + TRACE("IDeskBar::OnPosRectChangeDB(0x%p=(%d,%d,%d,%d))\n", prc, prc->left, prc->top, prc->right, prc->bottom); + if (prc->bottom - prc->top == 0) + return S_OK; + + return S_FALSE; + } + + /*****************************************************************************/ + + virtual HRESULT STDMETHODCALLTYPE GetClassID( + OUT CLSID *pClassID) + { + TRACE("ITaskBand::GetClassID(0x%p)\n", pClassID); + /* We're going to return the (internal!) CLSID of the task band interface */ + *pClassID = CLSID_ITaskBand; + return S_OK; + } + + virtual HRESULT STDMETHODCALLTYPE IsDirty() + { + /* The object hasn't changed since the last save! */ + return S_FALSE; + } + + virtual HRESULT STDMETHODCALLTYPE Load( + IN IStream *pStm) + { + TRACE("ITaskBand::Load called\n"); + /* Nothing to do */ + return S_OK; + } + + virtual HRESULT STDMETHODCALLTYPE Save( + IN IStream *pStm, + IN BOOL fClearDirty) + { + /* Nothing to do */ + return S_OK; + } + + virtual HRESULT STDMETHODCALLTYPE GetSizeMax( + OUT ULARGE_INTEGER *pcbSize) + { + TRACE("ITaskBand::GetSizeMax called\n"); + /* We don't need any space for the task band */ + pcbSize->QuadPart = 0; + return S_OK; + } + + /*****************************************************************************/ + + virtual HRESULT STDMETHODCALLTYPE SetSite(IUnknown *pUnkSite) + { + HRESULT hRet = E_FAIL; + + TRACE("ITaskBand::SetSite(0x%p)\n", pUnkSite); + + /* Release the current site */ + if (punkSite != NULL) + { + punkSite->Release(); + } + + punkSite = NULL; + hWnd = NULL; + + if (pUnkSite != NULL) + { + IOleWindow *OleWindow; + + /* Check if the site supports IOleWindow */ + hRet = pUnkSite->QueryInterface(IID_PPV_ARG(IOleWindow, &OleWindow)); + if (SUCCEEDED(hRet)) + { + HWND hWndParent = NULL; + + hRet = OleWindow->GetWindow( + &hWndParent); + if (SUCCEEDED(hRet)) + { + /* Attempt to create the task switch window */ + + TRACE("CreateTaskSwitchWnd(Parent: 0x%p)\n", hWndParent); + hWnd = CreateTaskSwitchWnd(hWndParent, Tray); + if (hWnd != NULL) + { + punkSite = pUnkSite; + hRet = S_OK; + } + else + { + TRACE("CreateTaskSwitchWnd() failed!\n"); + OleWindow->Release(); + hRet = E_FAIL; + } + } + else + OleWindow->Release(); + } + else + TRACE("Querying IOleWindow failed: 0x%x\n", hRet); + } + + return hRet; + } + + virtual HRESULT STDMETHODCALLTYPE GetSite( + IN REFIID riid, + OUT VOID **ppvSite) + { + TRACE("ITaskBand::GetSite(0x%p,0x%p)\n", riid, ppvSite); + + if (punkSite != NULL) + { + return punkSite->QueryInterface(riid, ppvSite); + } + + *ppvSite = NULL; + return E_FAIL; + } + + /*****************************************************************************/ + + virtual HRESULT STDMETHODCALLTYPE ProcessMessage( + IN HWND hWnd, + IN UINT uMsg, + IN WPARAM wParam, + IN LPARAM lParam, + OUT LRESULT *plrResult) + { + TRACE("ITaskBand: IWinEventHandler::ProcessMessage(0x%p, 0x%x, 0x%p, 0x%p, 0x%p)\n", hWnd, uMsg, wParam, lParam, plrResult); + return E_NOTIMPL; + } + + virtual HRESULT STDMETHODCALLTYPE ContainsWindow( + IN HWND hWnd) + { + if (hWnd == hWnd || + IsChild(hWnd, hWnd)) + { + TRACE("ITaskBand::ContainsWindow(0x%p) returns S_OK\n", hWnd); + return S_OK; + } + + return S_FALSE; + } + + virtual HRESULT STDMETHODCALLTYPE OnWinEvent(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *theResult) + { + UNIMPLEMENTED; + return E_NOTIMPL; + } + + virtual HRESULT STDMETHODCALLTYPE IsWindowOwner(HWND hWnd) + { + return (hWnd == this->hWnd) ? S_OK : S_FALSE; + } + + /*****************************************************************************/ + + HRESULT STDMETHODCALLTYPE _Init(IN OUT ITrayWindow *tray) + { + Tray = tray; + dwBandID = (DWORD) -1; + return S_OK; + } + + DECLARE_NOT_AGGREGATABLE(ITaskBandImpl) + + DECLARE_PROTECT_FINAL_CONSTRUCT() + BEGIN_COM_MAP(ITaskBandImpl) + COM_INTERFACE_ENTRY2_IID(IID_IOleWindow, IOleWindow, IDeskBand) + COM_INTERFACE_ENTRY_IID(IID_IDeskBand, IDeskBand) + COM_INTERFACE_ENTRY_IID(IID_IObjectWithSite, IObjectWithSite) + COM_INTERFACE_ENTRY_IID(IID_IPersist, IPersist) + COM_INTERFACE_ENTRY_IID(IID_IPersistStream, IPersistStream) + COM_INTERFACE_ENTRY_IID(IID_IWinEventHandler, IWinEventHandler) + COM_INTERFACE_ENTRY_IID(IID_IOleCommandTarget, IOleCommandTarget) + END_COM_MAP() +}; + +ITaskBand * CreateTaskBand(IN OUT ITrayWindow *Tray) +{ + HRESULT hr; + + ITaskBandImpl * tb = new CComObject(); + + if (!tb) + return NULL; + + hr = tb->AddRef(); + + hr = tb->_Init(Tray); + + if (FAILED_UNEXPECTEDLY(hr)) + tb->Release(); + + return tb; +} diff --git a/base/shell/explorer-new/taskswnd.c b/base/shell/explorer-new/taskswnd.c deleted file mode 100644 index fe3f896d90b..00000000000 --- a/base/shell/explorer-new/taskswnd.c +++ /dev/null @@ -1,2196 +0,0 @@ -/* - * ReactOS Explorer - * - * Copyright 2006 - 2007 Thomas Weidenmueller - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "precomp.h" - -/* Set DUMP_TASKS to 1 to enable a dump of the tasks and task groups every - 5 seconds */ -#define DUMP_TASKS 0 - -static const TCHAR szTaskSwitchWndClass[] = TEXT("MSTaskSwWClass"); -static const TCHAR szRunningApps[] = TEXT("Running Applications"); - -typedef struct _TASK_GROUP -{ - /* We have to use a linked list instead of an array so we don't have to - update all pointers to groups in the task item array when removing - groups. */ - struct _TASK_GROUP *Next; - - DWORD dwTaskCount; - DWORD dwProcessId; - INT Index; - union - { - DWORD dwFlags; - struct - { - - DWORD IsCollapsed : 1; - }; - }; -} TASK_GROUP, *PTASK_GROUP; - -typedef struct _TASK_ITEM -{ - HWND hWnd; - PTASK_GROUP Group; - INT Index; - INT IconIndex; - - - - union - { - DWORD dwFlags; - struct - { - - /* IsFlashing is TRUE when the task bar item should be flashing. */ - DWORD IsFlashing : 1; - - /* RenderFlashed is only TRUE if the task bar item should be - drawn with a flash. */ - DWORD RenderFlashed : 1; - }; - }; -} TASK_ITEM, *PTASK_ITEM; - -#define TASK_ITEM_ARRAY_ALLOC 64 - -typedef struct _TASK_SWITCH_WND -{ - HWND hWnd; - HWND hWndNotify; - - UINT ShellHookMsg; - ITrayWindow *Tray; - - PTASK_GROUP TaskGroups; - - WORD TaskItemCount; - WORD AllocatedTaskItems; - PTASK_ITEM TaskItems; - PTASK_ITEM ActiveTaskItem; - - HTHEME TaskBandTheme; - HWND hWndToolbar; - UINT TbButtonsPerLine; - WORD ToolbarBtnCount; - HIMAGELIST TaskIcons; - - union - { - DWORD dwFlags; - struct - { - DWORD IsGroupingEnabled : 1; - DWORD IsDestroying : 1; - DWORD IsToolbarSubclassed : 1; - }; - }; - - SIZE ButtonSize; - TCHAR szBuf[255]; -} TASK_SWITCH_WND, *PTASK_SWITCH_WND; - -#define TSW_TOOLBAR_SUBCLASS_ID 1 - -#define MAX_TASKS_COUNT (0x7FFF) - -static VOID TaskSwitchWnd_UpdateButtonsSize(IN OUT PTASK_SWITCH_WND This, - IN BOOL bRedrawDisabled); - -static LPTSTR -TaskSwitchWnd_GetWndTextFromTaskItem(IN OUT PTASK_SWITCH_WND This, - IN PTASK_ITEM TaskItem) -{ - /* Get the window text without sending a message so we don't hang if an - application isn't responding! */ - if (InternalGetWindowText(TaskItem->hWnd, - This->szBuf, - sizeof(This->szBuf) / sizeof(This->szBuf[0])) > 0) - { - return This->szBuf; - } - - return NULL; -} - - -#if DUMP_TASKS != 0 -static VOID -TaskSwitchWnd_DumpTasks(IN OUT PTASK_SWITCH_WND This) -{ - PTASK_GROUP CurrentGroup; - PTASK_ITEM CurrentTaskItem, LastTaskItem; - - TRACE("Tasks dump:\n"); - if (This->IsGroupingEnabled) - { - CurrentGroup = This->TaskGroups; - while (CurrentGroup != NULL) - { - TRACE("- Group PID: 0x%p Tasks: %d Index: %d\n", CurrentGroup->dwProcessId, CurrentGroup->dwTaskCount, CurrentGroup->Index); - - CurrentTaskItem = This->TaskItems; - LastTaskItem = CurrentTaskItem + This->TaskItemCount; - while (CurrentTaskItem != LastTaskItem) - { - if (CurrentTaskItem->Group == CurrentGroup) - { - TRACE(" + Task hwnd: 0x%p Index: %d\n", CurrentTaskItem->hWnd, CurrentTaskItem->Index); - } - CurrentTaskItem++; - } - - CurrentGroup = CurrentGroup->Next; - } - - CurrentTaskItem = This->TaskItems; - LastTaskItem = CurrentTaskItem + This->TaskItemCount; - while (CurrentTaskItem != LastTaskItem) - { - if (CurrentTaskItem->Group == NULL) - { - TRACE("- Task hwnd: 0x%p Index: %d\n", CurrentTaskItem->hWnd, CurrentTaskItem->Index); - } - CurrentTaskItem++; - } - } - else - { - CurrentTaskItem = This->TaskItems; - LastTaskItem = CurrentTaskItem + This->TaskItemCount; - while (CurrentTaskItem != LastTaskItem) - { - TRACE("- Task hwnd: 0x%p Index: %d\n", CurrentTaskItem->hWnd, CurrentTaskItem->Index); - CurrentTaskItem++; - } - } -} -#endif - -static VOID -TaskSwitchWnd_BeginUpdate(IN OUT PTASK_SWITCH_WND This) -{ - SendMessage(This->hWndToolbar, - WM_SETREDRAW, - FALSE, - 0); -} - -static VOID -TaskSwitchWnd_EndUpdate(IN OUT PTASK_SWITCH_WND This) -{ - SendMessage(This->hWndToolbar, - WM_SETREDRAW, - TRUE, - 0); - InvalidateRect(This->hWndToolbar, - NULL, - TRUE); -} - -static BOOL -TaskSwitchWnd_SetToolbarButtonCommandId(IN OUT PTASK_SWITCH_WND This, - IN INT iButtonIndex, - IN INT iCommandId) -{ - TBBUTTONINFO tbbi; - - tbbi.cbSize = sizeof(tbbi); - tbbi.dwMask = TBIF_BYINDEX | TBIF_COMMAND; - tbbi.idCommand = iCommandId; - - return SendMessage(This->hWndToolbar, - TB_SETBUTTONINFO, - (WPARAM)iButtonIndex, - (LPARAM)&tbbi) != 0; -} - -static VOID -TaskSwitchWnd_UpdateIndexesAfterButtonInserted(IN OUT PTASK_SWITCH_WND This, - IN INT iIndex) -{ - PTASK_GROUP CurrentGroup; - PTASK_ITEM CurrentTaskItem, LastTaskItem; - INT NewIndex; - - if (This->IsGroupingEnabled) - { - /* Update all affected groups */ - CurrentGroup = This->TaskGroups; - while (CurrentGroup != NULL) - { - if (CurrentGroup->IsCollapsed && - CurrentGroup->Index >= iIndex) - { - /* Update the toolbar buttons */ - NewIndex = CurrentGroup->Index + 1; - if (TaskSwitchWnd_SetToolbarButtonCommandId(This, - CurrentGroup->Index + 1, - NewIndex)) - { - CurrentGroup->Index = NewIndex; - } - else - CurrentGroup->Index = -1; - } - - CurrentGroup = CurrentGroup->Next; - } - } - - /* Update all affected task items */ - CurrentTaskItem = This->TaskItems; - LastTaskItem = CurrentTaskItem + This->TaskItemCount; - while (CurrentTaskItem != LastTaskItem) - { - CurrentGroup = CurrentTaskItem->Group; - if (CurrentGroup != NULL) - { - if (!CurrentGroup->IsCollapsed && - CurrentTaskItem->Index >= iIndex) - { - goto UpdateTaskItemBtn; - } - } - else if (CurrentTaskItem->Index >= iIndex) - { -UpdateTaskItemBtn: - /* Update the toolbar buttons */ - NewIndex = CurrentTaskItem->Index + 1; - if (TaskSwitchWnd_SetToolbarButtonCommandId(This, - CurrentTaskItem->Index + 1, - NewIndex)) - { - CurrentTaskItem->Index = NewIndex; - } - else - CurrentTaskItem->Index = -1; - } - - CurrentTaskItem++; - } -} - -static VOID -TaskSwitchWnd_UpdateIndexesAfterButtonDeleted(IN OUT PTASK_SWITCH_WND This, - IN INT iIndex) -{ - PTASK_GROUP CurrentGroup; - PTASK_ITEM CurrentTaskItem, LastTaskItem; - INT NewIndex; - - if (This->IsGroupingEnabled) - { - /* Update all affected groups */ - CurrentGroup = This->TaskGroups; - while (CurrentGroup != NULL) - { - if (CurrentGroup->IsCollapsed && - CurrentGroup->Index > iIndex) - { - /* Update the toolbar buttons */ - NewIndex = CurrentGroup->Index - 1; - if (TaskSwitchWnd_SetToolbarButtonCommandId(This, - CurrentGroup->Index - 1, - NewIndex)) - { - CurrentGroup->Index = NewIndex; - } - else - CurrentGroup->Index = -1; - } - - CurrentGroup = CurrentGroup->Next; - } - } - - /* Update all affected task items */ - CurrentTaskItem = This->TaskItems; - LastTaskItem = CurrentTaskItem + This->TaskItemCount; - while (CurrentTaskItem != LastTaskItem) - { - CurrentGroup = CurrentTaskItem->Group; - if (CurrentGroup != NULL) - { - if (!CurrentGroup->IsCollapsed && - CurrentTaskItem->Index > iIndex) - { - goto UpdateTaskItemBtn; - } - } - else if (CurrentTaskItem->Index > iIndex) - { -UpdateTaskItemBtn: - /* Update the toolbar buttons */ - NewIndex = CurrentTaskItem->Index - 1; - if (TaskSwitchWnd_SetToolbarButtonCommandId(This, - CurrentTaskItem->Index - 1, - NewIndex)) - { - CurrentTaskItem->Index = NewIndex; - } - else - CurrentTaskItem->Index = -1; - } - - CurrentTaskItem++; - } -} - -static INT -TaskSwitchWnd_UpdateTaskGroupButton(IN OUT PTASK_SWITCH_WND This, - IN PTASK_GROUP TaskGroup) -{ - ASSERT(TaskGroup->Index >= 0); - - /* FIXME: Implement */ - - return TaskGroup->Index; -} - -static VOID -TaskSwitchWnd_ExpandTaskGroup(IN OUT PTASK_SWITCH_WND This, - IN PTASK_GROUP TaskGroup) -{ - ASSERT(TaskGroup->dwTaskCount > 0); - ASSERT(TaskGroup->IsCollapsed); - ASSERT(TaskGroup->Index >= 0); - - /* FIXME: Implement */ -} - -static HICON -TaskSwitchWnd_GetWndIcon(HWND hwnd) -{ - HICON hIcon = 0; - - SendMessageTimeout(hwnd, WM_GETICON, ICON_SMALL2, 0, SMTO_ABORTIFHUNG, 1000, (PDWORD_PTR)&hIcon); - - if (!hIcon) - SendMessageTimeout(hwnd, WM_GETICON, ICON_SMALL, 0, SMTO_ABORTIFHUNG, 1000, (PDWORD_PTR)&hIcon); - - if (!hIcon) - SendMessageTimeout(hwnd, WM_GETICON, ICON_BIG, 0, SMTO_ABORTIFHUNG, 1000, (PDWORD_PTR)&hIcon); - - if (!hIcon) - hIcon = (HICON)GetClassLongPtr(hwnd, GCL_HICONSM); - - if (!hIcon) - hIcon = (HICON)GetClassLongPtr(hwnd, GCL_HICON); - - return hIcon; -} -static INT -TaskSwitchWnd_UpdateTaskItemButton(IN OUT PTASK_SWITCH_WND This, - IN PTASK_ITEM TaskItem) -{ - TBBUTTONINFO tbbi; - HICON icon; - - ASSERT(TaskItem->Index >= 0); - - tbbi.cbSize = sizeof(tbbi); - tbbi.dwMask = TBIF_BYINDEX | TBIF_STATE | TBIF_TEXT | TBIF_IMAGE; - tbbi.fsState = TBSTATE_ENABLED; - if (This->ActiveTaskItem == TaskItem) - tbbi.fsState |= TBSTATE_CHECKED; - - if (TaskItem->RenderFlashed) - tbbi.fsState |= TBSTATE_MARKED; - - /* Check if we're updating a button that is the last one in the - line. If so, we need to set the TBSTATE_WRAP flag! */ - if (This->TbButtonsPerLine != 0 && - (TaskItem->Index + 1) % This->TbButtonsPerLine == 0) - { - tbbi.fsState |= TBSTATE_WRAP; - } - - tbbi.pszText = TaskSwitchWnd_GetWndTextFromTaskItem(This, - TaskItem); - - icon = TaskSwitchWnd_GetWndIcon(TaskItem->hWnd); - TaskItem->IconIndex = ImageList_ReplaceIcon(This->TaskIcons, - TaskItem->IconIndex, - icon); - tbbi.iImage = TaskItem->IconIndex; - - if (!SendMessage(This->hWndToolbar, - TB_SETBUTTONINFO, - (WPARAM)TaskItem->Index, - (LPARAM)&tbbi)) - { - TaskItem->Index = -1; - return -1; - } - - TRACE("Updated button %d for hwnd 0x%p\n", TaskItem->Index, TaskItem->hWnd); - return TaskItem->Index; -} - -static VOID -TaskSwitchWnd_RemoveIcon(IN OUT PTASK_SWITCH_WND This, - IN PTASK_ITEM TaskItem) -{ - TBBUTTONINFO tbbi; - PTASK_ITEM currentTaskItem, LastItem; - - if (TaskItem->IconIndex == -1) - return; - - tbbi.cbSize = sizeof(tbbi); - tbbi.dwMask = TBIF_IMAGE; - - currentTaskItem = This->TaskItems; - LastItem = currentTaskItem + This->TaskItemCount; - while (currentTaskItem != LastItem) - { - if (currentTaskItem->IconIndex > TaskItem->IconIndex) - { - currentTaskItem->IconIndex--; - tbbi.iImage = currentTaskItem->IconIndex; - - SendMessage(This->hWndToolbar, - TB_SETBUTTONINFO, - currentTaskItem->Index, - (LPARAM)&tbbi); - } - currentTaskItem++; - } - - ImageList_Remove(This->TaskIcons, TaskItem->IconIndex); -} - -static PTASK_ITEM -TaskSwitchWnd_FindLastTaskItemOfGroup(IN OUT PTASK_SWITCH_WND This, - IN PTASK_GROUP TaskGroup OPTIONAL, - IN PTASK_ITEM NewTaskItem OPTIONAL) -{ - PTASK_ITEM TaskItem, LastTaskItem, FoundTaskItem = NULL; - DWORD dwTaskCount; - - ASSERT(This->IsGroupingEnabled); - - TaskItem = This->TaskItems; - LastTaskItem = TaskItem + This->TaskItemCount; - - dwTaskCount = (TaskGroup != NULL ? TaskGroup->dwTaskCount : MAX_TASKS_COUNT); - - ASSERT(dwTaskCount > 0); - - while (TaskItem != LastTaskItem) - { - if (TaskItem->Group == TaskGroup) - { - if ((NewTaskItem != NULL && TaskItem != NewTaskItem) || NewTaskItem == NULL) - { - FoundTaskItem = TaskItem; - } - - if (--dwTaskCount == 0) - { - /* We found the last task item in the group! */ - break; - } - } - - TaskItem++; - } - - return FoundTaskItem; -} - -static INT -TaskSwitchWnd_CalculateTaskItemNewButtonIndex(IN OUT PTASK_SWITCH_WND This, - IN PTASK_ITEM TaskItem) -{ - PTASK_GROUP TaskGroup; - PTASK_ITEM LastTaskItem; - - /* NOTE: This routine assumes that the group is *not* collapsed! */ - - TaskGroup = TaskItem->Group; - if (This->IsGroupingEnabled) - { - if (TaskGroup != NULL) - { - ASSERT(TaskGroup->Index < 0); - ASSERT(!TaskGroup->IsCollapsed); - - if (TaskGroup->dwTaskCount > 1) - { - LastTaskItem = TaskSwitchWnd_FindLastTaskItemOfGroup(This, - TaskGroup, - TaskItem); - if (LastTaskItem != NULL) - { - /* Since the group is expanded the task items must have an index */ - ASSERT(LastTaskItem->Index >= 0); - - return LastTaskItem->Index + 1; - } - } - } - else - { - /* Find the last NULL group button. NULL groups are added at the end of the - task item list when grouping is enabled */ - LastTaskItem = TaskSwitchWnd_FindLastTaskItemOfGroup(This, - NULL, - TaskItem); - if (LastTaskItem != NULL) - { - ASSERT(LastTaskItem->Index >= 0); - - return LastTaskItem->Index + 1; - } - } - } - - return This->ToolbarBtnCount; -} - -static INT -TaskSwitchWnd_AddTaskItemButton(IN OUT PTASK_SWITCH_WND This, - IN OUT PTASK_ITEM TaskItem) -{ - TBBUTTON tbBtn; - INT iIndex; - HICON icon; - - if (TaskItem->Index >= 0) - { - return TaskSwitchWnd_UpdateTaskItemButton(This, - TaskItem); - } - - if (TaskItem->Group != NULL && - TaskItem->Group->IsCollapsed) - { - /* The task group is collapsed, we only need to update the group button */ - return TaskSwitchWnd_UpdateTaskGroupButton(This, - TaskItem->Group); - } - - icon = TaskSwitchWnd_GetWndIcon(TaskItem->hWnd); - TaskItem->IconIndex = ImageList_AddIcon(This->TaskIcons, icon); - - tbBtn.iBitmap = TaskItem->IconIndex; - tbBtn.fsState = TBSTATE_ENABLED | TBSTATE_ELLIPSES; - tbBtn.fsStyle = BTNS_CHECK | BTNS_NOPREFIX | BTNS_SHOWTEXT; - tbBtn.dwData = TaskItem->Index; - - tbBtn.iString = (DWORD_PTR)TaskSwitchWnd_GetWndTextFromTaskItem(This, - TaskItem); - - /* Find out where to insert the new button */ - iIndex = TaskSwitchWnd_CalculateTaskItemNewButtonIndex(This, - TaskItem); - ASSERT(iIndex >= 0); - tbBtn.idCommand = iIndex; - - TaskSwitchWnd_BeginUpdate(This); - - if (SendMessage(This->hWndToolbar, - TB_INSERTBUTTON, - (WPARAM)iIndex, - (LPARAM)&tbBtn)) - { - TaskSwitchWnd_UpdateIndexesAfterButtonInserted(This, - iIndex); - - TRACE("Added button %d for hwnd 0x%p\n", iIndex, TaskItem->hWnd); - - TaskItem->Index = iIndex; - This->ToolbarBtnCount++; - - /* Update button sizes and fix the button wrapping */ - TaskSwitchWnd_UpdateButtonsSize(This, - TRUE); - return iIndex; - } - - TaskSwitchWnd_EndUpdate(This); - - return -1; -} - -static BOOL -TaskSwitchWnd_DeleteTaskItemButton(IN OUT PTASK_SWITCH_WND This, - IN OUT PTASK_ITEM TaskItem) -{ - PTASK_GROUP TaskGroup; - INT iIndex; - - TaskGroup = TaskItem->Group; - - if (TaskItem->Index >= 0) - { - if ((TaskGroup != NULL && !TaskGroup->IsCollapsed) || - TaskGroup == NULL) - { - TaskSwitchWnd_BeginUpdate(This); - - TaskSwitchWnd_RemoveIcon(This, TaskItem); - iIndex = TaskItem->Index; - if (SendMessage(This->hWndToolbar, - TB_DELETEBUTTON, - (WPARAM)iIndex, - 0)) - { - TaskItem->Index = -1; - This->ToolbarBtnCount--; - - TaskSwitchWnd_UpdateIndexesAfterButtonDeleted(This, - iIndex); - - /* Update button sizes and fix the button wrapping */ - TaskSwitchWnd_UpdateButtonsSize(This, - TRUE); - return TRUE; - } - - TaskSwitchWnd_EndUpdate(This); - } - } - - return FALSE; -} - -static PTASK_GROUP -TaskSwitchWnd_AddToTaskGroup(IN OUT PTASK_SWITCH_WND This, - IN HWND hWnd) -{ - DWORD dwProcessId; - PTASK_GROUP TaskGroup, *PrevLink; - - if (!GetWindowThreadProcessId(hWnd, - &dwProcessId)) - { - TRACE("Cannot get process id of hwnd 0x%p\n", hWnd); - return NULL; - } - - /* Try to find an existing task group */ - TaskGroup = This->TaskGroups; - PrevLink = &This->TaskGroups; - while (TaskGroup != NULL) - { - if (TaskGroup->dwProcessId == dwProcessId) - { - TaskGroup->dwTaskCount++; - return TaskGroup; - } - - PrevLink = &TaskGroup->Next; - TaskGroup = TaskGroup->Next; - } - - /* Allocate a new task group */ - TaskGroup = HeapAlloc(hProcessHeap, - HEAP_ZERO_MEMORY, - sizeof(*TaskGroup)); - if (TaskGroup != NULL) - { - TaskGroup->dwTaskCount = 1; - TaskGroup->dwProcessId = dwProcessId; - TaskGroup->Index = -1; - - /* Add the task group to the list */ - *PrevLink = TaskGroup; - } - - return TaskGroup; -} - -static VOID -TaskSwitchWnd_RemoveTaskFromTaskGroup(IN OUT PTASK_SWITCH_WND This, - IN OUT PTASK_ITEM TaskItem) -{ - PTASK_GROUP TaskGroup, CurrentGroup, *PrevLink; - - TaskGroup = TaskItem->Group; - if (TaskGroup != NULL) - { - DWORD dwNewTaskCount = --TaskGroup->dwTaskCount; - if (dwNewTaskCount == 0) - { - /* Find the previous pointer in the chain */ - CurrentGroup = This->TaskGroups; - PrevLink = &This->TaskGroups; - while (CurrentGroup != TaskGroup) - { - PrevLink = &CurrentGroup->Next; - CurrentGroup = CurrentGroup->Next; - } - - /* Remove the group from the list */ - ASSERT(TaskGroup == CurrentGroup); - *PrevLink = TaskGroup->Next; - - /* Free the task group */ - HeapFree(hProcessHeap, - 0, - TaskGroup); - } - else if (TaskGroup->IsCollapsed && - TaskGroup->Index >= 0) - { - if (dwNewTaskCount > 1) - { - /* FIXME: Check if we should expand the group */ - /* Update the task group button */ - TaskSwitchWnd_UpdateTaskGroupButton(This, - TaskGroup); - } - else - { - /* Expand the group of one task button to a task button */ - TaskSwitchWnd_ExpandTaskGroup(This, - TaskGroup); - } - } - } -} - -static PTASK_ITEM -TaskSwitchWnd_FindTaskItem(IN OUT PTASK_SWITCH_WND This, - IN HWND hWnd) -{ - PTASK_ITEM TaskItem, LastItem; - - TaskItem = This->TaskItems; - LastItem = TaskItem + This->TaskItemCount; - while (TaskItem != LastItem) - { - if (TaskItem->hWnd == hWnd) - return TaskItem; - - TaskItem++; - } - - return NULL; -} - -static PTASK_ITEM -TaskSwitchWnd_FindOtherTaskItem(IN OUT PTASK_SWITCH_WND This, - IN HWND hWnd) -{ - PTASK_ITEM LastItem, TaskItem; - PTASK_GROUP TaskGroup; - DWORD dwProcessId; - - if (!GetWindowThreadProcessId(hWnd, - &dwProcessId)) - { - return NULL; - } - - /* Try to find another task that belongs to the same - process as the given window */ - TaskItem = This->TaskItems; - LastItem = TaskItem + This->TaskItemCount; - while (TaskItem != LastItem) - { - TaskGroup = TaskItem->Group; - if (TaskGroup != NULL) - { - if (TaskGroup->dwProcessId == dwProcessId) - return TaskItem; - } - else - { - DWORD dwProcessIdTask; - - if (GetWindowThreadProcessId(TaskItem->hWnd, - &dwProcessIdTask) && - dwProcessIdTask == dwProcessId) - { - return TaskItem; - } - } - - TaskItem++; - } - - return NULL; -} - -static PTASK_ITEM -TaskSwitchWnd_AllocTaskItem(IN OUT PTASK_SWITCH_WND This) -{ - if (This->TaskItemCount >= MAX_TASKS_COUNT) - { - /* We need the most significant bit in 16 bit command IDs to indicate whether it - is a task group or task item. WM_COMMAND limits command IDs to 16 bits! */ - return NULL; - } - - ASSERT(This->AllocatedTaskItems >= This->TaskItemCount); - - if (This->TaskItemCount == 0) - { - This->TaskItems = HeapAlloc(hProcessHeap, - 0, - TASK_ITEM_ARRAY_ALLOC * sizeof(*This->TaskItems)); - if (This->TaskItems != NULL) - { - This->AllocatedTaskItems = TASK_ITEM_ARRAY_ALLOC; - } - else - return NULL; - } - else if (This->TaskItemCount >= This->AllocatedTaskItems) - { - PTASK_ITEM NewArray; - SIZE_T NewArrayLength, ActiveTaskItemIndex; - - NewArrayLength = This->AllocatedTaskItems + TASK_ITEM_ARRAY_ALLOC; - - NewArray = HeapReAlloc(hProcessHeap, - 0, - This->TaskItems, - NewArrayLength * sizeof(*This->TaskItems)); - if (NewArray != NULL) - { - if (This->ActiveTaskItem != NULL) - { - /* Fixup the ActiveTaskItem pointer */ - ActiveTaskItemIndex = This->ActiveTaskItem - This->TaskItems; - This->ActiveTaskItem = NewArray + ActiveTaskItemIndex; - } - This->AllocatedTaskItems = (WORD)NewArrayLength; - This->TaskItems = NewArray; - } - else - return NULL; - } - - return This->TaskItems + This->TaskItemCount++; -} - -static VOID -TaskSwitchWnd_FreeTaskItem(IN OUT PTASK_SWITCH_WND This, - IN OUT PTASK_ITEM TaskItem) -{ - WORD wIndex; - - if (TaskItem == This->ActiveTaskItem) - This->ActiveTaskItem = NULL; - - wIndex = (WORD)(TaskItem - This->TaskItems); - if (wIndex + 1 < This->TaskItemCount) - { - MoveMemory(TaskItem, - TaskItem + 1, - (This->TaskItemCount - wIndex - 1) * sizeof(*TaskItem)); - } - - This->TaskItemCount--; -} - -static VOID -TaskSwitchWnd_DeleteTaskItem(IN OUT PTASK_SWITCH_WND This, - IN OUT PTASK_ITEM TaskItem) -{ - if (!This->IsDestroying) - { - /* Delete the task button from the toolbar */ - TaskSwitchWnd_DeleteTaskItemButton(This, - TaskItem); - } - - /* Remove the task from it's group */ - TaskSwitchWnd_RemoveTaskFromTaskGroup(This, - TaskItem); - - /* Free the task item */ - TaskSwitchWnd_FreeTaskItem(This, - TaskItem); -} - -static VOID -TaskSwitchWnd_CheckActivateTaskItem(IN OUT PTASK_SWITCH_WND This, - IN OUT PTASK_ITEM TaskItem) -{ - PTASK_ITEM CurrentTaskItem; - PTASK_GROUP TaskGroup = NULL; - - CurrentTaskItem = This->ActiveTaskItem; - - if (TaskItem != NULL) - TaskGroup = TaskItem->Group; - - if (This->IsGroupingEnabled && - TaskGroup != NULL && - TaskGroup->IsCollapsed) - { - /* FIXME */ - return; - } - - if (CurrentTaskItem != NULL) - { - PTASK_GROUP CurrentTaskGroup; - - if (CurrentTaskItem == TaskItem) - return; - - CurrentTaskGroup = CurrentTaskItem->Group; - - if (This->IsGroupingEnabled && - CurrentTaskGroup != NULL && - CurrentTaskGroup->IsCollapsed) - { - if (CurrentTaskGroup == TaskGroup) - return; - - /* FIXME */ - } - else - { - This->ActiveTaskItem = NULL; - if (CurrentTaskItem->Index >= 0) - { - TaskSwitchWnd_UpdateTaskItemButton(This, CurrentTaskItem); - } - } - } - - This->ActiveTaskItem = TaskItem; - - if (TaskItem != NULL && TaskItem->Index >= 0) - { - TaskSwitchWnd_UpdateTaskItemButton(This, TaskItem); - } - else if (TaskItem == NULL) - { - TRACE("Active TaskItem now NULL\n"); - } -} - -static PTASK_ITEM -FindTaskItemByIndex(IN OUT PTASK_SWITCH_WND This, - IN INT Index) -{ - PTASK_ITEM TaskItem, LastItem; - - TaskItem = This->TaskItems; - LastItem = TaskItem + This->TaskItemCount; - while (TaskItem != LastItem) - { - if (TaskItem->Index == Index) - return TaskItem; - - TaskItem++; - } - - return NULL; -} - -static PTASK_GROUP -FindTaskGroupByIndex(IN OUT PTASK_SWITCH_WND This, - IN INT Index) -{ - PTASK_GROUP CurrentGroup; - - CurrentGroup = This->TaskGroups; - while (CurrentGroup != NULL) - { - if (CurrentGroup->Index == Index) - break; - - CurrentGroup = CurrentGroup->Next; - } - - return CurrentGroup; -} - -static BOOL -TaskSwitchWnd_AddTask(IN OUT PTASK_SWITCH_WND This, - IN HWND hWnd) -{ - PTASK_ITEM TaskItem; - - if (!IsWindow(hWnd) || ITrayWindow_IsSpecialHWND(This->Tray, hWnd)) - return FALSE; - - TaskItem = TaskSwitchWnd_FindTaskItem(This, - hWnd); - if (TaskItem == NULL) - { - TRACE("Add window 0x%p\n", hWnd); - TaskItem = TaskSwitchWnd_AllocTaskItem(This); - if (TaskItem != NULL) - { - ZeroMemory(TaskItem, - sizeof(*TaskItem)); - TaskItem->hWnd = hWnd; - TaskItem->Index = -1; - TaskItem->Group = TaskSwitchWnd_AddToTaskGroup(This, - hWnd); - - if (!This->IsDestroying) - { - TaskSwitchWnd_AddTaskItemButton(This, - TaskItem); - } - } - } - - return TaskItem != NULL; -} - -static BOOL -TaskSwitchWnd_ActivateTaskItem(IN OUT PTASK_SWITCH_WND This, - IN OUT PTASK_ITEM TaskItem OPTIONAL) -{ - if (TaskItem != NULL) - { - TRACE("Activate window 0x%p on button %d\n", TaskItem->hWnd, TaskItem->Index); - } - - TaskSwitchWnd_CheckActivateTaskItem(This, TaskItem); - - return FALSE; -} - -static BOOL -TaskSwitchWnd_ActivateTask(IN OUT PTASK_SWITCH_WND This, - IN HWND hWnd) -{ - PTASK_ITEM TaskItem; - - if (!hWnd) - { - return TaskSwitchWnd_ActivateTaskItem(This, NULL); - } - - TaskItem = TaskSwitchWnd_FindTaskItem(This, - hWnd); - if (TaskItem == NULL) - { - TaskItem = TaskSwitchWnd_FindOtherTaskItem(This, - hWnd); - } - - if (TaskItem == NULL) - { - TRACE("Activate window 0x%p, could not find task\n", hWnd); - } - - return TaskSwitchWnd_ActivateTaskItem(This, TaskItem); -} - -static BOOL -TaskSwitchWnd_DeleteTask(IN OUT PTASK_SWITCH_WND This, - IN HWND hWnd) -{ - PTASK_ITEM TaskItem; - - TaskItem = TaskSwitchWnd_FindTaskItem(This, - hWnd); - if (TaskItem != NULL) - { - TRACE("Delete window 0x%p on button %d\n", hWnd, TaskItem->Index); - TaskSwitchWnd_DeleteTaskItem(This, - TaskItem); - return TRUE; - } - //else - //TRACE("Failed to delete window 0x%p\n", hWnd); - - return FALSE; -} - -static VOID -TaskSwitchWnd_DeleteAllTasks(IN OUT PTASK_SWITCH_WND This) -{ - PTASK_ITEM CurrentTask; - - if (This->TaskItemCount > 0) - { - CurrentTask = This->TaskItems + This->TaskItemCount; - do - { - TaskSwitchWnd_DeleteTaskItem(This, - --CurrentTask); - } while (CurrentTask != This->TaskItems); - } -} - -static VOID -TaskSwitchWnd_FlashTaskItem(IN OUT PTASK_SWITCH_WND This, - IN OUT PTASK_ITEM TaskItem) -{ - TaskItem->RenderFlashed = 1; - TaskSwitchWnd_UpdateTaskItemButton(This, - TaskItem); -} - -static BOOL -TaskSwitchWnd_FlashTask(IN OUT PTASK_SWITCH_WND This, - IN HWND hWnd) -{ - PTASK_ITEM TaskItem; - - TaskItem = TaskSwitchWnd_FindTaskItem(This, - hWnd); - if (TaskItem != NULL) - { - TRACE("Flashing window 0x%p on button %d\n", hWnd, TaskItem->Index); - TaskSwitchWnd_FlashTaskItem(This, - TaskItem); - return TRUE; - } - - return FALSE; -} - -static VOID -TaskSwitchWnd_RedrawTaskItem(IN OUT PTASK_SWITCH_WND This, - IN OUT PTASK_ITEM TaskItem) -{ - PTASK_GROUP TaskGroup; - - TaskGroup = TaskItem->Group; - if (This->IsGroupingEnabled && TaskGroup != NULL) - { - if (TaskGroup->IsCollapsed && TaskGroup->Index >= 0) - { - TaskSwitchWnd_UpdateTaskGroupButton(This, - TaskGroup); - } - else if (TaskItem->Index >= 0) - { - goto UpdateTaskItem; - } - } - else if (TaskItem->Index >= 0) - { -UpdateTaskItem: - TaskItem->RenderFlashed = 0; - TaskSwitchWnd_UpdateTaskItemButton(This, - TaskItem); - } -} - - -static BOOL -TaskSwitchWnd_RedrawTask(IN OUT PTASK_SWITCH_WND This, - IN HWND hWnd) -{ - PTASK_ITEM TaskItem; - - TaskItem = TaskSwitchWnd_FindTaskItem(This, - hWnd); - if (TaskItem != NULL) - { - TaskSwitchWnd_RedrawTaskItem(This, - TaskItem); - return TRUE; - } - - return FALSE; -} - -static INT -TaskSwitchWnd_UpdateTbButtonSpacing(IN OUT PTASK_SWITCH_WND This, - IN BOOL bHorizontal, - IN UINT uiRows, - IN UINT uiBtnsPerLine) -{ - TBMETRICS tbm; - - tbm.cbSize = sizeof(tbm); - tbm.dwMask = TBMF_BARPAD | TBMF_BUTTONSPACING; - - tbm.cxBarPad = tbm.cyBarPad = 0; - - if (bHorizontal || uiBtnsPerLine > 1) - tbm.cxButtonSpacing = (3 * GetSystemMetrics(SM_CXEDGE) / 2); - else - tbm.cxButtonSpacing = 0; - - if (!bHorizontal || uiRows > 1) - tbm.cyButtonSpacing = (3 * GetSystemMetrics(SM_CYEDGE) / 2); - else - tbm.cyButtonSpacing = 0; - - SendMessage(This->hWndToolbar, - TB_SETMETRICS, - 0, - (LPARAM)&tbm); - - return tbm.cxButtonSpacing; -} - - -static VOID -TaskSwitchWnd_UpdateButtonsSize(IN OUT PTASK_SWITCH_WND This, - IN BOOL bRedrawDisabled) -{ - RECT rcClient; - UINT uiRows, uiMax, uiMin, uiBtnsPerLine, ui; - LONG NewBtnSize; - BOOL Horizontal; - TBBUTTONINFO tbbi; - TBMETRICS tbm; - - if (GetClientRect(This->hWnd, - &rcClient) && - !IsRectEmpty(&rcClient)) - { - if (This->ToolbarBtnCount > 0) - { - ZeroMemory (&tbm, sizeof (tbm)); - tbm.cbSize = sizeof(tbm); - tbm.dwMask = TBMF_BUTTONSPACING; - SendMessage(This->hWndToolbar, - TB_GETMETRICS, - 0, - (LPARAM)&tbm); - - uiRows = (rcClient.bottom + tbm.cyButtonSpacing) / (This->ButtonSize.cy + tbm.cyButtonSpacing); - if (uiRows == 0) - uiRows = 1; - - uiBtnsPerLine = (This->ToolbarBtnCount + uiRows - 1) / uiRows; - - Horizontal = ITrayWindow_IsHorizontal(This->Tray); - - if (!bRedrawDisabled) - TaskSwitchWnd_BeginUpdate(This); - - /* We might need to update the button spacing */ - tbm.cxButtonSpacing = TaskSwitchWnd_UpdateTbButtonSpacing(This, - Horizontal, - uiRows, - uiBtnsPerLine); - - /* Calculate the ideal width and make sure it's within the allowed range */ - NewBtnSize = (rcClient.right - (uiBtnsPerLine * tbm.cxButtonSpacing)) / uiBtnsPerLine; - - /* Determine the minimum and maximum width of a button */ - if (Horizontal) - uiMax = GetSystemMetrics(SM_CXMINIMIZED); - else - uiMax = rcClient.right; - - uiMin = GetSystemMetrics(SM_CXSIZE) + (2 * GetSystemMetrics(SM_CXEDGE)); - - if (NewBtnSize < (LONG)uiMin) - NewBtnSize = uiMin; - if (NewBtnSize > (LONG)uiMax) - NewBtnSize = uiMax; - - This->ButtonSize.cx = NewBtnSize; - - /* Recalculate how many buttons actually fit into one line */ - uiBtnsPerLine = rcClient.right / (NewBtnSize + tbm.cxButtonSpacing); - if (uiBtnsPerLine == 0) - uiBtnsPerLine++; - This->TbButtonsPerLine = uiBtnsPerLine; - - tbbi.cbSize = sizeof(tbbi); - tbbi.dwMask = TBIF_BYINDEX | TBIF_SIZE | TBIF_STATE; - tbbi.cx = (INT)NewBtnSize; - - for (ui = 0; ui != This->ToolbarBtnCount; ui++) - { - tbbi.fsState = TBSTATE_ENABLED; - - /* Check if we're updating a button that is the last one in the - line. If so, we need to set the TBSTATE_WRAP flag! */ - if ((ui + 1) % uiBtnsPerLine == 0) - tbbi.fsState |= TBSTATE_WRAP; - - if (This->ActiveTaskItem != NULL && - This->ActiveTaskItem->Index == ui) - { - tbbi.fsState |= TBSTATE_CHECKED; - } - - SendMessage(This->hWndToolbar, - TB_SETBUTTONINFO, - (WPARAM)ui, - (LPARAM)&tbbi); - } - -#if 0 - /* FIXME: Force the window to the correct position in case some idiot - did something to us */ - SetWindowPos(This->hWndToolbar, - NULL, - 0, - 0, - rcClient.right, /* FIXME */ - rcClient.bottom, /* FIXME */ - SWP_NOACTIVATE | SWP_NOZORDER); -#endif - } - else - { - This->TbButtonsPerLine = 0; - This->ButtonSize.cx = 0; - } - } - - TaskSwitchWnd_EndUpdate(This); -} - -static BOOL CALLBACK -TaskSwitchWnd_EnumWindowsProc(IN HWND hWnd, - IN LPARAM lParam) -{ - PTASK_SWITCH_WND This = (PTASK_SWITCH_WND)lParam; - - /* Only show windows that still exist and are visible and none of explorer's - special windows (such as the desktop or the tray window) */ - if (IsWindow(hWnd) && IsWindowVisible(hWnd) && - !ITrayWindow_IsSpecialHWND(This->Tray, hWnd)) - { - DWORD exStyle = GetWindowLong(hWnd, GWL_EXSTYLE); - /* Don't list popup windows and also no tool windows */ - if ((GetWindow(hWnd, GW_OWNER) == NULL || exStyle & WS_EX_APPWINDOW) && - !(exStyle & WS_EX_TOOLWINDOW)) - { - TaskSwitchWnd_AddTask(This, - hWnd); - } - } - - return TRUE; -} - -static LRESULT CALLBACK -TaskSwitchWnd_ToolbarSubclassedProc(IN HWND hWnd, - IN UINT msg, - IN WPARAM wParam, - IN LPARAM lParam, - IN UINT_PTR uIdSubclass, - IN DWORD_PTR dwRefData) -{ - LRESULT Ret; - - Ret = DefSubclassProc(hWnd, - msg, - wParam, - lParam); - - if (msg == WM_NCHITTEST && Ret == HTCLIENT) - { - POINT pt; - - /* See if the mouse is on a button */ - pt.x = (SHORT)LOWORD(lParam); - pt.y = (SHORT)HIWORD(lParam); - - if (MapWindowPoints(HWND_DESKTOP, - hWnd, - &pt, - 1) != 0 && - (INT)SendMessage(hWnd, - TB_HITTEST, - 0, - (LPARAM)&pt) < 0) - { - /* Make the control appear to be transparent outside of any buttons */ - Ret = HTTRANSPARENT; - } - } - - return Ret; -} - -static VOID -TaskSwitchWnd_UpdateTheme(IN OUT PTASK_SWITCH_WND This) -{ - if (This->TaskBandTheme) - CloseThemeData(This->TaskBandTheme); - - if (IsThemeActive()) - This->TaskBandTheme = OpenThemeData(This->hWnd, L"TaskBand"); - else - This->TaskBandTheme = NULL; -} - -static VOID -TaskSwitchWnd_Create(IN OUT PTASK_SWITCH_WND This) -{ - This->hWndToolbar = CreateWindowEx(0, - TOOLBARCLASSNAME, - szRunningApps, - WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | - TBSTYLE_TOOLTIPS | TBSTYLE_WRAPABLE | TBSTYLE_LIST | TBSTYLE_TRANSPARENT | - CCS_TOP | CCS_NORESIZE | CCS_NODIVIDER, - 0, - 0, - 0, - 0, - This->hWnd, - NULL, - hExplorerInstance, - NULL); - - if (This->hWndToolbar != NULL) - { - HMODULE hShell32; - SIZE BtnSize; - - SetWindowTheme(This->hWndToolbar, L"TaskBand", NULL); - TaskSwitchWnd_UpdateTheme(This); - /* Identify the version we're using */ - SendMessage(This->hWndToolbar, - TB_BUTTONSTRUCTSIZE, - sizeof(TBBUTTON), - 0); - - This->TaskIcons = ImageList_Create(16, 16, ILC_COLOR32 | ILC_MASK, 0, 1000); - SendMessage(This->hWndToolbar, TB_SETIMAGELIST, 0, (LPARAM)This->TaskIcons); - - /* Calculate the default button size. Don't save this in This->ButtonSize.cx so that - the actual button width gets updated correctly on the first recalculation */ - BtnSize.cx = GetSystemMetrics(SM_CXMINIMIZED); - This->ButtonSize.cy = BtnSize.cy = GetSystemMetrics(SM_CYSIZE) + (2 * GetSystemMetrics(SM_CYEDGE)); - SendMessage(This->hWndToolbar, - TB_SETBUTTONSIZE, - 0, - (LPARAM)MAKELONG(BtnSize.cx, - BtnSize.cy)); - - /* We don't want to see partially clipped buttons...not that we could see them... */ -#if 0 - SendMessage(This->hWndToolbar, - TB_SETEXTENDEDSTYLE, - 0, - TBSTYLE_EX_HIDECLIPPEDBUTTONS); -#endif - - /* Set proper spacing between buttons */ - TaskSwitchWnd_UpdateTbButtonSpacing(This, - ITrayWindow_IsHorizontal(This->Tray), - 0, - 0); - - /* Register the shell hook */ - This->ShellHookMsg = RegisterWindowMessage(TEXT("SHELLHOOK")); - hShell32 = GetModuleHandle(TEXT("SHELL32.DLL")); - if (hShell32 != NULL) - { - REGSHELLHOOK RegShellHook; - - /* RegisterShellHook */ - RegShellHook = (REGSHELLHOOK)GetProcAddress(hShell32, - (LPCSTR)((LONG)181)); - if (RegShellHook != NULL) - { - RegShellHook(This->hWnd, - 3); /* 1 if no NT! We're targeting NT so we don't care! */ - } - } - - /* Add all windows to the toolbar */ - EnumWindows(TaskSwitchWnd_EnumWindowsProc, - (LPARAM)This); - - /* Recalculate the button size */ - TaskSwitchWnd_UpdateButtonsSize(This, - FALSE); - - /* Subclass the toolbar control because it doesn't provide a - NM_NCHITTEST notification */ - This->IsToolbarSubclassed = SetWindowSubclass(This->hWndToolbar, - TaskSwitchWnd_ToolbarSubclassedProc, - TSW_TOOLBAR_SUBCLASS_ID, - (DWORD_PTR)This); - } -} - -static VOID -TaskSwitchWnd_NCDestroy(IN OUT PTASK_SWITCH_WND This) -{ - HMODULE hShell32; - - This->IsDestroying = TRUE; - - /* Unregister the shell hook */ - hShell32 = GetModuleHandle(TEXT("SHELL32.DLL")); - if (hShell32 != NULL) - { - REGSHELLHOOK RegShellHook; - - /* RegisterShellHook */ - RegShellHook = (REGSHELLHOOK)GetProcAddress(hShell32, - (LPCSTR)((LONG)181)); - if (RegShellHook != NULL) - { - RegShellHook(This->hWnd, - FALSE); - } - } - - CloseThemeData(This->TaskBandTheme); - TaskSwitchWnd_DeleteAllTasks(This); -} - -static BOOL -TaskSwitchWnd_HandleAppCommand(IN OUT PTASK_SWITCH_WND This, - IN WPARAM wParam, - IN LPARAM lParam) -{ - BOOL Ret = FALSE; - - switch (GET_APPCOMMAND_LPARAM(lParam)) - { - case APPCOMMAND_BROWSER_SEARCH: - Ret = SHFindFiles(NULL, - NULL); - break; - - case APPCOMMAND_BROWSER_HOME: - case APPCOMMAND_LAUNCH_MAIL: - default: - TRACE("Shell app command %d unhandled!\n", (INT)GET_APPCOMMAND_LPARAM(lParam)); - break; - } - - return Ret; -} - - -static LRESULT -TaskSwitchWnd_HandleShellHookMsg(IN OUT PTASK_SWITCH_WND This, - IN WPARAM wParam, - IN LPARAM lParam) -{ - BOOL Ret = FALSE; - - switch ((INT)wParam) - { - case HSHELL_APPCOMMAND: - TaskSwitchWnd_HandleAppCommand(This, - wParam, - lParam); - Ret = TRUE; - break; - - case HSHELL_WINDOWCREATED: - Ret = TaskSwitchWnd_AddTask(This, - (HWND)lParam); - break; - - case HSHELL_WINDOWDESTROYED: - /* The window still exists! Delay destroying it a bit */ - TaskSwitchWnd_DeleteTask(This, (HWND)lParam); - Ret = TRUE; - break; - - case HSHELL_RUDEAPPACTIVATED: - case HSHELL_WINDOWACTIVATED: - if (lParam) - { - TaskSwitchWnd_ActivateTask(This, (HWND) lParam); - Ret = TRUE; - } - break; - - case HSHELL_GETMINRECT: - goto UnhandledShellMessage; - - case HSHELL_FLASH: - TaskSwitchWnd_FlashTask(This, - (HWND)lParam); - Ret = TRUE; - break; - - case HSHELL_REDRAW: - TaskSwitchWnd_RedrawTask(This, - (HWND)lParam); - Ret = TRUE; - break; - - case HSHELL_TASKMAN: - PostMessage(ITrayWindow_GetHWND(This->Tray), TWM_OPENSTARTMENU,0, 0); - break; - - case HSHELL_ACTIVATESHELLWINDOW: - case HSHELL_LANGUAGE: - case HSHELL_SYSMENU: - case HSHELL_ENDTASK: - case HSHELL_ACCESSIBILITYSTATE: - case HSHELL_WINDOWREPLACED: - case HSHELL_WINDOWREPLACING: - default: - { - static const struct { - INT msg; - LPCWSTR msg_name; - } hshell_msg[] = { - {HSHELL_WINDOWCREATED, L"HSHELL_WINDOWCREATED"}, - {HSHELL_WINDOWDESTROYED, L"HSHELL_WINDOWDESTROYED"}, - {HSHELL_ACTIVATESHELLWINDOW, L"HSHELL_ACTIVATESHELLWINDOW"}, - {HSHELL_WINDOWACTIVATED, L"HSHELL_WINDOWACTIVATED"}, - {HSHELL_GETMINRECT, L"HSHELL_GETMINRECT"}, - {HSHELL_REDRAW, L"HSHELL_REDRAW"}, - {HSHELL_TASKMAN, L"HSHELL_TASKMAN"}, - {HSHELL_LANGUAGE, L"HSHELL_LANGUAGE"}, - {HSHELL_SYSMENU, L"HSHELL_SYSMENU"}, - {HSHELL_ENDTASK, L"HSHELL_ENDTASK"}, - {HSHELL_ACCESSIBILITYSTATE, L"HSHELL_ACCESSIBILITYSTATE"}, - {HSHELL_APPCOMMAND, L"HSHELL_APPCOMMAND"}, - {HSHELL_WINDOWREPLACED, L"HSHELL_WINDOWREPLACED"}, - {HSHELL_WINDOWREPLACING, L"HSHELL_WINDOWREPLACING"}, - {HSHELL_RUDEAPPACTIVATED, L"HSHELL_RUDEAPPACTIVATED"}, - }; - int i, found; -UnhandledShellMessage: - for (i = 0, found = 0; i != sizeof(hshell_msg) / sizeof(hshell_msg[0]); i++) - { - if (hshell_msg[i].msg == (INT)wParam) - { - TRACE("Shell message %ws unhandled (lParam = 0x%p)!\n", hshell_msg[i].msg_name, lParam); - found = 1; - break; - } - } - if (!found) - { - TRACE("Shell message %d unhandled (lParam = 0x%p)!\n", (INT)wParam, lParam); - } - break; - } - } - - return Ret; -} - -static VOID -TaskSwitchWnd_EnableGrouping(IN OUT PTASK_SWITCH_WND This, - IN BOOL bEnable) -{ - This->IsGroupingEnabled = bEnable; - - /* Collapse or expand groups if neccessary */ - TaskSwitchWnd_UpdateButtonsSize(This, - FALSE); -} - -static VOID -TaskSwitchWnd_HandleTaskItemClick(IN OUT PTASK_SWITCH_WND This, - IN OUT PTASK_ITEM TaskItem) -{ - BOOL bIsMinimized; - BOOL bIsActive; - - if (IsWindow(TaskItem->hWnd)) - { - bIsMinimized = IsIconic(TaskItem->hWnd); - bIsActive = (TaskItem == This->ActiveTaskItem); - - TRACE("Active TaskItem %p, selected TaskItem %p\n", This->ActiveTaskItem, TaskItem); - if (This->ActiveTaskItem) - TRACE("Active TaskItem hWnd=%p, TaskItem hWnd %p\n", This->ActiveTaskItem->hWnd, TaskItem->hWnd); - - TRACE("Valid button clicked. HWND=%p, IsMinimized=%s, IsActive=%s...\n", - TaskItem->hWnd, bIsMinimized ? "Yes" : "No", bIsActive ? "Yes" : "No"); - - if (!bIsMinimized && bIsActive) - { - PostMessage(TaskItem->hWnd, - WM_SYSCOMMAND, - SC_MINIMIZE, - 0); - TRACE("Valid button clicked. App window Minimized.\n"); - } - else - { - if (bIsMinimized) - { - PostMessage(TaskItem->hWnd, - WM_SYSCOMMAND, - SC_RESTORE, - 0); - TRACE("Valid button clicked. App window Restored.\n"); - } - - SetForegroundWindow(TaskItem->hWnd); - TRACE("Valid button clicked. App window Activated.\n"); - } - } -} - -static VOID -TaskSwitchWnd_HandleTaskGroupClick(IN OUT PTASK_SWITCH_WND This, - IN OUT PTASK_GROUP TaskGroup) -{ - /* TODO: Show task group menu */ -} - -static BOOL -TaskSwitchWnd_HandleButtonClick(IN OUT PTASK_SWITCH_WND This, - IN WORD wIndex) -{ - PTASK_ITEM TaskItem; - PTASK_GROUP TaskGroup; - - if (This->IsGroupingEnabled) - { - TaskGroup = FindTaskGroupByIndex(This, - (INT)wIndex); - if (TaskGroup != NULL && TaskGroup->IsCollapsed) - { - TaskSwitchWnd_HandleTaskGroupClick(This, - TaskGroup); - return TRUE; - } - } - - TaskItem = FindTaskItemByIndex(This, - (INT)wIndex); - if (TaskItem != NULL) - { - TaskSwitchWnd_HandleTaskItemClick(This, - TaskItem); - return TRUE; - } - - return FALSE; -} - - -static VOID -TaskSwitchWnd_HandleTaskItemRightClick(IN OUT PTASK_SWITCH_WND This, - IN OUT PTASK_ITEM TaskItem) -{ - - HMENU hmenu = GetSystemMenu(TaskItem->hWnd, FALSE); - - if (hmenu) { - POINT pt; - int cmd; - GetCursorPos(&pt); - cmd = TrackPopupMenu(hmenu, TPM_LEFTBUTTON|TPM_RIGHTBUTTON|TPM_RETURNCMD, pt.x, pt.y, 0, This->hWndToolbar, NULL); - if (cmd) { - SetForegroundWindow(TaskItem->hWnd); // reactivate window after the context menu has closed - PostMessage(TaskItem->hWnd, WM_SYSCOMMAND, cmd, 0); - } - } -} - -static VOID -TaskSwitchWnd_HandleTaskGroupRightClick(IN OUT PTASK_SWITCH_WND This, - IN OUT PTASK_GROUP TaskGroup) -{ - /* TODO: Show task group right click menu */ -} - -static BOOL -TaskSwitchWnd_HandleButtonRightClick(IN OUT PTASK_SWITCH_WND This, - IN WORD wIndex) -{ - PTASK_ITEM TaskItem; - PTASK_GROUP TaskGroup; - if (This->IsGroupingEnabled) - { - TaskGroup = FindTaskGroupByIndex(This, - (INT)wIndex); - if (TaskGroup != NULL && TaskGroup->IsCollapsed) - { - TaskSwitchWnd_HandleTaskGroupRightClick(This, - TaskGroup); - return TRUE; - } - } - - TaskItem = FindTaskItemByIndex(This, - (INT)wIndex); - - if (TaskItem != NULL) - { - TaskSwitchWnd_HandleTaskItemRightClick(This, - TaskItem); - return TRUE; - } - - return FALSE; -} - - -static LRESULT -TaskSwitchWnd_HandleItemPaint(IN OUT PTASK_SWITCH_WND This, - IN OUT NMTBCUSTOMDRAW *nmtbcd) -{ - LRESULT Ret = CDRF_DODEFAULT; - PTASK_GROUP TaskGroup; - PTASK_ITEM TaskItem; - - TaskItem = FindTaskItemByIndex(This, - (INT)nmtbcd->nmcd.dwItemSpec); - TaskGroup = FindTaskGroupByIndex(This, - (INT)nmtbcd->nmcd.dwItemSpec); - if (TaskGroup == NULL && TaskItem != NULL) - { - ASSERT(TaskItem != NULL); - - if (TaskItem != NULL && IsWindow(TaskItem->hWnd)) - { - /* Make the entire button flashing if neccessary */ - if (nmtbcd->nmcd.uItemState & CDIS_MARKED) - { - Ret = TBCDRF_NOBACKGROUND; - if (!This->TaskBandTheme) - { - SelectObject(nmtbcd->nmcd.hdc, GetSysColorBrush(COLOR_HIGHLIGHT)); - Rectangle(nmtbcd->nmcd.hdc, - nmtbcd->nmcd.rc.left, - nmtbcd->nmcd.rc.top, - nmtbcd->nmcd.rc.right, - nmtbcd->nmcd.rc.bottom); - } - else - { - DrawThemeBackground(This->TaskBandTheme, nmtbcd->nmcd.hdc, TDP_FLASHBUTTON, 0, &nmtbcd->nmcd.rc, 0); - } - nmtbcd->clrText = GetSysColor(COLOR_HIGHLIGHTTEXT); - return Ret; - } - } - } - else if (TaskGroup != NULL) - { - /* FIXME: Implement painting for task groups */ - } - return Ret; -} - -static LRESULT -TaskSwitchWnd_HandleToolbarNotification(IN OUT PTASK_SWITCH_WND This, - IN const NMHDR *nmh) -{ - LRESULT Ret = 0; - - switch (nmh->code) - { - case NM_CUSTOMDRAW: - { - LPNMTBCUSTOMDRAW nmtbcd = (LPNMTBCUSTOMDRAW)nmh; - - switch (nmtbcd->nmcd.dwDrawStage) - { - - case CDDS_ITEMPREPAINT: - Ret = TaskSwitchWnd_HandleItemPaint(This, - nmtbcd); - break; - - case CDDS_PREPAINT: - Ret = CDRF_NOTIFYITEMDRAW; - break; - - default: - Ret = CDRF_DODEFAULT; - break; - } - break; - } - } - - return Ret; -} - -static VOID -TaskSwitchWnd_DrawBackground(HWND hwnd, - HDC hdc) -{ - RECT rect; - - GetClientRect(hwnd, &rect); - DrawThemeParentBackground(hwnd, hdc, &rect); -} - -static LRESULT CALLBACK -TaskSwitchWndProc(IN HWND hwnd, - IN UINT uMsg, - IN WPARAM wParam, - IN LPARAM lParam) -{ - PTASK_SWITCH_WND This = NULL; - LRESULT Ret = FALSE; - - if (uMsg != WM_NCCREATE) - { - This = (PTASK_SWITCH_WND)GetWindowLongPtr(hwnd, 0); - } - - if (This != NULL || uMsg == WM_NCCREATE) - { - switch (uMsg) - { - case WM_THEMECHANGED: - TaskSwitchWnd_UpdateTheme(This); - break; - case WM_ERASEBKGND: - if (!This->TaskBandTheme) - break; - TaskSwitchWnd_DrawBackground(hwnd, (HDC) wParam); - return TRUE; - case WM_SIZE: - { - SIZE szClient; - - szClient.cx = LOWORD(lParam); - szClient.cy = HIWORD(lParam); - if (This->hWndToolbar != NULL) - { - SetWindowPos(This->hWndToolbar, - NULL, - 0, - 0, - szClient.cx, - szClient.cy, - SWP_NOZORDER); - - TaskSwitchWnd_UpdateButtonsSize(This, FALSE); - } - break; - } - - case WM_NCHITTEST: - { - /* We want the tray window to be draggable everywhere, so make the control - appear transparent */ - Ret = DefWindowProc(hwnd, uMsg, wParam, lParam); - if (Ret != HTVSCROLL && Ret != HTHSCROLL) - return HTTRANSPARENT; - return Ret; - } - - case WM_COMMAND: - { - if (lParam != 0 && (HWND)lParam == This->hWndToolbar) - { - TaskSwitchWnd_HandleButtonClick(This, LOWORD(wParam)); - } - break; - } - - case WM_NOTIFY: - { - const NMHDR *nmh = (const NMHDR *)lParam; - - if (nmh->hwndFrom == This->hWndToolbar) - { - return TaskSwitchWnd_HandleToolbarNotification(This, nmh); - } - return 0; - } - - case TSWM_ENABLEGROUPING: - { - Ret = This->IsGroupingEnabled; - if (wParam != This->IsGroupingEnabled) - { - TaskSwitchWnd_EnableGrouping(This, - (BOOL)wParam); - } - return Ret; - } - - case TSWM_UPDATETASKBARPOS: - { - /* Update the button spacing */ - TaskSwitchWnd_UpdateTbButtonSpacing(This, ITrayWindow_IsHorizontal(This->Tray), 0, 0); - break; - } - - case WM_CONTEXTMENU: - { - if (This->hWndToolbar != NULL) - { - POINT pt; - INT_PTR iBtn; - - pt.x = (LONG)LOWORD(lParam); - pt.y = (LONG)HIWORD(lParam); - - MapWindowPoints(NULL, This->hWndToolbar, &pt, 1); - - iBtn = (INT_PTR) SendMessage(This->hWndToolbar, TB_HITTEST, 0, (LPARAM) &pt); - if (iBtn >= 0) - { - TaskSwitchWnd_HandleButtonRightClick(This, iBtn); - } - else - goto ForwardContextMenuMsg; - } - else - { -ForwardContextMenuMsg: - /* Forward message */ - Ret = SendMessage(ITrayWindow_GetHWND(This->Tray), uMsg, wParam, lParam); - } - break; - } - - case WM_NCCREATE: - { - LPCREATESTRUCT CreateStruct = (LPCREATESTRUCT)lParam; - This = HeapAlloc(hProcessHeap, - HEAP_ZERO_MEMORY, - sizeof(*This)); - if (This == NULL) - return FALSE; - - This->hWnd = hwnd; - This->hWndNotify = CreateStruct->hwndParent; - This->Tray = (ITrayWindow*)CreateStruct->lpCreateParams; - This->IsGroupingEnabled = TRUE; /* FIXME */ - SetWindowLongPtr(hwnd, - 0, - (LONG_PTR)This); - - return TRUE; - } - - case WM_CREATE: - TaskSwitchWnd_Create(This); - -#if DUMP_TASKS != 0 - SetTimer(hwnd, 1, 5000, NULL); -#endif - - break; - - case WM_DESTROY: - if (This->IsToolbarSubclassed) - { - if (RemoveWindowSubclass(This->hWndToolbar, - TaskSwitchWnd_ToolbarSubclassedProc, - TSW_TOOLBAR_SUBCLASS_ID)) - { - This->IsToolbarSubclassed = FALSE; - } - } - break; - - case WM_NCDESTROY: - TaskSwitchWnd_NCDestroy(This); - HeapFree(hProcessHeap, 0, This); - SetWindowLongPtr(hwnd, 0, 0); - break; - -#if DUMP_TASKS != 0 - case WM_TIMER: - switch (wParam) - { - case 1: - TaskSwitchWnd_DumpTasks(This); - break; - } - break; -#endif - - case WM_KLUDGEMINRECT: - { - PTASK_ITEM TaskItem = TaskSwitchWnd_FindTaskItem(This, (HWND)wParam); - if (TaskItem) - { - RECT* prcMinRect = (RECT*)lParam; - RECT rcItem, rcToolbar; - SendMessageW(This->hWndToolbar,TB_GETITEMRECT, TaskItem->Index, (LPARAM)&rcItem); - GetWindowRect(This->hWndToolbar, &rcToolbar); - - OffsetRect(&rcItem, rcToolbar.left, rcToolbar.top); - - *prcMinRect = rcItem; - return TRUE; - } - return FALSE; - } - - default: -/* HandleDefaultMessage: */ - if (uMsg == This->ShellHookMsg && This->ShellHookMsg != 0) - { - /* Process shell messages */ - return (LRESULT) TaskSwitchWnd_HandleShellHookMsg(This, wParam, lParam); - } - - break; - } - } - - return DefWindowProc(hwnd, uMsg, wParam, lParam); -} - - -HWND -CreateTaskSwitchWnd(IN HWND hWndParent, - IN OUT ITrayWindow *Tray) -{ - HWND hwndTaskBar; - - hwndTaskBar = CreateWindowEx(0, - szTaskSwitchWndClass, - szRunningApps, - WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP, - 0, - 0, - 0, - 0, - hWndParent, - NULL, - hExplorerInstance, - (LPVOID)Tray); - - return hwndTaskBar; -} - -BOOL -RegisterTaskSwitchWndClass(VOID) -{ - WNDCLASS wc; - - wc.style = CS_DBLCLKS; - wc.lpfnWndProc = TaskSwitchWndProc; - wc.cbClsExtra = 0; - wc.cbWndExtra = sizeof(PTASK_SWITCH_WND); - wc.hInstance = hExplorerInstance; - wc.hIcon = NULL; - wc.hCursor = LoadCursor(NULL, - IDC_ARROW); - wc.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1); - wc.lpszMenuName = NULL; - wc.lpszClassName = szTaskSwitchWndClass; - - return RegisterClass(&wc) != 0; -} - -VOID -UnregisterTaskSwitchWndClass(VOID) -{ - UnregisterClass(szTaskSwitchWndClass, - hExplorerInstance); -} diff --git a/base/shell/explorer-new/taskswnd.cpp b/base/shell/explorer-new/taskswnd.cpp new file mode 100644 index 00000000000..0956ba4129f --- /dev/null +++ b/base/shell/explorer-new/taskswnd.cpp @@ -0,0 +1,2079 @@ +/* + * ReactOS Explorer + * + * Copyright 2006 - 2007 Thomas Weidenmueller + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "precomp.h" +#include + +#define GET_X_LPARAM(lp) ((int)(short)LOWORD(lp)) +#define GET_Y_LPARAM(lp) ((int)(short)HIWORD(lp)) + +/* Set DUMP_TASKS to 1 to enable a dump of the tasks and task groups every + 5 seconds */ +#define DUMP_TASKS 0 + +const WCHAR szTaskSwitchWndClass [] = TEXT("MSTaskSwWClass"); +const WCHAR szRunningApps [] = TEXT("Running Applications"); + +const struct { + INT msg; + LPCWSTR msg_name; +} hshell_msg [] = { + { HSHELL_WINDOWCREATED, L"HSHELL_WINDOWCREATED" }, + { HSHELL_WINDOWDESTROYED, L"HSHELL_WINDOWDESTROYED" }, + { HSHELL_ACTIVATESHELLWINDOW, L"HSHELL_ACTIVATESHELLWINDOW" }, + { HSHELL_WINDOWACTIVATED, L"HSHELL_WINDOWACTIVATED" }, + { HSHELL_GETMINRECT, L"HSHELL_GETMINRECT" }, + { HSHELL_REDRAW, L"HSHELL_REDRAW" }, + { HSHELL_TASKMAN, L"HSHELL_TASKMAN" }, + { HSHELL_LANGUAGE, L"HSHELL_LANGUAGE" }, + { HSHELL_SYSMENU, L"HSHELL_SYSMENU" }, + { HSHELL_ENDTASK, L"HSHELL_ENDTASK" }, + { HSHELL_ACCESSIBILITYSTATE, L"HSHELL_ACCESSIBILITYSTATE" }, + { HSHELL_APPCOMMAND, L"HSHELL_APPCOMMAND" }, + { HSHELL_WINDOWREPLACED, L"HSHELL_WINDOWREPLACED" }, + { HSHELL_WINDOWREPLACING, L"HSHELL_WINDOWREPLACING" }, + { HSHELL_RUDEAPPACTIVATED, L"HSHELL_RUDEAPPACTIVATED" }, +}; + +typedef struct _TASK_GROUP +{ + /* We have to use a linked list instead of an array so we don't have to + update all pointers to groups in the task item array when removing + groups. */ + struct _TASK_GROUP *Next; + + DWORD dwTaskCount; + DWORD dwProcessId; + INT Index; + union + { + DWORD dwFlags; + struct + { + + DWORD IsCollapsed : 1; + }; + }; +} TASK_GROUP, *PTASK_GROUP; + +typedef struct _TASK_ITEM +{ + HWND hWnd; + PTASK_GROUP Group; + INT Index; + INT IconIndex; + + + + union + { + DWORD dwFlags; + struct + { + + /* IsFlashing is TRUE when the task bar item should be flashing. */ + DWORD IsFlashing : 1; + + /* RenderFlashed is only TRUE if the task bar item should be + drawn with a flash. */ + DWORD RenderFlashed : 1; + }; + }; +} TASK_ITEM, *PTASK_ITEM; + +#define TASK_ITEM_ARRAY_ALLOC 64 + +class CTaskSwitchWnd : + public CWindowImpl < CTaskSwitchWnd, CWindow, CControlWinTraits > +{ + CContainedWindow TaskBar; + + HWND hWndNotify; + + UINT ShellHookMsg; + CComPtr Tray; + + PTASK_GROUP TaskGroups; + + WORD TaskItemCount; + WORD AllocatedTaskItems; + PTASK_ITEM TaskItems; + PTASK_ITEM ActiveTaskItem; + + HTHEME TaskBandTheme; + HWND hWndToolbar; + UINT TbButtonsPerLine; + WORD ToolbarBtnCount; + + IImageList * TaskIcons; + + BOOL IsGroupingEnabled; + BOOL IsDestroying; + + SIZE ButtonSize; + WCHAR szBuf[255]; + +public: + CTaskSwitchWnd() : + TaskBar(this, 1), + hWndNotify(NULL), + ShellHookMsg(NULL), + TaskGroups(NULL), + TaskItemCount(0), + AllocatedTaskItems(0), + TaskItems(0), + ActiveTaskItem(0), + TaskBandTheme(NULL), + hWndToolbar(NULL), + TbButtonsPerLine(0), + ToolbarBtnCount(0), + TaskIcons(NULL) + { + ZeroMemory(&ButtonSize, sizeof(ButtonSize)); + szBuf[0] = 0; + } + virtual ~CTaskSwitchWnd() { } + +#define MAX_TASKS_COUNT (0x7FFF) + + VOID TaskSwitchWnd_UpdateButtonsSize( + IN BOOL bRedrawDisabled); + + LPTSTR GetWndTextFromTaskItem( + IN PTASK_ITEM TaskItem) + { + /* Get the window text without sending a message so we don't hang if an + application isn't responding! */ + if (InternalGetWindowText(TaskItem->hWnd, + szBuf, + sizeof(szBuf) / sizeof(szBuf[0])) > 0) + { + return szBuf; + } + + return NULL; + } + + +#if DUMP_TASKS != 0 + VOID DumpTasks() + { + PTASK_GROUP CurrentGroup; + PTASK_ITEM CurrentTaskItem, LastTaskItem; + + TRACE("Tasks dump:\n"); + if (IsGroupingEnabled) + { + CurrentGroup = TaskGroups; + while (CurrentGroup != NULL) + { + TRACE("- Group PID: 0x%p Tasks: %d Index: %d\n", CurrentGroup->dwProcessId, CurrentGroup->dwTaskCount, CurrentGroup->Index); + + CurrentTaskItem = TaskItems; + LastTaskItem = CurrentTaskItem + TaskItemCount; + while (CurrentTaskItem != LastTaskItem) + { + if (CurrentTaskItem->Group == CurrentGroup) + { + TRACE(" + Task hwnd: 0x%p Index: %d\n", CurrentTaskItem->hWnd, CurrentTaskItem->Index); + } + CurrentTaskItem++; + } + + CurrentGroup = CurrentGroup->Next; + } + + CurrentTaskItem = TaskItems; + LastTaskItem = CurrentTaskItem + TaskItemCount; + while (CurrentTaskItem != LastTaskItem) + { + if (CurrentTaskItem->Group == NULL) + { + TRACE("- Task hwnd: 0x%p Index: %d\n", CurrentTaskItem->hWnd, CurrentTaskItem->Index); + } + CurrentTaskItem++; + } + } + else + { + CurrentTaskItem = TaskItems; + LastTaskItem = CurrentTaskItem + TaskItemCount; + while (CurrentTaskItem != LastTaskItem) + { + TRACE("- Task hwnd: 0x%p Index: %d\n", CurrentTaskItem->hWnd, CurrentTaskItem->Index); + CurrentTaskItem++; + } + } + } +#endif + + VOID BeginUpdate() + { + ::SendMessage(hWndToolbar, + WM_SETREDRAW, + FALSE, + 0); + } + + VOID EndUpdate() + { + ::SendMessage(hWndToolbar, + WM_SETREDRAW, + TRUE, + 0); + ::InvalidateRect(hWndToolbar, + NULL, + TRUE); + } + + BOOL SetToolbarButtonCommandId( + IN INT iButtonIndex, + IN INT iCommandId) + { + TBBUTTONINFO tbbi; + + tbbi.cbSize = sizeof(tbbi); + tbbi.dwMask = TBIF_BYINDEX | TBIF_COMMAND; + tbbi.idCommand = iCommandId; + + return SendMessage(hWndToolbar, + TB_SETBUTTONINFO, + (WPARAM) iButtonIndex, + (LPARAM) &tbbi) != 0; + } + + VOID UpdateIndexesAfterButtonInserted( + IN INT iIndex) + { + PTASK_GROUP CurrentGroup; + PTASK_ITEM CurrentTaskItem, LastTaskItem; + INT NewIndex; + + if (IsGroupingEnabled) + { + /* Update all affected groups */ + CurrentGroup = TaskGroups; + while (CurrentGroup != NULL) + { + if (CurrentGroup->IsCollapsed && + CurrentGroup->Index >= iIndex) + { + /* Update the toolbar buttons */ + NewIndex = CurrentGroup->Index + 1; + if (SetToolbarButtonCommandId( + CurrentGroup->Index + 1, + NewIndex)) + { + CurrentGroup->Index = NewIndex; + } + else + CurrentGroup->Index = -1; + } + + CurrentGroup = CurrentGroup->Next; + } + } + + /* Update all affected task items */ + CurrentTaskItem = TaskItems; + LastTaskItem = CurrentTaskItem + TaskItemCount; + while (CurrentTaskItem != LastTaskItem) + { + CurrentGroup = CurrentTaskItem->Group; + if (CurrentGroup != NULL) + { + if (!CurrentGroup->IsCollapsed && + CurrentTaskItem->Index >= iIndex) + { + goto UpdateTaskItemBtn; + } + } + else if (CurrentTaskItem->Index >= iIndex) + { + UpdateTaskItemBtn: + /* Update the toolbar buttons */ + NewIndex = CurrentTaskItem->Index + 1; + if (SetToolbarButtonCommandId( + CurrentTaskItem->Index + 1, + NewIndex)) + { + CurrentTaskItem->Index = NewIndex; + } + else + CurrentTaskItem->Index = -1; + } + + CurrentTaskItem++; + } + } + + VOID UpdateIndexesAfterButtonDeleted( + IN INT iIndex) + { + PTASK_GROUP CurrentGroup; + PTASK_ITEM CurrentTaskItem, LastTaskItem; + INT NewIndex; + + if (IsGroupingEnabled) + { + /* Update all affected groups */ + CurrentGroup = TaskGroups; + while (CurrentGroup != NULL) + { + if (CurrentGroup->IsCollapsed && + CurrentGroup->Index > iIndex) + { + /* Update the toolbar buttons */ + NewIndex = CurrentGroup->Index - 1; + if (SetToolbarButtonCommandId( + CurrentGroup->Index - 1, + NewIndex)) + { + CurrentGroup->Index = NewIndex; + } + else + CurrentGroup->Index = -1; + } + + CurrentGroup = CurrentGroup->Next; + } + } + + /* Update all affected task items */ + CurrentTaskItem = TaskItems; + LastTaskItem = CurrentTaskItem + TaskItemCount; + while (CurrentTaskItem != LastTaskItem) + { + CurrentGroup = CurrentTaskItem->Group; + if (CurrentGroup != NULL) + { + if (!CurrentGroup->IsCollapsed && + CurrentTaskItem->Index > iIndex) + { + goto UpdateTaskItemBtn; + } + } + else if (CurrentTaskItem->Index > iIndex) + { + UpdateTaskItemBtn: + /* Update the toolbar buttons */ + NewIndex = CurrentTaskItem->Index - 1; + if (SetToolbarButtonCommandId( + CurrentTaskItem->Index - 1, + NewIndex)) + { + CurrentTaskItem->Index = NewIndex; + } + else + CurrentTaskItem->Index = -1; + } + + CurrentTaskItem++; + } + } + + INT UpdateTaskGroupButton( + IN PTASK_GROUP TaskGroup) + { + ASSERT(TaskGroup->Index >= 0); + + /* FIXME: Implement */ + + return TaskGroup->Index; + } + + VOID ExpandTaskGroup( + IN PTASK_GROUP TaskGroup) + { + ASSERT(TaskGroup->dwTaskCount > 0); + ASSERT(TaskGroup->IsCollapsed); + ASSERT(TaskGroup->Index >= 0); + + /* FIXME: Implement */ + } + + HICON GetWndIcon(HWND hwnd) + { + HICON hIcon = 0; + + SendMessageTimeout(hwnd, WM_GETICON, ICON_SMALL2, 0, SMTO_ABORTIFHUNG, 1000, (PDWORD_PTR) &hIcon); + + if (!hIcon) + SendMessageTimeout(hwnd, WM_GETICON, ICON_SMALL, 0, SMTO_ABORTIFHUNG, 1000, (PDWORD_PTR) &hIcon); + + if (!hIcon) + SendMessageTimeout(hwnd, WM_GETICON, ICON_BIG, 0, SMTO_ABORTIFHUNG, 1000, (PDWORD_PTR) &hIcon); + + if (!hIcon) + hIcon = (HICON) GetClassLongPtr(hwnd, GCL_HICONSM); + + if (!hIcon) + hIcon = (HICON) GetClassLongPtr(hwnd, GCL_HICON); + + return hIcon; + } + INT UpdateTaskItemButton(IN PTASK_ITEM TaskItem) + { + TBBUTTONINFO tbbi; + HICON icon; + + ASSERT(TaskItem->Index >= 0); + + tbbi.cbSize = sizeof(tbbi); + tbbi.dwMask = TBIF_BYINDEX | TBIF_STATE | TBIF_TEXT | TBIF_IMAGE; + tbbi.fsState = TBSTATE_ENABLED; + if (ActiveTaskItem == TaskItem) + tbbi.fsState |= TBSTATE_CHECKED; + + if (TaskItem->RenderFlashed) + tbbi.fsState |= TBSTATE_MARKED; + + /* Check if we're updating a button that is the last one in the + line. If so, we need to set the TBSTATE_WRAP flag! */ + if (TbButtonsPerLine != 0 && + (TaskItem->Index + 1) % TbButtonsPerLine == 0) + { + tbbi.fsState |= TBSTATE_WRAP; + } + + tbbi.pszText = GetWndTextFromTaskItem( + TaskItem); + + icon = GetWndIcon(TaskItem->hWnd); + TaskIcons->ReplaceIcon(TaskItem->IconIndex, icon, &TaskItem->IconIndex); + tbbi.iImage = TaskItem->IconIndex; + + if (!SendMessage(hWndToolbar, + TB_SETBUTTONINFO, + (WPARAM) TaskItem->Index, + (LPARAM) &tbbi)) + { + TaskItem->Index = -1; + return -1; + } + + TRACE("Updated button %d for hwnd 0x%p\n", TaskItem->Index, TaskItem->hWnd); + return TaskItem->Index; + } + + VOID RemoveIcon( + IN PTASK_ITEM TaskItem) + { + TBBUTTONINFO tbbi; + PTASK_ITEM currentTaskItem, LastItem; + + if (TaskItem->IconIndex == -1) + return; + + tbbi.cbSize = sizeof(tbbi); + tbbi.dwMask = TBIF_IMAGE; + + currentTaskItem = TaskItems; + LastItem = currentTaskItem + TaskItemCount; + while (currentTaskItem != LastItem) + { + if (currentTaskItem->IconIndex > TaskItem->IconIndex) + { + currentTaskItem->IconIndex--; + tbbi.iImage = currentTaskItem->IconIndex; + + SendMessage(hWndToolbar, + TB_SETBUTTONINFO, + currentTaskItem->Index, + (LPARAM) &tbbi); + } + currentTaskItem++; + } + + TaskIcons->Remove(TaskItem->IconIndex); + } + + PTASK_ITEM FindLastTaskItemOfGroup( + IN PTASK_GROUP TaskGroup OPTIONAL, + IN PTASK_ITEM NewTaskItem OPTIONAL) + { + PTASK_ITEM TaskItem, LastTaskItem, FoundTaskItem = NULL; + DWORD dwTaskCount; + + ASSERT(IsGroupingEnabled); + + TaskItem = TaskItems; + LastTaskItem = TaskItem + TaskItemCount; + + dwTaskCount = (TaskGroup != NULL ? TaskGroup->dwTaskCount : MAX_TASKS_COUNT); + + ASSERT(dwTaskCount > 0); + + while (TaskItem != LastTaskItem) + { + if (TaskItem->Group == TaskGroup) + { + if ((NewTaskItem != NULL && TaskItem != NewTaskItem) || NewTaskItem == NULL) + { + FoundTaskItem = TaskItem; + } + + if (--dwTaskCount == 0) + { + /* We found the last task item in the group! */ + break; + } + } + + TaskItem++; + } + + return FoundTaskItem; + } + + INT CalculateTaskItemNewButtonIndex( + IN PTASK_ITEM TaskItem) + { + PTASK_GROUP TaskGroup; + PTASK_ITEM LastTaskItem; + + /* NOTE: This routine assumes that the group is *not* collapsed! */ + + TaskGroup = TaskItem->Group; + if (IsGroupingEnabled) + { + if (TaskGroup != NULL) + { + ASSERT(TaskGroup->Index < 0); + ASSERT(!TaskGroup->IsCollapsed); + + if (TaskGroup->dwTaskCount > 1) + { + LastTaskItem = FindLastTaskItemOfGroup( + TaskGroup, + TaskItem); + if (LastTaskItem != NULL) + { + /* Since the group is expanded the task items must have an index */ + ASSERT(LastTaskItem->Index >= 0); + + return LastTaskItem->Index + 1; + } + } + } + else + { + /* Find the last NULL group button. NULL groups are added at the end of the + task item list when grouping is enabled */ + LastTaskItem = FindLastTaskItemOfGroup( + NULL, + TaskItem); + if (LastTaskItem != NULL) + { + ASSERT(LastTaskItem->Index >= 0); + + return LastTaskItem->Index + 1; + } + } + } + + return ToolbarBtnCount; + } + + INT AddTaskItemButton( + IN OUT PTASK_ITEM TaskItem) + { + TBBUTTON tbBtn; + INT iIndex; + HICON icon; + + if (TaskItem->Index >= 0) + { + return UpdateTaskItemButton( + TaskItem); + } + + if (TaskItem->Group != NULL && + TaskItem->Group->IsCollapsed) + { + /* The task group is collapsed, we only need to update the group button */ + return UpdateTaskGroupButton( + TaskItem->Group); + } + + icon = GetWndIcon(TaskItem->hWnd); + TaskIcons->ReplaceIcon(-1, icon, &TaskItem->IconIndex); + + tbBtn.iBitmap = TaskItem->IconIndex; + tbBtn.fsState = TBSTATE_ENABLED | TBSTATE_ELLIPSES; + tbBtn.fsStyle = BTNS_CHECK | BTNS_NOPREFIX | BTNS_SHOWTEXT; + tbBtn.dwData = TaskItem->Index; + + tbBtn.iString = (DWORD_PTR) GetWndTextFromTaskItem( + TaskItem); + + /* Find out where to insert the new button */ + iIndex = CalculateTaskItemNewButtonIndex( + TaskItem); + ASSERT(iIndex >= 0); + tbBtn.idCommand = iIndex; + + BeginUpdate(); + + if (SendMessage(hWndToolbar, + TB_INSERTBUTTON, + (WPARAM) iIndex, + (LPARAM) &tbBtn)) + { + UpdateIndexesAfterButtonInserted( + iIndex); + + TRACE("Added button %d for hwnd 0x%p\n", iIndex, TaskItem->hWnd); + + TaskItem->Index = iIndex; + ToolbarBtnCount++; + + /* Update button sizes and fix the button wrapping */ + UpdateButtonsSize(TRUE); + return iIndex; + } + + EndUpdate(); + + return -1; + } + + BOOL DeleteTaskItemButton( + IN OUT PTASK_ITEM TaskItem) + { + PTASK_GROUP TaskGroup; + INT iIndex; + + TaskGroup = TaskItem->Group; + + if (TaskItem->Index >= 0) + { + if ((TaskGroup != NULL && !TaskGroup->IsCollapsed) || + TaskGroup == NULL) + { + BeginUpdate(); + + RemoveIcon(TaskItem); + iIndex = TaskItem->Index; + if (SendMessage(hWndToolbar, + TB_DELETEBUTTON, + (WPARAM) iIndex, + 0)) + { + TaskItem->Index = -1; + ToolbarBtnCount--; + + UpdateIndexesAfterButtonDeleted( + iIndex); + + /* Update button sizes and fix the button wrapping */ + UpdateButtonsSize( + TRUE); + return TRUE; + } + + EndUpdate(); + } + } + + return FALSE; + } + + PTASK_GROUP AddToTaskGroup( + IN HWND hWnd) + { + DWORD dwProcessId; + PTASK_GROUP TaskGroup, *PrevLink; + + if (!GetWindowThreadProcessId(hWnd, + &dwProcessId)) + { + TRACE("Cannot get process id of hwnd 0x%p\n", hWnd); + return NULL; + } + + /* Try to find an existing task group */ + TaskGroup = TaskGroups; + PrevLink = &TaskGroups; + while (TaskGroup != NULL) + { + if (TaskGroup->dwProcessId == dwProcessId) + { + TaskGroup->dwTaskCount++; + return TaskGroup; + } + + PrevLink = &TaskGroup->Next; + TaskGroup = TaskGroup->Next; + } + + /* Allocate a new task group */ + TaskGroup = (PTASK_GROUP) HeapAlloc(hProcessHeap, + HEAP_ZERO_MEMORY, + sizeof(*TaskGroup)); + if (TaskGroup != NULL) + { + TaskGroup->dwTaskCount = 1; + TaskGroup->dwProcessId = dwProcessId; + TaskGroup->Index = -1; + + /* Add the task group to the list */ + *PrevLink = TaskGroup; + } + + return TaskGroup; + } + + VOID RemoveTaskFromTaskGroup( + IN OUT PTASK_ITEM TaskItem) + { + PTASK_GROUP TaskGroup, CurrentGroup, *PrevLink; + + TaskGroup = TaskItem->Group; + if (TaskGroup != NULL) + { + DWORD dwNewTaskCount = --TaskGroup->dwTaskCount; + if (dwNewTaskCount == 0) + { + /* Find the previous pointer in the chain */ + CurrentGroup = TaskGroups; + PrevLink = &TaskGroups; + while (CurrentGroup != TaskGroup) + { + PrevLink = &CurrentGroup->Next; + CurrentGroup = CurrentGroup->Next; + } + + /* Remove the group from the list */ + ASSERT(TaskGroup == CurrentGroup); + *PrevLink = TaskGroup->Next; + + /* Free the task group */ + HeapFree(hProcessHeap, + 0, + TaskGroup); + } + else if (TaskGroup->IsCollapsed && + TaskGroup->Index >= 0) + { + if (dwNewTaskCount > 1) + { + /* FIXME: Check if we should expand the group */ + /* Update the task group button */ + UpdateTaskGroupButton( + TaskGroup); + } + else + { + /* Expand the group of one task button to a task button */ + ExpandTaskGroup( + TaskGroup); + } + } + } + } + + PTASK_ITEM FindTaskItem( + IN HWND hWnd) + { + PTASK_ITEM TaskItem, LastItem; + + TaskItem = TaskItems; + LastItem = TaskItem + TaskItemCount; + while (TaskItem != LastItem) + { + if (TaskItem->hWnd == hWnd) + return TaskItem; + + TaskItem++; + } + + return NULL; + } + + PTASK_ITEM FindOtherTaskItem( + IN HWND hWnd) + { + PTASK_ITEM LastItem, TaskItem; + PTASK_GROUP TaskGroup; + DWORD dwProcessId; + + if (!GetWindowThreadProcessId(hWnd, + &dwProcessId)) + { + return NULL; + } + + /* Try to find another task that belongs to the same + process as the given window */ + TaskItem = TaskItems; + LastItem = TaskItem + TaskItemCount; + while (TaskItem != LastItem) + { + TaskGroup = TaskItem->Group; + if (TaskGroup != NULL) + { + if (TaskGroup->dwProcessId == dwProcessId) + return TaskItem; + } + else + { + DWORD dwProcessIdTask; + + if (GetWindowThreadProcessId(TaskItem->hWnd, + &dwProcessIdTask) && + dwProcessIdTask == dwProcessId) + { + return TaskItem; + } + } + + TaskItem++; + } + + return NULL; + } + + PTASK_ITEM AllocTaskItem() + { + if (TaskItemCount >= MAX_TASKS_COUNT) + { + /* We need the most significant bit in 16 bit command IDs to indicate whether it + is a task group or task item. WM_COMMAND limits command IDs to 16 bits! */ + return NULL; + } + + ASSERT(AllocatedTaskItems >= TaskItemCount); + + if (TaskItemCount == 0) + { + TaskItems = (PTASK_ITEM) HeapAlloc(hProcessHeap, + 0, + TASK_ITEM_ARRAY_ALLOC * sizeof(*TaskItems)); + if (TaskItems != NULL) + { + AllocatedTaskItems = TASK_ITEM_ARRAY_ALLOC; + } + else + return NULL; + } + else if (TaskItemCount >= AllocatedTaskItems) + { + PTASK_ITEM NewArray; + SIZE_T NewArrayLength, ActiveTaskItemIndex; + + NewArrayLength = AllocatedTaskItems + TASK_ITEM_ARRAY_ALLOC; + + NewArray = (PTASK_ITEM) HeapReAlloc(hProcessHeap, + 0, + TaskItems, + NewArrayLength * sizeof(*TaskItems)); + if (NewArray != NULL) + { + if (ActiveTaskItem != NULL) + { + /* Fixup the ActiveTaskItem pointer */ + ActiveTaskItemIndex = ActiveTaskItem - TaskItems; + ActiveTaskItem = NewArray + ActiveTaskItemIndex; + } + AllocatedTaskItems = (WORD) NewArrayLength; + TaskItems = NewArray; + } + else + return NULL; + } + + return TaskItems + TaskItemCount++; + } + + VOID FreeTaskItem( + IN OUT PTASK_ITEM TaskItem) + { + WORD wIndex; + + if (TaskItem == ActiveTaskItem) + ActiveTaskItem = NULL; + + wIndex = (WORD) (TaskItem - TaskItems); + if (wIndex + 1 < TaskItemCount) + { + MoveMemory(TaskItem, + TaskItem + 1, + (TaskItemCount - wIndex - 1) * sizeof(*TaskItem)); + } + + TaskItemCount--; + } + + VOID DeleteTaskItem( + IN OUT PTASK_ITEM TaskItem) + { + if (!IsDestroying) + { + /* Delete the task button from the toolbar */ + DeleteTaskItemButton( + TaskItem); + } + + /* Remove the task from it's group */ + RemoveTaskFromTaskGroup( + TaskItem); + + /* Free the task item */ + FreeTaskItem( + TaskItem); + } + + VOID CheckActivateTaskItem( + IN OUT PTASK_ITEM TaskItem) + { + PTASK_ITEM CurrentTaskItem; + PTASK_GROUP TaskGroup = NULL; + + CurrentTaskItem = ActiveTaskItem; + + if (TaskItem != NULL) + TaskGroup = TaskItem->Group; + + if (IsGroupingEnabled && + TaskGroup != NULL && + TaskGroup->IsCollapsed) + { + /* FIXME */ + return; + } + + if (CurrentTaskItem != NULL) + { + PTASK_GROUP CurrentTaskGroup; + + if (CurrentTaskItem == TaskItem) + return; + + CurrentTaskGroup = CurrentTaskItem->Group; + + if (IsGroupingEnabled && + CurrentTaskGroup != NULL && + CurrentTaskGroup->IsCollapsed) + { + if (CurrentTaskGroup == TaskGroup) + return; + + /* FIXME */ + } + else + { + ActiveTaskItem = NULL; + if (CurrentTaskItem->Index >= 0) + { + UpdateTaskItemButton(CurrentTaskItem); + } + } + } + + ActiveTaskItem = TaskItem; + + if (TaskItem != NULL && TaskItem->Index >= 0) + { + UpdateTaskItemButton(TaskItem); + } + else if (TaskItem == NULL) + { + TRACE("Active TaskItem now NULL\n"); + } + } + + PTASK_ITEM + FindTaskItemByIndex( + IN INT Index) + { + PTASK_ITEM TaskItem, LastItem; + + TaskItem = TaskItems; + LastItem = TaskItem + TaskItemCount; + while (TaskItem != LastItem) + { + if (TaskItem->Index == Index) + return TaskItem; + + TaskItem++; + } + + return NULL; + } + + PTASK_GROUP + FindTaskGroupByIndex( + IN INT Index) + { + PTASK_GROUP CurrentGroup; + + CurrentGroup = TaskGroups; + while (CurrentGroup != NULL) + { + if (CurrentGroup->Index == Index) + break; + + CurrentGroup = CurrentGroup->Next; + } + + return CurrentGroup; + } + + BOOL AddTask(IN HWND hWnd) + { + PTASK_ITEM TaskItem; + + if (!::IsWindow(hWnd) || Tray->IsSpecialHWND(hWnd)) + return FALSE; + + TaskItem = FindTaskItem(hWnd); + if (TaskItem == NULL) + { + TRACE("Add window 0x%p\n", hWnd); + TaskItem = AllocTaskItem(); + if (TaskItem != NULL) + { + ZeroMemory(TaskItem, + sizeof(*TaskItem)); + TaskItem->hWnd = hWnd; + TaskItem->Index = -1; + TaskItem->Group = AddToTaskGroup( + hWnd); + + if (!IsDestroying) + { + AddTaskItemButton( + TaskItem); + } + } + } + + return TaskItem != NULL; + } + + BOOL ActivateTaskItem( + IN OUT PTASK_ITEM TaskItem OPTIONAL) + { + if (TaskItem != NULL) + { + TRACE("Activate window 0x%p on button %d\n", TaskItem->hWnd, TaskItem->Index); + } + + CheckActivateTaskItem(TaskItem); + + return FALSE; + } + + BOOL ActivateTask( + IN HWND hWnd) + { + PTASK_ITEM TaskItem; + + if (!hWnd) + { + return ActivateTaskItem(NULL); + } + + TaskItem = FindTaskItem( + hWnd); + if (TaskItem == NULL) + { + TaskItem = FindOtherTaskItem( + hWnd); + } + + if (TaskItem == NULL) + { + WARN("Activate window 0x%p, could not find task\n", hWnd); + RefreshWindowList(); + } + + return ActivateTaskItem(TaskItem); + } + + BOOL DeleteTask( + IN HWND hWnd) + { + PTASK_ITEM TaskItem; + + TaskItem = FindTaskItem( + hWnd); + if (TaskItem != NULL) + { + TRACE("Delete window 0x%p on button %d\n", hWnd, TaskItem->Index); + DeleteTaskItem( + TaskItem); + return TRUE; + } + //else + //TRACE("Failed to delete window 0x%p\n", hWnd); + + return FALSE; + } + + VOID DeleteAllTasks() + { + PTASK_ITEM CurrentTask; + + if (TaskItemCount > 0) + { + CurrentTask = TaskItems + TaskItemCount; + do + { + DeleteTaskItem( + --CurrentTask); + } while (CurrentTask != TaskItems); + } + } + + VOID FlashTaskItem( + IN OUT PTASK_ITEM TaskItem) + { + TaskItem->RenderFlashed = 1; + UpdateTaskItemButton( + TaskItem); + } + + BOOL FlashTask( + IN HWND hWnd) + { + PTASK_ITEM TaskItem; + + TaskItem = FindTaskItem( + hWnd); + if (TaskItem != NULL) + { + TRACE("Flashing window 0x%p on button %d\n", hWnd, TaskItem->Index); + FlashTaskItem( + TaskItem); + return TRUE; + } + + return FALSE; + } + + VOID RedrawTaskItem( + IN OUT PTASK_ITEM TaskItem) + { + PTASK_GROUP TaskGroup; + + TaskGroup = TaskItem->Group; + if (IsGroupingEnabled && TaskGroup != NULL) + { + if (TaskGroup->IsCollapsed && TaskGroup->Index >= 0) + { + UpdateTaskGroupButton( + TaskGroup); + } + else if (TaskItem->Index >= 0) + { + goto UpdateTaskItem; + } + } + else if (TaskItem->Index >= 0) + { + UpdateTaskItem: + TaskItem->RenderFlashed = 0; + UpdateTaskItemButton( + TaskItem); + } + } + + + BOOL RedrawTask( + IN HWND hWnd) + { + PTASK_ITEM TaskItem; + + TaskItem = FindTaskItem( + hWnd); + if (TaskItem != NULL) + { + RedrawTaskItem( + TaskItem); + return TRUE; + } + + return FALSE; + } + + INT UpdateTbButtonSpacing( + IN BOOL bHorizontal, + IN UINT uiRows, + IN UINT uiBtnsPerLine) + { + TBMETRICS tbm; + + tbm.cbSize = sizeof(tbm); + tbm.dwMask = TBMF_BARPAD | TBMF_BUTTONSPACING; + + tbm.cxBarPad = tbm.cyBarPad = 0; + + if (bHorizontal || uiBtnsPerLine > 1) + tbm.cxButtonSpacing = (3 * GetSystemMetrics(SM_CXEDGE) / 2); + else + tbm.cxButtonSpacing = 0; + + if (!bHorizontal || uiRows > 1) + tbm.cyButtonSpacing = (3 * GetSystemMetrics(SM_CYEDGE) / 2); + else + tbm.cyButtonSpacing = 0; + + SendMessage(hWndToolbar, + TB_SETMETRICS, + 0, + (LPARAM) &tbm); + + return tbm.cxButtonSpacing; + } + + + VOID UpdateButtonsSize(IN BOOL bRedrawDisabled) + { + RECT rcClient; + UINT uiRows, uiMax, uiMin, uiBtnsPerLine, ui; + LONG NewBtnSize; + BOOL Horizontal; + TBBUTTONINFO tbbi; + TBMETRICS tbm; + + if (GetClientRect(&rcClient) && + !IsRectEmpty(&rcClient)) + { + if (ToolbarBtnCount > 0) + { + ZeroMemory(&tbm, sizeof(tbm)); + tbm.cbSize = sizeof(tbm); + tbm.dwMask = TBMF_BUTTONSPACING; + SendMessage(hWndToolbar, + TB_GETMETRICS, + 0, + (LPARAM) &tbm); + + uiRows = (rcClient.bottom + tbm.cyButtonSpacing) / (ButtonSize.cy + tbm.cyButtonSpacing); + if (uiRows == 0) + uiRows = 1; + + uiBtnsPerLine = (ToolbarBtnCount + uiRows - 1) / uiRows; + + Horizontal = Tray->IsHorizontal(); + + if (!bRedrawDisabled) + BeginUpdate(); + + /* We might need to update the button spacing */ + tbm.cxButtonSpacing = UpdateTbButtonSpacing( + Horizontal, + uiRows, + uiBtnsPerLine); + + /* Calculate the ideal width and make sure it's within the allowed range */ + NewBtnSize = (rcClient.right - (uiBtnsPerLine * tbm.cxButtonSpacing)) / uiBtnsPerLine; + + /* Determine the minimum and maximum width of a button */ + if (Horizontal) + uiMax = GetSystemMetrics(SM_CXMINIMIZED); + else + uiMax = rcClient.right; + + uiMin = GetSystemMetrics(SM_CXSIZE) + (2 * GetSystemMetrics(SM_CXEDGE)); + + if (NewBtnSize < (LONG) uiMin) + NewBtnSize = uiMin; + if (NewBtnSize > (LONG)uiMax) + NewBtnSize = uiMax; + + ButtonSize.cx = NewBtnSize; + + /* Recalculate how many buttons actually fit into one line */ + uiBtnsPerLine = rcClient.right / (NewBtnSize + tbm.cxButtonSpacing); + if (uiBtnsPerLine == 0) + uiBtnsPerLine++; + TbButtonsPerLine = uiBtnsPerLine; + + tbbi.cbSize = sizeof(tbbi); + tbbi.dwMask = TBIF_BYINDEX | TBIF_SIZE | TBIF_STATE; + tbbi.cx = (INT) NewBtnSize; + + for (ui = 0; ui != ToolbarBtnCount; ui++) + { + tbbi.fsState = TBSTATE_ENABLED; + + /* Check if we're updating a button that is the last one in the + line. If so, we need to set the TBSTATE_WRAP flag! */ + if ((ui + 1) % uiBtnsPerLine == 0) + tbbi.fsState |= TBSTATE_WRAP; + + if (ActiveTaskItem != NULL && + ActiveTaskItem->Index == (INT)ui) + { + tbbi.fsState |= TBSTATE_CHECKED; + } + + SendMessage(hWndToolbar, + TB_SETBUTTONINFO, + (WPARAM) ui, + (LPARAM) &tbbi); + } + +#if 0 + /* FIXME: Force the window to the correct position in case some idiot + did something to us */ + SetWindowPos(hWndToolbar, + NULL, + 0, + 0, + rcClient.right, /* FIXME */ + rcClient.bottom, /* FIXME */ + SWP_NOACTIVATE | SWP_NOZORDER); +#endif + } + else + { + TbButtonsPerLine = 0; + ButtonSize.cx = 0; + } + } + + EndUpdate(); + } + + BOOL CALLBACK EnumWindowsProc(IN HWND hWnd) + { + /* Only show windows that still exist and are visible and none of explorer's + special windows (such as the desktop or the tray window) */ + if (::IsWindow(hWnd) && ::IsWindowVisible(hWnd) && + !Tray->IsSpecialHWND(hWnd)) + { + DWORD exStyle = GetWindowLong(hWnd, GWL_EXSTYLE); + /* Don't list popup windows and also no tool windows */ + if ((GetWindow(hWnd, GW_OWNER) == NULL || exStyle & WS_EX_APPWINDOW) && + !(exStyle & WS_EX_TOOLWINDOW)) + { + TRACE("Adding task for %p...\n", hWnd); + AddTask(hWnd); + } + + } + + return TRUE; + } + + static BOOL CALLBACK s_EnumWindowsProc(IN HWND hWnd, + IN LPARAM lParam) + { + CTaskSwitchWnd * This = (CTaskSwitchWnd *) lParam; + + return This->EnumWindowsProc(hWnd); + } + + BOOL RefreshWindowList() + { + TRACE("Refreshing window list...\n"); + /* Add all windows to the toolbar */ + return EnumWindows(s_EnumWindowsProc, (LPARAM)this); + } + + LRESULT OnThemeChanged() + { + if (TaskBandTheme) + CloseThemeData(TaskBandTheme); + + if (IsThemeActive()) + TaskBandTheme = OpenThemeData(m_hWnd, L"TaskBand"); + else + TaskBandTheme = NULL; + return TRUE; + } + + LRESULT OnThemeChanged(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + return OnThemeChanged(); + } + + LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + hWndToolbar = CreateWindowEx(0, + TOOLBARCLASSNAME, + szRunningApps, + WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | + TBSTYLE_TOOLTIPS | TBSTYLE_WRAPABLE | TBSTYLE_LIST | TBSTYLE_TRANSPARENT | + CCS_TOP | CCS_NORESIZE | CCS_NODIVIDER, + 0, + 0, + 0, + 0, + m_hWnd, + NULL, + hExplorerInstance, + NULL); + + if (hWndToolbar != NULL) + { + HMODULE hShell32; + SIZE BtnSize; + + TaskBar.SubclassWindow(hWndToolbar); + + SetWindowTheme(hWndToolbar, L"TaskBand", NULL); + OnThemeChanged(); + + /* Identify the version we're using */ + SendMessage(hWndToolbar, + TB_BUTTONSTRUCTSIZE, + sizeof(TBBUTTON), + 0); + + TaskIcons = (IImageList*) ImageList_Create(16, 16, ILC_COLOR32 | ILC_MASK, 0, 1000); + SendMessage(hWndToolbar, TB_SETIMAGELIST, 0, (LPARAM) TaskIcons); + + /* Calculate the default button size. Don't save this in ButtonSize.cx so that + the actual button width gets updated correctly on the first recalculation */ + BtnSize.cx = GetSystemMetrics(SM_CXMINIMIZED); + ButtonSize.cy = BtnSize.cy = GetSystemMetrics(SM_CYSIZE) + (2 * GetSystemMetrics(SM_CYEDGE)); + SendMessage(hWndToolbar, TB_SETBUTTONSIZE, 0, (LPARAM) MAKELONG(BtnSize.cx, BtnSize.cy)); + + /* We don't want to see partially clipped buttons...not that we could see them... */ +#if 0 + SendMessage(hWndToolbar, + TB_SETEXTENDEDSTYLE, + 0, + TBSTYLE_EX_HIDECLIPPEDBUTTONS); +#endif + + /* Set proper spacing between buttons */ + UpdateTbButtonSpacing(Tray->IsHorizontal(), 0, 0); + + /* Register the shell hook */ + ShellHookMsg = RegisterWindowMessage(TEXT("SHELLHOOK")); + + DbgPrint("ShellHookMsg got assigned number %d\n", ShellHookMsg); + + hShell32 = GetModuleHandle(TEXT("SHELL32.DLL")); + if (hShell32 != NULL) + { + REGSHELLHOOK RegShellHook; + + /* RegisterShellHook */ + RegShellHook = (REGSHELLHOOK) GetProcAddress(hShell32, (LPCSTR) ((LONG) 181)); + if (RegShellHook != NULL) + { + RegShellHook(m_hWnd, 3); /* 1 if no NT! We're targeting NT so we don't care! */ + } + } + + RefreshWindowList(); + + /* Recalculate the button size */ + UpdateButtonsSize(FALSE); + } + +#if DUMP_TASKS != 0 + SetTimer(hwnd, 1, 5000, NULL); +#endif + return TRUE; + } + + LRESULT OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + HMODULE hShell32; + + IsDestroying = TRUE; + + /* Unregister the shell hook */ + hShell32 = GetModuleHandle(TEXT("SHELL32.DLL")); + if (hShell32 != NULL) + { + REGSHELLHOOK RegShellHook; + + /* RegisterShellHook */ + RegShellHook = (REGSHELLHOOK) GetProcAddress(hShell32, + (LPCSTR) ((LONG) 181)); + if (RegShellHook != NULL) + { + RegShellHook(m_hWnd, + FALSE); + } + } + + CloseThemeData(TaskBandTheme); + DeleteAllTasks(); + return TRUE; + } + + BOOL HandleAppCommand( + IN WPARAM wParam, + IN LPARAM lParam) + { + BOOL Ret = FALSE; + + switch (GET_APPCOMMAND_LPARAM(lParam)) + { + case APPCOMMAND_BROWSER_SEARCH: + Ret = SHFindFiles(NULL, + NULL); + break; + + case APPCOMMAND_BROWSER_HOME: + case APPCOMMAND_LAUNCH_MAIL: + default: + TRACE("Shell app command %d unhandled!\n", (INT) GET_APPCOMMAND_LPARAM(lParam)); + break; + } + + return Ret; + } + + LRESULT HandleShellHookMsg(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + BOOL Ret = FALSE; + + /* In case the shell hook wasn't registered properly, ignore WM_NULLs*/ + if (uMsg == 0) + { + bHandled = FALSE; + return 0; + } + + DbgPrint("Received shell hook message: wParam=%08lx, lParam=%08lx\n", wParam, lParam); + + switch ((INT) wParam) + { + case HSHELL_APPCOMMAND: + HandleAppCommand( + wParam, + lParam); + Ret = TRUE; + break; + + case HSHELL_WINDOWCREATED: + Ret = AddTask( + (HWND) lParam); + break; + + case HSHELL_WINDOWDESTROYED: + /* The window still exists! Delay destroying it a bit */ + DeleteTask((HWND) lParam); + Ret = TRUE; + break; + + case HSHELL_RUDEAPPACTIVATED: + case HSHELL_WINDOWACTIVATED: + if (lParam) + { + ActivateTask((HWND) lParam); + Ret = TRUE; + } + break; + + case HSHELL_FLASH: + FlashTask((HWND) lParam); + Ret = TRUE; + break; + + case HSHELL_REDRAW: + RedrawTask((HWND) lParam); + Ret = TRUE; + break; + + case HSHELL_TASKMAN: + PostMessage(Tray->GetHWND(), TWM_OPENSTARTMENU, 0, 0); + break; + + case HSHELL_ACTIVATESHELLWINDOW: + case HSHELL_LANGUAGE: + case HSHELL_SYSMENU: + case HSHELL_ENDTASK: + case HSHELL_ACCESSIBILITYSTATE: + case HSHELL_WINDOWREPLACED: + case HSHELL_WINDOWREPLACING: + + case HSHELL_GETMINRECT: + default: + { + int i, found; + for (i = 0, found = 0; i != sizeof(hshell_msg) / sizeof(hshell_msg[0]); i++) + { + if (hshell_msg[i].msg == (INT) wParam) + { + TRACE("Shell message %ws unhandled (lParam = 0x%p)!\n", hshell_msg[i].msg_name, lParam); + found = 1; + break; + } + } + if (!found) + { + TRACE("Shell message %d unhandled (lParam = 0x%p)!\n", (INT) wParam, lParam); + } + break; + } + } + + return Ret; + } + + VOID EnableGrouping( + IN BOOL bEnable) + { + IsGroupingEnabled = bEnable; + + /* Collapse or expand groups if neccessary */ + UpdateButtonsSize( + FALSE); + } + + VOID HandleTaskItemClick( + IN OUT PTASK_ITEM TaskItem) + { + BOOL bIsMinimized; + BOOL bIsActive; + + if (::IsWindow(TaskItem->hWnd)) + { + bIsMinimized = IsIconic(TaskItem->hWnd); + bIsActive = (TaskItem == ActiveTaskItem); + + TRACE("Active TaskItem %p, selected TaskItem %p\n", ActiveTaskItem, TaskItem); + if (ActiveTaskItem) + TRACE("Active TaskItem hWnd=%p, TaskItem hWnd %p\n", ActiveTaskItem->hWnd, TaskItem->hWnd); + + TRACE("Valid button clicked. HWND=%p, IsMinimized=%s, IsActive=%s...\n", + TaskItem->hWnd, bIsMinimized ? "Yes" : "No", bIsActive ? "Yes" : "No"); + + if (!bIsMinimized && bIsActive) + { + PostMessage(TaskItem->hWnd, + WM_SYSCOMMAND, + SC_MINIMIZE, + 0); + TRACE("Valid button clicked. App window Minimized.\n"); + } + else + { + if (bIsMinimized) + { + PostMessage(TaskItem->hWnd, + WM_SYSCOMMAND, + SC_RESTORE, + 0); + TRACE("Valid button clicked. App window Restored.\n"); + } + + SetForegroundWindow(TaskItem->hWnd); + TRACE("Valid button clicked. App window Activated.\n"); + } + } + } + + VOID HandleTaskGroupClick( + IN OUT PTASK_GROUP TaskGroup) + { + /* TODO: Show task group menu */ + } + + BOOL HandleButtonClick( + IN WORD wIndex) + { + PTASK_ITEM TaskItem; + PTASK_GROUP TaskGroup; + + if (IsGroupingEnabled) + { + TaskGroup = FindTaskGroupByIndex((INT) wIndex); + if (TaskGroup != NULL && TaskGroup->IsCollapsed) + { + HandleTaskGroupClick( + TaskGroup); + return TRUE; + } + } + + TaskItem = FindTaskItemByIndex((INT) wIndex); + if (TaskItem != NULL) + { + HandleTaskItemClick( + TaskItem); + return TRUE; + } + + return FALSE; + } + + + VOID HandleTaskItemRightClick( + IN OUT PTASK_ITEM TaskItem) + { + + HMENU hmenu = GetSystemMenu(TaskItem->hWnd, FALSE); + + if (hmenu) { + POINT pt; + int cmd; + GetCursorPos(&pt); + cmd = TrackPopupMenu(hmenu, TPM_LEFTBUTTON | TPM_RIGHTBUTTON | TPM_RETURNCMD, pt.x, pt.y, 0, hWndToolbar, NULL); + if (cmd) { + SetForegroundWindow(TaskItem->hWnd); // reactivate window after the context menu has closed + PostMessage(TaskItem->hWnd, WM_SYSCOMMAND, cmd, 0); + } + } + } + + VOID HandleTaskGroupRightClick( + IN OUT PTASK_GROUP TaskGroup) + { + /* TODO: Show task group right click menu */ + } + + BOOL HandleButtonRightClick( + IN WORD wIndex) + { + PTASK_ITEM TaskItem; + PTASK_GROUP TaskGroup; + if (IsGroupingEnabled) + { + TaskGroup = FindTaskGroupByIndex((INT) wIndex); + if (TaskGroup != NULL && TaskGroup->IsCollapsed) + { + HandleTaskGroupRightClick( + TaskGroup); + return TRUE; + } + } + + TaskItem = FindTaskItemByIndex((INT) wIndex); + + if (TaskItem != NULL) + { + HandleTaskItemRightClick( + TaskItem); + return TRUE; + } + + return FALSE; + } + + + LRESULT HandleItemPaint(IN OUT NMTBCUSTOMDRAW *nmtbcd) + { + LRESULT Ret = CDRF_DODEFAULT; + PTASK_GROUP TaskGroup; + PTASK_ITEM TaskItem; + + TaskItem = FindTaskItemByIndex((INT) nmtbcd->nmcd.dwItemSpec); + TaskGroup = FindTaskGroupByIndex((INT) nmtbcd->nmcd.dwItemSpec); + if (TaskGroup == NULL && TaskItem != NULL) + { + ASSERT(TaskItem != NULL); + + if (TaskItem != NULL && ::IsWindow(TaskItem->hWnd)) + { + /* Make the entire button flashing if neccessary */ + if (nmtbcd->nmcd.uItemState & CDIS_MARKED) + { + Ret = TBCDRF_NOBACKGROUND; + if (!TaskBandTheme) + { + SelectObject(nmtbcd->nmcd.hdc, GetSysColorBrush(COLOR_HIGHLIGHT)); + Rectangle(nmtbcd->nmcd.hdc, + nmtbcd->nmcd.rc.left, + nmtbcd->nmcd.rc.top, + nmtbcd->nmcd.rc.right, + nmtbcd->nmcd.rc.bottom); + } + else + { + DrawThemeBackground(TaskBandTheme, nmtbcd->nmcd.hdc, TDP_FLASHBUTTON, 0, &nmtbcd->nmcd.rc, 0); + } + nmtbcd->clrText = GetSysColor(COLOR_HIGHLIGHTTEXT); + return Ret; + } + } + } + else if (TaskGroup != NULL) + { + /* FIXME: Implement painting for task groups */ + } + return Ret; + } + + LRESULT HandleToolbarNotification(IN const NMHDR *nmh) + { + LRESULT Ret = 0; + + switch (nmh->code) + { + case NM_CUSTOMDRAW: + { + LPNMTBCUSTOMDRAW nmtbcd = (LPNMTBCUSTOMDRAW) nmh; + + switch (nmtbcd->nmcd.dwDrawStage) + { + + case CDDS_ITEMPREPAINT: + Ret = HandleItemPaint( + nmtbcd); + break; + + case CDDS_PREPAINT: + Ret = CDRF_NOTIFYITEMDRAW; + break; + + default: + Ret = CDRF_DODEFAULT; + break; + } + break; + } + } + + return Ret; + } + + LRESULT DrawBackground(HDC hdc) + { + RECT rect; + + GetClientRect(&rect); + DrawThemeParentBackground(m_hWnd, hdc, &rect); + + return TRUE; + } + + LRESULT OnEraseBackground(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + HDC hdc = (HDC) wParam; + + if (!IsAppThemed()) + { + bHandled = FALSE; + return 0; + } + + return DrawBackground(hdc); + } + + LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + SIZE szClient; + + szClient.cx = LOWORD(lParam); + szClient.cy = HIWORD(lParam); + if (hWndToolbar != NULL) + { + ::SetWindowPos(hWndToolbar, + NULL, + 0, + 0, + szClient.cx, + szClient.cy, + SWP_NOZORDER); + + UpdateButtonsSize( + FALSE); + } + return TRUE; + } + + LRESULT OnNcHitTestToolbar(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + POINT pt; + + /* See if the mouse is on a button */ + pt.x = GET_X_LPARAM(lParam); + pt.y = GET_Y_LPARAM(lParam); + ScreenToClient(&pt); + + INT index = TaskBar.SendMessage(TB_HITTEST, 0, (LPARAM) &pt); + if (index < 0) + { + /* Make the control appear to be transparent outside of any buttons */ + return HTTRANSPARENT; + } + + bHandled = FALSE; + return 0; + } + + LRESULT OnNcHitTest(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + LRESULT Ret = TRUE; + /* We want the tray window to be draggable everywhere, so make the control + appear transparent */ + Ret = DefWindowProc(uMsg, wParam, lParam); + if (Ret != HTVSCROLL && Ret != HTHSCROLL) + Ret = HTTRANSPARENT; + return Ret; + } + + LRESULT OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + LRESULT Ret = TRUE; + if (lParam != 0 && (HWND) lParam == hWndToolbar) + { + HandleButtonClick( + LOWORD(wParam)); + } + return Ret; + } + + LRESULT OnNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + LRESULT Ret = TRUE; + const NMHDR *nmh = (const NMHDR *) lParam; + + if (nmh->hwndFrom == hWndToolbar) + { + Ret = HandleToolbarNotification( + nmh); + } + return Ret; + } + + LRESULT OnEnableGrouping(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + LRESULT Ret = IsGroupingEnabled; + if ((BOOL)wParam != IsGroupingEnabled) + { + EnableGrouping((BOOL) wParam); + } + return Ret; + } + + LRESULT OnUpdateTaskbarPos(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + /* Update the button spacing */ + UpdateTbButtonSpacing( + Tray->IsHorizontal(), + 0, + 0); + return TRUE; + } + + LRESULT OnContextMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + LRESULT Ret; + if (hWndToolbar != NULL) + { + POINT pt; + INT_PTR iBtn; + + pt.x = (LONG) LOWORD(lParam); + pt.y = (LONG) HIWORD(lParam); + + MapWindowPoints(NULL, + hWndToolbar, + &pt, + 1); + + iBtn = (INT_PTR) SendMessage(hWndToolbar, + TB_HITTEST, + 0, + (LPARAM) &pt); + if (iBtn >= 0) + { + HandleButtonRightClick( + iBtn); + } + else + goto ForwardContextMenuMsg; + } + else + { + ForwardContextMenuMsg: + /* Forward message */ + Ret = SendMessage(Tray->GetHWND(), + uMsg, + wParam, + lParam); + } + return Ret; + } + + LRESULT OnKludgeItemRect(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + PTASK_ITEM TaskItem = FindTaskItem((HWND) wParam); + if (TaskItem) + { + RECT* prcMinRect = (RECT*) lParam; + RECT rcItem, rcToolbar; + SendMessageW(hWndToolbar, TB_GETITEMRECT, TaskItem->Index, (LPARAM) &rcItem); + GetWindowRect(hWndToolbar, &rcToolbar); + + OffsetRect(&rcItem, rcToolbar.left, rcToolbar.top); + + *prcMinRect = rcItem; + return TRUE; + } + return FALSE; + } + + LRESULT OnTimer(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { +#if DUMP_TASKS != 0 + switch (wParam) + { + case 1: + DumpTasks(); + break; + } +#endif + return TRUE; + } + + DECLARE_WND_CLASS_EX(szTaskSwitchWndClass, CS_DBLCLKS, COLOR_3DFACE) + + BEGIN_MSG_MAP(CTaskSwitchWnd) + MESSAGE_HANDLER(WM_THEMECHANGED, OnThemeChanged) + MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground) + MESSAGE_HANDLER(WM_SIZE, OnSize) + MESSAGE_HANDLER(WM_CREATE, OnCreate) + MESSAGE_HANDLER(WM_DESTROY, OnDestroy) + MESSAGE_HANDLER(WM_NCHITTEST, OnNcHitTest) + MESSAGE_HANDLER(WM_COMMAND, OnCommand) + MESSAGE_HANDLER(WM_NOTIFY, OnNotify) + MESSAGE_HANDLER(TSWM_ENABLEGROUPING, OnEnableGrouping) + MESSAGE_HANDLER(TSWM_UPDATETASKBARPOS, OnUpdateTaskbarPos) + MESSAGE_HANDLER(WM_CONTEXTMENU, OnContextMenu) + MESSAGE_HANDLER(WM_TIMER, OnTimer) + MESSAGE_HANDLER(ShellHookMsg, HandleShellHookMsg) + ALT_MSG_MAP(1) + MESSAGE_HANDLER(WM_NCHITTEST, OnNcHitTestToolbar) + END_MSG_MAP() + + HWND _Init(IN HWND hWndParent, IN OUT ITrayWindow *tray) + { + Tray = tray; + hWndNotify = GetParent(); + IsGroupingEnabled = TRUE; /* FIXME */ + return Create(hWndParent, 0, szRunningApps, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP); + } +}; + +HWND +CreateTaskSwitchWnd(IN HWND hWndParent, IN OUT ITrayWindow *Tray) +{ + CTaskSwitchWnd * instance; + + // TODO: Destroy after the window is destroyed + instance = new CTaskSwitchWnd(); + + return instance->_Init(hWndParent, Tray); +} diff --git a/base/shell/explorer-new/tbsite.c b/base/shell/explorer-new/tbsite.c deleted file mode 100644 index b29879d683c..00000000000 --- a/base/shell/explorer-new/tbsite.c +++ /dev/null @@ -1,1067 +0,0 @@ -/* - * ReactOS Explorer - * - * Copyright 2006 - 2007 Thomas Weidenmueller - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "precomp.h" - -#include - -#include "undoc.h" - -/***************************************************************************** - ** ITrayBandSite ************************************************************ - *****************************************************************************/ - -static const ITrayBandSiteVtbl ITrayBandSiteImpl_Vtbl; -static const IBandSiteVtbl IBandSiteImpl_Vtbl; - -typedef struct -{ - const ITrayBandSiteVtbl *lpVtbl; - const IBandSiteVtbl *lpBandSiteVtbl; - LONG Ref; - - ITrayWindow *Tray; - - IUnknown *punkInner; - IBandSite *BandSite; - ITaskBand *TaskBand; - IWinEventHandler *WindowEventHandler; - IContextMenu *ContextMenu; - - HWND hWndRebar; - - union - { - DWORD dwFlags; - struct - { - DWORD Locked : 1; - }; - }; -} ITrayBandSiteImpl; - -static HRESULT -ITrayBandSiteImpl_Update(IN OUT ITrayBandSiteImpl *This); - -static IUnknown * -IUnknown_from_ITrayBandSiteImpl(ITrayBandSiteImpl *This) -{ - return (IUnknown *)&This->lpVtbl; -} - -IMPL_CASTS(ITrayBandSite, ITrayBandSite, lpVtbl) -IMPL_CASTS(IBandSite, ITrayBandSite, lpBandSiteVtbl) - -static ULONG STDMETHODCALLTYPE -ITrayBandSiteImpl_AddRef(IN OUT ITrayBandSite *iface) -{ - ITrayBandSiteImpl *This = ITrayBandSiteImpl_from_ITrayBandSite(iface); - - return InterlockedIncrement(&This->Ref); -} - -static VOID -ITrayBandSiteImpl_Free(IN OUT ITrayBandSiteImpl *This) -{ - if (This->BandSite != NULL) - { - IBandSite_Release(This->BandSite); - This->BandSite = NULL; - } - - if (This->WindowEventHandler != NULL) - { - IWinEventHandler_Release(This->WindowEventHandler); - This->WindowEventHandler = NULL; - } - - if (This->ContextMenu != NULL) - { - IContextMenu_Release(This->ContextMenu); - This->ContextMenu = NULL; - } - - if (This->punkInner != NULL) - { - IUnknown_Release(This->punkInner); - This->punkInner = NULL; - } - - HeapFree(hProcessHeap, - 0, - This); -} - -static ULONG STDMETHODCALLTYPE -ITrayBandSiteImpl_Release(IN OUT ITrayBandSite *iface) -{ - ITrayBandSiteImpl *This = ITrayBandSiteImpl_from_ITrayBandSite(iface); - ULONG Ret; - - Ret = InterlockedDecrement(&This->Ref); - - if (Ret == 0) - ITrayBandSiteImpl_Free(This); - - return Ret; -} - -static HRESULT STDMETHODCALLTYPE -ITrayBandSiteImpl_QueryInterface(IN OUT ITrayBandSite *iface, - IN REFIID riid, - OUT LPVOID *ppvObj) -{ - ITrayBandSiteImpl *This; - - if (ppvObj == NULL) - return E_POINTER; - - This = ITrayBandSiteImpl_from_ITrayBandSite(iface); - - if (IsEqualIID(riid, &IID_IUnknown) || - IsEqualIID(riid, &IID_IBandSiteStreamCallback)) - { - /* NOTE: IID_IBandSiteStreamCallback is queried by the shell, we - implement this interface directly */ - *ppvObj = IUnknown_from_ITrayBandSiteImpl(This); - } - else if (IsEqualIID(riid, &IID_IBandSite)) - { - *ppvObj = IBandSite_from_ITrayBandSiteImpl(This); - } - else if (IsEqualIID(riid, &IID_IWinEventHandler)) - { - TRACE("ITaskBandSite: IWinEventHandler queried!\n"); - *ppvObj = NULL; - return E_NOINTERFACE; - } - else if (This->punkInner != NULL) - { - return IUnknown_QueryInterface(This->punkInner, - riid, - ppvObj); - } - else - { - *ppvObj = NULL; - return E_NOINTERFACE; - } - - ITrayBandSiteImpl_AddRef(iface); - return S_OK; -} - -static HRESULT STDMETHODCALLTYPE -ITrayBandSiteImpl_OnLoad(IN OUT ITrayBandSite *iface, - IN OUT IStream *pStm, - IN REFIID riid, - OUT PVOID *pvObj) -{ - ITrayBandSiteImpl *This = ITrayBandSiteImpl_from_ITrayBandSite(iface); - LARGE_INTEGER liPosZero; - ULARGE_INTEGER liCurrent; - CLSID clsid; - ULONG ulRead; - HRESULT hRet; - - /* NOTE: Callback routine called by the shell while loading the task band - stream. We use it to intercept the default behavior when the task - band is loaded from the stream. - - NOTE: riid always points to IID_IUnknown! This is because the shell hasn't - read anything from the stream and therefore doesn't know what CLSID - it's dealing with. We'll have to find it out ourselves by reading - the GUID from the stream. */ - - /* Read the current position of the stream, we'll have to reset it everytime - we read a CLSID that's not the task band... */ - ZeroMemory(&liPosZero, - sizeof(liPosZero)); - hRet = IStream_Seek(pStm, - liPosZero, - STREAM_SEEK_CUR, - &liCurrent); - - if (SUCCEEDED(hRet)) - { - /* Now let's read the CLSID from the stream and see if it's our task band */ -#if defined(IStream_Read) - hRet = IStream_Read(pStm, - &clsid, - sizeof(clsid), - &ulRead); -#else - ulRead = sizeof(clsid); - hRet = IStream_Read(pStm, - &clsid, - sizeof(clsid)); -#endif - if (SUCCEEDED(hRet) && ulRead == sizeof(clsid)) - { - if (IsEqualGUID(&clsid, - &CLSID_ITaskBand)) - { - ASSERT(This->TaskBand != NULL); - /* We're trying to load the task band! Let's create it... */ - - hRet = ITaskBand_QueryInterface(This->TaskBand, - riid, - pvObj); - if (SUCCEEDED(hRet)) - { - /* Load the stream */ - TRACE("IBandSiteStreamCallback::OnLoad intercepted the task band CLSID!\n"); - } - - return hRet; - } - } - } - - /* Reset the position and let the shell do all the work for us */ - hRet = IStream_Seek(pStm, - *(LARGE_INTEGER*)&liCurrent, - STREAM_SEEK_SET, - NULL); - if (SUCCEEDED(hRet)) - { - /* Let the shell handle everything else for us :) */ - hRet = OleLoadFromStream(pStm, - riid, - pvObj); - } - - if (!SUCCEEDED(hRet)) - { - TRACE("IBandSiteStreamCallback::OnLoad(0x%p, 0x%p, 0x%p) returns 0x%x\n", pStm, riid, pvObj, hRet); - } - - return hRet; -} - -static HRESULT STDMETHODCALLTYPE -ITrayBandSiteImpl_OnSave(IN OUT ITrayBandSite *iface, - IN OUT IUnknown *pUnk, - IN OUT IStream *pStm) -{ - /* NOTE: Callback routine called by the shell while saving the task band - stream. We use it to intercept the default behavior when the task - band is saved to the stream */ - /* FIXME: Implement */ - TRACE("IBandSiteStreamCallback::OnSave(0x%p, 0x%p) returns E_NOTIMPL\n", pUnk, pStm); - return E_NOTIMPL; -} - -static HRESULT -IsSameObject(IN IUnknown *punk1, - IN IUnknown *punk2) -{ - HRESULT hRet; - - hRet = IUnknown_QueryInterface(punk1, - &IID_IUnknown, - (PVOID*)&punk1); - if (!SUCCEEDED(hRet)) - return hRet; - - hRet = IUnknown_QueryInterface(punk2, - &IID_IUnknown, - (PVOID*)&punk2); - IUnknown_Release(punk1); - - if (!SUCCEEDED(hRet)) - return hRet; - - IUnknown_Release(punk2); - - /* We're dealing with the same object if the IUnknown pointers are equal */ - return (punk1 == punk2) ? S_OK : S_FALSE; -} - -static HRESULT STDMETHODCALLTYPE -ITrayBandSiteImpl_IsTaskBand(IN OUT ITrayBandSite *iface, - IN IUnknown *punk) -{ - ITrayBandSiteImpl *This = ITrayBandSiteImpl_from_ITrayBandSite(iface); - return IsSameObject((IUnknown *)This->BandSite, - punk); -} - -static HRESULT STDMETHODCALLTYPE -ITrayBandSiteImpl_ProcessMessage(IN OUT ITrayBandSite *iface, - IN HWND hWnd, - IN UINT uMsg, - IN WPARAM wParam, - IN LPARAM lParam, - OUT LRESULT *plResult) -{ - ITrayBandSiteImpl *This = ITrayBandSiteImpl_from_ITrayBandSite(iface); - HRESULT hRet; - - ASSERT(This->hWndRebar != NULL); - - /* Custom task band behavior */ - switch (uMsg) - { - case WM_NOTIFY: - { - const NMHDR *nmh = (const NMHDR *)lParam; - - if (nmh->hwndFrom == This->hWndRebar) - { - switch (nmh->code) - { - case NM_NCHITTEST: - { - LPNMMOUSE nmm = (LPNMMOUSE)lParam; - - if (nmm->dwHitInfo == RBHT_CLIENT || nmm->dwHitInfo == RBHT_NOWHERE || - nmm->dwItemSpec == (DWORD_PTR)-1) - { - /* Make the rebar control appear transparent so the user - can drag the tray window */ - *plResult = HTTRANSPARENT; - } - return S_OK; - } - - case RBN_MINMAX: - /* Deny if an Administrator disabled this "feature" */ - *plResult = (SHRestricted(REST_NOMOVINGBAND) != 0); - return S_OK; - } - } - - //TRACE("ITrayBandSite::ProcessMessage: WM_NOTIFY for 0x%p, From: 0x%p, Code: NM_FIRST-%u...\n", hWnd, nmh->hwndFrom, NM_FIRST - nmh->code); - break; - } - }; - - /* Forward to the shell's IWinEventHandler interface to get the default - shell behavior! */ - if (This->WindowEventHandler != NULL) - { - /*TRACE("Calling IWinEventHandler::ProcessMessage(0x%p, 0x%x, 0x%p, 0x%p, 0x%p) This->hWndRebar=0x%p\n", hWnd, uMsg, wParam, lParam, plResult, This->hWndRebar);*/ - hRet = IWinEventHandler_OnWinEvent(This->WindowEventHandler, - hWnd, - uMsg, - wParam, - lParam, - plResult); - if (!SUCCEEDED(hRet)) - { - if (uMsg == WM_NOTIFY) - { - const NMHDR *nmh = (const NMHDR *)lParam; - TRACE("ITrayBandSite->IWinEventHandler::ProcessMessage: WM_NOTIFY for 0x%p, From: 0x%p, Code: NM_FIRST-%u returned 0x%x\n", hWnd, nmh->hwndFrom, NM_FIRST - nmh->code, hRet); - } - else - { - TRACE("ITrayBandSite->IWinEventHandler::ProcessMessage(0x%p,0x%x,0x%p,0x%p,0x%p->0x%p) returned: 0x%x\n", hWnd, uMsg, wParam, lParam, plResult, *plResult, hRet); - } - } - } - else - hRet = E_FAIL; - - return hRet; -} - -static HRESULT STDMETHODCALLTYPE -ITrayBandSiteImpl_AddContextMenus(IN OUT ITrayBandSite *iface, - IN HMENU hmenu, - IN UINT indexMenu, - IN UINT idCmdFirst, - IN UINT idCmdLast, - IN UINT uFlags, - OUT IContextMenu **ppcm) -{ - ITrayBandSiteImpl *This = ITrayBandSiteImpl_from_ITrayBandSite(iface); - IShellService *pSs; - HRESULT hRet; - - if (This->ContextMenu == NULL) - { - /* Cache the context menu so we don't need to CoCreateInstance all the time... */ - hRet = CoCreateInstance(&CLSID_IShellBandSiteMenu, - NULL, - CLSCTX_INPROC_SERVER, - &IID_IShellService, - (PVOID*)&pSs); - TRACE("CoCreateInstance(CLSID_IShellBandSiteMenu) for IShellService returned: 0x%x\n", hRet); - if (!SUCCEEDED(hRet)) - return hRet; - - hRet = IShellService_SetOwner(pSs, - IUnknown_from_ITrayBandSiteImpl(This)); - if (!SUCCEEDED(hRet)) - { - IShellService_Release(pSs); - return hRet; - } - - hRet = IShellService_QueryInterface(pSs, - &IID_IContextMenu, - (PVOID*)&This->ContextMenu); - - IShellService_Release(pSs); - - if (!SUCCEEDED(hRet)) - return hRet; - } - - if (ppcm != NULL) - { - IContextMenu_AddRef(This->ContextMenu); - *ppcm = This->ContextMenu; - } - - /* Add the menu items */ - return IContextMenu_QueryContextMenu(This->ContextMenu, - hmenu, - indexMenu, - idCmdFirst, - idCmdLast, - uFlags); -} - -static HRESULT STDMETHODCALLTYPE -ITrayBandSiteImpl_Lock(IN OUT ITrayBandSite *iface, - IN BOOL bLock) -{ - ITrayBandSiteImpl *This = ITrayBandSiteImpl_from_ITrayBandSite(iface); - BOOL bPrevLocked = This->Locked; - BANDSITEINFO bsi; - HRESULT hRet; - - ASSERT(This->BandSite != NULL); - - if (bPrevLocked != bLock) - { - This->Locked = bLock; - - bsi.dwMask = BSIM_STYLE; - bsi.dwStyle = (This->Locked ? BSIS_LOCKED | BSIS_NOGRIPPER : BSIS_AUTOGRIPPER); - - hRet = IBandSite_SetBandSiteInfo(This->BandSite, - &bsi); - if (SUCCEEDED(hRet)) - { - hRet = ITrayBandSiteImpl_Update(This); - } - - return hRet; - } - - return S_FALSE; -} - -static const ITrayBandSiteVtbl ITrayBandSiteImpl_Vtbl = -{ - /*** IUnknown methods ***/ - ITrayBandSiteImpl_QueryInterface, - ITrayBandSiteImpl_AddRef, - ITrayBandSiteImpl_Release, - /*** IBandSiteStreamCallback methods ***/ - ITrayBandSiteImpl_OnLoad, - ITrayBandSiteImpl_OnSave, - /*** ITrayBandSite methods ***/ - ITrayBandSiteImpl_IsTaskBand, - ITrayBandSiteImpl_ProcessMessage, - ITrayBandSiteImpl_AddContextMenus, - ITrayBandSiteImpl_Lock -}; - -/*******************************************************************/ - -METHOD_IUNKNOWN_INHERITED_ADDREF(IBandSite, ITrayBandSite) -METHOD_IUNKNOWN_INHERITED_RELEASE(IBandSite, ITrayBandSite) -METHOD_IUNKNOWN_INHERITED_QUERYINTERFACE(IBandSite, ITrayBandSite) - -static HRESULT STDMETHODCALLTYPE -ITrayBandSiteImpl_AddBand(IN OUT IBandSite *iface, - IN IUnknown *punk) -{ - ITrayBandSiteImpl *This = ITrayBandSiteImpl_from_IBandSite(iface); - IOleCommandTarget *pOct; - HRESULT hRet; - - hRet = IUnknown_QueryInterface(punk, - &IID_IOleCommandTarget, - (PVOID*)&pOct); - if (SUCCEEDED(hRet)) - { - /* Send the DBID_DELAYINIT command to initialize the band to be added */ - /* FIXME: Should be delayed */ - IOleCommandTarget_Exec(pOct, - &IID_IDeskBand, - DBID_DELAYINIT, - 0, - NULL, - NULL); - - IOleCommandTarget_Release(pOct); - } - - return IBandSite_AddBand(This->BandSite, - punk); -} - -static HRESULT STDMETHODCALLTYPE -ITrayBandSiteImpl_EnumBands(IN OUT IBandSite *iface, - IN UINT uBand, - OUT DWORD *pdwBandID) -{ - ITrayBandSiteImpl *This = ITrayBandSiteImpl_from_IBandSite(iface); - return IBandSite_EnumBands(This->BandSite, - uBand, - pdwBandID); -} - -static HRESULT STDMETHODCALLTYPE -ITrayBandSiteImpl_QueryBand(IN OUT IBandSite *iface, - IN DWORD dwBandID, - OUT IDeskBand **ppstb, - OUT DWORD *pdwState, - OUT LPWSTR pszName, - IN int cchName) -{ - HRESULT hRet; - IDeskBand *pstb = NULL; - ITrayBandSiteImpl *This = ITrayBandSiteImpl_from_IBandSite(iface); - - hRet = IBandSite_QueryBand(This->BandSite, - dwBandID, - &pstb, - pdwState, - pszName, - cchName); - - if (SUCCEEDED(hRet)) - { - hRet = IsSameObject((IUnknown *)pstb, - (IUnknown *)This->TaskBand); - if (hRet == S_OK) - { - /* Add the BSSF_UNDELETEABLE flag to pdwState because the task bar band shouldn't be deletable */ - if (pdwState != NULL) - *pdwState |= BSSF_UNDELETEABLE; - } - else if (!SUCCEEDED(hRet)) - { - IDeskBand_Release(pstb); - pstb = NULL; - } - - if (ppstb != NULL) - *ppstb = pstb; - } - else if (ppstb != NULL) - *ppstb = NULL; - - return hRet; -} - -static HRESULT STDMETHODCALLTYPE -ITrayBandSiteImpl_SetBandState(IN OUT IBandSite *iface, - IN DWORD dwBandID, - IN DWORD dwMask, - IN DWORD dwState) -{ - ITrayBandSiteImpl *This = ITrayBandSiteImpl_from_IBandSite(iface); - return IBandSite_SetBandState(This->BandSite, - dwBandID, - dwMask, - dwState); -} - -static HRESULT STDMETHODCALLTYPE -ITrayBandSiteImpl_RemoveBand(IN OUT IBandSite *iface, - IN DWORD dwBandID) -{ - ITrayBandSiteImpl *This = ITrayBandSiteImpl_from_IBandSite(iface); - return IBandSite_RemoveBand(This->BandSite, - dwBandID); -} - -static HRESULT STDMETHODCALLTYPE -ITrayBandSiteImpl_GetBandObject(IN OUT IBandSite *iface, - IN DWORD dwBandID, - IN REFIID riid, - OUT VOID **ppv) -{ - ITrayBandSiteImpl *This = ITrayBandSiteImpl_from_IBandSite(iface); - return IBandSite_GetBandObject(This->BandSite, - dwBandID, - riid, - ppv); -} - -static HRESULT STDMETHODCALLTYPE -ITrayBandSiteImpl_SetBandSiteInfo(IN OUT IBandSite *iface, - IN const BANDSITEINFO *pbsinfo) -{ - ITrayBandSiteImpl *This = ITrayBandSiteImpl_from_IBandSite(iface); - return IBandSite_SetBandSiteInfo(This->BandSite, - pbsinfo); -} - -static HRESULT STDMETHODCALLTYPE -ITrayBandSiteImpl_GetBandSiteInfo(IN OUT IBandSite *iface, - IN OUT BANDSITEINFO *pbsinfo) -{ - ITrayBandSiteImpl *This = ITrayBandSiteImpl_from_IBandSite(iface); - return IBandSite_GetBandSiteInfo(This->BandSite, - pbsinfo); -} - -static const IBandSiteVtbl IBandSiteImpl_Vtbl = -{ - /*** IUnknown methods ***/ - METHOD_IUNKNOWN_INHERITED_QUERYINTERFACE_NAME(IBandSite, ITrayBandSite), - METHOD_IUNKNOWN_INHERITED_ADDREF_NAME(IBandSite, ITrayBandSite), - METHOD_IUNKNOWN_INHERITED_RELEASE_NAME(IBandSite, ITrayBandSite), - /*** IBandSite methods ***/ - ITrayBandSiteImpl_AddBand, - ITrayBandSiteImpl_EnumBands, - ITrayBandSiteImpl_QueryBand, - ITrayBandSiteImpl_SetBandState, - ITrayBandSiteImpl_RemoveBand, - ITrayBandSiteImpl_GetBandObject, - ITrayBandSiteImpl_SetBandSiteInfo, - ITrayBandSiteImpl_GetBandSiteInfo, -}; - -static BOOL -ITrayBandSiteImpl_HasTaskBand(IN OUT ITrayBandSiteImpl *This) -{ - ASSERT(This->TaskBand != NULL); - - return SUCCEEDED(ITaskBand_GetRebarBandID(This->TaskBand, - NULL)); -} - -static HRESULT -ITrayBandSiteImpl_AddTaskBand(IN OUT ITrayBandSiteImpl *This) -{ -#if 0 - /* FIXME: This is the code for the simple taskbar */ - IObjectWithSite *pOws; - HRESULT hRet; - - hRet = ITaskBand_QueryInterface(This->TaskBand, - &IID_IObjectWithSite, - (PVOID*)&pOws); - if (SUCCEEDED(hRet)) - { - hRet = IObjectWithSite_SetSite(pOws, - (IUnknown *)This->TaskBand); - - IObjectWithSite_Release(pOws); - } - - return hRet; -#else - if (!ITrayBandSiteImpl_HasTaskBand(This)) - { - return IBandSite_AddBand(This->BandSite, - (IUnknown *)This->TaskBand); - } - - return S_OK; -#endif -} - -static HRESULT -ITrayBandSiteImpl_Update(IN OUT ITrayBandSiteImpl *This) -{ - IOleCommandTarget *pOct; - HRESULT hRet; - - hRet = IUnknown_QueryInterface(This->punkInner, - &IID_IOleCommandTarget, - (PVOID*)&pOct); - if (SUCCEEDED(hRet)) - { - /* Send the DBID_BANDINFOCHANGED command to update the band site */ - hRet = IOleCommandTarget_Exec(pOct, - &IID_IDeskBand, - DBID_BANDINFOCHANGED, - 0, - NULL, - NULL); - - IOleCommandTarget_Release(pOct); - } - - return hRet; -} - -static VOID -ITrayBandSiteImpl_BroadcastOleCommandExec(IN OUT ITrayBandSiteImpl *This, - const GUID *pguidCmdGroup, - DWORD nCmdID, - DWORD nCmdExecOpt, - VARIANTARG *pvaIn, - VARIANTARG *pvaOut) -{ - IOleCommandTarget *pOct; - DWORD dwBandID; - UINT uBand = 0; - - /* Enumerate all bands */ - while (SUCCEEDED(IBandSite_EnumBands(This->BandSite, - uBand, - &dwBandID))) - { - if (SUCCEEDED(IBandSite_GetBandObject(This->BandSite, - dwBandID, - &IID_IOleCommandTarget, - (PVOID*)&pOct))) - { - /* Execute the command */ - IOleCommandTarget_Exec(pOct, - pguidCmdGroup, - nCmdID, - nCmdExecOpt, - pvaIn, - pvaOut); - - IOleCommandTarget_Release(pOct); - } - - uBand++; - } -} - -static HRESULT -ITrayBandSiteImpl_FinishInit(IN OUT ITrayBandSiteImpl *This) -{ - /* Broadcast the DBID_FINISHINIT command */ - ITrayBandSiteImpl_BroadcastOleCommandExec(This, - &IID_IDeskBand, - DBID_FINISHINIT, - 0, - NULL, - NULL); - - return S_OK; -} - -static HRESULT -ITrayBandSiteImpl_Show(IN OUT ITrayBandSiteImpl *This, - IN BOOL bShow) -{ - IDeskBarClient *pDbc; - HRESULT hRet; - - hRet = IBandSite_QueryInterface(This->BandSite, - &IID_IDeskBarClient, - (PVOID*)&pDbc); - if (SUCCEEDED(hRet)) - { - hRet = IDeskBarClient_UIActivateDBC(pDbc, - bShow ? DBC_SHOW : DBC_HIDE); - IDeskBarClient_Release(pDbc); - } - - return hRet; -} - -static HRESULT -ITrayBandSiteImpl_LoadFromStream(IN OUT ITrayBandSiteImpl *This, - IN OUT IStream *pStm) -{ - IPersistStream *pPStm; - HRESULT hRet; - - ASSERT(This->BandSite != NULL); - - /* We implement the undocumented COM interface IBandSiteStreamCallback - that the shell will query so that we can intercept and custom-load - the task band when it finds the task band's CLSID (which is internal). - This way we can prevent the shell from attempting to CoCreateInstance - the (internal) task band, resulting in a failure... */ - hRet = IBandSite_QueryInterface(This->BandSite, - &IID_IPersistStream, - (PVOID*)&pPStm); - if (SUCCEEDED(hRet)) - { - hRet = IPersistStream_Load(pPStm, - pStm); - TRACE("IPersistStream_Load() returned 0x%x\n", hRet); - IPersistStream_Release(pPStm); - } - - return hRet; -} - -static IStream * -GetUserBandsStream(IN DWORD grfMode) -{ - HKEY hkStreams; - IStream *Stream = NULL; - - if (RegCreateKey(hkExplorer, - TEXT("Streams"), - &hkStreams) == ERROR_SUCCESS) - { - Stream = SHOpenRegStream(hkStreams, - TEXT("Desktop"), - TEXT("TaskbarWinXP"), - grfMode); - - RegCloseKey(hkStreams); - } - - return Stream; -} - -static IStream * -GetDefaultBandsStream(IN DWORD grfMode) -{ - HKEY hkStreams; - IStream *Stream = NULL; - - if (RegCreateKey(HKEY_LOCAL_MACHINE, - TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Streams"), - &hkStreams) == ERROR_SUCCESS) - { - Stream = SHOpenRegStream(hkStreams, - TEXT("Desktop"), - TEXT("Default Taskbar"), - grfMode); - - RegCloseKey(hkStreams); - } - - return Stream; -} - -static HRESULT -ITrayBandSiteImpl_Load(IN OUT ITrayBandSiteImpl *This) -{ - IStream *pStm; - HRESULT hRet; - - /* Try to load the user's settings */ - pStm = GetUserBandsStream(STGM_READ); - if (pStm != NULL) - { - hRet = ITrayBandSiteImpl_LoadFromStream(This, - pStm); - - TRACE("Loaded user bands settings: 0x%x\n", hRet); - IStream_Release(pStm); - } - else - hRet = E_FAIL; - - /* If the user's settings couldn't be loaded, try with - default settings (ie. when the user logs in for the - first time! */ - if (!SUCCEEDED(hRet)) - { - pStm = GetDefaultBandsStream(STGM_READ); - if (pStm != NULL) - { - hRet = ITrayBandSiteImpl_LoadFromStream(This, - pStm); - - TRACE("Loaded default user bands settings: 0x%x\n", hRet); - IStream_Release(pStm); - } - else - hRet = E_FAIL; - } - - return hRet; -} - -static ITrayBandSiteImpl * -ITrayBandSiteImpl_Construct(IN OUT ITrayWindow *Tray, - OUT HWND *phWndRebar, - OUT HWND *phwndTaskSwitch) -{ - ITrayBandSiteImpl *This; - IDeskBarClient *pDbc; - IDeskBand *pDb; - IOleWindow *pOw; - HRESULT hRet; - - *phWndRebar = NULL; - *phwndTaskSwitch = NULL; - - This = HeapAlloc(hProcessHeap, - HEAP_ZERO_MEMORY, - sizeof(*This)); - if (This == NULL) - return NULL; - - This->lpVtbl = &ITrayBandSiteImpl_Vtbl; - This->lpBandSiteVtbl = &IBandSiteImpl_Vtbl; - This->Ref = 1; - This->Tray = Tray; - - /* Create a RebarBandSite provided by the shell */ - hRet = CoCreateInstance(&CLSID_RebarBandSite, - (LPUNKNOWN)IBandSite_from_ITrayBandSiteImpl(This), - CLSCTX_INPROC_SERVER, - &IID_IUnknown, - (LPVOID*)&This->punkInner); - if (!SUCCEEDED(hRet)) - { - ITrayBandSiteImpl_Free(This); - return NULL; - } - - hRet = IUnknown_QueryInterface(This->punkInner, - &IID_IBandSite, - (PVOID*)&This->BandSite); - if (!SUCCEEDED(hRet)) - { - ITrayBandSiteImpl_Free(This); - return NULL; - } - - hRet = IUnknown_QueryInterface(This->punkInner, - &IID_IWinEventHandler, - (PVOID*)&This->WindowEventHandler); - if (!SUCCEEDED(hRet)) - { - ITrayBandSiteImpl_Free(This); - return NULL; - } - - This->TaskBand = CreateTaskBand(Tray); - if (This->TaskBand != NULL) - { - /* Add the task band to the site */ - hRet = IBandSite_QueryInterface(This->BandSite, - &IID_IDeskBarClient, - (PVOID*)&pDbc); - if (SUCCEEDED(hRet)) - { - hRet = ITaskBand_QueryInterface(This->TaskBand, - &IID_IOleWindow, - (PVOID*)&pOw); - if (SUCCEEDED(hRet)) - { - /* We cause IDeskBarClient to create the rebar control by passing the new - task band to it. The band reports the tray window handle as window handle - so that IDeskBarClient knows the parent window of the Rebar control that - it wants to create. */ - hRet = IDeskBarClient_SetDeskBarSite(pDbc, - (IUnknown *)pOw); - - if (SUCCEEDED(hRet)) - { - /* The Rebar control is now created, we can query the window handle */ - hRet = IDeskBarClient_GetWindow(pDbc, - &This->hWndRebar); - - if (SUCCEEDED(hRet)) - { - /* We need to manually remove the RBS_BANDBORDERS style! */ - SetWindowStyle(This->hWndRebar, - RBS_BANDBORDERS, - 0); - } - } - - IOleWindow_Release(pOw); - } - - if (SUCCEEDED(hRet)) - { - DWORD dwMode = 0; - - /* Set the Desk Bar mode to the current one */ - - /* FIXME: We need to set the mode (and update) whenever the user docks - the tray window to another monitor edge! */ - - if (!ITrayWindow_IsHorizontal(This->Tray)) - dwMode = DBIF_VIEWMODE_VERTICAL; - - hRet = IDeskBarClient_SetModeDBC(pDbc, - dwMode); - } - - IDeskBarClient_Release(pDbc); - } - - /* Load the saved state of the task band site */ - /* FIXME: We should delay loading shell extensions, also see DBID_DELAYINIT */ - ITrayBandSiteImpl_Load(This); - - /* Add the task bar band if it hasn't been added already */ - hRet = ITrayBandSiteImpl_AddTaskBand(This); - if (SUCCEEDED(hRet)) - { - hRet = ITaskBand_QueryInterface(This->TaskBand, - &IID_IDeskBand, - (PVOID*)&pDb); - if (SUCCEEDED(hRet)) - { - hRet = IDeskBand_GetWindow(pDb, - phwndTaskSwitch); - if (!SUCCEEDED(hRet)) - *phwndTaskSwitch = NULL; - - IDeskBand_Release(pDb); - } - } - - /* Should we send this after showing it? */ - ITrayBandSiteImpl_Update(This); - - /* FIXME: When should we send this? Does anyone care anyway? */ - ITrayBandSiteImpl_FinishInit(This); - - /* Activate the band site */ - ITrayBandSiteImpl_Show(This, - TRUE); - } - - *phWndRebar = This->hWndRebar; - - return This; -} - -/*******************************************************************/ - -ITrayBandSite * -CreateTrayBandSite(IN OUT ITrayWindow *Tray, - OUT HWND *phWndRebar, - OUT HWND *phWndTaskSwitch) -{ - ITrayBandSiteImpl *This; - - This = ITrayBandSiteImpl_Construct(Tray, - phWndRebar, - phWndTaskSwitch); - if (This != NULL) - { - return ITrayBandSite_from_ITrayBandSiteImpl(This); - } - - return NULL; -} diff --git a/base/shell/explorer-new/tbsite.cpp b/base/shell/explorer-new/tbsite.cpp new file mode 100644 index 00000000000..b75e3438b67 --- /dev/null +++ b/base/shell/explorer-new/tbsite.cpp @@ -0,0 +1,831 @@ +/* + * ReactOS Explorer + * + * Copyright 2006 - 2007 Thomas Weidenmueller + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "precomp.h" + +#include + +#include "undoc.h" + +/***************************************************************************** + ** ITrayBandSite ************************************************************ + *****************************************************************************/ + +// WARNING: Can't use ATL for this class due to our ATL not fully supporting the AGGREGATION functions needed for this class to be an "outer" class +// it works just fine this way. +class ITrayBandSiteImpl : + public ITrayBandSite, + public IBandSite, + public IBandSiteStreamCallback + /* TODO: IWinEventHandler */ +{ + volatile LONG m_RefCount; + + CComPtr Tray; + + CComPtr punkInner; + CComPtr BandSite; + CComPtr TaskBand; + CComPtr WindowEventHandler; + CComPtr ContextMenu; + + HWND hWndRebar; + + union + { + DWORD dwFlags; + struct + { + DWORD Locked : 1; + }; + }; + +public: + + virtual ULONG STDMETHODCALLTYPE AddRef() + { + return InterlockedIncrement(&m_RefCount); + } + + virtual ULONG STDMETHODCALLTYPE Release() + { + ULONG Ret = InterlockedDecrement(&m_RefCount); + + if (Ret == 0) + delete this; + + return Ret; + } + + virtual HRESULT STDMETHODCALLTYPE QueryInterface(IN REFIID riid, OUT LPVOID *ppvObj) + { + if (ppvObj == NULL) + return E_POINTER; + + if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IBandSiteStreamCallback)) + { + // return IBandSiteStreamCallback's IUnknown + *ppvObj = static_cast(this); + } + else if (IsEqualIID(riid, IID_IBandSite)) + { + *ppvObj = static_cast(this); + } + else if (IsEqualIID(riid, IID_IWinEventHandler)) + { + TRACE("ITaskBandSite: IWinEventHandler queried!\n"); + *ppvObj = NULL; + return E_NOINTERFACE; + } + else if (punkInner != NULL) + { + return punkInner->QueryInterface(riid, ppvObj); + } + else + { + *ppvObj = NULL; + return E_NOINTERFACE; + } + + AddRef(); + return S_OK; + } + +public: + ITrayBandSiteImpl() : + m_RefCount(0), + hWndRebar(NULL) + { + } + + virtual ~ITrayBandSiteImpl() { } + + virtual HRESULT STDMETHODCALLTYPE OnLoad( + IN OUT IStream *pStm, + IN REFIID riid, + OUT PVOID *pvObj) + { + LARGE_INTEGER liPosZero; + ULARGE_INTEGER liCurrent; + CLSID clsid; + ULONG ulRead; + HRESULT hRet; + + /* NOTE: Callback routine called by the shell while loading the task band + stream. We use it to intercept the default behavior when the task + band is loaded from the stream. + + NOTE: riid always points to IID_IUnknown! This is because the shell hasn't + read anything from the stream and therefore doesn't know what CLSID + it's dealing with. We'll have to find it out ourselves by reading + the GUID from the stream. */ + + /* Read the current position of the stream, we'll have to reset it everytime + we read a CLSID that's not the task band... */ + ZeroMemory(&liPosZero, + sizeof(liPosZero)); + hRet = pStm->Seek(liPosZero, STREAM_SEEK_CUR, &liCurrent); + + if (SUCCEEDED(hRet)) + { + /* Now let's read the CLSID from the stream and see if it's our task band */ + hRet = pStm->Read(&clsid, (ULONG)sizeof(clsid), &ulRead); + + if (SUCCEEDED(hRet) && ulRead == sizeof(clsid)) + { + if (IsEqualGUID(clsid, CLSID_ITaskBand)) + { + ASSERT(TaskBand != NULL); + /* We're trying to load the task band! Let's create it... */ + + hRet = TaskBand->QueryInterface( + riid, + pvObj); + if (SUCCEEDED(hRet)) + { + /* Load the stream */ + TRACE("IBandSiteStreamCallback::OnLoad intercepted the task band CLSID!\n"); + } + + return hRet; + } + } + } + + /* Reset the position and let the shell do all the work for us */ + hRet = pStm->Seek( + *(LARGE_INTEGER*) &liCurrent, + STREAM_SEEK_SET, + NULL); + if (SUCCEEDED(hRet)) + { + /* Let the shell handle everything else for us :) */ + hRet = OleLoadFromStream(pStm, + riid, + pvObj); + } + + if (!SUCCEEDED(hRet)) + { + TRACE("IBandSiteStreamCallback::OnLoad(0x%p, 0x%p, 0x%p) returns 0x%x\n", pStm, riid, pvObj, hRet); + } + + return hRet; + } + + virtual HRESULT STDMETHODCALLTYPE OnSave( + IN OUT IUnknown *pUnk, + IN OUT IStream *pStm) + { + /* NOTE: Callback routine called by the shell while saving the task band + stream. We use it to intercept the default behavior when the task + band is saved to the stream */ + /* FIXME: Implement */ + TRACE("IBandSiteStreamCallback::OnSave(0x%p, 0x%p) returns E_NOTIMPL\n", pUnk, pStm); + return E_NOTIMPL; + } + + virtual HRESULT STDMETHODCALLTYPE IsTaskBand( + IN IUnknown *punk) + { + return IsSameObject((IUnknown *) BandSite, + punk); + } + + virtual HRESULT STDMETHODCALLTYPE ProcessMessage( + IN HWND hWnd, + IN UINT uMsg, + IN WPARAM wParam, + IN LPARAM lParam, + OUT LRESULT *plResult) + { + HRESULT hRet; + + ASSERT(hWndRebar != NULL); + + /* Custom task band behavior */ + switch (uMsg) + { + case WM_NOTIFY: + { + const NMHDR *nmh = (const NMHDR *) lParam; + + if (nmh->hwndFrom == hWndRebar) + { + switch (nmh->code) + { + case NM_NCHITTEST: + { + LPNMMOUSE nmm = (LPNMMOUSE) lParam; + + if (nmm->dwHitInfo == RBHT_CLIENT || nmm->dwHitInfo == RBHT_NOWHERE || + nmm->dwItemSpec == (DWORD_PTR) -1) + { + /* Make the rebar control appear transparent so the user + can drag the tray window */ + *plResult = HTTRANSPARENT; + } + return S_OK; + } + + case RBN_MINMAX: + /* Deny if an Administrator disabled this "feature" */ + *plResult = (SHRestricted(REST_NOMOVINGBAND) != 0); + return S_OK; + } + } + + //TRACE("ITrayBandSite::ProcessMessage: WM_NOTIFY for 0x%p, From: 0x%p, Code: NM_FIRST-%u...\n", hWnd, nmh->hwndFrom, NM_FIRST - nmh->code); + break; + } + } + + /* Forward to the shell's IWinEventHandler interface to get the default shell behavior! */ + if (!WindowEventHandler) + return E_FAIL; + + /*TRACE("Calling IWinEventHandler::ProcessMessage(0x%p, 0x%x, 0x%p, 0x%p, 0x%p) hWndRebar=0x%p\n", hWnd, uMsg, wParam, lParam, plResult, hWndRebar);*/ + hRet = WindowEventHandler->OnWinEvent( + hWnd, + uMsg, + wParam, + lParam, + plResult); + if (FAILED_UNEXPECTEDLY(hRet)) + { + if (uMsg == WM_NOTIFY) + { + const NMHDR *nmh = (const NMHDR *) lParam; + ERR("ITrayBandSite->IWinEventHandler::ProcessMessage: WM_NOTIFY for 0x%p, From: 0x%p, Code: NM_FIRST-%u returned 0x%x\n", hWnd, nmh->hwndFrom, NM_FIRST - nmh->code, hRet); + } + else + { + ERR("ITrayBandSite->IWinEventHandler::ProcessMessage(0x%p,0x%x,0x%p,0x%p,0x%p->0x%p) returned: 0x%x\n", hWnd, uMsg, wParam, lParam, plResult, *plResult, hRet); + } + } + + return hRet; + } + + virtual HRESULT STDMETHODCALLTYPE AddContextMenus( + IN HMENU hmenu, + IN UINT indexMenu, + IN UINT idCmdFirst, + IN UINT idCmdLast, + IN UINT uFlags, + OUT IContextMenu **ppcm) + { + IShellService *pSs; + HRESULT hRet; + + if (ContextMenu == NULL) + { + /* Cache the context menu so we don't need to CoCreateInstance all the time... */ + hRet = CoCreateInstance(CLSID_IShellBandSiteMenu, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IShellService, &pSs)); + TRACE("CoCreateInstance(CLSID_IShellBandSiteMenu) for IShellService returned: 0x%x\n", hRet); + if (!SUCCEEDED(hRet)) + return hRet; + + hRet = pSs->SetOwner((IBandSite*)this); + if (!SUCCEEDED(hRet)) + { + pSs->Release(); + return hRet; + } + + hRet = pSs->QueryInterface(IID_PPV_ARG(IContextMenu, &ContextMenu)); + + pSs->Release(); + + if (!SUCCEEDED(hRet)) + return hRet; + } + + if (ppcm != NULL) + { + ContextMenu->AddRef(); + *ppcm = ContextMenu; + } + + /* Add the menu items */ + return ContextMenu->QueryContextMenu( + hmenu, + indexMenu, + idCmdFirst, + idCmdLast, + uFlags); + } + + virtual HRESULT STDMETHODCALLTYPE Lock( + IN BOOL bLock) + { + BOOL bPrevLocked = Locked; + BANDSITEINFO bsi; + HRESULT hRet; + + ASSERT(BandSite != NULL); + + if (bPrevLocked != bLock) + { + Locked = bLock; + + bsi.dwMask = BSIM_STYLE; + bsi.dwStyle = (Locked ? BSIS_LOCKED | BSIS_NOGRIPPER : BSIS_AUTOGRIPPER); + + hRet = BandSite->SetBandSiteInfo(&bsi); + if (SUCCEEDED(hRet)) + { + hRet = Update(); + } + + return hRet; + } + + return S_FALSE; + } + + /*******************************************************************/ + + virtual HRESULT STDMETHODCALLTYPE AddBand( + IN IUnknown *punk) + { + IOleCommandTarget *pOct; + HRESULT hRet; + + hRet = punk->QueryInterface(IID_PPV_ARG(IOleCommandTarget, &pOct)); + if (SUCCEEDED(hRet)) + { + /* Send the DBID_DELAYINIT command to initialize the band to be added */ + /* FIXME: Should be delayed */ + pOct->Exec( + &IID_IDeskBand, + DBID_DELAYINIT, + 0, + NULL, + NULL); + + pOct->Release(); + } + + return BandSite->AddBand( + punk); + } + + virtual HRESULT STDMETHODCALLTYPE EnumBands( + IN UINT uBand, + OUT DWORD *pdwBandID) + { + return BandSite->EnumBands( + uBand, + pdwBandID); + } + + virtual HRESULT STDMETHODCALLTYPE QueryBand( + IN DWORD dwBandID, + OUT IDeskBand **ppstb, + OUT DWORD *pdwState, + OUT LPWSTR pszName, + IN int cchName) + { + HRESULT hRet; + IDeskBand *pstb = NULL; + + hRet = BandSite->QueryBand( + dwBandID, + &pstb, + pdwState, + pszName, + cchName); + + if (SUCCEEDED(hRet)) + { + hRet = IsSameObject(pstb, TaskBand); + if (hRet == S_OK) + { + /* Add the BSSF_UNDELETEABLE flag to pdwState because the task bar band shouldn't be deletable */ + if (pdwState != NULL) + *pdwState |= BSSF_UNDELETEABLE; + } + else if (!SUCCEEDED(hRet)) + { + pstb->Release(); + pstb = NULL; + } + + if (ppstb != NULL) + *ppstb = pstb; + } + else if (ppstb != NULL) + *ppstb = NULL; + + return hRet; + } + + virtual HRESULT STDMETHODCALLTYPE SetBandState( + IN DWORD dwBandID, + IN DWORD dwMask, + IN DWORD dwState) + { + return BandSite->SetBandState(dwBandID, dwMask, dwState); + } + + virtual HRESULT STDMETHODCALLTYPE RemoveBand( + IN DWORD dwBandID) + { + return BandSite->RemoveBand(dwBandID); + } + + virtual HRESULT STDMETHODCALLTYPE GetBandObject( + IN DWORD dwBandID, + IN REFIID riid, + OUT VOID **ppv) + { + return BandSite->GetBandObject(dwBandID, riid, ppv); + } + + virtual HRESULT STDMETHODCALLTYPE SetBandSiteInfo( + IN const BANDSITEINFO *pbsinfo) + { + return BandSite->SetBandSiteInfo(pbsinfo); + } + + virtual HRESULT STDMETHODCALLTYPE GetBandSiteInfo( + IN OUT BANDSITEINFO *pbsinfo) + { + return BandSite->GetBandSiteInfo(pbsinfo); + } + + virtual BOOL HasTaskBand() + { + ASSERT(TaskBand != NULL); + + return SUCCEEDED(TaskBand->GetRebarBandID( + NULL)); + } + + virtual HRESULT AddTaskBand() + { +#if 0 + /* FIXME: This is the code for the simple taskbar */ + IObjectWithSite *pOws; + HRESULT hRet; + + hRet = TaskBand->QueryInterface( + &IID_IObjectWithSite, + (PVOID*) &pOws); + if (SUCCEEDED(hRet)) + { + hRet = pOws->SetSite( + (IUnknown *)TaskBand); + + pOws->Release(); + } + + return hRet; +#else + if (!HasTaskBand()) + { + return BandSite->AddBand(TaskBand); + } + + return S_OK; +#endif + } + + virtual HRESULT Update() + { + IOleCommandTarget *pOct; + HRESULT hRet; + + hRet = punkInner->QueryInterface(IID_PPV_ARG(IOleCommandTarget, &pOct)); + if (SUCCEEDED(hRet)) + { + /* Send the DBID_BANDINFOCHANGED command to update the band site */ + hRet = pOct->Exec( + &IID_IDeskBand, + DBID_BANDINFOCHANGED, + 0, + NULL, + NULL); + + pOct->Release(); + } + + return hRet; + } + + virtual VOID BroadcastOleCommandExec(const GUID *pguidCmdGroup, + DWORD nCmdID, + DWORD nCmdExecOpt, + VARIANTARG *pvaIn, + VARIANTARG *pvaOut) + { + IOleCommandTarget *pOct; + DWORD dwBandID; + UINT uBand = 0; + + /* Enumerate all bands */ + while (SUCCEEDED(BandSite->EnumBands(uBand, &dwBandID))) + { + if (SUCCEEDED(BandSite->GetBandObject(dwBandID, IID_PPV_ARG(IOleCommandTarget, &pOct)))) + { + /* Execute the command */ + pOct->Exec( + pguidCmdGroup, + nCmdID, + nCmdExecOpt, + pvaIn, + pvaOut); + + pOct->Release(); + } + + uBand++; + } + } + + virtual HRESULT FinishInit() + { + /* Broadcast the DBID_FINISHINIT command */ + BroadcastOleCommandExec(&IID_IDeskBand, DBID_FINISHINIT, 0, NULL, NULL); + + return S_OK; + } + + virtual HRESULT Show( + IN BOOL bShow) + { + IDeskBarClient *pDbc; + HRESULT hRet; + + hRet = BandSite->QueryInterface(IID_PPV_ARG(IDeskBarClient, &pDbc)); + if (SUCCEEDED(hRet)) + { + hRet = pDbc->UIActivateDBC( + bShow ? DBC_SHOW : DBC_HIDE); + pDbc->Release(); + } + + return hRet; + } + + virtual HRESULT LoadFromStream(IN OUT IStream *pStm) + { + IPersistStream *pPStm; + HRESULT hRet; + + ASSERT(BandSite != NULL); + + /* We implement the undocumented COM interface IBandSiteStreamCallback + that the shell will query so that we can intercept and custom-load + the task band when it finds the task band's CLSID (which is internal). + This way we can prevent the shell from attempting to CoCreateInstance + the (internal) task band, resulting in a failure... */ + hRet = BandSite->QueryInterface(IID_PPV_ARG(IPersistStream, &pPStm)); + if (SUCCEEDED(hRet)) + { + hRet = pPStm->Load( + pStm); + TRACE("->Load() returned 0x%x\n", hRet); + pPStm->Release(); + } + + return hRet; + } + + virtual IStream * + GetUserBandsStream(IN DWORD grfMode) + { + HKEY hkStreams; + IStream *Stream = NULL; + + if (RegCreateKey(hkExplorer, + TEXT("Streams"), + &hkStreams) == ERROR_SUCCESS) + { + Stream = SHOpenRegStream(hkStreams, + TEXT("Desktop"), + TEXT("TaskbarWinXP"), + grfMode); + + RegCloseKey(hkStreams); + } + + return Stream; + } + + virtual IStream * + GetDefaultBandsStream(IN DWORD grfMode) + { + HKEY hkStreams; + IStream *Stream = NULL; + + if (RegCreateKey(HKEY_LOCAL_MACHINE, + TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Streams"), + &hkStreams) == ERROR_SUCCESS) + { + Stream = SHOpenRegStream(hkStreams, + TEXT("Desktop"), + TEXT("Default Taskbar"), + grfMode); + + RegCloseKey(hkStreams); + } + + return Stream; + } + + virtual HRESULT Load() + { + IStream *pStm; + HRESULT hRet; + + /* Try to load the user's settings */ + pStm = GetUserBandsStream(STGM_READ); + if (pStm != NULL) + { + hRet = LoadFromStream(pStm); + + TRACE("Loaded user bands settings: 0x%x\n", hRet); + pStm->Release(); + } + else + hRet = E_FAIL; + + /* If the user's settings couldn't be loaded, try with + default settings (ie. when the user logs in for the + first time! */ + if (!SUCCEEDED(hRet)) + { + pStm = GetDefaultBandsStream(STGM_READ); + if (pStm != NULL) + { + hRet = LoadFromStream(pStm); + + TRACE("Loaded default user bands settings: 0x%x\n", hRet); + pStm->Release(); + } + else + hRet = E_FAIL; + } + + return hRet; + } + + HRESULT _Init(IN OUT ITrayWindow *tray, OUT HWND *phWndRebar, OUT HWND *phwndTaskSwitch) + { + IDeskBarClient *pDbc; + IDeskBand *pDb; + IOleWindow *pOw; + HRESULT hRet; + + *phWndRebar = NULL; + *phwndTaskSwitch = NULL; + + Tray = tray; + + /* Create a RebarBandSite provided by the shell */ + hRet = CoCreateInstance(CLSID_RebarBandSite, + static_cast(this), + CLSCTX_INPROC_SERVER, + IID_PPV_ARG(IUnknown, &punkInner)); + if (!SUCCEEDED(hRet)) + { + return hRet; + } + + hRet = punkInner->QueryInterface(IID_PPV_ARG(IBandSite, &BandSite)); + if (!SUCCEEDED(hRet)) + { + return hRet; + } + + hRet = punkInner->QueryInterface(IID_PPV_ARG(IWinEventHandler, &WindowEventHandler)); + if (!SUCCEEDED(hRet)) + { + return hRet; + } + + TaskBand = CreateTaskBand(Tray); + if (TaskBand != NULL) + { + /* Add the task band to the site */ + hRet = BandSite->QueryInterface(IID_PPV_ARG(IDeskBarClient, &pDbc)); + if (SUCCEEDED(hRet)) + { + hRet = TaskBand->QueryInterface(IID_PPV_ARG(IOleWindow, &pOw)); + if (SUCCEEDED(hRet)) + { + /* We cause IDeskBarClient to create the rebar control by passing the new + task band to it. The band reports the tray window handle as window handle + so that IDeskBarClient knows the parent window of the Rebar control that + it wants to create. */ + hRet = pDbc->SetDeskBarSite(pOw); + + if (SUCCEEDED(hRet)) + { + /* The Rebar control is now created, we can query the window handle */ + hRet = pDbc->GetWindow(&hWndRebar); + + if (SUCCEEDED(hRet)) + { + /* We need to manually remove the RBS_BANDBORDERS style! */ + SetWindowStyle(hWndRebar, RBS_BANDBORDERS, 0); + } + } + + pOw->Release(); + } + + if (SUCCEEDED(hRet)) + { + DWORD dwMode = 0; + + /* Set the Desk Bar mode to the current one */ + + /* FIXME: We need to set the mode (and update) whenever the user docks + the tray window to another monitor edge! */ + + if (!Tray->IsHorizontal()) + dwMode = DBIF_VIEWMODE_VERTICAL; + + hRet = pDbc->SetModeDBC(dwMode); + } + + pDbc->Release(); + } + + /* Load the saved state of the task band site */ + /* FIXME: We should delay loading shell extensions, also see DBID_DELAYINIT */ + Load(); + + /* Add the task bar band if it hasn't been added already */ + hRet = AddTaskBand(); + if (SUCCEEDED(hRet)) + { + hRet = TaskBand->QueryInterface(IID_PPV_ARG(IDeskBand, &pDb)); + if (SUCCEEDED(hRet)) + { + hRet = pDb->GetWindow(phwndTaskSwitch); + if (!SUCCEEDED(hRet)) + *phwndTaskSwitch = NULL; + + pDb->Release(); + } + } + + /* Should we send this after showing it? */ + Update(); + + /* FIXME: When should we send this? Does anyone care anyway? */ + FinishInit(); + + /* Activate the band site */ + Show( + TRUE); + } + + *phWndRebar = hWndRebar; + + return S_OK; + } + }; +/*******************************************************************/ + +ITrayBandSite * +CreateTrayBandSite(IN OUT ITrayWindow *Tray, +OUT HWND *phWndRebar, +OUT HWND *phWndTaskSwitch) +{ + HRESULT hr; + + ITrayBandSiteImpl * tb = new ITrayBandSiteImpl(); + + if (!tb) + return NULL; + + tb->AddRef(); + + hr = tb->_Init(Tray, phWndRebar, phWndTaskSwitch); + if (FAILED_UNEXPECTEDLY(hr)) + tb->Release(); + + return tb; +} diff --git a/base/shell/explorer-new/trayntfy.c b/base/shell/explorer-new/trayntfy.c deleted file mode 100644 index 49d4687499f..00000000000 --- a/base/shell/explorer-new/trayntfy.c +++ /dev/null @@ -1,1919 +0,0 @@ -/* - * ReactOS Explorer - * - * Copyright 2006 - 2007 Thomas Weidenmueller - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "precomp.h" -//#include - -/* - * SysPagerWnd - */ -static const TCHAR szSysPagerWndClass[] = TEXT("SysPager"); - -typedef struct _NOTIFY_ITEM -{ - struct _NOTIFY_ITEM *next; - INT Index; - INT IconIndex; - NOTIFYICONDATA iconData; -} NOTIFY_ITEM, *PNOTIFY_ITEM, **PPNOTIFY_ITEM; - -typedef struct _SYS_PAGER_DATA -{ - HWND hWnd; - HWND hWndToolbar; - HIMAGELIST SysIcons; - PNOTIFY_ITEM NotifyItems; - INT ButtonCount; - INT VisibleButtonCount; -} SYS_PAGER_WND_DATA, *PSYS_PAGER_WND_DATA; - -// Data comes from shell32/systray.cpp -> TrayNotifyCDS_Dummy -typedef struct _SYS_PAGER_COPY_DATA -{ - DWORD cookie; - DWORD notify_code; - NOTIFYICONDATA nicon_data; -} SYS_PAGER_COPY_DATA, *PSYS_PAGER_COPY_DATA; - -static PNOTIFY_ITEM -SysPagerWnd_CreateNotifyItemData(IN OUT PSYS_PAGER_WND_DATA This) -{ - PNOTIFY_ITEM *findNotifyPointer = &This->NotifyItems; - PNOTIFY_ITEM notifyItem; - - notifyItem = HeapAlloc(hProcessHeap, - HEAP_ZERO_MEMORY, - sizeof(*notifyItem)); - if (notifyItem == NULL) - return NULL; - - notifyItem->next = NULL; - - while (*findNotifyPointer != NULL) - { - findNotifyPointer = &(*findNotifyPointer)->next; - } - - *findNotifyPointer = notifyItem; - - return notifyItem; -} - -static PPNOTIFY_ITEM -SysPagerWnd_FindPPNotifyItemByIconData(IN OUT PSYS_PAGER_WND_DATA This, - IN CONST NOTIFYICONDATA *iconData) -{ - PPNOTIFY_ITEM findNotifyPointer = &This->NotifyItems; - - while (*findNotifyPointer != NULL) - { - if ((*findNotifyPointer)->iconData.hWnd == iconData->hWnd && - (*findNotifyPointer)->iconData.uID == iconData->uID) - { - return findNotifyPointer; - } - findNotifyPointer = &(*findNotifyPointer)->next; - } - - return NULL; -} - -static PPNOTIFY_ITEM -SysPagerWnd_FindPPNotifyItemByIndex(IN OUT PSYS_PAGER_WND_DATA This, - IN WORD wIndex) -{ - PPNOTIFY_ITEM findNotifyPointer = &This->NotifyItems; - - while (*findNotifyPointer != NULL) - { - if ((*findNotifyPointer)->Index == wIndex) - { - return findNotifyPointer; - } - findNotifyPointer = &(*findNotifyPointer)->next; - } - - return NULL; -} - -static VOID -SysPagerWnd_UpdateButton(IN OUT PSYS_PAGER_WND_DATA This, - IN CONST NOTIFYICONDATA *iconData) -{ - TBBUTTONINFO tbbi = {0}; - PNOTIFY_ITEM notifyItem; - PPNOTIFY_ITEM NotifyPointer; - - NotifyPointer = SysPagerWnd_FindPPNotifyItemByIconData(This, iconData); - notifyItem = *NotifyPointer; - - tbbi.cbSize = sizeof(tbbi); - tbbi.dwMask = TBIF_BYINDEX | TBIF_COMMAND; - tbbi.idCommand = notifyItem->Index; - - if (iconData->uFlags & NIF_MESSAGE) - { - notifyItem->iconData.uCallbackMessage = iconData->uCallbackMessage; - } - - if (iconData->uFlags & NIF_ICON) - { - tbbi.dwMask |= TBIF_IMAGE; - notifyItem->IconIndex = tbbi.iImage = ImageList_AddIcon(This->SysIcons, iconData->hIcon); - } - - if (iconData->uFlags & NIF_TIP) - { - StringCchCopy(notifyItem->iconData.szTip, _countof(notifyItem->iconData.szTip), iconData->szTip); - } - - if (iconData->uFlags & NIF_STATE) - { - if (iconData->dwStateMask & NIS_HIDDEN && - (notifyItem->iconData.dwState & NIS_HIDDEN) != (iconData->dwState & NIS_HIDDEN)) - { - tbbi.dwMask |= TBIF_STATE; - if (iconData->dwState & NIS_HIDDEN) - { - tbbi.fsState |= TBSTATE_HIDDEN; - This->VisibleButtonCount--; - } - else - { - tbbi.fsState &= ~TBSTATE_HIDDEN; - This->VisibleButtonCount++; - } - } - - notifyItem->iconData.dwState &= ~iconData->dwStateMask; - notifyItem->iconData.dwState |= (iconData->dwState & iconData->dwStateMask); - } - - /* TODO: support NIF_INFO, NIF_GUID, NIF_REALTIME, NIF_SHOWTIP */ - - SendMessage(This->hWndToolbar, - TB_SETBUTTONINFO, - (WPARAM)notifyItem->Index, - (LPARAM)&tbbi); -} - - -static VOID -SysPagerWnd_AddButton(IN OUT PSYS_PAGER_WND_DATA This, - IN CONST NOTIFYICONDATA *iconData) -{ - TBBUTTON tbBtn; - PNOTIFY_ITEM notifyItem; - TCHAR text[] = TEXT(""); - - notifyItem = SysPagerWnd_CreateNotifyItemData(This); - - notifyItem->next = NULL; - notifyItem->Index = This->ButtonCount; - This->ButtonCount++; - This->VisibleButtonCount++; - - notifyItem->iconData.hWnd = iconData->hWnd; - notifyItem->iconData.uID = iconData->uID; - - tbBtn.fsState = TBSTATE_ENABLED; - tbBtn.fsStyle = BTNS_NOPREFIX; - tbBtn.dwData = notifyItem->Index; - - tbBtn.iString = (INT_PTR)text; - tbBtn.idCommand = notifyItem->Index; - - if (iconData->uFlags & NIF_MESSAGE) - { - notifyItem->iconData.uCallbackMessage = iconData->uCallbackMessage; - } - - if (iconData->uFlags & NIF_ICON) - { - notifyItem->IconIndex = tbBtn.iBitmap = ImageList_AddIcon(This->SysIcons, iconData->hIcon); - } - - /* TODO: support NIF_TIP */ - - if (iconData->uFlags & NIF_STATE) - { - notifyItem->iconData.dwState &= ~iconData->dwStateMask; - notifyItem->iconData.dwState |= (iconData->dwState & iconData->dwStateMask); - if (notifyItem->iconData.dwState & NIS_HIDDEN) - { - tbBtn.fsState |= TBSTATE_HIDDEN; - This->VisibleButtonCount--; - } - - } - - /* TODO: support NIF_INFO, NIF_GUID, NIF_REALTIME, NIF_SHOWTIP */ - - SendMessage(This->hWndToolbar, - TB_INSERTBUTTON, - notifyItem->Index, - (LPARAM)&tbBtn); - - SendMessage(This->hWndToolbar, - TB_SETBUTTONSIZE, - 0, - MAKELONG(16, 16)); -} - -static VOID -SysPagerWnd_RemoveButton(IN OUT PSYS_PAGER_WND_DATA This, - IN CONST NOTIFYICONDATA *iconData) -{ - PPNOTIFY_ITEM NotifyPointer; - - NotifyPointer = SysPagerWnd_FindPPNotifyItemByIconData(This, iconData); - if (NotifyPointer) - { - PNOTIFY_ITEM deleteItem; - PNOTIFY_ITEM updateItem; - deleteItem = *NotifyPointer; - - SendMessage(This->hWndToolbar, - TB_DELETEBUTTON, - deleteItem->Index, - 0); - - *NotifyPointer = updateItem = deleteItem->next; - - if (!(deleteItem->iconData.dwState & NIS_HIDDEN)) - This->VisibleButtonCount--; - HeapFree(hProcessHeap, - 0, - deleteItem); - This->ButtonCount--; - - while (updateItem != NULL) - { - TBBUTTONINFO tbbi; - updateItem->Index--; - tbbi.cbSize = sizeof(tbbi); - tbbi.dwMask = TBIF_BYINDEX | TBIF_COMMAND; - tbbi.idCommand = updateItem->Index; - - SendMessage(This->hWndToolbar, - TB_SETBUTTONINFO, - updateItem->Index, - (LPARAM)&tbbi); - - updateItem = updateItem->next; - } - } -} - -static VOID -SysPagerWnd_HandleButtonClick(IN OUT PSYS_PAGER_WND_DATA This, - IN WORD wIndex, - IN UINT uMsg, - IN WPARAM wParam) -{ - PPNOTIFY_ITEM NotifyPointer; - - NotifyPointer = SysPagerWnd_FindPPNotifyItemByIndex(This, wIndex); - if (NotifyPointer) - { - PNOTIFY_ITEM notifyItem; - notifyItem = *NotifyPointer; - - if (IsWindow(notifyItem->iconData.hWnd)) - { - if (uMsg == WM_MOUSEMOVE || - uMsg == WM_LBUTTONDOWN || - uMsg == WM_MBUTTONDOWN || - uMsg == WM_RBUTTONDOWN) - { - PostMessage(notifyItem->iconData.hWnd, - notifyItem->iconData.uCallbackMessage, - notifyItem->iconData.uID, - uMsg); - } - else - { - DWORD pid; - GetWindowThreadProcessId(notifyItem->iconData.hWnd, &pid); - if (pid == GetCurrentProcessId()) - { - PostMessage(notifyItem->iconData.hWnd, - notifyItem->iconData.uCallbackMessage, - notifyItem->iconData.uID, - uMsg); - } - else - { - SendMessage(notifyItem->iconData.hWnd, - notifyItem->iconData.uCallbackMessage, - notifyItem->iconData.uID, - uMsg); - } - } - } - } -} - -static VOID -SysPagerWnd_DrawBackground(IN HWND hwnd, - IN HDC hdc) -{ - RECT rect; - - GetClientRect(hwnd, &rect); - DrawThemeParentBackground(hwnd, hdc, &rect); -} - -static LRESULT CALLBACK -SysPagerWnd_ToolbarSubclassedProc(IN HWND hWnd, - IN UINT msg, - IN WPARAM wParam, - IN LPARAM lParam, - IN UINT_PTR uIdSubclass, - IN DWORD_PTR dwRefData) -{ - if (msg >= WM_MOUSEFIRST && msg <= WM_MOUSELAST) - { - HWND parent = GetParent(hWnd); - - if (parent) - { - SendMessage(parent, msg, wParam, lParam); - } - } - - return DefSubclassProc(hWnd, msg, wParam, lParam); -} - -static VOID -SysPagerWnd_Create(IN OUT PSYS_PAGER_WND_DATA This) -{ - DWORD styles = - WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | - TBSTYLE_FLAT | TBSTYLE_TOOLTIPS | TBSTYLE_WRAPABLE | TBSTYLE_TRANSPARENT | - CCS_TOP | CCS_NORESIZE | CCS_NOPARENTALIGN | CCS_NODIVIDER; - DWORD exStyles = WS_EX_TOOLWINDOW; - - This->hWndToolbar = CreateWindowEx(exStyles, - TOOLBARCLASSNAME, - NULL, - styles, - 0, - 0, - 0, - 0, - This->hWnd, - NULL, - hExplorerInstance, - NULL); - if (This->hWndToolbar != NULL) - { - SIZE BtnSize; - SetWindowTheme(This->hWndToolbar, L"TrayNotify", NULL); - /* Identify the version we're using */ - SendMessage(This->hWndToolbar, - TB_BUTTONSTRUCTSIZE, - sizeof(TBBUTTON), - 0); - - This->SysIcons = ImageList_Create(16, 16, ILC_COLOR32 | ILC_MASK, 0, 1000); - SendMessage(This->hWndToolbar, TB_SETIMAGELIST, 0, (LPARAM)This->SysIcons); - - BtnSize.cx = BtnSize.cy = 18; - SendMessage(This->hWndToolbar, - TB_SETBUTTONSIZE, - 0, - MAKELONG(BtnSize.cx, BtnSize.cy)); - - SetWindowSubclass(This->hWndToolbar, - SysPagerWnd_ToolbarSubclassedProc, - 2, - (DWORD_PTR)This); - } -} - -static VOID -SysPagerWnd_NCDestroy(IN OUT PSYS_PAGER_WND_DATA This) -{ - /* Free allocated resources */ - SetWindowLongPtr(This->hWnd, - 0, - 0); - HeapFree(hProcessHeap, - 0, - This); -} - -static VOID -SysPagerWnd_NotifyMsg(IN HWND hwnd, - IN WPARAM wParam, - IN LPARAM lParam) -{ - PSYS_PAGER_WND_DATA This = (PSYS_PAGER_WND_DATA)GetWindowLongPtr(hwnd, 0); - - PCOPYDATASTRUCT cpData = (PCOPYDATASTRUCT)lParam; - if (cpData->dwData == 1) - { - SYS_PAGER_COPY_DATA * data; - NOTIFYICONDATA *iconData; - HWND parentHWND; - RECT windowRect; - parentHWND = GetParent(This->hWnd); - parentHWND = GetParent(parentHWND); - GetClientRect(parentHWND, &windowRect); - - data = (PSYS_PAGER_COPY_DATA) cpData->lpData; - iconData = &data->nicon_data; - - switch (data->notify_code) - { - case NIM_ADD: - { - PPNOTIFY_ITEM NotifyPointer; - - NotifyPointer = SysPagerWnd_FindPPNotifyItemByIconData(This, - iconData); - if (!NotifyPointer) - { - SysPagerWnd_AddButton(This, iconData); - } - break; - } - case NIM_MODIFY: - { - PPNOTIFY_ITEM NotifyPointer; - - NotifyPointer = SysPagerWnd_FindPPNotifyItemByIconData(This, - iconData); - if (!NotifyPointer) - { - SysPagerWnd_AddButton(This, iconData); - } - else - { - SysPagerWnd_UpdateButton(This, iconData); - } - break; - } - case NIM_DELETE: - { - SysPagerWnd_RemoveButton(This, iconData); - break; - } - default: - TRACE("NotifyMessage received with unknown code %d.\n", data->notify_code); - break; - } - SendMessage(parentHWND, - WM_SIZE, - 0, - MAKELONG(windowRect.right - windowRect.left, - windowRect.bottom - windowRect.top)); - } -} - -static void -SysPagerWnd_GetSize(IN HWND hwnd, - IN WPARAM wParam, - IN PSIZE size) -{ - PSYS_PAGER_WND_DATA This = (PSYS_PAGER_WND_DATA)GetWindowLongPtr(hwnd, 0); - INT rows = 0; - TBMETRICS tbm; - - if (wParam) /* horizontal */ - { - rows = size->cy / 24; - if (rows == 0) - rows++; - size->cx = (This->VisibleButtonCount+rows - 1) / rows * 24; - } - else - { - rows = size->cx / 24; - if (rows == 0) - rows++; - size->cy = (This->VisibleButtonCount+rows - 1) / rows * 24; - } - - tbm.cbSize = sizeof(tbm); - tbm.dwMask = TBMF_BARPAD | TBMF_BUTTONSPACING; - tbm.cxBarPad = tbm.cyBarPad = 0; - tbm.cxButtonSpacing = 0; - tbm.cyButtonSpacing = 0; - - SendMessage(This->hWndToolbar, - TB_SETMETRICS, - 0, - (LPARAM)&tbm); -} - -static LRESULT CALLBACK -SysPagerWndProc(IN HWND hwnd, - IN UINT uMsg, - IN WPARAM wParam, - IN LPARAM lParam) -{ - PSYS_PAGER_WND_DATA This = NULL; - LRESULT Ret = FALSE; - - if (uMsg != WM_NCCREATE) - { - This = (PSYS_PAGER_WND_DATA)GetWindowLongPtr(hwnd, 0); - } - - if (This != NULL || uMsg == WM_NCCREATE) - { - switch (uMsg) - { - case WM_ERASEBKGND: - if (!IsAppThemed()) - break; - - SysPagerWnd_DrawBackground(hwnd, (HDC) wParam); - return TRUE; - - case WM_NCCREATE: - { - LPCREATESTRUCT CreateStruct = (LPCREATESTRUCT)lParam; - This = CreateStruct->lpCreateParams; - This->hWnd = hwnd; - This->NotifyItems = NULL; - This->ButtonCount = 0; - This->VisibleButtonCount = 0; - - SetWindowLongPtr(hwnd, 0, (LONG_PTR) This); - - return TRUE; - } - case WM_CREATE: - SysPagerWnd_Create(This); - break; - case WM_NCDESTROY: - SysPagerWnd_NCDestroy(This); - break; - - case WM_NOTIFY: - { - const NMHDR * nmh = (const NMHDR *) lParam; - if (nmh->code == TBN_GETINFOTIPW) - { - NMTBGETINFOTIP * nmtip = (NMTBGETINFOTIP *) lParam; - PPNOTIFY_ITEM ptr = SysPagerWnd_FindPPNotifyItemByIndex(This, nmtip->iItem); - if (ptr) - { - PNOTIFY_ITEM item = *ptr; - StringCchCopy(nmtip->pszText, nmtip->cchTextMax, item->iconData.szTip); - } - } - else if (nmh->code == NM_CUSTOMDRAW) - { - NMCUSTOMDRAW * cdraw = (NMCUSTOMDRAW *) lParam; - switch (cdraw->dwDrawStage) - { - case CDDS_PREPAINT: - return CDRF_NOTIFYITEMDRAW; - - case CDDS_ITEMPREPAINT: - return TBCDRF_NOBACKGROUND | TBCDRF_NOEDGES | TBCDRF_NOOFFSET | TBCDRF_NOMARK | TBCDRF_NOETCHEDEFFECT; - } - } - - break; - } - - case WM_SIZE: - { - SIZE szClient; - szClient.cx = LOWORD(lParam); - szClient.cy = HIWORD(lParam); - - Ret = DefWindowProc(hwnd, uMsg, wParam, lParam); - - if (This->hWndToolbar != NULL && This->hWndToolbar != hwnd) - { - SetWindowPos(This->hWndToolbar, NULL, 0, 0, szClient.cx, szClient.cy, SWP_NOZORDER); - } - - return Ret; - } - - default: - if (uMsg >= WM_MOUSEFIRST && uMsg <= WM_MOUSELAST) - { - POINT pt; - INT iBtn; - - pt.x = LOWORD(lParam); - pt.y = HIWORD(lParam); - - iBtn = (INT)SendMessage(This->hWndToolbar, - TB_HITTEST, - 0, - (LPARAM)&pt); - - if (iBtn >= 0) - { - SysPagerWnd_HandleButtonClick(This,iBtn,uMsg,wParam); - } - - return 0; - } - - break; - } - } - - return DefWindowProc(hwnd, uMsg, wParam, lParam); -} - -static HWND -CreateSysPagerWnd(IN HWND hWndParent, - IN BOOL bVisible) -{ - PSYS_PAGER_WND_DATA SpData; - DWORD dwStyle; - HWND hWnd = NULL; - - SpData = HeapAlloc(hProcessHeap, - HEAP_ZERO_MEMORY, - sizeof(*SpData)); - if (SpData != NULL) - { - /* Create the window. The tray window is going to move it to the correct - position and resize it as needed. */ - dwStyle = WS_CHILD | WS_CLIPSIBLINGS; - if (bVisible) - dwStyle |= WS_VISIBLE; - - hWnd = CreateWindowEx(0, - szSysPagerWndClass, - NULL, - dwStyle, - 0, - 0, - 0, - 0, - hWndParent, - NULL, - hExplorerInstance, - SpData); - - if (hWnd != NULL) - { - SetWindowTheme(hWnd, L"TrayNotify", NULL); - } - else - { - HeapFree(hProcessHeap, - 0, - SpData); - } - } - - return hWnd; - -} - -static BOOL -RegisterSysPagerWndClass(VOID) -{ - WNDCLASS wcTrayClock; - - wcTrayClock.style = CS_DBLCLKS; - wcTrayClock.lpfnWndProc = SysPagerWndProc; - wcTrayClock.cbClsExtra = 0; - wcTrayClock.cbWndExtra = sizeof(PSYS_PAGER_WND_DATA); - wcTrayClock.hInstance = hExplorerInstance; - wcTrayClock.hIcon = NULL; - wcTrayClock.hCursor = LoadCursor(NULL, IDC_ARROW); - wcTrayClock.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1); - wcTrayClock.lpszMenuName = NULL; - wcTrayClock.lpszClassName = szSysPagerWndClass; - - return RegisterClass(&wcTrayClock) != 0; -} - -static VOID -UnregisterSysPagerWndClass(VOID) -{ - UnregisterClass(szSysPagerWndClass, - hExplorerInstance); -} - -/* - * TrayClockWnd - */ - -static const TCHAR szTrayClockWndClass[] = TEXT("TrayClockWClass"); - -#define ID_TRAYCLOCK_TIMER 0 -#define ID_TRAYCLOCK_TIMER_INIT 1 - -static const struct -{ - BOOL IsTime; - DWORD dwFormatFlags; - LPCTSTR lpFormat; -} ClockWndFormats[] = { - { TRUE, 0, NULL }, - { FALSE, 0, TEXT("dddd") }, - { FALSE, DATE_SHORTDATE, NULL } -}; - -#define CLOCKWND_FORMAT_COUNT (sizeof(ClockWndFormats) / sizeof(ClockWndFormats[0])) - -#define TRAY_CLOCK_WND_SPACING_X 0 -#define TRAY_CLOCK_WND_SPACING_Y 0 - -typedef struct _TRAY_CLOCK_WND_DATA -{ - HWND hWnd; - HWND hWndNotify; - HFONT hFont; - COLORREF textColor; - RECT rcText; - SYSTEMTIME LocalTime; - - union - { - DWORD dwFlags; - struct - { - DWORD IsTimerEnabled : 1; - DWORD IsInitTimerEnabled : 1; - DWORD LinesMeasured : 1; - DWORD IsHorizontal : 1; - }; - }; - DWORD LineSpacing; - SIZE CurrentSize; - WORD VisibleLines; - SIZE LineSizes[CLOCKWND_FORMAT_COUNT]; - TCHAR szLines[CLOCKWND_FORMAT_COUNT][48]; -} TRAY_CLOCK_WND_DATA, *PTRAY_CLOCK_WND_DATA; - -static VOID -TrayClockWnd_SetFont(IN OUT PTRAY_CLOCK_WND_DATA This, - IN HFONT hNewFont, - IN BOOL bRedraw); - -static VOID -TrayClockWnd_UpdateTheme(IN OUT PTRAY_CLOCK_WND_DATA This) -{ - LOGFONTW clockFont; - HTHEME clockTheme; - HFONT hFont; - - clockTheme = OpenThemeData(This->hWnd, L"Clock"); - - if (clockTheme) - { - GetThemeFont(clockTheme, - NULL, - CLP_TIME, - 0, - TMT_FONT, - &clockFont); - - hFont = CreateFontIndirectW(&clockFont); - - TrayClockWnd_SetFont(This, - hFont, - FALSE); - - GetThemeColor(clockTheme, - CLP_TIME, - 0, - TMT_TEXTCOLOR, - &This->textColor); - } - else - { - This->textColor = RGB(0,0,0); - } - - CloseThemeData(clockTheme); -} - -static BOOL -TrayClockWnd_MeasureLines(IN OUT PTRAY_CLOCK_WND_DATA This) -{ - HDC hDC; - HFONT hPrevFont; - INT c, i; - BOOL bRet = TRUE; - - hDC = GetDC(This->hWnd); - if (hDC != NULL) - { - hPrevFont = SelectObject(hDC, - This->hFont); - - for (i = 0; - i != CLOCKWND_FORMAT_COUNT && bRet; - i++) - { - if (This->szLines[i][0] != TEXT('\0') && - !GetTextExtentPoint(hDC, - This->szLines[i], - _tcslen(This->szLines[i]), - &This->LineSizes[i])) - { - bRet = FALSE; - break; - } - } - - SelectObject(hDC, - hPrevFont); - - ReleaseDC(This->hWnd, - hDC); - - if (bRet) - { - This->LineSpacing = 0; - - /* calculate the line spacing */ - for (i = 0, c = 0; - i != CLOCKWND_FORMAT_COUNT; - i++) - { - if (This->LineSizes[i].cx > 0) - { - This->LineSpacing += This->LineSizes[i].cy; - c++; - } - } - - if (c > 0) - { - /* We want a spaceing of 1/2 line */ - This->LineSpacing = (This->LineSpacing / c) / 2; - } - - return TRUE; - } - } - - return FALSE; -} - -static WORD -TrayClockWnd_GetMinimumSize(IN OUT PTRAY_CLOCK_WND_DATA This, - IN BOOL Horizontal, - IN OUT PSIZE pSize) -{ - WORD iLinesVisible = 0; - INT i; - SIZE szMax = { 0, 0 }; - - if (!This->LinesMeasured) - This->LinesMeasured = TrayClockWnd_MeasureLines(This); - - if (!This->LinesMeasured) - return 0; - - for (i = 0; - i != CLOCKWND_FORMAT_COUNT; - i++) - { - if (This->LineSizes[i].cx != 0) - { - if (iLinesVisible > 0) - { - if (Horizontal) - { - if (szMax.cy + This->LineSizes[i].cy + (LONG)This->LineSpacing > - pSize->cy - (2 * TRAY_CLOCK_WND_SPACING_Y)) - { - break; - } - } - else - { - if (This->LineSizes[i].cx > pSize->cx - (2 * TRAY_CLOCK_WND_SPACING_X)) - break; - } - - /* Add line spacing */ - szMax.cy += This->LineSpacing; - } - - iLinesVisible++; - - /* Increase maximum rectangle */ - szMax.cy += This->LineSizes[i].cy; - if (This->LineSizes[i].cx > szMax.cx - (2 * TRAY_CLOCK_WND_SPACING_X)) - szMax.cx = This->LineSizes[i].cx + (2 * TRAY_CLOCK_WND_SPACING_X); - } - } - - szMax.cx += 2 * TRAY_CLOCK_WND_SPACING_X; - szMax.cy += 2 * TRAY_CLOCK_WND_SPACING_Y; - - *pSize = szMax; - - return iLinesVisible; -} - - -static VOID -TrayClockWnd_UpdateWnd(IN OUT PTRAY_CLOCK_WND_DATA This) -{ - SIZE szPrevCurrent; - INT BufSize, iRet, i; - RECT rcClient; - - ZeroMemory(This->LineSizes, - sizeof(This->LineSizes)); - - szPrevCurrent = This->CurrentSize; - - for (i = 0; - i != CLOCKWND_FORMAT_COUNT; - i++) - { - This->szLines[i][0] = TEXT('\0'); - BufSize = sizeof(This->szLines[0]) / sizeof(This->szLines[0][0]); - - if (ClockWndFormats[i].IsTime) - { - iRet = GetTimeFormat(LOCALE_USER_DEFAULT, - AdvancedSettings.bShowSeconds ? ClockWndFormats[i].dwFormatFlags : TIME_NOSECONDS, - &This->LocalTime, - ClockWndFormats[i].lpFormat, - This->szLines[i], - BufSize); - } - else - { - iRet = GetDateFormat(LOCALE_USER_DEFAULT, - ClockWndFormats[i].dwFormatFlags, - &This->LocalTime, - ClockWndFormats[i].lpFormat, - This->szLines[i], - BufSize); - } - - if (iRet != 0 && i == 0) - { - /* Set the window text to the time only */ - SetWindowText(This->hWnd, - This->szLines[i]); - } - } - - This->LinesMeasured = TrayClockWnd_MeasureLines(This); - - if (This->LinesMeasured && - GetClientRect(This->hWnd, - &rcClient)) - { - SIZE szWnd; - - szWnd.cx = rcClient.right; - szWnd.cy = rcClient.bottom; - - This->VisibleLines = TrayClockWnd_GetMinimumSize(This, - This->IsHorizontal, - &szWnd); - This->CurrentSize = szWnd; - } - - if (IsWindowVisible(This->hWnd)) - { - InvalidateRect(This->hWnd, - NULL, - TRUE); - - if (This->hWndNotify != NULL && - (szPrevCurrent.cx != This->CurrentSize.cx || - szPrevCurrent.cy != This->CurrentSize.cy)) - { - NMHDR nmh; - - nmh.hwndFrom = This->hWnd; - nmh.idFrom = GetWindowLongPtr(This->hWnd, - GWLP_ID); - nmh.code = NTNWM_REALIGN; - - SendMessage(This->hWndNotify, - WM_NOTIFY, - (WPARAM)nmh.idFrom, - (LPARAM)&nmh); - } - } -} - -static VOID -TrayClockWnd_Update(IN OUT PTRAY_CLOCK_WND_DATA This) -{ - GetLocalTime(&This->LocalTime); - TrayClockWnd_UpdateWnd(This); -} - -static UINT -TrayClockWnd_CalculateDueTime(IN OUT PTRAY_CLOCK_WND_DATA This) -{ - UINT uiDueTime; - - /* Calculate the due time */ - GetLocalTime(&This->LocalTime); - uiDueTime = 1000 - (UINT)This->LocalTime.wMilliseconds; - if (AdvancedSettings.bShowSeconds) - uiDueTime += (UINT)This->LocalTime.wSecond * 100; - else - uiDueTime += (59 - (UINT)This->LocalTime.wSecond) * 1000; - - if (uiDueTime < USER_TIMER_MINIMUM || uiDueTime > USER_TIMER_MAXIMUM) - uiDueTime = 1000; - else - { - /* Add an artificial delay of 0.05 seconds to make sure the timer - doesn't fire too early*/ - uiDueTime += 50; - } - - return uiDueTime; -} - -static BOOL -TrayClockWnd_ResetTime(IN OUT PTRAY_CLOCK_WND_DATA This) -{ - UINT uiDueTime; - BOOL Ret; - - /* Disable all timers */ - if (This->IsTimerEnabled) - { - KillTimer(This->hWnd, - ID_TRAYCLOCK_TIMER); - This->IsTimerEnabled = FALSE; - } - - if (This->IsInitTimerEnabled) - { - KillTimer(This->hWnd, - ID_TRAYCLOCK_TIMER_INIT); - } - - uiDueTime = TrayClockWnd_CalculateDueTime(This); - - /* Set the new timer */ - Ret = SetTimer(This->hWnd, - ID_TRAYCLOCK_TIMER_INIT, - uiDueTime, - NULL) != 0; - This->IsInitTimerEnabled = Ret; - - /* Update the time */ - TrayClockWnd_Update(This); - - return Ret; -} - -static VOID -TrayClockWnd_CalibrateTimer(IN OUT PTRAY_CLOCK_WND_DATA This) -{ - UINT uiDueTime; - BOOL Ret; - UINT uiWait1, uiWait2; - - /* Kill the initialization timer */ - KillTimer(This->hWnd, - ID_TRAYCLOCK_TIMER_INIT); - This->IsInitTimerEnabled = FALSE; - - uiDueTime = TrayClockWnd_CalculateDueTime(This); - - if (AdvancedSettings.bShowSeconds) - { - uiWait1 = 1000 - 200; - uiWait2 = 1000; - } - else - { - uiWait1 = 60 * 1000 - 200; - uiWait2 = 60 * 1000; - } - - if (uiDueTime > uiWait1) - { - /* The update of the clock will be up to 200 ms late, but that's - acceptable. We're going to setup a timer that fires depending - uiWait2. */ - Ret = SetTimer(This->hWnd, - ID_TRAYCLOCK_TIMER, - uiWait2, - NULL) != 0; - This->IsTimerEnabled = Ret; - - /* Update the time */ - TrayClockWnd_Update(This); - } - else - { - /* Recalibrate the timer and recalculate again when the current - minute/second ends. */ - TrayClockWnd_ResetTime(This); - } -} - -static VOID -TrayClockWnd_NCDestroy(IN OUT PTRAY_CLOCK_WND_DATA This) -{ - /* Disable all timers */ - if (This->IsTimerEnabled) - { - KillTimer(This->hWnd, - ID_TRAYCLOCK_TIMER); - } - - if (This->IsInitTimerEnabled) - { - KillTimer(This->hWnd, - ID_TRAYCLOCK_TIMER_INIT); - } - - /* Free allocated resources */ - SetWindowLongPtr(This->hWnd, - 0, - 0); - HeapFree(hProcessHeap, - 0, - This); -} - -static VOID -TrayClockWnd_Paint(IN OUT PTRAY_CLOCK_WND_DATA This, - IN HDC hDC) -{ - RECT rcClient; - HFONT hPrevFont; - int iPrevBkMode, i, line; - - if (This->LinesMeasured && - GetClientRect(This->hWnd, - &rcClient)) - { - iPrevBkMode = SetBkMode(hDC, - TRANSPARENT); - - SetTextColor(hDC, This->textColor); - - hPrevFont = SelectObject(hDC, - This->hFont); - - rcClient.left = (rcClient.right / 2) - (This->CurrentSize.cx / 2); - rcClient.top = (rcClient.bottom / 2) - (This->CurrentSize.cy / 2); - rcClient.right = rcClient.left + This->CurrentSize.cx; - rcClient.bottom = rcClient.top + This->CurrentSize.cy; - - for (i = 0, line = 0; - i != CLOCKWND_FORMAT_COUNT && line < This->VisibleLines; - i++) - { - if (This->LineSizes[i].cx != 0) - { - TextOut(hDC, - rcClient.left + (This->CurrentSize.cx / 2) - (This->LineSizes[i].cx / 2) + - TRAY_CLOCK_WND_SPACING_X, - rcClient.top + TRAY_CLOCK_WND_SPACING_Y, - This->szLines[i], - _tcslen(This->szLines[i])); - - rcClient.top += This->LineSizes[i].cy + This->LineSpacing; - line++; - } - } - - SelectObject(hDC, - hPrevFont); - - SetBkMode(hDC, - iPrevBkMode); - } -} - -static VOID -TrayClockWnd_SetFont(IN OUT PTRAY_CLOCK_WND_DATA This, - IN HFONT hNewFont, - IN BOOL bRedraw) -{ - This->hFont = hNewFont; - This->LinesMeasured = TrayClockWnd_MeasureLines(This); - if (bRedraw) - { - InvalidateRect(This->hWnd, - NULL, - TRUE); - } -} - -static VOID -TrayClockWnd_DrawBackground(IN HWND hwnd, - IN HDC hdc) -{ - RECT rect; - - GetClientRect(hwnd, &rect); - DrawThemeParentBackground(hwnd, hdc, &rect); -} - -static LRESULT CALLBACK -TrayClockWndProc(IN HWND hwnd, - IN UINT uMsg, - IN WPARAM wParam, - IN LPARAM lParam) -{ - PTRAY_CLOCK_WND_DATA This = NULL; - - if (uMsg != WM_NCCREATE) - { - This = (PTRAY_CLOCK_WND_DATA)GetWindowLongPtr(hwnd, - 0); - } - - if (This != NULL || uMsg == WM_NCCREATE) - { - switch (uMsg) - { - case WM_THEMECHANGED: - TrayClockWnd_UpdateTheme(This); - break; - case WM_ERASEBKGND: - if (!IsAppThemed()) - break; - - TrayClockWnd_DrawBackground(hwnd, (HDC) wParam); - return TRUE; - case WM_PAINT: - case WM_PRINTCLIENT: - { - PAINTSTRUCT ps; - HDC hDC = (HDC)wParam; - - if (wParam == 0) - { - hDC = BeginPaint(This->hWnd, &ps); - } - - if (hDC != NULL) - { - TrayClockWnd_Paint(This, hDC); - - if (wParam == 0) - { - EndPaint(This->hWnd, &ps); - } - } - break; - } - - case WM_TIMER: - switch (wParam) - { - case ID_TRAYCLOCK_TIMER: - TrayClockWnd_Update(This); - break; - - case ID_TRAYCLOCK_TIMER_INIT: - TrayClockWnd_CalibrateTimer(This); - break; - } - break; - - case WM_NCHITTEST: - /* We want the user to be able to drag the task bar when clicking the clock */ - return HTTRANSPARENT; - - case TCWM_GETMINIMUMSIZE: - { - This->IsHorizontal = (BOOL)wParam; - - return (LRESULT) TrayClockWnd_GetMinimumSize(This, (BOOL) wParam, (PSIZE) lParam) != 0; - } - - case TCWM_UPDATETIME: - { - return (LRESULT)TrayClockWnd_ResetTime(This); - } - - case WM_NCCREATE: - { - LPCREATESTRUCT CreateStruct = (LPCREATESTRUCT)lParam; - This = (PTRAY_CLOCK_WND_DATA)CreateStruct->lpCreateParams; - This->hWnd = hwnd; - This->hWndNotify = CreateStruct->hwndParent; - - SetWindowLongPtr(hwnd, 0, (LONG_PTR) This); - TrayClockWnd_UpdateTheme(This); - - return TRUE; - } - - case WM_SETFONT: - { - TrayClockWnd_SetFont(This, - (HFONT)wParam, - (BOOL)LOWORD(lParam)); - break; - } - - case WM_CREATE: - TrayClockWnd_ResetTime(This); - break; - - case WM_NCDESTROY: - TrayClockWnd_NCDestroy(This); - break; - - case WM_SIZE: - { - SIZE szClient; - - szClient.cx = LOWORD(lParam); - szClient.cy = HIWORD(lParam); - This->VisibleLines = TrayClockWnd_GetMinimumSize(This, - This->IsHorizontal, - &szClient); - This->CurrentSize = szClient; - - InvalidateRect(This->hWnd, - NULL, - TRUE); - break; - } - } - } - - return DefWindowProc(hwnd, uMsg, wParam, lParam); -} - -static HWND -CreateTrayClockWnd(IN HWND hWndParent, - IN BOOL bVisible) -{ - PTRAY_CLOCK_WND_DATA TcData; - DWORD dwStyle; - HWND hWnd = NULL; - - TcData = HeapAlloc(hProcessHeap, - HEAP_ZERO_MEMORY, - sizeof(*TcData)); - if (TcData != NULL) - { - TcData->IsHorizontal = TRUE; - /* Create the window. The tray window is going to move it to the correct - position and resize it as needed. */ - dwStyle = WS_CHILD | WS_CLIPSIBLINGS; - if (bVisible) - dwStyle |= WS_VISIBLE; - - hWnd = CreateWindowEx(0, - szTrayClockWndClass, - NULL, - dwStyle, - 0, - 0, - 0, - 0, - hWndParent, - NULL, - hExplorerInstance, - TcData); - - if (hWnd != NULL) - { - SetWindowTheme(hWnd, L"TrayNotify", NULL); - } - else - { - HeapFree(hProcessHeap, - 0, - TcData); - } - } - - return hWnd; - -} - -static BOOL -RegisterTrayClockWndClass(VOID) -{ - WNDCLASS wcTrayClock; - - wcTrayClock.style = CS_DBLCLKS; - wcTrayClock.lpfnWndProc = TrayClockWndProc; - wcTrayClock.cbClsExtra = 0; - wcTrayClock.cbWndExtra = sizeof(PTRAY_CLOCK_WND_DATA); - wcTrayClock.hInstance = hExplorerInstance; - wcTrayClock.hIcon = NULL; - wcTrayClock.hCursor = LoadCursor(NULL, - IDC_ARROW); - wcTrayClock.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1); - wcTrayClock.lpszMenuName = NULL; - wcTrayClock.lpszClassName = szTrayClockWndClass; - - return RegisterClass(&wcTrayClock) != 0; -} - -static VOID -UnregisterTrayClockWndClass(VOID) -{ - UnregisterClass(szTrayClockWndClass, - hExplorerInstance); -} - -/* - * TrayNotifyWnd - */ - -static const TCHAR szTrayNotifyWndClass[] = TEXT("TrayNotifyWnd"); - -#define TRAY_NOTIFY_WND_SPACING_X 2 -#define TRAY_NOTIFY_WND_SPACING_Y 2 - -typedef struct _TRAY_NOTIFY_WND_DATA -{ - HWND hWnd; - HWND hWndTrayClock; - HWND hWndNotify; - HWND hWndSysPager; - HTHEME TrayTheme; - SIZE szTrayClockMin; - SIZE szTrayNotify; - MARGINS ContentMargin; - ITrayWindow *TrayWindow; - HFONT hFontClock; - union - { - DWORD dwFlags; - struct - { - DWORD HideClock : 1; - DWORD IsHorizontal : 1; - }; - }; -} TRAY_NOTIFY_WND_DATA, *PTRAY_NOTIFY_WND_DATA; - -static VOID -TrayNotifyWnd_UpdateTheme(IN OUT PTRAY_NOTIFY_WND_DATA This) -{ - LONG_PTR style; - - if (This->TrayTheme) - CloseThemeData(This->TrayTheme); - - if (IsThemeActive()) - This->TrayTheme = OpenThemeData(This->hWnd, L"TrayNotify"); - else - This->TrayTheme = 0; - - if (This->TrayTheme) - { - style = GetWindowLong(This->hWnd, GWL_EXSTYLE); - style = style & ~WS_EX_STATICEDGE; - SetWindowLong(This->hWnd, GWL_EXSTYLE, style); - - GetThemeMargins(This->TrayTheme, - NULL, - TNP_BACKGROUND, - 0, - TMT_CONTENTMARGINS, - NULL, - &This->ContentMargin); - } - else - { - style = GetWindowLong(This->hWnd, GWL_EXSTYLE); - style = style | WS_EX_STATICEDGE; - SetWindowLong(This->hWnd, GWL_EXSTYLE, style); - - This->ContentMargin.cxLeftWidth = 0; - This->ContentMargin.cxRightWidth = 0; - This->ContentMargin.cyTopHeight = 0; - This->ContentMargin.cyBottomHeight = 0; - } -} - -static VOID -TrayNotifyWnd_Create(IN OUT PTRAY_NOTIFY_WND_DATA This) -{ - This->hWndTrayClock = CreateTrayClockWnd(This->hWnd, - !This->HideClock); - - This->hWndSysPager = CreateSysPagerWnd(This->hWnd, - !This->HideClock); - - TrayNotifyWnd_UpdateTheme(This); -} - -static VOID -TrayNotifyWnd_NCDestroy(IN OUT PTRAY_NOTIFY_WND_DATA This) -{ - SetWindowLongPtr(This->hWnd, - 0, - 0); - HeapFree(hProcessHeap, - 0, - This); -} - -static BOOL -TrayNotifyWnd_GetMinimumSize(IN OUT PTRAY_NOTIFY_WND_DATA This, - IN BOOL Horizontal, - IN OUT PSIZE pSize) -{ - SIZE szClock = { 0, 0 }; - SIZE szTray = { 0, 0 }; - - This->IsHorizontal = Horizontal; - if (This->IsHorizontal) - SetWindowTheme(This->hWnd, L"TrayNotifyHoriz", NULL); - else - SetWindowTheme(This->hWnd, L"TrayNotifyVert", NULL); - - if (!This->HideClock) - { - if (Horizontal) - { - szClock.cy = pSize->cy - 2 * TRAY_NOTIFY_WND_SPACING_Y; - if (szClock.cy <= 0) - goto NoClock; - } - else - { - szClock.cx = pSize->cx - 2 * TRAY_NOTIFY_WND_SPACING_X; - if (szClock.cx <= 0) - goto NoClock; - } - - SendMessage(This->hWndTrayClock, - TCWM_GETMINIMUMSIZE, - (WPARAM)Horizontal, - (LPARAM)&szClock); - - This->szTrayClockMin = szClock; - } - else -NoClock: - This->szTrayClockMin = szClock; - - if (Horizontal) - { - szTray.cy = pSize->cy - 2 * TRAY_NOTIFY_WND_SPACING_Y; - } - else - { - szTray.cx = pSize->cx - 2 * TRAY_NOTIFY_WND_SPACING_X; - } - - SysPagerWnd_GetSize(This->hWndSysPager, - Horizontal, - &szTray); - - This->szTrayNotify = szTray; - - if (Horizontal) - { - pSize->cx = 2 * TRAY_NOTIFY_WND_SPACING_X; - - if (!This->HideClock) - pSize->cx += TRAY_NOTIFY_WND_SPACING_X + This->szTrayClockMin.cx; - - pSize->cx += szTray.cx; - } - else - { - pSize->cy = 2 * TRAY_NOTIFY_WND_SPACING_Y; - - if (!This->HideClock) - pSize->cy += TRAY_NOTIFY_WND_SPACING_Y + This->szTrayClockMin.cy; - - pSize->cy += szTray.cy; - } - - pSize->cy += This->ContentMargin.cyTopHeight + This->ContentMargin.cyBottomHeight; - pSize->cx += This->ContentMargin.cxLeftWidth + This->ContentMargin.cxRightWidth; - - return TRUE; -} - -static VOID -TrayNotifyWnd_Size(IN OUT PTRAY_NOTIFY_WND_DATA This, - IN const SIZE *pszClient) -{ - if (!This->HideClock) - { - POINT ptClock; - SIZE szClock; - - if (This->IsHorizontal) - { - ptClock.x = pszClient->cx - TRAY_NOTIFY_WND_SPACING_X - This->szTrayClockMin.cx; - ptClock.y = TRAY_NOTIFY_WND_SPACING_Y; - szClock.cx = This->szTrayClockMin.cx; - szClock.cy = pszClient->cy - (2 * TRAY_NOTIFY_WND_SPACING_Y); - } - else - { - ptClock.x = TRAY_NOTIFY_WND_SPACING_X; - ptClock.y = pszClient->cy - TRAY_NOTIFY_WND_SPACING_Y - This->szTrayClockMin.cy; - szClock.cx = pszClient->cx - (2 * TRAY_NOTIFY_WND_SPACING_X); - szClock.cy = This->szTrayClockMin.cy; - } - - SetWindowPos(This->hWndTrayClock, - NULL, - ptClock.x, - ptClock.y, - szClock.cx, - szClock.cy, - SWP_NOZORDER); - - if (This->IsHorizontal) - { - ptClock.x -= This->szTrayNotify.cx; - } - else - { - ptClock.y -= This->szTrayNotify.cy; - } - - SetWindowPos(This->hWndSysPager, - NULL, - ptClock.x, - ptClock.y, - This->szTrayNotify.cx, - This->szTrayNotify.cy, - SWP_NOZORDER); - } -} - -static VOID -TrayNotifyWnd_DrawBackground(IN HWND hwnd, - IN HDC hdc) -{ - PTRAY_NOTIFY_WND_DATA This = (PTRAY_NOTIFY_WND_DATA)GetWindowLongPtr(hwnd, 0); - RECT rect; - - GetClientRect(hwnd, &rect); - - DrawThemeParentBackground(hwnd, hdc, &rect); - DrawThemeBackground(This->TrayTheme, hdc, TNP_BACKGROUND, 0, &rect, 0); -} - -VOID -TrayNotify_NotifyMsg(IN HWND hwnd, - IN WPARAM wParam, - IN LPARAM lParam) -{ - PTRAY_NOTIFY_WND_DATA This = (PTRAY_NOTIFY_WND_DATA)GetWindowLongPtr(hwnd, 0); - if (This->hWndSysPager) - { - SysPagerWnd_NotifyMsg(This->hWndSysPager, - wParam, - lParam); - } -} - -BOOL -TrayNotify_GetClockRect(IN HWND hwnd, - OUT PRECT rcClock) -{ - PTRAY_NOTIFY_WND_DATA This = (PTRAY_NOTIFY_WND_DATA)GetWindowLongPtr(hwnd, 0); - if (!IsWindowVisible(This->hWndTrayClock)) - return FALSE; - - return GetWindowRect(This->hWndTrayClock, rcClock); -} - -static LRESULT CALLBACK -TrayNotifyWndProc(IN HWND hwnd, - IN UINT uMsg, - IN WPARAM wParam, - IN LPARAM lParam) -{ - PTRAY_NOTIFY_WND_DATA This = NULL; - - if (uMsg != WM_NCCREATE) - { - This = (PTRAY_NOTIFY_WND_DATA)GetWindowLongPtr(hwnd, 0); - } - - if (This != NULL || uMsg == WM_NCCREATE) - { - switch (uMsg) - { - case WM_THEMECHANGED: - TrayNotifyWnd_UpdateTheme(This); - return 0; - case WM_ERASEBKGND: - if (!This->TrayTheme) - break; - TrayNotifyWnd_DrawBackground(hwnd, (HDC) wParam); - return 0; - case TNWM_GETMINIMUMSIZE: - { - return (LRESULT) TrayNotifyWnd_GetMinimumSize(This, (BOOL) wParam, (PSIZE) lParam); - } - - case TNWM_UPDATETIME: - { - if (This->hWndTrayClock != NULL) - { - /* Forward the message to the tray clock window procedure */ - return TrayClockWndProc(This->hWndTrayClock, TCWM_UPDATETIME, wParam, lParam); - } - return 0; - } - - case WM_SIZE: - { - SIZE szClient; - - szClient.cx = LOWORD(lParam); - szClient.cy = HIWORD(lParam); - - TrayNotifyWnd_Size(This, &szClient); - return 0; - } - - case WM_NCHITTEST: - /* We want the user to be able to drag the task bar when clicking the - tray notification window */ - return HTTRANSPARENT; - case TNWM_SHOWCLOCK: - { - BOOL PrevHidden = This->HideClock; - This->HideClock = (wParam == 0); - - if (This->hWndTrayClock != NULL && PrevHidden != This->HideClock) - { - ShowWindow(This->hWndTrayClock, - This->HideClock ? SW_HIDE : SW_SHOW); - } - - return (LRESULT) (!PrevHidden); - } - - case WM_NOTIFY: - { - const NMHDR *nmh = (const NMHDR *)lParam; - - if (nmh->hwndFrom == This->hWndTrayClock) - { - /* Pass down notifications */ - return SendMessage(This->hWndNotify, WM_NOTIFY, wParam, lParam); - } - return 0; - } - - case WM_SETFONT: - { - if (This->hWndTrayClock != NULL) - { - SendMessage(This->hWndTrayClock, - WM_SETFONT, - wParam, - lParam); - } - break; - } - - case WM_NCCREATE: - { - LPCREATESTRUCT CreateStruct = (LPCREATESTRUCT)lParam; - This = (PTRAY_NOTIFY_WND_DATA)CreateStruct->lpCreateParams; - This->hWnd = hwnd; - This->hWndNotify = CreateStruct->hwndParent; - - SetWindowLongPtr(hwnd, 0, (LONG_PTR) This); - - return TRUE; - } - - case WM_CREATE: - TrayNotifyWnd_Create(This); - return 0; - - case WM_NCDESTROY: - TrayNotifyWnd_NCDestroy(This); - return 0; - } - } - - return DefWindowProc(hwnd, uMsg, wParam, lParam); -} - -HWND -CreateTrayNotifyWnd(IN OUT ITrayWindow *TrayWindow, - IN BOOL bHideClock) -{ - PTRAY_NOTIFY_WND_DATA TnData; - HWND hWndTrayWindow; - HWND hWnd = NULL; - - hWndTrayWindow = ITrayWindow_GetHWND(TrayWindow); - if (hWndTrayWindow == NULL) - return NULL; - - TnData = HeapAlloc(hProcessHeap, - HEAP_ZERO_MEMORY, - sizeof(*TnData)); - if (TnData != NULL) - { - TnData->TrayWindow = TrayWindow; - TnData->HideClock = bHideClock; - - /* Create the window. The tray window is going to move it to the correct - position and resize it as needed. */ - hWnd = CreateWindowEx(WS_EX_STATICEDGE, - szTrayNotifyWndClass, - NULL, - WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, - 0, - 0, - 0, - 0, - hWndTrayWindow, - NULL, - hExplorerInstance, - TnData); - - if (hWnd == NULL) - { - HeapFree(hProcessHeap, - 0, - TnData); - } - } - - return hWnd; -} - -BOOL -RegisterTrayNotifyWndClass(VOID) -{ - WNDCLASS wcTrayWnd; - BOOL Ret; - - wcTrayWnd.style = CS_DBLCLKS; - wcTrayWnd.lpfnWndProc = TrayNotifyWndProc; - wcTrayWnd.cbClsExtra = 0; - wcTrayWnd.cbWndExtra = sizeof(PTRAY_NOTIFY_WND_DATA); - wcTrayWnd.hInstance = hExplorerInstance; - wcTrayWnd.hIcon = NULL; - wcTrayWnd.hCursor = LoadCursor(NULL, - IDC_ARROW); - wcTrayWnd.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1); - wcTrayWnd.lpszMenuName = NULL; - wcTrayWnd.lpszClassName = szTrayNotifyWndClass; - - Ret = RegisterClass(&wcTrayWnd) != 0; - - if (Ret) - { - Ret = RegisterTrayClockWndClass(); - if (!Ret) - { - UnregisterClass(szTrayNotifyWndClass, - hExplorerInstance); - } - RegisterSysPagerWndClass(); - } - - return Ret; -} - -VOID -UnregisterTrayNotifyWndClass(VOID) -{ - UnregisterTrayClockWndClass(); - - UnregisterSysPagerWndClass(); - - UnregisterClass(szTrayNotifyWndClass, - hExplorerInstance); -} diff --git a/base/shell/explorer-new/trayntfy.cpp b/base/shell/explorer-new/trayntfy.cpp new file mode 100644 index 00000000000..87b6902644c --- /dev/null +++ b/base/shell/explorer-new/trayntfy.cpp @@ -0,0 +1,1618 @@ +/* + * ReactOS Explorer + * + * Copyright 2006 - 2007 Thomas Weidenmueller + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "precomp.h" +//#include + +typedef unsigned short USHORT; + +/* + * SysPagerWnd + */ +static const WCHAR szSysPagerWndClass [] = TEXT("SysPager"); + +typedef struct _NOTIFY_ITEM +{ + struct _NOTIFY_ITEM *next; + INT Index; + INT IconIndex; + NOTIFYICONDATA iconData; +} NOTIFY_ITEM, *PNOTIFY_ITEM, **PPNOTIFY_ITEM; + +// Data comes from shell32/systray.cpp -> TrayNotifyCDS_Dummy +typedef struct _SYS_PAGER_COPY_DATA +{ + DWORD cookie; + DWORD notify_code; + NOTIFYICONDATA nicon_data; +} SYS_PAGER_COPY_DATA, *PSYS_PAGER_COPY_DATA; + +class CSysPagerWnd : + public CComObjectRootEx, + public CWindowImpl < CSysPagerWnd, CWindow, CControlWinTraits > +{ + CContainedWindow NotificationBar; + + HWND hWndToolbar; + HIMAGELIST SysIcons; + PNOTIFY_ITEM NotifyItems; + INT ButtonCount; + INT VisibleButtonCount; + +public: + CSysPagerWnd() : + NotificationBar(this, 1), + hWndToolbar(NULL), + SysIcons(NULL), + NotifyItems(NULL), + ButtonCount(0), + VisibleButtonCount(0) + { + } + virtual ~CSysPagerWnd() { } + + PNOTIFY_ITEM CreateNotifyItemData() + { + PNOTIFY_ITEM *findNotifyPointer = &NotifyItems; + PNOTIFY_ITEM notifyItem; + + notifyItem = (PNOTIFY_ITEM) HeapAlloc(hProcessHeap, HEAP_ZERO_MEMORY, sizeof(*notifyItem)); + if (notifyItem == NULL) + return NULL; + + notifyItem->next = NULL; + + while (*findNotifyPointer != NULL) + { + findNotifyPointer = &(*findNotifyPointer)->next; + } + + *findNotifyPointer = notifyItem; + + return notifyItem; + } + + PPNOTIFY_ITEM FindPPNotifyItemByIconData(IN CONST NOTIFYICONDATA *iconData) + { + PPNOTIFY_ITEM findNotifyPointer = &NotifyItems; + + while (*findNotifyPointer != NULL) + { + if ((*findNotifyPointer)->iconData.hWnd == iconData->hWnd && + (*findNotifyPointer)->iconData.uID == iconData->uID) + { + return findNotifyPointer; + } + findNotifyPointer = &(*findNotifyPointer)->next; + } + + return NULL; + } + + PPNOTIFY_ITEM FindPPNotifyItemByIndex(IN WORD wIndex) + { + PPNOTIFY_ITEM findNotifyPointer = &NotifyItems; + + while (*findNotifyPointer != NULL) + { + if ((*findNotifyPointer)->Index == wIndex) + { + return findNotifyPointer; + } + findNotifyPointer = &(*findNotifyPointer)->next; + } + + return NULL; + } + + VOID UpdateButton(IN CONST NOTIFYICONDATA *iconData) + { + TBBUTTONINFO tbbi = { 0 }; + PNOTIFY_ITEM notifyItem; + PPNOTIFY_ITEM NotifyPointer; + + NotifyPointer = FindPPNotifyItemByIconData(iconData); + notifyItem = *NotifyPointer; + + tbbi.cbSize = sizeof(tbbi); + tbbi.dwMask = TBIF_BYINDEX | TBIF_COMMAND; + tbbi.idCommand = notifyItem->Index; + + if (iconData->uFlags & NIF_MESSAGE) + { + notifyItem->iconData.uCallbackMessage = iconData->uCallbackMessage; + } + + if (iconData->uFlags & NIF_ICON) + { + tbbi.dwMask |= TBIF_IMAGE; + notifyItem->IconIndex = tbbi.iImage = ImageList_AddIcon(SysIcons, iconData->hIcon); + } + + if (iconData->uFlags & NIF_TIP) + { + StringCchCopy(notifyItem->iconData.szTip, _countof(notifyItem->iconData.szTip), iconData->szTip); + } + + if (iconData->uFlags & NIF_STATE) + { + if (iconData->dwStateMask & NIS_HIDDEN && + (notifyItem->iconData.dwState & NIS_HIDDEN) != (iconData->dwState & NIS_HIDDEN)) + { + tbbi.dwMask |= TBIF_STATE; + if (iconData->dwState & NIS_HIDDEN) + { + tbbi.fsState |= TBSTATE_HIDDEN; + VisibleButtonCount--; + } + else + { + tbbi.fsState &= ~TBSTATE_HIDDEN; + VisibleButtonCount++; + } + } + + notifyItem->iconData.dwState &= ~iconData->dwStateMask; + notifyItem->iconData.dwState |= (iconData->dwState & iconData->dwStateMask); + } + + /* TODO: support NIF_INFO, NIF_GUID, NIF_REALTIME, NIF_SHOWTIP */ + + NotificationBar.SendMessageW(TB_SETBUTTONINFO, (WPARAM) notifyItem->Index, (LPARAM) &tbbi); + } + + VOID AddButton(IN CONST NOTIFYICONDATA *iconData) + { + TBBUTTON tbBtn; + PNOTIFY_ITEM notifyItem; + WCHAR text [] = TEXT(""); + + notifyItem = CreateNotifyItemData(); + + notifyItem->next = NULL; + notifyItem->Index = ButtonCount; + ButtonCount++; + VisibleButtonCount++; + + notifyItem->iconData.hWnd = iconData->hWnd; + notifyItem->iconData.uID = iconData->uID; + + tbBtn.fsState = TBSTATE_ENABLED; + tbBtn.fsStyle = BTNS_NOPREFIX; + tbBtn.dwData = notifyItem->Index; + + tbBtn.iString = (INT_PTR) text; + tbBtn.idCommand = notifyItem->Index; + + if (iconData->uFlags & NIF_MESSAGE) + { + notifyItem->iconData.uCallbackMessage = iconData->uCallbackMessage; + } + + if (iconData->uFlags & NIF_ICON) + { + notifyItem->IconIndex = tbBtn.iBitmap = ImageList_AddIcon(SysIcons, iconData->hIcon); + } + + /* TODO: support NIF_TIP */ + + if (iconData->uFlags & NIF_STATE) + { + notifyItem->iconData.dwState &= ~iconData->dwStateMask; + notifyItem->iconData.dwState |= (iconData->dwState & iconData->dwStateMask); + if (notifyItem->iconData.dwState & NIS_HIDDEN) + { + tbBtn.fsState |= TBSTATE_HIDDEN; + VisibleButtonCount--; + } + + } + + /* TODO: support NIF_INFO, NIF_GUID, NIF_REALTIME, NIF_SHOWTIP */ + + NotificationBar.SendMessageW(TB_INSERTBUTTON, notifyItem->Index, (LPARAM) &tbBtn); + + NotificationBar.SendMessageW(TB_SETBUTTONSIZE, 0, MAKELONG(16, 16)); + } + + VOID RemoveButton(IN CONST NOTIFYICONDATA *iconData) + { + PPNOTIFY_ITEM NotifyPointer; + + NotifyPointer = FindPPNotifyItemByIconData(iconData); + if (NotifyPointer) + { + PNOTIFY_ITEM deleteItem; + PNOTIFY_ITEM updateItem; + deleteItem = *NotifyPointer; + + NotificationBar.SendMessageW(TB_DELETEBUTTON, deleteItem->Index, 0); + + *NotifyPointer = updateItem = deleteItem->next; + + if (!(deleteItem->iconData.dwState & NIS_HIDDEN)) + VisibleButtonCount--; + HeapFree(hProcessHeap, + 0, + deleteItem); + ButtonCount--; + + while (updateItem != NULL) + { + TBBUTTONINFO tbbi; + updateItem->Index--; + tbbi.cbSize = sizeof(tbbi); + tbbi.dwMask = TBIF_BYINDEX | TBIF_COMMAND; + tbbi.idCommand = updateItem->Index; + + NotificationBar.SendMessageW(TB_SETBUTTONINFO, updateItem->Index, (LPARAM) &tbbi); + + updateItem = updateItem->next; + } + } + } + + VOID SendMouseEvent(IN WORD wIndex, IN UINT uMsg, IN WPARAM wParam) + { + PPNOTIFY_ITEM NotifyPointer; + + static LPCWSTR eventNames [] = { + L"WM_MOUSEMOVE", + L"WM_LBUTTONDOWN", + L"WM_LBUTTONUP", + L"WM_LBUTTONDBLCLK", + L"WM_RBUTTONDOWN", + L"WM_RBUTTONUP", + L"WM_RBUTTONDBLCLK", + L"WM_MBUTTONDOWN", + L"WM_MBUTTONUP", + L"WM_MBUTTONDBLCLK", + L"WM_MOUSEWHEEL", + L"WM_XBUTTONDOWN", + L"WM_XBUTTONUP", + L"WM_XBUTTONDBLCLK" + }; + + NotifyPointer = FindPPNotifyItemByIndex(wIndex); + if (!NotifyPointer) + return; + + PNOTIFY_ITEM notifyItem = *NotifyPointer; + + if (!::IsWindow(notifyItem->iconData.hWnd)) + return; + + if (uMsg >= WM_MOUSEFIRST && uMsg <= WM_MOUSELAST) + { + DbgPrint("Sending message %S from button %d to %p (msg=%x, w=%x, l=%x)...\n", + eventNames[uMsg - WM_MOUSEFIRST], wIndex, + notifyItem->iconData.hWnd, notifyItem->iconData.uCallbackMessage, notifyItem->iconData.uID, uMsg); + } + + DWORD pid; + GetWindowThreadProcessId(notifyItem->iconData.hWnd, &pid); + + if (pid == GetCurrentProcessId() || + (uMsg >= WM_MOUSEFIRST && uMsg <= WM_MOUSELAST)) + { + PostMessage(notifyItem->iconData.hWnd, + notifyItem->iconData.uCallbackMessage, + notifyItem->iconData.uID, + uMsg); + } + else + { + SendMessage(notifyItem->iconData.hWnd, + notifyItem->iconData.uCallbackMessage, + notifyItem->iconData.uID, + uMsg); + } + } + + LRESULT DrawBackground(HDC hdc) + { + RECT rect; + + GetClientRect(&rect); + DrawThemeParentBackground(m_hWnd, hdc, &rect); + + return TRUE; + } + + LRESULT OnEraseBackground(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + HDC hdc = (HDC) wParam; + + if (!IsAppThemed()) + { + bHandled = FALSE; + return 0; + } + + return DrawBackground(hdc); + } + + LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + DWORD styles = + WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | + TBSTYLE_FLAT | TBSTYLE_TOOLTIPS | TBSTYLE_WRAPABLE | TBSTYLE_TRANSPARENT | + CCS_TOP | CCS_NORESIZE | CCS_NOPARENTALIGN | CCS_NODIVIDER; + DWORD exStyles = WS_EX_TOOLWINDOW; + + hWndToolbar = CreateWindowEx(exStyles, + TOOLBARCLASSNAME, + NULL, + styles, + 0, + 0, + 0, + 0, + m_hWnd, + NULL, + hExplorerInstance, + NULL); + if (hWndToolbar != NULL) + { + SIZE BtnSize; + + NotificationBar.SubclassWindow(hWndToolbar); + + SetWindowTheme(hWndToolbar, L"TrayNotify", NULL); + + /* Identify the version we're using */ + NotificationBar.SendMessageW(TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0); + + SysIcons = ImageList_Create(16, 16, ILC_COLOR32 | ILC_MASK, 0, 1000); + NotificationBar.SendMessageW(TB_SETIMAGELIST, 0, (LPARAM) SysIcons); + + BtnSize.cx = BtnSize.cy = 18; + NotificationBar.SendMessageW(TB_SETBUTTONSIZE, 0, MAKELONG(BtnSize.cx, BtnSize.cy)); + + } + + return TRUE; + } + + LRESULT NotifyMsg(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + PCOPYDATASTRUCT cpData = (PCOPYDATASTRUCT) lParam; + if (cpData->dwData == 1) + { + SYS_PAGER_COPY_DATA * data; + NOTIFYICONDATA *iconData; + HWND parentHWND; + RECT windowRect; + parentHWND = GetParent(); + parentHWND = ::GetParent(parentHWND); + ::GetClientRect(parentHWND, &windowRect); + + data = (PSYS_PAGER_COPY_DATA) cpData->lpData; + iconData = &data->nicon_data; + + switch (data->notify_code) + { + case NIM_ADD: + { + PPNOTIFY_ITEM NotifyPointer; + + NotifyPointer = FindPPNotifyItemByIconData(iconData); + if (!NotifyPointer) + { + AddButton(iconData); + } + break; + } + case NIM_MODIFY: + { + PPNOTIFY_ITEM NotifyPointer; + + NotifyPointer = FindPPNotifyItemByIconData(iconData); + if (!NotifyPointer) + { + AddButton(iconData); + } + else + { + UpdateButton(iconData); + } + break; + } + case NIM_DELETE: + { + RemoveButton(iconData); + break; + } + default: + TRACE("NotifyMessage received with unknown code %d.\n", data->notify_code); + break; + } + SendMessage(parentHWND, + WM_SIZE, + 0, + MAKELONG(windowRect.right - windowRect.left, + windowRect.bottom - windowRect.top)); + } + + return TRUE; + } + + void GetSize(IN WPARAM wParam, IN PSIZE size) + { + INT rows = 0; + TBMETRICS tbm; + + if (wParam) /* horizontal */ + { + rows = size->cy / 24; + if (rows == 0) + rows++; + size->cx = (VisibleButtonCount + rows - 1) / rows * 24; + } + else + { + rows = size->cx / 24; + if (rows == 0) + rows++; + size->cy = (VisibleButtonCount + rows - 1) / rows * 24; + } + + tbm.cbSize = sizeof(tbm); + tbm.dwMask = TBMF_BARPAD | TBMF_BUTTONSPACING; + tbm.cxBarPad = tbm.cyBarPad = 0; + tbm.cxButtonSpacing = 0; + tbm.cyButtonSpacing = 0; + + NotificationBar.SendMessageW(TB_SETMETRICS, 0, (LPARAM) &tbm); + } + + LRESULT OnTimer(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + return TRUE; + } + + LRESULT OnGetInfoTip(INT uCode, LPNMHDR hdr, BOOL& bHandled) + { + NMTBGETINFOTIPW * nmtip = (NMTBGETINFOTIPW *) hdr; + PPNOTIFY_ITEM ptr = FindPPNotifyItemByIndex(nmtip->iItem); + if (ptr) + { + PNOTIFY_ITEM item = *ptr; + StringCchCopy(nmtip->pszText, nmtip->cchTextMax, item->iconData.szTip); + } + return TRUE; + } + + LRESULT OnCustomDraw(INT uCode, LPNMHDR hdr, BOOL& bHandled) + { + NMCUSTOMDRAW * cdraw = (NMCUSTOMDRAW *) hdr; + switch (cdraw->dwDrawStage) + { + case CDDS_PREPAINT: + return CDRF_NOTIFYITEMDRAW; + + case CDDS_ITEMPREPAINT: + return TBCDRF_NOBACKGROUND | TBCDRF_NOEDGES | TBCDRF_NOOFFSET | TBCDRF_NOMARK | TBCDRF_NOETCHEDEFFECT; + } + return TRUE; + } + + LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + LRESULT Ret = TRUE; + SIZE szClient; + szClient.cx = LOWORD(lParam); + szClient.cy = HIWORD(lParam); + + Ret = DefWindowProc(uMsg, wParam, lParam); + + if (hWndToolbar != NULL && hWndToolbar != m_hWnd) + { + NotificationBar.SetWindowPos(NULL, 0, 0, szClient.cx, szClient.cy, SWP_NOZORDER); + + NotificationBar.SendMessageW(TB_AUTOSIZE); + + RECT rc; + NotificationBar.GetClientRect(&rc); + + SIZE szBar = { rc.right - rc.left, rc.bottom - rc.top }; + + INT xOff = (szClient.cx - szBar.cx) / 2; + INT yOff = (szClient.cy - szBar.cy) / 2; + + NotificationBar.SetWindowPos(NULL, xOff, yOff, szBar.cx, szBar.cy, SWP_NOZORDER); + } + return Ret; + } + + LRESULT OnMouseEvent(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + POINT pt; + INT iBtn; + + pt.x = LOWORD(lParam); + pt.y = HIWORD(lParam); + + iBtn = (INT) NotificationBar.SendMessageW(TB_HITTEST, 0, (LPARAM) &pt); + + if (iBtn >= 0) + { + SendMouseEvent(iBtn, uMsg, wParam); + } + + return FALSE; + } + + DECLARE_WND_CLASS_EX(szSysPagerWndClass, CS_DBLCLKS, COLOR_3DFACE) + + BEGIN_MSG_MAP(CTaskSwitchWnd) + MESSAGE_HANDLER(WM_CREATE, OnCreate) + MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground) + MESSAGE_HANDLER(WM_SIZE, OnSize) + NOTIFY_CODE_HANDLER(TBN_GETINFOTIPW, OnGetInfoTip) + NOTIFY_CODE_HANDLER(NM_CUSTOMDRAW, OnCustomDraw) + ALT_MSG_MAP(1) + MESSAGE_RANGE_HANDLER(WM_MOUSEFIRST, WM_MOUSELAST, OnMouseEvent) + END_MSG_MAP() + + HWND _Init(IN HWND hWndParent, IN BOOL bVisible) + { + DWORD dwStyle; + + NotifyItems = NULL; + ButtonCount = 0; + VisibleButtonCount = 0; + + /* Create the window. The tray window is going to move it to the correct + position and resize it as needed. */ + dwStyle = WS_CHILD | WS_CLIPSIBLINGS; + if (bVisible) + dwStyle |= WS_VISIBLE; + + Create(hWndParent, 0, NULL, dwStyle); + + if (!m_hWnd) + { + return NULL; + } + + SetWindowTheme(m_hWnd, L"TrayNotify", NULL); + + return m_hWnd; + } +}; + +/* + * TrayClockWnd + */ + +static const WCHAR szTrayClockWndClass [] = TEXT("TrayClockWClass"); + +#define ID_TRAYCLOCK_TIMER 0 +#define ID_TRAYCLOCK_TIMER_INIT 1 + +static const struct +{ + BOOL IsTime; + DWORD dwFormatFlags; + LPCTSTR lpFormat; +} ClockWndFormats [] = { + { TRUE, 0, NULL }, + { FALSE, 0, TEXT("dddd") }, + { FALSE, DATE_SHORTDATE, NULL } +}; + +#define CLOCKWND_FORMAT_COUNT (sizeof(ClockWndFormats) / sizeof(ClockWndFormats[0])) + +#define TRAY_CLOCK_WND_SPACING_X 0 +#define TRAY_CLOCK_WND_SPACING_Y 0 + +class CTrayClockWnd : + public CComObjectRootEx, + public CWindowImpl < CTrayClockWnd, CWindow, CControlWinTraits > +{ + HWND hWndNotify; + HFONT hFont; + COLORREF textColor; + RECT rcText; + SYSTEMTIME LocalTime; + + union + { + DWORD dwFlags; + struct + { + DWORD IsTimerEnabled : 1; + DWORD IsInitTimerEnabled : 1; + DWORD LinesMeasured : 1; + DWORD IsHorizontal : 1; + }; + }; + DWORD LineSpacing; + SIZE CurrentSize; + WORD VisibleLines; + SIZE LineSizes[CLOCKWND_FORMAT_COUNT]; + WCHAR szLines[CLOCKWND_FORMAT_COUNT][48]; + +public: + CTrayClockWnd() : + hWndNotify(NULL), + hFont(NULL), + dwFlags(0), + LineSpacing(0), + VisibleLines(0) + { + ZeroMemory(&textColor, sizeof(textColor)); + ZeroMemory(&rcText, sizeof(rcText)); + ZeroMemory(&LocalTime, sizeof(LocalTime)); + ZeroMemory(&CurrentSize, sizeof(CurrentSize)); + ZeroMemory(LineSizes, sizeof(LineSizes)); + ZeroMemory(szLines, sizeof(LineSizes)); + } + virtual ~CTrayClockWnd() { } + + LRESULT OnThemeChanged() + { + LOGFONTW clockFont; + HTHEME clockTheme; + HFONT hFont; + + clockTheme = OpenThemeData(m_hWnd, L"Clock"); + + if (clockTheme) + { + GetThemeFont(clockTheme, + NULL, + CLP_TIME, + 0, + TMT_FONT, + &clockFont); + + hFont = CreateFontIndirectW(&clockFont); + + GetThemeColor(clockTheme, + CLP_TIME, + 0, + TMT_TEXTCOLOR, + &textColor); + } + else + { + NONCLIENTMETRICS ncm = { 0 }; + ncm.cbSize = sizeof(ncm); + SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, FALSE); + + hFont = CreateFontIndirectW(&ncm.lfMessageFont); + + textColor = RGB(0, 0, 0); + } + + SetFont(hFont, FALSE); + + CloseThemeData(clockTheme); + + return TRUE; + } + + LRESULT OnThemeChanged(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + return OnThemeChanged(); + } + + BOOL MeasureLines() + { + HDC hDC; + HFONT hPrevFont; + INT c, i; + BOOL bRet = TRUE; + + hDC = GetDC(m_hWnd); + if (hDC != NULL) + { + if (hFont) + hPrevFont = (HFONT) SelectObject(hDC, hFont); + + for (i = 0; i != CLOCKWND_FORMAT_COUNT && bRet; i++) + { + if (szLines[i][0] != TEXT('\0') && + !GetTextExtentPoint(hDC, szLines[i], _tcslen(szLines[i]), + &LineSizes[i])) + { + bRet = FALSE; + break; + } + } + + if (hFont) + SelectObject(hDC, hPrevFont); + + ReleaseDC(m_hWnd, hDC); + + if (bRet) + { + LineSpacing = 0; + + /* calculate the line spacing */ + for (i = 0, c = 0; i != CLOCKWND_FORMAT_COUNT; i++) + { + if (LineSizes[i].cx > 0) + { + LineSpacing += LineSizes[i].cy; + c++; + } + } + + if (c > 0) + { + /* We want a spaceing of 1/2 line */ + LineSpacing = (LineSpacing / c) / 2; + } + + return TRUE; + } + } + + return FALSE; + } + + WORD GetMinimumSize(IN BOOL Horizontal, IN OUT PSIZE pSize) + { + WORD iLinesVisible = 0; + INT i; + SIZE szMax = { 0, 0 }; + + if (!LinesMeasured) + LinesMeasured = MeasureLines(); + + if (!LinesMeasured) + return 0; + + for (i = 0; + i != CLOCKWND_FORMAT_COUNT; + i++) + { + if (LineSizes[i].cx != 0) + { + if (iLinesVisible > 0) + { + if (Horizontal) + { + if (szMax.cy + LineSizes[i].cy + (LONG) LineSpacing > + pSize->cy - (2 * TRAY_CLOCK_WND_SPACING_Y)) + { + break; + } + } + else + { + if (LineSizes[i].cx > pSize->cx - (2 * TRAY_CLOCK_WND_SPACING_X)) + break; + } + + /* Add line spacing */ + szMax.cy += LineSpacing; + } + + iLinesVisible++; + + /* Increase maximum rectangle */ + szMax.cy += LineSizes[i].cy; + if (LineSizes[i].cx > szMax.cx - (2 * TRAY_CLOCK_WND_SPACING_X)) + szMax.cx = LineSizes[i].cx + (2 * TRAY_CLOCK_WND_SPACING_X); + } + } + + szMax.cx += 2 * TRAY_CLOCK_WND_SPACING_X; + szMax.cy += 2 * TRAY_CLOCK_WND_SPACING_Y; + + *pSize = szMax; + + return iLinesVisible; + } + + + VOID UpdateWnd() + { + SIZE szPrevCurrent; + INT BufSize, iRet, i; + RECT rcClient; + + ZeroMemory(LineSizes, + sizeof(LineSizes)); + + szPrevCurrent = CurrentSize; + + for (i = 0; + i != CLOCKWND_FORMAT_COUNT; + i++) + { + szLines[i][0] = TEXT('\0'); + BufSize = sizeof(szLines[0]) / sizeof(szLines[0][0]); + + if (ClockWndFormats[i].IsTime) + { + iRet = GetTimeFormat(LOCALE_USER_DEFAULT, + AdvancedSettings.bShowSeconds ? ClockWndFormats[i].dwFormatFlags : TIME_NOSECONDS, + &LocalTime, + ClockWndFormats[i].lpFormat, + szLines[i], + BufSize); + } + else + { + iRet = GetDateFormat(LOCALE_USER_DEFAULT, + ClockWndFormats[i].dwFormatFlags, + &LocalTime, + ClockWndFormats[i].lpFormat, + szLines[i], + BufSize); + } + + if (iRet != 0 && i == 0) + { + /* Set the window text to the time only */ + SetWindowText(szLines[i]); + } + } + + LinesMeasured = MeasureLines(); + + if (LinesMeasured && + GetClientRect(&rcClient)) + { + SIZE szWnd; + + szWnd.cx = rcClient.right; + szWnd.cy = rcClient.bottom; + + VisibleLines = GetMinimumSize(IsHorizontal, &szWnd); + CurrentSize = szWnd; + } + + if (IsWindowVisible(m_hWnd)) + { + InvalidateRect(NULL, TRUE); + + if (hWndNotify != NULL && + (szPrevCurrent.cx != CurrentSize.cx || + szPrevCurrent.cy != CurrentSize.cy)) + { + NMHDR nmh; + + nmh.hwndFrom = m_hWnd; + nmh.idFrom = GetWindowLongPtr(m_hWnd, GWLP_ID); + nmh.code = NTNWM_REALIGN; + + SendMessage(hWndNotify, + WM_NOTIFY, + (WPARAM) nmh.idFrom, + (LPARAM) &nmh); + } + } + } + + VOID Update() + { + GetLocalTime(&LocalTime); + UpdateWnd(); + } + + UINT CalculateDueTime() + { + UINT uiDueTime; + + /* Calculate the due time */ + GetLocalTime(&LocalTime); + uiDueTime = 1000 - (UINT) LocalTime.wMilliseconds; + if (AdvancedSettings.bShowSeconds) + uiDueTime += (UINT) LocalTime.wSecond * 100; + else + uiDueTime += (59 - (UINT) LocalTime.wSecond) * 1000; + + if (uiDueTime < USER_TIMER_MINIMUM || uiDueTime > USER_TIMER_MAXIMUM) + uiDueTime = 1000; + else + { + /* Add an artificial delay of 0.05 seconds to make sure the timer + doesn't fire too early*/ + uiDueTime += 50; + } + + return uiDueTime; + } + + BOOL ResetTime() + { + UINT uiDueTime; + BOOL Ret; + + /* Disable all timers */ + if (IsTimerEnabled) + { + KillTimer(ID_TRAYCLOCK_TIMER); + IsTimerEnabled = FALSE; + } + + if (IsInitTimerEnabled) + { + KillTimer(ID_TRAYCLOCK_TIMER_INIT); + } + + uiDueTime = CalculateDueTime(); + + /* Set the new timer */ + Ret = SetTimer(ID_TRAYCLOCK_TIMER_INIT, uiDueTime, NULL) != 0; + IsInitTimerEnabled = Ret; + + /* Update the time */ + Update(); + + return Ret; + } + + VOID CalibrateTimer() + { + UINT uiDueTime; + BOOL Ret; + UINT uiWait1, uiWait2; + + /* Kill the initialization timer */ + KillTimer(ID_TRAYCLOCK_TIMER_INIT); + IsInitTimerEnabled = FALSE; + + uiDueTime = CalculateDueTime(); + + if (AdvancedSettings.bShowSeconds) + { + uiWait1 = 1000 - 200; + uiWait2 = 1000; + } + else + { + uiWait1 = 60 * 1000 - 200; + uiWait2 = 60 * 1000; + } + + if (uiDueTime > uiWait1) + { + /* The update of the clock will be up to 200 ms late, but that's + acceptable. We're going to setup a timer that fires depending + uiWait2. */ + Ret = SetTimer(ID_TRAYCLOCK_TIMER, uiWait2, NULL) != 0; + IsTimerEnabled = Ret; + + /* Update the time */ + Update(); + } + else + { + /* Recalibrate the timer and recalculate again when the current + minute/second ends. */ + ResetTime(); + } + } + + LRESULT OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + /* Disable all timers */ + if (IsTimerEnabled) + { + KillTimer(ID_TRAYCLOCK_TIMER); + } + + if (IsInitTimerEnabled) + { + KillTimer(ID_TRAYCLOCK_TIMER_INIT); + } + + return TRUE; + } + + LRESULT OnPaint(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + RECT rcClient; + HFONT hPrevFont; + int iPrevBkMode, i, line; + + PAINTSTRUCT ps; + HDC hDC = (HDC) wParam; + + if (wParam == 0) + { + hDC = BeginPaint(&ps); + } + + if (hDC == NULL) + return FALSE; + + if (LinesMeasured && + GetClientRect(&rcClient)) + { + iPrevBkMode = SetBkMode(hDC, TRANSPARENT); + + SetTextColor(hDC, textColor); + + hPrevFont = (HFONT) SelectObject(hDC, hFont); + + rcClient.left = (rcClient.right / 2) - (CurrentSize.cx / 2); + rcClient.top = (rcClient.bottom / 2) - (CurrentSize.cy / 2); + rcClient.right = rcClient.left + CurrentSize.cx; + rcClient.bottom = rcClient.top + CurrentSize.cy; + + for (i = 0, line = 0; + i != CLOCKWND_FORMAT_COUNT && line < VisibleLines; + i++) + { + if (LineSizes[i].cx != 0) + { + TextOut(hDC, + rcClient.left + (CurrentSize.cx / 2) - (LineSizes[i].cx / 2) + + TRAY_CLOCK_WND_SPACING_X, + rcClient.top + TRAY_CLOCK_WND_SPACING_Y, + szLines[i], + _tcslen(szLines[i])); + + rcClient.top += LineSizes[i].cy + LineSpacing; + line++; + } + } + + SelectObject(hDC, hPrevFont); + + SetBkMode(hDC, iPrevBkMode); + } + + if (wParam == 0) + { + EndPaint(&ps); + } + + return TRUE; + } + + VOID SetFont(IN HFONT hNewFont, IN BOOL bRedraw) + { + hFont = hNewFont; + LinesMeasured = MeasureLines(); + if (bRedraw) + { + InvalidateRect(NULL, TRUE); + } + } + + LRESULT DrawBackground(HDC hdc) + { + RECT rect; + + GetClientRect(&rect); + DrawThemeParentBackground(m_hWnd, hdc, &rect); + + return TRUE; + } + + LRESULT OnEraseBackground(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + HDC hdc = (HDC) wParam; + + if (!IsAppThemed()) + { + bHandled = FALSE; + return 0; + } + + return DrawBackground(hdc); + } + + LRESULT OnTimer(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + switch (wParam) + { + case ID_TRAYCLOCK_TIMER: + Update(); + break; + + case ID_TRAYCLOCK_TIMER_INIT: + CalibrateTimer(); + break; + } + return TRUE; + } + + LRESULT OnGetMinimumSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + IsHorizontal = (BOOL) wParam; + + return (LRESULT) GetMinimumSize((BOOL) wParam, (PSIZE) lParam) != 0; + } + + LRESULT OnUpdateTime(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + return (LRESULT) ResetTime(); + } + + LRESULT OnNcHitTest(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + return HTTRANSPARENT; + } + + LRESULT OnSetFont(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + SetFont((HFONT) wParam, (BOOL) LOWORD(lParam)); + return TRUE; + } + + LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + ResetTime(); + return TRUE; + } + + LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + SIZE szClient; + + szClient.cx = LOWORD(lParam); + szClient.cy = HIWORD(lParam); + + VisibleLines = GetMinimumSize(IsHorizontal, &szClient); + CurrentSize = szClient; + + InvalidateRect(NULL, TRUE); + return TRUE; + } + + DECLARE_WND_CLASS_EX(szTrayClockWndClass, CS_DBLCLKS, COLOR_3DFACE) + + BEGIN_MSG_MAP(CTaskSwitchWnd) + MESSAGE_HANDLER(WM_CREATE, OnCreate) + MESSAGE_HANDLER(WM_DESTROY, OnDestroy) + MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground) + MESSAGE_HANDLER(WM_SIZE, OnSize) + MESSAGE_HANDLER(WM_PAINT, OnPaint) + MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint) + MESSAGE_HANDLER(WM_TIMER, OnTimer) + MESSAGE_HANDLER(WM_NCHITTEST, OnNcHitTest) + MESSAGE_HANDLER(TCWM_GETMINIMUMSIZE, OnGetMinimumSize) + MESSAGE_HANDLER(TCWM_UPDATETIME, OnUpdateTime) + + END_MSG_MAP() + + HWND _Init(IN HWND hWndParent, IN BOOL bVisible) + { + IsHorizontal = TRUE; + + hWndNotify = hWndParent; + + /* Create the window. The tray window is going to move it to the correct + position and resize it as needed. */ + DWORD dwStyle = WS_CHILD | WS_CLIPSIBLINGS; + if (bVisible) + dwStyle |= WS_VISIBLE; + + Create(hWndParent, 0, NULL, dwStyle); + + if (m_hWnd != NULL) + { + SetWindowTheme(m_hWnd, L"TrayNotify", NULL); + OnThemeChanged(); + } + + return m_hWnd; + + } +}; + +/* + * TrayNotifyWnd + */ + +static const WCHAR szTrayNotifyWndClass [] = TEXT("TrayNotifyWnd"); + +#define TRAY_NOTIFY_WND_SPACING_X 2 +#define TRAY_NOTIFY_WND_SPACING_Y 2 + +class CTrayNotifyWnd : + public CComObjectRootEx, + public CWindowImpl < CTrayNotifyWnd, CWindow, CControlWinTraits > +{ + HWND hWndNotify; + + CSysPagerWnd * m_pager; + CTrayClockWnd * m_clock; + + CComPtr TrayWindow; + + HTHEME TrayTheme; + SIZE szTrayClockMin; + SIZE szTrayNotify; + MARGINS ContentMargin; + HFONT hFontClock; + union + { + DWORD dwFlags; + struct + { + DWORD HideClock : 1; + DWORD IsHorizontal : 1; + }; + }; + +public: + CTrayNotifyWnd() : + hWndNotify(NULL), + m_pager(NULL), + m_clock(NULL), + TrayTheme(NULL), + hFontClock(NULL), + dwFlags(0) + { + ZeroMemory(&szTrayClockMin, sizeof(szTrayClockMin)); + ZeroMemory(&szTrayNotify, sizeof(szTrayNotify)); + ZeroMemory(&ContentMargin, sizeof(ContentMargin)); + } + virtual ~CTrayNotifyWnd() { } + + LRESULT OnThemeChanged() + { + if (TrayTheme) + CloseThemeData(TrayTheme); + + if (IsThemeActive()) + TrayTheme = OpenThemeData(m_hWnd, L"TrayNotify"); + else + TrayTheme = NULL; + + if (TrayTheme) + { + SetWindowExStyle(m_hWnd, WS_EX_STATICEDGE, 0); + + GetThemeMargins(TrayTheme, + NULL, + TNP_BACKGROUND, + 0, + TMT_CONTENTMARGINS, + NULL, + &ContentMargin); + } + else + { + SetWindowExStyle(m_hWnd, WS_EX_STATICEDGE, WS_EX_STATICEDGE); + + ContentMargin.cxLeftWidth = 0; + ContentMargin.cxRightWidth = 0; + ContentMargin.cyTopHeight = 0; + ContentMargin.cyBottomHeight = 0; + } + + return TRUE; + } + + LRESULT OnThemeChanged(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + return OnThemeChanged(); + } + + LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + m_clock = new CTrayClockWnd(); + m_clock->_Init(m_hWnd, !HideClock); + + m_pager = new CSysPagerWnd(); + m_pager->_Init(m_hWnd, !HideClock); + + OnThemeChanged(); + + return TRUE; + } + + BOOL GetMinimumSize(IN BOOL Horizontal, IN OUT PSIZE pSize) + { + SIZE szClock = { 0, 0 }; + SIZE szTray = { 0, 0 }; + + IsHorizontal = Horizontal; + if (IsHorizontal) + SetWindowTheme(m_hWnd, L"TrayNotifyHoriz", NULL); + else + SetWindowTheme(m_hWnd, L"TrayNotifyVert", NULL); + + if (!HideClock) + { + if (Horizontal) + { + szClock.cy = pSize->cy - 2 * TRAY_NOTIFY_WND_SPACING_Y; + if (szClock.cy <= 0) + goto NoClock; + } + else + { + szClock.cx = pSize->cx - 2 * TRAY_NOTIFY_WND_SPACING_X; + if (szClock.cx <= 0) + goto NoClock; + } + + m_clock->SendMessage(TCWM_GETMINIMUMSIZE, (WPARAM) Horizontal, (LPARAM) &szClock); + + szTrayClockMin = szClock; + } + else + NoClock: + szTrayClockMin = szClock; + + if (Horizontal) + { + szTray.cy = pSize->cy - 2 * TRAY_NOTIFY_WND_SPACING_Y; + } + else + { + szTray.cx = pSize->cx - 2 * TRAY_NOTIFY_WND_SPACING_X; + } + + m_pager->GetSize(Horizontal, &szTray); + + szTrayNotify = szTray; + + if (Horizontal) + { + pSize->cx = 2 * TRAY_NOTIFY_WND_SPACING_X; + + if (!HideClock) + pSize->cx += TRAY_NOTIFY_WND_SPACING_X + szTrayClockMin.cx; + + pSize->cx += szTray.cx; + } + else + { + pSize->cy = 2 * TRAY_NOTIFY_WND_SPACING_Y; + + if (!HideClock) + pSize->cy += TRAY_NOTIFY_WND_SPACING_Y + szTrayClockMin.cy; + + pSize->cy += szTray.cy; + } + + pSize->cy += ContentMargin.cyTopHeight + ContentMargin.cyBottomHeight; + pSize->cx += ContentMargin.cxLeftWidth + ContentMargin.cxRightWidth; + + return TRUE; + } + + VOID Size(IN const SIZE *pszClient) + { + if (!HideClock) + { + POINT ptClock; + SIZE szClock; + + if (IsHorizontal) + { + ptClock.x = pszClient->cx - TRAY_NOTIFY_WND_SPACING_X - szTrayClockMin.cx; + ptClock.y = TRAY_NOTIFY_WND_SPACING_Y; + szClock.cx = szTrayClockMin.cx; + szClock.cy = pszClient->cy - (2 * TRAY_NOTIFY_WND_SPACING_Y); + } + else + { + ptClock.x = TRAY_NOTIFY_WND_SPACING_X; + ptClock.y = pszClient->cy - TRAY_NOTIFY_WND_SPACING_Y - szTrayClockMin.cy; + szClock.cx = pszClient->cx - (2 * TRAY_NOTIFY_WND_SPACING_X); + szClock.cy = szTrayClockMin.cy; + } + + m_clock->SetWindowPos( + NULL, + ptClock.x, + ptClock.y, + szClock.cx, + szClock.cy, + SWP_NOZORDER); + + if (IsHorizontal) + { + ptClock.x -= szTrayNotify.cx; + } + else + { + ptClock.y -= szTrayNotify.cy; + } + + m_pager->SetWindowPos( + NULL, + ptClock.x, + ptClock.y, + szTrayNotify.cx, + szTrayNotify.cy, + SWP_NOZORDER); + } + } + + LRESULT DrawBackground(HDC hdc) + { + RECT rect; + + GetClientRect(&rect); + + if (TrayTheme) + { + if (IsThemeBackgroundPartiallyTransparent(TrayTheme, TNP_BACKGROUND, 0)) + { + DrawThemeParentBackground(m_hWnd, hdc, &rect); + } + + DrawThemeBackground(TrayTheme, hdc, TNP_BACKGROUND, 0, &rect, 0); + } + + return TRUE; + } + + LRESULT OnEraseBackground(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + HDC hdc = (HDC) wParam; + + if (!TrayTheme) + { + bHandled = FALSE; + return 0; + } + + return DrawBackground(hdc); + } + + LRESULT NotifyMsg(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + if (m_pager) + { + m_pager->NotifyMsg(uMsg, wParam, lParam, bHandled); + } + + return TRUE; + } + + BOOL GetClockRect(OUT PRECT rcClock) + { + if (!IsWindowVisible(m_clock->m_hWnd)) + return FALSE; + + return GetWindowRect(m_clock->m_hWnd, rcClock); + } + + LRESULT OnGetMinimumSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + return (LRESULT) GetMinimumSize((BOOL) wParam, (PSIZE) lParam); + } + + LRESULT OnUpdateTime(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + if (m_clock != NULL) + { + /* Forward the message to the tray clock window procedure */ + return m_clock->OnUpdateTime(uMsg, wParam, lParam, bHandled); + } + return FALSE; + } + + LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + SIZE szClient; + + szClient.cx = LOWORD(lParam); + szClient.cy = HIWORD(lParam); + + Size(&szClient); + + return TRUE; + } + + LRESULT OnNcHitTest(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + return HTTRANSPARENT; + } + + LRESULT OnShowClock(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + BOOL PrevHidden = HideClock; + HideClock = (wParam == 0); + + if (m_clock != NULL && PrevHidden != HideClock) + { + m_clock->ShowWindow(HideClock ? SW_HIDE : SW_SHOW); + } + + return (LRESULT) (!PrevHidden); + } + + LRESULT OnNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + const NMHDR *nmh = (const NMHDR *) lParam; + + if (nmh->hwndFrom == m_clock->m_hWnd) + { + /* Pass down notifications */ + return m_clock->SendMessage(WM_NOTIFY, wParam, lParam); + } + + return FALSE; + } + + LRESULT OnSetFont(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + if (m_clock != NULL) + { + m_clock->SendMessageW(WM_SETFONT, wParam, lParam); + } + + bHandled = FALSE; + return FALSE; + } + + DECLARE_WND_CLASS_EX(szTrayNotifyWndClass, CS_DBLCLKS, COLOR_3DFACE) + + BEGIN_MSG_MAP(CTaskSwitchWnd) + MESSAGE_HANDLER(WM_CREATE, OnCreate) + MESSAGE_HANDLER(WM_THEMECHANGED, OnThemeChanged) + MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground) + MESSAGE_HANDLER(WM_SIZE, OnSize) + MESSAGE_HANDLER(WM_NCHITTEST, OnNcHitTest) + MESSAGE_HANDLER(WM_NOTIFY, OnNotify) + MESSAGE_HANDLER(WM_SETFONT, OnSetFont) + MESSAGE_HANDLER(TNWM_GETMINIMUMSIZE, OnGetMinimumSize) + MESSAGE_HANDLER(TNWM_UPDATETIME, OnUpdateTime) + MESSAGE_HANDLER(TNWM_SHOWCLOCK, OnShowClock) + END_MSG_MAP() + + HWND _Init(IN OUT ITrayWindow *TrayWindow, IN BOOL bHideClock) + { + HWND hWndTrayWindow; + + hWndTrayWindow = TrayWindow->GetHWND(); + if (hWndTrayWindow == NULL) + return NULL; + + this->TrayWindow = TrayWindow; + this->HideClock = bHideClock; + this->hWndNotify = hWndTrayWindow; + + DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN; + return Create(hWndTrayWindow, 0, NULL, dwStyle, WS_EX_STATICEDGE); + } +}; + +static CTrayNotifyWnd * g_Instance; + +HWND CreateTrayNotifyWnd(IN OUT ITrayWindow *Tray, BOOL bHideClock) +{ + // TODO: Destroy after the window is destroyed + g_Instance = new CTrayNotifyWnd(); + + return g_Instance->_Init(Tray, bHideClock); +} + +VOID +TrayNotify_NotifyMsg(WPARAM wParam, LPARAM lParam) +{ + BOOL bDummy; + g_Instance->NotifyMsg(0, wParam, lParam, bDummy); +} + +BOOL +TrayNotify_GetClockRect(OUT PRECT rcClock) +{ + return g_Instance->GetClockRect(rcClock); +} diff --git a/base/shell/explorer-new/trayprop.c b/base/shell/explorer-new/trayprop.cpp similarity index 99% rename from base/shell/explorer-new/trayprop.c rename to base/shell/explorer-new/trayprop.cpp index 36de295c48a..b813263558f 100644 --- a/base/shell/explorer-new/trayprop.c +++ b/base/shell/explorer-new/trayprop.cpp @@ -78,7 +78,7 @@ UpdateTaskbarBitmap(PPROPSHEET_INFO pPropInfo) DeleteObject(pPropInfo->hTaskbarBitmap); } - pPropInfo->hTaskbarBitmap = LoadImage(hExplorerInstance, + pPropInfo->hTaskbarBitmap = (HBITMAP)LoadImage(hExplorerInstance, lpImageName, IMAGE_BITMAP, 0, @@ -367,7 +367,7 @@ DisplayTrayProperties(IN HWND hwndOwner) PROPSHEET_INFO propInfo; PROPSHEETHEADER psh; PROPSHEETPAGE psp[5]; - TCHAR szCaption[256]; + WCHAR szCaption[256]; if (!LoadString(hExplorerInstance, IDS_TASKBAR_STARTMENU_PROP_CAPTION, diff --git a/base/shell/explorer-new/traywnd.c b/base/shell/explorer-new/traywnd.c deleted file mode 100644 index 3cd2f77d829..00000000000 --- a/base/shell/explorer-new/traywnd.c +++ /dev/null @@ -1,3346 +0,0 @@ -/* - * ReactOS Explorer - * - * Copyright 2006 - 2007 Thomas Weidenmueller - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "precomp.h" - -extern HRESULT InitShellServices(HDPA * phdpa); -extern HRESULT ShutdownShellServices(HDPA hdpa); - -static const TRAYWINDOW_CTXMENU TrayWindowCtxMenu; - -#define WM_APP_TRAYDESTROY (WM_APP + 0x100) - -#define TIMER_ID_AUTOHIDE 1 -#define TIMER_ID_MOUSETRACK 2 -#define MOUSETRACK_INTERVAL 100 -#define AUTOHIDE_DELAY_HIDE 2000 -#define AUTOHIDE_DELAY_SHOW 50 -#define AUTOHIDE_INTERVAL_ANIMATING 10 - -#define AUTOHIDE_SPEED_SHOW 10 -#define AUTOHIDE_SPEED_HIDE 1 - -#define AUTOHIDE_HIDDEN 0 -#define AUTOHIDE_SHOWING 1 -#define AUTOHIDE_SHOWN 2 -#define AUTOHIDE_HIDING 3 - -static LONG TrayWndCount = 0; - -static const TCHAR szTrayWndClass[] = TEXT("Shell_TrayWnd"); - -static const ITrayWindowVtbl ITrayWindowImpl_Vtbl; -static const IShellDesktopTrayVtbl IShellDesktopTrayImpl_Vtbl; - -/* - * ITrayWindow - */ - -const GUID IID_IShellDesktopTray = {0x213e2df9, 0x9a14, 0x4328, {0x99, 0xb1, 0x69, 0x61, 0xf9, 0x14, 0x3c, 0xe9}}; - -typedef struct -{ - const ITrayWindowVtbl *lpVtbl; - const IShellDesktopTrayVtbl *lpVtblShellDesktopTray; - LONG Ref; - - HTHEME TaskbarTheme; - HWND hWnd; - HWND hWndDesktop; - - HWND hwndStart; - HIMAGELIST himlStartBtn; - SIZE StartBtnSize; - HFONT hStartBtnFont; - HFONT hCaptionFont; - - ITrayBandSite *TrayBandSite; - HWND hwndRebar; - HWND hwndTaskSwitch; - HWND hwndTrayNotify; - - DWORD Position; - HMONITOR Monitor; - HMONITOR PreviousMonitor; - DWORD DraggingPosition; - HMONITOR DraggingMonitor; - - RECT rcTrayWnd[4]; - RECT rcNewPosSize; - SIZE TraySize; - union - { - DWORD Flags; - struct - { - DWORD AutoHide : 1; - DWORD AlwaysOnTop : 1; - DWORD SmSmallIcons : 1; - DWORD HideClock : 1; - DWORD Locked : 1; - - /* UI Status */ - DWORD InSizeMove : 1; - DWORD IsDragging : 1; - DWORD NewPosSize : 1; - }; - }; - - NONCLIENTMETRICS ncm; - HFONT hFont; - - IMenuBand *StartMenuBand; - IMenuPopup *StartMenuPopup; - HBITMAP hbmStartMenu; - - HWND hwndTrayPropertiesOwner; - HWND hwndRunFileDlgOwner; - - UINT AutoHideState; - SIZE AutoHideOffset; - TRACKMOUSEEVENT MouseTrackingInfo; - - HDPA hdpaShellServices; -} ITrayWindowImpl; - -static ITrayWindowImpl * g_TrayWindow; - -BOOL LaunchCPanel(HWND hwnd, LPCTSTR applet) -{ - TCHAR szParams[MAX_PATH]; - - StringCbCopy(szParams, sizeof(szParams), - TEXT("shell32.dll,Control_RunDLL ")); - if (FAILED(StringCbCat(szParams, sizeof(szParams), - applet))) - return FALSE; - - return (ShellExecute(hwnd, TEXT("open"), TEXT("rundll32.exe"), szParams, NULL, SW_SHOWDEFAULT) > (HINSTANCE)32); -} - -static IUnknown * -IUnknown_from_impl(ITrayWindowImpl *This) -{ - return (IUnknown *)&This->lpVtbl; -} - -static ITrayWindow * -ITrayWindow_from_impl(ITrayWindowImpl *This) -{ - return (ITrayWindow *)&This->lpVtbl; -} - -static IShellDesktopTray * -IShellDesktopTray_from_impl(ITrayWindowImpl *This) -{ - return (IShellDesktopTray *)&This->lpVtblShellDesktopTray; -} - -static ITrayWindowImpl * -impl_from_ITrayWindow(ITrayWindow *iface) -{ - return (ITrayWindowImpl *)((ULONG_PTR)iface - FIELD_OFFSET(ITrayWindowImpl, - lpVtbl)); -} - -static ITrayWindowImpl * -impl_from_IShellDesktopTray(IShellDesktopTray *iface) -{ - return (ITrayWindowImpl *)((ULONG_PTR)iface - FIELD_OFFSET(ITrayWindowImpl, - lpVtblShellDesktopTray)); -} - -/* - * ITrayWindow - */ - -static BOOL -ITrayWindowImpl_UpdateNonClientMetrics(IN OUT ITrayWindowImpl *This) -{ - This->ncm.cbSize = sizeof(This->ncm); - if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS, - sizeof(This->ncm), - &This->ncm, - 0)) - { - if (This->hFont != NULL) - DeleteObject(This->hFont); - - This->hFont = CreateFontIndirect(&This->ncm.lfMessageFont); - return TRUE; - } - - return FALSE; -} - -static VOID -ITrayWindowImpl_SetWindowsFont(IN OUT ITrayWindowImpl *This) -{ - if (This->hwndTrayNotify != NULL) - { - SendMessage(This->hwndTrayNotify, - WM_SETFONT, - (WPARAM)This->hFont, - TRUE); - } -} - -static HMONITOR -ITrayWindowImpl_GetScreenRectFromRect(IN OUT ITrayWindowImpl *This, - IN OUT RECT *pRect, - IN DWORD dwFlags) -{ - MONITORINFO mi; - HMONITOR hMon; - - mi.cbSize = sizeof(mi); - hMon = MonitorFromRect(pRect, - dwFlags); - if (hMon != NULL && - GetMonitorInfo(hMon, - &mi)) - { - *pRect = mi.rcMonitor; - } - else - { - pRect->left = 0; - pRect->top = 0; - pRect->right = GetSystemMetrics(SM_CXSCREEN); - pRect->bottom = GetSystemMetrics(SM_CYSCREEN); - - hMon = NULL; - } - - return hMon; -} - -static HMONITOR -ITrayWindowImpl_GetMonitorFromRect(IN OUT ITrayWindowImpl *This, - IN const RECT *pRect) -{ - HMONITOR hMon; - - /* In case the monitor sizes or saved sizes differ a bit (probably - not a lot, only so the tray window overlaps into another monitor - now), minimize the risk that we determine a wrong monitor by - using the center point of the tray window if we can't determine - it using the rectangle. */ - hMon = MonitorFromRect(pRect, - MONITOR_DEFAULTTONULL); - if (hMon == NULL) - { - POINT pt; - - pt.x = pRect->left + ((pRect->right - pRect->left) / 2); - pt.y = pRect->top + ((pRect->bottom - pRect->top) / 2); - - /* be less error-prone, find the nearest monitor */ - hMon = MonitorFromPoint(pt, - MONITOR_DEFAULTTONEAREST); - } - - return hMon; -} - -static HMONITOR -ITrayWindowImpl_GetScreenRect(IN OUT ITrayWindowImpl *This, - IN HMONITOR hMonitor, - IN OUT RECT *pRect) -{ - HMONITOR hMon = NULL; - - if (hMonitor != NULL) - { - MONITORINFO mi; - - mi.cbSize = sizeof(mi); - if (!GetMonitorInfo(hMonitor, - &mi)) - { - /* Hm, the monitor is gone? Try to find a monitor where it - could be located now */ - hMon = ITrayWindowImpl_GetMonitorFromRect(This, - pRect); - if (hMon == NULL || - !GetMonitorInfo(hMon, - &mi)) - { - hMon = NULL; - goto GetPrimaryRect; - } - } - - *pRect = mi.rcMonitor; - } - else - { -GetPrimaryRect: - pRect->left = 0; - pRect->top = 0; - pRect->right = GetSystemMetrics(SM_CXSCREEN); - pRect->bottom = GetSystemMetrics(SM_CYSCREEN); - } - - return hMon; -} - -static VOID -ITrayWindowImpl_MakeTrayRectWithSize(IN DWORD Position, - IN const SIZE *pTraySize, - IN OUT RECT *pRect) -{ - switch (Position) - { - case ABE_LEFT: - pRect->right = pRect->left + pTraySize->cx; - break; - - case ABE_TOP: - pRect->bottom = pRect->top + pTraySize->cy; - break; - - case ABE_RIGHT: - pRect->left = pRect->right - pTraySize->cx; - break; - - case ABE_BOTTOM: - default: - pRect->top = pRect->bottom - pTraySize->cy; - break; - } -} - -static VOID -ITrayWindowImpl_GetTrayRectFromScreenRect(IN OUT ITrayWindowImpl *This, - IN DWORD Position, - IN const RECT *pScreen, - IN const SIZE *pTraySize OPTIONAL, - OUT RECT *pRect) -{ - if (pTraySize == NULL) - pTraySize = &This->TraySize; - - *pRect = *pScreen; - - /* Move the border outside of the screen */ - InflateRect(pRect, - GetSystemMetrics(SM_CXEDGE), - GetSystemMetrics(SM_CYEDGE)); - - ITrayWindowImpl_MakeTrayRectWithSize(Position, - pTraySize, - pRect); -} - -BOOL -ITrayWindowImpl_IsPosHorizontal(IN OUT ITrayWindowImpl *This) -{ - return This->Position == ABE_TOP || This->Position == ABE_BOTTOM; -} - -static HMONITOR -ITrayWindowImpl_CalculateValidSize(IN OUT ITrayWindowImpl *This, - IN DWORD Position, - IN OUT RECT *pRect) -{ - RECT rcScreen; - //BOOL Horizontal; - HMONITOR hMon; - SIZE szMax, szWnd; - - //Horizontal = ITrayWindowImpl_IsPosHorizontal(This); - - szWnd.cx = pRect->right - pRect->left; - szWnd.cy = pRect->bottom - pRect->top; - - rcScreen = *pRect; - hMon = ITrayWindowImpl_GetScreenRectFromRect(This, - &rcScreen, - MONITOR_DEFAULTTONEAREST); - - /* Calculate the maximum size of the tray window and limit the window - size to half of the screen's size. */ - szMax.cx = (rcScreen.right - rcScreen.left) / 2; - szMax.cy = (rcScreen.bottom - rcScreen.top) / 2; - if (szWnd.cx > szMax.cx) - szWnd.cx = szMax.cx; - if (szWnd.cy > szMax.cy) - szWnd.cy = szMax.cy; - - /* FIXME - calculate */ - - ITrayWindowImpl_GetTrayRectFromScreenRect(This, - Position, - &rcScreen, - &szWnd, - pRect); - - return hMon; -} - -#if 0 -static VOID -ITrayWindowImpl_GetMinimumWindowSize(IN OUT ITrayWindowImpl *This, - OUT RECT *pRect) -{ - RECT rcMin = {0}; - - AdjustWindowRectEx(&rcMin, - GetWindowLong(This->hWnd, - GWL_STYLE), - FALSE, - GetWindowLong(This->hWnd, - GWL_EXSTYLE)); - - *pRect = rcMin; -} -#endif - - -static DWORD -ITrayWindowImpl_GetDraggingRectFromPt(IN OUT ITrayWindowImpl *This, - IN POINT pt, - OUT RECT *pRect, - OUT HMONITOR *phMonitor) -{ - HMONITOR hMon, hMonNew; - DWORD PosH, PosV, Pos; - SIZE DeltaPt, ScreenOffset; - RECT rcScreen; - - rcScreen.left = 0; - rcScreen.top = 0; - - /* Determine the screen rectangle */ - hMon = MonitorFromPoint(pt, - MONITOR_DEFAULTTONULL); - - if (hMon != NULL) - { - MONITORINFO mi; - - mi.cbSize = sizeof(mi); - if (!GetMonitorInfo(hMon, - &mi)) - { - hMon = NULL; - goto GetPrimaryScreenRect; - } - - /* make left top corner of the screen zero based to - make calculations easier */ - pt.x -= mi.rcMonitor.left; - pt.y -= mi.rcMonitor.top; - - ScreenOffset.cx = mi.rcMonitor.left; - ScreenOffset.cy = mi.rcMonitor.top; - rcScreen.right = mi.rcMonitor.right - mi.rcMonitor.left; - rcScreen.bottom = mi.rcMonitor.bottom - mi.rcMonitor.top; - } - else - { -GetPrimaryScreenRect: - ScreenOffset.cx = 0; - ScreenOffset.cy = 0; - rcScreen.right = GetSystemMetrics(SM_CXSCREEN); - rcScreen.bottom = GetSystemMetrics(SM_CYSCREEN); - } - - /* Calculate the nearest screen border */ - if (pt.x < rcScreen.right / 2) - { - DeltaPt.cx = pt.x; - PosH = ABE_LEFT; - } - else - { - DeltaPt.cx = rcScreen.right - pt.x; - PosH = ABE_RIGHT; - } - - if (pt.y < rcScreen.bottom / 2) - { - DeltaPt.cy = pt.y; - PosV = ABE_TOP; - } - else - { - DeltaPt.cy = rcScreen.bottom - pt.y; - PosV = ABE_BOTTOM; - } - - Pos = (DeltaPt.cx * rcScreen.bottom < DeltaPt.cy * rcScreen.right) ? PosH : PosV; - - /* Fix the screen origin to be relative to the primary monitor again */ - OffsetRect(&rcScreen, - ScreenOffset.cx, - ScreenOffset.cy); - - hMonNew = ITrayWindowImpl_GetMonitorFromRect(This, - &This->rcTrayWnd[Pos]); - if (hMon != hMonNew) - { - SIZE szTray; - - /* Recalculate the rectangle, we're dragging to another monitor. - We don't need to recalculate the rect on single monitor systems. */ - szTray.cx = This->rcTrayWnd[Pos].right - This->rcTrayWnd[Pos].left; - szTray.cy = This->rcTrayWnd[Pos].bottom - This->rcTrayWnd[Pos].top; - - ITrayWindowImpl_GetTrayRectFromScreenRect(This, - Pos, - &rcScreen, - &szTray, - pRect); - if (This->AutoHide) - { - pRect->left += This->AutoHideOffset.cx; - pRect->right += This->AutoHideOffset.cx; - pRect->top += This->AutoHideOffset.cy; - pRect->bottom += This->AutoHideOffset.cy; - } - hMon = hMonNew; - } - else - { - /* The user is dragging the tray window on the same monitor. We don't need - to recalculate the rectangle */ - *pRect = This->rcTrayWnd[Pos]; - if (This->AutoHide) - { - pRect->left += This->AutoHideOffset.cx; - pRect->right += This->AutoHideOffset.cx; - pRect->top += This->AutoHideOffset.cy; - pRect->bottom += This->AutoHideOffset.cy; - } - } - - *phMonitor = hMon; - - return Pos; -} - -static DWORD -ITrayWindowImpl_GetDraggingRectFromRect(IN OUT ITrayWindowImpl *This, - IN OUT RECT *pRect, - OUT HMONITOR *phMonitor) -{ - POINT pt; - - /* Calculate the center of the rectangle. We call - ITrayWindowImpl_GetDraggingRectFromPt to calculate a valid - dragging rectangle */ - pt.x = pRect->left + ((pRect->right - pRect->left) / 2); - pt.y = pRect->top + ((pRect->bottom - pRect->top) / 2); - - return ITrayWindowImpl_GetDraggingRectFromPt(This, - pt, - pRect, - phMonitor); -} - -static VOID -ITrayWindowImpl_ChangingWinPos(IN OUT ITrayWindowImpl *This, - IN OUT LPWINDOWPOS pwp) -{ - RECT rcTray; - - if (This->IsDragging) - { - rcTray.left = pwp->x; - rcTray.top = pwp->y; - rcTray.right = rcTray.left + pwp->cx; - rcTray.bottom = rcTray.top + pwp->cy; - if (This->AutoHide) - { - rcTray.left -= This->AutoHideOffset.cx; - rcTray.right -= This->AutoHideOffset.cx; - rcTray.top -= This->AutoHideOffset.cy; - rcTray.bottom -= This->AutoHideOffset.cy; - } - - if (!EqualRect(&rcTray, - &This->rcTrayWnd[This->DraggingPosition])) - { - /* Recalculate the rectangle, the user dragged the tray - window to another monitor or the window was somehow else - moved or resized */ - This->DraggingPosition = ITrayWindowImpl_GetDraggingRectFromRect(This, - &rcTray, - &This->DraggingMonitor); - //This->rcTrayWnd[This->DraggingPosition] = rcTray; - } - - //This->Monitor = ITrayWindowImpl_CalculateValidSize(This, - // This->DraggingPosition, - // &rcTray); - - This->Monitor = This->DraggingMonitor; - This->Position = This->DraggingPosition; - This->IsDragging = FALSE; - - This->rcTrayWnd[This->Position] = rcTray; - goto ChangePos; - } - else if (GetWindowRect(This->hWnd, - &rcTray)) - { - if (This->InSizeMove) - { - if (!(pwp->flags & SWP_NOMOVE)) - { - rcTray.left = pwp->x; - rcTray.top = pwp->y; - } - - if (!(pwp->flags & SWP_NOSIZE)) - { - rcTray.right = rcTray.left + pwp->cx; - rcTray.bottom = rcTray.top + pwp->cy; - } - - This->Position = ITrayWindowImpl_GetDraggingRectFromRect(This, - &rcTray, - &This->Monitor); - - if (!(pwp->flags & (SWP_NOMOVE | SWP_NOSIZE))) - { - SIZE szWnd; - - szWnd.cx = pwp->cx; - szWnd.cy = pwp->cy; - - ITrayWindowImpl_MakeTrayRectWithSize(This->Position, - &szWnd, - &rcTray); - } - - if (This->AutoHide) - { - rcTray.left -= This->AutoHideOffset.cx; - rcTray.right -= This->AutoHideOffset.cx; - rcTray.top -= This->AutoHideOffset.cy; - rcTray.bottom -= This->AutoHideOffset.cy; - } - This->rcTrayWnd[This->Position] = rcTray; - } - else - { - /* If the user isn't resizing the tray window we need to make sure the - new size or position is valid. This is to prevent changes to the window - without user interaction. */ - rcTray = This->rcTrayWnd[This->Position]; - } - -ChangePos: - This->TraySize.cx = rcTray.right - rcTray.left; - This->TraySize.cy = rcTray.bottom - rcTray.top; - - if (This->AutoHide) - { - rcTray.left += This->AutoHideOffset.cx; - rcTray.right += This->AutoHideOffset.cx; - rcTray.top += This->AutoHideOffset.cy; - rcTray.bottom += This->AutoHideOffset.cy; - } - - pwp->flags &= ~(SWP_NOMOVE | SWP_NOSIZE); - pwp->x = rcTray.left; - pwp->y = rcTray.top; - pwp->cx = This->TraySize.cx; - pwp->cy = This->TraySize.cy; - } -} - -static VOID -ITrayWindowImpl_ApplyClipping(IN OUT ITrayWindowImpl *This, - IN BOOL Clip) -{ - RECT rcClip, rcWindow; - HRGN hClipRgn; - - if (GetWindowRect(This->hWnd, - &rcWindow)) - { - /* Disable clipping on systems with only one monitor */ - if (GetSystemMetrics(SM_CMONITORS) <= 1) - Clip = FALSE; - - if (Clip) - { - rcClip = rcWindow; - - ITrayWindowImpl_GetScreenRect(This, - This->Monitor, - &rcClip); - - if (!IntersectRect(&rcClip, - &rcClip, - &rcWindow)) - { - rcClip = rcWindow; - } - - OffsetRect(&rcClip, - -rcWindow.left, - -rcWindow.top); - - hClipRgn = CreateRectRgnIndirect(&rcClip); - } - else - hClipRgn = NULL; - - /* Set the clipping region or make sure the window isn't clipped - by disabling it explicitly. */ - SetWindowRgn(This->hWnd, - hClipRgn, - TRUE); - } -} - -static VOID -ITrayWindowImpl_ResizeWorkArea(IN OUT ITrayWindowImpl *This) -{ - RECT rcTray,rcWorkArea; - - /* If monitor has changed then fix the previous monitors work area */ - if (This->PreviousMonitor != This->Monitor) - { - ITrayWindowImpl_GetScreenRect(This, - This->PreviousMonitor, - &rcWorkArea); - SystemParametersInfo(SPI_SETWORKAREA, - 1, - &rcWorkArea, - SPIF_SENDCHANGE); - } - - rcTray = This->rcTrayWnd[This->Position]; - - ITrayWindowImpl_GetScreenRect(This, - This->Monitor, - &rcWorkArea); - This->PreviousMonitor = This->Monitor; - - /* If AutoHide is false then change the workarea to exclude the area that - the taskbar covers. */ - if (!This->AutoHide) - { - switch (This->Position) - { - case ABE_TOP: - rcWorkArea.top = rcTray.bottom; - break; - case ABE_LEFT: - rcWorkArea.left = rcTray.right; - break; - case ABE_RIGHT: - rcWorkArea.right = rcTray.left; - break; - case ABE_BOTTOM: - rcWorkArea.bottom = rcTray.top; - break; - } - } - - SystemParametersInfo(SPI_SETWORKAREA, - 1, - &rcWorkArea, - SPIF_SENDCHANGE); -} - -static VOID -ITrayWindowImpl_CheckTrayWndPosition(IN OUT ITrayWindowImpl *This) -{ - RECT rcTray; - - rcTray = This->rcTrayWnd[This->Position]; - - if (This->AutoHide) - { - rcTray.left += This->AutoHideOffset.cx; - rcTray.right += This->AutoHideOffset.cx; - rcTray.top += This->AutoHideOffset.cy; - rcTray.bottom += This->AutoHideOffset.cy; - } - -// TRACE("CheckTray: %d: %d,%d,%d,%d\n", This->Position, rcTray.left, rcTray.top, rcTray.right, rcTray.bottom); - - /* Move the tray window */ - SetWindowPos(This->hWnd, - NULL, - rcTray.left, - rcTray.top, - rcTray.right - rcTray.left, - rcTray.bottom - rcTray.top, - SWP_NOZORDER); - - ITrayWindowImpl_ResizeWorkArea(This); - - ITrayWindowImpl_ApplyClipping(This, - TRUE); -} - -typedef struct _TW_STUCKRECTS2 -{ - DWORD cbSize; - LONG Unknown; - DWORD dwFlags; - DWORD Position; - SIZE Size; - RECT Rect; -} TW_STRUCKRECTS2, *PTW_STUCKRECTS2; - -static VOID -ITrayWindowImpl_RegLoadSettings(IN OUT ITrayWindowImpl *This) -{ - DWORD Pos; - TW_STRUCKRECTS2 sr; - RECT rcScreen; - SIZE WndSize, EdgeSize, DlgFrameSize; - DWORD cbSize = sizeof(sr); - - EdgeSize.cx = GetSystemMetrics(SM_CXEDGE); - EdgeSize.cy = GetSystemMetrics(SM_CYEDGE); - DlgFrameSize.cx = GetSystemMetrics(SM_CXDLGFRAME); - DlgFrameSize.cy = GetSystemMetrics(SM_CYDLGFRAME); - - if (SHGetValue(hkExplorer, - TEXT("StuckRects2"), - TEXT("Settings"), - NULL, - &sr, - &cbSize) == ERROR_SUCCESS && - sr.cbSize == sizeof(sr)) - { - This->AutoHide = (sr.dwFlags & ABS_AUTOHIDE) != 0; - This->AlwaysOnTop = (sr.dwFlags & ABS_ALWAYSONTOP) != 0; - This->SmSmallIcons = (sr.dwFlags & 0x4) != 0; - This->HideClock = (sr.dwFlags & 0x8) != 0; - - /* FIXME: Are there more flags? */ - - if (sr.Position > ABE_BOTTOM) - This->Position = ABE_BOTTOM; - else - This->Position = sr.Position; - - /* Try to find out which monitor the tray window was located on last. - Here we're only interested in the monitor screen that we think - is the last one used. We're going to determine on which monitor - we really are after calculating the docked position. */ - rcScreen = sr.Rect; - ITrayWindowImpl_GetScreenRectFromRect(This, - &rcScreen, - MONITOR_DEFAULTTONEAREST); - } - else - { - This->Position = ABE_BOTTOM; - This->AlwaysOnTop = TRUE; - - /* Use the minimum size of the taskbar, we'll use the start - button as a minimum for now. Make sure we calculate the - entire window size, not just the client size. However, we - use a thinner border than a standard thick border, so that - the start button and bands are not stuck to the screen border. */ - sr.Size.cx = This->StartBtnSize.cx + (2 * (EdgeSize.cx + DlgFrameSize.cx)); - sr.Size.cy = This->StartBtnSize.cy + (2 * (EdgeSize.cy + DlgFrameSize.cy)); - - /* Use the primary screen by default */ - rcScreen.left = 0; - rcScreen.top = 0; - rcScreen.right = GetSystemMetrics(SM_CXSCREEN); - rcScreen.bottom = GetSystemMetrics(SM_CYSCREEN); - ITrayWindowImpl_GetScreenRectFromRect(This, - &rcScreen, - MONITOR_DEFAULTTOPRIMARY); - } - - if (This->hWnd != NULL) - SetWindowPos(This->hWnd, - This->AlwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST, - 0, - 0, - 0, - 0, - SWP_NOMOVE | SWP_NOSIZE); - - /* Determine a minimum tray window rectangle. The "client" height is - zero here since we cannot determine an optimal minimum width when - loaded as a vertical tray window. We just need to make sure the values - loaded from the registry are at least. The windows explorer behaves - the same way, it allows the user to save a zero width vertical tray - window, but not a zero height horizontal tray window. */ - WndSize.cx = 2 * (EdgeSize.cx + DlgFrameSize.cx); - WndSize.cy = This->StartBtnSize.cy + (2 * (EdgeSize.cy + DlgFrameSize.cy)); - - if (WndSize.cx < sr.Size.cx) - WndSize.cx = sr.Size.cx; - if (WndSize.cy < sr.Size.cy) - WndSize.cy = sr.Size.cy; - - /* Save the calculated size */ - This->TraySize = WndSize; - - /* Calculate all docking rectangles. We need to do this here so they're - initialized and dragging the tray window to another position gives - usable results */ - for (Pos = ABE_LEFT; - Pos <= ABE_BOTTOM; - Pos++) - { - ITrayWindowImpl_GetTrayRectFromScreenRect(This, - Pos, - &rcScreen, - &This->TraySize, - &This->rcTrayWnd[Pos]); -// TRACE("rcTrayWnd[%d(%d)]: %d,%d,%d,%d\n", Pos, This->Position, This->rcTrayWnd[Pos].left, This->rcTrayWnd[Pos].top, This->rcTrayWnd[Pos].right, This->rcTrayWnd[Pos].bottom); - } - - /* Determine which monitor we are on. It shouldn't matter which docked - position rectangle we use */ - This->Monitor = ITrayWindowImpl_GetMonitorFromRect(This, - &This->rcTrayWnd[ABE_LEFT]); -} - -static UINT -ITrayWindowImpl_TrackMenu(IN OUT ITrayWindowImpl *This, - IN HMENU hMenu, - IN POINT *ppt OPTIONAL, - IN HWND hwndExclude OPTIONAL, - IN BOOL TrackUp, - IN BOOL IsContextMenu) -{ - TPMPARAMS tmp, *ptmp = NULL; - POINT pt; - UINT cmdId; - UINT fuFlags; - - if (hwndExclude != NULL) - { - /* Get the client rectangle and map it to screen coordinates */ - if (GetClientRect(hwndExclude, - &tmp.rcExclude) && - MapWindowPoints(hwndExclude, - NULL, - (LPPOINT)&tmp.rcExclude, - 2) != 0) - { - ptmp = &tmp; - } - } - - if (ppt == NULL) - { - if (ptmp == NULL && - GetClientRect(This->hWnd, - &tmp.rcExclude) && - MapWindowPoints(This->hWnd, - NULL, - (LPPOINT)&tmp.rcExclude, - 2) != 0) - { - ptmp = &tmp; - } - - if (ptmp != NULL) - { - /* NOTE: TrackPopupMenuEx will eventually align the track position - for us, no need to take care of it here as long as the - coordinates are somewhere within the exclusion rectangle */ - pt.x = ptmp->rcExclude.left; - pt.y = ptmp->rcExclude.top; - } - else - pt.x = pt.y = 0; - } - else - pt = *ppt; - - tmp.cbSize = sizeof(tmp); - - fuFlags = TPM_RETURNCMD | TPM_VERTICAL; - fuFlags |= (TrackUp ? TPM_BOTTOMALIGN : TPM_TOPALIGN); - if (IsContextMenu) - fuFlags |= TPM_RIGHTBUTTON; - else - fuFlags |= (TrackUp ? TPM_VERNEGANIMATION : TPM_VERPOSANIMATION); - - cmdId = TrackPopupMenuEx(hMenu, - fuFlags, - pt.x, - pt.y, - This->hWnd, - ptmp); - - return cmdId; -} - -static UINT -ITrayWindowImpl_TrackCtxMenu(IN OUT ITrayWindowImpl *This, - IN const TRAYWINDOW_CTXMENU *pMenu, - IN POINT *ppt OPTIONAL, - IN HWND hwndExclude OPTIONAL, - IN BOOL TrackUp, - IN PVOID Context OPTIONAL) -{ - HMENU hPopup; - UINT cmdId = 0; - PVOID pcmContext = NULL; - - hPopup = pMenu->CreateCtxMenu(This->hWnd, - &pcmContext, - Context); - if (hPopup != NULL) - { - cmdId = ITrayWindowImpl_TrackMenu(This, - hPopup, - ppt, - hwndExclude, - TrackUp, - TRUE); - - pMenu->CtxMenuCommand(This->hWnd, - cmdId, - pcmContext, - Context); - - DestroyMenu(hPopup); - } - - return cmdId; -} - -static VOID -ITrayWindowImpl_Free(ITrayWindowImpl *This) -{ - HeapFree(hProcessHeap, - 0, - This); -} - - -static ULONG STDMETHODCALLTYPE -ITrayWindowImpl_Release(IN OUT ITrayWindow *iface) -{ - ITrayWindowImpl *This = impl_from_ITrayWindow(iface); - ULONG Ret; - - Ret = InterlockedDecrement(&This->Ref); - if (Ret == 0) - ITrayWindowImpl_Free(This); - - return Ret; -} - -static VOID -ITrayWindowImpl_Destroy(ITrayWindowImpl *This) -{ - (void)InterlockedExchangePointer((PVOID*)&This->hWnd, - NULL); - - - if (This->hdpaShellServices != NULL) - { - ShutdownShellServices(This->hdpaShellServices); - This->hdpaShellServices = NULL; - } - - if (This->himlStartBtn != NULL) - { - ImageList_Destroy(This->himlStartBtn); - This->himlStartBtn = NULL; - } - - if (This->hCaptionFont != NULL) - { - DeleteObject(This->hCaptionFont); - This->hCaptionFont = NULL; - } - - if (This->hStartBtnFont != NULL) - { - DeleteObject(This->hStartBtnFont); - This->hStartBtnFont = NULL; - } - - if (This->hFont != NULL) - { - DeleteObject(This->hFont); - This->hFont = NULL; - } - - if (This->StartMenuPopup != NULL) - { - IMenuPopup_Release(This->StartMenuPopup); - This->StartMenuPopup = NULL; - } - - if (This->hbmStartMenu != NULL) - { - DeleteObject(This->hbmStartMenu); - This->hbmStartMenu = NULL; - } - - if (This->StartMenuBand != NULL) - { - IMenuBand_Release(This->StartMenuBand); - This->StartMenuBand = NULL; - } - - if (This->TrayBandSite != NULL) - { - /* FIXME: Unload bands */ - ITrayBandSite_Release(This->TrayBandSite); - This->TrayBandSite = NULL; - } - - if (This->TaskbarTheme) - { - CloseThemeData(This->TaskbarTheme); - This->TaskbarTheme = NULL; - } - - ITrayWindowImpl_Release(ITrayWindow_from_impl(This)); - - if (InterlockedDecrement(&TrayWndCount) == 0) - PostQuitMessage(0); -} - -static ULONG STDMETHODCALLTYPE -ITrayWindowImpl_AddRef(IN OUT ITrayWindow *iface) -{ - ITrayWindowImpl *This = impl_from_ITrayWindow(iface); - - return InterlockedIncrement(&This->Ref); -} - - -static BOOL -ITrayWindowImpl_NCCreate(IN OUT ITrayWindowImpl *This) -{ - ITrayWindowImpl_AddRef(ITrayWindow_from_impl(This)); - - return TRUE; -} - -static VOID -ITrayWindowImpl_UpdateStartButton(IN OUT ITrayWindowImpl *This, - IN HBITMAP hbmStart OPTIONAL) -{ - SIZE Size = { 0, 0 }; - - if (This->himlStartBtn == NULL || - !SendMessage(This->hwndStart, - BCM_GETIDEALSIZE, - 0, - (LPARAM)&Size)) - { - Size.cx = GetSystemMetrics(SM_CXEDGE); - Size.cy = GetSystemMetrics(SM_CYEDGE); - - if (hbmStart == NULL) - { - hbmStart = (HBITMAP)SendMessage(This->hwndStart, - BM_GETIMAGE, - IMAGE_BITMAP, - 0); - } - - if (hbmStart != NULL) - { - BITMAP bmp; - - if (GetObject(hbmStart, - sizeof(bmp), - &bmp) != 0) - { - Size.cx += bmp.bmWidth; - Size.cy += max(bmp.bmHeight, - GetSystemMetrics(SM_CYCAPTION)); - } - else - { - /* Huh?! Shouldn't happen... */ - goto DefSize; - } - } - else - { -DefSize: - Size.cx += GetSystemMetrics(SM_CXMINIMIZED); - Size.cy += GetSystemMetrics(SM_CYCAPTION); - } - } - - /* Save the size of the start button */ - This->StartBtnSize = Size; -} - -static VOID -ITrayWindowImpl_AlignControls(IN OUT ITrayWindowImpl *This, - IN PRECT prcClient OPTIONAL) -{ - RECT rcClient; - SIZE TraySize, StartSize; - POINT ptTrayNotify = { 0, 0 }; - BOOL Horizontal; - HDWP dwp; - - ITrayWindowImpl_UpdateStartButton(This, NULL); - if (prcClient != NULL) - { - rcClient = *prcClient; - } - else - { - if (!GetClientRect(This->hWnd, - &rcClient)) - { - return; - } - } - - Horizontal = ITrayWindowImpl_IsPosHorizontal(This); - - /* We're about to resize/move the start button, the rebar control and - the tray notification control */ - dwp = BeginDeferWindowPos(3); - if (dwp == NULL) - return; - - /* Limit the Start button width to the client width, if neccessary */ - StartSize = This->StartBtnSize; - if (StartSize.cx > rcClient.right) - StartSize.cx = rcClient.right; - - if (This->hwndStart != NULL) - { - /* Resize and reposition the button */ - dwp = DeferWindowPos(dwp, - This->hwndStart, - NULL, - 0, - 0, - StartSize.cx, - StartSize.cy, - SWP_NOZORDER | SWP_NOACTIVATE); - if (dwp == NULL) - return; - } - - /* Determine the size that the tray notification window needs */ - if (Horizontal) - { - TraySize.cx = 0; - TraySize.cy = rcClient.bottom; - } - else - { - TraySize.cx = rcClient.right; - TraySize.cy = 0; - } - - if (This->hwndTrayNotify != NULL && - SendMessage(This->hwndTrayNotify, - TNWM_GETMINIMUMSIZE, - (WPARAM)Horizontal, - (LPARAM)&TraySize)) - { - /* Move the tray notification window to the desired location */ - if (Horizontal) - ptTrayNotify.x = rcClient.right - TraySize.cx; - else - ptTrayNotify.y = rcClient.bottom - TraySize.cy; - - dwp = DeferWindowPos(dwp, - This->hwndTrayNotify, - NULL, - ptTrayNotify.x, - ptTrayNotify.y, - TraySize.cx, - TraySize.cy, - SWP_NOZORDER | SWP_NOACTIVATE); - if (dwp == NULL) - return; - } - - /* Resize/Move the rebar control */ - if (This->hwndRebar != NULL) - { - POINT ptRebar = { 0, 0 }; - SIZE szRebar; - - SetWindowStyle(This->hwndRebar, - CCS_VERT, - Horizontal ? 0 : CCS_VERT); - - if (Horizontal) - { - ptRebar.x = StartSize.cx + GetSystemMetrics(SM_CXSIZEFRAME); - szRebar.cx = ptTrayNotify.x - ptRebar.x; - szRebar.cy = rcClient.bottom; - } - else - { - ptRebar.y = StartSize.cy + GetSystemMetrics(SM_CYSIZEFRAME); - szRebar.cx = rcClient.right; - szRebar.cy = ptTrayNotify.y - ptRebar.y; - } - - dwp = DeferWindowPos(dwp, - This->hwndRebar, - NULL, - ptRebar.x, - ptRebar.y, - szRebar.cx, - szRebar.cy, - SWP_NOZORDER | SWP_NOACTIVATE); - } - - if (dwp != NULL) - EndDeferWindowPos(dwp); - - if (This->hwndTaskSwitch != NULL) - { - /* Update the task switch window configuration */ - SendMessage(This->hwndTaskSwitch, - TSWM_UPDATETASKBARPOS, - 0, - 0); - } -} - -static BOOL -ITrayWindowImpl_CreateStartBtnImageList(IN OUT ITrayWindowImpl *This) -{ - HICON hIconStart; - SIZE IconSize; - - if (This->himlStartBtn != NULL) - return TRUE; - - IconSize.cx = GetSystemMetrics(SM_CXSMICON); - IconSize.cy = GetSystemMetrics(SM_CYSMICON); - - /* Load the start button icon and create a image list for it */ - hIconStart = LoadImage(hExplorerInstance, - MAKEINTRESOURCE(IDI_START), - IMAGE_ICON, - IconSize.cx, - IconSize.cy, - LR_SHARED | LR_DEFAULTCOLOR); - - if (hIconStart != NULL) - { - This->himlStartBtn = ImageList_Create(IconSize.cx, - IconSize.cy, - ILC_COLOR32 | ILC_MASK, - 1, - 1); - if (This->himlStartBtn != NULL) - { - if (ImageList_AddIcon(This->himlStartBtn, - hIconStart) >= 0) - { - return TRUE; - } - - /* Failed to add the icon! */ - ImageList_Destroy(This->himlStartBtn); - This->himlStartBtn = NULL; - } - } - - return FALSE; -} - -static HBITMAP -ITrayWindowImpl_CreateStartButtonBitmap(IN OUT ITrayWindowImpl *This) -{ - TCHAR szStartCaption[32]; - HFONT hFontOld; - HDC hDC = NULL; - HDC hDCScreen = NULL; - SIZE Size, SmallIcon; - HBITMAP hbmpOld, hbmp = NULL; - HBITMAP hBitmap = NULL; - HICON hIconStart; - BOOL Ret; - UINT Flags; - RECT rcButton; - - /* NOTE: This is the backwards compatibility code that is used if the - Common Controls Version 6.0 are not available! */ - - if (!LoadString(hExplorerInstance, - IDS_START, - szStartCaption, - sizeof(szStartCaption) / sizeof(szStartCaption[0]))) - { - return NULL; - } - - /* Load the start button icon */ - SmallIcon.cx = GetSystemMetrics(SM_CXSMICON); - SmallIcon.cy = GetSystemMetrics(SM_CYSMICON); - hIconStart = LoadImage(hExplorerInstance, - MAKEINTRESOURCE(IDI_START), - IMAGE_ICON, - SmallIcon.cx, - SmallIcon.cy, - LR_SHARED | LR_DEFAULTCOLOR); - - hDCScreen = GetDC(NULL); - if (hDCScreen == NULL) - goto Cleanup; - - hDC = CreateCompatibleDC(hDCScreen); - if (hDC == NULL) - goto Cleanup; - - hFontOld = SelectObject(hDC, - This->hStartBtnFont); - - Ret = GetTextExtentPoint32(hDC, - szStartCaption, - _tcslen(szStartCaption), - &Size); - - SelectObject(hDC, - hFontOld); - if (!Ret) - goto Cleanup; - - /* Make sure the height is at least the size of a caption icon. */ - if (hIconStart != NULL) - Size.cx += SmallIcon.cx + 4; - Size.cy = max(Size.cy, - SmallIcon.cy); - - /* Create the bitmap */ - hbmp = CreateCompatibleBitmap(hDCScreen, - Size.cx, - Size.cy); - if (hbmp == NULL) - goto Cleanup; - - /* Caluclate the button rect */ - rcButton.left = 0; - rcButton.top = 0; - rcButton.right = Size.cx; - rcButton.bottom = Size.cy; - - /* Draw the button */ - hbmpOld = SelectObject(hDC, - hbmp); - - Flags = DC_TEXT | DC_INBUTTON; - if (hIconStart != NULL) - Flags |= DC_ICON; - - if (DrawCapTemp != NULL) - { - Ret = DrawCapTemp(NULL, - hDC, - &rcButton, - This->hStartBtnFont, - hIconStart, - szStartCaption, - Flags); - } - - SelectObject(hDC, - hbmpOld); - - if (!Ret) - goto Cleanup; - - /* We successfully created the bitmap! */ - hBitmap = hbmp; - hbmp = NULL; - -Cleanup: - if (hDCScreen != NULL) - { - ReleaseDC(NULL, - hDCScreen); - } - - if (hbmp != NULL) - DeleteObject(hbmp); - - if (hDC != NULL) - DeleteDC(hDC); - - return hBitmap; -} - -static VOID -ITrayWindowImpl_UpdateTheme(IN OUT ITrayWindowImpl *This) -{ - if (This->TaskbarTheme) - CloseThemeData(This->TaskbarTheme); - - if (IsThemeActive()) - This->TaskbarTheme = OpenThemeData(This->hWnd, L"Taskbar"); - else - This->TaskbarTheme = 0; -} - -static VOID -ITrayWindowImpl_Create(IN OUT ITrayWindowImpl *This) -{ - TCHAR szStartCaption[32]; - - SetWindowTheme(This->hWnd, L"TaskBar", NULL); - ITrayWindowImpl_UpdateTheme(This); - - InterlockedIncrement(&TrayWndCount); - - if (!LoadString(hExplorerInstance, - IDS_START, - szStartCaption, - sizeof(szStartCaption) / sizeof(szStartCaption[0]))) - { - szStartCaption[0] = TEXT('\0'); - } - - if (This->hStartBtnFont == NULL || This->hCaptionFont == NULL) - { - NONCLIENTMETRICS ncm; - - /* Get the system fonts, we use the caption font, - always bold, though. */ - ncm.cbSize = sizeof(ncm); - if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS, - sizeof(ncm), - &ncm, - FALSE)) - { - if (This->hCaptionFont == NULL) - { - ncm.lfCaptionFont.lfWeight = FW_NORMAL; - This->hCaptionFont = CreateFontIndirect(&ncm.lfCaptionFont); - } - - if (This->hStartBtnFont == NULL) - { - ncm.lfCaptionFont.lfWeight = FW_BOLD; - This->hStartBtnFont = CreateFontIndirect(&ncm.lfCaptionFont); - } - } - } - - /* Create the Start button */ - This->hwndStart = CreateWindowEx(0, - WC_BUTTON, - szStartCaption, - WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | - BS_PUSHBUTTON | BS_CENTER | BS_VCENTER | BS_BITMAP, - 0, - 0, - 0, - 0, - This->hWnd, - (HMENU)IDC_STARTBTN, - hExplorerInstance, - NULL); - if (This->hwndStart) - { - SetWindowTheme(This->hwndStart, L"Start", NULL); - SendMessage(This->hwndStart, - WM_SETFONT, - (WPARAM)This->hStartBtnFont, - FALSE); - - if (ITrayWindowImpl_CreateStartBtnImageList(This)) - { - BUTTON_IMAGELIST bil; - - /* Try to set the start button image. This requires the Common - Controls 6.0 to be present (XP and later) */ - bil.himl = This->himlStartBtn; - bil.margin.left = bil.margin.right = 1; - bil.margin.top = bil.margin.bottom = 1; - bil.uAlign = BUTTON_IMAGELIST_ALIGN_LEFT; - - if (!SendMessage(This->hwndStart, - BCM_SETIMAGELIST, - 0, - (LPARAM)&bil)) - { - /* Fall back to the deprecated method on older systems that don't - support Common Controls 6.0 */ - ImageList_Destroy(This->himlStartBtn); - This->himlStartBtn = NULL; - - goto SetStartBtnImage; - } - - /* We're using the image list, remove the BS_BITMAP style and - don't center it horizontally */ - SetWindowStyle(This->hwndStart, - BS_BITMAP | BS_RIGHT, - 0); - - ITrayWindowImpl_UpdateStartButton(This, - NULL); - } - else - { - HBITMAP hbmStart, hbmOld; - -SetStartBtnImage: - hbmStart = ITrayWindowImpl_CreateStartButtonBitmap(This); - if (hbmStart != NULL) - { - ITrayWindowImpl_UpdateStartButton(This, - hbmStart); - - hbmOld = (HBITMAP)SendMessage(This->hwndStart, - BM_SETIMAGE, - IMAGE_BITMAP, - (LPARAM)hbmStart); - - if (hbmOld != NULL) - DeleteObject(hbmOld); - } - } - } - - /* Load the saved tray window settings */ - ITrayWindowImpl_RegLoadSettings(This); - - /* Create and initialize the start menu */ - This->hbmStartMenu = LoadBitmap(hExplorerInstance, - MAKEINTRESOURCE(IDB_STARTMENU)); - This->StartMenuPopup = CreateStartMenu(ITrayWindow_from_impl(This), - &This->StartMenuBand, - This->hbmStartMenu, - 0); - - /* Load the tray band site */ - if (This->TrayBandSite != NULL) - { - ITrayBandSite_Release(This->TrayBandSite); - } - - This->TrayBandSite = CreateTrayBandSite(ITrayWindow_from_impl(This), - &This->hwndRebar, - &This->hwndTaskSwitch); - SetWindowTheme(This->hwndRebar, L"TaskBar", NULL); - - /* Create the tray notification window */ - This->hwndTrayNotify = CreateTrayNotifyWnd(ITrayWindow_from_impl(This), - This->HideClock); - - if (ITrayWindowImpl_UpdateNonClientMetrics(This)) - { - ITrayWindowImpl_SetWindowsFont(This); - } - - /* Move the tray window to the right position and resize it if neccessary */ - ITrayWindowImpl_CheckTrayWndPosition(This); - - /* Align all controls on the tray window */ - ITrayWindowImpl_AlignControls(This, - NULL); - - InitShellServices(&(This->hdpaShellServices)); - - if (This->AutoHide) - { - This->AutoHideState = AUTOHIDE_HIDING; - SetTimer(This->hWnd, TIMER_ID_AUTOHIDE, AUTOHIDE_DELAY_HIDE, NULL); - } -} - -static HRESULT STDMETHODCALLTYPE -ITrayWindowImpl_QueryInterface(IN OUT ITrayWindow *iface, - IN REFIID riid, - OUT LPVOID *ppvObj) -{ - ITrayWindowImpl *This; - - if (ppvObj == NULL) - return E_POINTER; - - This = impl_from_ITrayWindow(iface); - - if (IsEqualIID(riid, - &IID_IUnknown)) - { - *ppvObj = IUnknown_from_impl(This); - } - else if (IsEqualIID(riid, - &IID_IShellDesktopTray)) - { - *ppvObj = IShellDesktopTray_from_impl(This); - } - else - { - *ppvObj = NULL; - return E_NOINTERFACE; - } - - ITrayWindowImpl_AddRef(iface); - return S_OK; -} - -static ITrayWindowImpl * -ITrayWindowImpl_Construct(VOID) -{ - ITrayWindowImpl *This; - - This = HeapAlloc(hProcessHeap, - HEAP_ZERO_MEMORY, - sizeof(*This)); - if (This == NULL) - return NULL; - - This->lpVtbl = &ITrayWindowImpl_Vtbl; - This->lpVtblShellDesktopTray = &IShellDesktopTrayImpl_Vtbl; - This->Ref = 1; - This->Position = (DWORD)-1; - - return This; -} - -static HRESULT STDMETHODCALLTYPE -ITrayWindowImpl_Open(IN OUT ITrayWindow *iface) -{ - ITrayWindowImpl *This = impl_from_ITrayWindow(iface); - HRESULT Ret = S_OK; - HWND hWnd; - DWORD dwExStyle; - - /* Check if there's already a window created and try to show it. - If it was somehow destroyed just create a new tray window. */ - if (This->hWnd != NULL) - { - if (IsWindow(This->hWnd)) - { - if (!IsWindowVisible(This->hWnd)) - { - ITrayWindowImpl_CheckTrayWndPosition(This); - - ShowWindow(This->hWnd, - SW_SHOW); - } - } - else - goto TryCreateTrayWnd; - } - else - { - RECT rcWnd; - -TryCreateTrayWnd: - dwExStyle = WS_EX_TOOLWINDOW | WS_EX_WINDOWEDGE; - if (This->AlwaysOnTop) - dwExStyle |= WS_EX_TOPMOST; - - if (This->Position != (DWORD)-1) - rcWnd = This->rcTrayWnd[This->Position]; - else - { - ZeroMemory(&rcWnd, - sizeof(rcWnd)); - } - - hWnd = CreateWindowEx(dwExStyle, - szTrayWndClass, - NULL, - WS_POPUP | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | - WS_BORDER | WS_THICKFRAME, - rcWnd.left, - rcWnd.top, - rcWnd.right - rcWnd.left, - rcWnd.bottom - rcWnd.top, - NULL, - NULL, - hExplorerInstance, - This); - if (hWnd == NULL) - Ret = E_FAIL; - } - - return Ret; -} - -static HRESULT STDMETHODCALLTYPE -ITrayWindowImpl_Close(IN OUT ITrayWindow *iface) -{ - ITrayWindowImpl *This = impl_from_ITrayWindow(iface); - - if (This->hWnd != NULL) - { - SendMessage(This->hWnd, - WM_APP_TRAYDESTROY, - 0, - 0); - } - - return S_OK; -} - -static HWND STDMETHODCALLTYPE -ITrayWindowImpl_GetHWND(IN OUT ITrayWindow *iface) -{ - ITrayWindowImpl *This = impl_from_ITrayWindow(iface); - - return This->hWnd; -} - -static BOOL STDMETHODCALLTYPE -ITrayWindowImpl_IsSpecialHWND(IN OUT ITrayWindow *iface, - IN HWND hWnd) -{ - ITrayWindowImpl *This = impl_from_ITrayWindow(iface); - - return (hWnd == This->hWnd || - (This->hWndDesktop != NULL && hWnd == This->hWndDesktop)); -} - -static BOOL STDMETHODCALLTYPE -ITrayWindowImpl_IsHorizontal(IN OUT ITrayWindow *iface) -{ - ITrayWindowImpl *This = impl_from_ITrayWindow(iface); - return ITrayWindowImpl_IsPosHorizontal(This); -} - -static HFONT STDMETHODCALLTYPE -ITrayWIndowImpl_GetCaptionFonts(IN OUT ITrayWindow *iface, - OUT HFONT *phBoldCaption OPTIONAL) -{ - ITrayWindowImpl *This = impl_from_ITrayWindow(iface); - - if (phBoldCaption != NULL) - *phBoldCaption = This->hStartBtnFont; - - return This->hCaptionFont; -} - -static DWORD WINAPI -TrayPropertiesThread(IN OUT PVOID pParam) -{ - ITrayWindowImpl *This = pParam; - HWND hwnd; - RECT posRect; - - GetWindowRect(This->hwndStart, &posRect); - hwnd = CreateWindowEx(0, - WC_STATIC, - NULL, - WS_OVERLAPPED | WS_DISABLED | WS_CLIPSIBLINGS | WS_BORDER | SS_LEFT, - posRect.left, - posRect.top, - posRect.right - posRect.left, - posRect.bottom - posRect.top, - NULL, - NULL, - NULL, - NULL); - - This->hwndTrayPropertiesOwner = hwnd; - - DisplayTrayProperties(hwnd); - - This->hwndTrayPropertiesOwner = NULL; - DestroyWindow(hwnd); - - return 0; -} - -static HWND STDMETHODCALLTYPE -ITrayWindowImpl_DisplayProperties(IN OUT ITrayWindow *iface) -{ - ITrayWindowImpl *This = impl_from_ITrayWindow(iface); - HWND hTrayProp; - - if (This->hwndTrayPropertiesOwner) - { - hTrayProp = GetLastActivePopup(This->hwndTrayPropertiesOwner); - if (hTrayProp != NULL && - hTrayProp != This->hwndTrayPropertiesOwner) - { - SetForegroundWindow(hTrayProp); - return NULL; - } - } - - CloseHandle(CreateThread(NULL, 0, TrayPropertiesThread, This, 0, NULL)); - return NULL; -} - -static VOID -OpenCommonStartMenuDirectory(IN HWND hWndOwner, - IN LPCTSTR lpOperation) -{ - TCHAR szDir[MAX_PATH]; - - if (SHGetSpecialFolderPath(hWndOwner, - szDir, - CSIDL_COMMON_STARTMENU, - FALSE)) - { - ShellExecute(hWndOwner, - lpOperation, - NULL, - NULL, - szDir, - SW_SHOWNORMAL); - } -} - -static VOID -OpenTaskManager(IN HWND hWndOwner) -{ - ShellExecute(hWndOwner, - TEXT("open"), - TEXT("taskmgr.exe"), - NULL, - NULL, - SW_SHOWNORMAL); -} - -static BOOL STDMETHODCALLTYPE -ITrayWindowImpl_ExecContextMenuCmd(IN OUT ITrayWindow *iface, - IN UINT uiCmd) -{ - ITrayWindowImpl *This = impl_from_ITrayWindow(iface); - BOOL bHandled = TRUE; - - switch (uiCmd) - { - case ID_SHELL_CMD_PROPERTIES: - ITrayWindow_DisplayProperties(iface); - break; - - case ID_SHELL_CMD_OPEN_ALL_USERS: - OpenCommonStartMenuDirectory(This->hWnd, - TEXT("open")); - break; - - case ID_SHELL_CMD_EXPLORE_ALL_USERS: - OpenCommonStartMenuDirectory(This->hWnd, - TEXT("explore")); - break; - - case ID_LOCKTASKBAR: - if (SHRestricted(REST_CLASSICSHELL) == 0) - { - ITrayWindow_Lock(iface, - !This->Locked); - } - break; - - case ID_SHELL_CMD_OPEN_TASKMGR: - OpenTaskManager(This->hWnd); - break; - - case ID_SHELL_CMD_UNDO_ACTION: - break; - - case ID_SHELL_CMD_SHOW_DESKTOP: - break; - - case ID_SHELL_CMD_TILE_WND_H: - TileWindows(NULL, MDITILE_HORIZONTAL, NULL, 0, NULL); - break; - - case ID_SHELL_CMD_TILE_WND_V: - TileWindows(NULL, MDITILE_VERTICAL, NULL, 0, NULL); - break; - - case ID_SHELL_CMD_CASCADE_WND: - CascadeWindows(NULL, MDITILE_SKIPDISABLED, NULL, 0, NULL); - break; - - case ID_SHELL_CMD_CUST_NOTIF: - break; - - case ID_SHELL_CMD_ADJUST_DAT: - LaunchCPanel(NULL, TEXT("timedate.cpl")); - break; - - default: - TRACE("ITrayWindow::ExecContextMenuCmd(%u): Unhandled Command ID!\n", uiCmd); - bHandled = FALSE; - break; - } - - return bHandled; -} - -static BOOL STDMETHODCALLTYPE -ITrayWindowImpl_Lock(IN OUT ITrayWindow *iface, - IN BOOL bLock) -{ - BOOL bPrevLock; - ITrayWindowImpl *This = impl_from_ITrayWindow(iface); - - bPrevLock = This->Locked; - if (This->Locked != bLock) - { - This->Locked = bLock; - - if (This->TrayBandSite != NULL) - { - if (!SUCCEEDED(ITrayBandSite_Lock(This->TrayBandSite, - bLock))) - { - /* Reset?? */ - This->Locked = bPrevLock; - } - } - } - - return bPrevLock; -} - -static const ITrayWindowVtbl ITrayWindowImpl_Vtbl = -{ - /* IUnknown */ - ITrayWindowImpl_QueryInterface, - ITrayWindowImpl_AddRef, - ITrayWindowImpl_Release, - /* ITrayWindow */ - ITrayWindowImpl_Open, - ITrayWindowImpl_Close, - ITrayWindowImpl_GetHWND, - ITrayWindowImpl_IsSpecialHWND, - ITrayWindowImpl_IsHorizontal, - ITrayWIndowImpl_GetCaptionFonts, - ITrayWindowImpl_DisplayProperties, - ITrayWindowImpl_ExecContextMenuCmd, - ITrayWindowImpl_Lock -}; - -static int -ITrayWindowImpl_DrawBackground(IN ITrayWindowImpl *This, - IN HDC dc) -{ - int backoundPart; - RECT rect; - - GetClientRect(This->hWnd, &rect); - switch (This->Position) - { - case ABE_LEFT: - backoundPart = TBP_BACKGROUNDLEFT; - break; - case ABE_TOP: - backoundPart = TBP_BACKGROUNDTOP; - break; - case ABE_RIGHT: - backoundPart = TBP_BACKGROUNDRIGHT; - break; - case ABE_BOTTOM: - default: - backoundPart = TBP_BACKGROUNDBOTTOM; - break; - } - DrawThemeBackground(This->TaskbarTheme, dc, backoundPart, 0, &rect, 0); - return 0; -} - -static int -ITrayWindowImpl_DrawSizer(IN ITrayWindowImpl *This, - IN HRGN hRgn) -{ - HDC hdc; - RECT rect; - int backoundPart; - - GetWindowRect(This->hWnd, &rect); - OffsetRect(&rect, -rect.left, -rect.top); - - hdc = GetDCEx(This->hWnd, hRgn, DCX_WINDOW | DCX_INTERSECTRGN | DCX_PARENTCLIP); - - switch (This->Position) - { - case ABE_LEFT: - backoundPart = TBP_SIZINGBARLEFT; - rect.left = rect.right - GetSystemMetrics(SM_CXSIZEFRAME); - break; - case ABE_TOP: - backoundPart = TBP_SIZINGBARTOP; - rect.top = rect.bottom - GetSystemMetrics(SM_CYSIZEFRAME); - break; - case ABE_RIGHT: - backoundPart = TBP_SIZINGBARRIGHT; - rect.right = rect.left + GetSystemMetrics(SM_CXSIZEFRAME); - break; - case ABE_BOTTOM: - default: - backoundPart = TBP_SIZINGBARBOTTOM; - rect.bottom = rect.top + GetSystemMetrics(SM_CYSIZEFRAME); - break; - } - - DrawThemeBackground(This->TaskbarTheme, hdc, backoundPart, 0, &rect, 0); - - ReleaseDC(This->hWnd, hdc); - return 0; -} - -static DWORD WINAPI -RunFileDlgThread(IN OUT PVOID pParam) -{ - ITrayWindowImpl *This = pParam; - HANDLE hShell32; - RUNFILEDLG RunFileDlg; - HWND hwnd; - RECT posRect; - - GetWindowRect(This->hwndStart,&posRect); - - hwnd = CreateWindowEx(0, - WC_STATIC, - NULL, - WS_OVERLAPPED | WS_DISABLED | WS_CLIPSIBLINGS | WS_BORDER | SS_LEFT, - posRect.left, - posRect.top, - posRect.right - posRect.left, - posRect.bottom - posRect.top, - NULL, - NULL, - NULL, - NULL); - - This->hwndRunFileDlgOwner = hwnd; - - hShell32 = GetModuleHandle(TEXT("SHELL32.DLL")); - RunFileDlg = (RUNFILEDLG)GetProcAddress(hShell32, (LPCSTR)61); - - RunFileDlg(hwnd, NULL, NULL, NULL, NULL, RFF_CALCDIRECTORY); - - This->hwndRunFileDlgOwner = NULL; - DestroyWindow(hwnd); - - return 0; -} - -static void -ITrayWindowImpl_DisplayRunFileDlg(IN ITrayWindowImpl *This) -{ - HWND hRunDlg; - if (This->hwndRunFileDlgOwner) - { - hRunDlg = GetLastActivePopup(This->hwndRunFileDlgOwner); - if (hRunDlg != NULL && - hRunDlg != This->hwndRunFileDlgOwner) - { - SetForegroundWindow(hRunDlg); - return; - } - } - - CloseHandle(CreateThread(NULL, 0, RunFileDlgThread, This, 0, NULL)); -} - -static void PopupStartMenu(IN ITrayWindowImpl *This) -{ - if (This->StartMenuPopup != NULL) - { - POINTL pt; - RECTL rcExclude; - DWORD dwFlags = 0; - - if (GetWindowRect(This->hwndStart, - (RECT*) &rcExclude)) - { - switch (This->Position) - { - case ABE_BOTTOM: - pt.x = rcExclude.left; - pt.y = rcExclude.top; - dwFlags |= MPPF_BOTTOM; - break; - case ABE_TOP: - case ABE_LEFT: - pt.x = rcExclude.left; - pt.y = rcExclude.bottom; - dwFlags |= MPPF_TOP | MPPF_ALIGN_RIGHT; - break; - case ABE_RIGHT: - pt.x = rcExclude.right; - pt.y = rcExclude.bottom; - dwFlags |= MPPF_TOP | MPPF_ALIGN_LEFT; - break; - } - - IMenuPopup_Popup(This->StartMenuPopup, - &pt, - &rcExclude, - dwFlags); - - SendMessageW(This->hwndStart, BM_SETSTATE, TRUE, 0); - } - } -} - -static void -ProcessMouseTracking(ITrayWindowImpl * This) -{ - RECT rcCurrent; - POINT pt; - BOOL over; - UINT state = This->AutoHideState; - - GetCursorPos(&pt); - GetWindowRect(This->hWnd, &rcCurrent); - over = PtInRect(&rcCurrent, pt); - - if (SendMessage(This->hwndStart, BM_GETSTATE, 0, 0) != BST_UNCHECKED) - { - over = TRUE; - } - - if (over) - { - if (state == AUTOHIDE_HIDING) - { - TRACE("AutoHide cancelling hide.\n"); - This->AutoHideState = AUTOHIDE_SHOWING; - SetTimer(This->hWnd, TIMER_ID_AUTOHIDE, AUTOHIDE_INTERVAL_ANIMATING, NULL); - } - else if (state == AUTOHIDE_HIDDEN) - { - TRACE("AutoHide starting show.\n"); - This->AutoHideState = AUTOHIDE_SHOWING; - SetTimer(This->hWnd, TIMER_ID_AUTOHIDE, AUTOHIDE_DELAY_SHOW, NULL); - } - } - else - { - if (state == AUTOHIDE_SHOWING) - { - TRACE("AutoHide cancelling show.\n"); - This->AutoHideState = AUTOHIDE_HIDING; - SetTimer(This->hWnd, TIMER_ID_AUTOHIDE, AUTOHIDE_INTERVAL_ANIMATING, NULL); - } - else if (state == AUTOHIDE_SHOWN) - { - TRACE("AutoHide starting hide.\n"); - This->AutoHideState = AUTOHIDE_HIDING; - SetTimer(This->hWnd, TIMER_ID_AUTOHIDE, AUTOHIDE_DELAY_HIDE, NULL); - } - - KillTimer(This->hWnd, TIMER_ID_MOUSETRACK); - } -} - -static void -ProcessAutoHide(ITrayWindowImpl * This) -{ - RECT rc = This->rcTrayWnd[This->Position]; - INT w = This->TraySize.cx - GetSystemMetrics(SM_CXBORDER) * 2 - 1; - INT h = This->TraySize.cy - GetSystemMetrics(SM_CYBORDER) * 2 - 1; - - TRACE("AutoHide Timer received for %u, rc=(%d, %d, %d, %d), w=%d, h=%d.\n", This->AutoHideState, rc.left, rc.top, rc.right, rc.bottom, w, h); - - switch (This->AutoHideState) - { - case AUTOHIDE_HIDING: - switch (This->Position) - { - case ABE_LEFT: - This->AutoHideOffset.cy = 0; - This->AutoHideOffset.cx -= AUTOHIDE_SPEED_HIDE; - if (This->AutoHideOffset.cx < -w) - This->AutoHideOffset.cx = -w; - break; - case ABE_TOP: - This->AutoHideOffset.cx = 0; - This->AutoHideOffset.cy -= AUTOHIDE_SPEED_HIDE; - if (This->AutoHideOffset.cy < -h) - This->AutoHideOffset.cy = -h; - break; - case ABE_RIGHT: - This->AutoHideOffset.cy = 0; - This->AutoHideOffset.cx += AUTOHIDE_SPEED_HIDE; - if (This->AutoHideOffset.cx > w) - This->AutoHideOffset.cx = w; - break; - case ABE_BOTTOM: - This->AutoHideOffset.cx = 0; - This->AutoHideOffset.cy += AUTOHIDE_SPEED_HIDE; - if (This->AutoHideOffset.cy > h) - This->AutoHideOffset.cy = h; - break; - } - - if (This->AutoHideOffset.cx != w && This->AutoHideOffset.cy != h) - { - SetTimer(This->hWnd, TIMER_ID_AUTOHIDE, AUTOHIDE_INTERVAL_ANIMATING, NULL); - break; - } - - /* fallthrough */ - case AUTOHIDE_HIDDEN: - - switch (This->Position) - { - case ABE_LEFT: - This->AutoHideOffset.cx = -w; - This->AutoHideOffset.cy = 0; - break; - case ABE_TOP: - This->AutoHideOffset.cx = 0; - This->AutoHideOffset.cy = -h; - break; - case ABE_RIGHT: - This->AutoHideOffset.cx = w; - This->AutoHideOffset.cy = 0; - break; - case ABE_BOTTOM: - This->AutoHideOffset.cx = 0; - This->AutoHideOffset.cy = h; - break; - } - - KillTimer(This->hWnd, TIMER_ID_AUTOHIDE); - This->AutoHideState = AUTOHIDE_HIDDEN; - break; - - case AUTOHIDE_SHOWING: - if (This->AutoHideOffset.cx >= AUTOHIDE_SPEED_SHOW) - { - This->AutoHideOffset.cx -= AUTOHIDE_SPEED_SHOW; - } - else if (This->AutoHideOffset.cx <= -AUTOHIDE_SPEED_SHOW) - { - This->AutoHideOffset.cx += AUTOHIDE_SPEED_SHOW; - } - else - { - This->AutoHideOffset.cx = 0; - } - - if (This->AutoHideOffset.cy >= AUTOHIDE_SPEED_SHOW) - { - This->AutoHideOffset.cy -= AUTOHIDE_SPEED_SHOW; - } - else if (This->AutoHideOffset.cy <= -AUTOHIDE_SPEED_SHOW) - { - This->AutoHideOffset.cy += AUTOHIDE_SPEED_SHOW; - } - else - { - This->AutoHideOffset.cy = 0; - } - - if (This->AutoHideOffset.cx != 0 || This->AutoHideOffset.cy != 0) - { - SetTimer(This->hWnd, TIMER_ID_AUTOHIDE, AUTOHIDE_INTERVAL_ANIMATING, NULL); - break; - } - - /* fallthrough */ - case AUTOHIDE_SHOWN: - - KillTimer(This->hWnd, TIMER_ID_AUTOHIDE); - This->AutoHideState = AUTOHIDE_SHOWN; - break; - } - - rc.left += This->AutoHideOffset.cx; - rc.right += This->AutoHideOffset.cx; - rc.top += This->AutoHideOffset.cy; - rc.bottom += This->AutoHideOffset.cy; - - TRACE("AutoHide Changing position to (%d, %d, %d, %d) and state=%u.\n", rc.left, rc.top, rc.right, rc.bottom, This->AutoHideState); - SetWindowPos(This->hWnd, NULL, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, SWP_NOACTIVATE | SWP_NOZORDER); -} - -static LRESULT CALLBACK -TrayWndProc(IN HWND hwnd, - IN UINT uMsg, - IN WPARAM wParam, - IN LPARAM lParam) -{ - ITrayWindowImpl *This = NULL; - LRESULT Ret = FALSE; - - if (uMsg != WM_NCCREATE) - { - This = (ITrayWindowImpl*)GetWindowLongPtr(hwnd, - 0); - } - - if (This != NULL || uMsg == WM_NCCREATE) - { - if (This != NULL && This->StartMenuBand != NULL) - { - MSG Msg; - LRESULT lRet; - - Msg.hwnd = hwnd; - Msg.message = uMsg; - Msg.wParam = wParam; - Msg.lParam = lParam; - - if (IMenuBand_TranslateMenuMessage(This->StartMenuBand, - &Msg, - &lRet) == S_OK) - { - return lRet; - } - - wParam = Msg.wParam; - lParam = Msg.lParam; - } - - switch (uMsg) - { - case WM_DISPLAYCHANGE: - - /* Load the saved tray window settings */ - ITrayWindowImpl_RegLoadSettings(This); - - /* Move the tray window to the right position and resize it if neccessary */ - ITrayWindowImpl_CheckTrayWndPosition(This); - - /* Align all controls on the tray window */ - ITrayWindowImpl_AlignControls(This, NULL); - - break; - - case WM_COPYDATA: - { - if (This->hwndTrayNotify) - { - TrayNotify_NotifyMsg(This->hwndTrayNotify, - wParam, - lParam); - } - return TRUE; - } - case WM_THEMECHANGED: - ITrayWindowImpl_UpdateTheme(This); - return 0; - case WM_NCPAINT: - if (!This->TaskbarTheme) - goto DefHandler; - return ITrayWindowImpl_DrawSizer(This, - (HRGN)wParam); - case WM_ERASEBKGND: - if (!This->TaskbarTheme) - goto DefHandler; - return ITrayWindowImpl_DrawBackground(This, (HDC)wParam); - case WM_CTLCOLORBTN: - SetBkMode((HDC)wParam, TRANSPARENT); - return (LRESULT)GetStockObject(HOLLOW_BRUSH); - case WM_NCHITTEST: - { - RECT rcClient; - POINT pt; - - if (This->Locked) - { - /* The user may not be able to resize the tray window. - Pretend like the window is not sizeable when the user - clicks on the border. */ - return HTBORDER; - } - - SetLastError(ERROR_SUCCESS); - if (GetClientRect(hwnd, - &rcClient) && - (MapWindowPoints(hwnd, - NULL, - (LPPOINT)&rcClient, - 2) != 0 || GetLastError() == ERROR_SUCCESS)) - { - pt.x = (SHORT)LOWORD(lParam); - pt.y = (SHORT)HIWORD(lParam); - - if (PtInRect(&rcClient, - pt)) - { - /* The user is trying to drag the tray window */ - return HTCAPTION; - } - - /* Depending on the position of the tray window, allow only - changing the border next to the monitor working area */ - switch (This->Position) - { - case ABE_TOP: - if (pt.y > rcClient.bottom) - return HTBOTTOM; - break; - case ABE_LEFT: - if (pt.x > rcClient.right) - return HTRIGHT; - break; - case ABE_RIGHT: - if (pt.x < rcClient.left) - return HTLEFT; - break; - case ABE_BOTTOM: - default: - if (pt.y < rcClient.top) - return HTTOP; - break; - } - } - return HTBORDER; - } - case WM_MOVING: - { - POINT ptCursor; - PRECT pRect = (PRECT)lParam; - - /* We need to ensure that an application can not accidently - move the tray window (using SetWindowPos). However, we still - need to be able to move the window in case the user wants to - drag the tray window to another position or in case the user - wants to resize the tray window. */ - if (!This->Locked && GetCursorPos(&ptCursor)) - { - This->IsDragging = TRUE; - This->DraggingPosition = ITrayWindowImpl_GetDraggingRectFromPt(This, - ptCursor, - pRect, - &This->DraggingMonitor); - } - else - { - *pRect = This->rcTrayWnd[This->Position]; - - if (This->AutoHide) - { - pRect->left += This->AutoHideOffset.cx; - pRect->right += This->AutoHideOffset.cx; - pRect->top += This->AutoHideOffset.cy; - pRect->bottom += This->AutoHideOffset.cy; - } - } - return TRUE; - } - - case WM_SIZING: - { - PRECT pRect = (PRECT)lParam; - - if (!This->Locked) - { - ITrayWindowImpl_CalculateValidSize(This, - This->Position, - pRect); - } - else - { - *pRect = This->rcTrayWnd[This->Position]; - - if (This->AutoHide) - { - pRect->left += This->AutoHideOffset.cx; - pRect->right += This->AutoHideOffset.cx; - pRect->top += This->AutoHideOffset.cy; - pRect->bottom += This->AutoHideOffset.cy; - } - } - return TRUE; - } - - case WM_WINDOWPOSCHANGING: - { - ITrayWindowImpl_ChangingWinPos(This, - (LPWINDOWPOS)lParam); - break; - } - - case WM_SIZE: - { - RECT rcClient; - InvalidateRect(This->hWnd, NULL, TRUE); - if (wParam == SIZE_RESTORED && lParam == 0) - { - ITrayWindowImpl_ResizeWorkArea(This); - /* Clip the tray window on multi monitor systems so the edges can't - overlap into another monitor */ - ITrayWindowImpl_ApplyClipping(This, - TRUE); - - if (!GetClientRect(This->hWnd, - &rcClient)) - { - break; - } - } - else - { - rcClient.left = rcClient.top = 0; - rcClient.right = LOWORD(lParam); - rcClient.bottom = HIWORD(lParam); - } - - ITrayWindowImpl_AlignControls(This, - &rcClient); - break; - } - - case WM_ENTERSIZEMOVE: - This->InSizeMove = TRUE; - This->IsDragging = FALSE; - if (!This->Locked) - { - /* Remove the clipping on multi monitor systems while dragging around */ - ITrayWindowImpl_ApplyClipping(This, - FALSE); - } - break; - - case WM_EXITSIZEMOVE: - This->InSizeMove = FALSE; - if (!This->Locked) - { - /* Apply clipping */ - PostMessage(This->hWnd, - WM_SIZE, - SIZE_RESTORED, - 0); - } - break; - - case WM_SYSCHAR: - switch (wParam) - { - case TEXT(' '): - { - /* The user pressed Alt+Space, this usually brings up the system menu of a window. - The tray window needs to handle this specially, since it normally doesn't have - a system menu. */ - - static const UINT uidDisableItem[] = { - SC_RESTORE, - SC_MOVE, - SC_SIZE, - SC_MAXIMIZE, - SC_MINIMIZE, - }; - HMENU hSysMenu; - INT i; - UINT uId; - - /* temporarily enable the system menu */ - SetWindowStyle(hwnd, - WS_SYSMENU, - WS_SYSMENU); - - hSysMenu = GetSystemMenu(hwnd, - FALSE); - if (hSysMenu != NULL) - { - /* Disable all items that are not relevant */ - for (i = 0; i != sizeof(uidDisableItem) / sizeof(uidDisableItem[0]); i++) - { - EnableMenuItem(hSysMenu, - uidDisableItem[i], - MF_BYCOMMAND | MF_GRAYED); - } - - EnableMenuItem(hSysMenu, - SC_CLOSE, - MF_BYCOMMAND | - (SHRestricted(REST_NOCLOSE) ? MF_GRAYED : MF_ENABLED)); - - /* Display the system menu */ - uId = ITrayWindowImpl_TrackMenu(This, - hSysMenu, - NULL, - This->hwndStart, - This->Position != ABE_TOP, - FALSE); - if (uId != 0) - { - SendMessage(This->hWnd, - WM_SYSCOMMAND, - (WPARAM)uId, - 0); - } - } - - /* revert the system menu window style */ - SetWindowStyle(hwnd, - WS_SYSMENU, - 0); - break; - } - - default: - goto DefHandler; - } - break; - - case WM_NCRBUTTONUP: - /* We want the user to be able to get a context menu even on the nonclient - area (including the sizing border)! */ - uMsg = WM_CONTEXTMENU; - wParam = (WPARAM)hwnd; - /* fall through */ - - case WM_CONTEXTMENU: - { - POINT pt, *ppt = NULL; - HWND hWndExclude = NULL; - - /* Check if the administrator has forbidden access to context menus */ - if (SHRestricted(REST_NOTRAYCONTEXTMENU)) - break; - - pt.x = (SHORT)LOWORD(lParam); - pt.y = (SHORT)HIWORD(lParam); - - if (pt.x != -1 || pt.y != -1) - ppt = &pt; - else - hWndExclude = This->hwndStart; - - if ((HWND)wParam == This->hwndStart) - { - /* Make sure we can't track the context menu if the start - menu is currently being shown */ - if (!(SendMessage(This->hwndStart, - BM_GETSTATE, - 0, - 0) & BST_PUSHED)) - { - ITrayWindowImpl_TrackCtxMenu(This, - &StartMenuBtnCtxMenu, - ppt, - hWndExclude, - This->Position == ABE_BOTTOM, - This); - } - } - else - { - /* See if the context menu should be handled by the task band site */ - if (ppt != NULL && This->TrayBandSite != NULL) - { - HWND hWndAtPt; - POINT ptClient = *ppt; - - /* Convert the coordinates to client-coordinates */ - MapWindowPoints(NULL, - This->hWnd, - &ptClient, - 1); - - hWndAtPt = ChildWindowFromPoint(This->hWnd, - ptClient); - if (hWndAtPt != NULL && - (hWndAtPt == This->hwndRebar || IsChild(This->hwndRebar, - hWndAtPt))) - { - /* Check if the user clicked on the task switch window */ - ptClient = *ppt; - MapWindowPoints(NULL, - This->hwndRebar, - &ptClient, - 1); - - hWndAtPt = ChildWindowFromPointEx(This->hwndRebar, - ptClient, - CWP_SKIPINVISIBLE | CWP_SKIPDISABLED); - if (hWndAtPt == This->hwndTaskSwitch) - goto HandleTrayContextMenu; - - /* Forward the message to the task band site */ - ITrayBandSite_ProcessMessage(This->TrayBandSite, - hwnd, - uMsg, - wParam, - lParam, - &Ret); - } - else - goto HandleTrayContextMenu; - } - else - { -HandleTrayContextMenu: - /* Tray the default tray window context menu */ - ITrayWindowImpl_TrackCtxMenu(This, - &TrayWindowCtxMenu, - ppt, - NULL, - FALSE, - This); - } - } - break; - } - - case WM_NOTIFY: - { - /* FIXME: We can't check with IsChild whether the hwnd is somewhere inside - the rebar control! But we shouldn't forward messages that the band - site doesn't handle, such as other controls (start button, tray window */ - if (This->TrayBandSite == NULL || - !SUCCEEDED(ITrayBandSite_ProcessMessage(This->TrayBandSite, - hwnd, - uMsg, - wParam, - lParam, - &Ret))) - { - const NMHDR *nmh = (const NMHDR *)lParam; - - if (nmh->hwndFrom == This->hwndTrayNotify) - { - switch (nmh->code) - { - case NTNWM_REALIGN: - /* Cause all controls to be aligned */ - PostMessage(This->hWnd, - WM_SIZE, - SIZE_RESTORED, - 0); - break; - } - } - } - break; - } - - case WM_NCLBUTTONDBLCLK: - { - /* We "handle" this message so users can't cause a weird maximize/restore - window animation when double-clicking the tray window! */ - - /* We should forward mouse messages to child windows here. - Right now, this is only clock double-click */ - RECT rcClock; - if (TrayNotify_GetClockRect(This->hwndTrayNotify, &rcClock)) - { - POINT ptClick; - ptClick.x = MAKEPOINTS(lParam).x; - ptClick.y = MAKEPOINTS(lParam).y; - if (PtInRect(&rcClock, ptClick)) - LaunchCPanel(NULL, TEXT("timedate.cpl")); - } - break; - } - - case WM_NCCREATE: - { - LPCREATESTRUCT CreateStruct = (LPCREATESTRUCT)lParam; - This = (ITrayWindowImpl*)CreateStruct->lpCreateParams; - - if (InterlockedCompareExchangePointer((PVOID*)&This->hWnd, - (PVOID)hwnd, - NULL) != NULL) - { - /* Somebody else was faster... */ - return FALSE; - } - - SetWindowLongPtr(hwnd, - 0, - (LONG_PTR)This); - - return ITrayWindowImpl_NCCreate(This); - } - - case WM_CREATE: - ITrayWindowImpl_Create(This); - break; - - case WM_NCDESTROY: - ITrayWindowImpl_Destroy(This); - break; - - case WM_APP_TRAYDESTROY: - DestroyWindow(hwnd); - break; - - case TWM_OPENSTARTMENU: - { - HWND hwndStartMenu; - HRESULT hr = IUnknown_GetWindow((IUnknown*)This->StartMenuPopup, &hwndStartMenu); - if (FAILED(hr)) - break; - - if (IsWindowVisible(hwndStartMenu)) - { - IMenuPopup_OnSelect(This->StartMenuPopup, MPOS_CANCELLEVEL); - } - else - { - SendMessage(This->hWnd, WM_COMMAND, MAKEWPARAM(BN_CLICKED, IDC_STARTBTN), (LPARAM)This->hwndStart); - } - - break; - } - case WM_COMMAND: - if ((HWND)lParam == This->hwndStart) - { - PopupStartMenu(This); - break; - } - - if (This->TrayBandSite == NULL || - FAILED(ITrayBandSite_ProcessMessage(This->TrayBandSite, - hwnd, - uMsg, - wParam, - lParam, - &Ret))) - { - switch (LOWORD(wParam)) - { - /* FIXME: Handle these commands as well */ - case IDM_TASKBARANDSTARTMENU: - - ITrayWindowImpl_DisplayProperties(ITrayWindow_from_impl(This)); - break; - - case IDM_SEARCH: - break; - - case IDM_HELPANDSUPPORT: - { - /* TODO: Implement properly */ - - LPCWSTR strSite = L"https://www.reactos.org/"; - - /* TODO: Make localizable */ - LPCWSTR strCaption = L"Sorry"; - LPCWSTR strMessage = L"ReactOS could not browse to '%s' (error %d). Please make sure there is a web browser installed."; - WCHAR tmpMessage[512]; - - /* TODO: Read from the registry */ - LPCWSTR strVerb = NULL; /* default */ - LPCWSTR strPath = strSite; - LPCWSTR strParams = NULL; - - /* The return value is defined as HINSTANCE for backwards compatibility only, the cast is needed */ - int result = (int) ShellExecuteW(hwnd, strVerb, strPath, strParams, NULL, SW_SHOWNORMAL); - if (result <= 32) - { - StringCchPrintfW(tmpMessage, 512, strMessage, strSite, result); - MessageBoxExW(hwnd, tmpMessage, strCaption, MB_OK, 0); - } - break; - } - - case IDM_RUN: - { - ITrayWindowImpl_DisplayRunFileDlg(This); - break; - } - - /* FIXME: Handle these commands as well */ - case IDM_SYNCHRONIZE: - case IDM_LOGOFF: - case IDM_DISCONNECT: - case IDM_UNDOCKCOMPUTER: - break; - - case IDM_SHUTDOWN: - { - HANDLE hShell32; - EXITWINDLG ExitWinDlg; - - hShell32 = GetModuleHandle(TEXT("SHELL32.DLL")); - ExitWinDlg = (EXITWINDLG)GetProcAddress(hShell32, (LPCSTR)60); - - ExitWinDlg(hwnd); - break; - } - } - } - break; - - case WM_MOUSEMOVE: - case WM_NCMOUSEMOVE: - - if (This->AutoHide) - { - SetTimer(This->hWnd, TIMER_ID_MOUSETRACK, MOUSETRACK_INTERVAL, NULL); - } - - break; - case WM_TIMER: - if (wParam == TIMER_ID_MOUSETRACK) - { - ProcessMouseTracking(This); - } - else if (wParam == TIMER_ID_AUTOHIDE) - { - ProcessAutoHide(This); - } - - goto DefHandler; - - default: - goto DefHandler; - } - } - else - { -DefHandler: - Ret = DefWindowProc(hwnd, - uMsg, - wParam, - lParam); - } - - return Ret; -} - -/* - * Tray Window Context Menu - */ - -static HMENU -CreateTrayWindowContextMenu(IN HWND hWndOwner, - IN PVOID *ppcmContext, - IN PVOID Context OPTIONAL) -{ - ITrayWindowImpl *This = (ITrayWindowImpl *)Context; - IContextMenu *pcm = NULL; - HMENU hPopup; - - hPopup = LoadPopupMenu(hExplorerInstance, - MAKEINTRESOURCE(IDM_TRAYWND)); - - if (hPopup != NULL) - { - if (SHRestricted(REST_CLASSICSHELL) != 0) - { - DeleteMenu(hPopup, - ID_LOCKTASKBAR, - MF_BYCOMMAND); - } - - CheckMenuItem(hPopup, - ID_LOCKTASKBAR, - MF_BYCOMMAND | (This->Locked ? MF_CHECKED : MF_UNCHECKED)); - - if (This->TrayBandSite != NULL) - { - if (SUCCEEDED(ITrayBandSite_AddContextMenus(This->TrayBandSite, - hPopup, - 0, - ID_SHELL_CMD_FIRST, - ID_SHELL_CMD_LAST, - CMF_NORMAL, - &pcm))) - { - TRACE("ITrayBandSite::AddContextMenus succeeded!\n"); - *(IContextMenu **)ppcmContext = pcm; - } - } - } - - return hPopup; -} - -static VOID -OnTrayWindowContextMenuCommand(IN HWND hWndOwner, - IN UINT uiCmdId, - IN PVOID pcmContext OPTIONAL, - IN PVOID Context OPTIONAL) -{ - ITrayWindowImpl *This = (ITrayWindowImpl *)Context; - IContextMenu *pcm = (IContextMenu *)pcmContext; - - if (uiCmdId != 0) - { - if (uiCmdId >= ID_SHELL_CMD_FIRST && uiCmdId <= ID_SHELL_CMD_LAST) - { - CMINVOKECOMMANDINFO cmici = {0}; - - if (pcm != NULL) - { - /* Setup and invoke the shell command */ - cmici.cbSize = sizeof(cmici); - cmici.hwnd = hWndOwner; - cmici.lpVerb = (LPCSTR)MAKEINTRESOURCE(uiCmdId - ID_SHELL_CMD_FIRST); - cmici.nShow = SW_NORMAL; - - IContextMenu_InvokeCommand(pcm, - &cmici); - } - } - else - { - ITrayWindow_ExecContextMenuCmd(ITrayWindow_from_impl(This), - uiCmdId); - } - } - - if (pcm != NULL) - IContextMenu_Release(pcm); -} - -static const TRAYWINDOW_CTXMENU TrayWindowCtxMenu = { - CreateTrayWindowContextMenu, - OnTrayWindowContextMenuCommand -}; - -/*****************************************************************************/ - -BOOL -RegisterTrayWindowClass(VOID) -{ - WNDCLASS wcTrayWnd; - BOOL Ret; - - if (!RegisterTrayNotifyWndClass()) - return FALSE; - - wcTrayWnd.style = CS_DBLCLKS; - wcTrayWnd.lpfnWndProc = TrayWndProc; - wcTrayWnd.cbClsExtra = 0; - wcTrayWnd.cbWndExtra = sizeof(ITrayWindowImpl *); - wcTrayWnd.hInstance = hExplorerInstance; - wcTrayWnd.hIcon = NULL; - wcTrayWnd.hCursor = LoadCursor(NULL, - IDC_ARROW); - wcTrayWnd.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1); - wcTrayWnd.lpszMenuName = NULL; - wcTrayWnd.lpszClassName = szTrayWndClass; - - Ret = RegisterClass(&wcTrayWnd) != 0; - - if (!Ret) - UnregisterTrayNotifyWndClass(); - - return Ret; -} - -VOID -UnregisterTrayWindowClass(VOID) -{ - UnregisterTrayNotifyWndClass(); - - UnregisterClass(szTrayWndClass, - hExplorerInstance); -} - -ITrayWindow * -CreateTrayWindow(VOID) -{ - ITrayWindowImpl *This; - ITrayWindow *TrayWindow; - - This = ITrayWindowImpl_Construct(); - if (This != NULL) - { - TrayWindow = ITrayWindow_from_impl(This); - - ITrayWindowImpl_Open(TrayWindow); - - g_TrayWindow = This; - - return TrayWindow; - } - - return NULL; -} - -VOID -TrayProcessMessages(IN OUT ITrayWindow *Tray) -{ - ITrayWindowImpl *This; - MSG Msg; - - This = impl_from_ITrayWindow(Tray); - - /* FIXME: We should keep a reference here... */ - - while (PeekMessage(&Msg, - NULL, - 0, - 0, - PM_REMOVE)) - { - if (Msg.message == WM_QUIT) - break; - - if (This->StartMenuBand == NULL || - IMenuBand_IsMenuMessage(This->StartMenuBand, - &Msg) != S_OK) - { - TranslateMessage(&Msg); - DispatchMessage(&Msg); - } - } -} - -VOID -TrayMessageLoop(IN OUT ITrayWindow *Tray) -{ - ITrayWindowImpl *This; - MSG Msg; - BOOL Ret; - - This = impl_from_ITrayWindow(Tray); - - /* FIXME: We should keep a reference here... */ - - while (1) - { - Ret = GetMessage(&Msg, - NULL, - 0, - 0); - - if (!Ret || Ret == -1) - break; - - if (Msg.message == WM_HOTKEY) - { - switch (Msg.wParam) - { - case IDHK_RUN: /* Win+R */ - ITrayWindowImpl_DisplayRunFileDlg(This); - break; - } - } - - if (This->StartMenuBand == NULL || - IMenuBand_IsMenuMessage(This->StartMenuBand, - &Msg) != S_OK) - { - TranslateMessage(&Msg); - DispatchMessage(&Msg); - } - } -} - -/* - * IShellDesktopTray - * - * NOTE: This is a very windows-specific COM interface used by SHCreateDesktop()! - * These are the calls I observed, it may be wrong/incomplete/buggy!!! - * The reason we implement it is because we have to use SHCreateDesktop() so - * that the shell provides the desktop window and all the features that come - * with it (especially positioning of desktop icons) - */ - -static HRESULT STDMETHODCALLTYPE -ITrayWindowImpl_IShellDesktopTray_QueryInterface(IN OUT IShellDesktopTray *iface, - IN REFIID riid, - OUT LPVOID *ppvObj) -{ - ITrayWindowImpl *This = impl_from_IShellDesktopTray(iface); - ITrayWindow *tray = ITrayWindow_from_impl(This); - - TRACE("IShellDesktopTray::QueryInterface(0x%p, 0x%p)\n", riid, ppvObj); - return ITrayWindowImpl_QueryInterface(tray, - riid, - ppvObj); -} - -static ULONG STDMETHODCALLTYPE -ITrayWindowImpl_IShellDesktopTray_Release(IN OUT IShellDesktopTray *iface) -{ - ITrayWindowImpl *This = impl_from_IShellDesktopTray(iface); - ITrayWindow *tray = ITrayWindow_from_impl(This); - - TRACE("IShellDesktopTray::Release()\n"); - return ITrayWindowImpl_Release(tray); -} - -static ULONG STDMETHODCALLTYPE -ITrayWindowImpl_IShellDesktopTray_AddRef(IN OUT IShellDesktopTray *iface) -{ - ITrayWindowImpl *This = impl_from_IShellDesktopTray(iface); - ITrayWindow *tray = ITrayWindow_from_impl(This); - - TRACE("IShellDesktopTray::AddRef()\n"); - return ITrayWindowImpl_AddRef(tray); -} - -static ULONG STDMETHODCALLTYPE -ITrayWindowImpl_IShellDesktopTray_GetState(IN OUT IShellDesktopTray *iface) -{ - /* FIXME: Return ABS_ flags? */ - TRACE("IShellDesktopTray::GetState() unimplemented!\n"); - return 0; -} - -static HRESULT STDMETHODCALLTYPE -ITrayWindowImpl_IShellDesktopTray_GetTrayWindow(IN OUT IShellDesktopTray *iface, - OUT HWND *phWndTray) -{ - ITrayWindowImpl *This = impl_from_IShellDesktopTray(iface); - TRACE("IShellDesktopTray::GetTrayWindow(0x%p)\n", phWndTray); - *phWndTray = This->hWnd; - return S_OK; -} - -static HRESULT STDMETHODCALLTYPE -ITrayWindowImpl_IShellDesktopTray_RegisterDesktopWindow(IN OUT IShellDesktopTray *iface, - IN HWND hWndDesktop) -{ - ITrayWindowImpl *This = impl_from_IShellDesktopTray(iface); - TRACE("IShellDesktopTray::RegisterDesktopWindow(0x%p)\n", hWndDesktop); - - This->hWndDesktop = hWndDesktop; - return S_OK; -} - -static HRESULT STDMETHODCALLTYPE -ITrayWindowImpl_IShellDesktopTray_Unknown(IN OUT IShellDesktopTray *iface, - IN DWORD dwUnknown1, - IN DWORD dwUnknown2) -{ - TRACE("IShellDesktopTray::Unknown(%u,%u) unimplemented!\n", dwUnknown1, dwUnknown2); - return S_OK; -} - -static const IShellDesktopTrayVtbl IShellDesktopTrayImpl_Vtbl = -{ - /*** IUnknown ***/ - ITrayWindowImpl_IShellDesktopTray_QueryInterface, - ITrayWindowImpl_IShellDesktopTray_AddRef, - ITrayWindowImpl_IShellDesktopTray_Release, - /*** IShellDesktopTray ***/ - ITrayWindowImpl_IShellDesktopTray_GetState, - ITrayWindowImpl_IShellDesktopTray_GetTrayWindow, - ITrayWindowImpl_IShellDesktopTray_RegisterDesktopWindow, - ITrayWindowImpl_IShellDesktopTray_Unknown -}; - -HRESULT -ITrayWindowImpl_RaiseStartButton(ITrayWindowImpl * This) -{ - SendMessageW(This->hwndStart, BM_SETSTATE, FALSE, 0); - return S_OK; -} - -HRESULT -Tray_OnStartMenuDismissed() -{ - return ITrayWindowImpl_RaiseStartButton(g_TrayWindow); -} \ No newline at end of file diff --git a/base/shell/explorer-new/traywnd.cpp b/base/shell/explorer-new/traywnd.cpp new file mode 100644 index 00000000000..9e8edd5a97a --- /dev/null +++ b/base/shell/explorer-new/traywnd.cpp @@ -0,0 +1,3084 @@ +/* + * ReactOS Explorer + * + * Copyright 2006 - 2007 Thomas Weidenmueller + * + * this library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * this library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "precomp.h" +#include + +extern HRESULT InitShellServices(HDPA * phdpa); +extern HRESULT ShutdownShellServices(HDPA hdpa); + +extern const TRAYWINDOW_CTXMENU TrayWindowCtxMenu; + +#define WM_APP_TRAYDESTROY (WM_APP + 0x100) + +#define TIMER_ID_AUTOHIDE 1 +#define TIMER_ID_MOUSETRACK 2 +#define MOUSETRACK_INTERVAL 100 +#define AUTOHIDE_DELAY_HIDE 2000 +#define AUTOHIDE_DELAY_SHOW 50 +#define AUTOHIDE_INTERVAL_ANIMATING 10 + +#define AUTOHIDE_SPEED_SHOW 10 +#define AUTOHIDE_SPEED_HIDE 1 + +#define AUTOHIDE_HIDDEN 0 +#define AUTOHIDE_SHOWING 1 +#define AUTOHIDE_SHOWN 2 +#define AUTOHIDE_HIDING 3 + +static LONG TrayWndCount = 0; + +static const WCHAR szTrayWndClass [] = TEXT("Shell_TrayWnd"); + +/* + * ITrayWindow + */ + +const GUID IID_IShellDesktopTray = { 0x213e2df9, 0x9a14, 0x4328, { 0x99, 0xb1, 0x69, 0x61, 0xf9, 0x14, 0x3c, 0xe9 } }; + +class ITrayWindowImpl : + public CComCoClass, + public CComObjectRootEx, + public CWindowImpl < ITrayWindowImpl, CWindow, CControlWinTraits >, + public ITrayWindow, + public IShellDesktopTray +{ + HTHEME TaskbarTheme; + HWND hWndDesktop; + + HWND hwndStart; + + IImageList * himlStartBtn; + SIZE StartBtnSize; + HFONT hStartBtnFont; + HFONT hCaptionFont; + + CComPtr TrayBandSite; + HWND hwndRebar; + HWND hwndTaskSwitch; + HWND hwndTrayNotify; + + DWORD Position; + HMONITOR Monitor; + HMONITOR PreviousMonitor; + DWORD DraggingPosition; + HMONITOR DraggingMonitor; + + RECT rcTrayWnd[4]; + RECT rcNewPosSize; + SIZE TraySize; + union + { + DWORD Flags; + struct + { + DWORD AutoHide : 1; + DWORD AlwaysOnTop : 1; + DWORD SmSmallIcons : 1; + DWORD HideClock : 1; + DWORD Locked : 1; + + /* UI Status */ + DWORD InSizeMove : 1; + DWORD IsDragging : 1; + DWORD NewPosSize : 1; + }; + }; + + NONCLIENTMETRICS ncm; + HFONT hFont; + + CComPtr StartMenuBand; + CComPtr StartMenuPopup; + HBITMAP hbmStartMenu; + + HWND hwndTrayPropertiesOwner; + HWND hwndRunFileDlgOwner; + + UINT AutoHideState; + SIZE AutoHideOffset; + TRACKMOUSEEVENT MouseTrackingInfo; + + HDPA hdpaShellServices; + +public: + ITrayWindowImpl() : + TaskbarTheme(NULL), + hWndDesktop(NULL), + hwndStart(NULL), + himlStartBtn(NULL), + hStartBtnFont(NULL), + hCaptionFont(NULL), + hwndRebar(NULL), + hwndTaskSwitch(NULL), + hwndTrayNotify(NULL), + Position(0), + Monitor(NULL), + PreviousMonitor(NULL), + DraggingPosition(0), + DraggingMonitor(NULL), + Flags(0), + hFont(NULL), + hbmStartMenu(NULL), + hwndTrayPropertiesOwner(NULL), + hwndRunFileDlgOwner(NULL), + AutoHideState(NULL), + hdpaShellServices(NULL) + { + ZeroMemory(&StartBtnSize, sizeof(StartBtnSize)); + ZeroMemory(&rcTrayWnd, sizeof(rcTrayWnd)); + ZeroMemory(&rcNewPosSize, sizeof(rcNewPosSize)); + ZeroMemory(&TraySize, sizeof(TraySize)); + ZeroMemory(&ncm, sizeof(ncm)); + ZeroMemory(&AutoHideOffset, sizeof(AutoHideOffset)); + ZeroMemory(&MouseTrackingInfo, sizeof(MouseTrackingInfo)); + } + + virtual ~ITrayWindowImpl() + { + (void) InterlockedExchangePointer((PVOID*) &m_hWnd, NULL); + + + if (hdpaShellServices != NULL) + { + ShutdownShellServices(hdpaShellServices); + hdpaShellServices = NULL; + } + + if (himlStartBtn != NULL) + { + himlStartBtn->Release(); + himlStartBtn = NULL; + } + + if (hCaptionFont != NULL) + { + DeleteObject(hCaptionFont); + hCaptionFont = NULL; + } + + if (hStartBtnFont != NULL) + { + DeleteObject(hStartBtnFont); + hStartBtnFont = NULL; + } + + if (hFont != NULL) + { + DeleteObject(hFont); + hFont = NULL; + } + + if (hbmStartMenu != NULL) + { + DeleteObject(hbmStartMenu); + hbmStartMenu = NULL; + } + + if (TaskbarTheme) + { + CloseThemeData(TaskbarTheme); + TaskbarTheme = NULL; + } + + if (InterlockedDecrement(&TrayWndCount) == 0) + PostQuitMessage(0); + } + + BOOL LaunchCPanel(HWND hwnd, LPCTSTR applet) + { + WCHAR szParams[MAX_PATH]; + + StringCbCopy(szParams, sizeof(szParams), + TEXT("shell32.dll,Control_RunDLL ")); + if (FAILED_UNEXPECTEDLY(StringCbCat(szParams, sizeof(szParams), + applet))) + return FALSE; + + return (ShellExecute(hwnd, TEXT("open"), TEXT("rundll32.exe"), szParams, NULL, SW_SHOWDEFAULT) > (HINSTANCE) 32); + } + + /* + * ITrayWindow + */ + + BOOL UpdateNonClientMetrics() + { + ncm.cbSize = sizeof(ncm); + if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0)) + { + if (hFont != NULL) + DeleteObject(hFont); + + hFont = CreateFontIndirect(&ncm.lfMessageFont); + return TRUE; + } + + return FALSE; + } + + VOID SetWindowsFont() + { + if (hwndTrayNotify != NULL) + { + SendMessage(hwndTrayNotify, WM_SETFONT, (WPARAM) hFont, TRUE); + } + } + + HMONITOR GetScreenRectFromRect( + IN OUT RECT *pRect, + IN DWORD dwFlags) + { + MONITORINFO mi; + HMONITOR hMon; + + mi.cbSize = sizeof(mi); + hMon = MonitorFromRect(pRect, + dwFlags); + if (hMon != NULL && + GetMonitorInfo(hMon, + &mi)) + { + *pRect = mi.rcMonitor; + } + else + { + pRect->left = 0; + pRect->top = 0; + pRect->right = GetSystemMetrics(SM_CXSCREEN); + pRect->bottom = GetSystemMetrics(SM_CYSCREEN); + + hMon = NULL; + } + + return hMon; + } + + HMONITOR GetMonitorFromRect( + IN const RECT *pRect) + { + HMONITOR hMon; + + /* In case the monitor sizes or saved sizes differ a bit (probably + not a lot, only so the tray window overlaps into another monitor + now), minimize the risk that we determine a wrong monitor by + using the center point of the tray window if we can't determine + it using the rectangle. */ + hMon = MonitorFromRect(pRect, + MONITOR_DEFAULTTONULL); + if (hMon == NULL) + { + POINT pt; + + pt.x = pRect->left + ((pRect->right - pRect->left) / 2); + pt.y = pRect->top + ((pRect->bottom - pRect->top) / 2); + + /* be less error-prone, find the nearest monitor */ + hMon = MonitorFromPoint(pt, + MONITOR_DEFAULTTONEAREST); + } + + return hMon; + } + + HMONITOR GetScreenRect( + IN HMONITOR hMonitor, + IN OUT RECT *pRect) + { + HMONITOR hMon = NULL; + + if (hMonitor != NULL) + { + MONITORINFO mi; + + mi.cbSize = sizeof(mi); + if (!GetMonitorInfo(hMonitor, + &mi)) + { + /* Hm, the monitor is gone? Try to find a monitor where it + could be located now */ + hMon = GetMonitorFromRect( + pRect); + if (hMon == NULL || + !GetMonitorInfo(hMon, + &mi)) + { + hMon = NULL; + goto GetPrimaryRect; + } + } + + *pRect = mi.rcMonitor; + } + else + { +GetPrimaryRect: + pRect->left = 0; + pRect->top = 0; + pRect->right = GetSystemMetrics(SM_CXSCREEN); + pRect->bottom = GetSystemMetrics(SM_CYSCREEN); + } + + return hMon; + } + + VOID MakeTrayRectWithSize(IN DWORD Position, + IN const SIZE *pTraySize, + IN OUT RECT *pRect) + { + switch (Position) + { + case ABE_LEFT: + pRect->right = pRect->left + pTraySize->cx; + break; + + case ABE_TOP: + pRect->bottom = pRect->top + pTraySize->cy; + break; + + case ABE_RIGHT: + pRect->left = pRect->right - pTraySize->cx; + break; + + case ABE_BOTTOM: + default: + pRect->top = pRect->bottom - pTraySize->cy; + break; + } + } + + VOID GetTrayRectFromScreenRect(IN DWORD Position, + IN const RECT *pScreen, + IN const SIZE *pTraySize OPTIONAL, + OUT RECT *pRect) + { + if (pTraySize == NULL) + pTraySize = &TraySize; + + *pRect = *pScreen; + + /* Move the border outside of the screen */ + InflateRect(pRect, + GetSystemMetrics(SM_CXEDGE), + GetSystemMetrics(SM_CYEDGE)); + + MakeTrayRectWithSize(Position, pTraySize, pRect); + } + + BOOL + IsPosHorizontal() + { + return Position == ABE_TOP || Position == ABE_BOTTOM; + } + + HMONITOR + CalculateValidSize( + IN DWORD Position, + IN OUT RECT *pRect) + { + RECT rcScreen; + //BOOL Horizontal; + HMONITOR hMon; + SIZE szMax, szWnd; + + //Horizontal = IsPosHorizontal(); + + szWnd.cx = pRect->right - pRect->left; + szWnd.cy = pRect->bottom - pRect->top; + + rcScreen = *pRect; + hMon = GetScreenRectFromRect( + &rcScreen, + MONITOR_DEFAULTTONEAREST); + + /* Calculate the maximum size of the tray window and limit the window + size to half of the screen's size. */ + szMax.cx = (rcScreen.right - rcScreen.left) / 2; + szMax.cy = (rcScreen.bottom - rcScreen.top) / 2; + if (szWnd.cx > szMax.cx) + szWnd.cx = szMax.cx; + if (szWnd.cy > szMax.cy) + szWnd.cy = szMax.cy; + + /* FIXME - calculate */ + + GetTrayRectFromScreenRect( + Position, + &rcScreen, + &szWnd, + pRect); + + return hMon; + } + +#if 0 + VOID + GetMinimumWindowSize( + OUT RECT *pRect) + { + RECT rcMin = {0}; + + AdjustWindowRectEx(&rcMin, + GetWindowLong(m_hWnd, + GWL_STYLE), + FALSE, + GetWindowLong(m_hWnd, + GWL_EXSTYLE)); + + *pRect = rcMin; + } +#endif + + + DWORD + GetDraggingRectFromPt( + IN POINT pt, + OUT RECT *pRect, + OUT HMONITOR *phMonitor) + { + HMONITOR hMon, hMonNew; + DWORD PosH, PosV, Pos; + SIZE DeltaPt, ScreenOffset; + RECT rcScreen; + + rcScreen.left = 0; + rcScreen.top = 0; + + /* Determine the screen rectangle */ + hMon = MonitorFromPoint(pt, + MONITOR_DEFAULTTONULL); + + if (hMon != NULL) + { + MONITORINFO mi; + + mi.cbSize = sizeof(mi); + if (!GetMonitorInfo(hMon, + &mi)) + { + hMon = NULL; + goto GetPrimaryScreenRect; + } + + /* make left top corner of the screen zero based to + make calculations easier */ + pt.x -= mi.rcMonitor.left; + pt.y -= mi.rcMonitor.top; + + ScreenOffset.cx = mi.rcMonitor.left; + ScreenOffset.cy = mi.rcMonitor.top; + rcScreen.right = mi.rcMonitor.right - mi.rcMonitor.left; + rcScreen.bottom = mi.rcMonitor.bottom - mi.rcMonitor.top; + } + else + { +GetPrimaryScreenRect: + ScreenOffset.cx = 0; + ScreenOffset.cy = 0; + rcScreen.right = GetSystemMetrics(SM_CXSCREEN); + rcScreen.bottom = GetSystemMetrics(SM_CYSCREEN); + } + + /* Calculate the nearest screen border */ + if (pt.x < rcScreen.right / 2) + { + DeltaPt.cx = pt.x; + PosH = ABE_LEFT; + } + else + { + DeltaPt.cx = rcScreen.right - pt.x; + PosH = ABE_RIGHT; + } + + if (pt.y < rcScreen.bottom / 2) + { + DeltaPt.cy = pt.y; + PosV = ABE_TOP; + } + else + { + DeltaPt.cy = rcScreen.bottom - pt.y; + PosV = ABE_BOTTOM; + } + + Pos = (DeltaPt.cx * rcScreen.bottom < DeltaPt.cy * rcScreen.right) ? PosH : PosV; + + /* Fix the screen origin to be relative to the primary monitor again */ + OffsetRect(&rcScreen, + ScreenOffset.cx, + ScreenOffset.cy); + + hMonNew = GetMonitorFromRect( + &rcTrayWnd[Pos]); + if (hMon != hMonNew) + { + SIZE szTray; + + /* Recalculate the rectangle, we're dragging to another monitor. + We don't need to recalculate the rect on single monitor systems. */ + szTray.cx = rcTrayWnd[Pos].right - rcTrayWnd[Pos].left; + szTray.cy = rcTrayWnd[Pos].bottom - rcTrayWnd[Pos].top; + + GetTrayRectFromScreenRect( + Pos, + &rcScreen, + &szTray, + pRect); + if (AutoHide) + { + pRect->left += AutoHideOffset.cx; + pRect->right += AutoHideOffset.cx; + pRect->top += AutoHideOffset.cy; + pRect->bottom += AutoHideOffset.cy; + } + hMon = hMonNew; + } + else + { + /* The user is dragging the tray window on the same monitor. We don't need + to recalculate the rectangle */ + *pRect = rcTrayWnd[Pos]; + if (AutoHide) + { + pRect->left += AutoHideOffset.cx; + pRect->right += AutoHideOffset.cx; + pRect->top += AutoHideOffset.cy; + pRect->bottom += AutoHideOffset.cy; + } + } + + *phMonitor = hMon; + + return Pos; + } + + DWORD + GetDraggingRectFromRect( + IN OUT RECT *pRect, + OUT HMONITOR *phMonitor) + { + POINT pt; + + /* Calculate the center of the rectangle. We call + GetDraggingRectFromPt to calculate a valid + dragging rectangle */ + pt.x = pRect->left + ((pRect->right - pRect->left) / 2); + pt.y = pRect->top + ((pRect->bottom - pRect->top) / 2); + + return GetDraggingRectFromPt( + pt, + pRect, + phMonitor); + } + + VOID + ChangingWinPos( + IN OUT LPWINDOWPOS pwp) + { + RECT rcTray; + + if (IsDragging) + { + rcTray.left = pwp->x; + rcTray.top = pwp->y; + rcTray.right = rcTray.left + pwp->cx; + rcTray.bottom = rcTray.top + pwp->cy; + if (AutoHide) + { + rcTray.left -= AutoHideOffset.cx; + rcTray.right -= AutoHideOffset.cx; + rcTray.top -= AutoHideOffset.cy; + rcTray.bottom -= AutoHideOffset.cy; + } + + if (!EqualRect(&rcTray, + &rcTrayWnd[DraggingPosition])) + { + /* Recalculate the rectangle, the user dragged the tray + window to another monitor or the window was somehow else + moved or resized */ + DraggingPosition = GetDraggingRectFromRect( + &rcTray, + &DraggingMonitor); + //rcTrayWnd[DraggingPosition] = rcTray; + } + + //Monitor = CalculateValidSize( + // DraggingPosition, + // &rcTray); + + Monitor = DraggingMonitor; + Position = DraggingPosition; + IsDragging = FALSE; + + rcTrayWnd[Position] = rcTray; + goto ChangePos; + } + else if (GetWindowRect(m_hWnd, &rcTray)) + { + if (InSizeMove) + { + if (!(pwp->flags & SWP_NOMOVE)) + { + rcTray.left = pwp->x; + rcTray.top = pwp->y; + } + + if (!(pwp->flags & SWP_NOSIZE)) + { + rcTray.right = rcTray.left + pwp->cx; + rcTray.bottom = rcTray.top + pwp->cy; + } + + Position = GetDraggingRectFromRect( + &rcTray, + &Monitor); + + if (!(pwp->flags & (SWP_NOMOVE | SWP_NOSIZE))) + { + SIZE szWnd; + + szWnd.cx = pwp->cx; + szWnd.cy = pwp->cy; + + MakeTrayRectWithSize(Position, &szWnd, &rcTray); + } + + if (AutoHide) + { + rcTray.left -= AutoHideOffset.cx; + rcTray.right -= AutoHideOffset.cx; + rcTray.top -= AutoHideOffset.cy; + rcTray.bottom -= AutoHideOffset.cy; + } + rcTrayWnd[Position] = rcTray; + } + else + { + /* If the user isn't resizing the tray window we need to make sure the + new size or position is valid. this is to prevent changes to the window + without user interaction. */ + rcTray = rcTrayWnd[Position]; + } + +ChangePos: + TraySize.cx = rcTray.right - rcTray.left; + TraySize.cy = rcTray.bottom - rcTray.top; + + if (AutoHide) + { + rcTray.left += AutoHideOffset.cx; + rcTray.right += AutoHideOffset.cx; + rcTray.top += AutoHideOffset.cy; + rcTray.bottom += AutoHideOffset.cy; + } + + pwp->flags &= ~(SWP_NOMOVE | SWP_NOSIZE); + pwp->x = rcTray.left; + pwp->y = rcTray.top; + pwp->cx = TraySize.cx; + pwp->cy = TraySize.cy; + } + } + + VOID + ApplyClipping(IN BOOL Clip) + { + RECT rcClip, rcWindow; + HRGN hClipRgn; + + if (GetWindowRect(m_hWnd, &rcWindow)) + { + /* Disable clipping on systems with only one monitor */ + if (GetSystemMetrics(SM_CMONITORS) <= 1) + Clip = FALSE; + + if (Clip) + { + rcClip = rcWindow; + + GetScreenRect(Monitor, &rcClip); + + if (!IntersectRect(&rcClip, &rcClip, &rcWindow)) + { + rcClip = rcWindow; + } + + OffsetRect(&rcClip, + -rcWindow.left, + -rcWindow.top); + + hClipRgn = CreateRectRgnIndirect(&rcClip); + } + else + hClipRgn = NULL; + + /* Set the clipping region or make sure the window isn't clipped + by disabling it explicitly. */ + SetWindowRgn(m_hWnd, hClipRgn, TRUE); + } + } + + VOID ResizeWorkArea() + { +#if !WIN7_COMPAT_MODE + RECT rcTray, rcWorkArea; + + /* If monitor has changed then fix the previous monitors work area */ + if (PreviousMonitor != Monitor) + { + GetScreenRect( + PreviousMonitor, + &rcWorkArea); + SystemParametersInfo(SPI_SETWORKAREA, + 1, + &rcWorkArea, + SPIF_SENDCHANGE); + } + + rcTray = rcTrayWnd[Position]; + + GetScreenRect( + Monitor, + &rcWorkArea); + PreviousMonitor = Monitor; + + /* If AutoHide is false then change the workarea to exclude the area that + the taskbar covers. */ + if (!AutoHide) + { + switch (Position) + { + case ABE_TOP: + rcWorkArea.top = rcTray.bottom; + break; + case ABE_LEFT: + rcWorkArea.left = rcTray.right; + break; + case ABE_RIGHT: + rcWorkArea.right = rcTray.left; + break; + case ABE_BOTTOM: + rcWorkArea.bottom = rcTray.top; + break; + } + } + + SystemParametersInfo(SPI_SETWORKAREA, + 1, + &rcWorkArea, + SPIF_SENDCHANGE); +#endif + } + + VOID CheckTrayWndPosition() + { + RECT rcTray; + + rcTray = rcTrayWnd[Position]; + + if (AutoHide) + { + rcTray.left += AutoHideOffset.cx; + rcTray.right += AutoHideOffset.cx; + rcTray.top += AutoHideOffset.cy; + rcTray.bottom += AutoHideOffset.cy; + } + + // TRACE("CheckTray: %d: %d,%d,%d,%d\n", Position, rcTray.left, rcTray.top, rcTray.right, rcTray.bottom); + + /* Move the tray window */ + SetWindowPos(NULL, + rcTray.left, + rcTray.top, + rcTray.right - rcTray.left, + rcTray.bottom - rcTray.top, + SWP_NOZORDER); + + ResizeWorkArea(); + + ApplyClipping( + TRUE); + } + + typedef struct _TW_STUCKRECTS2 + { + DWORD cbSize; + LONG Unknown; + DWORD dwFlags; + DWORD Position; + SIZE Size; + RECT Rect; + } TW_STRUCKRECTS2, *PTW_STUCKRECTS2; + + VOID + RegLoadSettings() + { + DWORD Pos; + TW_STRUCKRECTS2 sr; + RECT rcScreen; + SIZE WndSize, EdgeSize, DlgFrameSize; + DWORD cbSize = sizeof(sr); + + EdgeSize.cx = GetSystemMetrics(SM_CXEDGE); + EdgeSize.cy = GetSystemMetrics(SM_CYEDGE); + DlgFrameSize.cx = GetSystemMetrics(SM_CXDLGFRAME); + DlgFrameSize.cy = GetSystemMetrics(SM_CYDLGFRAME); + + if (SHGetValue(hkExplorer, + TEXT("StuckRects2"), + TEXT("Settings"), + NULL, + &sr, + &cbSize) == ERROR_SUCCESS && + sr.cbSize == sizeof(sr)) + { + AutoHide = (sr.dwFlags & ABS_AUTOHIDE) != 0; + AlwaysOnTop = (sr.dwFlags & ABS_ALWAYSONTOP) != 0; + SmSmallIcons = (sr.dwFlags & 0x4) != 0; + HideClock = (sr.dwFlags & 0x8) != 0; + + /* FIXME: Are there more flags? */ + +#if WIN7_COMPAT_MODE + Position = ABE_LEFT; +#else + if (sr.Position > ABE_BOTTOM) + Position = ABE_BOTTOM; + else + Position = sr.Position; +#endif + + /* Try to find out which monitor the tray window was located on last. + Here we're only interested in the monitor screen that we think + is the last one used. We're going to determine on which monitor + we really are after calculating the docked position. */ + rcScreen = sr.Rect; + GetScreenRectFromRect( + &rcScreen, + MONITOR_DEFAULTTONEAREST); + } + else + { + Position = ABE_BOTTOM; + AlwaysOnTop = TRUE; + + /* Use the minimum size of the taskbar, we'll use the start + button as a minimum for now. Make sure we calculate the + entire window size, not just the client size. However, we + use a thinner border than a standard thick border, so that + the start button and bands are not stuck to the screen border. */ + sr.Size.cx = StartBtnSize.cx + (2 * (EdgeSize.cx + DlgFrameSize.cx)); + sr.Size.cy = StartBtnSize.cy + (2 * (EdgeSize.cy + DlgFrameSize.cy)); + + /* Use the primary screen by default */ + rcScreen.left = 0; + rcScreen.top = 0; + rcScreen.right = GetSystemMetrics(SM_CXSCREEN); + rcScreen.bottom = GetSystemMetrics(SM_CYSCREEN); + GetScreenRectFromRect( + &rcScreen, + MONITOR_DEFAULTTOPRIMARY); + } + + if (m_hWnd != NULL) + SetWindowPos( + AlwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST, + 0, + 0, + 0, + 0, + SWP_NOMOVE | SWP_NOSIZE); + + /* Determine a minimum tray window rectangle. The "client" height is + zero here since we cannot determine an optimal minimum width when + loaded as a vertical tray window. We just need to make sure the values + loaded from the registry are at least. The windows explorer behaves + the same way, it allows the user to save a zero width vertical tray + window, but not a zero height horizontal tray window. */ + WndSize.cx = 2 * (EdgeSize.cx + DlgFrameSize.cx); + WndSize.cy = StartBtnSize.cy + (2 * (EdgeSize.cy + DlgFrameSize.cy)); + + if (WndSize.cx < sr.Size.cx) + WndSize.cx = sr.Size.cx; + if (WndSize.cy < sr.Size.cy) + WndSize.cy = sr.Size.cy; + + /* Save the calculated size */ + TraySize = WndSize; + + /* Calculate all docking rectangles. We need to do this here so they're + initialized and dragging the tray window to another position gives + usable results */ + for (Pos = ABE_LEFT; + Pos <= ABE_BOTTOM; + Pos++) + { + GetTrayRectFromScreenRect( + Pos, + &rcScreen, + &TraySize, + &rcTrayWnd[Pos]); + // TRACE("rcTrayWnd[%d(%d)]: %d,%d,%d,%d\n", Pos, Position, rcTrayWnd[Pos].left, rcTrayWnd[Pos].top, rcTrayWnd[Pos].right, rcTrayWnd[Pos].bottom); + } + + /* Determine which monitor we are on. It shouldn't matter which docked + position rectangle we use */ + Monitor = GetMonitorFromRect( + &rcTrayWnd[ABE_LEFT]); + } + + UINT + TrackMenu( + IN HMENU hMenu, + IN POINT *ppt OPTIONAL, + IN HWND hwndExclude OPTIONAL, + IN BOOL TrackUp, + IN BOOL IsContextMenu) + { + TPMPARAMS tmp, *ptmp = NULL; + POINT pt; + UINT cmdId; + UINT fuFlags; + + if (hwndExclude != NULL) + { + /* Get the client rectangle and map it to screen coordinates */ + if (::GetClientRect(hwndExclude, + &tmp.rcExclude) && + MapWindowPoints(hwndExclude, + NULL, + (LPPOINT) &tmp.rcExclude, + 2) != 0) + { + ptmp = &tmp; + } + } + + if (ppt == NULL) + { + if (ptmp == NULL && + GetClientRect(&tmp.rcExclude) && + MapWindowPoints(m_hWnd, + NULL, + (LPPOINT) &tmp.rcExclude, + 2) != 0) + { + ptmp = &tmp; + } + + if (ptmp != NULL) + { + /* NOTE: TrackPopupMenuEx will eventually align the track position + for us, no need to take care of it here as long as the + coordinates are somewhere within the exclusion rectangle */ + pt.x = ptmp->rcExclude.left; + pt.y = ptmp->rcExclude.top; + } + else + pt.x = pt.y = 0; + } + else + pt = *ppt; + + tmp.cbSize = sizeof(tmp); + + fuFlags = TPM_RETURNCMD | TPM_VERTICAL; + fuFlags |= (TrackUp ? TPM_BOTTOMALIGN : TPM_TOPALIGN); + if (IsContextMenu) + fuFlags |= TPM_RIGHTBUTTON; + else + fuFlags |= (TrackUp ? TPM_VERNEGANIMATION : TPM_VERPOSANIMATION); + + cmdId = TrackPopupMenuEx(hMenu, + fuFlags, + pt.x, + pt.y, + m_hWnd, + ptmp); + + return cmdId; + } + + UINT TrackCtxMenu( + IN const TRAYWINDOW_CTXMENU *pMenu, + IN POINT *ppt OPTIONAL, + IN HWND hwndExclude OPTIONAL, + IN BOOL TrackUp, + IN PVOID Context OPTIONAL) + { + HMENU hPopup; + UINT cmdId = 0; + PVOID pcmContext = NULL; + + hPopup = pMenu->CreateCtxMenu(m_hWnd, + &pcmContext, + Context); + if (hPopup != NULL) + { + cmdId = TrackMenu( + hPopup, + ppt, + hwndExclude, + TrackUp, + TRUE); + + pMenu->CtxMenuCommand(m_hWnd, + cmdId, + pcmContext, + Context); + + DestroyMenu(hPopup); + } + + return cmdId; + } + + + VOID UpdateStartButton(IN HBITMAP hbmStart OPTIONAL) + { + SIZE Size = { 0, 0 }; + + if (himlStartBtn == NULL || + !SendMessage(hwndStart, + BCM_GETIDEALSIZE, + 0, + (LPARAM) &Size)) + { + Size.cx = GetSystemMetrics(SM_CXEDGE); + Size.cy = GetSystemMetrics(SM_CYEDGE); + + if (hbmStart == NULL) + { + hbmStart = (HBITMAP) SendMessage(hwndStart, + BM_GETIMAGE, + IMAGE_BITMAP, + 0); + } + + if (hbmStart != NULL) + { + BITMAP bmp; + + if (GetObject(hbmStart, + sizeof(bmp), + &bmp) != 0) + { + Size.cx += bmp.bmWidth; + Size.cy += max(bmp.bmHeight, + GetSystemMetrics(SM_CYCAPTION)); + } + else + { + /* Huh?! Shouldn't happen... */ + goto DefSize; + } + } + else + { +DefSize: + Size.cx += GetSystemMetrics(SM_CXMINIMIZED); + Size.cy += GetSystemMetrics(SM_CYCAPTION); + } + } + + /* Save the size of the start button */ + StartBtnSize = Size; + } + + VOID + AlignControls(IN PRECT prcClient OPTIONAL) + { + RECT rcClient; + SIZE TraySize, StartSize; + POINT ptTrayNotify = { 0, 0 }; + BOOL Horizontal; + HDWP dwp; + + UpdateStartButton(NULL); + if (prcClient != NULL) + { + rcClient = *prcClient; + } + else + { + if (!GetClientRect(&rcClient)) + { + return; + } + } + + Horizontal = IsPosHorizontal(); + + /* We're about to resize/move the start button, the rebar control and + the tray notification control */ + dwp = BeginDeferWindowPos(3); + if (dwp == NULL) + return; + + /* Limit the Start button width to the client width, if neccessary */ + StartSize = StartBtnSize; + if (StartSize.cx > rcClient.right) + StartSize.cx = rcClient.right; + + if (hwndStart != NULL) + { + /* Resize and reposition the button */ + dwp = DeferWindowPos(dwp, + hwndStart, + NULL, + 0, + 0, + StartSize.cx, + StartSize.cy, + SWP_NOZORDER | SWP_NOACTIVATE); + if (dwp == NULL) + return; + } + + /* Determine the size that the tray notification window needs */ + if (Horizontal) + { + TraySize.cx = 0; + TraySize.cy = rcClient.bottom; + } + else + { + TraySize.cx = rcClient.right; + TraySize.cy = 0; + } + + if (hwndTrayNotify != NULL && + SendMessage(hwndTrayNotify, + TNWM_GETMINIMUMSIZE, + (WPARAM) Horizontal, + (LPARAM) &TraySize)) + { + /* Move the tray notification window to the desired location */ + if (Horizontal) + ptTrayNotify.x = rcClient.right - TraySize.cx; + else + ptTrayNotify.y = rcClient.bottom - TraySize.cy; + + dwp = DeferWindowPos(dwp, + hwndTrayNotify, + NULL, + ptTrayNotify.x, + ptTrayNotify.y, + TraySize.cx, + TraySize.cy, + SWP_NOZORDER | SWP_NOACTIVATE); + if (dwp == NULL) + return; + } + + /* Resize/Move the rebar control */ + if (hwndRebar != NULL) + { + POINT ptRebar = { 0, 0 }; + SIZE szRebar; + + SetWindowStyle(hwndRebar, CCS_VERT, Horizontal ? 0 : CCS_VERT); + + if (Horizontal) + { + ptRebar.x = StartSize.cx + GetSystemMetrics(SM_CXSIZEFRAME); + szRebar.cx = ptTrayNotify.x - ptRebar.x; + szRebar.cy = rcClient.bottom; + } + else + { + ptRebar.y = StartSize.cy + GetSystemMetrics(SM_CYSIZEFRAME); + szRebar.cx = rcClient.right; + szRebar.cy = ptTrayNotify.y - ptRebar.y; + } + + dwp = DeferWindowPos(dwp, + hwndRebar, + NULL, + ptRebar.x, + ptRebar.y, + szRebar.cx, + szRebar.cy, + SWP_NOZORDER | SWP_NOACTIVATE); + } + + if (dwp != NULL) + EndDeferWindowPos(dwp); + + if (hwndTaskSwitch != NULL) + { + /* Update the task switch window configuration */ + SendMessage(hwndTaskSwitch, + TSWM_UPDATETASKBARPOS, + 0, + 0); + } + } + + BOOL + CreateStartBtnImageList() + { + HICON hIconStart; + SIZE IconSize; + + if (himlStartBtn != NULL) + return TRUE; + + IconSize.cx = GetSystemMetrics(SM_CXSMICON); + IconSize.cy = GetSystemMetrics(SM_CYSMICON); + + /* Load the start button icon and create a image list for it */ + hIconStart = (HICON) LoadImage(hExplorerInstance, + MAKEINTRESOURCE(IDI_START), + IMAGE_ICON, + IconSize.cx, + IconSize.cy, + LR_SHARED | LR_DEFAULTCOLOR); + + if (hIconStart != NULL) + { + himlStartBtn = (IImageList*) ImageList_Create(IconSize.cx, + IconSize.cy, + ILC_COLOR32 | ILC_MASK, + 1, + 1); + if (himlStartBtn != NULL) + { + int s; + himlStartBtn->ReplaceIcon(-1, hIconStart, &s); + if (s >= 0) + { + return TRUE; + } + + /* Failed to add the icon! */ + himlStartBtn->Release(); + himlStartBtn = NULL; + } + } + + return FALSE; + } + + HBITMAP CreateStartButtonBitmap() + { + WCHAR szStartCaption[32]; + HFONT hFontOld; + HDC hDC = NULL; + HDC hDCScreen = NULL; + SIZE Size, SmallIcon; + HBITMAP hbmpOld, hbmp = NULL; + HBITMAP hBitmap = NULL; + HICON hIconStart; + BOOL Ret; + UINT Flags; + RECT rcButton; + + /* NOTE: this is the backwards compatibility code that is used if the + Common Controls Version 6.0 are not available! */ + + if (!LoadString(hExplorerInstance, + IDS_START, + szStartCaption, + sizeof(szStartCaption) / sizeof(szStartCaption[0]))) + { + return NULL; + } + + /* Load the start button icon */ + SmallIcon.cx = GetSystemMetrics(SM_CXSMICON); + SmallIcon.cy = GetSystemMetrics(SM_CYSMICON); + hIconStart = (HICON) LoadImage(hExplorerInstance, + MAKEINTRESOURCE(IDI_START), + IMAGE_ICON, + SmallIcon.cx, + SmallIcon.cy, + LR_SHARED | LR_DEFAULTCOLOR); + + hDCScreen = GetDC(NULL); + if (hDCScreen == NULL) + goto Cleanup; + + hDC = CreateCompatibleDC(hDCScreen); + if (hDC == NULL) + goto Cleanup; + + hFontOld = (HFONT) SelectObject(hDC, hStartBtnFont); + + Ret = GetTextExtentPoint32(hDC, + szStartCaption, + _tcslen(szStartCaption), + &Size); + + SelectObject(hDC, + hFontOld); + if (!Ret) + goto Cleanup; + + /* Make sure the height is at least the size of a caption icon. */ + if (hIconStart != NULL) + Size.cx += SmallIcon.cx + 4; + Size.cy = max(Size.cy, + SmallIcon.cy); + + /* Create the bitmap */ + hbmp = CreateCompatibleBitmap(hDCScreen, + Size.cx, + Size.cy); + if (hbmp == NULL) + goto Cleanup; + + /* Caluclate the button rect */ + rcButton.left = 0; + rcButton.top = 0; + rcButton.right = Size.cx; + rcButton.bottom = Size.cy; + + /* Draw the button */ + hbmpOld = (HBITMAP) SelectObject(hDC, hbmp); + + Flags = DC_TEXT | DC_INBUTTON; + if (hIconStart != NULL) + Flags |= DC_ICON; + + if (DrawCapTemp != NULL) + { + Ret = DrawCapTemp(NULL, + hDC, + &rcButton, + hStartBtnFont, + hIconStart, + szStartCaption, + Flags); + } + + SelectObject(hDC, + hbmpOld); + + if (!Ret) + goto Cleanup; + + /* We successfully created the bitmap! */ + hBitmap = hbmp; + hbmp = NULL; + +Cleanup: + if (hDCScreen != NULL) + { + ReleaseDC(NULL, + hDCScreen); + } + + if (hbmp != NULL) + DeleteObject(hbmp); + + if (hDC != NULL) + DeleteDC(hDC); + + return hBitmap; + } + + LRESULT OnThemeChanged() + { + if (TaskbarTheme) + CloseThemeData(TaskbarTheme); + + if (IsThemeActive()) + TaskbarTheme = OpenThemeData(m_hWnd, L"TaskBar"); + else + TaskbarTheme = NULL; + + return TRUE; + } + + LRESULT OnThemeChanged(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + return OnThemeChanged(); + } + + LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + WCHAR szStartCaption[32]; + + ((ITrayWindow*)this)->AddRef(); + + SetWindowTheme(m_hWnd, L"TaskBar", NULL); + OnThemeChanged(); + + InterlockedIncrement(&TrayWndCount); + + if (!LoadString(hExplorerInstance, + IDS_START, + szStartCaption, + sizeof(szStartCaption) / sizeof(szStartCaption[0]))) + { + szStartCaption[0] = TEXT('\0'); + } + + if (hStartBtnFont == NULL || hCaptionFont == NULL) + { + NONCLIENTMETRICS ncm; + + /* Get the system fonts, we use the caption font, + always bold, though. */ + ncm.cbSize = sizeof(ncm); + if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS, + sizeof(ncm), + &ncm, + FALSE)) + { + if (hCaptionFont == NULL) + { + ncm.lfCaptionFont.lfWeight = FW_NORMAL; + hCaptionFont = CreateFontIndirect(&ncm.lfCaptionFont); + } + + if (hStartBtnFont == NULL) + { + ncm.lfCaptionFont.lfWeight = FW_BOLD; + hStartBtnFont = CreateFontIndirect(&ncm.lfCaptionFont); + } + } + } + + /* Create the Start button */ + hwndStart = CreateWindowEx(0, + WC_BUTTON, + szStartCaption, + WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | + BS_PUSHBUTTON | BS_CENTER | BS_VCENTER | BS_BITMAP, + 0, + 0, + 0, + 0, + m_hWnd, + (HMENU) IDC_STARTBTN, + hExplorerInstance, + NULL); + if (hwndStart) + { + SetWindowTheme(hwndStart, L"Start", NULL); + SendMessage(hwndStart, + WM_SETFONT, + (WPARAM) hStartBtnFont, + FALSE); + + if (CreateStartBtnImageList()) + { + BUTTON_IMAGELIST bil; + + /* Try to set the start button image. this requires the Common + Controls 6.0 to be present (XP and later) */ + bil.himl = (HIMAGELIST) himlStartBtn; + bil.margin.left = bil.margin.right = 1; + bil.margin.top = bil.margin.bottom = 1; + bil.uAlign = BUTTON_IMAGELIST_ALIGN_LEFT; + + if (!SendMessage(hwndStart, + BCM_SETIMAGELIST, + 0, + (LPARAM) &bil)) + { + /* Fall back to the deprecated method on older systems that don't + support Common Controls 6.0 */ + himlStartBtn->Release(); + himlStartBtn = NULL; + + goto SetStartBtnImage; + } + + /* We're using the image list, remove the BS_BITMAP style and + don't center it horizontally */ + SetWindowStyle(hwndStart, + BS_BITMAP | BS_RIGHT, + 0); + + UpdateStartButton( + NULL); + } + else + { + HBITMAP hbmStart, hbmOld; + +SetStartBtnImage: + hbmStart = CreateStartButtonBitmap(); + if (hbmStart != NULL) + { + UpdateStartButton( + hbmStart); + + hbmOld = (HBITMAP) SendMessage(hwndStart, + BM_SETIMAGE, + IMAGE_BITMAP, + (LPARAM) hbmStart); + + if (hbmOld != NULL) + DeleteObject(hbmOld); + } + } + } + + /* Load the saved tray window settings */ + RegLoadSettings(); + + /* Create and initialize the start menu */ + hbmStartMenu = LoadBitmap(hExplorerInstance, + MAKEINTRESOURCE(IDB_STARTMENU)); + StartMenuPopup = CreateStartMenu(this, &StartMenuBand, hbmStartMenu, 0); + + /* Load the tray band site */ + if (TrayBandSite != NULL) + { + TrayBandSite.Release(); + } + + TrayBandSite = CreateTrayBandSite(this, &hwndRebar, &hwndTaskSwitch); + SetWindowTheme(hwndRebar, L"TaskBar", NULL); + + /* Create the tray notification window */ + hwndTrayNotify = CreateTrayNotifyWnd(this, HideClock); + + if (UpdateNonClientMetrics()) + { + SetWindowsFont(); + } + + /* Move the tray window to the right position and resize it if neccessary */ + CheckTrayWndPosition(); + + /* Align all controls on the tray window */ + AlignControls( + NULL); + + InitShellServices(&(hdpaShellServices)); + + if (AutoHide) + { + AutoHideState = AUTOHIDE_HIDING; + SetTimer(TIMER_ID_AUTOHIDE, AUTOHIDE_DELAY_HIDE, NULL); + } + return TRUE; + } + + HRESULT STDMETHODCALLTYPE Open() + { + RECT rcWnd; + + /* Check if there's already a window created and try to show it. + If it was somehow destroyed just create a new tray window. */ + if (m_hWnd != NULL && IsWindow()) + { + if (!IsWindowVisible(m_hWnd)) + { + CheckTrayWndPosition(); + + ShowWindow(SW_SHOW); + } + + return S_OK; + } + + DWORD dwExStyle = WS_EX_TOOLWINDOW | WS_EX_WINDOWEDGE; + if (AlwaysOnTop) + dwExStyle |= WS_EX_TOPMOST; + + DWORD dwStyle = WS_POPUP | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | + WS_BORDER | WS_THICKFRAME; + + ZeroMemory(&rcWnd, sizeof(rcWnd)); + if (Position != (DWORD) -1) + rcWnd = rcTrayWnd[Position]; + + if (!Create(NULL, rcWnd, NULL, dwStyle, dwExStyle)) + return E_FAIL; + + return S_OK; + } + + HRESULT STDMETHODCALLTYPE Close() + { + if (m_hWnd != NULL) + { + SendMessage(m_hWnd, + WM_APP_TRAYDESTROY, + 0, + 0); + } + + return S_OK; + } + + HWND STDMETHODCALLTYPE GetHWND() + { + return m_hWnd; + } + + BOOL STDMETHODCALLTYPE IsSpecialHWND(IN HWND hWnd) + { + return (m_hWnd == hWnd || + (hWndDesktop != NULL && m_hWnd == hWndDesktop)); + } + + BOOL STDMETHODCALLTYPE + IsHorizontal() + { + return IsPosHorizontal(); + } + + HFONT STDMETHODCALLTYPE GetCaptionFonts(OUT HFONT *phBoldCaption OPTIONAL) + { + if (phBoldCaption != NULL) + *phBoldCaption = hStartBtnFont; + + return hCaptionFont; + } + + DWORD WINAPI TrayPropertiesThread() + { + HWND hwnd; + RECT posRect; + + GetWindowRect(hwndStart, &posRect); + hwnd = CreateWindowEx(0, + WC_STATIC, + NULL, + WS_OVERLAPPED | WS_DISABLED | WS_CLIPSIBLINGS | WS_BORDER | SS_LEFT, + posRect.left, + posRect.top, + posRect.right - posRect.left, + posRect.bottom - posRect.top, + NULL, + NULL, + NULL, + NULL); + + hwndTrayPropertiesOwner = hwnd; + + DisplayTrayProperties(hwnd); + + hwndTrayPropertiesOwner = NULL; + DestroyWindow(); + + return 0; + } + + static DWORD WINAPI s_TrayPropertiesThread(IN OUT PVOID pParam) + { + ITrayWindowImpl *This = (ITrayWindowImpl*) pParam; + + return This->TrayPropertiesThread(); + } + + HWND STDMETHODCALLTYPE DisplayProperties() + { + HWND hTrayProp; + + if (hwndTrayPropertiesOwner) + { + hTrayProp = GetLastActivePopup(hwndTrayPropertiesOwner); + if (hTrayProp != NULL && + hTrayProp != hwndTrayPropertiesOwner) + { + SetForegroundWindow(hTrayProp); + return NULL; + } + } + + CloseHandle(CreateThread(NULL, 0, s_TrayPropertiesThread, this, 0, NULL)); + return NULL; + } + + VOID OpenCommonStartMenuDirectory(IN HWND hWndOwner, IN LPCTSTR lpOperation) + { + WCHAR szDir[MAX_PATH]; + + if (SHGetSpecialFolderPath(hWndOwner, + szDir, + CSIDL_COMMON_STARTMENU, + FALSE)) + { + ShellExecute(hWndOwner, + lpOperation, + NULL, + NULL, + szDir, + SW_SHOWNORMAL); + } + } + + VOID OpenTaskManager(IN HWND hWndOwner) + { + ShellExecute(hWndOwner, + TEXT("open"), + TEXT("taskmgr.exe"), + NULL, + NULL, + SW_SHOWNORMAL); + } + + BOOL STDMETHODCALLTYPE ExecContextMenuCmd(IN UINT uiCmd) + { + BOOL bHandled = TRUE; + + switch (uiCmd) + { + case ID_SHELL_CMD_PROPERTIES: + DisplayProperties(); + break; + + case ID_SHELL_CMD_OPEN_ALL_USERS: + OpenCommonStartMenuDirectory(m_hWnd, + TEXT("open")); + break; + + case ID_SHELL_CMD_EXPLORE_ALL_USERS: + OpenCommonStartMenuDirectory(m_hWnd, + TEXT("explore")); + break; + + case ID_LOCKTASKBAR: + if (SHRestricted(REST_CLASSICSHELL) == 0) + { + Lock(!Locked); + } + break; + + case ID_SHELL_CMD_OPEN_TASKMGR: + OpenTaskManager(m_hWnd); + break; + + case ID_SHELL_CMD_UNDO_ACTION: + break; + + case ID_SHELL_CMD_SHOW_DESKTOP: + break; + + case ID_SHELL_CMD_TILE_WND_H: + TileWindows(NULL, MDITILE_HORIZONTAL, NULL, 0, NULL); + break; + + case ID_SHELL_CMD_TILE_WND_V: + TileWindows(NULL, MDITILE_VERTICAL, NULL, 0, NULL); + break; + + case ID_SHELL_CMD_CASCADE_WND: + CascadeWindows(NULL, MDITILE_SKIPDISABLED, NULL, 0, NULL); + break; + + case ID_SHELL_CMD_CUST_NOTIF: + break; + + case ID_SHELL_CMD_ADJUST_DAT: + LaunchCPanel(NULL, TEXT("timedate.cpl")); + break; + + default: + TRACE("ITrayWindow::ExecContextMenuCmd(%u): Unhandled Command ID!\n", uiCmd); + bHandled = FALSE; + break; + } + + return bHandled; + } + + BOOL STDMETHODCALLTYPE Lock(IN BOOL bLock) + { + BOOL bPrevLock; + + bPrevLock = Locked; + if (Locked != bLock) + { + Locked = bLock; + + if (TrayBandSite != NULL) + { + if (!SUCCEEDED(TrayBandSite->Lock( + bLock))) + { + /* Reset?? */ + Locked = bPrevLock; + } + } + } + + return bPrevLock; + } + + + LRESULT DrawBackground(HDC hdc) + { + RECT rect; + int partId; + + GetClientRect(&rect); + + if (TaskbarTheme) + { + GetClientRect(&rect); + switch (Position) + { + case ABE_LEFT: + partId = TBP_BACKGROUNDLEFT; + break; + case ABE_TOP: + partId = TBP_BACKGROUNDTOP; + break; + case ABE_RIGHT: + partId = TBP_BACKGROUNDRIGHT; + break; + case ABE_BOTTOM: + default: + partId = TBP_BACKGROUNDBOTTOM; + break; + } + + if (IsThemeBackgroundPartiallyTransparent(TaskbarTheme, partId, 0)) + { + DrawThemeParentBackground(m_hWnd, hdc, &rect); + } + + DrawThemeBackground(TaskbarTheme, hdc, partId, 0, &rect, 0); + } + + return TRUE; + } + + LRESULT OnEraseBackground(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + HDC hdc = (HDC) wParam; + + if (!TaskbarTheme) + { + bHandled = FALSE; + return 0; + } + + return DrawBackground(hdc); + } + + int DrawSizer(IN HRGN hRgn) + { + HDC hdc; + RECT rect; + int backoundPart; + + GetWindowRect(m_hWnd, &rect); + OffsetRect(&rect, -rect.left, -rect.top); + + hdc = GetDCEx(m_hWnd, hRgn, DCX_WINDOW | DCX_INTERSECTRGN | DCX_PARENTCLIP); + + switch (Position) + { + case ABE_LEFT: + backoundPart = TBP_SIZINGBARLEFT; + rect.left = rect.right - GetSystemMetrics(SM_CXSIZEFRAME); + break; + case ABE_TOP: + backoundPart = TBP_SIZINGBARTOP; + rect.top = rect.bottom - GetSystemMetrics(SM_CYSIZEFRAME); + break; + case ABE_RIGHT: + backoundPart = TBP_SIZINGBARRIGHT; + rect.right = rect.left + GetSystemMetrics(SM_CXSIZEFRAME); + break; + case ABE_BOTTOM: + default: + backoundPart = TBP_SIZINGBARBOTTOM; + rect.bottom = rect.top + GetSystemMetrics(SM_CYSIZEFRAME); + break; + } + + DrawThemeBackground(TaskbarTheme, hdc, backoundPart, 0, &rect, 0); + + ReleaseDC(m_hWnd, hdc); + return 0; + } + + DWORD WINAPI RunFileDlgThread() + { + HINSTANCE hShell32; + RUNFILEDLG RunFileDlg; + HWND hwnd; + RECT posRect; + + GetWindowRect(hwndStart, &posRect); + + hwnd = CreateWindowEx(0, + WC_STATIC, + NULL, + WS_OVERLAPPED | WS_DISABLED | WS_CLIPSIBLINGS | WS_BORDER | SS_LEFT, + posRect.left, + posRect.top, + posRect.right - posRect.left, + posRect.bottom - posRect.top, + NULL, + NULL, + NULL, + NULL); + + hwndRunFileDlgOwner = hwnd; + + hShell32 = GetModuleHandle(TEXT("SHELL32.DLL")); + RunFileDlg = (RUNFILEDLG) GetProcAddress(hShell32, (LPCSTR) 61); + + RunFileDlg(hwnd, NULL, NULL, NULL, NULL, RFF_CALCDIRECTORY); + + hwndRunFileDlgOwner = NULL; + ::DestroyWindow(hwnd); + + return 0; + } + + static DWORD WINAPI s_RunFileDlgThread(IN OUT PVOID pParam) + { + ITrayWindowImpl * This = (ITrayWindowImpl*) pParam; + return This->RunFileDlgThread(); + } + + void DisplayRunFileDlg() + { + HWND hRunDlg; + if (hwndRunFileDlgOwner) + { + hRunDlg = GetLastActivePopup(hwndRunFileDlgOwner); + if (hRunDlg != NULL && + hRunDlg != hwndRunFileDlgOwner) + { + SetForegroundWindow(hRunDlg); + return; + } + } + + CloseHandle(CreateThread(NULL, 0, s_RunFileDlgThread, this, 0, NULL)); + } + + void PopupStartMenu() + { + if (StartMenuPopup != NULL) + { + POINTL pt; + RECTL rcExclude; + DWORD dwFlags = 0; + + if (GetWindowRect(hwndStart, + (RECT*) &rcExclude)) + { + switch (Position) + { + case ABE_BOTTOM: + pt.x = rcExclude.left; + pt.y = rcExclude.top; + dwFlags |= MPPF_BOTTOM; + break; + case ABE_TOP: + case ABE_LEFT: + pt.x = rcExclude.left; + pt.y = rcExclude.bottom; + dwFlags |= MPPF_TOP | MPPF_ALIGN_RIGHT; + break; + case ABE_RIGHT: + pt.x = rcExclude.right; + pt.y = rcExclude.bottom; + dwFlags |= MPPF_TOP | MPPF_ALIGN_LEFT; + break; + } + + StartMenuPopup->Popup( + &pt, + &rcExclude, + dwFlags); + + SendMessageW(hwndStart, BM_SETSTATE, TRUE, 0); + } + } + } + + void ProcessMouseTracking() + { + RECT rcCurrent; + POINT pt; + BOOL over; + UINT state = AutoHideState; + + GetCursorPos(&pt); + GetWindowRect(m_hWnd, &rcCurrent); + over = PtInRect(&rcCurrent, pt); + + if (SendMessage(hwndStart, BM_GETSTATE, 0, 0) != BST_UNCHECKED) + { + over = TRUE; + } + + if (over) + { + if (state == AUTOHIDE_HIDING) + { + TRACE("AutoHide cancelling hide.\n"); + AutoHideState = AUTOHIDE_SHOWING; + SetTimer(TIMER_ID_AUTOHIDE, AUTOHIDE_INTERVAL_ANIMATING, NULL); + } + else if (state == AUTOHIDE_HIDDEN) + { + TRACE("AutoHide starting show.\n"); + AutoHideState = AUTOHIDE_SHOWING; + SetTimer(TIMER_ID_AUTOHIDE, AUTOHIDE_DELAY_SHOW, NULL); + } + } + else + { + if (state == AUTOHIDE_SHOWING) + { + TRACE("AutoHide cancelling show.\n"); + AutoHideState = AUTOHIDE_HIDING; + SetTimer(TIMER_ID_AUTOHIDE, AUTOHIDE_INTERVAL_ANIMATING, NULL); + } + else if (state == AUTOHIDE_SHOWN) + { + TRACE("AutoHide starting hide.\n"); + AutoHideState = AUTOHIDE_HIDING; + SetTimer(TIMER_ID_AUTOHIDE, AUTOHIDE_DELAY_HIDE, NULL); + } + + KillTimer(TIMER_ID_MOUSETRACK); + } + } + + void ProcessAutoHide() + { + RECT rc = rcTrayWnd[Position]; + INT w = TraySize.cx - GetSystemMetrics(SM_CXBORDER) * 2 - 1; + INT h = TraySize.cy - GetSystemMetrics(SM_CYBORDER) * 2 - 1; + + TRACE("AutoHide Timer received for %u, rc=(%d, %d, %d, %d), w=%d, h=%d.\n", AutoHideState, rc.left, rc.top, rc.right, rc.bottom, w, h); + + switch (AutoHideState) + { + case AUTOHIDE_HIDING: + switch (Position) + { + case ABE_LEFT: + AutoHideOffset.cy = 0; + AutoHideOffset.cx -= AUTOHIDE_SPEED_HIDE; + if (AutoHideOffset.cx < -w) + AutoHideOffset.cx = -w; + break; + case ABE_TOP: + AutoHideOffset.cx = 0; + AutoHideOffset.cy -= AUTOHIDE_SPEED_HIDE; + if (AutoHideOffset.cy < -h) + AutoHideOffset.cy = -h; + break; + case ABE_RIGHT: + AutoHideOffset.cy = 0; + AutoHideOffset.cx += AUTOHIDE_SPEED_HIDE; + if (AutoHideOffset.cx > w) + AutoHideOffset.cx = w; + break; + case ABE_BOTTOM: + AutoHideOffset.cx = 0; + AutoHideOffset.cy += AUTOHIDE_SPEED_HIDE; + if (AutoHideOffset.cy > h) + AutoHideOffset.cy = h; + break; + } + + if (AutoHideOffset.cx != w && AutoHideOffset.cy != h) + { + SetTimer(TIMER_ID_AUTOHIDE, AUTOHIDE_INTERVAL_ANIMATING, NULL); + break; + } + + /* fallthrough */ + case AUTOHIDE_HIDDEN: + + switch (Position) + { + case ABE_LEFT: + AutoHideOffset.cx = -w; + AutoHideOffset.cy = 0; + break; + case ABE_TOP: + AutoHideOffset.cx = 0; + AutoHideOffset.cy = -h; + break; + case ABE_RIGHT: + AutoHideOffset.cx = w; + AutoHideOffset.cy = 0; + break; + case ABE_BOTTOM: + AutoHideOffset.cx = 0; + AutoHideOffset.cy = h; + break; + } + + KillTimer(TIMER_ID_AUTOHIDE); + AutoHideState = AUTOHIDE_HIDDEN; + break; + + case AUTOHIDE_SHOWING: + if (AutoHideOffset.cx >= AUTOHIDE_SPEED_SHOW) + { + AutoHideOffset.cx -= AUTOHIDE_SPEED_SHOW; + } + else if (AutoHideOffset.cx <= -AUTOHIDE_SPEED_SHOW) + { + AutoHideOffset.cx += AUTOHIDE_SPEED_SHOW; + } + else + { + AutoHideOffset.cx = 0; + } + + if (AutoHideOffset.cy >= AUTOHIDE_SPEED_SHOW) + { + AutoHideOffset.cy -= AUTOHIDE_SPEED_SHOW; + } + else if (AutoHideOffset.cy <= -AUTOHIDE_SPEED_SHOW) + { + AutoHideOffset.cy += AUTOHIDE_SPEED_SHOW; + } + else + { + AutoHideOffset.cy = 0; + } + + if (AutoHideOffset.cx != 0 || AutoHideOffset.cy != 0) + { + SetTimer(TIMER_ID_AUTOHIDE, AUTOHIDE_INTERVAL_ANIMATING, NULL); + break; + } + + /* fallthrough */ + case AUTOHIDE_SHOWN: + + KillTimer(TIMER_ID_AUTOHIDE); + AutoHideState = AUTOHIDE_SHOWN; + break; + } + + rc.left += AutoHideOffset.cx; + rc.right += AutoHideOffset.cx; + rc.top += AutoHideOffset.cy; + rc.bottom += AutoHideOffset.cy; + + TRACE("AutoHide Changing position to (%d, %d, %d, %d) and state=%u.\n", rc.left, rc.top, rc.right, rc.bottom, AutoHideState); + SetWindowPos(NULL, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, SWP_NOACTIVATE | SWP_NOZORDER); + } + + LRESULT OnDisplayChange(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + /* Load the saved tray window settings */ + RegLoadSettings(); + + /* Move the tray window to the right position and resize it if neccessary */ + CheckTrayWndPosition(); + + /* Align all controls on the tray window */ + AlignControls(NULL); + + return TRUE; + } + + LRESULT OnCopyData(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + if (hwndTrayNotify) + { + TrayNotify_NotifyMsg(wParam, lParam); + } + return TRUE; + } + + LRESULT OnNcPaint(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + if (!TaskbarTheme) + { + bHandled = FALSE; + return 0; + } + + return DrawSizer((HRGN) wParam); + } + + LRESULT OnCtlColorBtn(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + SetBkMode((HDC) wParam, TRANSPARENT); + return (LRESULT) GetStockObject(HOLLOW_BRUSH); + } + + LRESULT OnNcHitTest(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + RECT rcClient; + POINT pt; + + if (Locked) + { + /* The user may not be able to resize the tray window. + Pretend like the window is not sizeable when the user + clicks on the border. */ + return HTBORDER; + } + + SetLastError(ERROR_SUCCESS); + if (GetClientRect(&rcClient) && + (MapWindowPoints(m_hWnd, NULL, (LPPOINT) &rcClient, 2) != 0 || GetLastError() == ERROR_SUCCESS)) + { + pt.x = (SHORT) LOWORD(lParam); + pt.y = (SHORT) HIWORD(lParam); + + if (PtInRect(&rcClient, + pt)) + { + /* The user is trying to drag the tray window */ + return HTCAPTION; + } + + /* Depending on the position of the tray window, allow only + changing the border next to the monitor working area */ + switch (Position) + { + case ABE_TOP: + if (pt.y > rcClient.bottom) + return HTBOTTOM; + break; + case ABE_LEFT: + if (pt.x > rcClient.right) + return HTRIGHT; + break; + case ABE_RIGHT: + if (pt.x < rcClient.left) + return HTLEFT; + break; + case ABE_BOTTOM: + default: + if (pt.y < rcClient.top) + return HTTOP; + break; + } + } + return HTBORDER; + return TRUE; + } + + LRESULT OnMoving(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + POINT ptCursor; + PRECT pRect = (PRECT) lParam; + + /* We need to ensure that an application can not accidently + move the tray window (using SetWindowPos). However, we still + need to be able to move the window in case the user wants to + drag the tray window to another position or in case the user + wants to resize the tray window. */ + if (!Locked && GetCursorPos(&ptCursor)) + { + IsDragging = TRUE; + DraggingPosition = GetDraggingRectFromPt( + ptCursor, + pRect, + &DraggingMonitor); + } + else + { + *pRect = rcTrayWnd[Position]; + + if (AutoHide) + { + pRect->left += AutoHideOffset.cx; + pRect->right += AutoHideOffset.cx; + pRect->top += AutoHideOffset.cy; + pRect->bottom += AutoHideOffset.cy; + } + } + return TRUE; + } + + LRESULT OnSizing(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + PRECT pRect = (PRECT) lParam; + + if (!Locked) + { + CalculateValidSize(Position, pRect); + } + else + { + *pRect = rcTrayWnd[Position]; + + if (AutoHide) + { + pRect->left += AutoHideOffset.cx; + pRect->right += AutoHideOffset.cx; + pRect->top += AutoHideOffset.cy; + pRect->bottom += AutoHideOffset.cy; + } + } + return TRUE; + } + + LRESULT OnWindowPosChange(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + ChangingWinPos((LPWINDOWPOS) lParam); + return TRUE; + } + + LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + RECT rcClient; + InvalidateRect(NULL, TRUE); + if (wParam == SIZE_RESTORED && lParam == 0) + { + ResizeWorkArea(); + /* Clip the tray window on multi monitor systems so the edges can't + overlap into another monitor */ + ApplyClipping(TRUE); + + if (!GetClientRect(&rcClient)) + { + return FALSE; + } + } + else + { + rcClient.left = rcClient.top = 0; + rcClient.right = LOWORD(lParam); + rcClient.bottom = HIWORD(lParam); + } + + AlignControls(&rcClient); + return TRUE; + } + + LRESULT OnEnterSizeMove(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + InSizeMove = TRUE; + IsDragging = FALSE; + if (!Locked) + { + /* Remove the clipping on multi monitor systems while dragging around */ + ApplyClipping(FALSE); + } + return TRUE; + } + + LRESULT OnExitSizeMove(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + InSizeMove = FALSE; + if (!Locked) + { + /* Apply clipping */ + PostMessage(m_hWnd, WM_SIZE, SIZE_RESTORED, 0); + } + return TRUE; + } + + LRESULT OnSysChar(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + switch (wParam) + { + case TEXT(' '): + { + /* The user pressed Alt+Space, this usually brings up the system menu of a window. + The tray window needs to handle this specially, since it normally doesn't have + a system menu. */ + + static const UINT uidDisableItem [] = { + SC_RESTORE, + SC_MOVE, + SC_SIZE, + SC_MAXIMIZE, + SC_MINIMIZE, + }; + HMENU hSysMenu; + INT i; + UINT uId; + + /* temporarily enable the system menu */ + SetWindowStyle(m_hWnd, WS_SYSMENU, WS_SYSMENU); + + hSysMenu = GetSystemMenu(m_hWnd, FALSE); + if (hSysMenu != NULL) + { + /* Disable all items that are not relevant */ + for (i = 0; i != sizeof(uidDisableItem) / sizeof(uidDisableItem[0]); i++) + { + EnableMenuItem(hSysMenu, + uidDisableItem[i], + MF_BYCOMMAND | MF_GRAYED); + } + + EnableMenuItem(hSysMenu, + SC_CLOSE, + MF_BYCOMMAND | + (SHRestricted(REST_NOCLOSE) ? MF_GRAYED : MF_ENABLED)); + + /* Display the system menu */ + uId = TrackMenu( + hSysMenu, + NULL, + hwndStart, + Position != ABE_TOP, + FALSE); + if (uId != 0) + { + SendMessage(m_hWnd, + WM_SYSCOMMAND, + (WPARAM) uId, + 0); + } + } + + /* revert the system menu window style */ + SetWindowStyle(m_hWnd, WS_SYSMENU, 0); + break; + } + + default: + bHandled = FALSE; + } + return TRUE; + } + + LRESULT OnNcRButtonUp(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + /* We want the user to be able to get a context menu even on the nonclient + area (including the sizing border)! */ + uMsg = WM_CONTEXTMENU; + wParam = (WPARAM) m_hWnd; + + return OnContextMenu(uMsg, wParam, lParam, bHandled); + } + + LRESULT OnContextMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + LRESULT Ret = FALSE; + POINT pt, *ppt = NULL; + HWND hWndExclude = NULL; + + /* Check if the administrator has forbidden access to context menus */ + if (SHRestricted(REST_NOTRAYCONTEXTMENU)) + return FALSE; + + pt.x = (SHORT) LOWORD(lParam); + pt.y = (SHORT) HIWORD(lParam); + + if (pt.x != -1 || pt.y != -1) + ppt = &pt; + else + hWndExclude = hwndStart; + + if ((HWND) wParam == hwndStart) + { + /* Make sure we can't track the context menu if the start + menu is currently being shown */ + if (!(SendMessage(hwndStart, + BM_GETSTATE, + 0, + 0) & BST_PUSHED)) + { + TrackCtxMenu( + &StartMenuBtnCtxMenu, + ppt, + hWndExclude, + Position == ABE_BOTTOM, + this); + } + } + else + { + /* See if the context menu should be handled by the task band site */ + if (ppt != NULL && TrayBandSite != NULL) + { + HWND hWndAtPt; + POINT ptClient = *ppt; + + /* Convert the coordinates to client-coordinates */ + MapWindowPoints(NULL, + m_hWnd, + &ptClient, + 1); + + hWndAtPt = ChildWindowFromPoint(m_hWnd, + ptClient); + if (hWndAtPt != NULL && + (hWndAtPt == hwndRebar || IsChild(hwndRebar, + hWndAtPt))) + { + /* Check if the user clicked on the task switch window */ + ptClient = *ppt; + MapWindowPoints(NULL, + hwndRebar, + &ptClient, + 1); + + hWndAtPt = ChildWindowFromPointEx(hwndRebar, + ptClient, + CWP_SKIPINVISIBLE | CWP_SKIPDISABLED); + if (hWndAtPt == hwndTaskSwitch) + goto HandleTrayContextMenu; + + /* Forward the message to the task band site */ + TrayBandSite->ProcessMessage(m_hWnd, uMsg, wParam, lParam, &Ret); + } + else + goto HandleTrayContextMenu; + } + else + { +HandleTrayContextMenu: + /* Tray the default tray window context menu */ + TrackCtxMenu( + &TrayWindowCtxMenu, + ppt, + NULL, + FALSE, + this); + } + } + return Ret; + } + + LRESULT OnNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + LRESULT Ret = FALSE; + /* FIXME: We can't check with IsChild whether the hwnd is somewhere inside + the rebar control! But we shouldn't forward messages that the band + site doesn't handle, such as other controls (start button, tray window */ + + HRESULT hr = E_FAIL; + + if (TrayBandSite) + { + hr = TrayBandSite->ProcessMessage(m_hWnd, uMsg, wParam, lParam, &Ret); + if (SUCCEEDED(hr)) + return Ret; + } + + if (TrayBandSite == NULL || FAILED_UNEXPECTEDLY(hr)) + { + const NMHDR *nmh = (const NMHDR *) lParam; + + if (nmh->hwndFrom == hwndTrayNotify) + { + switch (nmh->code) + { + case NTNWM_REALIGN: + /* Cause all controls to be aligned */ + PostMessage(m_hWnd, WM_SIZE, SIZE_RESTORED, 0); + break; + } + } + } + return Ret; + } + + LRESULT OnNcLButtonDblClick(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + /* We "handle" this message so users can't cause a weird maximize/restore + window animation when double-clicking the tray window! */ + + /* We should forward mouse messages to child windows here. + Right now, this is only clock double-click */ + RECT rcClock; + if (TrayNotify_GetClockRect(&rcClock)) + { + POINT ptClick; + ptClick.x = MAKEPOINTS(lParam).x; + ptClick.y = MAKEPOINTS(lParam).y; + if (PtInRect(&rcClock, ptClick)) + LaunchCPanel(NULL, TEXT("timedate.cpl")); + } + return TRUE; + } + + LRESULT OnAppTrayDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + DestroyWindow(); + return TRUE; + } + + LRESULT OnOpenStartMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + HWND hwndStartMenu; + HRESULT hr = IUnknown_GetWindow((IUnknown*) StartMenuPopup, &hwndStartMenu); + if (FAILED_UNEXPECTEDLY(hr)) + return FALSE; + + if (IsWindowVisible(hwndStartMenu)) + { + StartMenuPopup->OnSelect(MPOS_CANCELLEVEL); + } + else + { + SendMessage(m_hWnd, WM_COMMAND, MAKEWPARAM(BN_CLICKED, IDC_STARTBTN), reinterpret_cast(hwndStart)); + } + + return TRUE; + } + + LRESULT OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + LRESULT Ret = FALSE; + + if ((HWND) lParam == hwndStart) + { + PopupStartMenu(); + return FALSE; + } + + if (TrayBandSite == NULL || FAILED_UNEXPECTEDLY(TrayBandSite->ProcessMessage(m_hWnd, uMsg, wParam, lParam, &Ret))) + { + switch (LOWORD(wParam)) + { + /* FIXME: Handle these commands as well */ + case IDM_TASKBARANDSTARTMENU: + + DisplayProperties(); + break; + + case IDM_SEARCH: + break; + + case IDM_HELPANDSUPPORT: + { + /* TODO: Implement properly */ + + LPCWSTR strSite = L"https://www.reactos.org/"; + + /* TODO: Make localizable */ + LPCWSTR strCaption = L"Sorry"; + LPCWSTR strMessage = L"ReactOS could not browse to '%s' (error %d). Please make sure there is a web browser installed."; + WCHAR tmpMessage[512]; + + /* TODO: Read from the registry */ + LPCWSTR strVerb = NULL; /* default */ + LPCWSTR strPath = strSite; + LPCWSTR strParams = NULL; + + /* The return value is defined as HINSTANCE for backwards compatibility only, the cast is needed */ + int result = (int) ShellExecuteW(m_hWnd, strVerb, strPath, strParams, NULL, SW_SHOWNORMAL); + if (result <= 32) + { + StringCchPrintfW(tmpMessage, 512, strMessage, strSite, result); + MessageBoxExW(m_hWnd, tmpMessage, strCaption, MB_OK, 0); + } + break; + } + + case IDM_RUN: + { + DisplayRunFileDlg(); + break; + } + + /* FIXME: Handle these commands as well */ + case IDM_SYNCHRONIZE: + case IDM_LOGOFF: + case IDM_DISCONNECT: + case IDM_UNDOCKCOMPUTER: + break; + + case IDM_SHUTDOWN: + { + HINSTANCE hShell32; + EXITWINDLG ExitWinDlg; + + hShell32 = GetModuleHandle(TEXT("SHELL32.DLL")); + ExitWinDlg = (EXITWINDLG) GetProcAddress(hShell32, (LPCSTR) 60); + + ExitWinDlg(m_hWnd); + break; + } + } + } + return Ret; + } + + LRESULT OnMouseMove(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + if (AutoHide) + { + SetTimer(TIMER_ID_MOUSETRACK, MOUSETRACK_INTERVAL, NULL); + } + + return TRUE; + } + + LRESULT OnTimer(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + if (wParam == TIMER_ID_MOUSETRACK) + { + ProcessMouseTracking(); + } + else if (wParam == TIMER_ID_AUTOHIDE) + { + ProcessAutoHide(); + } + + bHandled = FALSE; + return TRUE; + } + + LRESULT OnRebarAutoSize(INT code, LPNMHDR nmhdr, BOOL& bHandled) + { +#if 0 + LPNMRBAUTOSIZE as = (LPNMRBAUTOSIZE) nmhdr; + + if (!as->fChanged) + return 0; + + RECT rc; + ::GetWindowRect(m_hWnd, &rc); + + SIZE szWindow = { + rc.right - rc.left, + rc.bottom - rc.top }; + SIZE szTarget = { + as->rcTarget.right - as->rcTarget.left, + as->rcTarget.bottom - as->rcTarget.top }; + SIZE szActual = { + as->rcActual.right - as->rcActual.left, + as->rcActual.bottom - as->rcActual.top }; + + SIZE borders = { + szWindow.cx - szTarget.cx, + szWindow.cy - szTarget.cx, + }; + + switch (Position) + { + case ABE_LEFT: + szWindow.cx = szActual.cx + borders.cx; + break; + case ABE_TOP: + szWindow.cy = szActual.cy + borders.cy; + break; + case ABE_RIGHT: + szWindow.cx = szActual.cx + borders.cx; + rc.left = rc.right - szWindow.cy; + break; + case ABE_BOTTOM: + szWindow.cy = szActual.cy + borders.cy; + rc.top = rc.bottom - szWindow.cy; + break; + } + + SetWindowPos(NULL, rc.left, rc.top, szWindow.cx, szWindow.cy, SWP_NOACTIVATE | SWP_NOZORDER); +#else + bHandled = FALSE; +#endif + return 0; + } + + DECLARE_WND_CLASS_EX(szTrayWndClass, CS_DBLCLKS, COLOR_3DFACE) + + BEGIN_MSG_MAP(ITrayWindowImpl) + if (StartMenuBand != NULL) + { + MSG Msg; + LRESULT lRet; + + Msg.hwnd = m_hWnd; + Msg.message = uMsg; + Msg.wParam = wParam; + Msg.lParam = lParam; + + if (StartMenuBand->TranslateMenuMessage( + &Msg, + &lRet) == S_OK) + { + return lRet; + } + + wParam = Msg.wParam; + lParam = Msg.lParam; + } + MESSAGE_HANDLER(WM_THEMECHANGED, OnThemeChanged) + NOTIFY_CODE_HANDLER(RBN_AUTOSIZE, OnRebarAutoSize) // Doesn't quite work ;P + MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground) + MESSAGE_HANDLER(WM_SIZE, OnSize) + MESSAGE_HANDLER(WM_CREATE, OnCreate) + /*MESSAGE_HANDLER(WM_DESTROY, OnDestroy)*/ + MESSAGE_HANDLER(WM_NCHITTEST, OnNcHitTest) + MESSAGE_HANDLER(WM_COMMAND, OnCommand) + MESSAGE_HANDLER(WM_NOTIFY, OnNotify) + MESSAGE_HANDLER(WM_CONTEXTMENU, OnContextMenu) + MESSAGE_HANDLER(WM_TIMER, OnTimer) + MESSAGE_HANDLER(WM_DISPLAYCHANGE, OnDisplayChange) + MESSAGE_HANDLER(WM_COPYDATA, OnCopyData) + MESSAGE_HANDLER(WM_NCPAINT, OnNcPaint) + MESSAGE_HANDLER(WM_CTLCOLORBTN, OnCtlColorBtn) + MESSAGE_HANDLER(WM_MOVING, OnMoving) + MESSAGE_HANDLER(WM_SIZING, OnSizing) + MESSAGE_HANDLER(WM_WINDOWPOSCHANGING, OnWindowPosChange) + MESSAGE_HANDLER(WM_ENTERSIZEMOVE, OnEnterSizeMove) + MESSAGE_HANDLER(WM_EXITSIZEMOVE, OnExitSizeMove) + MESSAGE_HANDLER(WM_SYSCHAR, OnSysChar) + MESSAGE_HANDLER(WM_NCRBUTTONUP, OnNcRButtonUp) + MESSAGE_HANDLER(WM_NCLBUTTONDBLCLK, OnNcLButtonDblClick) + MESSAGE_HANDLER(WM_MOUSEMOVE, OnMouseMove) + MESSAGE_HANDLER(WM_NCMOUSEMOVE, OnMouseMove) + MESSAGE_HANDLER(WM_APP_TRAYDESTROY, OnAppTrayDestroy) + MESSAGE_HANDLER(TWM_OPENSTARTMENU, OnOpenStartMenu) + END_MSG_MAP() + + /* + * Tray Window Context Menu + */ + + static HMENU CreateTrayWindowContextMenu(IN HWND hWndOwner, + IN PVOID *ppcmContext, + IN PVOID Context OPTIONAL) + { + ITrayWindowImpl *This = (ITrayWindowImpl *) Context; + IContextMenu *pcm = NULL; + HMENU hPopup; + + hPopup = LoadPopupMenu(hExplorerInstance, + MAKEINTRESOURCE(IDM_TRAYWND)); + + if (hPopup != NULL) + { + if (SHRestricted(REST_CLASSICSHELL) != 0) + { + DeleteMenu(hPopup, + ID_LOCKTASKBAR, + MF_BYCOMMAND); + } + + CheckMenuItem(hPopup, + ID_LOCKTASKBAR, + MF_BYCOMMAND | (This->Locked ? MF_CHECKED : MF_UNCHECKED)); + + if (This->TrayBandSite != NULL) + { + if (SUCCEEDED(This->TrayBandSite->AddContextMenus( + hPopup, + 0, + ID_SHELL_CMD_FIRST, + ID_SHELL_CMD_LAST, + CMF_NORMAL, + &pcm))) + { + TRACE("ITrayBandSite::AddContextMenus succeeded!\n"); + *(IContextMenu **) ppcmContext = pcm; + } + } + } + + return hPopup; + } + + static VOID OnTrayWindowContextMenuCommand(IN HWND hWndOwner, + IN UINT uiCmdId, + IN PVOID pcmContext OPTIONAL, + IN PVOID Context OPTIONAL) + { + ITrayWindowImpl *This = (ITrayWindowImpl *) Context; + IContextMenu *pcm = (IContextMenu *) pcmContext; + + if (uiCmdId != 0) + { + if (uiCmdId >= ID_SHELL_CMD_FIRST && uiCmdId <= ID_SHELL_CMD_LAST) + { + CMINVOKECOMMANDINFO cmici = { 0 }; + + if (pcm != NULL) + { + /* Setup and invoke the shell command */ + cmici.cbSize = sizeof(cmici); + cmici.hwnd = hWndOwner; + cmici.lpVerb = (LPCSTR) MAKEINTRESOURCE(uiCmdId - ID_SHELL_CMD_FIRST); + cmici.nShow = SW_NORMAL; + + pcm->InvokeCommand( + &cmici); + } + } + else + { + This->ExecContextMenuCmd(uiCmdId); + } + } + + if (pcm != NULL) + pcm->Release(); + } + + /*****************************************************************************/ + + VOID TrayProcessMessages() + { + MSG Msg; + + /* FIXME: We should keep a reference here... */ + + while (PeekMessage(&Msg, + NULL, + 0, + 0, + PM_REMOVE)) + { + if (Msg.message == WM_QUIT) + break; + + if (StartMenuBand == NULL || + StartMenuBand->IsMenuMessage( + &Msg) != S_OK) + { + TranslateMessage(&Msg); + DispatchMessage(&Msg); + } + } + } + + VOID TrayMessageLoop() + { + MSG Msg; + BOOL Ret; + + /* FIXME: We should keep a reference here... */ + + while (1) + { + Ret = GetMessage(&Msg, + NULL, + 0, + 0); + + if (!Ret || Ret == -1) + break; + + if (Msg.message == WM_HOTKEY) + { + switch (Msg.wParam) + { + case IDHK_RUN: /* Win+R */ + DisplayRunFileDlg(); + break; + } + } + + if (StartMenuBand == NULL || + StartMenuBand->IsMenuMessage(&Msg) != S_OK) + { + TranslateMessage(&Msg); + DispatchMessage(&Msg); + } + } + } + + /* + * IShellDesktopTray + * + * NOTE: this is a very windows-specific COM interface used by SHCreateDesktop()! + * These are the calls I observed, it may be wrong/incomplete/buggy!!! + * The reason we implement it is because we have to use SHCreateDesktop() so + * that the shell provides the desktop window and all the features that come + * with it (especially positioning of desktop icons) + */ + + virtual ULONG STDMETHODCALLTYPE GetState() + { + /* FIXME: Return ABS_ flags? */ + TRACE("IShellDesktopTray::GetState() unimplemented!\n"); + return 0; + } + + virtual HRESULT STDMETHODCALLTYPE GetTrayWindow(OUT HWND *phWndTray) + { + TRACE("IShellDesktopTray::GetTrayWindow(0x%p)\n", phWndTray); + *phWndTray = m_hWnd; + return S_OK; + } + + virtual HRESULT STDMETHODCALLTYPE RegisterDesktopWindow(IN HWND hWndDesktop) + { + TRACE("IShellDesktopTray::RegisterDesktopWindow(0x%p)\n", hWndDesktop); + + this->hWndDesktop = hWndDesktop; + return S_OK; + } + + virtual HRESULT STDMETHODCALLTYPE Unknown(IN DWORD dwUnknown1, IN DWORD dwUnknown2) + { + TRACE("IShellDesktopTray::Unknown(%u,%u) unimplemented!\n", dwUnknown1, dwUnknown2); + return S_OK; + } + + virtual HRESULT RaiseStartButton() + { + SendMessageW(hwndStart, BM_SETSTATE, FALSE, 0); + return S_OK; + } + + void _Init() + { + Position = (DWORD) -1; + } + + DECLARE_NOT_AGGREGATABLE(ITrayWindowImpl) + + DECLARE_PROTECT_FINAL_CONSTRUCT() + BEGIN_COM_MAP(ITrayWindowImpl) + /*COM_INTERFACE_ENTRY_IID(IID_ITrayWindow, ITrayWindow)*/ + COM_INTERFACE_ENTRY_IID(IID_IShellDesktopTray, IShellDesktopTray) + END_COM_MAP() +}; + +const TRAYWINDOW_CTXMENU TrayWindowCtxMenu = { + ITrayWindowImpl::CreateTrayWindowContextMenu, + ITrayWindowImpl::OnTrayWindowContextMenuCommand +}; + +ITrayWindowImpl * g_TrayWindow; + +HRESULT +Tray_OnStartMenuDismissed() +{ + return g_TrayWindow->RaiseStartButton(); +} + + +HRESULT CreateTrayWindow(ITrayWindow ** ppTray) +{ + CComPtr Tray = new CComObject(); + if (Tray == NULL) + return E_OUTOFMEMORY; + + Tray->_Init(); + Tray->Open(); + g_TrayWindow = Tray; + + *ppTray = (ITrayWindow *) Tray; + + return S_OK; +} + +VOID TrayProcessMessages(ITrayWindow *) +{ + g_TrayWindow->TrayProcessMessages(); +} + +VOID TrayMessageLoop(ITrayWindow *) +{ + g_TrayWindow->TrayMessageLoop(); +} diff --git a/base/shell/explorer-new/util.cpp b/base/shell/explorer-new/util.cpp new file mode 100644 index 00000000000..6bdea90833c --- /dev/null +++ b/base/shell/explorer-new/util.cpp @@ -0,0 +1,323 @@ +#include "precomp.h" +#include + +typedef struct _LANGCODEPAGE +{ + WORD wLanguage; + WORD wCodePage; +} LANGCODEPAGE, *PLANGCODEPAGE; + +HRESULT +IsSameObject(IN IUnknown *punk1, IN IUnknown *punk2) +{ + HRESULT hRet; + + hRet = punk1->QueryInterface(IID_PPV_ARG(IUnknown, &punk1)); + + if (!SUCCEEDED(hRet)) + return hRet; + + hRet = punk2->QueryInterface(IID_PPV_ARG(IUnknown, &punk2)); + + punk1->Release(); + + if (!SUCCEEDED(hRet)) + return hRet; + + punk2->Release(); + + /* We're dealing with the same object if the IUnknown pointers are equal */ + return (punk1 == punk2) ? S_OK : S_FALSE; +} + +LONG +SetWindowStyle(IN HWND hWnd, + IN LONG dwStyleMask, + IN LONG dwStyle) +{ + LONG PrevStyle, Style; + + ASSERT((~dwStyleMask & dwStyle) == 0); + + PrevStyle = GetWindowLong(hWnd, GWL_STYLE); + if (PrevStyle != 0 && + (PrevStyle & dwStyleMask) != dwStyle) + { + Style = PrevStyle & ~dwStyleMask; + Style |= dwStyle; + + PrevStyle = SetWindowLong(hWnd, GWL_STYLE, Style); + } + + return PrevStyle; +} + +LONG +SetWindowExStyle(IN HWND hWnd, + IN LONG dwStyleMask, + IN LONG dwStyle) +{ + LONG PrevStyle, Style; + + ASSERT((~dwStyleMask & dwStyle) == 0); + + PrevStyle = GetWindowLong(hWnd, GWL_EXSTYLE); + if (PrevStyle != 0 && + (PrevStyle & dwStyleMask) != dwStyle) + { + Style = PrevStyle & ~dwStyleMask; + Style |= dwStyle; + + PrevStyle = SetWindowLong(hWnd, GWL_EXSTYLE, Style); + } + + return PrevStyle; +} + +HMENU +LoadPopupMenu(IN HINSTANCE hInstance, + IN LPCTSTR lpMenuName) +{ + HMENU hMenu, hSubMenu = NULL; + + hMenu = LoadMenu(hInstance, + lpMenuName); + + if (hMenu != NULL) + { + hSubMenu = GetSubMenu(hMenu, + 0); + if (hSubMenu != NULL && + !RemoveMenu(hMenu, + 0, + MF_BYPOSITION)) + { + hSubMenu = NULL; + } + + DestroyMenu(hMenu); + } + + return hSubMenu; +} + +HMENU +FindSubMenu(IN HMENU hMenu, + IN UINT uItem, + IN BOOL fByPosition) +{ + MENUITEMINFO mii; + + mii.cbSize = sizeof(mii); + mii.fMask = MIIM_SUBMENU; + + if (GetMenuItemInfo(hMenu, + uItem, + fByPosition, + &mii)) + { + return mii.hSubMenu; + } + + return NULL; +} + +BOOL +GetCurrentLoggedOnUserName(OUT LPTSTR szBuffer, + IN DWORD dwBufferSize) +{ + DWORD dwType; + DWORD dwSize; + + /* Query the user name from the registry */ + dwSize = (dwBufferSize * sizeof(WCHAR)) - 1; + if (RegQueryValueEx(hkExplorer, + TEXT("Logon User Name"), + 0, + &dwType, + (LPBYTE) szBuffer, + &dwSize) == ERROR_SUCCESS && + (dwSize / sizeof(WCHAR)) > 1 && + szBuffer[0] != _T('\0')) + { + szBuffer[dwSize / sizeof(WCHAR)] = _T('\0'); + return TRUE; + } + + /* Fall back to GetUserName() */ + dwSize = dwBufferSize; + if (!GetUserName(szBuffer, + &dwSize)) + { + szBuffer[0] = _T('\0'); + return FALSE; + } + + return TRUE; +} + +BOOL +FormatMenuString(IN HMENU hMenu, + IN UINT uPosition, + IN UINT uFlags, +...) +{ + va_list vl; + MENUITEMINFO mii; + WCHAR szBuf[128]; + WCHAR szBufFmt[128]; + + /* Find the menu item and read the formatting string */ + mii.cbSize = sizeof(mii); + mii.fMask = MIIM_STRING; + mii.dwTypeData = (LPTSTR) szBufFmt; + mii.cch = sizeof(szBufFmt) / sizeof(szBufFmt[0]); + if (GetMenuItemInfo(hMenu, + uPosition, + uFlags, + &mii)) + { + /* Format the string */ + va_start(vl, uFlags); + _vsntprintf(szBuf, + (sizeof(szBuf) / sizeof(szBuf[0])) - 1, + szBufFmt, + vl); + va_end(vl); + szBuf[(sizeof(szBuf) / sizeof(szBuf[0])) - 1] = _T('\0'); + + /* Update the menu item */ + mii.dwTypeData = (LPTSTR) szBuf; + if (SetMenuItemInfo(hMenu, + uPosition, + uFlags, + &mii)) + { + return TRUE; + } + } + + return FALSE; +} + +BOOL +GetExplorerRegValueSet(IN HKEY hKey, + IN LPCTSTR lpSubKey, + IN LPCTSTR lpValue) +{ + WCHAR szBuffer[MAX_PATH]; + HKEY hkSubKey; + DWORD dwType, dwSize; + BOOL Ret = FALSE; + + StringCbCopy(szBuffer, sizeof(szBuffer), + TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer")); + if (FAILED_UNEXPECTEDLY(StringCbCat(szBuffer, sizeof(szBuffer), + _T("\\")))) + return FALSE; + if (FAILED_UNEXPECTEDLY(StringCbCat(szBuffer, sizeof(szBuffer), + lpSubKey))) + return FALSE; + + dwSize = sizeof(szBuffer); + if (RegOpenKeyEx(hKey, + szBuffer, + 0, + KEY_QUERY_VALUE, + &hkSubKey) == ERROR_SUCCESS) + { + ZeroMemory(szBuffer, + sizeof(szBuffer)); + + if (RegQueryValueEx(hkSubKey, + lpValue, + 0, + &dwType, + (LPBYTE) szBuffer, + &dwSize) == ERROR_SUCCESS) + { + if (dwType == REG_DWORD && dwSize == sizeof(DWORD)) + Ret = *((PDWORD) szBuffer) != 0; + else if (dwSize > 0) + Ret = *((PCHAR) szBuffer) != 0; + } + + RegCloseKey(hkSubKey); + } + return Ret; +} + +BOOL +GetVersionInfoString(IN WCHAR *szFileName, +IN WCHAR *szVersionInfo, +OUT WCHAR *szBuffer, +IN UINT cbBufLen) +{ + LPVOID lpData = NULL; + WCHAR szSubBlock[128]; + WCHAR *lpszLocalBuf = NULL; + LANGID UserLangId; + PLANGCODEPAGE lpTranslate = NULL; + DWORD dwLen; + DWORD dwHandle; + UINT cbTranslate; + UINT cbLen; + BOOL bRet = FALSE; + unsigned int i; + + dwLen = GetFileVersionInfoSize(szFileName, &dwHandle); + + if (dwLen > 0) + { + lpData = HeapAlloc(hProcessHeap, 0, dwLen); + + if (lpData != NULL) + { + if (GetFileVersionInfo(szFileName, + 0, + dwLen, + lpData) != 0) + { + UserLangId = GetUserDefaultLangID(); + + VerQueryValue(lpData, + TEXT("\\VarFileInfo\\Translation"), + (LPVOID *) &lpTranslate, + &cbTranslate); + + for (i = 0; i < cbTranslate / sizeof(LANGCODEPAGE); i++) + { + /* If the bottom eight bits of the language id's + match, use this version information (since this + means that the version information and the users + default language are the same). */ + if ((lpTranslate[i].wLanguage & 0xFF) == + (UserLangId & 0xFF)) + { + wnsprintf(szSubBlock, + sizeof(szSubBlock) / sizeof(szSubBlock[0]), + TEXT("\\StringFileInfo\\%04X%04X\\%s"), + lpTranslate[i].wLanguage, + lpTranslate[i].wCodePage, + szVersionInfo); + + if (VerQueryValue(lpData, + szSubBlock, + (LPVOID *) &lpszLocalBuf, + &cbLen) != 0) + { + _tcsncpy(szBuffer, lpszLocalBuf, cbBufLen / sizeof(*szBuffer)); + + bRet = TRUE; + break; + } + } + } + } + HeapFree(hProcessHeap, 0, lpData); + lpData = NULL; + } + } + + return bRet; +} diff --git a/dll/win32/browseui/bandsite.cpp b/dll/win32/browseui/bandsite.cpp index 602dd9b7aca..5e46e71855d 100644 --- a/dll/win32/browseui/bandsite.cpp +++ b/dll/win32/browseui/bandsite.cpp @@ -634,7 +634,7 @@ HRESULT STDMETHODCALLTYPE CBandSiteBase::SetDeskBarSite(IUnknown *pUnk) if (FAILED_UNEXPECTEDLY(hRet)) return E_FAIL; - style = WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | RBS_VARHEIGHT | + style = WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | RBS_VARHEIGHT | RBS_AUTOSIZE | RBS_BANDBORDERS | CCS_NODIVIDER | CCS_NORESIZE | CCS_NOPARENTALIGN; fRebarWindow = CreateWindowExW(WS_EX_TOOLWINDOW,