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"
29 #include "wx/dynarray.h"
34 #include <Carbon/Carbon.h>
38 #include <Quickdraw.h>
39 #include <Video.h> // for VDSwitchInfoRec
41 #include <Debugging.h>
44 #include "wx/display.h"
45 #include "wx/display_impl.h"
46 #include "wx/gdicmn.h"
47 #include "wx/string.h"
49 // ----------------------------------------------------------------------------
50 // display classes implementation
51 // ----------------------------------------------------------------------------
55 class wxDisplayImplMacOSX
: public wxDisplayImpl
58 wxDisplayImplMacOSX(CGDirectDisplayID id
) : m_id(id
) { }
60 virtual wxRect
GetGeometry() const;
61 virtual wxString
GetName() const { return wxString(); }
63 virtual wxArrayVideoModes
GetModes(const wxVideoMode
& mode
) const;
64 virtual wxVideoMode
GetCurrentMode() const;
65 virtual bool ChangeMode(const wxVideoMode
& mode
);
68 CGDirectDisplayID m_id
;
70 DECLARE_NO_COPY_CLASS(wxDisplayImplMacOSX
)
73 class wxDisplayFactoryMacOSX
: public wxDisplayFactory
76 wxDisplayFactoryMacOSX();
78 virtual wxDisplayImpl
*CreateDisplay(size_t n
);
79 virtual size_t GetCount();
80 virtual int GetFromPoint(const wxPoint
& pt
);
83 DECLARE_NO_COPY_CLASS(wxDisplayFactoryMacOSX
)
86 // ============================================================================
87 // wxDisplayFactoryMacOSX implementation
88 // ============================================================================
90 size_t wxDisplayFactoryMacOSX::GetCount()
96 CGGetActiveDisplayList(0, NULL
, &count
);
98 wxASSERT(err
== CGDisplayNoErr
);
103 int wxDisplayFactoryMacOSX::GetFromPoint(const wxPoint
& p
)
105 CGPoint thePoint
= {(float)p
.x
, (float)p
.y
};
106 CGDirectDisplayID theID
;
107 CGDisplayCount theCount
;
108 CGDisplayErr err
= CGGetDisplaysWithPoint(thePoint
, 1, &theID
, &theCount
);
109 wxASSERT(err
== CGDisplayNoErr
);
111 int nWhich
= wxNOT_FOUND
;
115 theCount
= GetCount();
116 CGDirectDisplayID
* theIDs
= new CGDirectDisplayID
[theCount
];
117 err
= CGGetActiveDisplayList(theCount
, theIDs
, &theCount
);
118 wxASSERT(err
== CGDisplayNoErr
);
120 for (nWhich
= 0; nWhich
< (int) theCount
; ++nWhich
)
122 if (theIDs
[nWhich
] == theID
)
128 if (nWhich
== (int) theCount
)
130 wxFAIL_MSG(wxT("Failed to find display in display list"));
131 nWhich
= wxNOT_FOUND
;
138 wxDisplayImpl
*wxDisplayFactoryMacOSX::CreateDisplay(size_t n
)
140 CGDisplayCount theCount
= GetCount();
141 CGDirectDisplayID
* theIDs
= new CGDirectDisplayID
[theCount
];
146 CGGetActiveDisplayList(theCount
, theIDs
, &theCount
);
148 wxASSERT( err
== CGDisplayNoErr
);
149 wxASSERT( n
< theCount
);
151 wxDisplayImplMacOSX
*display
= new wxDisplayImplMacOSX(theIDs
[n
]);
158 // ============================================================================
159 // wxDisplayImplMacOSX implementation
160 // ============================================================================
162 wxRect
wxDisplayImplMacOSX::GetGeometry() const
164 CGRect theRect
= CGDisplayBounds(m_id
);
165 return wxRect( (int)theRect
.origin
.x
,
166 (int)theRect
.origin
.y
,
167 (int)theRect
.size
.width
,
168 (int)theRect
.size
.height
); //floats
171 static int wxCFDictKeyToInt( CFDictionaryRef desc
, CFStringRef key
)
173 CFNumberRef value
= (CFNumberRef
) CFDictionaryGetValue( desc
, key
);
178 CFNumberGetValue( value
, kCFNumberIntType
, &num
);
183 wxArrayVideoModes
wxDisplayImplMacOSX::GetModes(const wxVideoMode
& mode
) const
185 wxArrayVideoModes resultModes
;
187 CFArrayRef theArray
= CGDisplayAvailableModes( m_id
);
189 for (CFIndex i
= 0; i
< CFArrayGetCount(theArray
); ++i
)
191 CFDictionaryRef theValue
= (CFDictionaryRef
) CFArrayGetValueAtIndex( theArray
, i
);
194 wxCFDictKeyToInt( theValue
, kCGDisplayWidth
),
195 wxCFDictKeyToInt( theValue
, kCGDisplayHeight
),
196 wxCFDictKeyToInt( theValue
, kCGDisplayBitsPerPixel
),
197 wxCFDictKeyToInt( theValue
, kCGDisplayRefreshRate
));
199 if (theMode
.Matches( mode
))
200 resultModes
.Add( theMode
);
206 wxVideoMode
wxDisplayImplMacOSX::GetCurrentMode() const
208 CFDictionaryRef theValue
= CGDisplayCurrentMode( m_id
);
211 wxCFDictKeyToInt( theValue
, kCGDisplayWidth
),
212 wxCFDictKeyToInt( theValue
, kCGDisplayHeight
),
213 wxCFDictKeyToInt( theValue
, kCGDisplayBitsPerPixel
),
214 wxCFDictKeyToInt( theValue
, kCGDisplayRefreshRate
));
217 bool wxDisplayImplMacOSX::ChangeMode( const wxVideoMode
& mode
)
219 // Changing to default mode (wxDefaultVideoMode) doesn't
220 // work because we don't have access to the system's 'scrn'
221 // resource which holds the user's mode which the system
222 // will return to after this app is done
223 boolean_t bExactMatch
;
224 CFDictionaryRef theCGMode
= CGDisplayBestModeForParametersAndRefreshRate(
229 (double)mode
.refresh
,
232 bool bOK
= bExactMatch
;
235 bOK
= CGDisplaySwitchToMode( m_id
, theCGMode
) == CGDisplayNoErr
;
240 // ============================================================================
241 // wxDisplay::CreateFactory()
242 // ============================================================================
244 /* static */ wxDisplayFactory
*wxDisplay::CreateFactory()
246 return new wxDisplayFactoryMacOSX
;
249 #else // !__WXMAC_OSX__
251 class wxDisplayImplMac
: public wxDisplayImpl
254 wxDisplayImplMac(GDHandle hndl
) : m_hndl(hndl
) { }
256 virtual wxRect
GetGeometry() const;
257 virtual wxString
GetName() const { return wxString(); }
259 virtual wxArrayVideoModes
GetModes(const wxVideoMode
& mode
) const;
260 virtual wxVideoMode
GetCurrentMode() const;
261 virtual bool ChangeMode(const wxVideoMode
& mode
);
266 DECLARE_NO_COPY_CLASS(wxDisplayImplMac
)
269 class wxDisplayFactoryMac
: public wxDisplayFactory
272 wxDisplayFactoryMac();
274 virtual wxDisplayImpl
*CreateDisplay(size_t n
);
275 virtual size_t GetCount();
276 virtual int GetFromPoint(const wxPoint
& pt
);
279 DECLARE_NO_COPY_CLASS(wxDisplayFactoryMac
)
282 // ============================================================================
283 // wxDisplayFactoryMac implementation
284 // ============================================================================
286 size_t wxDisplayFactoryMac::GetCount()
289 GDHandle hndl
= DMGetFirstScreenDevice(true);
293 hndl
= DMGetNextScreenDevice(hndl
, true);
298 int wxDisplayFactoryMac::GetFromPoint(const wxPoint
&p
)
301 GDHandle hndl
= DMGetFirstScreenDevice(true);
304 Rect screenrect
= (*hndl
)->gdRect
;
305 if (p
.x
>= screenrect
.left
&&
306 p
.x
<= screenrect
.right
&&
307 p
.y
>= screenrect
.top
&&
308 p
.y
<= screenrect
.bottom
)
313 hndl
= DMGetNextScreenDevice(hndl
, true);
319 wxDisplayImpl
*wxDisplayFactoryMac::CreateDisplay(size_t n
)
321 GDHandle hndl
= DMGetFirstScreenDevice(true);
326 return new wxDisplayImplMac(hndl
);
329 hndl
= DMGetNextScreenDevice(hndl
, true);
335 // ============================================================================
336 // wxDisplayImplMac implementation
337 // ============================================================================
339 wxRect
wxDisplayImplMac::GetGeometry() const
341 Rect screenrect
= (*m_hndl
)->gdRect
;
342 return wxRect(screenrect
.left
, screenrect
.top
,
343 screenrect
.right
- screenrect
.left
,
344 screenrect
.bottom
- screenrect
.top
);
347 struct DMModeIteratorRec
349 wxArrayVideoModes
* pModes
;
350 const wxVideoMode
* pMatchMode
;
353 pascal void DMModeListIteratorProc(
355 DMListIndexType nIndex
,
356 DMDisplayModeListEntryPtr pInfo
)
358 DMModeIteratorRec
* pInfoData
= (DMModeIteratorRec
*) pData
;
360 // Note that in testing the refresh rate is always 0 on my ibook - RN
361 int refresh
= (int) Fix2Long(pInfo
->displayModeResolutionInfo
->csRefreshRate
);
363 #define pDBI pInfo->displayModeDepthBlockInfo->depthVPBlock[i].depthVPBlock
365 for (unsigned long i
= 0; i
< pInfo
->displayModeDepthBlockInfo
->depthBlockCount
; ++i
)
367 if (wxVideoMode( (int) pInfo
->displayModeResolutionInfo
->csHorizontalPixels
,
368 (int) pInfo
->displayModeResolutionInfo
->csVerticalLines
,
369 (int) pDBI
->vpPixelSize
,
370 refresh
).Matches(*pInfoData
->pMatchMode
) )
372 pInfoData
->pModes
->Add(
374 (int) pInfo
->displayModeResolutionInfo
->csHorizontalPixels
,
375 (int) pInfo
->displayModeResolutionInfo
->csVerticalLines
,
376 (int) pDBI
->vpPixelSize
,
386 const wxVideoMode
* pMode
;
387 VDSwitchInfoRec sMode
;
391 pascal void DMModeInfoProc(
393 DMListIndexType nIndex
,
394 DMDisplayModeListEntryPtr pInfo
)
396 DMModeInfoRec
* pInfoData
= (DMModeInfoRec
*) pData
;
397 Fixed refresh
= Long2Fix(pInfoData
->pMode
->refresh
);
399 #define pDBI pInfo->displayModeDepthBlockInfo->depthVPBlock[i].depthVPBlock
401 for (unsigned long i
= 0; i
< pInfo
->displayModeDepthBlockInfo
->depthBlockCount
; ++i
)
403 if (pInfoData
->pMode
->w
== (int&) pInfo
->displayModeResolutionInfo
->csHorizontalPixels
&&
404 pInfoData
->pMode
->h
== (int&) pInfo
->displayModeResolutionInfo
->csVerticalLines
&&
405 pInfoData
->pMode
->bpp
== (int) pDBI
->vpPixelSize
&&
406 refresh
== pInfo
->displayModeResolutionInfo
->csRefreshRate
)
410 pInfo
->displayModeDepthBlockInfo
->depthVPBlock
[i
].depthSwitchInfo
,
411 sizeof(VDSwitchInfoRec
));
412 pInfoData
->sMode
.csMode
= pDBI
->vpPixelSize
;
413 pInfoData
->bMatched
= true;
421 struct DMModeTransRec
424 const VDSwitchInfoRec
* psMode
;
428 pascal void DMModeTransProc(
430 DMListIndexType nIndex
,
431 DMDisplayModeListEntryPtr pInfo
)
433 DMModeTransRec
* pInfoData
= (DMModeTransRec
*) pData
;
435 #define pDBI pInfo->displayModeDepthBlockInfo->depthVPBlock[i].depthVPBlock
437 for (unsigned long i
= 0; i
< pInfo
->displayModeDepthBlockInfo
->depthBlockCount
; ++i
)
439 if (pInfoData
->psMode
->csData
== pInfo
->displayModeDepthBlockInfo
->depthVPBlock
[i
].depthSwitchInfo
->csData
)
441 pInfoData
->Mode
= wxVideoMode(
442 (int) pInfo
->displayModeResolutionInfo
->csHorizontalPixels
,
443 (int) pInfo
->displayModeResolutionInfo
->csVerticalLines
,
444 (int) pDBI
->vpPixelSize
,
445 (int) Fix2Long(pInfo
->displayModeResolutionInfo
->csRefreshRate
) );
446 pInfoData
->bMatched
= true;
454 wxArrayVideoModes
wxDisplayImplMac::GetModes(const wxVideoMode
& mode
) const
456 wxArrayVideoModes Modes
;
457 unsigned long dwDMVer
;
459 // Check DM version == 2
460 // (for backward compatibility only - 7.5.3+ use 2.0)
461 Gestalt( gestaltDisplayMgrVers
, (long*) &dwDMVer
);
462 if (dwDMVer
>= 0x020000)
464 DMListIndexType nNumModes
;
466 DMDisplayModeListIteratorUPP uppMLI
;
467 DisplayIDType nDisplayID
;
470 err
= DMGetDisplayIDByGDevice(m_hndl
, &nDisplayID
, false);
473 // Create a new list...
474 err
= DMNewDisplayModeList(nDisplayID
, NULL
, NULL
, &nNumModes
, &pModes
);
475 wxASSERT_MSG( err
== noErr
, wxT("Could not create a new display mode list") );
477 uppMLI
= NewDMDisplayModeListIteratorUPP(DMModeListIteratorProc
);
480 DMModeIteratorRec sModeInfo
;
481 sModeInfo
.pModes
= &Modes
;
482 sModeInfo
.pMatchMode
= &mode
;
484 for (DMListIndexType i
= 0; i
< nNumModes
; ++i
)
486 err
= DMGetIndexedDisplayModeFromList(pModes
, i
, NULL
, uppMLI
, &sModeInfo
);
490 DisposeDMDisplayModeListIteratorUPP(uppMLI
);
491 err
= DMDisposeList(pModes
);
494 else // DM 1.0, 1.2, 1.x
498 wxT("Display Manager Version %u Not Supported! Present? %s"),
499 (unsigned int) dwDMVer
/ 0x10000,
500 (dwDMVer
& (1 << gestaltDisplayMgrPresent
) ? wxT("Yes") : wxT("No")) ) );
506 wxVideoMode
wxDisplayImplMac::GetCurrentMode() const
508 unsigned long dwDMVer
;
511 // Check DM version == 2
512 // (for backward compatibility only - 7.5.3+ use 2.0)
513 Gestalt( gestaltDisplayMgrVers
, (long*) &dwDMVer
);
514 if (dwDMVer
>= 0x020000)
516 VDSwitchInfoRec sMode
; // Note: csMode member also contains the bit depth
519 err
= DMGetDisplayMode( m_hndl
, &sMode
);
522 DMListIndexType nNumModes
;
524 DMDisplayModeListIteratorUPP uppMLI
;
525 DisplayIDType nDisplayID
;
527 err
= DMGetDisplayIDByGDevice(m_hndl
, &nDisplayID
, false);
530 // Create a new list...
531 err
= DMNewDisplayModeList(nDisplayID
, NULL
, NULL
, &nNumModes
, &pModes
);
532 wxASSERT_MSG( err
== noErr
, wxT("Could not create a new display mode list") );
534 uppMLI
= NewDMDisplayModeListIteratorUPP(DMModeTransProc
);
537 DMModeTransRec sModeInfo
;
538 sModeInfo
.bMatched
= false;
539 sModeInfo
.psMode
= &sMode
;
540 for (DMListIndexType i
= 0; i
< nNumModes
; ++i
)
542 err
= DMGetIndexedDisplayModeFromList(pModes
, i
, NULL
, uppMLI
, &sModeInfo
);
545 if ( sModeInfo
.bMatched
)
547 RetMode
= sModeInfo
.Mode
;
552 DisposeDMDisplayModeListIteratorUPP(uppMLI
);
553 err
= DMDisposeList(pModes
);
556 else // Can't get current mode?
560 wxT("Couldn't obtain current display mode!!!\ndwDMVer:%u"),
561 (unsigned int) dwDMVer
));
568 wxT("Display Manager Version %u Not Supported! Present? %s"),
569 (unsigned int) dwDMVer
/ 0x10000,
570 (dwDMVer
& (1 << gestaltDisplayMgrPresent
) ? wxT("Yes") : wxT("No")) ) );
576 bool wxDisplayImplMac::ChangeMode(const wxVideoMode
& mode
)
578 unsigned long dwDMVer
;
580 Gestalt( gestaltDisplayMgrVers
, (long*)&dwDMVer
);
581 if (GetCount() == 1 || dwDMVer
>= 0x020000)
583 if (mode
== wxDefaultVideoMode
)
589 // Handle hDisplayState;
590 // if (DMBeginConfigureDisplays(&hDisplayState) != noErr)
592 // wxLogSysError(wxT("Could not lock display for display mode changing!"));
596 // wxASSERT( DMUseScreenPrefs(true, hDisplayState) == noErr);
597 // DMEndConfigureDisplays(hDisplayState);
606 //0 & NULL for params 2 & 3 of DMSetVideoMode signal it to use defaults (current mode)
607 //DM 2.0+ doesn't use params 2 & 3 of DMSetDisplayMode
608 //so we have to use this icky structure
609 VDSwitchInfoRec sMode
;
610 memset( &sMode
, 0, sizeof(VDSwitchInfoRec
) );
612 DMListIndexType nNumModes
;
614 DMDisplayModeListIteratorUPP uppMLI
;
615 DisplayIDType nDisplayID
;
618 err
= DMGetDisplayIDByGDevice(m_hndl
, &nDisplayID
, false);
621 // Create a new list...
622 err
= DMNewDisplayModeList(nDisplayID
, NULL
, NULL
, &nNumModes
, &pModes
);
623 wxASSERT_MSG(err
== noErr
, wxT("Could not create a new display mode list") );
625 uppMLI
= NewDMDisplayModeListIteratorUPP(DMModeInfoProc
);
628 DMModeInfoRec sModeInfo
;
629 sModeInfo
.bMatched
= false;
630 sModeInfo
.pMode
= &mode
;
633 for (i
= 0; i
< nNumModes
; ++i
)
635 err
= DMGetIndexedDisplayModeFromList(pModes
, i
, NULL
, uppMLI
, &sModeInfo
);
638 if (sModeInfo
.bMatched
)
640 sMode
= sModeInfo
.sMode
;
648 DisposeDMDisplayModeListIteratorUPP(uppMLI
);
650 err
= DMDisposeList(pModes
);
653 // For the really paranoid -
654 // unsigned long flags;
656 // wxASSERT(noErr == DMCheckDisplayMode(m_hndl, sMode.csData,
657 // sMode.csMode, &flags, NULL, &bok));
660 Handle hDisplayState
;
661 if (DMBeginConfigureDisplays(&hDisplayState
) != noErr
)
663 wxLogSysError(wxT("Could not lock display for display mode changing!"));
668 unsigned long dwBPP
= (unsigned long) mode
.bpp
;
669 err
= DMSetDisplayMode(
670 m_hndl
, sMode
.csData
,
671 (unsigned long*) &(dwBPP
),
672 NULL
, //(unsigned long) &sMode
677 DMEndConfigureDisplays(hDisplayState
);
678 wxLogError(wxT("Could not set the display mode"));
683 DMEndConfigureDisplays(hDisplayState
);
685 else // DM 1.0, 1.2, 1.x
689 wxT("Monitor gravitation not supported yet. dwDMVer:%u"),
690 (unsigned int) dwDMVer
));
698 // ============================================================================
699 // wxDisplay::CreateFactory()
700 // ============================================================================
702 /* static */ wxDisplayFactory
*wxDisplay::CreateFactory()
704 return new wxDisplayFactoryMac
;
709 #endif // wxUSE_DISPLAY