* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#include <precomp.h>
+#include "precomp.h"
static const TRAYWINDOW_CTXMENU TrayWindowCtxMenu;
const IShellDesktopTrayVtbl *lpVtblShellDesktopTray;
LONG Ref;
+ HTHEME TaskbarTheme;
HWND hWnd;
HWND hWndDesktop;
DWORD Position;
HMONITOR Monitor;
+ HMONITOR PreviousMonitor;
DWORD DraggingPosition;
HMONITOR DraggingMonitor;
IMenuPopup *StartMenuPopup;
HBITMAP hbmStartMenu;
- HWND hWndTrayProperties;
+ HWND hwndTrayPropertiesOwner;
+ HWND hwndRunFileDlgOwner;
} ITrayWindowImpl;
+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)
{
MONITORINFO mi;
mi.cbSize = sizeof(mi);
- if (!GetMonitorInfo(This->Monitor,
+ if (!GetMonitorInfo(hMonitor,
&mi))
{
/* Hm, the monitor is gone? Try to find a monitor where it
IN OUT RECT *pRect)
{
RECT rcScreen;
- BOOL Horizontal;
+ //BOOL Horizontal;
HMONITOR hMon;
SIZE szMax, szWnd;
- Horizontal = ITrayWindowImpl_IsPosHorizontal(This);
+ //Horizontal = ITrayWindowImpl_IsPosHorizontal(This);
szWnd.cx = pRect->right - pRect->left;
szWnd.cy = pRect->bottom - pRect->top;
RECT rcMin = {0};
AdjustWindowRectEx(&rcMin,
- GetWindowLongPtr(This->hWnd,
- GWL_STYLE),
+ GetWindowLong(This->hWnd,
+ GWL_STYLE),
FALSE,
- GetWindowLongPtr(This->hWnd,
- GWL_EXSTYLE));
+ GetWindowLong(This->hWnd,
+ GWL_EXSTYLE));
*pRect = rcMin;
}
}
}
+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)
{
rcTray.bottom - rcTray.top,
SWP_NOZORDER);
+ ITrayWindowImpl_ResizeWorkArea(This);
+
ITrayWindowImpl_ApplyClipping(This,
TRUE);
}
rcScreen.left = 0;
rcScreen.top = 0;
rcScreen.right = GetSystemMetrics(SM_CXSCREEN);
- rcScreen.right = GetSystemMetrics(SM_CYSCREEN);
+ rcScreen.bottom = GetSystemMetrics(SM_CYSCREEN);
ITrayWindowImpl_GetScreenRectFromRect(This,
&rcScreen,
MONITOR_DEFAULTTOPRIMARY);
This->TrayBandSite = NULL;
}
+ if (This->TaskbarTheme)
+ {
+ CloseThemeData(This->TaskbarTheme);
+ This->TaskbarTheme = NULL;
+ }
+
ITrayWindowImpl_Release(ITrayWindow_from_impl(This));
if (InterlockedDecrement(&TrayWndCount) == 0)
BOOL Horizontal;
HDWP dwp;
+ ITrayWindowImpl_UpdateStartButton(This, NULL);
if (prcClient != NULL)
{
rcClient = *prcClient;
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,
NULL);
if (This->hwndStart)
{
+ SetWindowTheme(This->hwndStart, L"Start", NULL);
SendMessage(This->hwndStart,
WM_SETFONT,
(WPARAM)This->hStartBtnFont,
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),
ITrayWindowImpl *This;
This = HeapAlloc(hProcessHeap,
- 0,
+ HEAP_ZERO_MEMORY,
sizeof(*This));
if (This == NULL)
return NULL;
- ZeroMemory(This,
- sizeof(*This));
This->lpVtbl = &ITrayWindowImpl_Vtbl;
This->lpVtblShellDesktopTray = &IShellDesktopTrayImpl_Vtbl;
This->Ref = 1;
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->hWndTrayProperties != NULL)
+ if (This->hwndTrayPropertiesOwner)
{
- BringWindowToTop(This->hWndTrayProperties);
- return This->hWndTrayProperties;
+ hTrayProp = GetLastActivePopup(This->hwndTrayPropertiesOwner);
+ if (hTrayProp != NULL &&
+ hTrayProp != This->hwndTrayPropertiesOwner)
+ {
+ SetForegroundWindow(hTrayProp);
+ return NULL;
+ }
}
- This->hWndTrayProperties = DisplayTrayProperties(ITrayWindow_from_impl(This));
- return This->hWndTrayProperties;
+ CloseHandle(CreateThread(NULL, 0, TrayPropertiesThread, This, 0, NULL));
+ return NULL;
}
static VOID
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:
DbgPrint("ITrayWindow::ExecContextMenuCmd(%u): Unhandled Command ID!\n", uiCmd);
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 LRESULT CALLBACK
TrayWndProc(IN HWND hwnd,
IN UINT uMsg,
switch (uMsg)
{
+ 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;
return HTBORDER;
}
+ SetLastError(ERROR_SUCCESS);
if (GetClientRect(hwnd,
&rcClient) &&
- MapWindowPoints(hwnd,
- NULL,
- (LPPOINT)&rcClient,
- 2) != 0)
+ (MapWindowPoints(hwnd,
+ NULL,
+ (LPPOINT)&rcClient,
+ 2) != 0 || GetLastError() == ERROR_SUCCESS))
{
pt.x = (SHORT)LOWORD(lParam);
pt.y = (SHORT)HIWORD(lParam);
if (pt.y > rcClient.bottom)
return HTBOTTOM;
break;
-
- case ABE_BOTTOM:
- if (pt.y < rcClient.top)
- return HTTOP;
- 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;
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,
}
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:
{
DestroyWindow(hwnd);
break;
+ case TWM_OPENSTARTMENU:
+ {
+ HWND hwndStartMenu;
+ HRESULT hr = IUnknown_GetWindow((IUnknown*)This->StartMenuPopup, &hwndStartMenu);
+ if (FAILED(hr))
+ break;
+
+ if (IsWindowVisible(hwndStartMenu))
+ SetWindowPos(hwndStartMenu, 0,0,0,0,0, SWP_HIDEWINDOW | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER);
+ else
+ SendMessage(This->hWnd, WM_COMMAND, MAKEWPARAM(BN_CLICKED, IDC_STARTBTN), (LPARAM)This->hwndStart);
+
+ break;
+ }
case WM_COMMAND:
if ((HWND)lParam == This->hwndStart)
{
lParam,
&Ret)))
{
- switch(LOWORD(wParam))
+ switch (LOWORD(wParam))
{
/* FIXME: Handle these commands as well */
case IDM_TASKBARANDSTARTMENU:
+
+ ITrayWindowImpl_DisplayProperties(ITrayWindow_from_impl(This));
+ break;
+
case IDM_SEARCH:
case IDM_HELPANDSUPPORT:
break;
case IDM_RUN:
{
- HANDLE hShell32;
- RUNFILEDLG RunFileDlg;
-
- hShell32 = GetModuleHandle(TEXT("SHELL32.DLL"));
- RunFileDlg = (RUNFILEDLG)GetProcAddress(hShell32, (LPCSTR)61);
-
- RunFileDlg(hwnd, NULL, NULL, NULL, NULL, RFF_CALCDIRECTORY);
+ ITrayWindowImpl_DisplayRunFileDlg(This);
break;
}
while (1)
{
- Ret = (GetMessage(&Msg,
- NULL,
- 0,
- 0) != 0);
+ Ret = GetMessage(&Msg,
+ NULL,
+ 0,
+ 0);
- if (Ret != -1)
- {
- if (!Ret)
- break;
+ if (!Ret || Ret == -1)
+ break;
- if (This->StartMenuBand == NULL ||
- IMenuBand_IsMenuMessage(This->StartMenuBand,
- &Msg) != S_OK)
+ if (Msg.message == WM_HOTKEY)
+ {
+ switch (Msg.wParam)
{
- TranslateMessage(&Msg);
- DispatchMessage(&Msg);
+ case IDHK_RUN: /* Win+R */
+ ITrayWindowImpl_DisplayRunFileDlg(This);
+ break;
}
}
+
+ if (This->StartMenuBand == NULL ||
+ IMenuBand_IsMenuMessage(This->StartMenuBand,
+ &Msg) != S_OK)
+ {
+ TranslateMessage(&Msg);
+ DispatchMessage(&Msg);
+ }
}
}