test: fullscr.c Source File

Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

# fullscr.c

Go to the documentation of this file.

    00001 /****************************** Module Header ******************************\
    00002 * Module Name: fullscr.c
    00003 *
    00004 * Copyright (c) 1985 - 1999, Microsoft Corporation
    00005 *
    00006 * This module contains all the fullscreen code for the USERSRV.DLL.
    00007 *
    00008 * History:
    00009 * 12-Dec-1991 mikeke   Created
    00010 \***************************************************************************/
    00011
    00012 #include "precomp.h"
    00013 #pragma hdrstop
    00014
    00015 /***************************************************************************\
    00016 * We can only have one fullscreen window at a time so this information can
    00017 * be store globally
    00018 *
    00019 * We partially use busy waiting to set the state of the hardware.
    00020 * The problem is that while we are in the middle of a fullscreen switch,
    00021 * we leave the critical section !  So someone else could come in and change
    00022 * the state of the fullscreen stuff.
    00023 * In order to keep the system from getting confused about the state of the
    00024 * device, we actually "post" the request.
    00025 *
    00026 * What we do with external requests for switching, is that we will do busy
    00027 * waiting on these state variables.
    00028 * So an app won't be able to request a fullscreen switch while one is under
    00029 * way.  This is a way to make the system completely reentrant for state
    00030 * switches.
    00031 *
    00032 * The state variables themselves can only be touched while owning the
    00033 * critical section.  We are guaranteed that we will not busy wait forever
    00034 * since the switch operations (although long) will eventually finish.
    00035 *
    00036 * 20-Mar-1996 andreva  Created
    00037 \***************************************************************************/
    00038
    00039 LONG TraceFullscreenSwitch;
    00040
    00041 #define NOSWITCHER ((HANDLE)-1)
    00042
    00043 HANDLE idSwitcher = NOSWITCHER;
    00044 BOOL   fRedoFullScreenSwitch;
    00045 BOOL   fGdiEnabled = TRUE;
    00046 POINT  gptCursorFullScreen;
    00047
    00048 extern ULONG InitSafeBootMode;  // imported from NTOS (init.c), must use a pointer to reference the data
    00049
    00050 void SetVDMCursorBounds(LPRECT lprc);
    00051
    00052
    00053 VOID UserSetDelayedChangeBroadcastForAllDesktops(PDESKTOP pCurrentDesktop);
    00054
    00055
    00056 VOID UserSetDelayedChangeBroadcastForAllDesktops(
    00057     PDESKTOP pCurrentDesktop)
    00058 {
    00059     PWINDOWSTATION pwinsta;
    00060     PDESKTOP       pdesk;
    00061
    00062     /*
    00063      * Get a pointer to the windowstation so we can change display
    00064      * setting for all of its destops.
    00065      */
    00066     if ((pwinsta = grpWinStaList) == NULL) {
    00067         RIPMSG0(RIP_WARNING, "UserSaveCurrentModeForAllDesktops - No interactive WindowStation!!!\n");
    00068         return;
    00069     }
    00070
    00071     /*
    00072      * Walk all the desktops of the winstation and, for each of them,
    00073      * just set its delayed Broadcast indicator to TRUE so that
    00074      * next switch to that destop will force Display Settings change
    00075      * messages to be broadcasted to windows of that desktop.
    00076      */
    00077     pdesk = pwinsta->rpdeskList;
    00078
    00079     while (pdesk != NULL) {
    00080         if (pdesk != pCurrentDesktop) {
    00081             pdesk->dwDTFlags |= DF_NEWDISPLAYSETTINGS;
    00082         }
    00083         pdesk = pdesk->rpdeskNext;
    00084     }
    00085 }
    00086
    00087
    00088 /***************************************************************************\
    00089 * FullScreenCleanup
    00090 *
    00091 * This is called during thread cleanup, we test to see if we died during a
    00092 * full screen switch and switch back to the GDI desktop if we did.
    00093 *
    00094 * NOTE:
    00095 * All the variables touched here are guaranteed to be touched under
    00096 * the CritSect.
    00097 *
    00098 * 12-Dec-1991 mikeke   Created
    00099 \***************************************************************************/
    00100
    00101 void FullScreenCleanup()
    00102 {
    00103     if (PsGetCurrentThread()->Cid.UniqueThread == idSwitcher) {
    00104
    00105         /*
    00106          * correct the full screen state
    00107          */
    00108
    00109         if (fGdiEnabled) {
    00110
    00111             TRACE_SWITCH(("Switching: FullScreenCleanup: Gdi Enabled\n"));
    00112
    00113             /*
    00114              * gdi is enabled, we are switching away from gdi the only thing we
    00115              * could have done so far is locking the screen so unlock it.
    00116              */
    00117             CLEAR_PUDF(PUDF_LOCKFULLSCREEN);
    00118             LockWindowUpdate2(NULL, TRUE);
    00119
    00120         } else {
    00121
    00122             /*
    00123              * GDI is not enabled .  This means we were switching from a full
    00124              * screen to another fullscreen or back to GDI.  Or we could have
    00125              * disabled gdi and sent a message to the new full screen which
    00126              * never got completed.
    00127              *
    00128              * In any case this probably means the fullscreen guy is gone so
    00129              * we will switch back to gdi.
    00130              *
    00131              * delete any left over saved screen state stuff
    00132              * set the fullscreen to nothing and then send a message that will
    00133              * cause us to switch back to the gdi desktop
    00134              */
    00135             TL tlpwndT;
    00136
    00137             TRACE_SWITCH(("Switching: FullScreenCleanup: Gdi Disabled\n"));
    00138
    00139             Unlock(&gspwndFullScreen);
    00140             gbFullScreen = FULLSCREEN;
    00141
    00142             ThreadLock(grpdeskRitInput->pDeskInfo->spwnd, &tlpwndT);
    00143             xxxSendNotifyMessage(
    00144                                 grpdeskRitInput->pDeskInfo->spwnd, WM_FULLSCREEN,
    00145                                 GDIFULLSCREEN, (LPARAM)HW(grpdeskRitInput->pDeskInfo->spwnd));
    00146             ThreadUnlock(&tlpwndT);
    00147         }
    00148
    00149         idSwitcher = NOSWITCHER;
    00150         fRedoFullScreenSwitch = FALSE;
    00151     }
    00152 }
    00153
    00154 /***************************************************************************\
    00155 * xxxMakeWindowForegroundWithState
    00156 *
    00157 * Syncs the screen graphics mode with the mode of the specified (foreground)
    00158 * window
    00159 *
    00160 * We make sure only one thread is going through this code by checking
    00161 * idSwitcher.  If idSwticher is non-null someone is allready in this code
    00162 *
    00163 * 12-Dec-1991 mikeke   Created
    00164 \***************************************************************************/
    00165
    00166 BOOL xxxMakeWindowForegroundWithState(
    00167                                      PWND pwnd,
    00168                                      BYTE NewState)
    00169 {
    00170     PWND pwndNewFG;
    00171     TL tlpwndNewFG;
    00172
    00173     TRACE_SWITCH(("Switching: xxxMakeWindowForeground: Enter\n"));
    00174     TRACE_SWITCH(("\t \t pwnd     = %08lx\n", pwnd));
    00175     TRACE_SWITCH(("\t \t NewState = %d\n", NewState));
    00176
    00177     CheckLock(pwnd);
    00178     UserAssert(IsWinEventNotifyDeferredOK());
    00179
    00180     /*
    00181      * If we should switch to a specific window save that window
    00182      */
    00183
    00184     if (pwnd != NULL) {
    00185
    00186         if (NewState == GDIFULLSCREEN) {
    00187             Lock(&gspwndShouldBeForeground, pwnd);
    00188         }
    00189
    00190         /*
    00191          * Change to the new state
    00192          */
    00193
    00194         SetFullScreen(pwnd, NewState);
    00195
    00196         if (NewState == FULLSCREEN &&
    00197             (gpqForeground == NULL ||
    00198              gpqForeground->spwndActive != pwnd)) {
    00199
    00200             SetFullScreen(pwnd, FULLSCREENMIN);
    00201         }
    00202     }
    00203
    00204     //
    00205     // Since we leave the critical section during the switch, some other
    00206     // thread could come into this routine and request a switch.  The global
    00207     // will be reset, and we will use the loop to perform the next switch.
    00208     //
    00209
    00210     if (idSwitcher != NOSWITCHER) {
    00211         fRedoFullScreenSwitch = TRUE;
    00212         TRACE_SWITCH(("Switching: xxxMakeWindowForeground was posted: Exit\n"));
    00213
    00214         return TRUE;
    00215     }
    00216
    00217     UserAssert(!fRedoFullScreenSwitch);
    00218     idSwitcher = PsGetCurrentThread()->Cid.UniqueThread;
    00219
    00220     /*
    00221      * We loop, switching full screens until all states have stabilized
    00222      */
    00223
    00224     while (TRUE) {
    00225         /*
    00226          * figure out who should be foreground
    00227          */
    00228         fRedoFullScreenSwitch = FALSE;
    00229
    00230         if (gspwndShouldBeForeground != NULL) {
    00231             pwndNewFG = gspwndShouldBeForeground;
    00232             Unlock(&gspwndShouldBeForeground);
    00233         } else {
    00234             if (gpqForeground != NULL &&
    00235                 gpqForeground->spwndActive != NULL) {
    00236
    00237                 pwndNewFG = gpqForeground->spwndActive;
    00238
    00239                 if (GetFullScreen(pwndNewFG) == WINDOWED ||
    00240                     GetFullScreen(pwndNewFG) == FULLSCREENMIN) {
    00241
    00242                     pwndNewFG = PWNDDESKTOP(pwndNewFG);
    00243                 }
    00244             } else {
    00245                 /*
    00246                  * No active window, switch to current desktop
    00247                  */
    00248                 pwndNewFG = grpdeskRitInput->pDeskInfo->spwnd;
    00249             }
    00250         }
    00251
    00252         /*
    00253          * We don't need to switch if the right window is already foreground
    00254          */
    00255         if (pwndNewFG == gspwndFullScreen) {
    00256             break;
    00257         }
    00258
    00259         ThreadLock(pwndNewFG, &tlpwndNewFG);
    00260
    00261         {
    00262             BYTE bStateNew = GetFullScreen(pwndNewFG);
    00263             TL tlpwndOldFG;
    00264             PWND pwndOldFG = gspwndFullScreen;
    00265             BYTE bStateOld = gbFullScreen;
    00266
    00267             ThreadLock(pwndOldFG, &tlpwndOldFG);
    00268
    00269             Lock(&gspwndFullScreen, pwndNewFG);
    00270             gbFullScreen = bStateNew;
    00271
    00272             UserAssert(!HMIsMarkDestroy(gspwndFullScreen));
    00273
    00274             /*
    00275              * If the old screen was GDIFULLSCREEN and we are switching to
    00276              * GDIFULLSCREEN then just repaint
    00277              */
    00278
    00279             /*
    00280              * BUG 231647: For remote sessions it can happen that
    00281              * pwndOldFG is NULL but the display is enabled therefore a
    00282              * call to DrvEnableMDEV would confuse the Drv* code. The way
    00283              * this happens is when gspwndFullScreen was the desktop window
    00284              * of a desktop that got destroyed after we switched away from it.
    00285              */
    00286
    00287             if ((pwndOldFG != NULL || gbRemoteSession) &&
    00288                 bStateOld == GDIFULLSCREEN &&
    00289                 bStateNew == GDIFULLSCREEN) {
    00290
    00291                 xxxRedrawWindow(pwndNewFG, NULL, NULL,
    00292                                 RDW_INVALIDATE | RDW_ALLCHILDREN | RDW_ERASE | RDW_ERASENOW);
    00293
    00294                 ThreadUnlock(&tlpwndOldFG);
    00295
    00296             } else {
    00297
    00298                 /*
    00299                  * tell old 'foreground' window it is losing control of the screen
    00300                  */
    00301                 if (pwndOldFG != NULL) {
    00302                     switch (bStateOld) {
    00303                     case FULLSCREEN:
    00304                         if (GetFullScreen(pwndOldFG) == FULLSCREEN) {
    00305                             SetFullScreen(pwndOldFG, FULLSCREENMIN);
    00306                         }
    00307                         xxxSendMessage(pwndOldFG, WM_FULLSCREEN, FALSE, 0);
    00308                         xxxCapture(GETPTI(pwndOldFG), NULL, FULLSCREEN_CAPTURE);
    00309                         SetVDMCursorBounds(NULL);
    00310                         break;
    00311
    00312                     case GDIFULLSCREEN:
    00313                         /*
    00314                          * Lock out other windows from drawing while we are fullscreen
    00315                          */
    00316                         LockWindowUpdate2(pwndOldFG, TRUE);
    00317                         SET_PUDF(PUDF_LOCKFULLSCREEN);
    00318
    00319                         UserAssert(fGdiEnabled == TRUE);
    00320
    00321                         if (!DrvDisableMDEV(gpDispInfo->pmdev, TRUE)) {
    00322                             /*
    00323                              * Restore the previous state before bailing.
    00324                              */
    00325                             CLEAR_PUDF(PUDF_LOCKFULLSCREEN);
    00326                             LockWindowUpdate2(NULL, TRUE);
    00327
    00328                             Lock(&gspwndFullScreen, pwndOldFG);
    00329                             gbFullScreen = bStateOld;
    00330
    00331                             ThreadUnlock(&tlpwndOldFG);
    00332                             ThreadUnlock(&tlpwndNewFG);
    00333
    00334                             idSwitcher = NOSWITCHER;
    00335
    00336                             return FALSE;
    00337                         }
    00338
    00339                         gptCursorFullScreen = gpsi->ptCursor;
    00340                         fGdiEnabled = FALSE;
    00341                         break;
    00342
    00343                     default:
    00344                         RIPMSG0(RIP_ERROR, "xxxDoFullScreenSwitch: bad screen state");
    00345                         break;
    00346
    00347                     }
    00348                 }
    00349
    00350                 ThreadUnlock(&tlpwndOldFG);
    00351
    00352                 switch (bStateNew) {
    00353                 case FULLSCREEN:
    00354                     xxxCapture(GETPTI(pwndNewFG), pwndNewFG, FULLSCREEN_CAPTURE);
    00355                     xxxSendMessage(pwndNewFG, WM_FULLSCREEN, TRUE, 0);
    00356                     break;
    00357
    00358                 case GDIFULLSCREEN:
    00359                     if (ISTS() && pwndOldFG != NULL) {
    00360                         UserAssert(fGdiEnabled == FALSE);
    00361                     }
    00362
    00363                     DrvEnableMDEV(gpDispInfo->pmdev, TRUE);
    00364                     fGdiEnabled = TRUE;
    00365
    00366                     /*
    00367                      * Return the cursor to it's old state. Reset the screen saver mouse
    00368                      * position or it'll go away by accident.
    00369                      */
    00370                     gpqCursor = NULL;
    00371                     gpcurPhysCurrent = NULL;
    00372                     gpcurLogCurrent = NULL;
    00373                     SetPointer(FALSE);
    00374                     gptSSCursor = gptCursorFullScreen;
    00375
    00376                     /*
    00377                      * No need to DeferWinEventNotify() - we use only globals,
    00378                      * then make an xxx call below.
    00379                      */
    00380                     zzzInternalSetCursorPos(gptCursorFullScreen.x,
    00381                                             gptCursorFullScreen.y
    00382                                            );
    00383
    00384                     CLEAR_PUDF(PUDF_LOCKFULLSCREEN);
    00385                     LockWindowUpdate2(NULL, TRUE);
    00386
    00387                     xxxRedrawWindow(pwndNewFG, NULL, NULL,
    00388                                     RDW_INVALIDATE | RDW_ALLCHILDREN | RDW_ERASE | RDW_ERASENOW);
    00389                     break;
    00390
    00391                 default:
    00392                     RIPMSG0(RIP_ERROR, "xxxDoFullScreenSwitch: bad screen state\n");
    00393                     break;
    00394                 }
    00395             }
    00396         }
    00397
    00398         ThreadUnlock(&tlpwndNewFG);
    00399
    00400         if (!fRedoFullScreenSwitch) {
    00401             break;
    00402         }
    00403     }
    00404
    00405     TRACE_SWITCH(("Switching: xxxMakeWindowForeground: Exit\n"));
    00406
    00407     idSwitcher = NOSWITCHER;
    00408     return TRUE;
    00409 }
    00410
    00411 /***************************************************************************\
    00412 * MonitorFromHdev
    00413 \***************************************************************************/
    00414
    00415 PMONITOR MonitorFromHdev(HANDLE hdev)
    00416 {
    00417     PMONITOR pMonitor;
    00418
    00419     for (pMonitor = gpDispInfo->pMonitorFirst; pMonitor != NULL;
    00420             pMonitor = pMonitor->pMonitorNext) {
    00421         if (pMonitor->hDev == hdev) {
    00422             return pMonitor;
    00423         }
    00424     }
    00425     return NULL;
    00426 }
    00427
    00428 /***************************************************************************\
    00429 * HdevFromMonitor
    00430 \***************************************************************************/
    00431
    00432 ULONG HdevFromMonitor(PMONITOR pMonitor)
    00433 {
    00434     PMDEV pmdev = gpDispInfo->pmdev;
    00435     ULONG i;
    00436
    00437     for (i = 0; i < pmdev->chdev; i++) {
    00438         if (pmdev->Dev[i].hdev == pMonitor->hDev) {
    00439             return i;
    00440         }
    00441     }
    00442     return -1;
    00443 }
    00444
    00445 /***************************************************************************\
    00446 * CreateMonitor
    00447 \***************************************************************************/
    00448
    00449 PMONITOR CreateMonitor(void)
    00450 {
    00451     PMONITOR pMonitor;
    00452
    00453     pMonitor = (PMONITOR)HMAllocObject(NULL, NULL, TYPE_MONITOR, sizeof(MONITOR));
    00454
    00455     if (pMonitor == NULL) {
    00456         RIPERR0(ERROR_NOT_ENOUGH_MEMORY, RIP_WARNING, "CreateMonitor failed");
    00457     }
    00458
    00459     return pMonitor;
    00460 }
    00461
    00462 /***************************************************************************\
    00463 * CreateCachedMonitor
    00464 \***************************************************************************/
    00465
    00466 PMONITOR CreateCachedMonitor(VOID)
    00467 {
    00468     if (gpMonitorCached == NULL) {
    00469         gpMonitorCached = CreateMonitor();
    00470     }
    00471
    00472     return gpMonitorCached;
    00473 }
    00474
    00475 /***************************************************************************\
    00476 * SetMonitorData
    00477 \***************************************************************************/
    00478
    00479 PMONITOR SetMonitorData(PMONITOR pMonitor, ULONG iDev)
    00480 {
    00481     PMDEV pmdev = gpDispInfo->pmdev;
    00482     HDEV hdev = pmdev->Dev[iDev].hdev;
    00483     BOOL fVisible = TRUE;
    00484     BOOL fPrimary = FALSE;
    00485     HDC hdcTmp;
    00486
    00487     UserAssert(iDev < pmdev->chdev);
    00488
    00489     if (hdcTmp = GreCreateDisplayDC(hdev, DCTYPE_DIRECT, FALSE)) {
    00490         if (GreGetDeviceCaps(hdcTmp, CAPS1) & C1_MIRROR_DEVICE) {
    00491             fVisible = FALSE;
    00492         }
    00493         GreDeleteDC(hdcTmp);
    00494     }
    00495
    00496     if (fVisible && (pmdev->Dev[iDev].rect.top == 0) &&
    00497             (pmdev->Dev[iDev].rect.left == 0)) {
    00498         fPrimary = TRUE;
    00499     }
    00500
    00501     if (pMonitor == NULL) {
    00502         if (fPrimary) {
    00503             UserAssert(gpMonitorCached != NULL);
    00504             pMonitor = gpMonitorCached;
    00505             gpMonitorCached = NULL;
    00506         } else {
    00507             pMonitor = CreateMonitor();
    00508         }
    00509     }
    00510
    00511     if (pMonitor == NULL) {
    00512         return NULL;
    00513     }
    00514
    00515     SET_OR_CLEAR_FLAG(pMonitor->dwMONFlags, MONF_VISIBLE, fVisible);
    00516
    00517     /*
    00518      * When the monitor rect is changing, size the work area so the same
    00519      * amount as before is clipped off each edge.
    00520      */
    00521     if (!EqualRect(&pMonitor->rcMonitor, &pmdev->Dev[iDev].rect)) {
    00522         pMonitor->rcWork.left = pmdev->Dev[iDev].rect.left -
    00523                 (pMonitor->rcMonitor.left - pMonitor->rcWork.left);
    00524         pMonitor->rcWork.top = pmdev->Dev[iDev].rect.top -
    00525                 (pMonitor->rcMonitor.top - pMonitor->rcWork.top);
    00526         pMonitor->rcWork.right = pmdev->Dev[iDev].rect.right -
    00527                 (pMonitor->rcMonitor.right - pMonitor->rcWork.right);
    00528         pMonitor->rcWork.bottom = pmdev->Dev[iDev].rect.bottom -
    00529                 (pMonitor->rcMonitor.bottom - pMonitor->rcWork.bottom);
    00530     }
    00531     pMonitor->rcMonitor = pmdev->Dev[iDev].rect;
    00532     pMonitor->hDev = hdev;
    00533
    00534     if (fPrimary) {
    00535         gpDispInfo->pMonitorPrimary = pMonitor;
    00536     }
    00537
    00538     return pMonitor;
    00539 }
    00540
    00541 /***************************************************************************\
    00542 *
    00543 * Is this still TRUE ?
    00544 *
    00545 * When a window becomes FULLSCREEN, it is minimized and
    00546 * treated like any other minimized window.  Whenever the
    00547 * minimized window is restored, by double clicking, menu
    00548 * or keyboard, it remains minimized and the application
    00549 * is given control of the screen device.
    00550 *
    00551 * 12-Dec-1991 mikeke   Created
    00552 \***************************************************************************/
    00553
    00554
    00555 /***************************************************************************\
    00556 * UpdateUserScreen
    00557 *
    00558 * Updates USER information associated with the screen
    00559 *
    00560 * History:
    00561 * 28-Sep-1996 adams     Created.
    00562 \***************************************************************************/
    00563
    00564 BOOL UpdateUserScreen(void)
    00565 {
    00566     PMDEV           pmdev = gpDispInfo->pmdev;
    00567     ULONG           i;
    00568     PMONITOR        pMonitor;
    00569     TEXTMETRIC      tm;
    00570     int             iRgn;
    00571     PWINDOWSTATION  pwinsta;
    00572     PDESKTOP        pdesk;
    00573     HRGN            hrgn;
    00574     BOOL            fPaletteDisplay;
    00575     RECT            rc;
    00576     PMONITOR pMonitorNext = gpDispInfo->pMonitorFirst;
    00577     PMONITOR *ppMonitorLast = &gpDispInfo->pMonitorFirst;
    00578
    00579
    00580     TRACE_INIT(("UpdateUserScreen\n"));
    00581
    00582     UserAssert(gpDispInfo->hdcScreen);
    00583     UserAssert(gpMonitorCached != NULL);
    00584
    00585     /*
    00586      * Keep HMONITOR for the hdev that is the same.  Delete the
    00587      * monitors that weren't found in the new hdev list.
    00588      */
    00589     while (pMonitorNext != NULL) {
    00590         pMonitor = pMonitorNext;
    00591         pMonitorNext = pMonitor->pMonitorNext;
    00592
    00593         if ((i = HdevFromMonitor(pMonitor)) == -1) {
    00594             DestroyMonitor(pMonitor);
    00595         } else {
    00596             SetMonitorData(pMonitor, i);
    00597             ppMonitorLast = &pMonitor->pMonitorNext;
    00598         }
    00599     }
    00600
    00601     /*
    00602      * Create monitors for the hdevs that aren't yet on the monitor list.
    00603      */
    00604     for (i = 0; i < pmdev->chdev; i++) {
    00605         if ((pMonitor = MonitorFromHdev(pmdev->Dev[i].hdev)) == NULL) {
    00606
    00607             /*
    00608              * Try to create a new monitor.
    00609              */
    00610             pMonitor = SetMonitorData(NULL, i);
    00611
    00612             if (pMonitor != NULL) {
    00613                 *ppMonitorLast = pMonitor;
    00614                 ppMonitorLast = &pMonitor->pMonitorNext;
    00615             }
    00616         }
    00617     }
    00618
    00619     UserAssert(gpDispInfo->pMonitorFirst != NULL);
    00620     UserAssert(gpDispInfo->pMonitorPrimary != NULL);
    00621
    00622     /*
    00623      * For now, all monitors have the same display format.
    00624      */
    00625     SYSMET(SAMEDISPLAYFORMAT) = (pmdev->ulFlags & MDEV_MISMATCH_COLORDEPTH) ? FALSE : TRUE;
    00626     fPaletteDisplay = GreGetDeviceCaps(gpDispInfo->hdcScreen, RASTERCAPS) & RC_PALETTE;
    00627     gpDispInfo->fAnyPalette = !!fPaletteDisplay;
    00628
    00629     /*
    00630      * Determine the coordinates of the virtual desktop.
    00631      * Compute cMonitors as the number of visible monitors.
    00632      */
    00633     SetRectEmpty(&rc);
    00634
    00635     gpDispInfo->cMonitors = 0;
    00636     for (pMonitor = gpDispInfo->pMonitorFirst;
    00637         pMonitor;
    00638         pMonitor = pMonitor->pMonitorNext) {
    00639
    00640         /*
    00641          * Only visible monitors contribute to the desktop area
    00642          */
    00643         if (pMonitor->dwMONFlags & MONF_VISIBLE) {
    00644             rc.left = min(rc.left, pMonitor->rcMonitor.left);
    00645             rc.top = min(rc.top, pMonitor->rcMonitor.top);
    00646             rc.right = max(rc.right, pMonitor->rcMonitor.right);
    00647             rc.bottom = max(rc.bottom, pMonitor->rcMonitor.bottom);
    00648
    00649             gpDispInfo->cMonitors++;
    00650         }
    00651
    00652         if (SYSMET(SAMEDISPLAYFORMAT)) {
    00653             SET_OR_CLEAR_FLAG(pMonitor->dwMONFlags, MONF_PALETTEDISPLAY, fPaletteDisplay);
    00654         } else {
    00655             if (GreIsPaletteDisplay(pMonitor->hDev)) {
    00656                 pMonitor->dwMONFlags |= MONF_PALETTEDISPLAY;
    00657                 gpDispInfo->fAnyPalette = TRUE;
    00658             }
    00659         }
    00660     }
    00661     UserAssert(gpDispInfo->pMonitorPrimary != NULL);
    00662     gpDispInfo->rcScreen = rc;
    00663
    00664     /*
    00665      * Update system metrics
    00666      */
    00667     SYSMET(CXSCREEN)        = gpDispInfo->pMonitorPrimary->rcMonitor.right;
    00668     SYSMET(CYSCREEN)        = gpDispInfo->pMonitorPrimary->rcMonitor.bottom;
    00669     SYSMET(XVIRTUALSCREEN)  = gpDispInfo->rcScreen.left;
    00670     SYSMET(YVIRTUALSCREEN)  = gpDispInfo->rcScreen.top;
    00671     SYSMET(CXVIRTUALSCREEN) = gpDispInfo->rcScreen.right - gpDispInfo->rcScreen.left;
    00672     SYSMET(CYVIRTUALSCREEN) = gpDispInfo->rcScreen.bottom - gpDispInfo->rcScreen.top;
    00673     SYSMET(CXMAXTRACK)      = SYSMET(CXVIRTUALSCREEN) + (2 * (SYSMET(CXSIZEFRAME) + SYSMET(CXEDGE)));
    00674     SYSMET(CYMAXTRACK)      = SYSMET(CYVIRTUALSCREEN) + (2 * (SYSMET(CYSIZEFRAME) + SYSMET(CYEDGE)));
    00675     SYSMET(CMONITORS)       = gpDispInfo->cMonitors;
    00676
    00677     /*
    00678      * Bug 281219: flush out the mouse move points if a mode change occured
    00679      */
    00680     RtlZeroMemory(gaptMouse, MAX_MOUSEPOINTS * sizeof(MOUSEMOVEPOINT));
    00681
    00682     SetDesktopMetrics();
    00683
    00684     gpDispInfo->dmLogPixels = (WORD)GreGetDeviceCaps(gpDispInfo->hdcScreen, LOGPIXELSY);
    00685
    00686     UserAssert(gpDispInfo->dmLogPixels != 0);
    00687
    00688     /*
    00689      * Get per-monitor or sum of monitor information, including:
    00690      *     The desktop region.
    00691      *     The region of each monitor.
    00692      *     Min bit counts - Not for NT SP2.
    00693      *     Same color format - Not for NT SP2.
    00694      */
    00695
    00696     SetOrCreateRectRgnIndirectPublic(&gpDispInfo->hrgnScreen, PZERO(RECT));
    00697
    00698     if (gpDispInfo->hrgnScreen) {
    00699
    00700         for (pMonitor = gpDispInfo->pMonitorFirst;
    00701             pMonitor;
    00702             pMonitor = pMonitor->pMonitorNext) {
    00703
    00704             /*
    00705              *  We want to set up hrgnMonitor for all monitors, visible or not
    00706              */
    00707             if (SetOrCreateRectRgnIndirectPublic(&pMonitor->hrgnMonitor,
    00708                                                  &pMonitor->rcMonitor)) {
    00709
    00710                 /*
    00711                  *  But we want only visible monitors to contribute to hrgnScreen
    00712                  */
    00713                 if (pMonitor->dwMONFlags & MONF_VISIBLE) {
    00714                     iRgn = UnionRgn(gpDispInfo->hrgnScreen,
    00715                                     gpDispInfo->hrgnScreen,
    00716                                     pMonitor->hrgnMonitor);
    00717                 }
    00718
    00719             }
    00720         }
    00721
    00722         gpDispInfo->fDesktopIsRect = (iRgn == SIMPLEREGION);
    00723     }
    00724
    00725
    00726     /*
    00727      * Reset the window region of desktop windows.
    00728      */
    00729     hrgn = (gpDispInfo->fDesktopIsRect) ? NULL : gpDispInfo->hrgnScreen;
    00730     for (pwinsta = grpWinStaList; pwinsta; pwinsta = pwinsta->rpwinstaNext) {
    00731         for (pdesk = pwinsta->rpdeskList; pdesk; pdesk = pdesk->rpdeskNext) {
    00732             if (pdesk->pDispInfo == gpDispInfo) {
    00733                 pdesk->pDeskInfo->spwnd->hrgnClip = hrgn;
    00734             }
    00735         }
    00736     }
    00737
    00738     /*
    00739      * Updated information stored in gpsi.
    00740      */
    00741     gpsi->Planes        = (BYTE)GreGetDeviceCaps(gpDispInfo->hdcScreen, PLANES);
    00742     gpsi->BitsPixel     = (BYTE)GreGetDeviceCaps(gpDispInfo->hdcScreen, BITSPIXEL);
    00743     gpsi->BitCount      = gpsi->Planes * gpsi->BitsPixel;
    00744     gpDispInfo->BitCountMax = gpsi->BitCount;
    00745     SET_OR_CLEAR_PUSIF(PUSIF_PALETTEDISPLAY, fPaletteDisplay);
    00746     gpsi->dmLogPixels   = gpDispInfo->dmLogPixels;
    00747     gpsi->rcScreen      = gpDispInfo->rcScreen;
    00748     gpsi->cxSysFontChar = GetCharDimensions(HDCBITS(), &tm, &gpsi->cySysFontChar);
    00749     gpsi->tmSysFont     = tm;
    00750
    00751     EnforceColorDependentSettings();
    00752
    00753 #if DBG
    00754     VerifyVisibleMonitorCount();
    00755 #endif
    00756
    00757     return TRUE;
    00758 }
    00759
    00760
    00761 /**************************************************************************\
    00762 * InitUserScreen
    00763 *
    00764 * Initializes user variables at startup.
    00765 *
    00766 * BUGBUG (adams): This function needs to handle failures.
    00767 * BUGBUG (adams): Where do these variables get inited for
    00768 *     DISPLAYINFOs other than gpDispInfo?
    00769 *
    00770 * 12-Jan-1994 andreva       Created
    00771 * 23-Jan-1995 ChrisWil      ChangeDisplaySettings work.
    00772 \**************************************************************************/
    00773
    00774 BOOL
    00775 InitUserScreen()
    00776 {
    00777     int i;
    00778     TL tlName;
    00779     PUNICODE_STRING pProfileUserName = CreateProfileUserName(&tlName);
    00780     BOOL fSuccess = TRUE;
    00781
    00782     TRACE_INIT(("UserInit: Initialize Screen\n"));
    00783
    00784     /*
    00785      * Create screen and memory dcs.
    00786      */
    00787     gpDispInfo->hdcScreen = GreCreateDisplayDC(gpDispInfo->hDev, DCTYPE_DIRECT, FALSE);
    00788
    00789     if (gpDispInfo->hdcScreen == NULL) {
    00790         RIPMSG0(RIP_WARNING, "Fail to create gpDispInfo->hdcScreen");
    00791         fSuccess = FALSE;
    00792         goto Exit;
    00793     }
    00794
    00795     GreSelectFont(gpDispInfo->hdcScreen, GreGetStockObject(SYSTEM_FONT));
    00796     GreSetDCOwner(gpDispInfo->hdcScreen, OBJECT_OWNER_PUBLIC);
    00797
    00798     HDCBITS() = GreCreateCompatibleDC(gpDispInfo->hdcScreen);
    00799
    00800     if (HDCBITS() == NULL) {
    00801         RIPMSG0(RIP_WARNING, "Fail to create HDCBITS()");
    00802         fSuccess = FALSE;
    00803         goto Exit;
    00804     }
    00805
    00806     GreSelectFont(HDCBITS(), GreGetStockObject(SYSTEM_FONT));
    00807     GreSetDCOwner(HDCBITS(), OBJECT_OWNER_PUBLIC);
    00808
    00809     ghdcMem = GreCreateCompatibleDC(gpDispInfo->hdcScreen);
    00810     fSuccess &= !!ghdcMem;
    00811
    00812     ghdcMem2 = GreCreateCompatibleDC(gpDispInfo->hdcScreen);
    00813     fSuccess &= !!ghdcMem2;
    00814
    00815     if (!fSuccess) {
    00816         RIPMSG0(RIP_WARNING, "Fail to create ghdcMem or ghdcMem2");
    00817         goto Exit;
    00818     }
    00819
    00820     GreSetDCOwner(ghdcMem, OBJECT_OWNER_PUBLIC);
    00821     GreSetDCOwner(ghdcMem2, OBJECT_OWNER_PUBLIC);
    00822
    00823     if (CreateCachedMonitor() == NULL) {
    00824         fSuccess = FALSE;
    00825         goto Exit;
    00826     }
    00827
    00828     if (!UpdateUserScreen()) {
    00829         RIPMSG0(RIP_WARNING, "UpdateUserScreen failed");
    00830         fSuccess = FALSE;
    00831         goto Exit;
    00832     }
    00833
    00834     /*
    00835      * Do some initialization so we create the system colors.
    00836      */
    00837
    00838     /*
    00839      * Set the window sizing border width to something reasonable.
    00840      */
    00841     gpsi->gclBorder = 1;
    00842
    00843     /*
    00844      * Init InternalInvalidate globals
    00845      */
    00846     ghrgnInv0 = CreateEmptyRgnPublic();    // For InternalInvalidate()
    00847     fSuccess &= !!ghrgnInv0;
    00848
    00849     ghrgnInv1 = CreateEmptyRgnPublic();    // For InternalInvalidate()
    00850     fSuccess &= !!ghrgnInv1;
    00851
    00852     ghrgnInv2 = CreateEmptyRgnPublic();    // For InternalInvalidate()
    00853     fSuccess &= !!ghrgnInv2;
    00854
    00855     /*
    00856      * Initialize SPB globals
    00857      */
    00858     ghrgnSPB1 = CreateEmptyRgnPublic();
    00859     fSuccess &= !!ghrgnSPB1;
    00860
    00861     ghrgnSPB2 = CreateEmptyRgnPublic();
    00862     fSuccess &= !!ghrgnSPB2;
    00863
    00864     ghrgnSCR  = CreateEmptyRgnPublic();
    00865     fSuccess &= !!ghrgnSCR;
    00866
    00867     /*
    00868      * Initialize ScrollWindow/ScrollDC globals
    00869      */
    00870     ghrgnSW        = CreateEmptyRgnPublic();
    00871     fSuccess &= !!ghrgnSW;
    00872
    00873     ghrgnScrl1     = CreateEmptyRgnPublic();
    00874     fSuccess &= !!ghrgnScrl1;
    00875
    00876     ghrgnScrl2     = CreateEmptyRgnPublic();
    00877     fSuccess &= !!ghrgnScrl2;
    00878
    00879     ghrgnScrlVis   = CreateEmptyRgnPublic();
    00880     fSuccess &= !!ghrgnScrlVis;
    00881
    00882     ghrgnScrlSrc   = CreateEmptyRgnPublic();
    00883     fSuccess &= !!ghrgnScrlSrc;
    00884
    00885     ghrgnScrlDst   = CreateEmptyRgnPublic();
    00886     fSuccess &= !!ghrgnScrlDst;
    00887
    00888     ghrgnScrlValid = CreateEmptyRgnPublic();
    00889     fSuccess &= !!ghrgnScrlValid;
    00890
    00891     /*
    00892      * Initialize SetWindowPos()
    00893      */
    00894     ghrgnInvalidSum = CreateEmptyRgnPublic();
    00895     fSuccess &= !!ghrgnInvalidSum;
    00896
    00897     ghrgnVisNew     = CreateEmptyRgnPublic();
    00898     fSuccess &= !!ghrgnVisNew;
    00899
    00900     ghrgnSWP1       = CreateEmptyRgnPublic();
    00901     fSuccess &= !!ghrgnSWP1;
    00902
    00903     ghrgnValid      = CreateEmptyRgnPublic();
    00904     fSuccess &= !!ghrgnValid;
    00905
    00906     ghrgnValidSum   = CreateEmptyRgnPublic();
    00907     fSuccess &= !!ghrgnValidSum;
    00908
    00909     ghrgnInvalid    = CreateEmptyRgnPublic();
    00910     fSuccess &= !!ghrgnInvalid;
    00911
    00912     /*
    00913      * Initialize DC cache
    00914      */
    00915     ghrgnGDC = CreateEmptyRgnPublic();
    00916     fSuccess &= !!ghrgnGDC;
    00917
    00918     for (i = 0; i < DCE_SIZE_CACHEINIT; i++) {
    00919         fSuccess &= !!CreateCacheDC(NULL, DCX_INVALID | DCX_CACHE, NULL);
    00920     }
    00921
    00922     if (!fSuccess) {
    00923         RIPMSG0(RIP_WARNING, "CreateCacheDC failed");
    00924         goto Exit;
    00925     }
    00926
    00927     /*
    00928      * Let engine know that the display must be secure.
    00929      */
    00930
    00931     GreMarkDCUnreadable(gpDispInfo->hdcScreen);
    00932
    00933     /*
    00934      * LATER mikeke - if ghfontsys is changed anywhere but here
    00935      * we need to fix SetNCFont()
    00936      */
    00937     ghFontSys = (HFONT)GreGetStockObject(SYSTEM_FONT);
    00938
    00939 #if DBG
    00940     SYSMET(DEBUG) = TRUE;
    00941 #else
    00942     SYSMET(DEBUG) = FALSE;
    00943 #endif
    00944
    00945     SYSMET(CLEANBOOT) = **((PULONG *)&InitSafeBootMode);
    00946
    00947     SYSMET(SLOWMACHINE) = 0;
    00948
    00949     /*
    00950      * Initialize system colors from registry.
    00951      */
    00952     xxxODI_ColorInit(pProfileUserName);
    00953
    00954     /*
    00955      * Paint the screen background.
    00956      */
    00957     FillRect(gpDispInfo->hdcScreen, &gpDispInfo->rcScreen, SYSHBR(DESKTOP));
    00958
    00959     UserAssert(fSuccess);
    00960
    00961 Exit:
    00962     FreeProfileUserName(pProfileUserName, &tlName);
    00963
    00964     return fSuccess;
    00965 }
    00966
    00967
    00968 /***************************************************************************\
    00969 * xxxResetSharedDesktops
    00970 *
    00971 * Resets the attributes for other desktops which share the DISPINFO that
    00972 * was just changed.  We need to resize all visrgns of the other desktops
    00973 * so that clipping is allright.
    00974 *
    00975 * NOTE:  For now, we have to change all the desktop even though we keep
    00976 * track of the devmode on a per desktop basis, because we can switch
    00977 * back to a desktop that has a different resolution and paint it before
    00978 * we can change the resolution again.
    00979 * There is also an issue with CDS_FULLSCREEN where we currently loose track
    00980 * of whether or not the desktop settings need to be reset or not. [andreva]
    00981 *
    00982 * 19-Feb-1996 ChrisWil Created.
    00983 \***************************************************************************/
    00984
    00985 VOID ResetSharedDesktops(
    00986                         PDISPLAYINFO pDIChanged,
    00987                         PDESKTOP     pdeskChanged)
    00988 {
    00989     PWINDOWSTATION pwinsta = _GetProcessWindowStation(NULL);
    00990     PDESKTOP       pdesk;
    00991     HRGN           hrgn;
    00992     POINT          pt;
    00993     PRECT          prc;
    00994     UserAssert(IsWinEventNotifyDeferredOK());
    00995
    00996     /*
    00997      * If this is CSRSS doing the dynamic resolution change then use
    00998      * WinSta0 since the process windowstation is NULL for CSRSS.
    00999      */
    01000     if (gbRemoteSession && pwinsta == NULL && PsGetCurrentProcess() == gpepCSRSS) {
    01001         pwinsta = grpWinStaList;
    01002     }
    01003
    01004     if (pwinsta == NULL) {
    01005
    01006         if (PtiCurrent()->TIF_flags & (TIF_CSRSSTHREAD|TIF_SYSTEMTHREAD))
    01007         {
    01008             pwinsta =  grpdeskRitInput->rpwinstaParent;
    01009         }
    01010         else
    01011         {
    01012             TRACE_SWITCH(("ResetSharedDesktops - NULL window station !\n"));
    01013             return;
    01014         }
    01015     }
    01016
    01017     for (pdesk = pwinsta->rpdeskList; pdesk; pdesk = pdesk->rpdeskNext) {
    01018
    01019         /*
    01020          * Make sure this is a shared DISPINFO.
    01021          */
    01022         if (pdesk->pDispInfo == pDIChanged) {
    01023
    01024 #if 0
    01025             /*
    01026              * This is the preferable method to set the desktop-window.
    01027              * However, this causes synchronization problems where we
    01028              * leave the critical-section allowing other apps to call
    01029              * ChangeDisplaySettings() and thus mucking up the works.
    01030              *
    01031              * By calculating the vis-rgn ourselves, we can assure that
    01032              * the clipping is current for the desktop even when we leave
    01033              * the section.
    01034              */
    01035             {
    01036                 TL tlpwnd;
    01037
    01038                 ThreadLockAlways(pdesk->pDeskInfo->spwnd, &tlpwnd);
    01039                 xxxSetWindowPos(pdesk->pDeskInfo->spwnd,
    01040                                 PWND_TOP,
    01041                                 pDIChanged->rcScreen.left,
    01042                                 pDIChanged->rcScreen.top,
    01043                                 pDIChanged->rcScreen.right - pDIChanged->rcScreen.left,
    01044                                 pDIChanged->rcScreen.bottom - pDIChanged->rcScreen.top,
    01045                                 SWP_NOZORDER | SWP_NOACTIVATE);
    01046                 ThreadUnlock(&tlpwnd);
    01047             }
    01048 #else
    01049             CopyRect(&pdesk->pDeskInfo->spwnd->rcWindow, &pDIChanged->rcScreen);
    01050             CopyRect(&pdesk->pDeskInfo->spwnd->rcClient, &pDIChanged->rcScreen);
    01051 #endif
    01052         }
    01053     }
    01054
    01055     /*
    01056      * Recalc the desktop visrgn.  Since the hdcScreen is shared amoungts
    01057      * all the
    01058      */
    01059     hrgn = CreateEmptyRgn();
    01060     CalcVisRgn(&hrgn,
    01061                pdeskChanged->pDeskInfo->spwnd,
    01062                pdeskChanged->pDeskInfo->spwnd,
    01063                DCX_WINDOW);
    01064
    01065     GreSelectVisRgn(pDIChanged->hdcScreen, hrgn, SVR_DELETEOLD);
    01066
    01067     /*
    01068      * Invalidate all DCE's visrgns.
    01069      */
    01070     zzzInvalidateDCCache(pdeskChanged->pDeskInfo->spwnd, 0);
    01071
    01072     /*
    01073      * Position mouse so that it is within the new visrgn, once we
    01074      * recalc it.
    01075      */
    01076     if (grpdeskRitInput->pDispInfo == pDIChanged) {
    01077         prc = &pDIChanged->pMonitorPrimary->rcMonitor;
    01078         pt.x = (prc->right - prc->left) / 2;
    01079         pt.y = (prc->bottom - prc->top) / 2;
    01080
    01081         /*
    01082          * Remember new mouse pos. Makes sure we don't wake the screensaver.
    01083          */
    01084         gptSSCursor = pt;
    01085         zzzInternalSetCursorPos(pt.x, pt.y);
    01086     }
    01087 }
    01088
    01089 /***************************************************************************\
    01090 * DestroyMonitorDCs
    01091 *
    01092 * 03/03/1998      vadimg      created
    01093 \***************************************************************************/
    01094
    01095 void DestroyMonitorDCs(void)
    01096 {
    01097     PDCE pdce;
    01098     PDCE *ppdce;
    01099
    01100     /*
    01101      * Scan the DC cache to find any monitor DC's that need to be destroyed.
    01102      */
    01103     for (ppdce = &gpDispInfo->pdceFirst; *ppdce != NULL; ) {
    01104
    01105         pdce = *ppdce;
    01106
    01107         if (pdce->pMonitor != NULL) {
    01108             DestroyCacheDC(ppdce, pdce->hdc);
    01109         }
    01110
    01111         /*
    01112          * Step to the next DC.  If the DC was deleted, there
    01113          * is no need to calculate address of the next entry.
    01114          */
    01115         if (pdce == *ppdce)
    01116             ppdce = &pdce->pdceNext;
    01117     }
    01118 }
    01119
    01120 /***************************************************************************\
    01121 * ResetSystemColors
    01122 *
    01123 * Reset all system colors to make sure magic colors are reset and
    01124 * solid system colors are indeed solid after a mode change.
    01125 \***************************************************************************/
    01126
    01127 VOID ResetSystemColors(VOID)
    01128 {
    01129     INT         i;
    01130     INT         colorIndex[COLOR_MAX];
    01131     COLORREF    colorValue[COLOR_MAX];
    01132
    01133     for (i = 0; i < COLOR_MAX; i++) {
    01134         colorIndex[i] = i;
    01135         colorValue[i] = gpsi->argbSystem[i];
    01136     }
    01137
    01138     BEGINATOMICCHECK();
    01139     xxxSetSysColors(NULL, i, colorIndex, colorValue, SSCF_FORCESOLIDCOLOR |
    01140             SSCF_SETMAGICCOLORS);
    01141     ENDATOMICCHECK();
    01142 }
    01143
    01144 /***************************************************************************\
    01145 * xxxResetDisplayDevice
    01146 *
    01147 * Resets the user-globals with the new hdev settings.
    01148 *
    01149 * 19-Feb-1996 ChrisWil Created.
    01150 \***************************************************************************/
    01151
    01152 VOID xxxResetDisplayDevice(
    01153                           PDESKTOP     pdesk,
    01154                           PDISPLAYINFO pDI,
    01155                           DWORD        CDS_Flags)
    01156 {
    01157     WORD            wOldBpp;
    01158     PMONITORRECTS   pmr = NULL;
    01159     TL              tlPool;
    01160     PTHREADINFO     ptiCurrent = PtiCurrent();
    01161
    01162     /*
    01163      * BUGBUG: Correctly update work area for each monitor.
    01164      */
    01165     wOldBpp = gpsi->BitCount;
    01166
    01167     if (!(CDS_Flags & CDS_FULLSCREEN)) {
    01168
    01169         pmr = SnapshotMonitorRects();
    01170
    01171         if (pmr) {
    01172             ThreadLockPool(ptiCurrent, pmr, &tlPool);
    01173         }
    01174     }
    01175
    01176     /*
    01177      * Cleanup any monitor specific DCs we gave out.
    01178      */
    01179     DestroyMonitorDCs();
    01180
    01181     UpdateUserScreen();
    01182     ResetSharedDesktops(pDI, pdesk);
    01183
    01184     ResetSystemColors();
    01185
    01186     if (ghbmCaption) {
    01187         GreDeleteObject(ghbmCaption);
    01188         ghbmCaption = CreateCaptionStrip();
    01189     }
    01190
    01191     zzzClipCursor(&pDI->rcScreen);
    01192
    01193     /*
    01194      * Adjust window positions to fit new resolutions and
    01195      * positions of monitors.
    01196      */
    01197     if (pmr) {
    01198         xxxDesktopRecalc(pmr);
    01199         ThreadUnlockAndFreePool(PtiCurrent(), &tlPool);
    01200     }
    01201
    01202     /*
    01203      * Change the wallpaper metrics.
    01204      * Don't reload the wallpaper when in cleanup since that may
    01205      * go to the client for and we can't do that.
    01206      */
    01207     if (!(ptiCurrent->TIF_flags & TIF_INCLEANUP) && ghbmWallpaper) {
    01208         TL tlName;
    01209         PUNICODE_STRING pProfileUserName = CreateProfileUserName(&tlName);
    01210         xxxSetDeskWallpaper(pProfileUserName, SETWALLPAPER_METRICS);
    01211         FreeProfileUserName(pProfileUserName, &tlName);
    01212     }
    01213
    01214     /*
    01215      * Recreate cached bitmaps.
    01216      */
    01217     CreateBitmapStrip();
    01218
    01219     /*
    01220      * Broadcast that the display has changed resolution.
    01221      * Also broadcast a color-change if we were not in fullscreen, and a
    01222      * color-change took effect.
    01223      */
    01224     if (!(CDS_Flags & CDS_FULLSCREEN) && (gpsi->BitCount != wOldBpp)) {
    01225        xxxBroadcastDisplaySettingsChange(pdesk, TRUE);
    01226
    01227     } else {
    01228        xxxBroadcastDisplaySettingsChange(pdesk, FALSE);
    01229     }
    01230
    01231     /*
    01232      * If the user performed a CTL-ESC, it is possible that the
    01233      * tray-window is then in the menu-loop.  We want to clear this
    01234      * out so that we don't leave improper menu positioning.
    01235      */
    01236     if (gpqForeground && gpqForeground->spwndCapture)
    01237         QueueNotifyMessage(gpqForeground->spwndCapture, WM_CANCELMODE, 0, 0l);
    01238 }
    01239
    01240 /***************************************************************************\
    01241 * TrackFullscreenMode
    01242 *
    01243 * Remember the process going into the fullscreen mode, so that
    01244 * the mode can be restored if the process doesn't clean up upon
    01245 * exit. If some other mode change, clear the global since that
    01246 * means we're definitely out of the fullscreen mode.
    01247 *
    01248 * 1/12/1999        vadimg      created
    01249 \***************************************************************************/
    01250
    01251 VOID TrackFullscreenMode(DWORD dwFlags)
    01252 {
    01253     if (dwFlags & CDS_FULLSCREEN) {
    01254         gppiFullscreen = PtiCurrent()->ppi;
    01255     } else {
    01256         gppiFullscreen = NULL;
    01257     }
    01258 }
    01259
    01260 /***************************************************************************\
    01261 * NtUserChangeDisplaySettings
    01262 *
    01263 * ChangeDisplaySettings API
    01264 *
    01265 * 01-Sep-1995 andreva  Created
    01266 * 19-Feb-1996 ChrisWil Implemented Dynamic-Resolution changes.
    01267 \***************************************************************************/
    01268
    01269
    01270
    01271
    01272 LONG
    01273 xxxUserChangeDisplaySettings(
    01274                             IN PUNICODE_STRING pstrDeviceName,
    01275                             IN LPDEVMODEW      pDevMode,
    01276                             IN HWND            hwnd,
    01277                             IN PDESKTOP        pdesk,
    01278                             IN DWORD           dwFlags,
    01279                             IN PVOID           lParam,
    01280                             IN MODE            PreviousMode)
    01281 {
    01282     BOOL     bSwitchMode;
    01283     PDESKTOP pdesktop;
    01284     LONG     status;
    01285     PMDEV    pmdev;
    01286
    01287     /*
    01288      * BUGBUG: Has lParam been properly captured?
    01289      */
    01290
    01291     lParam;
    01292
    01293     TRACE_INIT(("ChangeDisplaySettings - Entering\n"));
    01294     TRACE_SWITCH(("ChangeDisplaySettings - Entering\n"));
    01295
    01296     TRACE_INIT(("    Flags -"));
    01297
    01298     if (dwFlags & CDS_UPDATEREGISTRY) TRACE_INIT((" CDS_UPDATEREGISTRY - "));
    01299     if (dwFlags & CDS_TEST) TRACE_INIT((" CDS_TEST - "));
    01300     if (dwFlags & CDS_FULLSCREEN) TRACE_INIT((" CDS_FULLSCREEN - "));
    01301     if (dwFlags & CDS_GLOBAL) TRACE_INIT((" CDS_GLOBAL - "));
    01302     if (dwFlags & CDS_SET_PRIMARY) TRACE_INIT((" CDS_SET_PRIMARY - "));
    01303     if (dwFlags & CDS_RESET) TRACE_INIT((" CDS_RESET - "));
    01304     if (dwFlags & CDS_NORESET) TRACE_INIT((" CDS_NORESET - "));
    01305     if (dwFlags & CDS_VIDEOPARAMETERS) TRACE_INIT((" CDS_VIDEOPARAMETERS - "));
    01306     TRACE_INIT(("\n"));
    01307
    01308 #if ((DISP_CHANGE_SUCCESSFUL != GRE_DISP_CHANGE_SUCCESSFUL)  ||  \
    01309      (DISP_CHANGE_RESTART    != GRE_DISP_CHANGE_RESTART)     ||  \
    01310      (DISP_CHANGE_FAILED     != GRE_DISP_CHANGE_FAILED)      ||  \
    01311      (DISP_CHANGE_BADMODE    != GRE_DISP_CHANGE_BADMODE)     ||  \
    01312      (DISP_CHANGE_NOTUPDATED != GRE_DISP_CHANGE_NOTUPDATED)  ||  \
    01313      (DISP_CHANGE_BADFLAGS   != GRE_DISP_CHANGE_BADFLAGS)    ||  \
    01314      (DISP_CHANGE_BADPARAM   != GRE_DISP_CHANGE_BADPARAM))
    01315     #error "inconsistent header files"
    01316 #endif
    01317
    01318     /*
    01319      * Perform Error Checking to verify flag combinations are valid.
    01320      */
    01321     if (dwFlags & (~CDS_VALID)) {
    01322
    01323         //BUGBUG
    01324         //RIPMSG0(RIP_ERROR, "ChangeDisplaySettings: invalid flags specified\n");
    01325         return DISP_CHANGE_BADFLAGS;
    01326     }
    01327
    01328     /*
    01329      * CDS_GLOBAL and CDS_NORESET can only be specified if UPDAREREGISTRY
    01330      * is specified.
    01331      */
    01332
    01333     if ((dwFlags & (CDS_GLOBAL | CDS_NORESET))  &&
    01334         (!(dwFlags & CDS_UPDATEREGISTRY))) {
    01335
    01336         //BUGBUG
    01337         //RIPMSG0(RIP_ERROR, "ChangeDisplaySettings: invalid registry flags specified\n");
    01338         return DISP_CHANGE_BADFLAGS;
    01339     }
    01340
    01341     if ((dwFlags & CDS_NORESET)  &&
    01342         (dwFlags & CDS_RESET)) {
    01343
    01344         //BUGBUG
    01345         //RIPMSG0(RIP_ERROR, "ChangeDisplaySettings: RESET and NORESET can not be put together\n");
    01346         return DISP_CHANGE_BADFLAGS;
    01347     }
    01348
    01349     if ((dwFlags & CDS_EXCLUSIVE) && (dwFlags & CDS_FULLSCREEN) && (dwFlags & CDS_RESET)) {
    01350
    01351         //BUGBUG
    01352         //RIPMSG0(RIP_ERROR, "ChangeDisplaySettings: invalid flags specified\n");
    01353         return DISP_CHANGE_BADFLAGS;
    01354     }
    01355
    01356     if (hwnd) {
    01357         return DISP_CHANGE_BADPARAM;
    01358     }
    01359
    01360     /*
    01361      * For now, don't allow dynamic-resolution changes to occur
    01362      * when GDI is in fullscreen.  We should almost never hit this
    01363      * condition, except for rare stress cases.
    01364      */
    01365
    01366
    01367     /*
    01368      * Allow mode change if this is a CSRSS of a remote
    01369      * session. This means we are changing display settings when
    01370      * reconnecting a session with a diferent resolution.
    01371      */
    01372     if (TEST_PUDF(PUDF_LOCKFULLSCREEN)) {
    01373         if (!(ISCSRSS() && gbRemoteSession)) {
    01374             return DISP_CHANGE_FAILED;
    01375         }
    01376     }
    01377
    01378
    01379     /*
    01380      * If the modeset is being done on a non-active desktop, we don't want
    01381      * it too happen.
    01382      *
    01383      * PtiCurrent()->rpdesk can be NULL !!! (in the case of thread shutdown).
    01384      */
    01385
    01386     if (pdesk) {
    01387         pdesktop = pdesk;
    01388     } else {
    01389         pdesktop = PtiCurrent()->rpdesk;
    01390     }
    01391
    01392     if (pdesktop != grpdeskRitInput) {
    01393         RIPMSG0(RIP_WARNING, "ChangeDisplaySettings on wrong desktop pdesk\n");
    01394         return DISP_CHANGE_FAILED;
    01395     }
    01396
    01397     bSwitchMode = !(dwFlags & (CDS_NORESET | CDS_TEST));
    01398
    01399     /*
    01400      * Turn off cursor and free the spb's prior to calling the mode-change.
    01401      * This will make sure off-screen memory is cleaned up for gdi.
    01402      * while mucking with the resolution changes.
    01403      */
    01404     if (bSwitchMode) {
    01405
    01406         if (CreateCachedMonitor() == NULL) {
    01407             return DISP_CHANGE_FAILED;
    01408         }
    01409
    01410         SetPointer(FALSE);
    01411         FreeAllSpbs();
    01412     }
    01413
    01414     /*
    01415      * Before calling gdi to change the mode, we should kill the fade sprite.  This is
    01416      * so that we won't keep pointers to gdi sprites during the mode change because
    01417      * the sprites could be reallocated.
    01418      */
    01419
    01420     if (gfade.hbm != NULL) {
    01421         StopFade();
    01422     }
    01423
    01424     /*
    01425      * Similarly, we should kill the sprites associated with the drag rect (if any
    01426      * exist) before the mode change.
    01427      */
    01428
    01429     bSetDevDragRect(gpDispInfo->hDev, NULL, NULL);
    01430
    01431     /*
    01432      * Lets capture our parameters.  They are both required.
    01433      *
    01434      * If the input string is not NULL, then we are trying to affect another
    01435      * Device. The device name is the same as for EnumDisplaySettings.
    01436      */
    01437
    01438     status = DrvChangeDisplaySettings(pstrDeviceName,
    01439                                       gpDispInfo->pMonitorPrimary->hDev,
    01440                                       pDevMode,
    01441                                       LongToPtr( pdesktop->dwDesktopId ),
    01442                                       PreviousMode,
    01443                                       (dwFlags & CDS_UPDATEREGISTRY),
    01444                                       bSwitchMode,
    01445                                       gpDispInfo->pmdev,
    01446                                       &pmdev,
    01447                                       (dwFlags & CDS_RAWMODE) ? GRE_RAWMODE : GRE_DEFAULT,
    01448                                       (dwFlags & CDS_TRYCLOSEST));
    01449
    01450
    01451     if (bSwitchMode) {
    01452
    01453         /*
    01454          * If the caller wanted a reset, but the mode is identical, just
    01455          * reset the current mode.
    01456          */
    01457
    01458         if (status == GRE_DISP_CHANGE_NO_CHANGE) {
    01459
    01460             TrackFullscreenMode(dwFlags);
    01461
    01462             if (pmdev != NULL) {
    01463                 GreFreePool(pmdev);
    01464             }
    01465
    01466             if (dwFlags & CDS_RESET) {
    01467
    01468                 if (DrvDisableMDEV(gpDispInfo->pmdev, TRUE)) {
    01469                     DrvEnableMDEV(gpDispInfo->pmdev, TRUE);
    01470                 }
    01471
    01472                 xxxUserResetDisplayDevice();
    01473             }
    01474
    01475             status = DISP_CHANGE_SUCCESSFUL;
    01476
    01477         } else if (status == DISP_CHANGE_SUCCESSFUL) {
    01478
    01479             TrackFullscreenMode(dwFlags);
    01480
    01481             /*
    01482              * ChangeDisplaySettings automatically destroys the old MDEV.
    01483              * We only have to delete it here.
    01484              */
    01485             GreFreePool(gpDispInfo->pmdev);
    01486             gpDispInfo->pmdev = pmdev;
    01487             xxxResetDisplayDevice(pdesktop, gpDispInfo, dwFlags);
    01488
    01489             /*
    01490              * set delayed change indicator for
    01491              * currently background desktops.
    01492              */
    01493             UserSetDelayedChangeBroadcastForAllDesktops(pdesktop);
    01494
    01495         } else if (status < DISP_CHANGE_SUCCESSFUL) {
    01496             UserAssert(pmdev == NULL);
    01497             xxxUserResetDisplayDevice();
    01498         }
    01499
    01500         /*
    01501          * Inline so we can specify which desktop this should happen on.
    01502          * xxxRedrawScreen();
    01503          */
    01504         xxxInternalInvalidate(pdesktop->pDeskInfo->spwnd,
    01505                               HRGN_FULL, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN);
    01506
    01507         /*
    01508          * Bring back the cursor-shape.
    01509          */
    01510         SetPointer(TRUE);
    01511         zzzUpdateCursorImage();
    01512     }
    01513
    01514     /*
    01515      * TV-Out Support
    01516      */
    01517
    01518     if (NT_SUCCESS(status) && (dwFlags & CDS_VIDEOPARAMETERS))
    01519     {
    01520         if (lParam == NULL) {
    01521             status = DISP_CHANGE_BADPARAM;
    01522         } else {
    01523             status = DrvSetVideoParameters(pstrDeviceName,
    01524                                            gpDispInfo->pMonitorPrimary->hDev,
    01525                                            PreviousMode,
    01526                                            lParam);
    01527         }
    01528     }
    01529
    01530     TRACE_INIT(("ChangeDisplaySettings - Leaving, Status = %d\n", status));
    01531
    01532     return status;
    01533 }
    01534
    01535
    01536 /***************************************************************************\
    01537 * xxxbFullscreenSwitch
    01538 *
    01539 * Switch in and out of fullscreen console mode
    01540 *
    01541 * 15-Apr-1997 andreva  Created
    01542 \***************************************************************************/
    01543
    01544 BOOL
    01545 xxxbFullscreenSwitch(
    01546                     BOOL bFullscreenSwitch,
    01547                     HWND hwnd)
    01548 {
    01549
    01550     PWND pwnd;
    01551     TL   tlpwnd;
    01552     BOOL bStat = TRUE;
    01553
    01554     pwnd = ValidateHwnd(hwnd);
    01555
    01556     if (!pwnd) {
    01557         return DISP_CHANGE_BADPARAM;
    01558     }
    01559
    01560     /*
    01561      * Lock the PWND, if it is provided
    01562      */
    01563
    01564     ThreadLock(pwnd, &tlpwnd);
    01565
    01566     /*
    01567      * We don't want our mode switch to be posted on the looping thread.
    01568      * So let's loop until the system has settled down and no mode switch
    01569      * is currently occuring.
    01570      */
    01571
    01572     while (idSwitcher != NOSWITCHER) {
    01573         /*
    01574          * Make sure we aren't blocking anyone who's sending us a message.
    01575          * They can have idSwitcher and never release it because they are
    01576          * waiting on us to process the sent message. And we're waiting on
    01577          * idSwitcher, hence a deadlock.
    01578          */
    01579         xxxSleepThread(0, 1, FALSE);
    01580     }
    01581
    01582     /*
    01583      * If there is a window, we want to check the state of the window.
    01584      * For most calls, we want to ensure we are in windowed mode.
    01585      * However, for Console, we want to make sure we are in fullscreen mode.
    01586      * So differentiate between the two.  We will check if the TEXTMODE
    01587      * flag is passed in the DEVMODE.
    01588      */
    01589
    01590     if (bFullscreenSwitch) {
    01591
    01592         if (GetFullScreen(pwnd) != FULLSCREEN) {
    01593
    01594             xxxShowWindow(pwnd, SW_SHOWMINIMIZED | TEST_PUDF(PUDF_ANIMATE));
    01595
    01596             xxxUpdateWindow(pwnd);
    01597         }
    01598
    01599         if (!xxxMakeWindowForegroundWithState(pwnd, FULLSCREEN)) {
    01600             goto FullscreenSwitchFailed;
    01601         }
    01602
    01603         if ((idSwitcher != NOSWITCHER) ||
    01604             (gbFullScreen != FULLSCREEN)) {
    01605             goto FullscreenSwitchFailed;
    01606         }
    01607
    01608     } else {
    01609
    01610         /*
    01611          * For the console windows, we want to call with WINDOWED
    01612          */
    01613
    01614         if (!xxxMakeWindowForegroundWithState(pwnd, WINDOWED)) {
    01615             goto FullscreenSwitchFailed;
    01616         }
    01617
    01618         if ((idSwitcher != NOSWITCHER) ||
    01619             (gbFullScreen != GDIFULLSCREEN)) {
    01620
    01621             FullscreenSwitchFailed:
    01622             TRACE_INIT(("ChangeDisplaySettings: Can not switch out of fullscreen\n"));
    01623             bStat = FALSE;
    01624         }
    01625     }
    01626
    01627     ThreadUnlock(&tlpwnd);
    01628
    01629     return bStat;
    01630 }
    01631
    01632
    01633 NTSTATUS
    01634 RemoteRedrawRectangle(
    01635     WORD Left,
    01636     WORD Top,
    01637     WORD Right,
    01638     WORD Bottom)
    01639 {
    01640     TL   tlpwnd;
    01641     RECT rcl;
    01642
    01643     CheckCritIn();
    01644
    01645     TRACE_HYDAPI(("RemoteRedrawRectangle\n"));
    01646
    01647     UserAssert(ISCSRSS());
    01648     /*
    01649      * If xxxRemoteStopScreenUpdates has not been called,
    01650      * then just repaint the current foreground window.
    01651      */
    01652     if (gspdeskShouldBeForeground == NULL) {
    01653         if (gspwndFullScreen) {
    01654
    01655             ThreadLock(gspwndFullScreen, &tlpwnd);
    01656
    01657             rcl.left   = Left;
    01658             rcl.top    = Top;
    01659             rcl.right  = Right;
    01660             rcl.bottom = Bottom;
    01661
    01662             vDrvInvalidateRect(gpDispInfo->hDev, &rcl);
    01663
    01664             xxxRedrawWindow(gspwndFullScreen, &rcl, NULL,
    01665                             RDW_INVALIDATE | RDW_ALLCHILDREN |
    01666                             RDW_ERASE | RDW_ERASENOW);
    01667             ThreadUnlock(&tlpwnd);
    01668         }
    01669     }
    01670
    01671     return STATUS_SUCCESS;
    01672 }
    01673
    01674 NTSTATUS
    01675 RemoteRedrawScreen(
    01676     VOID)
    01677 {
    01678     TL             tlpdesk;
    01679     PWINDOWSTATION pwinsta;
    01680     DWORD          dwFlagsPrev;
    01681     PTHREADINFO    ptiCurrent;
    01682
    01683     TRACE_HYDAPI(("RemoteRedrawScreen\n"));
    01684
    01685     CheckCritIn();
    01686
    01687     if (!gbFreezeScreenUpdates)
    01688         return STATUS_SUCCESS;
    01689
    01690     ptiCurrent = PtiCurrentShared();
    01691
    01692     gbFreezeScreenUpdates = FALSE;
    01693
    01694     /*
    01695      * Switch back to the previous desktop
    01696      */
    01697     if (gspdeskShouldBeForeground == NULL) {
    01698         RIPMSG0(RIP_WARNING, "RemoteRedrawScreen called with no gspdeskShouldBeForeground");
    01699         return STATUS_SUCCESS;
    01700     }
    01701
    01702     /*
    01703      * Clear desktop switch lock
    01704      * (WSF_SWITCHLOCK must be clear for xxxSwitchDesktop to succeed)
    01705      */
    01706     gbDesktopLocked = FALSE;
    01707
    01708     pwinsta = gspdeskShouldBeForeground->rpwinstaParent;
    01709
    01710     dwFlagsPrev = pwinsta->dwWSF_Flags;
    01711     pwinsta->dwWSF_Flags &= ~WSF_SWITCHLOCK;
    01712
    01713     /*
    01714      * Switch back to previous desktop
    01715      */
    01716     if (!(gspdeskShouldBeForeground->dwDTFlags & DF_DESTROYED)) {
    01717         ThreadLockDesktop(ptiCurrent, gspdeskShouldBeForeground, &tlpdesk, LDLT_FN_CTXREDRAWSCREEN);
    01718         xxxSwitchDesktop(pwinsta, gspdeskShouldBeForeground, FALSE);
    01719         ThreadUnlockDesktop(ptiCurrent, &tlpdesk, LDUT_FN_CTXREDRAWSCREEN);
    01720
    01721         /*
    01722          * Enable screen updates
    01723          */
    01724         DrvEnableMDEV(gpDispInfo->pmdev, TRUE);
    01725     }
    01726     pwinsta->dwWSF_Flags = dwFlagsPrev;
    01727     LockDesktop(&gspdeskShouldBeForeground, NULL, LDL_DESKSHOULDBEFOREGROUND2, 0 );
    01728
    01729     return STATUS_SUCCESS;
    01730 }
    01731
    01732 NTSTATUS
    01733 RemoteDisableScreen(
    01734     VOID)
    01735 {
    01736     TL             tlpdesk;
    01737     DWORD          dwFlagsPrev;
    01738     PTHREADINFO    ptiCurrent;
    01739     PWINDOWSTATION pwinsta;
    01740     NTSTATUS       Status = STATUS_SUCCESS;
    01741
    01742     CheckCritIn();
    01743
    01744     TRACE_HYDAPI(("RemoteDisableScreen\n"));
    01745
    01746
    01747     ptiCurrent = PtiCurrentShared();
    01748
    01749     if (grpdeskRitInput != gspdeskDisconnect &&
    01750         gspdeskDisconnect != NULL) {
    01751
    01752         pwinsta = gspdeskDisconnect->rpwinstaParent;
    01753
    01754         /*
    01755          * Save current desktop
    01756          */
    01757         UserAssert(grpdeskRitInput == pwinsta->pdeskCurrent);
    01758
    01759         LockDesktop(&gspdeskShouldBeForeground,
    01760                     grpdeskRitInput,
    01761                     LDL_DESKSHOULDBEFOREGROUND3, 0);
    01762
    01763         /*
    01764          * Set desktop switch lock
    01765          * (WSF_SWITCHLOCK must be clear for xxxSwitchDesktop to succeed)
    01766          */
    01767         dwFlagsPrev = pwinsta->dwWSF_Flags;
    01768         pwinsta->dwWSF_Flags &= ~WSF_SWITCHLOCK;
    01769         gbDesktopLocked = TRUE;
    01770
    01771         /*
    01772          * Switch to Disconnected desktop
    01773          */
    01774         ThreadLockDesktop(ptiCurrent, gspdeskDisconnect, &tlpdesk, LDLT_FN_CTXDISABLESCREEN);
    01775         xxxSwitchDesktop(pwinsta, gspdeskDisconnect, FALSE);
    01776         ThreadUnlockDesktop(ptiCurrent, &tlpdesk, LDUT_FN_CTXDISABLESCREEN);
    01777
    01778         pwinsta->dwWSF_Flags = dwFlagsPrev;
    01779
    01780         /*
    01781          * Disable screen updates
    01782          */
    01783         DrvDisableMDEV(gpDispInfo->pmdev, TRUE);
    01784
    01785     } else if (gspdeskDisconnect != NULL) {
    01786         /*
    01787          * For some reason the disconnected desktop was the current desktop.
    01788          * Now prevent switching from it.
    01789          */
    01790         gbDesktopLocked = TRUE;
    01791     }
    01792
    01793     return Status;
    01794 }
    01795
    01796 VOID
    01797 xxxBroadcastDisplaySettingsChange(
    01798     PDESKTOP pdesk,
    01799     BOOL     bBroadcastColorChange)
    01800 {
    01801
    01802     /*
    01803      * Broadcast that the display has changed resolution.  We are going
    01804      * to specify the desktop for the changing-desktop.  That way we
    01805      * don't get confused as to what desktop to broadcast to.
    01806      */
    01807     xxxBroadcastMessage(pdesk->pDeskInfo->spwnd,
    01808                        WM_DISPLAYCHANGE,
    01809                        gpsi->BitCount,
    01810                        MAKELONG(SYSMET(CXSCREEN), SYSMET(CYSCREEN)),
    01811                        BMSG_SENDNOTIFYMSG,
    01812                        NULL);
    01813
    01814     /*
    01815      * Broadcast a color-change if requested to do so.
    01816      */
    01817
    01818     if (bBroadcastColorChange){
    01819 #if 1 // We might want to remove this call, since color-change seems
    01820        // to provide apps the notification.  Need to review
    01821        // chriswil - 06/11/96
    01822
    01823        xxxBroadcastMessage(pdesk->pDeskInfo->spwnd,
    01824                           WM_SETTINGCHANGE,
    01825                           0,
    01826                           0,
    01827                           BMSG_SENDNOTIFYMSG,
    01828                           NULL);
    01829 #endif
    01830
    01831        xxxBroadcastMessage(pdesk->pDeskInfo->spwnd,
    01832                           WM_SYSCOLORCHANGE,
    01833                           0,
    01834                           0,
    01835                           BMSG_SENDNOTIFYMSG,
    01836                           NULL);
    01837     }
    01838
    01839 }