1 ///////////////////////////////////////////////////////////////////////////// 
   3 // Purpose:     Mac implementation of wxDisplay class 
   4 // Author:      Ryan Norton & Brian Victor 
   5 // Modified by: Royce Mitchell III  
   8 // Copyright:   (c) wxWidgets team 
   9 // Licence:     wxWindows licence 
  10 ///////////////////////////////////////////////////////////////////////////// 
  12 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA) 
  13     #pragma implementation "display.h" 
  16 // For compilers that support precompilation, includes "wx.h". 
  17 #include "wx/wxprec.h" 
  26    #include "wx/dynarray.h" 
  28    #include "wx/msgdlg.h" 
  32     #include <Carbon/Carbon.h> 
  36     #include <Quickdraw.h> 
  37     #include <Video.h>  //for VDSwitchInfoRec 
  41 #include "wx/display.h" 
  42 #include "wx/gdicmn.h" 
  43 #include "wx/string.h" 
  45 // ---------------------------------------------------------------------------- 
  47 // ---------------------------------------------------------------------------- 
  51 class wxDisplayMacPriv
 
  54     CGDirectDisplayID m_id
; 
  57 size_t wxDisplayBase::GetCount() 
  63     CGGetActiveDisplayList(0, NULL
, &count
); 
  65     wxASSERT(err 
== CGDisplayNoErr
); 
  69 int wxDisplayBase::GetFromPoint(const wxPoint 
&p
) 
  71     CGPoint thePoint 
= {(float)p
.x
, (float)p
.y
}; 
  72     CGDirectDisplayID theID
; 
  73     CGDisplayCount theCount
; 
  74     CGDisplayErr err 
= CGGetDisplaysWithPoint(thePoint
, 1, &theID
, &theCount
); 
  75     wxASSERT(err 
== CGDisplayNoErr
); 
  80         theCount 
= GetCount(); 
  81         CGDirectDisplayID
* theIDs 
= new CGDirectDisplayID
[theCount
]; 
  82         err 
= CGGetActiveDisplayList(theCount
, theIDs
, &theCount
); 
  83         wxASSERT(err 
== CGDisplayNoErr
); 
  85         for(nWhich 
= 0; nWhich 
< (int) theCount
; ++nWhich
) 
  87             if(theIDs
[nWhich
] == theID
) 
  93         if(nWhich 
== (int) theCount
) 
  95             wxFAIL_MSG(wxT("Failed to find display in display list")); 
 101 }//CFUserNotification[NSBundle bundleForClass:[self class]] 
 103 wxDisplay::wxDisplay(size_t index
) : wxDisplayBase ( index 
) , 
 104     m_priv ( new wxDisplayMacPriv() ) 
 106     CGDisplayCount theCount 
= GetCount(); 
 107     CGDirectDisplayID
* theIDs 
= new CGDirectDisplayID
[theCount
]; 
 111     CGGetActiveDisplayList(theCount
, theIDs
, &theCount
); 
 113     wxASSERT(err 
== CGDisplayNoErr
); 
 114     wxASSERT(index 
< theCount
); 
 116     m_priv
->m_id 
= theIDs
[index
]; 
 121 wxRect 
wxDisplay::GetGeometry() const 
 123     CGRect theRect 
= CGDisplayBounds(m_priv
->m_id
); 
 124     return wxRect(      (int)theRect
.origin
.x
, 
 125                     (int)theRect
.origin
.y
, 
 126                     (int)theRect
.size
.width
, 
 127                     (int)theRect
.size
.height  
); //floats 
 130 int wxDisplay::GetDepth() const 
 132     return (int) CGDisplayBitsPerPixel(m_priv
->m_id
); //size_t 
 135 wxString 
wxDisplay::GetName() const 
 137     // Macs don't name their displays... 
 138     return wxEmptyString
; 
 141 static int wxCFDictKeyToInt( CFDictionaryRef desc
, CFStringRef key 
) 
 146     if ( (value 
= (CFNumberRef
) CFDictionaryGetValue(desc
, key
)) == NULL 
) 
 148     CFNumberGetValue(value
, kCFNumberIntType
, &num
); 
 153     wxDisplay::GetModes(const wxVideoMode
& mode
) const 
 155     wxArrayVideoModes Modes
; 
 157     CFArrayRef theArray 
= CGDisplayAvailableModes(m_priv
->m_id
); 
 159     for(CFIndex i 
= 0; i 
< CFArrayGetCount(theArray
); ++i
) 
 161         CFDictionaryRef theValue 
= (CFDictionaryRef
) CFArrayGetValueAtIndex(theArray
, i
); 
 163         wxVideoMode 
theMode(wxCFDictKeyToInt(theValue
, kCGDisplayWidth
), 
 164                             wxCFDictKeyToInt(theValue
, kCGDisplayHeight
), 
 165                             wxCFDictKeyToInt(theValue
, kCGDisplayBitsPerPixel
), 
 166                             wxCFDictKeyToInt(theValue
, kCGDisplayRefreshRate
)); 
 168         if (theMode
.Matches(mode
)) 
 175 wxVideoMode 
wxDisplay::GetCurrentMode() const 
 177     CFDictionaryRef theValue 
= CGDisplayCurrentMode (m_priv
->m_id
); 
 179     return wxVideoMode(wxCFDictKeyToInt(theValue
, kCGDisplayWidth
), 
 180                             wxCFDictKeyToInt(theValue
, kCGDisplayHeight
), 
 181                             wxCFDictKeyToInt(theValue
, kCGDisplayBitsPerPixel
), 
 182                             wxCFDictKeyToInt(theValue
, kCGDisplayRefreshRate
)); 
 185 bool wxDisplay::ChangeMode(const wxVideoMode
& mode
) 
 187     //Changing to default mode (wxDefualtVideoMode) doesn't 
 188     //work because we don't have access to the system's 'scrn' 
 189     //resource which holds the user's mode which the system 
 190     //will return to after this app is done 
 191     boolean_t bExactMatch
; 
 192     CFDictionaryRef theCGMode 
= CGDisplayBestModeForParametersAndRefreshRate ( 
 197                                         (double)mode
.refresh
, 
 200     bool bOK 
= bExactMatch
; 
 203         bOK 
= CGDisplaySwitchToMode(m_priv
->m_id
, theCGMode
) == CGDisplayNoErr
; 
 208 wxDisplay::~wxDisplay() 
 219 class wxDisplayMacPriv
 
 225 size_t wxDisplayBase::GetCount() 
 229     hndl 
= DMGetFirstScreenDevice(true); 
 233         hndl 
= DMGetNextScreenDevice(hndl
, true); 
 238 int wxDisplayBase::GetFromPoint(const wxPoint 
&p
) 
 242     hndl 
= DMGetFirstScreenDevice(true); 
 245         Rect screenrect 
= (*hndl
)->gdRect
; 
 246         if (p
.x 
>= screenrect
.left 
&& 
 247             p
.x 
<= screenrect
.right 
&& 
 248             p
.y 
>= screenrect
.top 
&& 
 249             p
.y 
<= screenrect
.bottom
) 
 254         hndl 
= DMGetNextScreenDevice(hndl
, true); 
 259 wxDisplay::wxDisplay(size_t index
) : wxDisplayBase ( index 
), 
 260     m_priv ( new wxDisplayMacPriv() ) 
 263     hndl 
= DMGetFirstScreenDevice(true); 
 264     m_priv
->m_hndl 
= NULL
; 
 269             m_priv
->m_hndl 
= hndl
; 
 272         hndl 
= DMGetNextScreenDevice(hndl
, true); 
 276 wxRect 
wxDisplay::GetGeometry() const 
 278     if (!(m_priv
)) return wxRect(0, 0, 0, 0); 
 279     if (!(m_priv
->m_hndl
)) return wxRect(0, 0, 0, 0); 
 280     Rect screenrect 
= (*(m_priv
->m_hndl
))->gdRect
; 
 281     return wxRect( screenrect
.left
, screenrect
.top
,  
 282                    screenrect
.right 
- screenrect
.left
, screenrect
.bottom 
- screenrect
.top
); 
 285 int wxDisplay::GetDepth() const 
 287     if (!(m_priv
)) return 0; 
 288     if (!(m_priv
->m_hndl
)) return 0; 
 290     // This cryptic looking code is based on Apple's sample code: 
 291     // http://developer.apple.com/samplecode/Sample_Code/Graphics_2D/GDevVideo/Gen.cp.htm 
 293     //RN - according to the docs 
 294         //gdPMap is a bitmap-type representation of the GDevice, and all 
 295         //0x0000FFFF does is get the lower 16 bits of pixelSize.  However, 
 296         //since pixelSize is only 16 bits (a short)... 
 297     return ((*(*(m_priv
->m_hndl
))->gdPMap
)->pixelSize
) & 0x0000FFFF; 
 300 wxString 
wxDisplay::GetName() const 
 302     // Macs don't name their displays... 
 303     return wxEmptyString
; 
 306 struct DMModeIteratorRec
 
 308         wxArrayVideoModes
* pModes
; 
 309         const wxVideoMode
* pMatchMode
; 
 312 pascal void DMModeListIteratorProc (    void* pData
, 
 313                               DMListIndexType nIndex
, 
 314                               DMDisplayModeListEntryPtr pInfo
) 
 316     DMModeIteratorRec
* pInfoData 
= (DMModeIteratorRec
*) pData
; 
 318         //Note that in testing the refresh rate is always 0 on my ibook - RN 
 319     int refresh 
= (int) Fix2Long(pInfo
->displayModeResolutionInfo
->csRefreshRate
); 
 321         for(unsigned long i 
= 0; i 
< pInfo
->displayModeDepthBlockInfo
->depthBlockCount
; ++i
) 
 323 #define pDBI pInfo->displayModeDepthBlockInfo->depthVPBlock[i].depthVPBlock 
 325                 if (wxVideoMode((int) pInfo
->displayModeResolutionInfo
->csHorizontalPixels
, 
 326                                   (int) pInfo
->displayModeResolutionInfo
->csVerticalLines
, 
 327                                   (int) pDBI
->vpPixelSize
, 
 328                                   refresh
).Matches(*pInfoData
->pMatchMode
) ) 
 330                         pInfoData
->pModes
->Add(wxVideoMode((int) pInfo
->displayModeResolutionInfo
->csHorizontalPixels
, 
 331                                                    (int) pInfo
->displayModeResolutionInfo
->csVerticalLines
, 
 332                                                    (int) pDBI
->vpPixelSize
, 
 341         const wxVideoMode
* pMode
; 
 342         VDSwitchInfoRec sMode
; 
 346 pascal void DMModeInfoProc (    void* pData
, 
 347                                                           DMListIndexType nIndex
, 
 348                                                           DMDisplayModeListEntryPtr pInfo
) 
 350         DMModeInfoRec
* pInfoData 
= (DMModeInfoRec
*) pData
; 
 351         Fixed refresh 
= Long2Fix(pInfoData
->pMode
->refresh
); 
 353         for(unsigned long i 
= 0; i 
< pInfo
->displayModeDepthBlockInfo
->depthBlockCount
; ++i
) 
 355 #define pDBI pInfo->displayModeDepthBlockInfo->depthVPBlock[i].depthVPBlock 
 356                     if (pInfoData
->pMode
->w 
== (int&) pInfo
->displayModeResolutionInfo
->csHorizontalPixels 
&& 
 357                         pInfoData
->pMode
->h 
== (int&) pInfo
->displayModeResolutionInfo
->csVerticalLines 
&& 
 358                         pInfoData
->pMode
->bpp 
== (int) pDBI
->vpPixelSize 
&& 
 359                         refresh 
== pInfo
->displayModeResolutionInfo
->csRefreshRate
) 
 361                                 memcpy(&pInfoData
->sMode
, pInfo
->displayModeDepthBlockInfo
->depthVPBlock
[i
].depthSwitchInfo
, 
 362                                        sizeof(VDSwitchInfoRec
)); 
 363                                 pInfoData
->sMode
.csMode 
= pDBI
->vpPixelSize
; 
 364                                 pInfoData
->bMatched 
= true; 
 371 struct DMModeTransRec
 
 374         const VDSwitchInfoRec
* psMode
; 
 378 pascal void DMModeTransProc (   void* pData
, 
 379                                           DMListIndexType nIndex
, 
 380                                           DMDisplayModeListEntryPtr pInfo
) 
 382         DMModeTransRec
* pInfoData 
= (DMModeTransRec
*) pData
; 
 384         for(unsigned long i 
= 0; i 
< pInfo
->displayModeDepthBlockInfo
->depthBlockCount
; ++i
) 
 386 #define pDBI pInfo->displayModeDepthBlockInfo->depthVPBlock[i].depthVPBlock 
 387                 if (pInfoData
->psMode
->csData 
== pInfo
->displayModeDepthBlockInfo
->depthVPBlock
[i
].depthSwitchInfo
->csData
) 
 389                         pInfoData
->Mode 
= wxVideoMode((int) pInfo
->displayModeResolutionInfo
->csHorizontalPixels
, 
 390                                                                  (int) pInfo
->displayModeResolutionInfo
->csVerticalLines
, 
 391                                                                  (int) pDBI
->vpPixelSize
, 
 392                                                                  (int) Fix2Long(pInfo
->displayModeResolutionInfo
->csRefreshRate
) ); 
 393                         pInfoData
->bMatched 
= true; 
 401     wxDisplay::GetModes(const wxVideoMode
& mode
) const 
 404     wxArrayVideoModes Modes
; 
 406     unsigned long dwDMVer
; 
 407     Gestalt(gestaltDisplayMgrVers
, (long*) &dwDMVer
); 
 409     //Check DM version (for backward compatibility only - 7.5.3+ use 2.0) 
 410     if (dwDMVer 
>= 0x020000) //version 2? 
 413         DMListIndexType nNumModes
; 
 415         DMDisplayModeListIteratorUPP uppMLI
; 
 416         DisplayIDType nDisplayID
; 
 419         err 
= DMGetDisplayIDByGDevice(m_priv
->m_hndl
, &nDisplayID
, false); 
 420         wxASSERT(err 
== noErr
);  
 422         //Create a new list... 
 423         err 
= DMNewDisplayModeList(nDisplayID
, NULL
, NULL
, &nNumModes
, &pModes
); 
 424         wxASSERT_MSG(err 
== noErr
, wxT("Could not create a new display mode list") ); 
 426         uppMLI 
= NewDMDisplayModeListIteratorUPP(DMModeListIteratorProc
); 
 429         DMModeIteratorRec sModeInfo
; 
 430         sModeInfo
.pModes 
= &Modes
; 
 431         sModeInfo
.pMatchMode 
= &mode
; 
 432         for (DMListIndexType i 
= 0; i 
< nNumModes
; ++i
) 
 434             err 
= DMGetIndexedDisplayModeFromList(pModes
, i
, NULL
, uppMLI
, &sModeInfo
); 
 435             wxASSERT(err 
== noErr
); 
 437         DisposeDMDisplayModeListIteratorUPP(uppMLI
); 
 439         err 
= DMDisposeList(pModes
); 
 440         wxASSERT(err 
== noErr
);  
 442     else //DM 1.0, 1.2, 1.x 
 444         wxLogSysError(wxString::Format(wxT("Display Manager Version %u Not Supported!  Present? %s"), 
 445                                 (unsigned int) dwDMVer 
/ 0x10000, 
 446                                 (dwDMVer 
& (1 << gestaltDisplayMgrPresent
) ? wxT("Yes") : wxT("No"))  ) 
 453 wxVideoMode 
wxDisplay::GetCurrentMode() const 
 455     unsigned long dwDMVer
; 
 458     Gestalt(gestaltDisplayMgrVers
, (long*) &dwDMVer
);     
 459     //Check DM version (for backward compatibility only - 7.5.3+ use 2.0) 
 460     if (dwDMVer 
>= 0x020000) //version 2? 
 462         VDSwitchInfoRec sMode
; //Note - csMode member also contains the bit depth 
 463         if (DMGetDisplayMode(m_priv
->m_hndl
, &sMode
) == noErr
)  
 465             DMListIndexType nNumModes
; 
 467                 DMDisplayModeListIteratorUPP uppMLI
; 
 468             DisplayIDType nDisplayID
; 
 471             err 
= DMGetDisplayIDByGDevice(m_priv
->m_hndl
, &nDisplayID
, false); 
 472             wxASSERT(err 
== noErr
); 
 474             //Create a new list... 
 475             err 
= DMNewDisplayModeList(nDisplayID
, NULL
, NULL
, &nNumModes
, &pModes
); 
 476             wxASSERT_MSG(err 
== noErr
, wxT("Could not create a new display mode list") ); 
 478                 uppMLI 
= NewDMDisplayModeListIteratorUPP(DMModeTransProc
); 
 481                 DMModeTransRec sModeInfo
; 
 482                 sModeInfo
.bMatched 
= false; 
 483                 sModeInfo
.psMode 
= &sMode
; 
 484                 for (DMListIndexType i 
= 0; i 
< nNumModes
; ++i
) 
 486                 err 
= DMGetIndexedDisplayModeFromList(pModes
, i
, NULL
, uppMLI
, &sModeInfo
); 
 487                         wxASSERT(err 
== noErr
); 
 489                         if ( sModeInfo
.bMatched 
== true ) 
 491                                 RetMode 
= sModeInfo
.Mode
; 
 496             DisposeDMDisplayModeListIteratorUPP(uppMLI
); 
 498             err 
= DMDisposeList(pModes
); 
 499             wxASSERT(err 
== noErr
); 
 501         else //Can't get current mode? 
 503                 wxLogSysError(wxString::Format(wxT("Couldn't obtain current display mode!!!\ndwDMVer:%u"), 
 504                                                                 (unsigned int) dwDMVer
)); 
 509         wxLogSysError(wxString::Format(wxT("Display Manager Version %u Not Supported!  Present? %s"), 
 510                                 (unsigned int) dwDMVer 
/ 0x10000, 
 511                                 (dwDMVer 
& (1 << gestaltDisplayMgrPresent
) ? wxT("Yes") : wxT("No")) ) 
 518 bool wxDisplay::ChangeMode(const wxVideoMode
& mode
) 
 520     unsigned long dwDMVer
; 
 521     Gestalt(gestaltDisplayMgrVers
, (long*)&dwDMVer
); 
 522     if (GetCount() == 1 || dwDMVer 
>= 0x020000) 
 524                 if (mode 
== wxDefaultVideoMode
) 
 527 //                      Handle hDisplayState; 
 528 //                      if (DMBeginConfigureDisplays(&hDisplayState) != noErr) 
 530 //                              wxLogSysError(wxT("Could not lock display for display mode changing!")); 
 533 //                      wxASSERT( DMUseScreenPrefs(true, hDisplayState) == noErr); 
 534 //                      DMEndConfigureDisplays(hDisplayState); 
 542         //0 & NULL for params 2 & 3 of DMSetVideoMode signal it to use defaults (current mode) 
 543         //DM 2.0+ doesn't use params 2 & 3 of DMSetDisplayMode 
 544         //so we have to use this icky structure 
 545         VDSwitchInfoRec sMode
; 
 546         memset(&sMode
, 0, sizeof(VDSwitchInfoRec
) ); 
 548         DMListIndexType nNumModes
; 
 550         DMDisplayModeListIteratorUPP uppMLI
; 
 551         DisplayIDType nDisplayID
; 
 554         err 
= DMGetDisplayIDByGDevice(m_priv
->m_hndl
, &nDisplayID
, false); 
 555         wxASSERT(err 
== noErr
); 
 557         //Create a new list... 
 558         err 
= DMNewDisplayModeList(nDisplayID
, NULL
, NULL
, &nNumModes
, &pModes
); 
 559         wxASSERT_MSG(err 
== noErr
, wxT("Could not create a new display mode list") ); 
 561         uppMLI 
= NewDMDisplayModeListIteratorUPP(DMModeInfoProc
); 
 564         DMModeInfoRec sModeInfo
; 
 565         sModeInfo
.bMatched 
= false; 
 566         sModeInfo
.pMode 
= &mode
; 
 568         for(i 
= 0; i 
< nNumModes
; ++i
) 
 570             err 
= DMGetIndexedDisplayModeFromList(pModes
, i
, NULL
, uppMLI
, &sModeInfo
); 
 571                 wxASSERT(err 
== noErr
); 
 573                 if (sModeInfo
.bMatched 
== true) 
 575                         sMode 
= sModeInfo
.sMode
; 
 582         DisposeDMDisplayModeListIteratorUPP(uppMLI
); 
 584         err 
= DMDisposeList(pModes
); 
 585         wxASSERT(err 
== noErr
); 
 587         // For the really paranoid - 
 588         //          unsigned long flags; 
 590         //     wxASSERT(noErr == DMCheckDisplayMode(m_priv->m_hndl, sMode.csData, 
 591         //                                                                sMode.csMode, &flags, NULL, &bok)); 
 594         Handle hDisplayState
; 
 595         if (DMBeginConfigureDisplays(&hDisplayState
) != noErr
) 
 597             wxLogSysError(wxT("Could not lock display for display mode changing!")); 
 601         unsigned long dwBPP 
= (unsigned long) mode
.bpp
; 
 602         if (DMSetDisplayMode(m_priv
->m_hndl
, sMode
.csData
, 
 603                                             (unsigned long*) &(dwBPP
), NULL
 
 604                                            //(unsigned long) &sMode 
 608                 DMEndConfigureDisplays(hDisplayState
); 
 609                 wxMessageBox(wxString::Format(wxT("Could not set the display mode"))); 
 612         DMEndConfigureDisplays(hDisplayState
); 
 614     else  //DM 1.0, 1.2, 1.x 
 616         wxLogSysError(wxString::Format(wxT("Monitor gravitation not supported yet.  dwDMVer:%u"), 
 617                                 (unsigned int) dwDMVer
)); 
 624 wxDisplay::~wxDisplay() 
 635 #endif // wxUSE_DISPLAY