Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2815 lines
66 KiB

/*****************************************************************************
*
* HWPROC.C
*
* Copyright (C) Microsoft Corporation 1990.
* All Rights reserved.
*
******************************************************************************
*
* Module Intent
* Contains the window procedures for all global windows: help window, *
* topic window, title window, icon window, and note (glossary) window. *
*
*****************************************************************************/
#include "help.h"
#pragma hdrstop
#include "inc\printset.h"
#include "inc\sbutton.h"
#include "inc\hinit.h"
#include "inc\hwproc.h"
#include "inc\bookmark.h"
#ifdef _DEBUG
#include "inc\navpriv.h"
#endif
#include "inc\tmp.h" // until it gets added to windows.h
#ifdef _DEBUG
#include "inc\fsdriver.h"
#include "inc\andriver.h"
#include "inc\btdriver.h"
#endif
#include <string.h>
#define CPALETTEENTRIES 20
typedef struct {
int cBtn;
int iBtn;
int xWnd;
int yWnd;
int xBtn;
int yBtn;
int cHoriz;
} BUTTONLAYOUT;
/*****************************************************************************
*
* Defines
*
*****************************************************************************/
#define SCROLL_ASPERTHUMB 20
#define wMAX_WINDOWTEXT 100
/* There are matched defines in */
/* IMBED.C to these. These defines*/
#define WM_ASKPALETTE 0x706C // should not be changed since they*/
#define WM_FINDNEWPALETTE 0x706D // are "exported" to embedded wins
#define MSGF_CBTHELP 7 // MsgFilter define for the CBT
/*****************************************************************************
*
* Prototypes
*
*****************************************************************************/
static BOOL STDCALL FPaintTopicBackground (HWND, HDC);
static int STDCALL MapScrollType(int);
static VOID STDCALL ProcessHotspotCmd(UINT wNavCmd);
static VOID STDCALL VUpdateDefaultColorsHde(HDE hde, BOOL fAuthoredBack, int iWindow);
static void STDCALL doMsgJump(LPVOID pv, WORD wFlag, UINT16 cmd, LONG itcx);
static void STDCALL CheckOurMouse(HWND hwnd, UINT msg, WPARAM wParam);
static void STDCALL ForceRepaint(QDE qde, HWND hwnd, BOOL fFontChanged);
INLINE static void STDCALL SetIconWord(HWND hwnd);
INLINE static VOID STDCALL DestroyFloatingMenu(VOID);
INLINE static int STDCALL YGetArrangedHeight(HWND hwnd, int xWindow);
#define HdsGetHde(hde) QdeFromGh(hde)->hdc
/*****************************************************************************
*
* Variables
*
*****************************************************************************/
static HPALETTE hpal;
extern HSTACK hstackHistory;
extern int cSystemColors; // from bitmap.c
/*******************
-
- Name: HelpWndProc
*
* Purpose: Window procdeure for "main" help window
*
* Arguments: Standard windows proc
*
******************/
#ifndef NO_PRAGMAS
#pragma data_seg(".text", "CODE")
#endif
static const char txtSeqKey[] = "SeqTopicKeys";
#ifndef NO_PRAGMAS
#pragma data_seg()
#endif
static BOOL fKeyUsed;
LRESULT EXPORT HelpWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
BOOL fExec;
HDE hde;
HDC hdc;
HPALETTE hpalT;
RECT rc;
int iWindow;
int i;
// We need to save this in case a dll registers this message and tries
// to talk to us through it.
if (msg == msgWinHelp)
return DispatchProc((HWND) wParam, (GH) lParam);
switch(msg) {
case WM_SHOWWINDOW:
return DefWindowProc(hwnd, msg, wParam, lParam);
case WM_WINHELP:
return DispatchProc((HWND) wParam, (GH) lParam);
#if 0 // we don't support icons in the help file any more
/*
* 05-Jan-1993 [ralphw] I won't swear that all of these messages
* need to set the icon, but they get called infrequently enough that
* it won't be the kind of performance hit that existed in the previous
* version of WinHelp where every message resulted in a query for
* whether the window was iconized.
* 05-Jan-1993 [ralphw]
*/
case WM_SYSCOMMAND:
switch (wParam) {
case SC_MINIMIZE:
if (iCurWindow == MAIN_HWND) {
int i;
for (i = MAIN_HWND + 1; i < MAX_WINDOWS; i++) {
if (ahwnd[i].hwndParent)
ShowWindow(ahwnd[i].hwndParent, SW_HIDE);
}
}
break;
case SC_RESTORE:
if (iCurWindow == MAIN_HWND) {
int i;
for (i = MAIN_HWND + 1; i < MAX_WINDOWS; i++) {
if (ahwnd[i].hwndParent)
ShowWindow(ahwnd[i].hwndParent, SW_SHOWNA);
}
}
break;
}
// Intentionally fall through
case WM_GETMINMAXINFO:
case WM_ICONERASEBKGND:
case WM_ERASEBKGND:
SetIconWord(hwnd);
return DefWindowProc(hwnd, msg, wParam, lParam);
#endif
#if defined(BIDI_MULT) // jgross
case WM_LANGUAGE:
DefWindowProc(hWnd, wMsg, wParam, lParam);
if (wParam != -1) {
extern BOOL fMenuChanged, RtoL;
RtoL = (wParam == Arabic) || (wParam == Hebrew);
MakeScrollBarsRtoL(hwndTopicMain, RtoL, TRUE);
if (IsWindow(hwndList)) {
char szCap[40];
LoadString(hInsNow, sidHistoryCaption, szCap, sizeof(szCap));
SetWindowText(hwndPath, szCap);
MakeScrollBarsRtoL(hwndList, RtoL, TRUE);
}
if (IsWindow(hwndTopic2nd))
MakeScrollBarsRtoL(hwndTopic2nd, RtoL, TRUE);
ResetButtons(hwndIcon);
fMenuChanged = fTrue;
DoMenuStuff(MNU_RESET, NULL);
if (HdeGetEnv()) {
EnableMenuItem(GetSubMenu(GetMenu(hWnd), 1), 0, MF_BYPOSITION | MF_ENABLED);
EnableMenuItem(GetSubMenu(GetMenu(hWnd), 1), 2, MF_BYPOSITION | MF_ENABLED);
}
}
break;
#endif
case WM_WININICHANGE:
hde = HdeGetEnv();
if (hde)
UpdateWinIniValues(hde, (LPSTR) lParam);
for (i = MAIN_HWND; i < MAX_WINDOWS; i++) {
if (ahwnd[i].hwndParent && IsWindowVisible(ahwnd[i].hwndParent))
InvalidateRect(ahwnd[iCurWindow].hwndParent, NULL, TRUE);
}
if (GetHighContrastFlag() ||
GetSysColor(COLOR_WINDOW) != RGB(255, 255, 255) ||
GetSysColor(COLOR_WINDOWTEXT) != 0)
fDisableAuthorColors = TRUE;
else
fDisableAuthorColors = FALSE;
break;
case WM_CREATE:
SetWindowLong(hwnd, GHWL_HICON, 0);
goto defwinproc;
case WM_KILLFOCUS:
ToggleHotspots(FALSE);
break;
case WM_TIMER:
switch (wParam) {
case ID_AUTO_CLOSE:
KillOurTimers();
fNoHide = TRUE; // really, really close help
CloseHelp();
break;
}
break;
case WM_ENABLE:
break;
case WM_CLOSE:
/*
* ensure that any dialogs which are children of this window have
* been canceled.
*/
FDestroyDialogsHwnd(hwnd, FALSE);
// If
// - there IS a secondary window.
// or
// - we are help
// - and the low memory flag is clear
// - the window is currently visible
// then
// if this is a secondary window, post a message to the main window
// to close, else just hide, as we are the main window.
if (fMultiPrinting) {
fAbortPrint = TRUE;
fQuitHelp = TRUE;
EndMPrint();
goto KillThemAll;
}
if (IsValidWindow(hwndSecondHelp)) {
PostMessage(hwndSecondHelp, WM_CLOSE, 0, 0);
hwndSecondHelp = NULL;
}
if (IsValidWindow(hwndTCApp)) {
char szBuf[256];
wsprintf(szBuf, "W:%u %d %d\r\n", hwndTCApp, IDCLOSE, 0);
SendStringToParent(szBuf);
SendMessage(hwndTCApp, WM_TCARD, IDCLOSE, 0);
hwndTCApp = NULL;
}
if (fHelp != TCARD_HELP) {
// The shift key is up. We only do this when it is up, so that
// SHIFT+exit means REALLY REALLY exit
if (hwnd != ahwnd[MAIN_HWND].hwndParent) {
/*
* This is a secondary window. It will be closed. If the main
* window is not visible, it may need to be really closed. Post a
* message to it to let it decide for itself.
*/
int i;
iWindow = GetWindowIndex(hwnd);
ASSERT(iWindow != MAIN_HWND);
i = AreAnyWindowsVisible(0);
if (i == iWindow)
i = AreAnyWindowsVisible(iWindow + 1);
if (i < 0)
CloseHelp(); // only one window visible, so close help
else {
ASSERT(IsValidWindow(hwnd));
DestroyWindow(hwnd);
break;
}
}
else {
/*
* This is the main window being asked to close. If we're help,
* then we just close all our secondary windows and hide.
* Otherwise, we really do shut down.
*/
// REVIEW: 06-Sep-1993 [ralphw] -- Add a timer, to completely close
// down help.
if (fHelp && !fNoHide) {
DestroyAllSecondarys();
if (hwndHistory)
DestroyWindow(hwndHistory);
ShowWindow(ahwnd[MAIN_HWND].hwndParent, SW_HIDE);
/*
* If we aren't called again in NOTE_TIMEOUT seconds,
* then terminate ourselves.
*/
if (!fAutoClose) {
fAutoClose = TRUE;
SetTimer(ahwnd[MAIN_HWND].hwndParent, ID_AUTO_CLOSE,
NOTE_TIMEOUT, NULL);
}
break;
}
}
}
// If we got here, then we're going to exit.
KillThemAll:
if (IsValidWindow(hwndAnimate) && fHelp == STANDARD_HELP) {
/*
* This is a really bad situation. We're in the midst of
* creating a .GID file and the user or app has managed to
* convince us to close. We try to clean up as gracefully as we
* can, but ultimately, we hard exit.
*/
DestroyFloatingMenu();
DestroyAllSecondarys();
Cleanup();
_exit(-1);
}
DestroyFloatingMenu();
DestroyAllSecondarys();
goto defwinproc;
case WM_SIZE:
/* (kevynct)
* This global variable fButtonsBusy was introduced so that we do a
* minimum of screen updates when changing files. The flag is set
* ONLY in FReplaceCloneHde. We need to ignore resizes generated by
* the button code.
*/
if (fButtonsBusy)
break;
/*
* Ensure we are focused on the correct window, and resize it, if
* not iconic.
*/
SetFocusHwnd(hwnd);
// If we are iconizing the main help window, inform DLL's and make
// sure that any history window present is taken down. (Will take
// a history request to bring it back up).
if (wParam == SIZEICONIC) {
if (hwnd == ahwnd[MAIN_HWND].hwndParent) {
InformDLLs(DW_MINMAX, 1L, 0L);
if (IsValidWindow(hwndHistory))
DestroyWindow(hwndHistory);
}
}
if (!IsIconic(hwnd)) {
TLP tlpBogus;
SizeWindows(hwnd, wParam, lParam, FALSE, TRUE);
/*
* SizeWindows is called in TopicGoto, since it must finalize the
* size of the NSR and do the repaint. tlpBogus is not used. The
* current values of the TLP in whatever DEs there are, are used.
*/
TopicGoto(fGOTO_TLP_RESIZEONLY, (QV)&tlpBogus);
}
break;
case WM_INITMENU:
{
HMENU hmenu = (HMENU) wParam;
CheckMenuItem(hmenu, IDM_ONTOP_DEFAULT,
(cntFlags.fsOnTop == ONTOP_NOTSET) ?
MF_CHECKED : MF_UNCHECKED);
CheckMenuItem(hmenu, IDM_ONTOP_FORCEON,
(cntFlags.fsOnTop == ONTOP_FORCEON) ?
MF_CHECKED : MF_UNCHECKED);
CheckMenuItem(hmenu, IDM_ONTOP_FORCEOFF,
(cntFlags.fsOnTop == ONTOP_FORCEOFF) ?
MF_CHECKED : MF_UNCHECKED);
CheckMenuItem(hmenu, IDM_OVERRIDE_COLORS,
cntFlags.fOverColor ? MF_CHECKED : MF_UNCHECKED);
// Clear them all, then set the right one
CheckMenuItem(hmenu, IDM_FONTS_SMALLER,
cntFlags.iFontAdjustment == -4 ?
MF_CHECKED : MF_UNCHECKED);
CheckMenuItem(hmenu, IDM_FONTS_DEFAULT,
cntFlags.iFontAdjustment == 0 ?
MF_CHECKED : MF_UNCHECKED);
CheckMenuItem(hmenu, IDM_FONTS_BIGGER,
cntFlags.iFontAdjustment == 4 ?
MF_CHECKED : MF_UNCHECKED);
}
break;
case WM_INITMENUPOPUP:
if (((HMENU) wParam == hmenuBookmark) && (hde = HdeGetEnv())) {
if (hfsBM == NULL)
OpenBMFS();
if (!UpdBMMenu(hde, (HMENU) wParam))
return(TRUE);
}
break;
case WM_KEYDOWN:
fKeyDownSeen = TRUE;
FAcceleratorExecute(wParam);
/*
* We only want to process VK_ESCAPE on the down-key, because when
* you press ESCAPE in a dialog box, the down key cancels the dialog
* box, and then the Up key gets passed through to the app.
*/
if (wParam == VK_ESCAPE) {
if (fSequence) { // Are we running our auto-sequence macro?
fSequence = 0;
#ifdef _DEBUG
Command(IDM_MEM_USAGE);
#endif
break;
}
/*
* If the main window is the current window, then ESCAPE shuts
* down help. If the main window is visible, but is not the current
* window, then only close the current window. If the main window is
* not visible, then find out how many secondary windows are open.
* If there's more then one secondary window open, then just close
* the current window, otherwise close help.
*/
if (iCurWindow == MAIN_HWND)
QuitHelp();
else if (IsWindowVisible(ahwnd[MAIN_HWND].hwndParent)) {
SendMessage(ahwnd[iCurWindow].hwndParent, WM_CLOSE, 0, 0);
break;
}
else {
int i;
int cWindows = 0;
for (i = MAIN_HWND; i < MAX_WINDOWS; i++) {
if (ahwnd[i].hwndParent) {
if (++cWindows > 1)
break;
}
}
if (++cWindows > 1) {
ASSERT(IsValidWindow(ahwnd[iCurWindow].hwndParent));
SendMessage(ahwnd[iCurWindow].hwndParent, WM_CLOSE, 0, 0);
break;
}
else
QuitHelp();
}
break;
}
if (fKeyDown(VK_CONTROL) && fKeyDown(VK_SHIFT)) {
if ((wParam == VK_HOME || wParam == VK_END ||
wParam == VK_LEFT || wParam == VK_RIGHT) &&
(fHelpAuthor || GetProfileInt(txtIniHelpSection, txtSeqKey, 0))) {
HDE hde;
if ((hde = HdeGetEnvHwnd(ahwnd[iCurWindow].hwndTopic)) != NULL) {
QDE qde = QdeFromGh(hde);
if (wParam == VK_LEFT)
JumpToTopicNumber(qde->top.mtop.lTopicNo - 1);
else if (wParam == VK_END)
JumpToTopicNumber(-1);
else {
DWORD topic = (wParam == VK_RIGHT) ?
DwNextSeqTopic(qde) : DwFirstSeqTopic(qde);
JumpVA(topic);
if (hwndSecondHelp) {
JumpLinkedWinHelp((wParam == VK_RIGHT) ?
qde->top.mtop.lTopicNo : 0);
}
}
}
break;
}
}
// WARNING: Intentionally fall through
case WM_KEYUP:
// WARNING: Both KEYUP and KEYDOWN messages come here
{
HWND hwndCur;
hwndCur = HwndGetEnv();
ASSERT(ahwnd[iCurWindow].hwndTopic &&
IsWindow(ahwnd[iCurWindow].hwndTopic));
FSetEnv(ahwnd[iCurWindow].hwndTopic);
switch (wParam) {
/*
* The following code allows someone to use the CONTROL/TAB
* combo to hilite all screen hotspots while this combo is
* held down. It also handles regular hotspot tabbing.
*/
case VK_TAB:
if (msg == WM_KEYDOWN) {
if (!fKeyDown(VK_MENU) && !fKeyDown(VK_CONTROL))
ProcessHotspotCmd(fKeyDown(VK_SHIFT) ?
NAV_PREVHS : NAV_NEXTHS);
else if (fKeyDown(VK_CONTROL) && !fRepeatedKey(lParam))
ToggleHotspots(TRUE);
}
else if (msg == WM_KEYUP && fKeyDown(VK_CONTROL))
ToggleHotspots(FALSE);
fExec = TRUE;
break;
case VK_CONTROL:
if (fKeyDown(VK_TAB) && msg == WM_KEYUP)
ToggleHotspots(FALSE);
break;
case VK_RETURN:
if (msg == WM_KEYUP && fKeyDownSeen) {
ToggleHotspots(FALSE);
ProcessHotspotCmd(NAV_HITHS);
fExec = TRUE;
}
break;
#ifdef _DEBUG
/*
* Can't use F2 because VC wants it. F4 is too complicated for TandyT to
* figure out, so it's easier to just remove it then to explain it to him.
*/
case VK_F2:
if (iCurWindow == MAIN_HWND && msg == WM_KEYDOWN &&
hstackHistory &&
(CElementsStack(hstackHistory)) > 1) {
TLPHELP tlphelp;
FM fm;
RcGetIthTopic(1, &tlphelp.tlp, &fm);
tlphelp.cb = sizeof(TLPHELP);
if (!FWinHelp(PszFromGh(fm), cmdTLP, (DWORD) (QV) &tlphelp))
Error(wERRS_OOM, wERRA_RETURN);
fExec = TRUE;
}
break;
case VK_F4:
/*
* We need to use this system message rather then ShowWindow
* in order to hit the code that processes this message and
* hides all secondary windows.
*/
if (msg == WM_KEYUP && fKeyDownSeen)
SendMessage(ahwnd[iCurWindow].hwndParent, WM_SYSCOMMAND,
SC_MINIMIZE, 0);
break;
#endif
default:
if (msg == WM_KEYDOWN || fKeyDownSeen) {
if (wParam == 'C' && fKeyDown(VK_CONTROL))
break;
fExec = FExecKey(ahwnd[iCurWindow].hwndTopic, wParam,
msg == WM_KEYDOWN);
}
break;
}
FSetEnv(hwndCur);
if (msg == WM_KEYUP)
fKeyDownSeen = FALSE;
}
if (!fExec)
goto defwinproc;
break;
/*****
**
** HACK ALERT! - the following code with the fKeyUsed static is really
** gross. In addition, it depends on the undocumentd fact that we handle
** buttons on the "down" stroke of the key and that "up" stroke keys do
** not use the ALT key. FExeKey() should be broken apart and rewritten
** to correctly handle all the cases and allow extensions for both
** key down and key up. Note that fKeyUsed is used here so that we
** can return 1L from WM_SYSCHAR and avoid the computer beep that would
** otherwise be generated.
**
** 2/8/91 - RobertBu
**
******/
case WM_SYSKEYDOWN:
fSysKeyDownSeen = TRUE;
fKeyUsed = FAcceleratorExecute(wParam)
|| FExecKey(ahwnd[iCurWindow].hwndTopic, (UINT) wParam,
(msg == WM_SYSKEYDOWN));
if (fKeyUsed)
return 1L;
else
goto defwinproc;
case WM_SYSKEYUP:
if (fSysKeyDownSeen && FExecKey(ahwnd[iCurWindow].hwndTopic, wParam,
msg == WM_SYSKEYDOWN)) {
fSysKeyDownSeen = FALSE;
return 1L;
}
else
goto defwinproc;
case WM_SYSCHAR:
if (fKeyUsed) {
fKeyUsed = FALSE;
return 1L;
}
else
goto defwinproc;
case MSG_CHANGEMENU:
if ((ahwnd[MAIN_HWND].hwndParent == ahwnd[iCurWindow].hwndParent) ||
(wParam == MNU_ACCELERATOR))
DoMenuStuff(wParam, lParam);
break;
case MSG_CHANGEBUTTON:
if ((hde = HdeGetEnv()) && !HDE_TOPIC(hde))
break;
iWindow = GetWindowIndex(hwnd);
if (ahwnd[iWindow].hwndButtonBar)
SendMessage(ahwnd[iWindow].hwndButtonBar, IWM_UPDBTN, wParam, lParam);
break;
case MSG_HFS_OPEN:
return (LRESULT) HfsOpenFm((FM) wParam, fFSOpenReadOnly);
case MSG_HF_OPEN:
return (LRESULT) HfOpenHfs((HFS) wParam, (LPCSTR) lParam, fFSOpenReadOnly);
case MSG_GET_INFO:
return (LRESULT) LGetInfo((WORD) wParam, NULL);
case MSG_JUMP_TOPIC:
{
/*
* This message is only received by the linked WinHelp. We
* don't want JumpToTopicNumber to send the same message back to
* the other WinHelp, so we hide the window handle for the
* durationg of the call.
*/
HWND hwndSave = hwndSecondHelp;
hwndSecondHelp = NULL;
JumpToTopicNumber(lParam);
hwndSecondHelp = hwndSave;
}
break;
case MSG_LINKED_HELP:
hwndSecondHelp = (HWND) lParam;
break;
case WM_SYSCOLORCHANGE:
{
BOOL fAuthoredBack;
int iWindow = GetWindowIndex(hwnd);
/* (kevynct)
* We only update to the new background colour if there is
* not a preset author-defined one.
*/
hde = HdeGetEnvHwnd(ahwnd[iWindow].hwndTopic);
if (hde) {
DiscardBitmapsHde(hde);
fAuthoredBack =
GetWindowLong(ahwnd[iWindow].hwndTopic, GTWW_COBACK) != coNIL;
VUpdateDefaultColorsHde(hde, fAuthoredBack, iWindow);
}
hde = HdeGetEnvHwnd(ahwnd[iWindow].hwndTitle);
if (hde) {
fAuthoredBack =
GetWindowLong(ahwnd[iWindow].hwndTitle, GNWW_COBACK) != coNIL;
VUpdateDefaultColorsHde(hde, fAuthoredBack, iWindow);
}
InvalidateRect(ahwnd[iWindow].hwndParent, NULL, TRUE);
GenerateMessage(MSG_REPAINT, TRUE, 0);
}
break;
#if 0
10-Sep-1993 [ralphw] we don't need this unless we respond to WM_QUERYENDSESSION
case WM_ENDSESSION:
if ((BOOL) wParam == FALSE)
break;
/* If the EndSession has been cancelled, forget it; otherwise,
* drop through and clean up after ourselves.
*/
#endif
case WM_DESTROY:
if (hwnd != ahwnd[MAIN_HWND].hwndParent) {
MSG msg;
iWindow = GetWindowIndex(hwnd);
RcBackFini(iWindow); // close any back tree
ASSERT((HLOCAL) ahwnd[iWindow].pszMemberName);
FreeLh(ahwnd[iWindow].pszMemberName);
DestroyHde(HdeDefectEnv(ahwnd[iWindow].hwndTopic));
DestroyHde(HdeDefectEnv(ahwnd[iWindow].hwndTitle));
ZeroMemory(&ahwnd[iWindow], sizeof(HELPWINDOWS));
if (IsWindowVisible(ahwnd[MAIN_HWND].hwndParent))
SetFocusHwnd(ahwnd[MAIN_HWND].hwndParent);
/*------------------------------------------------------------*\
| If there is a WM_FINDNEWPALETTE message pending, we need to
| let the main window process it, since this secondary window
| is going away.
\*------------------------------------------------------------*/
if (PeekMessage(&msg, hwnd, WM_FINDNEWPALETTE, WM_FINDNEWPALETTE,
PM_REMOVE | PM_NOYIELD))
PostMessage(ahwnd[MAIN_HWND].hwndParent, WM_FINDNEWPALETTE, 0, 0);
}
else {
GetWindowWRect(hwnd, &rctHelp);
DestroyHelp();
}
break;
case WM_COMMAND:
ExecMnuCommand(hwnd, wParam, lParam);
break;
case MSG_NEXT_TOPIC:
if (fSequence) { // might have been cancelled by ESCAPE
if (NextTopic(FALSE)) {
FlushMessageQueue(0);
PostMessage(hwnd, MSG_NEXT_TOPIC, 0, 0);
}
else {
if (fSequence == 2)
Test(3);
else if (fSequence == 4 || fSequence == 6)
QuitHelp();
else {
#ifdef _PRIVATE
if (fSequence == 1) {
EndTimeReport();
}
#endif
fSequence = FALSE;
}
}
}
break;
case MSG_BROWSEBTNS:
hde = HdeGetEnv();
iWindow = GetWindowIndex(hwnd);
if (hde && HDE_TOPIC(hde) && IsValidWindow(ahwnd[iWindow].hwndButtonBar)) {
// GetWindowLong(ahwnd[iWindow].hwndButtonBar, GIWW_BUTTONSTATE)) {
CreateBrowseButtons(ahwnd[iWindow].hwndButtonBar);
EnableDisable(hde, TRUE, iWindow);
}
break;
case WM_JUMPPA:
{
LA laDest;
CbReadMemQLA(&laDest, (QB) &lParam, wVersion3_1);
TopicGoto(fGOTO_LA, (QV) &laDest);
break;
}
case MSG_JUMPITO:
doMsgJump((LPVOID) &lParam, (WORD) wParam,
fGOTO_ITO, (LONG) lParam);
break;
case MSG_JUMPHASH:
doMsgJump((LPVOID) &lParam, (WORD) wParam,
fGOTO_HASH, (LONG) lParam);
break;
case MSG_JUMPCTX:
doMsgJump((LPVOID) &lParam, (WORD) wParam,
fGOTO_CTX, (LONG) lParam);
break;
case MSG_ANNO:
EnableMenuItem(hmnuHelp, HLPMENUEDITANNOTATE,
(MF_DISABLED | MF_BYCOMMAND | MF_GRAYED));
if (FDisplayAnnoHde(HdeGetEnv()))
EnableMenuItem(hmnuHelp, HLPMENUEDITANNOTATE,
(MF_ENABLED | MF_BYCOMMAND));
break;
case MSG_EXECAPI:
ExecAPI((QHLP) PtrFromGh((GH) lParam));
FreeGh((HGLOBAL) lParam);
break;
case MSG_KILLDLG:
{
/*
* We *always* ensure that dialogs, any dialogs, are down. The
* point of this message.
*/
BOOL fRet = FDestroyDialogsHwnd(ahwnd[iCurWindow].hwndParent, TRUE);
/*
* Side effect of this message: if we are enabled, we ensure that
* we we are up and have focus.
*/
if (IsWindowEnabled(ahwnd[iCurWindow].hwndParent)) {
if (IsIconic(ahwnd[iCurWindow].hwndParent))
// This simulates double-clicking on the icon.
SendMessage(ahwnd[iCurWindow].hwndParent, WM_SYSCOMMAND,
SC_RESTORE, 0);
SetFocus(ahwnd[iCurWindow].hwndParent);
}
return fRet;
}
break;
case MSG_CLOSE_WIN:
CloseWin((PSTR) lParam);
lcFree((void*) lParam);
break;
case MSG_ERROR:
Error(wParam, (int) lParam);
break;
case MSG_REPAINT:
/*
* We now MUST paint all windows, since this code also handles font
* size changes accross all windows. 21-Dec-1993 [ralphw]
*/
{
int i;
for (i = 0; i < MAX_WINDOWS; i++) {
if (ahwnd[i].hwndParent) {
if (ahwnd[i].hwndTitle) {
hde = HdeGetEnvHwnd(ahwnd[i].hwndTitle);
if (hde)
ForceRepaint(QdeFromGh(hde), ahwnd[i].hwndTitle,
(BOOL) wParam);
}
hde = HdeGetEnvHwnd(ahwnd[i].hwndTopic);
if (hde) {
// If wParam is TRUE, then we have changed the size
// of the fonts.
ForceRepaint(QdeFromGh(hde), ahwnd[i].hwndTopic,
(BOOL) wParam);
/*
* A font-size change in an auto-size window
* requires us to jump to the same topic in that
* window to force a resize of the window.
*/
// if (wParam && ahwnd[i].fAutoSize) {
if (wParam && i == iCurWindow) {
TLP tlp;
tlp.va = QdeFromGh(hde)->top.mtop.vaSR;
tlp.lScroll = 0;
if (tlp.va.dword != vaNil)
TopicGoto(fGOTO_TLP, (void*) &tlp);
}
}
}
}
}
break;
case WM_FINDNEWPALETTE:
if (lParam) {
ASSERT(wParam);
hpal = (HPALETTE) wParam;
}
else
hpal = HpalGet();
// Fall through
case WM_QUERYNEWPALETTE:
if (hpal) {
hdc = GetDC(hwnd);
if (hdc) {
UINT c;
hpalT = SelectPalette(hdc, hpal, FALSE);
c = RealizePalette(hdc);
SelectPalette(hdc, hpalT, FALSE);
ReleaseDC(hwnd, hdc);
return c;
}
else
return FALSE;
}
break;
// REVIEW: 05-Mar-1994 [ralphw] Who uses this???
case WM_ASKPALETTE:
if (hpal)
return (LRESULT) hpal;
else {
if (!hpalSystemCopy) {
GH gh;
LPLOGPALETTE qlp;
gh = GhAlloc(GPTR, sizeof(*qlp) + (CPALETTEENTRIES - 1)
* sizeof(PALETTEENTRY));
if (gh) {
HDC hdc;
qlp = PtrFromGh(gh);
hdc = GetDC(NULL);
if (hdc) {
qlp->palVersion = 0x300;
qlp->palNumEntries = CPALETTEENTRIES;
GetSystemPaletteEntries(hdc, 0, CPALETTEENTRIES,
qlp->palPalEntry);
hpalSystemCopy = CreatePalette(qlp);
ReleaseDC(NULL, hdc);
}
}
FreeGh(gh);
}
return (LRESULT) hpalSystemCopy;
}
case MSG_APP_HWND:
if (iasCur == -1 || !IsValidWindow(aAppHwnd[iasCur]))
return NULL;
else
return (LRESULT) aAppHwnd[iasCur];
case MSG_COPYRIGHT:
{
HDE hde = HdeGetEnv();
if (hde)
return (LRESULT) QDE_RGCHCOPYRIGHT(QdeFromGh(hde));
else
return NULL;
}
case MSG_INFORMWIN:
InformWindow((int) wParam, (PWININFO) lParam);
break;
case MSG_NEW_MACRO:
#ifdef _DEBUG // ignore in _PRIVATE
ASSERT(!(QdeFromGh(HdeGetEnv())->fSelectionFlags & CAPTURE_LOCKED));
ASSERT(!(QdeFromGh(HdeGetEnv())->fSelectionFlags & MOUSE_CAPTURED));
#endif
if (lParam) {
Execute((PSTR) lParam);
}
break;
// REVIEW: MSG_MACRO is for backwards compatibility only. Remove this
// if it doesn't show up in the undocumented features book.
case MSG_MACRO:
if ((GH) wParam != NULL && wParam > 0x0ffff) {
Execute(PszFromGh((GH) wParam));
FreeGh((GH) wParam);
}
break;
case MSG_GET_DEFFONT:
return (LRESULT) hfontDefault;
case WM_PALETTECHANGED:
BroadcastChildren(hwnd, WM_PALETTECHANGED, wParam, lParam);
break;
case WM_ACTIVATE:
/* Window activation. Inform DLLs.
* wParam 0=deactivate; else activate
* lParam 0=main window; else secondary
*/
InformDLLs(DW_ACTIVATEWIN, (LONG) wParam,
(LONG) ((iCurWindow == MAIN_HWND) ? 0 : ahwnd[iCurWindow].hwndParent));
if (wParam != WA_INACTIVE) {
SetFocusHwnd (hwnd);
/* This code is to get around a bug */
/* in windows where it incorrectly*/
/* sets the focus to NULL (#505) */
if (!IsIconic(hwnd) && !GetFocus())
SetFocus(hwnd);
/*
* REVIEW: 23-Jan-1996 [ralphw]
* I added this in order to get any 256-color bitmaps to
* realize their palette. cSystemColors only gets initialized to
* non-zero if we actually see a bitmap (see CreateBIPalette in
* bitmap.c)
*/
if (cSystemColors == 256) {
InvalidateRect(ahwnd[iCurWindow].hwndTopic, NULL, FALSE);
InvalidateRect(ahwnd[iCurWindow].hwndTitle, NULL, FALSE);
}
}
break;
case WM_ACTIVATEAPP:
/* Application activation. If main window getting the message, Inform
* DLLs.
* wParam 0=deactivate; else activate
* lParam unused
*/
if (hwnd == ahwnd[MAIN_HWND].hwndParent)
InformDLLs(DW_ACTIVATE, (LONG) wParam,
(LONG) ((iCurWindow == MAIN_HWND) ? 0 : ahwnd[iCurWindow].hwndParent));
if (!wParam) {
HDE hde = HdeGetEnv();
if (hde) { // no hde means no file displayed yet
RcFlushHfs(QDE_HFS(QdeFromGh(HdeGetEnv())),
fFSCloseFile | fFSFreeBtreeCache);
/*
* We are losing focus; close the bookmark file system so
* that if we do some operations in some other instance then
* it reflects on all instances.
*/
CloseAndCleanUpBMFS();
}
}
else {
// Regaining focus
/* winhelp 3.1 bug #1013:
** Check the timestamp of the help file to make sure it
** hasn't changed.
*/
RC rc;
DWORD lTimestamp;
HDE hde = HdeGetEnv();
QDE qde;
if (hde != NULL) {
fKeyDownSeen = FALSE;
qde = QdeFromGh(HdeGetEnv());
rc = RcTimestampHfs(QDE_HFS(qde), &lTimestamp);
if (rc != rcSuccess) {
ErrorVarArgs(wERRS_NOTAVAILABLE, wERRA_RETURN,
QDE_FM(qde));
QuitHelp();
}
else if (lTimestamp != QDE_LTIMESTAMP(qde)) {
/*
* This file has changed since we lost focus. Put up
* an error message and go away. The reason we don't
* attempt to stick around and display the contents is
* that it's messy to get rid of the old DE and create a
* new one.
*/
ErrorFileChanged(qde);
}
}
}
break;
case MSG_ACTION:
switch(wParam) {
case IFW_BACK:
case IFW_CONTENTS:
case IFW_HISTORY:
case IFW_PRINT:
case IFW_SEARCH:
case IFW_PREV:
case IFW_NEXT:
case IFW_TOPICS:
case IFW_FIND:
/*
* For these commands, it isn't necessary to use the
* button bar's window procedure (which limits the commands
* to the main window). So, for these commands, we call the
* window procedure directly using our window handle.
*/
ButtonBarProc(hwnd, IWM_COMMAND, wParam, lParam);
break;
default:
// Transfer message. The parameters should be as needed for IWM_COMMAND.
SendMessage(ahwnd[GetWindowIndex(hwnd)].hwndButtonBar, IWM_COMMAND,
wParam, lParam);
break;
}
break;
case HWM_RESIZE:
// This message is sent when the windows need to be resized.
GetClientRect(hwnd, &rc);
SendMessage(hwnd, WM_SIZE,
IsZoomed(hwnd) ? SIZEFULLSCREEN : SIZENORMAL,
MAKELONG(rc.right - rc.left, rc.bottom - rc.top));
break;
case HWM_FOCUS:
/*
* This message is posted by buttons as they come up. The main
* window needs to regain the focus at this time.
*/
SetFocus(hwnd);
break;
case MSG_CLEANUP:
TmpCleanup();
break;
case MSG_FIND_HCW:
hwndParent = FindWindow("hcw_class", NULL);
break;
default:
defwinproc:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return(0L);
}
VOID STDCALL ToggleHotspots(BOOL fTurnOn)
{
HDE hde;
WORD msg;
if (fTurnOn)
msg = NAV_TOTALHILITEON;
else
msg = NAV_TOTALHILITEOFF;
if ((hde = HdeGetEnvHwnd(ahwnd[iCurWindow].hwndTitle)) != NULL) {
HDC hdc;
BOOL fMustRelease;
fMustRelease = FALSE;
hdc = HdsGetHde(hde);
if (hdc == NULL) {
hdc = GetAndSetHDC(ahwnd[iCurWindow].hwndTitle, hde);
fMustRelease = TRUE;
}
if (hdc) {
WNavMsgHde(hde, msg);
if (fMustRelease)
RelHDC(ahwnd[iCurWindow].hwndTitle, hde, hdc);
}
}
if ((hde = HdeGetEnvHwnd(ahwnd[iCurWindow].hwndTopic)) != NULL) {
HDC hdc;
BOOL fMustRelease;
fMustRelease = FALSE;
hdc = HdsGetHde(hde);
if (hdc == NULL) {
hdc = GetAndSetHDC(ahwnd[iCurWindow].hwndTopic, hde);
fMustRelease = TRUE;
}
if (hdc) {
WNavMsgHde(hde, msg);
if (fMustRelease)
RelHDC(ahwnd[iCurWindow].hwndTopic, hde, hdc);
}
}
}
/*******************
-
- Name: ButtonBarProc
*
* Purpose: Window proc for icon window.
*
******************/
LRESULT EXPORT ButtonBarProc (
HWND hwnd,
UINT msg,
WPARAM wParam,
LPARAM lParam
) {
HDC hdc;
PAINTSTRUCT ps;
RECT rctClient;
HPEN hpen;
HPEN hpenOld; // previously selected pen
HDE hde;
int yIcon;
switch(msg) {
case WM_CREATE:
SetWindowLong(hwnd, GIWW_BUTTONSTATE, (LONG) HbtnsCreate());
SetWindowLong(hwnd, GIWW_CXBUTTON, 1);
yIcon = HIWORD(LGetSmallTextExtent(" "));
yIcon += GetSystemMetrics(SM_CYBORDER) * 8;
SetWindowLong(hwnd, GIWW_CYBUTTON, yIcon);
SetWindowLong(hwnd, GIWW_CBUTTONS, 0);
break;
case WM_DESTROY:
FDestroyBs((HBTNS) GetWindowLong(hwnd, GIWW_BUTTONSTATE));
break;
case WM_LBUTTONDOWN:
break;
case WM_LBUTTONUP:
break;
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
FillRect(hdc, &ps.rcPaint, GetSysColorBrush(COLOR_BTNFACE));
GetClientRect(hwnd, &rctClient);
if (rctClient.bottom == ps.rcPaint.bottom) {
hpen = CreatePen(PS_SOLID, 1, GetSysColor(COLOR_WINDOWFRAME));
if (hpen) {
hpenOld = SelectObject(hdc, hpen);
MoveToEx(hdc, rctClient.left, rctClient.bottom-1, NULL);
LineTo(hdc, rctClient.right, rctClient.bottom-1);
if (hpenOld)
SelectObject(hdc, hpenOld);
DeleteObject(hpen);
}
}
EndPaint(hwnd, &ps);
break;
#if 0
case IWM_BUTTONKEY:
/*----------------------------------------------------------------------*\
* This is a special message used by the main window to query whether
* the indicated key is related to the buttons in this window. The
* parameters are used as follows:
* wParam: the value of the key being hit.
* lParam: a long with LOWORD being zero if keyup and HIWORD number of
* repeats for this key.
* A non-null return value indicates that the keystroke belongs to a
* button of this window and has been processed.
\*----------------------------------------------------------------------*/
hwndChild = HwndFromMnemonic(wParam, hwnd);
if (hwndChild != NULL) {
if (LOWORD(lParam)) {
if (IsWindowEnabled(hwndChild)) {
PostMessage(hwnd, IWM_COMMAND, GetWindowLong(hwndChild, GWW_ID),
(HWND) (LONG) hwndChild);
}
}
return 1l;
}
break;
#endif
case IWM_UPDBTN:
/*--------------------------------------------------------------------*\
* This is a special message used by the main window to indicate a change
* in the author-defined buttons.
* The return value is meaningless.
\*--------------------------------------------------------------------*/
VModifyButtons(hwnd, wParam, lParam);
break;
case IWM_GETHEIGHT:
yIcon = YGetArrangedHeight(hwnd, wParam);
return MAKELONG(yIcon, 0);
case IWM_RESIZE:
/*------------------------------------------------------------------*\
* This message is sent to the icon window when it's size changes.
* This seems like a good time to lay out the buttons again.
* wParam is the new width of the windows. This message returns
* the height of the icon window after laying out the buttons.
\*------------------------------------------------------------------*/
yIcon = YArrangeButtons(hwnd, wParam, FALSE);
return MAKELONG(yIcon, 0);
#ifdef OBSOLETE
22-Dec-1993 [ralphw] We now set the focus immediately when the button is
released. See sbutton.c.
case IWM_FOCUS:
/*
* This message is posted by a button when it has the focus. The
* icon window is responsible for finding if the focus is still in the
* button, and then setting it to the current window if its still set
* to the button.
*/
if (IsChild(hwnd, GetFocus()))
SetFocus(ahwnd[iCurWindow].hwndParent);
break;
#endif
case IWM_COMMAND:
/*-----------------------------------------------------------------*\
* This message is posted by a button when it has been clicked by
* the user. This replaces the normal windows WM_COMMAND.
* wParam is the id of the button
* lParam is the window handle (cast to HWND for Windows and PM)
\*-----------------------------------------------------------------*/
switch(wParam) {
case IFW_BACK:
{
int iWindow = GetWindowIndex(hwnd);
if (FBackAvailable(iWindow)) {
if (!FBackup(iWindow))
Error(wERRS_OOM, wERRA_RETURN);
}
}
break;
case IFW_HISTORY:
if (!IsValidWindow(hwndHistory) && !FCallPath())
Error(wERRS_OOM, wERRA_RETURN);
else {
SetFocus(hwndHistory);
SendMessage(hwndHistory, HWM_LBTWIDDLE, 0, 0L);
}
break;
case IFW_PRINT:
ASSERT(HdeGetEnv());
PrintHde(HdeGetEnv());
break;
case IFW_CLOSE:
QuitHelp();
break;
case IFW_CONTENTS:
/*
* Note that if we have a Contents Tab, then the Contents
* macro does NOT necessarily send us to that tab. Instead, the
* macro sends us to whatever tab was last active. If we have
* never seen a tab before, then the last active tab is the
* Contents tab.
*/
if (hfsGid && cntFlags.flags & GID_CONTENTS) {
cntFlags.idOldTab = 0; // force the Contents tab
goto DoTheTabThing;
}
hde = HdeGetEnv();
if (!hde)
break;
{
// REVIEW: does this take us to the Contents topic defined
// in the .HPJ file?
INT16 i = 0;
TopicGoto(fGOTO_ITO, (QV)&i);
}
break;
case IFW_SEARCH:
hde = HdeGetEnvHwnd(ahwnd[iCurWindow].hwndTopic);
if ((hde == NULL) || !(StateGetHde(hde) & NAV_SEARCHABLE))
break;
// intentionally fall through
case IFW_FIND:
case IFW_TOPICS:
// Hack -- because tabs are an enumerated type, we
// can't use them in this .C module. Change this when
// we switch all of WinHelp to C++.
if (wParam == IFW_SEARCH)
cntFlags.idOldTab = 1; // force the index tab
else if (wParam == IFW_FIND)
cntFlags.idOldTab = 2; // force the find tab
DoTheTabThing:
{
/*
* Avoid the temptation to use doTabSearch() as the first
* parameter. cntFlags.fUseGlobalIndex can change in the
* process of calling doTabSearch, and must, therefore, be
* specified AFTER doTabSearch() is called. We should not
* rely on order of evaluation, hence the two lines.
*/
int result = doTabSearch();
CompleteSearch(result, (!hfsGid || !cntFlags.fUseGlobalIndex));
}
break;
case IFW_TAB1:
case IFW_TAB2:
case IFW_TAB3:
case IFW_TAB4:
case IFW_TAB5:
case IFW_TAB6:
// Hack -- because tabs are an enumerated type, we
// can't use them in this .C module. Change this when
// we switch all of WinHelp to C++.
cntFlags.idOldTab = 2 + (wParam - IFW_FIND);
goto DoTheTabThing;
case (unsigned) ICON_USER:
VExecuteButtonMacro((HBTNS) GetWindowLong(hwnd, GIWW_BUTTONSTATE),
(HWND) lParam);
break;
case IFW_PREV:
hde = HdeGetEnvHwnd(ahwnd[iCurWindow].hwndTopic);
if ((hde != NULL) && (StateGetHde(hde) & NAV_PREVABLE))
JumpPrevTopic(hde);
break;
case IFW_NEXT:
hde = HdeGetEnvHwnd(ahwnd[iCurWindow].hwndTopic);
if ((hde != NULL) && (StateGetHde(hde) & NAV_NEXTABLE))
JumpNextTopic(hde);
break;
default:
break;
}
break;
case WM_SETREDRAW:
if (wParam) {
/*
* after redraw gets turned back on by DefWindowProc, make sure
* that the entire window gets repainted by invalidating it. (Cant
* do it before, because evidently redraw off means that it ignores
* the invalidate rect).
*/
DefWindowProc(hwnd, msg, wParam, lParam);
InvalidateRect(hwnd, NULL, TRUE);
break;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
default:
// Everything else comes here
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}
/*******************
-
- Name: TopicWndProc
*
* Purpose: Window procedure for the topic window
*
* Arguments: Standard window procedure
*
******************/
LRESULT EXPORT TopicWndProc (
HWND hwnd,
UINT msg,
WPARAM wParam,
LPARAM lParam
) {
int fScrollDir, fScroll;
HDC hdc;
PAINTSTRUCT ps;
HDE hde;
if (fFatalExit)
return(DefWindowProc(hwnd, msg, wParam, lParam ));
switch(msg) {
case WM_CREATE:
SetWindowLong(hwnd, GTWW_COBACK, coNIL);
break;
case WM_PAINT:
BeginPaint(hwnd, &ps);
hde = HdeGetEnvHwnd(hwnd);
if (hde) {
HDC hdcSave;
hdcSave= QdeFromGh(hde)->hdc;
SetPainting(hde, TRUE);
SetHDC(hde, ps.hdc);
RefreshHde(hde, &ps.rcPaint);
if (QdeFromGh(hde)->fVerScrollVis) {
ShowScrollBar(hwnd, SB_VERT, TRUE);
}
SetHDC(hde, hdcSave);
SetPainting(hde, FALSE);
}
EndPaint(hwnd, &ps);
break;
case WM_ERASEBKGND:
return (LRESULT) FPaintTopicBackground(hwnd, (HDC) wParam);
case WM_ASKPALETTE:
return SendMessage(GetParent(hwnd), WM_ASKPALETTE, wParam, lParam);
case WM_FINDNEWPALETTE:
return SendMessage(GetParent(hwnd), WM_FINDNEWPALETTE, wParam, lParam);
case WM_PALETTECHANGED:
BroadcastChildren(hwnd, WM_PALETTECHANGED, wParam, lParam);
break;
case WM_VSCROLL:
if (LOWORD(wParam) == SB_ENDSCROLL && !(fKeyDown(VK_CONTROL) && fKeyDown(VK_TAB)))
ToggleHotspots(FALSE);
if (LOWORD(wParam) == SB_ENDSCROLL && fHorzBarPending) {
/* (kevynct) Fix for H3.5 411:
* Force a re-paint of the non-client area if we have just
* inserted a horizontal scrollbar. The ugly global
* fHorzBarPending is SET in the scrollbar layer code, and RESET
* here.
*/
WRECT rc;
GetWindowWRect(hwnd, &rc);
SetWindowPos(hwnd, NULL, rc.left, rc.top, rc.cx,
rc.cy, SWP_DRAWFRAME | SWP_NOSIZE | SWP_NOMOVE);
fHorzBarPending = FALSE;
break;
}
// WARNING: Usually fall through
case WM_HSCROLL:
if (LOWORD(wParam) == SB_ENDSCROLL && !(fKeyDown(VK_CONTROL) && fKeyDown(VK_TAB)))
ToggleHotspots(FALSE);
hde = HdeGetEnvHwnd (hwnd);
if (hde) {
fScroll = MapScrollType(LOWORD(wParam));
if (fScroll) {
fScrollDir = (msg == WM_VSCROLL) ? SCROLL_VERT : SCROLL_HORZ;
hdc = GetAndSetHDC(hwnd, hde);
if (hdc) {
if (fScroll != SCROLL_ASPERTHUMB)
FScrollHde(hde, (SCRLAMT) fScroll, (SCRLDIR) fScrollDir, 1);
else
MoveToThumbHde(hde, HIWORD(wParam), (SCRLDIR) fScrollDir);
RelHDC(hwnd, hde, hdc);
}
}
}
break;
case WM_RBUTTONDOWN:
case WM_LBUTTONDOWN:
case WM_LBUTTONDBLCLK:
case WM_RBUTTONDBLCLK:
ToggleHotspots(FALSE);
// WARNING: Fall through
case WM_MOUSEMOVE:
case WM_LBUTTONUP:
case WM_RBUTTONUP:
// mouse actions: set environ to current window, and process mouse
// action on the associated de.
hde = HdeGetEnvHwnd(hwnd);
if (hde) {
hdc = GetAndSetHDC(hwnd, hde);
if (hdc) {
//POINTSTOPOINT(pPoint,MAKEPOINTS(lParam)); // lParam is not POINT nor POINTS!
//MouseInFrame(hde, (LPPOINT)&pPoint, msg, wParam);
MouseInFrame(hde, &MAKEPOINTS (lParam), msg, wParam);
RelHDC(hwnd, hde, hdc);
}
}
break;
case WM_TIMER:
CheckOurMouse(hwnd, msg, wParam);
break;
#if 0
case WM_COMMAND:
switch (LOWORD(wParam)) {
case IDEMBED_BUTTON:
if (HIWORD(lParam) == BN_CLICKED)
doBtnCmd((HWND) (lParam));
return TRUE;
}
break;
#endif
case WM_SETCURSOR:
if ((LOWORD(lParam) == HTCLIENT) && (HdeGetEnvHwnd(hwnd)))
return 0L;
// FALL THROUGH
default:
// Everything else comes here.
return(DefWindowProc(hwnd, msg, wParam, lParam));
break;
}
return(0L);
}
/*******************
-
- Name: NSRWndProc
*
* Purpose: Window procedure for the Non-Scrolling Region
*
* Arguments: Standard window procedure
*
******************/
static BOOL fShow; // Should I currently be shown?
LRESULT EXPORT NSRWndProc (
HWND hwnd,
UINT msg,
WPARAM wParam,
LPARAM lParam
) {
PAINTSTRUCT ps;
HDC hdc;
HDE hde;
switch(msg) {
case TIWM_GETFSHOW: // Sets the internal fShow varialbe
return (LONG) fShow;
break;
case TIWM_SETFSHOW: // Gets the internal fShow variable
fShow = wParam;
break;
case WM_CREATE:
SetWindowLong(hwnd, GNWW_COBACK, GetSysColor(COLOR_WINDOW));
break;
case WM_PAINT:
hdc = BeginPaint( hwnd, &ps );
hde = HdeGetEnvHwnd (hwnd);
if (hde) {
RECT rct;
HDC hdcSave;
hdcSave= QdeFromGh(hde)->hdc;
SetPainting(hde, TRUE);
SetHDC(hde, hdc);
RefreshHde(hde, (LPRECT)&ps.rcPaint);
GetClientRect(hwnd, &rct);
if (FTopicHasSR(hde) && rct.bottom != 0) {
HSGC hsgc;
QDE qde;
qde = QdeFromGh(hde);
hsgc = HsgcFromQde(qde);
FSetPen(hsgc, 1, coBLACK, coBLACK, wOPAQUE, roCOPY, wPenSolid);
MoveToEx(hsgc, rct.left, rct.bottom - 1, NULL);
LineTo(hsgc, rct.right, rct.bottom - 1);
FreeHsgc(hsgc);
}
SetHDC(hde, hdcSave);
SetPainting(hde, FALSE);
}
EndPaint(hwnd, &ps);
break;
case WM_LBUTTONDOWN:
if (wParam == SB_ENDSCROLL &&
!(fKeyDown(VK_CONTROL) && fKeyDown(VK_TAB)))
ToggleHotspots(FALSE);
// FALL THROUGH
default:
return TopicWndProc(hwnd, msg, wParam, lParam);
break;
}
return(0L);
}
/*******************
-
- Name: FPaintTopicBackground
*
* Purpose: Paints the topic background
*
*
* Arguments: hwnd - window handle of window to add shadow
* hdc - handle to display space (DC) for window
* wWidth - Width of the shadow
* wHeight - Height of the shadow
* bFrame - if TRUE, a frame will be painted around "fake" window.
*
* Returns: TRUE if the background was painted
*
******************/
static BOOL STDCALL FPaintTopicBackground(HWND hwnd, HDC hdc)
{
DWORD coBack; // background color to paint
HBRUSH hBrush; // brsh used to paint background
POINT ptOrg; // point to set as origin
RECT rctClient; // client rect to paint
/*
* color to paint is windows background color, unless overridden by a
* color in the window struct.
*/
coBack = GetWindowLong(hwnd, GTWW_COBACK);
if (coBack == coNIL)
coBack = GetSysColor(COLOR_WINDOW);
hBrush = CreateSolidBrush(coBack);
if (!hBrush)
return FALSE;
UnrealizeObject(hBrush);
ptOrg.x = ptOrg.y = 0;
ClientToScreen(hwnd, &ptOrg);
SetBrushOrgEx(hdc, ptOrg.x, ptOrg.y, NULL);
GetClientRect(hwnd, &rctClient);
FillRect(hdc, &rctClient, hBrush);
DeleteObject(hBrush);
return TRUE;
}
/*
* Notes about the focus window and hwndFocusCur:
*
* The focus window is currently updated by ProcessHotspotCmd and
* nowhere else. If an inter-file jump renders the current focus window
* invisible, (for example, by hiding the non-scrolling region window)
* the focus must be reset to the first available visible window before
* it (hwndFocusCur) is used again. This should only need to be done when
* processing the hotspot key message in the main help window proc.
*
* Currently, there are only two windows: NSR, and Topic, so I have been
* lazy (efficient?) about implementing these routines.
*/
#define HwndNextWindow(x) (((x) == ahwnd[iCurWindow].hwndTopic) ? ahwnd[iCurWindow].hwndTitle : ahwnd[iCurWindow].hwndTopic);
static VOID STDCALL ProcessHotspotCmd(UINT wNavCmd)
{
HWND hwndCur;
HDE hde;
hwndCur = HwndGetEnv();
/*
* If the current tabbing focus window does not have a DE, or is
* hidden, try the next one. If that fails, something is definately
* wrong, so return immediately. This assumes that there are only two
* tabbing windows.
*/
if (!FSetEnv(hwndFocusCur) || !IsWindowVisible(hwndFocusCur)) {
hwndFocusCur = HwndNextWindow(hwndFocusCur);
if (!FSetEnv(hwndFocusCur) || !IsWindowVisible(hwndFocusCur)) {
FSetEnv(hwndCur);
return;
}
}
if ((hde = HdeGetEnv()) != NULL) {
HDC hdc;
int wRes;
HDE hdeT;
HDC hdcT;
HWND hwndT;
int wResT;
HWND hwndNow;
hwndNow = hwndFocusCur;
hdc = GetAndSetHDC(hwndNow, hde);
if (!hdc)
return;
wRes = WNavMsgHde(hde, wNavCmd);
switch (wRes) {
case wNavNoMoreHotspots:
/*
* Attempt to move to next DE window. If the window is
* not there for some reason, we repeat the same command on
* the initial window. If we add more DEs, this method must
* change. In the case of two windows, we toggle.
*/
hwndT = HwndNextWindow(hwndFocusCur);
if (IsWindowVisible(hwndT) && FSetEnv(hwndT)) {
hdeT = HdeGetEnv();
hdcT = GetAndSetHDC(hwndT, hdeT);
if (hdcT) {
wResT = WNavMsgHde(hdeT, wNavCmd);
RelHDC(hwndT, hdeT, hdcT);
}
}
else
// NOTE: No DE enlisted for this window, so simulate failure
wResT = wNavFailure;
if (wResT != wNavSuccess)
/*
* Update the original window (returns Failure if no
* hotspots in any window)
*/
wRes = WNavMsgHde(hde, wNavCmd);
else
hwndFocusCur = hwndT; // Note that the current ENV is now hwndT
break;
case wNavSuccess:
break; // Do nothing
default:
NotReached();
}
RelHDC(hwndNow, hde, hdc);
}
FSetEnv(hwndCur);
}
/*******************
-
- Name: FExecKey
*
* Purpose: Maps key events into nagivator constants
*
* Arguments: hwnd - window handle to set in the DE
* wKey - param1 from the windows proc (i.e. the key)
* fDown - true iff key it is a down key event
* wRepeat - repeat count (currently not used)
*
* Returns: TRUE iff the event was handled
*
******************/
BOOL STDCALL FExecKey(HWND hwnd, UINT wKey, BOOL fDown)
{
int fRetVal = FALSE;
int fScroll = 0;
int fScrollDir;
HDC hdc;
POINT pt;
HDE hde;
HWND hwndCur;
WORD vk;
/*
* Both SYS and non-SYS key messages come here. We do not process them
* if we are iconized.
*/
if (IsIconic(GetParent(hwnd)))
return FALSE;
// REVIEW: we want this for popups?
hwndCur = HwndGetEnv();
if (!FSetEnv(hwnd))
return FALSE;
/*------------------------------------------------------------*\
| Build the high-order information like VkKeyScan returns.
\*------------------------------------------------------------*/
vk = (WORD) wKey;
vk |= (GetKeyState(VK_SHIFT) & 0x8000 ? 1 : 0) << 8;
hde = HdeGetEnv();
ASSERT (hde != NULL);
if (fDown) {
fRetVal = TRUE;
switch (vk) {
case VK_RIGHT:
fScroll = SCROLL_LINEDN;
fScrollDir = SCROLL_HORZ;
break;
case VK_LEFT:
fScroll = SCROLL_LINEUP;
fScrollDir = SCROLL_HORZ;
break;
case VK_DOWN:
fScroll = SCROLL_LINEDN;
fScrollDir = SCROLL_VERT;
break;
case VK_UP:
fScroll = SCROLL_LINEUP;
fScrollDir = SCROLL_VERT;
break;
case VK_NEXT:
fScroll = SCROLL_PAGEDN;
if (fKeyDown(VK_CONTROL))
fScrollDir = SCROLL_HORZ;
else
fScrollDir = SCROLL_VERT;
break;
case VK_PRIOR:
fScroll = SCROLL_PAGEUP;
if (fKeyDown(VK_CONTROL))
fScrollDir = SCROLL_HORZ;
else
fScrollDir = SCROLL_VERT;
break;
case VK_HOME:
fScroll = SCROLL_HOME;
if (fKeyDown(VK_CONTROL) || !QdeFromGh(hde)->fHorScrollVis)
fScrollDir = SCROLL_HORZ | SCROLL_VERT;
else
fScrollDir = SCROLL_HORZ;
break;
case VK_END:
fScroll = SCROLL_END;
if (fKeyDown(VK_CONTROL) || !QdeFromGh(hde)->fHorScrollVis)
fScrollDir = SCROLL_HORZ | SCROLL_VERT;
else
fScrollDir = SCROLL_HORZ;
break;
default:
fRetVal = FALSE;
break;
}
}
/*
* This SendMessage invokes a check to see if this key is a button
* accelerator? and processes the message!! Don't do this if we're a
* popup window.
*/
if (hwnd != hwndNote) {
if (ProcessMnemonic(vk, GetWindowIndex(hwnd), (fDown ? TRUE : FALSE))) {
FSetEnv(hwndCur);
return TRUE;
}
}
else { // this is a popup window
if (!fDown && ProcessMnemonic(vk, -1, (fDown ? TRUE : FALSE)))
return TRUE;
switch (vk) {
/*
* NOTE: This code is used directly by the glossary DE
* WndProc. The following is special purpose code to allow
* tabbing within a glossary DE.
*/
case VK_TAB:
if (fKeyDown(VK_MENU) || !fDown)
break;
hdc = GetAndSetHDC(hwnd, hde);
if (hdc) {
/*
* (kevynct) If we reach the end of the hotspot list,
* cycle back to the beginning/end.
*/
if (WNavMsgHde(hde, (fKeyDown(VK_SHIFT) ?
NAV_PREVHS : NAV_NEXTHS)) == wNavNoMoreHotspots) {
WNavMsgHde(hde, (fKeyDown(VK_SHIFT) ? NAV_PREVHS : NAV_NEXTHS));
}
RelHDC(hwnd, hde, hdc);
}
break;
case VK_RETURN:
/*
* NOTE: This code is used directly by the glossary DE
* WndProc. The following is special purpose code to allow
* ENTER within a glossary DE. If no hotspot is visible in the
* glossary, ENTER will bring the glossary down, otherwise it
* will activate the hotspot.
*/
{
if (!fDown)
break;
hdc = GetAndSetHDC(hwnd, hde);
if (hdc) {
WNavMsgHde(hde, NAV_HITHS);
RelHDC(hwnd, hde, hdc);
}
}
break;
default:
break;
}
}
if (fScroll) {
hdc = GetAndSetHDC(hwnd, hde);
if (hdc) {
POINTS pts;
FScrollHde(hde, (SCRLAMT) fScroll, (SCRLDIR) fScrollDir, 1);
GetCursorPos(&pt);
ScreenToClient(hwnd, &pt);
pts.x = (SHORT) pt.x;
pts.y = (SHORT) pt.y;
MouseInFrame(hde, &pts, NAV_MOUSEMOVED, 0);
RelHDC(hwnd, hde, hdc);
}
fRetVal = TRUE;
}
FSetEnv(hwndCur);
return fRetVal;
}
/*******************
-
- Name: MapScrollType
*
* Purpose: Maps a a mouse scroll event into a navigator
* constant.
*
* Arguments: code - type of mouse scroll
*
* Returns: navigator constant
*
******************/
static int STDCALL MapScrollType(int code)
{
int fScroll = 0;
switch(code) {
case SB_LINEUP:
fScroll = SCROLL_LINEUP;
break;
case SB_LINEDOWN:
fScroll = SCROLL_LINEDN;
break;
case SB_PAGEUP:
fScroll = SCROLL_PAGEUP;
break;
case SB_PAGEDOWN:
fScroll = SCROLL_PAGEDN;
break;
case SB_TOP:
fScroll = SCROLL_HOME;
break;
case SB_BOTTOM:
fScroll = SCROLL_END;
break;
case SB_THUMBPOSITION:
fScroll = SCROLL_ASPERTHUMB;
break;
#if 0
case SB_THUMBTRACK:
fScroll = SCROLL_ASPERTHUMB;
break;
#endif
}
return(fScroll);
}
/*******************
-
- Name: GetAndSetHDC
*
* Purpose: Gets and sets the hdc in a hde.
*
* Arguments: hwnd - window to use in getting the hdc (DC)
*
* Returns: what was placed in the HDE.
*
******************/
HDC STDCALL GetAndSetHDC(HWND hwnd, HDE hde)
{
HDC hdc;
ASSERT(IsValidWindow(hwnd));
hdc = GetDC(hwnd);
SetHDC(hde, hdc); /* We set the value even if it fails*/
/* so we do not have an old bogus */
/* value in the DE */
ASSERT(hdc); // This will warn of NO DC's
return(hdc);
}
/*******************
-
- Name: RelHDC
*
* Purpose: Releases the HDC from the HDE
*
* Arguments: hwnd - window handle used to create HDC (DC)
* hde - handle to display environment containing the HDC.
* hdc - device context to be released.
*
* Returns: Nothing.
*
******************/
void STDCALL RelHDC(HWND hwnd, HDE hde, HDC hdc)
{
SetHDC(hde, NULL);
ReleaseDC(hwnd, hdc);
}
#if 0 // we don't support icons in the help file any more
/***************************************************************************
FUNCTION: SetIconWord
PURPOSE: Set the current icon for this window
PARAMETERS:
hwnd
RETURNS:
COMMENTS:
There may be an icon specific to this window rather then the icon
for the window's class, so whenever we need to repaint the icon,
we must specify which icon to use.
MODIFICATION DATES:
05-Jan-1993 [ralphw]
***************************************************************************/
INLINE static void STDCALL SetIconWord(HWND hwnd)
{
HICON hiconLocal; // handle to icon, as store in wnd
if (IsIconic(hwnd)) { // if we're iconized, don't bother
hiconLocal = (HICON) GetWindowLong(ahwnd[MAIN_HWND].hwndParent, GHWL_HICON);
SetClassLong(hwnd, GCL_HICON,
(LONG) (hiconLocal ? hiconLocal : hIconDefault));
}
}
#endif
/*******************
*
- Name: VArrangeButtons
*
* Purpose: Lays out the buttons for the icon window. As a side effect,
* this proc also resizes the icon window, once the necessary
* size is known.
*
* Arguments: hwnd: The icon window
* cxWindow The width of the window in pixels
* fForce TRUE => force relayout, even if icon window didn't
* change in size (such as when adding or deleting
* a button)
*
* Returns: The height of the window in pixels.
*
******************/
int STDCALL YArrangeButtons(HWND hwnd, int xWindow, BOOL fForce)
{
BUTTONLAYOUT bl;
HBTNS hbtns;
PBS pbs;
WRECT rect; // current window size
#if defined(BIDI_MULT) // jgross
extern BOOL RtoL;
#endif
if ((hbtns = (HBTNS) GetWindowLong(hwnd, GIWW_BUTTONSTATE)) == NULL)
return 0;
bl.cBtn = (int) GetWindowLong(hwnd, GIWW_CBUTTONS);
if (bl.cBtn == 0)
return 0;
bl.xWnd = xWindow;
bl.xBtn = (int) GetWindowLong(hwnd, GIWW_CXBUTTON);
if (bl.xWnd < (bl.xBtn + ICON_SURROUND))
bl.xBtn = max((bl.xWnd - ICON_SURROUND), 1);
bl.yBtn = (int) GetWindowLong(hwnd, GIWW_CYBUTTON);
bl.cHoriz = (bl.xWnd - ICON_SURROUND)/(bl.xBtn);
if (bl.cHoriz <= 0)
bl.cHoriz = 1;
bl.yWnd = ICON_SURROUND + ICON_SURROUND +
((bl.cBtn - 1)/bl.cHoriz + 1)*(bl.yBtn);
GetWindowWRect(hwnd, &rect);
if (fForce || rect.cx != xWindow ||
rect.cy != bl.yWnd) {
MoveWindow(hwnd, 0, 0, bl.xWnd, bl.yWnd, FALSE);
pbs = (PBS) PtrFromGh(hbtns);
for (bl.iBtn = 0; bl.iBtn < pbs->cbp; bl.iBtn++)
#if defined(BIDI_MULT)
if (RtoL)
MoveWindow( pbs->rgbp[bl.iBtn].hwnd,
xWindow - bl.xBtn - bl.xBtn * (bl.iBtn % bl.cHoriz) + ICON_SURROUND,
bl.yBtn * (bl.iBtn / bl.cHoriz) + ICON_SURROUND,
bl.xBtn,
bl.yBtn,
FALSE
);
else
#endif
MoveWindow(pbs->rgbp[bl.iBtn].hwnd,
bl.xBtn * (bl.iBtn % bl.cHoriz) + ICON_SURROUND,
bl.yBtn * (bl.iBtn / bl.cHoriz) + ICON_SURROUND,
bl.xBtn,
bl.yBtn,
FALSE);
InvalidateRect(hwnd, NULL, TRUE);
}
return bl.yWnd;
}
INLINE static int STDCALL YGetArrangedHeight(HWND hwnd, int xWindow)
{
BUTTONLAYOUT bl;
bl.cBtn = (int) GetWindowLong(hwnd, GIWW_CBUTTONS);
if (bl.cBtn == 0)
return 0;
bl.iBtn = 0;
bl.xWnd = xWindow;
bl.xBtn = (int) GetWindowLong(hwnd, GIWW_CXBUTTON);
if (bl.xWnd < (bl.xBtn + ICON_SURROUND))
bl.xBtn = max((bl.xWnd - ICON_SURROUND), 1);
bl.yBtn = (int) GetWindowLong(hwnd, GIWW_CYBUTTON);
bl.cHoriz = (bl.xWnd - ICON_SURROUND)/(bl.xBtn);
if (bl.cHoriz <= 0)
bl.cHoriz = 1;
bl.yWnd = ICON_SURROUND + ICON_SURROUND +
((bl.cBtn - 1)/bl.cHoriz + 1)*(bl.yBtn);
return bl.yWnd;
}
/***************************************************************************
*
- Name: DestroyFloatingMenu
-
* Purpose: Destroys the floating menu; used when Help exits.
*
* Arguments: None.
*
* Returns: Nothing.
*
* Globals Used: hmenuFloating
*
* +++
*
* Notes: Called from WM_CLOSE handler in hwproc.c : HelpWndProc().
*
***************************************************************************/
INLINE static VOID STDCALL DestroyFloatingMenu(VOID)
{
if (hmenuFloating)
DestroyMenu(hmenuFloating);
hmenuFont = hmenuOnTop = hmenuFloating = NULL;
}
/*******************
**
** Name: VUpdateDefaultColorsHde
**
** Purpose: Changes the defaults for the de when the user changes the
** standard windows colors in win.ini.
**
** Arguments: hde The DE or NULLl, where no action will be taken.
** fAuthoredBack TRUE if there was an author-defined background
** colour.
**
** Returns: nothing.
**
*******************/
static VOID STDCALL VUpdateDefaultColorsHde(HDE hde, BOOL fAuthoredBack, int iWindow)
{
ASSERT(hde);
QdeFromGh(hde)->coFore = GetSysColor(COLOR_WINDOWTEXT);
if (!fAuthoredBack)
QdeFromGh(hde)->coBack = GetSysColor(COLOR_WINDOW);
else if (GetSysColor(COLOR_WINDOW) != RGB(255, 255, 255) ||
GetSysColor(COLOR_WINDOWTEXT) != 0) {
QdeFromGh(hde)->coBack = GetSysColor(COLOR_WINDOW);
SetWindowLong(ahwnd[iWindow].hwndTopic, GTWW_COBACK,
QdeFromGh(hde)->coBack);
}
else
FFocusSzHde(ahwnd[iWindow].pszMemberName, hde, FALSE);
return;
}
/***************************************************************************
FUNCTION: CompleteSearch
PURPOSE: Called after doTabSearch, doSearch, and by doAlink
PARAMETERS:
iHitNum
RETURNS:
COMMENTS:
MODIFICATION DATES:
25-Oct-1993 [ralphw]
***************************************************************************/
void STDCALL CompleteSearch(int iHitNum, BOOL fLocalIndex)
{
HBT hbtViola;
QDE qde = QdeFromGh(HdeGetEnv());
BOOL fWindowSet = FALSE;
PSTR psz;
ClearMacroFlag();
if (!qde) {
/*
* This happens when Finder is called from an app when we were
* already looking at the same help file.
*/
qde = (QDE) HdeGetEnvHwnd(ahwnd[MAIN_HWND].hwndTopic);
ASSERT(qde);
FSetEnv(ahwnd[MAIN_HWND].hwndTopic);
}
/*
* iHitNum is always zero if the search set is empty. HdeGetEnv()
* may become nil in the obscure case that help quits while the
* dialog is up.
*/
if (iHitNum > 0) {
LA la;
RC rc;
ASSERT(qde->hdc != (HDC) 0x66666666); // If asserts, qde is freed memory
rc = !fLocalIndex ?
RcGetLAFromGid(qde, (ISS) (iHitNum - 1), &la, szSavedKeyword) :
RcGetLAFromHss(qde->hss, qde, (ISS) (iHitNum - 1), &la, szSavedKeyword);
if (rc == rcMacroIndex)
return; // macro has already been run
else if (rc != rcSuccess) {
PostErrorMessage(wERRS_NOTOPIC);
if (fNoQuit)
fNoQuit = FALSE;
else if (AreAnyWindowsVisible(0) < 0)
PostMessage(ahwnd[MAIN_HWND].hwndParent, WM_CLOSE, 0, 0);
return;
}
qde = QdeFromGh(HdeGetEnv()); // Can change in call to RcGetLAFromHss
if ((hbtViola = HbtOpenBtreeSz(txtViola, QDE_HFS(qde), fFSOpenReadOnly))) {
int iWindow;
if (RcLookupByKey(hbtViola, (KEY) &la.pa, NULL, &iWindow) == rcSuccess) {
#ifdef _DEBUG
char szBuf[256];
wsprintf(szBuf, "Window footnote: %s\r\n",
ConvertToWindowName(iWindow, qde));
SendStringToParent(szBuf);
#endif
fWindowSet = TRUE;
FFocusSzHde(ConvertToWindowName(iWindow, qde), (HDE) qde, FALSE);
}
RcCloseBtreeHbt(hbtViola);
}
/*
* If a window name is specified in the contents base file, then
* ALL topics are to be displayed in that window.
*/
if (!fWindowSet && (pszHelpBase) && (psz = StrChrDBCS(pszHelpBase, WINDOWSEPARATOR))) {
if (IsWindowVisible(ahwnd[MAIN_HWND].hwndParent))
CloseWin((PSTR) txtMain);
FFocusSzHde(psz + 1, (HDE) qde, FALSE);
}
else if (!fWindowSet && !IsWindowVisible(ahwnd[iCurWindow].hwndParent))
ShowWindow(ahwnd[iCurWindow].hwndParent,
IsIconic(ahwnd[iCurWindow].hwndParent) ? SW_RESTORE : SW_SHOW);
TopicGoto(fGOTO_LA, (LPVOID) &la);
}
switch (iHitNum) {
case CONTEXT_SEARCH:
case FTS_HASH_SEARCH:
case FTS_VA_SEARCH:
case EXT_TAB_CONTEXT:
case EXT_TAB_MACRO:
case TAB_ALREADY_UP:
ProcessTabResult(iHitNum);
break;
case NO_TABS:
/*
* No keywords, no Contents Tab, no Find, no Extensable tab, no
* nothing nohow.
*/
{
INT16 topic = 0;
if (AreAnyWindowsVisible(0) < 0) {
iCurWindow = MAIN_HWND;
ShowWindow(ahwnd[iCurWindow].hwndParent,
IsIconic(ahwnd[iCurWindow].hwndParent) ? SW_RESTORE : SW_SHOW);
}
TopicGoto(fGOTO_ITO, (LPVOID) &topic);
}
break;
default:
// The search failed -- if there are no visible windows, then
// close help.
if (fNoQuit)
fNoQuit = FALSE;
else if (AreAnyWindowsVisible(0) < 0)
CloseHelp();
break;
}
}
static void STDCALL doMsgJump(LPVOID pv, WORD wFlag, UINT16 cmd, LONG itcx)
{
JD jd;
jd.word = wFlag;
if (!jd.bf.fNote) {
if (AreAnyWindowsVisible(0) < 0) {
HDE hde = GetMacroHde(); // make certain we have a help file
}
TopicGoto(cmd, pv);
}
else {
ShowNote(NULL,
HdeGetEnvHwnd((jd.bf.fFromNSR ?
ahwnd[iCurWindow].hwndTitle : ahwnd[iCurWindow].hwndTopic)),
itcx, cmd);
}
}
static void STDCALL CheckOurMouse(HWND hwnd, UINT msg, WPARAM wParam)
{
HDE hde = HdeGetEnvHwnd(hwnd);
if (hde) {
POINT pt;
POINTS pts;
DWORD dw;
HDC hdc;
dw = GetMessagePos();
pt.x = LOWORD(dw);
pt.y = HIWORD(dw);
ScreenToClient(hwnd, &pt);
hdc = GetAndSetHDC(hwnd, hde);
if (hdc) {
pts.x = (SHORT) pt.x;
pts.y = (SHORT) pt.y;
MouseInFrame(hde, &pts, msg, (UINT) wParam);
RelHDC(hwnd, hde, hdc);
}
}
}
BOOL STDCALL NextTopic(BOOL fFirst)
{
HDE hde;
if (fSequence == 5 || fSequence == 6)
return NextCntTopic();
if ((hde = HdeGetEnvHwnd(ahwnd[iCurWindow].hwndTopic)) != NULL) {
QDE qde = QdeFromGh(hde);
TLP tlp;
tlp.va.dword = fFirst ? DwFirstSeqTopic(qde) : DwNextSeqTopic(qde);
tlp.lScroll = 0;
// If the next topic is the same as the current topic, then
// we've reached the end of the help file.
if (tlp.va.dword == dwSequence)
return FALSE;
else
dwSequence = tlp.va.dword;
if (tlp.va.dword != vaNil)
TopicGoto(fGOTO_TLP, (QV)&tlp);
else
return FALSE;
return TRUE;
}
dwSequence = 0;
return FALSE;
}
void STDCALL JumpVA(DWORD dwTopic)
{
TLP tlp;
tlp.va.dword = dwTopic;
tlp.lScroll = 0;
if (tlp.va.dword != vaNil)
TopicGoto(fGOTO_TLP, (LPVOID) &tlp);
}
static void STDCALL ForceRepaint(QDE qde, HWND hwnd, BOOL fFontChanged)
{
// If wParam is TRUE, then we have changed the size
// of the fonts.
RECT rc;
HDC hdc;
if (fFontChanged) {
DestroyFontTablePdb(QDE_PDB(qde));
DestroyFntInfoQde(qde);
FInitFntInfoQde(qde);
}
ASSERT(hwnd);
hdc = GetAndSetHDC(hwnd, (HDE) qde);
if (hdc) {
GetClientRect(hwnd, &rc);
SetSizeHdeQrct((HDE) qde, &rc, TRUE);
InvalidateRect(hwnd, NULL, TRUE);
RelHDC(hwnd, (HDE) qde, hdc);
}
}
BOOL STDCALL ProcessTabResult(int result)
{
HBT hbtViola;
QDE qde = QdeFromGh(GetMacroHde());
BOOL fWindowSet = FALSE;
PSTR psz;
switch (result) {
case CONTEXT_SEARCH:
if (!IsWindowVisible(ahwnd[iCurWindow].hwndParent) &&
pszHelpBase && !StrChrDBCS(pszHelpBase, WINDOWSEPARATOR) &&
!StrChrDBCS(szSavedContext, WINDOWSEPARATOR))
ShowWindow(ahwnd[iCurWindow].hwndParent,
IsIconic(ahwnd[iCurWindow].hwndParent) ? SW_RESTORE : SW_SHOW);
if (szSavedContext[0] == chMACRO) {
Execute(szSavedContext + 1);
}
else {
PSTR psz = StrChrDBCS(szSavedContext, FILESEPARATOR);
ASSERT(psz);
*psz = '\0';
if (!StrChrDBCS(psz + 1, WINDOWSEPARATOR) &&
StrChrDBCS(pszHelpBase, WINDOWSEPARATOR)) {
iCurWindow = MAIN_HWND;
ShowWindow(ahwnd[iCurWindow].hwndParent,
IsIconic(ahwnd[iCurWindow].hwndParent) ? SW_RESTORE : SW_SHOW);
}
FJumpId(psz + 1, szSavedContext);
}
return TRUE;
case FTS_HASH_SEARCH:
// REVIEW: needs to be tested! Only works with compiler-generated
// fts files
ASSERT(!StrChrDBCS(szSavedContext, WINDOWSEPARATOR));
if ((hbtViola = HbtOpenBtreeSz(txtViola, QDE_HFS(qde), fFSOpenReadOnly))) {
int iWindow;
ADDR addr;
if (RcLookupByKey(QDE_HBTCONTEXT(qde), (KEY) &tabLparam, NULL,
&addr) == rcSuccess) {
if (RcLookupByKey(hbtViola, (KEY) &addr, NULL, &iWindow) == rcSuccess) {
#ifdef _DEBUG
char szBuf[256];
wsprintf(szBuf, "Window footnote: %s\r\n",
ConvertToWindowName(iWindow, qde));
SendStringToParent(szBuf);
#endif
strcat(szSavedContext, ">");
strcat(szSavedContext, ConvertToWindowName(iWindow, qde));
fWindowSet = TRUE;
}
}
RcCloseBtreeHbt(hbtViola);
}
if (!fWindowSet && (psz = StrChrDBCS(pszHelpBase, WINDOWSEPARATOR))) {
strcat(szSavedContext, psz);
}
FJumpHash(szSavedContext, tabLparam);
return TRUE;
case FTS_VA_SEARCH:
{
TLPHELP tlphelp;
tlphelp.cb = sizeof(TLPHELP);
tlphelp.tlp.va.dword = tabLparam;
tlphelp.tlp.lScroll = 0;
ASSERT(!StrChrDBCS(szSavedContext, WINDOWSEPARATOR));
if ((hbtViola = HbtOpenBtreeSz(txtViola, QDE_HFS(qde),
fFSOpenReadOnly))) {
int iWindow;
ADDR addr = AddrFromVA(tlphelp.tlp.va, qde);
if (addr != -1) {
if (RcLookupByKey(hbtViola, (KEY) &addr, NULL, &iWindow) == rcSuccess) {
#ifdef _DEBUG
char szBuf[256];
wsprintf(szBuf, "Window footnote: %s\r\n",
ConvertToWindowName(iWindow, qde));
SendStringToParent(szBuf);
#endif
strcat(szSavedContext, ">");
strcat(szSavedContext, ConvertToWindowName(iWindow, qde));
fWindowSet = TRUE;
}
}
RcCloseBtreeHbt(hbtViola);
}
if (!fWindowSet && (psz = StrChrDBCS(pszHelpBase, WINDOWSEPARATOR))) {
strcat(szSavedContext, psz);
}
if (!FWinHelp(szSavedContext, cmdTLP, (DWORD) &tlphelp))
Error(wERRS_OOM, wERRA_RETURN);
}
return TRUE;
case EXT_TAB_CONTEXT:
FWinHelp((PCSTR) tabLparam, HELP_CONTEXT, tabWparam);
return TRUE;
case EXT_TAB_MACRO:
if (!IsWindowVisible(ahwnd[iCurWindow].hwndParent) &&
pszHelpBase && !StrChrDBCS(pszHelpBase, WINDOWSEPARATOR))
ShowWindow(ahwnd[iCurWindow].hwndParent,
IsIconic(ahwnd[iCurWindow].hwndParent) ? SW_RESTORE : SW_SHOW);
Execute((PCSTR) tabLparam);
return TRUE;
case TAB_ALREADY_UP:
return TRUE;
default:
return FALSE;
}
}
int STDCALL AreAnyWindowsVisible(int iStart)
{
for (; iStart < MAX_WINDOWS; iStart++) {
if (ahwnd[iStart].hwndParent &&
IsWindowVisible(ahwnd[iStart].hwndParent))
return iStart;
}
return -1;
}