[PATCH 5/9] [WinHelp]: implementing the first round of support for links in RichEdit

Eric Pouech eric.pouech at orange.fr
Wed Apr 23 14:38:14 CDT 2008




A+
---

 programs/winhelp/hlpfile.c |   77 ++++++++++++++++------
 programs/winhelp/hlpfile.h |   13 +++-
 programs/winhelp/winhelp.c |  154 ++++++++++++++++++++++++++++++++++++++++----
 programs/winhelp/winhelp.h |    1 
 4 files changed, 209 insertions(+), 36 deletions(-)


diff --git a/programs/winhelp/hlpfile.c b/programs/winhelp/hlpfile.c
index e327b54..aae1385 100644
--- a/programs/winhelp/hlpfile.c
+++ b/programs/winhelp/hlpfile.c
@@ -433,6 +433,7 @@ static BOOL HLPFILE_AddPage(HLPFILE *hlpfile, BYTE *buf, BYTE *end, unsigned ref
     page->next            = NULL;
     page->first_paragraph = NULL;
     page->first_macro     = NULL;
+    page->first_link      = NULL;
     page->wNumber         = GET_UINT(buf, 0x21);
     page->offset          = offset;
     page->reference       = ref;
@@ -904,8 +905,9 @@ static  BOOL    HLPFILE_LoadGfxByIndex(HLPFILE *hlpfile, unsigned index,
  *
  *
  */
-static HLPFILE_LINK*       HLPFILE_AllocLink(int cookie, const char* str, LONG hash,
-                                             BOOL clrChange, unsigned wnd)
+static HLPFILE_LINK*       HLPFILE_AllocLink(struct RtfData* rd, int cookie,
+                                             const char* str, unsigned len, LONG hash,
+                                             unsigned clrChange, unsigned wnd)
 {
     HLPFILE_LINK*  link;
     char*          link_str;
@@ -913,20 +915,31 @@ static HLPFILE_LINK*       HLPFILE_AllocLink(int cookie, const char* str, LONG h
     /* FIXME: should build a string table for the attributes.link.lpszPath
      * they are reallocated for each link
      */
-    link = HeapAlloc(GetProcessHeap(), 0, sizeof(HLPFILE_LINK) + strlen(str) + 1);
+    if (len == -1) len = strlen(str);
+    link = HeapAlloc(GetProcessHeap(), 0, sizeof(HLPFILE_LINK) + len + 1);
     if (!link) return NULL;
 
     link->cookie     = cookie;
-    link->lpszString = link_str = (char*)link + sizeof(HLPFILE_LINK);
-    strcpy(link_str, str);
-    link->lHash      = hash;
+    link->string     = link_str = (char*)(link + 1);
+    memcpy(link_str, str, len);
+    link_str[len] = '\0';
+    link->hash       = hash;
     link->bClrChange = clrChange ? 1 : 0;
     link->window     = wnd;
-    link->wRefCount   = 1;
+    link->wRefCount  = 1;
+    if (rd) {
+    link->next       = rd->first_link;
+    rd->first_link   = link;
+    link->cpMin      = rd->char_pos;
+    link->cpMax      = 0;
+    rd->force_color  = clrChange;
+    link->wRefCount++;
+    if (rd->current_link) WINE_FIXME("Pending link\n");
+    rd->current_link = link;
+    }
 
     WINE_TRACE("Link[%d] to %s@%08x:%d\n",
-               link->cookie, link->lpszString, 
-               link->lHash, link->window);
+               link->cookie, link->string, link->hash, link->window);
     return link;
 }
 
@@ -1047,8 +1060,12 @@ static BOOL HLPFILE_BrowseParagraph(HLPFILE_PAGE* page, struct RtfData* rd, BYTE
                 paragraphptr = &paragraph->next;
 
                 paragraph->next            = NULL;
+                if (!rd)
+                {
                 paragraph->link            = attributes.link;
                 if (paragraph->link) paragraph->link->wRefCount++;
+                }
+                else paragraph->link       = NULL;
                 paragraph->cookie          = para_normal_text;
                 paragraph->u.text.wFont    = attributes.wFont;
                 paragraph->u.text.wVSpace  = attributes.wVSpace;
@@ -1060,7 +1077,12 @@ static BOOL HLPFILE_BrowseParagraph(HLPFILE_PAGE* page, struct RtfData* rd, BYTE
                 attributes.wVSpace = 0;
                 attributes.wHSpace = 0;
                 if (rd) /* FIXME: TEMP */ {
-                if (rd->force_color && !HLPFILE_RtfAddControl(rd, "{\\ul\\cf1 ")) goto done;
+                if (rd->force_color)
+                {
+                    if ((rd->current_link->cookie == hlp_link_popup) ?
+                        !HLPFILE_RtfAddControl(rd, "{\\uld\\cf1") :
+                        !HLPFILE_RtfAddControl(rd, "{\\ul\\cf1")) goto done;
+                }
                 if (!HLPFILE_RtfAddText(rd, text)) goto done;
                 if (rd->force_color && !HLPFILE_RtfAddControl(rd, "}")) goto done;
                 rd->char_pos += textsize;
@@ -1152,8 +1174,11 @@ static BOOL HLPFILE_BrowseParagraph(HLPFILE_PAGE* page, struct RtfData* rd, BYTE
                     paragraphptr = &paragraph->next;
 
                     paragraph->next        = NULL;
+                    if (!rd){
                     paragraph->link        = attributes.link;
                     if (paragraph->link) paragraph->link->wRefCount++;
+                    }
+                    else paragraph->link   = NULL;
                     paragraph->cookie      = para_bitmap;
                     paragraph->u.gfx.pos   = pos;
                     switch (type)
@@ -1197,6 +1222,14 @@ static BOOL HLPFILE_BrowseParagraph(HLPFILE_PAGE* page, struct RtfData* rd, BYTE
                 HLPFILE_FreeLink(attributes.link);
                 attributes.link = NULL;
                 format += 1;
+                if (rd) {
+                if (!rd->current_link)
+                    WINE_FIXME("No existing link\n");
+                else
+                rd->current_link->cpMax = rd->char_pos;
+                rd->current_link = NULL;
+                rd->force_color = FALSE;
+                }
                 break;
 
             case 0x8B:
@@ -1222,8 +1255,8 @@ static BOOL HLPFILE_BrowseParagraph(HLPFILE_PAGE* page, struct RtfData* rd, BYTE
             case 0xCC:
                 WINE_TRACE("macro => %s\n", format + 3);
                 HLPFILE_FreeLink(attributes.link);
-                attributes.link = HLPFILE_AllocLink(hlp_link_macro, (const char*)format + 3, 
-                                                    0, !(*format & 4), -1);
+                attributes.link = HLPFILE_AllocLink(rd, hlp_link_macro, (const char*)format + 3,
+                                                    GET_USHORT(format, 1), 0, !(*format & 4), -1);
                 format += 3 + GET_USHORT(format, 1);
                 break;
 
@@ -1231,8 +1264,8 @@ static BOOL HLPFILE_BrowseParagraph(HLPFILE_PAGE* page, struct RtfData* rd, BYTE
             case 0xE1:
                 WINE_WARN("jump topic 1 => %u\n", GET_UINT(format, 1));
                 HLPFILE_FreeLink(attributes.link);
-                attributes.link = HLPFILE_AllocLink((*format & 1) ? hlp_link_link : hlp_link_popup,
-                                                    page->file->lpszPath,
+                attributes.link = HLPFILE_AllocLink(rd, (*format & 1) ? hlp_link_link : hlp_link_popup,
+                                                    page->file->lpszPath, -1,
                                                     GET_UINT(format, 1)-16,
                                                     1, -1);
 
@@ -1244,10 +1277,9 @@ static BOOL HLPFILE_BrowseParagraph(HLPFILE_PAGE* page, struct RtfData* rd, BYTE
 	    case 0xE3:
             case 0xE6:
             case 0xE7:
-                HLPFILE_FreeLink(attributes.link);
-                attributes.link = HLPFILE_AllocLink((*format & 1) ? hlp_link_link : hlp_link_popup,
-                                                    page->file->lpszPath,
-                                                    GET_UINT(format, 1), 
+                attributes.link = HLPFILE_AllocLink(rd, (*format & 1) ? hlp_link_link : hlp_link_popup,
+                                                    page->file->lpszPath, -1,
+                                                    GET_UINT(format, 1),
                                                     !(*format & 4), -1);
                 format += 5;
                 break;
@@ -1285,8 +1317,8 @@ static BOOL HLPFILE_BrowseParagraph(HLPFILE_PAGE* page, struct RtfData* rd, BYTE
                         break;
                     }
                     HLPFILE_FreeLink(attributes.link);
-                    attributes.link = HLPFILE_AllocLink((*format & 1) ? hlp_link_link : hlp_link_popup,
-                                                        ptr, GET_UINT(format, 4),
+                    attributes.link = HLPFILE_AllocLink(rd, (*format & 1) ? hlp_link_link : hlp_link_popup,
+                                                        ptr, -1, GET_UINT(format, 4),
                                                         !(*format & 4), wnd);
                 }
                 format += 3 + GET_USHORT(format, 1);
@@ -1321,6 +1353,7 @@ BOOL    HLPFILE_BrowsePage(HLPFILE_PAGE* page, struct RtfData* rd)
     rd->in_text = TRUE;
     rd->data = rd->ptr = HeapAlloc(GetProcessHeap(), 0, rd->allocated = 32768);
     rd->char_pos = 0;
+    rd->first_link = rd->current_link = NULL;
     rd->force_color = FALSE;
     }
 
@@ -1451,6 +1484,8 @@ BOOL    HLPFILE_BrowsePage(HLPFILE_PAGE* page, struct RtfData* rd)
             ref = GET_UINT(buf, 0xc);
     } while (ref != 0xffffffff);
 done:
+    if (rd)
+    page->first_link = rd->first_link;
     return HLPFILE_RtfAddControl(rd, "}");
 }
 
@@ -2364,7 +2399,9 @@ static BOOL HLPFILE_GetMap(HLPFILE *hlpfile)
 void HLPFILE_FreeLink(HLPFILE_LINK* link)
 {
     if (link && !--link->wRefCount)
+    {
         HeapFree(GetProcessHeap(), 0, link);
+    }
 }
 
 /***********************************************************************
diff --git a/programs/winhelp/hlpfile.h b/programs/winhelp/hlpfile.h
index aa8cadc..63ddc0c 100644
--- a/programs/winhelp/hlpfile.h
+++ b/programs/winhelp/hlpfile.h
@@ -35,14 +35,17 @@ typedef struct
     COLORREF    nsr_color;      /* color for non scrollable region */
 } HLPFILE_WINDOWINFO;
 
-typedef struct
+typedef struct tagHlpFileLink
 {
     enum {hlp_link_link, hlp_link_popup, hlp_link_macro} cookie;
-    LPCSTR      lpszString;     /* name of the file to for the link (NULL if same file) */
-    LONG        lHash;          /* topic index */
+    LPCSTR      string;         /* name of the file to for the link (NULL if same file) */
+    LONG        hash;           /* topic index */
     unsigned    bClrChange : 1, /* true if the link is green & underlined */
                 wRefCount;      /* number of internal references to this object */
     unsigned    window;         /* window number for displaying the link (-1 is current) */
+    DWORD       cpMin;
+    DWORD       cpMax;
+    struct tagHlpFileLink* next;
 } HLPFILE_LINK;
 
 enum para_type {para_normal_text, para_debug_text, para_bitmap, para_metafile};
@@ -92,6 +95,8 @@ typedef struct tagHlpFilePage
     HLPFILE_PARAGRAPH*          first_paragraph;
     HLPFILE_MACRO*              first_macro;
 
+    HLPFILE_LINK*               first_link;
+
     unsigned                    wNumber;
     unsigned                    offset;
     DWORD                       reference;
@@ -207,6 +212,8 @@ struct RtfData {
     unsigned    allocated;      /* overall allocated size */
     unsigned    char_pos;       /* current char position (in richedit) */
     char*       where;          /* pointer to feed back richedit */
+    HLPFILE_LINK*first_link;
+    HLPFILE_LINK*current_link;
     BOOL        force_color;
 };
 
diff --git a/programs/winhelp/winhelp.c b/programs/winhelp/winhelp.c
index ce57b6a..5dc6891 100644
--- a/programs/winhelp/winhelp.c
+++ b/programs/winhelp/winhelp.c
@@ -55,6 +55,7 @@ static void    WINHELP_DeleteLines(WINHELP_WINDOW*);
 static void    WINHELP_DeleteWindow(WINHELP_WINDOW*);
 static void    WINHELP_DeleteButtons(WINHELP_WINDOW*);
 static void    WINHELP_SetupText(HWND hWnd, WINHELP_WINDOW *win, ULONG relative);
+static void    WINHELP_DeletePageLinks(HLPFILE_PAGE* page);
 static WINHELP_LINE_PART* WINHELP_IsOverLink(WINHELP_WINDOW*, WPARAM, LPARAM);
 
 WINHELP_GLOBALS Globals = {3, NULL, TRUE, NULL, NULL, NULL, NULL, NULL, {{{NULL,NULL}},0}};
@@ -207,7 +208,7 @@ HLPFILE_WINDOWINFO*     WINHELP_GetWindowInfo(HLPFILE* hlpfile, LPCSTR name)
  *
  */
 static HLPFILE_WINDOWINFO*     WINHELP_GetPopupWindowInfo(HLPFILE* hlpfile,
-                                                          WINHELP_WINDOW* parent, POINT* mouse)
+                                                          WINHELP_WINDOW* parent, LPARAM mouse)
 {
     static      HLPFILE_WINDOWINFO      wi;
 
@@ -220,7 +221,8 @@ static HLPFILE_WINDOWINFO*     WINHELP_GetPopupWindowInfo(HLPFILE* hlpfile,
     wi.size.cx = (parent_rect.right  - parent_rect.left) / 2;
     wi.size.cy = 10; /* need a non null value, so that border are taken into account while computing */
 
-    wi.origin = *mouse;
+    wi.origin.x = (short)LOWORD(mouse);
+    wi.origin.y = (short)HIWORD(mouse);
     ClientToScreen(parent->hMainWnd, &wi.origin);
     wi.origin.x -= wi.size.cx / 2;
     wi.origin.x  = min(wi.origin.x, GetSystemMetrics(SM_CXSCREEN) - wi.size.cx);
@@ -657,9 +659,13 @@ BOOL WINHELP_CreateHelpWindow(WINHELP_WNDPAGE* wpage, int nCmdShow, BOOL remembe
             hTextWnd = CreateWindow(TEXT_WIN_CLASS_NAME, "", WS_CHILD | WS_VISIBLE,
                                     0, 0, 0, 0, win->hMainWnd, (HMENU)CTL_ID_TEXT, Globals.hInstance, win);
         else
+        {
             hTextWnd = CreateWindow(RICHEDIT_CLASS, NULL,
                                     ES_MULTILINE | ES_READONLY | WS_CHILD | WS_HSCROLL | WS_VSCROLL | WS_VISIBLE,
                                     0, 0, 0, 0, win->hMainWnd, (HMENU)CTL_ID_TEXT, Globals.hInstance, NULL);
+            SendMessage(hTextWnd, EM_SETEVENTMASK, 0,
+                        SendMessage(hTextWnd, EM_GETEVENTMASK, 0, 0) | ENM_MOUSEEVENTS);
+        }
     }
 
     hIcon = (wpage->page) ? wpage->page->file->hIcon : NULL;
@@ -703,6 +709,106 @@ BOOL WINHELP_OpenHelpWindow(HLPFILE_PAGE* (*lookup)(HLPFILE*, LONG, ULONG*),
 
 /***********************************************************************
  *
+ *           WINHELP_FindLink
+ */
+static HLPFILE_LINK* WINHELP_FindLink(WINHELP_WINDOW* win, LPARAM pos)
+{
+    HLPFILE_LINK*           link;
+    POINTL                  mouse_ptl, char_ptl, char_next_ptl;
+    DWORD                   cp;
+
+    if (!win->page) return NULL;
+
+    mouse_ptl.x = (short)LOWORD(pos);
+    mouse_ptl.y = (short)HIWORD(pos);
+    cp = SendMessageW(GetDlgItem(win->hMainWnd, CTL_ID_TEXT), EM_CHARFROMPOS,
+                      0, (LPARAM)&mouse_ptl);
+
+    for (link = win->page->first_link; link; link = link->next)
+    {
+        if (link->cpMin <= cp && cp <= link->cpMax)
+        {
+            /* check whether we're at end of line */
+            SendMessageW(GetDlgItem(win->hMainWnd, CTL_ID_TEXT), EM_POSFROMCHAR,
+                         (LPARAM)&char_ptl, cp);
+            SendMessageW(GetDlgItem(win->hMainWnd, CTL_ID_TEXT), EM_POSFROMCHAR,
+                         (LPARAM)&char_next_ptl, cp + 1);
+            if (char_next_ptl.y != char_ptl.y || mouse_ptl.x >= char_next_ptl.x)
+                link = NULL;
+            break;
+        }
+    }
+    return link;
+}
+
+/******************************************************************
+ *             WINHELP_HandleTextMouse
+ *
+ */
+static BOOL WINHELP_HandleTextMouse(WINHELP_WINDOW* win, const MSGFILTER* msgf)
+{
+    HLPFILE*                hlpfile;
+    HLPFILE_LINK*           link;
+    BOOL                    ret = FALSE;
+
+    switch (msgf->msg)
+    {
+    case WM_MOUSEMOVE:
+        if (WINHELP_FindLink(win, msgf->lParam))
+            SetCursor(win->hHandCur);
+        else
+            SetCursor(LoadCursor(0, IDC_ARROW));
+        break;
+
+     case WM_LBUTTONDOWN:
+         if ((win->current_link = WINHELP_FindLink(win, msgf->lParam)))
+             ret = TRUE;
+         break;
+
+    case WM_LBUTTONUP:
+        if ((link = WINHELP_FindLink(win, msgf->lParam)) && link == win->current_link)
+        {
+            HLPFILE_WINDOWINFO*     wi;
+
+            switch (link->cookie)
+            {
+            case hlp_link_link:
+                if ((hlpfile = WINHELP_LookupHelpFile(link->string)))
+                {
+                    if (link->window == -1)
+                        wi = win->info;
+                    else if ((link->window >= 0) && (link->window < hlpfile->numWindows))
+                        wi = &hlpfile->windows[link->window];
+                    else
+                    {
+                        WINE_WARN("link to window %d/%d\n", link->window, hlpfile->numWindows);
+                        break;
+                    }
+                    WINHELP_OpenHelpWindow(HLPFILE_PageByHash, hlpfile, link->hash, wi, SW_NORMAL);
+                }
+                break;
+            case hlp_link_popup:
+                if ((hlpfile = WINHELP_LookupHelpFile(link->string)))
+                    WINHELP_OpenHelpWindow(HLPFILE_PageByHash, hlpfile, link->hash,
+                                           WINHELP_GetPopupWindowInfo(hlpfile, win, msgf->lParam),
+                                           SW_NORMAL);
+                break;
+            case hlp_link_macro:
+                MACRO_ExecuteMacro(link->string);
+                break;
+            default:
+                WINE_FIXME("Unknown link cookie %d\n", link->cookie);
+            }
+            ret = TRUE;
+        }
+        win->current_link = NULL;
+        break;
+    }
+    return ret;
+}
+
+/***********************************************************************
+ *
  *           WINHELP_MainWndProc
  */
 static LRESULT CALLBACK WINHELP_MainWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
@@ -813,6 +919,15 @@ static LRESULT CALLBACK WINHELP_MainWndProc(HWND hWnd, UINT msg, WPARAM wParam,
             return 0;
         }
         break;
+
+    case WM_NOTIFY:
+        if (wParam == CTL_ID_TEXT)
+        {
+            return WINHELP_HandleTextMouse((WINHELP_WINDOW*)GetWindowLong(hWnd, 0),
+                                           (const MSGFILTER*)lParam);
+        }
+        break;
+
     case WM_NCDESTROY:
         {
             BOOL bExit;
@@ -993,7 +1108,6 @@ static LRESULT CALLBACK WINHELP_TextWndProc(HWND hWnd, UINT msg, WPARAM wParam,
     WINDOWPOS         *winpos;
     PAINTSTRUCT        ps;
     HDC   hDc;
-    POINT mouse;
     INT   scroll_pos;
     HWND  hPopupWnd;
 
@@ -1259,13 +1373,10 @@ static LRESULT CALLBACK WINHELP_TextWndProc(HWND hWnd, UINT msg, WPARAM wParam,
             HLPFILE*            hlpfile;
             HLPFILE_WINDOWINFO* wi;
 
-            mouse.x = (short)LOWORD(lParam);
-            mouse.y = (short)HIWORD(lParam);
-
             if (part->link) switch (part->link->cookie)
             {
             case hlp_link_link:
-                hlpfile = WINHELP_LookupHelpFile(part->link->lpszString);
+                hlpfile = WINHELP_LookupHelpFile(part->link->string);
                 if (part->link->window == -1)
                     wi = win->info;
                 else if (part->link->window < hlpfile->numWindows)
@@ -1275,17 +1386,17 @@ static LRESULT CALLBACK WINHELP_TextWndProc(HWND hWnd, UINT msg, WPARAM wParam,
                     WINE_WARN("link to window %d/%d\n", part->link->window, hlpfile->numWindows);
                     break;
                 }
-                WINHELP_OpenHelpWindow(HLPFILE_PageByHash, hlpfile, part->link->lHash,
+                WINHELP_OpenHelpWindow(HLPFILE_PageByHash, hlpfile, part->link->hash,
                                        wi, SW_NORMAL);
                 break;
             case hlp_link_popup:
-                hlpfile = WINHELP_LookupHelpFile(part->link->lpszString);
-                if (hlpfile) WINHELP_OpenHelpWindow(HLPFILE_PageByHash, hlpfile, part->link->lHash,
-                                                    WINHELP_GetPopupWindowInfo(hlpfile, win, &mouse),
+                hlpfile = WINHELP_LookupHelpFile(part->link->string);
+                if (hlpfile) WINHELP_OpenHelpWindow(HLPFILE_PageByHash, hlpfile, part->link->hash,
+                                                    WINHELP_GetPopupWindowInfo(hlpfile, win, lParam),
                                                     SW_NORMAL);
                 break;
             case hlp_link_macro:
-                MACRO_ExecuteMacro(part->link->lpszString);
+                MACRO_ExecuteMacro(part->link->string);
                 break;
             default:
                 WINE_FIXME("Unknown link cookie %d\n", part->link->cookie);
@@ -1894,6 +2005,22 @@ void WINHELP_DeleteBackSet(WINHELP_WINDOW* win)
     win->back.index = 0;
 }
 
+/******************************************************************
+ *             WINHELP_DeletePageLinks
+ *
+ */
+static void WINHELP_DeletePageLinks(HLPFILE_PAGE* page)
+{
+    HLPFILE_LINK*       curr;
+    HLPFILE_LINK*       next;
+
+    for (curr = page->first_link; curr; curr = next)
+    {
+        next = curr->next;
+        HeapFree(GetProcessHeap(), 0, curr);
+    }
+}
+
 /***********************************************************************
  *
  *           WINHELP_DeleteWindow
@@ -1923,6 +2050,7 @@ static void WINHELP_DeleteWindow(WINHELP_WINDOW* win)
 
     WINHELP_DeleteButtons(win);
 
+    if (win->page) WINHELP_DeletePageLinks(win->page);
     if (win->hShadowWnd) DestroyWindow(win->hShadowWnd);
     if (win->hHistoryWnd) DestroyWindow(win->hHistoryWnd);
 
@@ -2005,7 +2133,7 @@ WINHELP_LINE_PART* WINHELP_IsOverLink(WINHELP_WINDOW* win, WPARAM wParam, LPARAM
         for (part = &line->first_part; part; part = part->next)
         {
             if (part->link && 
-                part->link->lpszString &&
+                part->link->string &&
                 part->rect.left   <= mouse.x &&
                 part->rect.right  >= mouse.x &&
                 part->rect.top    <= mouse.y + scroll_pos &&
diff --git a/programs/winhelp/winhelp.h b/programs/winhelp/winhelp.h
index b3ebac1..8739124 100644
--- a/programs/winhelp/winhelp.h
+++ b/programs/winhelp/winhelp.h
@@ -126,6 +126,7 @@ typedef struct tagWinHelp
     HBRUSH              hBrush;
 
     HLPFILE_WINDOWINFO* info;
+    HLPFILE_LINK*       current_link;
 
     WINHELP_PAGESET     back;
 





More information about the wine-patches mailing list