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 // ----------------------------------------------------------------------------
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
;
249 err
= DMGetDisplayIDByGDevice(m_priv
->m_hndl
, &nDisplayID
, false);
250 wxASSERT(err
== noErr
);
252 //Create a new list...
253 err
= DMNewDisplayModeList(nDisplayID
, NULL
, NULL
, &nNumModes
, &pModes
);
254 wxASSERT_MSG(err
== noErr
, wxT("Could not create a new display mode list") );
256 uppMLI
= NewDMDisplayModeListIteratorUPP(DMModeListIteratorProc
);
259 DMModeIteratorRec sModeInfo
;
260 sModeInfo
.pModes
= &Modes
;
261 sModeInfo
.pMatchMode
= &mode
;
262 for (DMListIndexType i
= 0; i
< nNumModes
; ++i
)
264 err
= DMGetIndexedDisplayModeFromList(pModes
, i
, NULL
, uppMLI
, &sModeInfo
);
265 wxASSERT(err
== noErr
);
267 DisposeDMDisplayModeListIteratorUPP(uppMLI
);
269 err
= DMDisposeList(pModes
);
270 wxASSERT(err
== noErr
);
272 else //DM 1.0, 1.2, 1.x
274 wxLogSysError(wxString::Format(wxT("Display Manager Version %u Not Supported! Present? %s"),
275 (unsigned int) dwDMVer
/ 0x10000,
276 (dwDMVer
& (1 << gestaltDisplayMgrPresent
) ? wxT("Yes") : wxT("No")) )
283 wxVideoMode
wxDisplay::GetCurrentMode() const
285 unsigned long dwDMVer
;
288 Gestalt(gestaltDisplayMgrVers
, (long*) &dwDMVer
);
289 //Check DM version (for backward compatibility only - 7.5.3+ use 2.0)
290 if (dwDMVer
>= 0x020000) //version 2?
292 VDSwitchInfoRec sMode
; //Note - csMode member also contains the bit depth
293 if (DMGetDisplayMode(m_priv
->m_hndl
, &sMode
) == noErr
)
295 DMListIndexType nNumModes
;
297 DMDisplayModeListIteratorUPP uppMLI
;
298 DisplayIDType nDisplayID
;
301 err
= DMGetDisplayIDByGDevice(m_priv
->m_hndl
, &nDisplayID
, false);
302 wxASSERT(err
== noErr
);
304 //Create a new list...
305 err
= DMNewDisplayModeList(nDisplayID
, NULL
, NULL
, &nNumModes
, &pModes
);
306 wxASSERT_MSG(err
== noErr
, wxT("Could not create a new display mode list") );
308 uppMLI
= NewDMDisplayModeListIteratorUPP(DMModeTransProc
);
311 DMModeTransRec sModeInfo
;
312 sModeInfo
.bMatched
= false;
313 sModeInfo
.psMode
= &sMode
;
314 for (DMListIndexType i
= 0; i
< nNumModes
; ++i
)
316 err
= DMGetIndexedDisplayModeFromList(pModes
, i
, NULL
, uppMLI
, &sModeInfo
);
317 wxASSERT(err
== noErr
);
319 if ( sModeInfo
.bMatched
== true )
321 RetMode
= sModeInfo
.Mode
;
326 DisposeDMDisplayModeListIteratorUPP(uppMLI
);
328 err
= DMDisposeList(pModes
);
329 wxASSERT(err
== noErr
);
331 else //Can't get current mode?
333 wxLogSysError(wxString::Format(wxT("Couldn't obtain current display mode!!!\ndwDMVer:%u"),
334 (unsigned int) dwDMVer
));
339 wxLogSysError(wxString::Format(wxT("Display Manager Version %u Not Supported! Present? %s"),
340 (unsigned int) dwDMVer
/ 0x10000,
341 (dwDMVer
& (1 << gestaltDisplayMgrPresent
) ? wxT("Yes") : wxT("No")) )
348 bool wxDisplay::ChangeMode(const wxVideoMode
& mode
)
350 unsigned long dwDMVer
;
351 Gestalt(gestaltDisplayMgrVers
, (long*)&dwDMVer
);
352 if (GetCount() == 1 || dwDMVer
>= 0x020000)
354 if (mode
== wxDefaultVideoMode
)
357 // Handle hDisplayState;
358 // if (DMBeginConfigureDisplays(&hDisplayState) != noErr)
360 // wxLogSysError(wxT("Could not lock display for display mode changing!"));
363 // wxASSERT( DMUseScreenPrefs(true, hDisplayState) == noErr);
364 // DMEndConfigureDisplays(hDisplayState);
372 //0 & NULL for params 2 & 3 of DMSetVideoMode signal it to use defaults (current mode)
373 //DM 2.0+ doesn't use params 2 & 3 of DMSetDisplayMode
374 //so we have to use this icky structure
375 VDSwitchInfoRec sMode
;
376 memset(&sMode
, 0, sizeof(VDSwitchInfoRec
) );
378 DMListIndexType nNumModes
;
380 DMDisplayModeListIteratorUPP uppMLI
;
381 DisplayIDType nDisplayID
;
384 err
= DMGetDisplayIDByGDevice(m_priv
->m_hndl
, &nDisplayID
, false);
385 wxASSERT(err
== noErr
);
387 //Create a new list...
388 err
= DMNewDisplayModeList(nDisplayID
, NULL
, NULL
, &nNumModes
, &pModes
);
389 wxASSERT_MSG(err
== noErr
, wxT("Could not create a new display mode list") );
391 uppMLI
= NewDMDisplayModeListIteratorUPP(DMModeInfoProc
);
394 DMModeInfoRec sModeInfo
;
395 sModeInfo
.bMatched
= false;
396 sModeInfo
.pMode
= &mode
;
398 for(i
= 0; i
< nNumModes
; ++i
)
400 err
= DMGetIndexedDisplayModeFromList(pModes
, i
, NULL
, uppMLI
, &sModeInfo
);
401 wxASSERT(err
== noErr
);
403 if (sModeInfo
.bMatched
== true)
405 sMode
= sModeInfo
.sMode
;
412 DisposeDMDisplayModeListIteratorUPP(uppMLI
);
414 err
= DMDisposeList(pModes
);
415 wxASSERT(err
== noErr
);
417 // For the really paranoid -
418 // unsigned long flags;
420 // wxASSERT(noErr == DMCheckDisplayMode(m_priv->m_hndl, sMode.csData,
421 // sMode.csMode, &flags, NULL, &bok));
424 Handle hDisplayState
;
425 if (DMBeginConfigureDisplays(&hDisplayState
) != noErr
)
427 wxLogSysError(wxT("Could not lock display for display mode changing!"));
431 unsigned long dwBPP
= (unsigned long) mode
.bpp
;
432 if (DMSetDisplayMode(m_priv
->m_hndl
, sMode
.csData
,
433 (unsigned long*) &(dwBPP
), NULL
434 //(unsigned long) &sMode
438 DMEndConfigureDisplays(hDisplayState
);
439 wxMessageBox(wxString::Format(wxT("Could not set the display mode")));
442 DMEndConfigureDisplays(hDisplayState
);
444 else //DM 1.0, 1.2, 1.x
446 wxLogSysError(wxString::Format(wxT("Monitor gravitation not supported yet. dwDMVer:%u"),
447 (unsigned int) dwDMVer
));
454 wxDisplay::~wxDisplay()
463 #endif // wxUSE_DISPLAY