mshtml: Added IHTMLElement2::get_scrollHeight implementation.
[wine/wine-kai.git] / programs / winhlp32 / winhelp.c
blobd65a752c30841cbbede1c75866c7a078218bc1fb
1 /*
2 * Help Viewer
4 * Copyright 1996 Ulrich Schmid <uschmid@mail.hh.provi.de>
5 * 2002 Sylvain Petreolle <spetreolle@yahoo.fr>
6 * 2002, 2008 Eric Pouech <eric.pouech@wanadoo.fr>
7 * 2004 Ken Belleau <jamez@ivic.qc.ca>
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 #include <assert.h>
25 #include <stdio.h>
26 #include <string.h>
27 #include <stdarg.h>
28 #include <stdlib.h>
30 #define NONAMELESSUNION
31 #define NONAMELESSSTRUCT
33 #include "windef.h"
34 #include "winbase.h"
35 #include "wingdi.h"
36 #include "winuser.h"
37 #include "commdlg.h"
38 #include "winhelp.h"
39 #include "winhelp_res.h"
40 #include "shellapi.h"
41 #include "richedit.h"
42 #include "commctrl.h"
44 #include "wine/debug.h"
46 WINE_DEFAULT_DEBUG_CHANNEL(winhelp);
48 static BOOL WINHELP_RegisterWinClasses(void);
49 static LRESULT CALLBACK WINHELP_MainWndProc(HWND, UINT, WPARAM, LPARAM);
50 static LRESULT CALLBACK WINHELP_ButtonBoxWndProc(HWND, UINT, WPARAM, LPARAM);
51 static LRESULT CALLBACK WINHELP_ButtonWndProc(HWND, UINT, WPARAM, LPARAM);
52 static LRESULT CALLBACK WINHELP_HistoryWndProc(HWND, UINT, WPARAM, LPARAM);
53 static LRESULT CALLBACK WINHELP_ShadowWndProc(HWND, UINT, WPARAM, LPARAM);
54 static BOOL WINHELP_CheckPopup(HWND, UINT, WPARAM, LPARAM, LRESULT*);
55 static void WINHELP_InitFonts(HWND hWnd);
56 static void WINHELP_DeleteWindow(WINHELP_WINDOW*);
57 static void WINHELP_DeleteButtons(WINHELP_WINDOW*);
58 static void WINHELP_SetupText(HWND hWnd, WINHELP_WINDOW *win, ULONG relative);
59 static void WINHELP_DeletePageLinks(HLPFILE_PAGE* page);
61 WINHELP_GLOBALS Globals = {3, NULL, TRUE, NULL, NULL, NULL, NULL, NULL, {{{NULL,NULL}},0}, NULL};
63 #define CTL_ID_BUTTON 0x700
64 #define CTL_ID_TEXT 0x701
66 /***********************************************************************
68 * WINHELP_GetOpenFileName
70 BOOL WINHELP_GetOpenFileName(LPSTR lpszFile, int len)
72 OPENFILENAME openfilename;
73 CHAR szDir[MAX_PATH];
74 CHAR szzFilter[2 * MAX_STRING_LEN + 100];
75 LPSTR p = szzFilter;
77 WINE_TRACE("()\n");
79 LoadString(Globals.hInstance, STID_HELP_FILES_HLP, p, MAX_STRING_LEN);
80 p += strlen(p) + 1;
81 lstrcpy(p, "*.hlp");
82 p += strlen(p) + 1;
83 LoadString(Globals.hInstance, STID_ALL_FILES, p, MAX_STRING_LEN);
84 p += strlen(p) + 1;
85 lstrcpy(p, "*.*");
86 p += strlen(p) + 1;
87 *p = '\0';
89 GetCurrentDirectory(sizeof(szDir), szDir);
91 lpszFile[0]='\0';
93 openfilename.lStructSize = sizeof(OPENFILENAME);
94 openfilename.hwndOwner = NULL;
95 openfilename.hInstance = Globals.hInstance;
96 openfilename.lpstrFilter = szzFilter;
97 openfilename.lpstrCustomFilter = 0;
98 openfilename.nMaxCustFilter = 0;
99 openfilename.nFilterIndex = 1;
100 openfilename.lpstrFile = lpszFile;
101 openfilename.nMaxFile = len;
102 openfilename.lpstrFileTitle = 0;
103 openfilename.nMaxFileTitle = 0;
104 openfilename.lpstrInitialDir = szDir;
105 openfilename.lpstrTitle = 0;
106 openfilename.Flags = 0;
107 openfilename.nFileOffset = 0;
108 openfilename.nFileExtension = 0;
109 openfilename.lpstrDefExt = 0;
110 openfilename.lCustData = 0;
111 openfilename.lpfnHook = 0;
112 openfilename.lpTemplateName = 0;
114 return GetOpenFileName(&openfilename);
117 static char* WINHELP_GetCaption(WINHELP_WNDPAGE* wpage)
119 if (wpage->wininfo->caption[0]) return wpage->wininfo->caption;
120 return wpage->page->file->lpszTitle;
123 /***********************************************************************
125 * WINHELP_LookupHelpFile
127 HLPFILE* WINHELP_LookupHelpFile(LPCSTR lpszFile)
129 HLPFILE* hlpfile;
130 char szFullName[MAX_PATH];
131 char szAddPath[MAX_PATH];
132 char *p;
135 * NOTE: This is needed by popup windows only.
136 * In other cases it's not needed but does not hurt though.
138 if (Globals.active_win && Globals.active_win->page && Globals.active_win->page->file)
140 strcpy(szAddPath, Globals.active_win->page->file->lpszPath);
141 p = strrchr(szAddPath, '\\');
142 if (p) *p = 0;
146 * FIXME: Should we swap conditions?
148 if (!SearchPath(NULL, lpszFile, ".hlp", MAX_PATH, szFullName, NULL) &&
149 !SearchPath(szAddPath, lpszFile, ".hlp", MAX_PATH, szFullName, NULL))
151 if (WINHELP_MessageBoxIDS_s(STID_FILE_NOT_FOUND_s, lpszFile, STID_WHERROR,
152 MB_YESNO|MB_ICONQUESTION) != IDYES)
153 return NULL;
154 if (!WINHELP_GetOpenFileName(szFullName, MAX_PATH))
155 return NULL;
157 hlpfile = HLPFILE_ReadHlpFile(szFullName);
158 if (!hlpfile)
159 WINHELP_MessageBoxIDS_s(STID_HLPFILE_ERROR_s, lpszFile,
160 STID_WHERROR, MB_OK|MB_ICONSTOP);
161 return hlpfile;
164 /******************************************************************
165 * WINHELP_GetWindowInfo
169 HLPFILE_WINDOWINFO* WINHELP_GetWindowInfo(HLPFILE* hlpfile, LPCSTR name)
171 static HLPFILE_WINDOWINFO mwi;
172 unsigned int i;
174 if (!name || !name[0])
175 name = Globals.active_win->lpszName;
177 if (hlpfile)
178 for (i = 0; i < hlpfile->numWindows; i++)
179 if (!strcmp(hlpfile->windows[i].name, name))
180 return &hlpfile->windows[i];
182 if (strcmp(name, "main") != 0)
184 WINE_FIXME("Couldn't find window info for %s\n", name);
185 assert(0);
186 return NULL;
188 if (!mwi.name[0])
190 strcpy(mwi.type, "primary");
191 strcpy(mwi.name, "main");
192 if (!LoadString(Globals.hInstance, STID_WINE_HELP,
193 mwi.caption, sizeof(mwi.caption)))
194 strcpy(mwi.caption, hlpfile->lpszTitle);
195 mwi.origin.x = mwi.origin.y = mwi.size.cx = mwi.size.cy = CW_USEDEFAULT;
196 mwi.style = SW_SHOW;
197 mwi.win_style = WS_OVERLAPPEDWINDOW;
198 mwi.sr_color = mwi.sr_color = 0xFFFFFF;
200 return &mwi;
203 /******************************************************************
204 * HLPFILE_GetPopupWindowInfo
208 static HLPFILE_WINDOWINFO* WINHELP_GetPopupWindowInfo(HLPFILE* hlpfile,
209 WINHELP_WINDOW* parent, LPARAM mouse)
211 static HLPFILE_WINDOWINFO wi;
213 RECT parent_rect;
215 wi.type[0] = wi.name[0] = wi.caption[0] = '\0';
217 /* Calculate horizontal size and position of a popup window */
218 GetWindowRect(parent->hMainWnd, &parent_rect);
219 wi.size.cx = (parent_rect.right - parent_rect.left) / 2;
220 wi.size.cy = 10; /* need a non null value, so that border are taken into account while computing */
222 wi.origin.x = (short)LOWORD(mouse);
223 wi.origin.y = (short)HIWORD(mouse);
224 ClientToScreen(parent->hMainWnd, &wi.origin);
225 wi.origin.x -= wi.size.cx / 2;
226 wi.origin.x = min(wi.origin.x, GetSystemMetrics(SM_CXSCREEN) - wi.size.cx);
227 wi.origin.x = max(wi.origin.x, 0);
229 wi.style = SW_SHOW;
230 wi.win_style = WS_POPUP | WS_BORDER;
231 if (parent->page->file->has_popup_color)
232 wi.sr_color = parent->page->file->popup_color;
233 else
234 wi.sr_color = parent->info->sr_color;
235 wi.nsr_color = 0xFFFFFF;
237 return &wi;
240 /***********************************************************************
242 * WinMain
244 int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE prev, LPSTR cmdline, int show)
246 MSG msg;
247 LONG lHash = 0;
248 HLPFILE* hlpfile;
249 static CHAR default_wndname[] = "main";
250 LPSTR wndname = default_wndname;
251 WINHELP_DLL* dll;
253 Globals.hInstance = hInstance;
255 if (LoadLibrary("riched20.dll") == NULL)
256 return MessageBox(0, MAKEINTRESOURCE(STID_NO_RICHEDIT),
257 MAKEINTRESOURCE(STID_WHERROR), MB_OK);
259 /* Get options */
260 while (*cmdline && (*cmdline == ' ' || *cmdline == '-'))
262 CHAR option;
263 LPCSTR topic_id;
264 if (*cmdline++ == ' ') continue;
266 option = *cmdline;
267 if (option) cmdline++;
268 while (*cmdline && *cmdline == ' ') cmdline++;
269 switch (option)
271 case 'i':
272 case 'I':
273 topic_id = cmdline;
274 while (*cmdline && *cmdline != ' ') cmdline++;
275 if (*cmdline) *cmdline++ = '\0';
276 lHash = HLPFILE_Hash(topic_id);
277 break;
279 case '3':
280 case '4':
281 Globals.wVersion = option - '0';
282 break;
284 case 'x':
285 show = SW_HIDE;
286 Globals.isBook = FALSE;
287 break;
289 default:
290 WINE_FIXME("Unsupported cmd line: %s\n", cmdline);
291 break;
295 /* Create primary window */
296 if (!WINHELP_RegisterWinClasses())
298 WINE_FIXME("Couldn't register classes\n");
299 return 0;
302 if (*cmdline)
304 char* ptr;
305 if ((*cmdline == '"') && (ptr = strchr(cmdline+1, '"')))
307 cmdline++;
308 *ptr = '\0';
310 if ((ptr = strchr(cmdline, '>')))
312 *ptr = '\0';
313 wndname = ptr + 1;
315 hlpfile = WINHELP_LookupHelpFile(cmdline);
316 if (!hlpfile) return 0;
318 else hlpfile = NULL;
319 WINHELP_OpenHelpWindow(HLPFILE_PageByHash, hlpfile, lHash,
320 WINHELP_GetWindowInfo(hlpfile, wndname), show);
322 /* Message loop */
323 while (GetMessage(&msg, 0, 0, 0))
325 TranslateMessage(&msg);
326 DispatchMessage(&msg);
328 for (dll = Globals.dlls; dll; dll = dll->next)
330 if (dll->class & DC_INITTERM) dll->handler(DW_TERM, 0, 0);
332 return 0;
335 /***********************************************************************
337 * RegisterWinClasses
339 static BOOL WINHELP_RegisterWinClasses(void)
341 WNDCLASS class_main, class_button_box, class_shadow, class_history;
343 class_main.style = CS_HREDRAW | CS_VREDRAW;
344 class_main.lpfnWndProc = WINHELP_MainWndProc;
345 class_main.cbClsExtra = 0;
346 class_main.cbWndExtra = sizeof(LONG);
347 class_main.hInstance = Globals.hInstance;
348 class_main.hIcon = LoadIcon(Globals.hInstance, MAKEINTRESOURCE(IDI_WINHELP));
349 class_main.hCursor = LoadCursor(0, IDC_ARROW);
350 class_main.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
351 class_main.lpszMenuName = 0;
352 class_main.lpszClassName = MAIN_WIN_CLASS_NAME;
354 class_button_box = class_main;
355 class_button_box.lpfnWndProc = WINHELP_ButtonBoxWndProc;
356 class_button_box.cbWndExtra = 0;
357 class_button_box.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
358 class_button_box.lpszClassName = BUTTON_BOX_WIN_CLASS_NAME;
360 class_shadow = class_main;
361 class_shadow.lpfnWndProc = WINHELP_ShadowWndProc;
362 class_shadow.cbWndExtra = 0;
363 class_shadow.hbrBackground = (HBRUSH)(COLOR_3DDKSHADOW+1);
364 class_shadow.lpszClassName = SHADOW_WIN_CLASS_NAME;
366 class_history = class_main;
367 class_history.lpfnWndProc = WINHELP_HistoryWndProc;
368 class_history.lpszClassName = HISTORY_WIN_CLASS_NAME;
370 return (RegisterClass(&class_main) &&
371 RegisterClass(&class_button_box) &&
372 RegisterClass(&class_shadow) &&
373 RegisterClass(&class_history));
376 typedef struct
378 WORD size;
379 WORD command;
380 LONG data;
381 LONG reserved;
382 WORD ofsFilename;
383 WORD ofsData;
384 } WINHELP,*LPWINHELP;
386 static BOOL WINHELP_HasWorkingWindow(void)
388 if (!Globals.active_win) return FALSE;
389 if (Globals.active_win->next || Globals.win_list != Globals.active_win) return TRUE;
390 return Globals.active_win->page != NULL && Globals.active_win->page->file != NULL;
393 /******************************************************************
394 * WINHELP_HandleCommand
398 static LRESULT WINHELP_HandleCommand(HWND hSrcWnd, LPARAM lParam)
400 COPYDATASTRUCT* cds = (COPYDATASTRUCT*)lParam;
401 WINHELP* wh;
403 if (cds->dwData != 0xA1DE505)
405 WINE_FIXME("Wrong magic number (%08lx)\n", cds->dwData);
406 return 0;
409 wh = (WINHELP*)cds->lpData;
411 if (wh)
413 char* ptr = (wh->ofsFilename) ? (LPSTR)wh + wh->ofsFilename : NULL;
415 WINE_TRACE("Got[%u]: cmd=%u data=%08x fn=%s\n",
416 wh->size, wh->command, wh->data, ptr);
417 switch (wh->command)
419 case HELP_CONTEXT:
420 if (ptr)
422 MACRO_JumpContext(ptr, "main", wh->data);
424 if (!WINHELP_HasWorkingWindow()) MACRO_Exit();
425 break;
426 case HELP_QUIT:
427 MACRO_Exit();
428 break;
429 case HELP_CONTENTS:
430 if (ptr)
432 MACRO_JumpContents(ptr, "main");
434 if (!WINHELP_HasWorkingWindow()) MACRO_Exit();
435 break;
436 case HELP_HELPONHELP:
437 MACRO_HelpOn();
438 if (!WINHELP_HasWorkingWindow()) MACRO_Exit();
439 break;
440 /* case HELP_SETINDEX: */
441 case HELP_SETCONTENTS:
442 if (ptr)
444 MACRO_SetContents(ptr, wh->data);
446 break;
447 case HELP_CONTEXTPOPUP:
448 if (ptr)
450 MACRO_PopupContext(ptr, wh->data);
452 break;
453 /* case HELP_FORCEFILE:*/
454 /* case HELP_CONTEXTMENU: */
455 case HELP_FINDER:
456 /* in fact, should be the topic dialog box */
457 WINE_FIXME("HELP_FINDER: stub\n");
458 if (ptr)
460 MACRO_JumpHash(ptr, "main", 0);
462 break;
463 /* case HELP_WM_HELP: */
464 /* case HELP_SETPOPUP_POS: */
465 /* case HELP_KEY: */
466 /* case HELP_COMMAND: */
467 /* case HELP_PARTIALKEY: */
468 /* case HELP_MULTIKEY: */
469 /* case HELP_SETWINPOS: */
470 default:
471 WINE_FIXME("Unhandled command (%x) for remote winhelp control\n", wh->command);
472 break;
475 /* Always return success for now */
476 return 1;
479 void WINHELP_LayoutMainWindow(WINHELP_WINDOW* win)
481 RECT rect, button_box_rect;
482 INT text_top = 0;
483 HWND hButtonBoxWnd = GetDlgItem(win->hMainWnd, CTL_ID_BUTTON);
484 HWND hTextWnd = GetDlgItem(win->hMainWnd, CTL_ID_TEXT);
486 GetClientRect(win->hMainWnd, &rect);
488 /* Update button box and text Window */
489 SetWindowPos(hButtonBoxWnd, HWND_TOP,
490 rect.left, rect.top,
491 rect.right - rect.left,
492 rect.bottom - rect.top, 0);
494 if (GetWindowRect(hButtonBoxWnd, &button_box_rect))
495 text_top = rect.top + button_box_rect.bottom - button_box_rect.top;
497 SetWindowPos(hTextWnd, HWND_TOP,
498 rect.left, text_top,
499 rect.right - rect.left,
500 rect.bottom - text_top, 0);
504 static void WINHELP_RememberPage(WINHELP_WINDOW* win, WINHELP_WNDPAGE* wpage)
506 unsigned num;
508 if (!Globals.history.index || Globals.history.set[0].page != wpage->page)
510 num = sizeof(Globals.history.set) / sizeof(Globals.history.set[0]);
511 /* we're full, remove latest entry */
512 if (Globals.history.index == num)
514 HLPFILE_FreeHlpFile(Globals.history.set[num - 1].page->file);
515 Globals.history.index--;
517 memmove(&Globals.history.set[1], &Globals.history.set[0],
518 Globals.history.index * sizeof(Globals.history.set[0]));
519 Globals.history.set[0] = *wpage;
520 Globals.history.index++;
521 wpage->page->file->wRefCount++;
523 if (win->hHistoryWnd) InvalidateRect(win->hHistoryWnd, NULL, TRUE);
525 num = sizeof(win->back.set) / sizeof(win->back.set[0]);
526 if (win->back.index == num)
528 /* we're full, remove latest entry */
529 HLPFILE_FreeHlpFile(win->back.set[0].page->file);
530 memmove(&win->back.set[0], &win->back.set[1],
531 (num - 1) * sizeof(win->back.set[0]));
532 win->back.index--;
534 win->back.set[win->back.index++] = *wpage;
535 wpage->page->file->wRefCount++;
538 /***********************************************************************
540 * WINHELP_CreateHelpWindow
542 BOOL WINHELP_CreateHelpWindow(WINHELP_WNDPAGE* wpage, int nCmdShow, BOOL remember)
544 WINHELP_WINDOW* win = NULL;
545 BOOL bPrimary, bPopup, bReUsed = FALSE;
546 LPSTR name;
547 HICON hIcon;
548 HWND hTextWnd = NULL;
550 bPrimary = !lstrcmpi(wpage->wininfo->name, "main");
551 bPopup = !bPrimary && (wpage->wininfo->win_style & WS_POPUP);
553 if (!bPopup)
555 for (win = Globals.win_list; win; win = win->next)
557 if (!lstrcmpi(win->lpszName, wpage->wininfo->name))
559 POINT pt = {0, 0};
560 SIZE sz = {0, 0};
561 DWORD flags = SWP_NOSIZE | SWP_NOMOVE;
563 WINHELP_DeleteButtons(win);
564 bReUsed = TRUE;
565 SetWindowText(win->hMainWnd, WINHELP_GetCaption(wpage));
566 if (wpage->wininfo->origin.x != CW_USEDEFAULT &&
567 wpage->wininfo->origin.y != CW_USEDEFAULT)
569 pt = wpage->wininfo->origin;
570 flags &= ~SWP_NOSIZE;
572 if (wpage->wininfo->size.cx != CW_USEDEFAULT &&
573 wpage->wininfo->size.cy != CW_USEDEFAULT)
575 sz = wpage->wininfo->size;
576 flags &= ~SWP_NOMOVE;
578 SetWindowPos(win->hMainWnd, HWND_TOP, pt.x, pt.y, sz.cx, sz.cy, flags);
580 if (wpage->page && win->page && wpage->page->file != win->page->file)
581 WINHELP_DeleteBackSet(win);
582 WINHELP_InitFonts(win->hMainWnd);
584 win->page = wpage->page;
585 win->info = wpage->wininfo;
586 hTextWnd = GetDlgItem(win->hMainWnd, CTL_ID_TEXT);
587 WINHELP_SetupText(hTextWnd, win, wpage->relative);
589 InvalidateRect(win->hMainWnd, NULL, TRUE);
590 if (win->hHistoryWnd) InvalidateRect(win->hHistoryWnd, NULL, TRUE);
592 break;
597 if (!win)
599 /* Initialize WINHELP_WINDOW struct */
600 win = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
601 sizeof(WINHELP_WINDOW) + strlen(wpage->wininfo->name) + 1);
602 if (!win) return FALSE;
603 win->next = Globals.win_list;
604 Globals.win_list = win;
606 name = (char*)win + sizeof(WINHELP_WINDOW);
607 lstrcpy(name, wpage->wininfo->name);
608 win->lpszName = name;
609 win->hHandCur = LoadCursorW(0, (LPWSTR)IDC_HAND);
610 win->back.index = 0;
611 win->font_scale = 1;
613 win->page = wpage->page;
614 win->info = wpage->wininfo;
616 if (!bPopup && wpage->page && remember)
618 WINHELP_RememberPage(win, wpage);
621 if (bPopup)
622 Globals.active_popup = win;
623 else
624 Globals.active_win = win;
626 /* Initialize default pushbuttons */
627 if (bPrimary && wpage->page)
629 CHAR buffer[MAX_STRING_LEN];
631 LoadString(Globals.hInstance, STID_CONTENTS, buffer, sizeof(buffer));
632 MACRO_CreateButton("BTN_CONTENTS", buffer, "Contents()");
633 LoadString(Globals.hInstance, STID_INDEX, buffer, sizeof(buffer));
634 MACRO_CreateButton("BTN_INDEX", buffer, "Finder()");
635 LoadString(Globals.hInstance, STID_BACK, buffer, sizeof(buffer));
636 MACRO_CreateButton("BTN_BACK", buffer, "Back()");
637 if (win->back.index <= 1) MACRO_DisableButton("BTN_BACK");
640 if (!bReUsed)
642 win->hMainWnd = CreateWindowEx((bPopup) ? WS_EX_TOOLWINDOW : 0, MAIN_WIN_CLASS_NAME,
643 WINHELP_GetCaption(wpage),
644 bPrimary ? WS_OVERLAPPEDWINDOW : wpage->wininfo->win_style,
645 wpage->wininfo->origin.x, wpage->wininfo->origin.y,
646 wpage->wininfo->size.cx, wpage->wininfo->size.cy,
647 bPopup ? Globals.active_win->hMainWnd : NULL,
648 bPrimary ? LoadMenu(Globals.hInstance, MAKEINTRESOURCE(MAIN_MENU)) : 0,
649 Globals.hInstance, win);
650 if (!bPopup)
651 /* Create button box and text Window */
652 CreateWindow(BUTTON_BOX_WIN_CLASS_NAME, "", WS_CHILD | WS_VISIBLE,
653 0, 0, 0, 0, win->hMainWnd, (HMENU)CTL_ID_BUTTON, Globals.hInstance, NULL);
655 hTextWnd = CreateWindow(RICHEDIT_CLASS, NULL,
656 ES_MULTILINE | ES_READONLY | WS_CHILD | WS_HSCROLL | WS_VSCROLL | WS_VISIBLE,
657 0, 0, 0, 0, win->hMainWnd, (HMENU)CTL_ID_TEXT, Globals.hInstance, NULL);
658 SendMessage(hTextWnd, EM_SETEVENTMASK, 0,
659 SendMessage(hTextWnd, EM_GETEVENTMASK, 0, 0) | ENM_MOUSEEVENTS);
662 hIcon = (wpage->page) ? wpage->page->file->hIcon : NULL;
663 if (!hIcon) hIcon = LoadIcon(Globals.hInstance, MAKEINTRESOURCE(IDI_WINHELP));
664 SendMessage(win->hMainWnd, WM_SETICON, ICON_SMALL, (DWORD_PTR)hIcon);
666 /* Initialize file specific pushbuttons */
667 if (!(wpage->wininfo->win_style & WS_POPUP) && wpage->page)
669 HLPFILE_MACRO *macro;
670 for (macro = wpage->page->file->first_macro; macro; macro = macro->next)
671 MACRO_ExecuteMacro(macro->lpszMacro);
673 for (macro = wpage->page->first_macro; macro; macro = macro->next)
674 MACRO_ExecuteMacro(macro->lpszMacro);
677 if (bPopup)
679 DWORD mask = SendMessage(hTextWnd, EM_GETEVENTMASK, 0, 0);
680 RECT rect;
682 win->font_scale = Globals.active_win->font_scale;
683 WINHELP_SetupText(hTextWnd, win, wpage->relative);
685 /* we need the window to be shown for richedit to compute the size */
686 ShowWindow(win->hMainWnd, nCmdShow);
687 SendMessage(hTextWnd, EM_SETEVENTMASK, 0, mask | ENM_REQUESTRESIZE);
688 SendMessage(hTextWnd, EM_REQUESTRESIZE, 0, 0);
689 SendMessage(hTextWnd, EM_SETEVENTMASK, 0, mask);
691 GetWindowRect(win->hMainWnd, &rect);
692 win->hShadowWnd = CreateWindowEx(WS_EX_TOOLWINDOW, SHADOW_WIN_CLASS_NAME,
693 "", WS_POPUP | WS_VISIBLE,
694 rect.left + SHADOW_DX, rect.top + SHADOW_DY,
695 rect.right - rect.left,
696 rect.bottom - rect.top,
697 Globals.active_win->hMainWnd, 0,
698 Globals.hInstance, NULL);
699 SetWindowPos(win->hMainWnd, win->hShadowWnd, 0, 0, 0, 0,
700 SWP_NOSIZE | SWP_NOMOVE);
702 else
704 WINHELP_SetupText(hTextWnd, win, wpage->relative);
705 WINHELP_LayoutMainWindow(win);
706 ShowWindow(win->hMainWnd, nCmdShow);
709 return TRUE;
712 /******************************************************************
713 * WINHELP_OpenHelpWindow
714 * Main function to search for a page and display it in a window
716 BOOL WINHELP_OpenHelpWindow(HLPFILE_PAGE* (*lookup)(HLPFILE*, LONG, ULONG*),
717 HLPFILE* hlpfile, LONG val, HLPFILE_WINDOWINFO* wi,
718 int nCmdShow)
720 WINHELP_WNDPAGE wpage;
722 wpage.page = lookup(hlpfile, val, &wpage.relative);
723 if (wpage.page) wpage.page->file->wRefCount++;
724 wpage.wininfo = wi;
725 return WINHELP_CreateHelpWindow(&wpage, nCmdShow, TRUE);
728 /***********************************************************************
730 * WINHELP_FindLink
732 static HLPFILE_LINK* WINHELP_FindLink(WINHELP_WINDOW* win, LPARAM pos)
734 HLPFILE_LINK* link;
735 POINTL mouse_ptl, char_ptl, char_next_ptl;
736 DWORD cp;
738 if (!win->page) return NULL;
740 mouse_ptl.x = (short)LOWORD(pos);
741 mouse_ptl.y = (short)HIWORD(pos);
742 cp = SendMessageW(GetDlgItem(win->hMainWnd, CTL_ID_TEXT), EM_CHARFROMPOS,
743 0, (LPARAM)&mouse_ptl);
745 for (link = win->page->first_link; link; link = link->next)
747 if (link->cpMin <= cp && cp <= link->cpMax)
749 /* check whether we're at end of line */
750 SendMessageW(GetDlgItem(win->hMainWnd, CTL_ID_TEXT), EM_POSFROMCHAR,
751 (LPARAM)&char_ptl, cp);
752 SendMessageW(GetDlgItem(win->hMainWnd, CTL_ID_TEXT), EM_POSFROMCHAR,
753 (LPARAM)&char_next_ptl, cp + 1);
754 if (char_next_ptl.y != char_ptl.y || mouse_ptl.x >= char_next_ptl.x)
755 link = NULL;
756 break;
759 return link;
762 /******************************************************************
763 * WINHELP_HandleTextMouse
766 static BOOL WINHELP_HandleTextMouse(WINHELP_WINDOW* win, UINT msg, LPARAM lParam)
768 HLPFILE* hlpfile;
769 HLPFILE_LINK* link;
770 BOOL ret = FALSE;
772 switch (msg)
774 case WM_MOUSEMOVE:
775 if (WINHELP_FindLink(win, lParam))
776 SetCursor(win->hHandCur);
777 else
778 SetCursor(LoadCursor(0, IDC_ARROW));
779 break;
781 case WM_LBUTTONDOWN:
782 if ((win->current_link = WINHELP_FindLink(win, lParam)))
783 ret = TRUE;
784 break;
786 case WM_LBUTTONUP:
787 if ((link = WINHELP_FindLink(win, lParam)) && link == win->current_link)
789 HLPFILE_WINDOWINFO* wi;
791 switch (link->cookie)
793 case hlp_link_link:
794 if ((hlpfile = WINHELP_LookupHelpFile(link->string)))
796 if (link->window == -1)
797 wi = win->info;
798 else if (link->window < hlpfile->numWindows)
799 wi = &hlpfile->windows[link->window];
800 else
802 WINE_WARN("link to window %d/%d\n", link->window, hlpfile->numWindows);
803 break;
805 WINHELP_OpenHelpWindow(HLPFILE_PageByHash, hlpfile, link->hash, wi, SW_NORMAL);
807 break;
808 case hlp_link_popup:
809 if ((hlpfile = WINHELP_LookupHelpFile(link->string)))
810 WINHELP_OpenHelpWindow(HLPFILE_PageByHash, hlpfile, link->hash,
811 WINHELP_GetPopupWindowInfo(hlpfile, win, lParam),
812 SW_NORMAL);
813 break;
814 case hlp_link_macro:
815 MACRO_ExecuteMacro(link->string);
816 break;
817 default:
818 WINE_FIXME("Unknown link cookie %d\n", link->cookie);
820 ret = TRUE;
822 win->current_link = NULL;
823 break;
825 return ret;
828 /***********************************************************************
830 * WINHELP_MainWndProc
832 static LRESULT CALLBACK WINHELP_MainWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
834 WINHELP_WINDOW *win;
835 WINHELP_BUTTON *button;
836 RECT rect;
837 INT curPos, min, max, dy, keyDelta;
838 HWND hTextWnd;
839 LRESULT ret;
841 if (WINHELP_CheckPopup(hWnd, msg, wParam, lParam, &ret)) return ret;
843 switch (msg)
845 case WM_NCCREATE:
846 win = (WINHELP_WINDOW*) ((LPCREATESTRUCT) lParam)->lpCreateParams;
847 SetWindowLongPtr(hWnd, 0, (ULONG_PTR) win);
848 if (!win->page && Globals.isBook)
849 PostMessage(hWnd, WM_COMMAND, MNID_FILE_OPEN, 0);
850 win->hMainWnd = hWnd;
851 break;
853 case WM_WINDOWPOSCHANGED:
854 WINHELP_LayoutMainWindow((WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0));
855 break;
857 case WM_COMMAND:
858 win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0);
859 switch (wParam)
861 /* Menu FILE */
862 case MNID_FILE_OPEN: MACRO_FileOpen(); break;
863 case MNID_FILE_PRINT: MACRO_Print(); break;
864 case MNID_FILE_SETUP: MACRO_PrinterSetup(); break;
865 case MNID_FILE_EXIT: MACRO_Exit(); break;
867 /* Menu EDIT */
868 case MNID_EDIT_COPYDLG:
869 SendMessage(GetDlgItem(hWnd, CTL_ID_TEXT), WM_COPY, 0, 0);
870 break;
871 case MNID_EDIT_ANNOTATE:MACRO_Annotate(); break;
873 /* Menu Bookmark */
874 case MNID_BKMK_DEFINE: MACRO_BookmarkDefine(); break;
876 /* Menu Help */
877 case MNID_HELP_HELPON: MACRO_HelpOn(); break;
878 case MNID_HELP_HELPTOP: MACRO_HelpOnTop(); break;
879 case MNID_HELP_ABOUT: MACRO_About(); break;
880 case MNID_HELP_WINE: ShellAbout(hWnd, "WINE", "Help", 0); break;
882 /* Context help */
883 case MNID_CTXT_ANNOTATE:MACRO_Annotate(); break;
884 case MNID_CTXT_COPY: MACRO_CopyDialog(); break;
885 case MNID_CTXT_PRINT: MACRO_Print(); break;
886 case MNID_OPTS_HISTORY: MACRO_History(); break;
887 case MNID_OPTS_FONTS_SMALL:
888 case MNID_CTXT_FONTS_SMALL:
889 win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0);
890 if (win->font_scale != 0)
892 win->font_scale = 0;
893 WINHELP_SetupText(GetDlgItem(hWnd, CTL_ID_TEXT), win, 0 /* FIXME */);
895 break;
896 case MNID_OPTS_FONTS_NORMAL:
897 case MNID_CTXT_FONTS_NORMAL:
898 win = (WINHELP_WINDOW*) GetWindowLong(hWnd, 0);
899 if (win->font_scale != 1)
901 win->font_scale = 1;
902 WINHELP_SetupText(GetDlgItem(hWnd, CTL_ID_TEXT), win, 0 /* FIXME */);
904 break;
905 case MNID_OPTS_FONTS_LARGE:
906 case MNID_CTXT_FONTS_LARGE:
907 win = (WINHELP_WINDOW*) GetWindowLong(hWnd, 0);
908 if (win->font_scale != 2)
910 win->font_scale = 2;
911 WINHELP_SetupText(GetDlgItem(hWnd, CTL_ID_TEXT), win, 0 /* FIXME */);
913 break;
914 case MNID_OPTS_HELP_DEFAULT:
915 case MNID_OPTS_HELP_VISIBLE:
916 case MNID_OPTS_HELP_NONVISIBLE:
917 case MNID_OPTS_SYSTEM_COLORS:
918 case MNID_CTXT_HELP_DEFAULT:
919 case MNID_CTXT_HELP_VISIBLE:
920 case MNID_CTXT_HELP_NONVISIBLE:
921 case MNID_CTXT_SYSTEM_COLORS:
922 /* FIXME: NIY */
924 default:
925 /* Buttons */
926 for (button = win->first_button; button; button = button->next)
927 if (wParam == button->wParam) break;
928 if (button)
929 MACRO_ExecuteMacro(button->lpszMacro);
930 else if (!HIWORD(wParam))
931 MessageBox(0, MAKEINTRESOURCE(STID_NOT_IMPLEMENTED),
932 MAKEINTRESOURCE(STID_WHERROR), MB_OK);
933 break;
935 break;
936 /* EPP case WM_DESTROY: */
937 /* EPP if (Globals.hPopupWnd) DestroyWindow(Globals.hPopupWnd); */
938 /* EPP break; */
939 case WM_COPYDATA:
940 return WINHELP_HandleCommand((HWND)wParam, lParam);
942 case WM_CHAR:
943 if (wParam == 3)
945 SendMessage(GetDlgItem(hWnd, CTL_ID_TEXT), WM_COPY, 0, 0);
946 return 0;
948 break;
950 case WM_KEYDOWN:
951 keyDelta = 0;
953 switch (wParam)
955 case VK_UP:
956 case VK_DOWN:
957 keyDelta = GetSystemMetrics(SM_CXVSCROLL);
958 if (wParam == VK_UP)
959 keyDelta = -keyDelta;
961 case VK_PRIOR:
962 case VK_NEXT:
963 win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0);
964 hTextWnd = GetDlgItem(win->hMainWnd, CTL_ID_TEXT);
965 curPos = GetScrollPos(hTextWnd, SB_VERT);
966 GetScrollRange(hTextWnd, SB_VERT, &min, &max);
968 if (keyDelta == 0)
970 GetClientRect(hTextWnd, &rect);
971 keyDelta = (rect.bottom - rect.top) / 2;
972 if (wParam == VK_PRIOR)
973 keyDelta = -keyDelta;
976 curPos += keyDelta;
977 if (curPos > max)
978 curPos = max;
979 else if (curPos < min)
980 curPos = min;
982 dy = GetScrollPos(hTextWnd, SB_VERT) - curPos;
983 SetScrollPos(hTextWnd, SB_VERT, curPos, TRUE);
984 ScrollWindow(hTextWnd, 0, dy, NULL, NULL);
985 UpdateWindow(hTextWnd);
986 return 0;
988 case VK_ESCAPE:
989 MACRO_Exit();
990 return 0;
992 break;
994 case WM_NOTIFY:
995 if (wParam == CTL_ID_TEXT)
997 RECT rc;
999 switch (((NMHDR*)lParam)->code)
1001 case EN_MSGFILTER:
1003 const MSGFILTER* msgf = (const MSGFILTER*)lParam;
1004 switch (msgf->msg)
1006 case WM_KEYUP:
1007 if (msgf->wParam == VK_ESCAPE) DestroyWindow(hWnd);
1008 break;
1009 case WM_RBUTTONDOWN:
1011 HMENU hMenu;
1012 POINT pt;
1014 win = (WINHELP_WINDOW*) GetWindowLong(hWnd, 0);
1015 hMenu = LoadMenu(Globals.hInstance, (LPSTR)CONTEXT_MENU);
1016 switch (win->font_scale)
1018 case 0:
1019 CheckMenuItem(hMenu, MNID_CTXT_FONTS_SMALL,
1020 MF_BYCOMMAND|MF_CHECKED);
1021 break;
1022 default:
1023 WINE_FIXME("Unsupported %d\n", win->font_scale);
1024 case 1:
1025 CheckMenuItem(hMenu, MNID_CTXT_FONTS_NORMAL,
1026 MF_BYCOMMAND|MF_CHECKED);
1027 break;
1028 case 2:
1029 CheckMenuItem(hMenu, MNID_CTXT_FONTS_LARGE,
1030 MF_BYCOMMAND|MF_CHECKED);
1031 break;
1033 pt.x = (int)(short)LOWORD(msgf->lParam);
1034 pt.y = (int)(short)HIWORD(msgf->lParam);
1035 ClientToScreen(msgf->nmhdr.hwndFrom, &pt);
1036 TrackPopupMenu(GetSubMenu(hMenu, 0), TPM_LEFTALIGN|TPM_TOPALIGN,
1037 pt.x, pt.y, 0, hWnd, NULL);
1038 DestroyMenu(hMenu);
1040 break;
1041 default:
1042 return WINHELP_HandleTextMouse((WINHELP_WINDOW*)GetWindowLongPtr(hWnd, 0),
1043 msgf->msg, msgf->lParam);
1046 break;
1048 case EN_REQUESTRESIZE:
1049 rc = ((REQRESIZE*)lParam)->rc;
1050 win = (WINHELP_WINDOW*) GetWindowLong(hWnd, 0);
1051 AdjustWindowRect(&rc, GetWindowLong(win->hMainWnd, GWL_STYLE),
1052 FALSE);
1053 SetWindowPos(win->hMainWnd, HWND_TOP, 0, 0,
1054 rc.right - rc.left, rc.bottom - rc.top,
1055 SWP_NOMOVE | SWP_NOZORDER);
1056 WINHELP_LayoutMainWindow(win);
1057 break;
1060 break;
1062 case WM_INITMENUPOPUP:
1063 win = (WINHELP_WINDOW*) GetWindowLong(hWnd, 0);
1064 CheckMenuItem((HMENU)wParam, MNID_OPTS_FONTS_SMALL,
1065 MF_BYCOMMAND | (win->font_scale == 0) ? MF_CHECKED : 0);
1066 CheckMenuItem((HMENU)wParam, MNID_OPTS_FONTS_NORMAL,
1067 MF_BYCOMMAND | (win->font_scale == 1) ? MF_CHECKED : 0);
1068 CheckMenuItem((HMENU)wParam, MNID_OPTS_FONTS_LARGE,
1069 MF_BYCOMMAND | (win->font_scale == 2) ? MF_CHECKED : 0);
1070 break;
1072 case WM_NCDESTROY:
1074 BOOL bExit;
1075 win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0);
1076 bExit = (Globals.wVersion >= 4 && !lstrcmpi(win->lpszName, "main"));
1077 WINHELP_DeleteWindow(win);
1079 if (bExit) MACRO_Exit();
1080 if (!Globals.win_list)
1081 PostQuitMessage(0);
1083 break;
1085 return DefWindowProc(hWnd, msg, wParam, lParam);
1088 static DWORD CALLBACK WINHELP_RtfStreamIn(DWORD_PTR cookie, BYTE* buff,
1089 LONG cb, LONG* pcb)
1091 struct RtfData* rd = (struct RtfData*)cookie;
1093 if (rd->where >= rd->ptr) return 1;
1094 if (rd->where + cb > rd->ptr)
1095 cb = rd->ptr - rd->where;
1096 memcpy(buff, rd->where, cb);
1097 rd->where += cb;
1098 *pcb = cb;
1099 return 0;
1102 static void WINHELP_SetupText(HWND hTextWnd, WINHELP_WINDOW* win, ULONG relative)
1104 SendMessage(hTextWnd, WM_SETREDRAW, FALSE, 0);
1105 SendMessage(hTextWnd, EM_SETBKGNDCOLOR, 0, (LPARAM)win->info->sr_color);
1106 /* set word-wrap to window size (undocumented) */
1107 SendMessage(hTextWnd, EM_SETTARGETDEVICE, 0, 0);
1108 if (win->page)
1110 struct RtfData rd;
1111 EDITSTREAM es;
1112 unsigned cp = 0;
1113 POINTL ptl;
1114 POINT pt;
1117 if (HLPFILE_BrowsePage(win->page, &rd, win->font_scale, relative))
1119 rd.where = rd.data;
1120 es.dwCookie = (DWORD_PTR)&rd;
1121 es.dwError = 0;
1122 es.pfnCallback = WINHELP_RtfStreamIn;
1124 SendMessageW(hTextWnd, EM_STREAMIN, SF_RTF, (LPARAM)&es);
1125 cp = rd.char_pos_rel;
1127 /* FIXME: else leaking potentially the rd.first_link chain */
1128 HeapFree(GetProcessHeap(), 0, rd.data);
1129 SendMessage(hTextWnd, EM_POSFROMCHAR, (WPARAM)&ptl, cp ? cp - 1 : 0);
1130 pt.x = 0; pt.y = ptl.y;
1131 SendMessage(hTextWnd, EM_SETSCROLLPOS, 0, (LPARAM)&pt);
1133 else
1135 SendMessage(hTextWnd, WM_SETTEXT, 0, (LPARAM)"");
1137 SendMessage(hTextWnd, WM_SETREDRAW, TRUE, 0);
1138 InvalidateRect(hTextWnd, NULL, TRUE);
1141 /***********************************************************************
1143 * WINHELP_ButtonBoxWndProc
1145 static LRESULT CALLBACK WINHELP_ButtonBoxWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
1147 WINDOWPOS *winpos;
1148 WINHELP_WINDOW *win;
1149 WINHELP_BUTTON *button;
1150 SIZE button_size;
1151 INT x, y;
1153 if (WINHELP_CheckPopup(hWnd, msg, wParam, lParam, NULL)) return 0L;
1155 switch (msg)
1157 case WM_WINDOWPOSCHANGING:
1158 winpos = (WINDOWPOS*) lParam;
1159 win = (WINHELP_WINDOW*) GetWindowLongPtr(GetParent(hWnd), 0);
1161 /* Update buttons */
1162 button_size.cx = 0;
1163 button_size.cy = 0;
1164 for (button = win->first_button; button; button = button->next)
1166 HDC hDc;
1167 SIZE textsize;
1168 if (!button->hWnd)
1170 button->hWnd = CreateWindow(STRING_BUTTON, button->lpszName,
1171 WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
1172 0, 0, 0, 0,
1173 hWnd, (HMENU) button->wParam,
1174 Globals.hInstance, 0);
1175 if (button->hWnd)
1177 if (Globals.button_proc == NULL)
1179 NONCLIENTMETRICSW ncm;
1180 Globals.button_proc = (WNDPROC) GetWindowLongPtr(button->hWnd, GWLP_WNDPROC);
1182 ncm.cbSize = sizeof(NONCLIENTMETRICSW);
1183 SystemParametersInfoW(SPI_GETNONCLIENTMETRICS,
1184 sizeof(NONCLIENTMETRICSW), &ncm, 0);
1185 Globals.hButtonFont = CreateFontIndirectW(&ncm.lfMenuFont);
1187 SetWindowLongPtr(button->hWnd, GWLP_WNDPROC, (LONG_PTR) WINHELP_ButtonWndProc);
1188 if (Globals.hButtonFont)
1189 SendMessage(button->hWnd, WM_SETFONT, (WPARAM)Globals.hButtonFont, TRUE);
1192 hDc = GetDC(button->hWnd);
1193 GetTextExtentPoint(hDc, button->lpszName,
1194 lstrlen(button->lpszName), &textsize);
1195 ReleaseDC(button->hWnd, hDc);
1197 button_size.cx = max(button_size.cx, textsize.cx + BUTTON_CX);
1198 button_size.cy = max(button_size.cy, textsize.cy + BUTTON_CY);
1201 x = 0;
1202 y = 0;
1203 for (button = win->first_button; button; button = button->next)
1205 SetWindowPos(button->hWnd, HWND_TOP, x, y, button_size.cx, button_size.cy, 0);
1207 if (x + 2 * button_size.cx <= winpos->cx)
1208 x += button_size.cx;
1209 else
1210 x = 0, y += button_size.cy;
1212 winpos->cy = y + (x ? button_size.cy : 0);
1213 break;
1215 case WM_COMMAND:
1216 SendMessage(GetParent(hWnd), msg, wParam, lParam);
1217 break;
1219 case WM_KEYDOWN:
1220 switch (wParam)
1222 case VK_UP:
1223 case VK_DOWN:
1224 case VK_PRIOR:
1225 case VK_NEXT:
1226 case VK_ESCAPE:
1227 return SendMessage(GetParent(hWnd), msg, wParam, lParam);
1229 break;
1232 return DefWindowProc(hWnd, msg, wParam, lParam);
1235 /***********************************************************************
1237 * WINHELP_ButtonWndProc
1239 static LRESULT CALLBACK WINHELP_ButtonWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
1241 if (WINHELP_CheckPopup(hWnd, msg, wParam, lParam, NULL)) return 0;
1243 if (msg == WM_KEYDOWN)
1245 switch (wParam)
1247 case VK_UP:
1248 case VK_DOWN:
1249 case VK_PRIOR:
1250 case VK_NEXT:
1251 case VK_ESCAPE:
1252 return SendMessage(GetParent(hWnd), msg, wParam, lParam);
1256 return CallWindowProc(Globals.button_proc, hWnd, msg, wParam, lParam);
1259 /******************************************************************
1260 * WINHELP_HistoryWndProc
1264 static LRESULT CALLBACK WINHELP_HistoryWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
1266 WINHELP_WINDOW* win;
1267 PAINTSTRUCT ps;
1268 HDC hDc;
1269 TEXTMETRIC tm;
1270 unsigned int i;
1271 RECT r;
1273 switch (msg)
1275 case WM_NCCREATE:
1276 win = (WINHELP_WINDOW*)((LPCREATESTRUCT)lParam)->lpCreateParams;
1277 SetWindowLongPtr(hWnd, 0, (ULONG_PTR)win);
1278 win->hHistoryWnd = hWnd;
1279 break;
1280 case WM_CREATE:
1281 win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0);
1282 hDc = GetDC(hWnd);
1283 GetTextMetrics(hDc, &tm);
1284 GetWindowRect(hWnd, &r);
1286 r.right = r.left + 30 * tm.tmAveCharWidth;
1287 r.bottom = r.top + (sizeof(Globals.history.set) / sizeof(Globals.history.set[0])) * tm.tmHeight;
1288 AdjustWindowRect(&r, GetWindowLong(hWnd, GWL_STYLE), FALSE);
1289 if (r.left < 0) {r.right -= r.left; r.left = 0;}
1290 if (r.top < 0) {r.bottom -= r.top; r.top = 0;}
1292 MoveWindow(hWnd, r.left, r.top, r.right, r.bottom, TRUE);
1293 ReleaseDC(hWnd, hDc);
1294 break;
1295 case WM_LBUTTONDOWN:
1296 win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0);
1297 hDc = GetDC(hWnd);
1298 GetTextMetrics(hDc, &tm);
1299 i = HIWORD(lParam) / tm.tmHeight;
1300 if (i < Globals.history.index)
1301 WINHELP_CreateHelpWindow(&Globals.history.set[i], SW_SHOW, TRUE);
1302 ReleaseDC(hWnd, hDc);
1303 break;
1304 case WM_PAINT:
1305 hDc = BeginPaint(hWnd, &ps);
1306 win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0);
1307 GetTextMetrics(hDc, &tm);
1309 for (i = 0; i < Globals.history.index; i++)
1311 if (Globals.history.set[i].page->file == Globals.active_win->page->file)
1313 TextOut(hDc, 0, i * tm.tmHeight,
1314 Globals.history.set[i].page->lpszTitle,
1315 strlen(Globals.history.set[i].page->lpszTitle));
1317 else
1319 char buffer[1024];
1320 const char* ptr1;
1321 const char* ptr2;
1322 unsigned len;
1324 ptr1 = strrchr(Globals.history.set[i].page->file->lpszPath, '\\');
1325 if (!ptr1) ptr1 = Globals.history.set[i].page->file->lpszPath;
1326 else ptr1++;
1327 ptr2 = strrchr(ptr1, '.');
1328 len = ptr2 ? ptr2 - ptr1 : strlen(ptr1);
1329 if (len > sizeof(buffer)) len = sizeof(buffer);
1330 memcpy(buffer, ptr1, len);
1331 if (len < sizeof(buffer)) buffer[len++] = ':';
1332 strncpy(&buffer[len], Globals.history.set[i].page->lpszTitle, sizeof(buffer) - len);
1333 buffer[sizeof(buffer) - 1] = '\0';
1334 TextOut(hDc, 0, i * tm.tmHeight, buffer, strlen(buffer));
1337 EndPaint(hWnd, &ps);
1338 break;
1339 case WM_DESTROY:
1340 win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0);
1341 if (hWnd == win->hHistoryWnd)
1342 win->hHistoryWnd = 0;
1343 break;
1345 return DefWindowProc(hWnd, msg, wParam, lParam);
1348 /***********************************************************************
1350 * WINHELP_ShadowWndProc
1352 static LRESULT CALLBACK WINHELP_ShadowWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
1354 if (WINHELP_CheckPopup(hWnd, msg, wParam, lParam, NULL)) return 0;
1355 return WINHELP_CheckPopup(hWnd, msg, wParam, lParam, NULL) ? 0L : DefWindowProc(hWnd, msg, wParam, lParam);
1358 /***********************************************************************
1360 * WINHELP_CheckPopup
1362 static BOOL WINHELP_CheckPopup(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, LRESULT* lret)
1364 HWND hPopup;
1366 if (!Globals.active_popup) return FALSE;
1368 switch (msg)
1370 case WM_NOTIFY:
1372 MSGFILTER* msgf = (MSGFILTER*)lParam;
1373 if (msgf->nmhdr.code == EN_MSGFILTER)
1375 if (!WINHELP_CheckPopup(hWnd, msgf->msg, msgf->wParam, msgf->lParam, NULL))
1376 return FALSE;
1377 if (lret) *lret = 1;
1378 return TRUE;
1381 break;
1382 case WM_ACTIVATE:
1383 if (wParam != WA_INACTIVE || (HWND)lParam == Globals.active_win->hMainWnd ||
1384 (HWND)lParam == Globals.active_popup->hMainWnd ||
1385 GetWindow((HWND)lParam, GW_OWNER) == Globals.active_win->hMainWnd)
1386 break;
1387 case WM_LBUTTONUP:
1388 case WM_LBUTTONDOWN:
1389 if (WINHELP_HandleTextMouse(Globals.active_popup, msg, lParam) && msg == WM_LBUTTONDOWN)
1390 return FALSE;
1391 /* fall through */
1392 case WM_MBUTTONDOWN:
1393 case WM_RBUTTONDOWN:
1394 case WM_NCLBUTTONDOWN:
1395 case WM_NCMBUTTONDOWN:
1396 case WM_NCRBUTTONDOWN:
1397 hPopup = Globals.active_popup->hMainWnd;
1398 Globals.active_popup = NULL;
1399 DestroyWindow(hPopup);
1400 return TRUE;
1402 return FALSE;
1405 /******************************************************************
1406 * WINHELP_DeleteButtons
1409 static void WINHELP_DeleteButtons(WINHELP_WINDOW* win)
1411 WINHELP_BUTTON* b;
1412 WINHELP_BUTTON* bp;
1414 for (b = win->first_button; b; b = bp)
1416 DestroyWindow(b->hWnd);
1417 bp = b->next;
1418 HeapFree(GetProcessHeap(), 0, b);
1420 win->first_button = NULL;
1423 /******************************************************************
1424 * WINHELP_DeleteBackSet
1427 void WINHELP_DeleteBackSet(WINHELP_WINDOW* win)
1429 unsigned int i;
1431 for (i = 0; i < win->back.index; i++)
1433 HLPFILE_FreeHlpFile(win->back.set[i].page->file);
1434 win->back.set[i].page = NULL;
1436 win->back.index = 0;
1439 /******************************************************************
1440 * WINHELP_DeletePageLinks
1443 static void WINHELP_DeletePageLinks(HLPFILE_PAGE* page)
1445 HLPFILE_LINK* curr;
1446 HLPFILE_LINK* next;
1448 for (curr = page->first_link; curr; curr = next)
1450 next = curr->next;
1451 HeapFree(GetProcessHeap(), 0, curr);
1455 /***********************************************************************
1457 * WINHELP_DeleteWindow
1459 static void WINHELP_DeleteWindow(WINHELP_WINDOW* win)
1461 WINHELP_WINDOW** w;
1463 for (w = &Globals.win_list; *w; w = &(*w)->next)
1465 if (*w == win)
1467 *w = win->next;
1468 break;
1472 if (Globals.active_win == win)
1474 Globals.active_win = Globals.win_list;
1475 if (Globals.win_list)
1476 SetActiveWindow(Globals.win_list->hMainWnd);
1479 if (win == Globals.active_popup)
1480 Globals.active_popup = NULL;
1482 WINHELP_DeleteButtons(win);
1484 if (win->page) WINHELP_DeletePageLinks(win->page);
1485 if (win->hShadowWnd) DestroyWindow(win->hShadowWnd);
1486 if (win->hHistoryWnd) DestroyWindow(win->hHistoryWnd);
1488 DeleteObject(win->hBrush);
1490 WINHELP_DeleteBackSet(win);
1492 if (win->page) HLPFILE_FreeHlpFile(win->page->file);
1493 HeapFree(GetProcessHeap(), 0, win);
1496 /***********************************************************************
1498 * WINHELP_InitFonts
1500 static void WINHELP_InitFonts(HWND hWnd)
1502 WINHELP_WINDOW *win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0);
1503 LOGFONT logfontlist[] = {
1504 {-10, 0, 0, 0, 400, 0, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 32, "Helv"},
1505 {-12, 0, 0, 0, 700, 0, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 32, "Helv"},
1506 {-12, 0, 0, 0, 700, 0, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 32, "Helv"},
1507 {-12, 0, 0, 0, 400, 0, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 32, "Helv"},
1508 {-12, 0, 0, 0, 700, 0, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 32, "Helv"},
1509 {-10, 0, 0, 0, 700, 0, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 32, "Helv"},
1510 { -8, 0, 0, 0, 400, 0, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 32, "Helv"}};
1511 #define FONTS_LEN (sizeof(logfontlist)/sizeof(*logfontlist))
1513 static HFONT fonts[FONTS_LEN];
1514 static BOOL init = 0;
1516 win->fonts_len = FONTS_LEN;
1517 win->fonts = fonts;
1519 if (!init)
1521 UINT i;
1523 for (i = 0; i < FONTS_LEN; i++)
1525 fonts[i] = CreateFontIndirect(&logfontlist[i]);
1528 init = 1;
1532 /***********************************************************************
1534 * WINHELP_MessageBoxIDS_s
1536 INT WINHELP_MessageBoxIDS_s(UINT ids_text, LPCSTR str, UINT ids_title, WORD type)
1538 CHAR text[MAX_STRING_LEN];
1539 CHAR newtext[MAX_STRING_LEN + MAX_PATH];
1541 LoadString(Globals.hInstance, ids_text, text, sizeof(text));
1542 wsprintf(newtext, text, str);
1544 return MessageBox(0, newtext, MAKEINTRESOURCE(ids_title), type);
1547 /**************************************************************************
1548 * cb_KWBTree
1550 * HLPFILE_BPTreeCallback enumeration function for '|KWBTREE' internal file.
1553 static void cb_KWBTree(void *p, void **next, void *cookie)
1555 HWND hListWnd = (HWND)cookie;
1556 int count;
1558 WINE_TRACE("Adding '%s' to search list\n", (char *)p);
1559 SendMessage(hListWnd, LB_INSERTSTRING, -1, (LPARAM)p);
1560 count = SendMessage(hListWnd, LB_GETCOUNT, 0, 0);
1561 SendMessage(hListWnd, LB_SETITEMDATA, count-1, (LPARAM)p);
1562 *next = (char*)p + strlen((char*)p) + 7;
1565 struct index_data
1567 HLPFILE* hlpfile;
1568 BOOL jump;
1569 ULONG offset;
1572 /**************************************************************************
1573 * WINHELP_IndexDlgProc
1575 * Index dialog callback function.
1577 * nResult passed to EndDialog:
1578 * 1: CANCEL button
1579 * >1: valid offset value +2.
1580 * EndDialog itself can return 0 (error).
1582 INT_PTR CALLBACK WINHELP_IndexDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
1584 static struct index_data* id;
1585 int sel;
1587 switch (msg)
1589 case WM_INITDIALOG:
1590 id = (struct index_data*)((PROPSHEETPAGE*)lParam)->lParam;
1591 HLPFILE_BPTreeEnum(id->hlpfile->kwbtree, cb_KWBTree,
1592 GetDlgItem(hWnd, IDC_INDEXLIST));
1593 id->jump = FALSE;
1594 id->offset = 1;
1595 return TRUE;
1596 case WM_COMMAND:
1597 switch (HIWORD(wParam))
1599 case LBN_DBLCLK:
1600 if (LOWORD(wParam) == IDC_INDEXLIST)
1601 SendMessage(GetParent(hWnd), PSM_PRESSBUTTON, PSBTN_OK, 0);
1602 break;
1604 break;
1605 case WM_NOTIFY:
1606 switch (((NMHDR*)lParam)->code)
1608 case PSN_APPLY:
1609 sel = SendDlgItemMessage(hWnd, IDC_INDEXLIST, LB_GETCURSEL, 0, 0);
1610 if (sel != LB_ERR)
1612 BYTE *p;
1613 int count;
1615 p = (BYTE*)SendDlgItemMessage(hWnd, IDC_INDEXLIST,
1616 LB_GETITEMDATA, sel, 0);
1617 count = *(short*)((char *)p + strlen((char *)p) + 1);
1618 if (count > 1)
1620 MessageBox(hWnd, "count > 1 not supported yet", "Error", MB_OK | MB_ICONSTOP);
1621 SetWindowLongPtr(hWnd, DWLP_MSGRESULT, PSNRET_INVALID);
1622 return TRUE;
1624 id->offset = *(ULONG*)((char *)p + strlen((char *)p) + 3);
1625 id->offset = *(long*)(id->hlpfile->kwdata + id->offset + 9);
1626 if (id->offset == 0xFFFFFFFF)
1628 MessageBox(hWnd, "macro keywords not supported yet", "Error", MB_OK | MB_ICONSTOP);
1629 SetWindowLongPtr(hWnd, DWLP_MSGRESULT, PSNRET_INVALID);
1630 return TRUE;
1632 id->jump = TRUE;
1633 SetWindowLongPtr(hWnd, DWLP_MSGRESULT, PSNRET_NOERROR);
1635 return TRUE;
1636 default:
1637 return FALSE;
1639 break;
1640 default:
1641 break;
1643 return FALSE;
1646 /**************************************************************************
1647 * WINHELP_SearchDlgProc
1650 INT_PTR CALLBACK WINHELP_SearchDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
1652 static struct index_data* id;
1654 switch (msg)
1656 case WM_INITDIALOG:
1657 id = (struct index_data*)((PROPSHEETPAGE*)lParam)->lParam;
1658 return TRUE;
1659 case WM_NOTIFY:
1660 switch (((NMHDR*)lParam)->code)
1662 case PSN_APPLY:
1663 SetWindowLongPtr(hWnd, DWLP_MSGRESULT, PSNRET_NOERROR);
1664 return TRUE;
1665 default:
1666 return FALSE;
1668 break;
1669 default:
1670 break;
1672 return FALSE;
1675 /**************************************************************************
1676 * WINHELP_CreateIndexWindow
1678 * Displays a dialog with keywords of current help file.
1681 BOOL WINHELP_CreateIndexWindow(BOOL is_search)
1683 HPROPSHEETPAGE psPage[3];
1684 PROPSHEETPAGE psp;
1685 PROPSHEETHEADER psHead;
1686 struct index_data id;
1687 char buf[256];
1689 if (Globals.active_win && Globals.active_win->page && Globals.active_win->page->file)
1690 id.hlpfile = Globals.active_win->page->file;
1691 else
1692 return FALSE;
1694 if (id.hlpfile->kwbtree == NULL)
1696 WINE_TRACE("No index provided\n");
1697 return FALSE;
1700 InitCommonControls();
1702 id.jump = FALSE;
1703 memset(&psp, 0, sizeof(psp));
1704 psp.dwSize = sizeof(psp);
1705 psp.dwFlags = 0;
1706 psp.hInstance = Globals.hInstance;
1708 psp.u.pszTemplate = MAKEINTRESOURCE(IDD_INDEX);
1709 psp.lParam = (LPARAM)&id;
1710 psp.pfnDlgProc = WINHELP_IndexDlgProc;
1711 psPage[0] = CreatePropertySheetPage(&psp);
1713 psp.u.pszTemplate = MAKEINTRESOURCE(IDD_SEARCH);
1714 psp.lParam = (LPARAM)&id;
1715 psp.pfnDlgProc = WINHELP_SearchDlgProc;
1716 psPage[1] = CreatePropertySheetPage(&psp);
1718 memset(&psHead, 0, sizeof(psHead));
1719 psHead.dwSize = sizeof(psHead);
1721 LoadString(Globals.hInstance, STID_PSH_INDEX, buf, sizeof(buf));
1722 strcat(buf, Globals.active_win->info->caption);
1724 psHead.pszCaption = buf;
1725 psHead.nPages = 2;
1726 psHead.u2.nStartPage = is_search ? 1 : 0;
1727 psHead.hwndParent = Globals.active_win->hMainWnd;
1728 psHead.u3.phpage = psPage;
1729 psHead.dwFlags = PSH_NOAPPLYNOW;
1731 PropertySheet(&psHead);
1732 if (id.jump)
1734 WINE_TRACE("got %d as an offset\n", id.offset);
1735 WINHELP_OpenHelpWindow(HLPFILE_PageByOffset, id.hlpfile, id.offset,
1736 Globals.active_win->info, SW_NORMAL);
1738 return TRUE;