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.
275 lines
9.3 KiB
275 lines
9.3 KiB
/**************************** Module Header ********************************\
|
|
* Module Name: help.c
|
|
*
|
|
* Copyright (c) 1985 - 1999, Microsoft Corporation
|
|
*
|
|
* Help function
|
|
*
|
|
* History:
|
|
* 04-15-91 JimA Ported.
|
|
\***************************************************************************/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
DWORD _GetWindowContextHelpId(PWND pWnd)
|
|
{
|
|
return (DWORD)(ULONG_PTR)_GetProp(pWnd, MAKEINTATOM(gpsi->atomContextHelpIdProp),
|
|
PROPF_INTERNAL);
|
|
}
|
|
|
|
|
|
BOOL _SetWindowContextHelpId(PWND pWnd, DWORD dwContextId)
|
|
{
|
|
//If dwContextId is NULL, then this implies that the caller wants to
|
|
// remove the dwContextId associated with this Window.
|
|
if(dwContextId == 0) {
|
|
InternalRemoveProp(pWnd, MAKEINTATOM(gpsi->atomContextHelpIdProp),
|
|
PROPF_INTERNAL);
|
|
return(TRUE);
|
|
}
|
|
|
|
return (InternalSetProp(pWnd, MAKEINTATOM(gpsi->atomContextHelpIdProp),
|
|
(HANDLE)LongToHandle( dwContextId ), PROPF_INTERNAL | PROPF_NOPOOL));
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* SendHelpMessage
|
|
*
|
|
*
|
|
\***************************************************************************/
|
|
|
|
void xxxSendHelpMessage(
|
|
PWND pwnd,
|
|
int iType,
|
|
int iCtrlId,
|
|
HANDLE hItemHandle,
|
|
DWORD dwContextId)
|
|
{
|
|
HELPINFO HelpInfo;
|
|
long lValue;
|
|
|
|
CheckLock(pwnd);
|
|
|
|
HelpInfo.cbSize = sizeof(HELPINFO);
|
|
HelpInfo.iContextType = iType;
|
|
HelpInfo.iCtrlId = iCtrlId;
|
|
HelpInfo.hItemHandle = hItemHandle;
|
|
HelpInfo.dwContextId = dwContextId;
|
|
|
|
lValue = _GetMessagePos();
|
|
HelpInfo.MousePos.x = GET_X_LPARAM(lValue);
|
|
HelpInfo.MousePos.y = GET_Y_LPARAM(lValue);
|
|
|
|
xxxSendMessage(pwnd, WM_HELP, 0, (LPARAM)(LPHELPINFO)&HelpInfo);
|
|
}
|
|
|
|
|
|
/*
|
|
* Modal loop for when the user has selected the help icon from the titlebar
|
|
*
|
|
*/
|
|
VOID xxxHelpLoop(PWND pwnd)
|
|
{
|
|
HWND hwndChild;
|
|
PWND pwndChild;
|
|
PWND pwndControl;
|
|
MSG msg;
|
|
RECT rc;
|
|
int cBorders;
|
|
PTHREADINFO ptiCurrent = PtiCurrent();
|
|
DLGENUMDATA DlgEnumData;
|
|
TL tlpwndChild;
|
|
|
|
CheckLock(pwnd);
|
|
UserAssert(IsWinEventNotifyDeferredOK());
|
|
|
|
xxxWindowEvent(EVENT_SYSTEM_CONTEXTHELPSTART, pwnd, OBJID_WINDOW, INDEXID_CONTAINER, 0);
|
|
|
|
zzzSetCursor(SYSCUR(HELP));
|
|
xxxCapture(ptiCurrent, pwnd, SCREEN_CAPTURE);
|
|
|
|
cBorders = GetWindowBorders(pwnd->style, pwnd->ExStyle, TRUE, FALSE);
|
|
|
|
CopyInflateRect(&rc, &pwnd->rcWindow, -cBorders * SYSMET(CXBORDER), -cBorders * SYSMET(CYBORDER));
|
|
|
|
while (ptiCurrent->pq->spwndCapture == pwnd) {
|
|
if (!xxxPeekMessage(&msg, NULL, 0, 0, PM_NOYIELD | PM_NOREMOVE)) {
|
|
xxxWaitMessage();
|
|
continue;
|
|
}
|
|
|
|
if (msg.message == WM_NCLBUTTONDOWN) {
|
|
break;
|
|
} else if (msg.message == WM_LBUTTONDOWN) {
|
|
/*
|
|
* If user clicked outside of window client, bail out now.
|
|
*/
|
|
if (!PtInRect(&rc, msg.pt))
|
|
break;
|
|
|
|
/*
|
|
* WindowHitTest() won't return a static control's handle
|
|
*/
|
|
hwndChild = xxxWindowHitTest(pwnd, msg.pt, NULL, 0);
|
|
pwndChild = ValidateHwnd( hwndChild );
|
|
ThreadLock(pwndChild, &tlpwndChild);
|
|
|
|
if (pwndChild && FIsParentDude(pwndChild))
|
|
{
|
|
/*
|
|
* If this is a dialog class, then one of three things has
|
|
* happened:
|
|
*
|
|
* o This is a static text control
|
|
* o This is the background of the dialog box.
|
|
*
|
|
* What we do is enumerate the child windows and see if
|
|
* any of them contain the current cursor point. If they do,
|
|
* change our window handle and continue on. Otherwise,
|
|
* return doing nothing -- we don't want context-sensitive
|
|
* help for a dialog background.
|
|
*
|
|
* If this is a group box, then we might have clicked on a
|
|
* disabled control, so we enumerate child windows to see
|
|
* if we get another control.
|
|
*/
|
|
|
|
/*
|
|
* We're enumerating a dialog's children. So, if we don't
|
|
* find any matches, hwndChild will be NULL and the check
|
|
* below will drop out.
|
|
*/
|
|
DlgEnumData.pwndDialog = pwndChild;
|
|
DlgEnumData.pwndControl = NULL;
|
|
DlgEnumData.ptCurHelp = msg.pt;
|
|
xxxInternalEnumWindow(pwndChild, EnumPwndDlgChildProc, (LPARAM)&DlgEnumData, BWL_ENUMCHILDREN);
|
|
pwndControl = DlgEnumData.pwndControl;
|
|
} else {
|
|
pwndControl = pwndChild;
|
|
}
|
|
|
|
/*
|
|
* If we click on nothing, just exit.
|
|
*/
|
|
if (pwndControl == pwnd) {
|
|
pwndControl = NULL;
|
|
}
|
|
|
|
/*
|
|
* HACK ALERT (Visual Basic 4.0) - they have their own non-window
|
|
* based controls that draw directly on the main dialog. In order
|
|
* to provide help for these controls, we pass along the WM_HELP
|
|
* message iff the main dialog has a context id assigned.
|
|
*
|
|
* If the top level window has its own context help ID,
|
|
* then pass it in the context help message.
|
|
*/
|
|
if (!pwndControl) {
|
|
if (_GetProp(pwnd, MAKEINTATOM(gpsi->atomContextHelpIdProp), TRUE))
|
|
pwndControl = pwnd;
|
|
}
|
|
|
|
if (pwndControl) {
|
|
PWND pwndSend;
|
|
int id;
|
|
TL tlpwndSend;
|
|
TL tlpwndControl;
|
|
|
|
ThreadLockAlways(pwndControl, &tlpwndControl);
|
|
|
|
zzzSetCursor(SYSCUR(ARROW));
|
|
xxxReleaseCapture();
|
|
xxxRedrawTitle(pwnd, DC_BUTTONS);
|
|
ClrWF(pwnd, WFHELPBUTTONDOWN);
|
|
xxxGetMessage(&msg, NULL, 0, 0);
|
|
|
|
xxxWindowEvent(EVENT_OBJECT_STATECHANGE, pwnd, OBJID_TITLEBAR,
|
|
INDEX_TITLEBAR_HELPBUTTON, FALSE);
|
|
|
|
xxxWindowEvent(EVENT_SYSTEM_CONTEXTHELPEND, pwnd, OBJID_WINDOW,
|
|
INDEXID_CONTAINER, FALSE);
|
|
|
|
/*
|
|
* Determine the ID of the control
|
|
* We used to always sign extend, but Win98 doesn't do that
|
|
* so we only sign extend 0xffff. MCostea #218711
|
|
*/
|
|
if (TestwndChild(pwndControl)) {
|
|
id = PTR_TO_ID(pwndControl->spmenu);
|
|
if (id == 0xffff) {
|
|
id = -1;
|
|
}
|
|
} else {
|
|
id = -1;
|
|
}
|
|
|
|
/*
|
|
* Disabled controls and static controls won't pass this
|
|
* on to their parent, so instead, we send the message to
|
|
* their parent.
|
|
*/
|
|
|
|
if (TestWF(pwndControl, WFDISABLED)) {
|
|
PWND pwndParent = _GetParent(pwndControl);
|
|
if (!pwndParent)
|
|
{
|
|
ThreadUnlock( &tlpwndControl );
|
|
ThreadUnlock( &tlpwndChild );
|
|
return;
|
|
}
|
|
pwndSend = pwndParent;
|
|
} else {
|
|
pwndSend = pwndControl;
|
|
}
|
|
|
|
ThreadLockAlways(pwndSend, &tlpwndSend);
|
|
xxxSendHelpMessage( pwndSend, HELPINFO_WINDOW, id,
|
|
(HANDLE)HWq(pwndControl), GetContextHelpId(pwndControl));
|
|
ThreadUnlock(&tlpwndSend);
|
|
ThreadUnlock(&tlpwndControl);
|
|
ThreadUnlock(&tlpwndChild);
|
|
return;
|
|
}
|
|
ThreadUnlock(&tlpwndChild);
|
|
break;
|
|
|
|
}
|
|
else if ((msg.message == WM_RBUTTONDOWN) ||
|
|
(msg.message == WM_MBUTTONDOWN) ||
|
|
(msg.message == WM_XBUTTONDOWN)) {
|
|
/*
|
|
* fix bug 29852; break the loop for right and middle buttons
|
|
* and pass along the messages to the control
|
|
*/
|
|
break;
|
|
}
|
|
else if (msg.message == WM_MOUSEMOVE) {
|
|
if (PtInRect(&rc, msg.pt))
|
|
zzzSetCursor(SYSCUR(HELP));
|
|
else
|
|
zzzSetCursor(SYSCUR(ARROW));
|
|
}
|
|
else if (msg.message == WM_KEYDOWN && msg.wParam == VK_ESCAPE)
|
|
{
|
|
xxxGetMessage( &msg, NULL, 0, 0 );
|
|
break;
|
|
}
|
|
|
|
xxxGetMessage(&msg, NULL, 0, 0);
|
|
xxxTranslateMessage(&msg, 0);
|
|
xxxDispatchMessage(&msg);
|
|
}
|
|
|
|
xxxReleaseCapture();
|
|
zzzSetCursor(SYSCUR(ARROW));
|
|
xxxRedrawTitle(pwnd, DC_BUTTONS);
|
|
|
|
ClrWF(pwnd, WFHELPBUTTONDOWN);
|
|
xxxWindowEvent(EVENT_OBJECT_STATECHANGE, pwnd, OBJID_TITLEBAR,
|
|
INDEX_TITLEBAR_HELPBUTTON, 0);
|
|
|
|
xxxWindowEvent(EVENT_SYSTEM_CONTEXTHELPEND, pwnd, OBJID_WINDOW,
|
|
INDEXID_CONTAINER, 0);
|
|
}
|