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"
31 #include <Carbon/Carbon.h>
35 #include <Quickdraw.h>
36 #include <Video.h> //for VDSwitchInfoRec
40 #include "wx/display.h"
41 #include "wx/gdicmn.h"
42 #include "wx/string.h"
44 // ----------------------------------------------------------------------------
46 // ----------------------------------------------------------------------------
48 class wxDisplayMacPriv
54 size_t wxDisplayBase::GetCount()
58 hndl
= DMGetFirstScreenDevice(true);
62 hndl
= DMGetNextScreenDevice(hndl
, true);
67 int wxDisplayBase::GetFromPoint(const wxPoint
&p
)
71 hndl
= DMGetFirstScreenDevice(true);
74 Rect screenrect
= (*hndl
)->gdRect
;
75 if (p
.x
>= screenrect
.left
&&
76 p
.x
<= screenrect
.right
&&
77 p
.y
>= screenrect
.top
&&
78 p
.y
<= screenrect
.bottom
)
83 hndl
= DMGetNextScreenDevice(hndl
, true);
88 wxDisplay::wxDisplay(size_t index
) : wxDisplayBase ( index
),
89 m_priv ( new wxDisplayMacPriv() )
92 hndl
= DMGetFirstScreenDevice(true);
93 m_priv
->m_hndl
= NULL
;
98 m_priv
->m_hndl
= hndl
;
101 hndl
= DMGetNextScreenDevice(hndl
, true);
105 wxRect
wxDisplay::GetGeometry() const
107 if (!(m_priv
)) return wxRect(0, 0, 0, 0);
108 if (!(m_priv
->m_hndl
)) return wxRect(0, 0, 0, 0);
109 Rect screenrect
= (*(m_priv
->m_hndl
))->gdRect
;
110 return wxRect( screenrect
.left
, screenrect
.top
,
111 screenrect
.right
- screenrect
.left
, screenrect
.bottom
- screenrect
.top
);
114 int wxDisplay::GetDepth() const
116 if (!(m_priv
)) return 0;
117 if (!(m_priv
->m_hndl
)) return 0;
119 // This cryptic looking code is based on Apple's sample code:
120 // http://developer.apple.com/samplecode/Sample_Code/Graphics_2D/GDevVideo/Gen.cp.htm
122 //RN - according to the docs
123 //gdPMap is a bitmap-type representation of the GDevice, and all
124 //0x0000FFFF does is get the lower 16 bits of pixelSize. However,
125 //since pixelSize is only 16 bits (a short)...
126 return ((*(*(m_priv
->m_hndl
))->gdPMap
)->pixelSize
) & 0x0000FFFF;
129 wxString
wxDisplay::GetName() const
131 // Macs don't name their displays...
132 return wxEmptyString
;
135 struct DMModeIteratorRec
137 wxArrayVideoModes
* pModes
;
138 const wxVideoMode
* pMatchMode
;
141 pascal void DMModeListIteratorProc ( void* pData
,
142 DMListIndexType nIndex
,
143 DMDisplayModeListEntryPtr pInfo
)
145 DMModeIteratorRec
* pInfoData
= (DMModeIteratorRec
*) pData
;
147 //Note that in testing the refresh rate is always 0 on my ibook - RN
148 int refresh
= (int) Fix2Long(pInfo
->displayModeResolutionInfo
->csRefreshRate
);
150 for(unsigned long i
= 0; i
< pInfo
->displayModeDepthBlockInfo
->depthBlockCount
; ++i
)
152 #define pDBI pInfo->displayModeDepthBlockInfo->depthVPBlock[i].depthVPBlock
154 if (wxVideoMode((int) pInfo
->displayModeResolutionInfo
->csHorizontalPixels
,
155 (int) pInfo
->displayModeResolutionInfo
->csVerticalLines
,
156 (int) pDBI
->vpPixelSize
,
157 refresh
).Matches(*pInfoData
->pMatchMode
) )
159 pInfoData
->pModes
->Add(wxVideoMode((int) pInfo
->displayModeResolutionInfo
->csHorizontalPixels
,
160 (int) pInfo
->displayModeResolutionInfo
->csVerticalLines
,
161 (int) pDBI
->vpPixelSize
,
170 const wxVideoMode
* pMode
;
171 VDSwitchInfoRec sMode
;
175 pascal void DMModeInfoProc ( void* pData
,
176 DMListIndexType nIndex
,
177 DMDisplayModeListEntryPtr pInfo
)
179 DMModeInfoRec
* pInfoData
= (DMModeInfoRec
*) pData
;
180 Fixed refresh
= Long2Fix(pInfoData
->pMode
->refresh
);
182 for(unsigned long i
= 0; i
< pInfo
->displayModeDepthBlockInfo
->depthBlockCount
; ++i
)
184 #define pDBI pInfo->displayModeDepthBlockInfo->depthVPBlock[i].depthVPBlock
185 if (pInfoData
->pMode
->w
== (int&) pInfo
->displayModeResolutionInfo
->csHorizontalPixels
&&
186 pInfoData
->pMode
->h
== (int&) pInfo
->displayModeResolutionInfo
->csVerticalLines
&&
187 pInfoData
->pMode
->bpp
== (int) pDBI
->vpPixelSize
&&
188 refresh
== pInfo
->displayModeResolutionInfo
->csRefreshRate
)
190 memcpy(&pInfoData
->sMode
, pInfo
->displayModeDepthBlockInfo
->depthVPBlock
[i
].depthSwitchInfo
,
191 sizeof(VDSwitchInfoRec
));
192 pInfoData
->sMode
.csMode
= pDBI
->vpPixelSize
;
193 pInfoData
->bMatched
= true;
200 struct DMModeTransRec
203 const VDSwitchInfoRec
* psMode
;
207 pascal void DMModeTransProc ( void* pData
,
208 DMListIndexType nIndex
,
209 DMDisplayModeListEntryPtr pInfo
)
211 DMModeTransRec
* pInfoData
= (DMModeTransRec
*) pData
;
213 for(unsigned long i
= 0; i
< pInfo
->displayModeDepthBlockInfo
->depthBlockCount
; ++i
)
215 #define pDBI pInfo->displayModeDepthBlockInfo->depthVPBlock[i].depthVPBlock
216 if (pInfoData
->psMode
->csData
== pInfo
->displayModeDepthBlockInfo
->depthVPBlock
[i
].depthSwitchInfo
->csData
)
218 pInfoData
->Mode
= wxVideoMode((int) pInfo
->displayModeResolutionInfo
->csHorizontalPixels
,
219 (int) pInfo
->displayModeResolutionInfo
->csVerticalLines
,
220 (int) pDBI
->vpPixelSize
,
221 (int) Fix2Long(pInfo
->displayModeResolutionInfo
->csRefreshRate
) );
222 pInfoData
->bMatched
= true;
230 wxDisplay::GetModes(const wxVideoMode
& mode
) const
233 wxArrayVideoModes Modes
;
235 unsigned long dwDMVer
;
236 Gestalt(gestaltDisplayMgrVers
, (long*) &dwDMVer
);
238 //Check DM version (for backward compatibility only - 7.5.3+ use 2.0)
239 if (dwDMVer
>= 0x020000) //version 2?
242 DMListIndexType nNumModes
;
244 DMDisplayModeListIteratorUPP uppMLI
;
245 DisplayIDType nDisplayID
;
247 wxASSERT(DMGetDisplayIDByGDevice(m_priv
->m_hndl
, &nDisplayID
, false) == noErr
);
248 //Create a new list...
249 wxASSERT_MSG(DMNewDisplayModeList(nDisplayID
, NULL
, NULL
, &nNumModes
, &pModes
) == noErr
, wxT("Could not create a new display mode list") );
251 uppMLI
= NewDMDisplayModeListIteratorUPP(DMModeListIteratorProc
);
254 DMModeIteratorRec sModeInfo
;
255 sModeInfo
.pModes
= &Modes
;
256 sModeInfo
.pMatchMode
= &mode
;
257 for (DMListIndexType i
= 0; i
< nNumModes
; ++i
)
259 wxASSERT(DMGetIndexedDisplayModeFromList(pModes
, i
, NULL
,
260 uppMLI
, &sModeInfo
) == noErr
);
262 DisposeDMDisplayModeListIteratorUPP(uppMLI
);
263 wxASSERT(DMDisposeList(pModes
) == noErr
);
265 else //DM 1.0, 1.2, 1.x
267 wxLogSysError(wxString::Format(wxT("Display Manager Version %u Not Supported! Present? %s"),
268 (unsigned int) dwDMVer
/ 0x10000,
269 (dwDMVer
& (1 << gestaltDisplayMgrPresent
) ? wxT("Yes") : wxT("No")) )
276 wxVideoMode
wxDisplay::GetCurrentMode() const
278 unsigned long dwDMVer
;
281 Gestalt(gestaltDisplayMgrVers
, (long*) &dwDMVer
);
282 //Check DM version (for backward compatibility only - 7.5.3+ use 2.0)
283 if (dwDMVer
>= 0x020000) //version 2?
285 VDSwitchInfoRec sMode
; //Note - csMode member also contains the bit depth
286 if (DMGetDisplayMode(m_priv
->m_hndl
, &sMode
) == noErr
)
288 DMListIndexType nNumModes
;
290 DMDisplayModeListIteratorUPP uppMLI
;
291 DisplayIDType nDisplayID
;
293 wxASSERT(DMGetDisplayIDByGDevice(m_priv
->m_hndl
, &nDisplayID
, false) == noErr
);
294 //Create a new list...
295 wxASSERT_MSG(DMNewDisplayModeList(nDisplayID
, NULL
, NULL
, &nNumModes
, &pModes
) == noErr
,
296 wxT("Could not create a new display mode list") );
298 uppMLI
= NewDMDisplayModeListIteratorUPP(DMModeTransProc
);
301 DMModeTransRec sModeInfo
;
302 sModeInfo
.bMatched
= false;
303 sModeInfo
.psMode
= &sMode
;
304 for (DMListIndexType i
= 0; i
< nNumModes
; ++i
)
306 wxASSERT(DMGetIndexedDisplayModeFromList(pModes
, i
, NULL
,
307 uppMLI
, &sModeInfo
) == noErr
);
309 if ( sModeInfo
.bMatched
== true )
311 RetMode
= sModeInfo
.Mode
;
316 DisposeDMDisplayModeListIteratorUPP(uppMLI
);
317 wxASSERT(DMDisposeList(pModes
) == noErr
);
319 else //Can't get current mode?
321 wxLogSysError(wxString::Format(wxT("Couldn't obtain current display mode!!!\ndwDMVer:%u"),
322 (unsigned int) dwDMVer
));
327 wxLogSysError(wxString::Format(wxT("Display Manager Version %u Not Supported! Present? %s"),
328 (unsigned int) dwDMVer
/ 0x10000,
329 (dwDMVer
& (1 << gestaltDisplayMgrPresent
) ? wxT("Yes") : wxT("No")) )
336 bool wxDisplay::ChangeMode(const wxVideoMode
& mode
)
338 unsigned long dwDMVer
;
339 Gestalt(gestaltDisplayMgrVers
, (long*)&dwDMVer
);
340 if (GetCount() == 1 || dwDMVer
>= 0x020000)
342 if (mode
== wxDefaultVideoMode
)
345 // Handle hDisplayState;
346 // if (DMBeginConfigureDisplays(&hDisplayState) != noErr)
348 // wxLogSysError(wxT("Could not lock display for display mode changing!"));
351 // wxASSERT( DMUseScreenPrefs(true, hDisplayState) == noErr);
352 // DMEndConfigureDisplays(hDisplayState);
360 //0 & NULL for params 2 & 3 of DMSetVideoMode signal it to use defaults (current mode)
361 //DM 2.0+ doesn't use params 2 & 3 of DMSetDisplayMode
362 //so we have to use this icky structure
363 VDSwitchInfoRec sMode
;
364 memset(&sMode
, 0, sizeof(VDSwitchInfoRec
) );
366 DMListIndexType nNumModes
;
368 DMDisplayModeListIteratorUPP uppMLI
;
369 DisplayIDType nDisplayID
;
371 wxASSERT(DMGetDisplayIDByGDevice(m_priv
->m_hndl
, &nDisplayID
, false) == noErr
);
372 //Create a new list...
373 wxASSERT_MSG(DMNewDisplayModeList(nDisplayID
, NULL
, NULL
, &nNumModes
, &pModes
) == noErr
,
374 wxT("Could not create a new display mode list") );
376 uppMLI
= NewDMDisplayModeListIteratorUPP(DMModeInfoProc
);
379 DMModeInfoRec sModeInfo
;
380 sModeInfo
.bMatched
= false;
381 sModeInfo
.pMode
= &mode
;
383 for(i
= 0; i
< nNumModes
; ++i
)
385 wxASSERT(DMGetIndexedDisplayModeFromList(pModes
, i
, NULL
,
386 uppMLI
, &sModeInfo
) == noErr
);
387 if (sModeInfo
.bMatched
== true)
389 sMode
= sModeInfo
.sMode
;
396 DisposeDMDisplayModeListIteratorUPP(uppMLI
);
397 wxASSERT(DMDisposeList(pModes
) == noErr
);
399 // For the really paranoid -
400 // unsigned long flags;
402 // wxASSERT(noErr == DMCheckDisplayMode(m_priv->m_hndl, sMode.csData,
403 // sMode.csMode, &flags, NULL, &bok));
406 Handle hDisplayState
;
407 if (DMBeginConfigureDisplays(&hDisplayState
) != noErr
)
409 wxLogSysError(wxT("Could not lock display for display mode changing!"));
413 unsigned long dwBPP
= (unsigned long) mode
.bpp
;
414 if (DMSetDisplayMode(m_priv
->m_hndl
, sMode
.csData
,
415 (unsigned long*) &(dwBPP
), NULL
416 //(unsigned long) &sMode
420 DMEndConfigureDisplays(hDisplayState
);
421 wxMessageBox(wxString::Format(wxT("Could not set the display mode")));
424 DMEndConfigureDisplays(hDisplayState
);
426 else //DM 1.0, 1.2, 1.x
428 wxLogSysError(wxString::Format(wxT("Monitor gravitation not supported yet. dwDMVer:%u"),
429 (unsigned int) dwDMVer
));
436 wxDisplay::~wxDisplay()
445 #endif // wxUSE_DISPLAY