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.

1870 lines
52 KiB

  1. /****************************** Module Header ******************************\
  2. * Module Name: sprite.c
  3. *
  4. * Copyright (c) 1985 - 1999, Microsoft Corporation
  5. *
  6. * Windows Layering (Sprite) support.
  7. *
  8. * History:
  9. * 12/05/97 vadimg created
  10. \***************************************************************************/
  11. #include "precomp.h"
  12. #pragma hdrstop
  13. #ifdef MOUSE_IP
  14. #define MOUSE_SONAR_RADIUS_INIT 100
  15. #define MOUSE_SONAR_LINE_WIDTH 4
  16. #define MOUSE_SONAR_RADIUS_DELTA 20
  17. #define MOUSE_SONAR_RADIUS_TIMER 50
  18. #define COLORKEY_COLOR RGB(255, 0, 255)
  19. VOID DrawSonar(HDC hdc);
  20. #endif
  21. #ifdef REDIRECTION
  22. /***************************************************************************\
  23. * UserGetRedirectionBitmap
  24. *
  25. \***************************************************************************/
  26. HBITMAP UserGetRedirectionBitmap(
  27. HWND hwnd)
  28. {
  29. HBITMAP hbm;
  30. PWND pwnd;
  31. EnterCrit();
  32. if ((pwnd = RevalidateHwnd(hwnd)) == NULL) {
  33. return NULL;
  34. }
  35. hbm = GetRedirectionBitmap(pwnd);
  36. LeaveCrit();
  37. return hbm;
  38. }
  39. /***************************************************************************\
  40. * SetRedirectionMode
  41. *
  42. \***************************************************************************/
  43. BOOL SetRedirectionMode(
  44. PBWL pbwl,
  45. PPROCESSINFO ppi)
  46. {
  47. HWND *phwnd;
  48. PWND pwndT;
  49. BOOL fRet = TRUE;
  50. for (phwnd = pbwl->rghwnd; *phwnd != (HWND)1; phwnd++) {
  51. if ((pwndT = RevalidateHwnd(*phwnd)) == NULL) {
  52. continue;
  53. }
  54. if (TestWF(pwndT, WFVISIBLE) && (ppi == NULL || GETPTI(pwndT)->ppi != ppi)) {
  55. if (SetRedirectedWindow(pwndT, REDIRECT_EXTREDIRECTED)) {
  56. SetWF(pwndT, WEFEXTREDIRECTED);
  57. } else {
  58. fRet = FALSE;
  59. break;
  60. }
  61. }
  62. }
  63. return fRet;
  64. }
  65. /***************************************************************************\
  66. * UnsetRedirectionMode
  67. *
  68. \***************************************************************************/
  69. VOID UnsetRedirectionMode(
  70. PBWL pbwl,
  71. PPROCESSINFO ppi)
  72. {
  73. HWND *phwnd;
  74. PWND pwndT;
  75. for (phwnd = pbwl->rghwnd; *phwnd != (HWND)1; phwnd++) {
  76. if ((pwndT = RevalidateHwnd(*phwnd)) == NULL) {
  77. continue;
  78. }
  79. if (TestWF(pwndT, WFVISIBLE) && ppi == NULL || GETPTI(pwndT)->ppi != ppi) {
  80. UnsetRedirectedWindow(pwndT, REDIRECT_EXTREDIRECTED);
  81. ClrWF(pwndT, WEFEXTREDIRECTED);
  82. }
  83. }
  84. }
  85. /***************************************************************************\
  86. * xxxSetRedirectionMode
  87. *
  88. \***************************************************************************/
  89. BOOL xxxSetRedirectionMode(
  90. BOOL fEnable,
  91. PDESKTOP pDesk,
  92. PTHREADINFO pti,
  93. PPROCESSINFO ppi)
  94. {
  95. PBWL pbwl;
  96. PWND pwndDesktop = pDesk->pDeskInfo->spwnd;
  97. pbwl = BuildHwndList(pwndDesktop->spwndChild, BWL_ENUMLIST, pti);
  98. if (pbwl == NULL) {
  99. return FALSE;
  100. }
  101. if (fEnable) {
  102. if (!SetRedirectionMode(pbwl, ppi)) {
  103. UnsetRedirectionMode(pbwl, ppi);
  104. }
  105. } else {
  106. UnsetRedirectionMode(pbwl, ppi);
  107. }
  108. FreeHwndList(pbwl);
  109. GreEnableDirectDrawRedirection(gpDispInfo->hDev, fEnable);
  110. xxxBroadcastDisplaySettingsChange(PtiCurrent()->rpdesk, FALSE);
  111. pwndDesktop = PtiCurrent()->rpdesk->pDeskInfo->spwnd;
  112. BEGINATOMICCHECK();
  113. xxxInternalInvalidate(pwndDesktop, HRGN_FULL, RDW_INVALIDATE |
  114. RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN);
  115. ENDATOMICCHECK();
  116. return TRUE;
  117. }
  118. /***************************************************************************\
  119. * xxxSetProcessRedirectionMode
  120. *
  121. \***************************************************************************/
  122. BOOL xxxSetProcessRedirectionMode(
  123. BOOL fEnable,
  124. PPROCESSINFO ppi)
  125. {
  126. PTHREADINFO pti = ppi->ptiList;
  127. TL tl;
  128. while (pti != NULL) {
  129. ThreadLockPti(PtiCurrent(), pti, &tl);
  130. if (!xxxSetRedirectionMode(fEnable, pti->rpdesk, pti, NULL)) {
  131. ThreadUnlockPti(PtiCurrent(), &tl);
  132. return FALSE;
  133. }
  134. pti = pti->ptiSibling;
  135. ThreadUnlockPti(PtiCurrent(), &tl);
  136. }
  137. return TRUE;
  138. }
  139. /***************************************************************************\
  140. * xxxSetDesktopRedirectionMode
  141. *
  142. \***************************************************************************/
  143. BOOL xxxSetDesktopRedirectionMode(
  144. BOOL fEnable,
  145. PDESKTOP pDesk,
  146. PPROCESSINFO ppi)
  147. {
  148. return xxxSetRedirectionMode(fEnable, pDesk, NULL, ppi);
  149. }
  150. #endif
  151. /***************************************************************************\
  152. * IncrementRedirectedCount
  153. *
  154. \***************************************************************************/
  155. VOID IncrementRedirectedCount(
  156. PWND pwnd)
  157. {
  158. if (TestWF(pwnd, WFVISIBLE)) {
  159. gnVisibleRedirectedCount++;
  160. if (gnVisibleRedirectedCount == 1) {
  161. InternalSetTimer(gTermIO.spwndDesktopOwner,
  162. IDSYS_LAYER,
  163. 100,
  164. xxxSystemTimerProc,
  165. TMRF_SYSTEM | TMRF_PTIWINDOW);
  166. }
  167. }
  168. }
  169. /***************************************************************************\
  170. * DecrementRedirectedCount
  171. *
  172. \***************************************************************************/
  173. VOID DecrementRedirectedCount(
  174. PWND pwnd)
  175. {
  176. if (TestWF(pwnd, WFVISIBLE)) {
  177. if (gnVisibleRedirectedCount > 0) {
  178. gnVisibleRedirectedCount--;
  179. if (gnVisibleRedirectedCount == 0) {
  180. _KillSystemTimer(gTermIO.spwndDesktopOwner, IDSYS_LAYER);
  181. }
  182. }
  183. }
  184. }
  185. /***************************************************************************\
  186. * CreateRedirectionBitmap
  187. *
  188. * 10/1/1998 vadimg created
  189. \***************************************************************************/
  190. HBITMAP CreateRedirectionBitmap(
  191. PWND pwnd)
  192. {
  193. HBITMAP hbm;
  194. UserAssert(pwnd->rcWindow.right >= pwnd->rcWindow.left);
  195. UserAssert(pwnd->rcWindow.bottom >= pwnd->rcWindow.top);
  196. /*
  197. * Make sure the (0,0) case doesn't fail, since the window really
  198. * can be sized this way.
  199. */
  200. if ((hbm = GreCreateCompatibleBitmap(gpDispInfo->hdcScreen,
  201. max(pwnd->rcWindow.right - pwnd->rcWindow.left, 1),
  202. max(pwnd->rcWindow.bottom - pwnd->rcWindow.top, 1) |
  203. CCB_NOVIDEOMEMORY)) == NULL) {
  204. RIPMSG0(RIP_WARNING, "CreateRedirectionBitmap: bitmap create failed");
  205. return NULL;
  206. }
  207. if (!GreSetBitmapOwner(hbm, OBJECT_OWNER_PUBLIC) ||
  208. !GreMarkUndeletableBitmap(hbm) ||
  209. !SetRedirectionBitmap(pwnd, hbm)) {
  210. RIPMSG0(RIP_WARNING, "CreateRedirectionBitmap: bitmap set failed");
  211. GreMarkDeletableBitmap(hbm);
  212. GreDeleteObject(hbm);
  213. return NULL;
  214. }
  215. SetWF(pwnd, WEFPREDIRECTED);
  216. /*
  217. * Force the window to redraw if we could recreate the bitmap since
  218. * the redirection bitmap we just allocated doesn't contain anything
  219. * yet.
  220. */
  221. BEGINATOMICCHECK();
  222. xxxInternalInvalidate(pwnd,
  223. HRGN_FULL,
  224. RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN);
  225. ENDATOMICCHECK();
  226. IncrementRedirectedCount(pwnd);
  227. return hbm;
  228. }
  229. /***************************************************************************\
  230. * ConvertRedirectionDCs
  231. *
  232. * 11/19/1998 vadimg created
  233. \***************************************************************************/
  234. VOID ConvertRedirectionDCs(
  235. PWND pwnd,
  236. HBITMAP hbm)
  237. {
  238. PDCE pdce;
  239. GreLockDisplay(gpDispInfo->hDev);
  240. for (pdce = gpDispInfo->pdceFirst; pdce != NULL; pdce = pdce->pdceNext) {
  241. if (pdce->DCX_flags & DCX_DESTROYTHIS) {
  242. continue;
  243. }
  244. if (!(pdce->DCX_flags & DCX_INUSE)) {
  245. continue;
  246. }
  247. if (!_IsDescendant(pwnd, pdce->pwndOrg)) {
  248. continue;
  249. }
  250. /*
  251. * Only normal DCs can be redirected. Redirection on monitor
  252. * specific DCs is not supported.
  253. */
  254. if (pdce->pMonitor != NULL) {
  255. continue;
  256. }
  257. SET_OR_CLEAR_FLAG(pdce->DCX_flags, DCX_REDIRECTED, (hbm != NULL));
  258. UserVerify(GreSelectRedirectionBitmap(pdce->hdc, hbm));
  259. InvalidateDce(pdce);
  260. }
  261. GreUnlockDisplay(gpDispInfo->hDev);
  262. }
  263. /***************************************************************************\
  264. * UpdateRedirectedDC
  265. *
  266. * 11/19/1998 vadimg created
  267. \***************************************************************************/
  268. VOID UpdateRedirectedDC(
  269. PDCE pdce)
  270. {
  271. RECT rcBounds;
  272. PWND pwnd;
  273. SIZE size;
  274. POINT pt;
  275. HBITMAP hbm, hbmOld;
  276. PREDIRECT prdr;
  277. UserAssert(pdce->DCX_flags & DCX_REDIRECTED);
  278. /*
  279. * Check to see if any drawing has been done into this DC
  280. * that should be transferred to the sprite.
  281. */
  282. if (!GreGetBounds(pdce->hdc, &rcBounds, 0)) {
  283. return;
  284. }
  285. pwnd = GetStyleWindow(pdce->pwndOrg, WEFPREDIRECTED);
  286. UserAssert(pwnd);
  287. prdr = (PREDIRECT)_GetProp(pwnd, PROP_LAYER, TRUE);
  288. #ifdef REDIRECTION
  289. BEGINATOMICCHECK();
  290. xxxWindowEvent(EVENT_SYSTEM_REDIRECTEDPAINT,
  291. pwnd,
  292. MAKELONG(rcBounds.left, rcBounds.top),
  293. MAKELONG(rcBounds.right, rcBounds.bottom),
  294. WEF_ASYNC);
  295. ENDATOMICCHECK();
  296. #endif
  297. if (TestWF(pwnd, WEFCOMPOSITED)) {
  298. if (TestWF(pwnd, WEFPCOMPOSITING)) {
  299. UnionRect(&prdr->rcUpdate, &prdr->rcUpdate, &rcBounds);
  300. } else {
  301. HRGN hrgn;
  302. OffsetRect(&rcBounds, pwnd->rcWindow.left, pwnd->rcWindow.top);
  303. hrgn = GreCreateRectRgnIndirect(&rcBounds);
  304. BEGINATOMICCHECK();
  305. xxxInternalInvalidate(pwnd,
  306. hrgn,
  307. RDW_ALLCHILDREN | RDW_INVALIDATE |
  308. RDW_ERASE | RDW_FRAME);
  309. ENDATOMICCHECK();
  310. GreDeleteObject(hrgn);
  311. }
  312. } else if (TestWF(pwnd, WEFLAYERED)) {
  313. hbm = prdr->hbm;
  314. hbmOld = GreSelectBitmap(ghdcMem, hbm);
  315. size.cx = pwnd->rcWindow.right - pwnd->rcWindow.left;
  316. size.cy = pwnd->rcWindow.bottom - pwnd->rcWindow.top;
  317. pt.x = pt.y = 0;
  318. GreUpdateSprite(gpDispInfo->hDev, PtoHq(pwnd), NULL, NULL, NULL,
  319. &size, ghdcMem, &pt, 0, NULL, ULW_DEFAULT_ATTRIBUTES, &rcBounds);
  320. GreSelectBitmap(ghdcMem, hbmOld);
  321. }
  322. }
  323. /***************************************************************************\
  324. * DeleteRedirectionBitmap
  325. *
  326. \***************************************************************************/
  327. VOID DeleteRedirectionBitmap(
  328. PWND pwnd,
  329. HBITMAP hbm)
  330. {
  331. GreMarkDeletableBitmap(hbm);
  332. GreDeleteObject(hbm);
  333. DecrementRedirectedCount(pwnd);
  334. }
  335. /***************************************************************************\
  336. * RemoveRedirectionBitmap
  337. *
  338. * 9/23/1998 vadimg created
  339. \***************************************************************************/
  340. VOID RemoveRedirectionBitmap(
  341. PWND pwnd)
  342. {
  343. HBITMAP hbm;
  344. /*
  345. * Delete the backing bitmap for this layered window.
  346. */
  347. if ((hbm = GetRedirectionBitmap(pwnd)) == NULL) {
  348. return;
  349. }
  350. UserAssert(TestWF(pwnd, WEFPREDIRECTED));
  351. ClrWF(pwnd, WEFPREDIRECTED);
  352. ConvertRedirectionDCs(pwnd, NULL);
  353. SetRedirectionBitmap(pwnd, NULL);
  354. DeleteRedirectionBitmap(pwnd, hbm);
  355. }
  356. /***************************************************************************\
  357. * _GetLayeredWindowAttributes
  358. *
  359. * 3/14/2000 jstall created
  360. \***************************************************************************/
  361. BOOL _GetLayeredWindowAttributes(
  362. PWND pwnd,
  363. COLORREF *pcrKey,
  364. BYTE *pbAlpha,
  365. DWORD *pdwFlags)
  366. {
  367. BLENDFUNCTION bf;
  368. UserAssert(pcrKey != NULL);
  369. UserAssert(pbAlpha != NULL);
  370. UserAssert(pdwFlags != NULL);
  371. if (!TestWF(pwnd, WEFLAYERED)) {
  372. RIPERR1(ERROR_INVALID_PARAMETER,
  373. RIP_WARNING,
  374. "GetLayeredWindowAttributes: not a sprite 0x%p",
  375. pwnd);
  376. return FALSE;
  377. }
  378. /*
  379. * Check that the window has a redirection bitmap and is marked as
  380. * layered through WS_EX_LAYERED. If the window is layered through
  381. * UpdateLayeredWindow, this function should fail.
  382. */
  383. if ((GetRedirectionFlags(pwnd) & REDIRECT_LAYER) == 0 ||
  384. !TestWF(pwnd, WEFLAYERED)) {
  385. return FALSE;
  386. }
  387. if (GreGetSpriteAttributes(gpDispInfo->hDev, PtoHq(pwnd), NULL, pcrKey, &bf, pdwFlags)) {
  388. *pbAlpha = bf.SourceConstantAlpha;
  389. return TRUE;
  390. }
  391. return FALSE;
  392. }
  393. /***************************************************************************\
  394. * _SetLayeredWindowAttributes
  395. *
  396. * 9/24/1998 vadimg created
  397. \***************************************************************************/
  398. BOOL _SetLayeredWindowAttributes(
  399. PWND pwnd,
  400. COLORREF crKey,
  401. BYTE bAlpha,
  402. DWORD dwFlags)
  403. {
  404. BOOL bRet;
  405. BLENDFUNCTION blend;
  406. HBITMAP hbm;
  407. if (!TestWF(pwnd, WEFLAYERED)) {
  408. RIPERR1(ERROR_INVALID_PARAMETER,
  409. RIP_WARNING,
  410. "SetLayeredWindowAttributes: not a sprite 0x%p",
  411. pwnd);
  412. return FALSE;
  413. }
  414. if ((hbm = GetRedirectionBitmap(pwnd)) == NULL) {
  415. if (!SetRedirectedWindow(pwnd, REDIRECT_LAYER)) {
  416. return FALSE;
  417. }
  418. }
  419. blend.BlendOp = AC_SRC_OVER;
  420. blend.BlendFlags = 0;
  421. blend.AlphaFormat = 0;
  422. blend.SourceConstantAlpha = bAlpha;
  423. dwFlags |= ULW_NEW_ATTRIBUTES; // Notify gdi that these are new attributes
  424. if (hbm != NULL) {
  425. HBITMAP hbmOld;
  426. SIZE size;
  427. POINT ptSrc = {0,0};
  428. hbmOld = GreSelectBitmap(ghdcMem, hbm);
  429. size.cx = pwnd->rcWindow.right - pwnd->rcWindow.left;
  430. size.cy = pwnd->rcWindow.bottom - pwnd->rcWindow.top;
  431. bRet = GreUpdateSprite(gpDispInfo->hDev, PtoHq(pwnd), NULL, NULL,
  432. NULL, &size, ghdcMem, &ptSrc, crKey, &blend, dwFlags, NULL);
  433. GreSelectBitmap(ghdcMem, hbmOld);
  434. } else {
  435. bRet = GreUpdateSprite(gpDispInfo->hDev, PtoHq(pwnd), NULL, NULL,
  436. NULL, NULL, NULL, NULL, crKey, &blend, dwFlags, NULL);
  437. }
  438. return bRet;
  439. }
  440. /***************************************************************************\
  441. * RecreateRedirectionBitmap
  442. *
  443. * 10/1/1998 vadimg created
  444. \***************************************************************************/
  445. BOOL RecreateRedirectionBitmap(
  446. PWND pwnd)
  447. {
  448. HBITMAP hbm, hbmNew, hbmMem, hbmMem2;
  449. BITMAP bm, bmNew;
  450. int cx, cy;
  451. PDCE pdce;
  452. /*
  453. * No need to do anything if this layered window doesn't have
  454. * a redirection bitmap.
  455. */
  456. if ((hbm = GetRedirectionBitmap(pwnd)) == NULL) {
  457. return FALSE;
  458. }
  459. UserAssert(TestWF(pwnd, WEFPREDIRECTED));
  460. /*
  461. * Try to create a new redirection bitmap with the new size. If failed,
  462. * delete the old one and remove it from the window property list.
  463. */
  464. if ((hbmNew = CreateRedirectionBitmap(pwnd)) == NULL) {
  465. RemoveRedirectionBitmap(pwnd);
  466. return FALSE;
  467. }
  468. /*
  469. * Make sure that the display is locked, so that nobody can be drawing
  470. * into the redirection DCs while we're switching bitmaps under them.
  471. */
  472. UserAssert(GreIsDisplayLocked(gpDispInfo->hDev));
  473. /*
  474. * Get the size of the old bitmap to know how much to copy.
  475. */
  476. GreExtGetObjectW(hbm, sizeof(bm), (LPSTR)&bm);
  477. GreExtGetObjectW(hbmNew, sizeof(bmNew), (LPSTR)&bmNew);
  478. /*
  479. * Copy the bitmap from the old bitmap into the new one.
  480. */
  481. hbmMem = GreSelectBitmap(ghdcMem, hbm);
  482. hbmMem2 = GreSelectBitmap(ghdcMem2, hbmNew);
  483. cx = min(bm.bmWidth, bmNew.bmWidth);
  484. cy = min(bm.bmHeight, bmNew.bmHeight);
  485. GreBitBlt(ghdcMem2, 0, 0, cx, cy, ghdcMem, 0, 0, SRCCOPY | NOMIRRORBITMAP, 0);
  486. /*
  487. * Find layered DCs that are in use corresponding to this window and
  488. * replace the old redirection bitmap by the new one.
  489. */
  490. for (pdce = gpDispInfo->pdceFirst; pdce != NULL; pdce = pdce->pdceNext) {
  491. if (pdce->DCX_flags & DCX_DESTROYTHIS) {
  492. continue;
  493. }
  494. if (!(pdce->DCX_flags & DCX_REDIRECTED) || !(pdce->DCX_flags & DCX_INUSE)) {
  495. continue;
  496. }
  497. if (!_IsDescendant(pwnd, pdce->pwndOrg)) {
  498. continue;
  499. }
  500. UserVerify(GreSelectRedirectionBitmap(pdce->hdc, hbmNew));
  501. }
  502. GreSelectBitmap(ghdcMem, hbmMem);
  503. GreSelectBitmap(ghdcMem2, hbmMem2);
  504. /*
  505. * Finally, delete the old redirection bitmap.
  506. */
  507. DeleteRedirectionBitmap(pwnd, hbm);
  508. return TRUE;
  509. }
  510. /***************************************************************************\
  511. * ResetRedirectedWindows
  512. *
  513. \***************************************************************************/
  514. VOID ResetRedirectedWindows(
  515. VOID)
  516. {
  517. PHE phe, pheMax;
  518. PWND pwnd;
  519. GreLockDisplay(gpDispInfo->hDev);
  520. pheMax = &gSharedInfo.aheList[giheLast];
  521. for (phe = gSharedInfo.aheList; phe <= pheMax; phe++) {
  522. if (phe->bType != TYPE_WINDOW) {
  523. continue;
  524. }
  525. pwnd = (PWND)phe->phead;
  526. if (!TestWF(pwnd, WEFPREDIRECTED)) {
  527. continue;
  528. }
  529. RecreateRedirectionBitmap(pwnd);
  530. /*
  531. * Recreate the sprite so the surfaces are at the proper color depth.
  532. */
  533. if (TestWF(pwnd, WEFLAYERED)) {
  534. COLORREF cr;
  535. BLENDFUNCTION blend;
  536. DWORD dwFlags;
  537. GreGetSpriteAttributes(gpDispInfo->hDev, PtoHq(pwnd), NULL,
  538. &cr, &blend, &dwFlags);
  539. GreDeleteSprite(gpDispInfo->hDev, PtoHq(pwnd), NULL);
  540. if (GreCreateSprite(gpDispInfo->hDev, PtoHq(pwnd), &pwnd->rcWindow)) {
  541. _SetLayeredWindowAttributes(pwnd, cr, blend.SourceConstantAlpha,
  542. dwFlags);
  543. } else {
  544. RemoveRedirectionBitmap(pwnd);
  545. ClrWF(pwnd, WEFLAYERED);
  546. }
  547. }
  548. }
  549. GreUnlockDisplay(gpDispInfo->hDev);
  550. }
  551. /***************************************************************************\
  552. * UnsetLayeredWindow
  553. *
  554. * 1/30/1998 vadimg created
  555. \***************************************************************************/
  556. VOID UnsetLayeredWindow(
  557. PWND pwnd)
  558. {
  559. HWND hwnd = PtoHq(pwnd);
  560. UnsetRedirectedWindow(pwnd, REDIRECT_LAYER);
  561. /*
  562. * If the window is still visible, leave the sprite bits on the screen.
  563. */
  564. if (TestWF(pwnd, WFVISIBLE)) {
  565. GreUpdateSprite(gpDispInfo->hDev,
  566. hwnd,
  567. NULL,
  568. NULL,
  569. NULL,
  570. NULL,
  571. NULL,
  572. NULL,
  573. 0,
  574. NULL,
  575. ULW_NOREPAINT,
  576. NULL);
  577. }
  578. /*
  579. * Delete the sprite object.
  580. */
  581. if (!GreDeleteSprite(gpDispInfo->hDev, PtoHq(pwnd), NULL)) {
  582. RIPMSG1(RIP_WARNING, "xxxSetLayeredWindow failed 0x%p", pwnd);
  583. }
  584. ClrWF(pwnd, WEFLAYERED);
  585. /*
  586. * Make sure the window gets painted if visible.
  587. *
  588. * RAID 143578.
  589. * Should consider to jiggle the mouse. Remove IDC_NOMOUSE when
  590. * SetFMouseMoved and thus InvalidateDCCache don't leave crit.
  591. * This is because the hit-testing by a window may change when it
  592. * transitions the layering state.
  593. */
  594. if (TestWF(pwnd, WFVISIBLE)) {
  595. BEGINATOMICCHECK();
  596. zzzInvalidateDCCache(pwnd, IDC_DEFAULT | IDC_NOMOUSE);
  597. ENDATOMICCHECK();
  598. }
  599. }
  600. /***************************************************************************\
  601. * xxxSetLayeredWindow
  602. *
  603. * 12/05/97 vadimg wrote
  604. \***************************************************************************/
  605. HANDLE xxxSetLayeredWindow(
  606. PWND pwnd,
  607. BOOL fRepaintBehind)
  608. {
  609. HANDLE hsprite;
  610. SIZE size;
  611. CheckLock(pwnd);
  612. #ifndef CHILD_LAYERING
  613. if (!FTopLevel(pwnd)) {
  614. RIPMSG1(RIP_WARNING, "xxxSetLayeredWindow: not top-level 0x%p", pwnd);
  615. return NULL;
  616. }
  617. #endif
  618. UserAssertMsg1(!TestWF(pwnd, WEFLAYERED),
  619. "xxxSetLayeredWindow: already layered 0x%p",
  620. pwnd);
  621. size.cx = pwnd->rcWindow.right - pwnd->rcWindow.left;
  622. size.cy = pwnd->rcWindow.bottom - pwnd->rcWindow.top;
  623. hsprite = GreCreateSprite(gpDispInfo->hDev, PtoHq(pwnd), &pwnd->rcWindow);
  624. if (hsprite == NULL) {
  625. RIPMSG1(RIP_WARNING, "xxxSetLayeredWindow failed 0x%p", pwnd);
  626. return NULL;
  627. }
  628. SetWF(pwnd, WEFLAYERED);
  629. TrackLayeredZorder(pwnd);
  630. /*
  631. * Invalidate the DC cache because changing the sprite status
  632. * may change the visrgn for some windows.
  633. *
  634. * RAID 143578.
  635. * Should jiggle the mouse. Remove IDC_NOMOUSE when
  636. * SetFMouseMoved and thus InvalidateDCCache don't leave crit.
  637. * This is because the hit-testing by a window may change when it
  638. * transitions the layering state.
  639. */
  640. BEGINATOMICCHECK();
  641. zzzInvalidateDCCache(pwnd, IDC_DEFAULT | IDC_NOMOUSE);
  642. ENDATOMICCHECK();
  643. /*
  644. * For the dynamic promotion to a sprite, put the proper bits into
  645. * the sprite itself by doing ULW with the current screen content
  646. * and into the background by invalidating windows behind. There
  647. * might be some dirty bits if the window is partially obscured, but
  648. * they will be refreshed as soon as the app calls ULW on its own.
  649. */
  650. if (TestWF(pwnd, WFVISIBLE)) {
  651. if (fRepaintBehind) {
  652. POINT pt;
  653. pt.x = pwnd->rcWindow.left;
  654. pt.y = pwnd->rcWindow.top;
  655. _UpdateLayeredWindow(pwnd, gpDispInfo->hdcScreen, &pt, &size,
  656. gpDispInfo->hdcScreen, &pt, 0, NULL, ULW_OPAQUE);
  657. }
  658. } else {
  659. /*
  660. * No need to repaint behind if the window is still invisible.
  661. */
  662. fRepaintBehind = FALSE;
  663. }
  664. /*
  665. * This must be done after the DC cache is invalidated, because
  666. * the xxxUpdateWindows call will redraw some stuff.
  667. */
  668. if (fRepaintBehind) {
  669. HRGN hrgn = GreCreateRectRgnIndirect(&pwnd->rcWindow);
  670. xxxRedrawWindow(NULL, NULL, hrgn,
  671. RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ALLCHILDREN);
  672. xxxUpdateWindows(pwnd, hrgn);
  673. GreDeleteObject(hrgn);
  674. }
  675. return hsprite;
  676. }
  677. /***************************************************************************\
  678. * UserVisrgnFromHwnd
  679. *
  680. * Calculate a non-clipchildren visrgn for sprites. This function must be
  681. * called while inside the USER critical section.
  682. *
  683. * 12/05/97 vadimg wrote
  684. \***************************************************************************/
  685. BOOL UserVisrgnFromHwnd(HRGN *phrgn, HWND hwnd)
  686. {
  687. PWND pwnd;
  688. DWORD dwFlags;
  689. RECT rcWindow;
  690. BOOL fRet;
  691. CheckCritIn();
  692. if ((pwnd = RevalidateHwnd(hwnd)) == NULL) {
  693. RIPMSG0(RIP_WARNING, "VisrgnFromHwnd: invalid hwnd");
  694. return FALSE;
  695. }
  696. /*
  697. * So that we don't have to recompute the layered window's visrgn
  698. * every time the layered window is moved, we compute the visrgn once
  699. * as if the layered window covered the entire screen. GDI will
  700. * automatically intersect with this region whenever the sprite moves.
  701. */
  702. rcWindow = pwnd->rcWindow;
  703. pwnd->rcWindow = gpDispInfo->rcScreen;
  704. /*
  705. * Since we use DCX_WINDOW, only rcWindow needs to be faked and saved.
  706. * Never specify DCX_REDIRECTEDBITMAP here. See comments in CalcVisRgn().
  707. */
  708. dwFlags = DCX_WINDOW | DCX_LOCKWINDOWUPDATE;
  709. if (TestWF(pwnd, WFCLIPSIBLINGS))
  710. dwFlags |= DCX_CLIPSIBLINGS;
  711. fRet = CalcVisRgn(phrgn, pwnd, pwnd, dwFlags);
  712. pwnd->rcWindow = rcWindow;
  713. return fRet;
  714. }
  715. /***************************************************************************\
  716. * SetRectRelative
  717. \***************************************************************************/
  718. void SetRectRelative(PRECT prc, int dx, int dy, int dcx, int dcy)
  719. {
  720. prc->left += dx;
  721. prc->top += dy;
  722. prc->right += (dx + dcx);
  723. prc->bottom += (dy + dcy);
  724. }
  725. /***************************************************************************\
  726. * xxxUpdateLayeredWindow
  727. *
  728. * 1/20/1998 vadimg created
  729. \***************************************************************************/
  730. BOOL _UpdateLayeredWindow(
  731. PWND pwnd,
  732. HDC hdcDst,
  733. POINT *pptDst,
  734. SIZE *psize,
  735. HDC hdcSrc,
  736. POINT *pptSrc,
  737. COLORREF crKey,
  738. BLENDFUNCTION *pblend,
  739. DWORD dwFlags)
  740. {
  741. int dx, dy, dcx, dcy;
  742. BOOL fMove = FALSE, fSize = FALSE;
  743. /*
  744. * Verify that we're called with a real layered window.
  745. */
  746. if (!TestWF(pwnd, WEFLAYERED) ||
  747. GetRedirectionBitmap(pwnd) != NULL) {
  748. RIPERR1(ERROR_INVALID_PARAMETER, RIP_WARNING,
  749. "_UpdateLayeredWindow: can't call on window 0x%p", pwnd);
  750. return FALSE;
  751. }
  752. if (!GreUpdateSprite(gpDispInfo->hDev, PtoHq(pwnd), NULL, hdcDst, pptDst,
  753. psize, hdcSrc, pptSrc, crKey, pblend, dwFlags, NULL)) {
  754. RIPMSG1(RIP_WARNING, "_UpdateLayeredWindow: !UpdateSprite 0x%p", pwnd);
  755. return FALSE;
  756. }
  757. /*
  758. * Figure out relative adjustments in position and size.
  759. */
  760. if (pptDst != NULL) {
  761. dx = pptDst->x - pwnd->rcWindow.left;
  762. dy = pptDst->y - pwnd->rcWindow.top;
  763. if (dx != 0 || dy != 0) {
  764. fMove = TRUE;
  765. }
  766. } else {
  767. dx = 0;
  768. dy = 0;
  769. }
  770. if (psize != NULL) {
  771. dcx = psize->cx - (pwnd->rcWindow.right - pwnd->rcWindow.left);
  772. dcy = psize->cy - (pwnd->rcWindow.bottom - pwnd->rcWindow.top);
  773. if (dcx != 0 || dcy != 0) {
  774. fSize = TRUE;
  775. }
  776. } else {
  777. dcx = 0;
  778. dcy = 0;
  779. }
  780. if (fMove || fSize) {
  781. /*
  782. * Adjust the client rect position and size relative to
  783. * the window rect.
  784. */
  785. SetRectRelative(&pwnd->rcWindow, dx, dy, dcx, dcy);
  786. SetRectRelative(&pwnd->rcClient, dx, dy, dcx, dcy);
  787. /*
  788. * Since the client rect could be smaller than the window
  789. * rect make sure the client rect doesn't underflow!
  790. */
  791. if ((dcx < 0) && (pwnd->rcClient.left < pwnd->rcWindow.left)) {
  792. pwnd->rcClient.left = pwnd->rcWindow.left;
  793. pwnd->rcClient.right = pwnd->rcWindow.left;
  794. }
  795. if ((dcy < 0) && (pwnd->rcClient.top < pwnd->rcWindow.top)) {
  796. pwnd->rcClient.top = pwnd->rcWindow.top;
  797. pwnd->rcClient.bottom = pwnd->rcWindow.top;
  798. }
  799. /*
  800. * RAID 143578.
  801. * The shape of the layered window may have changed and thus
  802. * ideally we should jiggle the mouse. Currently, that would
  803. * make us leave the critical section which we don't want to do.
  804. *
  805. * SetFMouseMoved();
  806. */
  807. }
  808. return TRUE;
  809. }
  810. /***************************************************************************\
  811. * DeleteFadeSprite
  812. \***************************************************************************/
  813. PWND DeleteFadeSprite(void)
  814. {
  815. PWND pwnd = NULL;
  816. if (gfade.dwFlags & FADE_WINDOW) {
  817. if ((pwnd = RevalidateHwnd(gfade.hsprite)) != NULL) {
  818. if (TestWF(pwnd, WEFLAYERED)) {
  819. UnsetLayeredWindow(pwnd);
  820. }
  821. } else {
  822. RIPMSG0(RIP_WARNING, "DeleteFadeSprite: hwnd no longer valid");
  823. }
  824. } else {
  825. GreDeleteSprite(gpDispInfo->hDev, NULL, gfade.hsprite);
  826. }
  827. gfade.hsprite = NULL;
  828. return pwnd;
  829. }
  830. /***************************************************************************\
  831. * UpdateFade
  832. *
  833. * 2/16/1998 vadimg created
  834. \***************************************************************************/
  835. void UpdateFade(POINT *pptDst, SIZE *psize, HDC hdcSrc, POINT *pptSrc,
  836. BLENDFUNCTION *pblend)
  837. {
  838. PWND pwnd;
  839. if (gfade.dwFlags & FADE_WINDOW) {
  840. if ((pwnd = RevalidateHwnd(gfade.hsprite)) != NULL) {
  841. _UpdateLayeredWindow(pwnd, NULL, pptDst, psize, hdcSrc,
  842. pptSrc, 0, pblend, ULW_ALPHA);
  843. }
  844. } else {
  845. #ifdef MOUSE_IP
  846. DWORD dwShape = ULW_ALPHA;
  847. if (gfade.dwFlags & FADE_COLORKEY) {
  848. dwShape = ULW_COLORKEY;
  849. }
  850. GreUpdateSprite(gpDispInfo->hDev, NULL, gfade.hsprite, NULL,
  851. pptDst, psize, hdcSrc, pptSrc, gfade.crColorKey, pblend, dwShape, NULL);
  852. #else
  853. GreUpdateSprite(gpDispInfo->hDev, NULL, gfade.hsprite, NULL,
  854. pptDst, psize, hdcSrc, pptSrc, 0, pblend, ULW_ALPHA, NULL);
  855. #endif
  856. }
  857. }
  858. /***************************************************************************\
  859. * CreateFade
  860. *
  861. * 2/5/1998 vadimg created
  862. \***************************************************************************/
  863. HDC CreateFade(PWND pwnd, RECT *prc, DWORD dwTime, DWORD dwFlags)
  864. {
  865. SIZE size;
  866. /*
  867. * Bail if there is a fade animation going on already.
  868. */
  869. if (gfade.hbm != NULL) {
  870. RIPMSG0(RIP_WARNING, "CreateFade: failed, fade not available");
  871. return NULL;
  872. }
  873. /*
  874. * Create a cached compatible DC.
  875. */
  876. if (gfade.hdc == NULL) {
  877. gfade.hdc = GreCreateCompatibleDC(gpDispInfo->hdcScreen);
  878. if (gfade.hdc == NULL) {
  879. return NULL;
  880. }
  881. } else {
  882. /*
  883. * Reset the hdc before reusing it.
  884. */
  885. GreSetLayout(gfade.hdc , -1, 0);
  886. }
  887. /*
  888. * A windowed fade must have window position and size, so
  889. * prc passed in is disregarded.
  890. */
  891. UserAssert((pwnd == NULL) || (prc == NULL));
  892. if (pwnd != NULL) {
  893. prc = &pwnd->rcWindow;
  894. }
  895. size.cx = prc->right - prc->left;
  896. size.cy = prc->bottom - prc->top;
  897. if (pwnd == NULL) {
  898. gfade.hsprite = GreCreateSprite(gpDispInfo->hDev, NULL, prc);
  899. } else {
  900. gfade.dwFlags |= FADE_WINDOW;
  901. gfade.hsprite = HWq(pwnd);
  902. BEGINATOMICCHECK();
  903. xxxSetLayeredWindow(pwnd, FALSE);
  904. ENDATOMICCHECK();
  905. }
  906. if (gfade.hsprite == NULL)
  907. return FALSE;
  908. /*
  909. * Create a compatible bitmap for this size animation.
  910. */
  911. gfade.hbm = GreCreateCompatibleBitmap(gpDispInfo->hdcScreen, size.cx, size.cy);
  912. if (gfade.hbm == NULL) {
  913. DeleteFadeSprite();
  914. return NULL;
  915. }
  916. GreSelectBitmap(gfade.hdc, gfade.hbm);
  917. /*
  918. * Mirror the hdc if it will be used to fade a mirrored window.
  919. */
  920. if ((pwnd != NULL) && TestWF(pwnd, WEFLAYOUTRTL)) {
  921. GreSetLayout(gfade.hdc , -1, LAYOUT_RTL);
  922. }
  923. /*
  924. * Since this isn't necessarily the first animation and the hdc could
  925. * be set to public, make sure the owner is the current process. This
  926. * way this process will be able to draw into it.
  927. */
  928. GreSetDCOwner(gfade.hdc, OBJECT_OWNER_CURRENT);
  929. /*
  930. * Initialize all other fade animation data.
  931. */
  932. gfade.ptDst.x = prc->left;
  933. gfade.ptDst.y = prc->top;
  934. gfade.size.cx = size.cx;
  935. gfade.size.cy = size.cy;
  936. gfade.dwTime = dwTime;
  937. gfade.dwFlags |= dwFlags;
  938. #ifdef MOUSE_IP
  939. if (gfade.dwFlags & FADE_COLORKEY) {
  940. gfade.crColorKey = COLORKEY_COLOR;
  941. } else {
  942. gfade.crColorKey = 0;
  943. }
  944. #endif
  945. return gfade.hdc;
  946. }
  947. /***************************************************************************\
  948. * ShowFade
  949. *
  950. * GDI says that for alpha fade-out it's more efficient to do the first
  951. * show as opaque alpha instead of using ULW_OPAQUE.
  952. \***************************************************************************/
  953. #define ALPHASTART 40
  954. VOID ShowFade(
  955. VOID)
  956. {
  957. BLENDFUNCTION blend;
  958. POINT ptSrc;
  959. BOOL fShow;
  960. UserAssert(gfade.hdc != NULL);
  961. UserAssert(gfade.hbm != NULL);
  962. if (gfade.dwFlags & FADE_SHOWN) {
  963. return;
  964. }
  965. fShow = (gfade.dwFlags & FADE_SHOW);
  966. ptSrc.x = ptSrc.y = 0;
  967. blend.BlendOp = AC_SRC_OVER;
  968. blend.BlendFlags = 0;
  969. blend.AlphaFormat = 0;
  970. blend.SourceConstantAlpha = fShow ? ALPHASTART : (255 - ALPHASTART);
  971. UpdateFade(&gfade.ptDst, &gfade.size, gfade.hdc, &ptSrc, &blend);
  972. gfade.dwFlags |= FADE_SHOWN;
  973. }
  974. /***************************************************************************\
  975. * StartFade
  976. *
  977. * 2/5/1998 vadimg created
  978. \***************************************************************************/
  979. VOID StartFade(
  980. VOID)
  981. {
  982. DWORD dwTimer = 10;
  983. DWORD dwElapsed;
  984. UserAssert(gfade.hdc != NULL);
  985. UserAssert(gfade.hbm != NULL);
  986. /*
  987. * Set dc and bitmap to public so the desktop thread can use them.
  988. */
  989. GreSetDCOwner(gfade.hdc, OBJECT_OWNER_PUBLIC);
  990. GreSetBitmapOwner(gfade.hbm, OBJECT_OWNER_PUBLIC);
  991. /*
  992. * If it's not already shown, do the initial update that makes copy of
  993. * the source. All other updates will only need to change the alpha value.
  994. */
  995. ShowFade();
  996. /*
  997. * Get the start time for the fade animation.
  998. */
  999. dwElapsed = (gfade.dwTime * ALPHASTART + 255) / 255;
  1000. gfade.dwStart = NtGetTickCount() - dwElapsed;
  1001. /*
  1002. * Set the timer in the desktop thread. This will insure that the
  1003. * animation is smooth and won't get stuck if the current thread hangs.
  1004. */
  1005. #ifdef MOUSE_IP
  1006. if (gfade.dwFlags & FADE_SONAR) {
  1007. /*
  1008. * Sonar requires slower timer.
  1009. */
  1010. dwTimer = MOUSE_SONAR_RADIUS_TIMER;
  1011. }
  1012. #endif
  1013. InternalSetTimer(gTermIO.spwndDesktopOwner,
  1014. IDSYS_FADE,
  1015. dwTimer,
  1016. xxxSystemTimerProc,
  1017. TMRF_SYSTEM | TMRF_PTIWINDOW);
  1018. }
  1019. /***************************************************************************\
  1020. * StopFade
  1021. *
  1022. * 2/5/1998 vadimg created
  1023. \***************************************************************************/
  1024. VOID StopFade(
  1025. VOID)
  1026. {
  1027. DWORD dwRop = SRCCOPY;
  1028. PWND pwnd;
  1029. UserAssert(gfade.hdc != NULL);
  1030. UserAssert(gfade.hbm != NULL);
  1031. /*
  1032. * Stop the fade animation timer.
  1033. */
  1034. _KillSystemTimer(gTermIO.spwndDesktopOwner, IDSYS_FADE);
  1035. pwnd = DeleteFadeSprite();
  1036. /*
  1037. * If showing and the animation isn't completed, blt the last frame.
  1038. */
  1039. if (!(gfade.dwFlags & FADE_COMPLETED) && (gfade.dwFlags & FADE_SHOW)) {
  1040. int x, y;
  1041. HDC hdc;
  1042. /*
  1043. * For a windowed fade, make sure we observe the current visrgn.
  1044. */
  1045. if (pwnd != NULL) {
  1046. hdc = _GetDCEx(pwnd, NULL, DCX_WINDOW | DCX_CACHE);
  1047. x = 0;
  1048. y = 0;
  1049. } else {
  1050. hdc = gpDispInfo->hdcScreen;
  1051. x = gfade.ptDst.x;
  1052. y = gfade.ptDst.y;
  1053. }
  1054. /*
  1055. * If the destination DC is RTL mirrored, then BitBlt call should mirror the
  1056. * content, since we want the menu to preserve it text (i.e. not to
  1057. * be flipped). [samera]
  1058. */
  1059. if (GreGetLayout(hdc) & LAYOUT_RTL) {
  1060. dwRop |= NOMIRRORBITMAP;
  1061. }
  1062. GreBitBlt(hdc, x, y, gfade.size.cx, gfade.size.cy, gfade.hdc, 0, 0, dwRop, 0);
  1063. _ReleaseDC(hdc);
  1064. }
  1065. /*
  1066. * Clean up the animation data.
  1067. */
  1068. GreSelectBitmap(gfade.hdc, GreGetStockObject(PRIV_STOCK_BITMAP));
  1069. GreCleanDC(gfade.hdc);
  1070. GreSetDCOwner(gfade.hdc, OBJECT_OWNER_PUBLIC);
  1071. GreDeleteObject(gfade.hbm);
  1072. gfade.hbm = NULL;
  1073. gfade.dwFlags = 0;
  1074. }
  1075. /***************************************************************************\
  1076. * AnimateFade
  1077. *
  1078. * 2/5/1998 vadimg created
  1079. \***************************************************************************/
  1080. VOID AnimateFade(
  1081. VOID)
  1082. {
  1083. DWORD dwTimeElapsed;
  1084. BLENDFUNCTION blend;
  1085. BYTE bAlpha;
  1086. BOOL fShow;
  1087. UserAssert(gfade.hdc != NULL);
  1088. UserAssert(gfade.hbm != NULL);
  1089. dwTimeElapsed = NtGetTickCount() - gfade.dwStart;
  1090. /*
  1091. * If exceeding the allowed time, stop the animation now.
  1092. */
  1093. if (dwTimeElapsed > gfade.dwTime) {
  1094. StopFade();
  1095. return;
  1096. }
  1097. fShow = (gfade.dwFlags & FADE_SHOW);
  1098. /*
  1099. * Calculate new alpha value based on time elapsed.
  1100. */
  1101. if (fShow) {
  1102. bAlpha = (BYTE)((255 * dwTimeElapsed) / gfade.dwTime);
  1103. } else {
  1104. bAlpha = (BYTE)(255 * (gfade.dwTime - dwTimeElapsed) / gfade.dwTime);
  1105. }
  1106. blend.BlendOp = AC_SRC_OVER;
  1107. blend.BlendFlags = 0;
  1108. blend.AlphaFormat = 0;
  1109. blend.SourceConstantAlpha = bAlpha;
  1110. #ifdef MOUSE_IP
  1111. if (gfade.dwFlags & FADE_SONAR) {
  1112. DrawSonar(gfade.hdc);
  1113. UpdateFade(&gfade.ptDst, &gfade.size, gfade.hdc, (LPPOINT)&gZero.pt, NULL);
  1114. giSonarRadius -= MOUSE_SONAR_RADIUS_DELTA;
  1115. } else {
  1116. UpdateFade(NULL, NULL, NULL, NULL, &blend);
  1117. }
  1118. /*
  1119. * Check if finished animating the fade.
  1120. */
  1121. if ((fShow && bAlpha == 255) || (!fShow && bAlpha == 0) || ((gfade.dwFlags & FADE_SONAR) && giSonarRadius < 0)) {
  1122. gfade.dwFlags |= FADE_COMPLETED;
  1123. StopFade();
  1124. }
  1125. #else
  1126. UpdateFade(NULL, NULL, NULL, NULL, &blend);
  1127. /*
  1128. * Check if finished animating the fade.
  1129. */
  1130. if ((fShow && bAlpha == 255) || (!fShow && bAlpha == 0)) {
  1131. gfade.dwFlags |= FADE_COMPLETED;
  1132. StopFade();
  1133. }
  1134. #endif
  1135. }
  1136. /***************************************************************************\
  1137. * SetRedirectedWindow
  1138. *
  1139. * 1/27/99 vadimg wrote
  1140. \***************************************************************************/
  1141. BOOL SetRedirectedWindow(
  1142. PWND pwnd,
  1143. UINT uFlags)
  1144. {
  1145. HBITMAP hbmNew = NULL;
  1146. PREDIRECT prdr;
  1147. PCLS pcls;
  1148. if (!TestWF(pwnd, WEFPREDIRECTED)) {
  1149. /*
  1150. * Setup the window for Redirection. This will create a new bitmap to
  1151. * redirect drawing into, and then converting all HDC's to that window
  1152. * to draw into that bitmap. The contents of the bitmap will be copied
  1153. * to the screen in UpdateRedirectedDC().
  1154. */
  1155. UserAssert(GetRedirectionBitmap(pwnd) == NULL);
  1156. /*
  1157. * NOTE: We can only redirect windows that don't use CS_CLASSDC or
  1158. * CS_PARENTDC. This is because we need to setup a new to draw into
  1159. * that is not the screen HDC. When we do this, we explicitely mark
  1160. * the DC with DCX_REDIRECTED.
  1161. *
  1162. * In the case of CS_CLASSDC or CS_PARENTDC, that DC may be shared
  1163. * between a redirected window and a non-redirected window, causing a
  1164. * conflict.
  1165. *
  1166. * This is not a problem for CS_OWNDC, since the window has its own
  1167. * HDC that will not be shared. It does however require that we setup
  1168. * redirection after this HDC is already built. This behavior was
  1169. * changed in Whistler (NT 5.1).
  1170. */
  1171. pcls = pwnd->pcls;
  1172. if (TestCF2(pcls, CFPARENTDC) || TestCF2(pcls, CFCLASSDC)) {
  1173. RIPMSG0(RIP_WARNING, "Cannot enable redirection on CS_PARENTDC, or CS_CLASSDC window");
  1174. return FALSE;
  1175. }
  1176. if ((hbmNew = CreateRedirectionBitmap(pwnd)) == NULL) {
  1177. return FALSE;
  1178. }
  1179. ConvertRedirectionDCs(pwnd, hbmNew);
  1180. }
  1181. prdr = _GetProp(pwnd, PROP_LAYER, TRUE);
  1182. prdr->uFlags |= uFlags;
  1183. #if DBG
  1184. prdr->pwnd = pwnd;
  1185. #endif
  1186. return TRUE;
  1187. }
  1188. /***************************************************************************\
  1189. * UnsetRedirectedWindow
  1190. *
  1191. * 1/27/1999 vadimg created
  1192. \***************************************************************************/
  1193. VOID UnsetRedirectedWindow(
  1194. PWND pwnd,
  1195. UINT uFlags)
  1196. {
  1197. if (TestWF(pwnd, WEFPREDIRECTED)) {
  1198. PREDIRECT prdr = _GetProp(pwnd, PROP_LAYER, TRUE);
  1199. prdr->uFlags &= ~uFlags;
  1200. if (prdr->uFlags != 0) {
  1201. return;
  1202. }
  1203. RemoveRedirectionBitmap(pwnd);
  1204. }
  1205. }
  1206. #ifdef CHILD_LAYERING
  1207. /***************************************************************************\
  1208. * GetNextLayeredWindow
  1209. *
  1210. * Preorder traversal of the window tree to find the next layering window
  1211. * below in zorder than pwnd. We need this because sprites are stored in a
  1212. * linked list. Note that this algorithm is iterative which is cool!
  1213. \***************************************************************************/
  1214. PWND GetNextLayeredWindow(
  1215. PWND pwnd)
  1216. {
  1217. while (TRUE) {
  1218. if (pwnd->spwndChild != NULL) {
  1219. pwnd = pwnd->spwndChild;
  1220. } else if (pwnd->spwndNext != NULL) {
  1221. pwnd = pwnd->spwndNext;
  1222. } else {
  1223. do {
  1224. pwnd = pwnd->spwndParent;
  1225. if (pwnd == NULL) {
  1226. return NULL;
  1227. }
  1228. } while (pwnd->spwndNext == NULL);
  1229. pwnd = pwnd->spwndNext;
  1230. }
  1231. if (TestWF(pwnd, WEFLAYERED)) {
  1232. return pwnd;
  1233. }
  1234. }
  1235. }
  1236. #endif
  1237. /***************************************************************************\
  1238. * GetStyleWindow
  1239. *
  1240. \***************************************************************************/
  1241. PWND GetStyleWindow(
  1242. PWND pwnd,
  1243. DWORD dwStyle)
  1244. {
  1245. while (pwnd != NULL) {
  1246. if (TestWF(pwnd, dwStyle)) {
  1247. break;
  1248. }
  1249. pwnd = pwnd->spwndParent;
  1250. }
  1251. return pwnd;
  1252. }
  1253. /***************************************************************************\
  1254. * TrackLayeredZorder
  1255. *
  1256. * Unlike USER, GDI stores sprites from bottom to top.
  1257. \***************************************************************************/
  1258. VOID TrackLayeredZorder(
  1259. PWND pwnd)
  1260. {
  1261. #ifdef CHILD_LAYERING
  1262. PWND pwndT = GetNextLayeredWindow(pwnd);
  1263. #else
  1264. PWND pwndT = pwnd->spwndNext;
  1265. while (pwndT != NULL) {
  1266. if (TestWF(pwndT, WEFLAYERED)) {
  1267. break;
  1268. }
  1269. pwndT = pwndT->spwndNext;
  1270. }
  1271. #endif
  1272. GreZorderSprite(gpDispInfo->hDev, PtoHq(pwnd), PtoH(pwndT));
  1273. }
  1274. /***************************************************************************\
  1275. * GetRedirectionBitmap
  1276. *
  1277. \***************************************************************************/
  1278. HBITMAP GetRedirectionBitmap(
  1279. PWND pwnd)
  1280. {
  1281. PREDIRECT prdr = _GetProp(pwnd, PROP_LAYER, TRUE);
  1282. if (prdr != NULL) {
  1283. return prdr->hbm;
  1284. }
  1285. return NULL;
  1286. }
  1287. /***************************************************************************\
  1288. * SetRedirectionBitmap
  1289. *
  1290. \***************************************************************************/
  1291. BOOL SetRedirectionBitmap(
  1292. PWND pwnd,
  1293. HBITMAP hbm)
  1294. {
  1295. PREDIRECT prdr;
  1296. if (hbm == NULL) {
  1297. prdr = (PREDIRECT)InternalRemoveProp(pwnd, PROP_LAYER, TRUE);
  1298. if (prdr != NULL) {
  1299. UserFreePool(prdr);
  1300. }
  1301. } else {
  1302. prdr = _GetProp(pwnd, PROP_LAYER, TRUE);
  1303. if (prdr == NULL) {
  1304. if ((prdr = (PREDIRECT)UserAllocPool(sizeof(REDIRECT),
  1305. TAG_REDIRECT)) == NULL) {
  1306. return FALSE;
  1307. }
  1308. if (!InternalSetProp(pwnd, PROP_LAYER, (HANDLE)prdr, PROPF_INTERNAL)) {
  1309. UserFreePool(prdr);
  1310. return FALSE;
  1311. }
  1312. } else {
  1313. DeleteMaybeSpecialRgn(prdr->hrgnComp);
  1314. }
  1315. prdr->hbm = hbm;
  1316. prdr->uFlags = 0;
  1317. prdr->hrgnComp = NULL;
  1318. SetRectEmpty(&prdr->rcUpdate);
  1319. }
  1320. return TRUE;
  1321. }
  1322. #ifdef MOUSE_IP
  1323. CONST RECT grcSonar = {0, 0, MOUSE_SONAR_RADIUS_INIT * 2, MOUSE_SONAR_RADIUS_INIT * 2};
  1324. VOID DrawSonar(
  1325. HDC hdc)
  1326. {
  1327. HBRUSH hbrBackground;
  1328. HBRUSH hbrRing, hbrOld;
  1329. HPEN hpen, hpenOld;
  1330. hbrBackground = GreCreateSolidBrush(COLORKEY_COLOR);
  1331. if (hbrBackground == NULL) {
  1332. RIPMSG0(RIP_WARNING, "DrawSonar: failed to create background brush.");
  1333. return;
  1334. }
  1335. FillRect(hdc, &grcSonar, hbrBackground);
  1336. /*
  1337. * Pen for the edges.
  1338. */
  1339. hpen = GreCreatePen(PS_SOLID, 0, RGB(255, 255, 255), NULL);
  1340. if (hpen == NULL) {
  1341. RIPMSG0(RIP_WARNING, "DrawSonar: failed to create pen.");
  1342. goto return1;
  1343. }
  1344. hpenOld = GreSelectPen(hdc, hpen);
  1345. /*
  1346. * Draw the ring.
  1347. */
  1348. hbrRing = GreCreateSolidBrush(RGB(128, 128, 128));
  1349. if (hbrRing == NULL) {
  1350. goto return2;
  1351. }
  1352. hbrOld = GreSelectBrush(hdc, hbrRing);
  1353. NtGdiEllipse(hdc, MOUSE_SONAR_RADIUS_INIT - giSonarRadius, MOUSE_SONAR_RADIUS_INIT - giSonarRadius,
  1354. MOUSE_SONAR_RADIUS_INIT + giSonarRadius, MOUSE_SONAR_RADIUS_INIT + giSonarRadius);
  1355. /*
  1356. * Draw innter hollow area (this draws inner edge as well).
  1357. */
  1358. GreSelectBrush(hdc, hbrBackground);
  1359. NtGdiEllipse(hdc, MOUSE_SONAR_RADIUS_INIT - giSonarRadius + MOUSE_SONAR_LINE_WIDTH,
  1360. MOUSE_SONAR_RADIUS_INIT - giSonarRadius + MOUSE_SONAR_LINE_WIDTH,
  1361. MOUSE_SONAR_RADIUS_INIT + giSonarRadius - MOUSE_SONAR_LINE_WIDTH,
  1362. MOUSE_SONAR_RADIUS_INIT + giSonarRadius - MOUSE_SONAR_LINE_WIDTH);
  1363. /*
  1364. * Clean up things.
  1365. */
  1366. GreSelectBrush(hdc, hbrOld);
  1367. UserAssert(hbrRing);
  1368. GreDeleteObject(hbrRing);
  1369. return2:
  1370. GreSelectPen(hdc, hpenOld);
  1371. if (hpen) {
  1372. GreDeleteObject(hpen);
  1373. }
  1374. return1:
  1375. if (hbrBackground) {
  1376. GreDeleteObject(hbrBackground);
  1377. }
  1378. }
  1379. /***************************************************************************\
  1380. * SonarAction
  1381. *
  1382. \***************************************************************************/
  1383. BOOL StartSonar(
  1384. VOID)
  1385. {
  1386. HDC hdc;
  1387. RECT rc;
  1388. UserAssert(TestUP(MOUSESONAR));
  1389. gptSonarCenter = gpsi->ptCursor;
  1390. /*
  1391. * LATER: Is this the right thing?
  1392. */
  1393. if (gfade.dwFlags) {
  1394. /*
  1395. * Some other animation is going on.
  1396. * Stop it first.
  1397. */
  1398. UserAssert(!TestFadeFlags(FADE_SONAR));
  1399. StopSonar();
  1400. UserAssert(gfade.dwFlags == 0);
  1401. }
  1402. rc.left = gptSonarCenter.x - MOUSE_SONAR_RADIUS_INIT;
  1403. rc.right = gptSonarCenter.x + MOUSE_SONAR_RADIUS_INIT;
  1404. rc.top = gptSonarCenter.y - MOUSE_SONAR_RADIUS_INIT;
  1405. rc.bottom = gptSonarCenter.y + MOUSE_SONAR_RADIUS_INIT;
  1406. giSonarRadius = MOUSE_SONAR_RADIUS_INIT;
  1407. hdc = CreateFade(NULL, &rc, CMS_SONARTIMEOUT, FADE_SONAR | FADE_COLORKEY);
  1408. if (hdc == NULL) {
  1409. RIPMSG0(RIP_WARNING, "StartSonar: failed to create a new sonar.");
  1410. return FALSE;
  1411. }
  1412. /*
  1413. * Start sonar animation.
  1414. */
  1415. DrawSonar(hdc);
  1416. StartFade();
  1417. AnimateFade();
  1418. return TRUE;
  1419. }
  1420. VOID StopSonar(
  1421. VOID)
  1422. {
  1423. UserAssert(TestUP(MOUSESONAR));
  1424. StopFade();
  1425. giSonarRadius = -1;
  1426. }
  1427. #endif // MOUSE_IP
  1428. /***************************************************************************\
  1429. * GetRedirectionFlags
  1430. *
  1431. * GetRedirectionFlags returns the current redirection flags for a given
  1432. * window.
  1433. *
  1434. * 2/8/2000 JStall created
  1435. \***************************************************************************/
  1436. UINT GetRedirectionFlags(
  1437. PWND pwnd)
  1438. {
  1439. PREDIRECT prdr = _GetProp(pwnd, PROP_LAYER, TRUE);
  1440. if (prdr != NULL) {
  1441. return prdr->uFlags;
  1442. }
  1443. return 0;
  1444. }
  1445. /***************************************************************************\
  1446. * xxxPrintWindow
  1447. *
  1448. * xxxPrintWindow uses redirection to get a complete bitmap of a window. If
  1449. * the window already has a redirection bitmap, the bits will be directly
  1450. * copied. If the window doesn't have a redirection bitmap, it will be
  1451. * temporarily redirected, forcibly redrawn, and then returned to its
  1452. * previous state.
  1453. *
  1454. * 2/8/2000 JStall created
  1455. \***************************************************************************/
  1456. BOOL xxxPrintWindow(
  1457. PWND pwnd,
  1458. HDC hdcBlt,
  1459. UINT nFlags)
  1460. {
  1461. HDC hdcSrc;
  1462. SIZE sizeBmpPxl;
  1463. POINT ptOffsetPxl;
  1464. BOOL fTempRedir;
  1465. BOOL fSuccess;
  1466. CheckLock(pwnd);
  1467. /*
  1468. * Determine the area of the window to copy.
  1469. */
  1470. if ((nFlags & PW_CLIENTONLY) != 0) {
  1471. /*
  1472. * Only get the client area
  1473. */
  1474. ptOffsetPxl.x = pwnd->rcWindow.left - pwnd->rcClient.left;
  1475. ptOffsetPxl.y = pwnd->rcWindow.top - pwnd->rcClient.top;
  1476. sizeBmpPxl.cx = pwnd->rcClient.right - pwnd->rcClient.left;
  1477. sizeBmpPxl.cy = pwnd->rcClient.bottom - pwnd->rcClient.top;
  1478. } else {
  1479. /*
  1480. * Return the entire window
  1481. */
  1482. ptOffsetPxl.x = 0;
  1483. ptOffsetPxl.y = 0;
  1484. sizeBmpPxl.cx = pwnd->rcWindow.right - pwnd->rcWindow.left;
  1485. sizeBmpPxl.cy = pwnd->rcWindow.bottom - pwnd->rcWindow.top;
  1486. }
  1487. /*
  1488. * Redirect the window so that we can get the bits. Since this flag never
  1489. * is turned on outside this function call, always safe to turn it on here.
  1490. */
  1491. fTempRedir = (GetRedirectionFlags(pwnd) == 0);
  1492. if (!SetRedirectedWindow(pwnd, REDIRECT_PRINT)) {
  1493. /*
  1494. * Unable to redirect the window, so can't get the bits.
  1495. */
  1496. fSuccess = FALSE;
  1497. goto Done;
  1498. } else {
  1499. fSuccess = TRUE;
  1500. }
  1501. if (fTempRedir) {
  1502. xxxUpdateWindow(pwnd);
  1503. }
  1504. hdcSrc = _GetDCEx(pwnd, NULL, DCX_WINDOW | DCX_CACHE);
  1505. GreBitBlt(hdcBlt, 0, 0, sizeBmpPxl.cx, sizeBmpPxl.cy,
  1506. hdcSrc, ptOffsetPxl.x, ptOffsetPxl.y, SRCCOPY | NOMIRRORBITMAP, 0);
  1507. _ReleaseDC(hdcSrc);
  1508. /*
  1509. * Cleanup
  1510. */
  1511. UnsetRedirectedWindow(pwnd, REDIRECT_PRINT);
  1512. Done:
  1513. return fSuccess;
  1514. }
  1515. /***************************************************************************\
  1516. * xxxEnumTurnOffCompositing
  1517. *
  1518. * xxxEnumTurnOffCompositing() is called for each window, giving an
  1519. * opportunity to turn off WS_EX_COMPOSITED for that window.
  1520. *
  1521. * 8/21/2000 JStall created
  1522. \***************************************************************************/
  1523. BOOL APIENTRY xxxEnumTurnOffCompositing(PWND pwnd, LPARAM lParam)
  1524. {
  1525. CheckLock(pwnd);
  1526. UNREFERENCED_PARAMETER(lParam);
  1527. if (TestWF(pwnd, WEFCOMPOSITED)) {
  1528. DWORD dwStyle = (pwnd->ExStyle & ~WS_EX_COMPOSITED) & WS_EX_ALLVALID;
  1529. xxxSetWindowStyle(pwnd, GWL_EXSTYLE, dwStyle);
  1530. }
  1531. return TRUE;
  1532. }
  1533. /***************************************************************************\
  1534. * xxxTurnOffCompositing
  1535. *
  1536. * xxxTurnOffCompositing() turns off WS_EX_COMPOSITED for (optionally a
  1537. * PWND and) its children. This is used when reparenting under
  1538. * a parent-chain that has WS_EX_COMPOSITED already turned on. If we don't
  1539. * turn off WS_EX_COMPOSITED for the children, it takes extra bitmaps and the
  1540. * compositing will not properly work.
  1541. *
  1542. * 8/21/2000 JStall created
  1543. \***************************************************************************/
  1544. VOID xxxTurnOffCompositing(
  1545. PWND pwndStart,
  1546. BOOL fChild)
  1547. {
  1548. TL tlpwnd;
  1549. UINT nFlags = BWL_ENUMCHILDREN;
  1550. CheckLock(pwndStart);
  1551. /*
  1552. * If they want to skip over the wnd itself and start with this WND's
  1553. * child, we need to get and lock that child. We will unlock it when
  1554. * finished. We also need to mark BWL_ENUMLIST so that we will enumerate
  1555. * all of the children.
  1556. */
  1557. if (fChild) {
  1558. pwndStart = pwndStart->spwndChild;
  1559. if (pwndStart == NULL) {
  1560. return;
  1561. }
  1562. nFlags |= BWL_ENUMLIST;
  1563. ThreadLockAlways(pwndStart, &tlpwnd);
  1564. }
  1565. /*
  1566. * Enumerate the windows.
  1567. */
  1568. xxxInternalEnumWindow(pwndStart, xxxEnumTurnOffCompositing, 0, nFlags);
  1569. if (fChild) {
  1570. ThreadUnlock(&tlpwnd);
  1571. }
  1572. }