1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/mac/carbon/display.cpp 
   3 // Purpose:     Mac implementation of wxDisplay class 
   4 // Author:      Ryan Norton & Brian Victor 
   5 // Modified by: Royce Mitchell III, Vadim Zeitlin 
   8 // Copyright:   (c) wxWidgets team 
   9 // Licence:     wxWindows licence 
  10 ///////////////////////////////////////////////////////////////////////////// 
  12 // ============================================================================ 
  14 // ============================================================================ 
  16 // ---------------------------------------------------------------------------- 
  18 // ---------------------------------------------------------------------------- 
  20 #include "wx/wxprec.h" 
  28 #include "wx/display.h" 
  31     #include "wx/dynarray.h" 
  33     #include "wx/string.h" 
  34     #include "wx/gdicmn.h" 
  38     #include <Carbon/Carbon.h> 
  42     #include <Quickdraw.h> 
  43     #include <Video.h>  // for VDSwitchInfoRec 
  45     #include <Debugging.h> 
  48 #include "wx/display_impl.h" 
  50 // ---------------------------------------------------------------------------- 
  51 // display classes implementation 
  52 // ---------------------------------------------------------------------------- 
  56 class wxDisplayImplMacOSX 
: public wxDisplayImpl
 
  59     wxDisplayImplMacOSX(unsigned n
, CGDirectDisplayID id
) 
  65     virtual wxRect 
GetGeometry() const; 
  66     virtual wxRect 
GetClientArea() const; 
  67     virtual wxString 
GetName() const { return wxString(); } 
  69     virtual wxArrayVideoModes 
GetModes(const wxVideoMode
& mode
) const; 
  70     virtual wxVideoMode 
GetCurrentMode() const; 
  71     virtual bool ChangeMode(const wxVideoMode
& mode
); 
  74     CGDirectDisplayID m_id
; 
  76     DECLARE_NO_COPY_CLASS(wxDisplayImplMacOSX
) 
  79 class wxDisplayFactoryMacOSX 
: public wxDisplayFactory
 
  82     wxDisplayFactoryMacOSX() {} 
  84     virtual wxDisplayImpl 
*CreateDisplay(unsigned n
); 
  85     virtual unsigned GetCount(); 
  86     virtual int GetFromPoint(const wxPoint
& pt
); 
  89     DECLARE_NO_COPY_CLASS(wxDisplayFactoryMacOSX
) 
  92 // ============================================================================ 
  93 // wxDisplayFactoryMacOSX implementation 
  94 // ============================================================================ 
  96 unsigned wxDisplayFactoryMacOSX::GetCount() 
 102     CGGetActiveDisplayList(0, NULL
, &count
); 
 104     wxASSERT(err 
== CGDisplayNoErr
); 
 109 int wxDisplayFactoryMacOSX::GetFromPoint(const wxPoint
& p
) 
 111     CGPoint thePoint 
= {(float)p
.x
, (float)p
.y
}; 
 112     CGDirectDisplayID theID
; 
 113     CGDisplayCount theCount
; 
 114     CGDisplayErr err 
= CGGetDisplaysWithPoint(thePoint
, 1, &theID
, &theCount
); 
 115     wxASSERT(err 
== CGDisplayNoErr
); 
 117     int nWhich 
= wxNOT_FOUND
; 
 121         theCount 
= GetCount(); 
 122         CGDirectDisplayID
* theIDs 
= new CGDirectDisplayID
[theCount
]; 
 123         err 
= CGGetActiveDisplayList(theCount
, theIDs
, &theCount
); 
 124         wxASSERT(err 
== CGDisplayNoErr
); 
 126         for (nWhich 
= 0; nWhich 
< (int) theCount
; ++nWhich
) 
 128             if (theIDs
[nWhich
] == theID
) 
 134         if (nWhich 
== (int) theCount
) 
 136             wxFAIL_MSG(wxT("Failed to find display in display list")); 
 137             nWhich 
= wxNOT_FOUND
; 
 144 wxDisplayImpl 
*wxDisplayFactoryMacOSX::CreateDisplay(unsigned n
) 
 146     CGDisplayCount theCount 
= GetCount(); 
 147     CGDirectDisplayID
* theIDs 
= new CGDirectDisplayID
[theCount
]; 
 152     CGGetActiveDisplayList(theCount
, theIDs
, &theCount
); 
 154     wxASSERT( err 
== CGDisplayNoErr 
); 
 155     wxASSERT( n 
< theCount 
); 
 157     wxDisplayImplMacOSX 
*display 
= new wxDisplayImplMacOSX(n
, theIDs
[n
]); 
 164 // ============================================================================ 
 165 // wxDisplayImplMacOSX implementation 
 166 // ============================================================================ 
 168 wxRect 
wxDisplayImplMacOSX::GetGeometry() const 
 170     CGRect theRect 
= CGDisplayBounds(m_id
); 
 171     return wxRect( (int)theRect
.origin
.x
, 
 172                    (int)theRect
.origin
.y
, 
 173                    (int)theRect
.size
.width
, 
 174                    (int)theRect
.size
.height 
); //floats 
 177 wxRect 
wxDisplayImplMacOSX::GetClientArea() const 
 179     // VZ: I don't know how to get client area for arbitrary display but 
 180     //     wxGetClientDisplayRect() does work correctly for at least the main 
 181     //     one (TODO: do it correctly for the other displays too) 
 183         return wxGetClientDisplayRect(); 
 185     return wxDisplayImpl::GetClientArea(); 
 188 static int wxCFDictKeyToInt( CFDictionaryRef desc
, CFStringRef key 
) 
 190     CFNumberRef value 
= (CFNumberRef
) CFDictionaryGetValue( desc
, key 
); 
 195     CFNumberGetValue( value
, kCFNumberIntType
, &num 
); 
 200 wxArrayVideoModes 
wxDisplayImplMacOSX::GetModes(const wxVideoMode
& mode
) const 
 202     wxArrayVideoModes resultModes
; 
 204     CFArrayRef theArray 
= CGDisplayAvailableModes( m_id 
); 
 206     for (CFIndex i 
= 0; i 
< CFArrayGetCount(theArray
); ++i
) 
 208         CFDictionaryRef theValue 
= (CFDictionaryRef
) CFArrayGetValueAtIndex( theArray
, i 
); 
 211             wxCFDictKeyToInt( theValue
, kCGDisplayWidth 
), 
 212             wxCFDictKeyToInt( theValue
, kCGDisplayHeight 
), 
 213             wxCFDictKeyToInt( theValue
, kCGDisplayBitsPerPixel 
), 
 214             wxCFDictKeyToInt( theValue
, kCGDisplayRefreshRate 
)); 
 216         if (theMode
.Matches( mode 
)) 
 217             resultModes
.Add( theMode 
); 
 223 wxVideoMode 
wxDisplayImplMacOSX::GetCurrentMode() const 
 225     CFDictionaryRef theValue 
= CGDisplayCurrentMode( m_id 
); 
 228         wxCFDictKeyToInt( theValue
, kCGDisplayWidth 
), 
 229         wxCFDictKeyToInt( theValue
, kCGDisplayHeight 
), 
 230         wxCFDictKeyToInt( theValue
, kCGDisplayBitsPerPixel 
), 
 231         wxCFDictKeyToInt( theValue
, kCGDisplayRefreshRate 
)); 
 234 bool wxDisplayImplMacOSX::ChangeMode( const wxVideoMode
& mode 
) 
 236     // Changing to default mode (wxDefaultVideoMode) doesn't 
 237     // work because we don't have access to the system's 'scrn' 
 238     // resource which holds the user's mode which the system 
 239     // will return to after this app is done 
 240     boolean_t bExactMatch
; 
 241     CFDictionaryRef theCGMode 
= CGDisplayBestModeForParametersAndRefreshRate( 
 246         (double)mode
.refresh
, 
 249     bool bOK 
= bExactMatch
; 
 252         bOK 
= CGDisplaySwitchToMode( m_id
, theCGMode 
) == CGDisplayNoErr
; 
 257 // ============================================================================ 
 258 // wxDisplay::CreateFactory() 
 259 // ============================================================================ 
 261 /* static */ wxDisplayFactory 
*wxDisplay::CreateFactory() 
 263     return new wxDisplayFactoryMacOSX
; 
 266 #else // !__WXMAC_OSX__ 
 268 class wxDisplayImplMac 
: public wxDisplayImpl
 
 271     wxDisplayImplMac(unsigned n
, GDHandle hndl
) 
 277     virtual wxRect 
GetGeometry() const; 
 278     virtual wxString 
GetName() const { return wxString(); } 
 280     virtual wxArrayVideoModes 
GetModes(const wxVideoMode
& mode
) const; 
 281     virtual wxVideoMode 
GetCurrentMode() const; 
 282     virtual bool ChangeMode(const wxVideoMode
& mode
); 
 287     DECLARE_NO_COPY_CLASS(wxDisplayImplMac
) 
 290 class wxDisplayFactoryMac 
: public wxDisplayFactory
 
 293     wxDisplayFactoryMac(); 
 295     virtual wxDisplayImpl 
*CreateDisplay(unsigned n
); 
 296     virtual unsigned GetCount(); 
 297     virtual int GetFromPoint(const wxPoint
& pt
); 
 300     DECLARE_NO_COPY_CLASS(wxDisplayFactoryMac
) 
 303 // ============================================================================ 
 304 // wxDisplayFactoryMac implementation 
 305 // ============================================================================ 
 307 unsigned wxDisplayFactoryMac::GetCount() 
 310     GDHandle hndl 
= DMGetFirstScreenDevice(true); 
 314         hndl 
= DMGetNextScreenDevice(hndl
, true); 
 319 int wxDisplayFactoryMac::GetFromPoint(const wxPoint 
&p
) 
 322     GDHandle hndl 
= DMGetFirstScreenDevice(true); 
 325         Rect screenrect 
= (*hndl
)->gdRect
; 
 326         if (p
.x 
>= screenrect
.left 
&& 
 327             p
.x 
<= screenrect
.right 
&& 
 328             p
.y 
>= screenrect
.top 
&& 
 329             p
.y 
<= screenrect
.bottom
) 
 334         hndl 
= DMGetNextScreenDevice(hndl
, true); 
 340 wxDisplayImpl 
*wxDisplayFactoryMac::CreateDisplay(unsigned n
) 
 344     GDHandle hndl 
= DMGetFirstScreenDevice(true); 
 349             return new wxDisplayImplMac(nOrig
, hndl
); 
 352         hndl 
= DMGetNextScreenDevice(hndl
, true); 
 358 // ============================================================================ 
 359 // wxDisplayImplMac implementation 
 360 // ============================================================================ 
 362 wxRect 
wxDisplayImplMac::GetGeometry() const 
 364     Rect screenrect 
= (*m_hndl
)->gdRect
; 
 365     return wxRect(screenrect
.left
, screenrect
.top
, 
 366                   screenrect
.right 
- screenrect
.left
, 
 367                   screenrect
.bottom 
- screenrect
.top
); 
 370 struct DMModeIteratorRec
 
 372     wxArrayVideoModes
* pModes
; 
 373     const wxVideoMode
* pMatchMode
; 
 376 pascal void DMModeListIteratorProc( 
 378     DMListIndexType nIndex
, 
 379     DMDisplayModeListEntryPtr pInfo
) 
 381     DMModeIteratorRec
* pInfoData 
= (DMModeIteratorRec
*) pData
; 
 383     // Note that in testing the refresh rate is always 0 on my ibook - RN 
 384     int refresh 
= (int) Fix2Long(pInfo
->displayModeResolutionInfo
->csRefreshRate
); 
 386 #define pDBI pInfo->displayModeDepthBlockInfo->depthVPBlock[i].depthVPBlock 
 388     for (unsigned long i 
= 0; i 
< pInfo
->displayModeDepthBlockInfo
->depthBlockCount
; ++i
) 
 390         if (wxVideoMode( (int) pInfo
->displayModeResolutionInfo
->csHorizontalPixels
, 
 391                         (int) pInfo
->displayModeResolutionInfo
->csVerticalLines
, 
 392                         (int) pDBI
->vpPixelSize
, 
 393                         refresh
).Matches(*pInfoData
->pMatchMode
) ) 
 395             pInfoData
->pModes
->Add( 
 397                     (int) pInfo
->displayModeResolutionInfo
->csHorizontalPixels
, 
 398                     (int) pInfo
->displayModeResolutionInfo
->csVerticalLines
, 
 399                     (int) pDBI
->vpPixelSize
, 
 409     const wxVideoMode
* pMode
; 
 410     VDSwitchInfoRec sMode
; 
 414 pascal void DMModeInfoProc( 
 416     DMListIndexType nIndex
, 
 417     DMDisplayModeListEntryPtr pInfo 
) 
 419     DMModeInfoRec
* pInfoData 
= (DMModeInfoRec
*) pData
; 
 420     Fixed refresh 
= Long2Fix(pInfoData
->pMode
->refresh
); 
 422 #define pDBI pInfo->displayModeDepthBlockInfo->depthVPBlock[i].depthVPBlock 
 424     for (unsigned long i 
= 0; i 
< pInfo
->displayModeDepthBlockInfo
->depthBlockCount
; ++i
) 
 426         if (pInfoData
->pMode
->w 
== (int&) pInfo
->displayModeResolutionInfo
->csHorizontalPixels 
&& 
 427             pInfoData
->pMode
->h 
== (int&) pInfo
->displayModeResolutionInfo
->csVerticalLines 
&& 
 428             pInfoData
->pMode
->bpp 
== (int) pDBI
->vpPixelSize 
&& 
 429             refresh 
== pInfo
->displayModeResolutionInfo
->csRefreshRate
) 
 433                 pInfo
->displayModeDepthBlockInfo
->depthVPBlock
[i
].depthSwitchInfo
, 
 434                 sizeof(VDSwitchInfoRec
)); 
 435             pInfoData
->sMode
.csMode 
= pDBI
->vpPixelSize
; 
 436             pInfoData
->bMatched 
= true; 
 444 struct DMModeTransRec
 
 447     const VDSwitchInfoRec
* psMode
; 
 451 pascal void DMModeTransProc( 
 453     DMListIndexType nIndex
, 
 454     DMDisplayModeListEntryPtr pInfo
) 
 456     DMModeTransRec
* pInfoData 
= (DMModeTransRec
*) pData
; 
 458 #define pDBI pInfo->displayModeDepthBlockInfo->depthVPBlock[i].depthVPBlock 
 460     for (unsigned long i 
= 0; i 
< pInfo
->displayModeDepthBlockInfo
->depthBlockCount
; ++i
) 
 462         if (pInfoData
->psMode
->csData 
== pInfo
->displayModeDepthBlockInfo
->depthVPBlock
[i
].depthSwitchInfo
->csData
) 
 464             pInfoData
->Mode 
= wxVideoMode( 
 465                 (int) pInfo
->displayModeResolutionInfo
->csHorizontalPixels
, 
 466                 (int) pInfo
->displayModeResolutionInfo
->csVerticalLines
, 
 467                 (int) pDBI
->vpPixelSize
, 
 468                 (int) Fix2Long(pInfo
->displayModeResolutionInfo
->csRefreshRate
) ); 
 469             pInfoData
->bMatched 
= true; 
 477 wxArrayVideoModes 
wxDisplayImplMac::GetModes(const wxVideoMode
& mode
) const 
 479     wxArrayVideoModes Modes
; 
 480     unsigned long dwDMVer
; 
 482     // Check DM version == 2 
 483     // (for backward compatibility only - 7.5.3+ use 2.0) 
 484     Gestalt( gestaltDisplayMgrVers
, (long*) &dwDMVer 
); 
 485     if (dwDMVer 
>= 0x020000) 
 487         DMListIndexType nNumModes
; 
 489         DMDisplayModeListIteratorUPP uppMLI
; 
 490         DisplayIDType nDisplayID
; 
 493         err 
= DMGetDisplayIDByGDevice(m_hndl
, &nDisplayID
, false); 
 496         // Create a new list... 
 497         err 
= DMNewDisplayModeList(nDisplayID
, NULL
, NULL
, &nNumModes
, &pModes
); 
 498         wxASSERT_MSG( err 
== noErr
, wxT("Could not create a new display mode list") ); 
 500         uppMLI 
= NewDMDisplayModeListIteratorUPP(DMModeListIteratorProc
); 
 503         DMModeIteratorRec sModeInfo
; 
 504         sModeInfo
.pModes 
= &Modes
; 
 505         sModeInfo
.pMatchMode 
= &mode
; 
 507         for (DMListIndexType i 
= 0; i 
< nNumModes
; ++i
) 
 509             err 
= DMGetIndexedDisplayModeFromList(pModes
, i
, NULL
, uppMLI
, &sModeInfo
); 
 513         DisposeDMDisplayModeListIteratorUPP(uppMLI
); 
 514         err 
= DMDisposeList(pModes
); 
 517     else // DM 1.0, 1.2, 1.x 
 521                 wxT("Display Manager Version %u Not Supported!  Present? %s"), 
 522                 (unsigned int) dwDMVer 
/ 0x10000, 
 523                 (dwDMVer 
& (1 << gestaltDisplayMgrPresent
) ? wxT("Yes") : wxT("No")) ) ); 
 529 wxVideoMode 
wxDisplayImplMac::GetCurrentMode() const 
 531     unsigned long dwDMVer
; 
 534     // Check DM version == 2 
 535     // (for backward compatibility only - 7.5.3+ use 2.0) 
 536     Gestalt( gestaltDisplayMgrVers
, (long*) &dwDMVer 
); 
 537     if (dwDMVer 
>= 0x020000) 
 539         VDSwitchInfoRec sMode
; // Note: csMode member also contains the bit depth 
 542         err 
= DMGetDisplayMode( m_hndl
, &sMode 
); 
 545             DMListIndexType nNumModes
; 
 547             DMDisplayModeListIteratorUPP uppMLI
; 
 548             DisplayIDType nDisplayID
; 
 550             err 
= DMGetDisplayIDByGDevice(m_hndl
, &nDisplayID
, false); 
 553             // Create a new list... 
 554             err 
= DMNewDisplayModeList(nDisplayID
, NULL
, NULL
, &nNumModes
, &pModes
); 
 555             wxASSERT_MSG( err 
== noErr
, wxT("Could not create a new display mode list") ); 
 557             uppMLI 
= NewDMDisplayModeListIteratorUPP(DMModeTransProc
); 
 560             DMModeTransRec sModeInfo
; 
 561             sModeInfo
.bMatched 
= false; 
 562             sModeInfo
.psMode 
= &sMode
; 
 563             for (DMListIndexType i 
= 0; i 
< nNumModes
; ++i
) 
 565                 err 
= DMGetIndexedDisplayModeFromList(pModes
, i
, NULL
, uppMLI
, &sModeInfo
); 
 568                 if ( sModeInfo
.bMatched 
) 
 570                     RetMode 
= sModeInfo
.Mode
; 
 575             DisposeDMDisplayModeListIteratorUPP(uppMLI
); 
 576             err 
= DMDisposeList(pModes
); 
 579         else // Can't get current mode? 
 583                     wxT("Couldn't obtain current display mode!!!\ndwDMVer:%u"), 
 584                     (unsigned int) dwDMVer
)); 
 591                 wxT("Display Manager Version %u Not Supported!  Present? %s"), 
 592                 (unsigned int) dwDMVer 
/ 0x10000, 
 593                 (dwDMVer 
& (1 << gestaltDisplayMgrPresent
) ? wxT("Yes") : wxT("No")) ) ); 
 599 bool wxDisplayImplMac::ChangeMode(const wxVideoMode
& mode
) 
 601     unsigned long dwDMVer
; 
 603     Gestalt( gestaltDisplayMgrVers
, (long*)&dwDMVer 
); 
 604     if (GetCount() == 1 || dwDMVer 
>= 0x020000) 
 606         if (mode 
== wxDefaultVideoMode
) 
 612 //            Handle hDisplayState; 
 613 //            if (DMBeginConfigureDisplays(&hDisplayState) != noErr) 
 615 //                wxLogSysError(wxT("Could not lock display for display mode changing!")); 
 619 //            wxASSERT( DMUseScreenPrefs(true, hDisplayState) == noErr); 
 620 //            DMEndConfigureDisplays(hDisplayState); 
 629         //0 & NULL for params 2 & 3 of DMSetVideoMode signal it to use defaults (current mode) 
 630         //DM 2.0+ doesn't use params 2 & 3 of DMSetDisplayMode 
 631         //so we have to use this icky structure 
 632         VDSwitchInfoRec sMode
; 
 633         memset( &sMode
, 0, sizeof(VDSwitchInfoRec
) ); 
 635         DMListIndexType nNumModes
; 
 637         DMDisplayModeListIteratorUPP uppMLI
; 
 638         DisplayIDType nDisplayID
; 
 641         err 
= DMGetDisplayIDByGDevice(m_hndl
, &nDisplayID
, false); 
 644         // Create a new list... 
 645         err 
= DMNewDisplayModeList(nDisplayID
, NULL
, NULL
, &nNumModes
, &pModes
); 
 646         wxASSERT_MSG(err 
== noErr
, wxT("Could not create a new display mode list") ); 
 648         uppMLI 
= NewDMDisplayModeListIteratorUPP(DMModeInfoProc
); 
 651         DMModeInfoRec sModeInfo
; 
 652         sModeInfo
.bMatched 
= false; 
 653         sModeInfo
.pMode 
= &mode
; 
 656         for (i 
= 0; i 
< nNumModes
; ++i
) 
 658             err 
= DMGetIndexedDisplayModeFromList(pModes
, i
, NULL
, uppMLI
, &sModeInfo
); 
 661             if (sModeInfo
.bMatched
) 
 663                 sMode 
= sModeInfo
.sMode
; 
 671         DisposeDMDisplayModeListIteratorUPP(uppMLI
); 
 673         err 
= DMDisposeList(pModes
); 
 676         // For the really paranoid - 
 677         //     unsigned long flags; 
 679         //     wxASSERT(noErr == DMCheckDisplayMode(m_hndl, sMode.csData, 
 680         //                                          sMode.csMode, &flags, NULL, &bok)); 
 683         Handle hDisplayState
; 
 684         if (DMBeginConfigureDisplays(&hDisplayState
) != noErr
) 
 686             wxLogSysError(wxT("Could not lock display for display mode changing!")); 
 691         unsigned long dwBPP 
= (unsigned long) mode
.bpp
; 
 692         err 
= DMSetDisplayMode( 
 693             m_hndl
, sMode
.csData
, 
 694             (unsigned long*) &(dwBPP
), 
 695             NULL
, //(unsigned long) &sMode 
 700             DMEndConfigureDisplays(hDisplayState
); 
 701             wxLogError(wxT("Could not set the display mode")); 
 706         DMEndConfigureDisplays(hDisplayState
); 
 708     else  // DM 1.0, 1.2, 1.x 
 712                 wxT("Monitor gravitation not supported yet.  dwDMVer:%u"), 
 713                 (unsigned int) dwDMVer
)); 
 721 // ============================================================================ 
 722 // wxDisplay::CreateFactory() 
 723 // ============================================================================ 
 725 /* static */ wxDisplayFactory 
*wxDisplay::CreateFactory() 
 727     return new wxDisplayFactoryMac
; 
 732 #endif // wxUSE_DISPLAY