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.

2147 lines
65 KiB

  1. /****************************** Module Header ******************************\
  2. * Module Name: winmgrc.c
  3. *
  4. * Copyright (c) 1985 - 1999, Microsoft Corporation
  5. *
  6. * This module contains
  7. *
  8. * History:
  9. * 20-Feb-1992 DarrinM Pulled functions from user\server.
  10. \***************************************************************************/
  11. #include "precomp.h"
  12. #pragma hdrstop
  13. #define CONSOLE_WINDOW_CLASS (L"ConsoleWindowClass")
  14. /***************************************************************************\
  15. * GetWindowWord (API)
  16. *
  17. * Return a window word. Positive index values return application window words
  18. * while negative index values return system window words. The negative
  19. * indices are published in WINDOWS.H.
  20. *
  21. * History:
  22. * 20-Feb-1992 DarrinM Wrote.
  23. \***************************************************************************/
  24. FUNCLOG2(LOG_GENERAL, WORD, DUMMYCALLINGTYPE, GetWindowWord, HWND, hwnd, int, index)
  25. WORD GetWindowWord(
  26. HWND hwnd,
  27. int index)
  28. {
  29. PWND pwnd;
  30. pwnd = ValidateHwnd(hwnd);
  31. if (pwnd == NULL)
  32. return 0;
  33. /*
  34. * If it's a dialog window the window data is on the server side
  35. * We just call the "long" routine instead of have two thunks.
  36. * We know there is enough data if its DWLP_USER so we won't fault.
  37. */
  38. if (TestWF(pwnd, WFDIALOGWINDOW) && (index == DWLP_USER)) {
  39. return (WORD)_GetWindowLong(pwnd, index, FALSE);
  40. }
  41. return _GetWindowWord(pwnd, index);
  42. }
  43. BOOL FChildVisible(
  44. HWND hwnd)
  45. {
  46. PWND pwnd;
  47. pwnd = ValidateHwnd(hwnd);
  48. if (pwnd == NULL)
  49. return 0;
  50. return (_FChildVisible(pwnd));
  51. }
  52. FUNCLOG4(LOG_GENERAL, BOOL, WINAPI, AdjustWindowRectEx, LPRECT, lpRect, DWORD, dwStyle, BOOL, bMenu, DWORD, dwExStyle)
  53. BOOL WINAPI AdjustWindowRectEx(
  54. LPRECT lpRect,
  55. DWORD dwStyle,
  56. BOOL bMenu,
  57. DWORD dwExStyle)
  58. {
  59. ConnectIfNecessary(0);
  60. return _AdjustWindowRectEx(lpRect, dwStyle, bMenu, dwExStyle);
  61. }
  62. FUNCLOG3(LOG_GENERAL, int, WINAPI, GetClassNameW, HWND, hwnd, LPWSTR, lpClassName, int, nMaxCount)
  63. int WINAPI GetClassNameW(
  64. HWND hwnd,
  65. LPWSTR lpClassName,
  66. int nMaxCount)
  67. {
  68. UNICODE_STRING strClassName;
  69. strClassName.MaximumLength = (USHORT)(nMaxCount * sizeof(WCHAR));
  70. strClassName.Buffer = lpClassName;
  71. return NtUserGetClassName(hwnd, FALSE, &strClassName);
  72. }
  73. HWND GetFocus(VOID)
  74. {
  75. return (HWND)NtUserGetThreadState(UserThreadStateFocusWindow);
  76. }
  77. HWND GetCapture(VOID)
  78. {
  79. /*
  80. * If no captures are currently taking place, just return NULL.
  81. */
  82. if (gpsi->cCaptures == 0) {
  83. return NULL;
  84. }
  85. return (HWND)NtUserGetThreadState(UserThreadStateCaptureWindow);
  86. }
  87. /***************************************************************************\
  88. * AnyPopup (API)
  89. *
  90. *
  91. *
  92. * History:
  93. * 12-Nov-1990 DarrinM Ported.
  94. \***************************************************************************/
  95. BOOL AnyPopup(VOID)
  96. {
  97. PWND pwnd = _GetDesktopWindow();
  98. for (pwnd = REBASEPWND(pwnd, spwndChild); pwnd; pwnd = REBASEPWND(pwnd, spwndNext)) {
  99. if ((pwnd->spwndOwner != NULL) && TestWF(pwnd, WFVISIBLE))
  100. return TRUE;
  101. }
  102. return FALSE;
  103. }
  104. /***************************************************************************\
  105. * GetInputState
  106. *
  107. *
  108. *
  109. * History:
  110. \***************************************************************************/
  111. BOOL GetInputState(VOID)
  112. {
  113. CLIENTTHREADINFO *pcti = GETCLIENTTHREADINFO();
  114. if ((pcti == NULL) || (pcti->fsChangeBits & (QS_MOUSEBUTTON | QS_KEY)))
  115. return (BOOL)NtUserGetThreadState(UserThreadStateInputState);
  116. return FALSE;
  117. }
  118. /***************************************************************************\
  119. * MapWindowPoints
  120. *
  121. *
  122. *
  123. * History:
  124. \***************************************************************************/
  125. FUNCLOG4(LOG_GENERAL, int, DUMMYCALLINGTYPE, MapWindowPoints, HWND, hwndFrom, HWND, hwndTo, LPPOINT, lppt, UINT, cpt)
  126. int MapWindowPoints(
  127. HWND hwndFrom,
  128. HWND hwndTo,
  129. LPPOINT lppt,
  130. UINT cpt)
  131. {
  132. PWND pwndFrom;
  133. PWND pwndTo;
  134. if (hwndFrom != NULL) {
  135. if ((pwndFrom = ValidateHwnd(hwndFrom)) == NULL)
  136. return 0;
  137. } else {
  138. pwndFrom = NULL;
  139. }
  140. if (hwndTo != NULL) {
  141. if ((pwndTo = ValidateHwnd(hwndTo)) == NULL)
  142. return 0;
  143. } else {
  144. pwndTo = NULL;
  145. }
  146. return _MapWindowPoints(pwndFrom, pwndTo, lppt, cpt);
  147. }
  148. /***************************************************************************\
  149. * GetLastActivePopup
  150. *
  151. *
  152. *
  153. * History:
  154. \***************************************************************************/
  155. FUNCLOG1(LOG_GENERAL, HWND, DUMMYCALLINGTYPE, GetLastActivePopup, HWND, hwnd)
  156. HWND GetLastActivePopup(
  157. HWND hwnd)
  158. {
  159. PWND pwnd = ValidateHwnd(hwnd);
  160. if (pwnd == NULL)
  161. return NULL;
  162. pwnd = _GetLastActivePopup(pwnd);
  163. return HW(pwnd);
  164. }
  165. /**************************************************************************\
  166. * PtiWindow
  167. *
  168. * Gets the PTHREADINFO of window or NULL if not valid.
  169. *
  170. * 12-Feb-1997 JerrySh Created.
  171. \**************************************************************************/
  172. PTHREADINFO PtiWindow(
  173. HWND hwnd)
  174. {
  175. PHE phe;
  176. DWORD dw;
  177. WORD uniq;
  178. dw = HMIndexFromHandle(hwnd);
  179. if (dw < gpsi->cHandleEntries) {
  180. phe = &gSharedInfo.aheList[dw];
  181. if ((phe->bType == TYPE_WINDOW) && !(phe->bFlags & HANDLEF_DESTROY)) {
  182. uniq = HMUniqFromHandle(hwnd);
  183. if ( uniq == phe->wUniq
  184. #if !defined(_WIN64) && !defined(BUILD_WOW6432)
  185. || uniq == 0
  186. || uniq == HMUNIQBITS
  187. #endif
  188. ) {
  189. return phe->pOwner;
  190. }
  191. }
  192. }
  193. UserSetLastError(ERROR_INVALID_WINDOW_HANDLE);
  194. return NULL;
  195. }
  196. /***************************************************************************\
  197. * GetWindowThreadProcessId
  198. *
  199. * Get's windows process and thread ids.
  200. *
  201. * 24-Jun-1991 ScottLu Created.
  202. \***************************************************************************/
  203. FUNCLOG2(LOG_GENERAL, DWORD, DUMMYCALLINGTYPE, GetWindowThreadProcessId, HWND, hwnd, LPDWORD, lpdwProcessId)
  204. DWORD GetWindowThreadProcessId(
  205. HWND hwnd,
  206. LPDWORD lpdwProcessId)
  207. {
  208. PTHREADINFO ptiWindow;
  209. DWORD dwThreadId;
  210. if ((ptiWindow = PtiWindow(hwnd)) == NULL)
  211. return 0;
  212. /*
  213. * For non-system threads get the info from the thread info structure
  214. */
  215. if (ptiWindow == PtiCurrent()) {
  216. if (lpdwProcessId != NULL)
  217. *lpdwProcessId = HandleToUlong(NtCurrentTeb()->ClientId.UniqueProcess);
  218. dwThreadId = HandleToUlong(NtCurrentTeb()->ClientId.UniqueThread);
  219. } else {
  220. /*
  221. * Make this better later on.
  222. */
  223. if (lpdwProcessId != NULL)
  224. *lpdwProcessId = HandleToUlong(NtUserQueryWindow(hwnd, WindowProcess));
  225. dwThreadId = HandleToUlong(NtUserQueryWindow(hwnd, WindowThread));
  226. }
  227. return dwThreadId;
  228. }
  229. /***************************************************************************\
  230. * GetScrollPos
  231. *
  232. * Returns the current position of a scroll bar
  233. *
  234. * !!! WARNING a similiar copy of this code is in server\sbapi.c
  235. *
  236. * History:
  237. \***************************************************************************/
  238. FUNCLOG2(LOG_GENERAL, int, DUMMYCALLINGTYPE, GetScrollPos, HWND, hwnd, int, code)
  239. int GetScrollPos(
  240. HWND hwnd,
  241. int code)
  242. {
  243. PWND pwnd;
  244. if ((pwnd = ValidateHwnd(hwnd)) == NULL)
  245. return 0;
  246. switch (code) {
  247. case SB_CTL:
  248. return (int)SendMessageWorker(pwnd, SBM_GETPOS, 0, 0, FALSE);
  249. case SB_HORZ:
  250. case SB_VERT:
  251. if (pwnd->pSBInfo != NULL) {
  252. PSBINFO pSBInfo = (PSBINFO)(REBASEALWAYS(pwnd, pSBInfo));
  253. return (code == SB_VERT) ? pSBInfo->Vert.pos : pSBInfo->Horz.pos;
  254. } else {
  255. RIPERR0(ERROR_NO_SCROLLBARS, RIP_VERBOSE, "");
  256. }
  257. break;
  258. default:
  259. /*
  260. * Win3.1 validation layer code.
  261. */
  262. RIPERR0(ERROR_INVALID_PARAMETER, RIP_VERBOSE, "");
  263. }
  264. return 0;
  265. }
  266. /***************************************************************************\
  267. * GetScrollRange
  268. *
  269. * !!! WARNING a similiar copy of this code is in server\sbapi.c
  270. *
  271. * History:
  272. * 16-May-1991 mikeke Changed to return BOOL
  273. \***************************************************************************/
  274. FUNCLOG4(LOG_GENERAL, BOOL, DUMMYCALLINGTYPE, GetScrollRange, HWND, hwnd, int, code, LPINT, lpposMin, LPINT, lpposMax)
  275. BOOL GetScrollRange(
  276. HWND hwnd,
  277. int code,
  278. LPINT lpposMin,
  279. LPINT lpposMax)
  280. {
  281. PSBINFO pSBInfo;
  282. PWND pwnd;
  283. if ((pwnd = ValidateHwnd(hwnd)) == NULL)
  284. return FALSE;
  285. switch (code) {
  286. case SB_CTL:
  287. SendMessageWorker(pwnd, SBM_GETRANGE, (WPARAM)lpposMin, (LPARAM)lpposMax, FALSE);
  288. return TRUE;
  289. case SB_VERT:
  290. case SB_HORZ:
  291. if (pSBInfo = REBASE(pwnd, pSBInfo)) {
  292. PSBDATA pSBData;
  293. pSBData = KPSBDATA_TO_PSBDATA((code == SB_VERT) ? &pSBInfo->Vert : &pSBInfo->Horz);
  294. *lpposMin = pSBData->posMin;
  295. *lpposMax = pSBData->posMax;
  296. } else {
  297. RIPERR0(ERROR_NO_SCROLLBARS, RIP_VERBOSE, "");
  298. *lpposMin = 0;
  299. *lpposMax = 0;
  300. }
  301. return TRUE;
  302. default:
  303. /*
  304. * Win3.1 validation layer code.
  305. */
  306. RIPERR0(ERROR_INVALID_PARAMETER, RIP_VERBOSE, "");
  307. return FALSE;
  308. }
  309. }
  310. FUNCLOG4(LOG_GENERAL, int, DUMMYCALLINGTYPE, SetScrollInfo, HWND, hwnd, int, fnBar, LPCSCROLLINFO, lpsi, BOOL, fRedraw)
  311. int SetScrollInfo(
  312. HWND hwnd,
  313. int fnBar,
  314. LPCSCROLLINFO lpsi,
  315. BOOL fRedraw)
  316. {
  317. int ret;
  318. BEGIN_USERAPIHOOK()
  319. ret = guah.pfnSetScrollInfo(hwnd, fnBar, lpsi, fRedraw);
  320. END_USERAPIHOOK()
  321. return ret;
  322. }
  323. int RealSetScrollInfo(
  324. HWND hwnd,
  325. int fnBar,
  326. LPCSCROLLINFO lpsi,
  327. BOOL fRedraw)
  328. {
  329. return NtUserSetScrollInfo(hwnd, fnBar, lpsi, fRedraw);
  330. }
  331. FUNCLOG3(LOG_GENERAL, BOOL, DUMMYCALLINGTYPE, GetScrollInfo, HWND, hwnd, int, code, LPSCROLLINFO, lpsi)
  332. BOOL GetScrollInfo(
  333. HWND hwnd,
  334. int code,
  335. LPSCROLLINFO lpsi)
  336. {
  337. int ret;
  338. BEGIN_USERAPIHOOK()
  339. ret = guah.pfnGetScrollInfo(hwnd, code, lpsi);
  340. END_USERAPIHOOK()
  341. return ret;
  342. }
  343. /***************************************************************************\
  344. * RealGetScrollInfo
  345. *
  346. * !!! WARNING a similiar copy of this code is in server\winmgrc.c
  347. *
  348. \***************************************************************************/
  349. BOOL RealGetScrollInfo(
  350. HWND hwnd,
  351. int code,
  352. LPSCROLLINFO lpsi)
  353. {
  354. PWND pwnd;
  355. PSBINFO pSBInfo;
  356. PSBDATA pSBData;
  357. if (lpsi->cbSize != sizeof(SCROLLINFO)) {
  358. if (lpsi->cbSize != sizeof(SCROLLINFO) - 4) {
  359. RIPMSG0(RIP_WARNING, "SCROLLINFO: Invalid cbSize");
  360. return FALSE;
  361. } else {
  362. RIPMSG0(RIP_WARNING, "SCROLLINFO: Invalid cbSize");
  363. }
  364. }
  365. if (lpsi->fMask & ~SIF_MASK) {
  366. RIPMSG0(RIP_WARNING, "SCROLLINFO: Invalid fMask");
  367. return FALSE;
  368. }
  369. if ((pwnd = ValidateHwnd(hwnd)) == NULL)
  370. return FALSE;
  371. switch (code) {
  372. case SB_CTL:
  373. SendMessageWorker(pwnd, SBM_GETSCROLLINFO, 0, (LPARAM)lpsi, FALSE);
  374. return TRUE;
  375. case SB_HORZ:
  376. case SB_VERT:
  377. if (pwnd->pSBInfo == NULL) {
  378. RIPERR0(ERROR_NO_SCROLLBARS, RIP_VERBOSE, "");
  379. return FALSE;
  380. }
  381. /*
  382. * Rebase rgwScroll so probing will work
  383. */
  384. pSBInfo = (PSBINFO)REBASEALWAYS(pwnd, pSBInfo);
  385. pSBData = KPSBDATA_TO_PSBDATA((code == SB_VERT) ? &pSBInfo->Vert : &pSBInfo->Horz);
  386. return(NtUserSBGetParms(hwnd, code, pSBData, lpsi));
  387. default:
  388. /*
  389. * Win3.1 validation layer code.
  390. */
  391. RIPERR0(ERROR_INVALID_PARAMETER, RIP_VERBOSE, "");
  392. return FALSE;
  393. }
  394. }
  395. /****************************************************************************\
  396. * _GetActiveWindow (API)
  397. *
  398. *
  399. * 23-Oct-1990 MikeHar Ported from Windows.
  400. * 12-Nov-1990 DarrinM Moved from getset.c to here.
  401. \****************************************************************************/
  402. HWND GetActiveWindow(VOID)
  403. {
  404. return (HWND)NtUserGetThreadState(UserThreadStateActiveWindow);
  405. }
  406. /****************************************************************************\
  407. * GetCursor
  408. *
  409. *
  410. * History:
  411. \****************************************************************************/
  412. HCURSOR GetCursor(VOID)
  413. {
  414. return (HCURSOR)NtUserGetThreadState(UserThreadStateCursor);
  415. }
  416. /***************************************************************************\
  417. * BOOL IsMenu(HMENU);
  418. *
  419. * Verifies that the handle passed in is a menu handle.
  420. *
  421. * Histroy:
  422. * 10-Jul-1992 MikeHar Created.
  423. \***************************************************************************/
  424. FUNCLOG1(LOG_GENERAL, BOOL, DUMMYCALLINGTYPE, IsMenu, HMENU, hMenu)
  425. BOOL IsMenu(
  426. HMENU hMenu)
  427. {
  428. if (HMValidateHandle(hMenu, TYPE_MENU))
  429. return TRUE;
  430. return FALSE;
  431. }
  432. /***************************************************************************\
  433. * GetAppCompatFlags
  434. *
  435. * Compatibility flags for < Win 3.1 apps running on 3.1
  436. *
  437. * History:
  438. * 01-Apr-1992 ScottLu Created.
  439. * 04-May-1992 DarrinM Moved to USERRTL.DLL.
  440. \***************************************************************************/
  441. FUNCLOG1(LOG_GENERAL, DWORD, DUMMYCALLINGTYPE, GetAppCompatFlags, PTHREADINFO, pti)
  442. DWORD GetAppCompatFlags(
  443. PTHREADINFO pti)
  444. {
  445. UNREFERENCED_PARAMETER(pti);
  446. ConnectIfNecessary(0);
  447. return GetClientInfo()->dwCompatFlags;
  448. }
  449. /***************************************************************************\
  450. * GetAppCompatFlags2
  451. *
  452. * Compatibility flags for <= wVer apps. Newer apps will get no hacks
  453. * from this DWORD.
  454. *
  455. * History:
  456. * 06-29-98 MCostea Created.
  457. \***************************************************************************/
  458. FUNCLOG1(LOG_GENERAL, DWORD, DUMMYCALLINGTYPE, GetAppCompatFlags2, WORD, wVer)
  459. DWORD GetAppCompatFlags2(
  460. WORD wVer)
  461. {
  462. ConnectIfNecessary(0);
  463. /*
  464. * Newer apps should behave, so they get no hacks
  465. */
  466. if (wVer < GETAPPVER()) {
  467. return 0;
  468. }
  469. return GetClientInfo()->dwCompatFlags2;
  470. }
  471. /**************************************************************************\
  472. * IsWindowUnicode
  473. *
  474. * 25-Feb-1992 IanJa Created
  475. \**************************************************************************/
  476. BOOL IsWindowUnicode(
  477. IN HWND hwnd)
  478. {
  479. PWND pwnd;
  480. if ((pwnd = ValidateHwnd(hwnd)) == NULL)
  481. return FALSE;
  482. return !TestWF(pwnd, WFANSIPROC);
  483. }
  484. /**************************************************************************\
  485. * TestWindowProcess
  486. *
  487. * 14-Nov-1994 JimA Created.
  488. \**************************************************************************/
  489. BOOL TestWindowProcess(
  490. PWND pwnd)
  491. {
  492. /*
  493. * If the threads are the same, don't bother going to the kernel
  494. * to get the window's process id.
  495. */
  496. if (GETPTI(pwnd) == PtiCurrent()) {
  497. return TRUE;
  498. }
  499. return (GetWindowProcess(HW(pwnd)) == GETPROCESSID());
  500. }
  501. /**************************************************************************\
  502. * IsHungAppWindow
  503. *
  504. * 11-14-94 JimA Created.
  505. \**************************************************************************/
  506. FUNCLOG1(LOG_GENERAL, BOOL, DUMMYCALLINGTYPE, IsHungAppWindow, HWND, hwnd)
  507. BOOL IsHungAppWindow(
  508. HWND hwnd)
  509. {
  510. return (NtUserQueryWindow(hwnd, WindowIsHung) != NULL);
  511. }
  512. /***************************************************************************\
  513. * CreateSystemThreads
  514. *
  515. * Simply calls xxxCreateSystemThreads, which will call the appropriate
  516. * thread routine (depending on uThreadID).
  517. *
  518. * History:
  519. * 20-Aug-00 MSadek Created.
  520. \***************************************************************************/
  521. WINUSERAPI
  522. DWORD
  523. WINAPI
  524. CreateSystemThreads (
  525. LPVOID pUnused)
  526. {
  527. UNREFERENCED_PARAMETER(pUnused);
  528. NtUserCallOneParam(TRUE, SFI_XXXCREATESYSTEMTHREADS);
  529. ExitThread(0);
  530. }
  531. /***************************************************************************\
  532. * PtiCurrent
  533. *
  534. * Returns the THREADINFO structure for the current thread.
  535. * LATER: Get DLL_THREAD_ATTACH initialization working right and we won't
  536. * need this connect code.
  537. *
  538. * History:
  539. * 10-28-90 DavidPe Created.
  540. \***************************************************************************/
  541. PTHREADINFO PtiCurrent(VOID)
  542. {
  543. ConnectIfNecessary(0);
  544. return (PTHREADINFO)NtCurrentTebShared()->Win32ThreadInfo;
  545. }
  546. /***************************************************************************\
  547. * _AdjustWindowRectEx (API)
  548. *
  549. *
  550. *
  551. * History:
  552. * 10-24-90 darrinm Ported from Win 3.0.
  553. \***************************************************************************/
  554. BOOL _AdjustWindowRectEx(
  555. LPRECT lprc,
  556. DWORD style,
  557. BOOL fMenu,
  558. DWORD dwExStyle)
  559. {
  560. BOOL ret;
  561. BEGIN_USERAPIHOOK()
  562. ret = guah.pfnAdjustWindowRectEx(lprc, style, fMenu, dwExStyle);
  563. END_USERAPIHOOK()
  564. return ret;
  565. }
  566. BOOL RealAdjustWindowRectEx(
  567. LPRECT lprc,
  568. DWORD style,
  569. BOOL fMenu,
  570. DWORD dwExStyle)
  571. {
  572. //
  573. // Here we add on the appropriate 3D borders for old and new apps.
  574. //
  575. // Rules:
  576. // (1) Do nothing for windows that have 3D border styles.
  577. // (2) If the window has a dlgframe border (has a caption or is a
  578. // a dialog), then add on the window edge style.
  579. // (3) We NEVER add on the CLIENT STYLE. New apps can create
  580. // it if they want. This is because it screws up alignment
  581. // when the app doesn't know about it.
  582. //
  583. if (NeedsWindowEdge(style, dwExStyle, GETAPPVER() >= VER40))
  584. dwExStyle |= WS_EX_WINDOWEDGE;
  585. else
  586. dwExStyle &= ~WS_EX_WINDOWEDGE;
  587. //
  588. // Space for a menu bar
  589. //
  590. if (fMenu)
  591. lprc->top -= SYSMET(CYMENU);
  592. //
  593. // Space for a caption bar
  594. //
  595. if ((HIWORD(style) & HIWORD(WS_CAPTION)) == HIWORD(WS_CAPTION)) {
  596. lprc->top -= (dwExStyle & WS_EX_TOOLWINDOW) ? SYSMET(CYSMCAPTION) : SYSMET(CYCAPTION);
  597. }
  598. //
  599. // Space for borders (window AND client)
  600. //
  601. {
  602. int cBorders;
  603. //
  604. // Window AND Client borders
  605. //
  606. if (cBorders = GetWindowBorders(style, dwExStyle, TRUE, TRUE))
  607. InflateRect(lprc, cBorders*SYSMET(CXBORDER), cBorders*SYSMET(CYBORDER));
  608. }
  609. return TRUE;
  610. }
  611. /***************************************************************************\
  612. * ShowWindowNoRepaint
  613. \***************************************************************************/
  614. void ShowWindowNoRepaint(PWND pwnd)
  615. {
  616. HWND hwnd = HWq(pwnd);
  617. PCLS pcls = REBASE(pwnd, pcls);
  618. NtUserSetWindowPos(hwnd, NULL, 0, 0, 0, 0, SWP_NOMOVE |
  619. SWP_NOSIZE | SWP_NOZORDER | SWP_NOOWNERZORDER |
  620. SWP_NOREDRAW | SWP_SHOWWINDOW | SWP_NOACTIVATE |
  621. ((pcls->style & CS_SAVEBITS) ? SWP_CREATESPB : 0));
  622. }
  623. /***************************************************************************\
  624. * AnimateBlend
  625. *
  626. * 6-Mar-1997 vadimg created
  627. \***************************************************************************/
  628. #define ALPHASTART 40
  629. #define ONEFRAME 10
  630. BOOL AnimateBlend(PWND pwnd, HDC hdcScreen, HDC hdcImage, DWORD dwTime, BOOL fHide, BOOL fActivateWindow)
  631. {
  632. HWND hwnd = HWq(pwnd);
  633. SIZE size;
  634. POINT ptSrc = {0, 0}, ptDst;
  635. BLENDFUNCTION blend;
  636. DWORD dwElapsed;
  637. BYTE bAlpha = ALPHASTART;
  638. LARGE_INTEGER liFreq, liStart, liDiff;
  639. LARGE_INTEGER liIter;
  640. DWORD dwIter;
  641. BOOL fFirstFrame = TRUE;
  642. if (QueryPerformanceFrequency(&liFreq) == 0)
  643. return FALSE;
  644. SetLastError(0);
  645. SetWindowLong(hwnd, GWL_EXSTYLE, GetWindowLong(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED);
  646. if (GetLastError() != 0) {
  647. return FALSE;
  648. }
  649. if (fHide) {
  650. /*
  651. * Give up the time slice and sleep just a touch to allow windows
  652. * below invalidated by the SetWindowLong(WS_EX_LAYERED) call to
  653. * repaint enough for the sprite to get good background image.
  654. */
  655. Sleep(10);
  656. }
  657. ptDst.x = pwnd->rcWindow.left;
  658. ptDst.y = pwnd->rcWindow.top;
  659. size.cx = pwnd->rcWindow.right - pwnd->rcWindow.left;
  660. size.cy = pwnd->rcWindow.bottom - pwnd->rcWindow.top;
  661. blend.BlendOp = AC_SRC_OVER;
  662. blend.BlendFlags = 0;
  663. blend.AlphaFormat = 0;
  664. blend.SourceConstantAlpha = fHide ? (255 - bAlpha) : bAlpha;
  665. /*
  666. * Copy the initial image with the initial alpha.
  667. */
  668. NtUserUpdateLayeredWindow(hwnd, NULL, &ptDst, &size, hdcImage, &ptSrc, 0,
  669. &blend, ULW_ALPHA);
  670. if (!fHide) {
  671. ShowWindowNoRepaint(pwnd);
  672. }
  673. /*
  674. * Time and start the animation cycle.
  675. */
  676. dwElapsed = (dwTime * ALPHASTART + 255) / 255 + 10;
  677. QueryPerformanceCounter(&liStart);
  678. liStart.QuadPart = liStart.QuadPart - dwElapsed * liFreq.QuadPart / 1000;
  679. while (dwElapsed < dwTime) {
  680. if (fHide) {
  681. blend.SourceConstantAlpha = (BYTE)((255 * (dwTime - dwElapsed)) / dwTime);
  682. } else {
  683. blend.SourceConstantAlpha = (BYTE)((255 * dwElapsed) / dwTime);
  684. }
  685. QueryPerformanceCounter(&liIter);
  686. if (fFirstFrame && fActivateWindow) {
  687. NtUserSetWindowPos(hwnd, NULL, 0, 0, 0, 0,
  688. SWP_NOMOVE | SWP_NOSIZE | SWP_NOOWNERZORDER);
  689. }
  690. fFirstFrame = FALSE;
  691. NtUserUpdateLayeredWindow(hwnd, NULL, NULL, NULL, NULL, NULL, 0,
  692. &blend, ULW_ALPHA);
  693. QueryPerformanceCounter(&liDiff);
  694. /*
  695. * Calculate how long in ms the previous frame took.
  696. */
  697. liIter.QuadPart = liDiff.QuadPart - liIter.QuadPart;
  698. dwIter = (DWORD)((liIter.QuadPart * 1000) / liFreq.QuadPart);
  699. if (dwIter < ONEFRAME) {
  700. Sleep(ONEFRAME - dwIter);
  701. }
  702. liDiff.QuadPart -= liStart.QuadPart;
  703. dwElapsed = (DWORD)((liDiff.QuadPart * 1000) / liFreq.QuadPart);
  704. }
  705. /*
  706. * Hide the window before removing the layered bit to make sure that
  707. * the bits for the window are not left on the screen.
  708. */
  709. if (fHide) {
  710. NtUserSetWindowPos(hwnd, NULL, 0, 0, 0, 0, SWP_HIDEWINDOW |
  711. SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
  712. }
  713. SetWindowLong(hwnd, GWL_EXSTYLE, GetWindowLong(hwnd, GWL_EXSTYLE) &
  714. ~WS_EX_LAYERED);
  715. if (!fHide) {
  716. BitBlt(hdcScreen, 0, 0, size.cx, size.cy, hdcImage, 0, 0, SRCCOPY | NOMIRRORBITMAP);
  717. }
  718. return TRUE;
  719. }
  720. /***************************************************************************\
  721. * TakeWindowSnapshot
  722. *
  723. * Helper routine to grab the visual appearance of a window to a bitmap.
  724. *
  725. \***************************************************************************/
  726. HBITMAP TakeWindowSnapshot(HWND hwnd, HDC hdcWindow, HDC hdcSnapshot)
  727. {
  728. PWND pwnd;
  729. int cx;
  730. int cy;
  731. HBITMAP hbmOld, hbmSnapshot;
  732. BOOL fOK = FALSE;
  733. pwnd = ValidateHwnd(hwnd);
  734. if (pwnd == NULL)
  735. return NULL;
  736. cx = pwnd->rcWindow.right - pwnd->rcWindow.left;
  737. cy = pwnd->rcWindow.bottom - pwnd->rcWindow.top;
  738. hbmSnapshot = CreateCompatibleBitmap(hdcWindow, cx, cy);
  739. if (hbmSnapshot == NULL) {
  740. return NULL;
  741. }
  742. hbmOld = SelectObject(hdcSnapshot, hbmSnapshot);
  743. /*
  744. * Try redirection first.
  745. */
  746. /*
  747. if (NtUserPrintWindow(hwnd, hdcSnapshot, 0)) {
  748. fOK = TRUE;
  749. } else */ {
  750. /*
  751. * We failed to redirect the window! This can be caused by windows
  752. * with class or parent DCs. Maybe other reasons as well. Revert to
  753. * the old way of sending a WM_PRINT to the window.
  754. */
  755. UINT uBounds;
  756. RECT rcBounds;
  757. DWORD dwOldLayout = GDI_ERROR;
  758. BOOL fError = TRUE;
  759. /*
  760. * The WM_PRINT message expects a "normal" layout setting on the DC.
  761. * The message will handle RTL stuff itself.
  762. */
  763. dwOldLayout = SetLayout(hdcSnapshot, 0);
  764. /*
  765. * Clear the dirty bounds so we can tell if anything was painted.
  766. */
  767. SetBoundsRect(hdcSnapshot, NULL, DCB_RESET | DCB_ENABLE);
  768. /*
  769. * Get the actual image. The windows participating here must implement
  770. * WM_PRINTCLIENT or they will look ugly.
  771. */
  772. SendMessage(hwnd, WM_PRINT, (WPARAM)hdcSnapshot, PRF_CLIENT | PRF_NONCLIENT | PRF_CHILDREN | PRF_ERASEBKGND);
  773. /*
  774. * Check to see if the app painted in our DC. We do this by checking to
  775. * see if the bounding rect of operations performed on the DC is set.
  776. */
  777. uBounds = GetBoundsRect(hdcSnapshot, &rcBounds, 0);
  778. if ((uBounds & DCB_RESET) && (!(uBounds & DCB_ACCUMULATE))) {
  779. goto Cleanup;
  780. }
  781. fOK = TRUE;
  782. Cleanup:
  783. SetLayout(hdcSnapshot, dwOldLayout);
  784. }
  785. SelectObject(hdcSnapshot, hbmOld);
  786. if (!fOK) {
  787. DeleteObject(hbmSnapshot);
  788. hbmSnapshot = NULL;
  789. }
  790. return hbmSnapshot;
  791. }
  792. /***************************************************************************\
  793. * AnimateWindow (API)
  794. *
  795. * Hide animations are done by updating a la full-drag. Uses window's window
  796. * region to do some of the magic.
  797. *
  798. * We have to put in the CLIPCHILDREN hack to work around a bug with the
  799. * DC cache resetting attributes even if DCX_USESTYLE is not used whe
  800. * the DC cache is invalidated.
  801. *
  802. * History:
  803. * 9-Sep-1996 vadimg created
  804. \***************************************************************************/
  805. #define AW_HOR (AW_HOR_POSITIVE | AW_HOR_NEGATIVE | AW_CENTER)
  806. #define AW_VER (AW_VER_POSITIVE | AW_VER_NEGATIVE | AW_CENTER)
  807. __inline int AnimInc(int x, int y, int z)
  808. {
  809. return MultDiv(x, y, z);
  810. }
  811. __inline int AnimDec(int x, int y, int z)
  812. {
  813. return x - AnimInc(x, y, z);
  814. }
  815. FUNCLOG3(LOG_GENERAL, BOOL, WINAPI, AnimateWindow, HWND, hwnd, DWORD, dwTime, DWORD, dwFlags)
  816. BOOL WINAPI AnimateWindow(HWND hwnd, DWORD dwTime, DWORD dwFlags)
  817. {
  818. PTHREADINFO ptiCurrent = PtiCurrent();
  819. HDC hdc = NULL, hdcMem = NULL;
  820. PCLS pcls = NULL;
  821. HRGN hrgnOriginal = NULL, hrgnUpdate = NULL, hrgnOldAnim = NULL, hrgnAnim = NULL;
  822. HBITMAP hbmMem = NULL, hbmOld;
  823. BOOL fHide = dwFlags & AW_HIDE, fRet = FALSE, fSlide = dwFlags & AW_SLIDE;
  824. BOOL fRestoreClipChildren = FALSE;
  825. BOOL fRestoreOriginalRegion = FALSE;
  826. BOOL fShowWindow = FALSE;
  827. BOOL fHideWindow = FALSE;
  828. BOOL fActivateWindow = FALSE;
  829. BOOL fFirstFrame = TRUE;
  830. BOOL fRedrawParentWindow = FALSE;
  831. HWND hwndParent;
  832. int x, y, nx, ny, cx, cy, ix, iy, ixLast, iyLast, xWin, yWin;
  833. int xReal, yReal, xMem, yMem, xRgn, yRgn;
  834. DWORD dwStart, dwElapsed;
  835. RECT rcAnim, rcWin;
  836. PWND pwnd;
  837. BOOL fRTL = FALSE;
  838. #if DBG
  839. int cAnimationFrames = 0;
  840. DWORD dwElapsed2 = 0;
  841. #endif
  842. /*
  843. * Check to see if we have nothing to do or the flags didn't validate.
  844. */
  845. if ((dwFlags & ~AW_VALID) != 0 ||
  846. (dwFlags & (AW_HOR_POSITIVE | AW_HOR_NEGATIVE | AW_CENTER | AW_VER_POSITIVE | AW_VER_NEGATIVE | AW_BLEND)) == 0)
  847. return FALSE;
  848. /*
  849. * Convert the HWND to a PWND. Fail if this is an invalid window.
  850. */
  851. pwnd = ValidateHwnd(hwnd);
  852. if (pwnd == NULL)
  853. return FALSE;
  854. /*
  855. * The animation effect is applied to a window that is changing from being
  856. * hidden to being visible, or from being visible to being hidden. If the
  857. * window is already in the final state, there is nothing to do.
  858. */
  859. if (!IsWindowVisible(hwnd)) {
  860. if (fHide) {
  861. return FALSE;
  862. }
  863. } else {
  864. if (!fHide) {
  865. return FALSE;
  866. }
  867. }
  868. /*
  869. * Grab a DC for this window.
  870. */
  871. if ((hdc = GetDCEx(hwnd, NULL, DCX_WINDOW | DCX_USESTYLE | DCX_CACHE)) == NULL) {
  872. return FALSE;
  873. }
  874. fRTL = (GetLayout(hdc) & LAYOUT_RTL) ? TRUE : FALSE;
  875. /*
  876. * ----------------------------------------------------------------------
  877. * After this point, we will not return directly. Instead, we will fall
  878. * out through the cleanup section at the bottom! Up until this point
  879. * we may have bailed out for any number of easily-detected problems.
  880. * From now on, we have resources we'll need to clean up.
  881. * ----------------------------------------------------------------------
  882. */
  883. /*
  884. * Remember to hide/show/activate the window as requested.
  885. */
  886. if (dwFlags & AW_HIDE) {
  887. TAGMSG0(DBGTAG_AnimateWindow, "AnimateWindow: Need to hide window");
  888. fHideWindow = TRUE;
  889. } else {
  890. TAGMSG0(DBGTAG_AnimateWindow, "AnimateWindow: Need to show window");
  891. fShowWindow = TRUE;
  892. }
  893. if (dwFlags & AW_ACTIVATE) {
  894. TAGMSG0(DBGTAG_AnimateWindow, "AnimateWindow: Need to activate window");
  895. fActivateWindow = TRUE;
  896. }
  897. /*
  898. * If this is a child window we are animating, then we may need to
  899. * repaint the parent every time we move the child so that the
  900. * background can be refreshed.
  901. */
  902. if (TestWF(pwnd, WFCHILD) && (pwnd->spwndParent != NULL)) {
  903. TAGMSG0(DBGTAG_AnimateWindow, "AnimateWindow: Animating a child window" );
  904. if (dwFlags & AW_BLEND) {
  905. TAGMSG0(DBGTAG_AnimateWindow, "AnimateWindow: Can not fade a child window!" );
  906. goto Cleanup;
  907. }
  908. fRedrawParentWindow = TRUE;
  909. hwndParent = HW(_GetParent(pwnd));
  910. }
  911. /*
  912. * In the process of animating the window, we are going to draw directly
  913. * on top of the window region ourselves. As such, we don't want any
  914. * "holes" in the window region due to it clipping out the children. But
  915. * we will need to restore this setting when we are all done, so we set
  916. * a flag here and check it at the end.
  917. */
  918. if (TestWF(pwnd, WFCLIPCHILDREN)) {
  919. fRestoreClipChildren = TRUE;
  920. ClearWindowState(pwnd, WFCLIPCHILDREN);
  921. }
  922. /*
  923. * Remember the original window region. We will restore this when we are
  924. * all done.
  925. */
  926. if (pwnd->hrgnClip != NULL) {
  927. hrgnOriginal = CreateRectRgn(0, 0, 0, 0);
  928. if (hrgnOriginal == NULL) {
  929. goto Cleanup;
  930. }
  931. if (GetWindowRgn(hwnd, hrgnOriginal) == ERROR) {
  932. goto Cleanup;
  933. }
  934. }
  935. fRestoreOriginalRegion = TRUE;
  936. /*
  937. * Precreate the regions we use.
  938. */
  939. if (((hrgnUpdate = CreateRectRgn(0, 0, 0, 0)) == NULL) ||
  940. ((hrgnOldAnim = CreateRectRgn(0, 0, 0, 0)) == NULL)) {
  941. goto Cleanup;
  942. }
  943. rcWin = pwnd->rcWindow;
  944. xWin = rcWin.left;
  945. yWin = rcWin.top;
  946. cx = rcWin.right - rcWin.left;
  947. cy = rcWin.bottom - rcWin.top;
  948. /*
  949. * Initialize the "old" animation region to be:
  950. * 1) Empty, if the window is being show.
  951. * 2) Full, if the window is being hiddem.
  952. */
  953. if (fHide) {
  954. if (hrgnOriginal != NULL) {
  955. if (CombineRgn(hrgnOldAnim, hrgnOriginal, NULL, RGN_COPY) == ERROR) {
  956. goto Cleanup;
  957. }
  958. } else {
  959. if (SetRectRgn(hrgnOldAnim, 0, 0, cx, cy) == 0) {
  960. goto Cleanup;
  961. }
  962. }
  963. } else {
  964. if (SetRectRgn(hrgnOldAnim, 0, 0, 0, 0) == 0) {
  965. goto Cleanup;
  966. }
  967. }
  968. /*
  969. * The window needs to be visible since we are going to be drawing parts
  970. * of it. If the window is being hidden, then it is currently visible.
  971. * If the window is being shown, then we go ahead and make it visible
  972. * now but we don't repaint it.
  973. */
  974. if (!(dwFlags & AW_BLEND)) {
  975. HRGN hrgnWin = NULL;
  976. /*
  977. * Set window region to nothing, so that if the window draws during
  978. * callbacks in WM_PRINT, it doesn't happen on screen.
  979. */
  980. if ((hrgnWin = CreateRectRgn(0, 0, 0, 0)) == NULL) {
  981. goto Cleanup;
  982. }
  983. RealSetWindowRgn(hwnd, hrgnWin, FALSE);
  984. if (!fHide) {
  985. ShowWindowNoRepaint(pwnd);
  986. fShowWindow = FALSE;
  987. }
  988. }
  989. /*
  990. * Set up an offscreen DC, and back it to a bitmap. We will use this to
  991. * capture the visual representation of the window being animated.
  992. */
  993. if ((hdcMem = CreateCompatibleDC(hdc)) == NULL) {
  994. goto Cleanup;
  995. }
  996. hbmMem = TakeWindowSnapshot(hwnd, hdc, hdcMem);
  997. if (hbmMem != NULL) {
  998. /*
  999. * If the window changed its size while we were taking a snapshot,
  1000. * we need to do it again. For instance, like RAID does with
  1001. * combo boxes by resizing them on WM_CTLCOLOR from WM_ERASEBKGND.
  1002. */
  1003. if (!EqualRect(&rcWin, KPRECT_TO_PRECT(&pwnd->rcWindow))) {
  1004. /*
  1005. * Update all of our variables taking into account the new size.
  1006. */
  1007. TAGMSG0(DBGTAG_AnimateWindow, "AnimateWindow: Size change on paint!");
  1008. TAGMSG4(DBGTAG_AnimateWindow, "AnimateWindow: Old = (%d,%d)-(%d,%d)", rcWin.left, rcWin.top, rcWin.right, rcWin.bottom);
  1009. rcWin = pwnd->rcWindow;
  1010. TAGMSG4(DBGTAG_AnimateWindow, "AnimateWindow: New = (%d,%d)-(%d,%d)", rcWin.left, rcWin.top, rcWin.right, rcWin.bottom);
  1011. xWin = rcWin.left;
  1012. yWin = rcWin.top;
  1013. cx = rcWin.right - rcWin.left;
  1014. cy = rcWin.bottom - rcWin.top;
  1015. if (hrgnOriginal != NULL) {
  1016. if (GetWindowRgn(hwnd, hrgnOriginal) == ERROR) {
  1017. goto Cleanup;
  1018. }
  1019. }
  1020. /*
  1021. * Initialize the "old" animation region to be:
  1022. * 1) Empty, if the window is being show.
  1023. * 2) Full, if the window is being hiddem.
  1024. */
  1025. if (fHide) {
  1026. if (hrgnOriginal != NULL) {
  1027. if (CombineRgn(hrgnOldAnim, hrgnOriginal, NULL, RGN_COPY) == ERROR) {
  1028. goto Cleanup;
  1029. }
  1030. } else {
  1031. if (SetRectRgn(hrgnOldAnim, 0, 0, cx, cy) == 0) {
  1032. goto Cleanup;
  1033. }
  1034. }
  1035. } else {
  1036. if (SetRectRgn(hrgnOldAnim, 0, 0, 0, 0) == 0) {
  1037. goto Cleanup;
  1038. }
  1039. }
  1040. DeleteObject(hbmMem);
  1041. hbmMem = TakeWindowSnapshot(hwnd, hdc, hdcMem);
  1042. }
  1043. if (hbmMem != NULL) {
  1044. hbmOld = SelectBitmap(hdcMem, hbmMem);
  1045. } else {
  1046. goto Cleanup;
  1047. }
  1048. } else {
  1049. goto Cleanup;
  1050. }
  1051. /*
  1052. * Use the default animation duration if the caller didn't specify it.
  1053. */
  1054. if (dwTime == 0) {
  1055. dwTime = CMS_QANIMATION;
  1056. }
  1057. /*
  1058. * If we are doing an alpha blend animation, call a separate routine to
  1059. * do it and then return.
  1060. */
  1061. if (dwFlags & AW_BLEND) {
  1062. fRet = AnimateBlend(pwnd, hdc, hdcMem, dwTime, fHide, fActivateWindow);
  1063. if (fRet) {
  1064. fHideWindow = FALSE;
  1065. fShowWindow = FALSE;
  1066. }
  1067. goto Cleanup;
  1068. }
  1069. /*
  1070. * Our central animation routine uses an equation to update the new
  1071. * position of the window during the animation. This equation uses some
  1072. * variables so that it is configurable.
  1073. *
  1074. * x and y describe where the left and top edges are caluclated relative
  1075. * to. xReal and yReal are the result of that calculation.
  1076. *
  1077. * nx and ny are used to control in which direction the the top and left
  1078. * edges are offset from x and y. The left/top edges are either fixed in
  1079. * place (nx and ny are set to 0), or are calculated as a negative offset
  1080. * from the right/bottom edges (nx and ny are set to -1).
  1081. *
  1082. * ix, and iy are the amount of the width and height that the
  1083. * animation should be showing at a particular iteration through the
  1084. * loop. If we are showing the window, this amount starts at
  1085. * 0 and increments towards the window's true dimension. If we are
  1086. * hiding a window, this amount starts at the window's true dimension
  1087. * and decrements towards 0.
  1088. */
  1089. ix = iy = 0;
  1090. ixLast = fHide ? cx : 0; // The opposite condition of what signals we're done.
  1091. iyLast = fHide ? cy : 0; // The opposite condition of what signals we're done.
  1092. if (dwFlags & AW_CENTER) {
  1093. /*
  1094. * Expand the window from the center. The left edge is calculated as
  1095. * a negative offset from the center. As the width either grows or
  1096. * shrinks, the left edge will be repositioned.
  1097. */
  1098. x = cx / 2;
  1099. nx = -1;
  1100. fSlide = FALSE;
  1101. } else if (dwFlags & AW_HOR_POSITIVE) {
  1102. if (fHide) {
  1103. /*
  1104. * Slide/Roll to the right. The left edge moves to the right, and
  1105. * the right edge stays put. Thus, the width gets smaller. The
  1106. * left edge is calculated as a negative offset from the right
  1107. * edge.
  1108. */
  1109. x = cx;
  1110. nx = -1;
  1111. } else {
  1112. /*
  1113. * Slide/Roll to the right. The left edge stays put, and the right
  1114. * edge moves to the right. Thus, the width gets bigger. The
  1115. * left edge is always 0.
  1116. */
  1117. x = 0;
  1118. nx = 0;
  1119. }
  1120. } else if (dwFlags & AW_HOR_NEGATIVE) {
  1121. if (fHide) {
  1122. /*
  1123. * Slide/Roll to the left. The left edge stays put, and the right
  1124. * edge moves to the left. Thus, the width gets smaller. The
  1125. * left edge is always 0.
  1126. */
  1127. x = 0;
  1128. nx = 0;
  1129. } else {
  1130. /*
  1131. * Slide/Roll to the left. The left edge moves to the left, and
  1132. * the right edge stays put. Thus, the width gets bigger.
  1133. * The left edge is calculated as a negative offset from the right
  1134. * edge.
  1135. */
  1136. x = cx;
  1137. nx = -1;
  1138. }
  1139. } else {
  1140. /*
  1141. * There is not supposed to be any horizontal animation. The
  1142. * animation is always as wide as the window.
  1143. */
  1144. x = 0;
  1145. nx = 0;
  1146. ix = cx;
  1147. }
  1148. if (dwFlags & AW_CENTER) {
  1149. /*
  1150. * Expand the window from the center. The top edge is calculated as
  1151. * a negative offset from the center. As the height either grows or
  1152. * shrinks, the top edge will be repositioned.
  1153. */
  1154. y = cy / 2;
  1155. ny = -1;
  1156. } else if (dwFlags & AW_VER_POSITIVE) {
  1157. if (fHide) {
  1158. /*
  1159. * Slide/Roll down. The top edge moves down, and the bottom
  1160. * edge stays put. Thus, the height gets smaller. The top edge
  1161. * is calculated as a negative offset from the bottom edge.
  1162. */
  1163. y = cy;
  1164. ny = -1;
  1165. } else {
  1166. /*
  1167. * Slide/Roll down. The top edge stays put, and the bottom edge
  1168. * moves down. Thus, the height gets bigger. The top edge is
  1169. * always 0.
  1170. */
  1171. y = 0;
  1172. ny = 0;
  1173. }
  1174. } else if (dwFlags & AW_VER_NEGATIVE) {
  1175. if (fHide) {
  1176. /*
  1177. * Slide/Roll up. The top edge stays put, and the bottom edge
  1178. * moves up. Thus, the height gets smaller. The top edge is
  1179. * always 0.
  1180. */
  1181. y = 0;
  1182. ny = 0;
  1183. } else {
  1184. /*
  1185. * Slide/Roll up. The top edge moves up, and the bottom edge
  1186. * stays put. Thus, the height gets bigger. The top edge is
  1187. * calculated as a negative offset from the bottom edge.
  1188. */
  1189. y = cy;
  1190. ny = -1;
  1191. }
  1192. } else {
  1193. /*
  1194. * There is not supposed to be any vertical animation. The
  1195. * animation is always as tall as the window.
  1196. */
  1197. y = 0;
  1198. ny = 0;
  1199. iy = cy;
  1200. }
  1201. /*
  1202. * Summary of the animation loop:
  1203. *
  1204. * We sit in a tight loop and update the positions of the left and
  1205. * top edges of the window, as well as the width and height. We set
  1206. * a window region with these dimensions on the window so that windows
  1207. * behind it will be updated properly. Then we draw the cached snapshot
  1208. * of the window on top of (and clipped to) this region.
  1209. *
  1210. * dwTime is the amount of time the animation should take. dwStart
  1211. * was the value of the internal tick counter when we started the
  1212. * animation loop. dwElapsed counts how many ticks (nilliseconds)
  1213. * have passed at the start of each pass through the animation loop.
  1214. *
  1215. * ixLast and iyLast are simply the values of ix and iy the last
  1216. * time we went through the loop. If these are the same, there is
  1217. * no work to be done, and we force our thread to be rescheduled by
  1218. * calling Sleep(1).
  1219. */
  1220. dwStart = GetTickCount();
  1221. #if DBG
  1222. cAnimationFrames = 0;
  1223. #endif
  1224. while (TRUE) {
  1225. dwElapsed = GetTickCount() - dwStart;
  1226. /*
  1227. * Calculate the amount of the window width we should be showing.
  1228. */
  1229. if (dwFlags & AW_HOR) {
  1230. ix = (fHide ? AnimDec : AnimInc)(cx, dwElapsed, dwTime);
  1231. }
  1232. /*
  1233. * Calculate the amount of the window height we should be showing.
  1234. */
  1235. if (dwFlags & AW_VER) {
  1236. iy = (fHide ? AnimDec : AnimInc)(cy, dwElapsed, dwTime);
  1237. }
  1238. /*
  1239. * We have exceeded our time, make sure we draw the final frame.
  1240. */
  1241. if (dwElapsed > dwTime) {
  1242. TAGMSG0(DBGTAG_AnimateWindow, "AnimateWindow: Exceeded animation time. Drawing fimal frame.");
  1243. ix = fHide ? 0 : cx;
  1244. iy = fHide ? 0 : cy;
  1245. }
  1246. if (ixLast == ix && iyLast == iy) {
  1247. /*
  1248. * There was no change in the amount of the window we are
  1249. * supposed to show since last time. Chances are we are
  1250. * being animated really slowly or a short distance. Either
  1251. * way, sitting in this tight loop is kind of a waste. So
  1252. * force the thread to get rescheduled.
  1253. */
  1254. TAGMSG0(DBGTAG_AnimateWindow, "AnimateWindow: Drawing frames faster than needed. Sleeping." );
  1255. Sleep(1);
  1256. } else {
  1257. /*
  1258. * Calculate the new positions of the left and top edges of the
  1259. * window being animated.
  1260. */
  1261. if (dwFlags & AW_CENTER) {
  1262. xReal = x + nx * (ix / 2);
  1263. yReal = y + ny * (iy / 2);
  1264. } else {
  1265. xReal = x + nx * ix;
  1266. yReal = y + ny * iy;
  1267. }
  1268. /*
  1269. * Calculate new animation dimensions on the screen.
  1270. */
  1271. rcAnim.left = xReal;
  1272. rcAnim.top = yReal;
  1273. rcAnim.right = rcAnim.left + ix;
  1274. rcAnim.bottom = rcAnim.top + iy;
  1275. TAGMSG5(DBGTAG_AnimateWindow, "AnimateWindow: Frame %d = (%d,%d)-(%d,%d)", cAnimationFrames, rcAnim.left, rcAnim.top, rcAnim.right, rcAnim.bottom);
  1276. /*
  1277. * Calculate the offset of this animation rectangle in the bitmap.
  1278. */
  1279. if (fSlide) {
  1280. if (dwFlags & AW_HOR_POSITIVE) {
  1281. xMem = fHide ? 0: cx - ix;
  1282. } else if (dwFlags & AW_HOR_NEGATIVE) {
  1283. xMem = fHide ? cx - ix : 0;
  1284. } else {
  1285. xMem = xReal;
  1286. }
  1287. xRgn = xMem ? -xMem : xReal;
  1288. if (dwFlags & AW_VER_POSITIVE) {
  1289. yMem = fHide ? 0 : cy - iy;
  1290. } else if (dwFlags & AW_VER_NEGATIVE) {
  1291. yMem = fHide ? cy - iy : 0;
  1292. } else {
  1293. yMem = yReal;
  1294. }
  1295. yRgn = yMem ? -yMem : yReal;
  1296. } else {
  1297. xMem = xReal;
  1298. yMem = yReal;
  1299. xRgn = 0;
  1300. yRgn = 0;
  1301. }
  1302. /*
  1303. * Create a new region that spans the animation rectangle. We
  1304. * have to create a new region every time because when we set
  1305. * it into the window, the system will take ownership of it.
  1306. */
  1307. hrgnAnim = CreateRectRgnIndirect(&rcAnim);
  1308. if (hrgnAnim == NULL) {
  1309. goto Cleanup;
  1310. }
  1311. /*
  1312. * If the original window had a region, we need to merge it
  1313. * with the animation rectangle. We may have to offset the
  1314. * original region to accomplish effects like slides.
  1315. */
  1316. if (hrgnOriginal != NULL) {
  1317. if (OffsetRgn(hrgnOriginal, xRgn, yRgn) == ERROR) {
  1318. goto Cleanup;
  1319. }
  1320. if (CombineRgn(hrgnAnim, hrgnOriginal, hrgnAnim, RGN_AND) == ERROR) {
  1321. goto Cleanup;
  1322. }
  1323. if (OffsetRgn(hrgnOriginal, -xRgn, -yRgn) == ERROR) {
  1324. goto Cleanup;
  1325. }
  1326. }
  1327. /*
  1328. * Now calculate how much of the screen (ie desktop window)
  1329. * we need to update. All we really need to paint is the
  1330. * difference in the new animation region and the old
  1331. * animation region. Note that we have to convert to
  1332. * coordinates in the regions to be relative to the desktop
  1333. * window instead of being relative to the window being
  1334. * animated.
  1335. */
  1336. if (CombineRgn(hrgnUpdate, hrgnOldAnim, hrgnAnim, RGN_DIFF) == ERROR) {
  1337. goto Cleanup;
  1338. }
  1339. if (fRTL) {
  1340. MirrorRgn(hwnd, hrgnUpdate);
  1341. }
  1342. if (OffsetRgn(hrgnUpdate, xWin, yWin) == ERROR) {
  1343. goto Cleanup;
  1344. }
  1345. /*
  1346. * The system will own the region when we set it into the
  1347. * window. We need to keep it around so that we can
  1348. * calculate the update region on the next pass through
  1349. * the animation loop. So we make a copy.
  1350. */
  1351. if (CombineRgn(hrgnOldAnim, hrgnAnim, NULL, RGN_COPY) == ERROR) {
  1352. goto Cleanup;
  1353. }
  1354. /*
  1355. * Set the window region. Note that we haven't actually moved
  1356. * the window. And that the coordinates in the region are all
  1357. * relative to the window. After this call, the system owns
  1358. * the hrgnAnim. Then repaint the update region of the
  1359. * DESKTOP window. This is the region under/around the window
  1360. * that we have exposed.
  1361. *
  1362. * Note: We use the RealSetWindowRgn to work around theming.
  1363. * The theming system will hook the standard SetWindowRgn API
  1364. * and revoke the theming of the window since it detects us
  1365. * setting our own region. The idea being that if we are setting
  1366. * a region, we must have a "custom" look in mind for the window.
  1367. * Which we dont, we just want to hide parts of it temporarily.
  1368. */
  1369. if(0 == RealSetWindowRgn(hwnd, hrgnAnim, FALSE)) {
  1370. goto Cleanup;
  1371. } else {
  1372. /*
  1373. * The system now owns the region. Lets simply forget about
  1374. * it to be safe.
  1375. */
  1376. hrgnAnim = NULL;
  1377. }
  1378. /*
  1379. * If we are supposed to activate the window, do so on the first
  1380. * frame of the animation. This will cause the window to be
  1381. * z-ordered properly. Note that we leave the flag set to
  1382. * true so that we will activate it again at the end. This will
  1383. * force a repaint since we are currently drawing the bits of the
  1384. * window that doesn't look activated.
  1385. */
  1386. if (fFirstFrame && fActivateWindow) {
  1387. NtUserSetWindowPos(hwnd, NULL, 0, 0, 0, 0,
  1388. SWP_NOMOVE | SWP_NOSIZE | SWP_NOOWNERZORDER | SWP_NOREDRAW);
  1389. }
  1390. fFirstFrame = FALSE;
  1391. if (RedrawWindow(NULL, NULL, hrgnUpdate, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN) == 0) {
  1392. goto Cleanup;
  1393. }
  1394. if (fRedrawParentWindow) {
  1395. if (NtUserCallHwndParamLock(hwndParent, (ULONG_PTR)hrgnUpdate, SFI_XXXUPDATEWINDOWS) == 0) {
  1396. TAGMSG0(DBGTAG_AnimateWindow, "AnimateWindow: Warning: xxxUpdateWindows failed!");
  1397. goto Cleanup;
  1398. }
  1399. }
  1400. /*
  1401. * Now draw the cached snapshot of the window on top of the window
  1402. * itself. We do this by drawing into the window's DC. Since we
  1403. * applied a region already, all clipping is done for us.
  1404. */
  1405. if (BitBlt(hdc, xReal, yReal, ix, iy, hdcMem, xMem, yMem, SRCCOPY | NOMIRRORBITMAP) == 0) {
  1406. goto Cleanup;
  1407. }
  1408. #if DBG
  1409. cAnimationFrames++;
  1410. dwElapsed2 = GetTickCount() - dwStart;
  1411. dwElapsed2 -= dwElapsed;
  1412. #endif
  1413. TAGMSG2(DBGTAG_AnimateWindow, "AnimateWindow: Frame %d took %lums", cAnimationFrames, dwElapsed2 );
  1414. ixLast = ix;
  1415. iyLast = iy;
  1416. /*
  1417. * Break out of the animation loop when, either:
  1418. * 1) We've exceeded the animation time.
  1419. * 2) We're hiding the window and one of the dimensions is 0.
  1420. * The window is completely hidden now anyways,
  1421. * 3) We're showing the window and both dimensions are at their
  1422. * full size. The window is completely shown now anyways.
  1423. */
  1424. if (dwElapsed > dwTime) {
  1425. TAGMSG0(DBGTAG_AnimateWindow, "AnimateWindow: Done with the animation late!");
  1426. break;
  1427. }
  1428. if ((fHide && (ix == 0 || iy == 0)) ||
  1429. (!fHide && (ix == cx && iy == cy))) {
  1430. TAGMSG0(DBGTAG_AnimateWindow, "AnimateWindow: Done with the animation on time or early!");
  1431. break;
  1432. }
  1433. }
  1434. }
  1435. TAGMSG2(DBGTAG_AnimateWindow, "AnimateWindow: Animation completed after %lums, drawing %d frames.", dwElapsed, cAnimationFrames);
  1436. fRet = TRUE;
  1437. if (fHide) {
  1438. UserAssert(ixLast == 0 || iyLast == 0);
  1439. /*
  1440. * We are supposed to be hiding the window. Go ahead and restore the
  1441. * child clipping setting, and hide the window.
  1442. */
  1443. if (fRestoreClipChildren) {
  1444. SetWindowState(pwnd, WFCLIPCHILDREN);
  1445. fRestoreClipChildren = FALSE;
  1446. }
  1447. NtUserSetWindowPos(hwnd, NULL, 0, 0, 0, 0,
  1448. SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_NOREDRAW | SWP_HIDEWINDOW | SWP_NOACTIVATE);
  1449. fHideWindow = FALSE;
  1450. } else {
  1451. UserAssert(ixLast == cx && iyLast == cy);
  1452. /*
  1453. * We successfully finished the animation loop! Validate the entire window since
  1454. * we claimed responsibility for drawing it correctly.
  1455. */
  1456. RedrawWindow(hwnd, NULL, NULL, RDW_NOERASE | RDW_NOFRAME | RDW_NOINTERNALPAINT | RDW_VALIDATE);
  1457. }
  1458. Cleanup:
  1459. /*
  1460. * Things to do on cleanup. Make sure we restore the "children clipping"
  1461. * setting of the window if we removed it!
  1462. */
  1463. if (fRestoreClipChildren) {
  1464. SetWindowState(pwnd, WFCLIPCHILDREN);
  1465. fRestoreClipChildren = FALSE;
  1466. }
  1467. /*
  1468. * Hide the window if needed before we reapply the window region.
  1469. */
  1470. if (fHideWindow) {
  1471. TAGMSG0(DBGTAG_AnimateWindow, "AnimateWindow: Hiding the window during cleanup" );
  1472. NtUserShowWindow(hwnd, SW_HIDE);
  1473. }
  1474. /*
  1475. * Restore the original window region. Note that the system now owns
  1476. * the handle, so we should not delete it. Also, if the original
  1477. * handle was NULL, this removes any regions we inflicted on the window
  1478. * in order to do the animation.
  1479. */
  1480. if (fRestoreOriginalRegion) {
  1481. RealSetWindowRgn(hwnd, hrgnOriginal, FALSE);
  1482. hrgnOriginal = NULL;
  1483. fRestoreOriginalRegion = FALSE;
  1484. }
  1485. /*
  1486. * More things to do on cleanup. Make sure we show/activate the window
  1487. * if needed!
  1488. */
  1489. if (fShowWindow && fActivateWindow) {
  1490. TAGMSG0(DBGTAG_AnimateWindow, "AnimateWindow: Showing and activating the window during cleanup" );
  1491. NtUserSetWindowPos(hwnd, NULL, 0, 0, 0, 0, SWP_DRAWFRAME | SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE | SWP_NOOWNERZORDER);
  1492. fShowWindow = FALSE;
  1493. fActivateWindow = FALSE;
  1494. }
  1495. if (fShowWindow) {
  1496. TAGMSG0(DBGTAG_AnimateWindow, "AnimateWindow: Showing the window during cleanup" );
  1497. NtUserSetWindowPos(hwnd, NULL, 0, 0, 0, 0,
  1498. SWP_SHOWWINDOW | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOOWNERZORDER);
  1499. fShowWindow = FALSE;
  1500. }
  1501. if (fActivateWindow) {
  1502. TAGMSG0(DBGTAG_AnimateWindow, "AnimateWindow: Activating the window during cleanup" );
  1503. NtUserSetWindowPos(hwnd, NULL, 0, 0, 0, 0,
  1504. SWP_DRAWFRAME | SWP_NOMOVE | SWP_NOSIZE | SWP_NOOWNERZORDER);
  1505. fActivateWindow = FALSE;
  1506. }
  1507. if (hdcMem != NULL) {
  1508. DeleteDC(hdcMem);
  1509. }
  1510. if (hbmMem != NULL) {
  1511. DeleteObject(hbmMem);
  1512. }
  1513. if (hdc != NULL) {
  1514. ReleaseDC(hwnd, hdc);
  1515. }
  1516. if (hrgnAnim != NULL) {
  1517. DeleteObject(hrgnAnim);
  1518. hrgnAnim = NULL;
  1519. }
  1520. if (hrgnOldAnim != NULL) {
  1521. DeleteObject(hrgnOldAnim);
  1522. hrgnOldAnim = NULL;
  1523. }
  1524. if (hrgnUpdate != NULL) {
  1525. DeleteObject(hrgnUpdate);
  1526. hrgnUpdate = NULL;
  1527. }
  1528. return fRet;
  1529. }
  1530. /***************************************************************************\
  1531. * SmoothScrollWindowEx
  1532. *
  1533. * History:
  1534. * 24-Sep-1996 vadimg wrote
  1535. \***************************************************************************/
  1536. #define MINSCROLL 10
  1537. #define MAXSCROLLTIME 200
  1538. int SmoothScrollWindowEx(HWND hwnd, int dx, int dy, CONST RECT *prcScroll,
  1539. CONST RECT *prcClip, HRGN hrgnUpdate, LPRECT prcUpdate, DWORD dwFlags,
  1540. DWORD dwTime)
  1541. {
  1542. RECT rc, rcT, rcUpdate;
  1543. int dxStep, dyStep, dxDone, dyDone, xSrc, ySrc, xDst, yDst, dxBlt, dyBlt;
  1544. int nRet = ERROR, nClip;
  1545. BOOL fNegX = FALSE, fNegY = FALSE;
  1546. HDC hdc, hdcMem = NULL;
  1547. HBITMAP hbmMem = NULL, hbmOld;
  1548. DWORD dwSleep;
  1549. BOOL fCalcSubscroll = FALSE;
  1550. PWND pwnd = ValidateHwnd(hwnd);
  1551. HRGN hrgnScroll = NULL, hrgnErase = NULL;
  1552. MSG msg;
  1553. UINT uBounds;
  1554. RECT rcBounds;
  1555. if (pwnd == NULL)
  1556. return ERROR;
  1557. /*
  1558. * Keep track of the signs so we don't have to mess with abs all the time.
  1559. */
  1560. if (dx < 0) {
  1561. fNegX = TRUE;
  1562. dx = -dx;
  1563. }
  1564. if (dy < 0) {
  1565. fNegY = TRUE;
  1566. dy = -dy;
  1567. }
  1568. /*
  1569. * Set up the client rectangle.
  1570. */
  1571. if (prcScroll != NULL) {
  1572. rc = *prcScroll;
  1573. } else {
  1574. rc.left = rc.top = 0;
  1575. rc.right = pwnd->rcClient.right - pwnd->rcClient.left;
  1576. rc.bottom = pwnd->rcClient.bottom - pwnd->rcClient.top;
  1577. }
  1578. /*
  1579. * If they want to scroll less than we can let them, or more than
  1580. * one page, or need repainting send them to the API.
  1581. */
  1582. if (pwnd->hrgnUpdate != NULL || (dx == 0 && dy == 0) ||
  1583. (dx != 0 && dx > rc.right) ||
  1584. (dy != 0 && dy > rc.bottom)) {
  1585. return NtUserScrollWindowEx(hwnd, fNegX ? -dx : dx, fNegY ? -dy : dy,
  1586. prcScroll, prcClip, hrgnUpdate, prcUpdate,
  1587. dwFlags | SW_ERASE | SW_INVALIDATE);
  1588. }
  1589. if ((hdc = GetDCEx(hwnd, NULL, DCX_USESTYLE | DCX_CACHE)) == NULL) {
  1590. return ERROR;
  1591. }
  1592. /*
  1593. * Part of the window may be obscured, which means that more may be
  1594. * invisible and may need to be bltted. Take that into account by
  1595. * gettting the clip box.
  1596. */
  1597. nClip = GetClipBox(hdc, &rcT);
  1598. if (nClip == ERROR || nClip == NULLREGION) {
  1599. goto Cleanup;
  1600. }
  1601. /*
  1602. * Set up the offscreen dc and send WM_PRINT to get the image.
  1603. */
  1604. if ((hbmMem = CreateCompatibleBitmap(hdc, rc.right, rc.bottom)) == NULL) {
  1605. goto Cleanup;
  1606. }
  1607. if ((hdcMem = CreateCompatibleDC(hdc)) == NULL) {
  1608. goto Cleanup;
  1609. }
  1610. hbmOld = SelectBitmap(hdcMem, hbmMem);
  1611. SetBoundsRect(hdcMem, NULL, DCB_RESET | DCB_ENABLE);
  1612. SendMessage(hwnd, WM_PRINT, (WPARAM)hdcMem, PRF_CLIENT |
  1613. PRF_ERASEBKGND | ((dwFlags & SW_SCROLLCHILDREN) ? PRF_CHILDREN : 0));
  1614. /*
  1615. * If the client rect changes during the callback, send WM_PRINT
  1616. * again to get the correctly sized image.
  1617. */
  1618. if (prcScroll == NULL) {
  1619. rcT.left = rcT.top = 0;
  1620. rcT.right = pwnd->rcClient.right - pwnd->rcClient.left;
  1621. rcT.bottom = pwnd->rcClient.bottom - pwnd->rcClient.top;
  1622. if (!EqualRect(&rc, &rcT)) {
  1623. rc = rcT;
  1624. SelectObject(hdcMem, hbmOld);
  1625. DeleteObject(hbmMem);
  1626. if ((hbmMem = CreateCompatibleBitmap(hdc, rc.right, rc.bottom)) == NULL) {
  1627. goto Cleanup;
  1628. }
  1629. SelectObject(hdcMem, hbmMem);
  1630. SendMessage(hwnd, WM_PRINT, (WPARAM)hdcMem, PRF_CLIENT |
  1631. PRF_ERASEBKGND | ((dwFlags & SW_SCROLLCHILDREN) ? PRF_CHILDREN : 0));
  1632. }
  1633. }
  1634. /*
  1635. * Check to see if the app painted in our DC.
  1636. */
  1637. uBounds = GetBoundsRect(hdcMem, &rcBounds, 0);
  1638. if ((uBounds & DCB_RESET) && (!(uBounds & DCB_ACCUMULATE))) {
  1639. goto Cleanup;
  1640. }
  1641. if ((hrgnScroll = CreateRectRgn(0, 0, 0, 0)) == NULL) {
  1642. goto Cleanup;
  1643. }
  1644. if ((hrgnErase = CreateRectRgn(0, 0, 0, 0)) == NULL) {
  1645. goto Cleanup;
  1646. }
  1647. SetRectEmpty(&rcUpdate);
  1648. /*
  1649. * Start off with MINSCROLL and adjust it based on available time after
  1650. * the first iteration. We should consider adding a NOTIMELIMIT flag.
  1651. */
  1652. xDst = xSrc = 0;
  1653. yDst = ySrc = 0;
  1654. dxBlt = rc.right;
  1655. dyBlt = rc.bottom;
  1656. if (dx == 0) {
  1657. dxDone = rc.right;
  1658. dxStep = 0;
  1659. } else {
  1660. dxDone = 0;
  1661. dxStep = max(dx / MINSCROLL, 1);
  1662. }
  1663. if (dy == 0) {
  1664. dyDone = rc.bottom;
  1665. dyStep = 0;
  1666. } else {
  1667. dyDone = 0;
  1668. dyStep = max(dy / MINSCROLL, 1);
  1669. }
  1670. if (dwTime == 0) {
  1671. dwTime = MAXSCROLLTIME;
  1672. }
  1673. dwSleep = dwTime / MINSCROLL;
  1674. do {
  1675. /*
  1676. * When the dc is scrolled, the part that's revealed cannot be
  1677. * updated properly. We set up the variables to blt just the part that
  1678. * was just uncovered.
  1679. */
  1680. if (dx != 0) {
  1681. if (dxDone + dxStep > dx) {
  1682. dxStep = dx - dxDone;
  1683. }
  1684. dxDone += dxStep;
  1685. xDst = dx - dxDone;
  1686. dxBlt = rc.right - xDst;
  1687. if (!fNegX) {
  1688. xSrc = xDst;
  1689. xDst = 0;
  1690. }
  1691. }
  1692. if (dy != 0) {
  1693. if (dyDone + dyStep > dy) {
  1694. dyStep = dy - dyDone;
  1695. }
  1696. dyDone += dyStep;
  1697. yDst = dy - dyDone;
  1698. dyBlt = rc.bottom - yDst;
  1699. if (!fNegY) {
  1700. ySrc = yDst;
  1701. yDst = 0;
  1702. }
  1703. }
  1704. /*
  1705. * This is a hack for ReaderMode to be smoothly continuous. We'll make an
  1706. * attempt for the scrolling to take as close to dwTime
  1707. * as possible. We'll also dispatch MOUSEMOVEs to the ReaderMode window, so it
  1708. * can update mouse cursor.
  1709. */
  1710. if (MsgWaitForMultipleObjects(0, NULL, FALSE, dwSleep, QS_MOUSEMOVE) == WAIT_OBJECT_0) {
  1711. if (PeekMessage(&msg, NULL, WM_MOUSEMOVE, WM_MOUSEMOVE, MAKELONG(PM_NOREMOVE, QS_INPUT))) {
  1712. PWND pwndPeek = ValidateHwnd(msg.hwnd);
  1713. if (pwndPeek != NULL) {
  1714. PCLS pcls = (PCLS)REBASEALWAYS(pwndPeek, pcls);
  1715. if (pcls->atomClassName == gatomReaderMode) {
  1716. if (PeekMessage(&msg, msg.hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, MAKELONG(PM_REMOVE, QS_INPUT))) {
  1717. DispatchMessage(&msg);
  1718. }
  1719. }
  1720. }
  1721. }
  1722. }
  1723. if ((nRet = NtUserScrollWindowEx(hwnd, fNegX ? -dxStep : dxStep,
  1724. fNegY ? -dyStep : dyStep, prcScroll, prcClip,
  1725. hrgnScroll, &rcT, dwFlags)) == ERROR)
  1726. goto Cleanup;
  1727. UnionRect(&rcUpdate, &rcUpdate, &rcT);
  1728. /*
  1729. * Blt the uncovered part.
  1730. */
  1731. BitBlt(hdc, xDst, yDst, dxBlt, dyBlt, hdcMem, xSrc, ySrc, SRCCOPY | NOMIRRORBITMAP);
  1732. SetRectRgn(hrgnErase, xDst, yDst, xDst + dxBlt, yDst + dyBlt);
  1733. CombineRgn(hrgnErase, hrgnScroll, hrgnErase, RGN_DIFF);
  1734. RedrawWindow(hwnd, NULL, hrgnErase, RDW_ERASE | RDW_INVALIDATE | RDW_ERASENOW);
  1735. } while (dxDone < dx || dyDone < dy);
  1736. if (prcUpdate != NULL) {
  1737. *prcUpdate = rcUpdate;
  1738. }
  1739. if (hrgnUpdate != NULL) {
  1740. SetRectRgn(hrgnUpdate, rcUpdate.left, rcUpdate.top,
  1741. rcUpdate.right, rcUpdate.bottom);
  1742. }
  1743. Cleanup:
  1744. if (hdcMem != NULL) {
  1745. DeleteDC(hdcMem);
  1746. }
  1747. if (hbmMem != NULL) {
  1748. DeleteObject(hbmMem);
  1749. }
  1750. if (hdc != NULL) {
  1751. ReleaseDC(hwnd, hdc);
  1752. }
  1753. if (hrgnErase != NULL) {
  1754. DeleteObject(hrgnErase);
  1755. }
  1756. if (hrgnScroll != NULL) {
  1757. DeleteObject(hrgnScroll);
  1758. }
  1759. return nRet;
  1760. }
  1761. /***************************************************************************\
  1762. * ScrollWindowEx (API)
  1763. *
  1764. \***************************************************************************/
  1765. int ScrollWindowEx(HWND hwnd, int dx, int dy, CONST RECT *prcScroll,
  1766. CONST RECT *prcClip, HRGN hrgnUpdate, LPRECT prcUpdate,
  1767. UINT dwFlags)
  1768. {
  1769. if (dwFlags & SW_SMOOTHSCROLL) {
  1770. return SmoothScrollWindowEx(hwnd, dx, dy, prcScroll, prcClip,
  1771. hrgnUpdate, prcUpdate, LOWORD(dwFlags), HIWORD(dwFlags));
  1772. } else {
  1773. return NtUserScrollWindowEx(hwnd, dx, dy, prcScroll, prcClip,
  1774. hrgnUpdate, prcUpdate, dwFlags);
  1775. }
  1776. }
  1777. /***************************************************************************\
  1778. * IsGUIThread (API)
  1779. *
  1780. * Checks whether the current thread is a GUI thread. If bConvert is TRUE, will
  1781. * convert the current thread to GUI, if necessary.
  1782. *
  1783. * History:
  1784. * 22-Jun-2000 JasonSch Wrote.
  1785. \***************************************************************************/
  1786. FUNCLOG1(LOG_GENERAL, BOOL, DUMMYCALLINGTYPE, IsGUIThread, BOOL, bConvert)
  1787. BOOL IsGUIThread(BOOL bConvert)
  1788. {
  1789. BOOL bIsGUI = (NtCurrentTebShared()->Win32ThreadInfo != NULL);
  1790. if (!bIsGUI && bConvert) {
  1791. bIsGUI = (BOOL)USERTHREADCONNECT();
  1792. if (!bIsGUI) {
  1793. UserSetLastError(ERROR_OUTOFMEMORY);
  1794. }
  1795. }
  1796. return bIsGUI;
  1797. }
  1798. /***************************************************************************\
  1799. * IsWindowInDestroy (API)
  1800. *
  1801. * Checks whether the current window is in the process of being destroyed.
  1802. *
  1803. * History:
  1804. * 02-Jan-2001 Mohamed Wrote.
  1805. \***************************************************************************/
  1806. FUNCLOG1(LOG_GENERAL, BOOL, DUMMYCALLINGTYPE, IsWindowInDestroy, HWND, hwnd)
  1807. BOOL IsWindowInDestroy(IN HWND hwnd)
  1808. {
  1809. PWND pwnd;
  1810. pwnd = ValidateHwnd(hwnd);
  1811. if (pwnd == NULL) {
  1812. return FALSE;
  1813. }
  1814. return TestWF(pwnd, WFINDESTROY);
  1815. }
  1816. /***************************************************************************\
  1817. * IsServerSideWindow (API)
  1818. *
  1819. * Checks whether the current window is marked as having a server side WndProc.
  1820. *
  1821. * History:
  1822. * 13-Jun-2001 Mohamed Created.
  1823. \***************************************************************************/
  1824. FUNCLOG1(LOG_GENERAL, BOOL, DUMMYCALLINGTYPE, IsServerSideWindow, HWND, hwnd)
  1825. BOOL IsServerSideWindow(IN HWND hwnd)
  1826. {
  1827. PWND pwnd;
  1828. pwnd = ValidateHwnd(hwnd);
  1829. if (pwnd == NULL) {
  1830. return FALSE;
  1831. }
  1832. return TestWF(pwnd, WFSERVERSIDEPROC);
  1833. }