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.

616 lines
17 KiB

  1. /****************************** Module Header ******************************\
  2. * Module Name: visrgn.c
  3. *
  4. * Copyright (c) 1985 - 1999, Microsoft Corporation
  5. *
  6. * This module contains User's visible region ('visrgn') manipulation
  7. * functions.
  8. *
  9. * History:
  10. * 23-Oct-1990 DarrinM Created.
  11. \***************************************************************************/
  12. #include "precomp.h"
  13. #pragma hdrstop
  14. /*
  15. * Globals used to keep track of pwnds which
  16. * need to be excluded from the visrgns.
  17. */
  18. #define CEXCLUDERECTSMAX 30
  19. #define CEXCLUDEPWNDSMAX 30
  20. BOOL gfVisAlloc;
  21. int gcrcVisExclude;
  22. int gcrcVisExcludeMax;
  23. PWND *gapwndVisExclude;
  24. PWND *gapwndVisDefault;
  25. /***************************************************************************\
  26. * SetRectRgnIndirect
  27. *
  28. * Sets a rect region from a rectangle.
  29. *
  30. * History:
  31. * 26-Sep-1996 adams Created.
  32. \***************************************************************************/
  33. BOOL
  34. SetRectRgnIndirect(HRGN hrgn, LPCRECT lprc)
  35. {
  36. return GreSetRectRgn(hrgn, lprc->left, lprc->top, lprc->right, lprc->bottom);
  37. }
  38. /***************************************************************************\
  39. * CreateEmptyRgn
  40. *
  41. * Creates an empty region.
  42. *
  43. * History:
  44. * 24-Sep-1996 adams Created.
  45. \***************************************************************************/
  46. HRGN
  47. CreateEmptyRgn(void)
  48. {
  49. return GreCreateRectRgnIndirect(PZERO(RECT));
  50. }
  51. /***************************************************************************\
  52. * CreateEmptyRgnPublic
  53. *
  54. * Creates an empty region and make it public.
  55. *
  56. * History:
  57. * 24-Sep-1996 adams Created.
  58. \***************************************************************************/
  59. HRGN
  60. CreateEmptyRgnPublic(void)
  61. {
  62. HRGN hrgn;
  63. if (hrgn = CreateEmptyRgn()) {
  64. UserVerify(GreSetRegionOwner(hrgn, OBJECT_OWNER_PUBLIC));
  65. }
  66. return hrgn;
  67. }
  68. /***************************************************************************\
  69. * SetEmptyRgn
  70. *
  71. * Sets an empty region.
  72. *
  73. * History:
  74. * 26-Sep-1996 adams Created.
  75. \***************************************************************************/
  76. BOOL
  77. SetEmptyRgn(HRGN hrgn)
  78. {
  79. return SetRectRgnIndirect(hrgn, PZERO(RECT));
  80. }
  81. /***************************************************************************\
  82. * SetOrCreateRectRgnIndirectPublic
  83. *
  84. * Sets a region to a rectangle, creating it and making it public
  85. * if it is not already there.
  86. *
  87. * History:
  88. * 01-Oct-1996 adams Created.
  89. \***************************************************************************/
  90. HRGN
  91. SetOrCreateRectRgnIndirectPublic(HRGN * phrgn, LPCRECT lprc)
  92. {
  93. if (*phrgn) {
  94. UserVerify(SetRectRgnIndirect(*phrgn, lprc));
  95. } else if (*phrgn = GreCreateRectRgnIndirect((LPRECT) lprc)) {
  96. UserVerify(GreSetRegionOwner(*phrgn, OBJECT_OWNER_PUBLIC));
  97. }
  98. return *phrgn;
  99. }
  100. /***************************************************************************\
  101. * ResizeVisExcludeMemory
  102. *
  103. * This routine is used to resize the vis-rgn memory buffer if the count
  104. * is exceeded.
  105. *
  106. *
  107. * History:
  108. * 22-Oct-1994 ChrisWil Created
  109. * 27-Feb-1997 adams Removed call to UserReallocPool, since the pool
  110. * allocator doesn't support realloc.
  111. \***************************************************************************/
  112. BOOL ResizeVisExcludeMemory(VOID)
  113. {
  114. int crcNew;
  115. PWND apwndNew;
  116. /*
  117. * Note (adams): a previous version of the code called UserReallocPool
  118. * if memory had already been allocated. Unfortunately, UserReallocPool
  119. * just has to allocate more memory and copy the contents, since Rtl
  120. * doesn't have a realloc function. If Rtl later gains a Realloc function,
  121. * this code should be changed to the previous version.
  122. */
  123. crcNew = gcrcVisExcludeMax + CEXCLUDEPWNDSMAX;
  124. apwndNew = (PWND)UserAllocPool(
  125. crcNew * sizeof(PWND), TAG_VISRGN);
  126. if (!apwndNew)
  127. return FALSE;
  128. UserAssert(gcrcVisExcludeMax == gcrcVisExclude);
  129. RtlCopyMemory(apwndNew, gapwndVisExclude, gcrcVisExcludeMax * sizeof(PWND));
  130. if (gfVisAlloc) {
  131. UserFreePool(gapwndVisExclude);
  132. } else {
  133. gfVisAlloc = TRUE;
  134. }
  135. gcrcVisExcludeMax = crcNew;
  136. gapwndVisExclude = (PWND *)apwndNew;
  137. return TRUE;
  138. }
  139. /***************************************************************************\
  140. * ExcludeWindowRects
  141. * This routine checks to see if the pwnd needs to be added to the list
  142. * of excluded-clip-rects. If so, it appends the pwnd to the array. They
  143. * do not need to be sorted, since GreSubtractRgnRectList() sorts them
  144. * internally.
  145. *
  146. *
  147. * History:
  148. * 05-Nov-1992 DavidPe Created.
  149. * 21-Oct-1994 ChrisWil Removed pwnd->pwndNextYX. No longer sorts pwnds.
  150. \***************************************************************************/
  151. #define CheckIntersectRect(prc1, prc2) \
  152. ( prc1->left < prc2->right \
  153. && prc2->left < prc1->right \
  154. && prc1->top < prc2->bottom \
  155. && prc2->top < prc1->bottom)
  156. #define EmptyRect(prc) \
  157. ( prc->left >= prc->right \
  158. || prc->top >= prc->bottom)
  159. BOOL ExcludeWindowRects(
  160. PWND pwnd ,
  161. PWND pwndStop,
  162. LPRECT lprcIntersect)
  163. {
  164. PRECT prc;
  165. #if DBG
  166. if (pwnd != NULL && pwndStop != NULL &&
  167. pwnd->spwndParent != pwndStop->spwndParent) {
  168. RIPMSG0(RIP_ERROR, "ExcludeWindowRects: bad windows passed in");
  169. }
  170. #endif
  171. while ((pwnd != NULL) && (pwnd != pwndStop)) {
  172. UserAssert(pwnd);
  173. prc = &pwnd->rcWindow;
  174. if ( TestWF(pwnd, WFVISIBLE)
  175. #ifdef REDIRECTION
  176. && (TestWF(pwnd, WEFEXTREDIRECTED) == 0)
  177. #endif // REDIRECTION
  178. && (TestWF(pwnd, WEFLAYERED) == 0)
  179. && (TestWF(pwnd, WEFTRANSPARENT) == 0)
  180. && CheckIntersectRect(lprcIntersect, prc)
  181. && !EmptyRect(prc)) {
  182. UserAssert(gcrcVisExclude <= gcrcVisExcludeMax);
  183. if (gcrcVisExclude == gcrcVisExcludeMax) {
  184. if (!ResizeVisExcludeMemory()) {
  185. return FALSE;
  186. }
  187. }
  188. gapwndVisExclude[gcrcVisExclude++] = pwnd;
  189. }
  190. pwnd = pwnd->spwndNext;
  191. }
  192. return TRUE;
  193. }
  194. /***************************************************************************\
  195. * CalcWindowVisRgn
  196. *
  197. * This routine performs the work of calculating the VisRgn for a window.
  198. *
  199. *
  200. * History:
  201. * 02-Nov-1992 DavidPe Created.
  202. * 21-Oct-1992 ChrisWil Removed pwnd->pwndNextYX. No longer sorts pwnds.
  203. \***************************************************************************/
  204. BOOL CalcWindowVisRgn(
  205. PWND pwnd,
  206. HRGN *phrgn,
  207. DWORD flags)
  208. {
  209. RECT rcWindow;
  210. PWND pwndParent;
  211. PWND pwndRoot;
  212. PWND pwndLoop;
  213. BOOL fClipSiblings;
  214. BOOL fRgnParent = FALSE;
  215. BOOL fResult;
  216. PWND apwndVisDefault[CEXCLUDEPWNDSMAX];
  217. /*
  218. * First get the initial window rectangle which will be used for
  219. * the basis of exclusion calculations.
  220. */
  221. rcWindow = (flags & DCX_WINDOW ? pwnd->rcWindow : pwnd->rcClient);
  222. /*
  223. * Get the parent of this window. We start at the parent and backtrack
  224. * through the window-parent-list until we reach the end of the parent-
  225. * list. This will give us the intersect-rectangle which is used as
  226. * the basis for checking intersection of the exclusion rects.
  227. */
  228. pwndRoot = pwnd->head.rpdesk->pDeskInfo->spwnd->spwndParent;
  229. pwndParent = pwnd->spwndParent;
  230. /*
  231. * The parent can be NULL in the case when pwnd == pwndRoot. In other
  232. * cases we should figure why the parent is NULL.
  233. */
  234. if (pwndParent == NULL) {
  235. #if DBG
  236. if (pwnd != pwndRoot) {
  237. RIPMSG0(RIP_ERROR, "CalcWindowVisRgn: pwndParent is NULL");
  238. }
  239. #endif
  240. goto NullRegion;
  241. }
  242. while (pwndParent != pwndRoot) {
  243. /*
  244. * Don't clip layered DCs to the desktop. The surface of the layered
  245. * DC is the size of the window and we always want to have the image
  246. * of the entire window in that surface.
  247. */
  248. if ((flags & DCX_REDIRECTED) && (GETFNID(pwndParent) == FNID_DESKTOP))
  249. break;
  250. /*
  251. * Remember if any of the parents have a window region.
  252. */
  253. if (pwndParent->hrgnClip != NULL)
  254. fRgnParent = TRUE;
  255. /*
  256. * Intersect the parent's client rectangle with the window rectangle.
  257. */
  258. if (!IntersectRect(&rcWindow, &rcWindow, &pwndParent->rcClient))
  259. goto NullRegion;
  260. pwndParent = pwndParent->spwndParent;
  261. }
  262. /*
  263. * Initialize the VisRgn memory-buffer. This is
  264. * used to hold the pwnd's.
  265. */
  266. gapwndVisDefault = apwndVisDefault;
  267. gapwndVisExclude = gapwndVisDefault;
  268. gcrcVisExcludeMax = ARRAY_SIZE(apwndVisDefault);
  269. gcrcVisExclude = 0;
  270. /*
  271. * Build the list of exclude-rects.
  272. */
  273. fClipSiblings = (BOOL)(flags & DCX_CLIPSIBLINGS);
  274. pwndParent = pwnd->spwndParent;
  275. pwndLoop = pwnd;
  276. while (pwndParent != pwndRoot) {
  277. /*
  278. * If we reach a redirected window, we can stop excluding any
  279. * siblings any siblings of any parents.
  280. */
  281. if ((flags & DCX_REDIRECTED) && TestWF(pwndLoop, WEFPREDIRECTED)) {
  282. break;
  283. }
  284. /*
  285. * Exclude any siblings if necessary.
  286. */
  287. if (fClipSiblings && (pwndParent->spwndChild != pwndLoop)) {
  288. if (!ExcludeWindowRects(pwndParent->spwndChild,
  289. pwndLoop,
  290. &rcWindow)) {
  291. goto NullRegion;
  292. }
  293. }
  294. /*
  295. * Set this flag for next time through the loop...
  296. */
  297. fClipSiblings = TestWF(pwndParent, WFCLIPSIBLINGS);
  298. pwndLoop = pwndParent;
  299. pwndParent = pwndLoop->spwndParent;
  300. }
  301. if ((flags & DCX_CLIPCHILDREN) && (pwnd->spwndChild != NULL)) {
  302. if (!ExcludeWindowRects(pwnd->spwndChild, NULL, &rcWindow)) {
  303. goto NullRegion;
  304. }
  305. }
  306. /*
  307. * If there are rectangles to exclude call GDI to create
  308. * a region excluding them from the window rectangle. If
  309. * not simply call GreSetRectRgn().
  310. */
  311. if (gcrcVisExclude > 0) {
  312. RECT arcVisRects[CEXCLUDERECTSMAX];
  313. PRECT arcExclude;
  314. int i;
  315. int ircVisExclude = 0;
  316. int irgnVisExclude = 0;
  317. /*
  318. * If we need to exclude more rectangles than fit in
  319. * the pre-allocated buffer, obviously we have to
  320. * allocate one that's big enough.
  321. */
  322. if (gcrcVisExclude <= CEXCLUDERECTSMAX) {
  323. arcExclude = arcVisRects;
  324. } else {
  325. arcExclude = (PRECT)UserAllocPoolWithQuota(
  326. sizeof(RECT) * gcrcVisExclude, TAG_VISRGN);
  327. if (!arcExclude)
  328. goto NullRegion;
  329. }
  330. /*
  331. * Now run through the list and put the
  332. * window rectangles into the array for the call
  333. * to CombineRgnRectList().
  334. */
  335. for (i = 0; i < gcrcVisExclude; i++) {
  336. /*
  337. * If the window has a clip-rgn associated with
  338. * it, then re-use gpwneExcludeList[] entries for
  339. * storing them.
  340. */
  341. if (gapwndVisExclude[i]->hrgnClip != NULL) {
  342. gapwndVisExclude[irgnVisExclude++] = gapwndVisExclude[i];
  343. continue;
  344. }
  345. /*
  346. * This window doesn't have a clipping region; remember its
  347. * rect for clipping purposes.
  348. */
  349. arcExclude[ircVisExclude++] = gapwndVisExclude[i]->rcWindow;
  350. }
  351. if (*phrgn == NULL)
  352. *phrgn = CreateEmptyRgn();
  353. if (ircVisExclude != 0) {
  354. GreSubtractRgnRectList(*phrgn,
  355. &rcWindow,
  356. arcExclude,
  357. ircVisExclude);
  358. } else {
  359. SetRectRgnIndirect(*phrgn, &rcWindow);
  360. }
  361. for (i = 0; i < irgnVisExclude; i++) {
  362. SetRectRgnIndirect(ghrgnInv2, &gapwndVisExclude[i]->rcWindow);
  363. IntersectRgn(ghrgnInv2, ghrgnInv2, gapwndVisExclude[i]->hrgnClip);
  364. if (SubtractRgn(*phrgn, *phrgn, ghrgnInv2) == NULLREGION)
  365. break;
  366. }
  367. if (arcExclude != arcVisRects) {
  368. UserFreePool((HLOCAL)arcExclude);
  369. }
  370. } else {
  371. /*
  372. * If the window was somehow destroyed, then we will return
  373. * a null-region. Emptying the rect will accomplish this.
  374. */
  375. if (TestWF(pwnd, WFDESTROYED)) {
  376. SetRectEmpty(&rcWindow);
  377. }
  378. /*
  379. * If there weren't any rectangles to exclude, simply call
  380. * GreSetRectRgn() with the window rectangle.
  381. */
  382. SetOrCreateRectRgnIndirectPublic(phrgn, &rcWindow);
  383. }
  384. /*
  385. * Clip out this window's window region
  386. */
  387. if (pwnd->hrgnClip != NULL) {
  388. IntersectRgn(*phrgn, *phrgn, pwnd->hrgnClip);
  389. }
  390. /*
  391. * Clip out parent's window regions, if there are any.
  392. */
  393. if (fRgnParent) {
  394. PWND pwndT;
  395. for (pwndT = pwnd->spwndParent;
  396. pwndT != pwndRoot;
  397. pwndT = pwndT->spwndParent) {
  398. if (pwndT->hrgnClip != NULL) {
  399. if (IntersectRgn(*phrgn, *phrgn, pwndT->hrgnClip) == NULLREGION)
  400. break;
  401. }
  402. }
  403. }
  404. fResult = TRUE;
  405. // fall-through
  406. Cleanup:
  407. if (gfVisAlloc) {
  408. UserFreePool((HLOCAL)gapwndVisExclude);
  409. gfVisAlloc = FALSE;
  410. }
  411. return fResult;
  412. NullRegion:
  413. SetOrCreateRectRgnIndirectPublic(phrgn, PZERO(RECT));
  414. fResult = FALSE;
  415. goto Cleanup;
  416. }
  417. /***************************************************************************\
  418. * CalcVisRgn
  419. *
  420. * Will return FALSE if the pwndOrg is not visible, TRUE otherwise.
  421. *
  422. * History:
  423. * 17-Jul-1991 DarrinM Ported from Win 3.1 sources.
  424. \***************************************************************************/
  425. BOOL CalcVisRgn(
  426. HRGN *phrgn,
  427. PWND pwndOrg,
  428. PWND pwndClip,
  429. DWORD flags)
  430. {
  431. PDESKTOP pdesk;
  432. UserAssert(pwndOrg != NULL);
  433. /*
  434. * If the window's not visible or is not an active desktop,
  435. * or if the clip window is in the process of being destroyed,
  436. * the visrgn is empty.
  437. */
  438. pdesk = pwndOrg->head.rpdesk;
  439. UserAssert(pdesk);
  440. /*
  441. * Make sure this happens in the IO windowstation
  442. */
  443. #if DBG
  444. if (grpdeskRitInput != NULL) {
  445. UserAssert(pdesk->rpwinstaParent == grpdeskRitInput->rpwinstaParent ||
  446. !IsVisible(pwndOrg));
  447. }
  448. #endif // DBG
  449. /*
  450. * For redirected windows, if it is on the non I/O desktop, we still need
  451. * to pass the application a non empty region in order to update the bitmap
  452. * Otherwise, the bitmap will never got the chance to be updated and we will end up
  453. * rendering a black window region (for the case of layered windows) by the time
  454. * we switch to this desktop. (see bug# 287315). Note that this will not render the window on the screen
  455. * because the call to CalcVisRgn from UserVisrgnFromHwnd() should never specify
  456. * DCX_REDIRECTEDBITMAP.
  457. */
  458. #if DBG
  459. if (!TestWF(pwndOrg, WEFPREDIRECTED)) {
  460. UserAssert(!(flags & DCX_REDIRECTEDBITMAP));
  461. }
  462. #endif
  463. if (!IsVisible(pwndOrg) ||
  464. ((pdesk != grpdeskRitInput) && !(flags & DCX_REDIRECTEDBITMAP))) {
  465. goto EmptyRgn;
  466. }
  467. /*
  468. * If LockWindowUpdate() has been called, and this window is a child
  469. * of the lock window, always return an empty visrgn.
  470. */
  471. if ((gspwndLockUpdate != NULL) &&
  472. !(flags & DCX_LOCKWINDOWUPDATE) &&
  473. _IsDescendant(gspwndLockUpdate, pwndOrg)) {
  474. goto EmptyRgn;
  475. }
  476. /*
  477. * Now go compute the visrgn for pwndClip.
  478. */
  479. return CalcWindowVisRgn(pwndClip, phrgn, flags);
  480. EmptyRgn:
  481. SetOrCreateRectRgnIndirectPublic(phrgn, PZERO(RECT));
  482. return FALSE;
  483. }
  484. /***************************************************************************\
  485. * CalcWindowRgn
  486. *
  487. *
  488. * History:
  489. * 17-Jul-1991 DarrinM Ported from Win 3.1 sources.
  490. \***************************************************************************/
  491. int CalcWindowRgn(
  492. PWND pwnd,
  493. HRGN hrgn,
  494. BOOL fClient)
  495. {
  496. SetRectRgnIndirect(hrgn, (fClient) ? &pwnd->rcClient : &pwnd->rcWindow);
  497. /*
  498. * If the window has a region, then intersect the rectangle region with
  499. * that. If this is low on memory, it'll propagate ERROR back.
  500. */
  501. if (pwnd->hrgnClip != NULL) {
  502. return IntersectRgn(hrgn, hrgn, pwnd->hrgnClip);
  503. }
  504. return SIMPLEREGION;
  505. }