1 ///////////////////////////////////////////////////////////////////////////// 
   3 // Purpose:     Mac implementation of wxDisplay class 
   4 // Author:      Brian Victor 
   5 // Modified by: Royce Mitchell III & Ryan Norton 
   8 // Copyright:   (c) wxWindows team 
   9 // Licence:     wxWindows licence 
  10 ///////////////////////////////////////////////////////////////////////////// 
  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 // ---------------------------------------------------------------------------- 
  49 class wxDisplayMacPriv
 
  55 size_t wxDisplayBase::GetCount() 
  59     hndl 
= DMGetFirstScreenDevice(true); 
  63         hndl 
= DMGetNextScreenDevice(hndl
, true); 
  68 int wxDisplayBase::GetFromPoint(const wxPoint 
&p
) 
  72     hndl 
= DMGetFirstScreenDevice(true); 
  75         Rect screenrect 
= (*hndl
)->gdRect
; 
  76         if (p
.x 
>= screenrect
.left 
&& 
  77             p
.x 
<= screenrect
.right 
&& 
  78             p
.y 
>= screenrect
.top 
&& 
  79             p
.y 
<= screenrect
.bottom
) 
  84         hndl 
= DMGetNextScreenDevice(hndl
, true); 
  89 wxDisplay::wxDisplay(size_t index
) : wxDisplayBase ( index 
), 
  90     m_priv ( new wxDisplayMacPriv() ) 
  93     hndl 
= DMGetFirstScreenDevice(true); 
  94     m_priv
->m_hndl 
= NULL
; 
  99             m_priv
->m_hndl 
= hndl
; 
 102         hndl 
= DMGetNextScreenDevice(hndl
, true); 
 106 wxRect 
wxDisplay::GetGeometry() const 
 108     if (!(m_priv
)) return wxRect(0, 0, 0, 0); 
 109     if (!(m_priv
->m_hndl
)) return wxRect(0, 0, 0, 0); 
 110     Rect screenrect 
= (*(m_priv
->m_hndl
))->gdRect
; 
 111     return wxRect( screenrect
.left
, screenrect
.top
,  
 112                    screenrect
.right 
- screenrect
.left
, screenrect
.bottom 
- screenrect
.top
); 
 115 int wxDisplay::GetDepth() const 
 117     if (!(m_priv
)) return 0; 
 118     if (!(m_priv
->m_hndl
)) return 0; 
 120     // This cryptic looking code is based on Apple's sample code: 
 121     // http://developer.apple.com/samplecode/Sample_Code/Graphics_2D/GDevVideo/Gen.cp.htm 
 123     //RN - according to the docs 
 124         //gdPMap is a bitmap-type representation of the GDevice, and all 
 125         //0x0000FFFF does is get the lower 16 bits of pixelSize.  However, 
 126         //since pixelSize is only 16 bits (a short)... 
 127     return ((*(*(m_priv
->m_hndl
))->gdPMap
)->pixelSize
) & 0x0000FFFF; 
 130 wxString 
wxDisplay::GetName() const 
 132     // Macs don't name their displays... 
 133     return wxEmptyString
; 
 136 struct DMModeIteratorRec
 
 138         wxArrayVideoModes
* pModes
; 
 139         const wxVideoMode
* pMatchMode
; 
 142 pascal void DMModeListIteratorProc (    void* pData
, 
 143                               DMListIndexType nIndex
, 
 144                               DMDisplayModeListEntryPtr pInfo
) 
 146     DMModeIteratorRec
* pInfoData 
= (DMModeIteratorRec
*) pData
; 
 148         //Note that in testing the refresh rate is always 0 on my ibook - RN 
 149     int refresh 
= (int) Fix2Long(pInfo
->displayModeResolutionInfo
->csRefreshRate
); 
 151         for(unsigned long i 
= 0; i 
< pInfo
->displayModeDepthBlockInfo
->depthBlockCount
; ++i
) 
 153 #define pDBI pInfo->displayModeDepthBlockInfo->depthVPBlock[i].depthVPBlock 
 155                 if (wxVideoMode((int) pInfo
->displayModeResolutionInfo
->csHorizontalPixels
, 
 156                                   (int) pInfo
->displayModeResolutionInfo
->csVerticalLines
, 
 157                                   (int) pDBI
->vpPixelSize
, 
 158                                   refresh
).Matches(*pInfoData
->pMatchMode
) ) 
 160                         pInfoData
->pModes
->Add(wxVideoMode((int) pInfo
->displayModeResolutionInfo
->csHorizontalPixels
, 
 161                                                    (int) pInfo
->displayModeResolutionInfo
->csVerticalLines
, 
 162                                                    (int) pDBI
->vpPixelSize
, 
 171         const wxVideoMode
* pMode
; 
 172         VDSwitchInfoRec sMode
; 
 176 pascal void DMModeInfoProc (    void* pData
, 
 177                                                           DMListIndexType nIndex
, 
 178                                                           DMDisplayModeListEntryPtr pInfo
) 
 180         DMModeInfoRec
* pInfoData 
= (DMModeInfoRec
*) pData
; 
 181         Fixed refresh 
= Long2Fix(pInfoData
->pMode
->refresh
); 
 183         for(unsigned long i 
= 0; i 
< pInfo
->displayModeDepthBlockInfo
->depthBlockCount
; ++i
) 
 185 #define pDBI pInfo->displayModeDepthBlockInfo->depthVPBlock[i].depthVPBlock 
 186                     if (pInfoData
->pMode
->w 
== (int&) pInfo
->displayModeResolutionInfo
->csHorizontalPixels 
&& 
 187                         pInfoData
->pMode
->h 
== (int&) pInfo
->displayModeResolutionInfo
->csVerticalLines 
&& 
 188                         pInfoData
->pMode
->bpp 
== (int) pDBI
->vpPixelSize 
&& 
 189                         refresh 
== pInfo
->displayModeResolutionInfo
->csRefreshRate
) 
 191                                 memcpy(&pInfoData
->sMode
, pInfo
->displayModeDepthBlockInfo
->depthVPBlock
[i
].depthSwitchInfo
, 
 192                                        sizeof(VDSwitchInfoRec
)); 
 193                                 pInfoData
->sMode
.csMode 
= pDBI
->vpPixelSize
; 
 194                                 pInfoData
->bMatched 
= true; 
 201 struct DMModeTransRec
 
 204         const VDSwitchInfoRec
* psMode
; 
 208 pascal void DMModeTransProc (   void* pData
, 
 209                                           DMListIndexType nIndex
, 
 210                                           DMDisplayModeListEntryPtr pInfo
) 
 212         DMModeTransRec
* pInfoData 
= (DMModeTransRec
*) pData
; 
 214         for(unsigned long i 
= 0; i 
< pInfo
->displayModeDepthBlockInfo
->depthBlockCount
; ++i
) 
 216 #define pDBI pInfo->displayModeDepthBlockInfo->depthVPBlock[i].depthVPBlock 
 217                 if (pInfoData
->psMode
->csData 
== pInfo
->displayModeDepthBlockInfo
->depthVPBlock
[i
].depthSwitchInfo
->csData
) 
 219                         pInfoData
->Mode 
= wxVideoMode((int) pInfo
->displayModeResolutionInfo
->csHorizontalPixels
, 
 220                                                                  (int) pInfo
->displayModeResolutionInfo
->csVerticalLines
, 
 221                                                                  (int) pDBI
->vpPixelSize
, 
 222                                                                  (int) Fix2Long(pInfo
->displayModeResolutionInfo
->csRefreshRate
) ); 
 223                         pInfoData
->bMatched 
= true; 
 231     wxDisplay::GetModes(const wxVideoMode
& mode
) const 
 234     wxArrayVideoModes Modes
; 
 236     unsigned long dwDMVer
; 
 237     Gestalt(gestaltDisplayMgrVers
, (long*) &dwDMVer
); 
 239     //Check DM version (for backward compatibility only - 7.5.3+ use 2.0) 
 240     if (dwDMVer 
>= 0x020000) //version 2? 
 243         DMListIndexType nNumModes
; 
 245         DMDisplayModeListIteratorUPP uppMLI
; 
 246         DisplayIDType nDisplayID
; 
 248         wxASSERT(DMGetDisplayIDByGDevice(m_priv
->m_hndl
, &nDisplayID
, false) == noErr
);  
 249         //Create a new list... 
 250         wxASSERT_MSG(DMNewDisplayModeList(nDisplayID
, NULL
, NULL
, &nNumModes
,                                                   &pModes
) == noErr
, wxT("Could not create a new display mode list") ); 
 252         uppMLI 
= NewDMDisplayModeListIteratorUPP(DMModeListIteratorProc
); 
 255         DMModeIteratorRec sModeInfo
; 
 256         sModeInfo
.pModes 
= &Modes
; 
 257         sModeInfo
.pMatchMode 
= &mode
; 
 258         for (DMListIndexType i 
= 0; i 
< nNumModes
; ++i
) 
 260             wxASSERT(DMGetIndexedDisplayModeFromList(pModes
, i
, NULL
, 
 261                                               uppMLI
, &sModeInfo
) == noErr
); 
 263         DisposeDMDisplayModeListIteratorUPP(uppMLI
); 
 264         wxASSERT(DMDisposeList(pModes
) == noErr
);        
 266     else //DM 1.0, 1.2, 1.x 
 268         wxLogSysError(wxString::Format(wxT("Display Manager Version %u Not Supported!  Present? %s"), 
 269                                 (unsigned int) dwDMVer 
/ 0x10000, 
 270                                 (dwDMVer 
& (1 << gestaltDisplayMgrPresent
) ? wxT("Yes") : wxT("No"))  ) 
 277 wxVideoMode 
wxDisplay::GetCurrentMode() const 
 279     unsigned long dwDMVer
; 
 282     Gestalt(gestaltDisplayMgrVers
, (long*) &dwDMVer
);     
 283     //Check DM version (for backward compatibility only - 7.5.3+ use 2.0) 
 284     if (dwDMVer 
>= 0x020000) //version 2? 
 286         VDSwitchInfoRec sMode
; //Note - csMode member also contains the bit depth 
 287         if (DMGetDisplayMode(m_priv
->m_hndl
, &sMode
) == noErr
)  
 289             DMListIndexType nNumModes
; 
 291                 DMDisplayModeListIteratorUPP uppMLI
; 
 292             DisplayIDType nDisplayID
; 
 294             wxASSERT(DMGetDisplayIDByGDevice(m_priv
->m_hndl
, &nDisplayID
, false) == noErr
); 
 295             //Create a new list... 
 296             wxASSERT_MSG(DMNewDisplayModeList(nDisplayID
, NULL
, NULL
, &nNumModes
, &pModes
) == noErr
, 
 297                                   wxT("Could not create a new display mode list") ); 
 299                 uppMLI 
= NewDMDisplayModeListIteratorUPP(DMModeTransProc
); 
 302                 DMModeTransRec sModeInfo
; 
 303                 sModeInfo
.bMatched 
= false; 
 304                 sModeInfo
.psMode 
= &sMode
; 
 305                 for (DMListIndexType i 
= 0; i 
< nNumModes
; ++i
) 
 307                         wxASSERT(DMGetIndexedDisplayModeFromList(pModes
, i
, NULL
, 
 308                                                                                         uppMLI
, &sModeInfo
) == noErr
); 
 310                         if ( sModeInfo
.bMatched 
== true ) 
 312                                 RetMode 
= sModeInfo
.Mode
; 
 317             DisposeDMDisplayModeListIteratorUPP(uppMLI
); 
 318             wxASSERT(DMDisposeList(pModes
) == noErr
); 
 320         else //Can't get current mode? 
 322                 wxLogSysError(wxString::Format(wxT("Couldn't obtain current display mode!!!\ndwDMVer:%u"), 
 323                                                                 (unsigned int) dwDMVer
)); 
 328         wxLogSysError(wxString::Format(wxT("Display Manager Version %u Not Supported!  Present? %s"), 
 329                                 (unsigned int) dwDMVer 
/ 0x10000, 
 330                                 (dwDMVer 
& (1 << gestaltDisplayMgrPresent
) ? wxT("Yes") : wxT("No")) ) 
 337 bool wxDisplay::ChangeMode(const wxVideoMode
& mode
) 
 339     unsigned long dwDMVer
; 
 340     Gestalt(gestaltDisplayMgrVers
, (long*)&dwDMVer
); 
 341     if (GetCount() == 1 || dwDMVer 
>= 0x020000) 
 343                 if (mode 
== wxDefaultVideoMode
) 
 346 //                      Handle hDisplayState; 
 347 //                      if (DMBeginConfigureDisplays(&hDisplayState) != noErr) 
 349 //                              wxLogSysError(wxT("Could not lock display for display mode changing!")); 
 352 //                      wxASSERT( DMUseScreenPrefs(true, hDisplayState) == noErr); 
 353 //                      DMEndConfigureDisplays(hDisplayState); 
 361         //0 & NULL for params 2 & 3 of DMSetVideoMode signal it to use defaults (current mode) 
 362         //DM 2.0+ doesn't use params 2 & 3 of DMSetDisplayMode 
 363         //so we have to use this icky structure 
 364         VDSwitchInfoRec sMode
; 
 365         memset(&sMode
, 0, sizeof(VDSwitchInfoRec
) ); 
 367         DMListIndexType nNumModes
; 
 369         DMDisplayModeListIteratorUPP uppMLI
; 
 370         DisplayIDType nDisplayID
; 
 372         wxASSERT(DMGetDisplayIDByGDevice(m_priv
->m_hndl
, &nDisplayID
, false) == noErr
); 
 373         //Create a new list... 
 374         wxASSERT_MSG(DMNewDisplayModeList(nDisplayID
, NULL
, NULL
, &nNumModes
, &pModes
) == noErr
, 
 375                           wxT("Could not create a new display mode list") ); 
 377         uppMLI 
= NewDMDisplayModeListIteratorUPP(DMModeInfoProc
); 
 380         DMModeInfoRec sModeInfo
; 
 381         sModeInfo
.bMatched 
= false; 
 382         sModeInfo
.pMode 
= &mode
; 
 384         for(i 
= 0; i 
< nNumModes
; ++i
) 
 386                 wxASSERT(DMGetIndexedDisplayModeFromList(pModes
, i
, NULL
, 
 387                                                                                    uppMLI
, &sModeInfo
) == noErr
); 
 388                 if (sModeInfo
.bMatched 
== true) 
 390                         sMode 
= sModeInfo
.sMode
; 
 397         DisposeDMDisplayModeListIteratorUPP(uppMLI
); 
 398         wxASSERT(DMDisposeList(pModes
) == noErr
); 
 400         // For the really paranoid - 
 401         //          unsigned long flags; 
 403         //     wxASSERT(noErr == DMCheckDisplayMode(m_priv->m_hndl, sMode.csData, 
 404         //                                                                sMode.csMode, &flags, NULL, &bok)); 
 407         Handle hDisplayState
; 
 408         if (DMBeginConfigureDisplays(&hDisplayState
) != noErr
) 
 410             wxLogSysError(wxT("Could not lock display for display mode changing!")); 
 414         unsigned long dwBPP 
= (unsigned long) mode
.bpp
; 
 415         if (DMSetDisplayMode(m_priv
->m_hndl
, sMode
.csData
, 
 416                                             (unsigned long*) &(dwBPP
), NULL
 
 417                                            //(unsigned long) &sMode 
 421                 DMEndConfigureDisplays(hDisplayState
); 
 422                 wxMessageBox(wxString::Format(wxT("Could not set the display mode"))); 
 425         DMEndConfigureDisplays(hDisplayState
); 
 427     else  //DM 1.0, 1.2, 1.x 
 429         wxLogSysError(wxString::Format(wxT("Monitor gravitation not supported yet.  dwDMVer:%u"), 
 430                                 (unsigned int) dwDMVer
)); 
 437 wxDisplay::~wxDisplay() 
 446 #endif // wxUSE_DISPLAY