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
36 #include "wx/display.h"
37 #include "wx/gdicmn.h"
38 #include "wx/string.h"
40 // ----------------------------------------------------------------------------
42 // ----------------------------------------------------------------------------
46 class wxDisplayMacPriv
49 CGDirectDisplayID m_id
;
52 size_t wxDisplayBase::GetCount()
55 CGDisplayErr err
= CGGetActiveDisplayList(0, NULL
, &count
);
57 wxASSERT(err
== CGDisplayNoErr
);
62 int wxDisplayBase::GetFromPoint(const wxPoint
&p
)
64 CGPoint thePoint
= {(float)p
.x
, (float)p
.y
};
65 CGDirectDisplayID theID
;
66 CGDisplayCount theCount
;
67 CGDisplayErr err
= CGGetDisplaysWithPoint(thePoint
, 1, &theID
, &theCount
);
68 wxASSERT(err
== CGDisplayNoErr
);
74 theCount
= GetCount();
75 CGDirectDisplayID
* theIDs
= new CGDirectDisplayID
[theCount
];
76 err
= CGGetActiveDisplayList(theCount
, theIDs
, &theCount
);
77 wxASSERT(err
== CGDisplayNoErr
);
79 for (nWhich
= 0; nWhich
< (int) theCount
; ++nWhich
)
81 if (theIDs
[nWhich
] == theID
)
87 if (nWhich
== (int) theCount
)
89 wxFAIL_MSG(wxT("Failed to find display in display list"));
97 wxDisplay::wxDisplay(size_t index
)
98 : wxDisplayBase( index
) ,
99 m_priv( new wxDisplayMacPriv() )
101 CGDisplayCount theCount
= GetCount();
102 CGDirectDisplayID
* theIDs
= new CGDirectDisplayID
[theCount
];
104 CGDisplayErr err
= CGGetActiveDisplayList(theCount
, theIDs
, &theCount
);
106 wxASSERT( err
== CGDisplayNoErr
);
107 wxASSERT( index
< theCount
);
109 m_priv
->m_id
= theIDs
[index
];
114 wxRect
wxDisplay::GetGeometry() const
116 CGRect theRect
= CGDisplayBounds(m_priv
->m_id
);
117 return wxRect( (int)theRect
.origin
.x
,
118 (int)theRect
.origin
.y
,
119 (int)theRect
.size
.width
,
120 (int)theRect
.size
.height
); //floats
123 int wxDisplay::GetDepth() const
125 return (int) CGDisplayBitsPerPixel( m_priv
->m_id
); //size_t
128 wxString
wxDisplay::GetName() const
130 // Macs don't name their displays...
131 return wxEmptyString
;
134 static int wxCFDictKeyToInt( CFDictionaryRef desc
, CFStringRef key
)
136 CFNumberRef value
= (CFNumberRef
) CFDictionaryGetValue( desc
, key
);
141 CFNumberGetValue( value
, kCFNumberIntType
, &num
);
147 wxDisplay::GetModes(const wxVideoMode
& mode
) const
149 wxArrayVideoModes resultModes
;
151 CFArrayRef theArray
= CGDisplayAvailableModes( m_priv
->m_id
);
153 for (CFIndex i
= 0; i
< CFArrayGetCount(theArray
); ++i
)
155 CFDictionaryRef theValue
= (CFDictionaryRef
) CFArrayGetValueAtIndex( theArray
, i
);
158 wxCFDictKeyToInt( theValue
, kCGDisplayWidth
),
159 wxCFDictKeyToInt( theValue
, kCGDisplayHeight
),
160 wxCFDictKeyToInt( theValue
, kCGDisplayBitsPerPixel
),
161 wxCFDictKeyToInt( theValue
, kCGDisplayRefreshRate
));
163 if (theMode
.Matches( mode
))
164 resultModes
.Add( theMode
);
170 wxVideoMode
wxDisplay::GetCurrentMode() const
172 CFDictionaryRef theValue
= CGDisplayCurrentMode( m_priv
->m_id
);
175 wxCFDictKeyToInt( theValue
, kCGDisplayWidth
),
176 wxCFDictKeyToInt( theValue
, kCGDisplayHeight
),
177 wxCFDictKeyToInt( theValue
, kCGDisplayBitsPerPixel
),
178 wxCFDictKeyToInt( theValue
, kCGDisplayRefreshRate
));
181 bool wxDisplay::ChangeMode( const wxVideoMode
& mode
)
183 // Changing to default mode (wxDefaultVideoMode) doesn't
184 // work because we don't have access to the system's 'scrn'
185 // resource which holds the user's mode which the system
186 // will return to after this app is done
187 boolean_t bExactMatch
;
188 CFDictionaryRef theCGMode
= CGDisplayBestModeForParametersAndRefreshRate(
193 (double)mode
.refresh
,
196 bool bOK
= bExactMatch
;
199 bOK
= CGDisplaySwitchToMode( m_priv
->m_id
, theCGMode
) == CGDisplayNoErr
;
204 wxDisplay::~wxDisplay()
215 class wxDisplayMacPriv
221 size_t wxDisplayBase::GetCount()
225 hndl
= DMGetFirstScreenDevice(true);
229 hndl
= DMGetNextScreenDevice(hndl
, true);
235 int wxDisplayBase::GetFromPoint(const wxPoint
&p
)
239 hndl
= DMGetFirstScreenDevice(true);
243 Rect screenrect
= (*hndl
)->gdRect
;
244 if (p
.x
>= screenrect
.left
&&
245 p
.x
<= screenrect
.right
&&
246 p
.y
>= screenrect
.top
&&
247 p
.y
<= screenrect
.bottom
)
253 hndl
= DMGetNextScreenDevice(hndl
, true);
259 wxDisplay::wxDisplay( size_t index
)
260 : wxDisplayBase( index
),
261 m_priv( new wxDisplayMacPriv() )
264 hndl
= DMGetFirstScreenDevice(true);
265 m_priv
->m_hndl
= NULL
;
270 m_priv
->m_hndl
= hndl
;
273 hndl
= DMGetNextScreenDevice(hndl
, true);
277 wxRect
wxDisplay::GetGeometry() const
279 if ((m_priv
== NULL
) || (m_priv
->m_hndl
== NULL
))
280 return wxRect(0, 0, 0, 0);
282 Rect screenrect
= (*(m_priv
->m_hndl
))->gdRect
;
284 screenrect
.left
, screenrect
.top
,
285 screenrect
.right
- screenrect
.left
,
286 screenrect
.bottom
- screenrect
.top
);
289 int wxDisplay::GetDepth() const
291 if ((m_priv
== NULL
) || (m_priv
->m_hndl
== NULL
))
294 // This cryptic looking code is based on Apple's sample code:
295 // http://developer.apple.com/samplecode/Sample_Code/Graphics_2D/GDevVideo/Gen.cp.htm
297 // RN - according to the docs
298 // gdPMap is a bitmap-type representation of the GDevice, and all
299 // 0x0000FFFF does is get the lower 16 bits of pixelSize. However,
300 // since pixelSize is only 16 bits (a short)...
301 return ((*(*(m_priv
->m_hndl
))->gdPMap
)->pixelSize
) & 0x0000FFFF;
304 wxString
wxDisplay::GetName() const
306 // Macs don't name their displays...
307 return wxEmptyString
;
310 struct DMModeIteratorRec
312 wxArrayVideoModes
* pModes
;
313 const wxVideoMode
* pMatchMode
;
316 pascal void DMModeListIteratorProc(
318 DMListIndexType nIndex
,
319 DMDisplayModeListEntryPtr pInfo
)
321 DMModeIteratorRec
* pInfoData
= (DMModeIteratorRec
*) pData
;
323 // Note that in testing the refresh rate is always 0 on my ibook - RN
324 int refresh
= (int) Fix2Long(pInfo
->displayModeResolutionInfo
->csRefreshRate
);
326 #define pDBI pInfo->displayModeDepthBlockInfo->depthVPBlock[i].depthVPBlock
328 for (unsigned long i
= 0; i
< pInfo
->displayModeDepthBlockInfo
->depthBlockCount
; ++i
)
330 if (wxVideoMode( (int) pInfo
->displayModeResolutionInfo
->csHorizontalPixels
,
331 (int) pInfo
->displayModeResolutionInfo
->csVerticalLines
,
332 (int) pDBI
->vpPixelSize
,
333 refresh
).Matches(*pInfoData
->pMatchMode
) )
335 pInfoData
->pModes
->Add(
337 (int) pInfo
->displayModeResolutionInfo
->csHorizontalPixels
,
338 (int) pInfo
->displayModeResolutionInfo
->csVerticalLines
,
339 (int) pDBI
->vpPixelSize
,
349 const wxVideoMode
* pMode
;
350 VDSwitchInfoRec sMode
;
354 pascal void DMModeInfoProc(
356 DMListIndexType nIndex
,
357 DMDisplayModeListEntryPtr pInfo
)
359 DMModeInfoRec
* pInfoData
= (DMModeInfoRec
*) pData
;
360 Fixed refresh
= Long2Fix(pInfoData
->pMode
->refresh
);
362 #define pDBI pInfo->displayModeDepthBlockInfo->depthVPBlock[i].depthVPBlock
364 for (unsigned long i
= 0; i
< pInfo
->displayModeDepthBlockInfo
->depthBlockCount
; ++i
)
366 if (pInfoData
->pMode
->w
== (int&) pInfo
->displayModeResolutionInfo
->csHorizontalPixels
&&
367 pInfoData
->pMode
->h
== (int&) pInfo
->displayModeResolutionInfo
->csVerticalLines
&&
368 pInfoData
->pMode
->bpp
== (int) pDBI
->vpPixelSize
&&
369 refresh
== pInfo
->displayModeResolutionInfo
->csRefreshRate
)
373 pInfo
->displayModeDepthBlockInfo
->depthVPBlock
[i
].depthSwitchInfo
,
374 sizeof(VDSwitchInfoRec
));
375 pInfoData
->sMode
.csMode
= pDBI
->vpPixelSize
;
376 pInfoData
->bMatched
= true;
384 struct DMModeTransRec
387 const VDSwitchInfoRec
* psMode
;
391 pascal void DMModeTransProc(
393 DMListIndexType nIndex
,
394 DMDisplayModeListEntryPtr pInfo
)
396 DMModeTransRec
* pInfoData
= (DMModeTransRec
*) pData
;
398 #define pDBI pInfo->displayModeDepthBlockInfo->depthVPBlock[i].depthVPBlock
400 for (unsigned long i
= 0; i
< pInfo
->displayModeDepthBlockInfo
->depthBlockCount
; ++i
)
402 if (pInfoData
->psMode
->csData
== pInfo
->displayModeDepthBlockInfo
->depthVPBlock
[i
].depthSwitchInfo
->csData
)
404 pInfoData
->Mode
= wxVideoMode(
405 (int) pInfo
->displayModeResolutionInfo
->csHorizontalPixels
,
406 (int) pInfo
->displayModeResolutionInfo
->csVerticalLines
,
407 (int) pDBI
->vpPixelSize
,
408 (int) Fix2Long(pInfo
->displayModeResolutionInfo
->csRefreshRate
) );
409 pInfoData
->bMatched
= true;
418 wxDisplay::GetModes(const wxVideoMode
& mode
) const
420 wxArrayVideoModes Modes
;
421 unsigned long dwDMVer
;
423 // Check DM version == 2
424 // (for backward compatibility only - 7.5.3+ use 2.0)
425 Gestalt( gestaltDisplayMgrVers
, (long*) &dwDMVer
);
426 if (dwDMVer
>= 0x020000)
428 DMListIndexType nNumModes
;
430 DMDisplayModeListIteratorUPP uppMLI
;
431 DisplayIDType nDisplayID
;
434 err
= DMGetDisplayIDByGDevice(m_priv
->m_hndl
, &nDisplayID
, false);
437 // Create a new list...
438 err
= DMNewDisplayModeList(nDisplayID
, NULL
, NULL
, &nNumModes
, &pModes
);
439 wxASSERT_MSG( err
== noErr
, wxT("Could not create a new display mode list") );
441 uppMLI
= NewDMDisplayModeListIteratorUPP(DMModeListIteratorProc
);
444 DMModeIteratorRec sModeInfo
;
445 sModeInfo
.pModes
= &Modes
;
446 sModeInfo
.pMatchMode
= &mode
;
448 for (DMListIndexType i
= 0; i
< nNumModes
; ++i
)
450 err
= DMGetIndexedDisplayModeFromList(pModes
, i
, NULL
, uppMLI
, &sModeInfo
);
454 DisposeDMDisplayModeListIteratorUPP(uppMLI
);
455 err
= DMDisposeList(pModes
);
458 else // DM 1.0, 1.2, 1.x
462 wxT("Display Manager Version %u Not Supported! Present? %s"),
463 (unsigned int) dwDMVer
/ 0x10000,
464 (dwDMVer
& (1 << gestaltDisplayMgrPresent
) ? wxT("Yes") : wxT("No")) ) );
470 wxVideoMode
wxDisplay::GetCurrentMode() const
472 unsigned long dwDMVer
;
475 // Check DM version == 2
476 // (for backward compatibility only - 7.5.3+ use 2.0)
477 Gestalt( gestaltDisplayMgrVers
, (long*) &dwDMVer
);
478 if (dwDMVer
>= 0x020000)
480 VDSwitchInfoRec sMode
; // Note: csMode member also contains the bit depth
483 err
= DMGetDisplayMode( m_priv
->m_hndl
, &sMode
);
486 DMListIndexType nNumModes
;
488 DMDisplayModeListIteratorUPP uppMLI
;
489 DisplayIDType nDisplayID
;
491 err
= DMGetDisplayIDByGDevice(m_priv
->m_hndl
, &nDisplayID
, false);
494 // Create a new list...
495 err
= DMNewDisplayModeList(nDisplayID
, NULL
, NULL
, &nNumModes
, &pModes
);
496 wxASSERT_MSG( err
== noErr
, wxT("Could not create a new display mode list") );
498 uppMLI
= NewDMDisplayModeListIteratorUPP(DMModeTransProc
);
501 DMModeTransRec sModeInfo
;
502 sModeInfo
.bMatched
= false;
503 sModeInfo
.psMode
= &sMode
;
504 for (DMListIndexType i
= 0; i
< nNumModes
; ++i
)
506 err
= DMGetIndexedDisplayModeFromList(pModes
, i
, NULL
, uppMLI
, &sModeInfo
);
509 if ( sModeInfo
.bMatched
)
511 RetMode
= sModeInfo
.Mode
;
516 DisposeDMDisplayModeListIteratorUPP(uppMLI
);
517 err
= DMDisposeList(pModes
);
520 else // Can't get current mode?
524 wxT("Couldn't obtain current display mode!!!\ndwDMVer:%u"),
525 (unsigned int) dwDMVer
));
532 wxT("Display Manager Version %u Not Supported! Present? %s"),
533 (unsigned int) dwDMVer
/ 0x10000,
534 (dwDMVer
& (1 << gestaltDisplayMgrPresent
) ? wxT("Yes") : wxT("No")) ) );
540 bool wxDisplay::ChangeMode(const wxVideoMode
& mode
)
542 unsigned long dwDMVer
;
544 Gestalt( gestaltDisplayMgrVers
, (long*)&dwDMVer
);
545 if (GetCount() == 1 || dwDMVer
>= 0x020000)
547 if (mode
== wxDefaultVideoMode
)
553 // Handle hDisplayState;
554 // if (DMBeginConfigureDisplays(&hDisplayState) != noErr)
556 // wxLogSysError(wxT("Could not lock display for display mode changing!"));
560 // wxASSERT( DMUseScreenPrefs(true, hDisplayState) == noErr);
561 // DMEndConfigureDisplays(hDisplayState);
570 //0 & NULL for params 2 & 3 of DMSetVideoMode signal it to use defaults (current mode)
571 //DM 2.0+ doesn't use params 2 & 3 of DMSetDisplayMode
572 //so we have to use this icky structure
573 VDSwitchInfoRec sMode
;
574 memset( &sMode
, 0, sizeof(VDSwitchInfoRec
) );
576 DMListIndexType nNumModes
;
578 DMDisplayModeListIteratorUPP uppMLI
;
579 DisplayIDType nDisplayID
;
582 err
= DMGetDisplayIDByGDevice(m_priv
->m_hndl
, &nDisplayID
, false);
585 // Create a new list...
586 err
= DMNewDisplayModeList(nDisplayID
, NULL
, NULL
, &nNumModes
, &pModes
);
587 wxASSERT_MSG(err
== noErr
, wxT("Could not create a new display mode list") );
589 uppMLI
= NewDMDisplayModeListIteratorUPP(DMModeInfoProc
);
592 DMModeInfoRec sModeInfo
;
593 sModeInfo
.bMatched
= false;
594 sModeInfo
.pMode
= &mode
;
597 for (i
= 0; i
< nNumModes
; ++i
)
599 err
= DMGetIndexedDisplayModeFromList(pModes
, i
, NULL
, uppMLI
, &sModeInfo
);
602 if (sModeInfo
.bMatched
)
604 sMode
= sModeInfo
.sMode
;
612 DisposeDMDisplayModeListIteratorUPP(uppMLI
);
614 err
= DMDisposeList(pModes
);
617 // For the really paranoid -
618 // unsigned long flags;
620 // wxASSERT(noErr == DMCheckDisplayMode(m_priv->m_hndl, sMode.csData,
621 // sMode.csMode, &flags, NULL, &bok));
624 Handle hDisplayState
;
625 if (DMBeginConfigureDisplays(&hDisplayState
) != noErr
)
627 wxLogSysError(wxT("Could not lock display for display mode changing!"));
632 unsigned long dwBPP
= (unsigned long) mode
.bpp
;
633 err
= DMSetDisplayMode(
634 m_priv
->m_hndl
, sMode
.csData
,
635 (unsigned long*) &(dwBPP
),
636 NULL
, //(unsigned long) &sMode
641 DMEndConfigureDisplays(hDisplayState
);
642 wxMessageBox( wxString::Format(wxT("Could not set the display mode")) );
647 DMEndConfigureDisplays(hDisplayState
);
649 else // DM 1.0, 1.2, 1.x
653 wxT("Monitor gravitation not supported yet. dwDMVer:%u"),
654 (unsigned int) dwDMVer
));
662 wxDisplay::~wxDisplay()
673 #endif // wxUSE_DISPLAY