diff --git a/programs/winhelp/hlpfile.c b/programs/winhelp/hlpfile.c index e327b541315c6dda77969c5eb7fb17b7f72a5d82..aae1385fc9d0bc9818efea385444d4fad9cee0d1 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 = ¶graph->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 = ¶graph->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 aa8cadc902238287223cae21c59899e0a9ecd495..63ddc0cf56131b742e5970d75d6d2e270db8700f 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 ce57b6aeb7be1efc5048427fff6cf6e1150000d8..5dc689156069e903dab5dde35ed546940aed60c0 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; @@ -701,6 +707,106 @@ BOOL WINHELP_OpenHelpWindow(HLPFILE_PAGE* (*lookup)(HLPFILE*, LONG, ULONG*), return WINHELP_CreateHelpWindow(&wpage, nCmdShow, TRUE); } +/*********************************************************************** + * + * 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 @@ -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 b3ebac13297b40e99b53332db6cd3992c04814dc..8739124da36c4748cc76137de3e71dcf53b3db77 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;