Leaked source code of windows server 2003
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.

469 lines
12 KiB

  1. /****************************** Module Header ******************************\
  2. * Module Name: winwhere.c
  3. *
  4. * Copyright (c) 1985 - 1999, Microsoft Corporation
  5. *
  6. * History:
  7. * 08-Nov-1990 DavidPe Created.
  8. * 23-Jan-1991 IanJa Serialization: Handle revalidation added
  9. * 19-Feb-1991 JimA Added enum access checks
  10. \***************************************************************************/
  11. #include "precomp.h"
  12. #pragma hdrstop
  13. /***************************************************************************\
  14. * LayerHitTest
  15. *
  16. * 9/21/1998 vadimg created
  17. \***************************************************************************/
  18. __inline BOOL LayerHitTest(PWND pwnd, POINT pt)
  19. {
  20. ASSERT(TestWF(pwnd, WEFLAYERED));
  21. if (TestWF(pwnd, WEFTRANSPARENT))
  22. return FALSE;
  23. if (!GrePtInSprite(gpDispInfo->hDev, PtoHq(pwnd), pt.x, pt.y))
  24. return FALSE;
  25. return TRUE;
  26. }
  27. /***************************************************************************\
  28. * ChildWindowFromPoint (API)
  29. *
  30. * Returns NULL if pt is not in parent's client area at all,
  31. * hwndParent if point is not over any children, and a child window if it is
  32. * over a child. Will return hidden and disabled windows if they are at the
  33. * given point.
  34. *
  35. * History:
  36. * 19-Nov-1990 DavidPe Created.
  37. * 19-Feb-1991 JimA Added enum access check
  38. \***************************************************************************/
  39. PWND _ChildWindowFromPointEx(
  40. PWND pwnd,
  41. POINT pt,
  42. UINT uFlags)
  43. {
  44. if (pwnd != PWNDDESKTOP(pwnd)) {
  45. if (TestWF(pwnd, WEFLAYOUTRTL)) {
  46. pt.x = pwnd->rcClient.right - pt.x;
  47. } else {
  48. pt.x += pwnd->rcClient.left;
  49. }
  50. pt.y += pwnd->rcClient.top;
  51. }
  52. // _ClientToScreen(pwndParent, (LPPOINT)&pt);
  53. if (PtInRect(&pwnd->rcClient, pt)) {
  54. PWND pwndChild;
  55. if (pwnd->hrgnClip != NULL) {
  56. if (!GrePtInRegion(pwnd->hrgnClip, pt.x, pt.y))
  57. return NULL;
  58. }
  59. if (TestWF(pwnd, WEFLAYERED)) {
  60. if (!LayerHitTest(pwnd, pt))
  61. return NULL;
  62. }
  63. /*
  64. * Enumerate the children, skipping disabled and invisible ones
  65. * if so desired. Still doesn't work for WS_EX_TRANSPARENT windows.
  66. */
  67. for (pwndChild = pwnd->spwndChild;
  68. pwndChild;
  69. pwndChild = pwndChild->spwndNext) {
  70. /*
  71. * Skip windows as desired.
  72. */
  73. if ((uFlags & CWP_SKIPINVISIBLE) && !TestWF(pwndChild, WFVISIBLE))
  74. continue;
  75. if ((uFlags & CWP_SKIPDISABLED) && TestWF(pwndChild, WFDISABLED))
  76. continue;
  77. if ((uFlags & CWP_SKIPTRANSPARENT) && TestWF(pwndChild, WEFTRANSPARENT))
  78. continue;
  79. if (PtInRect(&pwndChild->rcWindow, pt)) {
  80. if (pwndChild->hrgnClip != NULL) {
  81. if (!GrePtInRegion(pwndChild->hrgnClip, pt.x, pt.y))
  82. continue;
  83. }
  84. if (TestWF(pwndChild, WEFLAYERED)) {
  85. if (!LayerHitTest(pwndChild, pt))
  86. continue;
  87. }
  88. return(pwndChild);
  89. }
  90. }
  91. return pwnd;
  92. }
  93. return NULL;
  94. }
  95. /***************************************************************************\
  96. * xxxWindowFromPoint (API)
  97. *
  98. * History:
  99. * 19-Nov-1990 DavidPe Created.
  100. * 19-Feb-1991 JimA Added enum access check
  101. \***************************************************************************/
  102. PWND xxxWindowFromPoint(
  103. POINT pt)
  104. {
  105. HWND hwnd;
  106. PWND pwndT;
  107. TL tlpwndT;
  108. pwndT = _GetDesktopWindow();
  109. ThreadLock(pwndT, &tlpwndT);
  110. hwnd = xxxWindowHitTest2(pwndT, pt, NULL, WHT_IGNOREDISABLED);
  111. ThreadUnlock(&tlpwndT);
  112. return RevalidateHwnd(hwnd);
  113. }
  114. #ifdef REDIRECTION
  115. /***************************************************************************\
  116. * xxxCallSpeedHitTestHook
  117. *
  118. * Call the speed hit test hook to give the opportunity to the hook to fake
  119. * where the mouse pointer is.
  120. *
  121. * 25-Jan-1999 CLupu Created.
  122. \***************************************************************************/
  123. PWND xxxCallSpeedHitTestHook(POINT* ppt)
  124. {
  125. PHOOK pHook;
  126. PWND pwnd = NULL;
  127. /*
  128. * Call the hit test hooks to give them the opportunity to change
  129. * the coordinates and the hwnd
  130. */
  131. if ((pHook = PhkFirstValid(PtiCurrent(), WH_HITTEST)) != NULL) {
  132. HTHOOKSTRUCT ht;
  133. BOOL bAnsiHook;
  134. ht.pt = *ppt;
  135. ht.hwndHit = NULL;
  136. xxxCallHook2(pHook, HC_ACTION, 0, (LPARAM)&ht, &bAnsiHook);
  137. if (ht.hwndHit != NULL) {
  138. pwnd = HMValidateHandle(ht.hwndHit, TYPE_WINDOW);
  139. if (pwnd != NULL) {
  140. ppt->x = ht.pt.x;
  141. ppt->y = ht.pt.y;
  142. }
  143. }
  144. }
  145. return pwnd;
  146. }
  147. #endif // REDIRECTION
  148. /***************************************************************************\
  149. * SpeedHitTest
  150. *
  151. * This routine quickly finds out what top level window this mouse point
  152. * belongs to. Used purely for ownership purposes.
  153. *
  154. * 12-Nov-1992 ScottLu Created.
  155. \***************************************************************************/
  156. PWND SpeedHitTest(
  157. PWND pwndParent,
  158. POINT pt)
  159. {
  160. PWND pwndT;
  161. PWND pwnd;
  162. if (pwndParent == NULL)
  163. return NULL;
  164. for (pwnd = pwndParent->spwndChild; pwnd != NULL; pwnd = pwnd->spwndNext) {
  165. /*
  166. * Are we looking at an hidden window?
  167. */
  168. if (!TestWF(pwnd, WFVISIBLE))
  169. continue;
  170. /*
  171. * Are we barking up the wrong tree?
  172. */
  173. if (!PtInRect((LPRECT)&pwnd->rcWindow, pt)) {
  174. continue;
  175. }
  176. /*
  177. * Check to see if in window region (if it has one)
  178. */
  179. if (pwnd->hrgnClip != NULL) {
  180. if (!GrePtInRegion(pwnd->hrgnClip, pt.x, pt.y))
  181. continue;
  182. }
  183. /*
  184. * Is this a sprite?
  185. */
  186. if (TestWF(pwnd, WEFLAYERED)) {
  187. if (!LayerHitTest(pwnd, pt))
  188. continue;
  189. }
  190. #ifdef REDIRECTION
  191. if (TestWF(pwnd, WEFEXTREDIRECTED)) {
  192. continue;
  193. }
  194. #endif // REDIRECTION
  195. /*
  196. * Children?
  197. */
  198. if ((pwnd->spwndChild != NULL) &&
  199. PtInRect((LPRECT)&pwnd->rcClient, pt)) {
  200. pwndT = SpeedHitTest(pwnd, pt);
  201. if (pwndT != NULL)
  202. return pwndT;
  203. }
  204. return pwnd;
  205. }
  206. return pwndParent;
  207. }
  208. /***************************************************************************\
  209. * xxxWindowHitTest
  210. *
  211. * History:
  212. * 08-Nov-1990 DavidPe Ported.
  213. * 28-Nov-1990 DavidPe Add pwndTransparent support for HTTRANSPARENT.
  214. * 25-Jan-1991 IanJa change PWNDPOS parameter to int *
  215. * 19-Feb-1991 JimA Added enum access check
  216. * 02-Nov-1992 ScottLu Removed pwndTransparent.
  217. * 12-Nov-1992 ScottLu Took out fSendHitTest, fixed locking bug
  218. \***************************************************************************/
  219. HWND xxxWindowHitTest(
  220. PWND pwnd,
  221. POINT pt,
  222. int *piPos,
  223. DWORD dwHitTestFlags)
  224. {
  225. HWND hwndT;
  226. TL tlpwnd;
  227. CheckLock(pwnd);
  228. hwndT = NULL;
  229. ThreadLockNever(&tlpwnd);
  230. while (pwnd != NULL) {
  231. ThreadLockExchangeAlways(pwnd, &tlpwnd);
  232. hwndT = xxxWindowHitTest2(pwnd, pt, piPos, dwHitTestFlags);
  233. if (hwndT != NULL)
  234. break;
  235. pwnd = pwnd->spwndNext;
  236. }
  237. ThreadUnlock(&tlpwnd);
  238. return hwndT;
  239. }
  240. /***************************************************************************\
  241. * xxxWindowHitTest2
  242. *
  243. * When this routine is entered, all windows must be locked. When this
  244. * routine returns a window handle, it locks that window handle and unlocks
  245. * all windows. If this routine returns NULL, all windows are still locked.
  246. * Ignores disabled and hidden windows.
  247. *
  248. * History:
  249. * 08-Nov-1990 DavidPe Ported.
  250. * 25-Jan-1991 IanJa change PWNDPOS parameter to int *
  251. * 19-Feb-1991 JimA Added enum access check
  252. * 12-Nov-1992 ScottLu Took out fSendHitTest
  253. \***************************************************************************/
  254. HWND xxxWindowHitTest2(
  255. PWND pwnd,
  256. POINT pt,
  257. int *piPos,
  258. DWORD dwHitTestFlags)
  259. {
  260. int ht = HTERROR, htGrip=HTBOTTOMRIGHT;
  261. HWND hwndT;
  262. TL tlpwndChild;
  263. CheckLock(pwnd);
  264. /*
  265. * Are we at the bottom of the window chain?
  266. */
  267. if (pwnd == NULL)
  268. return NULL;
  269. /*
  270. * Are we looking at an hidden window?
  271. */
  272. if (!TestWF(pwnd, WFVISIBLE))
  273. return NULL;
  274. /*
  275. * Are we barking up the wrong tree?
  276. */
  277. if (!PtInRect((LPRECT)&pwnd->rcWindow, pt)) {
  278. return NULL;
  279. }
  280. if (pwnd->hrgnClip != NULL) {
  281. if (!GrePtInRegion(pwnd->hrgnClip, pt.x, pt.y))
  282. return(NULL);
  283. }
  284. if (TestWF(pwnd, WEFLAYERED)) {
  285. if (!LayerHitTest(pwnd, pt))
  286. return NULL;
  287. }
  288. #ifdef REDIRECTION
  289. /*
  290. * If this is called when the layered window is actually trying
  291. * to process the message then let it see the hit test
  292. */
  293. if (TestWF(pwnd, WEFEXTREDIRECTED) && PpiCurrent() != GETPTI(pwnd)->ppi) {
  294. return NULL;
  295. }
  296. #endif // REDIRECTION
  297. /*
  298. * Are we looking at an disabled window?
  299. */
  300. if (TestWF(pwnd, WFDISABLED) && (dwHitTestFlags & WHT_IGNOREDISABLED)) {
  301. if (TestwndChild(pwnd)) {
  302. return NULL;
  303. } else {
  304. ht = HTERROR;
  305. goto Exit;
  306. }
  307. }
  308. #ifdef SYSMODALWINDOWS
  309. /*
  310. * If SysModal window present and we're not in it, return an error.
  311. * Be sure to assign the point to the SysModal window, so the message
  312. * will be sure to be removed from the queue.
  313. */
  314. if (!CheckPwndFilter(pwnd, gspwndSysModal)) {
  315. pwnd = gspwndSysModal;
  316. /*
  317. * Fix notorious stack overflow bug (some WINABLE fix from Memphis)
  318. */
  319. ht = HTCLIENT;
  320. goto Exit;
  321. }
  322. #endif
  323. /*
  324. * Are we on a minimized window?
  325. */
  326. if (!TestWF(pwnd, WFMINIMIZED)) {
  327. /*
  328. * Are we in the window's client area?
  329. */
  330. if (PtInRect((LPRECT)&pwnd->rcClient, pt)) {
  331. /*
  332. * Recurse through the children.
  333. */
  334. ThreadLock(pwnd->spwndChild, &tlpwndChild);
  335. hwndT = xxxWindowHitTest(pwnd->spwndChild,
  336. pt,
  337. piPos,
  338. dwHitTestFlags);
  339. ThreadUnlock(&tlpwndChild);
  340. if (hwndT != NULL)
  341. return hwndT;
  342. }
  343. }
  344. /*
  345. * If window not in same task, don't send WM_NCHITTEST.
  346. */
  347. if (GETPTI(pwnd) != PtiCurrent()) {
  348. ht = HTCLIENT;
  349. goto Exit;
  350. }
  351. /*
  352. * Send the message.
  353. */
  354. ht = (int)xxxSendMessage(pwnd, WM_NCHITTEST, 0, MAKELONG(pt.x, pt.y));
  355. /*
  356. * If window is transparent keep enumerating.
  357. */
  358. if (ht == HTTRANSPARENT) {
  359. return NULL;
  360. }
  361. Exit:
  362. /*
  363. * Set wndpos accordingly.
  364. */
  365. if (piPos) {
  366. *piPos = ht;
  367. }
  368. /*
  369. * If this is a RTL mirrored window, then the grip is at
  370. * HTBOTTOMLEFT (in terms of screen coordinates since they are
  371. * not RTL mirrored).
  372. */
  373. if (TestWF(pwnd, WEFLAYOUTRTL)) {
  374. htGrip = HTBOTTOMLEFT;
  375. }
  376. /*
  377. * if the click is in the sizebox of the window and this window itself is
  378. * not sizable, return the window that will be sized by this sizebox
  379. */
  380. if ((ht == htGrip) && !TestWF(pwnd, WFSIZEBOX)) {
  381. PWND pwndT;
  382. /*
  383. * SizeBoxHwnd() can return NULL! We don't want to act like this
  384. * is transparent if the sizebox isn't a grip
  385. */
  386. pwnd = (pwndT = SizeBoxHwnd(pwnd)) ? pwndT : pwnd;
  387. }
  388. return HWq(pwnd);
  389. }