[CLIPBRD] Improvements for the Clipboard Viewer.
authorHermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
Sun, 13 May 2018 20:15:41 +0000 (22:15 +0200)
committerHermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
Sun, 13 May 2018 20:25:55 +0000 (22:25 +0200)
- Improve the scrolling support for bitmaps, DIBs and text formats.
  This completes the work started in CORE-10679 by Ricardo Hanke.
  Includes scrolling with the keyboard and the mouse wheel.
- Add support for the CF_DSP* clipboard formats, as well as CF_TEXT
  and CF_OEMTEXT.
- Add support for owner-display clipboard format CF_OWNERDISPLAY.
- Realize any palette found in the clipboard (CF_PALETTE) before
  displaying the clipboard data format we want.
- Remove dead code.
- Update the file headers.

12 files changed:
base/applications/clipbrd/clipbrd.c
base/applications/clipbrd/clipbrd.rc
base/applications/clipbrd/cliputils.c
base/applications/clipbrd/cliputils.h
base/applications/clipbrd/fileutils.c
base/applications/clipbrd/fileutils.h
base/applications/clipbrd/precomp.h
base/applications/clipbrd/resources.h
base/applications/clipbrd/scrollutils.c
base/applications/clipbrd/scrollutils.h
base/applications/clipbrd/winutils.c
base/applications/clipbrd/winutils.h

index f46daeb..280cc6f 100644 (file)
@@ -1,9 +1,9 @@
 /*
- * COPYRIGHT:       See COPYING in the top level directory
- * PROJECT:         ReactOS Clipboard Viewer
- * FILE:            base/applications/clipbrd/clipbrd.c
- * PURPOSE:         Provides a view of the contents of the ReactOS clipboard.
- * PROGRAMMERS:     Ricardo Hanke
+ * PROJECT:     ReactOS Clipboard Viewer
+ * LICENSE:     GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
+ * PURPOSE:     Provides a view of the contents of the ReactOS clipboard.
+ * COPYRIGHT:   Copyright 2015-2018 Ricardo Hanke
+ *              Copyright 2015-2018 Hermes Belusca-Maito
  */
 
 #include "precomp.h"
@@ -13,26 +13,12 @@ static const WCHAR szClassName[] = L"ClipBookWClass";
 CLIPBOARD_GLOBALS Globals;
 SCROLLSTATE Scrollstate;
 
-static void UpdateLinesToScroll(void)
-{
-    UINT uLinesToScroll;
-
-    if (!SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &uLinesToScroll, 0))
-    {
-        Globals.uLinesToScroll = 3;
-    }
-    else
-    {
-        Globals.uLinesToScroll = uLinesToScroll;
-    }
-}
-
 static void SaveClipboardToFile(void)
 {
     OPENFILENAMEW sfn;
+    LPWSTR c;
     WCHAR szFileName[MAX_PATH];
     WCHAR szFilterMask[MAX_STRING_LEN + 10];
-    LPWSTR c;
 
     ZeroMemory(&szFilterMask, sizeof(szFilterMask));
     c = szFilterMask + LoadStringW(Globals.hInstance, STRING_FORMAT_NT, szFilterMask, MAX_STRING_LEN) + 1;
@@ -87,9 +73,9 @@ static void LoadClipboardDataFromFile(LPWSTR lpszFileName)
 static void LoadClipboardFromFile(void)
 {
     OPENFILENAMEW ofn;
+    LPWSTR c;
     WCHAR szFileName[MAX_PATH];
     WCHAR szFilterMask[MAX_STRING_LEN + 10];
-    LPWSTR c;
 
     ZeroMemory(&szFilterMask, sizeof(szFilterMask));
     c = szFilterMask + LoadStringW(Globals.hInstance, STRING_FORMAT_GEN, szFilterMask, MAX_STRING_LEN) + 1;
@@ -123,6 +109,8 @@ static void LoadClipboardFromDrop(HDROP hDrop)
 
 static void SetDisplayFormat(UINT uFormat)
 {
+    RECT rc;
+
     CheckMenuItem(Globals.hMenu, Globals.uCheckedItem, MF_BYCOMMAND | MF_UNCHECKED);
     Globals.uCheckedItem = uFormat + CMD_AUTOMATIC;
     CheckMenuItem(Globals.hMenu, Globals.uCheckedItem, MF_BYCOMMAND | MF_CHECKED);
@@ -136,13 +124,10 @@ static void SetDisplayFormat(UINT uFormat)
         Globals.uDisplayFormat = uFormat;
     }
 
-    if (Globals.hDspBmp)
-    {
-        DeleteObject(Globals.hDspBmp);
-    }
-
-    ZeroMemory(&Scrollstate, sizeof(Scrollstate));
-    UpdateWindowScrollState(Globals.hMainWnd, Globals.hDspBmp, &Scrollstate);
+    GetClipboardDataDimensions(Globals.uDisplayFormat, &rc);
+    Scrollstate.CurrentX = Scrollstate.CurrentY = 0;
+    Scrollstate.iWheelCarryoverX = Scrollstate.iWheelCarryoverY = 0;
+    UpdateWindowScrollState(Globals.hMainWnd, rc.right, rc.bottom, &Scrollstate);
 
     InvalidateRect(Globals.hMainWnd, NULL, TRUE);
 }
@@ -169,8 +154,8 @@ static void InitMenuPopup(HMENU hMenu, LPARAM index)
 static void UpdateDisplayMenu(void)
 {
     UINT uFormat;
-    WCHAR szFormatName[MAX_FMT_NAME_LEN + 1];
     HMENU hMenu;
+    WCHAR szFormatName[MAX_FMT_NAME_LEN + 1];
 
     hMenu = GetSubMenu(Globals.hMenu, DISPLAY_MENU_POS);
 
@@ -187,27 +172,34 @@ static void UpdateDisplayMenu(void)
 
     AppendMenuW(hMenu, MF_SEPARATOR, 0, NULL);
 
-    uFormat = EnumClipboardFormats(0);
-    while (uFormat)
+    /* Display the supported clipboard formats first */
+    for (uFormat = EnumClipboardFormats(0); uFormat;
+         uFormat = EnumClipboardFormats(uFormat))
     {
-        RetrieveClipboardFormatName(Globals.hInstance, uFormat, TRUE, szFormatName, ARRAYSIZE(szFormatName));
+        if (IsClipboardFormatSupported(uFormat))
+        {
+            RetrieveClipboardFormatName(Globals.hInstance, uFormat, TRUE,
+                                        szFormatName, ARRAYSIZE(szFormatName));
+            AppendMenuW(hMenu, MF_STRING, CMD_AUTOMATIC + uFormat, szFormatName);
+        }
+    }
 
+    /* Now display the unsupported clipboard formats */
+    for (uFormat = EnumClipboardFormats(0); uFormat;
+         uFormat = EnumClipboardFormats(uFormat))
+    {
         if (!IsClipboardFormatSupported(uFormat))
         {
+            RetrieveClipboardFormatName(Globals.hInstance, uFormat, TRUE,
+                                        szFormatName, ARRAYSIZE(szFormatName));
             AppendMenuW(hMenu, MF_STRING | MF_GRAYED, 0, szFormatName);
         }
-        else
-        {
-            AppendMenuW(hMenu, MF_STRING, CMD_AUTOMATIC + uFormat, szFormatName);
-        }
-
-        uFormat = EnumClipboardFormats(uFormat);
     }
 
     CloseClipboard();
 }
 
-static int ClipboardCommandHandler(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+static int OnCommand(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
 {
     switch (LOWORD(wParam))
     {
@@ -274,68 +266,113 @@ static int ClipboardCommandHandler(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM l
     return 0;
 }
 
-static void ClipboardPaintHandler(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+static void OnPaint(HWND hWnd, WPARAM wParam, LPARAM lParam)
 {
     HDC hdc;
     PAINTSTRUCT ps;
+    COLORREF crOldBkColor, crOldTextColor;
     RECT rc;
 
     if (!OpenClipboard(Globals.hMainWnd))
         return;
 
     hdc = BeginPaint(hWnd, &ps);
-    GetClientRect(hWnd, &rc);
+
+    /* Erase the background if needed */
+    if (ps.fErase)
+        FillRect(ps.hdc, &ps.rcPaint, (HBRUSH)(COLOR_WINDOW + 1));
+
+    /* Set the correct background and text colors */
+    crOldBkColor   = SetBkColor(ps.hdc, GetSysColor(COLOR_WINDOW));
+    crOldTextColor = SetTextColor(ps.hdc, GetSysColor(COLOR_WINDOWTEXT));
+
+    /* Realize the clipboard palette if there is one */
+    RealizeClipboardPalette(ps.hdc);
 
     switch (Globals.uDisplayFormat)
     {
         case CF_NONE:
         {
+            /* The clipboard is empty */
             break;
         }
 
+        case CF_DSPTEXT:
+        case CF_TEXT:
+        case CF_OEMTEXT:
         case CF_UNICODETEXT:
         {
-            DrawTextFromClipboard(hdc, &rc, DT_LEFT | DT_NOPREFIX);
+            DrawTextFromClipboard(Globals.uDisplayFormat, ps, Scrollstate);
             break;
         }
 
+        case CF_DSPBITMAP:
         case CF_BITMAP:
         {
-            BitBltFromClipboard(hdc, rc.left, rc.top, rc.right, rc.bottom, 0, 0, SRCCOPY);
+            BitBltFromClipboard(ps, Scrollstate, SRCCOPY);
             break;
         }
 
         case CF_DIB:
-        {
-            SetDIBitsToDeviceFromClipboard(CF_DIB, hdc, rc.left, rc.top, 0, 0, 0, DIB_RGB_COLORS);
-            break;
-        }
-
         case CF_DIBV5:
         {
-            SetDIBitsToDeviceFromClipboard(CF_DIBV5, hdc, rc.left, rc.top, 0, 0, 0, DIB_RGB_COLORS);
+            SetDIBitsToDeviceFromClipboard(Globals.uDisplayFormat, ps, Scrollstate, DIB_RGB_COLORS);
             break;
         }
 
+        case CF_DSPMETAFILEPICT:
         case CF_METAFILEPICT:
         {
+            GetClientRect(hWnd, &rc);
             PlayMetaFileFromClipboard(hdc, &rc);
             break;
         }
 
+        case CF_DSPENHMETAFILE:
         case CF_ENHMETAFILE:
         {
+            GetClientRect(hWnd, &rc);
             PlayEnhMetaFileFromClipboard(hdc, &rc);
             break;
         }
 
+        // case CF_PALETTE:
+            // TODO: Draw a palette with squares filled with colors.
+            // break;
+
+        case CF_OWNERDISPLAY:
+        {
+            HGLOBAL hglb;
+            PPAINTSTRUCT pps;
+
+            hglb = GlobalAlloc(GMEM_MOVEABLE, sizeof(ps));
+            if (hglb)
+            {
+                pps = GlobalLock(hglb);
+                CopyMemory(pps, &ps, sizeof(ps));
+                GlobalUnlock(hglb);
+
+                SendClipboardOwnerMessage(TRUE, WM_PAINTCLIPBOARD,
+                                          (WPARAM)hWnd, (LPARAM)hglb);
+
+                GlobalFree(hglb);
+            }
+            break;
+        }
+
         default:
         {
-            DrawTextFromResource(Globals.hInstance, ERROR_UNSUPPORTED_FORMAT, hdc, &rc, DT_CENTER | DT_WORDBREAK | DT_NOPREFIX);
+            GetClientRect(hWnd, &rc);
+            DrawTextFromResource(Globals.hInstance, ERROR_UNSUPPORTED_FORMAT,
+                                 hdc, &rc, DT_CENTER | DT_WORDBREAK | DT_NOPREFIX);
             break;
         }
     }
 
+    /* Restore the original colors */
+    SetTextColor(ps.hdc, crOldTextColor);
+    SetBkColor(ps.hdc, crOldBkColor);
+
     EndPaint(hWnd, &ps);
 
     CloseClipboard();
@@ -347,12 +384,29 @@ static LRESULT WINAPI MainWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lP
     {
         case WM_CREATE:
         {
+            TEXTMETRICW tm;
+            HDC hDC = GetDC(hWnd);
+
+            /*
+             * Note that the method with GetObjectW just returns
+             * the original parameters with which the font was created.
+             */
+            if (GetTextMetricsW(hDC, &tm))
+            {
+                Globals.CharWidth  = tm.tmMaxCharWidth; // tm.tmAveCharWidth;
+                Globals.CharHeight = tm.tmHeight + tm.tmExternalLeading;
+            }
+            ReleaseDC(hWnd, hDC);
+
+
             Globals.hMenu = GetMenu(hWnd);
             Globals.hWndNext = SetClipboardViewer(hWnd);
-            
+
             // For now, the Help dialog item is disabled because of lacking of HTML support
             EnableMenuItem(Globals.hMenu, CMD_HELP, MF_BYCOMMAND | MF_GRAYED);
-            
+
+            UpdateLinesToScroll(&Scrollstate);
+
             UpdateDisplayMenu();
             SetDisplayFormat(0);
             break;
@@ -367,61 +421,114 @@ static LRESULT WINAPI MainWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lP
         case WM_DESTROY:
         {
             ChangeClipboardChain(hWnd, Globals.hWndNext);
+
+            if (Globals.uDisplayFormat == CF_OWNERDISPLAY)
+            {
+                HGLOBAL hglb;
+                PRECT prc;
+
+                hglb = GlobalAlloc(GMEM_MOVEABLE, sizeof(*prc));
+                if (hglb)
+                {
+                    prc = GlobalLock(hglb);
+                    SetRectEmpty(prc);
+                    GlobalUnlock(hglb);
+
+                    SendClipboardOwnerMessage(TRUE, WM_SIZECLIPBOARD,
+                                              (WPARAM)hWnd, (LPARAM)hglb);
+
+                    GlobalFree(hglb);
+                }
+            }
+
             PostQuitMessage(0);
             break;
         }
 
         case WM_PAINT:
         {
-            ClipboardPaintHandler(hWnd, uMsg, wParam, lParam);
+            OnPaint(hWnd, wParam, lParam);
             break;
         }
 
         case WM_KEYDOWN:
         {
-            HandleKeyboardScrollEvents(hWnd, uMsg, wParam, lParam);
+            OnKeyScroll(hWnd, wParam, lParam, &Scrollstate);
             break;
         }
 
         case WM_MOUSEWHEEL:
+        case WM_MOUSEHWHEEL:
         {
-            HandleMouseScrollEvents(hWnd, uMsg, wParam, lParam, &Scrollstate);
+            OnMouseScroll(hWnd, uMsg, wParam, lParam, &Scrollstate);
             break;
         }
 
         case WM_HSCROLL:
         {
-            HandleHorizontalScrollEvents(hWnd, uMsg, wParam, lParam, &Scrollstate);
+            // NOTE: Windows uses an offset of 16 pixels
+            OnScroll(hWnd, SB_HORZ, wParam, 5, &Scrollstate);
             break;
         }
 
         case WM_VSCROLL:
         {
-            HandleVerticalScrollEvents(hWnd, uMsg, wParam, lParam, &Scrollstate);
+            // NOTE: Windows uses an offset of 16 pixels
+            OnScroll(hWnd, SB_VERT, wParam, 5, &Scrollstate);
             break;
         }
 
         case WM_SIZE:
         {
-            UpdateWindowScrollState(hWnd, Globals.hDspBmp, &Scrollstate);
+            RECT rc;
 
-            if ((Globals.uDisplayFormat == CF_METAFILEPICT) ||
-                (Globals.uDisplayFormat == CF_ENHMETAFILE) ||
-                (Globals.uDisplayFormat == CF_DSPENHMETAFILE) ||
-                (Globals.uDisplayFormat == CF_DSPMETAFILEPICT))
+            if (Globals.uDisplayFormat == CF_OWNERDISPLAY)
             {
-                InvalidateRect(Globals.hMainWnd, NULL, FALSE);
+                HGLOBAL hglb;
+                PRECT prc;
+
+                hglb = GlobalAlloc(GMEM_MOVEABLE, sizeof(*prc));
+                if (hglb)
+                {
+                    prc = GlobalLock(hglb);
+                    if (wParam == SIZE_MINIMIZED)
+                        SetRectEmpty(prc);
+                    else
+                        GetClientRect(hWnd, prc);
+                    GlobalUnlock(hglb);
+
+                    SendClipboardOwnerMessage(TRUE, WM_SIZECLIPBOARD,
+                                              (WPARAM)hWnd, (LPARAM)hglb);
+
+                    GlobalFree(hglb);
+                }
+                break;
             }
-            else if (!IsClipboardFormatSupported(Globals.uDisplayFormat))
+
+            GetClipboardDataDimensions(Globals.uDisplayFormat, &rc);
+            UpdateWindowScrollState(hWnd, rc.right, rc.bottom, &Scrollstate);
+
+            // NOTE: There still are little problems drawing
+            // the background when displaying clipboard text.
+            if (!IsClipboardFormatSupported(Globals.uDisplayFormat) ||
+                Globals.uDisplayFormat == CF_DSPTEXT ||
+                Globals.uDisplayFormat == CF_TEXT    ||
+                Globals.uDisplayFormat == CF_OEMTEXT ||
+                Globals.uDisplayFormat == CF_UNICODETEXT)
             {
                 InvalidateRect(Globals.hMainWnd, NULL, TRUE);
             }
+            else
+            {
+                InvalidateRect(Globals.hMainWnd, NULL, FALSE);
+            }
 
             break;
         }
 
         case WM_CHANGECBCHAIN:
         {
+            /* Transmit through the clipboard viewer chain */
             if ((HWND)wParam == Globals.hWndNext)
             {
                 Globals.hWndNext = (HWND)lParam;
@@ -434,11 +541,32 @@ static LRESULT WINAPI MainWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lP
             break;
         }
 
+        case WM_DESTROYCLIPBOARD:
+            break;
+
+        case WM_RENDERALLFORMATS:
+        {
+            /*
+             * When the user has cleared the clipboard via the DELETE command,
+             * we (clipboard viewer) become the clipboard owner. When we are
+             * subsequently closed, this message is then sent to us so that
+             * we get a chance to render everything we can. Since we don't have
+             * anything to render, just empty the clipboard.
+             */
+            DeleteClipboardContent();
+            break;
+        }
+
+        case WM_RENDERFORMAT:
+            // TODO!
+            break;
+
         case WM_DRAWCLIPBOARD:
         {
             UpdateDisplayMenu();
             SetDisplayFormat(0);
 
+            /* Pass the message to the next window in clipboard viewer chain */
             SendMessageW(Globals.hWndNext, uMsg, wParam, lParam);
             break;
         }
@@ -451,7 +579,7 @@ static LRESULT WINAPI MainWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lP
             }
             else
             {
-                ClipboardCommandHandler(hWnd, uMsg, wParam, lParam);
+                OnCommand(hWnd, uMsg, wParam, lParam);
             }
             break;
         }
@@ -468,9 +596,36 @@ static LRESULT WINAPI MainWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lP
             break;
         }
 
+        case WM_PALETTECHANGED:
+        {
+            /* Ignore if this comes from ourselves */
+            if ((HWND)wParam == hWnd)
+                break;
+
+            /* Fall back to WM_QUERYNEWPALETTE */
+        }
+
         case WM_QUERYNEWPALETTE:
         {
-            if (RealizeClipboardPalette(hWnd) != GDI_ERROR)
+            BOOL Success;
+            HDC hDC;
+
+            if (!OpenClipboard(Globals.hMainWnd))
+                return FALSE;
+
+            hDC = GetDC(hWnd);
+            if (!hDC)
+            {
+                CloseClipboard();
+                return FALSE;
+            }
+
+            Success = RealizeClipboardPalette(hDC);
+
+            ReleaseDC(hWnd, hDC);
+            CloseClipboard();
+
+            if (Success)
             {
                 InvalidateRect(hWnd, NULL, TRUE);
                 UpdateWindow(hWnd);
@@ -479,19 +634,6 @@ static LRESULT WINAPI MainWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lP
             return FALSE;
         }
 
-        case WM_PALETTECHANGED:
-        {
-            if ((HWND)wParam != hWnd)
-            {
-                if (RealizeClipboardPalette(hWnd) != GDI_ERROR)
-                {
-                    InvalidateRect(hWnd, NULL, TRUE);
-                    UpdateWindow(hWnd);
-                }
-            }
-            break;
-        }
-
         case WM_SYSCOLORCHANGE:
         {
             SetDisplayFormat(Globals.uDisplayFormat);
@@ -502,7 +644,7 @@ static LRESULT WINAPI MainWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lP
         {
             if (wParam == SPI_SETWHEELSCROLLLINES)
             {
-                UpdateLinesToScroll();
+                UpdateLinesToScroll(&Scrollstate);
             }
             break;
         }
@@ -512,6 +654,7 @@ static LRESULT WINAPI MainWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lP
             return DefWindowProc(hWnd, uMsg, wParam, lParam);
         }
     }
+
     return 0;
 }
 
@@ -530,6 +673,16 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLi
         return 0;
     }
 
+    switch (GetUserDefaultUILanguage())
+    {
+        case MAKELANGID(LANG_HEBREW, SUBLANG_DEFAULT):
+            SetProcessDefaultLayout(LAYOUT_RTL);
+            break;
+
+        default:
+            break;
+    }
+
     ZeroMemory(&Globals, sizeof(Globals));
     Globals.hInstance = hInstance;
 
@@ -542,16 +695,6 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLi
     wndclass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
     wndclass.lpszMenuName = MAKEINTRESOURCEW(MAIN_MENU);
     wndclass.lpszClassName = szClassName;
-    
-    switch (GetUserDefaultUILanguage())
-    {
-        case MAKELANGID(LANG_HEBREW, SUBLANG_DEFAULT):
-            SetProcessDefaultLayout(LAYOUT_RTL);
-            break;
-
-        default:
-            break;
-    }
 
     if (!RegisterClassExW(&wndclass))
     {
@@ -559,6 +702,8 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLi
         return 0;
     }
 
+    ZeroMemory(&Scrollstate, sizeof(Scrollstate));
+
     LoadStringW(hInstance, STRING_CLIPBOARD, szBuffer, ARRAYSIZE(szBuffer));
     Globals.hMainWnd = CreateWindowExW(WS_EX_CLIENTEDGE | WS_EX_ACCEPTFILES,
                                        szClassName,
@@ -591,8 +736,6 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLi
     if (lpCmdLine != NULL && *lpCmdLine)
         LoadClipboardDataFromFile(lpCmdLine);
 
-    UpdateLinesToScroll();
-
     while (GetMessageW(&msg, 0, 0, 0))
     {
         if (!TranslateAcceleratorW(Globals.hMainWnd, hAccel, &msg))
@@ -602,10 +745,5 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLi
         }
     }
 
-    if (Globals.hDspBmp)
-    {
-        DeleteObject(Globals.hDspBmp);
-    }
-
     return (int)msg.wParam;
 }
index 5f3e293..178c6ce 100644 (file)
@@ -1,11 +1,18 @@
+/*
+ * PROJECT:     ReactOS Clipboard Viewer
+ * LICENSE:     GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
+ * PURPOSE:     Resources file.
+ * COPYRIGHT:   Copyright 2015-2018 Ricardo Hanke
+ */
+
 #include <windef.h>
 #include <winuser.h>
 
 #include "resources.h"
 
-#define REACTOS_STR_FILE_DESCRIPTION  "ReactOS Clipboard Viewer"
-#define REACTOS_STR_INTERNAL_NAME     "clipbrd"
-#define REACTOS_STR_ORIGINAL_FILENAME "clipbrd.exe"
+#define REACTOS_STR_FILE_DESCRIPTION    "ReactOS Clipboard Viewer"
+#define REACTOS_STR_INTERNAL_NAME       "clipbrd"
+#define REACTOS_STR_ORIGINAL_FILENAME   "clipbrd.exe"
 #include <reactos/version.rc>
 
 CLIPBRD_ICON ICON "res/clipbrd.ico"
index e13348a..daee843 100644 (file)
@@ -1,13 +1,32 @@
 /*
- * COPYRIGHT:       See COPYING in the top level directory
- * PROJECT:         ReactOS Clipboard Viewer
- * FILE:            base/applications/clipbrd/cliputils.c
- * PURPOSE:         Clipboard helper functions.
- * PROGRAMMERS:     Ricardo Hanke
+ * PROJECT:     ReactOS Clipboard Viewer
+ * LICENSE:     GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
+ * PURPOSE:     Clipboard helper functions.
+ * COPYRIGHT:   Copyright 2015-2018 Ricardo Hanke
+ *              Copyright 2015-2018 Hermes Belusca-Maito
  */
 
 #include "precomp.h"
 
+LRESULT
+SendClipboardOwnerMessage(
+    IN BOOL bUnicode,
+    IN UINT uMsg,
+    IN WPARAM wParam,
+    IN LPARAM lParam)
+{
+    HWND hwndOwner;
+
+    hwndOwner = GetClipboardOwner();
+    if (!hwndOwner)
+        return GetLastError();
+
+    if (bUnicode)
+        return SendMessageW(hwndOwner, uMsg, wParam, lParam);
+    else
+        return SendMessageA(hwndOwner, uMsg, wParam, lParam);
+}
+
 static int
 GetPredefinedClipboardFormatName(HINSTANCE hInstance,
                                  UINT uFormat,
@@ -79,18 +98,36 @@ RetrieveClipboardFormatName(HINSTANCE hInstance,
                             PVOID lpszFormat,
                             UINT cch)
 {
-    if (!GetPredefinedClipboardFormatName(hInstance, uFormat, Unicode, lpszFormat, cch))
+    ZeroMemory(lpszFormat, cch * (Unicode ? sizeof(WCHAR) : sizeof(CHAR)));
+
+    /* Check for predefined clipboard format */
+    if (GetPredefinedClipboardFormatName(hInstance, uFormat, Unicode, lpszFormat, cch) != 0)
+        return;
+
+    /* Check for owner-display format */
+    if (uFormat == CF_OWNERDISPLAY)
     {
-        if (Unicode)
+        if (SendClipboardOwnerMessage(Unicode, WM_ASKCBFORMATNAME,
+                                      (WPARAM)cch, (LPARAM)lpszFormat) != 0)
         {
-            if (!GetClipboardFormatNameW(uFormat, (LPWSTR)lpszFormat, cch))
+            if (Unicode)
                 LoadStringW(hInstance, STRING_CF_UNKNOWN, (LPWSTR)lpszFormat, cch);
-        }
-        else
-        {
-            if (!GetClipboardFormatNameA(uFormat, (LPSTR)lpszFormat, cch))
+            else
                 LoadStringA(hInstance, STRING_CF_UNKNOWN, (LPSTR)lpszFormat, cch);
         }
+        return;
+    }
+
+    /* Fallback to registered clipboard format */
+    if (Unicode)
+    {
+        if (!GetClipboardFormatNameW(uFormat, (LPWSTR)lpszFormat, cch))
+            LoadStringW(hInstance, STRING_CF_UNKNOWN, (LPWSTR)lpszFormat, cch);
+    }
+    else
+    {
+        if (!GetClipboardFormatNameA(uFormat, (LPSTR)lpszFormat, cch))
+            LoadStringA(hInstance, STRING_CF_UNKNOWN, (LPSTR)lpszFormat, cch);
     }
 }
 
@@ -112,13 +149,22 @@ void DeleteClipboardContent(void)
 
 UINT GetAutomaticClipboardFormat(void)
 {
-    static UINT uFormatList[] = {
+    static UINT uFormatList[] =
+    {
+        CF_OWNERDISPLAY,
         CF_UNICODETEXT,
+        CF_TEXT,
+        CF_OEMTEXT,
         CF_ENHMETAFILE,
         CF_METAFILEPICT,
         CF_DIBV5,
         CF_DIB,
-        CF_BITMAP
+        CF_BITMAP,
+        CF_DSPTEXT,
+        CF_DSPBITMAP,
+        CF_DSPMETAFILEPICT,
+        CF_DSPENHMETAFILE,
+        CF_PALETTE
     };
 
     return GetPriorityClipboardFormat(uFormatList, ARRAYSIZE(uFormatList));
@@ -128,12 +174,16 @@ BOOL IsClipboardFormatSupported(UINT uFormat)
 {
     switch (uFormat)
     {
+        case CF_OWNERDISPLAY:
         case CF_UNICODETEXT:
+        case CF_TEXT:
+        case CF_OEMTEXT:
         case CF_BITMAP:
         case CF_ENHMETAFILE:
         case CF_METAFILEPICT:
         case CF_DIB:
         case CF_DIBV5:
+        case CF_HDROP:
         {
             return TRUE;
         }
@@ -144,3 +194,179 @@ BOOL IsClipboardFormatSupported(UINT uFormat)
         }
     }
 }
+
+SIZE_T
+GetLineExtentW(
+    IN LPCWSTR lpText,
+    OUT LPCWSTR* lpNextLine)
+{
+    LPCWSTR ptr;
+
+    /* Find the next line of text (lpText is NULL-terminated) */
+    /* For newlines, focus only on '\n', not on '\r' */
+    ptr = wcschr(lpText, L'\n'); // Find the end of this line.
+    if (ptr)
+    {
+        /* We have the end of this line, go to the next line (ignore the endline in the count) */
+        *lpNextLine = ptr + 1;
+    }
+    else
+    {
+        /* This line was the last one, go pointing to the terminating NULL */
+        ptr = lpText + wcslen(lpText);
+        *lpNextLine = ptr;
+    }
+
+    return (ptr - lpText);
+}
+
+SIZE_T
+GetLineExtentA(
+    IN LPCSTR lpText,
+    OUT LPCSTR* lpNextLine)
+{
+    LPCSTR ptr;
+
+    /* Find the next line of text (lpText is NULL-terminated) */
+    /* For newlines, focus only on '\n', not on '\r' */
+    ptr = strchr(lpText, '\n'); // Find the end of this line.
+    if (ptr)
+    {
+        /* We have the end of this line, go to the next line (ignore the endline in the count) */
+        *lpNextLine = ptr + 1;
+    }
+    else
+    {
+        /* This line was the last one, go pointing to the terminating NULL */
+        ptr = lpText + strlen(lpText);
+        *lpNextLine = ptr;
+    }
+
+    return (ptr - lpText);
+}
+
+BOOL GetClipboardDataDimensions(UINT uFormat, PRECT pRc)
+{
+    SetRectEmpty(pRc);
+
+    if (!OpenClipboard(Globals.hMainWnd))
+    {
+        return FALSE;
+    }
+
+    switch (uFormat)
+    {
+        case CF_DSPBITMAP:
+        case CF_BITMAP:
+        {
+            HBITMAP hBitmap;
+            BITMAP bmp;
+
+            hBitmap = (HBITMAP)GetClipboardData(CF_BITMAP);
+            GetObjectW(hBitmap, sizeof(bmp), &bmp);
+            SetRect(pRc, 0, 0, bmp.bmWidth, bmp.bmHeight);
+            break;
+        }
+
+        case CF_DIB:
+        case CF_DIBV5:
+        {
+            HGLOBAL hGlobal;
+            LPBITMAPINFOHEADER lpInfoHeader;
+
+            hGlobal = GetClipboardData(uFormat);
+            if (!hGlobal)
+                break;
+
+            lpInfoHeader = GlobalLock(hGlobal);
+            if (!lpInfoHeader)
+                break;
+
+            if (lpInfoHeader->biSize == sizeof(BITMAPCOREHEADER))
+            {
+                LPBITMAPCOREHEADER lpCoreHeader = (LPBITMAPCOREHEADER)lpInfoHeader;
+                SetRect(pRc, 0, 0,
+                        lpCoreHeader->bcWidth,
+                        lpCoreHeader->bcHeight);
+            }
+            else if ((lpInfoHeader->biSize == sizeof(BITMAPINFOHEADER)) ||
+                     (lpInfoHeader->biSize == sizeof(BITMAPV4HEADER))   ||
+                     (lpInfoHeader->biSize == sizeof(BITMAPV5HEADER)))
+            {
+                SetRect(pRc, 0, 0,
+                        lpInfoHeader->biWidth,
+                        /* NOTE: biHeight < 0 for bottom-up DIBs, or > 0 for top-down DIBs */
+                        (lpInfoHeader->biHeight > 0) ?  lpInfoHeader->biHeight
+                                                     : -lpInfoHeader->biHeight);
+            }
+            else
+            {
+                /* Invalid format */
+            }
+
+            GlobalUnlock(hGlobal);
+            break;
+        }
+
+        case CF_DSPTEXT:
+        case CF_TEXT:
+        case CF_OEMTEXT:
+        case CF_UNICODETEXT:
+        {
+            HDC hDC;
+            HGLOBAL hGlobal;
+            PVOID lpText, ptr;
+            DWORD dwSize;
+            SIZE txtSize = {0, 0};
+            SIZE_T lineSize;
+
+            hGlobal = GetClipboardData(uFormat);
+            if (!hGlobal)
+                break;
+
+            lpText = GlobalLock(hGlobal);
+            if (!lpText)
+                break;
+
+            hDC = GetDC(Globals.hMainWnd);
+
+            /* Find the size of the rectangle enclosing the text */
+            for (;;)
+            {
+                if (uFormat == CF_UNICODETEXT)
+                {
+                    if (*(LPCWSTR)lpText == UNICODE_NULL)
+                        break;
+                    lineSize = GetLineExtentW(lpText, (LPCWSTR*)&ptr);
+                    dwSize = GetTabbedTextExtentW(hDC, lpText, lineSize, 0, NULL);
+                }
+                else
+                {
+                    if (*(LPCSTR)lpText == ANSI_NULL)
+                        break;
+                    lineSize = GetLineExtentA(lpText, (LPCSTR*)&ptr);
+                    dwSize = GetTabbedTextExtentA(hDC, lpText, lineSize, 0, NULL);
+                }
+                txtSize.cx = max(txtSize.cx, LOWORD(dwSize));
+                txtSize.cy += HIWORD(dwSize);
+                lpText = ptr;
+            }
+
+            ReleaseDC(Globals.hMainWnd, hDC);
+
+            GlobalUnlock(hGlobal);
+
+            SetRect(pRc, 0, 0, txtSize.cx, txtSize.cy);
+            break;
+        }
+
+        default:
+        {
+            break;
+        }
+    }
+
+    CloseClipboard();
+
+    return TRUE;
+}
index 28d64b8..f126108 100644 (file)
@@ -1,11 +1,20 @@
 /*
- * COPYRIGHT:       See COPYING in the top level directory
- * PROJECT:         ReactOS Clipboard Viewer
- * FILE:            base/applications/clipbrd/cliputils.h
- * PURPOSE:         Clipboard helper functions.
- * PROGRAMMERS:     Ricardo Hanke
+ * PROJECT:     ReactOS Clipboard Viewer
+ * LICENSE:     GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
+ * PURPOSE:     Clipboard helper functions.
+ * COPYRIGHT:   Copyright 2015-2018 Ricardo Hanke
+ *              Copyright 2015-2018 Hermes Belusca-Maito
  */
 
+#pragma once
+
+LRESULT
+SendClipboardOwnerMessage(
+    IN BOOL bUnicode,
+    IN UINT uMsg,
+    IN WPARAM wParam,
+    IN LPARAM lParam);
+
 void
 RetrieveClipboardFormatName(HINSTANCE hInstance,
                             UINT uFormat,
@@ -16,3 +25,15 @@ RetrieveClipboardFormatName(HINSTANCE hInstance,
 void DeleteClipboardContent(void);
 UINT GetAutomaticClipboardFormat(void);
 BOOL IsClipboardFormatSupported(UINT uFormat);
+
+SIZE_T
+GetLineExtentW(
+    IN LPCWSTR lpText,
+    OUT LPCWSTR* lpNextLine);
+
+SIZE_T
+GetLineExtentA(
+    IN LPCSTR lpText,
+    OUT LPCSTR* lpNextLine);
+
+BOOL GetClipboardDataDimensions(UINT uFormat, PRECT pRc);
index 3be9acb..d4b3ba7 100644 (file)
@@ -1,10 +1,9 @@
 /*
- * COPYRIGHT:       See COPYING in the top level directory
- * PROJECT:         ReactOS Clipboard Viewer
- * FILE:            base/applications/clipbrd/fileutils.c
- * PURPOSE:         Clipboard file format helper functions.
- * PROGRAMMERS:     Ricardo Hanke
- *                  Hermes Belusca-Maito
+ * PROJECT:     ReactOS Clipboard Viewer
+ * LICENSE:     GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
+ * PURPOSE:     Clipboard file format helper functions.
+ * COPYRIGHT:   Copyright 2015-2018 Ricardo Hanke
+ *              Copyright 2015-2018 Hermes Belusca-Maito
  */
 
 #include "precomp.h"
@@ -399,22 +398,22 @@ void ReadClipboardFile(LPCWSTR lpFileName)
                 break;
             }
 
-            case CF_BITMAP:
             case CF_DSPBITMAP:
+            case CF_BITMAP:
             {
                 bResult = ClipboardReadBitmap(hFile, dwOffData, dwLenData);
                 break;
             }
 
-            case CF_METAFILEPICT:
             case CF_DSPMETAFILEPICT:
+            case CF_METAFILEPICT:
             {
                 bResult = ClipboardReadMetafile(hFile, dwOffData, dwLenData);
                 break;
             }
 
-            case CF_ENHMETAFILE:
             case CF_DSPENHMETAFILE:
+            case CF_ENHMETAFILE:
             {
                 bResult = ClipboardReadEnhMetafile(hFile, dwOffData, dwLenData);
                 break;
index e103d8e..b17c450 100644 (file)
@@ -1,15 +1,18 @@
 /*
- * COPYRIGHT:       See COPYING in the top level directory
- * PROJECT:         ReactOS Clipboard Viewer
- * FILE:            base/applications/clipbrd/fileutils.h
- * PURPOSE:         Clipboard file format helper functions.
- * PROGRAMMERS:     Ricardo Hanke
- *                  Hermes Belusca-Maito
+ * PROJECT:     ReactOS Clipboard Viewer
+ * LICENSE:     GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
+ * PURPOSE:     Clipboard file format helper functions.
+ * COPYRIGHT:   Copyright 2015-2018 Ricardo Hanke
+ *              Copyright 2015-2018 Hermes Belusca-Maito
  */
 
+#pragma once
+
+/* Clipboard file format signatures */
 #define CLIP_FMT_31 0xC350
 #define CLIP_FMT_NT 0xC351
 #define CLIP_FMT_BK 0xC352
+
 #define MAX_FMT_NAME_LEN 79
 
 /*
index 5159ec2..7a04b96 100644 (file)
@@ -1,8 +1,18 @@
+/*
+ * PROJECT:     ReactOS Clipboard Viewer
+ * LICENSE:     GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
+ * PURPOSE:     Precompiled header.
+ * COPYRIGHT:   Copyright 2015-2018 Ricardo Hanke
+ */
+
 #ifndef _CLIPBRD_PCH_
 #define _CLIPBRD_PCH_
 
 // #pragma once
 
+#undef _WIN32_WINNT
+#define _WIN32_WINNT    0x600
+
 #include <limits.h>
 
 #include <assert.h>
 #include "resources.h"
 #include "cliputils.h"
 #include "fileutils.h"
-#include "winutils.h"
 #include "scrollutils.h"
+#include "winutils.h"
 
 #define MAX_STRING_LEN 255
 #define DISPLAY_MENU_POS 2
+
 #define CF_NONE 0
 
 typedef struct _CLIPBOARD_GLOBALS
@@ -34,8 +45,10 @@ typedef struct _CLIPBOARD_GLOBALS
     HMENU hMenu;
     UINT uDisplayFormat;
     UINT uCheckedItem;
-    UINT uLinesToScroll;
-    HBITMAP hDspBmp;
+
+    /* Metrics of the current font */
+    LONG CharWidth;
+    LONG CharHeight;
 } CLIPBOARD_GLOBALS;
 
 extern CLIPBOARD_GLOBALS Globals;
index ac958ef..afc9ae8 100644 (file)
@@ -1,3 +1,10 @@
+/*
+ * PROJECT:     ReactOS Clipboard Viewer
+ * LICENSE:     GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
+ * PURPOSE:     Resources header.
+ * COPYRIGHT:   Copyright 2015-2018 Ricardo Hanke
+ */
+
 #pragma once
 
 #define CLIPBRD_ICON 100
index 424921f..87c6ce8 100644 (file)
 /*
- * COPYRIGHT:       See COPYING in the top level directory
- * PROJECT:         ReactOS Clipboard Viewer
- * FILE:            base/applications/clipbrd/scrollutils.c
- * PURPOSE:         Scrolling related helper functions.
- * PROGRAMMERS:     Ricardo Hanke
+ * PROJECT:     ReactOS Clipboard Viewer
+ * LICENSE:     GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
+ * PURPOSE:     Scrolling related helper functions.
+ * COPYRIGHT:   Copyright 2015-2018 Ricardo Hanke
+ *              Copyright 2015-2018 Hermes Belusca-Maito
  */
 
 #include "precomp.h"
 
-static int InternalSetScrollInfo(HWND hWnd, int nMin, int nMax, UINT nPage, int nPos, int fnBar)
-{
-    SCROLLINFO si;
-
-    ZeroMemory(&si, sizeof(si));
-    si.cbSize = sizeof(si);
-    si.fMask  = SIF_RANGE | SIF_PAGE | SIF_POS | SIF_DISABLENOSCROLL;
-    si.nMin   = nMin;
-    si.nMax   = nMax;
-    si.nPage  = nPage;
-    si.nPos   = nPos;
-
-    return SetScrollInfo(hWnd, fnBar, &si, TRUE);
-}
-
-void HandleKeyboardScrollEvents(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+void OnKeyScroll(HWND hWnd, WPARAM wParam, LPARAM lParam, LPSCROLLSTATE state)
 {
+    // NOTE: Windows uses an offset of 16 pixels
     switch (wParam)
     {
         case VK_UP:
-        {
-            SendMessage(hWnd, WM_VSCROLL, MAKELONG(SB_LINEUP, 0), 0);
+            OnScroll(hWnd, SB_VERT, MAKELONG(SB_LINEUP, 0), 5, state);
             break;
-        }
 
         case VK_DOWN:
-        {
-            SendMessage(hWnd, WM_VSCROLL, MAKELONG(SB_LINEDOWN, 0), 0);
+            OnScroll(hWnd, SB_VERT, MAKELONG(SB_LINEDOWN, 0), 5, state);
             break;
-        }
 
         case VK_LEFT:
-        {
-            SendMessage(hWnd, WM_HSCROLL, MAKELONG(SB_LINEUP, 0), 0);
+            OnScroll(hWnd, SB_HORZ, MAKELONG(SB_LINELEFT, 0), 5, state);
             break;
-        }
 
         case VK_RIGHT:
-        {
-            SendMessage(hWnd, WM_HSCROLL, MAKELONG(SB_LINEDOWN, 0), 0);
+            OnScroll(hWnd, SB_HORZ, MAKELONG(SB_LINERIGHT, 0), 5, state);
             break;
-        }
 
         case VK_PRIOR:
-        {
-            SendMessage(hWnd, WM_VSCROLL, MAKELONG(SB_PAGEUP, 0), 0);
+            OnScroll(hWnd, SB_VERT, MAKELONG(SB_PAGEUP, 0), state->nPageY, state);
             break;
-        }
 
         case VK_NEXT:
+            OnScroll(hWnd, SB_VERT, MAKELONG(SB_PAGEDOWN, 0), state->nPageY, state);
+            break;
+
+        case VK_HOME:
         {
-            SendMessage(hWnd, WM_VSCROLL, MAKELONG(SB_PAGEDOWN, 0), 0);
+            OnScroll(hWnd, SB_HORZ, MAKELONG(SB_LEFT, 0), 0, state);
+            if (GetKeyState(VK_CONTROL) & 0x8000)
+                OnScroll(hWnd, SB_VERT, MAKELONG(SB_TOP, 0), 0, state);
             break;
         }
 
-        default:
+        case VK_END:
         {
+            OnScroll(hWnd, SB_HORZ, MAKELONG(SB_RIGHT, 0), 0, state);
+            if (GetKeyState(VK_CONTROL) & 0x8000)
+                OnScroll(hWnd, SB_VERT, MAKELONG(SB_BOTTOM, 0), 0, state);
             break;
         }
+
+        default:
+            break;
     }
 }
 
-void HandleMouseScrollEvents(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LPSCROLLSTATE state)
+void OnMouseScroll(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LPSCROLLSTATE state)
 {
-    SCROLLINFO si;
-    int Delta;
-    int NewPos;
+    INT nBar;
+    INT nPage;
+    INT iDelta;
+    UINT uLinesToScroll = state->uLinesToScroll;
+    INT zDelta = GET_WHEEL_DELTA_WPARAM(wParam);
+    WORD sbCode;
 
-    si.cbSize = sizeof(si);
-    si.fMask = SIF_PAGE;
-    GetScrollInfo(hWnd, SB_VERT, &si);
+    assert(uMsg == WM_MOUSEWHEEL || uMsg == WM_MOUSEHWHEEL);
 
-    if (Globals.uLinesToScroll == WHEEL_PAGESCROLL)
+    if (uMsg == WM_MOUSEWHEEL)
     {
-        NewPos = si.nPage;
+        nBar = SB_VERT;
+        nPage = state->nPageY;
+
+        /* Accumulate wheel rotation ticks */
+        zDelta += state->iWheelCarryoverY;
+        state->iWheelCarryoverY = zDelta % WHEEL_DELTA;
     }
-    else
+    else // if (uMsg == WM_MOUSEHWHEEL)
     {
-        NewPos = Globals.uLinesToScroll * 5;
+        nBar = SB_HORZ;
+        nPage = state->nPageX;
+
+        /* Accumulate wheel rotation ticks */
+        zDelta += state->iWheelCarryoverX;
+        state->iWheelCarryoverX = zDelta % WHEEL_DELTA;
     }
 
-    if (GET_WHEEL_DELTA_WPARAM(wParam) > 0)
+    /*
+     * If the user specified scrolling by pages, do so.
+     * Due to a bug on Windows where, if the window height is
+     * less than the scroll lines delta default value (== 3),
+     * several lines would be skipped when scrolling if we
+     * used the WHEEL_PAGESCROLL value. Instead of this, use
+     * the number of lines per page as the limiting value.
+     * See https://www.strchr.com/corrections_to_raymond_chen_s_wheel_scrolling_code
+     * for more details.
+     */
+    if (uLinesToScroll > nPage) // (uLinesToScroll == WHEEL_PAGESCROLL)
+        uLinesToScroll = nPage;
+    /* If the user specified no wheel scrolling, don't do anything */
+    else if (uLinesToScroll == 0)
+        return;
+
+    /* Compute the scroll direction and the absolute delta value */
+    if (zDelta > 0)
     {
-        NewPos = state->CurrentY - NewPos;
+        sbCode = SB_LINEUP;
     }
     else
     {
-        NewPos = state->CurrentY + NewPos;
-    }
-
-    NewPos = min(state->MaxY, max(0, NewPos));
-
-    if (NewPos == state->CurrentY)
-    {
-        return;
+        sbCode = SB_LINEDOWN;
+        zDelta = -zDelta;
     }
 
-    Delta = NewPos - state->CurrentY;
-
-    state->CurrentY = NewPos;
+    /* Compute how many lines we should scroll (in absolute value) */
+    iDelta = (INT)uLinesToScroll * zDelta / WHEEL_DELTA;
 
-    ScrollWindowEx(hWnd, 0, -Delta, NULL, NULL, NULL, NULL, SW_INVALIDATE);
-
-    si.cbSize = sizeof(si);
-    si.fMask = SIF_POS;
-    si.nPos = state->CurrentY;
-    SetScrollInfo(hWnd, SB_VERT, &si, TRUE);
+    OnScroll(hWnd, nBar, MAKELONG(sbCode, 0), iDelta, state);
 }
 
-void HandleHorizontalScrollEvents(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LPSCROLLSTATE state)
+void OnScroll(HWND hWnd, INT nBar, WPARAM wParam, INT iDelta, LPSCROLLSTATE state)
 {
     SCROLLINFO si;
-    int Delta;
-    int NewPos;
+    PINT pCurrent;
+    INT Maximum;
+    INT NewPos;
+    INT OldX, OldY;
 
-    ZeroMemory(&si, sizeof(si));
-    si.cbSize = sizeof(si);
-    si.fMask = SIF_PAGE | SIF_TRACKPOS;
-    GetScrollInfo(hWnd, SB_HORZ, &si);
+    assert(nBar == SB_HORZ || nBar == SB_VERT);
 
-    switch (LOWORD(wParam))
+    if (Globals.uDisplayFormat == CF_OWNERDISPLAY)
     {
-        case SB_THUMBPOSITION:
-        case SB_THUMBTRACK:
+        if (nBar == SB_HORZ)
         {
-            NewPos = si.nTrackPos;
-            break;
+            SendClipboardOwnerMessage(TRUE, WM_HSCROLLCLIPBOARD,
+                                      (WPARAM)hWnd, (LPARAM)wParam);
         }
-
-        case SB_LINELEFT:
+        else // if (nBar == SB_VERT)
         {
-            NewPos = state->CurrentX - 5;
-            break;
-        }
-
-        case SB_LINERIGHT:
-        {
-            NewPos = state->CurrentX + 5;
-            break;
-        }
-
-        case SB_PAGELEFT:
-        {
-            NewPos = state->CurrentX - si.nPage;
-            break;
-        }
-
-        case SB_PAGERIGHT:
-        {
-            NewPos = state->CurrentX + si.nPage;
-            break;
-        }
-
-        default:
-        {
-            NewPos = state->CurrentX;
-            break;
+            SendClipboardOwnerMessage(TRUE, WM_VSCROLLCLIPBOARD,
+                                      (WPARAM)hWnd, (LPARAM)wParam);
         }
+        return;
     }
 
-   NewPos = min(state->MaxX, max(0, NewPos));
-
-   if (NewPos == state->CurrentX)
-   {
-       return;
-   }
-
-   Delta = NewPos - state->CurrentX;
-
-   state->CurrentX = NewPos;
-
-   ScrollWindowEx(hWnd, -Delta, 0, NULL, NULL, NULL, NULL, SW_INVALIDATE);
-
-   si.cbSize = sizeof(si);
-   si.fMask = SIF_POS;
-   si.nPos = state->CurrentX;
-   SetScrollInfo(hWnd, SB_HORZ, &si, TRUE);
-}
-
-void HandleVerticalScrollEvents(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LPSCROLLSTATE state)
-{
-    SCROLLINFO si;
-    int Delta;
-    int NewPos;
+    if (nBar == SB_HORZ)
+    {
+        pCurrent = &state->CurrentX;
+        Maximum = state->MaxX;
+    }
+    else // if (nBar == SB_VERT)
+    {
+        pCurrent = &state->CurrentY;
+        Maximum = state->MaxY;
+    }
 
     ZeroMemory(&si, sizeof(si));
     si.cbSize = sizeof(si);
-    si.fMask = SIF_PAGE | SIF_TRACKPOS;
-    GetScrollInfo(hWnd, SB_VERT, &si);
+    si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS | SIF_TRACKPOS;
+    GetScrollInfo(hWnd, nBar, &si);
 
     switch (LOWORD(wParam))
     {
@@ -207,108 +171,117 @@ void HandleVerticalScrollEvents(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPar
             break;
         }
 
-        case SB_LINEUP:
+        case SB_LINEUP:     // SB_LINELEFT:
         {
-            NewPos = state->CurrentY - 5;
+            NewPos = si.nPos - iDelta;
             break;
         }
 
-        case SB_LINEDOWN:
+        case SB_LINEDOWN:   // SB_LINERIGHT:
         {
-            NewPos = state->CurrentY + 5;
+            NewPos = si.nPos + iDelta;
             break;
         }
 
-        case SB_PAGEUP:
+        case SB_PAGEUP:     // SB_PAGELEFT:
         {
-            NewPos = state->CurrentY - si.nPage;
+            NewPos = si.nPos - si.nPage;
             break;
         }
 
-        case SB_PAGEDOWN:
+        case SB_PAGEDOWN:   // SB_PAGERIGHT:
         {
-            NewPos = state->CurrentY + si.nPage;
+            NewPos = si.nPos + si.nPage;
             break;
         }
 
-        default:
+        case SB_TOP:        // SB_LEFT:
         {
-            NewPos = state->CurrentY;
+            NewPos = si.nMin;
             break;
         }
-   }
 
-   NewPos = min(state->MaxY, max(0, NewPos));
+        case SB_BOTTOM:     // SB_RIGHT:
+        {
+            NewPos = si.nMax;
+            break;
+        }
 
-   if (NewPos == state->CurrentY)
-   {
-       return;
-   }
+        default:
+        {
+            NewPos = si.nPos;
+            break;
+        }
+    }
+
+    NewPos = min(max(NewPos, 0), Maximum);
 
-   Delta = NewPos - state->CurrentY;
+    if (si.nPos == NewPos)
+        return;
 
-   state->CurrentY = NewPos;
+    OldX = state->CurrentX;
+    OldY = state->CurrentY;
+    *pCurrent = NewPos;
 
-   ScrollWindowEx(hWnd, 0, -Delta, NULL, NULL, NULL, NULL, SW_INVALIDATE);
+    ScrollWindowEx(hWnd,
+                   OldX - state->CurrentX,
+                   OldY - state->CurrentY,
+                   NULL,
+                   NULL,
+                   NULL,
+                   NULL,
+                   SW_ERASE | SW_INVALIDATE);
+    UpdateWindow(hWnd);
 
-   si.cbSize = sizeof(si);
-   si.fMask = SIF_POS;
-   si.nPos = state->CurrentY;
-   SetScrollInfo(hWnd, SB_VERT, &si, TRUE);
+    si.fMask = SIF_POS;
+    si.nPos = NewPos;
+    SetScrollInfo(hWnd, nBar, &si, TRUE);
 }
 
-void UpdateWindowScrollState(HWND hWnd, HBITMAP hBitmap, LPSCROLLSTATE lpState)
+void UpdateLinesToScroll(LPSCROLLSTATE state)
 {
-    BITMAP bmp;
-    RECT rc;
+    UINT uLinesToScroll;
 
-    if (!GetObject(hBitmap, sizeof(BITMAP), &bmp))
+    if (!SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &uLinesToScroll, 0))
     {
-        bmp.bmWidth = 0;
-        bmp.bmHeight = 0;
+        /* Default value on Windows */
+        state->uLinesToScroll = 3;
     }
-
-    if (!GetClientRect(hWnd, &rc))
+    else
     {
-        SetRectEmpty(&rc);
+        state->uLinesToScroll = uLinesToScroll;
     }
-
-    lpState->MaxX = max(bmp.bmWidth - rc.right, 0);
-    lpState->CurrentX = min(lpState->CurrentX, lpState->MaxX);
-    InternalSetScrollInfo(hWnd, 0, bmp.bmWidth, rc.right, lpState->CurrentX, SB_HORZ);
-
-    lpState->MaxY = max(bmp.bmHeight - rc.bottom, 0);
-    lpState->CurrentY = min(lpState->CurrentY, lpState->MaxY);
-    InternalSetScrollInfo(hWnd, 0, bmp.bmHeight, rc.bottom, lpState->CurrentY, SB_VERT);
 }
 
-BOOL ScrollBlt(PAINTSTRUCT ps, HBITMAP hBmp, SCROLLSTATE state)
+void UpdateWindowScrollState(HWND hWnd, INT nMaxWidth, INT nMaxHeight, LPSCROLLSTATE lpState)
 {
-    RECT rect;
-    BOOL ret;
-    HDC hdc;
-    int xpos;
-    int ypos;
-
-    rect.left = ps.rcPaint.left;
-    rect.top = ps.rcPaint.top;
-    rect.right = (ps.rcPaint.right - ps.rcPaint.left);
-    rect.bottom = (ps.rcPaint.bottom - ps.rcPaint.top);
-
-    xpos = ps.rcPaint.left + state.CurrentX;
-    ypos = ps.rcPaint.top + state.CurrentY;
+    RECT rc;
+    SCROLLINFO si;
 
-    ret = FALSE;
+    if (!GetClientRect(hWnd, &rc))
+        SetRectEmpty(&rc);
 
-    hdc = CreateCompatibleDC(ps.hdc);
-    if (hdc)
-    {
-        if (SelectObject(hdc, hBmp))
-        {
-            ret = BitBlt(ps.hdc, rect.left, rect.top, rect.right, rect.bottom, hdc, xpos, ypos, SRCCOPY);
-        }
-        DeleteDC(hdc);
-    }
+    ZeroMemory(&si, sizeof(si));
+    si.cbSize = sizeof(si);
+    si.fMask  = SIF_RANGE | SIF_PAGE | SIF_POS | SIF_DISABLENOSCROLL;
 
-    return ret;
+    lpState->nMaxWidth = nMaxWidth;
+    lpState->MaxX = max(nMaxWidth - rc.right, 0);
+    lpState->CurrentX = min(lpState->CurrentX, lpState->MaxX);
+    lpState->nPageX = rc.right;
+    si.nMin  = 0;
+    si.nMax  = nMaxWidth;
+    si.nPage = lpState->nPageX;
+    si.nPos  = lpState->CurrentX;
+    SetScrollInfo(hWnd, SB_HORZ, &si, TRUE);
+
+    lpState->nMaxHeight = nMaxHeight;
+    lpState->MaxY = max(nMaxHeight - rc.bottom, 0);
+    lpState->CurrentY = min(lpState->CurrentY, lpState->MaxY);
+    lpState->nPageY = rc.bottom;
+    si.nMin  = 0;
+    si.nMax  = nMaxHeight;
+    si.nPage = lpState->nPageY;
+    si.nPos  = lpState->CurrentY;
+    SetScrollInfo(hWnd, SB_VERT, &si, TRUE);
 }
index 221bf50..4645a24 100644 (file)
@@ -1,22 +1,31 @@
 /*
- * COPYRIGHT:       See COPYING in the top level directory
- * PROJECT:         ReactOS Clipboard Viewer
- * FILE:            base/applications/clipbrd/scrollutils.h
- * PURPOSE:         Scrolling related helper functions.
- * PROGRAMMERS:     Ricardo Hanke
+ * PROJECT:     ReactOS Clipboard Viewer
+ * LICENSE:     GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
+ * PURPOSE:     Scrolling related helper functions.
+ * COPYRIGHT:   Copyright 2015-2018 Ricardo Hanke
+ *              Copyright 2015-2018 Hermes Belusca-Maito
  */
 
+#pragma once
+
 typedef struct _SCROLLSTATE
 {
-    int CurrentX;
-    int CurrentY;
-    int MaxX;
-    int MaxY;
+    UINT uLinesToScroll;    /* Number of lines to scroll on one wheel rotation movement (== one "click" == WHEEL_DELTA ticks) */
+    INT iWheelCarryoverX;   /* Unused wheel ticks (< WHEEL_DELTA) */
+    INT iWheelCarryoverY;
+    INT nPageX;             /* Number of lines per page */
+    INT nPageY;
+    INT CurrentX;           /* Current scrollbar position */
+    INT CurrentY;
+    INT MaxX;               /* Maximum scrollbar position */
+    INT MaxY;
+    INT nMaxWidth;          /* Maximum span of displayed data */
+    INT nMaxHeight;
 } SCROLLSTATE, *LPSCROLLSTATE;
 
-void HandleKeyboardScrollEvents(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
-void HandleMouseScrollEvents(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LPSCROLLSTATE state);
-void HandleHorizontalScrollEvents(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LPSCROLLSTATE state);
-void HandleVerticalScrollEvents(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LPSCROLLSTATE state);
-void UpdateWindowScrollState(HWND hWnd, HBITMAP hBmp, LPSCROLLSTATE lpState);
-BOOL ScrollBlt(PAINTSTRUCT ps, HBITMAP hBmp, SCROLLSTATE state);
+void OnKeyScroll(HWND hWnd, WPARAM wParam, LPARAM lParam, LPSCROLLSTATE state);
+void OnMouseScroll(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LPSCROLLSTATE state);
+void OnScroll(HWND hWnd, INT nBar, WPARAM wParam, INT iDelta, LPSCROLLSTATE state);
+
+void UpdateLinesToScroll(LPSCROLLSTATE state);
+void UpdateWindowScrollState(HWND hWnd, INT nMaxWidth, INT nMaxHeight, LPSCROLLSTATE lpState);
index 43697d5..eb1cf03 100644 (file)
@@ -1,9 +1,9 @@
 /*
- * COPYRIGHT:       See COPYING in the top level directory
- * PROJECT:         ReactOS Clipboard Viewer
- * FILE:            base/applications/clipbrd/winutils.c
- * PURPOSE:         Miscellaneous helper functions.
- * PROGRAMMERS:     Ricardo Hanke
+ * PROJECT:     ReactOS Clipboard Viewer
+ * LICENSE:     GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
+ * PURPOSE:     Display helper functions.
+ * COPYRIGHT:   Copyright 2015-2018 Ricardo Hanke
+ *              Copyright 2015-2018 Hermes Belusca-Maito
  */
 
 #include "precomp.h"
@@ -46,22 +46,6 @@ void BringWindowToFront(HWND hWnd)
     }
 }
 
-int DrawTextFromResource(HINSTANCE hInstance, UINT uID, HDC hDC, LPRECT lpRect, UINT uFormat)
-{
-    LPWSTR lpBuffer;
-    int nCount;
-
-    nCount = LoadStringW(hInstance, uID, (LPWSTR)&lpBuffer, 0);
-    if (nCount)
-    {
-        return DrawTextW(hDC, lpBuffer, nCount, lpRect, uFormat);
-    }
-    else
-    {
-        return 0;
-    }
-}
-
 int MessageBoxRes(HWND hWnd, HINSTANCE hInstance, UINT uText, UINT uCaption, UINT uType)
 {
     MSGBOXPARAMSW mb;
@@ -78,45 +62,135 @@ int MessageBoxRes(HWND hWnd, HINSTANCE hInstance, UINT uText, UINT uCaption, UIN
     return MessageBoxIndirectW(&mb);
 }
 
-void DrawTextFromClipboard(HDC hDC, LPRECT lpRect, UINT uFormat)
+void DrawTextFromResource(HINSTANCE hInstance, UINT uID, HDC hDC, LPRECT lpRect, UINT uFormat)
 {
+    LPWSTR lpBuffer;
+    int nCount;
+
+    nCount = LoadStringW(hInstance, uID, (LPWSTR)&lpBuffer, 0);
+    if (nCount)
+        DrawTextW(hDC, lpBuffer, nCount, lpRect, uFormat);
+}
+
+void DrawTextFromClipboard(UINT uFormat, PAINTSTRUCT ps, SCROLLSTATE state)
+{
+    POINT ptOrg;
     HGLOBAL hGlobal;
-    LPWSTR lpchText;
+    PVOID lpText, ptr;
+    SIZE_T lineSize;
+    INT FirstLine, LastLine;
 
-    hGlobal = GetClipboardData(CF_UNICODETEXT);
+    hGlobal = GetClipboardData(uFormat);
     if (!hGlobal)
         return;
 
-    lpchText = GlobalLock(hGlobal);
-    if (!lpchText)
+    lpText = GlobalLock(hGlobal);
+    if (!lpText)
         return;
 
-    DrawTextW(hDC, lpchText, -1, lpRect, uFormat);
+    /* Find the first and last line indices to display (Note that CurrentX/Y are in pixels!) */
+    FirstLine = max(0, (state.CurrentY + ps.rcPaint.top) / Globals.CharHeight);
+    // LastLine = min(LINES - 1, (state.CurrentY + ps.rcPaint.bottom) / Globals.CharHeight);
+    // NOTE: Can be less or greater than the actual number of lines in the text.
+    LastLine = (state.CurrentY + ps.rcPaint.bottom) / Globals.CharHeight;
+
+    /* Find the first text line to display */
+    while (FirstLine > 0)
+    {
+        if (uFormat == CF_UNICODETEXT)
+        {
+            if (*(LPCWSTR)lpText == UNICODE_NULL)
+                break;
+            GetLineExtentW(lpText, (LPCWSTR*)&ptr);
+        }
+        else
+        {
+            if (*(LPCSTR)lpText == ANSI_NULL)
+                break;
+            GetLineExtentA(lpText, (LPCSTR*)&ptr);
+        }
+
+        --FirstLine;
+        --LastLine;
+
+        lpText = ptr;
+    }
+
+    ptOrg.x = ps.rcPaint.left;
+    ptOrg.y = /* FirstLine */ max(0, (state.CurrentY + ps.rcPaint.top) / Globals.CharHeight)
+                    * Globals.CharHeight - state.CurrentY;
+
+    /* Display each line from the current one up to the last one */
+    ++LastLine;
+    while (LastLine >= 0)
+    {
+        if (uFormat == CF_UNICODETEXT)
+        {
+            if (*(LPCWSTR)lpText == UNICODE_NULL)
+                break;
+            lineSize = GetLineExtentW(lpText, (LPCWSTR*)&ptr);
+            TabbedTextOutW(ps.hdc, /*ptOrg.x*/0 - state.CurrentX, ptOrg.y,
+                           lpText, lineSize, 0, NULL,
+                           /*ptOrg.x*/0 - state.CurrentX);
+        }
+        else
+        {
+            if (*(LPCSTR)lpText == ANSI_NULL)
+                break;
+            lineSize = GetLineExtentA(lpText, (LPCSTR*)&ptr);
+            TabbedTextOutA(ps.hdc, /*ptOrg.x*/0 - state.CurrentX, ptOrg.y,
+                           lpText, lineSize, 0, NULL,
+                           /*ptOrg.x*/0 - state.CurrentX);
+        }
+
+        --LastLine;
+
+        ptOrg.y += Globals.CharHeight;
+        lpText = ptr;
+    }
+
     GlobalUnlock(hGlobal);
 }
 
-void BitBltFromClipboard(HDC hdcDest, int nXDest, int nYDest, int nWidth, int nHeight, int nXSrc, int nYSrc, DWORD dwRop)
+void BitBltFromClipboard(PAINTSTRUCT ps, SCROLLSTATE state, DWORD dwRop)
 {
     HDC hdcMem;
-    HBITMAP hbm;
+    HBITMAP hBitmap;
+    BITMAP bmp;
+    LONG bmWidth, bmHeight;
 
-    hdcMem = CreateCompatibleDC(hdcDest);
-    if (hdcMem)
-    {
-        hbm = (HBITMAP)GetClipboardData(CF_BITMAP);
-        SelectObject(hdcMem, hbm);
-        BitBlt(hdcDest, nXDest, nYDest, nWidth, nHeight, hdcMem, nXSrc, nYSrc, dwRop);
-        DeleteDC(hdcMem);
-    }
+    hdcMem = CreateCompatibleDC(ps.hdc);
+    if (!hdcMem)
+        return;
+
+    hBitmap = (HBITMAP)GetClipboardData(CF_BITMAP);
+    GetObjectW(hBitmap, sizeof(bmp), &bmp);
+
+    SelectObject(hdcMem, hBitmap);
+
+    bmWidth  = min(ps.rcPaint.right  - ps.rcPaint.left, bmp.bmWidth  - ps.rcPaint.left - state.CurrentX);
+    bmHeight = min(ps.rcPaint.bottom - ps.rcPaint.top , bmp.bmHeight - ps.rcPaint.top  - state.CurrentY);
+
+    BitBlt(ps.hdc,
+           ps.rcPaint.left,
+           ps.rcPaint.top,
+           bmWidth,
+           bmHeight,
+           hdcMem,
+           ps.rcPaint.left + state.CurrentX,
+           ps.rcPaint.top  + state.CurrentY,
+           dwRop);
+
+    DeleteDC(hdcMem);
 }
 
-void SetDIBitsToDeviceFromClipboard(UINT uFormat, HDC hdc, int XDest, int YDest, int XSrc, int YSrc, UINT uStartScan, UINT fuColorUse)
+void SetDIBitsToDeviceFromClipboard(UINT uFormat, PAINTSTRUCT ps, SCROLLSTATE state, UINT fuColorUse)
 {
+    HGLOBAL hGlobal;
     LPBITMAPINFOHEADER lpInfoHeader;
     LPBYTE lpBits;
     LONG bmWidth, bmHeight;
     DWORD dwPalSize = 0;
-    HGLOBAL hGlobal;
 
     hGlobal = GetClipboardData(uFormat);
     if (!hGlobal)
@@ -183,9 +257,9 @@ void SetDIBitsToDeviceFromClipboard(UINT uFormat, HDC hdc, int XDest, int YDest,
          *
          * FIXME: investigate!!
          * ANSWER: this is a Windows bug; part of the answer is there:
-         * http://go4answers.webhost4life.com/Help/bug-clipboard-format-conversions-28724.aspx
+         * https://social.msdn.microsoft.com/Forums/windowsdesktop/en-US/ac7ab3b5-8609-4478-b86a-976dab44c271/bug-clipboard-format-conversions-cfdib-cfdibv5-cfdib
          * May be related:
-         * http://blog.talosintel.com/2015/10/dangerous-clipboard.html
+         * https://blog.talosintelligence.com/2015/10/dangerous-clipboard.html
          */
 #if 0
         if ((lpInfoHeader->biSize == sizeof(BITMAPINFOHEADER)) &&
@@ -196,6 +270,7 @@ void SetDIBitsToDeviceFromClipboard(UINT uFormat, HDC hdc, int XDest, int YDest,
 #endif
 
         bmWidth  = lpInfoHeader->biWidth;
+        /* NOTE: biHeight < 0 for bottom-up DIBs, or > 0 for top-down DIBs */
         bmHeight = lpInfoHeader->biHeight;
     }
     else
@@ -207,11 +282,19 @@ void SetDIBitsToDeviceFromClipboard(UINT uFormat, HDC hdc, int XDest, int YDest,
 
     lpBits = (LPBYTE)lpInfoHeader + lpInfoHeader->biSize + dwPalSize;
 
-    SetDIBitsToDevice(hdc,
-                      XDest, YDest,
-                      bmWidth, bmHeight,
-                      XSrc, YSrc,
-                      uStartScan,
+    /*
+     * The seventh parameter (YSrc) of SetDIBitsToDevice always designates
+     * the Y-coordinate of the "lower-left corner" of the image, be the DIB
+     * in bottom-up or top-down mode.
+     */
+    SetDIBitsToDevice(ps.hdc,
+                      -state.CurrentX, // ps.rcPaint.left,
+                      -state.CurrentY, // ps.rcPaint.top,
+                      bmWidth,
+                      bmHeight,
+                      0, // ps.rcPaint.left + state.CurrentX,
+                      0, // -(ps.rcPaint.top  + state.CurrentY),
+                      0, // uStartScan,
                       bmHeight,
                       lpBits,
                       (LPBITMAPINFO)lpInfoHeader,
@@ -248,52 +331,25 @@ void PlayEnhMetaFileFromClipboard(HDC hdc, const RECT *lpRect)
     PlayEnhMetaFile(hdc, hEmf, lpRect);
 }
 
-UINT RealizeClipboardPalette(HWND hWnd)
+BOOL RealizeClipboardPalette(HDC hdc)
 {
-    HPALETTE hPalette;
-    HPALETTE hOldPalette;
-    UINT uResult;
-    HDC hDevContext;
-
-    if (!OpenClipboard(Globals.hMainWnd))
-    {
-        return GDI_ERROR;
-    }
+    BOOL Success;
+    HPALETTE hPalette, hOldPalette;
 
     if (!IsClipboardFormatAvailable(CF_PALETTE))
-    {
-        CloseClipboard();
-        return GDI_ERROR;
-    }
+        return FALSE;
 
     hPalette = GetClipboardData(CF_PALETTE);
     if (!hPalette)
-    {
-        CloseClipboard();
-        return GDI_ERROR;
-    }
-
-    hDevContext = GetDC(hWnd);
-    if (!hDevContext)
-    {
-        CloseClipboard();
-        return GDI_ERROR;
-    }
+        return FALSE;
 
-    hOldPalette = SelectPalette(hDevContext, hPalette, FALSE);
+    hOldPalette = SelectPalette(hdc, hPalette, FALSE);
     if (!hOldPalette)
-    {
-        ReleaseDC(hWnd, hDevContext);
-        CloseClipboard();
-        return GDI_ERROR;
-    }
-
-    uResult = RealizePalette(hDevContext);
+        return FALSE;
 
-    SelectPalette(hDevContext, hOldPalette, FALSE);
-    ReleaseDC(hWnd, hDevContext);
+    Success = (RealizePalette(hdc) != GDI_ERROR);
 
-    CloseClipboard();
+    SelectPalette(hdc, hOldPalette, FALSE);
 
-    return uResult;
+    return Success;
 }
index 12dde90..e29ec92 100644 (file)
@@ -1,18 +1,20 @@
 /*
- * COPYRIGHT:       See COPYING in the top level directory
- * PROJECT:         ReactOS Clipboard Viewer
- * FILE:            base/applications/clipbrd/winutils.h
- * PURPOSE:         Miscellaneous helper functions.
- * PROGRAMMERS:     Ricardo Hanke
+ * PROJECT:     ReactOS Clipboard Viewer
+ * LICENSE:     GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
+ * PURPOSE:     Display helper functions.
+ * COPYRIGHT:   Copyright 2015-2018 Ricardo Hanke
+ *              Copyright 2015-2018 Hermes Belusca-Maito
  */
 
+#pragma once
+
 void ShowLastWin32Error(HWND hwndParent);
 void BringWindowToFront(HWND hWnd);
-int DrawTextFromResource(HINSTANCE hInstance, UINT uID, HDC hDC, LPRECT lpRect, UINT uFormat);
 int MessageBoxRes(HWND hWnd, HINSTANCE hInstance, UINT uText, UINT uCaption, UINT uType);
-void DrawTextFromClipboard(HDC hDC, LPRECT lpRect, UINT uFormat);
-void BitBltFromClipboard(HDC hdcDest, int nXDest, int nYDest, int nWidth, int nHeight, int nXSrc, int nYSrc, DWORD dwRop);
-void SetDIBitsToDeviceFromClipboard(UINT uFormat, HDC hdc, int XDest, int YDest, int XSrc, int YSrc, UINT uStartScan, UINT fuColorUse);
+void DrawTextFromResource(HINSTANCE hInstance, UINT uID, HDC hDC, LPRECT lpRect, UINT uFormat);
+void DrawTextFromClipboard(UINT uFormat, PAINTSTRUCT ps, SCROLLSTATE state);
+void BitBltFromClipboard(PAINTSTRUCT ps, SCROLLSTATE state, DWORD dwRop);
+void SetDIBitsToDeviceFromClipboard(UINT uFormat, PAINTSTRUCT ps, SCROLLSTATE state, UINT fuColorUse);
 void PlayMetaFileFromClipboard(HDC hdc, const RECT *lpRect);
 void PlayEnhMetaFileFromClipboard(HDC hdc, const RECT *lpRect);
-UINT RealizeClipboardPalette(HWND hWnd);
+BOOL RealizeClipboardPalette(HDC hdc);