https://git.reactos.org/?p=reactos.git;a=commitdiff;h=dd34ad7037edbc90117dbf24dcdca6135ac9c1b6

commit dd34ad7037edbc90117dbf24dcdca6135ac9c1b6
Author:     Whindmar Saksit <whinds...@proton.me>
AuthorDate: Sat Feb 8 16:22:20 2025 +0100
Commit:     GitHub <nore...@github.com>
CommitDate: Sat Feb 8 16:22:20 2025 +0100

    [SHIMGVW] Fixes and enhancements (#7705)
    
    Fixes:
    - Reduce flicker when resizing main window
    - Fixed slideshow starting with 1x1 pixel image zoom
    - Don't reset zoom levels > 100% when resizing main window
    - Always retain an active window on toggle slideshow (show/hide actions 
order)
    - Enable/disable real-size button as required
    - Correctly handle accelerators in main window after slideshow has been 
closed
    - Use same zoom shortcuts as NT6
    
    New features (unique to ROS):
    - Fullscreen mode (slideshow mode but without timer)
    - Alt+Enter or double-click to toggle fullscreen mode
    - Shift +/- to change fullscreen slideshow next picture timer
    
    CORE-19358
---
 dll/win32/shimgvw/resource.h |   5 ++
 dll/win32/shimgvw/shimgvw.c  | 132 +++++++++++++++++++++++++++++++++++++------
 dll/win32/shimgvw/shimgvw.rc |  11 +++-
 3 files changed, 131 insertions(+), 17 deletions(-)

diff --git a/dll/win32/shimgvw/resource.h b/dll/win32/shimgvw/resource.h
index ec2fbf116bd..17fce85b7fc 100644
--- a/dll/win32/shimgvw/resource.h
+++ b/dll/win32/shimgvw/resource.h
@@ -30,6 +30,11 @@
 
 /* ToolBar buttons */
 #define IDC_TOOL_BASE   500
+#define IDC_ACCEL_BASE (IDC_TOOL_BASE + 100) /* Accelerator commands not on 
the toolbar */
+
+#define IDC_TOGGLEFULLSCREEN (IDC_ACCEL_BASE + 0)
+#define IDC_INCTIMER    (IDC_ACCEL_BASE + 1)
+#define IDC_DECTIMER    (IDC_ACCEL_BASE + 2)
 
 #define IDC_PREV_PIC    (IDC_TOOL_BASE + 0)
 #define IDC_NEXT_PIC    (IDC_TOOL_BASE + 1)
diff --git a/dll/win32/shimgvw/shimgvw.c b/dll/win32/shimgvw/shimgvw.c
index 693b499761f..c0ce4de2d39 100644
--- a/dll/win32/shimgvw/shimgvw.c
+++ b/dll/win32/shimgvw/shimgvw.c
@@ -20,6 +20,8 @@
 /* Slide show timer */
 #define SLIDESHOW_TIMER_ID          0xFACE
 #define SLIDESHOW_TIMER_INTERVAL    5000 /* 5 seconds */
+#define HIDECURSOR_TIMER_ID         0xBABE
+#define HIDECURSOR_TIMER_TIMEOUT    3000
 
 HINSTANCE           g_hInstance         = NULL;
 HWND                g_hMainWnd          = NULL;
@@ -109,11 +111,15 @@ typedef struct tagPREVIEW_DATA
     INT m_xScrollOffset;
     INT m_yScrollOffset;
     UINT m_nMouseDownMsg;
+    UINT m_nTimerInterval;
+    BOOL m_bHideCursor;
     POINT m_ptOrigin;
     IStream *m_pMemStream;
     WCHAR m_szFile[MAX_PATH];
 } PREVIEW_DATA, *PPREVIEW_DATA;
 
+static VOID Preview_ToggleSlideShowEx(PPREVIEW_DATA pData, BOOL StartTimer);
+
 static inline PPREVIEW_DATA
 Preview_GetData(HWND hwnd)
 {
@@ -131,14 +137,34 @@ Preview_RestartTimer(HWND hwnd)
 {
     if (!Preview_IsMainWnd(hwnd))
     {
+        PPREVIEW_DATA pData = Preview_GetData(hwnd);
         KillTimer(hwnd, SLIDESHOW_TIMER_ID);
-        SetTimer(hwnd, SLIDESHOW_TIMER_ID, SLIDESHOW_TIMER_INTERVAL, NULL);
+        if (pData->m_nTimerInterval)
+            SetTimer(hwnd, SLIDESHOW_TIMER_ID, pData->m_nTimerInterval, NULL);
     }
 }
 
 static VOID
-ZoomWnd_UpdateScroll(PPREVIEW_DATA pData, HWND hwnd, BOOL bResetPos)
+Preview_ChangeSlideShowTimer(PPREVIEW_DATA pData, BOOL bSlower)
 {
+    BOOL IsFullscreen = !Preview_IsMainWnd(pData->m_hwnd);
+    enum { mintime = 1000, maxtime = SLIDESHOW_TIMER_INTERVAL * 3, step = 1000 
};
+    UINT interval = pData->m_nTimerInterval ? pData->m_nTimerInterval : 
SLIDESHOW_TIMER_INTERVAL;
+    if (IsFullscreen)
+    {
+        interval = bSlower ? min(interval + step, maxtime) : max(interval - 
step, mintime);
+        if (pData->m_nTimerInterval != interval)
+        {
+            pData->m_nTimerInterval = interval;
+            Preview_RestartTimer(pData->m_hwnd);
+        }
+    }
+}
+
+static VOID
+ZoomWnd_UpdateScroll(PPREVIEW_DATA pData, BOOL bResetPos)
+{
+    HWND hwnd = pData->m_hwndZoom;
     RECT rcClient;
     UINT ImageWidth, ImageHeight, ZoomedWidth, ZoomedHeight;
     SCROLLINFO si;
@@ -221,10 +247,10 @@ Preview_UpdateZoom(PPREVIEW_DATA pData, UINT NewZoom, 
BOOL bEnableBestFit, BOOL
     bEnableZoomOut = (NewZoom > MIN_ZOOM);
 
     /* Update toolbar buttons */
-    PostMessageW(hToolBar, TB_ENABLEBUTTON, IDC_ZOOM_OUT, bEnableZoomOut);
-    PostMessageW(hToolBar, TB_ENABLEBUTTON, IDC_ZOOM_IN,  bEnableZoomIn);
-    PostMessageW(hToolBar, TB_ENABLEBUTTON, IDC_BEST_FIT, bEnableBestFit);
-    PostMessageW(hToolBar, TB_ENABLEBUTTON, IDC_REAL_SIZE, bEnableRealSize);
+    SendMessageW(hToolBar, TB_ENABLEBUTTON, IDC_BEST_FIT, bEnableBestFit);
+    SendMessageW(hToolBar, TB_ENABLEBUTTON, IDC_REAL_SIZE, NewZoom != 100);
+    SendMessageW(hToolBar, TB_ENABLEBUTTON, IDC_ZOOM_IN,  bEnableZoomIn);
+    SendMessageW(hToolBar, TB_ENABLEBUTTON, IDC_ZOOM_OUT, bEnableZoomOut);
 
     /* Redraw the display window */
     InvalidateRect(pData->m_hwndZoom, NULL, TRUE);
@@ -233,7 +259,7 @@ Preview_UpdateZoom(PPREVIEW_DATA pData, UINT NewZoom, BOOL 
bEnableBestFit, BOOL
     Preview_RestartTimer(pData->m_hwnd);
 
     /* Update scroll info */
-    ZoomWnd_UpdateScroll(pData, pData->m_hwndZoom, FALSE);
+    ZoomWnd_UpdateScroll(pData, FALSE);
 }
 
 static VOID
@@ -592,7 +618,7 @@ Preview_UpdateImage(PPREVIEW_DATA pData)
     if (!Preview_IsMainWnd(pData->m_hwnd))
         Preview_ResetZoom(pData);
 
-    ZoomWnd_UpdateScroll(pData, pData->m_hwndZoom, TRUE);
+    ZoomWnd_UpdateScroll(pData, TRUE);
 }
 
 static SHIMGVW_FILENODE*
@@ -985,11 +1011,24 @@ Preview_EndSlideShow(HWND hwnd)
         return;
 
     KillTimer(hwnd, SLIDESHOW_TIMER_ID);
+    ShowWindow(g_hMainWnd, SW_SHOW);
     ShowWindow(hwnd, SW_HIDE);
-    ShowWindow(g_hMainWnd, SW_SHOWNORMAL);
     Preview_ResetZoom(Preview_GetData(g_hMainWnd));
 }
 
+static VOID
+GenerateSetCursor(HWND hwnd, UINT uMsg)
+{
+    SendMessage(hwnd, WM_SETCURSOR, (WPARAM)hwnd, MAKELONG(HTCLIENT, uMsg));
+}
+
+static VOID
+ZoomWnd_StopHideCursor(PPREVIEW_DATA pData)
+{
+    pData->m_bHideCursor = FALSE;
+    KillTimer(pData->m_hwndZoom, HIDECURSOR_TIMER_ID);
+}
+
 static VOID
 ZoomWnd_OnButtonDown(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
 {
@@ -1002,6 +1041,7 @@ ZoomWnd_OnButtonDown(HWND hwnd, UINT uMsg, WPARAM wParam, 
LPARAM lParam)
         return;
     }
 
+    ZoomWnd_StopHideCursor(pData);
     pData->m_nMouseDownMsg = uMsg;
     pData->m_ptOrigin.x = GET_X_LPARAM(lParam);
     pData->m_ptOrigin.y = GET_Y_LPARAM(lParam);
@@ -1015,6 +1055,13 @@ ZoomWnd_OnMouseMove(HWND hwnd, UINT uMsg, WPARAM wParam, 
LPARAM lParam)
     PPREVIEW_DATA pData = Preview_GetData(hwnd);
     POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
 
+    if (!Preview_IsMainWnd(pData->m_hwnd))
+    {
+        ZoomWnd_StopHideCursor(pData);
+        if (!pData->m_nMouseDownMsg)
+            SetTimer(hwnd, HIDECURSOR_TIMER_ID, HIDECURSOR_TIMER_TIMEOUT, 
NULL);
+    }
+
     if (pData->m_nMouseDownMsg == WM_MBUTTONDOWN)
     {
         INT x = GetScrollPos(hwnd, SB_HORZ) - (pt.x - pData->m_ptOrigin.x);
@@ -1034,6 +1081,12 @@ ZoomWnd_OnSetCursor(HWND hwnd, UINT uMsg, WPARAM wParam, 
LPARAM lParam)
         SetCursor(LoadCursorW(g_hInstance, MAKEINTRESOURCEW(IDC_HANDDRAG)));
         return TRUE;
     }
+
+    if (pData->m_bHideCursor)
+    {
+        SetCursor(NULL); /* Hide cursor in fullscreen */
+        return TRUE;
+    }
     return FALSE;
 }
 
@@ -1041,8 +1094,15 @@ static VOID
 ZoomWnd_OnButtonUp(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
 {
     PPREVIEW_DATA pData = Preview_GetData(hwnd);
+    BOOL wasdrag = pData->m_nMouseDownMsg == WM_MBUTTONDOWN;
+
     pData->m_nMouseDownMsg = 0;
+    if (wasdrag)
+        GenerateSetCursor(hwnd, uMsg); /* Reset to default cursor */
     ReleaseCapture();
+
+    if (!Preview_IsMainWnd(pData->m_hwnd))
+        SetTimer(hwnd, HIDECURSOR_TIMER_ID, HIDECURSOR_TIMER_TIMEOUT, NULL);
 }
 
 static VOID
@@ -1167,6 +1227,12 @@ ZoomWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM 
lParam)
             ZoomWnd_OnButtonUp(hwnd, uMsg, wParam, lParam);
             break;
         }
+        case WM_LBUTTONDBLCLK:
+        {
+            if (Preview_IsMainWnd(pData->m_hwnd))
+                Preview_ToggleSlideShowEx(pData, FALSE);
+            break;
+        }
         case WM_PAINT:
         {
             ZoomWnd_OnPaint(pData, hwnd);
@@ -1184,8 +1250,19 @@ ZoomWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM 
lParam)
             break;
         case WM_TIMER:
         {
+            if (wParam == HIDECURSOR_TIMER_ID)
+            {
+                ZoomWnd_StopHideCursor(pData);
+                if (IsWindowVisible(hwnd))
+                {
+                    pData->m_bHideCursor = TRUE;
+                    GenerateSetCursor(hwnd, uMsg);
+                }
+            }
             if (Anime_OnTimer(&pData->m_Anime, wParam))
+            {
                 InvalidateRect(hwnd, NULL, FALSE);
+            }
             break;
         }
         default:
@@ -1298,7 +1375,9 @@ Preview_OnSize(HWND hwnd)
 
         MoveWindow(pData->m_hwndZoom, 0, 0, cx, cy - (rc.bottom - rc.top), 
TRUE);
 
-        if (!IsIconic(hwnd)) /* Is it not minimized? */
+        if (pData->m_nZoomPercents > 100)
+            ZoomWnd_UpdateScroll(pData, FALSE);
+        else if (!IsIconic(hwnd)) /* Is it not minimized? */
             Preview_ResetZoom(pData);
 
         Preview_OnMoveSize(hwnd);
@@ -1372,7 +1451,7 @@ Preview_Edit(HWND hwnd)
 }
 
 static VOID
-Preview_ToggleSlideShow(PPREVIEW_DATA pData)
+Preview_ToggleSlideShowEx(PPREVIEW_DATA pData, BOOL StartTimer)
 {
     if (!IsWindow(g_hwndFullscreen))
     {
@@ -1385,18 +1464,28 @@ Preview_ToggleSlideShow(PPREVIEW_DATA pData)
 
     if (IsWindowVisible(g_hwndFullscreen))
     {
-        ShowWindow(g_hwndFullscreen, SW_HIDE);
-        ShowWindow(g_hMainWnd, SW_SHOWNORMAL);
         KillTimer(g_hwndFullscreen, SLIDESHOW_TIMER_ID);
+        ShowWindow(g_hMainWnd, SW_SHOW);
+        ShowWindow(g_hwndFullscreen, SW_HIDE);
     }
     else
     {
-        ShowWindow(g_hMainWnd, SW_HIDE);
+        PPREVIEW_DATA pSlideData = Preview_GetData(g_hwndFullscreen);
+        pSlideData->m_nTimerInterval = StartTimer ? SLIDESHOW_TIMER_INTERVAL : 
0;
         ShowWindow(g_hwndFullscreen, SW_SHOWMAXIMIZED);
+        ShowWindow(g_hMainWnd, SW_HIDE);
+        Preview_ResetZoom(pSlideData);
         Preview_RestartTimer(g_hwndFullscreen);
+        PostMessage(pSlideData->m_hwndZoom, WM_MOUSEMOVE, 0, 0); /* Start hide 
cursor */
     }
 }
 
+static inline VOID
+Preview_ToggleSlideShow(PPREVIEW_DATA pData)
+{
+    Preview_ToggleSlideShowEx(pData, TRUE);
+}
+
 static VOID
 Preview_GoNextPic(PPREVIEW_DATA pData, BOOL bNext)
 {
@@ -1452,6 +1541,15 @@ Preview_OnCommand(HWND hwnd, UINT nCommandID)
             Preview_EndSlideShow(hwnd);
             break;
 
+        case IDC_TOGGLEFULLSCREEN:
+            Preview_ToggleSlideShowEx(pData, FALSE);
+            break;
+
+        case IDC_INCTIMER:
+        case IDC_DECTIMER:
+            Preview_ChangeSlideShowTimer(pData, nCommandID == IDC_INCTIMER);
+            break;
+
         default:
             break;
     }
@@ -1541,6 +1639,7 @@ Preview_OnDestroy(HWND hwnd)
     PPREVIEW_DATA pData = Preview_GetData(hwnd);
 
     KillTimer(hwnd, SLIDESHOW_TIMER_ID);
+    KillTimer(hwnd, HIDECURSOR_TIMER_ID);
 
     pFreeFileList(g_pCurrentFile);
     g_pCurrentFile = NULL;
@@ -1683,7 +1782,7 @@ ImageView_Main(HWND hwnd, LPCWSTR szFileName)
     WndClass.style          = CS_HREDRAW | CS_VREDRAW;
     WndClass.hIcon          = LoadIconW(g_hInstance, 
MAKEINTRESOURCEW(IDI_APP_ICON));
     WndClass.hCursor        = LoadCursorW(NULL, (LPCWSTR)IDC_ARROW);
-    WndClass.hbrBackground  = (HBRUSH)UlongToHandle(COLOR_3DFACE + 1);
+    WndClass.hbrBackground  = GetStockBrush(NULL_BRUSH); /* less flicker */
     if (!RegisterClassW(&WndClass))
         return -1;
     WndClass.lpszClassName  = WC_ZOOM;
@@ -1714,7 +1813,8 @@ ImageView_Main(HWND hwnd, LPCWSTR szFileName)
     /* Message Loop */
     while (GetMessageW(&msg, NULL, 0, 0) > 0)
     {
-        if (g_hwndFullscreen && TranslateAcceleratorW(g_hwndFullscreen, 
hAccel, &msg))
+        const HWND hwndFull = g_hwndFullscreen;
+        if (IsWindowVisible(hwndFull) && TranslateAcceleratorW(hwndFull, 
hAccel, &msg))
             continue;
         if (TranslateAcceleratorW(hMainWnd, hAccel, &msg))
             continue;
diff --git a/dll/win32/shimgvw/shimgvw.rc b/dll/win32/shimgvw/shimgvw.rc
index bb46198ded1..bec550cb4c3 100644
--- a/dll/win32/shimgvw/shimgvw.rc
+++ b/dll/win32/shimgvw/shimgvw.rc
@@ -43,10 +43,19 @@ BEGIN
     "B",         IDC_BEST_FIT,   VIRTKEY, CONTROL
     "A",         IDC_REAL_SIZE,  VIRTKEY, CONTROL
     VK_F11,      IDC_SLIDE_SHOW, VIRTKEY
+    VK_RETURN,   IDC_TOGGLEFULLSCREEN, VIRTKEY, ALT
+    VK_ADD,      IDC_INCTIMER,   VIRTKEY, SHIFT
+    VK_OEM_PLUS, IDC_INCTIMER,   VIRTKEY, SHIFT
+    VK_OEM_MINUS,IDC_DECTIMER,   VIRTKEY, SHIFT
+    VK_SUBTRACT, IDC_DECTIMER,   VIRTKEY, SHIFT
     VK_ADD,      IDC_ZOOM_IN,    VIRTKEY
+    VK_ADD,      IDC_ZOOM_IN,    VIRTKEY, CONTROL
+    VK_OEM_PLUS, IDC_ZOOM_IN,    VIRTKEY
+    VK_OEM_PLUS, IDC_ZOOM_IN,    VIRTKEY, CONTROL
     VK_SUBTRACT, IDC_ZOOM_OUT,   VIRTKEY
-    VK_OEM_PLUS, IDC_ZOOM_IN,    VIRTKEY, SHIFT
+    VK_SUBTRACT, IDC_ZOOM_OUT,   VIRTKEY, CONTROL
     VK_OEM_MINUS,IDC_ZOOM_OUT,   VIRTKEY
+    VK_OEM_MINUS,IDC_ZOOM_OUT,   VIRTKEY, CONTROL
     "K",         IDC_ROT_CLOCKW, VIRTKEY, CONTROL
     "L",         IDC_ROT_COUNCW, VIRTKEY, CONTROL
     VK_DELETE,   IDC_DELETE,     VIRTKEY

Reply via email to