Solve remaining problems with scroll bars in the edit control.

diff --git a/controls/edit.c b/controls/edit.c
index 99e738c..57ed054 100644
--- a/controls/edit.c
+++ b/controls/edit.c
@@ -46,8 +46,6 @@
 #define EF_UPDATE		0x0004	/* notify parent of changed state on next WM_PAINT */
 #define EF_VSCROLL_TRACK	0x0008	/* don't SetScrollPos() since we are tracking the thumb */
 #define EF_HSCROLL_TRACK	0x0010	/* don't SetScrollPos() since we are tracking the thumb */
-#define EF_VSCROLL_HACK		0x0020	/* we already have informed the user of the hacked handler */
-#define EF_HSCROLL_HACK		0x0040	/* we already have informed the user of the hacked handler */
 #define EF_AFTER_WRAP		0x0080	/* the caret is displayed after the last character of a
 					   wrapped line, instead of in front of the next character */
 #define EF_USE_SOFTBRK		0x0100	/* Enable soft breaks in text. */
@@ -1030,6 +1028,10 @@
 		EDIT_WM_SetFont(wnd, es, (HFONT)wParam, LOWORD(lParam) != 0);
 		break;
 
+	case WM_SETREDRAW:
+		/* FIXME: actually set an internal flag and behave accordingly */
+		break;
+
 	case WM_SETTEXT:
 		DPRINTF_EDIT_MSG32("WM_SETTEXT");
 		EDIT_WM_SetText(wnd, es, lParam, unicode);
@@ -2128,6 +2130,9 @@
 	    if(max_y_offset < 0) max_y_offset = 0;
 	    if(es->y_offset > max_y_offset)
 		es->y_offset = max_y_offset;
+
+	    /* force scroll info update */
+	    EDIT_UpdateScrollInfo(wnd, es);
 	}
 	else
 	/* Windows doesn't care to fix text placement for SL controls */
@@ -2543,9 +2548,6 @@
  *	own scrollbars) (and maybe only for multiline controls ?)
  *	All in all: very poorly documented
  *
- *	FIXME: now it's also broken, because of the new WM_HSCROLL /
- *		WM_VSCROLL handlers
- *
  */
 static LRESULT EDIT_EM_GetThumb(WND *wnd, EDITSTATE *es)
 {
@@ -2715,6 +2717,8 @@
 		IntersectRect(&rc, &rc1, &es->format_rect);
 		ScrollWindowEx(wnd->hwndSelf, -dx, dy,
 				NULL, &rc, (HRGN)NULL, NULL, SW_INVALIDATE);
+		/* force scroll info update */
+		EDIT_UpdateScrollInfo(wnd, es);
 	}
 	if (dx && !(es->flags & EF_HSCROLL_TRACK))
 		EDIT_NOTIFY_PARENT(wnd, EN_HSCROLL, "EN_HSCROLL");
@@ -2893,6 +2897,9 @@
 	es->flags |= EF_MODIFIED;
 	if (send_update) es->flags |= EF_UPDATE;
 	EDIT_EM_ScrollCaret(wnd, es);
+	
+	/* force scroll info update */
+	EDIT_UpdateScrollInfo(wnd, es);
 
 	/* FIXME: really inefficient */
 	EDIT_UpdateText(wnd, NULL, TRUE);
@@ -3095,6 +3102,8 @@
 	EDIT_BuildLineDefs_ML(wnd, es);
 	EDIT_UpdateText(wnd, NULL, TRUE);
 	EDIT_EM_ScrollCaret(wnd, es);
+	/* force scroll info update */
+	EDIT_UpdateScrollInfo(wnd, es);
 }
 
 
@@ -3159,6 +3168,8 @@
 	EDIT_BuildLineDefs_ML(wnd, es);
 	EDIT_UpdateText(wnd, NULL, TRUE);
 	EDIT_EM_ScrollCaret(wnd, es);
+	/* force scroll info update */
+	EDIT_UpdateScrollInfo(wnd, es);
 }
 
 
@@ -3632,6 +3643,8 @@
 		EDIT_NOTIFY_PARENT(wnd, EN_CHANGE, "EN_CHANGE");
 	   }
        }
+       /* force scroll info update */
+       EDIT_UpdateScrollInfo(wnd, es);
        return 0;
 }
 
@@ -3718,96 +3731,6 @@
     }
 }
 
-
-/*********************************************************************
- *
- *	EDIT_HScroll_Hack
- *
- *	16 bit notepad needs this.  Actually it is not _our_ hack,
- *	it is notepad's.  Notepad is sending us scrollbar messages with
- *	undocumented parameters without us even having a scrollbar ... !?!?
- *
- */
-static LRESULT EDIT_HScroll_Hack(WND *wnd, EDITSTATE *es, INT action, INT pos)
-{
-	INT dx = 0;
-	INT fw = es->format_rect.right - es->format_rect.left;
-	LRESULT ret = 0;
-
-	if (!(es->flags & EF_HSCROLL_HACK)) {
-		ERR("hacked WM_HSCROLL handler invoked\n");
-		ERR("      if you are _not_ running 16 bit notepad, please report\n");
-		ERR("      (this message is only displayed once per edit control)\n");
-		es->flags |= EF_HSCROLL_HACK;
-	}
-
-	switch (action) {
-	case SB_LINELEFT:
-		if (es->x_offset)
-			dx = -es->char_width;
-		break;
-	case SB_LINERIGHT:
-		if (es->x_offset < es->text_width)
-			dx = es->char_width;
-		break;
-	case SB_PAGELEFT:
-		if (es->x_offset)
-			dx = -fw / HSCROLL_FRACTION / es->char_width * es->char_width;
-		break;
-	case SB_PAGERIGHT:
-		if (es->x_offset < es->text_width)
-			dx = fw / HSCROLL_FRACTION / es->char_width * es->char_width;
-		break;
-	case SB_LEFT:
-		if (es->x_offset)
-			dx = -es->x_offset;
-		break;
-	case SB_RIGHT:
-		if (es->x_offset < es->text_width)
-			dx = es->text_width - es->x_offset;
-		break;
-	case SB_THUMBTRACK:
-		es->flags |= EF_HSCROLL_TRACK;
-		dx = pos * es->text_width / 100 - es->x_offset;
-		break;
-	case SB_THUMBPOSITION:
-		es->flags &= ~EF_HSCROLL_TRACK;
-		if (!(dx = pos * es->text_width / 100 - es->x_offset))
-			EDIT_NOTIFY_PARENT(wnd, EN_HSCROLL, "EN_HSCROLL");
-		break;
-	case SB_ENDSCROLL:
-		break;
-
-	/*
-	 *	FIXME : the next two are undocumented !
-	 *	Are we doing the right thing ?
-	 *	At least Win 3.1 Notepad makes use of EM_GETTHUMB this way,
-	 *	although it's also a regular control message.
-	 */
-	case EM_GETTHUMB16:
-		ret = es->text_width ? es->x_offset * 100 / es->text_width : 0;
-		break;
-	case EM_LINESCROLL16:
-		dx = pos;
-		break;
-
-	default:
-		ERR("undocumented (hacked) WM_HSCROLL parameter, please report\n");
-		return 0;
-	}
-	if (dx)
-	{
-	    INT fw = es->format_rect.right - es->format_rect.left;
-	    /* check if we are going to move too far */
-	    if(es->x_offset + dx + fw > es->text_width)
-		dx = es->text_width - fw - es->x_offset;
-	    if(dx)
-		EDIT_EM_LineScroll_internal(wnd, es, dx, 0);
-	}
-	return ret;
-}
-
-
 /*********************************************************************
  *
  *	WM_HSCROLL
@@ -3824,52 +3747,108 @@
 	if (!(es->style & ES_AUTOHSCROLL))
 		return 0;
 
-	if (!(es->style & WS_HSCROLL))
-		return EDIT_HScroll_Hack(wnd, es, action, pos);
-
 	dx = 0;
 	fw = es->format_rect.right - es->format_rect.left;
 	switch (action) {
 	case SB_LINELEFT:
+		TRACE("SB_LINELEFT\n");
 		if (es->x_offset)
 			dx = -es->char_width;
 		break;
 	case SB_LINERIGHT:
+		TRACE("SB_LINERIGHT\n");
 		if (es->x_offset < es->text_width)
 			dx = es->char_width;
 		break;
 	case SB_PAGELEFT:
+		TRACE("SB_PAGELEFT\n");
 		if (es->x_offset)
 			dx = -fw / HSCROLL_FRACTION / es->char_width * es->char_width;
 		break;
 	case SB_PAGERIGHT:
+		TRACE("SB_PAGERIGHT\n");
 		if (es->x_offset < es->text_width)
 			dx = fw / HSCROLL_FRACTION / es->char_width * es->char_width;
 		break;
 	case SB_LEFT:
+		TRACE("SB_LEFT\n");
 		if (es->x_offset)
 			dx = -es->x_offset;
 		break;
 	case SB_RIGHT:
+		TRACE("SB_RIGHT\n");
 		if (es->x_offset < es->text_width)
 			dx = es->text_width - es->x_offset;
 		break;
 	case SB_THUMBTRACK:
+		TRACE("SB_THUMBTRACK %d\n", pos);
 		es->flags |= EF_HSCROLL_TRACK;
-		dx = pos - es->x_offset;
+		if(es->style & WS_HSCROLL)
+		    dx = pos - es->x_offset;
+		else
+		{
+		    INT fw, new_x;
+		    /* Sanity check */
+		    if(pos < 0 || pos > 100) return 0;
+		    /* Assume default scroll range 0-100 */
+		    fw = es->format_rect.right - es->format_rect.left;
+		    new_x = pos * (es->text_width - fw) / 100;
+		    dx = es->text_width ? (new_x - es->x_offset) : 0;
+		}
 		break;
 	case SB_THUMBPOSITION:
+		TRACE("SB_THUMBPOSITION %d\n", pos);
 		es->flags &= ~EF_HSCROLL_TRACK;
-		if (!(dx = pos - es->x_offset)) {
-			SetScrollPos(wnd->hwndSelf, SB_HORZ, pos, TRUE);
+		if(wnd->dwStyle & WS_HSCROLL)
+		    dx = pos - es->x_offset;
+		else
+		{
+		    INT fw, new_x;
+		    /* Sanity check */
+		    if(pos < 0 || pos > 100) return 0;
+		    /* Assume default scroll range 0-100 */
+		    fw = es->format_rect.right - es->format_rect.left;
+		    new_x = pos * (es->text_width - fw) / 100;
+		    dx = es->text_width ? (new_x - es->x_offset) : 0;
+		}
+		if (!dx) {
+			/* force scroll info update */
+			EDIT_UpdateScrollInfo(wnd, es);
 			EDIT_NOTIFY_PARENT(wnd, EN_HSCROLL, "EN_HSCROLL");
 		}
 		break;
 	case SB_ENDSCROLL:
+		TRACE("SB_ENDSCROLL\n");
+		break;
+	/*
+	 *	FIXME : the next two are undocumented !
+	 *	Are we doing the right thing ?
+	 *	At least Win 3.1 Notepad makes use of EM_GETTHUMB this way,
+	 *	although it's also a regular control message.
+	 */
+	case EM_GETTHUMB: /* this one is used by NT notepad */
+	case EM_GETTHUMB16:
+	{
+		LRESULT ret;
+		if(wnd->dwStyle & WS_HSCROLL)
+		    ret = GetScrollPos(wnd->hwndSelf, SB_HORZ);
+		else
+		{
+		    /* Assume default scroll range 0-100 */
+		    INT fw = es->format_rect.right - es->format_rect.left;
+		    ret = es->text_width ? es->x_offset * 100 / (es->text_width - fw) : 0;
+		}
+		TRACE("EM_GETTHUMB: returning %ld\n", ret);
+		return ret;
+	}
+	case EM_LINESCROLL16:
+		TRACE("EM_LINESCROLL16\n");
+		dx = pos;
 		break;
 
 	default:
-		ERR("undocumented WM_HSCROLL parameter, please report\n");
+		ERR("undocumented WM_HSCROLL action %d (0x%04x), please report\n",
+                    action, action);
 		return 0;
 	}
 	if (dx)
@@ -4357,8 +4336,6 @@
 
         if (!wParam)
             EndPaint(wnd->hwndSelf, &ps);
-
-	EDIT_UpdateScrollInfo(wnd, es);
 }
 
 
@@ -4559,76 +4536,6 @@
  */
 }
 
-
-/*********************************************************************
- *
- *	EDIT_VScroll_Hack
- *
- *	16 bit notepad needs this.  Actually it is not _our_ hack,
- *	it is notepad's.  Notepad is sending us scrollbar messages with
- *	undocumented parameters without us even having a scrollbar ... !?!?
- *
- */
-static LRESULT EDIT_VScroll_Hack(WND *wnd, EDITSTATE *es, INT action, INT pos)
-{
-	INT dy = 0;
-	LRESULT ret = 0;
-
-	if (!(es->flags & EF_VSCROLL_HACK)) {
-		ERR("hacked WM_VSCROLL handler invoked\n");
-		ERR("      if you are _not_ running 16 bit notepad, please report\n");
-		ERR("      (this message is only displayed once per edit control)\n");
-		es->flags |= EF_VSCROLL_HACK;
-	}
-
-	switch (action) {
-	case SB_LINEUP:
-	case SB_LINEDOWN:
-	case SB_PAGEUP:
-	case SB_PAGEDOWN:
-		EDIT_EM_Scroll(wnd, es, action);
-		return 0;
-	case SB_TOP:
-		dy = -es->y_offset;
-		break;
-	case SB_BOTTOM:
-		dy = es->line_count - 1 - es->y_offset;
-		break;
-	case SB_THUMBTRACK:
-		es->flags |= EF_VSCROLL_TRACK;
-		dy = (pos * (es->line_count - 1) + 50) / 100 - es->y_offset;
-		break;
-	case SB_THUMBPOSITION:
-		es->flags &= ~EF_VSCROLL_TRACK;
-		if (!(dy = (pos * (es->line_count - 1) + 50) / 100 - es->y_offset))
-			EDIT_NOTIFY_PARENT(wnd, EN_VSCROLL, "EN_VSCROLL");
-		break;
-	case SB_ENDSCROLL:
-		break;
-
-	/*
-	 *	FIXME : the next two are undocumented !
-	 *	Are we doing the right thing ?
-	 *	At least Win 3.1 Notepad makes use of EM_GETTHUMB this way,
-	 *	although it's also a regular control message.
-	 */
-	case EM_GETTHUMB16:
-		ret = (es->line_count > 1) ? es->y_offset * 100 / (es->line_count - 1) : 0;
-		break;
-	case EM_LINESCROLL16:
-		dy = pos;
-		break;
-
-	default:
-		ERR("undocumented (hacked) WM_VSCROLL parameter, please report\n");
-		return 0;
-	}
-	if (dy)
-		EDIT_EM_LineScroll(wnd, es, 0, dy);
-	return ret;
-}
-
-
 /*********************************************************************
  *
  *	WM_VSCROLL
@@ -4644,41 +4551,97 @@
 	if (!(es->style & ES_AUTOVSCROLL))
 		return 0;
 
-	if (!(es->style & WS_VSCROLL))
-		return EDIT_VScroll_Hack(wnd, es, action, pos);
-
 	dy = 0;
 	switch (action) {
 	case SB_LINEUP:
 	case SB_LINEDOWN:
 	case SB_PAGEUP:
 	case SB_PAGEDOWN:
+		TRACE("action %d\n", action);
 		EDIT_EM_Scroll(wnd, es, action);
 		return 0;
-
 	case SB_TOP:
+		TRACE("SB_TOP\n");
 		dy = -es->y_offset;
 		break;
 	case SB_BOTTOM:
+		TRACE("SB_BOTTOM\n");
 		dy = es->line_count - 1 - es->y_offset;
 		break;
 	case SB_THUMBTRACK:
+		TRACE("SB_THUMBTRACK %d\n", pos);
 		es->flags |= EF_VSCROLL_TRACK;
-		dy = pos - es->y_offset;
+		if(es->style & WS_VSCROLL)
+		    dy = pos - es->y_offset;
+		else
+		{
+		    /* Assume default scroll range 0-100 */
+		    INT vlc, new_y;
+		    /* Sanity check */
+		    if(pos < 0 || pos > 100) return 0;
+		    vlc = (es->format_rect.bottom - es->format_rect.top) / es->line_height;
+		    new_y = pos * (es->line_count - vlc) / 100;
+		    dy = es->line_count ? (new_y - es->y_offset) : 0;
+		    TRACE("line_count=%d, y_offset=%d, pos=%d, dy = %d\n",
+			    es->line_count, es->y_offset, pos, dy);
+		}
 		break;
 	case SB_THUMBPOSITION:
+		TRACE("SB_THUMBPOSITION %d\n", pos);
 		es->flags &= ~EF_VSCROLL_TRACK;
-		if (!(dy = pos - es->y_offset)) {
-			SetScrollPos(wnd->hwndSelf, SB_VERT, pos, TRUE);
+		if(es->style & WS_VSCROLL)
+		    dy = pos - es->y_offset;
+		else
+		{
+		    /* Assume default scroll range 0-100 */
+		    INT vlc, new_y;
+		    /* Sanity check */
+		    if(pos < 0 || pos > 100) return 0;
+		    vlc = (es->format_rect.bottom - es->format_rect.top) / es->line_height;
+		    new_y = pos * (es->line_count - vlc) / 100;
+		    dy = es->line_count ? (new_y - es->y_offset) : 0;
+		    TRACE("line_count=%d, y_offset=%d, pos=%d, dy = %d\n",
+			    es->line_count, es->y_offset, pos, dy);
+		}
+		if (!dy)
+		{
+			/* force scroll info update */
+			EDIT_UpdateScrollInfo(wnd, es);
 			EDIT_NOTIFY_PARENT(wnd, EN_VSCROLL, "EN_VSCROLL");
 		}
 		break;
 	case SB_ENDSCROLL:
+		TRACE("SB_ENDSCROLL\n");
+		break;
+	/*
+	 *	FIXME : the next two are undocumented !
+	 *	Are we doing the right thing ?
+	 *	At least Win 3.1 Notepad makes use of EM_GETTHUMB this way,
+	 *	although it's also a regular control message.
+	 */
+	case EM_GETTHUMB: /* this one is used by NT notepad */
+	case EM_GETTHUMB16:
+	{
+		LRESULT ret;
+		if(wnd->dwStyle & WS_VSCROLL)
+		    ret = GetScrollPos(wnd->hwndSelf, SB_VERT);
+		else
+		{
+		    /* Assume default scroll range 0-100 */
+		    INT vlc = (es->format_rect.bottom - es->format_rect.top) / es->line_height;
+		    ret = es->line_count ? es->y_offset * 100 / (es->line_count - vlc) : 0;
+		}
+		TRACE("EM_GETTHUMB: returning %ld\n", ret);
+		return ret;
+	}
+	case EM_LINESCROLL16:
+		TRACE("EM_LINESCROLL16 %d\n", pos);
+		dy = pos;
 		break;
 
 	default:
-		ERR("undocumented WM_VSCROLL action %d, please report\n",
-                    action);
+		ERR("undocumented WM_VSCROLL action %d (0x%04x), please report\n",
+                    action, action);
 		return 0;
 	}
 	if (dy)