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.
284 lines
8.4 KiB
284 lines
8.4 KiB
/****************************** Module Header ******************************\
|
|
* Module Name: capture.c
|
|
*
|
|
* Copyright (c) 1985 - 1999, Microsoft Corporation
|
|
*
|
|
* History:
|
|
* 08-Nov-1990 DavidPe Created.
|
|
* 01-Feb-1991 MikeKe Added Revalidation code
|
|
\***************************************************************************/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
/***************************************************************************\
|
|
* xxxSetCapture (API)
|
|
*
|
|
* This function sets the capture window for the current queue.
|
|
*
|
|
* History:
|
|
* 08-Nov-1990 DavidPe Created.
|
|
\***************************************************************************/
|
|
|
|
PWND xxxSetCapture(
|
|
PWND pwnd)
|
|
{
|
|
PQ pq;
|
|
PWND pwndCaptureOld;
|
|
HWND hwndCaptureOld;
|
|
PTHREADINFO ptiCurrent = PtiCurrent();
|
|
|
|
pq = (PQ)PtiCurrent()->pq;
|
|
|
|
/*
|
|
* If the capture is locked, bail
|
|
*/
|
|
if (pq->QF_flags & QF_CAPTURELOCKED) {
|
|
RIPMSG2(RIP_WARNING, "xxxSetCapture(%#p): Capture is locked. pq:%#p", pwnd, pq);
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* Don't allow the app to set capture to a window
|
|
* from another queue.
|
|
*/
|
|
if ((pwnd != NULL) && GETPTI(pwnd)->pq != pq)
|
|
return NULL;
|
|
|
|
/*
|
|
* If full screen capture don't allow any other capture
|
|
*/
|
|
if (gspwndScreenCapture)
|
|
return NULL;
|
|
|
|
pwndCaptureOld = pq->spwndCapture;
|
|
hwndCaptureOld = HW(pwndCaptureOld);
|
|
|
|
xxxCapture(ptiCurrent, pwnd, CLIENT_CAPTURE);
|
|
|
|
if (hwndCaptureOld != NULL) {
|
|
|
|
if (RevalidateHwnd(hwndCaptureOld))
|
|
return pwndCaptureOld;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* xxxReleaseCapture (API)
|
|
*
|
|
* This function release the capture for the current queue.
|
|
*
|
|
* History:
|
|
* 08-Nov-1990 DavidPe Created.
|
|
* 16-May-1991 MikeKe Changed to return BOOL
|
|
\***************************************************************************/
|
|
|
|
BOOL xxxReleaseCapture(VOID)
|
|
{
|
|
PTHREADINFO ptiCurrent = PtiCurrent();
|
|
/*
|
|
* If the capture is locked, bail
|
|
*/
|
|
if (ptiCurrent->pq->QF_flags & QF_CAPTURELOCKED) {
|
|
RIPMSG0(RIP_WARNING, "xxxReleaseCapture: Capture is locked");
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* If we're releasing the capture from a window during tracking,
|
|
* cancel tracking first.
|
|
*/
|
|
if (ptiCurrent->pmsd != NULL) {
|
|
|
|
/*
|
|
* Only remove the tracking rectangle if it's
|
|
* been made visible.
|
|
*/
|
|
if (ptiCurrent->TIF_flags & TIF_TRACKRECTVISIBLE) {
|
|
|
|
bSetDevDragRect(gpDispInfo->hDev, NULL, NULL);
|
|
|
|
if (!(ptiCurrent->pmsd->fDragFullWindows))
|
|
xxxDrawDragRect(ptiCurrent->pmsd, NULL, DDR_ENDCANCEL);
|
|
|
|
ptiCurrent->TIF_flags &= ~(TIF_TRACKRECTVISIBLE | TIF_MOVESIZETRACKING);
|
|
}
|
|
}
|
|
|
|
xxxCapture(ptiCurrent, NULL, NO_CAP_CLIENT);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* xxxCapture
|
|
*
|
|
* This is the workhorse routine of capture setting and releasing.
|
|
*
|
|
* History:
|
|
* 13-Nov-1990 DavidPe Created.
|
|
\***************************************************************************/
|
|
|
|
VOID xxxCapture(
|
|
PTHREADINFO pti,
|
|
PWND pwnd,
|
|
UINT code)
|
|
{
|
|
CheckLock(pwnd);
|
|
UserAssert(IsWinEventNotifyDeferredOK());
|
|
|
|
if ((gspwndScreenCapture == NULL) ||
|
|
(code == FULLSCREEN_CAPTURE) ||
|
|
((pwnd == NULL) && (code == NO_CAP_CLIENT) && (pti->pq != GETPTI(gspwndScreenCapture)->pq))) {
|
|
|
|
PQ pq;
|
|
PWND pwndCaptureOld = NULL;
|
|
|
|
if (code == FULLSCREEN_CAPTURE) {
|
|
if (pwnd) {
|
|
|
|
Lock(&gspwndScreenCapture, pwnd);
|
|
|
|
/*
|
|
* We're going full screen so clear the mouse owner
|
|
*/
|
|
Unlock(&gspwndMouseOwner);
|
|
|
|
} else {
|
|
|
|
Unlock(&gspwndScreenCapture);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Internal capture works like Win 3.1 capture unlike the NT capture
|
|
* which can be lost if the user clicks down on another application
|
|
*/
|
|
if (code == CLIENT_CAPTURE_INTERNAL) {
|
|
Lock(&gspwndInternalCapture, pwnd);
|
|
code = CLIENT_CAPTURE;
|
|
}
|
|
|
|
/*
|
|
* Free the internal capture if the app (thread) that did the internal
|
|
* capture is freeing the capture.
|
|
*/
|
|
if ((code == NO_CAP_CLIENT) &&
|
|
gspwndInternalCapture &&
|
|
(pti == GETPTI(gspwndInternalCapture))) {
|
|
|
|
Unlock(&gspwndInternalCapture);
|
|
}
|
|
|
|
if ((pq = pti->pq) != NULL) {
|
|
PDESKTOP pdesk = pti->rpdesk;
|
|
|
|
#if DBG
|
|
if (pq->QF_flags & QF_CAPTURELOCKED) {
|
|
RIPMSG1(RIP_WARNING, "pq %p already has QF_CAPTURELOCKED", pq);
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* If someone is tracking mouse events in the client area and
|
|
* we're setting or releasing an internal capture mode (!= CLIENT_CAPTURE),
|
|
* then cancel tracking -- because we're either taking or relinquishing
|
|
* control over the mouse.
|
|
*/
|
|
if ((pdesk->dwDTFlags & DF_TRACKMOUSEEVENT)
|
|
&& (pdesk->htEx == HTCLIENT)
|
|
&& ((pdesk->spwndTrack == pwnd)
|
|
&& (code != CLIENT_CAPTURE)
|
|
|| ((pdesk->spwndTrack == pq->spwndCapture)
|
|
&& (pq->codeCapture != CLIENT_CAPTURE)))) {
|
|
|
|
BEGINATOMICCHECK();
|
|
xxxCancelMouseMoveTracking(pdesk->dwDTFlags, pdesk->spwndTrack,
|
|
pdesk->htEx, DF_TRACKMOUSEEVENT);
|
|
ENDATOMICCHECK();
|
|
|
|
}
|
|
|
|
pwndCaptureOld = pq->spwndCapture;
|
|
LockCaptureWindow(pq, pwnd);
|
|
pq->codeCapture = code;
|
|
} else {
|
|
/*
|
|
* A thread without a queue?
|
|
*/
|
|
UserAssert(pti->pq != NULL);
|
|
}
|
|
|
|
/*
|
|
* If there was a capture window and we're releasing it, post
|
|
* a WM_MOUSEMOVE to the window we're over so they can know about
|
|
* the current mouse position.
|
|
* Defer WinEvent notifications to protect pwndCaptureOld
|
|
*/
|
|
DeferWinEventNotify();
|
|
|
|
if (pwnd == NULL && pwndCaptureOld != NULL) {
|
|
#ifdef REDIRECTION
|
|
if (!IsGlobalHooked(pti, WHF_FROM_WH(WH_HITTEST)))
|
|
#endif
|
|
zzzSetFMouseMoved();
|
|
}
|
|
|
|
if (pwndCaptureOld) {
|
|
zzzWindowEvent(EVENT_SYSTEM_CAPTUREEND, pwndCaptureOld, OBJID_WINDOW,
|
|
INDEXID_CONTAINER, WEF_USEPWNDTHREAD);
|
|
}
|
|
|
|
if (pwnd) {
|
|
zzzWindowEvent(EVENT_SYSTEM_CAPTURESTART, pwnd, OBJID_WINDOW,
|
|
INDEXID_CONTAINER, WEF_USEPWNDTHREAD);
|
|
}
|
|
|
|
/*
|
|
* New for win95 - send WM_CAPTURECHANGED.
|
|
*
|
|
* The FNID_DELETED_BIT is set in xxxFreeWindow which means we
|
|
* DON'T want to send the message.
|
|
*/
|
|
if (pwndCaptureOld &&
|
|
TestWF(pwndCaptureOld, WFWIN40COMPAT) &&
|
|
!(pwndCaptureOld->fnid & FNID_DELETED_BIT)) {
|
|
|
|
TL tlpwnd;
|
|
|
|
/*
|
|
* If we are in menu mode and just set capture,
|
|
* don't let them take it from us during this
|
|
* callback.
|
|
*/
|
|
if ((pti->pMenuState != NULL) && (pwnd != NULL)) {
|
|
pq->QF_flags |= QF_CAPTURELOCKED;
|
|
}
|
|
|
|
ThreadLockAlways(pwndCaptureOld, &tlpwnd);
|
|
zzzEndDeferWinEventNotify();
|
|
xxxSendMessageCallback(pwndCaptureOld,
|
|
WM_CAPTURECHANGED,
|
|
FALSE,
|
|
(LPARAM)HW(pwnd),
|
|
NULL,
|
|
0,
|
|
FALSE);
|
|
/* The thread's queue may have changed during the callback,
|
|
* so we need to refresh the local. Bug #377795
|
|
*/
|
|
pq = pti->pq;
|
|
UserAssert(pq != NULL);
|
|
ThreadUnlock(&tlpwnd);
|
|
|
|
/*
|
|
* Release the temporary lock, if any
|
|
*/
|
|
pq->QF_flags &= ~QF_CAPTURELOCKED;
|
|
} else {
|
|
zzzEndDeferWinEventNotify();
|
|
}
|
|
}
|
|
}
|