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 #include "wx/wxprec.h"
21 #include "wx/dynarray.h"
23 #include "wx/msgdlg.h"
27 #include <Carbon/Carbon.h>
31 #include <Quickdraw.h>
32 #include <Video.h> // for VDSwitchInfoRec
34 #include <Debugging.h>
37 #include "wx/display.h"
38 #include "wx/gdicmn.h"
39 #include "wx/string.h"
41 // ----------------------------------------------------------------------------
43 // ----------------------------------------------------------------------------
47 class wxDisplayMacPriv
50 CGDirectDisplayID m_id
;
53 size_t wxDisplayBase::GetCount()
56 CGDisplayErr err
= CGGetActiveDisplayList(0, NULL
, &count
);
58 wxASSERT(err
== CGDisplayNoErr
);
63 int wxDisplayBase::GetFromPoint(const wxPoint
&p
)
65 CGPoint thePoint
= {(float)p
.x
, (float)p
.y
};
66 CGDirectDisplayID theID
;
67 CGDisplayCount theCount
;
68 CGDisplayErr err
= CGGetDisplaysWithPoint(thePoint
, 1, &theID
, &theCount
);
69 wxASSERT(err
== CGDisplayNoErr
);
75 theCount
= GetCount();
76 CGDirectDisplayID
* theIDs
= new CGDirectDisplayID
[theCount
];
77 err
= CGGetActiveDisplayList(theCount
, theIDs
, &theCount
);
78 wxASSERT(err
== CGDisplayNoErr
);
80 for (nWhich
= 0; nWhich
< (int) theCount
; ++nWhich
)
82 if (theIDs
[nWhich
] == theID
)
88 if (nWhich
== (int) theCount
)
90 wxFAIL_MSG(wxT("Failed to find display in display list"));
98 wxDisplay::wxDisplay(size_t index
)
99 : wxDisplayBase( index
) ,
100 m_priv( new wxDisplayMacPriv() )
102 CGDisplayCount theCount
= GetCount();
103 CGDirectDisplayID
* theIDs
= new CGDirectDisplayID
[theCount
];
105 CGDisplayErr err
= CGGetActiveDisplayList(theCount
, theIDs
, &theCount
);
107 wxASSERT( err
== CGDisplayNoErr
);
108 wxASSERT( index
< theCount
);
110 m_priv
->m_id
= theIDs
[index
];
115 wxRect
wxDisplay::GetGeometry() const
117 CGRect theRect
= CGDisplayBounds(m_priv
->m_id
);
118 return wxRect( (int)theRect
.origin
.x
,
119 (int)theRect
.origin
.y
,
120 (int)theRect
.size
.width
,
121 (int)theRect
.size
.height
); //floats
124 int wxDisplay::GetDepth() const
126 return (int) CGDisplayBitsPerPixel( m_priv
->m_id
); //size_t
129 wxString
wxDisplay::GetName() const
131 // Macs don't name their displays...
132 return wxEmptyString
;
135 static int wxCFDictKeyToInt( CFDictionaryRef desc
, CFStringRef key
)
137 CFNumberRef value
= (CFNumberRef
) CFDictionaryGetValue( desc
, key
);
142 CFNumberGetValue( value
, kCFNumberIntType
, &num
);
148 wxDisplay::GetModes(const wxVideoMode
& mode
) const
150 wxArrayVideoModes resultModes
;
152 CFArrayRef theArray
= CGDisplayAvailableModes( m_priv
->m_id
);
154 for (CFIndex i
= 0; i
< CFArrayGetCount(theArray
); ++i
)
156 CFDictionaryRef theValue
= (CFDictionaryRef
) CFArrayGetValueAtIndex( theArray
, i
);
159 wxCFDictKeyToInt( theValue
, kCGDisplayWidth
),
160 wxCFDictKeyToInt( theValue
, kCGDisplayHeight
),
161 wxCFDictKeyToInt( theValue
, kCGDisplayBitsPerPixel
),
162 wxCFDictKeyToInt( theValue
, kCGDisplayRefreshRate
));
164 if (theMode
.Matches( mode
))
165 resultModes
.Add( theMode
);
171 wxVideoMode
wxDisplay::GetCurrentMode() const
173 CFDictionaryRef theValue
= CGDisplayCurrentMode( m_priv
->m_id
);
176 wxCFDictKeyToInt( theValue
, kCGDisplayWidth
),
177 wxCFDictKeyToInt( theValue
, kCGDisplayHeight
),
178 wxCFDictKeyToInt( theValue
, kCGDisplayBitsPerPixel
),
179 wxCFDictKeyToInt( theValue
, kCGDisplayRefreshRate
));
182 bool wxDisplay::ChangeMode( const wxVideoMode
& mode
)
184 // Changing to default mode (wxDefaultVideoMode) doesn't
185 // work because we don't have access to the system's 'scrn'
186 // resource which holds the user's mode which the system
187 // will return to after this app is done
188 boolean_t bExactMatch
;
189 CFDictionaryRef theCGMode
= CGDisplayBestModeForParametersAndRefreshRate(
194 (double)mode
.refresh
,
197 bool bOK
= bExactMatch
;
200 bOK
= CGDisplaySwitchToMode( m_priv
->m_id
, theCGMode
) == CGDisplayNoErr
;
205 wxDisplay::~wxDisplay()
216 class wxDisplayMacPriv
222 size_t wxDisplayBase::GetCount()
226 hndl
= DMGetFirstScreenDevice(true);
230 hndl
= DMGetNextScreenDevice(hndl
, true);
236 int wxDisplayBase::GetFromPoint(const wxPoint
&p
)
240 hndl
= DMGetFirstScreenDevice(true);
244 Rect screenrect
= (*hndl
)->gdRect
;
245 if (p
.x
>= screenrect
.left
&&
246 p
.x
<= screenrect
.right
&&
247 p
.y
>= screenrect
.top
&&
248 p
.y
<= screenrect
.bottom
)
254 hndl
= DMGetNextScreenDevice(hndl
, true);
260 wxDisplay::wxDisplay( size_t index
)
261 : wxDisplayBase( index
),
262 m_priv( new wxDisplayMacPriv() )
265 hndl
= DMGetFirstScreenDevice(true);
266 m_priv
->m_hndl
= NULL
;
271 m_priv
->m_hndl
= hndl
;
274 hndl
= DMGetNextScreenDevice(hndl
, true);
278 wxRect
wxDisplay::GetGeometry() const
280 if ((m_priv
== NULL
) || (m_priv
->m_hndl
== NULL
))
281 return wxRect(0, 0, 0, 0);
283 Rect screenrect
= (*(m_priv
->m_hndl
))->gdRect
;
285 screenrect
.left
, screenrect
.top
,
286 screenrect
.right
- screenrect
.left
,
287 screenrect
.bottom
- screenrect
.top
);
290 int wxDisplay::GetDepth() const
292 if ((m_priv
== NULL
) || (m_priv
->m_hndl
== NULL
))
295 // This cryptic looking code is based on Apple's sample code:
296 // http://developer.apple.com/samplecode/Sample_Code/Graphics_2D/GDevVideo/Gen.cp.htm
298 // RN - according to the docs
299 // gdPMap is a bitmap-type representation of the GDevice, and all
300 // 0x0000FFFF does is get the lower 16 bits of pixelSize. However,
301 // since pixelSize is only 16 bits (a short)...
302 return ((*(*(m_priv
->m_hndl
))->gdPMap
)->pixelSize
) & 0x0000FFFF;
305 wxString
wxDisplay::GetName() const
307 // Macs don't name their displays...
308 return wxEmptyString
;
311 struct DMModeIteratorRec
313 wxArrayVideoModes
* pModes
;
314 const wxVideoMode
* pMatchMode
;
317 pascal void DMModeListIteratorProc(
319 DMListIndexType nIndex
,
320 DMDisplayModeListEntryPtr pInfo
)
322 DMModeIteratorRec
* pInfoData
= (DMModeIteratorRec
*) pData
;
324 // Note that in testing the refresh rate is always 0 on my ibook - RN
325 int refresh
= (int) Fix2Long(pInfo
->displayModeResolutionInfo
->csRefreshRate
);
327 #define pDBI pInfo->displayModeDepthBlockInfo->depthVPBlock[i].depthVPBlock
329 for (unsigned long i
= 0; i
< pInfo
->displayModeDepthBlockInfo
->depthBlockCount
; ++i
)
331 if (wxVideoMode( (int) pInfo
->displayModeResolutionInfo
->csHorizontalPixels
,
332 (int) pInfo
->displayModeResolutionInfo
->csVerticalLines
,
333 (int) pDBI
->vpPixelSize
,
334 refresh
).Matches(*pInfoData
->pMatchMode
) )
336 pInfoData
->pModes
->Add(
338 (int) pInfo
->displayModeResolutionInfo
->csHorizontalPixels
,
339 (int) pInfo
->displayModeResolutionInfo
->csVerticalLines
,
340 (int) pDBI
->vpPixelSize
,
350 const wxVideoMode
* pMode
;
351 VDSwitchInfoRec sMode
;
355 pascal void DMModeInfoProc(
357 DMListIndexType nIndex
,
358 DMDisplayModeListEntryPtr pInfo
)
360 DMModeInfoRec
* pInfoData
= (DMModeInfoRec
*) pData
;
361 Fixed refresh
= Long2Fix(pInfoData
->pMode
->refresh
);
363 #define pDBI pInfo->displayModeDepthBlockInfo->depthVPBlock[i].depthVPBlock
365 for (unsigned long i
= 0; i
< pInfo
->displayModeDepthBlockInfo
->depthBlockCount
; ++i
)
367 if (pInfoData
->pMode
->w
== (int&) pInfo
->displayModeResolutionInfo
->csHorizontalPixels
&&
368 pInfoData
->pMode
->h
== (int&) pInfo
->displayModeResolutionInfo
->csVerticalLines
&&
369 pInfoData
->pMode
->bpp
== (int) pDBI
->vpPixelSize
&&
370 refresh
== pInfo
->displayModeResolutionInfo
->csRefreshRate
)
374 pInfo
->displayModeDepthBlockInfo
->depthVPBlock
[i
].depthSwitchInfo
,
375 sizeof(VDSwitchInfoRec
));
376 pInfoData
->sMode
.csMode
= pDBI
->vpPixelSize
;
377 pInfoData
->bMatched
= true;
385 struct DMModeTransRec
388 const VDSwitchInfoRec
* psMode
;
392 pascal void DMModeTransProc(
394 DMListIndexType nIndex
,
395 DMDisplayModeListEntryPtr pInfo
)
397 DMModeTransRec
* pInfoData
= (DMModeTransRec
*) pData
;
399 #define pDBI pInfo->displayModeDepthBlockInfo->depthVPBlock[i].depthVPBlock
401 for (unsigned long i
= 0; i
< pInfo
->displayModeDepthBlockInfo
->depthBlockCount
; ++i
)
403 if (pInfoData
->psMode
->csData
== pInfo
->displayModeDepthBlockInfo
->depthVPBlock
[i
].depthSwitchInfo
->csData
)
405 pInfoData
->Mode
= wxVideoMode(
406 (int) pInfo
->displayModeResolutionInfo
->csHorizontalPixels
,
407 (int) pInfo
->displayModeResolutionInfo
->csVerticalLines
,
408 (int) pDBI
->vpPixelSize
,
409 (int) Fix2Long(pInfo
->displayModeResolutionInfo
->csRefreshRate
) );
410 pInfoData
->bMatched
= true;
419 wxDisplay::GetModes(const wxVideoMode
& mode
) const
421 wxArrayVideoModes Modes
;
422 unsigned long dwDMVer
;
424 // Check DM version == 2
425 // (for backward compatibility only - 7.5.3+ use 2.0)
426 Gestalt( gestaltDisplayMgrVers
, (long*) &dwDMVer
);
427 if (dwDMVer
>= 0x020000)
429 DMListIndexType nNumModes
;
431 DMDisplayModeListIteratorUPP uppMLI
;
432 DisplayIDType nDisplayID
;
435 err
= DMGetDisplayIDByGDevice(m_priv
->m_hndl
, &nDisplayID
, false);
438 // Create a new list...
439 err
= DMNewDisplayModeList(nDisplayID
, NULL
, NULL
, &nNumModes
, &pModes
);
440 wxASSERT_MSG( err
== noErr
, wxT("Could not create a new display mode list") );
442 uppMLI
= NewDMDisplayModeListIteratorUPP(DMModeListIteratorProc
);
445 DMModeIteratorRec sModeInfo
;
446 sModeInfo
.pModes
= &Modes
;
447 sModeInfo
.pMatchMode
= &mode
;
449 for (DMListIndexType i
= 0; i
< nNumModes
; ++i
)
451 err
= DMGetIndexedDisplayModeFromList(pModes
, i
, NULL
, uppMLI
, &sModeInfo
);
455 DisposeDMDisplayModeListIteratorUPP(uppMLI
);
456 err
= DMDisposeList(pModes
);
459 else // DM 1.0, 1.2, 1.x
463 wxT("Display Manager Version %u Not Supported! Present? %s"),
464 (unsigned int) dwDMVer
/ 0x10000,
465 (dwDMVer
& (1 << gestaltDisplayMgrPresent
) ? wxT("Yes") : wxT("No")) ) );
471 wxVideoMode
wxDisplay::GetCurrentMode() const
473 unsigned long dwDMVer
;
476 // Check DM version == 2
477 // (for backward compatibility only - 7.5.3+ use 2.0)
478 Gestalt( gestaltDisplayMgrVers
, (long*) &dwDMVer
);
479 if (dwDMVer
>= 0x020000)
481 VDSwitchInfoRec sMode
; // Note: csMode member also contains the bit depth
484 err
= DMGetDisplayMode( m_priv
->m_hndl
, &sMode
);
487 DMListIndexType nNumModes
;
489 DMDisplayModeListIteratorUPP uppMLI
;
490 DisplayIDType nDisplayID
;
492 err
= DMGetDisplayIDByGDevice(m_priv
->m_hndl
, &nDisplayID
, false);
495 // Create a new list...
496 err
= DMNewDisplayModeList(nDisplayID
, NULL
, NULL
, &nNumModes
, &pModes
);
497 wxASSERT_MSG( err
== noErr
, wxT("Could not create a new display mode list") );
499 uppMLI
= NewDMDisplayModeListIteratorUPP(DMModeTransProc
);
502 DMModeTransRec sModeInfo
;
503 sModeInfo
.bMatched
= false;
504 sModeInfo
.psMode
= &sMode
;
505 for (DMListIndexType i
= 0; i
< nNumModes
; ++i
)
507 err
= DMGetIndexedDisplayModeFromList(pModes
, i
, NULL
, uppMLI
, &sModeInfo
);
510 if ( sModeInfo
.bMatched
)
512 RetMode
= sModeInfo
.Mode
;
517 DisposeDMDisplayModeListIteratorUPP(uppMLI
);
518 err
= DMDisposeList(pModes
);
521 else // Can't get current mode?
525 wxT("Couldn't obtain current display mode!!!\ndwDMVer:%u"),
526 (unsigned int) dwDMVer
));
533 wxT("Display Manager Version %u Not Supported! Present? %s"),
534 (unsigned int) dwDMVer
/ 0x10000,
535 (dwDMVer
& (1 << gestaltDisplayMgrPresent
) ? wxT("Yes") : wxT("No")) ) );
541 bool wxDisplay::ChangeMode(const wxVideoMode
& mode
)
543 unsigned long dwDMVer
;
545 Gestalt( gestaltDisplayMgrVers
, (long*)&dwDMVer
);
546 if (GetCount() == 1 || dwDMVer
>= 0x020000)
548 if (mode
== wxDefaultVideoMode
)
554 // Handle hDisplayState;
555 // if (DMBeginConfigureDisplays(&hDisplayState) != noErr)
557 // wxLogSysError(wxT("Could not lock display for display mode changing!"));
561 // wxASSERT( DMUseScreenPrefs(true, hDisplayState) == noErr);
562 // DMEndConfigureDisplays(hDisplayState);
571 //0 & NULL for params 2 & 3 of DMSetVideoMode signal it to use defaults (current mode)
572 //DM 2.0+ doesn't use params 2 & 3 of DMSetDisplayMode
573 //so we have to use this icky structure
574 VDSwitchInfoRec sMode
;
575 memset( &sMode
, 0, sizeof(VDSwitchInfoRec
) );
577 DMListIndexType nNumModes
;
579 DMDisplayModeListIteratorUPP uppMLI
;
580 DisplayIDType nDisplayID
;
583 err
= DMGetDisplayIDByGDevice(m_priv
->m_hndl
, &nDisplayID
, false);
586 // Create a new list...
587 err
= DMNewDisplayModeList(nDisplayID
, NULL
, NULL
, &nNumModes
, &pModes
);
588 wxASSERT_MSG(err
== noErr
, wxT("Could not create a new display mode list") );
590 uppMLI
= NewDMDisplayModeListIteratorUPP(DMModeInfoProc
);
593 DMModeInfoRec sModeInfo
;
594 sModeInfo
.bMatched
= false;
595 sModeInfo
.pMode
= &mode
;
598 for (i
= 0; i
< nNumModes
; ++i
)
600 err
= DMGetIndexedDisplayModeFromList(pModes
, i
, NULL
, uppMLI
, &sModeInfo
);
603 if (sModeInfo
.bMatched
)
605 sMode
= sModeInfo
.sMode
;
613 DisposeDMDisplayModeListIteratorUPP(uppMLI
);
615 err
= DMDisposeList(pModes
);
618 // For the really paranoid -
619 // unsigned long flags;
621 // wxASSERT(noErr == DMCheckDisplayMode(m_priv->m_hndl, sMode.csData,
622 // sMode.csMode, &flags, NULL, &bok));
625 Handle hDisplayState
;
626 if (DMBeginConfigureDisplays(&hDisplayState
) != noErr
)
628 wxLogSysError(wxT("Could not lock display for display mode changing!"));
633 unsigned long dwBPP
= (unsigned long) mode
.bpp
;
634 err
= DMSetDisplayMode(
635 m_priv
->m_hndl
, sMode
.csData
,
636 (unsigned long*) &(dwBPP
),
637 NULL
, //(unsigned long) &sMode
642 DMEndConfigureDisplays(hDisplayState
);
643 wxMessageBox( wxString::Format(wxT("Could not set the display mode")) );
648 DMEndConfigureDisplays(hDisplayState
);
650 else // DM 1.0, 1.2, 1.x
654 wxT("Monitor gravitation not supported yet. dwDMVer:%u"),
655 (unsigned int) dwDMVer
));
663 wxDisplay::~wxDisplay()
674 #endif // wxUSE_DISPLAY