1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: Mac implementation of wxDisplay class
4 // Author: Brian Victor
5 // Modified by: Royce Mitchell III & Ryan Norton
8 // Copyright: (c) wxWidgets team
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // For compilers that support precompilation, includes "wx.h".
13 #include "wx/wxprec.h"
22 #include "wx/dynarray.h"
24 #include "wx/msgdlg.h"
28 #include <Carbon/Carbon.h>
32 #include <Quickdraw.h>
33 #include <Video.h> //for VDSwitchInfoRec
37 #include "wx/display.h"
38 #include "wx/gdicmn.h"
39 #include "wx/string.h"
41 // ----------------------------------------------------------------------------
43 // ----------------------------------------------------------------------------
45 class wxDisplayMacPriv
51 size_t wxDisplayBase::GetCount()
55 hndl
= DMGetFirstScreenDevice(true);
59 hndl
= DMGetNextScreenDevice(hndl
, true);
64 int wxDisplayBase::GetFromPoint(const wxPoint
&p
)
68 hndl
= DMGetFirstScreenDevice(true);
71 Rect screenrect
= (*hndl
)->gdRect
;
72 if (p
.x
>= screenrect
.left
&&
73 p
.x
<= screenrect
.right
&&
74 p
.y
>= screenrect
.top
&&
75 p
.y
<= screenrect
.bottom
)
80 hndl
= DMGetNextScreenDevice(hndl
, true);
85 wxDisplay::wxDisplay(size_t index
) : wxDisplayBase ( index
),
86 m_priv ( new wxDisplayMacPriv() )
89 hndl
= DMGetFirstScreenDevice(true);
90 m_priv
->m_hndl
= NULL
;
95 m_priv
->m_hndl
= hndl
;
98 hndl
= DMGetNextScreenDevice(hndl
, true);
102 wxRect
wxDisplay::GetGeometry() const
104 if (!(m_priv
)) return wxRect(0, 0, 0, 0);
105 if (!(m_priv
->m_hndl
)) return wxRect(0, 0, 0, 0);
106 Rect screenrect
= (*(m_priv
->m_hndl
))->gdRect
;
107 return wxRect( screenrect
.left
, screenrect
.top
,
108 screenrect
.right
- screenrect
.left
, screenrect
.bottom
- screenrect
.top
);
111 int wxDisplay::GetDepth() const
113 if (!(m_priv
)) return 0;
114 if (!(m_priv
->m_hndl
)) return 0;
116 // This cryptic looking code is based on Apple's sample code:
117 // http://developer.apple.com/samplecode/Sample_Code/Graphics_2D/GDevVideo/Gen.cp.htm
119 //RN - according to the docs
120 //gdPMap is a bitmap-type representation of the GDevice, and all
121 //0x0000FFFF does is get the lower 16 bits of pixelSize. However,
122 //since pixelSize is only 16 bits (a short)...
123 return ((*(*(m_priv
->m_hndl
))->gdPMap
)->pixelSize
) & 0x0000FFFF;
126 wxString
wxDisplay::GetName() const
128 // Macs don't name their displays...
129 return wxEmptyString
;
132 struct DMModeIteratorRec
134 wxArrayVideoModes
* pModes
;
135 const wxVideoMode
* pMatchMode
;
138 pascal void DMModeListIteratorProc ( void* pData
,
139 DMListIndexType nIndex
,
140 DMDisplayModeListEntryPtr pInfo
)
142 DMModeIteratorRec
* pInfoData
= (DMModeIteratorRec
*) pData
;
144 //Note that in testing the refresh rate is always 0 on my ibook - RN
145 int refresh
= (int) Fix2Long(pInfo
->displayModeResolutionInfo
->csRefreshRate
);
147 for(unsigned long i
= 0; i
< pInfo
->displayModeDepthBlockInfo
->depthBlockCount
; ++i
)
149 #define pDBI pInfo->displayModeDepthBlockInfo->depthVPBlock[i].depthVPBlock
151 if (wxVideoMode((int) pInfo
->displayModeResolutionInfo
->csHorizontalPixels
,
152 (int) pInfo
->displayModeResolutionInfo
->csVerticalLines
,
153 (int) pDBI
->vpPixelSize
,
154 refresh
).Matches(*pInfoData
->pMatchMode
) )
156 pInfoData
->pModes
->Add(wxVideoMode((int) pInfo
->displayModeResolutionInfo
->csHorizontalPixels
,
157 (int) pInfo
->displayModeResolutionInfo
->csVerticalLines
,
158 (int) pDBI
->vpPixelSize
,
167 const wxVideoMode
* pMode
;
168 VDSwitchInfoRec sMode
;
172 pascal void DMModeInfoProc ( void* pData
,
173 DMListIndexType nIndex
,
174 DMDisplayModeListEntryPtr pInfo
)
176 DMModeInfoRec
* pInfoData
= (DMModeInfoRec
*) pData
;
177 Fixed refresh
= Long2Fix(pInfoData
->pMode
->refresh
);
179 for(unsigned long i
= 0; i
< pInfo
->displayModeDepthBlockInfo
->depthBlockCount
; ++i
)
181 #define pDBI pInfo->displayModeDepthBlockInfo->depthVPBlock[i].depthVPBlock
182 if (pInfoData
->pMode
->w
== (int&) pInfo
->displayModeResolutionInfo
->csHorizontalPixels
&&
183 pInfoData
->pMode
->h
== (int&) pInfo
->displayModeResolutionInfo
->csVerticalLines
&&
184 pInfoData
->pMode
->bpp
== (int) pDBI
->vpPixelSize
&&
185 refresh
== pInfo
->displayModeResolutionInfo
->csRefreshRate
)
187 memcpy(&pInfoData
->sMode
, pInfo
->displayModeDepthBlockInfo
->depthVPBlock
[i
].depthSwitchInfo
,
188 sizeof(VDSwitchInfoRec
));
189 pInfoData
->sMode
.csMode
= pDBI
->vpPixelSize
;
190 pInfoData
->bMatched
= true;
197 struct DMModeTransRec
200 const VDSwitchInfoRec
* psMode
;
204 pascal void DMModeTransProc ( void* pData
,
205 DMListIndexType nIndex
,
206 DMDisplayModeListEntryPtr pInfo
)
208 DMModeTransRec
* pInfoData
= (DMModeTransRec
*) pData
;
210 for(unsigned long i
= 0; i
< pInfo
->displayModeDepthBlockInfo
->depthBlockCount
; ++i
)
212 #define pDBI pInfo->displayModeDepthBlockInfo->depthVPBlock[i].depthVPBlock
213 if (pInfoData
->psMode
->csData
== pInfo
->displayModeDepthBlockInfo
->depthVPBlock
[i
].depthSwitchInfo
->csData
)
215 pInfoData
->Mode
= wxVideoMode((int) pInfo
->displayModeResolutionInfo
->csHorizontalPixels
,
216 (int) pInfo
->displayModeResolutionInfo
->csVerticalLines
,
217 (int) pDBI
->vpPixelSize
,
218 (int) Fix2Long(pInfo
->displayModeResolutionInfo
->csRefreshRate
) );
219 pInfoData
->bMatched
= true;
227 wxDisplay::GetModes(const wxVideoMode
& mode
) const
230 wxArrayVideoModes Modes
;
232 unsigned long dwDMVer
;
233 Gestalt(gestaltDisplayMgrVers
, (long*) &dwDMVer
);
235 //Check DM version (for backward compatibility only - 7.5.3+ use 2.0)
236 if (dwDMVer
>= 0x020000) //version 2?
239 DMListIndexType nNumModes
;
241 DMDisplayModeListIteratorUPP uppMLI
;
242 DisplayIDType nDisplayID
;
244 wxASSERT(DMGetDisplayIDByGDevice(m_priv
->m_hndl
, &nDisplayID
, false) == noErr
);
245 //Create a new list...
246 wxASSERT_MSG(DMNewDisplayModeList(nDisplayID
, NULL
, NULL
, &nNumModes
, &pModes
) == noErr
, wxT("Could not create a new display mode list") );
248 uppMLI
= NewDMDisplayModeListIteratorUPP(DMModeListIteratorProc
);
251 DMModeIteratorRec sModeInfo
;
252 sModeInfo
.pModes
= &Modes
;
253 sModeInfo
.pMatchMode
= &mode
;
254 for (DMListIndexType i
= 0; i
< nNumModes
; ++i
)
256 wxASSERT(DMGetIndexedDisplayModeFromList(pModes
, i
, NULL
,
257 uppMLI
, &sModeInfo
) == noErr
);
259 DisposeDMDisplayModeListIteratorUPP(uppMLI
);
260 wxASSERT(DMDisposeList(pModes
) == noErr
);
262 else //DM 1.0, 1.2, 1.x
264 wxLogSysError(wxString::Format(wxT("Display Manager Version %u Not Supported! Present? %s"),
265 (unsigned int) dwDMVer
/ 0x10000,
266 (dwDMVer
& (1 << gestaltDisplayMgrPresent
) ? wxT("Yes") : wxT("No")) )
273 wxVideoMode
wxDisplay::GetCurrentMode() const
275 unsigned long dwDMVer
;
278 Gestalt(gestaltDisplayMgrVers
, (long*) &dwDMVer
);
279 //Check DM version (for backward compatibility only - 7.5.3+ use 2.0)
280 if (dwDMVer
>= 0x020000) //version 2?
282 VDSwitchInfoRec sMode
; //Note - csMode member also contains the bit depth
283 if (DMGetDisplayMode(m_priv
->m_hndl
, &sMode
) == noErr
)
285 DMListIndexType nNumModes
;
287 DMDisplayModeListIteratorUPP uppMLI
;
288 DisplayIDType nDisplayID
;
290 wxASSERT(DMGetDisplayIDByGDevice(m_priv
->m_hndl
, &nDisplayID
, false) == noErr
);
291 //Create a new list...
292 wxASSERT_MSG(DMNewDisplayModeList(nDisplayID
, NULL
, NULL
, &nNumModes
, &pModes
) == noErr
,
293 wxT("Could not create a new display mode list") );
295 uppMLI
= NewDMDisplayModeListIteratorUPP(DMModeTransProc
);
298 DMModeTransRec sModeInfo
;
299 sModeInfo
.bMatched
= false;
300 sModeInfo
.psMode
= &sMode
;
301 for (DMListIndexType i
= 0; i
< nNumModes
; ++i
)
303 wxASSERT(DMGetIndexedDisplayModeFromList(pModes
, i
, NULL
,
304 uppMLI
, &sModeInfo
) == noErr
);
306 if ( sModeInfo
.bMatched
== true )
308 RetMode
= sModeInfo
.Mode
;
313 DisposeDMDisplayModeListIteratorUPP(uppMLI
);
314 wxASSERT(DMDisposeList(pModes
) == noErr
);
316 else //Can't get current mode?
318 wxLogSysError(wxString::Format(wxT("Couldn't obtain current display mode!!!\ndwDMVer:%u"),
319 (unsigned int) dwDMVer
));
324 wxLogSysError(wxString::Format(wxT("Display Manager Version %u Not Supported! Present? %s"),
325 (unsigned int) dwDMVer
/ 0x10000,
326 (dwDMVer
& (1 << gestaltDisplayMgrPresent
) ? wxT("Yes") : wxT("No")) )
333 bool wxDisplay::ChangeMode(const wxVideoMode
& mode
)
335 unsigned long dwDMVer
;
336 Gestalt(gestaltDisplayMgrVers
, (long*)&dwDMVer
);
337 if (GetCount() == 1 || dwDMVer
>= 0x020000)
339 if (mode
== wxDefaultVideoMode
)
342 // Handle hDisplayState;
343 // if (DMBeginConfigureDisplays(&hDisplayState) != noErr)
345 // wxLogSysError(wxT("Could not lock display for display mode changing!"));
348 // wxASSERT( DMUseScreenPrefs(true, hDisplayState) == noErr);
349 // DMEndConfigureDisplays(hDisplayState);
357 //0 & NULL for params 2 & 3 of DMSetVideoMode signal it to use defaults (current mode)
358 //DM 2.0+ doesn't use params 2 & 3 of DMSetDisplayMode
359 //so we have to use this icky structure
360 VDSwitchInfoRec sMode
;
361 memset(&sMode
, 0, sizeof(VDSwitchInfoRec
) );
363 DMListIndexType nNumModes
;
365 DMDisplayModeListIteratorUPP uppMLI
;
366 DisplayIDType nDisplayID
;
368 wxASSERT(DMGetDisplayIDByGDevice(m_priv
->m_hndl
, &nDisplayID
, false) == noErr
);
369 //Create a new list...
370 wxASSERT_MSG(DMNewDisplayModeList(nDisplayID
, NULL
, NULL
, &nNumModes
, &pModes
) == noErr
,
371 wxT("Could not create a new display mode list") );
373 uppMLI
= NewDMDisplayModeListIteratorUPP(DMModeInfoProc
);
376 DMModeInfoRec sModeInfo
;
377 sModeInfo
.bMatched
= false;
378 sModeInfo
.pMode
= &mode
;
380 for(i
= 0; i
< nNumModes
; ++i
)
382 wxASSERT(DMGetIndexedDisplayModeFromList(pModes
, i
, NULL
,
383 uppMLI
, &sModeInfo
) == noErr
);
384 if (sModeInfo
.bMatched
== true)
386 sMode
= sModeInfo
.sMode
;
393 DisposeDMDisplayModeListIteratorUPP(uppMLI
);
394 wxASSERT(DMDisposeList(pModes
) == noErr
);
396 // For the really paranoid -
397 // unsigned long flags;
399 // wxASSERT(noErr == DMCheckDisplayMode(m_priv->m_hndl, sMode.csData,
400 // sMode.csMode, &flags, NULL, &bok));
403 Handle hDisplayState
;
404 if (DMBeginConfigureDisplays(&hDisplayState
) != noErr
)
406 wxLogSysError(wxT("Could not lock display for display mode changing!"));
410 unsigned long dwBPP
= (unsigned long) mode
.bpp
;
411 if (DMSetDisplayMode(m_priv
->m_hndl
, sMode
.csData
,
412 (unsigned long*) &(dwBPP
), NULL
413 //(unsigned long) &sMode
417 DMEndConfigureDisplays(hDisplayState
);
418 wxMessageBox(wxString::Format(wxT("Could not set the display mode")));
421 DMEndConfigureDisplays(hDisplayState
);
423 else //DM 1.0, 1.2, 1.x
425 wxLogSysError(wxString::Format(wxT("Monitor gravitation not supported yet. dwDMVer:%u"),
426 (unsigned int) dwDMVer
));
433 wxDisplay::~wxDisplay()
442 #endif // wxUSE_DISPLAY