1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/mac/carbon/display.cpp
3 // Purpose: Mac implementation of wxDisplay class
4 // Author: Ryan Norton & Brian Victor
5 // Modified by: Royce Mitchell III, Vadim Zeitlin
8 // Copyright: (c) wxWidgets team
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // ============================================================================
14 // ============================================================================
16 // ----------------------------------------------------------------------------
18 // ----------------------------------------------------------------------------
20 #include "wx/wxprec.h"
28 #include "wx/display.h"
31 #include "wx/dynarray.h"
33 #include "wx/string.h"
34 #include "wx/gdicmn.h"
38 #include <Carbon/Carbon.h>
42 #include <Quickdraw.h>
43 #include <Video.h> // for VDSwitchInfoRec
45 #include <Debugging.h>
48 #include "wx/display_impl.h"
50 // ----------------------------------------------------------------------------
51 // display classes implementation
52 // ----------------------------------------------------------------------------
56 class wxDisplayImplMacOSX
: public wxDisplayImpl
59 wxDisplayImplMacOSX(unsigned n
, CGDirectDisplayID id
)
65 virtual wxRect
GetGeometry() const;
66 virtual wxRect
GetClientArea() const;
67 virtual wxString
GetName() const { return wxString(); }
69 virtual wxArrayVideoModes
GetModes(const wxVideoMode
& mode
) const;
70 virtual wxVideoMode
GetCurrentMode() const;
71 virtual bool ChangeMode(const wxVideoMode
& mode
);
74 CGDirectDisplayID m_id
;
76 DECLARE_NO_COPY_CLASS(wxDisplayImplMacOSX
)
79 class wxDisplayFactoryMacOSX
: public wxDisplayFactory
82 wxDisplayFactoryMacOSX() {}
84 virtual wxDisplayImpl
*CreateDisplay(unsigned n
);
85 virtual unsigned GetCount();
86 virtual int GetFromPoint(const wxPoint
& pt
);
89 DECLARE_NO_COPY_CLASS(wxDisplayFactoryMacOSX
)
92 // ============================================================================
93 // wxDisplayFactoryMacOSX implementation
94 // ============================================================================
96 unsigned wxDisplayFactoryMacOSX::GetCount()
102 CGGetActiveDisplayList(0, NULL
, &count
);
104 wxASSERT(err
== CGDisplayNoErr
);
109 int wxDisplayFactoryMacOSX::GetFromPoint(const wxPoint
& p
)
111 CGPoint thePoint
= {(float)p
.x
, (float)p
.y
};
112 CGDirectDisplayID theID
;
113 CGDisplayCount theCount
;
114 CGDisplayErr err
= CGGetDisplaysWithPoint(thePoint
, 1, &theID
, &theCount
);
115 wxASSERT(err
== CGDisplayNoErr
);
117 int nWhich
= wxNOT_FOUND
;
121 theCount
= GetCount();
122 CGDirectDisplayID
* theIDs
= new CGDirectDisplayID
[theCount
];
123 err
= CGGetActiveDisplayList(theCount
, theIDs
, &theCount
);
124 wxASSERT(err
== CGDisplayNoErr
);
126 for (nWhich
= 0; nWhich
< (int) theCount
; ++nWhich
)
128 if (theIDs
[nWhich
] == theID
)
134 if (nWhich
== (int) theCount
)
136 wxFAIL_MSG(wxT("Failed to find display in display list"));
137 nWhich
= wxNOT_FOUND
;
144 wxDisplayImpl
*wxDisplayFactoryMacOSX::CreateDisplay(unsigned n
)
146 CGDisplayCount theCount
= GetCount();
147 CGDirectDisplayID
* theIDs
= new CGDirectDisplayID
[theCount
];
152 CGGetActiveDisplayList(theCount
, theIDs
, &theCount
);
154 wxASSERT( err
== CGDisplayNoErr
);
155 wxASSERT( n
< theCount
);
157 wxDisplayImplMacOSX
*display
= new wxDisplayImplMacOSX(n
, theIDs
[n
]);
164 // ============================================================================
165 // wxDisplayImplMacOSX implementation
166 // ============================================================================
168 wxRect
wxDisplayImplMacOSX::GetGeometry() const
170 CGRect theRect
= CGDisplayBounds(m_id
);
171 return wxRect( (int)theRect
.origin
.x
,
172 (int)theRect
.origin
.y
,
173 (int)theRect
.size
.width
,
174 (int)theRect
.size
.height
); //floats
177 wxRect
wxDisplayImplMacOSX::GetClientArea() const
179 // VZ: I don't know how to get client area for arbitrary display but
180 // wxGetClientDisplayRect() does work correctly for at least the main
181 // one (TODO: do it correctly for the other displays too)
183 return wxGetClientDisplayRect();
185 return wxDisplayImpl::GetClientArea();
188 static int wxCFDictKeyToInt( CFDictionaryRef desc
, CFStringRef key
)
190 CFNumberRef value
= (CFNumberRef
) CFDictionaryGetValue( desc
, key
);
195 CFNumberGetValue( value
, kCFNumberIntType
, &num
);
200 wxArrayVideoModes
wxDisplayImplMacOSX::GetModes(const wxVideoMode
& mode
) const
202 wxArrayVideoModes resultModes
;
204 CFArrayRef theArray
= CGDisplayAvailableModes( m_id
);
206 for (CFIndex i
= 0; i
< CFArrayGetCount(theArray
); ++i
)
208 CFDictionaryRef theValue
= (CFDictionaryRef
) CFArrayGetValueAtIndex( theArray
, i
);
211 wxCFDictKeyToInt( theValue
, kCGDisplayWidth
),
212 wxCFDictKeyToInt( theValue
, kCGDisplayHeight
),
213 wxCFDictKeyToInt( theValue
, kCGDisplayBitsPerPixel
),
214 wxCFDictKeyToInt( theValue
, kCGDisplayRefreshRate
));
216 if (theMode
.Matches( mode
))
217 resultModes
.Add( theMode
);
223 wxVideoMode
wxDisplayImplMacOSX::GetCurrentMode() const
225 CFDictionaryRef theValue
= CGDisplayCurrentMode( m_id
);
228 wxCFDictKeyToInt( theValue
, kCGDisplayWidth
),
229 wxCFDictKeyToInt( theValue
, kCGDisplayHeight
),
230 wxCFDictKeyToInt( theValue
, kCGDisplayBitsPerPixel
),
231 wxCFDictKeyToInt( theValue
, kCGDisplayRefreshRate
));
234 bool wxDisplayImplMacOSX::ChangeMode( const wxVideoMode
& mode
)
236 // Changing to default mode (wxDefaultVideoMode) doesn't
237 // work because we don't have access to the system's 'scrn'
238 // resource which holds the user's mode which the system
239 // will return to after this app is done
240 boolean_t bExactMatch
;
241 CFDictionaryRef theCGMode
= CGDisplayBestModeForParametersAndRefreshRate(
246 (double)mode
.refresh
,
249 bool bOK
= bExactMatch
;
252 bOK
= CGDisplaySwitchToMode( m_id
, theCGMode
) == CGDisplayNoErr
;
257 // ============================================================================
258 // wxDisplay::CreateFactory()
259 // ============================================================================
261 /* static */ wxDisplayFactory
*wxDisplay::CreateFactory()
263 return new wxDisplayFactoryMacOSX
;
266 #else // !__WXMAC_OSX__
268 class wxDisplayImplMac
: public wxDisplayImpl
271 wxDisplayImplMac(unsigned n
, GDHandle hndl
)
277 virtual wxRect
GetGeometry() const;
278 virtual wxString
GetName() const { return wxString(); }
280 virtual wxArrayVideoModes
GetModes(const wxVideoMode
& mode
) const;
281 virtual wxVideoMode
GetCurrentMode() const;
282 virtual bool ChangeMode(const wxVideoMode
& mode
);
287 DECLARE_NO_COPY_CLASS(wxDisplayImplMac
)
290 class wxDisplayFactoryMac
: public wxDisplayFactory
293 wxDisplayFactoryMac();
295 virtual wxDisplayImpl
*CreateDisplay(unsigned n
);
296 virtual unsigned GetCount();
297 virtual int GetFromPoint(const wxPoint
& pt
);
300 DECLARE_NO_COPY_CLASS(wxDisplayFactoryMac
)
303 // ============================================================================
304 // wxDisplayFactoryMac implementation
305 // ============================================================================
307 unsigned wxDisplayFactoryMac::GetCount()
310 GDHandle hndl
= DMGetFirstScreenDevice(true);
314 hndl
= DMGetNextScreenDevice(hndl
, true);
319 int wxDisplayFactoryMac::GetFromPoint(const wxPoint
&p
)
322 GDHandle hndl
= DMGetFirstScreenDevice(true);
325 Rect screenrect
= (*hndl
)->gdRect
;
326 if (p
.x
>= screenrect
.left
&&
327 p
.x
<= screenrect
.right
&&
328 p
.y
>= screenrect
.top
&&
329 p
.y
<= screenrect
.bottom
)
334 hndl
= DMGetNextScreenDevice(hndl
, true);
340 wxDisplayImpl
*wxDisplayFactoryMac::CreateDisplay(unsigned n
)
344 GDHandle hndl
= DMGetFirstScreenDevice(true);
349 return new wxDisplayImplMac(nOrig
, hndl
);
352 hndl
= DMGetNextScreenDevice(hndl
, true);
358 // ============================================================================
359 // wxDisplayImplMac implementation
360 // ============================================================================
362 wxRect
wxDisplayImplMac::GetGeometry() const
364 Rect screenrect
= (*m_hndl
)->gdRect
;
365 return wxRect(screenrect
.left
, screenrect
.top
,
366 screenrect
.right
- screenrect
.left
,
367 screenrect
.bottom
- screenrect
.top
);
370 struct DMModeIteratorRec
372 wxArrayVideoModes
* pModes
;
373 const wxVideoMode
* pMatchMode
;
376 pascal void DMModeListIteratorProc(
378 DMListIndexType nIndex
,
379 DMDisplayModeListEntryPtr pInfo
)
381 DMModeIteratorRec
* pInfoData
= (DMModeIteratorRec
*) pData
;
383 // Note that in testing the refresh rate is always 0 on my ibook - RN
384 int refresh
= (int) Fix2Long(pInfo
->displayModeResolutionInfo
->csRefreshRate
);
386 #define pDBI pInfo->displayModeDepthBlockInfo->depthVPBlock[i].depthVPBlock
388 for (unsigned long i
= 0; i
< pInfo
->displayModeDepthBlockInfo
->depthBlockCount
; ++i
)
390 if (wxVideoMode( (int) pInfo
->displayModeResolutionInfo
->csHorizontalPixels
,
391 (int) pInfo
->displayModeResolutionInfo
->csVerticalLines
,
392 (int) pDBI
->vpPixelSize
,
393 refresh
).Matches(*pInfoData
->pMatchMode
) )
395 pInfoData
->pModes
->Add(
397 (int) pInfo
->displayModeResolutionInfo
->csHorizontalPixels
,
398 (int) pInfo
->displayModeResolutionInfo
->csVerticalLines
,
399 (int) pDBI
->vpPixelSize
,
409 const wxVideoMode
* pMode
;
410 VDSwitchInfoRec sMode
;
414 pascal void DMModeInfoProc(
416 DMListIndexType nIndex
,
417 DMDisplayModeListEntryPtr pInfo
)
419 DMModeInfoRec
* pInfoData
= (DMModeInfoRec
*) pData
;
420 Fixed refresh
= Long2Fix(pInfoData
->pMode
->refresh
);
422 #define pDBI pInfo->displayModeDepthBlockInfo->depthVPBlock[i].depthVPBlock
424 for (unsigned long i
= 0; i
< pInfo
->displayModeDepthBlockInfo
->depthBlockCount
; ++i
)
426 if (pInfoData
->pMode
->w
== (int&) pInfo
->displayModeResolutionInfo
->csHorizontalPixels
&&
427 pInfoData
->pMode
->h
== (int&) pInfo
->displayModeResolutionInfo
->csVerticalLines
&&
428 pInfoData
->pMode
->bpp
== (int) pDBI
->vpPixelSize
&&
429 refresh
== pInfo
->displayModeResolutionInfo
->csRefreshRate
)
433 pInfo
->displayModeDepthBlockInfo
->depthVPBlock
[i
].depthSwitchInfo
,
434 sizeof(VDSwitchInfoRec
));
435 pInfoData
->sMode
.csMode
= pDBI
->vpPixelSize
;
436 pInfoData
->bMatched
= true;
444 struct DMModeTransRec
447 const VDSwitchInfoRec
* psMode
;
451 pascal void DMModeTransProc(
453 DMListIndexType nIndex
,
454 DMDisplayModeListEntryPtr pInfo
)
456 DMModeTransRec
* pInfoData
= (DMModeTransRec
*) pData
;
458 #define pDBI pInfo->displayModeDepthBlockInfo->depthVPBlock[i].depthVPBlock
460 for (unsigned long i
= 0; i
< pInfo
->displayModeDepthBlockInfo
->depthBlockCount
; ++i
)
462 if (pInfoData
->psMode
->csData
== pInfo
->displayModeDepthBlockInfo
->depthVPBlock
[i
].depthSwitchInfo
->csData
)
464 pInfoData
->Mode
= wxVideoMode(
465 (int) pInfo
->displayModeResolutionInfo
->csHorizontalPixels
,
466 (int) pInfo
->displayModeResolutionInfo
->csVerticalLines
,
467 (int) pDBI
->vpPixelSize
,
468 (int) Fix2Long(pInfo
->displayModeResolutionInfo
->csRefreshRate
) );
469 pInfoData
->bMatched
= true;
477 wxArrayVideoModes
wxDisplayImplMac::GetModes(const wxVideoMode
& mode
) const
479 wxArrayVideoModes Modes
;
480 unsigned long dwDMVer
;
482 // Check DM version == 2
483 // (for backward compatibility only - 7.5.3+ use 2.0)
484 Gestalt( gestaltDisplayMgrVers
, (long*) &dwDMVer
);
485 if (dwDMVer
>= 0x020000)
487 DMListIndexType nNumModes
;
489 DMDisplayModeListIteratorUPP uppMLI
;
490 DisplayIDType nDisplayID
;
493 err
= DMGetDisplayIDByGDevice(m_hndl
, &nDisplayID
, false);
496 // Create a new list...
497 err
= DMNewDisplayModeList(nDisplayID
, NULL
, NULL
, &nNumModes
, &pModes
);
498 wxASSERT_MSG( err
== noErr
, wxT("Could not create a new display mode list") );
500 uppMLI
= NewDMDisplayModeListIteratorUPP(DMModeListIteratorProc
);
503 DMModeIteratorRec sModeInfo
;
504 sModeInfo
.pModes
= &Modes
;
505 sModeInfo
.pMatchMode
= &mode
;
507 for (DMListIndexType i
= 0; i
< nNumModes
; ++i
)
509 err
= DMGetIndexedDisplayModeFromList(pModes
, i
, NULL
, uppMLI
, &sModeInfo
);
513 DisposeDMDisplayModeListIteratorUPP(uppMLI
);
514 err
= DMDisposeList(pModes
);
517 else // DM 1.0, 1.2, 1.x
521 wxT("Display Manager Version %u Not Supported! Present? %s"),
522 (unsigned int) dwDMVer
/ 0x10000,
523 (dwDMVer
& (1 << gestaltDisplayMgrPresent
) ? wxT("Yes") : wxT("No")) ) );
529 wxVideoMode
wxDisplayImplMac::GetCurrentMode() const
531 unsigned long dwDMVer
;
534 // Check DM version == 2
535 // (for backward compatibility only - 7.5.3+ use 2.0)
536 Gestalt( gestaltDisplayMgrVers
, (long*) &dwDMVer
);
537 if (dwDMVer
>= 0x020000)
539 VDSwitchInfoRec sMode
; // Note: csMode member also contains the bit depth
542 err
= DMGetDisplayMode( m_hndl
, &sMode
);
545 DMListIndexType nNumModes
;
547 DMDisplayModeListIteratorUPP uppMLI
;
548 DisplayIDType nDisplayID
;
550 err
= DMGetDisplayIDByGDevice(m_hndl
, &nDisplayID
, false);
553 // Create a new list...
554 err
= DMNewDisplayModeList(nDisplayID
, NULL
, NULL
, &nNumModes
, &pModes
);
555 wxASSERT_MSG( err
== noErr
, wxT("Could not create a new display mode list") );
557 uppMLI
= NewDMDisplayModeListIteratorUPP(DMModeTransProc
);
560 DMModeTransRec sModeInfo
;
561 sModeInfo
.bMatched
= false;
562 sModeInfo
.psMode
= &sMode
;
563 for (DMListIndexType i
= 0; i
< nNumModes
; ++i
)
565 err
= DMGetIndexedDisplayModeFromList(pModes
, i
, NULL
, uppMLI
, &sModeInfo
);
568 if ( sModeInfo
.bMatched
)
570 RetMode
= sModeInfo
.Mode
;
575 DisposeDMDisplayModeListIteratorUPP(uppMLI
);
576 err
= DMDisposeList(pModes
);
579 else // Can't get current mode?
583 wxT("Couldn't obtain current display mode!!!\ndwDMVer:%u"),
584 (unsigned int) dwDMVer
));
591 wxT("Display Manager Version %u Not Supported! Present? %s"),
592 (unsigned int) dwDMVer
/ 0x10000,
593 (dwDMVer
& (1 << gestaltDisplayMgrPresent
) ? wxT("Yes") : wxT("No")) ) );
599 bool wxDisplayImplMac::ChangeMode(const wxVideoMode
& mode
)
601 unsigned long dwDMVer
;
603 Gestalt( gestaltDisplayMgrVers
, (long*)&dwDMVer
);
604 if (GetCount() == 1 || dwDMVer
>= 0x020000)
606 if (mode
== wxDefaultVideoMode
)
612 // Handle hDisplayState;
613 // if (DMBeginConfigureDisplays(&hDisplayState) != noErr)
615 // wxLogSysError(wxT("Could not lock display for display mode changing!"));
619 // wxASSERT( DMUseScreenPrefs(true, hDisplayState) == noErr);
620 // DMEndConfigureDisplays(hDisplayState);
629 //0 & NULL for params 2 & 3 of DMSetVideoMode signal it to use defaults (current mode)
630 //DM 2.0+ doesn't use params 2 & 3 of DMSetDisplayMode
631 //so we have to use this icky structure
632 VDSwitchInfoRec sMode
;
633 memset( &sMode
, 0, sizeof(VDSwitchInfoRec
) );
635 DMListIndexType nNumModes
;
637 DMDisplayModeListIteratorUPP uppMLI
;
638 DisplayIDType nDisplayID
;
641 err
= DMGetDisplayIDByGDevice(m_hndl
, &nDisplayID
, false);
644 // Create a new list...
645 err
= DMNewDisplayModeList(nDisplayID
, NULL
, NULL
, &nNumModes
, &pModes
);
646 wxASSERT_MSG(err
== noErr
, wxT("Could not create a new display mode list") );
648 uppMLI
= NewDMDisplayModeListIteratorUPP(DMModeInfoProc
);
651 DMModeInfoRec sModeInfo
;
652 sModeInfo
.bMatched
= false;
653 sModeInfo
.pMode
= &mode
;
656 for (i
= 0; i
< nNumModes
; ++i
)
658 err
= DMGetIndexedDisplayModeFromList(pModes
, i
, NULL
, uppMLI
, &sModeInfo
);
661 if (sModeInfo
.bMatched
)
663 sMode
= sModeInfo
.sMode
;
671 DisposeDMDisplayModeListIteratorUPP(uppMLI
);
673 err
= DMDisposeList(pModes
);
676 // For the really paranoid -
677 // unsigned long flags;
679 // wxASSERT(noErr == DMCheckDisplayMode(m_hndl, sMode.csData,
680 // sMode.csMode, &flags, NULL, &bok));
683 Handle hDisplayState
;
684 if (DMBeginConfigureDisplays(&hDisplayState
) != noErr
)
686 wxLogSysError(wxT("Could not lock display for display mode changing!"));
691 unsigned long dwBPP
= (unsigned long) mode
.bpp
;
692 err
= DMSetDisplayMode(
693 m_hndl
, sMode
.csData
,
694 (unsigned long*) &(dwBPP
),
695 NULL
, //(unsigned long) &sMode
700 DMEndConfigureDisplays(hDisplayState
);
701 wxLogError(wxT("Could not set the display mode"));
706 DMEndConfigureDisplays(hDisplayState
);
708 else // DM 1.0, 1.2, 1.x
712 wxT("Monitor gravitation not supported yet. dwDMVer:%u"),
713 (unsigned int) dwDMVer
));
721 // ============================================================================
722 // wxDisplay::CreateFactory()
723 // ============================================================================
725 /* static */ wxDisplayFactory
*wxDisplay::CreateFactory()
727 return new wxDisplayFactoryMac
;
732 #endif // wxUSE_DISPLAY