-/*\r
- * Help Viewer\r
- *\r
- * Copyright 1996 Ulrich Schmid <uschmid@mail.hh.provi.de>\r
- * 2002 Sylvain Petreolle <spetreolle@yahoo.fr>\r
- * 2002, 2008 Eric Pouech <eric.pouech@wanadoo.fr>\r
- * 2004 Ken Belleau <jamez@ivic.qc.ca>\r
- * 2008 Kirill K. Smirnov <lich@math.spbu.ru>\r
- *\r
- * This library is free software; you can redistribute it and/or\r
- * modify it under the terms of the GNU Lesser General Public\r
- * License as published by the Free Software Foundation; either\r
- * version 2.1 of the License, or (at your option) any later version.\r
- *\r
- * This library is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
- * Lesser General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU Lesser General Public\r
- * License along with this library; if not, write to the Free Software\r
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA\r
- */\r
-\r
-#include <assert.h>\r
-#include <stdio.h>\r
-#include <string.h>\r
-#include <stdarg.h>\r
-#include <stdlib.h>\r
-\r
-#define NONAMELESSUNION\r
-#define NONAMELESSSTRUCT\r
-\r
-#include "windef.h"\r
-#include "winbase.h"\r
-#include "wingdi.h"\r
-#include "winuser.h"\r
-#include "commdlg.h"\r
-#include "winhelp.h"\r
-#include "winhelp_res.h"\r
-#include "shellapi.h"\r
-#include "richedit.h"\r
-#include "commctrl.h"\r
-\r
-#include "wine/debug.h"\r
-\r
-WINE_DEFAULT_DEBUG_CHANNEL(winhelp);\r
-\r
-static BOOL WINHELP_RegisterWinClasses(void);\r
-static LRESULT CALLBACK WINHELP_MainWndProc(HWND, UINT, WPARAM, LPARAM);\r
-static LRESULT CALLBACK WINHELP_ButtonBoxWndProc(HWND, UINT, WPARAM, LPARAM);\r
-static LRESULT CALLBACK WINHELP_ButtonWndProc(HWND, UINT, WPARAM, LPARAM);\r
-static LRESULT CALLBACK WINHELP_HistoryWndProc(HWND, UINT, WPARAM, LPARAM);\r
-static LRESULT CALLBACK WINHELP_ShadowWndProc(HWND, UINT, WPARAM, LPARAM);\r
-static BOOL WINHELP_CheckPopup(HWND, UINT, WPARAM, LPARAM, LRESULT*);\r
-static void WINHELP_InitFonts(HWND hWnd);\r
-static void WINHELP_DeleteWindow(WINHELP_WINDOW*);\r
-static void WINHELP_DeleteButtons(WINHELP_WINDOW*);\r
-static void WINHELP_SetupText(HWND hWnd, WINHELP_WINDOW *win, ULONG relative);\r
-static void WINHELP_DeletePageLinks(HLPFILE_PAGE* page);\r
-\r
-WINHELP_GLOBALS Globals = {3, NULL, TRUE, NULL, NULL, NULL, NULL, NULL, {{{NULL,NULL}},0}, NULL};\r
-\r
-#define CTL_ID_BUTTON 0x700\r
-#define CTL_ID_TEXT 0x701\r
-\r
-/***********************************************************************\r
- *\r
- * WINHELP_GetOpenFileName\r
- */\r
-BOOL WINHELP_GetOpenFileName(LPSTR lpszFile, int len)\r
-{\r
- OPENFILENAME openfilename;\r
- CHAR szDir[MAX_PATH];\r
- CHAR szzFilter[2 * MAX_STRING_LEN + 100];\r
- LPSTR p = szzFilter;\r
-\r
- WINE_TRACE("()\n");\r
-\r
- LoadString(Globals.hInstance, STID_HELP_FILES_HLP, p, MAX_STRING_LEN);\r
- p += strlen(p) + 1;\r
- lstrcpy(p, "*.hlp");\r
- p += strlen(p) + 1;\r
- LoadString(Globals.hInstance, STID_ALL_FILES, p, MAX_STRING_LEN);\r
- p += strlen(p) + 1;\r
- lstrcpy(p, "*.*");\r
- p += strlen(p) + 1;\r
- *p = '\0';\r
-\r
- GetCurrentDirectory(sizeof(szDir), szDir);\r
-\r
- lpszFile[0]='\0';\r
-\r
- openfilename.lStructSize = sizeof(OPENFILENAME);\r
- openfilename.hwndOwner = NULL;\r
- openfilename.hInstance = Globals.hInstance;\r
- openfilename.lpstrFilter = szzFilter;\r
- openfilename.lpstrCustomFilter = 0;\r
- openfilename.nMaxCustFilter = 0;\r
- openfilename.nFilterIndex = 1;\r
- openfilename.lpstrFile = lpszFile;\r
- openfilename.nMaxFile = len;\r
- openfilename.lpstrFileTitle = 0;\r
- openfilename.nMaxFileTitle = 0;\r
- openfilename.lpstrInitialDir = szDir;\r
- openfilename.lpstrTitle = 0;\r
- openfilename.Flags = 0;\r
- openfilename.nFileOffset = 0;\r
- openfilename.nFileExtension = 0;\r
- openfilename.lpstrDefExt = 0;\r
- openfilename.lCustData = 0;\r
- openfilename.lpfnHook = 0;\r
- openfilename.lpTemplateName = 0;\r
-\r
- return GetOpenFileName(&openfilename);\r
-}\r
-\r
-static char* WINHELP_GetCaption(WINHELP_WNDPAGE* wpage)\r
-{\r
- if (wpage->wininfo->caption[0]) return wpage->wininfo->caption;\r
- return wpage->page->file->lpszTitle;\r
-}\r
-\r
-/***********************************************************************\r
- *\r
- * WINHELP_LookupHelpFile\r
- */\r
-HLPFILE* WINHELP_LookupHelpFile(LPCSTR lpszFile)\r
-{\r
- HLPFILE* hlpfile;\r
- char szFullName[MAX_PATH];\r
- char szAddPath[MAX_PATH];\r
- char *p;\r
-\r
- /*\r
- * NOTE: This is needed by popup windows only.\r
- * In other cases it's not needed but does not hurt though.\r
- */\r
- if (Globals.active_win && Globals.active_win->page && Globals.active_win->page->file)\r
- {\r
- strcpy(szAddPath, Globals.active_win->page->file->lpszPath);\r
- p = strrchr(szAddPath, '\\');\r
- if (p) *p = 0;\r
- }\r
-\r
- /*\r
- * FIXME: Should we swap conditions?\r
- */\r
- if (!SearchPath(NULL, lpszFile, ".hlp", MAX_PATH, szFullName, NULL) &&\r
- !SearchPath(szAddPath, lpszFile, ".hlp", MAX_PATH, szFullName, NULL))\r
- {\r
- if (WINHELP_MessageBoxIDS_s(STID_FILE_NOT_FOUND_s, lpszFile, STID_WHERROR,\r
- MB_YESNO|MB_ICONQUESTION) != IDYES)\r
- return NULL;\r
- if (!WINHELP_GetOpenFileName(szFullName, MAX_PATH))\r
- return NULL;\r
- }\r
- hlpfile = HLPFILE_ReadHlpFile(szFullName);\r
- if (!hlpfile)\r
- WINHELP_MessageBoxIDS_s(STID_HLPFILE_ERROR_s, lpszFile,\r
- STID_WHERROR, MB_OK|MB_ICONSTOP);\r
- return hlpfile;\r
-}\r
-\r
-/******************************************************************\r
- * WINHELP_GetWindowInfo\r
- *\r
- *\r
- */\r
-HLPFILE_WINDOWINFO* WINHELP_GetWindowInfo(HLPFILE* hlpfile, LPCSTR name)\r
-{\r
- static HLPFILE_WINDOWINFO mwi;\r
- unsigned int i;\r
-\r
- if (!name || !name[0])\r
- name = Globals.active_win->lpszName;\r
-\r
- if (hlpfile)\r
- for (i = 0; i < hlpfile->numWindows; i++)\r
- if (!strcmp(hlpfile->windows[i].name, name))\r
- return &hlpfile->windows[i];\r
-\r
- if (strcmp(name, "main") != 0)\r
- {\r
- WINE_FIXME("Couldn't find window info for %s\n", name);\r
- assert(0);\r
- return NULL;\r
- }\r
- if (!mwi.name[0])\r
- {\r
- strcpy(mwi.type, "primary");\r
- strcpy(mwi.name, "main");\r
- if (!LoadString(Globals.hInstance, STID_WINE_HELP, \r
- mwi.caption, sizeof(mwi.caption)))\r
- strcpy(mwi.caption, hlpfile->lpszTitle);\r
- mwi.origin.x = mwi.origin.y = mwi.size.cx = mwi.size.cy = CW_USEDEFAULT;\r
- mwi.style = SW_SHOW;\r
- mwi.win_style = WS_OVERLAPPEDWINDOW;\r
- mwi.sr_color = mwi.sr_color = 0xFFFFFF;\r
- }\r
- return &mwi;\r
-}\r
-\r
-/******************************************************************\r
- * HLPFILE_GetPopupWindowInfo\r
- *\r
- *\r
- */\r
-static HLPFILE_WINDOWINFO* WINHELP_GetPopupWindowInfo(HLPFILE* hlpfile,\r
- WINHELP_WINDOW* parent, LPARAM mouse)\r
-{\r
- static HLPFILE_WINDOWINFO wi;\r
-\r
- RECT parent_rect;\r
- \r
- wi.type[0] = wi.name[0] = wi.caption[0] = '\0';\r
-\r
- /* Calculate horizontal size and position of a popup window */\r
- GetWindowRect(parent->hMainWnd, &parent_rect);\r
- wi.size.cx = (parent_rect.right - parent_rect.left) / 2;\r
- wi.size.cy = 10; /* need a non null value, so that border are taken into account while computing */\r
-\r
- wi.origin.x = (short)LOWORD(mouse);\r
- wi.origin.y = (short)HIWORD(mouse);\r
- ClientToScreen(parent->hMainWnd, &wi.origin);\r
- wi.origin.x -= wi.size.cx / 2;\r
- wi.origin.x = min(wi.origin.x, GetSystemMetrics(SM_CXSCREEN) - wi.size.cx);\r
- wi.origin.x = max(wi.origin.x, 0);\r
-\r
- wi.style = SW_SHOW;\r
- wi.win_style = WS_POPUP | WS_BORDER;\r
- if (parent->page->file->has_popup_color)\r
- wi.sr_color = parent->page->file->popup_color;\r
- else\r
- wi.sr_color = parent->info->sr_color;\r
- wi.nsr_color = 0xFFFFFF;\r
-\r
- return &wi;\r
-}\r
-\r
-/***********************************************************************\r
- *\r
- * WinMain\r
- */\r
-int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE prev, LPSTR cmdline, int show)\r
-{\r
- MSG msg;\r
- LONG lHash = 0;\r
- HLPFILE* hlpfile;\r
- static CHAR default_wndname[] = "main";\r
- LPSTR wndname = default_wndname;\r
- WINHELP_DLL* dll;\r
-\r
- Globals.hInstance = hInstance;\r
-\r
- if (LoadLibrary("riched20.dll") == NULL)\r
- return MessageBox(0, MAKEINTRESOURCE(STID_NO_RICHEDIT),\r
- MAKEINTRESOURCE(STID_WHERROR), MB_OK);\r
-\r
- /* Get options */\r
- while (*cmdline && (*cmdline == ' ' || *cmdline == '-'))\r
- {\r
- CHAR option;\r
- LPCSTR topic_id;\r
- if (*cmdline++ == ' ') continue;\r
-\r
- option = *cmdline;\r
- if (option) cmdline++;\r
- while (*cmdline && *cmdline == ' ') cmdline++;\r
- switch (option)\r
- {\r
- case 'i':\r
- case 'I':\r
- topic_id = cmdline;\r
- while (*cmdline && *cmdline != ' ') cmdline++;\r
- if (*cmdline) *cmdline++ = '\0';\r
- lHash = HLPFILE_Hash(topic_id);\r
- break;\r
-\r
- case '3':\r
- case '4':\r
- Globals.wVersion = option - '0';\r
- break;\r
-\r
- case 'x':\r
- show = SW_HIDE; \r
- Globals.isBook = FALSE;\r
- break;\r
-\r
- default:\r
- WINE_FIXME("Unsupported cmd line: %s\n", cmdline);\r
- break;\r
- }\r
- }\r
-\r
- /* Create primary window */\r
- if (!WINHELP_RegisterWinClasses())\r
- {\r
- WINE_FIXME("Couldn't register classes\n");\r
- return 0;\r
- }\r
-\r
- if (*cmdline)\r
- {\r
- char* ptr;\r
- if ((*cmdline == '"') && (ptr = strchr(cmdline+1, '"')))\r
- {\r
- cmdline++;\r
- *ptr = '\0';\r
- }\r
- if ((ptr = strchr(cmdline, '>')))\r
- {\r
- *ptr = '\0';\r
- wndname = ptr + 1;\r
- }\r
- hlpfile = WINHELP_LookupHelpFile(cmdline);\r
- if (!hlpfile) return 0;\r
- }\r
- else hlpfile = NULL;\r
- WINHELP_OpenHelpWindow(HLPFILE_PageByHash, hlpfile, lHash,\r
- WINHELP_GetWindowInfo(hlpfile, wndname), show);\r
-\r
- /* Message loop */\r
- while (GetMessage(&msg, 0, 0, 0))\r
- {\r
- TranslateMessage(&msg);\r
- DispatchMessage(&msg);\r
- }\r
- for (dll = Globals.dlls; dll; dll = dll->next)\r
- {\r
- if (dll->class & DC_INITTERM) dll->handler(DW_TERM, 0, 0);\r
- }\r
- return 0;\r
-}\r
-\r
-/***********************************************************************\r
- *\r
- * RegisterWinClasses\r
- */\r
-static BOOL WINHELP_RegisterWinClasses(void)\r
-{\r
- WNDCLASS class_main, class_button_box, class_shadow, class_history;\r
-\r
- class_main.style = CS_HREDRAW | CS_VREDRAW;\r
- class_main.lpfnWndProc = WINHELP_MainWndProc;\r
- class_main.cbClsExtra = 0;\r
- class_main.cbWndExtra = sizeof(LONG);\r
- class_main.hInstance = Globals.hInstance;\r
- class_main.hIcon = LoadIcon(Globals.hInstance, MAKEINTRESOURCE(IDI_WINHELP));\r
- class_main.hCursor = LoadCursor(0, IDC_ARROW);\r
- class_main.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);\r
- class_main.lpszMenuName = 0;\r
- class_main.lpszClassName = MAIN_WIN_CLASS_NAME;\r
-\r
- class_button_box = class_main;\r
- class_button_box.lpfnWndProc = WINHELP_ButtonBoxWndProc;\r
- class_button_box.cbWndExtra = 0;\r
- class_button_box.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);\r
- class_button_box.lpszClassName = BUTTON_BOX_WIN_CLASS_NAME;\r
-\r
- class_shadow = class_main;\r
- class_shadow.lpfnWndProc = WINHELP_ShadowWndProc;\r
- class_shadow.cbWndExtra = 0;\r
- class_shadow.hbrBackground = (HBRUSH)(COLOR_3DDKSHADOW+1);\r
- class_shadow.lpszClassName = SHADOW_WIN_CLASS_NAME;\r
-\r
- class_history = class_main;\r
- class_history.lpfnWndProc = WINHELP_HistoryWndProc;\r
- class_history.lpszClassName = HISTORY_WIN_CLASS_NAME;\r
-\r
- return (RegisterClass(&class_main) &&\r
- RegisterClass(&class_button_box) &&\r
- RegisterClass(&class_shadow) &&\r
- RegisterClass(&class_history));\r
-}\r
-\r
-typedef struct\r
-{\r
- WORD size;\r
- WORD command;\r
- LONG data;\r
- LONG reserved;\r
- WORD ofsFilename;\r
- WORD ofsData;\r
-} WINHELP,*LPWINHELP;\r
-\r
-static BOOL WINHELP_HasWorkingWindow(void)\r
-{\r
- if (!Globals.active_win) return FALSE;\r
- if (Globals.active_win->next || Globals.win_list != Globals.active_win) return TRUE;\r
- return Globals.active_win->page != NULL && Globals.active_win->page->file != NULL;\r
-}\r
-\r
-/******************************************************************\r
- * WINHELP_HandleCommand\r
- *\r
- *\r
- */\r
-static LRESULT WINHELP_HandleCommand(HWND hSrcWnd, LPARAM lParam)\r
-{\r
- COPYDATASTRUCT* cds = (COPYDATASTRUCT*)lParam;\r
- WINHELP* wh;\r
-\r
- if (cds->dwData != 0xA1DE505)\r
- {\r
- WINE_FIXME("Wrong magic number (%08lx)\n", cds->dwData);\r
- return 0;\r
- }\r
-\r
- wh = (WINHELP*)cds->lpData;\r
-\r
- if (wh)\r
- {\r
- char* ptr = (wh->ofsFilename) ? (LPSTR)wh + wh->ofsFilename : NULL;\r
-\r
- WINE_TRACE("Got[%u]: cmd=%u data=%08x fn=%s\n",\r
- wh->size, wh->command, wh->data, ptr);\r
- switch (wh->command)\r
- {\r
- case HELP_CONTEXT:\r
- if (ptr)\r
- {\r
- MACRO_JumpContext(ptr, "main", wh->data);\r
- }\r
- if (!WINHELP_HasWorkingWindow()) MACRO_Exit();\r
- break;\r
- case HELP_QUIT:\r
- MACRO_Exit();\r
- break;\r
- case HELP_CONTENTS:\r
- if (ptr)\r
- {\r
- MACRO_JumpContents(ptr, "main");\r
- }\r
- if (!WINHELP_HasWorkingWindow()) MACRO_Exit();\r
- break;\r
- case HELP_HELPONHELP:\r
- MACRO_HelpOn();\r
- if (!WINHELP_HasWorkingWindow()) MACRO_Exit();\r
- break;\r
- /* case HELP_SETINDEX: */\r
- case HELP_SETCONTENTS:\r
- if (ptr)\r
- {\r
- MACRO_SetContents(ptr, wh->data);\r
- }\r
- break;\r
- case HELP_CONTEXTPOPUP:\r
- if (ptr)\r
- {\r
- MACRO_PopupContext(ptr, wh->data);\r
- }\r
- break;\r
- /* case HELP_FORCEFILE:*/\r
- /* case HELP_CONTEXTMENU: */\r
- case HELP_FINDER:\r
- /* in fact, should be the topic dialog box */\r
- WINE_FIXME("HELP_FINDER: stub\n");\r
- if (ptr)\r
- {\r
- MACRO_JumpHash(ptr, "main", 0);\r
- }\r
- break;\r
- /* case HELP_WM_HELP: */\r
- /* case HELP_SETPOPUP_POS: */\r
- /* case HELP_KEY: */\r
- /* case HELP_COMMAND: */\r
- /* case HELP_PARTIALKEY: */\r
- /* case HELP_MULTIKEY: */\r
- /* case HELP_SETWINPOS: */\r
- default:\r
- WINE_FIXME("Unhandled command (%x) for remote winhelp control\n", wh->command);\r
- break;\r
- }\r
- }\r
- /* Always return success for now */\r
- return 1;\r
-}\r
-\r
-void WINHELP_LayoutMainWindow(WINHELP_WINDOW* win)\r
-{\r
- RECT rect, button_box_rect;\r
- INT text_top = 0;\r
- HWND hButtonBoxWnd = GetDlgItem(win->hMainWnd, CTL_ID_BUTTON);\r
- HWND hTextWnd = GetDlgItem(win->hMainWnd, CTL_ID_TEXT);\r
-\r
- GetClientRect(win->hMainWnd, &rect);\r
-\r
- /* Update button box and text Window */\r
- SetWindowPos(hButtonBoxWnd, HWND_TOP,\r
- rect.left, rect.top,\r
- rect.right - rect.left,\r
- rect.bottom - rect.top, 0);\r
-\r
- if (GetWindowRect(hButtonBoxWnd, &button_box_rect))\r
- text_top = rect.top + button_box_rect.bottom - button_box_rect.top;\r
-\r
- SetWindowPos(hTextWnd, HWND_TOP,\r
- rect.left, text_top,\r
- rect.right - rect.left,\r
- rect.bottom - text_top, 0);\r
-\r
-}\r
-\r
-static void WINHELP_RememberPage(WINHELP_WINDOW* win, WINHELP_WNDPAGE* wpage)\r
-{\r
- unsigned num;\r
-\r
- if (!Globals.history.index || Globals.history.set[0].page != wpage->page)\r
- {\r
- num = sizeof(Globals.history.set) / sizeof(Globals.history.set[0]);\r
- /* we're full, remove latest entry */\r
- if (Globals.history.index == num)\r
- {\r
- HLPFILE_FreeHlpFile(Globals.history.set[num - 1].page->file);\r
- Globals.history.index--;\r
- }\r
- memmove(&Globals.history.set[1], &Globals.history.set[0],\r
- Globals.history.index * sizeof(Globals.history.set[0]));\r
- Globals.history.set[0] = *wpage;\r
- Globals.history.index++;\r
- wpage->page->file->wRefCount++;\r
- }\r
- if (win->hHistoryWnd) InvalidateRect(win->hHistoryWnd, NULL, TRUE);\r
-\r
- num = sizeof(win->back.set) / sizeof(win->back.set[0]);\r
- if (win->back.index == num)\r
- {\r
- /* we're full, remove latest entry */\r
- HLPFILE_FreeHlpFile(win->back.set[0].page->file);\r
- memmove(&win->back.set[0], &win->back.set[1],\r
- (num - 1) * sizeof(win->back.set[0]));\r
- win->back.index--;\r
- }\r
- win->back.set[win->back.index++] = *wpage;\r
- wpage->page->file->wRefCount++;\r
-}\r
-\r
-/***********************************************************************\r
- *\r
- * WINHELP_CreateHelpWindow\r
- */\r
-BOOL WINHELP_CreateHelpWindow(WINHELP_WNDPAGE* wpage, int nCmdShow, BOOL remember)\r
-{\r
- WINHELP_WINDOW* win = NULL;\r
- BOOL bPrimary, bPopup, bReUsed = FALSE;\r
- LPSTR name;\r
- HICON hIcon;\r
- HWND hTextWnd = NULL;\r
-\r
- bPrimary = !lstrcmpi(wpage->wininfo->name, "main");\r
- bPopup = !bPrimary && (wpage->wininfo->win_style & WS_POPUP);\r
-\r
- if (!bPopup)\r
- {\r
- for (win = Globals.win_list; win; win = win->next)\r
- {\r
- if (!lstrcmpi(win->lpszName, wpage->wininfo->name))\r
- {\r
- POINT pt = {0, 0};\r
- SIZE sz = {0, 0};\r
- DWORD flags = SWP_NOSIZE | SWP_NOMOVE;\r
-\r
- WINHELP_DeleteButtons(win);\r
- bReUsed = TRUE;\r
- SetWindowText(win->hMainWnd, WINHELP_GetCaption(wpage));\r
- if (wpage->wininfo->origin.x != CW_USEDEFAULT &&\r
- wpage->wininfo->origin.y != CW_USEDEFAULT)\r
- {\r
- pt = wpage->wininfo->origin;\r
- flags &= ~SWP_NOSIZE;\r
- }\r
- if (wpage->wininfo->size.cx != CW_USEDEFAULT &&\r
- wpage->wininfo->size.cy != CW_USEDEFAULT)\r
- {\r
- sz = wpage->wininfo->size;\r
- flags &= ~SWP_NOMOVE;\r
- }\r
- SetWindowPos(win->hMainWnd, HWND_TOP, pt.x, pt.y, sz.cx, sz.cy, flags);\r
-\r
- if (wpage->page && win->page && wpage->page->file != win->page->file)\r
- WINHELP_DeleteBackSet(win);\r
- WINHELP_InitFonts(win->hMainWnd);\r
-\r
- win->page = wpage->page;\r
- win->info = wpage->wininfo;\r
- hTextWnd = GetDlgItem(win->hMainWnd, CTL_ID_TEXT);\r
- WINHELP_SetupText(hTextWnd, win, wpage->relative);\r
-\r
- InvalidateRect(win->hMainWnd, NULL, TRUE);\r
- if (win->hHistoryWnd) InvalidateRect(win->hHistoryWnd, NULL, TRUE);\r
-\r
- break;\r
- }\r
- }\r
- }\r
-\r
- if (!win)\r
- {\r
- /* Initialize WINHELP_WINDOW struct */\r
- win = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,\r
- sizeof(WINHELP_WINDOW) + strlen(wpage->wininfo->name) + 1);\r
- if (!win) return FALSE;\r
- win->next = Globals.win_list;\r
- Globals.win_list = win;\r
-\r
- name = (char*)win + sizeof(WINHELP_WINDOW);\r
- lstrcpy(name, wpage->wininfo->name);\r
- win->lpszName = name;\r
- win->hHandCur = LoadCursorW(0, (LPWSTR)IDC_HAND);\r
- win->back.index = 0;\r
- win->font_scale = 1;\r
- }\r
- win->page = wpage->page;\r
- win->info = wpage->wininfo;\r
-\r
- if (!bPopup && wpage->page && remember)\r
- {\r
- WINHELP_RememberPage(win, wpage);\r
- }\r
-\r
- if (bPopup)\r
- Globals.active_popup = win;\r
- else\r
- Globals.active_win = win;\r
-\r
- /* Initialize default pushbuttons */\r
- if (bPrimary && wpage->page)\r
- {\r
- CHAR buffer[MAX_STRING_LEN];\r
-\r
- LoadString(Globals.hInstance, STID_CONTENTS, buffer, sizeof(buffer));\r
- MACRO_CreateButton("BTN_CONTENTS", buffer, "Contents()");\r
- LoadString(Globals.hInstance, STID_INDEX, buffer, sizeof(buffer));\r
- MACRO_CreateButton("BTN_INDEX", buffer, "Finder()");\r
- LoadString(Globals.hInstance, STID_BACK, buffer, sizeof(buffer));\r
- MACRO_CreateButton("BTN_BACK", buffer, "Back()");\r
- if (win->back.index <= 1) MACRO_DisableButton("BTN_BACK");\r
- }\r
-\r
- if (!bReUsed)\r
- {\r
- win->hMainWnd = CreateWindowEx((bPopup) ? WS_EX_TOOLWINDOW : 0, MAIN_WIN_CLASS_NAME,\r
- WINHELP_GetCaption(wpage),\r
- bPrimary ? WS_OVERLAPPEDWINDOW : wpage->wininfo->win_style,\r
- wpage->wininfo->origin.x, wpage->wininfo->origin.y,\r
- wpage->wininfo->size.cx, wpage->wininfo->size.cy,\r
- bPopup ? Globals.active_win->hMainWnd : NULL,\r
- bPrimary ? LoadMenu(Globals.hInstance, MAKEINTRESOURCE(MAIN_MENU)) : 0,\r
- Globals.hInstance, win);\r
- if (!bPopup)\r
- /* Create button box and text Window */\r
- CreateWindow(BUTTON_BOX_WIN_CLASS_NAME, "", WS_CHILD | WS_VISIBLE,\r
- 0, 0, 0, 0, win->hMainWnd, (HMENU)CTL_ID_BUTTON, Globals.hInstance, NULL);\r
-\r
- hTextWnd = CreateWindow(RICHEDIT_CLASS, NULL,\r
- ES_MULTILINE | ES_READONLY | WS_CHILD | WS_HSCROLL | WS_VSCROLL | WS_VISIBLE,\r
- 0, 0, 0, 0, win->hMainWnd, (HMENU)CTL_ID_TEXT, Globals.hInstance, NULL);\r
- SendMessage(hTextWnd, EM_SETEVENTMASK, 0,\r
- SendMessage(hTextWnd, EM_GETEVENTMASK, 0, 0) | ENM_MOUSEEVENTS);\r
- }\r
-\r
- hIcon = (wpage->page) ? wpage->page->file->hIcon : NULL;\r
- if (!hIcon) hIcon = LoadIcon(Globals.hInstance, MAKEINTRESOURCE(IDI_WINHELP));\r
- SendMessage(win->hMainWnd, WM_SETICON, ICON_SMALL, (DWORD_PTR)hIcon);\r
-\r
- /* Initialize file specific pushbuttons */\r
- if (!(wpage->wininfo->win_style & WS_POPUP) && wpage->page)\r
- {\r
- HLPFILE_MACRO *macro;\r
- for (macro = wpage->page->file->first_macro; macro; macro = macro->next)\r
- MACRO_ExecuteMacro(macro->lpszMacro);\r
-\r
- for (macro = wpage->page->first_macro; macro; macro = macro->next)\r
- MACRO_ExecuteMacro(macro->lpszMacro);\r
- }\r
-\r
- if (bPopup)\r
- {\r
- DWORD mask = SendMessage(hTextWnd, EM_GETEVENTMASK, 0, 0);\r
- RECT rect;\r
-\r
- win->font_scale = Globals.active_win->font_scale;\r
- WINHELP_SetupText(hTextWnd, win, wpage->relative);\r
-\r
- /* we need the window to be shown for richedit to compute the size */\r
- ShowWindow(win->hMainWnd, nCmdShow);\r
- SendMessage(hTextWnd, EM_SETEVENTMASK, 0, mask | ENM_REQUESTRESIZE);\r
- SendMessage(hTextWnd, EM_REQUESTRESIZE, 0, 0);\r
- SendMessage(hTextWnd, EM_SETEVENTMASK, 0, mask);\r
-\r
- GetWindowRect(win->hMainWnd, &rect);\r
- win->hShadowWnd = CreateWindowEx(WS_EX_TOOLWINDOW, SHADOW_WIN_CLASS_NAME,\r
- "", WS_POPUP | WS_VISIBLE,\r
- rect.left + SHADOW_DX, rect.top + SHADOW_DY,\r
- rect.right - rect.left,\r
- rect.bottom - rect.top,\r
- Globals.active_win->hMainWnd, 0,\r
- Globals.hInstance, NULL);\r
- SetWindowPos(win->hMainWnd, win->hShadowWnd, 0, 0, 0, 0,\r
- SWP_NOSIZE | SWP_NOMOVE);\r
- }\r
- else\r
- {\r
- WINHELP_SetupText(hTextWnd, win, wpage->relative);\r
- WINHELP_LayoutMainWindow(win);\r
- ShowWindow(win->hMainWnd, nCmdShow);\r
- }\r
-\r
- return TRUE;\r
-}\r
-\r
-/******************************************************************\r
- * WINHELP_OpenHelpWindow\r
- * Main function to search for a page and display it in a window\r
- */\r
-BOOL WINHELP_OpenHelpWindow(HLPFILE_PAGE* (*lookup)(HLPFILE*, LONG, ULONG*),\r
- HLPFILE* hlpfile, LONG val, HLPFILE_WINDOWINFO* wi,\r
- int nCmdShow)\r
-{\r
- WINHELP_WNDPAGE wpage;\r
-\r
- wpage.page = lookup(hlpfile, val, &wpage.relative);\r
- if (wpage.page) wpage.page->file->wRefCount++;\r
- wpage.wininfo = wi;\r
- return WINHELP_CreateHelpWindow(&wpage, nCmdShow, TRUE);\r
-}\r
-\r
-/***********************************************************************\r
- *\r
- * WINHELP_FindLink\r
- */\r
-static HLPFILE_LINK* WINHELP_FindLink(WINHELP_WINDOW* win, LPARAM pos)\r
-{\r
- HLPFILE_LINK* link;\r
- POINTL mouse_ptl, char_ptl, char_next_ptl;\r
- DWORD cp;\r
-\r
- if (!win->page) return NULL;\r
-\r
- mouse_ptl.x = (short)LOWORD(pos);\r
- mouse_ptl.y = (short)HIWORD(pos);\r
- cp = SendMessageW(GetDlgItem(win->hMainWnd, CTL_ID_TEXT), EM_CHARFROMPOS,\r
- 0, (LPARAM)&mouse_ptl);\r
-\r
- for (link = win->page->first_link; link; link = link->next)\r
- {\r
- if (link->cpMin <= cp && cp <= link->cpMax)\r
- {\r
- /* check whether we're at end of line */\r
- SendMessageW(GetDlgItem(win->hMainWnd, CTL_ID_TEXT), EM_POSFROMCHAR,\r
- (LPARAM)&char_ptl, cp);\r
- SendMessageW(GetDlgItem(win->hMainWnd, CTL_ID_TEXT), EM_POSFROMCHAR,\r
- (LPARAM)&char_next_ptl, cp + 1);\r
- if (char_next_ptl.y != char_ptl.y || mouse_ptl.x >= char_next_ptl.x)\r
- link = NULL;\r
- break;\r
- }\r
- }\r
- return link;\r
-}\r
-\r
-/******************************************************************\r
- * WINHELP_HandleTextMouse\r
- *\r
- */\r
-static BOOL WINHELP_HandleTextMouse(WINHELP_WINDOW* win, UINT msg, LPARAM lParam)\r
-{\r
- HLPFILE* hlpfile;\r
- HLPFILE_LINK* link;\r
- BOOL ret = FALSE;\r
-\r
- switch (msg)\r
- {\r
- case WM_MOUSEMOVE:\r
- if (WINHELP_FindLink(win, lParam))\r
- SetCursor(win->hHandCur);\r
- else\r
- SetCursor(LoadCursor(0, IDC_ARROW));\r
- break;\r
-\r
- case WM_LBUTTONDOWN:\r
- if ((win->current_link = WINHELP_FindLink(win, lParam)))\r
- ret = TRUE;\r
- break;\r
-\r
- case WM_LBUTTONUP:\r
- if ((link = WINHELP_FindLink(win, lParam)) && link == win->current_link)\r
- {\r
- HLPFILE_WINDOWINFO* wi;\r
-\r
- switch (link->cookie)\r
- {\r
- case hlp_link_link:\r
- if ((hlpfile = WINHELP_LookupHelpFile(link->string)))\r
- {\r
- if (link->window == -1)\r
- wi = win->info;\r
- else if (link->window < hlpfile->numWindows)\r
- wi = &hlpfile->windows[link->window];\r
- else\r
- {\r
- WINE_WARN("link to window %d/%d\n", link->window, hlpfile->numWindows);\r
- break;\r
- }\r
- WINHELP_OpenHelpWindow(HLPFILE_PageByHash, hlpfile, link->hash, wi, SW_NORMAL);\r
- }\r
- break;\r
- case hlp_link_popup:\r
- if ((hlpfile = WINHELP_LookupHelpFile(link->string)))\r
- WINHELP_OpenHelpWindow(HLPFILE_PageByHash, hlpfile, link->hash,\r
- WINHELP_GetPopupWindowInfo(hlpfile, win, lParam),\r
- SW_NORMAL);\r
- break;\r
- case hlp_link_macro:\r
- MACRO_ExecuteMacro(link->string);\r
- break;\r
- default:\r
- WINE_FIXME("Unknown link cookie %d\n", link->cookie);\r
- }\r
- ret = TRUE;\r
- }\r
- win->current_link = NULL;\r
- break;\r
- }\r
- return ret;\r
-}\r
-\r
-/***********************************************************************\r
- *\r
- * WINHELP_MainWndProc\r
- */\r
-static LRESULT CALLBACK WINHELP_MainWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)\r
-{\r
- WINHELP_WINDOW *win;\r
- WINHELP_BUTTON *button;\r
- RECT rect;\r
- INT curPos, min, max, dy, keyDelta;\r
- HWND hTextWnd;\r
- LRESULT ret;\r
-\r
- if (WINHELP_CheckPopup(hWnd, msg, wParam, lParam, &ret)) return ret;\r
-\r
- switch (msg)\r
- {\r
- case WM_NCCREATE:\r
- win = (WINHELP_WINDOW*) ((LPCREATESTRUCT) lParam)->lpCreateParams;\r
- SetWindowLongPtr(hWnd, 0, (ULONG_PTR) win);\r
- if (!win->page && Globals.isBook)\r
- PostMessage(hWnd, WM_COMMAND, MNID_FILE_OPEN, 0);\r
- win->hMainWnd = hWnd;\r
- break;\r
-\r
- case WM_WINDOWPOSCHANGED:\r
- WINHELP_LayoutMainWindow((WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0));\r
- break;\r
-\r
- case WM_COMMAND:\r
- win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0);\r
- switch (wParam)\r
- {\r
- /* Menu FILE */\r
- case MNID_FILE_OPEN: MACRO_FileOpen(); break;\r
- case MNID_FILE_PRINT: MACRO_Print(); break;\r
- case MNID_FILE_SETUP: MACRO_PrinterSetup(); break;\r
- case MNID_FILE_EXIT: MACRO_Exit(); break;\r
-\r
- /* Menu EDIT */\r
- case MNID_EDIT_COPYDLG:\r
- SendMessage(GetDlgItem(hWnd, CTL_ID_TEXT), WM_COPY, 0, 0);\r
- break;\r
- case MNID_EDIT_ANNOTATE:MACRO_Annotate(); break;\r
-\r
- /* Menu Bookmark */\r
- case MNID_BKMK_DEFINE: MACRO_BookmarkDefine(); break;\r
-\r
- /* Menu Help */\r
- case MNID_HELP_HELPON: MACRO_HelpOn(); break;\r
- case MNID_HELP_HELPTOP: MACRO_HelpOnTop(); break;\r
- case MNID_HELP_ABOUT: MACRO_About(); break;\r
- case MNID_HELP_WINE: ShellAbout(hWnd, "WINE", "Help", 0); break;\r
-\r
- /* Context help */\r
- case MNID_CTXT_ANNOTATE:MACRO_Annotate(); break;\r
- case MNID_CTXT_COPY: MACRO_CopyDialog(); break;\r
- case MNID_CTXT_PRINT: MACRO_Print(); break;\r
- case MNID_OPTS_HISTORY: MACRO_History(); break;\r
- case MNID_OPTS_FONTS_SMALL:\r
- case MNID_CTXT_FONTS_SMALL:\r
- win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0);\r
- if (win->font_scale != 0)\r
- {\r
- win->font_scale = 0;\r
- WINHELP_SetupText(GetDlgItem(hWnd, CTL_ID_TEXT), win, 0 /* FIXME */);\r
- }\r
- break;\r
- case MNID_OPTS_FONTS_NORMAL:\r
- case MNID_CTXT_FONTS_NORMAL:\r
- win = (WINHELP_WINDOW*) GetWindowLong(hWnd, 0);\r
- if (win->font_scale != 1)\r
- {\r
- win->font_scale = 1;\r
- WINHELP_SetupText(GetDlgItem(hWnd, CTL_ID_TEXT), win, 0 /* FIXME */);\r
- }\r
- break;\r
- case MNID_OPTS_FONTS_LARGE:\r
- case MNID_CTXT_FONTS_LARGE:\r
- win = (WINHELP_WINDOW*) GetWindowLong(hWnd, 0);\r
- if (win->font_scale != 2)\r
- {\r
- win->font_scale = 2;\r
- WINHELP_SetupText(GetDlgItem(hWnd, CTL_ID_TEXT), win, 0 /* FIXME */);\r
- }\r
- break;\r
- case MNID_OPTS_HELP_DEFAULT:\r
- case MNID_OPTS_HELP_VISIBLE:\r
- case MNID_OPTS_HELP_NONVISIBLE:\r
- case MNID_OPTS_SYSTEM_COLORS:\r
- case MNID_CTXT_HELP_DEFAULT:\r
- case MNID_CTXT_HELP_VISIBLE:\r
- case MNID_CTXT_HELP_NONVISIBLE:\r
- case MNID_CTXT_SYSTEM_COLORS:\r
- /* FIXME: NIY */\r
-\r
- default:\r
- /* Buttons */\r
- for (button = win->first_button; button; button = button->next)\r
- if (wParam == button->wParam) break;\r
- if (button)\r
- MACRO_ExecuteMacro(button->lpszMacro);\r
- else if (!HIWORD(wParam))\r
- MessageBox(0, MAKEINTRESOURCE(STID_NOT_IMPLEMENTED),\r
- MAKEINTRESOURCE(STID_WHERROR), MB_OK);\r
- break;\r
- }\r
- break;\r
-/* EPP case WM_DESTROY: */\r
-/* EPP if (Globals.hPopupWnd) DestroyWindow(Globals.hPopupWnd); */\r
-/* EPP break; */\r
- case WM_COPYDATA:\r
- return WINHELP_HandleCommand((HWND)wParam, lParam);\r
-\r
- case WM_CHAR:\r
- if (wParam == 3)\r
- {\r
- SendMessage(GetDlgItem(hWnd, CTL_ID_TEXT), WM_COPY, 0, 0);\r
- return 0;\r
- }\r
- break;\r
-\r
- case WM_KEYDOWN:\r
- keyDelta = 0;\r
-\r
- switch (wParam)\r
- {\r
- case VK_UP:\r
- case VK_DOWN:\r
- keyDelta = GetSystemMetrics(SM_CXVSCROLL);\r
- if (wParam == VK_UP)\r
- keyDelta = -keyDelta;\r
-\r
- case VK_PRIOR:\r
- case VK_NEXT:\r
- win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0);\r
- hTextWnd = GetDlgItem(win->hMainWnd, CTL_ID_TEXT);\r
- curPos = GetScrollPos(hTextWnd, SB_VERT);\r
- GetScrollRange(hTextWnd, SB_VERT, &min, &max);\r
-\r
- if (keyDelta == 0)\r
- { \r
- GetClientRect(hTextWnd, &rect);\r
- keyDelta = (rect.bottom - rect.top) / 2;\r
- if (wParam == VK_PRIOR)\r
- keyDelta = -keyDelta;\r
- }\r
-\r
- curPos += keyDelta;\r
- if (curPos > max)\r
- curPos = max;\r
- else if (curPos < min)\r
- curPos = min;\r
-\r
- dy = GetScrollPos(hTextWnd, SB_VERT) - curPos;\r
- SetScrollPos(hTextWnd, SB_VERT, curPos, TRUE);\r
- ScrollWindow(hTextWnd, 0, dy, NULL, NULL);\r
- UpdateWindow(hTextWnd);\r
- return 0;\r
-\r
- case VK_ESCAPE:\r
- MACRO_Exit();\r
- return 0;\r
- }\r
- break;\r
-\r
- case WM_NOTIFY:\r
- if (wParam == CTL_ID_TEXT)\r
- {\r
- RECT rc;\r
-\r
- switch (((NMHDR*)lParam)->code)\r
- {\r
- case EN_MSGFILTER:\r
- {\r
- const MSGFILTER* msgf = (const MSGFILTER*)lParam;\r
- switch (msgf->msg)\r
- {\r
- case WM_KEYUP:\r
- if (msgf->wParam == VK_ESCAPE) DestroyWindow(hWnd);\r
- break;\r
- case WM_RBUTTONDOWN:\r
- {\r
- HMENU hMenu;\r
- POINT pt;\r
-\r
- win = (WINHELP_WINDOW*) GetWindowLong(hWnd, 0);\r
- hMenu = LoadMenu(Globals.hInstance, (LPSTR)CONTEXT_MENU);\r
- switch (win->font_scale)\r
- {\r
- case 0:\r
- CheckMenuItem(hMenu, MNID_CTXT_FONTS_SMALL,\r
- MF_BYCOMMAND|MF_CHECKED);\r
- break;\r
- default:\r
- WINE_FIXME("Unsupported %d\n", win->font_scale);\r
- case 1:\r
- CheckMenuItem(hMenu, MNID_CTXT_FONTS_NORMAL,\r
- MF_BYCOMMAND|MF_CHECKED);\r
- break;\r
- case 2:\r
- CheckMenuItem(hMenu, MNID_CTXT_FONTS_LARGE,\r
- MF_BYCOMMAND|MF_CHECKED);\r
- break;\r
- }\r
- pt.x = (int)(short)LOWORD(msgf->lParam);\r
- pt.y = (int)(short)HIWORD(msgf->lParam);\r
- ClientToScreen(msgf->nmhdr.hwndFrom, &pt);\r
- TrackPopupMenu(GetSubMenu(hMenu, 0), TPM_LEFTALIGN|TPM_TOPALIGN,\r
- pt.x, pt.y, 0, hWnd, NULL);\r
- DestroyMenu(hMenu);\r
- }\r
- break;\r
- default:\r
- return WINHELP_HandleTextMouse((WINHELP_WINDOW*)GetWindowLongPtr(hWnd, 0),\r
- msgf->msg, msgf->lParam);\r
- }\r
- }\r
- break;\r
-\r
- case EN_REQUESTRESIZE:\r
- rc = ((REQRESIZE*)lParam)->rc;\r
- win = (WINHELP_WINDOW*) GetWindowLong(hWnd, 0);\r
- AdjustWindowRect(&rc, GetWindowLong(win->hMainWnd, GWL_STYLE),\r
- FALSE);\r
- SetWindowPos(win->hMainWnd, HWND_TOP, 0, 0,\r
- rc.right - rc.left, rc.bottom - rc.top,\r
- SWP_NOMOVE | SWP_NOZORDER);\r
- WINHELP_LayoutMainWindow(win);\r
- break;\r
- }\r
- }\r
- break;\r
-\r
- case WM_INITMENUPOPUP:\r
- win = (WINHELP_WINDOW*) GetWindowLong(hWnd, 0);\r
- CheckMenuItem((HMENU)wParam, MNID_OPTS_FONTS_SMALL,\r
- MF_BYCOMMAND | (win->font_scale == 0) ? MF_CHECKED : 0);\r
- CheckMenuItem((HMENU)wParam, MNID_OPTS_FONTS_NORMAL,\r
- MF_BYCOMMAND | (win->font_scale == 1) ? MF_CHECKED : 0);\r
- CheckMenuItem((HMENU)wParam, MNID_OPTS_FONTS_LARGE,\r
- MF_BYCOMMAND | (win->font_scale == 2) ? MF_CHECKED : 0);\r
- break;\r
-\r
- case WM_NCDESTROY:\r
- {\r
- BOOL bExit;\r
- win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0);\r
- bExit = (Globals.wVersion >= 4 && !lstrcmpi(win->lpszName, "main"));\r
- WINHELP_DeleteWindow(win);\r
-\r
- if (bExit) MACRO_Exit();\r
- if (!Globals.win_list)\r
- PostQuitMessage(0);\r
- }\r
- break;\r
- }\r
- return DefWindowProc(hWnd, msg, wParam, lParam);\r
-}\r
-\r
-static DWORD CALLBACK WINHELP_RtfStreamIn(DWORD_PTR cookie, BYTE* buff,\r
- LONG cb, LONG* pcb)\r
-{\r
- struct RtfData* rd = (struct RtfData*)cookie;\r
-\r
- if (rd->where >= rd->ptr) return 1;\r
- if (rd->where + cb > rd->ptr)\r
- cb = rd->ptr - rd->where;\r
- memcpy(buff, rd->where, cb);\r
- rd->where += cb;\r
- *pcb = cb;\r
- return 0;\r
-}\r
-\r
-static void WINHELP_SetupText(HWND hTextWnd, WINHELP_WINDOW* win, ULONG relative)\r
-{\r
- /* At first clear area - needed by EM_POSFROMCHAR/EM_SETSCROLLPOS */\r
- SendMessage(hTextWnd, WM_SETTEXT, 0, (LPARAM)"");\r
- SendMessage(hTextWnd, WM_SETREDRAW, FALSE, 0);\r
- SendMessage(hTextWnd, EM_SETBKGNDCOLOR, 0, (LPARAM)win->info->sr_color);\r
- /* set word-wrap to window size (undocumented) */\r
- SendMessage(hTextWnd, EM_SETTARGETDEVICE, 0, 0);\r
- if (win->page)\r
- {\r
- struct RtfData rd;\r
- EDITSTREAM es;\r
- unsigned cp = 0;\r
- POINTL ptl;\r
- POINT pt;\r
-\r
-\r
- if (HLPFILE_BrowsePage(win->page, &rd, win->font_scale, relative))\r
- {\r
- rd.where = rd.data;\r
- es.dwCookie = (DWORD_PTR)&rd;\r
- es.dwError = 0;\r
- es.pfnCallback = WINHELP_RtfStreamIn;\r
-\r
- SendMessageW(hTextWnd, EM_STREAMIN, SF_RTF, (LPARAM)&es);\r
- cp = rd.char_pos_rel;\r
- }\r
- /* FIXME: else leaking potentially the rd.first_link chain */\r
- HeapFree(GetProcessHeap(), 0, rd.data);\r
- SendMessage(hTextWnd, EM_POSFROMCHAR, (WPARAM)&ptl, cp ? cp - 1 : 0);\r
- pt.x = 0; pt.y = ptl.y;\r
- SendMessage(hTextWnd, EM_SETSCROLLPOS, 0, (LPARAM)&pt);\r
- }\r
- SendMessage(hTextWnd, WM_SETREDRAW, TRUE, 0);\r
- InvalidateRect(hTextWnd, NULL, TRUE);\r
-}\r
-\r
-/***********************************************************************\r
- *\r
- * WINHELP_ButtonBoxWndProc\r
- */\r
-static LRESULT CALLBACK WINHELP_ButtonBoxWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)\r
-{\r
- WINDOWPOS *winpos;\r
- WINHELP_WINDOW *win;\r
- WINHELP_BUTTON *button;\r
- SIZE button_size;\r
- INT x, y;\r
-\r
- if (WINHELP_CheckPopup(hWnd, msg, wParam, lParam, NULL)) return 0L;\r
-\r
- switch (msg)\r
- {\r
- case WM_WINDOWPOSCHANGING:\r
- winpos = (WINDOWPOS*) lParam;\r
- win = (WINHELP_WINDOW*) GetWindowLongPtr(GetParent(hWnd), 0);\r
-\r
- /* Update buttons */\r
- button_size.cx = 0;\r
- button_size.cy = 0;\r
- for (button = win->first_button; button; button = button->next)\r
- {\r
- HDC hDc;\r
- SIZE textsize;\r
- if (!button->hWnd)\r
- {\r
- button->hWnd = CreateWindow(STRING_BUTTON, button->lpszName,\r
- WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,\r
- 0, 0, 0, 0,\r
- hWnd, (HMENU) button->wParam,\r
- Globals.hInstance, 0);\r
- if (button->hWnd)\r
- {\r
- if (Globals.button_proc == NULL)\r
- {\r
- NONCLIENTMETRICSW ncm;\r
- Globals.button_proc = (WNDPROC) GetWindowLongPtr(button->hWnd, GWLP_WNDPROC);\r
-\r
- ncm.cbSize = sizeof(NONCLIENTMETRICSW);\r
- SystemParametersInfoW(SPI_GETNONCLIENTMETRICS,\r
- sizeof(NONCLIENTMETRICSW), &ncm, 0);\r
- Globals.hButtonFont = CreateFontIndirectW(&ncm.lfMenuFont);\r
- }\r
- SetWindowLongPtr(button->hWnd, GWLP_WNDPROC, (LONG_PTR) WINHELP_ButtonWndProc);\r
- if (Globals.hButtonFont)\r
- SendMessage(button->hWnd, WM_SETFONT, (WPARAM)Globals.hButtonFont, TRUE);\r
- }\r
- }\r
- hDc = GetDC(button->hWnd);\r
- GetTextExtentPoint(hDc, button->lpszName,\r
- lstrlen(button->lpszName), &textsize);\r
- ReleaseDC(button->hWnd, hDc);\r
-\r
- button_size.cx = max(button_size.cx, textsize.cx + BUTTON_CX);\r
- button_size.cy = max(button_size.cy, textsize.cy + BUTTON_CY);\r
- }\r
-\r
- x = 0;\r
- y = 0;\r
- for (button = win->first_button; button; button = button->next)\r
- {\r
- SetWindowPos(button->hWnd, HWND_TOP, x, y, button_size.cx, button_size.cy, 0);\r
-\r
- if (x + 2 * button_size.cx <= winpos->cx)\r
- x += button_size.cx;\r
- else\r
- x = 0, y += button_size.cy;\r
- }\r
- winpos->cy = y + (x ? button_size.cy : 0);\r
- break;\r
-\r
- case WM_COMMAND:\r
- SendMessage(GetParent(hWnd), msg, wParam, lParam);\r
- break;\r
-\r
- case WM_KEYDOWN:\r
- switch (wParam)\r
- {\r
- case VK_UP:\r
- case VK_DOWN:\r
- case VK_PRIOR:\r
- case VK_NEXT:\r
- case VK_ESCAPE:\r
- return SendMessage(GetParent(hWnd), msg, wParam, lParam);\r
- }\r
- break;\r
- }\r
-\r
- return DefWindowProc(hWnd, msg, wParam, lParam);\r
-}\r
-\r
-/***********************************************************************\r
- *\r
- * WINHELP_ButtonWndProc\r
- */\r
-static LRESULT CALLBACK WINHELP_ButtonWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)\r
-{\r
- if (WINHELP_CheckPopup(hWnd, msg, wParam, lParam, NULL)) return 0;\r
-\r
- if (msg == WM_KEYDOWN)\r
- {\r
- switch (wParam)\r
- {\r
- case VK_UP:\r
- case VK_DOWN:\r
- case VK_PRIOR:\r
- case VK_NEXT:\r
- case VK_ESCAPE:\r
- return SendMessage(GetParent(hWnd), msg, wParam, lParam);\r
- }\r
- }\r
-\r
- return CallWindowProc(Globals.button_proc, hWnd, msg, wParam, lParam);\r
-}\r
-\r
-/******************************************************************\r
- * WINHELP_HistoryWndProc\r
- *\r
- *\r
- */\r
-static LRESULT CALLBACK WINHELP_HistoryWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)\r
-{\r
- WINHELP_WINDOW* win;\r
- PAINTSTRUCT ps;\r
- HDC hDc;\r
- TEXTMETRIC tm;\r
- unsigned int i;\r
- RECT r;\r
-\r
- switch (msg)\r
- {\r
- case WM_NCCREATE:\r
- win = (WINHELP_WINDOW*)((LPCREATESTRUCT)lParam)->lpCreateParams;\r
- SetWindowLongPtr(hWnd, 0, (ULONG_PTR)win);\r
- win->hHistoryWnd = hWnd;\r
- break;\r
- case WM_CREATE:\r
- win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0);\r
- hDc = GetDC(hWnd);\r
- GetTextMetrics(hDc, &tm);\r
- GetWindowRect(hWnd, &r);\r
-\r
- r.right = r.left + 30 * tm.tmAveCharWidth;\r
- r.bottom = r.top + (sizeof(Globals.history.set) / sizeof(Globals.history.set[0])) * tm.tmHeight;\r
- AdjustWindowRect(&r, GetWindowLong(hWnd, GWL_STYLE), FALSE);\r
- if (r.left < 0) {r.right -= r.left; r.left = 0;}\r
- if (r.top < 0) {r.bottom -= r.top; r.top = 0;}\r
-\r
- MoveWindow(hWnd, r.left, r.top, r.right, r.bottom, TRUE);\r
- ReleaseDC(hWnd, hDc);\r
- break;\r
- case WM_LBUTTONDOWN:\r
- win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0);\r
- hDc = GetDC(hWnd);\r
- GetTextMetrics(hDc, &tm);\r
- i = HIWORD(lParam) / tm.tmHeight;\r
- if (i < Globals.history.index)\r
- WINHELP_CreateHelpWindow(&Globals.history.set[i], SW_SHOW, TRUE);\r
- ReleaseDC(hWnd, hDc);\r
- break;\r
- case WM_PAINT:\r
- hDc = BeginPaint(hWnd, &ps);\r
- win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0);\r
- GetTextMetrics(hDc, &tm);\r
-\r
- for (i = 0; i < Globals.history.index; i++)\r
- {\r
- if (Globals.history.set[i].page->file == Globals.active_win->page->file)\r
- {\r
- TextOut(hDc, 0, i * tm.tmHeight,\r
- Globals.history.set[i].page->lpszTitle,\r
- strlen(Globals.history.set[i].page->lpszTitle));\r
- }\r
- else\r
- {\r
- char buffer[1024];\r
- const char* ptr1;\r
- const char* ptr2;\r
- unsigned len;\r
-\r
- ptr1 = strrchr(Globals.history.set[i].page->file->lpszPath, '\\');\r
- if (!ptr1) ptr1 = Globals.history.set[i].page->file->lpszPath;\r
- else ptr1++;\r
- ptr2 = strrchr(ptr1, '.');\r
- len = ptr2 ? ptr2 - ptr1 : strlen(ptr1);\r
- if (len > sizeof(buffer)) len = sizeof(buffer);\r
- memcpy(buffer, ptr1, len);\r
- if (len < sizeof(buffer)) buffer[len++] = ':';\r
- strncpy(&buffer[len], Globals.history.set[i].page->lpszTitle, sizeof(buffer) - len);\r
- buffer[sizeof(buffer) - 1] = '\0';\r
- TextOut(hDc, 0, i * tm.tmHeight, buffer, strlen(buffer));\r
- }\r
- }\r
- EndPaint(hWnd, &ps);\r
- break;\r
- case WM_DESTROY:\r
- win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0);\r
- if (hWnd == win->hHistoryWnd)\r
- win->hHistoryWnd = 0;\r
- break;\r
- }\r
- return DefWindowProc(hWnd, msg, wParam, lParam);\r
-}\r
-\r
-/***********************************************************************\r
- *\r
- * WINHELP_ShadowWndProc\r
- */\r
-static LRESULT CALLBACK WINHELP_ShadowWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)\r
-{\r
- if (WINHELP_CheckPopup(hWnd, msg, wParam, lParam, NULL)) return 0;\r
- return WINHELP_CheckPopup(hWnd, msg, wParam, lParam, NULL) ? 0L : DefWindowProc(hWnd, msg, wParam, lParam);\r
-}\r
-\r
-/***********************************************************************\r
- *\r
- * WINHELP_CheckPopup\r
- */\r
-static BOOL WINHELP_CheckPopup(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, LRESULT* lret)\r
-{\r
- HWND hPopup;\r
-\r
- if (!Globals.active_popup) return FALSE;\r
-\r
- switch (msg)\r
- {\r
- case WM_NOTIFY:\r
- {\r
- MSGFILTER* msgf = (MSGFILTER*)lParam;\r
- if (msgf->nmhdr.code == EN_MSGFILTER)\r
- {\r
- if (!WINHELP_CheckPopup(hWnd, msgf->msg, msgf->wParam, msgf->lParam, NULL))\r
- return FALSE;\r
- if (lret) *lret = 1;\r
- return TRUE;\r
- }\r
- }\r
- break;\r
- case WM_ACTIVATE:\r
- if (wParam != WA_INACTIVE || (HWND)lParam == Globals.active_win->hMainWnd ||\r
- (HWND)lParam == Globals.active_popup->hMainWnd ||\r
- GetWindow((HWND)lParam, GW_OWNER) == Globals.active_win->hMainWnd)\r
- break;\r
- case WM_LBUTTONUP:\r
- case WM_LBUTTONDOWN:\r
- if (WINHELP_HandleTextMouse(Globals.active_popup, msg, lParam) && msg == WM_LBUTTONDOWN)\r
- return FALSE;\r
- /* fall through */\r
- case WM_MBUTTONDOWN:\r
- case WM_RBUTTONDOWN:\r
- case WM_NCLBUTTONDOWN:\r
- case WM_NCMBUTTONDOWN:\r
- case WM_NCRBUTTONDOWN:\r
- hPopup = Globals.active_popup->hMainWnd;\r
- Globals.active_popup = NULL;\r
- DestroyWindow(hPopup);\r
- return TRUE;\r
- }\r
- return FALSE;\r
-}\r
-\r
-/******************************************************************\r
- * WINHELP_DeleteButtons\r
- *\r
- */\r
-static void WINHELP_DeleteButtons(WINHELP_WINDOW* win)\r
-{\r
- WINHELP_BUTTON* b;\r
- WINHELP_BUTTON* bp;\r
-\r
- for (b = win->first_button; b; b = bp)\r
- {\r
- DestroyWindow(b->hWnd);\r
- bp = b->next;\r
- HeapFree(GetProcessHeap(), 0, b);\r
- }\r
- win->first_button = NULL;\r
-}\r
-\r
-/******************************************************************\r
- * WINHELP_DeleteBackSet\r
- *\r
- */\r
-void WINHELP_DeleteBackSet(WINHELP_WINDOW* win)\r
-{\r
- unsigned int i;\r
-\r
- for (i = 0; i < win->back.index; i++)\r
- {\r
- HLPFILE_FreeHlpFile(win->back.set[i].page->file);\r
- win->back.set[i].page = NULL;\r
- }\r
- win->back.index = 0;\r
-}\r
-\r
-/******************************************************************\r
- * WINHELP_DeletePageLinks\r
- *\r
- */\r
-static void WINHELP_DeletePageLinks(HLPFILE_PAGE* page)\r
-{\r
- HLPFILE_LINK* curr;\r
- HLPFILE_LINK* next;\r
-\r
- for (curr = page->first_link; curr; curr = next)\r
- {\r
- next = curr->next;\r
- HeapFree(GetProcessHeap(), 0, curr);\r
- }\r
-}\r
-\r
-/***********************************************************************\r
- *\r
- * WINHELP_DeleteWindow\r
- */\r
-static void WINHELP_DeleteWindow(WINHELP_WINDOW* win)\r
-{\r
- WINHELP_WINDOW** w;\r
-\r
- for (w = &Globals.win_list; *w; w = &(*w)->next)\r
- {\r
- if (*w == win)\r
- {\r
- *w = win->next;\r
- break;\r
- }\r
- }\r
-\r
- if (Globals.active_win == win)\r
- {\r
- Globals.active_win = Globals.win_list;\r
- if (Globals.win_list)\r
- SetActiveWindow(Globals.win_list->hMainWnd);\r
- }\r
-\r
- if (win == Globals.active_popup)\r
- Globals.active_popup = NULL;\r
-\r
- WINHELP_DeleteButtons(win);\r
-\r
- if (win->page) WINHELP_DeletePageLinks(win->page);\r
- if (win->hShadowWnd) DestroyWindow(win->hShadowWnd);\r
- if (win->hHistoryWnd) DestroyWindow(win->hHistoryWnd);\r
-\r
- DeleteObject(win->hBrush);\r
-\r
- WINHELP_DeleteBackSet(win);\r
-\r
- if (win->page) HLPFILE_FreeHlpFile(win->page->file);\r
- HeapFree(GetProcessHeap(), 0, win);\r
-}\r
-\r
-/***********************************************************************\r
- *\r
- * WINHELP_InitFonts\r
- */\r
-static void WINHELP_InitFonts(HWND hWnd)\r
-{\r
- WINHELP_WINDOW *win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0);\r
- LOGFONT logfontlist[] = {\r
- {-10, 0, 0, 0, 400, 0, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 32, "Helv"},\r
- {-12, 0, 0, 0, 700, 0, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 32, "Helv"},\r
- {-12, 0, 0, 0, 700, 0, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 32, "Helv"},\r
- {-12, 0, 0, 0, 400, 0, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 32, "Helv"},\r
- {-12, 0, 0, 0, 700, 0, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 32, "Helv"},\r
- {-10, 0, 0, 0, 700, 0, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 32, "Helv"},\r
- { -8, 0, 0, 0, 400, 0, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 32, "Helv"}};\r
-#define FONTS_LEN (sizeof(logfontlist)/sizeof(*logfontlist))\r
-\r
- static HFONT fonts[FONTS_LEN];\r
- static BOOL init = 0;\r
-\r
- win->fonts_len = FONTS_LEN;\r
- win->fonts = fonts;\r
-\r
- if (!init)\r
- {\r
- UINT i;\r
-\r
- for (i = 0; i < FONTS_LEN; i++)\r
- {\r
- fonts[i] = CreateFontIndirect(&logfontlist[i]);\r
- }\r
-\r
- init = 1;\r
- }\r
-}\r
-\r
-/***********************************************************************\r
- *\r
- * WINHELP_MessageBoxIDS_s\r
- */\r
-INT WINHELP_MessageBoxIDS_s(UINT ids_text, LPCSTR str, UINT ids_title, WORD type)\r
-{\r
- CHAR text[MAX_STRING_LEN];\r
- CHAR newtext[MAX_STRING_LEN + MAX_PATH];\r
-\r
- LoadString(Globals.hInstance, ids_text, text, sizeof(text));\r
- wsprintf(newtext, text, str);\r
-\r
- return MessageBox(0, newtext, MAKEINTRESOURCE(ids_title), type);\r
-}\r
-\r
-/**************************************************************************\r
- * cb_KWBTree\r
- *\r
- * HLPFILE_BPTreeCallback enumeration function for '|KWBTREE' internal file.\r
- *\r
- */\r
-static void cb_KWBTree(void *p, void **next, void *cookie)\r
-{\r
- HWND hListWnd = (HWND)cookie;\r
- int count;\r
-\r
- WINE_TRACE("Adding '%s' to search list\n", (char *)p);\r
- SendMessage(hListWnd, LB_INSERTSTRING, -1, (LPARAM)p);\r
- count = SendMessage(hListWnd, LB_GETCOUNT, 0, 0);\r
- SendMessage(hListWnd, LB_SETITEMDATA, count-1, (LPARAM)p);\r
- *next = (char*)p + strlen((char*)p) + 7;\r
-}\r
-\r
-struct index_data\r
-{\r
- HLPFILE* hlpfile;\r
- BOOL jump;\r
- ULONG offset;\r
-};\r
-\r
-/**************************************************************************\r
- * WINHELP_IndexDlgProc\r
- *\r
- */\r
-INT_PTR CALLBACK WINHELP_IndexDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)\r
-{\r
- static struct index_data* id;\r
- int sel;\r
-\r
- switch (msg)\r
- {\r
- case WM_INITDIALOG:\r
- id = (struct index_data*)((PROPSHEETPAGE*)lParam)->lParam;\r
- HLPFILE_BPTreeEnum(id->hlpfile->kwbtree, cb_KWBTree,\r
- GetDlgItem(hWnd, IDC_INDEXLIST));\r
- id->jump = FALSE;\r
- id->offset = 1;\r
- return TRUE;\r
- case WM_COMMAND:\r
- switch (HIWORD(wParam))\r
- {\r
- case LBN_DBLCLK:\r
- if (LOWORD(wParam) == IDC_INDEXLIST)\r
- SendMessage(GetParent(hWnd), PSM_PRESSBUTTON, PSBTN_OK, 0);\r
- break;\r
- }\r
- break;\r
- case WM_NOTIFY:\r
- switch (((NMHDR*)lParam)->code)\r
- {\r
- case PSN_APPLY:\r
- sel = SendDlgItemMessage(hWnd, IDC_INDEXLIST, LB_GETCURSEL, 0, 0);\r
- if (sel != LB_ERR)\r
- {\r
- BYTE *p;\r
- int count;\r
-\r
- p = (BYTE*)SendDlgItemMessage(hWnd, IDC_INDEXLIST,\r
- LB_GETITEMDATA, sel, 0);\r
- count = *(short*)((char *)p + strlen((char *)p) + 1);\r
- if (count > 1)\r
- {\r
- MessageBox(hWnd, "count > 1 not supported yet", "Error", MB_OK | MB_ICONSTOP);\r
- SetWindowLongPtr(hWnd, DWLP_MSGRESULT, PSNRET_INVALID);\r
- return TRUE;\r
- }\r
- id->offset = *(ULONG*)((char *)p + strlen((char *)p) + 3);\r
- id->offset = *(long*)(id->hlpfile->kwdata + id->offset + 9);\r
- if (id->offset == 0xFFFFFFFF)\r
- {\r
- MessageBox(hWnd, "macro keywords not supported yet", "Error", MB_OK | MB_ICONSTOP);\r
- SetWindowLongPtr(hWnd, DWLP_MSGRESULT, PSNRET_INVALID);\r
- return TRUE;\r
- }\r
- id->jump = TRUE;\r
- SetWindowLongPtr(hWnd, DWLP_MSGRESULT, PSNRET_NOERROR);\r
- }\r
- return TRUE;\r
- default:\r
- return FALSE;\r
- }\r
- break;\r
- default:\r
- break;\r
- }\r
- return FALSE;\r
-}\r
-\r
-/**************************************************************************\r
- * WINHELP_SearchDlgProc\r
- *\r
- */\r
-INT_PTR CALLBACK WINHELP_SearchDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)\r
-{\r
- static struct index_data* id;\r
-\r
- switch (msg)\r
- {\r
- case WM_INITDIALOG:\r
- id = (struct index_data*)((PROPSHEETPAGE*)lParam)->lParam;\r
- return TRUE;\r
- case WM_NOTIFY:\r
- switch (((NMHDR*)lParam)->code)\r
- {\r
- case PSN_APPLY:\r
- SetWindowLongPtr(hWnd, DWLP_MSGRESULT, PSNRET_NOERROR);\r
- return TRUE;\r
- default:\r
- return FALSE;\r
- }\r
- break;\r
- default:\r
- break;\r
- }\r
- return FALSE;\r
-}\r
-\r
-/**************************************************************************\r
- * WINHELP_CreateIndexWindow\r
- *\r
- * Displays a dialog with keywords of current help file.\r
- *\r
- */\r
-BOOL WINHELP_CreateIndexWindow(BOOL is_search)\r
-{\r
- HPROPSHEETPAGE psPage[3];\r
- PROPSHEETPAGE psp;\r
- PROPSHEETHEADER psHead;\r
- struct index_data id;\r
- char buf[256];\r
-\r
- if (Globals.active_win && Globals.active_win->page && Globals.active_win->page->file)\r
- id.hlpfile = Globals.active_win->page->file;\r
- else\r
- return FALSE;\r
-\r
- if (id.hlpfile->kwbtree == NULL)\r
- {\r
- WINE_TRACE("No index provided\n");\r
- return FALSE;\r
- }\r
-\r
- InitCommonControls();\r
-\r
- id.jump = FALSE;\r
- memset(&psp, 0, sizeof(psp));\r
- psp.dwSize = sizeof(psp);\r
- psp.dwFlags = 0;\r
- psp.hInstance = Globals.hInstance;\r
-\r
- psp.u.pszTemplate = MAKEINTRESOURCE(IDD_INDEX);\r
- psp.lParam = (LPARAM)&id;\r
- psp.pfnDlgProc = WINHELP_IndexDlgProc;\r
- psPage[0] = CreatePropertySheetPage(&psp);\r
-\r
- psp.u.pszTemplate = MAKEINTRESOURCE(IDD_SEARCH);\r
- psp.lParam = (LPARAM)&id;\r
- psp.pfnDlgProc = WINHELP_SearchDlgProc;\r
- psPage[1] = CreatePropertySheetPage(&psp);\r
-\r
- memset(&psHead, 0, sizeof(psHead));\r
- psHead.dwSize = sizeof(psHead);\r
-\r
- LoadString(Globals.hInstance, STID_PSH_INDEX, buf, sizeof(buf));\r
- strcat(buf, Globals.active_win->info->caption);\r
-\r
- psHead.pszCaption = buf;\r
- psHead.nPages = 2;\r
- psHead.u2.nStartPage = is_search ? 1 : 0;\r
- psHead.hwndParent = Globals.active_win->hMainWnd;\r
- psHead.u3.phpage = psPage;\r
- psHead.dwFlags = PSH_NOAPPLYNOW;\r
-\r
- PropertySheet(&psHead);\r
- if (id.jump)\r
- {\r
- WINE_TRACE("got %d as an offset\n", id.offset);\r
- WINHELP_OpenHelpWindow(HLPFILE_PageByOffset, id.hlpfile, id.offset,\r
- Globals.active_win->info, SW_NORMAL);\r
- }\r
- return TRUE;\r
-}\r
+/*
+ * Help Viewer
+ *
+ * Copyright 1996 Ulrich Schmid <uschmid@mail.hh.provi.de>
+ * 2002 Sylvain Petreolle <spetreolle@yahoo.fr>
+ * 2002, 2008 Eric Pouech <eric.pouech@wanadoo.fr>
+ * 2004 Ken Belleau <jamez@ivic.qc.ca>
+ * 2008 Kirill K. Smirnov <lich@math.spbu.ru>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdlib.h>
+
+#define NONAMELESSUNION
+#define NONAMELESSSTRUCT
+
+#include "windef.h"
+#include "winbase.h"
+#include "wingdi.h"
+#include "winuser.h"
+#include "commdlg.h"
+#include "winhelp.h"
+#include "winhelp_res.h"
+#include "shellapi.h"
+#include "richedit.h"
+#include "commctrl.h"
+
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(winhelp);
+
+WINHELP_GLOBALS Globals = {3, NULL, TRUE, NULL, NULL, NULL, NULL, NULL, {{{NULL,NULL}},0}, NULL};
+
+#define CTL_ID_BUTTON 0x700
+#define CTL_ID_TEXT 0x701
+
+
+/***********************************************************************
+ *
+ * WINHELP_InitFonts
+ */
+static void WINHELP_InitFonts(HWND hWnd)
+{
+ WINHELP_WINDOW *win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0);
+ LOGFONT logfontlist[] = {
+ {-10, 0, 0, 0, 400, 0, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 32, "Helv"},
+ {-12, 0, 0, 0, 700, 0, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 32, "Helv"},
+ {-12, 0, 0, 0, 700, 0, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 32, "Helv"},
+ {-12, 0, 0, 0, 400, 0, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 32, "Helv"},
+ {-12, 0, 0, 0, 700, 0, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 32, "Helv"},
+ {-10, 0, 0, 0, 700, 0, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 32, "Helv"},
+ { -8, 0, 0, 0, 400, 0, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 32, "Helv"}};
+#define FONTS_LEN (sizeof(logfontlist)/sizeof(*logfontlist))
+
+ static HFONT fonts[FONTS_LEN];
+ static BOOL init = 0;
+
+ win->fonts_len = FONTS_LEN;
+ win->fonts = fonts;
+
+ if (!init)
+ {
+ UINT i;
+
+ for (i = 0; i < FONTS_LEN; i++)
+ {
+ fonts[i] = CreateFontIndirect(&logfontlist[i]);
+ }
+
+ init = 1;
+ }
+}
+
+static DWORD CALLBACK WINHELP_RtfStreamIn(DWORD_PTR cookie, BYTE* buff,
+ LONG cb, LONG* pcb)
+{
+ struct RtfData* rd = (struct RtfData*)cookie;
+
+ if (rd->where >= rd->ptr) return 1;
+ if (rd->where + cb > rd->ptr)
+ cb = rd->ptr - rd->where;
+ memcpy(buff, rd->where, cb);
+ rd->where += cb;
+ *pcb = cb;
+ return 0;
+}
+
+static void WINHELP_SetupText(HWND hTextWnd, WINHELP_WINDOW* win, ULONG relative)
+{
+ /* At first clear area - needed by EM_POSFROMCHAR/EM_SETSCROLLPOS */
+ SendMessage(hTextWnd, WM_SETTEXT, 0, (LPARAM)"");
+ SendMessage(hTextWnd, WM_SETREDRAW, FALSE, 0);
+ SendMessage(hTextWnd, EM_SETBKGNDCOLOR, 0, (LPARAM)win->info->sr_color);
+ /* set word-wrap to window size (undocumented) */
+ SendMessage(hTextWnd, EM_SETTARGETDEVICE, 0, 0);
+ if (win->page)
+ {
+ struct RtfData rd;
+ EDITSTREAM es;
+ unsigned cp = 0;
+ POINTL ptl;
+ POINT pt;
+
+
+ if (HLPFILE_BrowsePage(win->page, &rd, win->font_scale, relative))
+ {
+ rd.where = rd.data;
+ es.dwCookie = (DWORD_PTR)&rd;
+ es.dwError = 0;
+ es.pfnCallback = WINHELP_RtfStreamIn;
+
+ SendMessageW(hTextWnd, EM_STREAMIN, SF_RTF, (LPARAM)&es);
+ cp = rd.char_pos_rel;
+ }
+ /* FIXME: else leaking potentially the rd.first_link chain */
+ HeapFree(GetProcessHeap(), 0, rd.data);
+ SendMessage(hTextWnd, EM_POSFROMCHAR, (WPARAM)&ptl, cp ? cp - 1 : 0);
+ pt.x = 0; pt.y = ptl.y;
+ SendMessage(hTextWnd, EM_SETSCROLLPOS, 0, (LPARAM)&pt);
+ }
+ SendMessage(hTextWnd, WM_SETREDRAW, TRUE, 0);
+ RedrawWindow(hTextWnd, NULL, NULL, RDW_FRAME|RDW_INVALIDATE);
+}
+
+/***********************************************************************
+ *
+ * WINHELP_GetOpenFileName
+ */
+BOOL WINHELP_GetOpenFileName(LPSTR lpszFile, int len)
+{
+ OPENFILENAME openfilename;
+ CHAR szDir[MAX_PATH];
+ CHAR szzFilter[2 * MAX_STRING_LEN + 100];
+ LPSTR p = szzFilter;
+
+ WINE_TRACE("()\n");
+
+ LoadString(Globals.hInstance, STID_HELP_FILES_HLP, p, MAX_STRING_LEN);
+ p += strlen(p) + 1;
+ lstrcpy(p, "*.hlp");
+ p += strlen(p) + 1;
+ LoadString(Globals.hInstance, STID_ALL_FILES, p, MAX_STRING_LEN);
+ p += strlen(p) + 1;
+ lstrcpy(p, "*.*");
+ p += strlen(p) + 1;
+ *p = '\0';
+
+ GetCurrentDirectory(sizeof(szDir), szDir);
+
+ lpszFile[0]='\0';
+
+ openfilename.lStructSize = sizeof(OPENFILENAME);
+ openfilename.hwndOwner = (Globals.active_win ? Globals.active_win->hMainWnd : 0);
+ openfilename.hInstance = Globals.hInstance;
+ openfilename.lpstrFilter = szzFilter;
+ openfilename.lpstrCustomFilter = 0;
+ openfilename.nMaxCustFilter = 0;
+ openfilename.nFilterIndex = 1;
+ openfilename.lpstrFile = lpszFile;
+ openfilename.nMaxFile = len;
+ openfilename.lpstrFileTitle = 0;
+ openfilename.nMaxFileTitle = 0;
+ openfilename.lpstrInitialDir = szDir;
+ openfilename.lpstrTitle = 0;
+ openfilename.Flags = OFN_ENABLESIZING;
+ openfilename.nFileOffset = 0;
+ openfilename.nFileExtension = 0;
+ openfilename.lpstrDefExt = 0;
+ openfilename.lCustData = 0;
+ openfilename.lpfnHook = 0;
+ openfilename.lpTemplateName = 0;
+
+ return GetOpenFileName(&openfilename);
+}
+
+/***********************************************************************
+ *
+ * WINHELP_MessageBoxIDS_s
+ */
+static INT WINHELP_MessageBoxIDS_s(UINT ids_text, LPCSTR str, UINT ids_title, WORD type)
+{
+ CHAR text[MAX_STRING_LEN];
+ CHAR newtext[MAX_STRING_LEN + MAX_PATH];
+
+ LoadString(Globals.hInstance, ids_text, text, sizeof(text));
+ wsprintf(newtext, text, str);
+
+ return MessageBox(0, newtext, MAKEINTRESOURCE(ids_title), type);
+}
+
+/***********************************************************************
+ *
+ * WINHELP_LookupHelpFile
+ */
+HLPFILE* WINHELP_LookupHelpFile(LPCSTR lpszFile)
+{
+ HLPFILE* hlpfile;
+ char szFullName[MAX_PATH];
+ char szAddPath[MAX_PATH];
+ char *p;
+
+ /*
+ * NOTE: This is needed by popup windows only.
+ * In other cases it's not needed but does not hurt though.
+ */
+ if (Globals.active_win && Globals.active_win->page && Globals.active_win->page->file)
+ {
+ strcpy(szAddPath, Globals.active_win->page->file->lpszPath);
+ p = strrchr(szAddPath, '\\');
+ if (p) *p = 0;
+ }
+
+ /*
+ * FIXME: Should we swap conditions?
+ */
+ if (!SearchPath(NULL, lpszFile, ".hlp", MAX_PATH, szFullName, NULL) &&
+ !SearchPath(szAddPath, lpszFile, ".hlp", MAX_PATH, szFullName, NULL))
+ {
+ if (WINHELP_MessageBoxIDS_s(STID_FILE_NOT_FOUND_s, lpszFile, STID_WHERROR,
+ MB_YESNO|MB_ICONQUESTION) != IDYES)
+ return NULL;
+ if (!WINHELP_GetOpenFileName(szFullName, MAX_PATH))
+ return NULL;
+ }
+ hlpfile = HLPFILE_ReadHlpFile(szFullName);
+ if (!hlpfile)
+ WINHELP_MessageBoxIDS_s(STID_HLPFILE_ERROR_s, lpszFile,
+ STID_WHERROR, MB_OK|MB_ICONSTOP);
+ return hlpfile;
+}
+
+/******************************************************************
+ * WINHELP_GetWindowInfo
+ *
+ *
+ */
+HLPFILE_WINDOWINFO* WINHELP_GetWindowInfo(HLPFILE* hlpfile, LPCSTR name)
+{
+ static HLPFILE_WINDOWINFO mwi;
+ unsigned int i;
+
+ if (!name || !name[0])
+ name = Globals.active_win->info->name;
+
+ if (hlpfile)
+ for (i = 0; i < hlpfile->numWindows; i++)
+ if (!lstrcmpi(hlpfile->windows[i].name, name))
+ return &hlpfile->windows[i];
+
+ if (strcmp(name, "main") != 0)
+ {
+ WINE_FIXME("Couldn't find window info for %s\n", name);
+ assert(0);
+ return NULL;
+ }
+ if (!mwi.name[0])
+ {
+ strcpy(mwi.type, "primary");
+ strcpy(mwi.name, "main");
+ if (hlpfile && hlpfile->lpszTitle[0])
+ {
+ char tmp[128];
+ LoadString(Globals.hInstance, STID_WINE_HELP, tmp, sizeof(tmp));
+ snprintf(mwi.caption, sizeof(mwi.caption), "%s %s - %s",
+ hlpfile->lpszTitle, tmp, hlpfile->lpszPath);
+ }
+ else
+ LoadString(Globals.hInstance, STID_WINE_HELP, mwi.caption, sizeof(mwi.caption));
+ mwi.origin.x = mwi.origin.y = mwi.size.cx = mwi.size.cy = CW_USEDEFAULT;
+ mwi.style = SW_SHOW;
+ mwi.win_style = WS_OVERLAPPEDWINDOW;
+ mwi.sr_color = mwi.nsr_color = 0xFFFFFF;
+ }
+ return &mwi;
+}
+
+/******************************************************************
+ * HLPFILE_GetPopupWindowInfo
+ *
+ *
+ */
+static HLPFILE_WINDOWINFO* WINHELP_GetPopupWindowInfo(HLPFILE* hlpfile,
+ WINHELP_WINDOW* parent, LPARAM mouse)
+{
+ static HLPFILE_WINDOWINFO wi;
+
+ RECT parent_rect;
+
+ wi.type[0] = wi.name[0] = wi.caption[0] = '\0';
+
+ /* Calculate horizontal size and position of a popup window */
+ GetWindowRect(parent->hMainWnd, &parent_rect);
+ 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.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);
+ wi.origin.x = max(wi.origin.x, 0);
+
+ wi.style = SW_SHOW;
+ wi.win_style = WS_POPUP | WS_BORDER;
+ if (parent->page->file->has_popup_color)
+ wi.sr_color = parent->page->file->popup_color;
+ else
+ wi.sr_color = parent->info->sr_color;
+ wi.nsr_color = 0xFFFFFF;
+
+ return &wi;
+}
+
+typedef struct
+{
+ WORD size;
+ WORD command;
+ LONG data;
+ LONG reserved;
+ WORD ofsFilename;
+ WORD ofsData;
+} WINHELP,*LPWINHELP;
+
+static BOOL WINHELP_HasWorkingWindow(void)
+{
+ if (!Globals.active_win) return FALSE;
+ if (Globals.active_win->next || Globals.win_list != Globals.active_win) return TRUE;
+ return Globals.active_win->page != NULL && Globals.active_win->page->file != NULL;
+}
+
+/******************************************************************
+ * WINHELP_HandleCommand
+ *
+ *
+ */
+static LRESULT WINHELP_HandleCommand(HWND hSrcWnd, LPARAM lParam)
+{
+ COPYDATASTRUCT* cds = (COPYDATASTRUCT*)lParam;
+ WINHELP* wh;
+
+ if (cds->dwData != 0xA1DE505)
+ {
+ WINE_FIXME("Wrong magic number (%08lx)\n", cds->dwData);
+ return 0;
+ }
+
+ wh = cds->lpData;
+
+ if (wh)
+ {
+ char* ptr = (wh->ofsFilename) ? (LPSTR)wh + wh->ofsFilename : NULL;
+
+ WINE_TRACE("Got[%u]: cmd=%u data=%08x fn=%s\n",
+ wh->size, wh->command, wh->data, ptr);
+ switch (wh->command)
+ {
+ case HELP_CONTEXT:
+ if (ptr)
+ {
+ MACRO_JumpContext(ptr, "main", wh->data);
+ }
+ if (!WINHELP_HasWorkingWindow()) MACRO_Exit();
+ break;
+ case HELP_QUIT:
+ MACRO_Exit();
+ break;
+ case HELP_CONTENTS:
+ if (ptr)
+ {
+ MACRO_JumpContents(ptr, "main");
+ }
+ if (!WINHELP_HasWorkingWindow()) MACRO_Exit();
+ break;
+ case HELP_HELPONHELP:
+ MACRO_HelpOn();
+ if (!WINHELP_HasWorkingWindow()) MACRO_Exit();
+ break;
+ /* case HELP_SETINDEX: */
+ case HELP_SETCONTENTS:
+ if (ptr)
+ {
+ MACRO_SetContents(ptr, wh->data);
+ }
+ break;
+ case HELP_CONTEXTPOPUP:
+ if (ptr)
+ {
+ MACRO_PopupContext(ptr, wh->data);
+ }
+ break;
+ /* case HELP_FORCEFILE:*/
+ /* case HELP_CONTEXTMENU: */
+ case HELP_FINDER:
+ /* in fact, should be the topic dialog box */
+ WINE_FIXME("HELP_FINDER: stub\n");
+ if (ptr)
+ {
+ MACRO_JumpHash(ptr, "main", 0);
+ }
+ break;
+ /* case HELP_WM_HELP: */
+ /* case HELP_SETPOPUP_POS: */
+ /* case HELP_KEY: */
+ /* case HELP_COMMAND: */
+ /* case HELP_PARTIALKEY: */
+ /* case HELP_MULTIKEY: */
+ /* case HELP_SETWINPOS: */
+ default:
+ WINE_FIXME("Unhandled command (%x) for remote winhelp control\n", wh->command);
+ break;
+ }
+ }
+ /* Always return success for now */
+ return 1;
+}
+
+void WINHELP_LayoutMainWindow(WINHELP_WINDOW* win)
+{
+ RECT rect, button_box_rect;
+ INT text_top = 0;
+ HWND hButtonBoxWnd = GetDlgItem(win->hMainWnd, CTL_ID_BUTTON);
+ HWND hTextWnd = GetDlgItem(win->hMainWnd, CTL_ID_TEXT);
+
+ GetClientRect(win->hMainWnd, &rect);
+
+ /* Update button box and text Window */
+ SetWindowPos(hButtonBoxWnd, HWND_TOP,
+ rect.left, rect.top,
+ rect.right - rect.left,
+ rect.bottom - rect.top, 0);
+
+ if (GetWindowRect(hButtonBoxWnd, &button_box_rect))
+ text_top = rect.top + button_box_rect.bottom - button_box_rect.top;
+
+ SetWindowPos(hTextWnd, HWND_TOP,
+ rect.left, text_top,
+ rect.right - rect.left,
+ rect.bottom - text_top, 0);
+
+}
+
+/******************************************************************
+ * WINHELP_DeleteButtons
+ *
+ */
+static void WINHELP_DeleteButtons(WINHELP_WINDOW* win)
+{
+ WINHELP_BUTTON* b;
+ WINHELP_BUTTON* bp;
+
+ for (b = win->first_button; b; b = bp)
+ {
+ DestroyWindow(b->hWnd);
+ bp = b->next;
+ HeapFree(GetProcessHeap(), 0, b);
+ }
+ win->first_button = NULL;
+}
+
+/******************************************************************
+ * WINHELP_DeleteBackSet
+ *
+ */
+void WINHELP_DeleteBackSet(WINHELP_WINDOW* win)
+{
+ unsigned int i;
+
+ for (i = 0; i < win->back.index; i++)
+ {
+ HLPFILE_FreeHlpFile(win->back.set[i].page->file);
+ win->back.set[i].page = NULL;
+ }
+ 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_GrabWindow
+ */
+WINHELP_WINDOW* WINHELP_GrabWindow(WINHELP_WINDOW* win)
+{
+ WINE_TRACE("Grab %p#%d++\n", win, win->ref_count);
+ win->ref_count++;
+ return win;
+}
+
+/***********************************************************************
+ *
+ * WINHELP_RelaseWindow
+ */
+BOOL WINHELP_ReleaseWindow(WINHELP_WINDOW* win)
+{
+ WINE_TRACE("Release %p#%d--\n", win, win->ref_count);
+
+ if (!--win->ref_count)
+ {
+ DestroyWindow(win->hMainWnd);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/***********************************************************************
+ *
+ * WINHELP_DeleteWindow
+ */
+static void WINHELP_DeleteWindow(WINHELP_WINDOW* win)
+{
+ WINHELP_WINDOW** w;
+ BOOL bExit;
+ HWND hTextWnd;
+
+ for (w = &Globals.win_list; *w; w = &(*w)->next)
+ {
+ if (*w == win)
+ {
+ *w = win->next;
+ break;
+ }
+ }
+ bExit = (Globals.wVersion >= 4 && !lstrcmpi(win->info->name, "main"));
+
+ if (Globals.active_win == win)
+ {
+ Globals.active_win = Globals.win_list;
+ if (Globals.win_list)
+ SetActiveWindow(Globals.win_list->hMainWnd);
+ }
+
+ if (win == Globals.active_popup)
+ Globals.active_popup = NULL;
+
+ hTextWnd = GetDlgItem(win->hMainWnd, CTL_ID_TEXT);
+ SetWindowLongPtr(hTextWnd, GWLP_WNDPROC,
+ (LONG_PTR)win->origRicheditWndProc);
+
+ WINHELP_DeleteButtons(win);
+
+ if (win->page) WINHELP_DeletePageLinks(win->page);
+ if (win->hShadowWnd) DestroyWindow(win->hShadowWnd);
+ if (win->hHistoryWnd) DestroyWindow(win->hHistoryWnd);
+
+ DeleteObject(win->hBrush);
+
+ WINHELP_DeleteBackSet(win);
+
+ if (win->page) HLPFILE_FreeHlpFile(win->page->file);
+ HeapFree(GetProcessHeap(), 0, win);
+
+ if (bExit) MACRO_Exit();
+ if (!Globals.win_list)
+ PostQuitMessage(0);
+}
+
+static char* WINHELP_GetCaption(WINHELP_WNDPAGE* wpage)
+{
+ if (wpage->wininfo->caption[0]) return wpage->wininfo->caption;
+ return wpage->page->file->lpszTitle;
+}
+
+static void WINHELP_RememberPage(WINHELP_WINDOW* win, WINHELP_WNDPAGE* wpage)
+{
+ unsigned num;
+
+ if (!Globals.history.index || Globals.history.set[0].page != wpage->page)
+ {
+ num = sizeof(Globals.history.set) / sizeof(Globals.history.set[0]);
+ /* we're full, remove latest entry */
+ if (Globals.history.index == num)
+ {
+ HLPFILE_FreeHlpFile(Globals.history.set[num - 1].page->file);
+ Globals.history.index--;
+ }
+ memmove(&Globals.history.set[1], &Globals.history.set[0],
+ Globals.history.index * sizeof(Globals.history.set[0]));
+ Globals.history.set[0] = *wpage;
+ Globals.history.index++;
+ wpage->page->file->wRefCount++;
+ }
+ if (win->hHistoryWnd) InvalidateRect(win->hHistoryWnd, NULL, TRUE);
+
+ num = sizeof(win->back.set) / sizeof(win->back.set[0]);
+ if (win->back.index == num)
+ {
+ /* we're full, remove latest entry */
+ HLPFILE_FreeHlpFile(win->back.set[0].page->file);
+ memmove(&win->back.set[0], &win->back.set[1],
+ (num - 1) * sizeof(win->back.set[0]));
+ win->back.index--;
+ }
+ win->back.set[win->back.index++] = *wpage;
+ wpage->page->file->wRefCount++;
+}
+
+/***********************************************************************
+ *
+ * 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 (link->bHotSpot)
+ {
+ HLPFILE_HOTSPOTLINK* hslink = (HLPFILE_HOTSPOTLINK*)link;
+ if ((mouse_ptl.x < char_ptl.x + hslink->x) ||
+ (mouse_ptl.x >= char_ptl.x + hslink->x + hslink->width) ||
+ (mouse_ptl.y < char_ptl.y + hslink->y) ||
+ (mouse_ptl.y >= char_ptl.y + hslink->y + hslink->height))
+ continue;
+ break;
+ }
+ if (char_next_ptl.y != char_ptl.y || mouse_ptl.x >= char_next_ptl.x)
+ link = NULL;
+ break;
+ }
+ }
+ return link;
+}
+
+static LRESULT CALLBACK WINHELP_RicheditWndProc(HWND hWnd, UINT msg,
+ WPARAM wParam, LPARAM lParam)
+{
+ WINHELP_WINDOW *win = (WINHELP_WINDOW*) GetWindowLongPtr(GetParent(hWnd), 0);
+ DWORD messagePos;
+ POINT pt;
+ switch(msg)
+ {
+ case WM_SETCURSOR:
+ messagePos = GetMessagePos();
+ pt.x = (short)LOWORD(messagePos);
+ pt.y = (short)HIWORD(messagePos);
+ ScreenToClient(hWnd, &pt);
+ if (win->page && WINHELP_FindLink(win, MAKELPARAM(pt.x, pt.y)))
+ {
+ SetCursor(win->hHandCur);
+ return 0;
+ }
+ /* fall through */
+ default:
+ return CallWindowProcA(win->origRicheditWndProc, hWnd, msg, wParam, lParam);
+ }
+}
+
+/***********************************************************************
+ *
+ * WINHELP_CreateHelpWindow
+ */
+BOOL WINHELP_CreateHelpWindow(WINHELP_WNDPAGE* wpage, int nCmdShow, BOOL remember)
+{
+ WINHELP_WINDOW* win = NULL;
+ BOOL bPrimary, bPopup, bReUsed = FALSE;
+ HICON hIcon;
+ HWND hTextWnd = NULL;
+
+ bPrimary = !lstrcmpi(wpage->wininfo->name, "main");
+ bPopup = !bPrimary && (wpage->wininfo->win_style & WS_POPUP);
+
+ if (!bPopup)
+ {
+ for (win = Globals.win_list; win; win = win->next)
+ {
+ if (!lstrcmpi(win->info->name, wpage->wininfo->name))
+ {
+ POINT pt = {0, 0};
+ SIZE sz = {0, 0};
+ DWORD flags = SWP_NOSIZE | SWP_NOMOVE;
+
+ WINHELP_DeleteButtons(win);
+ bReUsed = TRUE;
+ SetWindowText(win->hMainWnd, WINHELP_GetCaption(wpage));
+ if (wpage->wininfo->origin.x != CW_USEDEFAULT &&
+ wpage->wininfo->origin.y != CW_USEDEFAULT)
+ {
+ pt = wpage->wininfo->origin;
+ flags &= ~SWP_NOSIZE;
+ }
+ if (wpage->wininfo->size.cx != CW_USEDEFAULT &&
+ wpage->wininfo->size.cy != CW_USEDEFAULT)
+ {
+ sz = wpage->wininfo->size;
+ flags &= ~SWP_NOMOVE;
+ }
+ SetWindowPos(win->hMainWnd, HWND_TOP, pt.x, pt.y, sz.cx, sz.cy, flags);
+
+ if (wpage->page && win->page && wpage->page->file != win->page->file)
+ WINHELP_DeleteBackSet(win);
+ WINHELP_InitFonts(win->hMainWnd);
+
+ win->page = wpage->page;
+ win->info = wpage->wininfo;
+ hTextWnd = GetDlgItem(win->hMainWnd, CTL_ID_TEXT);
+ WINHELP_SetupText(hTextWnd, win, wpage->relative);
+
+ InvalidateRect(win->hMainWnd, NULL, TRUE);
+ if (win->hHistoryWnd) InvalidateRect(win->hHistoryWnd, NULL, TRUE);
+
+ break;
+ }
+ }
+ }
+
+ if (!win)
+ {
+ /* Initialize WINHELP_WINDOW struct */
+ win = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WINHELP_WINDOW));
+ if (!win) return FALSE;
+ win->next = Globals.win_list;
+ Globals.win_list = win;
+
+ win->hHandCur = LoadCursorW(0, (LPWSTR)IDC_HAND);
+ win->back.index = 0;
+ win->font_scale = 1;
+ WINHELP_GrabWindow(win);
+ }
+ win->page = wpage->page;
+ win->info = wpage->wininfo;
+ WINHELP_GrabWindow(win);
+
+ if (!bPopup && wpage->page && remember)
+ {
+ WINHELP_RememberPage(win, wpage);
+ }
+
+ if (bPopup)
+ Globals.active_popup = win;
+ else
+ Globals.active_win = win;
+
+ /* Initialize default pushbuttons */
+ if (bPrimary && wpage->page)
+ {
+ CHAR buffer[MAX_STRING_LEN];
+
+ LoadString(Globals.hInstance, STID_CONTENTS, buffer, sizeof(buffer));
+ MACRO_CreateButton("BTN_CONTENTS", buffer, "Contents()");
+ LoadString(Globals.hInstance, STID_INDEX, buffer, sizeof(buffer));
+ MACRO_CreateButton("BTN_INDEX", buffer, "Finder()");
+ LoadString(Globals.hInstance, STID_BACK, buffer, sizeof(buffer));
+ MACRO_CreateButton("BTN_BACK", buffer, "Back()");
+ if (win->back.index <= 1) MACRO_DisableButton("BTN_BACK");
+ }
+
+ if (!bReUsed)
+ {
+ win->hMainWnd = CreateWindowEx((bPopup) ? WS_EX_TOOLWINDOW : 0, MAIN_WIN_CLASS_NAME,
+ WINHELP_GetCaption(wpage),
+ bPrimary ? WS_OVERLAPPEDWINDOW : wpage->wininfo->win_style,
+ wpage->wininfo->origin.x, wpage->wininfo->origin.y,
+ wpage->wininfo->size.cx, wpage->wininfo->size.cy,
+ bPopup ? Globals.active_win->hMainWnd : NULL,
+ bPrimary ? LoadMenu(Globals.hInstance, MAKEINTRESOURCE(MAIN_MENU)) : 0,
+ Globals.hInstance, win);
+ if (!bPopup)
+ /* Create button box and text Window */
+ CreateWindow(BUTTON_BOX_WIN_CLASS_NAME, "", WS_CHILD | WS_VISIBLE,
+ 0, 0, 0, 0, win->hMainWnd, (HMENU)CTL_ID_BUTTON, Globals.hInstance, NULL);
+
+ 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);
+ win->origRicheditWndProc = (WNDPROC)SetWindowLongPtr(hTextWnd, GWLP_WNDPROC,
+ (LONG_PTR)WINHELP_RicheditWndProc);
+ }
+
+ hIcon = (wpage->page) ? wpage->page->file->hIcon : NULL;
+ if (!hIcon) hIcon = LoadIcon(Globals.hInstance, MAKEINTRESOURCE(IDI_WINHELP));
+ SendMessage(win->hMainWnd, WM_SETICON, ICON_SMALL, (DWORD_PTR)hIcon);
+
+ /* Initialize file specific pushbuttons */
+ if (!(wpage->wininfo->win_style & WS_POPUP) && wpage->page)
+ {
+ HLPFILE_MACRO *macro;
+ for (macro = wpage->page->file->first_macro; macro; macro = macro->next)
+ MACRO_ExecuteMacro(win, macro->lpszMacro);
+
+ for (macro = wpage->page->first_macro; macro; macro = macro->next)
+ MACRO_ExecuteMacro(win, macro->lpszMacro);
+ }
+ /* See #17681, in some cases, the newly created window is closed by the macros it contains
+ * (braindead), so deal with this case
+ */
+ for (win = Globals.win_list; win; win = win->next)
+ {
+ if (!lstrcmpi(win->info->name, wpage->wininfo->name)) break;
+ }
+ if (!win || !WINHELP_ReleaseWindow(win)) return TRUE;
+
+ if (bPopup)
+ {
+ DWORD mask = SendMessage(hTextWnd, EM_GETEVENTMASK, 0, 0);
+ RECT rect;
+
+ win->font_scale = Globals.active_win->font_scale;
+ WINHELP_SetupText(hTextWnd, win, wpage->relative);
+
+ /* we need the window to be shown for richedit to compute the size */
+ ShowWindow(win->hMainWnd, nCmdShow);
+ SendMessage(hTextWnd, EM_SETEVENTMASK, 0, mask | ENM_REQUESTRESIZE);
+ SendMessage(hTextWnd, EM_REQUESTRESIZE, 0, 0);
+ SendMessage(hTextWnd, EM_SETEVENTMASK, 0, mask);
+
+ GetWindowRect(win->hMainWnd, &rect);
+ win->hShadowWnd = CreateWindowEx(WS_EX_TOOLWINDOW, SHADOW_WIN_CLASS_NAME,
+ "", WS_POPUP | WS_VISIBLE,
+ rect.left + SHADOW_DX, rect.top + SHADOW_DY,
+ rect.right - rect.left,
+ rect.bottom - rect.top,
+ Globals.active_win->hMainWnd, 0,
+ Globals.hInstance, NULL);
+ SetWindowPos(win->hMainWnd, win->hShadowWnd, 0, 0, 0, 0,
+ SWP_NOSIZE | SWP_NOMOVE);
+ }
+ else
+ {
+ WINHELP_SetupText(hTextWnd, win, wpage->relative);
+ WINHELP_LayoutMainWindow(win);
+ ShowWindow(win->hMainWnd, nCmdShow);
+ }
+
+ return TRUE;
+}
+
+/******************************************************************
+ * WINHELP_OpenHelpWindow
+ * Main function to search for a page and display it in a window
+ */
+BOOL WINHELP_OpenHelpWindow(HLPFILE_PAGE* (*lookup)(HLPFILE*, LONG, ULONG*),
+ HLPFILE* hlpfile, LONG val, HLPFILE_WINDOWINFO* wi,
+ int nCmdShow)
+{
+ WINHELP_WNDPAGE wpage;
+
+ wpage.page = lookup(hlpfile, val, &wpage.relative);
+ if (wpage.page) wpage.page->file->wRefCount++;
+ wpage.wininfo = wi;
+ return WINHELP_CreateHelpWindow(&wpage, nCmdShow, TRUE);
+}
+
+/******************************************************************
+ * WINHELP_HandleTextMouse
+ *
+ */
+static BOOL WINHELP_HandleTextMouse(WINHELP_WINDOW* win, UINT msg, LPARAM lParam)
+{
+ HLPFILE* hlpfile;
+ HLPFILE_LINK* link;
+ BOOL ret = FALSE;
+
+ switch (msg)
+ {
+ case WM_LBUTTONDOWN:
+ if ((link = WINHELP_FindLink(win, lParam)))
+ {
+ 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 < 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, lParam),
+ SW_NORMAL);
+ break;
+ case hlp_link_macro:
+ MACRO_ExecuteMacro(win, link->string);
+ break;
+ default:
+ WINE_FIXME("Unknown link cookie %d\n", link->cookie);
+ }
+ ret = TRUE;
+ }
+ break;
+ }
+ return ret;
+}
+
+/***********************************************************************
+ *
+ * WINHELP_CheckPopup
+ */
+static BOOL WINHELP_CheckPopup(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, LRESULT* lret)
+{
+ WINHELP_WINDOW* popup;
+
+ if (!Globals.active_popup) return FALSE;
+
+ switch (msg)
+ {
+ case WM_NOTIFY:
+ {
+ MSGFILTER* msgf = (MSGFILTER*)lParam;
+ if (msgf->nmhdr.code == EN_MSGFILTER)
+ {
+ if (!WINHELP_CheckPopup(hWnd, msgf->msg, msgf->wParam, msgf->lParam, NULL))
+ return FALSE;
+ if (lret) *lret = 1;
+ return TRUE;
+ }
+ }
+ break;
+ case WM_ACTIVATE:
+ if (wParam != WA_INACTIVE || (HWND)lParam == Globals.active_win->hMainWnd ||
+ (HWND)lParam == Globals.active_popup->hMainWnd ||
+ GetWindow((HWND)lParam, GW_OWNER) == Globals.active_win->hMainWnd)
+ break;
+ case WM_LBUTTONDOWN:
+ if (WINHELP_HandleTextMouse(Globals.active_popup, msg, lParam))
+ return FALSE;
+ /* fall through */
+ case WM_LBUTTONUP:
+ case WM_MBUTTONDOWN:
+ case WM_RBUTTONDOWN:
+ case WM_NCLBUTTONDOWN:
+ case WM_NCMBUTTONDOWN:
+ case WM_NCRBUTTONDOWN:
+ popup = Globals.active_popup;
+ Globals.active_popup = NULL;
+ WINHELP_ReleaseWindow(popup);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/***********************************************************************
+ *
+ * WINHELP_ButtonWndProc
+ */
+static LRESULT CALLBACK WINHELP_ButtonWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ if (WINHELP_CheckPopup(hWnd, msg, wParam, lParam, NULL)) return 0;
+
+ if (msg == WM_KEYDOWN)
+ {
+ switch (wParam)
+ {
+ case VK_UP:
+ case VK_DOWN:
+ case VK_PRIOR:
+ case VK_NEXT:
+ case VK_ESCAPE:
+ return SendMessage(GetParent(hWnd), msg, wParam, lParam);
+ }
+ }
+
+ return CallWindowProc(Globals.button_proc, hWnd, msg, wParam, lParam);
+}
+
+/***********************************************************************
+ *
+ * WINHELP_ButtonBoxWndProc
+ */
+static LRESULT CALLBACK WINHELP_ButtonBoxWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ WINDOWPOS *winpos;
+ WINHELP_WINDOW *win;
+ WINHELP_BUTTON *button;
+ SIZE button_size;
+ INT x, y;
+
+ if (WINHELP_CheckPopup(hWnd, msg, wParam, lParam, NULL)) return 0L;
+
+ switch (msg)
+ {
+ case WM_WINDOWPOSCHANGING:
+ winpos = (WINDOWPOS*) lParam;
+ win = (WINHELP_WINDOW*) GetWindowLongPtr(GetParent(hWnd), 0);
+
+ /* Update buttons */
+ button_size.cx = 0;
+ button_size.cy = 0;
+ for (button = win->first_button; button; button = button->next)
+ {
+ HDC hDc;
+ SIZE textsize;
+ if (!button->hWnd)
+ {
+ button->hWnd = CreateWindow(STRING_BUTTON, button->lpszName,
+ WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
+ 0, 0, 0, 0,
+ hWnd, (HMENU) button->wParam,
+ Globals.hInstance, 0);
+ if (button->hWnd)
+ {
+ if (Globals.button_proc == NULL)
+ {
+ NONCLIENTMETRICSW ncm;
+ Globals.button_proc = (WNDPROC) GetWindowLongPtr(button->hWnd, GWLP_WNDPROC);
+
+ ncm.cbSize = sizeof(NONCLIENTMETRICSW);
+ SystemParametersInfoW(SPI_GETNONCLIENTMETRICS,
+ sizeof(NONCLIENTMETRICSW), &ncm, 0);
+ Globals.hButtonFont = CreateFontIndirectW(&ncm.lfMenuFont);
+ }
+ SetWindowLongPtr(button->hWnd, GWLP_WNDPROC, (LONG_PTR) WINHELP_ButtonWndProc);
+ if (Globals.hButtonFont)
+ SendMessage(button->hWnd, WM_SETFONT, (WPARAM)Globals.hButtonFont, TRUE);
+ }
+ }
+ hDc = GetDC(button->hWnd);
+ GetTextExtentPoint(hDc, button->lpszName,
+ lstrlen(button->lpszName), &textsize);
+ ReleaseDC(button->hWnd, hDc);
+
+ button_size.cx = max(button_size.cx, textsize.cx + BUTTON_CX);
+ button_size.cy = max(button_size.cy, textsize.cy + BUTTON_CY);
+ }
+
+ x = 0;
+ y = 0;
+ for (button = win->first_button; button; button = button->next)
+ {
+ SetWindowPos(button->hWnd, HWND_TOP, x, y, button_size.cx, button_size.cy, 0);
+
+ if (x + 2 * button_size.cx <= winpos->cx)
+ x += button_size.cx;
+ else
+ x = 0, y += button_size.cy;
+ }
+ winpos->cy = y + (x ? button_size.cy : 0);
+ break;
+
+ case WM_COMMAND:
+ SendMessage(GetParent(hWnd), msg, wParam, lParam);
+ break;
+
+ case WM_KEYDOWN:
+ switch (wParam)
+ {
+ case VK_UP:
+ case VK_DOWN:
+ case VK_PRIOR:
+ case VK_NEXT:
+ case VK_ESCAPE:
+ return SendMessage(GetParent(hWnd), msg, wParam, lParam);
+ }
+ break;
+ }
+
+ return DefWindowProc(hWnd, msg, wParam, lParam);
+}
+
+/******************************************************************
+ * WINHELP_HistoryWndProc
+ *
+ *
+ */
+static LRESULT CALLBACK WINHELP_HistoryWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ WINHELP_WINDOW* win;
+ PAINTSTRUCT ps;
+ HDC hDc;
+ TEXTMETRIC tm;
+ unsigned int i;
+ RECT r;
+
+ switch (msg)
+ {
+ case WM_NCCREATE:
+ win = (WINHELP_WINDOW*)((LPCREATESTRUCT)lParam)->lpCreateParams;
+ SetWindowLongPtr(hWnd, 0, (ULONG_PTR)win);
+ win->hHistoryWnd = hWnd;
+ break;
+ case WM_CREATE:
+ win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0);
+ hDc = GetDC(hWnd);
+ GetTextMetrics(hDc, &tm);
+ GetWindowRect(hWnd, &r);
+
+ r.right = r.left + 30 * tm.tmAveCharWidth;
+ r.bottom = r.top + (sizeof(Globals.history.set) / sizeof(Globals.history.set[0])) * tm.tmHeight;
+ AdjustWindowRect(&r, GetWindowLong(hWnd, GWL_STYLE), FALSE);
+ if (r.left < 0) {r.right -= r.left; r.left = 0;}
+ if (r.top < 0) {r.bottom -= r.top; r.top = 0;}
+
+ MoveWindow(hWnd, r.left, r.top, r.right, r.bottom, TRUE);
+ ReleaseDC(hWnd, hDc);
+ break;
+ case WM_LBUTTONDOWN:
+ win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0);
+ hDc = GetDC(hWnd);
+ GetTextMetrics(hDc, &tm);
+ i = HIWORD(lParam) / tm.tmHeight;
+ if (i < Globals.history.index)
+ WINHELP_CreateHelpWindow(&Globals.history.set[i], SW_SHOW, TRUE);
+ ReleaseDC(hWnd, hDc);
+ break;
+ case WM_PAINT:
+ hDc = BeginPaint(hWnd, &ps);
+ win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0);
+ GetTextMetrics(hDc, &tm);
+
+ for (i = 0; i < Globals.history.index; i++)
+ {
+ if (Globals.history.set[i].page->file == Globals.active_win->page->file)
+ {
+ TextOut(hDc, 0, i * tm.tmHeight,
+ Globals.history.set[i].page->lpszTitle,
+ strlen(Globals.history.set[i].page->lpszTitle));
+ }
+ else
+ {
+ char buffer[1024];
+ const char* ptr1;
+ const char* ptr2;
+ unsigned len;
+
+ ptr1 = strrchr(Globals.history.set[i].page->file->lpszPath, '\\');
+ if (!ptr1) ptr1 = Globals.history.set[i].page->file->lpszPath;
+ else ptr1++;
+ ptr2 = strrchr(ptr1, '.');
+ len = ptr2 ? ptr2 - ptr1 : strlen(ptr1);
+ if (len > sizeof(buffer)) len = sizeof(buffer);
+ memcpy(buffer, ptr1, len);
+ if (len < sizeof(buffer)) buffer[len++] = ':';
+ strncpy(&buffer[len], Globals.history.set[i].page->lpszTitle, sizeof(buffer) - len);
+ buffer[sizeof(buffer) - 1] = '\0';
+ TextOut(hDc, 0, i * tm.tmHeight, buffer, strlen(buffer));
+ }
+ }
+ EndPaint(hWnd, &ps);
+ break;
+ case WM_DESTROY:
+ win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0);
+ if (hWnd == win->hHistoryWnd)
+ win->hHistoryWnd = 0;
+ break;
+ }
+ return DefWindowProc(hWnd, msg, wParam, lParam);
+}
+
+/***********************************************************************
+ *
+ * WINHELP_ShadowWndProc
+ */
+static LRESULT CALLBACK WINHELP_ShadowWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ if (WINHELP_CheckPopup(hWnd, msg, wParam, lParam, NULL)) return 0;
+ return WINHELP_CheckPopup(hWnd, msg, wParam, lParam, NULL) ? 0L : DefWindowProc(hWnd, msg, wParam, lParam);
+}
+
+/**************************************************************************
+ * cb_KWBTree
+ *
+ * HLPFILE_BPTreeCallback enumeration function for '|KWBTREE' internal file.
+ *
+ */
+static void cb_KWBTree(void *p, void **next, void *cookie)
+{
+ HWND hListWnd = cookie;
+ int count;
+
+ WINE_TRACE("Adding '%s' to search list\n", (char *)p);
+ SendMessage(hListWnd, LB_INSERTSTRING, -1, (LPARAM)p);
+ count = SendMessage(hListWnd, LB_GETCOUNT, 0, 0);
+ SendMessage(hListWnd, LB_SETITEMDATA, count-1, (LPARAM)p);
+ *next = (char*)p + strlen((char*)p) + 7;
+}
+
+struct index_data
+{
+ HLPFILE* hlpfile;
+ BOOL jump;
+ ULONG offset;
+};
+
+/**************************************************************************
+ * WINHELP_IndexDlgProc
+ *
+ */
+static INT_PTR CALLBACK WINHELP_IndexDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ static struct index_data* id;
+ int sel;
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ id = (struct index_data*)((PROPSHEETPAGE*)lParam)->lParam;
+ HLPFILE_BPTreeEnum(id->hlpfile->kwbtree, cb_KWBTree,
+ GetDlgItem(hWnd, IDC_INDEXLIST));
+ id->jump = FALSE;
+ id->offset = 1;
+ return TRUE;
+ case WM_COMMAND:
+ switch (HIWORD(wParam))
+ {
+ case LBN_DBLCLK:
+ if (LOWORD(wParam) == IDC_INDEXLIST)
+ SendMessage(GetParent(hWnd), PSM_PRESSBUTTON, PSBTN_OK, 0);
+ break;
+ }
+ break;
+ case WM_NOTIFY:
+ switch (((NMHDR*)lParam)->code)
+ {
+ case PSN_APPLY:
+ sel = SendDlgItemMessage(hWnd, IDC_INDEXLIST, LB_GETCURSEL, 0, 0);
+ if (sel != LB_ERR)
+ {
+ BYTE *p;
+ int count;
+
+ p = (BYTE*)SendDlgItemMessage(hWnd, IDC_INDEXLIST,
+ LB_GETITEMDATA, sel, 0);
+ count = *(short*)((char *)p + strlen((char *)p) + 1);
+ if (count > 1)
+ {
+ MessageBox(hWnd, "count > 1 not supported yet", "Error", MB_OK | MB_ICONSTOP);
+ SetWindowLongPtr(hWnd, DWLP_MSGRESULT, PSNRET_INVALID);
+ return TRUE;
+ }
+ id->offset = *(ULONG*)((char *)p + strlen((char *)p) + 3);
+ id->offset = *(long*)(id->hlpfile->kwdata + id->offset + 9);
+ if (id->offset == 0xFFFFFFFF)
+ {
+ MessageBox(hWnd, "macro keywords not supported yet", "Error", MB_OK | MB_ICONSTOP);
+ SetWindowLongPtr(hWnd, DWLP_MSGRESULT, PSNRET_INVALID);
+ return TRUE;
+ }
+ id->jump = TRUE;
+ SetWindowLongPtr(hWnd, DWLP_MSGRESULT, PSNRET_NOERROR);
+ }
+ return TRUE;
+ default:
+ return FALSE;
+ }
+ break;
+ default:
+ break;
+ }
+ return FALSE;
+}
+
+/**************************************************************************
+ * WINHELP_SearchDlgProc
+ *
+ */
+static INT_PTR CALLBACK WINHELP_SearchDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ static struct index_data* id;
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ id = (struct index_data*)((PROPSHEETPAGE*)lParam)->lParam;
+ return TRUE;
+ case WM_NOTIFY:
+ switch (((NMHDR*)lParam)->code)
+ {
+ case PSN_APPLY:
+ SetWindowLongPtr(hWnd, DWLP_MSGRESULT, PSNRET_NOERROR);
+ return TRUE;
+ default:
+ return FALSE;
+ }
+ break;
+ default:
+ break;
+ }
+ return FALSE;
+}
+
+/***********************************************************************
+ *
+ * WINHELP_MainWndProc
+ */
+static LRESULT CALLBACK WINHELP_MainWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ WINHELP_WINDOW *win;
+ WINHELP_BUTTON *button;
+ INT keyDelta;
+ HWND hTextWnd;
+ LRESULT ret;
+
+ if (WINHELP_CheckPopup(hWnd, msg, wParam, lParam, &ret)) return ret;
+
+ switch (msg)
+ {
+ case WM_NCCREATE:
+ win = (WINHELP_WINDOW*) ((LPCREATESTRUCT) lParam)->lpCreateParams;
+ SetWindowLongPtr(hWnd, 0, (ULONG_PTR) win);
+ if (!win->page && Globals.isBook)
+ PostMessage(hWnd, WM_COMMAND, MNID_FILE_OPEN, 0);
+ win->hMainWnd = hWnd;
+ break;
+
+ case WM_WINDOWPOSCHANGED:
+ WINHELP_LayoutMainWindow((WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0));
+ break;
+
+ case WM_COMMAND:
+ win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0);
+ switch (wParam)
+ {
+ /* Menu FILE */
+ case MNID_FILE_OPEN: MACRO_FileOpen(); break;
+ case MNID_FILE_PRINT: MACRO_Print(); break;
+ case MNID_FILE_SETUP: MACRO_PrinterSetup(); break;
+ case MNID_FILE_EXIT: MACRO_Exit(); break;
+
+ /* Menu EDIT */
+ case MNID_EDIT_COPYDLG:
+ SendMessage(GetDlgItem(hWnd, CTL_ID_TEXT), WM_COPY, 0, 0);
+ break;
+ case MNID_EDIT_ANNOTATE:MACRO_Annotate(); break;
+
+ /* Menu Bookmark */
+ case MNID_BKMK_DEFINE: MACRO_BookmarkDefine(); break;
+
+ /* Menu Help */
+ case MNID_HELP_HELPON: MACRO_HelpOn(); break;
+ case MNID_HELP_HELPTOP: MACRO_HelpOnTop(); break;
+ case MNID_HELP_ABOUT: MACRO_About(); break;
+ case MNID_HELP_WINE: ShellAbout(hWnd, "WINE", "Help", 0); break;
+
+ /* Context help */
+ case MNID_CTXT_ANNOTATE:MACRO_Annotate(); break;
+ case MNID_CTXT_COPY: MACRO_CopyDialog(); break;
+ case MNID_CTXT_PRINT: MACRO_Print(); break;
+ case MNID_OPTS_HISTORY: MACRO_History(); break;
+ case MNID_OPTS_FONTS_SMALL:
+ case MNID_CTXT_FONTS_SMALL:
+ win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0);
+ if (win->font_scale != 0)
+ {
+ win->font_scale = 0;
+ WINHELP_SetupText(GetDlgItem(hWnd, CTL_ID_TEXT), win, 0 /* FIXME */);
+ }
+ break;
+ case MNID_OPTS_FONTS_NORMAL:
+ case MNID_CTXT_FONTS_NORMAL:
+ win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0);
+ if (win->font_scale != 1)
+ {
+ win->font_scale = 1;
+ WINHELP_SetupText(GetDlgItem(hWnd, CTL_ID_TEXT), win, 0 /* FIXME */);
+ }
+ break;
+ case MNID_OPTS_FONTS_LARGE:
+ case MNID_CTXT_FONTS_LARGE:
+ win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0);
+ if (win->font_scale != 2)
+ {
+ win->font_scale = 2;
+ WINHELP_SetupText(GetDlgItem(hWnd, CTL_ID_TEXT), win, 0 /* FIXME */);
+ }
+ break;
+ case MNID_OPTS_HELP_DEFAULT:
+ case MNID_OPTS_HELP_VISIBLE:
+ case MNID_OPTS_HELP_NONVISIBLE:
+ case MNID_OPTS_SYSTEM_COLORS:
+ case MNID_CTXT_HELP_DEFAULT:
+ case MNID_CTXT_HELP_VISIBLE:
+ case MNID_CTXT_HELP_NONVISIBLE:
+ case MNID_CTXT_SYSTEM_COLORS:
+ /* FIXME: NIY */
+
+ default:
+ /* Buttons */
+ for (button = win->first_button; button; button = button->next)
+ if (wParam == button->wParam) break;
+ if (button)
+ MACRO_ExecuteMacro(win, button->lpszMacro);
+ else if (!HIWORD(wParam))
+ MessageBox(0, MAKEINTRESOURCE(STID_NOT_IMPLEMENTED),
+ MAKEINTRESOURCE(STID_WHERROR), MB_OK);
+ break;
+ }
+ break;
+/* EPP case WM_DESTROY: */
+/* EPP if (Globals.hPopupWnd) DestroyWindow(Globals.hPopupWnd); */
+/* EPP break; */
+ case WM_COPYDATA:
+ return WINHELP_HandleCommand((HWND)wParam, lParam);
+
+ case WM_CHAR:
+ if (wParam == 3)
+ {
+ SendMessage(GetDlgItem(hWnd, CTL_ID_TEXT), WM_COPY, 0, 0);
+ return 0;
+ }
+ break;
+
+ case WM_KEYDOWN:
+ keyDelta = 0;
+ win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0);
+ hTextWnd = GetDlgItem(win->hMainWnd, CTL_ID_TEXT);
+
+ switch (wParam)
+ {
+ case VK_UP:
+ SendMessage(hTextWnd, EM_SCROLL, SB_LINEUP, 0);
+ return 0;
+ case VK_DOWN:
+ SendMessage(hTextWnd, EM_SCROLL, SB_LINEDOWN, 0);
+ return 0;
+ case VK_PRIOR:
+ SendMessage(hTextWnd, EM_SCROLL, SB_PAGEUP, 0);
+ return 0;
+ case VK_NEXT:
+ SendMessage(hTextWnd, EM_SCROLL, SB_PAGEDOWN, 0);
+ return 0;
+ case VK_ESCAPE:
+ MACRO_Exit();
+ return 0;
+ }
+ break;
+
+ case WM_NOTIFY:
+ if (wParam == CTL_ID_TEXT)
+ {
+ RECT rc;
+
+ switch (((NMHDR*)lParam)->code)
+ {
+ case EN_MSGFILTER:
+ {
+ const MSGFILTER* msgf = (const MSGFILTER*)lParam;
+ switch (msgf->msg)
+ {
+ case WM_KEYUP:
+ if (msgf->wParam == VK_ESCAPE)
+ WINHELP_ReleaseWindow((WINHELP_WINDOW*)GetWindowLongPtr(hWnd, 0));
+ break;
+ case WM_RBUTTONDOWN:
+ {
+ HMENU hMenu;
+ POINT pt;
+
+ win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0);
+ hMenu = LoadMenu(Globals.hInstance, (LPSTR)CONTEXT_MENU);
+ switch (win->font_scale)
+ {
+ case 0:
+ CheckMenuItem(hMenu, MNID_CTXT_FONTS_SMALL,
+ MF_BYCOMMAND|MF_CHECKED);
+ break;
+ default:
+ WINE_FIXME("Unsupported %d\n", win->font_scale);
+ case 1:
+ CheckMenuItem(hMenu, MNID_CTXT_FONTS_NORMAL,
+ MF_BYCOMMAND|MF_CHECKED);
+ break;
+ case 2:
+ CheckMenuItem(hMenu, MNID_CTXT_FONTS_LARGE,
+ MF_BYCOMMAND|MF_CHECKED);
+ break;
+ }
+ pt.x = (int)(short)LOWORD(msgf->lParam);
+ pt.y = (int)(short)HIWORD(msgf->lParam);
+ ClientToScreen(msgf->nmhdr.hwndFrom, &pt);
+ TrackPopupMenu(GetSubMenu(hMenu, 0), TPM_LEFTALIGN|TPM_TOPALIGN,
+ pt.x, pt.y, 0, hWnd, NULL);
+ DestroyMenu(hMenu);
+ }
+ break;
+ default:
+ return WINHELP_HandleTextMouse((WINHELP_WINDOW*)GetWindowLongPtr(hWnd, 0),
+ msgf->msg, msgf->lParam);
+ }
+ }
+ break;
+
+ case EN_REQUESTRESIZE:
+ rc = ((REQRESIZE*)lParam)->rc;
+ win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0);
+ AdjustWindowRect(&rc, GetWindowLong(win->hMainWnd, GWL_STYLE),
+ FALSE);
+ SetWindowPos(win->hMainWnd, HWND_TOP, 0, 0,
+ rc.right - rc.left, rc.bottom - rc.top,
+ SWP_NOMOVE | SWP_NOZORDER);
+ WINHELP_LayoutMainWindow(win);
+ break;
+ }
+ }
+ break;
+
+ case WM_INITMENUPOPUP:
+ win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0);
+ CheckMenuItem((HMENU)wParam, MNID_OPTS_FONTS_SMALL,
+ MF_BYCOMMAND | (win->font_scale == 0) ? MF_CHECKED : 0);
+ CheckMenuItem((HMENU)wParam, MNID_OPTS_FONTS_NORMAL,
+ MF_BYCOMMAND | (win->font_scale == 1) ? MF_CHECKED : 0);
+ CheckMenuItem((HMENU)wParam, MNID_OPTS_FONTS_LARGE,
+ MF_BYCOMMAND | (win->font_scale == 2) ? MF_CHECKED : 0);
+ break;
+ case WM_DESTROY:
+ win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0);
+ WINHELP_DeleteWindow(win);
+ break;
+ }
+ return DefWindowProc(hWnd, msg, wParam, lParam);
+}
+
+/**************************************************************************
+ * WINHELP_CreateIndexWindow
+ *
+ * Displays a dialog with keywords of current help file.
+ *
+ */
+BOOL WINHELP_CreateIndexWindow(BOOL is_search)
+{
+ HPROPSHEETPAGE psPage[3];
+ PROPSHEETPAGE psp;
+ PROPSHEETHEADER psHead;
+ struct index_data id;
+ char buf[256];
+
+ if (Globals.active_win && Globals.active_win->page && Globals.active_win->page->file)
+ id.hlpfile = Globals.active_win->page->file;
+ else
+ return FALSE;
+
+ if (id.hlpfile->kwbtree == NULL)
+ {
+ WINE_TRACE("No index provided\n");
+ return FALSE;
+ }
+
+ InitCommonControls();
+
+ id.jump = FALSE;
+ memset(&psp, 0, sizeof(psp));
+ psp.dwSize = sizeof(psp);
+ psp.dwFlags = 0;
+ psp.hInstance = Globals.hInstance;
+
+ psp.u.pszTemplate = MAKEINTRESOURCE(IDD_INDEX);
+ psp.lParam = (LPARAM)&id;
+ psp.pfnDlgProc = WINHELP_IndexDlgProc;
+ psPage[0] = CreatePropertySheetPage(&psp);
+
+ psp.u.pszTemplate = MAKEINTRESOURCE(IDD_SEARCH);
+ psp.lParam = (LPARAM)&id;
+ psp.pfnDlgProc = WINHELP_SearchDlgProc;
+ psPage[1] = CreatePropertySheetPage(&psp);
+
+ memset(&psHead, 0, sizeof(psHead));
+ psHead.dwSize = sizeof(psHead);
+
+ LoadString(Globals.hInstance, STID_PSH_INDEX, buf, sizeof(buf));
+ strcat(buf, Globals.active_win->info->caption);
+
+ psHead.pszCaption = buf;
+ psHead.nPages = 2;
+ psHead.u2.nStartPage = is_search ? 1 : 0;
+ psHead.hwndParent = Globals.active_win->hMainWnd;
+ psHead.u3.phpage = psPage;
+ psHead.dwFlags = PSH_NOAPPLYNOW;
+
+ PropertySheet(&psHead);
+ if (id.jump)
+ {
+ WINE_TRACE("got %d as an offset\n", id.offset);
+ WINHELP_OpenHelpWindow(HLPFILE_PageByOffset, id.hlpfile, id.offset,
+ Globals.active_win->info, SW_NORMAL);
+ }
+ return TRUE;
+}
+
+/***********************************************************************
+ *
+ * RegisterWinClasses
+ */
+static BOOL WINHELP_RegisterWinClasses(void)
+{
+ WNDCLASS class_main, class_button_box, class_shadow, class_history;
+
+ class_main.style = CS_HREDRAW | CS_VREDRAW;
+ class_main.lpfnWndProc = WINHELP_MainWndProc;
+ class_main.cbClsExtra = 0;
+ class_main.cbWndExtra = sizeof(WINHELP_WINDOW *);
+ class_main.hInstance = Globals.hInstance;
+ class_main.hIcon = LoadIcon(Globals.hInstance, MAKEINTRESOURCE(IDI_WINHELP));
+ class_main.hCursor = LoadCursor(0, IDC_ARROW);
+ class_main.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
+ class_main.lpszMenuName = 0;
+ class_main.lpszClassName = MAIN_WIN_CLASS_NAME;
+
+ class_button_box = class_main;
+ class_button_box.lpfnWndProc = WINHELP_ButtonBoxWndProc;
+ class_button_box.cbWndExtra = 0;
+ class_button_box.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
+ class_button_box.lpszClassName = BUTTON_BOX_WIN_CLASS_NAME;
+
+ class_shadow = class_main;
+ class_shadow.lpfnWndProc = WINHELP_ShadowWndProc;
+ class_shadow.cbWndExtra = 0;
+ class_shadow.hbrBackground = (HBRUSH)(COLOR_3DDKSHADOW+1);
+ class_shadow.lpszClassName = SHADOW_WIN_CLASS_NAME;
+
+ class_history = class_main;
+ class_history.lpfnWndProc = WINHELP_HistoryWndProc;
+ class_history.lpszClassName = HISTORY_WIN_CLASS_NAME;
+
+ return (RegisterClass(&class_main) &&
+ RegisterClass(&class_button_box) &&
+ RegisterClass(&class_shadow) &&
+ RegisterClass(&class_history));
+}
+
+/***********************************************************************
+ *
+ * WinMain
+ */
+int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE prev, LPSTR cmdline, int show)
+{
+ MSG msg;
+ LONG lHash = 0;
+ HLPFILE* hlpfile;
+ static CHAR default_wndname[] = "main";
+ LPSTR wndname = default_wndname;
+ WINHELP_DLL* dll;
+
+ Globals.hInstance = hInstance;
+
+ if (LoadLibrary("riched20.dll") == NULL)
+ return MessageBox(0, MAKEINTRESOURCE(STID_NO_RICHEDIT),
+ MAKEINTRESOURCE(STID_WHERROR), MB_OK);
+
+ /* Get options */
+ while (*cmdline && (*cmdline == ' ' || *cmdline == '-'))
+ {
+ CHAR option;
+ LPCSTR topic_id;
+ if (*cmdline++ == ' ') continue;
+
+ option = *cmdline;
+ if (option) cmdline++;
+ while (*cmdline && *cmdline == ' ') cmdline++;
+ switch (option)
+ {
+ case 'i':
+ case 'I':
+ topic_id = cmdline;
+ while (*cmdline && *cmdline != ' ') cmdline++;
+ if (*cmdline) *cmdline++ = '\0';
+ lHash = HLPFILE_Hash(topic_id);
+ break;
+
+ case '3':
+ case '4':
+ Globals.wVersion = option - '0';
+ break;
+
+ case 'x':
+ show = SW_HIDE;
+ Globals.isBook = FALSE;
+ break;
+
+ default:
+ WINE_FIXME("Unsupported cmd line: %s\n", cmdline);
+ break;
+ }
+ }
+
+ /* Create primary window */
+ if (!WINHELP_RegisterWinClasses())
+ {
+ WINE_FIXME("Couldn't register classes\n");
+ return 0;
+ }
+
+ if (*cmdline)
+ {
+ char* ptr;
+ if ((*cmdline == '"') && (ptr = strchr(cmdline+1, '"')))
+ {
+ cmdline++;
+ *ptr = '\0';
+ }
+ if ((ptr = strchr(cmdline, '>')))
+ {
+ *ptr = '\0';
+ wndname = ptr + 1;
+ }
+ hlpfile = WINHELP_LookupHelpFile(cmdline);
+ if (!hlpfile) return 0;
+ }
+ else hlpfile = NULL;
+ WINHELP_OpenHelpWindow(HLPFILE_PageByHash, hlpfile, lHash,
+ WINHELP_GetWindowInfo(hlpfile, wndname), show);
+
+ /* Message loop */
+ while ((Globals.win_list || Globals.active_popup) && GetMessage(&msg, 0, 0, 0))
+ {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ for (dll = Globals.dlls; dll; dll = dll->next)
+ {
+ if (dll->class & DC_INITTERM) dll->handler(DW_TERM, 0, 0);
+ }
+ return 0;
+}