[explorer_new]
[reactos.git] / base / shell / explorer-new / traywnd.c
index 926e435..b806c5d 100644 (file)
@@ -18,7 +18,7 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
-#include <precomp.h>
+#include "precomp.h"
 
 static const TRAYWINDOW_CTXMENU TrayWindowCtxMenu;
 
@@ -43,6 +43,7 @@ typedef struct
     const IShellDesktopTrayVtbl *lpVtblShellDesktopTray;
     LONG Ref;
 
+    HTHEME TaskbarTheme;
     HWND hWnd;
     HWND hWndDesktop;
 
@@ -59,6 +60,7 @@ typedef struct
 
     DWORD Position;
     HMONITOR Monitor;
+    HMONITOR PreviousMonitor;
     DWORD DraggingPosition;
     HMONITOR DraggingMonitor;
 
@@ -90,9 +92,23 @@ typedef struct
     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)
 {
@@ -230,7 +246,7 @@ ITrayWindowImpl_GetScreenRect(IN OUT 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
@@ -320,11 +336,11 @@ ITrayWindowImpl_CalculateValidSize(IN OUT ITrayWindowImpl *This,
                                    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;
@@ -362,11 +378,11 @@ ITrayWindowImpl_GetMinimumWindowSize(IN OUT ITrayWindowImpl *This,
     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;
 }
@@ -639,6 +655,57 @@ ITrayWindowImpl_ApplyClipping(IN OUT ITrayWindowImpl *This,
     }
 }
 
+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)
 {
@@ -656,6 +723,8 @@ ITrayWindowImpl_CheckTrayWndPosition(IN OUT ITrayWindowImpl *This)
                  rcTray.bottom - rcTray.top,
                  SWP_NOZORDER);
 
+    ITrayWindowImpl_ResizeWorkArea(This);
+
     ITrayWindowImpl_ApplyClipping(This,
                                   TRUE);
 }
@@ -738,7 +807,7 @@ ITrayWindowImpl_RegLoadSettings(IN OUT ITrayWindowImpl *This)
         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);
@@ -965,6 +1034,12 @@ ITrayWindowImpl_Destroy(ITrayWindowImpl *This)
         This->TrayBandSite = NULL;
     }
 
+    if (This->TaskbarTheme)
+    {
+        CloseThemeData(This->TaskbarTheme);
+        This->TaskbarTheme = NULL;
+    }
+
     ITrayWindowImpl_Release(ITrayWindow_from_impl(This));
 
     if (InterlockedDecrement(&TrayWndCount) == 0)
@@ -1051,6 +1126,7 @@ ITrayWindowImpl_AlignControls(IN OUT ITrayWindowImpl *This,
     BOOL Horizontal;
     HDWP dwp;
 
+    ITrayWindowImpl_UpdateStartButton(This, NULL);
     if (prcClient != NULL)
     {
         rcClient = *prcClient;
@@ -1339,11 +1415,26 @@ Cleanup:
     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,
@@ -1396,6 +1487,7 @@ ITrayWindowImpl_Create(IN OUT ITrayWindowImpl *This)
                                      NULL);
     if (This->hwndStart)
     {
+        SetWindowTheme(This->hwndStart, L"Start", NULL);
         SendMessage(This->hwndStart,
                     WM_SETFONT,
                     (WPARAM)This->hStartBtnFont,
@@ -1476,6 +1568,7 @@ SetStartBtnImage:
     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),
@@ -1532,13 +1625,11 @@ ITrayWindowImpl_Construct(VOID)
     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;
@@ -1662,19 +1753,56 @@ ITrayWIndowImpl_GetCaptionFonts(IN OUT ITrayWindow *iface,
     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
@@ -1743,6 +1871,30 @@ ITrayWindowImpl_ExecContextMenuCmd(IN OUT ITrayWindow *iface,
             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);
@@ -1797,6 +1949,129 @@ static const ITrayWindowVtbl ITrayWindowImpl_Vtbl =
     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,
@@ -1837,6 +2112,32 @@ TrayWndProc(IN HWND hwnd,
 
         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;
@@ -1850,12 +2151,13 @@ TrayWndProc(IN HWND hwnd,
                     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);
@@ -1875,30 +2177,23 @@ TrayWndProc(IN HWND hwnd,
                             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;
@@ -1951,9 +2246,10 @@ TrayWndProc(IN HWND hwnd,
             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,
@@ -2203,9 +2499,23 @@ HandleTrayContextMenu:
             }
 
             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:
             {
@@ -2239,6 +2549,20 @@ HandleTrayContextMenu:
                 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)
                 {
@@ -2285,23 +2609,21 @@ HandleTrayContextMenu:
                                                             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;
                         }
 
@@ -2535,24 +2857,31 @@ TrayMessageLoop(IN OUT ITrayWindow *Tray)
 
     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);
+        }
     }
 }