Fix usage of the first parameter for TranslateAccelerator: this should be the handle...
[reactos.git] / reactos / base / applications / magnify / magnifier.c
index af2a3bc..79c3f91 100644 (file)
@@ -8,7 +8,8 @@
  *     David Quintana <gigaherz@gmail.com>
  */
 
-/* TODO: AppBar */
+/* TODO: Support AppBar types other than ABE_TOP */
+
 #include "magnifier.h"
 
 #include <winbase.h>
 
 #include "resource.h"
 
-const TCHAR szWindowClass[] = TEXT("MAGNIFIER");
+#define APPMSG_NOTIFYICON (WM_APP+1)
+#define APPMSG_APPBAR     (WM_APP+2)
 
-#define MAX_LOADSTRING 100
+const TCHAR szWindowClass[] = TEXT("MAGNIFIER");
 
 /* Global Variables */
 HINSTANCE hInst;
 HWND hMainWnd;
 
+#define MAX_LOADSTRING 100
 TCHAR szTitle[MAX_LOADSTRING];
 
 #define TIMER_SPEED   1
@@ -37,19 +40,19 @@ DWORD lastTicks = 0;
 
 HWND hDesktopWindow = NULL;
 
-#define APPMSG_NOTIFYICON (WM_APP+1)
-HICON notifyIcon;
 NOTIFYICONDATA nid;
+HICON notifyIcon;
 HMENU notifyMenu;
-HWND hOptionsDialog;
-BOOL bOptionsDialog = FALSE;
-
-BOOL bRecreateOffscreenDC = TRUE;
-LONG sourceWidth = 0;
-LONG sourceHeight = 0;
-HDC hdcOffscreen = NULL;
-HANDLE hbmpOld;
+HWND  hOptionsDialog;
+BOOL  bOptionsDialog = FALSE;
+BOOL  bRecreateOffscreenDC = TRUE;
+LONG  sourceWidth = 0;
+LONG  sourceHeight = 0;
+HDC     hdcOffscreen = NULL;
 HBITMAP hbmpOffscreen = NULL;
+HANDLE  hbmpOld;
+POINT ptDragOffset;
+INT nearEdge;
 
 /* Current magnified area */
 POINT cp;
@@ -68,7 +71,7 @@ INT_PTR CALLBACK    AboutProc(HWND, UINT, WPARAM, LPARAM);
 INT_PTR CALLBACK    OptionsProc(HWND, UINT, WPARAM, LPARAM);
 INT_PTR CALLBACK    WarningProc(HWND, UINT, WPARAM, LPARAM);
 
-int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
+int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
 {
     MSG msg;
     HACCEL hAccelTable;
@@ -99,7 +102,7 @@ int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLin
     /* Main message loop */
     while (GetMessage(&msg, NULL, 0, 0))
     {
-        if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
+        if (!TranslateAccelerator(hMainWnd, hAccelTable, &msg))
         {
             TranslateMessage(&msg);
             DispatchMessage(&msg);
@@ -132,23 +135,158 @@ ATOM MyRegisterClass(HINSTANCE hInstance)
     return RegisterClass(&wc);
 }
 
+void DoAppBarStuff(DWORD mode)
+{
+    UINT uState;
+    APPBARDATA data = {0};
+    data.cbSize = sizeof(data);
+    data.hWnd = hMainWnd;
+    data.uCallbackMessage = APPMSG_APPBAR;
+
+    if (mode == ABM_NEW || mode == ABM_SETPOS)
+    {
+        HWND hWndOrder = HWND_BOTTOM;
+        int rcw, rch;
+        RECT rcWorkArea;
+        SystemParametersInfo(SPI_GETWORKAREA, 0, &rcWorkArea, 0);
+
+        if(mode == ABM_NEW)
+        {
+            SHAppBarMessage(ABM_NEW, &data);
+
+            switch(AppBarConfig.uEdge)
+            {
+                case ABE_LEFT:
+                    data.rc.top = rcWorkArea.top;
+                    data.rc.bottom = rcWorkArea.bottom;
+                    data.rc.left = rcWorkArea.left;
+                    data.rc.right = data.rc.left + AppBarConfig.appBarSizes.left;
+                    break;
+                case ABE_TOP:
+                    data.rc.left = rcWorkArea.left;
+                    data.rc.right = rcWorkArea.right;
+                    data.rc.top = rcWorkArea.top;
+                    data.rc.bottom = data.rc.top + AppBarConfig.appBarSizes.top;
+                    break;
+                case ABE_RIGHT:
+                    data.rc.top = rcWorkArea.top;
+                    data.rc.bottom = rcWorkArea.bottom;
+                    data.rc.right = rcWorkArea.left;
+                    data.rc.left = data.rc.right - AppBarConfig.appBarSizes.right;
+                    break;
+                case ABE_BOTTOM:
+                    data.rc.left = rcWorkArea.left;
+                    data.rc.right = rcWorkArea.right;
+                    data.rc.bottom = rcWorkArea.bottom;
+                    data.rc.top = data.rc.bottom - AppBarConfig.appBarSizes.bottom;
+                    break;
+            }
+        }
+        else
+        {
+            GetWindowRect(hMainWnd, &data.rc);
+        }
+
+        data.uEdge = AppBarConfig.uEdge;
+        uState = SHAppBarMessage(ABM_QUERYPOS, &data);
+
+        uState = SHAppBarMessage(ABM_SETPOS, &data);
+
+        rcw = data.rc.right-data.rc.left;
+        rch = data.rc.bottom-data.rc.top;
+
+        uState = SHAppBarMessage(ABM_GETSTATE, &data);
+        if(uState & ABS_ALWAYSONTOP)
+            hWndOrder = HWND_TOPMOST;
+
+        SetWindowPos(hMainWnd, hWndOrder, data.rc.left, data.rc.top, rcw, rch, SWP_SHOWWINDOW|SWP_NOCOPYBITS);
+
+    }
+    else if(mode == ABM_GETSTATE)
+    {
+        HWND hWndOrder = HWND_BOTTOM;
+        uState = SHAppBarMessage(ABM_GETSTATE, &data);
+        if(uState & ABS_ALWAYSONTOP)
+            hWndOrder = HWND_TOPMOST;
+        SetWindowPos(hMainWnd, hWndOrder, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
+    }
+    else if(mode == ABM_ACTIVATE)
+    {
+        SHAppBarMessage(ABM_ACTIVATE, &data);
+    }
+    else if(mode == ABM_WINDOWPOSCHANGED)
+    {
+        SHAppBarMessage(ABM_WINDOWPOSCHANGED, &data);
+    }
+    else if(mode == ABM_REMOVE)
+    {
+        SHAppBarMessage(ABM_REMOVE, &data);
+    }
+}
+
+void AttachAppBar(INT uEdge)
+{
+    if (AppBarConfig.uEdge == uEdge)
+        return;
+
+    if(AppBarConfig.uEdge < 0 && uEdge >= 0)
+    {
+        SetWindowLongPtr(hMainWnd, GWL_STYLE, GetWindowLongPtr(hMainWnd, GWL_STYLE) & (~WS_CAPTION));
+    }
+    else if(uEdge < 0 && AppBarConfig.uEdge>=0)
+    {
+        SetWindowLongPtr(hMainWnd, GWL_STYLE, GetWindowLongPtr(hMainWnd, GWL_STYLE) | WS_CAPTION);
+        SetWindowPos(hMainWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_FRAMECHANGED);
+    }
+
+    if(AppBarConfig.uEdge >= 0)
+    {
+        DoAppBarStuff(ABM_REMOVE);
+    }
+
+    if (uEdge >=0)
+    {
+        AppBarConfig.uEdge = uEdge;
+        DoAppBarStuff(ABM_NEW);
+    }
+    else
+    {
+        RECT rc = AppBarConfig.rcFloating;
+        SetWindowPos(hMainWnd, HWND_TOPMOST, rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top, 0);
+    }
+
+    AppBarConfig.uEdge = uEdge;
+}
+
 BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
 {
-    RECT rcWorkArea;
+    RECT rc;
+    DWORD exStyles = WS_EX_TOOLWINDOW | WS_EX_CONTROLPARENT;
+    DWORD dwStyles = WS_SIZEBOX | WS_SYSMENU | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_POPUP;
+
+    /* Load settings from registry */
+    LoadSettings();
+
+    rc = AppBarConfig.rcFloating;
+
     hInst = hInstance; // Store instance handle in our global variable
 
-    SystemParametersInfo(SPI_GETWORKAREA, 0, &rcWorkArea, 0);
+    if (AppBarConfig.uEdge<0)
+    {
+        dwStyles |= WS_CAPTION;
+        exStyles |= WS_EX_TOPMOST;
+    }
 
     /* Create the Window */
     hMainWnd = CreateWindowEx(
-        WS_EX_TOPMOST | WS_EX_PALETTEWINDOW,
+        exStyles,
         szWindowClass,
         szTitle,
-        WS_OVERLAPPEDWINDOW,
-        CW_USEDEFAULT,
-        CW_USEDEFAULT,
-        (rcWorkArea.right - rcWorkArea.left) * 2 / 3,
-        200,
+        dwStyles,
+        rc.left,
+        rc.top,
+        rc.right-rc.left,
+        rc.bottom-rc.top,
         NULL,
         NULL,
         hInstance,
@@ -157,12 +295,16 @@ BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
     if (!hMainWnd)
         return FALSE;
 
-    ShowWindow(hMainWnd, bStartMinimized ? SW_MINIMIZE : nCmdShow);
-    UpdateWindow(hMainWnd);
+    if (AppBarConfig.uEdge>=0) DoAppBarStuff(ABM_NEW);
+    else SetWindowPos(hMainWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_SHOWWINDOW);
 
-    // Windows 2003's Magnifier always shows this dialog, and exits when the dialog isclosed.
-    // Should we add a custom means to prevent opening it?
+    // In Windows 2003's Magnifier, the "Start Minimized" setting
+    // refers exclusively to the options dialog, not the main window itself.
     hOptionsDialog = CreateDialog(hInstance, MAKEINTRESOURCE(IDD_DIALOGOPTIONS), hMainWnd, OptionsProc);
+    if (bStartMinimized)
+        ShowWindow(hOptionsDialog, SW_HIDE);
+    else
+        ShowWindow(hOptionsDialog, SW_SHOW);
 
     if (bShowWarning)
         DialogBox(hInstance, MAKEINTRESOURCE(IDD_WARNINGDIALOG), hMainWnd, WarningProc);
@@ -363,8 +505,10 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
                 //Get current mouse position
                 GetCursorPos (&pNewMouse);
 
+#define PointsAreEqual(pt1, pt2) (((pt1).x == (pt2).x) && ((pt1).y == (pt2).y))
+
                 //If mouse has moved ...
-                if (((pMouse.x != pNewMouse.x) || (pMouse.y != pNewMouse.y)))
+                if (!PointsAreEqual(pMouse, pNewMouse))
                 {
                     //Update to new position
                     pMouse = pNewMouse;
@@ -372,45 +516,64 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
                     hasMoved = TRUE;
                 }
             }
-            
-            if (bFollowCaret && guiInfo.hwndCaret)
-            {
-                POINT ptCaret;
-                ptCaret.x = (guiInfo.rcCaret.left + guiInfo.rcCaret.right) / 2;
-                ptCaret.y = (guiInfo.rcCaret.top + guiInfo.rcCaret.bottom) / 2;
 
-                if (guiInfo.hwndCaret && ((pCaretWnd != guiInfo.hwndCaret) || (pCaret.x != ptCaret.x) || (pCaret.y != ptCaret.y)))
+            if(guiInfo.hwndActive != hMainWnd)
+            {
+                if (bFollowCaret)
                 {
-                    //Update to new position
-                    pCaret = ptCaret;
-                    pCaretWnd = guiInfo.hwndCaret;
-                    if(!hasMoved)
+                    if (guiInfo.hwndCaret)
                     {
-                        ClientToScreen (guiInfo.hwndCaret, (LPPOINT) &ptCaret);
-                        cp = ptCaret;
+                        POINT ptCaret;
+                        ptCaret.x = (guiInfo.rcCaret.left + guiInfo.rcCaret.right) / 2;
+                        ptCaret.y = (guiInfo.rcCaret.top + guiInfo.rcCaret.bottom) / 2;
+
+                        if ((pCaretWnd != guiInfo.hwndCaret) || !PointsAreEqual(pCaret, ptCaret))
+                        {
+                            //Update to new position
+                            pCaret = ptCaret;
+                            pCaretWnd = guiInfo.hwndCaret;
+                            if(!hasMoved)
+                            {
+                                ClientToScreen (guiInfo.hwndCaret, (LPPOINT) &ptCaret);
+                                cp = ptCaret;
+                                hasMoved = TRUE;
+                            }
+                        }
+                    }
+                    else
+                    {
+                        pCaretWnd = NULL;
                     }
-                    hasMoved = TRUE;
                 }
-            }
 
-            if (bFollowFocus && guiInfo.hwndFocus)
-            {
-                POINT ptFocus;
-                RECT activeRect;
-
-                //Get current control focus
-                GetWindowRect (guiInfo.hwndFocus, &activeRect);
-                ptFocus.x = (activeRect.left + activeRect.right) / 2;
-                ptFocus.y = (activeRect.top + activeRect.bottom) / 2;
-
-                if(guiInfo.hwndFocus && ((guiInfo.hwndFocus != pFocusWnd) || (pFocus.x != ptFocus.x) || (pFocus.y != ptFocus.y)))
+                if (bFollowFocus)
                 {
-                    //Update to new position
-                    pFocus = ptFocus;
-                    pFocusWnd = guiInfo.hwndFocus;
-                    if(!hasMoved)
-                        cp = ptFocus;
-                    hasMoved = TRUE;
+                    if(guiInfo.hwndFocus && !guiInfo.hwndCaret)
+                    {
+                        POINT ptFocus;
+                        RECT activeRect;
+
+                        //Get current control focus
+                        GetWindowRect(guiInfo.hwndFocus, &activeRect);
+                        ptFocus.x = (activeRect.left + activeRect.right) / 2;
+                        ptFocus.y = (activeRect.top + activeRect.bottom) / 2;
+
+                        if((guiInfo.hwndFocus != pFocusWnd) || !PointsAreEqual(pFocus, ptFocus))
+                        {
+                            //Update to new position
+                            pFocus = ptFocus;
+                            pFocusWnd = guiInfo.hwndFocus;
+                            if(!hasMoved)
+                            {
+                                cp = ptFocus;
+                                hasMoved = TRUE;
+                            }
+                        }
+                    }
+                    else
+                    {
+                        pFocusWnd = NULL;
+                    }
                 }
             }
 
@@ -429,8 +592,9 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
                 lastTicks = GetTickCount();
                 Refresh();
             }
+
+            return 0;
         }
-        break;
 
         case WM_COMMAND:
         {
@@ -457,7 +621,7 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
                 default:
                     return DefWindowProc(hWnd, message, wParam, lParam);
             }
-            break;
+            return 0;
         }
 
         case WM_PAINT:
@@ -467,24 +631,117 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
             dc = BeginPaint(hWnd, &PaintStruct);
             Draw(dc);
             EndPaint(hWnd, &PaintStruct);
-            break;
+            return 0;
         }
 
         case WM_CONTEXTMENU:
             TrackPopupMenu(notifyMenu, 0, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), 0, hWnd, NULL);
+            return 0;
+
+        case WM_LBUTTONDOWN:
+        {
+            RECT rc;
+            POINT pt;
+            SetCapture(hWnd);
+
+            GetCursorPos(&pt);
+            GetWindowRect(hWnd, &rc);
+            ptDragOffset.x = pt.x - rc.left;
+            ptDragOffset.y = pt.y - rc.top;
+
+            nearEdge = AppBarConfig.uEdge;
+
             break;
+        }
+        case WM_MOUSEMOVE:
+            if(GetCapture() == hWnd)
+            {
+                RECT rc;
+                POINT pt;
+                RECT rcWorkArea;
+                SystemParametersInfo(SPI_GETWORKAREA, 0, &rcWorkArea, 0);
+                GetCursorPos(&pt);
+                GetWindowRect(hWnd, &rc);
+
+                if(AppBarConfig.uEdge>=0)
+                {
+                    if (pt.x >= rcWorkArea.left && pt.x <= rcWorkArea.right &&
+                        pt.y >= rcWorkArea.top && pt.y <= rcWorkArea.bottom)
+                    {
+                        AttachAppBar(-2);
+
+                        // Fixup offset
+                        GetWindowRect(hWnd, &rc);
+                        ptDragOffset.x = (rc.right-rc.left)/2;
+                        ptDragOffset.y = 2;
+
+                        rc.left = pt.x - ptDragOffset.x;
+                        rc.top = pt.y - ptDragOffset.y;
+
+                        SetWindowPos(hWnd, HWND_TOPMOST, rc.left, rc.top, 0, 0, SWP_NOSIZE);
+                    }
+                }
+                else
+                {
+                    if(pt.x <= rcWorkArea.left+8 && nearEdge != ABE_LEFT)
+                    {
+                        AttachAppBar(ABE_LEFT);
+                        nearEdge = ABE_LEFT;
+                    }
+                    else if(pt.y <= rcWorkArea.top+8 && nearEdge != ABE_TOP)
+                    {
+                        AttachAppBar(ABE_TOP);
+                        nearEdge = ABE_TOP;
+                    }
+                    else if(pt.x >= rcWorkArea.right-8 && nearEdge != ABE_RIGHT)
+                    {
+                        AttachAppBar(ABE_RIGHT);
+                        nearEdge = ABE_RIGHT;
+                    }
+                    else if(pt.y >= rcWorkArea.bottom-8 && nearEdge != ABE_BOTTOM)
+                    {
+                        AttachAppBar(ABE_BOTTOM);
+                        nearEdge = ABE_BOTTOM;
+                    }
+                    else
+                    {
+                        rc.left = pt.x - ptDragOffset.x;
+                        rc.top = pt.y - ptDragOffset.y;
+
+                        SetWindowPos(hWnd, HWND_TOPMOST, rc.left, rc.top, 0, 0, SWP_NOSIZE);
+                        nearEdge = -1;
+                    }
+                }
+
+                pMouse = pt;
+                Refresh();
+            }
+            break;
+        case WM_LBUTTONUP:
+            if(GetCapture() == hWnd)
+            {
+                if (AppBarConfig.uEdge>=0)
+                    DoAppBarStuff(ABM_GETSTATE);
+                else
+                    SetWindowPos(hWnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
+                ReleaseCapture();
+            }
 
         case WM_SIZE:
+            if(AppBarConfig.uEdge>=0) DoAppBarStuff(ABM_SETPOS);
+            /* fallthrough */
         case WM_DISPLAYCHANGE:
             bRecreateOffscreenDC = TRUE;
             Refresh();
-            return DefWindowProc(hWnd, message, wParam, lParam);
+            break;
 
         case WM_ERASEBKGND:
             // handle WM_ERASEBKGND by simply returning non-zero because we did all the drawing in WM_PAINT.
-            break;
+            return 0;
 
         case WM_DESTROY:
+            if(AppBarConfig.uEdge>=0) DoAppBarStuff(ABM_REMOVE);
+
             /* Save settings to registry */
             SaveSettings();
             KillTimer(hWnd , 1);
@@ -501,15 +758,12 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
             DestroyIcon(notifyIcon);
 
             DestroyWindow(hOptionsDialog);
-            break;
+            return 0;
 
         case WM_CREATE:
         {
             HMENU tempMenu;
 
-            /* Load settings from registry */
-            LoadSettings();
-
             /* Get the desktop window */
             hDesktopWindow = GetDesktopWindow();
 
@@ -531,20 +785,57 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
             notifyMenu = GetSubMenu(tempMenu, 0);
             RemoveMenu(tempMenu, 0, MF_BYPOSITION);
             DestroyMenu(tempMenu);
+            return 0;
+        }
 
-            break;
+        case APPMSG_APPBAR:
+        {
+            switch (wParam)
+            {
+                case ABN_STATECHANGE:
+                    DoAppBarStuff(ABM_GETSTATE);
+                    break;
+                case ABN_POSCHANGED:
+                    DoAppBarStuff(ABM_SETPOS);
+                    break;
+                case ABN_FULLSCREENAPP:
+                {
+                    if(!lParam)
+                    {
+                        DoAppBarStuff(ABM_GETSTATE);
+                        break;
+                    }
+
+                    SetWindowPos(hMainWnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
+                    break;
+                }
+               case ABN_WINDOWARRANGE:
+                    if(lParam)
+                        ShowWindow(hMainWnd, SW_HIDE);
+                    else
+                        ShowWindow(hMainWnd, SW_SHOW);
+            }
+            return 0;
         }
 
         case APPMSG_NOTIFYICON:
             HandleNotifyIconMessage(hWnd, wParam, lParam);
+            return 0;
 
+        case WM_ACTIVATE:
+            if(AppBarConfig.uEdge>=0) DoAppBarStuff(ABM_ACTIVATE);
+            break;
+
+        case WM_WINDOWPOSCHANGED:
+            if(AppBarConfig.uEdge>=0) DoAppBarStuff(ABM_WINDOWPOSCHANGED);
+            Refresh();
             break;
 
         default:
-            return DefWindowProc(hWnd, message, wParam, lParam);
+            break;
     }
 
-    return 0;
+    return DefWindowProc(hWnd, message, wParam, lParam);
 }
 
 INT_PTR CALLBACK AboutProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)