[EXPLORER_NEW]
[reactos.git] / base / shell / explorer-new / traywnd.c
index 7abf162..3cd2f77 100644 (file)
@@ -27,6 +27,21 @@ 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");
@@ -98,9 +113,15 @@ typedef struct
     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];
@@ -489,7 +510,13 @@ GetPrimaryScreenRect:
                                                   &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
@@ -497,6 +524,13 @@ GetPrimaryScreenRect:
         /* 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;
@@ -535,6 +569,13 @@ ITrayWindowImpl_ChangingWinPos(IN OUT ITrayWindowImpl *This,
         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]))
@@ -592,6 +633,13 @@ ITrayWindowImpl_ChangingWinPos(IN OUT ITrayWindowImpl *This,
                                                      &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
@@ -606,6 +654,14 @@ 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;
@@ -665,8 +721,6 @@ ITrayWindowImpl_ResizeWorkArea(IN OUT ITrayWindowImpl *This)
 {
     RECT rcTray,rcWorkArea;
 
-    return;
-
     /* If monitor has changed then fix the previous monitors work area */
     if (This->PreviousMonitor != This->Monitor)
     {
@@ -719,7 +773,16 @@ ITrayWindowImpl_CheckTrayWndPosition(IN OUT ITrayWindowImpl *This)
     RECT rcTray;
 
     rcTray = This->rcTrayWnd[This->Position];
-//    DbgPrint("CheckTray: %d: %d,%d,%d,%d\n", This->Position, rcTray.left, rcTray.top, rcTray.right, rcTray.bottom);
+    
+    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,
@@ -775,11 +838,10 @@ ITrayWindowImpl_RegLoadSettings(IN OUT ITrayWindowImpl *This)
 
         /* FIXME: Are there more flags? */
 
-        //if (sr.Position > ABE_BOTTOM)
-        //    This->Position = ABE_BOTTOM;
-        //else
-        //    This->Position = sr.Position;
-        This->Position = ABE_LEFT;
+        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
@@ -851,7 +913,7 @@ ITrayWindowImpl_RegLoadSettings(IN OUT ITrayWindowImpl *This)
                                                   &rcScreen,
                                                   &This->TraySize,
                                                   &This->rcTrayWnd[Pos]);
-//        DbgPrint("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);
+//        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
@@ -961,6 +1023,8 @@ ITrayWindowImpl_TrackCtxMenu(IN OUT ITrayWindowImpl *This,
                               cmdId,
                               pcmContext,
                               Context);
+
+        DestroyMenu(hPopup);
     }
 
     return cmdId;
@@ -1603,6 +1667,12 @@ SetStartBtnImage:
                                   NULL);
 
     InitShellServices(&(This->hdpaShellServices));
+
+    if (This->AutoHide)
+    {
+        This->AutoHideState = AUTOHIDE_HIDING;
+        SetTimer(This->hWnd, TIMER_ID_AUTOHIDE, AUTOHIDE_DELAY_HIDE, NULL);
+    }
 }
 
 static HRESULT STDMETHODCALLTYPE
@@ -1915,7 +1985,7 @@ ITrayWindowImpl_ExecContextMenuCmd(IN OUT ITrayWindow *iface,
             break;
 
         default:
-            DbgPrint("ITrayWindow::ExecContextMenuCmd(%u): Unhandled Command ID!\n", uiCmd);
+            TRACE("ITrayWindow::ExecContextMenuCmd(%u): Unhandled Command ID!\n", uiCmd);
             bHandled = FALSE;
             break;
     }
@@ -2125,8 +2195,184 @@ static void PopupStartMenu(IN ITrayWindowImpl *This)
                 &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
@@ -2203,8 +2449,7 @@ TrayWndProc(IN HWND hwnd,
             case WM_ERASEBKGND:
                 if (!This->TaskbarTheme)
                     goto DefHandler;
-                return ITrayWindowImpl_DrawBackground(This,
-                                                      (HDC)wParam);
+                return ITrayWindowImpl_DrawBackground(This, (HDC)wParam);
             case WM_CTLCOLORBTN:
                 SetBkMode((HDC)wParam, TRANSPARENT);
                 return (LRESULT)GetStockObject(HOLLOW_BRUSH);
@@ -2285,6 +2530,14 @@ TrayWndProc(IN HWND hwnd,
                 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;
             }
@@ -2302,6 +2555,14 @@ TrayWndProc(IN HWND hwnd,
                 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;
             }
@@ -2627,9 +2888,13 @@ HandleTrayContextMenu:
                     break;
 
                 if (IsWindowVisible(hwndStartMenu))
-                    SetWindowPos(hwndStartMenu, 0,0,0,0,0, SWP_HIDEWINDOW | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER);
+                {
+                    IMenuPopup_OnSelect(This->StartMenuPopup, MPOS_CANCELLEVEL);
+                }
                 else
+                {
                     SendMessage(This->hWnd, WM_COMMAND, MAKEWPARAM(BN_CLICKED, IDC_STARTBTN), (LPARAM)This->hwndStart);
+                }
 
                 break;
             }
@@ -2663,7 +2928,7 @@ HandleTrayContextMenu:
                         {
                             /* TODO: Implement properly */
 
-                            LPCWSTR strSite = L"http://www.reactos.org/";
+                            LPCWSTR strSite = L"https://www.reactos.org/";
 
                             /* TODO: Make localizable */
                             LPCWSTR strCaption = L"Sorry";
@@ -2713,6 +2978,27 @@ HandleTrayContextMenu:
                 }
                 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;
         }
@@ -2768,7 +3054,7 @@ CreateTrayWindowContextMenu(IN HWND hWndOwner,
                                                         CMF_NORMAL,
                                                         &pcm)))
             {
-                DbgPrint("ITrayBandSite::AddContextMenus succeeded!\n");
+                TRACE("ITrayBandSite::AddContextMenus succeeded!\n");
                 *(IContextMenu **)ppcmContext = pcm;
             }
         }
@@ -2873,6 +3159,8 @@ CreateTrayWindow(VOID)
 
         ITrayWindowImpl_Open(TrayWindow);
 
+        g_TrayWindow = This;
+
         return TrayWindow;
     }
 
@@ -2967,7 +3255,7 @@ ITrayWindowImpl_IShellDesktopTray_QueryInterface(IN OUT IShellDesktopTray *iface
     ITrayWindowImpl *This = impl_from_IShellDesktopTray(iface);
     ITrayWindow *tray = ITrayWindow_from_impl(This);
 
-    DbgPrint("IShellDesktopTray::QueryInterface(0x%p, 0x%p)\n", riid, ppvObj);
+    TRACE("IShellDesktopTray::QueryInterface(0x%p, 0x%p)\n", riid, ppvObj);
     return ITrayWindowImpl_QueryInterface(tray,
                                           riid,
                                           ppvObj);
@@ -2979,7 +3267,7 @@ ITrayWindowImpl_IShellDesktopTray_Release(IN OUT IShellDesktopTray *iface)
     ITrayWindowImpl *This = impl_from_IShellDesktopTray(iface);
     ITrayWindow *tray = ITrayWindow_from_impl(This);
 
-    DbgPrint("IShellDesktopTray::Release()\n");
+    TRACE("IShellDesktopTray::Release()\n");
     return ITrayWindowImpl_Release(tray);
 }
 
@@ -2989,7 +3277,7 @@ ITrayWindowImpl_IShellDesktopTray_AddRef(IN OUT IShellDesktopTray *iface)
     ITrayWindowImpl *This = impl_from_IShellDesktopTray(iface);
     ITrayWindow *tray = ITrayWindow_from_impl(This);
 
-    DbgPrint("IShellDesktopTray::AddRef()\n");
+    TRACE("IShellDesktopTray::AddRef()\n");
     return ITrayWindowImpl_AddRef(tray);
 }
 
@@ -2997,7 +3285,7 @@ static ULONG STDMETHODCALLTYPE
 ITrayWindowImpl_IShellDesktopTray_GetState(IN OUT IShellDesktopTray *iface)
 {
     /* FIXME: Return ABS_ flags? */
-    DbgPrint("IShellDesktopTray::GetState() unimplemented!\n");
+    TRACE("IShellDesktopTray::GetState() unimplemented!\n");
     return 0;
 }
 
@@ -3006,7 +3294,7 @@ ITrayWindowImpl_IShellDesktopTray_GetTrayWindow(IN OUT IShellDesktopTray *iface,
                                                 OUT HWND *phWndTray)
 {
     ITrayWindowImpl *This = impl_from_IShellDesktopTray(iface);
-    DbgPrint("IShellDesktopTray::GetTrayWindow(0x%p)\n", phWndTray);
+    TRACE("IShellDesktopTray::GetTrayWindow(0x%p)\n", phWndTray);
     *phWndTray = This->hWnd;
     return S_OK;
 }
@@ -3016,7 +3304,7 @@ ITrayWindowImpl_IShellDesktopTray_RegisterDesktopWindow(IN OUT IShellDesktopTray
                                                         IN HWND hWndDesktop)
 {
     ITrayWindowImpl *This = impl_from_IShellDesktopTray(iface);
-    DbgPrint("IShellDesktopTray::RegisterDesktopWindow(0x%p)\n", hWndDesktop);
+    TRACE("IShellDesktopTray::RegisterDesktopWindow(0x%p)\n", hWndDesktop);
 
     This->hWndDesktop = hWndDesktop;
     return S_OK;
@@ -3027,7 +3315,7 @@ ITrayWindowImpl_IShellDesktopTray_Unknown(IN OUT IShellDesktopTray *iface,
                                           IN DWORD dwUnknown1,
                                           IN DWORD dwUnknown2)
 {
-    DbgPrint("IShellDesktopTray::Unknown(%u,%u) unimplemented!\n", dwUnknown1, dwUnknown2);
+    TRACE("IShellDesktopTray::Unknown(%u,%u) unimplemented!\n", dwUnknown1, dwUnknown2);
     return S_OK;
 }
 
@@ -3043,3 +3331,16 @@ static const IShellDesktopTrayVtbl IShellDesktopTrayImpl_Vtbl =
     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