hhctrl.ocx: Call PostQuitMessage only in hh.exe process.
[wine] / dlls / hhctrl.ocx / help.c
1 /*
2  * Help Viewer Implementation
3  *
4  * Copyright 2005 James Hawkins
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include "hhctrl.h"
22
23 #include "wingdi.h"
24 #include "commctrl.h"
25 #include "wininet.h"
26
27 #include "wine/debug.h"
28
29 #include "resource.h"
30
31 WINE_DEFAULT_DEBUG_CHANNEL(htmlhelp);
32
33 static LRESULT Help_OnSize(HWND hWnd);
34
35 /* Window type defaults */
36
37 #define WINTYPE_DEFAULT_X           280
38 #define WINTYPE_DEFAULT_Y           100
39 #define WINTYPE_DEFAULT_WIDTH       740
40 #define WINTYPE_DEFAULT_HEIGHT      640
41 #define WINTYPE_DEFAULT_NAVWIDTH    250
42
43 static const WCHAR szEmpty[] = {0};
44
45 /* Loads a string from the resource file */
46 static LPWSTR HH_LoadString(DWORD dwID)
47 {
48     LPWSTR string = NULL;
49     int iSize;
50
51     iSize = LoadStringW(hhctrl_hinstance, dwID, NULL, 0);
52     iSize += 2; /* some strings (tab text) needs double-null termination */
53
54     string = hhctrl_alloc(iSize * sizeof(WCHAR));
55     LoadStringW(hhctrl_hinstance, dwID, string, iSize);
56
57     return string;
58 }
59
60 BOOL NavigateToChm(HHInfo *info, LPCWSTR file, LPCWSTR index)
61 {
62     WCHAR buf[INTERNET_MAX_URL_LENGTH];
63     WCHAR full_path[MAX_PATH];
64     VARIANT url;
65
66     static const WCHAR url_format[] =
67         {'m','k',':','@','M','S','I','T','S','t','o','r','e',':','%','s',':',':','/','%','s',0};
68
69     if (!info->web_browser)
70         return FALSE;
71
72     if(!GetFullPathNameW(file, sizeof(full_path), full_path, NULL)) {
73         WARN("GetFullPathName failed: %u\n", GetLastError());
74         return FALSE;
75     }
76
77     wsprintfW(buf, url_format, full_path, index);
78
79     V_VT(&url) = VT_BSTR;
80     V_BSTR(&url) = SysAllocString(buf);
81
82     IWebBrowser2_Navigate2(info->web_browser, &url, 0, 0, 0, 0);
83     VariantClear(&url);
84
85     return TRUE;
86 }
87
88 /* Size Bar */
89
90 #define SIZEBAR_WIDTH   4
91
92 static const WCHAR szSizeBarClass[] = {
93     'H','H',' ','S','i','z','e','B','a','r',0
94 };
95
96 /* Draw the SizeBar */
97 static void SB_OnPaint(HWND hWnd)
98 {
99     PAINTSTRUCT ps;
100     HDC hdc;
101     RECT rc;
102     
103     hdc = BeginPaint(hWnd, &ps);
104
105     GetClientRect(hWnd, &rc);
106
107     /* dark frame */
108     rc.right += 1;
109     rc.bottom -= 1;
110     FrameRect(hdc, &rc, GetStockObject(GRAY_BRUSH));
111
112     /* white highlight */
113     SelectObject(hdc, GetStockObject(WHITE_PEN));
114     MoveToEx(hdc, rc.right, 1, NULL);
115     LineTo(hdc, 1, 1);
116     LineTo(hdc, 1, rc.bottom - 1);
117
118     
119     MoveToEx(hdc, 0, rc.bottom, NULL);
120     LineTo(hdc, rc.right, rc.bottom);
121
122     EndPaint(hWnd, &ps);
123 }
124
125 static void SB_OnLButtonDown(HWND hWnd, WPARAM wParam, LPARAM lParam)
126 {
127     SetCapture(hWnd);
128 }
129
130 static void SB_OnLButtonUp(HWND hWnd, WPARAM wParam, LPARAM lParam)
131 {
132     HHInfo *pHHInfo = (HHInfo *)GetWindowLongPtrW(hWnd, GWLP_USERDATA);
133     POINT pt;
134
135     pt.x = (short)LOWORD(lParam);
136     pt.y = (short)HIWORD(lParam);
137
138     /* update the window sizes */
139     pHHInfo->WinType.iNavWidth += pt.x;
140     Help_OnSize(hWnd);
141
142     ReleaseCapture();
143 }
144
145 static void SB_OnMouseMove(HWND hWnd, WPARAM wParam, LPARAM lParam)
146 {
147     /* ignore WM_MOUSEMOVE if not dragging the SizeBar */
148     if (!(wParam & MK_LBUTTON))
149         return;
150 }
151
152 static LRESULT CALLBACK SizeBar_WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
153 {
154     switch (message)
155     {
156         case WM_LBUTTONDOWN:
157             SB_OnLButtonDown(hWnd, wParam, lParam);
158             break;
159         case WM_LBUTTONUP:
160             SB_OnLButtonUp(hWnd, wParam, lParam);
161             break;
162         case WM_MOUSEMOVE:
163             SB_OnMouseMove(hWnd, wParam, lParam);
164             break;
165         case WM_PAINT:
166             SB_OnPaint(hWnd);
167             break;
168         default:
169             return DefWindowProcW(hWnd, message, wParam, lParam);
170     }
171
172     return 0;
173 }
174
175 static void HH_RegisterSizeBarClass(HHInfo *pHHInfo)
176 {
177     WNDCLASSEXW wcex;
178
179     wcex.cbSize         = sizeof(WNDCLASSEXW);
180     wcex.style          = 0;
181     wcex.lpfnWndProc    = SizeBar_WndProc;
182     wcex.cbClsExtra     = 0;
183     wcex.cbWndExtra     = 0;
184     wcex.hInstance      = hhctrl_hinstance;
185     wcex.hIcon          = LoadIconW(NULL, (LPCWSTR)IDI_APPLICATION);
186     wcex.hCursor        = LoadCursorW(NULL, (LPCWSTR)IDC_SIZEWE);
187     wcex.hbrBackground  = (HBRUSH)(COLOR_MENU + 1);
188     wcex.lpszMenuName   = NULL;
189     wcex.lpszClassName  = szSizeBarClass;
190     wcex.hIconSm        = LoadIconW(NULL, (LPCWSTR)IDI_APPLICATION);
191
192     RegisterClassExW(&wcex);
193 }
194
195 static void SB_GetSizeBarRect(HHInfo *info, RECT *rc)
196 {
197     RECT rectWND, rectTB, rectNP;
198
199     GetClientRect(info->WinType.hwndHelp, &rectWND);
200     GetClientRect(info->WinType.hwndToolBar, &rectTB);
201     GetClientRect(info->WinType.hwndNavigation, &rectNP);
202
203     rc->left = rectNP.right;
204     rc->top = rectTB.bottom;
205     rc->bottom = rectWND.bottom - rectTB.bottom;
206     rc->right = SIZEBAR_WIDTH;
207 }
208
209 static BOOL HH_AddSizeBar(HHInfo *pHHInfo)
210 {
211     HWND hWnd;
212     HWND hwndParent = pHHInfo->WinType.hwndHelp;
213     DWORD dwStyles = WS_CHILDWINDOW | WS_VISIBLE | WS_OVERLAPPED;
214     DWORD dwExStyles = WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR;
215     RECT rc;
216
217     SB_GetSizeBarRect(pHHInfo, &rc);
218
219     hWnd = CreateWindowExW(dwExStyles, szSizeBarClass, szEmpty, dwStyles,
220                            rc.left, rc.top, rc.right, rc.bottom,
221                            hwndParent, NULL, hhctrl_hinstance, NULL);
222     if (!hWnd)
223         return FALSE;
224
225     /* store the pointer to the HH info struct */
226     SetWindowLongPtrW(hWnd, GWLP_USERDATA, (LONG_PTR)pHHInfo);
227
228     pHHInfo->hwndSizeBar = hWnd;
229     return TRUE;
230 }
231
232 /* Child Window */
233
234 static const WCHAR szChildClass[] = {
235     'H','H',' ','C','h','i','l','d',0
236 };
237
238 static void Child_OnPaint(HWND hWnd)
239 {
240     PAINTSTRUCT ps;
241     HDC hdc;
242     RECT rc;
243
244     hdc = BeginPaint(hWnd, &ps);
245
246     /* Only paint the Navigation pane, identified by the fact
247      * that it has a child window
248      */
249     if (GetWindow(hWnd, GW_CHILD))
250     {
251         GetClientRect(hWnd, &rc);
252
253         /* set the border color */
254         SelectObject(hdc, GetStockObject(DC_PEN));
255         SetDCPenColor(hdc, GetSysColor(COLOR_BTNSHADOW));
256
257         /* Draw the top border */
258         LineTo(hdc, rc.right, 0);
259
260         SelectObject(hdc, GetStockObject(WHITE_PEN));
261         MoveToEx(hdc, 0, 1, NULL);
262         LineTo(hdc, rc.right, 1);
263     }
264
265     EndPaint(hWnd, &ps);
266 }
267
268 static LRESULT CALLBACK Child_WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
269 {
270     switch (message)
271     {
272         case WM_PAINT:
273             Child_OnPaint(hWnd);
274             break;
275         default:
276             return DefWindowProcW(hWnd, message, wParam, lParam);
277     }
278
279     return 0;
280 }
281
282 static void HH_RegisterChildWndClass(HHInfo *pHHInfo)
283 {
284     WNDCLASSEXW wcex;
285
286     wcex.cbSize         = sizeof(WNDCLASSEXW);
287     wcex.style          = 0;
288     wcex.lpfnWndProc    = Child_WndProc;
289     wcex.cbClsExtra     = 0;
290     wcex.cbWndExtra     = 0;
291     wcex.hInstance      = hhctrl_hinstance;
292     wcex.hIcon          = LoadIconW(NULL, (LPCWSTR)IDI_APPLICATION);
293     wcex.hCursor        = LoadCursorW(NULL, (LPCWSTR)IDC_ARROW);
294     wcex.hbrBackground  = (HBRUSH)(COLOR_BTNFACE + 1);
295     wcex.lpszMenuName   = NULL;
296     wcex.lpszClassName  = szChildClass;
297     wcex.hIconSm        = LoadIconW(NULL, (LPCWSTR)IDI_APPLICATION);
298
299     RegisterClassExW(&wcex);
300 }
301
302 /* Toolbar */
303
304 #define ICON_SIZE   20
305
306 static void TB_OnClick(HWND hWnd, DWORD dwID)
307 {
308     HHInfo *info = (HHInfo *)GetWindowLongPtrW(hWnd, GWLP_USERDATA);
309
310     switch (dwID)
311     {
312         case IDTB_STOP:
313             DoPageAction(info, WB_STOP);
314             break;
315         case IDTB_REFRESH:
316             DoPageAction(info, WB_REFRESH);
317             break;
318         case IDTB_BACK:
319             DoPageAction(info, WB_GOBACK);
320             break;
321         case IDTB_HOME:
322             NavigateToChm(info, info->pCHMInfo->szFile, info->WinType.pszHome);
323             break;
324         case IDTB_FORWARD:
325             DoPageAction(info, WB_GOFORWARD);
326             break;
327         case IDTB_EXPAND:
328         case IDTB_CONTRACT:
329         case IDTB_SYNC:
330         case IDTB_PRINT:
331         case IDTB_OPTIONS:
332         case IDTB_BROWSE_FWD:
333         case IDTB_BROWSE_BACK:
334         case IDTB_JUMP1:
335         case IDTB_JUMP2:
336         case IDTB_CUSTOMIZE:
337         case IDTB_ZOOM:
338         case IDTB_TOC_NEXT:
339         case IDTB_TOC_PREV:
340             break;
341     }
342 }
343
344 static void TB_AddButton(TBBUTTON *pButtons, DWORD dwIndex, DWORD dwID)
345 {
346     /* FIXME: Load the correct button bitmaps */
347     pButtons[dwIndex].iBitmap = STD_PRINT;
348     pButtons[dwIndex].idCommand = dwID;
349     pButtons[dwIndex].fsState = TBSTATE_ENABLED;
350     pButtons[dwIndex].fsStyle = BTNS_BUTTON;
351     pButtons[dwIndex].dwData = 0;
352     pButtons[dwIndex].iString = 0;
353 }
354
355 static void TB_AddButtonsFromFlags(TBBUTTON *pButtons, DWORD dwButtonFlags, LPDWORD pdwNumButtons)
356 {
357     *pdwNumButtons = 0;
358
359     if (dwButtonFlags & HHWIN_BUTTON_EXPAND)
360         TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_EXPAND);
361
362     if (dwButtonFlags & HHWIN_BUTTON_BACK)
363         TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_BACK);
364
365     if (dwButtonFlags & HHWIN_BUTTON_FORWARD)
366         TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_FORWARD);
367
368     if (dwButtonFlags & HHWIN_BUTTON_STOP)
369         TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_STOP);
370
371     if (dwButtonFlags & HHWIN_BUTTON_REFRESH)
372         TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_REFRESH);
373
374     if (dwButtonFlags & HHWIN_BUTTON_HOME)
375         TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_HOME);
376
377     if (dwButtonFlags & HHWIN_BUTTON_SYNC)
378         TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_SYNC);
379
380     if (dwButtonFlags & HHWIN_BUTTON_OPTIONS)
381         TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_OPTIONS);
382
383     if (dwButtonFlags & HHWIN_BUTTON_PRINT)
384         TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_PRINT);
385
386     if (dwButtonFlags & HHWIN_BUTTON_JUMP1)
387         TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_JUMP1);
388
389     if (dwButtonFlags & HHWIN_BUTTON_JUMP2)
390         TB_AddButton(pButtons,(*pdwNumButtons)++, IDTB_JUMP2);
391
392     if (dwButtonFlags & HHWIN_BUTTON_ZOOM)
393         TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_ZOOM);
394
395     if (dwButtonFlags & HHWIN_BUTTON_TOC_NEXT)
396         TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_TOC_NEXT);
397
398     if (dwButtonFlags & HHWIN_BUTTON_TOC_PREV)
399         TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_TOC_PREV);
400 }
401
402 static BOOL HH_AddToolbar(HHInfo *pHHInfo)
403 {
404     HWND hToolbar;
405     HWND hwndParent = pHHInfo->WinType.hwndHelp;
406     DWORD toolbarFlags;
407     TBBUTTON buttons[IDTB_TOC_PREV - IDTB_EXPAND];
408     TBADDBITMAP tbAB;
409     DWORD dwStyles, dwExStyles;
410     DWORD dwNumButtons, dwIndex;
411
412     if (pHHInfo->WinType.fsWinProperties & HHWIN_PARAM_TB_FLAGS)
413         toolbarFlags = pHHInfo->WinType.fsToolBarFlags;
414     else
415         toolbarFlags = HHWIN_DEF_BUTTONS;
416
417     TB_AddButtonsFromFlags(buttons, toolbarFlags, &dwNumButtons);
418
419     dwStyles = WS_CHILDWINDOW | WS_VISIBLE | TBSTYLE_FLAT |
420                TBSTYLE_WRAPABLE | TBSTYLE_TOOLTIPS | CCS_NODIVIDER;
421     dwExStyles = WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR;
422
423     hToolbar = CreateWindowExW(dwExStyles, TOOLBARCLASSNAMEW, NULL, dwStyles,
424                                0, 0, 0, 0, hwndParent, NULL,
425                                hhctrl_hinstance, NULL);
426     if (!hToolbar)
427         return FALSE;
428
429     SendMessageW(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(ICON_SIZE, ICON_SIZE));
430     SendMessageW(hToolbar, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
431     SendMessageW(hToolbar, WM_SETFONT, (WPARAM)pHHInfo->hFont, TRUE);
432
433     /* FIXME: Load correct icons for all buttons */
434     tbAB.hInst = HINST_COMMCTRL;
435     tbAB.nID = IDB_STD_LARGE_COLOR;
436     SendMessageW(hToolbar, TB_ADDBITMAP, 0, (LPARAM)&tbAB);
437
438     for (dwIndex = 0; dwIndex < dwNumButtons; dwIndex++)
439     {
440         LPWSTR szBuf = HH_LoadString(buttons[dwIndex].idCommand);
441         DWORD dwLen = strlenW(szBuf);
442         szBuf[dwLen + 2] = 0; /* Double-null terminate */
443
444         buttons[dwIndex].iString = (DWORD)SendMessageW(hToolbar, TB_ADDSTRINGW, 0, (LPARAM)szBuf);
445         hhctrl_free(szBuf);
446     }
447
448     SendMessageW(hToolbar, TB_ADDBUTTONSW, dwNumButtons, (LPARAM)&buttons);
449     SendMessageW(hToolbar, TB_AUTOSIZE, 0, 0);
450     ShowWindow(hToolbar, SW_SHOW);
451
452     pHHInfo->WinType.hwndToolBar = hToolbar;
453     return TRUE;
454 }
455
456 /* Navigation Pane */
457
458 #define TAB_TOP_PADDING     8
459 #define TAB_RIGHT_PADDING   4
460
461 static void NP_GetNavigationRect(HHInfo *pHHInfo, RECT *rc)
462 {
463     HWND hwndParent = pHHInfo->WinType.hwndHelp;
464     HWND hwndToolbar = pHHInfo->WinType.hwndToolBar;
465     RECT rectWND, rectTB;
466
467     GetClientRect(hwndParent, &rectWND);
468     GetClientRect(hwndToolbar, &rectTB);
469
470     rc->left = 0;
471     rc->top = rectTB.bottom;
472     rc->bottom = rectWND.bottom - rectTB.bottom;
473
474     if (!(pHHInfo->WinType.fsValidMembers & HHWIN_PARAM_NAV_WIDTH) &&
475           pHHInfo->WinType.iNavWidth == 0)
476     {
477         pHHInfo->WinType.iNavWidth = WINTYPE_DEFAULT_NAVWIDTH;
478     }
479
480     rc->right = pHHInfo->WinType.iNavWidth;
481 }
482
483 static void NP_CreateTab(HINSTANCE hInstance, HWND hwndTabCtrl, DWORD dwStrID, DWORD dwIndex)
484 {
485     TCITEMW tie;
486     LPWSTR tabText = HH_LoadString(dwStrID);
487
488     tie.mask = TCIF_TEXT;
489     tie.pszText = tabText;
490
491     SendMessageW( hwndTabCtrl, TCM_INSERTITEMW, dwIndex, (LPARAM)&tie );
492     hhctrl_free(tabText);
493 }
494
495 static BOOL HH_AddNavigationPane(HHInfo *info)
496 {
497     HWND hWnd, hwndTabCtrl;
498     HWND hwndParent = info->WinType.hwndHelp;
499     DWORD dwStyles = WS_CHILDWINDOW | WS_VISIBLE;
500     DWORD dwExStyles = WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR;
501     DWORD dwIndex = 0;
502     RECT rc;
503
504     NP_GetNavigationRect(info, &rc);
505
506     hWnd = CreateWindowExW(dwExStyles, szChildClass, szEmpty, dwStyles,
507                            rc.left, rc.top, rc.right, rc.bottom,
508                            hwndParent, NULL, hhctrl_hinstance, NULL);
509     if (!hWnd)
510         return FALSE;
511
512     hwndTabCtrl = CreateWindowExW(dwExStyles, WC_TABCONTROLW, szEmpty, dwStyles,
513                                   0, TAB_TOP_PADDING,
514                                   rc.right - TAB_RIGHT_PADDING,
515                                   rc.bottom - TAB_TOP_PADDING,
516                                   hWnd, NULL, hhctrl_hinstance, NULL);
517     if (!hwndTabCtrl)
518         return FALSE;
519
520     if (*info->WinType.pszToc)
521         NP_CreateTab(hhctrl_hinstance, hwndTabCtrl, IDS_CONTENTS, dwIndex++);
522
523     if (*info->WinType.pszIndex)
524         NP_CreateTab(hhctrl_hinstance, hwndTabCtrl, IDS_INDEX, dwIndex++);
525
526     if (info->WinType.fsWinProperties & HHWIN_PROP_TAB_SEARCH)
527         NP_CreateTab(hhctrl_hinstance, hwndTabCtrl, IDS_SEARCH, dwIndex++);
528
529     if (info->WinType.fsWinProperties & HHWIN_PROP_TAB_FAVORITES)
530         NP_CreateTab(hhctrl_hinstance, hwndTabCtrl, IDS_FAVORITES, dwIndex++);
531
532     SendMessageW(hwndTabCtrl, WM_SETFONT, (WPARAM)info->hFont, TRUE);
533
534     info->hwndTabCtrl = hwndTabCtrl;
535     info->WinType.hwndNavigation = hWnd;
536     return TRUE;
537 }
538
539 /* HTML Pane */
540
541 static void HP_GetHTMLRect(HHInfo *info, RECT *rc)
542 {
543     RECT rectTB, rectWND, rectNP, rectSB;
544
545     GetClientRect(info->WinType.hwndHelp, &rectWND);
546     GetClientRect(info->WinType.hwndToolBar, &rectTB);
547     GetClientRect(info->WinType.hwndNavigation, &rectNP);
548     GetClientRect(info->hwndSizeBar, &rectSB);
549
550     rc->left = rectNP.right + rectSB.right;
551     rc->top = rectTB.bottom;
552     rc->right = rectWND.right - rc->left;
553     rc->bottom = rectWND.bottom - rectTB.bottom;
554 }
555
556 static BOOL HH_AddHTMLPane(HHInfo *pHHInfo)
557 {
558     HWND hWnd;
559     HWND hwndParent = pHHInfo->WinType.hwndHelp;
560     DWORD dwStyles = WS_CHILDWINDOW | WS_VISIBLE | WS_CLIPCHILDREN;
561     DWORD dwExStyles = WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR | WS_EX_CLIENTEDGE;
562     RECT rc;
563
564     HP_GetHTMLRect(pHHInfo, &rc);
565
566     hWnd = CreateWindowExW(dwExStyles, szChildClass, szEmpty, dwStyles,
567                            rc.left, rc.top, rc.right, rc.bottom,
568                            hwndParent, NULL, hhctrl_hinstance, NULL);
569     if (!hWnd)
570         return FALSE;
571
572     if (!InitWebBrowser(pHHInfo, hWnd))
573         return FALSE;
574
575     /* store the pointer to the HH info struct */
576     SetWindowLongPtrW(hWnd, GWLP_USERDATA, (LONG_PTR)pHHInfo);
577
578     ShowWindow(hWnd, SW_SHOW);
579     UpdateWindow(hWnd);
580
581     pHHInfo->WinType.hwndHTML = hWnd;
582     return TRUE;
583 }
584
585 /* Viewer Window */
586
587 static LRESULT Help_OnSize(HWND hWnd)
588 {
589     HHInfo *pHHInfo = (HHInfo *)GetWindowLongPtrW(hWnd, GWLP_USERDATA);
590     DWORD dwSize;
591     RECT rc;
592
593     if (!pHHInfo)
594         return 0;
595
596     NP_GetNavigationRect(pHHInfo, &rc);
597     SetWindowPos(pHHInfo->WinType.hwndNavigation, HWND_TOP, 0, 0,
598                  rc.right, rc.bottom, SWP_NOMOVE);
599
600     GetClientRect(pHHInfo->WinType.hwndNavigation, &rc);
601     SetWindowPos(pHHInfo->hwndTabCtrl, HWND_TOP, 0, 0,
602                  rc.right - TAB_RIGHT_PADDING,
603                  rc.bottom - TAB_TOP_PADDING, SWP_NOMOVE);
604
605     SB_GetSizeBarRect(pHHInfo, &rc);
606     SetWindowPos(pHHInfo->hwndSizeBar, HWND_TOP, rc.left, rc.top,
607                  rc.right, rc.bottom, SWP_SHOWWINDOW);
608
609     HP_GetHTMLRect(pHHInfo, &rc);
610     SetWindowPos(pHHInfo->WinType.hwndHTML, HWND_TOP, rc.left, rc.top,
611                  rc.right, rc.bottom, SWP_SHOWWINDOW);
612
613     /* Resize browser window taking the frame size into account */
614     dwSize = GetSystemMetrics(SM_CXFRAME);
615     ResizeWebBrowser(pHHInfo, rc.right - dwSize, rc.bottom - dwSize);
616
617     return 0;
618 }
619
620 static LRESULT CALLBACK Help_WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
621 {
622     switch (message)
623     {
624     case WM_COMMAND:
625         if (HIWORD(wParam) == BN_CLICKED)
626             TB_OnClick(hWnd, LOWORD(wParam));
627         break;
628     case WM_SIZE:
629         return Help_OnSize(hWnd);
630     case WM_CLOSE:
631         ReleaseHelpViewer((HHInfo *)GetWindowLongPtrW(hWnd, GWLP_USERDATA));
632         return 0;
633     case WM_DESTROY:
634         if(hh_process)
635             PostQuitMessage(0);
636         break;
637
638     default:
639         return DefWindowProcW(hWnd, message, wParam, lParam);
640     }
641
642     return 0;
643 }
644
645 static BOOL HH_CreateHelpWindow(HHInfo *info)
646 {
647     HWND hWnd;
648     RECT winPos = info->WinType.rcWindowPos;
649     WNDCLASSEXW wcex;
650     DWORD dwStyles, dwExStyles;
651     DWORD x, y, width, height;
652
653     static const WCHAR windowClassW[] = {
654         'H','H',' ', 'P','a','r','e','n','t',0
655     };
656
657     wcex.cbSize         = sizeof(WNDCLASSEXW);
658     wcex.style          = CS_HREDRAW | CS_VREDRAW;
659     wcex.lpfnWndProc    = Help_WndProc;
660     wcex.cbClsExtra     = 0;
661     wcex.cbWndExtra     = 0;
662     wcex.hInstance      = hhctrl_hinstance;
663     wcex.hIcon          = LoadIconW(NULL, (LPCWSTR)IDI_APPLICATION);
664     wcex.hCursor        = LoadCursorW(NULL, (LPCWSTR)IDC_ARROW);
665     wcex.hbrBackground  = (HBRUSH)(COLOR_MENU + 1);
666     wcex.lpszMenuName   = NULL;
667     wcex.lpszClassName  = windowClassW;
668     wcex.hIconSm        = LoadIconW(NULL, (LPCWSTR)IDI_APPLICATION);
669
670     RegisterClassExW(&wcex);
671
672     /* Read in window parameters if available */
673     if (info->WinType.fsValidMembers & HHWIN_PARAM_STYLES)
674         dwStyles = info->WinType.dwStyles;
675     else
676         dwStyles = WS_OVERLAPPEDWINDOW | WS_VISIBLE |
677                    WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
678
679     if (info->WinType.fsValidMembers & HHWIN_PARAM_EXSTYLES)
680         dwExStyles = info->WinType.dwExStyles;
681     else
682         dwExStyles = WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_APPWINDOW |
683                      WS_EX_WINDOWEDGE | WS_EX_RIGHTSCROLLBAR;
684
685     if (info->WinType.fsValidMembers & HHWIN_PARAM_RECT)
686     {
687         x = winPos.left;
688         y = winPos.top;
689         width = winPos.right - x;
690         height = winPos.bottom - y;
691     }
692     else
693     {
694         x = WINTYPE_DEFAULT_X;
695         y = WINTYPE_DEFAULT_Y;
696         width = WINTYPE_DEFAULT_WIDTH;
697         height = WINTYPE_DEFAULT_HEIGHT;
698     }
699
700     hWnd = CreateWindowExW(dwExStyles, windowClassW, info->WinType.pszCaption,
701                            dwStyles, x, y, width, height, NULL, NULL, hhctrl_hinstance, NULL);
702     if (!hWnd)
703         return FALSE;
704
705     ShowWindow(hWnd, SW_SHOW);
706     UpdateWindow(hWnd);
707
708     /* store the pointer to the HH info struct */
709     SetWindowLongPtrW(hWnd, GWLP_USERDATA, (LONG_PTR)info);
710
711     info->WinType.hwndHelp = hWnd;
712     return TRUE;
713 }
714
715 static void HH_CreateFont(HHInfo *pHHInfo)
716 {
717     LOGFONTW lf;
718
719     GetObjectW(GetStockObject(ANSI_VAR_FONT), sizeof(LOGFONTW), &lf);
720     lf.lfWeight = FW_NORMAL;
721     lf.lfItalic = FALSE;
722     lf.lfUnderline = FALSE;
723
724     pHHInfo->hFont = CreateFontIndirectW(&lf);
725 }
726
727 static void HH_InitRequiredControls(DWORD dwControls)
728 {
729     INITCOMMONCONTROLSEX icex;
730
731     icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
732     icex.dwICC = dwControls;
733     InitCommonControlsEx(&icex);
734 }
735
736 /* Creates the whole package */
737 static BOOL CreateViewer(HHInfo *pHHInfo)
738 {
739     HH_CreateFont(pHHInfo);
740
741     if (!HH_CreateHelpWindow(pHHInfo))
742         return FALSE;
743
744     HH_InitRequiredControls(ICC_BAR_CLASSES);
745
746     if (!HH_AddToolbar(pHHInfo))
747         return FALSE;
748
749     HH_RegisterChildWndClass(pHHInfo);
750
751     if (!HH_AddNavigationPane(pHHInfo))
752         return FALSE;
753
754     HH_RegisterSizeBarClass(pHHInfo);
755
756     if (!HH_AddSizeBar(pHHInfo))
757         return FALSE;
758
759     if (!HH_AddHTMLPane(pHHInfo))
760         return FALSE;
761
762     return TRUE;
763 }
764
765 void ReleaseHelpViewer(HHInfo *info)
766 {
767     if (!info)
768         return;
769
770     /* Free allocated strings */
771     hhctrl_free((LPWSTR)info->WinType.pszType);
772     hhctrl_free((LPWSTR)info->WinType.pszCaption);
773     hhctrl_free((LPWSTR)info->WinType.pszToc);
774     hhctrl_free((LPWSTR)info->WinType.pszIndex);
775     hhctrl_free((LPWSTR)info->WinType.pszFile);
776     hhctrl_free((LPWSTR)info->WinType.pszHome);
777     hhctrl_free((LPWSTR)info->WinType.pszJump1);
778     hhctrl_free((LPWSTR)info->WinType.pszJump2);
779     hhctrl_free((LPWSTR)info->WinType.pszUrlJump1);
780     hhctrl_free((LPWSTR)info->WinType.pszUrlJump2);
781
782     if (info->pCHMInfo)
783         CloseCHM(info->pCHMInfo);
784
785     ReleaseWebBrowser(info);
786
787     if(info->WinType.hwndHelp)
788         DestroyWindow(info->WinType.hwndHelp);
789
790     hhctrl_free(info);
791     OleUninitialize();
792 }
793
794 HHInfo *CreateHelpViewer(LPCWSTR filename)
795 {
796     HHInfo *info = hhctrl_alloc_zero(sizeof(HHInfo));
797
798     OleInitialize(NULL);
799
800     info->pCHMInfo = OpenCHM(filename);
801     if(!info->pCHMInfo) {
802         ReleaseHelpViewer(info);
803         return NULL;
804     }
805
806     if (!LoadWinTypeFromCHM(info->pCHMInfo, &info->WinType)) {
807         ReleaseHelpViewer(info);
808         return NULL;
809     }
810
811     if(!CreateViewer(info)) {
812         ReleaseHelpViewer(info);
813         return NULL;
814     }
815
816     return info;
817 }