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.

1867 lines
59 KiB

  1. /****************************** Module Header ******************************\
  2. * Module Name: fullscr.c
  3. *
  4. * Copyright (c) 1985 - 1999, Microsoft Corporation
  5. *
  6. * This module contains all the fullscreen code for Win32k.
  7. *
  8. * History:
  9. * 12-Dec-1991 mikeke Created
  10. \***************************************************************************/
  11. #include "precomp.h"
  12. #pragma hdrstop
  13. /***************************************************************************\
  14. * We can only have one fullscreen window at a time so this information can
  15. * be stored globally.
  16. *
  17. * We partially use busy waiting to set the state of the hardware. The
  18. * problem is that while we are in the middle of a fullscreen switch, we
  19. * leave the critical section, so someone else could come in and change the
  20. * state of the fullscreen stuff. In order to keep the system from getting
  21. * confused about the state of the device, we actually "post" the request.
  22. *
  23. * What we do with external requests for switching, is that we will do busy
  24. * waiting on these state variables. So an app won't be able to request a
  25. * fullscreen switch while one is under way. This is a way to make the
  26. * system completely reentrant for state switches.
  27. *
  28. * The state variables themselves can only be touched while owning the
  29. * critical section. We are guaranteed that we will not busy wait forever
  30. * since the switch operations (although long) will eventually finish.
  31. *
  32. * 20-Mar-1996 andreva Created
  33. \***************************************************************************/
  34. #if DBG
  35. LONG TraceFullscreenSwitch;
  36. #endif
  37. HANDLE ghSwitcher;
  38. BOOL gfRedoFullScreenSwitch, gfGdiEnabled = TRUE;
  39. POINT gptCursorFullScreen;
  40. VOID SetVDMCursorBounds(LPRECT lprc);
  41. VOID UserSetDelayedChangeBroadcastForAllDesktops(
  42. PDESKTOP pCurrentDesktop)
  43. {
  44. PWINDOWSTATION pwinsta;
  45. PDESKTOP pdesk;
  46. /*
  47. * Get a pointer to the windowstation so we can change display setting
  48. * for all of its destops.
  49. */
  50. if ((pwinsta = grpWinStaList) == NULL) {
  51. RIPMSGF0(RIP_ERROR, "No interactive WindowStation");
  52. return;
  53. }
  54. /*
  55. * Walk all the desktops of the winstation and, for each of them, just
  56. * set its delayed Broadcast indicator to TRUE so that next switch to
  57. * that destop will force Display Settings change messages to be
  58. * broadcasted to windows of that desktop.
  59. */
  60. pdesk = pwinsta->rpdeskList;
  61. while (pdesk != NULL) {
  62. if (pdesk != pCurrentDesktop) {
  63. pdesk->dwDTFlags |= DF_NEWDISPLAYSETTINGS;
  64. }
  65. pdesk = pdesk->rpdeskNext;
  66. }
  67. }
  68. /***************************************************************************\
  69. * FullScreenCleanup
  70. *
  71. * This is called during thread cleanup, we test to see if we died during a
  72. * full screen switch and switch back to the GDI desktop if we did.
  73. *
  74. * NOTE:
  75. * All the variables touched here are guaranteed to be touched under
  76. * the CritSect.
  77. *
  78. * 12-Dec-1991 mikeke Created
  79. \***************************************************************************/
  80. VOID FullScreenCleanup(
  81. VOID)
  82. {
  83. if (PsGetCurrentThreadId() == ghSwitcher) {
  84. /*
  85. * Correct the full screen state.
  86. */
  87. if (gfGdiEnabled) {
  88. TRACE_SWITCH(("Switching: FullScreenCleanup: Gdi Enabled\n"));
  89. /*
  90. * Gdi is enabled; since we are switching away from gdi the only
  91. * thing we could have done so far is locking the screen so
  92. * unlock it.
  93. */
  94. CLEAR_PUDF(PUDF_LOCKFULLSCREEN);
  95. LockWindowUpdate2(NULL, TRUE);
  96. } else {
  97. /*
  98. * GDI is not enabled. This means we were switching from a full
  99. * screen to another fullscreen or back to GDI. Or we could have
  100. * disabled gdi and sent a message to the new full screen which
  101. * never got completed.
  102. *
  103. * In any case this probably means the fullscreen guy is gone so
  104. * we will switch back to gdi.
  105. *
  106. * Delete any left over saved screen state stuff set the fullscreen
  107. * to nothing and then send a message that will cause us to switch
  108. * back to the gdi desktop.
  109. */
  110. TL tlpwndT;
  111. TRACE_SWITCH(("Switching: FullScreenCleanup: Gdi Disabled\n"));
  112. Unlock(&gspwndFullScreen);
  113. gbFullScreen = FULLSCREEN;
  114. ThreadLock(grpdeskRitInput->pDeskInfo->spwnd, &tlpwndT);
  115. xxxSendNotifyMessage(grpdeskRitInput->pDeskInfo->spwnd, WM_FULLSCREEN,
  116. GDIFULLSCREEN,
  117. (LPARAM)HW(grpdeskRitInput->pDeskInfo->spwnd));
  118. ThreadUnlock(&tlpwndT);
  119. }
  120. ghSwitcher = NULL;
  121. gfRedoFullScreenSwitch = FALSE;
  122. }
  123. }
  124. /***************************************************************************\
  125. * xxxMakeWindowForegroundWithState
  126. *
  127. * Syncs the screen graphics mode with the mode of the specified (foreground)
  128. * window.
  129. *
  130. * We make sure only one thread is going through this code by checking
  131. * ghSwitcher. If ghSwitcher is non-NULL someone is already in this code.
  132. *
  133. * 12-Dec-1991 mikeke Created
  134. \***************************************************************************/
  135. BOOL xxxMakeWindowForegroundWithState(
  136. PWND pwnd,
  137. BYTE NewState)
  138. {
  139. PWND pwndNewFG;
  140. TL tlpwndNewFG;
  141. TRACE_SWITCH(("Switching: xxxMakeWindowForegroundWithState: Enter\n"));
  142. TRACE_SWITCH(("\t \t pwnd = %08lx\n", pwnd));
  143. TRACE_SWITCH(("\t \t NewState = %d\n", NewState));
  144. CheckLock(pwnd);
  145. UserAssert(IsWinEventNotifyDeferredOK());
  146. /*
  147. * If we should switch to a specific window save that window.
  148. */
  149. if (pwnd != NULL) {
  150. if (NewState == GDIFULLSCREEN) {
  151. Lock(&gspwndShouldBeForeground, pwnd);
  152. }
  153. /*
  154. * Change to the new state.
  155. */
  156. SetFullScreen(pwnd, NewState);
  157. if (NewState == FULLSCREEN &&
  158. (gpqForeground == NULL || gpqForeground->spwndActive != pwnd)) {
  159. SetFullScreen(pwnd, FULLSCREENMIN);
  160. }
  161. }
  162. /*
  163. * Since we leave the critical section during the switch, some other
  164. * thread could come into this routine and request a switch. The global
  165. * will be reset, and we will use the loop to perform the next switch.
  166. */
  167. if (ghSwitcher != NULL) {
  168. gfRedoFullScreenSwitch = TRUE;
  169. TRACE_SWITCH(("Switching: xxxMakeWindowForegroundWithState was posted: Exit\n"));
  170. return TRUE;
  171. }
  172. UserAssert(!gfRedoFullScreenSwitch);
  173. ghSwitcher = PsGetCurrentThreadId();
  174. /*
  175. * We loop, switching full screens until all states have stabilized
  176. */
  177. while (TRUE) {
  178. /*
  179. * Figure out who should be foreground.
  180. */
  181. gfRedoFullScreenSwitch = FALSE;
  182. if (gspwndShouldBeForeground != NULL) {
  183. pwndNewFG = gspwndShouldBeForeground;
  184. Unlock(&gspwndShouldBeForeground);
  185. } else {
  186. if (gpqForeground != NULL && gpqForeground->spwndActive != NULL) {
  187. pwndNewFG = gpqForeground->spwndActive;
  188. if (GetFullScreen(pwndNewFG) == WINDOWED ||
  189. GetFullScreen(pwndNewFG) == FULLSCREENMIN) {
  190. pwndNewFG = PWNDDESKTOP(pwndNewFG);
  191. }
  192. } else {
  193. /*
  194. * No active window, switch to current desktop.
  195. */
  196. pwndNewFG = grpdeskRitInput->pDeskInfo->spwnd;
  197. }
  198. }
  199. /*
  200. * We don't need to switch if the right window is already foreground.
  201. */
  202. if (pwndNewFG == gspwndFullScreen) {
  203. break;
  204. }
  205. ThreadLock(pwndNewFG, &tlpwndNewFG);
  206. {
  207. BYTE bStateNew = GetFullScreen(pwndNewFG);
  208. TL tlpwndOldFG;
  209. PWND pwndOldFG = gspwndFullScreen;
  210. BYTE bStateOld = gbFullScreen;
  211. ThreadLock(pwndOldFG, &tlpwndOldFG);
  212. Lock(&gspwndFullScreen, pwndNewFG);
  213. gbFullScreen = bStateNew;
  214. UserAssert(!HMIsMarkDestroy(gspwndFullScreen));
  215. /*
  216. * If the old screen was GDIFULLSCREEN and we are switching to
  217. * GDIFULLSCREEN then just repaint.
  218. *
  219. * BUG 231647: For remote sessions it can happen that pwndOldFG is
  220. * NULL but the display is enabled therefore a call to
  221. * DrvEnableMDEV would confuse the Drv* code. The way this happens
  222. * is when gspwndFullScreen was the desktop window of a desktop
  223. * that got destroyed after we switched away from it.
  224. */
  225. if ((pwndOldFG != NULL || gbRemoteSession) &&
  226. bStateOld == GDIFULLSCREEN &&
  227. bStateNew == GDIFULLSCREEN) {
  228. xxxRedrawWindow(pwndNewFG,
  229. NULL,
  230. NULL,
  231. RDW_INVALIDATE | RDW_ALLCHILDREN | RDW_ERASE |
  232. RDW_ERASENOW);
  233. ThreadUnlock(&tlpwndOldFG);
  234. } else {
  235. /*
  236. * Tell old 'foreground' window it is losing control of the
  237. * screen.
  238. */
  239. if (pwndOldFG != NULL) {
  240. switch (bStateOld) {
  241. case FULLSCREEN:
  242. if (GetFullScreen(pwndOldFG) == FULLSCREEN) {
  243. SetFullScreen(pwndOldFG, FULLSCREENMIN);
  244. }
  245. xxxSendMessage(pwndOldFG, WM_FULLSCREEN, FALSE, 0);
  246. xxxCapture(GETPTI(pwndOldFG), NULL, FULLSCREEN_CAPTURE);
  247. SetVDMCursorBounds(NULL);
  248. break;
  249. case GDIFULLSCREEN:
  250. /*
  251. * Lock out other windows from drawing while we are
  252. * fullscreen.
  253. */
  254. LockWindowUpdate2(pwndOldFG, TRUE);
  255. SET_PUDF(PUDF_LOCKFULLSCREEN);
  256. UserAssert(gfGdiEnabled == TRUE);
  257. /*
  258. * We are about to switch to FULLSCREEN mode.
  259. *
  260. * IsRemoteConnection() == TRUE indicates that we
  261. * are on a remote session. Switching to FULLSCREEN
  262. * mode is not supported on remote sessions.
  263. *
  264. * gfSwitchInProgress flag means that we are
  265. * currently in process of disconnecting the
  266. * session, so even if it is not remote right now it
  267. * is about to go remote. In these cases we must not
  268. * switch to FULLSCREEN mode.
  269. */
  270. if (IsRemoteConnection() || gfSwitchInProgress ||
  271. !SafeDisableMDEV()) {
  272. /*
  273. * Restore the previous state before bailing.
  274. */
  275. CLEAR_PUDF(PUDF_LOCKFULLSCREEN);
  276. LockWindowUpdate2(NULL, TRUE);
  277. Lock(&gspwndFullScreen, pwndOldFG);
  278. gbFullScreen = bStateOld;
  279. ThreadUnlock(&tlpwndOldFG);
  280. ThreadUnlock(&tlpwndNewFG);
  281. ghSwitcher = NULL;
  282. return FALSE;
  283. }
  284. gptCursorFullScreen = gpsi->ptCursor;
  285. gfGdiEnabled = FALSE;
  286. break;
  287. default:
  288. RIPMSG0(RIP_ERROR, "xxxMakeWindowForegroundWithState: bad screen state");
  289. break;
  290. }
  291. }
  292. ThreadUnlock(&tlpwndOldFG);
  293. switch (bStateNew) {
  294. case FULLSCREEN:
  295. xxxCapture(GETPTI(pwndNewFG), pwndNewFG, FULLSCREEN_CAPTURE);
  296. xxxSendMessage(pwndNewFG, WM_FULLSCREEN, TRUE, 0);
  297. break;
  298. case GDIFULLSCREEN:
  299. if (ISTS() && pwndOldFG != NULL) {
  300. UserAssert(gfGdiEnabled == FALSE);
  301. }
  302. SafeEnableMDEV();
  303. gfGdiEnabled = TRUE;
  304. /*
  305. * Return the cursor to it's old state. Reset the screen
  306. * saver mouse position or it'll go away by accident.
  307. */
  308. gpqCursor = NULL;
  309. gpcurPhysCurrent = NULL;
  310. gpcurLogCurrent = NULL;
  311. SetPointer(FALSE);
  312. gptSSCursor = gptCursorFullScreen;
  313. /*
  314. * No need to DeferWinEventNotify() - we use only globals,
  315. * then make an xxx call below.
  316. */
  317. zzzInternalSetCursorPos(gptCursorFullScreen.x,
  318. gptCursorFullScreen.y);
  319. CLEAR_PUDF(PUDF_LOCKFULLSCREEN);
  320. LockWindowUpdate2(NULL, TRUE);
  321. xxxRedrawWindow(pwndNewFG,
  322. NULL,
  323. NULL,
  324. RDW_INVALIDATE | RDW_ALLCHILDREN | RDW_ERASE |
  325. RDW_ERASENOW);
  326. break;
  327. default:
  328. RIPMSG0(RIP_ERROR, "xxxMakeWindowForegroundWithState: bad screen state");
  329. break;
  330. }
  331. }
  332. }
  333. ThreadUnlock(&tlpwndNewFG);
  334. if (!gfRedoFullScreenSwitch) {
  335. break;
  336. }
  337. }
  338. TRACE_SWITCH(("Switching: xxxMakeWindowForegroundWithState: Exit\n"));
  339. ghSwitcher = NULL;
  340. return TRUE;
  341. }
  342. /***************************************************************************\
  343. * MonitorFromHdev
  344. \***************************************************************************/
  345. PMONITOR MonitorFromHdev(
  346. HANDLE hdev)
  347. {
  348. PMONITOR pMonitor;
  349. for (pMonitor = gpDispInfo->pMonitorFirst; pMonitor != NULL;
  350. pMonitor = pMonitor->pMonitorNext) {
  351. if (pMonitor->hDev == hdev) {
  352. return pMonitor;
  353. }
  354. }
  355. return NULL;
  356. }
  357. /***************************************************************************\
  358. * HdevFromMonitor
  359. \***************************************************************************/
  360. ULONG HdevFromMonitor(
  361. PMONITOR pMonitor)
  362. {
  363. PMDEV pmdev = gpDispInfo->pmdev;
  364. ULONG i;
  365. for (i = 0; i < pmdev->chdev; i++) {
  366. if (pmdev->Dev[i].hdev == pMonitor->hDev) {
  367. return i;
  368. }
  369. }
  370. return -1;
  371. }
  372. /***************************************************************************\
  373. * CreateMonitor
  374. \***************************************************************************/
  375. PMONITOR CreateMonitor(
  376. VOID)
  377. {
  378. PMONITOR pMonitor;
  379. pMonitor = (PMONITOR)HMAllocObject(NULL, NULL, TYPE_MONITOR, sizeof(MONITOR));
  380. if (pMonitor != NULL) {
  381. pMonitor->rcMonitor.left = 0;
  382. pMonitor->rcMonitor.top = 0;
  383. pMonitor->rcMonitor.right = 0;
  384. pMonitor->rcMonitor.bottom = 0;
  385. pMonitor->rcWork.left = 0;
  386. pMonitor->rcWork.top = 0;
  387. pMonitor->rcWork.right = 0;
  388. pMonitor->rcWork.bottom = 0;
  389. } else {
  390. RIPERR0(ERROR_NOT_ENOUGH_MEMORY, RIP_WARNING, "CreateMonitor failed");
  391. }
  392. return pMonitor;
  393. }
  394. /***************************************************************************\
  395. * CreateCachedMonitor
  396. \***************************************************************************/
  397. PMONITOR CreateCachedMonitor(
  398. VOID)
  399. {
  400. if (gpMonitorCached == NULL) {
  401. gpMonitorCached = CreateMonitor();
  402. }
  403. return gpMonitorCached;
  404. }
  405. /***************************************************************************\
  406. * SetMonitorData
  407. \***************************************************************************/
  408. PMONITOR SetMonitorData(
  409. PMONITOR pMonitor,
  410. ULONG iDev)
  411. {
  412. PMDEV pmdev = gpDispInfo->pmdev;
  413. HDEV hdev = pmdev->Dev[iDev].hdev;
  414. BOOL fVisible = TRUE;
  415. BOOL fPrimary = FALSE;
  416. HDC hdcTmp;
  417. UserAssert(iDev < pmdev->chdev);
  418. if (hdcTmp = GreCreateDisplayDC(hdev, DCTYPE_DIRECT, FALSE)) {
  419. if (GreGetDeviceCaps(hdcTmp, CAPS1) & C1_MIRROR_DEVICE) {
  420. fVisible = FALSE;
  421. }
  422. GreDeleteDC(hdcTmp);
  423. }
  424. if (fVisible && (pmdev->Dev[iDev].rect.top == 0) &&
  425. (pmdev->Dev[iDev].rect.left == 0)) {
  426. fPrimary = TRUE;
  427. }
  428. if (pMonitor == NULL) {
  429. if (fPrimary) {
  430. UserAssert(gpMonitorCached != NULL);
  431. pMonitor = gpMonitorCached;
  432. gpMonitorCached = NULL;
  433. } else {
  434. pMonitor = CreateMonitor();
  435. }
  436. }
  437. if (pMonitor == NULL) {
  438. return NULL;
  439. }
  440. SET_OR_CLEAR_FLAG(pMonitor->dwMONFlags, MONF_VISIBLE, fVisible);
  441. /*
  442. * When the monitor rect is changing, size the work area so the same
  443. * amount as before is clipped off each edge.
  444. */
  445. if (!EqualRect(&pMonitor->rcMonitor, &pmdev->Dev[iDev].rect)) {
  446. pMonitor->rcWork.left = pmdev->Dev[iDev].rect.left -
  447. (pMonitor->rcMonitor.left - pMonitor->rcWork.left);
  448. pMonitor->rcWork.top = pmdev->Dev[iDev].rect.top -
  449. (pMonitor->rcMonitor.top - pMonitor->rcWork.top);
  450. pMonitor->rcWork.right = pmdev->Dev[iDev].rect.right -
  451. (pMonitor->rcMonitor.right - pMonitor->rcWork.right);
  452. pMonitor->rcWork.bottom = pmdev->Dev[iDev].rect.bottom -
  453. (pMonitor->rcMonitor.bottom - pMonitor->rcWork.bottom);
  454. }
  455. pMonitor->rcMonitor = pmdev->Dev[iDev].rect;
  456. pMonitor->hDev = hdev;
  457. /*
  458. * Make sure that the work area is inside the monitor's bounds.
  459. */
  460. if (pMonitor->rcWork.right < pMonitor->rcWork.left) {
  461. pMonitor->rcWork.right = pMonitor->rcWork.left;
  462. }
  463. if (pMonitor->rcWork.bottom < pMonitor->rcWork.top) {
  464. pMonitor->rcWork.bottom = pMonitor->rcWork.top;
  465. }
  466. if (!IntersectRect(&pMonitor->rcWork, &pMonitor->rcWork, &pMonitor->rcMonitor)) {
  467. pMonitor->rcWork = pMonitor->rcMonitor;
  468. }
  469. if (fPrimary) {
  470. gpDispInfo->pMonitorPrimary = pMonitor;
  471. }
  472. return pMonitor;
  473. }
  474. /***************************************************************************\
  475. *
  476. * Is this still TRUE ?
  477. *
  478. * When a window becomes FULLSCREEN, it is minimized and
  479. * treated like any other minimized window. Whenever the
  480. * minimized window is restored, by double clicking, menu
  481. * or keyboard, it remains minimized and the application
  482. * is given control of the screen device.
  483. *
  484. * 12-Dec-1991 mikeke Created
  485. \***************************************************************************/
  486. DWORD gdwMonitorBusy;
  487. /***************************************************************************\
  488. * xxxUpdateUserScreen
  489. *
  490. * Updates USER information associated with the screen
  491. *
  492. * History:
  493. * 28-Sep-1996 adams Created.
  494. \***************************************************************************/
  495. BOOL xxxUpdateUserScreen(
  496. BOOL fInitializeTime)
  497. {
  498. PMDEV pmdev = gpDispInfo->pmdev;
  499. ULONG i;
  500. PMONITOR pMonitor;
  501. TEXTMETRIC tm;
  502. PWINDOWSTATION pwinsta;
  503. PDESKTOP pdesk;
  504. HRGN hrgn;
  505. BOOL fPaletteDisplay;
  506. RECT rc;
  507. PMONITOR pMonitorNext = gpDispInfo->pMonitorFirst;
  508. PMONITOR *ppMonitorLast = &gpDispInfo->pMonitorFirst;
  509. TRACE_INIT(("xxxUpdateUserScreen\n"));
  510. UserAssert(gpDispInfo->hdcScreen);
  511. UserAssert(gpMonitorCached != NULL);
  512. CheckCritIn();
  513. if (!fInitializeTime) {
  514. /*
  515. * Wait until the unprotected code goes through the monitor reference.
  516. * We skip this if it's initializing the session to avoid leaving the
  517. * critical section.
  518. */
  519. while (InterlockedCompareExchange(&gdwMonitorBusy, TRUE, FALSE) != FALSE) {
  520. UserAssert(gdwMonitorBusy == TRUE);
  521. RIPMSGF0(RIP_VERBOSE, "Monitor is busy referenced by the mouse input.");
  522. LeaveCrit();
  523. UserSleep(1);
  524. EnterCrit();
  525. }
  526. }
  527. /*
  528. * Keep HMONITOR for the hdev that is the same. Delete the monitors that
  529. * weren't found in the new hdev list.
  530. */
  531. while (pMonitorNext != NULL) {
  532. pMonitor = pMonitorNext;
  533. pMonitorNext = pMonitor->pMonitorNext;
  534. if ((i = HdevFromMonitor(pMonitor)) == -1) {
  535. DestroyMonitor(pMonitor);
  536. } else {
  537. SetMonitorData(pMonitor, i);
  538. ppMonitorLast = &pMonitor->pMonitorNext;
  539. }
  540. }
  541. /*
  542. * Create monitors for the hdevs that aren't yet on the monitor list.
  543. */
  544. for (i = 0; i < pmdev->chdev; i++) {
  545. if ((pMonitor = MonitorFromHdev(pmdev->Dev[i].hdev)) == NULL) {
  546. /*
  547. * Try to create a new monitor.
  548. */
  549. pMonitor = SetMonitorData(NULL, i);
  550. if (pMonitor != NULL) {
  551. *ppMonitorLast = pMonitor;
  552. ppMonitorLast = &pMonitor->pMonitorNext;
  553. }
  554. }
  555. }
  556. UserAssert(gpDispInfo->pMonitorFirst != NULL);
  557. UserAssert(gpDispInfo->pMonitorPrimary != NULL);
  558. /*
  559. * For now, all monitors have the same display format.
  560. */
  561. SYSMET(SAMEDISPLAYFORMAT) = (pmdev->ulFlags & MDEV_MISMATCH_COLORDEPTH) ? FALSE : TRUE;
  562. fPaletteDisplay = GreGetDeviceCaps(gpDispInfo->hdcScreen, RASTERCAPS) & RC_PALETTE;
  563. gpDispInfo->fAnyPalette = !!fPaletteDisplay;
  564. /*
  565. * Determine the coordinates of the virtual desktop. Compute cMonitors as
  566. * the number of visible monitors.
  567. */
  568. SetRectEmpty(&rc);
  569. gpDispInfo->cMonitors = 0;
  570. for (pMonitor = gpDispInfo->pMonitorFirst; pMonitor; pMonitor = pMonitor->pMonitorNext) {
  571. /*
  572. * Only visible monitors contribute to the desktop area.
  573. */
  574. if (pMonitor->dwMONFlags & MONF_VISIBLE) {
  575. rc.left = min(rc.left, pMonitor->rcMonitor.left);
  576. rc.top = min(rc.top, pMonitor->rcMonitor.top);
  577. rc.right = max(rc.right, pMonitor->rcMonitor.right);
  578. rc.bottom = max(rc.bottom, pMonitor->rcMonitor.bottom);
  579. gpDispInfo->cMonitors++;
  580. }
  581. if (SYSMET(SAMEDISPLAYFORMAT)) {
  582. SET_OR_CLEAR_FLAG(pMonitor->dwMONFlags, MONF_PALETTEDISPLAY, fPaletteDisplay);
  583. } else {
  584. if (GreIsPaletteDisplay(pMonitor->hDev)) {
  585. pMonitor->dwMONFlags |= MONF_PALETTEDISPLAY;
  586. gpDispInfo->fAnyPalette = TRUE;
  587. }
  588. }
  589. #ifdef SUBPIXEL_MOUSE
  590. /*
  591. * The new mouse's acceleration curves depend on the screen resolution,
  592. * so we rebuild the curves here.
  593. */
  594. BuildMouseAccelerationCurve(pMonitor);
  595. #endif // SUBPIXEL_MOUSE
  596. }
  597. UserAssert(gpDispInfo->pMonitorPrimary != NULL);
  598. gpDispInfo->rcScreen = rc;
  599. if (!fInitializeTime) {
  600. /*
  601. * Release the monitor busy lock, so that the
  602. * mouse cursor update can resume.
  603. */
  604. UserAssert(gdwMonitorBusy == TRUE);
  605. InterlockedExchange(&gdwMonitorBusy, FALSE);
  606. }
  607. /*
  608. * Notify the TS service if one coordinate of the virtual screen changed
  609. * and we're doing console shadow.
  610. */
  611. if (gfRemotingConsole &&
  612. gpConsoleShadowDisplayChangeEvent &&
  613. !((SYSMET(XVIRTUALSCREEN) == gpDispInfo->rcScreen.left) &&
  614. (SYSMET(YVIRTUALSCREEN) == gpDispInfo->rcScreen.top) &&
  615. (SYSMET(CXVIRTUALSCREEN) == gpDispInfo->rcScreen.right - gpDispInfo->rcScreen.left) &&
  616. (SYSMET(CYVIRTUALSCREEN) == gpDispInfo->rcScreen.bottom - gpDispInfo->rcScreen.top))) {
  617. KeSetEvent(gpConsoleShadowDisplayChangeEvent, EVENT_INCREMENT, FALSE);
  618. }
  619. /*
  620. * Update system metrics
  621. */
  622. SYSMET(CXSCREEN) = gpDispInfo->pMonitorPrimary->rcMonitor.right;
  623. SYSMET(CYSCREEN) = gpDispInfo->pMonitorPrimary->rcMonitor.bottom;
  624. SYSMET(XVIRTUALSCREEN) = gpDispInfo->rcScreen.left;
  625. SYSMET(YVIRTUALSCREEN) = gpDispInfo->rcScreen.top;
  626. SYSMET(CXVIRTUALSCREEN) = gpDispInfo->rcScreen.right - gpDispInfo->rcScreen.left;
  627. SYSMET(CYVIRTUALSCREEN) = gpDispInfo->rcScreen.bottom - gpDispInfo->rcScreen.top;
  628. SYSMET(CXMAXTRACK) = SYSMET(CXVIRTUALSCREEN) + (2 * (SYSMET(CXSIZEFRAME) + SYSMET(CXEDGE)));
  629. SYSMET(CYMAXTRACK) = SYSMET(CYVIRTUALSCREEN) + (2 * (SYSMET(CYSIZEFRAME) + SYSMET(CYEDGE)));
  630. SYSMET(CMONITORS) = gpDispInfo->cMonitors;
  631. /*
  632. * Bug 281219: Flush out the mouse move points if a mode change occured.
  633. */
  634. RtlZeroMemory(gaptMouse, MAX_MOUSEPOINTS * sizeof(MOUSEMOVEPOINT));
  635. SetDesktopMetrics();
  636. gpDispInfo->dmLogPixels = (WORD)GreGetDeviceCaps(gpDispInfo->hdcScreen, LOGPIXELSY);
  637. UserAssert(gpDispInfo->dmLogPixels != 0);
  638. /*
  639. * Get per-monitor or sum of monitor information, including:
  640. * The desktop region.
  641. * The region of each monitor.
  642. * Min bit counts - Not for NT SP2.
  643. * Same color format - Not for NT SP2.
  644. */
  645. SetOrCreateRectRgnIndirectPublic(&gpDispInfo->hrgnScreen, PZERO(RECT));
  646. if (gpDispInfo->hrgnScreen) {
  647. int iRgn = RGN_ERROR;
  648. for (pMonitor = gpDispInfo->pMonitorFirst;
  649. pMonitor;
  650. pMonitor = pMonitor->pMonitorNext) {
  651. /*
  652. * We want to set up hrgnMonitor for all monitors, visible or
  653. * not.
  654. */
  655. if (SetOrCreateRectRgnIndirectPublic(&pMonitor->hrgnMonitor,
  656. &pMonitor->rcMonitor)) {
  657. /*
  658. * But we want only visible monitors to contribute to
  659. * hrgnScreen.
  660. */
  661. if (pMonitor->dwMONFlags & MONF_VISIBLE) {
  662. iRgn = UnionRgn(gpDispInfo->hrgnScreen,
  663. gpDispInfo->hrgnScreen,
  664. pMonitor->hrgnMonitor);
  665. }
  666. }
  667. }
  668. gpDispInfo->fDesktopIsRect = (iRgn == SIMPLEREGION);
  669. }
  670. /*
  671. * Reset the window region of desktop windows.
  672. */
  673. hrgn = (gpDispInfo->fDesktopIsRect) ? NULL : gpDispInfo->hrgnScreen;
  674. for (pwinsta = grpWinStaList; pwinsta; pwinsta = pwinsta->rpwinstaNext) {
  675. for (pdesk = pwinsta->rpdeskList; pdesk; pdesk = pdesk->rpdeskNext) {
  676. if (pdesk->pDispInfo == gpDispInfo) {
  677. pdesk->pDeskInfo->spwnd->hrgnClip = hrgn;
  678. }
  679. }
  680. }
  681. /*
  682. * Updated information stored in gpsi.
  683. */
  684. gpsi->Planes = (BYTE)GreGetDeviceCaps(gpDispInfo->hdcScreen, PLANES);
  685. gpsi->BitsPixel = (BYTE)GreGetDeviceCaps(gpDispInfo->hdcScreen, BITSPIXEL);
  686. gpsi->BitCount = gpsi->Planes * gpsi->BitsPixel;
  687. gpDispInfo->BitCountMax = gpsi->BitCount;
  688. SET_OR_CLEAR_PUSIF(PUSIF_PALETTEDISPLAY, fPaletteDisplay);
  689. gpsi->dmLogPixels = gpDispInfo->dmLogPixels;
  690. gpsi->rcScreen = gpDispInfo->rcScreen;
  691. gpsi->cxSysFontChar = GetCharDimensions(HDCBITS(), &tm, &gpsi->cySysFontChar);
  692. gpsi->tmSysFont = tm;
  693. EnforceColorDependentSettings();
  694. VerifyVisibleMonitorCount();
  695. return TRUE;
  696. }
  697. /**************************************************************************\
  698. * InitUserScreen
  699. *
  700. * Initializes user variables at startup.
  701. *
  702. * The caller of this function needs to handle failures. If this is called as
  703. * part of the interactive console and it fails, USER will currently bugcheck.
  704. * If this is called as part of RemoteConnect() for Terminal Server, the
  705. * resources will be cleaned up in CleanupGDI() as part of normal thread
  706. * cleanup.
  707. *
  708. * 12-Jan-1994 andreva Created
  709. * 23-Jan-1995 ChrisWil ChangeDisplaySettings work.
  710. \**************************************************************************/
  711. BOOL InitUserScreen(
  712. VOID)
  713. {
  714. int i;
  715. TL tlName;
  716. PUNICODE_STRING pProfileUserName = CreateProfileUserName(&tlName);
  717. BOOL fSuccess = TRUE;
  718. TRACE_INIT(("UserInit: Initialize Screen\n"));
  719. /*
  720. * Create screen and memory dcs.
  721. */
  722. gpDispInfo->hdcScreen = GreCreateDisplayDC(gpDispInfo->hDev, DCTYPE_DIRECT, FALSE);
  723. if (gpDispInfo->hdcScreen == NULL) {
  724. RIPMSG0(RIP_WARNING, "Fail to create gpDispInfo->hdcScreen");
  725. fSuccess = FALSE;
  726. goto Exit;
  727. }
  728. GreSelectFont(gpDispInfo->hdcScreen, GreGetStockObject(SYSTEM_FONT));
  729. GreSetDCOwner(gpDispInfo->hdcScreen, OBJECT_OWNER_PUBLIC);
  730. HDCBITS() = GreCreateCompatibleDC(gpDispInfo->hdcScreen);
  731. if (HDCBITS() == NULL) {
  732. RIPMSG0(RIP_WARNING, "Fail to create HDCBITS()");
  733. fSuccess = FALSE;
  734. goto Exit;
  735. }
  736. GreSelectFont(HDCBITS(), GreGetStockObject(SYSTEM_FONT));
  737. GreSetDCOwner(HDCBITS(), OBJECT_OWNER_PUBLIC);
  738. ghdcMem = GreCreateCompatibleDC(gpDispInfo->hdcScreen);
  739. fSuccess &= !!ghdcMem;
  740. ghdcMem2 = GreCreateCompatibleDC(gpDispInfo->hdcScreen);
  741. fSuccess &= !!ghdcMem2;
  742. if (!fSuccess) {
  743. RIPMSG0(RIP_WARNING, "Fail to create ghdcMem or ghdcMem2");
  744. goto Exit;
  745. }
  746. GreSetDCOwner(ghdcMem, OBJECT_OWNER_PUBLIC);
  747. GreSetDCOwner(ghdcMem2, OBJECT_OWNER_PUBLIC);
  748. if (CreateCachedMonitor() == NULL) {
  749. fSuccess = FALSE;
  750. goto Exit;
  751. }
  752. /*
  753. * N.b. although it's xxx, this function does not
  754. * leave the critical section if fInitializeTime is TRUE.
  755. */
  756. BEGINATOMICCHECK();
  757. if (!xxxUpdateUserScreen(TRUE)) {
  758. RIPMSG0(RIP_WARNING, "xxxUpdateUserScreen failed");
  759. fSuccess = FALSE;
  760. goto Exit;
  761. }
  762. ENDATOMICCHECK();
  763. /*
  764. * Do some initialization so we create the system colors.
  765. */
  766. /*
  767. * Set the window sizing border width to something reasonable.
  768. */
  769. gpsi->gclBorder = 1;
  770. /*
  771. * Init InternalInvalidate globals
  772. */
  773. ghrgnInv0 = CreateEmptyRgnPublic(); // For InternalInvalidate()
  774. fSuccess &= !!ghrgnInv0;
  775. ghrgnInv1 = CreateEmptyRgnPublic(); // For InternalInvalidate()
  776. fSuccess &= !!ghrgnInv1;
  777. ghrgnInv2 = CreateEmptyRgnPublic(); // For InternalInvalidate()
  778. fSuccess &= !!ghrgnInv2;
  779. /*
  780. * Initialize SPB globals
  781. */
  782. ghrgnSPB1 = CreateEmptyRgnPublic();
  783. fSuccess &= !!ghrgnSPB1;
  784. ghrgnSPB2 = CreateEmptyRgnPublic();
  785. fSuccess &= !!ghrgnSPB2;
  786. ghrgnSCR = CreateEmptyRgnPublic();
  787. fSuccess &= !!ghrgnSCR;
  788. /*
  789. * Initialize ScrollWindow/ScrollDC globals
  790. */
  791. ghrgnSW = CreateEmptyRgnPublic();
  792. fSuccess &= !!ghrgnSW;
  793. ghrgnScrl1 = CreateEmptyRgnPublic();
  794. fSuccess &= !!ghrgnScrl1;
  795. ghrgnScrl2 = CreateEmptyRgnPublic();
  796. fSuccess &= !!ghrgnScrl2;
  797. ghrgnScrlVis = CreateEmptyRgnPublic();
  798. fSuccess &= !!ghrgnScrlVis;
  799. ghrgnScrlSrc = CreateEmptyRgnPublic();
  800. fSuccess &= !!ghrgnScrlSrc;
  801. ghrgnScrlDst = CreateEmptyRgnPublic();
  802. fSuccess &= !!ghrgnScrlDst;
  803. ghrgnScrlValid = CreateEmptyRgnPublic();
  804. fSuccess &= !!ghrgnScrlValid;
  805. /*
  806. * Initialize SetWindowPos()
  807. */
  808. ghrgnInvalidSum = CreateEmptyRgnPublic();
  809. fSuccess &= !!ghrgnInvalidSum;
  810. ghrgnVisNew = CreateEmptyRgnPublic();
  811. fSuccess &= !!ghrgnVisNew;
  812. ghrgnSWP1 = CreateEmptyRgnPublic();
  813. fSuccess &= !!ghrgnSWP1;
  814. ghrgnValid = CreateEmptyRgnPublic();
  815. fSuccess &= !!ghrgnValid;
  816. ghrgnValidSum = CreateEmptyRgnPublic();
  817. fSuccess &= !!ghrgnValidSum;
  818. ghrgnInvalid = CreateEmptyRgnPublic();
  819. fSuccess &= !!ghrgnInvalid;
  820. /*
  821. * Initialize DC cache
  822. */
  823. ghrgnGDC = CreateEmptyRgnPublic();
  824. fSuccess &= !!ghrgnGDC;
  825. for (i = 0; i < DCE_SIZE_CACHEINIT; i++) {
  826. fSuccess &= !!CreateCacheDC(NULL, DCX_INVALID | DCX_CACHE, NULL);
  827. }
  828. if (!fSuccess) {
  829. RIPMSG0(RIP_WARNING, "CreateCacheDC failed");
  830. goto Exit;
  831. }
  832. /*
  833. * Let engine know that the display must be secure.
  834. */
  835. GreMarkDCUnreadable(gpDispInfo->hdcScreen);
  836. /*
  837. * LATER mikeke - if ghfontsys is changed anywhere but here
  838. * we need to fix SetNCFont()
  839. */
  840. ghFontSys = (HFONT)GreGetStockObject(SYSTEM_FONT);
  841. #if DBG
  842. SYSMET(DEBUG) = TRUE;
  843. #else
  844. SYSMET(DEBUG) = FALSE;
  845. #endif
  846. SYSMET(CLEANBOOT) = **((PULONG *)&InitSafeBootMode);
  847. SYSMET(SLOWMACHINE) = 0;
  848. /*
  849. * Initialize system colors from registry.
  850. */
  851. xxxODI_ColorInit(pProfileUserName);
  852. /*
  853. * Paint the screen background.
  854. */
  855. FillRect(gpDispInfo->hdcScreen, &gpDispInfo->rcScreen, SYSHBR(DESKTOP));
  856. UserAssert(fSuccess);
  857. Exit:
  858. FreeProfileUserName(pProfileUserName, &tlName);
  859. return fSuccess;
  860. }
  861. /***************************************************************************\
  862. * xxxResetSharedDesktops
  863. *
  864. * Resets the attributes for other desktops which share the DISPINFO that
  865. * was just changed. We need to resize all visrgns of the other desktops
  866. * so that clipping is allright.
  867. *
  868. * NOTE: For now, we have to change all the desktop even though we keep
  869. * track of the devmode on a per desktop basis, because we can switch
  870. * back to a desktop that has a different resolution and paint it before
  871. * we can change the resolution again.
  872. *
  873. * There is also an issue with CDS_FULLSCREEN where we currently lose track
  874. * of whether or not the desktop settings need to be reset or not. [andreva]
  875. *
  876. * 19-Feb-1996 ChrisWil Created.
  877. \***************************************************************************/
  878. VOID ResetSharedDesktops(
  879. PDISPLAYINFO pDIChanged,
  880. PDESKTOP pdeskChanged)
  881. {
  882. PWINDOWSTATION pwinsta = _GetProcessWindowStation(NULL);
  883. PDESKTOP pdesk;
  884. HRGN hrgn;
  885. POINT pt;
  886. PRECT prc;
  887. UserAssert(IsWinEventNotifyDeferredOK());
  888. /*
  889. * If this is CSRSS doing the dynamic resolution change then use
  890. * WinSta0 since the process windowstation is NULL for CSRSS.
  891. */
  892. if ((IsRemoteConnection()) && pwinsta == NULL && PsGetCurrentProcess() == gpepCSRSS) {
  893. pwinsta = grpWinStaList;
  894. }
  895. if (pwinsta == NULL) {
  896. if (PtiCurrent()->TIF_flags & (TIF_CSRSSTHREAD|TIF_SYSTEMTHREAD)) {
  897. pwinsta = grpdeskRitInput->rpwinstaParent;
  898. } else {
  899. TRACE_SWITCH(("ResetSharedDesktops - NULL window station !\n"));
  900. return;
  901. }
  902. }
  903. for (pdesk = pwinsta->rpdeskList; pdesk; pdesk = pdesk->rpdeskNext) {
  904. /*
  905. * Make sure this is a shared DISPINFO.
  906. */
  907. if (pdesk->pDispInfo == pDIChanged) {
  908. #if 0
  909. /*
  910. * This is the preferable method to set the desktop-window.
  911. * However, this causes synchronization problems where we
  912. * leave the critical-section allowing other apps to call
  913. * ChangeDisplaySettings() and thus mucking up the works.
  914. *
  915. * By calculating the vis-rgn ourselves, we can assure that
  916. * the clipping is current for the desktop even when we leave
  917. * the section.
  918. */
  919. {
  920. TL tlpwnd;
  921. ThreadLockAlways(pdesk->pDeskInfo->spwnd, &tlpwnd);
  922. xxxSetWindowPos(pdesk->pDeskInfo->spwnd,
  923. PWND_TOP,
  924. pDIChanged->rcScreen.left,
  925. pDIChanged->rcScreen.top,
  926. pDIChanged->rcScreen.right - pDIChanged->rcScreen.left,
  927. pDIChanged->rcScreen.bottom - pDIChanged->rcScreen.top,
  928. SWP_NOZORDER | SWP_NOACTIVATE);
  929. ThreadUnlock(&tlpwnd);
  930. }
  931. #else
  932. CopyRect(&pdesk->pDeskInfo->spwnd->rcWindow, &pDIChanged->rcScreen);
  933. CopyRect(&pdesk->pDeskInfo->spwnd->rcClient, &pDIChanged->rcScreen);
  934. #endif
  935. }
  936. }
  937. /*
  938. * Recalc the desktop visrgn.
  939. */
  940. hrgn = CreateEmptyRgn();
  941. CalcVisRgn(&hrgn,
  942. pdeskChanged->pDeskInfo->spwnd,
  943. pdeskChanged->pDeskInfo->spwnd,
  944. DCX_WINDOW);
  945. GreSelectVisRgn(pDIChanged->hdcScreen, hrgn, SVR_DELETEOLD);
  946. /*
  947. * Invalidate all DCE's visrgns.
  948. */
  949. zzzInvalidateDCCache(pdeskChanged->pDeskInfo->spwnd, 0);
  950. /*
  951. * Position mouse so that it is within the new visrgn, once we
  952. * recalc it.
  953. */
  954. if (grpdeskRitInput->pDispInfo == pDIChanged) {
  955. prc = &pDIChanged->pMonitorPrimary->rcMonitor;
  956. pt.x = (prc->right - prc->left) / 2;
  957. pt.y = (prc->bottom - prc->top) / 2;
  958. /*
  959. * Remember new mouse pos. Makes sure we don't wake the screensaver.
  960. */
  961. gptSSCursor = pt;
  962. zzzInternalSetCursorPos(pt.x, pt.y);
  963. }
  964. }
  965. /***************************************************************************\
  966. * DestroyMonitorDCs
  967. *
  968. * 03/03/1998 vadimg created
  969. \***************************************************************************/
  970. VOID DestroyMonitorDCs(
  971. VOID)
  972. {
  973. PDCE pdce;
  974. PDCE *ppdce;
  975. /*
  976. * Scan the DC cache to find any monitor DC's that need to be destroyed.
  977. */
  978. for (ppdce = &gpDispInfo->pdceFirst; *ppdce != NULL;) {
  979. pdce = *ppdce;
  980. if (pdce->pMonitor != NULL) {
  981. DestroyCacheDC(ppdce, pdce->hdc);
  982. }
  983. /*
  984. * Step to the next DC. If the DC was deleted, there is no need to
  985. * calculate address of the next entry.
  986. */
  987. if (pdce == *ppdce) {
  988. ppdce = &pdce->pdceNext;
  989. }
  990. }
  991. }
  992. /***************************************************************************\
  993. * ResetSystemColors
  994. *
  995. * Reset all system colors to make sure magic colors are reset and
  996. * solid system colors are indeed solid after a mode change.
  997. \***************************************************************************/
  998. VOID ResetSystemColors(
  999. VOID)
  1000. {
  1001. INT i, colorIndex[COLOR_MAX];
  1002. COLORREF colorValue[COLOR_MAX];
  1003. for (i = 0; i < COLOR_MAX; i++) {
  1004. colorIndex[i] = i;
  1005. colorValue[i] = gpsi->argbSystemUnmatched[i];
  1006. }
  1007. BEGINATOMICCHECK();
  1008. xxxSetSysColors(NULL,
  1009. i,
  1010. colorIndex,
  1011. colorValue,
  1012. SSCF_FORCESOLIDCOLOR | SSCF_SETMAGICCOLORS);
  1013. ENDATOMICCHECK();
  1014. }
  1015. /***************************************************************************\
  1016. * xxxResetDisplayDevice
  1017. *
  1018. * Resets the user-globals with the new hdev settings.
  1019. *
  1020. * 19-Feb-1996 ChrisWil Created.
  1021. \***************************************************************************/
  1022. VOID xxxResetDisplayDevice(
  1023. PDESKTOP pdesk,
  1024. PDISPLAYINFO pDI,
  1025. DWORD CDS_Flags)
  1026. {
  1027. WORD wOldBpp;
  1028. PMONITORRECTS pmr = NULL;
  1029. TL tlPool;
  1030. PTHREADINFO ptiCurrent = PtiCurrent();
  1031. wOldBpp = gpsi->BitCount;
  1032. if (!(CDS_Flags & CDS_FULLSCREEN)) {
  1033. pmr = SnapshotMonitorRects();
  1034. if (pmr) {
  1035. ThreadLockPool(ptiCurrent, pmr, &tlPool);
  1036. }
  1037. }
  1038. /*
  1039. * Cleanup any monitor specific DCs we gave out.
  1040. */
  1041. DestroyMonitorDCs();
  1042. xxxUpdateUserScreen(FALSE);
  1043. ResetSharedDesktops(pDI, pdesk);
  1044. ResetSystemColors();
  1045. if (ghbmCaption) {
  1046. GreDeleteObject(ghbmCaption);
  1047. ghbmCaption = CreateCaptionStrip();
  1048. }
  1049. zzzClipCursor(&pDI->rcScreen);
  1050. /*
  1051. * Adjust window positions to fit new resolutions and positions of
  1052. * monitors.
  1053. *
  1054. * Don't adjust the windows if we are in a temporary mode change.
  1055. */
  1056. if (pmr) {
  1057. xxxDesktopRecalc(pmr);
  1058. ThreadUnlockAndFreePool(PtiCurrent(), &tlPool);
  1059. }
  1060. /*
  1061. * Relead the desktop wallpaper on a video mode change.
  1062. */
  1063. if (ghbmWallpaper) {
  1064. UserAssert(gpszWall);
  1065. if (ptiCurrent->TIF_flags & TIF_INCLEANUP) {
  1066. /*
  1067. * The thread is being terminated. We cannot transition back to
  1068. * the client side. So we ask the desktop to do it for us.
  1069. */
  1070. _PostThreadMessage(gTermIO.ptiDesktop,
  1071. WM_DESKTOPNOTIFY,
  1072. DESKTOP_RELOADWALLPAPER,
  1073. 0);
  1074. } else {
  1075. TL tlName;
  1076. PUNICODE_STRING pProfileUserName = CreateProfileUserName(&tlName);
  1077. xxxSetDeskWallpaper(pProfileUserName, SETWALLPAPER_METRICS);
  1078. FreeProfileUserName(pProfileUserName, &tlName);
  1079. }
  1080. }
  1081. /*
  1082. * Recreate cached bitmaps.
  1083. */
  1084. CreateBitmapStrip();
  1085. /*
  1086. * Broadcast that the display has changed resolution. Also broadcast a
  1087. * color-change if we were not in fullscreen, and a color-change took
  1088. * effect.
  1089. */
  1090. if (!(CDS_Flags & CDS_FULLSCREEN) && gpsi->BitCount != wOldBpp) {
  1091. xxxBroadcastDisplaySettingsChange(pdesk, TRUE);
  1092. } else {
  1093. xxxBroadcastDisplaySettingsChange(pdesk, FALSE);
  1094. }
  1095. /*
  1096. * If the user performed a CTL-ESC, it is possible that the tray-window
  1097. * is then in the menu-loop. We want to clear this out so that we don't
  1098. * leave improper menu positioning.
  1099. */
  1100. if (gpqForeground && gpqForeground->spwndCapture) {
  1101. QueueNotifyMessage(gpqForeground->spwndCapture, WM_CANCELMODE, 0, 0);
  1102. }
  1103. }
  1104. /***************************************************************************\
  1105. * TrackFullscreenMode
  1106. *
  1107. * Remember the process going into the fullscreen mode, so that the mode can
  1108. * be restored if the process doesn't clean up upon exit. If some other mode
  1109. * change, clear the global since that means we're definitely out of the
  1110. * fullscreen mode.
  1111. *
  1112. * 1/12/1999 vadimg created
  1113. \***************************************************************************/
  1114. VOID TrackFullscreenMode(
  1115. DWORD dwFlags)
  1116. {
  1117. if (dwFlags & CDS_FULLSCREEN) {
  1118. gppiFullscreen = PtiCurrent()->ppi;
  1119. } else {
  1120. gppiFullscreen = NULL;
  1121. }
  1122. }
  1123. /***************************************************************************\
  1124. * NtUserChangeDisplaySettings
  1125. *
  1126. * ChangeDisplaySettings API
  1127. *
  1128. * 01-Sep-1995 andreva Created
  1129. * 19-Feb-1996 ChrisWil Implemented Dynamic-Resolution changes.
  1130. \***************************************************************************/
  1131. LONG xxxUserChangeDisplaySettings(
  1132. IN PUNICODE_STRING pstrDeviceName,
  1133. IN LPDEVMODEW pDevMode,
  1134. IN PDESKTOP pdesk,
  1135. IN DWORD dwFlags,
  1136. IN PVOID lParam,
  1137. IN MODE PreviousMode)
  1138. {
  1139. BOOL bSwitchMode;
  1140. PDESKTOP pdesktop;
  1141. LONG status;
  1142. PMDEV pmdev;
  1143. /*
  1144. * NOTE: The lParam has NOT been properly captured. It is not used in
  1145. * this function, but is passed onto other called functions. Once the
  1146. * correct type is determined and it is to be used, it must be properly
  1147. * captured.
  1148. */
  1149. TRACE_INIT(("ChangeDisplaySettings - Entering\n"));
  1150. TRACE_SWITCH(("ChangeDisplaySettings - Entering\n"));
  1151. TRACE_INIT((" Flags -"));
  1152. if (dwFlags & CDS_UPDATEREGISTRY) TRACE_INIT((" CDS_UPDATEREGISTRY - "));
  1153. if (dwFlags & CDS_TEST) TRACE_INIT((" CDS_TEST - "));
  1154. if (dwFlags & CDS_FULLSCREEN) TRACE_INIT((" CDS_FULLSCREEN - "));
  1155. if (dwFlags & CDS_GLOBAL) TRACE_INIT((" CDS_GLOBAL - "));
  1156. if (dwFlags & CDS_SET_PRIMARY) TRACE_INIT((" CDS_SET_PRIMARY - "));
  1157. if (dwFlags & CDS_RESET) TRACE_INIT((" CDS_RESET - "));
  1158. if (dwFlags & CDS_NORESET) TRACE_INIT((" CDS_NORESET - "));
  1159. if (dwFlags & CDS_VIDEOPARAMETERS) TRACE_INIT((" CDS_VIDEOPARAMETERS - "));
  1160. TRACE_INIT(("\n"));
  1161. /*
  1162. * Perform Error Checking to verify flag combinations are valid.
  1163. */
  1164. if (dwFlags & ~CDS_VALID) {
  1165. return GRE_DISP_CHANGE_BADFLAGS;
  1166. }
  1167. if (DrvQueryMDEVPowerState(gpDispInfo->pmdev) == FALSE) {
  1168. RIPMSG0(RIP_WARNING, "ChangeDisplaySettings failed because the device is powered off");
  1169. return GRE_DISP_CHANGE_BADPARAM;
  1170. }
  1171. if (gbMDEVDisabled) {
  1172. RIPMSG0(RIP_WARNING, "ChangeDisplaySettings failed because the MDEV is already disabled");
  1173. return GRE_DISP_CHANGE_FAILED;
  1174. }
  1175. /*
  1176. * CDS_GLOBAL and CDS_NORESET can only be specified if UPDATEREGISTRY
  1177. * is specified.
  1178. */
  1179. if ((dwFlags & (CDS_GLOBAL | CDS_NORESET)) && (!(dwFlags & CDS_UPDATEREGISTRY))) {
  1180. return GRE_DISP_CHANGE_BADFLAGS;
  1181. }
  1182. if ((dwFlags & CDS_NORESET) && (dwFlags & CDS_RESET)) {
  1183. return GRE_DISP_CHANGE_BADFLAGS;
  1184. }
  1185. if ((dwFlags & CDS_EXCLUSIVE) && (dwFlags & CDS_FULLSCREEN) && (dwFlags & CDS_RESET)) {
  1186. return GRE_DISP_CHANGE_BADFLAGS;
  1187. }
  1188. /*
  1189. * Allow mode change if this is a CSRSS of a remote session. This means we
  1190. * are changing display settings when reconnecting a session with a
  1191. * diferent resolution.
  1192. */
  1193. if (TEST_PUDF(PUDF_LOCKFULLSCREEN)) {
  1194. if (!(ISCSRSS() && (IsRemoteConnection()))) {
  1195. return GRE_DISP_CHANGE_FAILED;
  1196. }
  1197. }
  1198. /*
  1199. * If the modeset is being done on a non-active desktop, we don't want
  1200. * it to happen.
  1201. *
  1202. * PtiCurrent()->rpdesk can be NULL in the case of thread shutdown.
  1203. */
  1204. if (pdesk) {
  1205. pdesktop = pdesk;
  1206. } else {
  1207. pdesktop = PtiCurrent()->rpdesk;
  1208. }
  1209. if (pdesktop != grpdeskRitInput) {
  1210. RIPMSG0(RIP_WARNING, "ChangeDisplaySettings on wrong desktop pdesk\n");
  1211. return GRE_DISP_CHANGE_FAILED;
  1212. }
  1213. bSwitchMode = !(dwFlags & (CDS_NORESET | CDS_TEST));
  1214. /*
  1215. * Turn off cursor and free the spb's prior to calling the mode-change.
  1216. * This will make sure off-screen memory is cleaned up for gdi while
  1217. * mucking with the resolution changes.
  1218. */
  1219. if (bSwitchMode) {
  1220. if (CreateCachedMonitor() == NULL) {
  1221. return GRE_DISP_CHANGE_FAILED;
  1222. }
  1223. SetPointer(FALSE);
  1224. FreeAllSpbs();
  1225. }
  1226. /*
  1227. * Before calling gdi to change the mode, we should kill the fade sprite.
  1228. * This is so that we won't keep pointers to gdi sprites during the mode
  1229. * change because the sprites could be reallocated.
  1230. */
  1231. if (gfade.hbm != NULL) {
  1232. StopFade();
  1233. }
  1234. /*
  1235. * Similarly, we should kill the sprites associated with the drag rect
  1236. * (if any exist) before the mode change.
  1237. */
  1238. bSetDevDragRect(gpDispInfo->hDev, NULL, NULL);
  1239. /*
  1240. * Let's capture our parameters. They are both required.
  1241. *
  1242. * If the input string is not NULL, then we are trying to affect another
  1243. * device. The device name is the same as for EnumDisplaySettings.
  1244. */
  1245. status = DrvChangeDisplaySettings(pstrDeviceName,
  1246. gpDispInfo->pMonitorPrimary->hDev,
  1247. pDevMode,
  1248. LongToPtr(pdesktop->dwDesktopId),
  1249. PreviousMode,
  1250. (dwFlags & CDS_UPDATEREGISTRY),
  1251. bSwitchMode,
  1252. gpDispInfo->pmdev,
  1253. &pmdev,
  1254. (dwFlags & CDS_RAWMODE) ? GRE_RAWMODE : GRE_DEFAULT,
  1255. (dwFlags & CDS_TRYCLOSEST));
  1256. if (bSwitchMode) {
  1257. /*
  1258. * If the caller wanted a reset, but the mode is identical, just reset
  1259. * the current mode.
  1260. */
  1261. if (status == GRE_DISP_CHANGE_NO_CHANGE) {
  1262. TrackFullscreenMode(dwFlags);
  1263. if (pmdev != NULL) {
  1264. GreFreePool(pmdev);
  1265. }
  1266. if (dwFlags & CDS_RESET) {
  1267. if (SafeDisableMDEV()) {
  1268. SafeEnableMDEV();
  1269. }
  1270. xxxUserResetDisplayDevice();
  1271. }
  1272. status = GRE_DISP_CHANGE_SUCCESSFUL;
  1273. } else if (status == GRE_DISP_CHANGE_SUCCESSFUL) {
  1274. ResetRedirectedWindows();
  1275. TrackFullscreenMode(dwFlags);
  1276. /*
  1277. * ChangeDisplaySettings automatically destroys the old MDEV, we
  1278. * only have to delete it here.
  1279. */
  1280. GreFreePool(gpDispInfo->pmdev);
  1281. gpDispInfo->pmdev = pmdev;
  1282. xxxResetDisplayDevice(pdesktop, gpDispInfo, dwFlags);
  1283. /*
  1284. * Set delayed change indicator for currently background desktops.
  1285. */
  1286. UserSetDelayedChangeBroadcastForAllDesktops(pdesktop);
  1287. } else if (status < GRE_DISP_CHANGE_SUCCESSFUL) {
  1288. UserAssert(pmdev == NULL);
  1289. xxxUserResetDisplayDevice();
  1290. }
  1291. xxxInternalInvalidate(pdesktop->pDeskInfo->spwnd,
  1292. HRGN_FULL,
  1293. RDW_INVALIDATE | RDW_ERASE | RDW_FRAME |
  1294. RDW_ALLCHILDREN);
  1295. /*
  1296. * Bring back the cursor-shape.
  1297. */
  1298. SetPointer(TRUE);
  1299. zzzUpdateCursorImage();
  1300. }
  1301. /*
  1302. * TV-Out Support.
  1303. */
  1304. if (NT_SUCCESS(status) && (dwFlags & CDS_VIDEOPARAMETERS)) {
  1305. if (lParam == NULL) {
  1306. status = GRE_DISP_CHANGE_BADPARAM;
  1307. } else {
  1308. status = DrvSetVideoParameters(pstrDeviceName,
  1309. gpDispInfo->pMonitorPrimary->hDev,
  1310. PreviousMode,
  1311. lParam);
  1312. }
  1313. }
  1314. TRACE_INIT(("ChangeDisplaySettings - Leaving, Status = %d\n", status));
  1315. return status;
  1316. }
  1317. /***************************************************************************\
  1318. * xxxbFullscreenSwitch
  1319. *
  1320. * Switch in and out of fullscreen console mode
  1321. *
  1322. * 15-Apr-1997 andreva Created
  1323. \***************************************************************************/
  1324. BOOL xxxbFullscreenSwitch(
  1325. BOOL bFullscreenSwitch,
  1326. HWND hwnd)
  1327. {
  1328. PWND pwnd;
  1329. TL tlpwnd;
  1330. BOOL bStat = TRUE;
  1331. pwnd = ValidateHwnd(hwnd);
  1332. if (!pwnd) {
  1333. return GRE_DISP_CHANGE_BADPARAM;
  1334. }
  1335. /*
  1336. * We don't want our mode switch to be posted on the looping thread.
  1337. * So let's loop until the system has settled down and no mode switch
  1338. * is currently occuring.
  1339. */
  1340. ThreadLock(pwnd, &tlpwnd);
  1341. UserAssert(ghSwitcher != PsGetCurrentThreadId());
  1342. while (ghSwitcher != NULL) {
  1343. /*
  1344. * Make sure we aren't blocking anyone who's sending us a message.
  1345. * They can have ghSwitcher and never release it because they are
  1346. * waiting on us to process the sent message. And we're waiting on
  1347. * ghSwitcher, hence a deadlock.
  1348. */
  1349. xxxSleepThread(0, 1, FALSE);
  1350. }
  1351. /*
  1352. * Syncronize with session switching.
  1353. */
  1354. if (gfSwitchInProgress || IsRemoteConnection() || gfSessionSwitchBlock) {
  1355. ThreadUnlock(&tlpwnd);
  1356. return FALSE;
  1357. } else {
  1358. gfSessionSwitchBlock = TRUE;
  1359. }
  1360. /*
  1361. * If there is a window, we want to check the state of the window. For
  1362. * most calls, we want to ensure we are in windowed mode. However, for
  1363. * Console, we want to make sure we are in fullscreen mode. So
  1364. * differentiate between the two. We will check if the TEXTMODE flag
  1365. * is passed in the DEVMODE.
  1366. */
  1367. if (bFullscreenSwitch) {
  1368. if (GetFullScreen(pwnd) != FULLSCREEN) {
  1369. xxxShowWindow(pwnd, SW_SHOWMINIMIZED | TEST_PUDF(PUDF_ANIMATE));
  1370. xxxUpdateWindow(pwnd);
  1371. }
  1372. if (!xxxMakeWindowForegroundWithState(pwnd, FULLSCREEN)) {
  1373. goto FullscreenSwitchFailed;
  1374. }
  1375. if (ghSwitcher != NULL || gbFullScreen != FULLSCREEN) {
  1376. goto FullscreenSwitchFailed;
  1377. }
  1378. } else {
  1379. /*
  1380. * For the console windows, we want to call with WINDOWED.
  1381. */
  1382. if (!xxxMakeWindowForegroundWithState(pwnd, WINDOWED)) {
  1383. goto FullscreenSwitchFailed;
  1384. }
  1385. if (ghSwitcher != NULL || gbFullScreen != GDIFULLSCREEN) {
  1386. FullscreenSwitchFailed:
  1387. TRACE_INIT(("ChangeDisplaySettings: Can not switch out of fullscreen\n"));
  1388. bStat = FALSE;
  1389. }
  1390. }
  1391. ThreadUnlock(&tlpwnd);
  1392. gfSessionSwitchBlock = FALSE;
  1393. return bStat;
  1394. }
  1395. NTSTATUS RemoteRedrawRectangle(
  1396. WORD Left,
  1397. WORD Top,
  1398. WORD Right,
  1399. WORD Bottom)
  1400. {
  1401. CheckCritIn();
  1402. TRACE_HYDAPI(("RemoteRedrawRectangle\n"));
  1403. UserAssert(ISCSRSS());
  1404. /*
  1405. * If xxxRemoteStopScreenUpdates has not been called, then just repaint
  1406. * the current foreground window.
  1407. */
  1408. if (gspdeskShouldBeForeground == NULL) {
  1409. if (gspwndFullScreen) {
  1410. TL tlpwnd;
  1411. RECT rcl;
  1412. ThreadLock(gspwndFullScreen, &tlpwnd);
  1413. rcl.left = Left;
  1414. rcl.top = Top;
  1415. rcl.right = Right;
  1416. rcl.bottom = Bottom;
  1417. vDrvInvalidateRect(gpDispInfo->hDev, &rcl);
  1418. xxxRedrawWindow(gspwndFullScreen, &rcl, NULL,
  1419. RDW_INVALIDATE | RDW_ALLCHILDREN |
  1420. RDW_ERASE | RDW_ERASENOW);
  1421. ThreadUnlock(&tlpwnd);
  1422. }
  1423. }
  1424. return STATUS_SUCCESS;
  1425. }
  1426. NTSTATUS RemoteRedrawScreen(
  1427. VOID)
  1428. {
  1429. TL tlpdesk;
  1430. PWINDOWSTATION pwinsta;
  1431. PTHREADINFO ptiCurrent;
  1432. TRACE_HYDAPI(("RemoteRedrawScreen\n"));
  1433. CheckCritIn();
  1434. if (!gbFreezeScreenUpdates) {
  1435. return STATUS_SUCCESS;
  1436. }
  1437. ptiCurrent = PtiCurrentShared();
  1438. gbFreezeScreenUpdates = FALSE;
  1439. /*
  1440. * Switch back to the previous desktop
  1441. */
  1442. if (gspdeskShouldBeForeground == NULL) {
  1443. RIPMSG0(RIP_WARNING,
  1444. "RemoteRedrawScreen called with no gspdeskShouldBeForeground");
  1445. return STATUS_SUCCESS;
  1446. }
  1447. gbDesktopLocked = FALSE;
  1448. pwinsta = gspdeskShouldBeForeground->rpwinstaParent;
  1449. /*
  1450. * Switch back to the previous desktop.
  1451. */
  1452. if (!(gspdeskShouldBeForeground->dwDTFlags & DF_DESTROYED)) {
  1453. ThreadLockDesktop(ptiCurrent, gspdeskShouldBeForeground, &tlpdesk, LDLT_FN_CTXREDRAWSCREEN);
  1454. xxxSwitchDesktop(pwinsta, gspdeskShouldBeForeground, SDF_SLOVERRIDE);
  1455. ThreadUnlockDesktop(ptiCurrent, &tlpdesk, LDUT_FN_CTXREDRAWSCREEN);
  1456. }
  1457. LockDesktop(&gspdeskShouldBeForeground, NULL, LDL_DESKSHOULDBEFOREGROUND2, 0);
  1458. return STATUS_SUCCESS;
  1459. }
  1460. NTSTATUS RemoteDisableScreen(
  1461. VOID)
  1462. {
  1463. TL tlpdesk;
  1464. PTHREADINFO ptiCurrent;
  1465. PWINDOWSTATION pwinsta;
  1466. NTSTATUS Status = STATUS_SUCCESS;
  1467. CheckCritIn();
  1468. TRACE_HYDAPI(("RemoteDisableScreen\n"));
  1469. ptiCurrent = PtiCurrentShared();
  1470. if (grpdeskRitInput != gspdeskDisconnect &&
  1471. gspdeskDisconnect != NULL) {
  1472. pwinsta = gspdeskDisconnect->rpwinstaParent;
  1473. /*
  1474. * Save current desktop
  1475. */
  1476. UserAssert(grpdeskRitInput == pwinsta->pdeskCurrent);
  1477. LockDesktop(&gspdeskShouldBeForeground,
  1478. grpdeskRitInput,
  1479. LDL_DESKSHOULDBEFOREGROUND3,
  1480. 0);
  1481. gbDesktopLocked = TRUE;
  1482. /*
  1483. * Switch to disconnected desktop.
  1484. */
  1485. ThreadLockDesktop(ptiCurrent, gspdeskDisconnect, &tlpdesk, LDLT_FN_CTXDISABLESCREEN);
  1486. xxxSwitchDesktop(pwinsta, gspdeskDisconnect, SDF_SLOVERRIDE);
  1487. ThreadUnlockDesktop(ptiCurrent, &tlpdesk, LDUT_FN_CTXDISABLESCREEN);
  1488. } else if (gspdeskDisconnect != NULL) {
  1489. /*
  1490. * For some reason the disconnected desktop was the current desktop.
  1491. * Now prevent switching from it.
  1492. */
  1493. gbDesktopLocked = TRUE;
  1494. }
  1495. return Status;
  1496. }
  1497. VOID xxxBroadcastDisplaySettingsChange(
  1498. PDESKTOP pdesk,
  1499. BOOL bBroadcastColorChange)
  1500. {
  1501. /*
  1502. * Broadcast that the display has changed resolution. We are going
  1503. * to specify the desktop for the changing-desktop. That way we
  1504. * don't get confused as to what desktop to broadcast to.
  1505. */
  1506. xxxBroadcastMessage(pdesk->pDeskInfo->spwnd,
  1507. WM_DISPLAYCHANGE,
  1508. gpsi->BitCount,
  1509. MAKELONG(SYSMET(CXSCREEN), SYSMET(CYSCREEN)),
  1510. BMSG_SENDNOTIFYMSG,
  1511. NULL);
  1512. /*
  1513. * Broadcast a color-change if requested to do so.
  1514. */
  1515. if (bBroadcastColorChange) {
  1516. xxxBroadcastMessage(pdesk->pDeskInfo->spwnd,
  1517. WM_SETTINGCHANGE,
  1518. 0,
  1519. 0,
  1520. BMSG_SENDNOTIFYMSG,
  1521. NULL);
  1522. xxxBroadcastMessage(pdesk->pDeskInfo->spwnd,
  1523. WM_SYSCOLORCHANGE,
  1524. 0,
  1525. 0,
  1526. BMSG_SENDNOTIFYMSG,
  1527. NULL);
  1528. }
  1529. }
  1530. NTSTATUS xxxRequestOutOfFullScreenMode(
  1531. VOID)
  1532. {
  1533. TL tlpwndT;
  1534. NTSTATUS Status = STATUS_SUCCESS;
  1535. if (gspwndFullScreen) {
  1536. /*
  1537. * Give the console window a chance to orderly exit full screen mode.
  1538. */
  1539. ThreadLock(gspwndFullScreen, &tlpwndT);
  1540. xxxSendMessage(gspwndFullScreen, CM_MODE_TRANSITION, (WPARAM)WINDOWED, (LPARAM)0);
  1541. ThreadUnlock(&tlpwndT);
  1542. /*
  1543. * Let's loop until the system has settled down and no mode switch
  1544. * is currently occuring.
  1545. */
  1546. while (ghSwitcher != NULL) {
  1547. /*
  1548. * Make sure we aren't blocking anyone who's sending us a
  1549. * message. They can have ghSwitcher and never release it
  1550. * because they are waiting on us to process the sent message.
  1551. * And we're waiting on ghSwitcher, hence a deadlock.
  1552. */
  1553. xxxSleepThread(0, 1, FALSE);
  1554. }
  1555. /*
  1556. * See if the fullscreen window didn't exit fullscreen mode
  1557. * gracefully.
  1558. */
  1559. if (gspwndFullScreen && (gbFullScreen == FULLSCREEN)) {
  1560. Status = STATUS_UNSUCCESSFUL;
  1561. }
  1562. }
  1563. return Status;
  1564. }