server: Define a generic context structure instead of using the platform-specific...
[wine] / dlls / comctl32 / syslink.c
index 6a383c5..8f48b4c 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * SysLink control
  *
- * Copyright 2004 Thomas Weidenmueller <w3seek@reactos.com>
+ * Copyright 2004 - 2006 Thomas Weidenmueller <w3seek@reactos.com>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  *
  * 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
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  *
- * TODO:
- * - Fix SHIFT+TAB and TAB issue (wrong link is selected when control gets the focus)
- * - Better string parsing
- * - Improve word wrapping
- * - Control styles?!
+ * NOTES
  *
+ * This code was audited for completeness against the documented features
+ * of Comctl32.dll version 6.0 on Apr. 4, 2005, by Dimitrie O. Paun.
+ * 
+ * Unless otherwise noted, we believe this code to be complete, as per
+ * the specification mentioned above.
+ * If you discover missing features, or bugs, please note them below.
  */
 
 #include <stdarg.h>
@@ -44,6 +46,7 @@ INT WINAPI StrCmpNIW(LPCWSTR,LPCWSTR,INT);
 typedef struct
 {
     int nChars;
+    int nSkip;
     RECT rc;
 } DOC_TEXTBLOCK, *PDOC_TEXTBLOCK;
 
@@ -59,7 +62,6 @@ typedef enum
 typedef struct _DOC_ITEM
 {
     struct _DOC_ITEM *Next; /* Address to the next item */
-    LPWSTR Text;            /* Text of the document item */
     UINT nText;             /* Number of characters of the text */
     SL_ITEM_TYPE Type;      /* type of the item */
     PDOC_TEXTBLOCK Blocks;  /* Array of text blocks */
@@ -70,18 +72,20 @@ typedef struct _DOC_ITEM
             UINT state;     /* Link state */
             WCHAR *szID;    /* Link ID string */
             WCHAR *szUrl;   /* Link URL string */
-            HRGN hRgn;      /* Region of the link */
         } Link;
         struct
         {
             UINT Dummy;
         } Text;
     } u;
+    WCHAR Text[1];          /* Text of the document item */
 } DOC_ITEM, *PDOC_ITEM;
 
 typedef struct
 {
     HWND      Self;         /* The window handle for this control */
+    HWND      Notify;       /* The parent handle to receive notifications */
+    DWORD     Style;        /* Styles for this control */
     PDOC_ITEM Items;        /* Address to the first document item */
     BOOL      HasFocus;     /* Whether the control has the input focus */
     int       MouseDownID;  /* ID of the link that the mouse button first selected */
@@ -90,6 +94,7 @@ typedef struct
     COLORREF  TextColor;    /* Color of the text */
     COLORREF  LinkColor;    /* Color of links */
     COLORREF  VisitedColor; /* Color of visited links */
+    WCHAR     BreakChar;    /* Break Character for the current font */
 } SYSLINK_INFO;
 
 static const WCHAR SL_LINKOPEN[] =  { '<','a', 0 };
@@ -116,11 +121,6 @@ static VOID SYSLINK_FreeDocItem (PDOC_ITEM DocItem)
         Free(DocItem->u.Link.szUrl);
     }
 
-    if(DocItem->Type == slLink && DocItem->u.Link.hRgn != NULL)
-    {
-        DeleteObject(DocItem->u.Link.hRgn);
-    }
-
     /* we don't free Text because it's just a pointer to a character in the
        entire window text string */
 
@@ -131,20 +131,20 @@ static VOID SYSLINK_FreeDocItem (PDOC_ITEM DocItem)
  * SYSLINK_AppendDocItem
  * Create and append a new document item.
  */
-static PDOC_ITEM SYSLINK_AppendDocItem (SYSLINK_INFO *infoPtr, LPWSTR Text, UINT textlen,
+static PDOC_ITEM SYSLINK_AppendDocItem (SYSLINK_INFO *infoPtr, LPCWSTR Text, UINT textlen,
                                         SL_ITEM_TYPE type, PDOC_ITEM LastItem)
 {
     PDOC_ITEM Item;
-    Item = Alloc(sizeof(DOC_ITEM) + ((textlen + 1) * sizeof(WCHAR)));
+
+    textlen = min(textlen, strlenW(Text));
+    Item = Alloc(FIELD_OFFSET(DOC_ITEM, Text[textlen + 1]));
     if(Item == NULL)
     {
         ERR("Failed to alloc DOC_ITEM structure!\n");
         return NULL;
     }
-    textlen = min(textlen, lstrlenW(Text));
 
     Item->Next = NULL;
-    Item->Text = (LPWSTR)(Item + 1);
     Item->nText = textlen;
     Item->Type = type;
     Item->Blocks = NULL;
@@ -159,7 +159,6 @@ static PDOC_ITEM SYSLINK_AppendDocItem (SYSLINK_INFO *infoPtr, LPWSTR Text, UINT
     }
     
     lstrcpynW(Item->Text, Text, textlen + 1);
-    Item->Text[textlen] = 0;
     
     return Item;
 }
@@ -188,25 +187,16 @@ static VOID SYSLINK_ClearDoc (SYSLINK_INFO *infoPtr)
  * Parses the window text string and creates a document. Returns the
  * number of document items created.
  */
-static UINT SYSLINK_ParseText (SYSLINK_INFO *infoPtr, LPWSTR Text)
+static UINT SYSLINK_ParseText (SYSLINK_INFO *infoPtr, LPCWSTR Text)
 {
-    WCHAR *current, *textstart, *linktext, *firsttag;
-    int taglen = 0, textlen, linklen, docitems = 0;
+    LPCWSTR current, textstart = NULL, linktext = NULL, firsttag = NULL;
+    int taglen = 0, textlen = 0, linklen = 0, docitems = 0;
     PDOC_ITEM Last = NULL;
     SL_ITEM_TYPE CurrentType = slText;
-    DWORD Style;
-    LPWSTR lpID, lpUrl;
+    LPCWSTR lpID, lpUrl;
     UINT lenId, lenUrl;
 
-    Style = GetWindowLongW(infoPtr->Self, GWL_STYLE);
-
-    firsttag = NULL;
-    textstart = NULL;
-    linktext = NULL;
-    textlen = 0;
-    linklen = 0;
-    
-    for(current = (WCHAR*)Text; *current != 0;)
+    for(current = Text; *current != 0;)
     {
         if(*current == '<')
         {
@@ -214,9 +204,8 @@ static UINT SYSLINK_ParseText (SYSLINK_INFO *infoPtr, LPWSTR Text)
             {
                 BOOL ValidParam = FALSE, ValidLink = FALSE;
 
-                switch (*(current + 2))
+                if(*(current + 2) == '>')
                 {
-                case '>':
                     /* we just have to deal with a <a> tag */
                     taglen = 3;
                     ValidLink = TRUE;
@@ -225,13 +214,12 @@ static UINT SYSLINK_ParseText (SYSLINK_INFO *infoPtr, LPWSTR Text)
                     linklen = 0;
                     lpID = NULL;
                     lpUrl = NULL;
-                    break;
-                case ' ':
+                }
+                else if(*(current + 2) == infoPtr->BreakChar)
                 {
                     /* we expect parameters, parse them */
-                    LPWSTR *CurrentParameter = NULL;
+                    LPCWSTR *CurrentParameter = NULL, tmp;
                     UINT *CurrentParameterLen = NULL;
-                    WCHAR *tmp;
 
                     taglen = 3;
                     tmp = current + taglen;
@@ -285,27 +273,20 @@ CheckParameter:
                          * 1. another parameter is coming, so expect a ' ' (space) character
                          * 2. the tag is being closed, so expect a '<' character
                          */
-                        switch(*tmp)
+                        if(*tmp == infoPtr->BreakChar)
                         {
-                        case ' ':
                             /* we expect another parameter, do the whole thing again */
                             taglen++;
                             tmp++;
                             goto CheckParameter;
-
-                        case '>':
+                        }
+                        else if(*tmp == '>')
+                        {
                             /* the tag is being closed, we're done */
                             ValidLink = TRUE;
                             taglen++;
-                            break;
-                        default:
-                            tmp++;
-                            break;
                         }
                     }
-                    
-                    break;
-                }
                 }
                 
                 if(ValidLink && ValidParam)
@@ -359,7 +340,7 @@ CheckParameter:
                     {
                         int nc;
 
-                        if(!(Style & WS_DISABLED))
+                        if(!(infoPtr->Style & WS_DISABLED))
                         {
                             Last->u.Link.state |= LIS_ENABLED;
                         }
@@ -367,12 +348,11 @@ CheckParameter:
                         if(lpID != NULL)
                         {
                             nc = min(lenId, strlenW(lpID));
-                            nc = min(nc, MAX_LINKID_TEXT);
-                            Last->u.Link.szID = Alloc((MAX_LINKID_TEXT + 1) * sizeof(WCHAR));
+                            nc = min(nc, MAX_LINKID_TEXT - 1);
+                            Last->u.Link.szID = Alloc((nc + 1) * sizeof(WCHAR));
                             if(Last->u.Link.szID != NULL)
                             {
                                 lstrcpynW(Last->u.Link.szID, lpID, nc + 1);
-                                Last->u.Link.szID[nc] = 0;
                             }
                         }
                         else
@@ -380,12 +360,11 @@ CheckParameter:
                         if(lpUrl != NULL)
                         {
                             nc = min(lenUrl, strlenW(lpUrl));
-                            nc = min(nc, L_MAX_URL_LENGTH);
-                            Last->u.Link.szUrl = Alloc((L_MAX_URL_LENGTH + 1) * sizeof(WCHAR));
+                            nc = min(nc, L_MAX_URL_LENGTH - 1);
+                            Last->u.Link.szUrl = Alloc((nc + 1) * sizeof(WCHAR));
                             if(Last->u.Link.szUrl != NULL)
                             {
                                 lstrcpynW(Last->u.Link.szUrl, lpUrl, nc + 1);
-                                Last->u.Link.szUrl[nc] = 0;
                             }
                         }
                         else
@@ -439,7 +418,7 @@ CheckParameter:
         {
             int nc;
 
-            if(!(Style & WS_DISABLED))
+            if(!(infoPtr->Style & WS_DISABLED))
             {
                 Last->u.Link.state |= LIS_ENABLED;
             }
@@ -447,12 +426,11 @@ CheckParameter:
             if(lpID != NULL)
             {
                 nc = min(lenId, strlenW(lpID));
-                nc = min(nc, MAX_LINKID_TEXT);
-                Last->u.Link.szID = Alloc((MAX_LINKID_TEXT + 1) * sizeof(WCHAR));
+                nc = min(nc, MAX_LINKID_TEXT - 1);
+                Last->u.Link.szID = Alloc((nc + 1) * sizeof(WCHAR));
                 if(Last->u.Link.szID != NULL)
                 {
                     lstrcpynW(Last->u.Link.szID, lpID, nc + 1);
-                    Last->u.Link.szID[nc] = 0;
                 }
             }
             else
@@ -460,12 +438,11 @@ CheckParameter:
             if(lpUrl != NULL)
             {
                 nc = min(lenUrl, strlenW(lpUrl));
-                nc = min(nc, L_MAX_URL_LENGTH);
-                Last->u.Link.szUrl = Alloc((L_MAX_URL_LENGTH + 1) * sizeof(WCHAR));
+                nc = min(nc, L_MAX_URL_LENGTH - 1);
+                Last->u.Link.szUrl = Alloc((nc + 1) * sizeof(WCHAR));
                 if(Last->u.Link.szUrl != NULL)
                 {
                     lstrcpynW(Last->u.Link.szUrl, lpUrl, nc + 1);
-                    Last->u.Link.szUrl[nc] = 0;
                 }
             }
             else
@@ -493,18 +470,28 @@ CheckParameter:
  * SYSLINK_RepaintLink
  * Repaints a link.
  */
-static VOID SYSLINK_RepaintLink (SYSLINK_INFO *infoPtr, PDOC_ITEM DocItem)
+static VOID SYSLINK_RepaintLink (const SYSLINK_INFO *infoPtr, const DOC_ITEM *DocItem)
 {
+    PDOC_TEXTBLOCK bl;
+    int n;
+
     if(DocItem->Type != slLink)
     {
         ERR("DocItem not a link!\n");
         return;
     }
     
-    if(DocItem->u.Link.hRgn != NULL)
+    bl = DocItem->Blocks;
+    if (bl != NULL)
     {
-        /* repaint the region */
-        RedrawWindow(infoPtr->Self, NULL, DocItem->u.Link.hRgn, RDW_INVALIDATE | RDW_UPDATENOW);
+        n = DocItem->nText;
+        
+        while(n > 0)
+        {
+            InvalidateRect(infoPtr->Self, &bl->rc, TRUE);
+            n -= bl->nChars + bl->nSkip;
+            bl++;
+        }
     }
 }
 
@@ -512,7 +499,7 @@ static VOID SYSLINK_RepaintLink (SYSLINK_INFO *infoPtr, PDOC_ITEM DocItem)
  * SYSLINK_GetLinkItemByIndex
  * Retrieves a document link by its index
  */
-static PDOC_ITEM SYSLINK_GetLinkItemByIndex (SYSLINK_INFO *infoPtr, int iLink)
+static PDOC_ITEM SYSLINK_GetLinkItemByIndex (const SYSLINK_INFO *infoPtr, int iLink)
 {
     PDOC_ITEM Current = infoPtr->Items;
 
@@ -531,7 +518,7 @@ static PDOC_ITEM SYSLINK_GetLinkItemByIndex (SYSLINK_INFO *infoPtr, int iLink)
  * SYSLINK_GetFocusLink
  * Retrieves the link that has the LIS_FOCUSED bit
  */
-static PDOC_ITEM SYSLINK_GetFocusLink (SYSLINK_INFO *infoPtr, int *LinkId)
+static PDOC_ITEM SYSLINK_GetFocusLink (const SYSLINK_INFO *infoPtr, int *LinkId)
 {
     PDOC_ITEM Current = infoPtr->Items;
     int id = 0;
@@ -557,7 +544,7 @@ static PDOC_ITEM SYSLINK_GetFocusLink (SYSLINK_INFO *infoPtr, int *LinkId)
  * SYSLINK_GetNextLink
  * Gets the next link
  */
-static PDOC_ITEM SYSLINK_GetNextLink (SYSLINK_INFO *infoPtr, PDOC_ITEM Current)
+static PDOC_ITEM SYSLINK_GetNextLink (const SYSLINK_INFO *infoPtr, PDOC_ITEM Current)
 {
     for(Current = (Current != NULL ? Current->Next : infoPtr->Items);
         Current != NULL;
@@ -575,7 +562,7 @@ static PDOC_ITEM SYSLINK_GetNextLink (SYSLINK_INFO *infoPtr, PDOC_ITEM Current)
  * SYSLINK_GetPrevLink
  * Gets the previous link
  */
-static PDOC_ITEM SYSLINK_GetPrevLink (SYSLINK_INFO *infoPtr, PDOC_ITEM Current)
+static PDOC_ITEM SYSLINK_GetPrevLink (const SYSLINK_INFO *infoPtr, PDOC_ITEM Current)
 {
     if(Current == NULL)
     {
@@ -615,7 +602,8 @@ static PDOC_ITEM SYSLINK_GetPrevLink (SYSLINK_INFO *infoPtr, PDOC_ITEM Current)
  * SYSLINK_WrapLine
  * Tries to wrap a line.
  */
-static BOOL SYSLINK_WrapLine (HDC hdc, LPWSTR Text, WCHAR BreakChar, int *LineLen, int nFit, LPSIZE Extent, int Width)
+static BOOL SYSLINK_WrapLine (LPWSTR Text, WCHAR BreakChar, int *LineLen,
+                             int nFit, LPSIZE Extent)
 {
     WCHAR *Current;
 
@@ -653,22 +641,26 @@ static BOOL SYSLINK_WrapLine (HDC hdc, LPWSTR Text, WCHAR BreakChar, int *LineLe
  * SYSLINK_Render
  * Renders the document in memory
  */
-static VOID SYSLINK_Render (SYSLINK_INFO *infoPtr, HDC hdc)
+static VOID SYSLINK_Render (const SYSLINK_INFO *infoPtr, HDC hdc, PRECT pRect)
 {
     RECT rc;
     PDOC_ITEM Current;
     HGDIOBJ hOldFont;
     int x, y, LineHeight;
-    TEXTMETRICW tm;
-    
-    GetClientRect(infoPtr->Self, &rc);
+    SIZE szDoc;
+
+    szDoc.cx = szDoc.cy = 0;
+
+    rc = *pRect;
     rc.right -= SL_RIGHTMARGIN;
     rc.bottom -= SL_BOTTOMMARGIN;
-    
-    if(rc.right - SL_LEFTMARGIN < 0 || rc.bottom - SL_TOPMARGIN < 0) return;
+
+    if(rc.right - SL_LEFTMARGIN < 0)
+        rc.right = MAXLONG;
+    if (rc.bottom - SL_TOPMARGIN < 0)
+        rc.bottom = MAXLONG;
     
     hOldFont = SelectObject(hdc, infoPtr->Font);
-    GetTextMetricsW(hdc, &tm);
     
     x = SL_LEFTMARGIN;
     y = SL_TOPMARGIN;
@@ -681,18 +673,20 @@ static VOID SYSLINK_Render (SYSLINK_INFO *infoPtr, HDC hdc)
         PDOC_TEXTBLOCK bl, cbl;
         INT nFit;
         SIZE szDim;
-        
+
         if(Current->nText == 0)
         {
-            ERR("DOC_ITEM with no text?!\n");
             continue;
         }
-        
+
         tx = Current->Text;
         n = Current->nText;
-        bl = Current->Blocks;
+
+        Free(Current->Blocks);
+        Current->Blocks = NULL;
+        bl = NULL;
         nBlocks = 0;
-        
+
         if(Current->Type == slText)
         {
             SelectObject(hdc, infoPtr->Font);
@@ -704,87 +698,102 @@ static VOID SYSLINK_Render (SYSLINK_INFO *infoPtr, HDC hdc)
         
         while(n > 0)
         {
-            if(GetTextExtentExPointW(hdc, tx, n, rc.right - x, &nFit, NULL, &szDim))
+            int SkipChars = 0;
+
+            /* skip break characters unless they're the first of the doc item */
+            if(tx != Current->Text || x == SL_LEFTMARGIN)
+            {
+                while(n > 0 && (*tx) == infoPtr->BreakChar)
+                {
+                    tx++;
+                    SkipChars++;
+                    n--;
+                }
+            }
+
+            if((n == 0 && SkipChars != 0) ||
+               GetTextExtentExPointW(hdc, tx, n, rc.right - x, &nFit, NULL, &szDim))
             {
                 int LineLen = n;
-                BOOL Wrap = SYSLINK_WrapLine(hdc, tx, tm.tmBreakChar, &LineLen, nFit, &szDim, rc.right - x);
+                BOOL Wrap = FALSE;
+                PDOC_TEXTBLOCK nbl;
                 
-                if(LineLen == 0)
+                if(n != 0)
                 {
-                    if(x > SL_LEFTMARGIN)
+                    Wrap = SYSLINK_WrapLine(tx, infoPtr->BreakChar, &LineLen, nFit, &szDim);
+
+                    if(LineLen == 0)
                     {
-                        /* move one line down, the word didn't fit into the line */
-                        x = SL_LEFTMARGIN;
-                        y += LineHeight;
-                        LineHeight = 0;
-                        continue;
+                        if(x > SL_LEFTMARGIN)
+                        {
+                            /* move one line down, the word didn't fit into the line */
+                            x = SL_LEFTMARGIN;
+                            y += LineHeight;
+                            LineHeight = 0;
+                            continue;
+                        }
+                        else
+                        {
+                            /* the word starts at the beginning of the line and doesn't
+                               fit into the line, so break it at the last character that fits */
+                            LineLen = max(nFit, 1);
+                        }
                     }
-                    else
+
+                    if(LineLen != n)
                     {
-                        /* the word starts at the beginning of the line and doesn't
-                           fit into the line, so break it at the last character that fits */
-                        LineLen = max(nFit, 1);
+                        if(!GetTextExtentExPointW(hdc, tx, LineLen, rc.right - x, NULL, NULL, &szDim))
+                        {
+                            if(bl != NULL)
+                            {
+                                Free(bl);
+                                bl = NULL;
+                                nBlocks = 0;
+                            }
+                            break;
+                        }
                     }
                 }
                 
-                if(LineLen != n)
-                {
-                    GetTextExtentExPointW(hdc, tx, LineLen, rc.right - x, NULL, NULL, &szDim);
-                }
-                
-                if(bl != NULL)
-                {
-                    bl = ReAlloc(bl, ++nBlocks * sizeof(DOC_TEXTBLOCK));
-                }
-                else
-                {
-                    bl = Alloc(++nBlocks * sizeof(DOC_TEXTBLOCK));
-                }
-                
-                if(bl != NULL)
+                nbl = ReAlloc(bl, (nBlocks + 1) * sizeof(DOC_TEXTBLOCK));
+                if (nbl != NULL)
                 {
+                    bl = nbl;
+                    nBlocks++;
+
                     cbl = bl + nBlocks - 1;
                     
                     cbl->nChars = LineLen;
+                    cbl->nSkip = SkipChars;
                     cbl->rc.left = x;
                     cbl->rc.top = y;
                     cbl->rc.right = x + szDim.cx;
                     cbl->rc.bottom = y + szDim.cy;
-                    
-                    x += szDim.cx;
-                    LineHeight = max(LineHeight, szDim.cy);
-                    
-                    /* (re)calculate the link's region */
-                    if(Current->Type == slLink)
+
+                    if (cbl->rc.right > szDoc.cx)
+                        szDoc.cx = cbl->rc.right;
+                    if (cbl->rc.bottom > szDoc.cy)
+                        szDoc.cy = cbl->rc.bottom;
+
+                    if(LineLen != 0)
                     {
-                        if(nBlocks <= 1)
-                        {
-                            if(Current->u.Link.hRgn != NULL)
-                            {
-                                DeleteObject(Current->u.Link.hRgn);
-                            }
-                            /* initialize the link's hRgn */
-                            Current->u.Link.hRgn = CreateRectRgnIndirect(&cbl->rc);
-                        }
-                        else if(Current->u.Link.hRgn != NULL)
+                        x += szDim.cx;
+                        LineHeight = max(LineHeight, szDim.cy);
+
+                        if(Wrap)
                         {
-                            HRGN hrgn;
-                            hrgn = CreateRectRgnIndirect(&cbl->rc);
-                            /* add the rectangle */
-                            CombineRgn(Current->u.Link.hRgn, Current->u.Link.hRgn, hrgn, RGN_OR);
-                            DeleteObject(hrgn);
+                            x = SL_LEFTMARGIN;
+                            y += LineHeight;
+                            LineHeight = 0;
                         }
                     }
-                    
-                    if(Wrap)
-                    {
-                        x = SL_LEFTMARGIN;
-                        y += LineHeight;
-                        LineHeight = 0;
-                    }
                 }
                 else
                 {
+                    Free(bl);
+                    bl = NULL;
+                    nBlocks = 0;
+
                     ERR("Failed to alloc DOC_TEXTBLOCK structure!\n");
                     break;
                 }
@@ -793,21 +802,27 @@ static VOID SYSLINK_Render (SYSLINK_INFO *infoPtr, HDC hdc)
             }
             else
             {
-                ERR("GetTextExtentExPoint() failed?!\n");
                 n--;
             }
         }
-        Current->Blocks = bl;
+
+        if(nBlocks != 0)
+        {
+            Current->Blocks = bl;
+        }
     }
     
     SelectObject(hdc, hOldFont);
+
+    pRect->right = pRect->left + szDoc.cx;
+    pRect->bottom = pRect->top + szDoc.cy;
 }
 
 /***********************************************************************
  * SYSLINK_Draw
  * Draws the SysLink control.
  */
-static LRESULT SYSLINK_Draw (SYSLINK_INFO *infoPtr, HDC hdc)
+static LRESULT SYSLINK_Draw (const SYSLINK_INFO *infoPtr, HDC hdc)
 {
     RECT rc;
     PDOC_ITEM Current;
@@ -849,16 +864,17 @@ static LRESULT SYSLINK_Draw (SYSLINK_INFO *infoPtr, HDC hdc)
 
             while(n > 0)
             {
+                tx += bl->nSkip;
                 ExtTextOutW(hdc, bl->rc.left, bl->rc.top, ETO_OPAQUE | ETO_CLIPPED, &bl->rc, tx, bl->nChars, NULL);
                 if((Current->Type == slLink) && (Current->u.Link.state & LIS_FOCUSED) && infoPtr->HasFocus)
                 {
-                    COLORREF PrevColor;
-                    PrevColor = SetBkColor(hdc, OldBkColor);
+                    COLORREF PrevTextColor;
+                    PrevTextColor = SetTextColor(hdc, infoPtr->TextColor);
                     DrawFocusRect(hdc, &bl->rc);
-                    SetBkColor(hdc, PrevColor);
+                    SetTextColor(hdc, PrevTextColor);
                 }
                 tx += bl->nChars;
-                n -= bl->nChars;
+                n -= bl->nChars + bl->nSkip;
                 bl++;
             }
         }
@@ -876,14 +892,17 @@ static LRESULT SYSLINK_Draw (SYSLINK_INFO *infoPtr, HDC hdc)
  * SYSLINK_Paint
  * Handles the WM_PAINT message.
  */
-static LRESULT SYSLINK_Paint (SYSLINK_INFO *infoPtr, HDC hdcParam)
+static LRESULT SYSLINK_Paint (const SYSLINK_INFO *infoPtr, HDC hdcParam)
 {
     HDC hdc;
     PAINTSTRUCT ps;
 
     hdc = hdcParam ? hdcParam : BeginPaint (infoPtr->Self, &ps);
-    SYSLINK_Draw (infoPtr, hdc);
-    if (!hdcParam) EndPaint (infoPtr->Self, &ps);
+    if (hdc)
+    {
+        SYSLINK_Draw (infoPtr, hdc);
+        if (!hdcParam) EndPaint (infoPtr->Self, &ps);
+    }
     return 0;
 }
 
@@ -896,6 +915,8 @@ static HFONT SYSLINK_SetFont (SYSLINK_INFO *infoPtr, HFONT hFont, BOOL bRedraw)
 {
     HDC hdc;
     LOGFONTW lf;
+    TEXTMETRICW tm;
+    RECT rcClient;
     HFONT hOldFont = infoPtr->Font;
     infoPtr->Font = hFont;
     
@@ -907,22 +928,27 @@ static HFONT SYSLINK_SetFont (SYSLINK_INFO *infoPtr, HFONT hFont, BOOL bRedraw)
     }
 
     /* Render text position and word wrapping in memory */
-    hdc = GetDC(infoPtr->Self);
-    if(hdc != NULL)
+    if (GetClientRect(infoPtr->Self, &rcClient))
     {
-        /* create a new underline font */
-        if(GetObjectW(infoPtr->Font, sizeof(LOGFONTW), &lf))
-        {
-            lf.lfUnderline = TRUE;
-            infoPtr->LinkFont = CreateFontIndirectW(&lf);
-        }
-        else
+        hdc = GetDC(infoPtr->Self);
+        if(hdc != NULL)
         {
-            ERR("Failed to create link font!\n");
-        }
+            /* create a new underline font */
+            if(GetTextMetricsW(hdc, &tm) &&
+               GetObjectW(infoPtr->Font, sizeof(LOGFONTW), &lf))
+            {
+                lf.lfUnderline = TRUE;
+                infoPtr->LinkFont = CreateFontIndirectW(&lf);
+                infoPtr->BreakChar = tm.tmBreakChar;
+            }
+            else
+            {
+                ERR("Failed to create link font!\n");
+            }
 
-        SYSLINK_Render(infoPtr, hdc);
-        ReleaseDC(infoPtr->Self, hdc);
+            SYSLINK_Render(infoPtr, hdc, &rcClient);
+            ReleaseDC(infoPtr->Self, hdc);
+        }
     }
     
     if(bRedraw)
@@ -937,27 +963,33 @@ static HFONT SYSLINK_SetFont (SYSLINK_INFO *infoPtr, HFONT hFont, BOOL bRedraw)
  *           SYSLINK_SetText
  * Set new text for the SysLink control.
  */
-static LRESULT SYSLINK_SetText (SYSLINK_INFO *infoPtr, LPWSTR Text)
+static LRESULT SYSLINK_SetText (SYSLINK_INFO *infoPtr, LPCWSTR Text)
 {
-    int textlen;
-
     /* clear the document */
     SYSLINK_ClearDoc(infoPtr);
-    
-    textlen = lstrlenW(Text);
-    if(Text == NULL || textlen == 0)
+
+    if(Text == NULL || *Text == 0)
     {
         return TRUE;
     }
-    
+
     /* let's parse the string and create a document */
     if(SYSLINK_ParseText(infoPtr, Text) > 0)
     {
+        RECT rcClient;
+
         /* Render text position and word wrapping in memory */
-        HDC hdc = GetDC(infoPtr->Self);
-        SYSLINK_Render(infoPtr, hdc);
-        SYSLINK_Draw(infoPtr, hdc);
-        ReleaseDC(infoPtr->Self, hdc);
+        if (GetClientRect(infoPtr->Self, &rcClient))
+        {
+            HDC hdc = GetDC(infoPtr->Self);
+            if (hdc != NULL)
+            {
+                SYSLINK_Render(infoPtr, hdc, &rcClient);
+                ReleaseDC(infoPtr->Self, hdc);
+
+                InvalidateRect(infoPtr->Self, NULL, TRUE);
+            }
+        }
     }
     
     return TRUE;
@@ -969,7 +1001,7 @@ static LRESULT SYSLINK_SetText (SYSLINK_INFO *infoPtr, LPWSTR Text)
  * If no document item is specified, the focus bit will be removed from all links.
  * Returns the previous focused item.
  */
-static PDOC_ITEM SYSLINK_SetFocusLink (SYSLINK_INFO *infoPtr, PDOC_ITEM DocItem)
+static PDOC_ITEM SYSLINK_SetFocusLink (const SYSLINK_INFO *infoPtr, const DOC_ITEM *DocItem)
 {
     PDOC_ITEM Current, PrevFocus = NULL;
     
@@ -1000,11 +1032,13 @@ static PDOC_ITEM SYSLINK_SetFocusLink (SYSLINK_INFO *infoPtr, PDOC_ITEM DocItem)
  *           SYSLINK_SetItem
  * Sets the states and attributes of a link item.
  */
-static LRESULT SYSLINK_SetItem (SYSLINK_INFO *infoPtr, PLITEM Item)
+static LRESULT SYSLINK_SetItem (const SYSLINK_INFO *infoPtr, const LITEM *Item)
 {
     PDOC_ITEM di;
+    int nc;
+    PWSTR szId = NULL;
+    PWSTR szUrl = NULL;
     BOOL Repaint = FALSE;
-    BOOL Ret = TRUE;
 
     if(!(Item->mask & LIF_ITEMINDEX) || !(Item->mask & (LIF_FLAGSMASK)))
     {
@@ -1018,67 +1052,77 @@ static LRESULT SYSLINK_SetItem (SYSLINK_INFO *infoPtr, PLITEM Item)
         ERR("Link %d couldn't be found\n", Item->iLink);
         return FALSE;
     }
-    
-    if(Item->mask & LIF_STATE)
-    {
-        UINT oldstate = di->u.Link.state;
-        /* clear the masked bits */
-        di->u.Link.state &= ~(Item->stateMask & LIS_MASK);
-        /* copy the bits */
-        di->u.Link.state |= (Item->state & Item->stateMask) & LIS_MASK;
-        Repaint = (oldstate != di->u.Link.state);
-        
-        /* update the focus */
-        SYSLINK_SetFocusLink(infoPtr, ((di->u.Link.state & LIS_FOCUSED) ? di : NULL));
-    }
 
     if(Item->mask & LIF_ITEMID)
     {
-        if(!di->u.Link.szID)
+        nc = min(lstrlenW(Item->szID), MAX_LINKID_TEXT - 1);
+        szId = Alloc((nc + 1) * sizeof(WCHAR));
+        if(szId)
         {
-            di->u.Link.szID = Alloc((MAX_LINKID_TEXT + 1) * sizeof(WCHAR));
-            if(!Item->szID)
-            {
-                ERR("Unable to allocate memory for link id\n");
-                Ret = FALSE;
-            }
+            lstrcpynW(szId, Item->szID, nc + 1);
         }
-        if(di->u.Link.szID)
+        else
         {
-            lstrcpynW(di->u.Link.szID, Item->szID, MAX_LINKID_TEXT + 1);
+            ERR("Unable to allocate memory for link id\n");
+            return FALSE;
         }
     }
 
     if(Item->mask & LIF_URL)
     {
-        if(!di->u.Link.szUrl)
+        nc = min(lstrlenW(Item->szUrl), L_MAX_URL_LENGTH - 1);
+        szUrl = Alloc((nc + 1) * sizeof(WCHAR));
+        if(szUrl)
         {
-            di->u.Link.szUrl = Alloc((MAX_LINKID_TEXT + 1) * sizeof(WCHAR));
-            if(!Item->szUrl)
-            {
-                ERR("Unable to allocate memory for link url\n");
-                Ret = FALSE;
-            }
+            lstrcpynW(szUrl, Item->szUrl, nc + 1);
         }
-        if(di->u.Link.szUrl)
+        else
         {
-            lstrcpynW(di->u.Link.szUrl, Item->szUrl, MAX_LINKID_TEXT + 1);
+            Free(szId);
+
+            ERR("Unable to allocate memory for link url\n");
+            return FALSE;
         }
     }
+
+    if(Item->mask & LIF_ITEMID)
+    {
+        Free(di->u.Link.szID);
+        di->u.Link.szID = szId;
+    }
+
+    if(Item->mask & LIF_URL)
+    {
+        Free(di->u.Link.szUrl);
+        di->u.Link.szUrl = szUrl;
+    }
+
+    if(Item->mask & LIF_STATE)
+    {
+        UINT oldstate = di->u.Link.state;
+        /* clear the masked bits */
+        di->u.Link.state &= ~(Item->stateMask & LIS_MASK);
+        /* copy the bits */
+        di->u.Link.state |= (Item->state & Item->stateMask) & LIS_MASK;
+        Repaint = (oldstate != di->u.Link.state);
+        
+        /* update the focus */
+        SYSLINK_SetFocusLink(infoPtr, ((di->u.Link.state & LIS_FOCUSED) ? di : NULL));
+    }
     
     if(Repaint)
     {
         SYSLINK_RepaintLink(infoPtr, di);
     }
     
-    return Ret;
+    return TRUE;
 }
 
 /***********************************************************************
  *           SYSLINK_GetItem
  * Retrieves the states and attributes of a link item.
  */
-static LRESULT SYSLINK_GetItem (SYSLINK_INFO *infoPtr, PLITEM Item)
+static LRESULT SYSLINK_GetItem (const SYSLINK_INFO *infoPtr, PLITEM Item)
 {
     PDOC_ITEM di;
     
@@ -1109,7 +1153,7 @@ static LRESULT SYSLINK_GetItem (SYSLINK_INFO *infoPtr, PLITEM Item)
     {
         if(di->u.Link.szID)
         {
-            lstrcpynW(Item->szID, di->u.Link.szID, MAX_LINKID_TEXT + 1);
+            lstrcpyW(Item->szID, di->u.Link.szID);
         }
         else
         {
@@ -1121,7 +1165,7 @@ static LRESULT SYSLINK_GetItem (SYSLINK_INFO *infoPtr, PLITEM Item)
     {
         if(di->u.Link.szUrl)
         {
-            lstrcpynW(Item->szUrl, di->u.Link.szUrl, L_MAX_URL_LENGTH + 1);
+            lstrcpyW(Item->szUrl, di->u.Link.szUrl);
         }
         else
         {
@@ -1132,11 +1176,39 @@ static LRESULT SYSLINK_GetItem (SYSLINK_INFO *infoPtr, PLITEM Item)
     return TRUE;
 }
 
+/***********************************************************************
+ *           SYSLINK_PtInDocItem
+ * Determines if a point is in the region of a document item
+ */
+static BOOL SYSLINK_PtInDocItem (const DOC_ITEM *DocItem, POINT pt)
+{
+    PDOC_TEXTBLOCK bl;
+    int n;
+
+    bl = DocItem->Blocks;
+    if (bl != NULL)
+    {
+        n = DocItem->nText;
+
+        while(n > 0)
+        {
+            if (PtInRect(&bl->rc, pt))
+            {
+                return TRUE;
+            }
+            n -= bl->nChars + bl->nSkip;
+            bl++;
+        }
+    }
+    
+    return FALSE;
+}
+
 /***********************************************************************
  *           SYSLINK_HitTest
  * Determines the link the user clicked on.
  */
-static LRESULT SYSLINK_HitTest (SYSLINK_INFO *infoPtr, PLHITTESTINFO HitTest)
+static LRESULT SYSLINK_HitTest (const SYSLINK_INFO *infoPtr, PLHITTESTINFO HitTest)
 {
     PDOC_ITEM Current;
     int id = 0;
@@ -1145,8 +1217,7 @@ static LRESULT SYSLINK_HitTest (SYSLINK_INFO *infoPtr, PLHITTESTINFO HitTest)
     {
         if(Current->Type == slLink)
         {
-            if((Current->u.Link.hRgn != NULL) &&
-               PtInRegion(Current->u.Link.hRgn, HitTest->pt.x, HitTest->pt.y))
+            if(SYSLINK_PtInDocItem(Current, HitTest->pt))
             {
                 HitTest->item.mask = 0;
                 HitTest->item.iLink = id;
@@ -1154,7 +1225,7 @@ static LRESULT SYSLINK_HitTest (SYSLINK_INFO *infoPtr, PLHITTESTINFO HitTest)
                 HitTest->item.stateMask = 0;
                 if(Current->u.Link.szID)
                 {
-                    lstrcpynW(HitTest->item.szID, Current->u.Link.szID, MAX_LINKID_TEXT + 1);
+                    lstrcpyW(HitTest->item.szID, Current->u.Link.szID);
                 }
                 else
                 {
@@ -1162,7 +1233,7 @@ static LRESULT SYSLINK_HitTest (SYSLINK_INFO *infoPtr, PLHITTESTINFO HitTest)
                 }
                 if(Current->u.Link.szUrl)
                 {
-                    lstrcpynW(HitTest->item.szUrl, Current->u.Link.szUrl, L_MAX_URL_LENGTH + 1);
+                    lstrcpyW(HitTest->item.szUrl, Current->u.Link.szUrl);
                 }
                 else
                 {
@@ -1181,7 +1252,7 @@ static LRESULT SYSLINK_HitTest (SYSLINK_INFO *infoPtr, PLHITTESTINFO HitTest)
  *           SYSLINK_GetIdealHeight
  * Returns the preferred height of a link at the current control's width.
  */
-static LRESULT SYSLINK_GetIdealHeight (SYSLINK_INFO *infoPtr)
+static LRESULT SYSLINK_GetIdealHeight (const SYSLINK_INFO *infoPtr)
 {
     HDC hdc = GetDC(infoPtr->Self);
     if(hdc != NULL)
@@ -1210,7 +1281,7 @@ static LRESULT SYSLINK_GetIdealHeight (SYSLINK_INFO *infoPtr)
  *           SYSLINK_SendParentNotify
  * Sends a WM_NOTIFY message to the parent window.
  */
-static LRESULT SYSLINK_SendParentNotify (SYSLINK_INFO *infoPtr, UINT code, PDOC_ITEM Link, int iLink)
+static LRESULT SYSLINK_SendParentNotify (const SYSLINK_INFO *infoPtr, UINT code, const DOC_ITEM *Link, int iLink)
 {
     NMLINK nml;
 
@@ -1224,7 +1295,7 @@ static LRESULT SYSLINK_SendParentNotify (SYSLINK_INFO *infoPtr, UINT code, PDOC_
     nml.item.stateMask = 0;
     if(Link->u.Link.szID)
     {
-        lstrcpynW(nml.item.szID, Link->u.Link.szID, MAX_LINKID_TEXT + 1);
+        lstrcpyW(nml.item.szID, Link->u.Link.szID);
     }
     else
     {
@@ -1232,45 +1303,33 @@ static LRESULT SYSLINK_SendParentNotify (SYSLINK_INFO *infoPtr, UINT code, PDOC_
     }
     if(Link->u.Link.szUrl)
     {
-        lstrcpynW(nml.item.szUrl, Link->u.Link.szUrl, L_MAX_URL_LENGTH + 1);
+        lstrcpyW(nml.item.szUrl, Link->u.Link.szUrl);
     }
     else
     {
         nml.item.szUrl[0] = 0;
     }
 
-    return SendMessageW(GetParent(infoPtr->Self), WM_NOTIFY, (WPARAM)nml.hdr.idFrom, (LPARAM)&nml);
+    return SendMessageW(infoPtr->Notify, WM_NOTIFY, nml.hdr.idFrom, (LPARAM)&nml);
 }
 
 /***********************************************************************
  *           SYSLINK_SetFocus
  * Handles receiving the input focus.
  */
-static LRESULT SYSLINK_SetFocus (SYSLINK_INFO *infoPtr, HWND PrevFocusWindow)
+static LRESULT SYSLINK_SetFocus (SYSLINK_INFO *infoPtr)
 {
     PDOC_ITEM Focus;
     
     infoPtr->HasFocus = TRUE;
 
-#if 1
-    /* FIXME - How to detect whether SHIFT+TAB or just TAB has been pressed?
-     *         The problem is we could get this message without keyboard input, too
-     */
-    Focus = SYSLINK_GetFocusLink(infoPtr, NULL);
-    
-    if(Focus == NULL && (Focus = SYSLINK_GetNextLink(infoPtr, NULL)))
-    {
-        SYSLINK_SetFocusLink(infoPtr, Focus);
-    }
-#else
-    /* This is a temporary hack since I'm not really sure how to detect which link to select.
-       See message above! */
+    /* We always select the first link, even if we activated the control using
+       SHIFT+TAB. This is the default behavior */
     Focus = SYSLINK_GetNextLink(infoPtr, NULL);
     if(Focus != NULL)
     {
         SYSLINK_SetFocusLink(infoPtr, Focus);
     }
-#endif
     
     SYSLINK_RepaintLink(infoPtr, Focus);
     
@@ -1281,7 +1340,7 @@ static LRESULT SYSLINK_SetFocus (SYSLINK_INFO *infoPtr, HWND PrevFocusWindow)
  *           SYSLINK_KillFocus
  * Handles losing the input focus.
  */
-static LRESULT SYSLINK_KillFocus (SYSLINK_INFO *infoPtr, HWND NewFocusWindow)
+static LRESULT SYSLINK_KillFocus (SYSLINK_INFO *infoPtr)
 {
     PDOC_ITEM Focus;
     
@@ -1300,15 +1359,14 @@ static LRESULT SYSLINK_KillFocus (SYSLINK_INFO *infoPtr, HWND NewFocusWindow)
  *           SYSLINK_LinkAtPt
  * Returns a link at the specified position
  */
-static PDOC_ITEM SYSLINK_LinkAtPt (SYSLINK_INFO *infoPtr, POINT *pt, int *LinkId, BOOL MustBeEnabled)
+static PDOC_ITEM SYSLINK_LinkAtPt (const SYSLINK_INFO *infoPtr, const POINT *pt, int *LinkId, BOOL MustBeEnabled)
 {
     PDOC_ITEM Current;
     int id = 0;
 
     for(Current = infoPtr->Items; Current != NULL; Current = Current->Next)
     {
-        if((Current->Type == slLink) && (Current->u.Link.hRgn != NULL) &&
-           PtInRegion(Current->u.Link.hRgn, pt->x, pt->y) &&
+        if((Current->Type == slLink) && SYSLINK_PtInDocItem(Current, *pt) &&
            (!MustBeEnabled || (MustBeEnabled && (Current->u.Link.state & LIS_ENABLED))))
         {
             if(LinkId != NULL)
@@ -1327,7 +1385,7 @@ static PDOC_ITEM SYSLINK_LinkAtPt (SYSLINK_INFO *infoPtr, POINT *pt, int *LinkId
  *           SYSLINK_LButtonDown
  * Handles mouse clicks
  */
-static LRESULT SYSLINK_LButtonDown (SYSLINK_INFO *infoPtr, DWORD Buttons, POINT *pt)
+static LRESULT SYSLINK_LButtonDown (SYSLINK_INFO *infoPtr, const POINT *pt)
 {
     PDOC_ITEM Current, Old;
     int id;
@@ -1335,6 +1393,8 @@ static LRESULT SYSLINK_LButtonDown (SYSLINK_INFO *infoPtr, DWORD Buttons, POINT
     Current = SYSLINK_LinkAtPt(infoPtr, pt, &id, TRUE);
     if(Current != NULL)
     {
+      SetFocus(infoPtr->Self);
+
       Old = SYSLINK_SetFocusLink(infoPtr, Current);
       if(Old != NULL && Old != Current)
       {
@@ -1342,7 +1402,6 @@ static LRESULT SYSLINK_LButtonDown (SYSLINK_INFO *infoPtr, DWORD Buttons, POINT
       }
       infoPtr->MouseDownID = id;
       SYSLINK_RepaintLink(infoPtr, Current);
-      SetFocus(infoPtr->Self);
     }
 
     return 0;
@@ -1352,7 +1411,7 @@ static LRESULT SYSLINK_LButtonDown (SYSLINK_INFO *infoPtr, DWORD Buttons, POINT
  *           SYSLINK_LButtonUp
  * Handles mouse clicks
  */
-static LRESULT SYSLINK_LButtonUp (SYSLINK_INFO *infoPtr, DWORD Buttons, POINT *pt)
+static LRESULT SYSLINK_LButtonUp (SYSLINK_INFO *infoPtr, const POINT *pt)
 {
     if(infoPtr->MouseDownID > -1)
     {
@@ -1375,7 +1434,7 @@ static LRESULT SYSLINK_LButtonUp (SYSLINK_INFO *infoPtr, DWORD Buttons, POINT *p
  *           SYSLINK_OnEnter
  * Handles ENTER key events
  */
-static BOOL SYSLINK_OnEnter (SYSLINK_INFO *infoPtr)
+static BOOL SYSLINK_OnEnter (const SYSLINK_INFO *infoPtr)
 {
     if(infoPtr->HasFocus)
     {
@@ -1396,7 +1455,7 @@ static BOOL SYSLINK_OnEnter (SYSLINK_INFO *infoPtr)
  *           SYSKEY_SelectNextPrevLink
  * Changes the currently focused link
  */
-static BOOL SYSKEY_SelectNextPrevLink (SYSLINK_INFO *infoPtr, BOOL Prev)
+static BOOL SYSKEY_SelectNextPrevLink (const SYSLINK_INFO *infoPtr, BOOL Prev)
 {
     if(infoPtr->HasFocus)
     {
@@ -1434,7 +1493,7 @@ static BOOL SYSKEY_SelectNextPrevLink (SYSLINK_INFO *infoPtr, BOOL Prev)
  * Determines if there's a next or previous link to decide whether the control
  * should capture the tab key message
  */
-static BOOL SYSLINK_NoNextLink (SYSLINK_INFO *infoPtr, BOOL Prev)
+static BOOL SYSLINK_NoNextLink (const SYSLINK_INFO *infoPtr, BOOL Prev)
 {
     PDOC_ITEM Focus, NewFocus;
 
@@ -1447,6 +1506,33 @@ static BOOL SYSLINK_NoNextLink (SYSLINK_INFO *infoPtr, BOOL Prev)
     return NewFocus == NULL;
 }
 
+/***********************************************************************
+ *           SYSLINK_GetIdealSize
+ * Calculates the ideal size of a link control at a given maximum width.
+ */
+static VOID SYSLINK_GetIdealSize (const SYSLINK_INFO *infoPtr, int cxMaxWidth, LPSIZE lpSize)
+{
+    RECT rc;
+    HDC hdc;
+
+    rc.left = rc.top = rc.bottom = 0;
+    rc.right = cxMaxWidth;
+
+    hdc = GetDC(infoPtr->Self);
+    if (hdc != NULL)
+    {
+        HGDIOBJ hOldFont = SelectObject(hdc, infoPtr->Font);
+
+        SYSLINK_Render(infoPtr, hdc, &rc);
+
+        SelectObject(hdc, hOldFont);
+        ReleaseDC(infoPtr->Self, hdc);
+
+        lpSize->cx = rc.right;
+        lpSize->cy = rc.bottom;
+    }
+}
+
 /***********************************************************************
  *           SysLinkWindowProc
  */
@@ -1455,14 +1541,15 @@ static LRESULT WINAPI SysLinkWindowProc(HWND hwnd, UINT message,
 {
     SYSLINK_INFO *infoPtr;
 
-    TRACE("hwnd=%p msg=%04x wparam=%x lParam=%lx\n", hwnd, message, wParam, lParam);
+    TRACE("hwnd=%p msg=%04x wparam=%lx lParam=%lx\n", hwnd, message, wParam, lParam);
 
     infoPtr = (SYSLINK_INFO *)GetWindowLongPtrW(hwnd, 0);
 
     if (!infoPtr && message != WM_CREATE)
-        return DefWindowProcW( hwnd, message, wParam, lParam );
+        goto HandleDefaultMessage;
 
     switch(message) {
+    case WM_PRINTCLIENT:
     case WM_PAINT:
         return SYSLINK_Paint (infoPtr, (HDC)wParam);
 
@@ -1481,17 +1568,20 @@ static LRESULT WINAPI SysLinkWindowProc(HWND hwnd, UINT message,
             return TRUE;
         }
         /* let the default window proc handle this message */
-        return DefWindowProcW(hwnd, message, wParam, lParam);
-
+        goto HandleDefaultMessage;
     }
 
     case WM_SIZE:
     {
-        HDC hdc = GetDC(infoPtr->Self);
-        if(hdc != NULL)
+        RECT rcClient;
+        if (GetClientRect(infoPtr->Self, &rcClient))
         {
-          SYSLINK_Render(infoPtr, hdc);
-          ReleaseDC(infoPtr->Self, hdc);
+            HDC hdc = GetDC(infoPtr->Self);
+            if(hdc != NULL)
+            {
+                SYSLINK_Render(infoPtr, hdc, &rcClient);
+                ReleaseDC(infoPtr->Self, hdc);
+            }
         }
         return 0;
     }
@@ -1504,21 +1594,21 @@ static LRESULT WINAPI SysLinkWindowProc(HWND hwnd, UINT message,
 
     case WM_SETTEXT:
         SYSLINK_SetText(infoPtr, (LPWSTR)lParam);
-        return DefWindowProcW(hwnd, message, wParam, lParam);
+        goto HandleDefaultMessage;
 
     case WM_LBUTTONDOWN:
     {
         POINT pt;
-        pt.x = LOWORD(lParam);
-        pt.y = HIWORD(lParam);
-        return SYSLINK_LButtonDown(infoPtr, wParam, &pt);
+        pt.x = (short)LOWORD(lParam);
+        pt.y = (short)HIWORD(lParam);
+        return SYSLINK_LButtonDown(infoPtr, &pt);
     }
     case WM_LBUTTONUP:
     {
         POINT pt;
-        pt.x = LOWORD(lParam);
-        pt.y = HIWORD(lParam);
-        return SYSLINK_LButtonUp(infoPtr, wParam, &pt);
+        pt.x = (short)LOWORD(lParam);
+        pt.y = (short)HIWORD(lParam);
+        return SYSLINK_LButtonUp(infoPtr, &pt);
     }
     
     case WM_KEYDOWN:
@@ -1535,7 +1625,7 @@ static LRESULT WINAPI SysLinkWindowProc(HWND hwnd, UINT message,
             return 0;
         }
         }
-        return DefWindowProcW(hwnd, message, wParam, lParam);
+        goto HandleDefaultMessage;
     }
     
     case WM_GETDLGCODE:
@@ -1568,8 +1658,8 @@ static LRESULT WINAPI SysLinkWindowProc(HWND hwnd, UINT message,
     {
         POINT pt;
         RECT rc;
-        pt.x = LOWORD(lParam);
-        pt.y = HIWORD(lParam);
+        pt.x = (short)LOWORD(lParam);
+        pt.y = (short)HIWORD(lParam);
         
         GetClientRect(infoPtr->Self, &rc);
         ScreenToClient(infoPtr->Self, &pt);
@@ -1596,13 +1686,33 @@ static LRESULT WINAPI SysLinkWindowProc(HWND hwnd, UINT message,
         return SYSLINK_GetItem(infoPtr, (PLITEM)lParam);
 
     case LM_GETIDEALHEIGHT:
+        if (lParam)
+        {
+            /* LM_GETIDEALSIZE */
+            SYSLINK_GetIdealSize(infoPtr, (int)wParam, (LPSIZE)lParam);
+        }
         return SYSLINK_GetIdealHeight(infoPtr);
 
     case WM_SETFOCUS:
-        return SYSLINK_SetFocus(infoPtr, (HWND)wParam);
+        return SYSLINK_SetFocus(infoPtr);
 
     case WM_KILLFOCUS:
-        return SYSLINK_KillFocus(infoPtr, (HWND)wParam);
+        return SYSLINK_KillFocus(infoPtr);
+
+    case WM_ENABLE:
+        infoPtr->Style &= ~WS_DISABLED;
+        infoPtr->Style |= (wParam ? 0 : WS_DISABLED);
+        InvalidateRect (infoPtr->Self, NULL, FALSE);
+        return 0;
+
+    case WM_STYLECHANGED:
+        if (wParam == GWL_STYLE)
+        {
+            infoPtr->Style = ((LPSTYLESTRUCT)lParam)->styleNew;
+
+            InvalidateRect(infoPtr->Self, NULL, TRUE);
+        }
+        return 0;
 
     case WM_CREATE:
         /* allocate memory for info struct */
@@ -1612,6 +1722,8 @@ static LRESULT WINAPI SysLinkWindowProc(HWND hwnd, UINT message,
 
         /* initialize the info struct */
         infoPtr->Self = hwnd;
+        infoPtr->Notify = ((LPCREATESTRUCTW)lParam)->hwndParent;
+        infoPtr->Style = ((LPCREATESTRUCTW)lParam)->style;
         infoPtr->Font = 0;
         infoPtr->LinkFont = 0;
         infoPtr->Items = NULL;
@@ -1620,9 +1732,9 @@ static LRESULT WINAPI SysLinkWindowProc(HWND hwnd, UINT message,
         infoPtr->TextColor = GetSysColor(COLOR_WINDOWTEXT);
         infoPtr->LinkColor = GetSysColor(COLOR_HIGHLIGHT);
         infoPtr->VisitedColor = GetSysColor(COLOR_HIGHLIGHT);
+        infoPtr->BreakChar = ' ';
         TRACE("SysLink Ctrl creation, hwnd=%p\n", hwnd);
-        lParam = (LPARAM)(((LPCREATESTRUCTW)lParam)->lpszName);
-        SYSLINK_SetText(infoPtr, (LPWSTR)lParam);
+        SYSLINK_SetText(infoPtr, ((LPCREATESTRUCTW)lParam)->lpszName);
         return 0;
 
     case WM_DESTROY:
@@ -1635,8 +1747,11 @@ static LRESULT WINAPI SysLinkWindowProc(HWND hwnd, UINT message,
         return 0;
 
     default:
-        if ((message >= WM_USER) && (message < WM_APP))
-           ERR("unknown msg %04x wp=%04x lp=%08lx\n", message, wParam, lParam );
+HandleDefaultMessage:
+        if ((message >= WM_USER) && (message < WM_APP) && !COMCTL32_IsReflectedMessage(message))
+        {
+            ERR("unknown msg %04x wp=%04lx lp=%08lx\n", message, wParam, lParam );
+        }
         return DefWindowProcW(hwnd, message, wParam, lParam);
     }
 }