Progress bar and Status bar: Redraw Immediately, Bug Fixes

Michael Kaufmann hallo at michael-kaufmann.ch
Sun Aug 21 08:41:31 CDT 2005


This is a better patch (with tests, for the progress bar and status bar 
only ) for the issue discussed here:
http://www.winehq.org/hypermail/wine-devel/2004/09/0535.html

Changelog:
  - Status bar: Redraw immediately upon WM_SETTEXT, WM_SETFONT, 
SB_SETTEXT, SB_SETICON
  - Status bar: SB_SETICON didn't work for simple status bars
  - Progress bar: Redraw immediately upon PBM_SETPOS, PBM_DELTAPOS, 
PBM_STEPIT
  - Add SB_SIMPLEID to commctrl.h
  - New tests

-------------- next part --------------
Index: dlls/comctl32/progress.c
===================================================================
RCS file: /home/wine/wine/dlls/comctl32/progress.c,v
retrieving revision 1.42
diff -u -r1.42 progress.c
--- dlls/comctl32/progress.c	15 Aug 2005 09:34:02 -0000	1.42
+++ dlls/comctl32/progress.c	21 Aug 2005 12:57:49 -0000
@@ -513,6 +513,7 @@
         }
 
         InvalidateRect(infoPtr->Self, &rect, FALSE);
+        UpdateWindow(infoPtr->Self);
     }
     return 0;
 }
@@ -660,6 +661,7 @@
 	    PROGRESS_CoercePos (infoPtr);
 	    TRACE("PBM_DELTAPOS: current pos changed from %d to %d\n", oldVal, infoPtr->CurVal);
             PROGRESS_Invalidate( infoPtr, oldVal, infoPtr->CurVal );
+            UpdateWindow( infoPtr->Self );
         }
         return oldVal;
     }
@@ -673,6 +675,7 @@
 	    PROGRESS_CoercePos(infoPtr);
 	    TRACE("PBM_SETPOS: current pos changed from %d to %d\n", oldVal, infoPtr->CurVal);
             PROGRESS_Invalidate( infoPtr, oldVal, infoPtr->CurVal );
+            UpdateWindow( infoPtr->Self );
         }
         return oldVal;
     }
@@ -699,6 +702,7 @@
 	{
 	    TRACE("PBM_STEPIT: current pos changed from %d to %d\n", oldVal, infoPtr->CurVal);
             PROGRESS_Invalidate( infoPtr, oldVal, infoPtr->CurVal );
+            UpdateWindow( infoPtr->Self );
 	}
         return oldVal;
     }
Index: dlls/comctl32/status.c
===================================================================
RCS file: /home/wine/wine/dlls/comctl32/status.c,v
retrieving revision 1.74
diff -u -r1.74 status.c
--- dlls/comctl32/status.c	11 Aug 2005 18:34:45 -0000	1.74
+++ dlls/comctl32/status.c	21 Aug 2005 12:57:55 -0000
@@ -38,6 +38,7 @@
  * 	-- CCS_RIGHT
  * 	-- CCS_TOP
  * 	-- CCS_VERT (defaults to RIGHT)
+ * 	-- WM_SETFONT: Adjust the control size (undocumented)
  */
 
 #include <stdarg.h>
@@ -593,15 +594,19 @@
 	if (infoPtr->part0.hIcon == hIcon) /* same as - no redraw */
 	    return TRUE;
 	infoPtr->part0.hIcon = hIcon;
-	if (infoPtr->simple)
+	if (infoPtr->simple) {
             InvalidateRect(infoPtr->Self, &infoPtr->part0.bound, FALSE);
+            UpdateWindow(infoPtr->Self);
+        }
     } else {
 	if (infoPtr->parts[nPart].hIcon == hIcon) /* same as - no redraw */
 	    return TRUE;
 
 	infoPtr->parts[nPart].hIcon = hIcon;
-	if (!(infoPtr->simple))
+	if (!(infoPtr->simple)) {
             InvalidateRect(infoPtr->Self, &infoPtr->parts[nPart].bound, FALSE);
+            UpdateWindow(infoPtr->Self);
+        }
     }
     return TRUE;
 }
@@ -734,7 +739,7 @@
     /* MSDN says: "If the parameter is set to SB_SIMPLEID (255), the status
      * window is assumed to be a simple window */
 
-    if (nPart == 0x00ff) {
+    if (nPart == SB_SIMPLEID) {
 	part = &infoPtr->part0;
     } else {
 	if (infoPtr->parts && nPart >= 0 && nPart < infoPtr->numParts) {
@@ -786,6 +791,7 @@
 	part->text = ntext;
     }
     InvalidateRect(infoPtr->Self, &part->bound, FALSE);
+    UpdateWindow(infoPtr->Self);
 
     return TRUE;
 }
@@ -1116,8 +1122,10 @@
 {
     infoPtr->hFont = font;
     TRACE("%p\n", infoPtr->hFont);
-    if (redraw)
+    if (redraw) {
         InvalidateRect(infoPtr->Self, NULL, FALSE);
+        UpdateWindow(infoPtr->Self);
+    }
 
     return 0;
 }
@@ -1155,6 +1163,7 @@
     }
 
     InvalidateRect(infoPtr->Self, &part->bound, FALSE);
+    UpdateWindow(infoPtr->Self);
 
     return TRUE;
 }
@@ -1229,7 +1238,7 @@
 StatusWindowProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
 {
     STATUS_INFO *infoPtr = (STATUS_INFO *)GetWindowLongPtrW (hwnd, 0);
-    INT nPart = ((INT) wParam) & 0x00ff;
+    INT nPart = (INT) wParam;
     LRESULT res;
 
     TRACE("hwnd=%p msg=%x wparam=%x lparam=%lx\n", hwnd, msg, wParam, lParam);
Index: dlls/comctl32/tests/Makefile.in
===================================================================
RCS file: /home/wine/wine/dlls/comctl32/tests/Makefile.in,v
retrieving revision 1.8
diff -u -r1.8 Makefile.in
--- dlls/comctl32/tests/Makefile.in	3 Jul 2005 12:02:10 -0000	1.8
+++ dlls/comctl32/tests/Makefile.in	21 Aug 2005 12:57:55 -0000
@@ -9,6 +9,8 @@
 	dpa.c \
 	imagelist.c \
 	mru.c \
+	progress.c \
+	status.c \
 	subclass.c \
 	tab.c \
 	treeview.c \
Index: include/commctrl.h
===================================================================
RCS file: /home/wine/wine/include/commctrl.h,v
retrieving revision 1.152
diff -u -r1.152 commctrl.h
--- include/commctrl.h	15 Aug 2005 09:44:53 -0000	1.152
+++ include/commctrl.h	21 Aug 2005 12:58:20 -0000
@@ -297,6 +297,8 @@
 
 #define SBARS_SIZEGRIP		0x0100
 
+#define SB_SIMPLEID		0xff
+
 #define SB_SETTEXTA		(WM_USER+1)
 #define SB_SETTEXTW		(WM_USER+11)
 #define SB_SETTEXT		WINELIB_NAME_AW(SB_SETTEXT)
--- /dev/null	2005-08-21 16:36:21.997817008 +0200
+++ dlls/comctl32/tests/progress.c	2005-08-21 14:40:10.719356392 +0200
@@ -0,0 +1,148 @@
+/* Unit tests for the progress bar control.
+ *
+ * Copyright 2005 Michael Kaufmann
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <assert.h>
+#include <stdarg.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "wingdi.h"
+#include "winuser.h"
+#include "commctrl.h" 
+
+#include "wine/test.h"
+
+
+HWND hProgressParentWnd, hProgressWnd;
+
+
+LRESULT CALLBACK ProgressTestWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+    switch(msg) {
+    
+    case WM_DESTROY:
+        PostQuitMessage(0);
+        break;
+  
+    default:
+        return DefWindowProcA(hWnd, msg, wParam, lParam);
+    }
+    
+    return 0L;
+}
+
+
+static void update_window(HWND hWnd)
+{
+    UpdateWindow(hWnd);
+    ok(!GetUpdateRect(hWnd, NULL, FALSE), "GetUpdateRect must return zero after UpdateWindow\n");    
+}
+
+
+static void init(void)
+{
+    WNDCLASSA wc;
+    INITCOMMONCONTROLSEX icex;
+    RECT rect;
+    
+    icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
+    icex.dwICC   = ICC_PROGRESS_CLASS;
+    InitCommonControlsEx(&icex);
+  
+    wc.style = CS_HREDRAW | CS_VREDRAW;
+    wc.cbClsExtra = 0;
+    wc.cbWndExtra = 0;
+    wc.hInstance = GetModuleHandleA(NULL);
+    wc.hIcon = NULL;
+    wc.hCursor = LoadCursorA(NULL, MAKEINTRESOURCEA(IDC_ARROW));
+    wc.hbrBackground = GetSysColorBrush(COLOR_WINDOW);
+    wc.lpszMenuName = NULL;
+    wc.lpszClassName = "ProgressBarTestClass";
+    wc.lpfnWndProc = ProgressTestWndProc;
+    RegisterClassA(&wc);
+    
+    rect.left = 0;
+    rect.top = 0;
+    rect.right = 400;
+    rect.bottom = 20;
+    assert(AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, FALSE));
+    
+    hProgressParentWnd = CreateWindowExA(0, "ProgressBarTestClass", "Progress Bar Test", WS_OVERLAPPEDWINDOW,
+      CW_USEDEFAULT, CW_USEDEFAULT, rect.right - rect.left, rect.bottom - rect.top, NULL, NULL, GetModuleHandleA(NULL), 0);
+    assert(hProgressParentWnd != NULL);
+    
+    GetClientRect(hProgressParentWnd, &rect);
+    hProgressWnd = CreateWindowEx(0, PROGRESS_CLASS, "", WS_CHILD | WS_VISIBLE,
+      0, 0, rect.right, rect.bottom, hProgressParentWnd, NULL, GetModuleHandleA(NULL), 0);
+    assert(hProgressWnd != NULL);
+    
+    ShowWindow(hProgressParentWnd, SW_SHOWNORMAL);
+    ok(GetUpdateRect(hProgressParentWnd, NULL, FALSE), "GetUpdateRect: There should be a region that needs to be updated\n");
+    update_window(hProgressParentWnd);    
+}
+
+
+/*
+ * Tests if a progress bar repaints itself immediately when it receives
+ * some specific messages.
+ */
+static void test_redraw(void)
+{
+    SendMessageA(hProgressWnd, PBM_SETRANGE, 0, MAKELPARAM(0, 100));
+    SendMessageA(hProgressWnd, PBM_SETPOS, 10, 0);
+    SendMessageA(hProgressWnd, PBM_SETSTEP, 20, 0);
+    update_window(hProgressWnd);
+
+    /* PBM_SETPOS */
+    ok(SendMessageA(hProgressWnd, PBM_SETPOS, 50, 0) == 10, "PBM_SETPOS must return the previous position\n");
+    ok(!GetUpdateRect(hProgressWnd, NULL, FALSE), "PBM_SETPOS: The progress bar should be redrawn immediately\n");
+    
+    /* PBM_DELTAPOS */
+    ok(SendMessageA(hProgressWnd, PBM_DELTAPOS, 15, 0) == 50, "PBM_DELTAPOS must return the previous position\n");
+    ok(!GetUpdateRect(hProgressWnd, NULL, FALSE), "PBM_DELTAPOS: The progress bar should be redrawn immediately\n");
+    
+    /* PBM_SETPOS */
+    ok(SendMessageA(hProgressWnd, PBM_SETPOS, 80, 0) == 65, "PBM_SETPOS must return the previous position\n");
+    ok(!GetUpdateRect(hProgressWnd, NULL, FALSE), "PBM_SETPOS: The progress bar should be redrawn immediately\n");
+    
+    /* PBM_STEPIT */
+    ok(SendMessageA(hProgressWnd, PBM_STEPIT, 0, 0) == 80, "PBM_STEPIT must return the previous position\n");
+    ok(!GetUpdateRect(hProgressWnd, NULL, FALSE), "PBM_STEPIT: The progress bar should be redrawn immediately\n");
+    ok((UINT)SendMessageA(hProgressWnd, PBM_GETPOS, 0, 0) == 100, "PBM_GETPOS returned a wrong position\n");
+    
+    /* PBM_SETRANGE and PBM_SETRANGE32:
+    Usually the progress bar doesn't repaint itself immediately. If the
+    position is not in the new range, it does.
+    Don't test this, it may change in future Windows versions. */
+}
+
+
+START_TEST(progress)
+{
+    MSG msg;
+    init();
+    
+    test_redraw();
+    
+    PostMessageA(hProgressParentWnd, WM_CLOSE, 0, 0);
+    while (GetMessageA(&msg,0,0,0)) {
+        TranslateMessage(&msg);
+        DispatchMessageA(&msg);
+    }
+}
--- /dev/null	2005-08-21 16:36:21.997817008 +0200
+++ dlls/comctl32/tests/status.c	2005-08-21 14:39:44.276376336 +0200
@@ -0,0 +1,211 @@
+/* Unit tests for the status bar control.
+ *
+ * Copyright 2005 Michael Kaufmann
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <assert.h>
+#include <stdarg.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "wingdi.h"
+#include "winuser.h"
+#include "commctrl.h" 
+
+#include "wine/test.h"
+
+
+HWND hStatusParentWnd, hStatusWnd;
+char first_status_text[] = "First Status Text";
+char second_status_text[] = "Second Status Text";
+
+
+LRESULT CALLBACK StatusTestWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+    switch(msg) {
+    
+    case WM_DESTROY:
+        PostQuitMessage(0);
+        break;
+  
+    default:
+        return DefWindowProcA(hWnd, msg, wParam, lParam);
+    }
+    
+    return 0L;
+}
+
+
+static void update_window(HWND hWnd)
+{
+    UpdateWindow(hWnd);
+    ok(!GetUpdateRect(hWnd, NULL, FALSE), "GetUpdateRect must return zero after UpdateWindow\n");    
+}
+
+
+static void init(void)
+{
+    WNDCLASSA wc;
+    INITCOMMONCONTROLSEX icex;
+    RECT rect;
+    
+    icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
+    icex.dwICC   = ICC_BAR_CLASSES;
+    InitCommonControlsEx(&icex);
+  
+    wc.style = CS_HREDRAW | CS_VREDRAW;
+    wc.cbClsExtra = 0;
+    wc.cbWndExtra = 0;
+    wc.hInstance = GetModuleHandleA(NULL);
+    wc.hIcon = NULL;
+    wc.hCursor = LoadCursorA(NULL, MAKEINTRESOURCEA(IDC_ARROW));
+    wc.hbrBackground = GetSysColorBrush(COLOR_WINDOW);
+    wc.lpszMenuName = NULL;
+    wc.lpszClassName = "StatusBarTestClass";
+    wc.lpfnWndProc = StatusTestWndProc;
+    RegisterClassA(&wc);
+    
+    rect.left = 0;
+    rect.top = 0;
+    rect.right = 300;
+    rect.bottom = 200;
+    assert(AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, FALSE));
+    
+    hStatusParentWnd = CreateWindowExA(0, "StatusBarTestClass", "Status Bar Test", WS_OVERLAPPEDWINDOW,
+      CW_USEDEFAULT, CW_USEDEFAULT, rect.right - rect.left, rect.bottom - rect.top, NULL, NULL, GetModuleHandleA(NULL), 0);
+    assert(hStatusParentWnd != NULL);
+    
+    hStatusWnd = CreateWindowEx(0, STATUSCLASSNAME, "", WS_CHILD | WS_VISIBLE,
+      0, 0, 0, 0, hStatusParentWnd, NULL, GetModuleHandleA(NULL), 0);
+    assert(hStatusWnd != NULL);
+      
+    ShowWindow(hStatusParentWnd, SW_SHOWNORMAL);
+    ok(GetUpdateRect(hStatusParentWnd, NULL, FALSE), "GetUpdateRect: There should be a region that needs to be updated\n");
+    update_window(hStatusParentWnd);
+}
+
+
+static HFONT create_some_font(void)
+{
+    return CreateFont(30, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE,
+      DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
+      DEFAULT_QUALITY, DEFAULT_PITCH, "Arial");
+}
+
+
+/*
+ * Tests if a simple status bar repaints itself immediately when it receives
+ * some specific messages.
+ */
+static void test_redraw_simple_statusbar(void)
+{
+    HICON icon;
+    HFONT font, old_font;
+    
+    SendMessageA(hStatusWnd, SB_SIMPLE, TRUE, 0);
+    update_window(hStatusWnd);
+    
+    /* SB_SETTEXT */
+    ok(SendMessageA(hStatusWnd, SB_SETTEXT, SB_SIMPLEID, (LPARAM)first_status_text), "SB_SETTEXT failed\n");
+    ok(!GetUpdateRect(hStatusWnd, NULL, FALSE), "SB_SETTEXT: The new text should be drawn immediately\n");
+    
+    update_window(hStatusWnd);
+    
+    /* SB_SETICON */
+    icon = LoadIcon(NULL, IDI_INFORMATION);
+    ok(icon != NULL, "LoadIcon failed\n");
+    ok(SendMessageA(hStatusWnd, SB_SETICON, -1, (LPARAM)icon), "SB_SETICON failed\n");
+    ok(!GetUpdateRect(hStatusWnd, NULL, FALSE), "SB_SETICON: The new icon should be drawn immediately\n");
+    
+    update_window(hStatusWnd);
+    
+    /* WM_SETFONT */
+    font = create_some_font();
+    ok(font != NULL, "CreateFont failed\n");
+    old_font = (HFONT)SendMessageA(hStatusWnd, WM_GETFONT, 0, 0);
+    SendMessageA(hStatusWnd, WM_SETFONT, (WPARAM)font, TRUE);
+    ok(!GetUpdateRect(hStatusWnd, NULL, FALSE), "WM_SETFONT: The text should be redrawn immediately\n");
+    
+    SendMessageA(hStatusWnd, WM_SETFONT, (WPARAM)old_font, TRUE);
+    DeleteObject(font);
+}
+
+
+/*
+ * Tests if a normal status bar repaints itself immediately when it receives
+ * some specific messages.
+ */
+static void test_redraw_nonsimple_statusbar(void)
+{
+    INT widths[3];
+    HICON icon;
+    HFONT font, old_font;
+    
+    widths[0] = 50;
+    widths[1] = 100;
+    widths[2] = -1;
+    
+    SendMessageA(hStatusWnd, SB_SIMPLE, FALSE, 0);
+    ok(SendMessageA(hStatusWnd, SB_SETPARTS, 3, (LPARAM)widths), "SB_SETPARTS failed\n");
+    update_window(hStatusWnd);
+    
+    /* WM_SETTEXT (sets the text of the first part) */
+    ok(SendMessageA(hStatusWnd, WM_SETTEXT, 0, (LPARAM)first_status_text), "WM_SETTEXT failed\n");
+    ok(!GetUpdateRect(hStatusWnd, NULL, FALSE), "WM_SETTEXT: The new text should be drawn immediately\n");
+    
+    update_window(hStatusWnd);
+    
+    /* SB_SETTEXT */
+    ok(SendMessageA(hStatusWnd, SB_SETTEXT, 1, (LPARAM)second_status_text), "SB_SETTEXT failed\n");
+    ok(!GetUpdateRect(hStatusWnd, NULL, FALSE), "SB_SETTEXT: The new text should be drawn immediately\n");
+    
+    update_window(hStatusWnd);
+    
+    /* SB_SETICON */
+    icon = LoadIcon(NULL, IDI_INFORMATION);
+    ok(icon != NULL, "LoadIcon failed\n");
+    ok(SendMessageA(hStatusWnd, SB_SETICON, 2, (LPARAM)icon), "SB_SETICON failed\n");
+    ok(!GetUpdateRect(hStatusWnd, NULL, FALSE), "SB_SETICON: The new icon should be drawn immediately\n");
+    
+    update_window(hStatusWnd);
+    
+    /* WM_SETFONT */
+    font = create_some_font();
+    ok(font != NULL, "CreateFont failed\n");
+    old_font = (HFONT)SendMessageA(hStatusWnd, WM_GETFONT, 0, 0);
+    SendMessageA(hStatusWnd, WM_SETFONT, (WPARAM)font, TRUE);
+    ok(!GetUpdateRect(hStatusWnd, NULL, FALSE), "WM_SETFONT: The text should be redrawn immediately\n");
+    
+    SendMessageA(hStatusWnd, WM_SETFONT, (WPARAM)old_font, TRUE);
+    DeleteObject(font);
+}
+
+
+START_TEST(status)
+{
+    MSG msg;
+    init();
+    
+    test_redraw_simple_statusbar();
+    test_redraw_nonsimple_statusbar();
+    
+    PostMessageA(hStatusParentWnd, WM_CLOSE, 0, 0);
+    while (GetMessageA(&msg,0,0,0)) {
+        TranslateMessage(&msg);
+        DispatchMessageA(&msg);
+    }
+}


More information about the wine-patches mailing list