UpdateWindow vs. WM_PAINT

Michael Kaufmann hallo at michael-kaufmann.ch
Mon Sep 20 05:55:53 CDT 2004


Hi,

I've noticed that many Windows controls don't wait for a WM_PAINT 
message. They redraw themselves immediately (with GetDC/ReleaseDC, 
UpdateWindow or RedrawWindow). This is necessary if a program is 
carrying out a lengthy operation without fetching messages. TextPad is 
such a program: Its progress control doesn't get updated in WINE while 
loading a file.

To see the redraw differences between Windows and WINE, I've created 
this test program: 
http://www.michael-kaufmann.ch/WINE/ControlsRepaintTest.zip
It changes properties of different controls and then calls Sleep() to 
simulate a lengthy operation.

The big problem is that it's undocumented in which cases a control 
should wait for a WM_PAINT message and in which cases it should redraw 
itself immediately. I've observed that many controls redraw themselves 
immediately if an important property of the control gets changed (e.g. 
the position of a progress control, the text of a status bar) or if the 
user selects an item (ListBox, ListView, TreeView) or if he presses a 
key (Edit box). Most controls wait for WM_PAINT if the data that they 
display was modified. But sometimes it's just arbitrary.


Examples (tested on Windows 2000):

Edit Control:
  - Redraw immediately: WM_REPLACESEL, EM_SETSEL, WM_CLEAR, WM_PASTE, WM_CUT
  - Don't redraw immediately: WM_SETTEXT, EM_UNDO, other messages

Listbox Control:
  - Redraw immediately: LB_SETCURSEL, LB_SETTOPINDEX
  - Don't redraw immediately: LB_SETSEL, LB_RESETCONTENT, LB_ADDSTRING, 
other messages


I've created a patch which should work for most lazy programs. Please 
review it.

Regards

Michael
-------------- next part --------------
Index: dlls/comctl32/progress.c
===================================================================
RCS file: /home/wine/wine/dlls/comctl32/progress.c,v
retrieving revision 1.38
diff -u -r1.38 progress.c
--- dlls/comctl32/progress.c	25 Aug 2004 17:33:01 -0000	1.38
+++ dlls/comctl32/progress.c	19 Sep 2004 21:45:55 -0000
@@ -485,7 +485,7 @@
     infoPtr->MinVal = low;
     infoPtr->MaxVal = high;
     PROGRESS_CoercePos(infoPtr);
-    InvalidateRect(infoPtr->Self, NULL, TRUE);
+    RedrawWindow(infoPtr->Self, NULL, NULL, RDW_ERASE | RDW_INVALIDATE | RDW_UPDATENOW);
     return res;
 }
 
@@ -562,6 +562,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;
     }
@@ -575,6 +576,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;
     }
@@ -601,6 +603,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.66
diff -u -r1.66 status.c
--- dlls/comctl32/status.c	14 Sep 2004 00:45:26 -0000	1.66
+++ dlls/comctl32/status.c	19 Sep 2004 21:45:56 -0000
@@ -539,14 +539,14 @@
 	    return TRUE;
 	infoPtr->part0.hIcon = hIcon;
 	if (infoPtr->simple)
-            InvalidateRect(infoPtr->Self, &infoPtr->part0.bound, FALSE);
+	    RedrawWindow(infoPtr->Self, &infoPtr->part0.bound, NULL, RDW_INVALIDATE | RDW_UPDATENOW);	
     } else {
 	if (infoPtr->parts[nPart].hIcon == hIcon) /* same as - no redraw */
 	    return TRUE;
 
 	infoPtr->parts[nPart].hIcon = hIcon;
 	if (!(infoPtr->simple))
-            InvalidateRect(infoPtr->Self, &infoPtr->parts[nPart].bound, FALSE);
+	    RedrawWindow(infoPtr->Self, &infoPtr->parts[nPart].bound, NULL, RDW_INVALIDATE | RDW_UPDATENOW);
     }
     return TRUE;
 }
@@ -641,7 +641,7 @@
 	}
     }
     STATUSBAR_SetPartBounds (infoPtr);
-    InvalidateRect(infoPtr->Self, NULL, FALSE);
+    RedrawWindow(infoPtr->Self, NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW);
     return TRUE;
 }
 
@@ -708,7 +708,7 @@
 	    Free (part->text);
 	part->text = ntext;
     }
-    InvalidateRect(infoPtr->Self, &part->bound, FALSE);
+    RedrawWindow(infoPtr->Self, &part->bound, NULL, RDW_INVALIDATE | RDW_UPDATENOW);
 
     return TRUE;
 }
@@ -780,7 +780,8 @@
     nmhdr.idFrom = GetWindowLongPtrW (infoPtr->Self, GWLP_ID);
     nmhdr.code = SBN_SIMPLEMODECHANGE;
     SendMessageW (infoPtr->Notify, WM_NOTIFY, 0, (LPARAM)&nmhdr);
-    InvalidateRect(infoPtr->Self, NULL, FALSE);
+    RedrawWindow(infoPtr->Self, NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW);
+
     return TRUE;
 }
 
@@ -839,9 +840,7 @@
     i = SendMessageW(infoPtr->Notify, WM_NOTIFYFORMAT, (WPARAM)hwnd, NF_QUERY);
     infoPtr->NtfUnicode = (i == NFR_UNICODE);
 
-    GetClientRect (hwnd, &rect);
-    InvalidateRect (hwnd, &rect, 0);
-    UpdateWindow(hwnd);
+    RedrawWindow(hwnd, NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW);
 
     ZeroMemory (&nclm, sizeof(nclm));
     nclm.cbSize = sizeof(nclm);
@@ -1051,7 +1050,7 @@
 	}
     }
 
-    InvalidateRect(infoPtr->Self, &part->bound, FALSE);
+    RedrawWindow(infoPtr->Self, &part->bound, NULL, RDW_INVALIDATE | RDW_UPDATENOW);
 
     return TRUE;
 }
Index: dlls/comctl32/tab.c
===================================================================
RCS file: /home/wine/wine/dlls/comctl32/tab.c,v
retrieving revision 1.99
diff -u -r1.99 tab.c
--- dlls/comctl32/tab.c	14 Sep 2004 00:44:26 -0000	1.99
+++ dlls/comctl32/tab.c	19 Sep 2004 21:45:58 -0000
@@ -236,6 +236,7 @@
       infoPtr->iSelected=iItem;
       TAB_EnsureSelectionVisible(hwnd, infoPtr);
       TAB_InvalidateTabArea(hwnd, infoPtr);
+      UpdateWindow(hwnd);
   }
   return prevItem;
 }
Index: dlls/comctl32/trackbar.c
===================================================================
RCS file: /home/wine/wine/dlls/comctl32/trackbar.c,v
retrieving revision 1.62
diff -u -r1.62 trackbar.c
--- dlls/comctl32/trackbar.c	14 Sep 2004 00:45:26 -0000	1.62
+++ dlls/comctl32/trackbar.c	19 Sep 2004 21:45:59 -0000
@@ -375,12 +375,6 @@
     TRACKBAR_CalcThumb(infoPtr, infoPtr->lPos, &infoPtr->rcThumb);
 }
 
-static inline void
-TRACKBAR_InvalidateAll(TRACKBAR_INFO * infoPtr)
-{
-    InvalidateRect(infoPtr->hwndSelf, NULL, FALSE);
-}
-
 static void
 TRACKBAR_InvalidateThumb (TRACKBAR_INFO *infoPtr, LONG thumbPos)
 {
@@ -951,7 +945,8 @@
     infoPtr->lSelMax = 0;
     infoPtr->flags |= TB_SELECTIONCHANGED;
 
-    if (fRedraw) TRACKBAR_InvalidateAll(infoPtr);
+    if (fRedraw)
+        RedrawWindow(infoPtr->hwndSelf, NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW);
 
     return 0;
 }
@@ -966,7 +961,8 @@
         infoPtr->uNumTics = 0;
     }
 
-    if (fRedraw) TRACKBAR_InvalidateAll(infoPtr);
+    if (fRedraw)
+        RedrawWindow(infoPtr->hwndSelf, NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW);
 
     return 0;
 }
@@ -1096,7 +1092,11 @@
 	infoPtr->lPos = infoPtr->lRangeMax;
     infoPtr->flags |= TB_THUMBPOSCHANGED;
 
-    if (fPosition) TRACKBAR_InvalidateThumbMove(infoPtr, oldPos, lPosition);
+    if (fPosition)
+    {
+    	TRACKBAR_InvalidateThumbMove(infoPtr, oldPos, lPosition);
+	UpdateWindow(infoPtr->hwndSelf);
+    }
 
     return 0;
 }
@@ -1121,7 +1121,8 @@
     infoPtr->lPageSize = (infoPtr->lRangeMax - infoPtr->lRangeMin) / 5;
     if (infoPtr->lPageSize == 0) infoPtr->lPageSize = 1;
 
-    if (fRedraw) TRACKBAR_InvalidateAll(infoPtr);
+    if (fRedraw)
+        RedrawWindow(infoPtr->hwndSelf, NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW);
 
     return 0;
 }
@@ -1139,7 +1140,8 @@
     infoPtr->lPageSize = (infoPtr->lRangeMax - infoPtr->lRangeMin) / 5;
     if (infoPtr->lPageSize == 0) infoPtr->lPageSize = 1;
 
-    if (fRedraw) TRACKBAR_InvalidateAll(infoPtr);
+    if (fRedraw)
+    	RedrawWindow(infoPtr->hwndSelf, NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW);
 
     return 0;
 }
@@ -1157,7 +1159,8 @@
     infoPtr->lPageSize = (infoPtr->lRangeMax - infoPtr->lRangeMin) / 5;
     if (infoPtr->lPageSize == 0) infoPtr->lPageSize = 1;
 
-    if (fRedraw) TRACKBAR_InvalidateAll(infoPtr);
+    if (fRedraw)
+        RedrawWindow(infoPtr->hwndSelf, NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW);
 
     return 0;
 }
@@ -1178,7 +1181,8 @@
     if (infoPtr->lSelMax > infoPtr->lRangeMax)
         infoPtr->lSelMax = infoPtr->lRangeMax;
 
-    if (fRedraw) TRACKBAR_InvalidateAll(infoPtr);
+    if (fRedraw)
+        RedrawWindow(infoPtr->hwndSelf, NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW);
 
     return 0;
 }
@@ -1196,7 +1200,8 @@
     if (infoPtr->lSelMax > infoPtr->lRangeMax)
         infoPtr->lSelMax = infoPtr->lRangeMax;
 
-    if (fRedraw) TRACKBAR_InvalidateAll(infoPtr);
+    if (fRedraw)
+        RedrawWindow(infoPtr->hwndSelf, NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW);
 
     return 0;
 }
@@ -1214,7 +1219,8 @@
     if (infoPtr->lSelMin < infoPtr->lRangeMin)
         infoPtr->lSelMin = infoPtr->lRangeMin;
 
-    if (fRedraw) TRACKBAR_InvalidateAll(infoPtr);
+    if (fRedraw)
+        RedrawWindow(infoPtr->hwndSelf, NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW);
 
     return 0;
 }
@@ -1226,7 +1232,7 @@
     if (GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE) & TBS_FIXEDLENGTH) {
         infoPtr->uThumbLen = iLength;
 	infoPtr->flags |= TB_THUMBSIZECHANGED;
-	InvalidateRect (infoPtr->hwndSelf, &infoPtr->rcThumb, FALSE);
+	RedrawWindow(infoPtr->hwndSelf, &infoPtr->rcThumb, NULL, RDW_INVALIDATE | RDW_UPDATENOW);
     }
 
     return 0;
@@ -1254,8 +1260,8 @@
     }
     infoPtr->tics[infoPtr->uNumTics-1] = lPos;
 
-    TRACKBAR_InvalidateAll(infoPtr);
-
+    RedrawWindow(infoPtr->hwndSelf, NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW);
+    
     return TRUE;
 }
 
@@ -1266,7 +1272,7 @@
     if (GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE) & TBS_AUTOTICKS) {
         infoPtr->uTicFreq = wFreq;
 	TRACKBAR_RecalculateTics (infoPtr);
-	TRACKBAR_InvalidateAll(infoPtr);
+	RedrawWindow(infoPtr->hwndSelf, NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW);
     }
 
     return 0;
@@ -1412,7 +1418,7 @@
 {
     TRACE("\n");
     infoPtr->bFocussed = FALSE;
-    TRACKBAR_InvalidateAll(infoPtr);
+    InvalidateRect(infoPtr->hwndSelf, NULL, FALSE);
 
     return 0;
 }
@@ -1496,7 +1502,7 @@
 {
     TRACE("\n");
     infoPtr->bFocussed = TRUE;
-    TRACKBAR_InvalidateAll(infoPtr);
+    InvalidateRect(infoPtr->hwndSelf, NULL, FALSE);
 
     return 0;
 }
Index: dlls/comctl32/treeview.c
===================================================================
RCS file: /home/wine/wine/dlls/comctl32/treeview.c,v
retrieving revision 1.151
diff -u -r1.151 treeview.c
--- dlls/comctl32/treeview.c	13 Sep 2004 23:22:30 -0000	1.151
+++ dlls/comctl32/treeview.c	19 Sep 2004 21:46:02 -0000
@@ -4114,7 +4114,9 @@
 	TREEVIEW_Invalidate(infoPtr, NULL);
 	break;
     }
-
+    
+    UpdateWindow(infoPtr->hwnd);
+    
     TRACE("Leaving state %d\n", newSelect ? newSelect->state : 0);
     return TRUE;
 }
Index: dlls/user/combo.c
===================================================================
RCS file: /home/wine/wine/dlls/user/combo.c,v
retrieving revision 1.1
diff -u -r1.1 combo.c
--- dlls/user/combo.c	31 Aug 2004 01:10:08 -0000	1.1
+++ dlls/user/combo.c	19 Sep 2004 21:46:07 -0000
@@ -1141,9 +1141,9 @@
 		 SWP_NOACTIVATE | SWP_SHOWWINDOW);
 
 
-   if( !(lphc->wState & CBF_NOREDRAW) )
-     RedrawWindow( lphc->self, NULL, 0, RDW_INVALIDATE |
-			   RDW_ERASE | RDW_UPDATENOW | RDW_NOCHILDREN );
+   if( !(lphc->wState & CBF_NOREDRAW) && !IsRectEmpty(&lphc->buttonRect) )
+	RedrawWindow ( lphc->self, &lphc->buttonRect, 0, RDW_INVALIDATE |
+	                     RDW_ERASE | RDW_UPDATENOW);
 
    EnableWindow( lphc->hWndLBox, TRUE );
    if (GetCapture() != lphc->self)
@@ -1314,7 +1314,7 @@
 	   case (EN_CHANGE >> 8):
 	       /*
 	        * In some circumstances (when the selection of the combobox
-		* is changed for example) we don't wans the EN_CHANGE notification
+		* is changed for example) we don't want the EN_CHANGE notification
 		* to be forwarded to the parent of the combobox. This code
 		* checks a flag that is set in these occasions and ignores the
 		* notification.
@@ -1382,6 +1382,10 @@
 
 		CB_NOTIFY( lphc, CBN_SELCHANGE );
 
+		/* FIXME: Calling this before CB_NOTIFY looks much nicer,
+		          but Windows does it this way */
+		UpdateWindow(lphc->self);
+	
 		/* fall through */
 
 	   case LBN_SETFOCUS:
Index: dlls/user/edit.c
===================================================================
RCS file: /home/wine/wine/dlls/user/edit.c,v
retrieving revision 1.3
diff -u -r1.3 edit.c
--- dlls/user/edit.c	16 Sep 2004 20:28:10 -0000	1.3
+++ dlls/user/edit.c	19 Sep 2004 21:46:11 -0000
@@ -229,7 +229,7 @@
 static BOOL	EDIT_EM_LineScroll(EDITSTATE *es, INT dx, INT dy);
 static BOOL	EDIT_EM_LineScroll_internal(EDITSTATE *es, INT dx, INT dy);
 static LRESULT	EDIT_EM_PosFromChar(EDITSTATE *es, INT index, BOOL after_wrap);
-static void	EDIT_EM_ReplaceSel(EDITSTATE *es, BOOL can_undo, LPCWSTR lpsz_replace, BOOL send_update, BOOL honor_limit);
+static void	EDIT_EM_ReplaceSel(EDITSTATE *es, BOOL can_undo, LPCWSTR lpsz_replace, BOOL send_update, BOOL honor_limit, BOOL drawImmediately);
 static LRESULT	EDIT_EM_Scroll(EDITSTATE *es, INT action);
 static void	EDIT_EM_ScrollCaret(EDITSTATE *es);
 static void	EDIT_EM_SetHandle(EDITSTATE *es, HLOCAL hloc);
@@ -237,7 +237,7 @@
 static void	EDIT_EM_SetLimitText(EDITSTATE *es, INT limit);
 static void	EDIT_EM_SetMargins(EDITSTATE *es, INT action, INT left, INT right);
 static void	EDIT_EM_SetPasswordChar(EDITSTATE *es, WCHAR c);
-static void	EDIT_EM_SetSel(EDITSTATE *es, UINT start, UINT end, BOOL after_wrap);
+static void	EDIT_EM_SetSel(EDITSTATE *es, UINT start, UINT end, BOOL after_wrap, BOOL drawImmediately);
 static BOOL	EDIT_EM_SetTabStops(EDITSTATE *es, INT count, LPINT tabs);
 static BOOL	EDIT_EM_SetTabStops16(EDITSTATE *es, INT count, LPINT16 tabs);
 static void	EDIT_EM_SetWordBreakProc(EDITSTATE *es, LPARAM lParam);
@@ -330,7 +330,7 @@
 	if(es->style & ES_READONLY)
 	    return;
 
-	EDIT_EM_ReplaceSel(es, TRUE, empty_stringW, TRUE, TRUE);
+	EDIT_EM_ReplaceSel(es, TRUE, empty_stringW, TRUE, TRUE, TRUE);
 }
 
 
@@ -445,15 +445,15 @@
 
 	case EM_SETSEL16:
 		if ((short)LOWORD(lParam) == -1)
-			EDIT_EM_SetSel(es, (UINT)-1, 0, FALSE);
+			EDIT_EM_SetSel(es, (UINT)-1, 0, FALSE, TRUE);
 		else
-			EDIT_EM_SetSel(es, LOWORD(lParam), HIWORD(lParam), FALSE);
+			EDIT_EM_SetSel(es, LOWORD(lParam), HIWORD(lParam), FALSE, TRUE);
 		if (!wParam)
 			EDIT_EM_ScrollCaret(es);
 		result = 1;
 		break;
 	case EM_SETSEL:
-		EDIT_EM_SetSel(es, wParam, lParam, FALSE);
+		EDIT_EM_SetSel(es, wParam, lParam, FALSE, TRUE);
 		EDIT_EM_ScrollCaret(es);
 		result = 1;
 		break;
@@ -608,7 +608,7 @@
 			MultiByteToWideChar(CP_ACP, 0, textA, -1, textW, countW);
 		}
 
-		EDIT_EM_ReplaceSel(es, (BOOL)wParam, textW, TRUE, TRUE);
+		EDIT_EM_ReplaceSel(es, (BOOL)wParam, textW, TRUE, TRUE, TRUE);
 		result = 1;
 
 		if(!unicode)
@@ -1813,7 +1813,7 @@
 				e--;
 		}
 	}
-	EDIT_EM_SetSel(es, extend ? es->selection_start : e, e, FALSE);
+	EDIT_EM_SetSel(es, extend ? es->selection_start : e, e, FALSE, TRUE);
 	EDIT_EM_ScrollCaret(es);
 }
 
@@ -1839,7 +1839,7 @@
 	e = EDIT_CharFromPos(es, x, y + es->line_height, &after_wrap);
 	if (!extend)
 		s = e;
-	EDIT_EM_SetSel(es, s, e, after_wrap);
+	EDIT_EM_SetSel(es, s, e, after_wrap, TRUE);
 	EDIT_EM_ScrollCaret(es);
 }
 
@@ -1860,7 +1860,7 @@
 			HIWORD(EDIT_EM_PosFromChar(es, es->selection_end, es->flags & EF_AFTER_WRAP)), &after_wrap);
 	else
 		e = strlenW(es->text);
-	EDIT_EM_SetSel(es, extend ? es->selection_start : e, e, after_wrap);
+	EDIT_EM_SetSel(es, extend ? es->selection_start : e, e, after_wrap, TRUE);
 	EDIT_EM_ScrollCaret(es);
 }
 
@@ -1883,7 +1883,7 @@
 				e += 2;
 		}
 	}
-	EDIT_EM_SetSel(es, extend ? es->selection_start : e, e, FALSE);
+	EDIT_EM_SetSel(es, extend ? es->selection_start : e, e, FALSE, TRUE);
 	EDIT_EM_ScrollCaret(es);
 }
 
@@ -1905,7 +1905,7 @@
 			HIWORD(EDIT_EM_PosFromChar(es, es->selection_end, es->flags & EF_AFTER_WRAP)), NULL);
 	else
 		e = 0;
-	EDIT_EM_SetSel(es, extend ? es->selection_start : e, e, FALSE);
+	EDIT_EM_SetSel(es, extend ? es->selection_start : e, e, FALSE, TRUE);
 	EDIT_EM_ScrollCaret(es);
 }
 
@@ -1933,7 +1933,7 @@
 		&after_wrap);
 	if (!extend)
 		s = e;
-	EDIT_EM_SetSel(es, s, e, after_wrap);
+	EDIT_EM_SetSel(es, s, e, after_wrap, TRUE);
 	EDIT_EM_ScrollCaret(es);
 }
 
@@ -1961,7 +1961,7 @@
 		&after_wrap);
 	if (!extend)
 		s = e;
-	EDIT_EM_SetSel(es, s, e, after_wrap);
+	EDIT_EM_SetSel(es, s, e, after_wrap, TRUE);
 	EDIT_EM_ScrollCaret(es);
 }
 
@@ -1987,7 +1987,7 @@
 	e = EDIT_CharFromPos(es, x, y - es->line_height, &after_wrap);
 	if (!extend)
 		s = e;
-	EDIT_EM_SetSel(es, s, e, after_wrap);
+	EDIT_EM_SetSel(es, s, e, after_wrap, TRUE);
 	EDIT_EM_ScrollCaret(es);
 }
 
@@ -2019,7 +2019,7 @@
 	}
 	if (!extend)
 		s = e;
-	EDIT_EM_SetSel(es, s, e, FALSE);
+	EDIT_EM_SetSel(es, s, e, FALSE, TRUE);
 	EDIT_EM_ScrollCaret(es);
 }
 
@@ -2049,7 +2049,7 @@
 	}
 	if (!extend)
 		s = e;
-	EDIT_EM_SetSel(es, s, e, FALSE);
+	EDIT_EM_SetSel(es, s, e, FALSE, TRUE);
 	EDIT_EM_ScrollCaret(es);
 }
 
@@ -2897,7 +2897,7 @@
  *	FIXME: handle ES_NUMBER and ES_OEMCONVERT here
  *
  */
-static void EDIT_EM_ReplaceSel(EDITSTATE *es, BOOL can_undo, LPCWSTR lpsz_replace, BOOL send_update, BOOL honor_limit)
+static void EDIT_EM_ReplaceSel(EDITSTATE *es, BOOL can_undo, LPCWSTR lpsz_replace, BOOL send_update, BOOL honor_limit, BOOL drawImmediately)
 {
 	UINT strl = strlenW(lpsz_replace);
 	UINT tl = strlenW(es->text);
@@ -3009,7 +3009,7 @@
 	else
 	    EDIT_CalcLineWidth_SL(es);
 
-	EDIT_EM_SetSel(es, s, s, FALSE);
+	EDIT_EM_SetSel(es, s, s, FALSE, FALSE);
 	es->flags |= EF_MODIFIED;
 	if (send_update) es->flags |= EF_UPDATE;
 	if (hrgn)
@@ -3025,6 +3025,7 @@
 	/* force scroll info update */
 	EDIT_UpdateScrollInfo(es);
 
+	if (drawImmediately) UpdateWindow(es->hwndSelf);
 
 	if(es->flags & EF_UPDATE)
 	{
@@ -3421,7 +3422,7 @@
  *		In other words: this handler is OK
  *
  */
-static void EDIT_EM_SetSel(EDITSTATE *es, UINT start, UINT end, BOOL after_wrap)
+static void EDIT_EM_SetSel(EDITSTATE *es, UINT start, UINT end, BOOL after_wrap, BOOL drawImmediately)
 {
 	UINT old_start = es->selection_start;
 	UINT old_end = es->selection_end;
@@ -3466,6 +3467,8 @@
             }
 	}
         else EDIT_InvalidateText(es, start, old_end);
+	
+	if (drawImmediately) UpdateWindow(es->hwndSelf);
 }
 
 
@@ -3578,10 +3581,10 @@
 	TRACE("before UNDO:insertion length = %d, deletion buffer = %s\n",
 		     es->undo_insert_count, debugstr_w(utext));
 
-	EDIT_EM_SetSel(es, es->undo_position, es->undo_position + es->undo_insert_count, FALSE);
+	EDIT_EM_SetSel(es, es->undo_position, es->undo_position + es->undo_insert_count, FALSE, FALSE);
 	EDIT_EM_EmptyUndoBuffer(es);
-	EDIT_EM_ReplaceSel(es, TRUE, utext, TRUE, TRUE);
-	EDIT_EM_SetSel(es, es->undo_position, es->undo_position + es->undo_insert_count, FALSE);
+	EDIT_EM_ReplaceSel(es, TRUE, utext, TRUE, TRUE, FALSE);
+	EDIT_EM_SetSel(es, es->undo_position, es->undo_position + es->undo_insert_count, FALSE, FALSE);
         /* send the notification after the selection start and end are set */
         EDIT_NOTIFY_PARENT(es, EN_CHANGE, "EN_CHANGE");
 	EDIT_EM_ScrollCaret(es);
@@ -3616,7 +3619,7 @@
 				EDIT_MoveDown_ML(es, FALSE);
 			} else {
 				static const WCHAR cr_lfW[] = {'\r','\n',0};
-				EDIT_EM_ReplaceSel(es, TRUE, cr_lfW, TRUE, TRUE);
+				EDIT_EM_ReplaceSel(es, TRUE, cr_lfW, TRUE, TRUE, TRUE);
 			}
 		}
 		break;
@@ -3624,7 +3627,7 @@
 		if ((es->style & ES_MULTILINE) && !(es->style & ES_READONLY))
 		{
 			static const WCHAR tabW[] = {'\t',0};
-			EDIT_EM_ReplaceSel(es, TRUE, tabW, TRUE, TRUE);
+			EDIT_EM_ReplaceSel(es, TRUE, tabW, TRUE, TRUE, TRUE);
 		}
 		break;
 	case VK_BACK:
@@ -3633,7 +3636,7 @@
 				EDIT_WM_Clear(es);
 			else {
 				/* delete character left of caret */
-				EDIT_EM_SetSel(es, (UINT)-1, 0, FALSE);
+				EDIT_EM_SetSel(es, (UINT)-1, 0, FALSE, TRUE);
 				EDIT_MoveBackward(es, TRUE);
 				EDIT_WM_Clear(es);
 			}
@@ -3660,7 +3663,7 @@
 			WCHAR str[2];
  			str[0] = c;
  			str[1] = '\0';
- 			EDIT_EM_ReplaceSel(es, TRUE, str, TRUE, TRUE);
+ 			EDIT_EM_ReplaceSel(es, TRUE, str, TRUE, TRUE, TRUE);
  		}
 		break;
 	}
@@ -3694,7 +3697,7 @@
 			EDIT_WM_Clear(es);
 			break;
 		case EM_SETSEL:
-			EDIT_EM_SetSel(es, 0, (UINT)-1, FALSE);
+			EDIT_EM_SetSel(es, 0, (UINT)-1, FALSE, TRUE);
 			EDIT_EM_ScrollCaret(es);
 			break;
 		default:
@@ -3792,7 +3795,7 @@
         EDIT_EM_EmptyUndoBuffer(es);
 
        if (name && *name) {
-	   EDIT_EM_ReplaceSel(es, FALSE, name, FALSE, TRUE);
+	   EDIT_EM_ReplaceSel(es, FALSE, name, FALSE, TRUE, FALSE);
 	   /* if we insert text to the editline, the text scrolls out
             * of the window, as the caret is placed after the insert
             * pos normally; thus we reset es->selection... to 0 and
@@ -4158,17 +4161,17 @@
 			} else {
 				if (shift) {
 					/* delete character left of caret */
-					EDIT_EM_SetSel(es, (UINT)-1, 0, FALSE);
+					EDIT_EM_SetSel(es, (UINT)-1, 0, FALSE, TRUE);
 					EDIT_MoveBackward(es, TRUE);
 					EDIT_WM_Clear(es);
 				} else if (control) {
 					/* delete to end of line */
-					EDIT_EM_SetSel(es, (UINT)-1, 0, FALSE);
+					EDIT_EM_SetSel(es, (UINT)-1, 0, FALSE, TRUE);
 					EDIT_MoveEnd(es, TRUE);
 					EDIT_WM_Clear(es);
 				} else {
 					/* delete character right of caret */
-					EDIT_EM_SetSel(es, (UINT)-1, 0, FALSE);
+					EDIT_EM_SetSel(es, (UINT)-1, 0, FALSE, TRUE);
 					EDIT_MoveForward(es, TRUE);
 					EDIT_WM_Clear(es);
 				}
@@ -4240,7 +4243,7 @@
 	ll = EDIT_EM_LineLength(es, e);
 	s = li + EDIT_CallWordBreakProc(es, li, e - li, ll, WB_LEFT);
 	e = li + EDIT_CallWordBreakProc(es, li, e - li, ll, WB_RIGHT);
-	EDIT_EM_SetSel(es, s, e, FALSE);
+	EDIT_EM_SetSel(es, s, e, FALSE, TRUE);
 	EDIT_EM_ScrollCaret(es);
 	return 0;
 }
@@ -4264,7 +4267,7 @@
 	SetCapture(es->hwndSelf);
 	EDIT_ConfinePoint(es, &x, &y);
 	e = EDIT_CharFromPos(es, x, y, &after_wrap);
-	EDIT_EM_SetSel(es, (keys & MK_SHIFT) ? es->selection_start : e, e, after_wrap);
+	EDIT_EM_SetSel(es, (keys & MK_SHIFT) ? es->selection_start : e, e, after_wrap, TRUE);
 	EDIT_EM_ScrollCaret(es);
 	es->region_posx = es->region_posy = 0;
 	SetTimer(es->hwndSelf, 0, 100, NULL);
@@ -4323,7 +4326,7 @@
 	es->region_posx = (prex < x) ? -1 : ((prex > x) ? 1 : 0);
 	es->region_posy = (prey < y) ? -1 : ((prey > y) ? 1 : 0);
 	e = EDIT_CharFromPos(es, x, y, &after_wrap);
-	EDIT_EM_SetSel(es, es->selection_start, e, after_wrap);
+	EDIT_EM_SetSel(es, es->selection_start, e, after_wrap, TRUE);
 	EDIT_SetCaretPos(es,es->selection_end,es->flags & EF_AFTER_WRAP);
 	return 0;
 }
@@ -4533,7 +4536,7 @@
 	OpenClipboard(es->hwndSelf);
 	if ((hsrc = GetClipboardData(CF_UNICODETEXT))) {
 		src = (LPWSTR)GlobalLock(hsrc);
-		EDIT_EM_ReplaceSel(es, TRUE, src, TRUE, TRUE);
+		EDIT_EM_ReplaceSel(es, TRUE, src, TRUE, TRUE, TRUE);
 		GlobalUnlock(hsrc);
 	}
 	CloseClipboard();
@@ -4634,20 +4637,20 @@
 	    MultiByteToWideChar(CP_ACP, 0, textA, -1, text, countW);
     }
 
-	EDIT_EM_SetSel(es, 0, (UINT)-1, FALSE);
+	EDIT_EM_SetSel(es, 0, (UINT)-1, FALSE, FALSE);
 	if (text) {
 		TRACE("%s\n", debugstr_w(text));
-		EDIT_EM_ReplaceSel(es, FALSE, text, FALSE, FALSE);
+		EDIT_EM_ReplaceSel(es, FALSE, text, FALSE, FALSE, FALSE);
 		if(!unicode)
 		    HeapFree(GetProcessHeap(), 0, text);
 	} else {
 		static const WCHAR empty_stringW[] = {0};
 		TRACE("<NULL>\n");
-		EDIT_EM_ReplaceSel(es, FALSE, empty_stringW, FALSE, FALSE);
+		EDIT_EM_ReplaceSel(es, FALSE, empty_stringW, FALSE, FALSE, FALSE);
 	}
 	es->x_offset = 0;
 	es->flags &= ~EF_MODIFIED;
-	EDIT_EM_SetSel(es, 0, 0, FALSE);
+	EDIT_EM_SetSel(es, 0, 0, FALSE, FALSE);
         /* Send the notification after the selection start and end have been set
          * edit control doesn't send notification on WM_SETTEXT
          * if it is multiline, or it is part of combobox
@@ -4890,7 +4893,7 @@
 
 /*********************************************************************
  *
- *	EDIT_UpdateText
+ *	EDIT_UpdateTextRegion
  *
  */
 static void EDIT_UpdateTextRegion(EDITSTATE *es, HRGN hrgn, BOOL bErase)
Index: dlls/user/listbox.c
===================================================================
RCS file: /home/wine/wine/dlls/user/listbox.c,v
retrieving revision 1.1
diff -u -r1.1 listbox.c
--- dlls/user/listbox.c	31 Aug 2004 01:10:08 -0000	1.1
+++ dlls/user/listbox.c	19 Sep 2004 21:46:13 -0000
@@ -2363,6 +2363,12 @@
             descr->anchor_item = caret;
         LISTBOX_MoveCaret( hwnd, descr, caret, TRUE );
         LISTBOX_SetSelection( hwnd, descr, caret, TRUE, FALSE);
+
+        /* If the content has been scrolled, the new items
+         * need to be drawn immediately (Windows does it this way)
+         */
+        UpdateWindow(hwnd);
+
         if (descr->style & LBS_NOTIFY)
         {
 	    if( descr->lphc )
@@ -2712,7 +2718,9 @@
 
     case LB_SETTOPINDEX16:
     case LB_SETTOPINDEX:
-        return LISTBOX_SetTopItem( hwnd, descr, wParam, TRUE );
+        ret = LISTBOX_SetTopItem( hwnd, descr, wParam, TRUE );
+        UpdateWindow(hwnd); /* Windows does this too */
+        return ret;
 
     case LB_SETCOLUMNWIDTH16:
     case LB_SETCOLUMNWIDTH:
@@ -2831,7 +2839,9 @@
     case LB_SETCURSEL:
         if (IS_MULTISELECT(descr)) return LB_ERR;
         LISTBOX_SetCaretIndex( hwnd, descr, wParam, TRUE );
-        return LISTBOX_SetSelection( hwnd, descr, wParam, TRUE, FALSE );
+        ret = LISTBOX_SetSelection( hwnd, descr, wParam, TRUE, FALSE );
+        UpdateWindow(hwnd); /* Windows does this too */
+        return ret;
 
     case LB_GETSELCOUNT16:
     case LB_GETSELCOUNT:
Index: dlls/user/static.c
===================================================================
RCS file: /home/wine/wine/dlls/user/static.c,v
retrieving revision 1.1
diff -u -r1.1 static.c
--- dlls/user/static.c	31 Aug 2004 01:10:08 -0000	1.1
+++ dlls/user/static.c	19 Sep 2004 21:46:14 -0000
@@ -319,8 +319,6 @@
 		else
 		    lResult = DefWindowProcA( hwnd, WM_SETTEXT, wParam, lParam );
 	    }
-	    if (uMsg == WM_SETTEXT)
-		STATIC_TryPaintFcn( hwnd, full_style );
 	    break;
 	}
 	default:
@@ -331,9 +329,10 @@
 		else
 		    lResult = DefWindowProcA( hwnd, WM_SETTEXT, wParam, lParam );
 	    }
-	    if(uMsg == WM_SETTEXT)
-		InvalidateRect(hwnd, NULL, TRUE);
 	}
+	
+	STATIC_TryPaintFcn( hwnd, full_style );
+	
         return 1; /* success. FIXME: check text length */
 
     case WM_SETFONT:



More information about the wine-devel mailing list