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"
37 #include <Carbon/Carbon.h>
41 #include <Quickdraw.h>
42 #include <Video.h> // for VDSwitchInfoRec
44 #include <Debugging.h>
47 #include "wx/display_impl.h"
48 #include "wx/gdicmn.h"
50 // ----------------------------------------------------------------------------
51 // display classes implementation
52 // ----------------------------------------------------------------------------
56 class wxDisplayImplMacOSX
: public wxDisplayImpl
59 wxDisplayImplMacOSX(size_t n
, CGDirectDisplayID id
)
65 virtual wxRect
GetGeometry() const;
66 virtual wxString
GetName() const { return wxString(); }
68 virtual wxArrayVideoModes
GetModes(const wxVideoMode
& mode
) const;
69 virtual wxVideoMode
GetCurrentMode() const;
70 virtual bool ChangeMode(const wxVideoMode
& mode
);
73 CGDirectDisplayID m_id
;
75 DECLARE_NO_COPY_CLASS(wxDisplayImplMacOSX
)
78 class wxDisplayFactoryMacOSX
: public wxDisplayFactory
81 wxDisplayFactoryMacOSX() {}
83 virtual wxDisplayImpl
*CreateDisplay(size_t n
);
84 virtual size_t GetCount();
85 virtual int GetFromPoint(const wxPoint
& pt
);
88 DECLARE_NO_COPY_CLASS(wxDisplayFactoryMacOSX
)
91 // ============================================================================
92 // wxDisplayFactoryMacOSX implementation
93 // ============================================================================
95 size_t wxDisplayFactoryMacOSX::GetCount()
101 CGGetActiveDisplayList(0, NULL
, &count
);
103 wxASSERT(err
== CGDisplayNoErr
);
108 int wxDisplayFactoryMacOSX::GetFromPoint(const wxPoint
& p
)
110 CGPoint thePoint
= {(float)p
.x
, (float)p
.y
};
111 CGDirectDisplayID theID
;
112 CGDisplayCount theCount
;
113 CGDisplayErr err
= CGGetDisplaysWithPoint(thePoint
, 1, &theID
, &theCount
);
114 wxASSERT(err
== CGDisplayNoErr
);
116 int nWhich
= wxNOT_FOUND
;
120 theCount
= GetCount();
121 CGDirectDisplayID
* theIDs
= new CGDirectDisplayID
[theCount
];
122 err
= CGGetActiveDisplayList(theCount
, theIDs
, &theCount
);
123 wxASSERT(err
== CGDisplayNoErr
);
125 for (nWhich
= 0; nWhich
< (int) theCount
; ++nWhich
)
127 if (theIDs
[nWhich
] == theID
)
133 if (nWhich
== (int) theCount
)
135 wxFAIL_MSG(wxT("Failed to find display in display list"));
136 nWhich
= wxNOT_FOUND
;
143 wxDisplayImpl
*wxDisplayFactoryMacOSX::CreateDisplay(size_t n
)
145 CGDisplayCount theCount
= GetCount();
146 CGDirectDisplayID
* theIDs
= new CGDirectDisplayID
[theCount
];
151 CGGetActiveDisplayList(theCount
, theIDs
, &theCount
);
153 wxASSERT( err
== CGDisplayNoErr
);
154 wxASSERT( n
< theCount
);
156 wxDisplayImplMacOSX
*display
= new wxDisplayImplMacOSX(n
, theIDs
[n
]);
163 // ============================================================================
164 // wxDisplayImplMacOSX implementation
165 // ============================================================================
167 wxRect
wxDisplayImplMacOSX::GetGeometry() const
169 CGRect theRect
= CGDisplayBounds(m_id
);
170 return wxRect( (int)theRect
.origin
.x
,
171 (int)theRect
.origin
.y
,
172 (int)theRect
.size
.width
,
173 (int)theRect
.size
.height
); //floats
176 static int wxCFDictKeyToInt( CFDictionaryRef desc
, CFStringRef key
)
178 CFNumberRef value
= (CFNumberRef
) CFDictionaryGetValue( desc
, key
);
183 CFNumberGetValue( value
, kCFNumberIntType
, &num
);
188 wxArrayVideoModes
wxDisplayImplMacOSX::GetModes(const wxVideoMode
& mode
) const
190 wxArrayVideoModes resultModes
;
192 CFArrayRef theArray
= CGDisplayAvailableModes( m_id
);
194 for (CFIndex i
= 0; i
< CFArrayGetCount(theArray
); ++i
)
196 CFDictionaryRef theValue
= (CFDictionaryRef
) CFArrayGetValueAtIndex( theArray
, i
);
199 wxCFDictKeyToInt( theValue
, kCGDisplayWidth
),
200 wxCFDictKeyToInt( theValue
, kCGDisplayHeight
),
201 wxCFDictKeyToInt( theValue
, kCGDisplayBitsPerPixel
),
202 wxCFDictKeyToInt( theValue
, kCGDisplayRefreshRate
));
204 if (theMode
.Matches( mode
))
205 resultModes
.Add( theMode
);
211 wxVideoMode
wxDisplayImplMacOSX::GetCurrentMode() const
213 CFDictionaryRef theValue
= CGDisplayCurrentMode( m_id
);
216 wxCFDictKeyToInt( theValue
, kCGDisplayWidth
),
217 wxCFDictKeyToInt( theValue
, kCGDisplayHeight
),
218 wxCFDictKeyToInt( theValue
, kCGDisplayBitsPerPixel
),
219 wxCFDictKeyToInt( theValue
, kCGDisplayRefreshRate
));
222 bool wxDisplayImplMacOSX::ChangeMode( const wxVideoMode
& mode
)
224 // Changing to default mode (wxDefaultVideoMode) doesn't
225 // work because we don't have access to the system's 'scrn'
226 // resource which holds the user's mode which the system
227 // will return to after this app is done
228 boolean_t bExactMatch
;
229 CFDictionaryRef theCGMode
= CGDisplayBestModeForParametersAndRefreshRate(
234 (double)mode
.refresh
,
237 bool bOK
= bExactMatch
;
240 bOK
= CGDisplaySwitchToMode( m_id
, theCGMode
) == CGDisplayNoErr
;
245 // ============================================================================
246 // wxDisplay::CreateFactory()
247 // ============================================================================
249 /* static */ wxDisplayFactory
*wxDisplay::CreateFactory()
251 return new wxDisplayFactoryMacOSX
;
254 #else // !__WXMAC_OSX__
256 class wxDisplayImplMac
: public wxDisplayImpl
259 wxDisplayImplMac(size_t n
, GDHandle hndl
)
265 virtual wxRect
GetGeometry() const;
266 virtual wxString
GetName() const { return wxString(); }
268 virtual wxArrayVideoModes
GetModes(const wxVideoMode
& mode
) const;
269 virtual wxVideoMode
GetCurrentMode() const;
270 virtual bool ChangeMode(const wxVideoMode
& mode
);
275 DECLARE_NO_COPY_CLASS(wxDisplayImplMac
)
278 class wxDisplayFactoryMac
: public wxDisplayFactory
281 wxDisplayFactoryMac();
283 virtual wxDisplayImpl
*CreateDisplay(size_t n
);
284 virtual size_t GetCount();
285 virtual int GetFromPoint(const wxPoint
& pt
);
288 DECLARE_NO_COPY_CLASS(wxDisplayFactoryMac
)
291 // ============================================================================
292 // wxDisplayFactoryMac implementation
293 // ============================================================================
295 size_t wxDisplayFactoryMac::GetCount()
298 GDHandle hndl
= DMGetFirstScreenDevice(true);
302 hndl
= DMGetNextScreenDevice(hndl
, true);
307 int wxDisplayFactoryMac::GetFromPoint(const wxPoint
&p
)
310 GDHandle hndl
= DMGetFirstScreenDevice(true);
313 Rect screenrect
= (*hndl
)->gdRect
;
314 if (p
.x
>= screenrect
.left
&&
315 p
.x
<= screenrect
.right
&&
316 p
.y
>= screenrect
.top
&&
317 p
.y
<= screenrect
.bottom
)
322 hndl
= DMGetNextScreenDevice(hndl
, true);
328 wxDisplayImpl
*wxDisplayFactoryMac::CreateDisplay(size_t n
)
332 GDHandle hndl
= DMGetFirstScreenDevice(true);
337 return new wxDisplayImplMac(nOrig
, hndl
);
340 hndl
= DMGetNextScreenDevice(hndl
, true);
346 // ============================================================================
347 // wxDisplayImplMac implementation
348 // ============================================================================
350 wxRect
wxDisplayImplMac::GetGeometry() const
352 Rect screenrect
= (*m_hndl
)->gdRect
;
353 return wxRect(screenrect
.left
, screenrect
.top
,
354 screenrect
.right
- screenrect
.left
,
355 screenrect
.bottom
- screenrect
.top
);
358 struct DMModeIteratorRec
360 wxArrayVideoModes
* pModes
;
361 const wxVideoMode
* pMatchMode
;
364 pascal void DMModeListIteratorProc(
366 DMListIndexType nIndex
,
367 DMDisplayModeListEntryPtr pInfo
)
369 DMModeIteratorRec
* pInfoData
= (DMModeIteratorRec
*) pData
;
371 // Note that in testing the refresh rate is always 0 on my ibook - RN
372 int refresh
= (int) Fix2Long(pInfo
->displayModeResolutionInfo
->csRefreshRate
);
374 #define pDBI pInfo->displayModeDepthBlockInfo->depthVPBlock[i].depthVPBlock
376 for (unsigned long i
= 0; i
< pInfo
->displayModeDepthBlockInfo
->depthBlockCount
; ++i
)
378 if (wxVideoMode( (int) pInfo
->displayModeResolutionInfo
->csHorizontalPixels
,
379 (int) pInfo
->displayModeResolutionInfo
->csVerticalLines
,
380 (int) pDBI
->vpPixelSize
,
381 refresh
).Matches(*pInfoData
->pMatchMode
) )
383 pInfoData
->pModes
->Add(
385 (int) pInfo
->displayModeResolutionInfo
->csHorizontalPixels
,
386 (int) pInfo
->displayModeResolutionInfo
->csVerticalLines
,
387 (int) pDBI
->vpPixelSize
,
397 const wxVideoMode
* pMode
;
398 VDSwitchInfoRec sMode
;
402 pascal void DMModeInfoProc(
404 DMListIndexType nIndex
,
405 DMDisplayModeListEntryPtr pInfo
)
407 DMModeInfoRec
* pInfoData
= (DMModeInfoRec
*) pData
;
408 Fixed refresh
= Long2Fix(pInfoData
->pMode
->refresh
);
410 #define pDBI pInfo->displayModeDepthBlockInfo->depthVPBlock[i].depthVPBlock
412 for (unsigned long i
= 0; i
< pInfo
->displayModeDepthBlockInfo
->depthBlockCount
; ++i
)
414 if (pInfoData
->pMode
->w
== (int&) pInfo
->displayModeResolutionInfo
->csHorizontalPixels
&&
415 pInfoData
->pMode
->h
== (int&) pInfo
->displayModeResolutionInfo
->csVerticalLines
&&
416 pInfoData
->pMode
->bpp
== (int) pDBI
->vpPixelSize
&&
417 refresh
== pInfo
->displayModeResolutionInfo
->csRefreshRate
)
421 pInfo
->displayModeDepthBlockInfo
->depthVPBlock
[i
].depthSwitchInfo
,
422 sizeof(VDSwitchInfoRec
));
423 pInfoData
->sMode
.csMode
= pDBI
->vpPixelSize
;
424 pInfoData
->bMatched
= true;
432 struct DMModeTransRec
435 const VDSwitchInfoRec
* psMode
;
439 pascal void DMModeTransProc(
441 DMListIndexType nIndex
,
442 DMDisplayModeListEntryPtr pInfo
)
444 DMModeTransRec
* pInfoData
= (DMModeTransRec
*) pData
;
446 #define pDBI pInfo->displayModeDepthBlockInfo->depthVPBlock[i].depthVPBlock
448 for (unsigned long i
= 0; i
< pInfo
->displayModeDepthBlockInfo
->depthBlockCount
; ++i
)
450 if (pInfoData
->psMode
->csData
== pInfo
->displayModeDepthBlockInfo
->depthVPBlock
[i
].depthSwitchInfo
->csData
)
452 pInfoData
->Mode
= wxVideoMode(
453 (int) pInfo
->displayModeResolutionInfo
->csHorizontalPixels
,
454 (int) pInfo
->displayModeResolutionInfo
->csVerticalLines
,
455 (int) pDBI
->vpPixelSize
,
456 (int) Fix2Long(pInfo
->displayModeResolutionInfo
->csRefreshRate
) );
457 pInfoData
->bMatched
= true;
465 wxArrayVideoModes
wxDisplayImplMac::GetModes(const wxVideoMode
& mode
) const
467 wxArrayVideoModes Modes
;
468 unsigned long dwDMVer
;
470 // Check DM version == 2
471 // (for backward compatibility only - 7.5.3+ use 2.0)
472 Gestalt( gestaltDisplayMgrVers
, (long*) &dwDMVer
);
473 if (dwDMVer
>= 0x020000)
475 DMListIndexType nNumModes
;
477 DMDisplayModeListIteratorUPP uppMLI
;
478 DisplayIDType nDisplayID
;
481 err
= DMGetDisplayIDByGDevice(m_hndl
, &nDisplayID
, false);
484 // Create a new list...
485 err
= DMNewDisplayModeList(nDisplayID
, NULL
, NULL
, &nNumModes
, &pModes
);
486 wxASSERT_MSG( err
== noErr
, wxT("Could not create a new display mode list") );
488 uppMLI
= NewDMDisplayModeListIteratorUPP(DMModeListIteratorProc
);
491 DMModeIteratorRec sModeInfo
;
492 sModeInfo
.pModes
= &Modes
;
493 sModeInfo
.pMatchMode
= &mode
;
495 for (DMListIndexType i
= 0; i
< nNumModes
; ++i
)
497 err
= DMGetIndexedDisplayModeFromList(pModes
, i
, NULL
, uppMLI
, &sModeInfo
);
501 DisposeDMDisplayModeListIteratorUPP(uppMLI
);
502 err
= DMDisposeList(pModes
);
505 else // DM 1.0, 1.2, 1.x
509 wxT("Display Manager Version %u Not Supported! Present? %s"),
510 (unsigned int) dwDMVer
/ 0x10000,
511 (dwDMVer
& (1 << gestaltDisplayMgrPresent
) ? wxT("Yes") : wxT("No")) ) );
517 wxVideoMode
wxDisplayImplMac::GetCurrentMode() const
519 unsigned long dwDMVer
;
522 // Check DM version == 2
523 // (for backward compatibility only - 7.5.3+ use 2.0)
524 Gestalt( gestaltDisplayMgrVers
, (long*) &dwDMVer
);
525 if (dwDMVer
>= 0x020000)
527 VDSwitchInfoRec sMode
; // Note: csMode member also contains the bit depth
530 err
= DMGetDisplayMode( m_hndl
, &sMode
);
533 DMListIndexType nNumModes
;
535 DMDisplayModeListIteratorUPP uppMLI
;
536 DisplayIDType nDisplayID
;
538 err
= DMGetDisplayIDByGDevice(m_hndl
, &nDisplayID
, false);
541 // Create a new list...
542 err
= DMNewDisplayModeList(nDisplayID
, NULL
, NULL
, &nNumModes
, &pModes
);
543 wxASSERT_MSG( err
== noErr
, wxT("Could not create a new display mode list") );
545 uppMLI
= NewDMDisplayModeListIteratorUPP(DMModeTransProc
);
548 DMModeTransRec sModeInfo
;
549 sModeInfo
.bMatched
= false;
550 sModeInfo
.psMode
= &sMode
;
551 for (DMListIndexType i
= 0; i
< nNumModes
; ++i
)
553 err
= DMGetIndexedDisplayModeFromList(pModes
, i
, NULL
, uppMLI
, &sModeInfo
);
556 if ( sModeInfo
.bMatched
)
558 RetMode
= sModeInfo
.Mode
;
563 DisposeDMDisplayModeListIteratorUPP(uppMLI
);
564 err
= DMDisposeList(pModes
);
567 else // Can't get current mode?
571 wxT("Couldn't obtain current display mode!!!\ndwDMVer:%u"),
572 (unsigned int) dwDMVer
));
579 wxT("Display Manager Version %u Not Supported! Present? %s"),
580 (unsigned int) dwDMVer
/ 0x10000,
581 (dwDMVer
& (1 << gestaltDisplayMgrPresent
) ? wxT("Yes") : wxT("No")) ) );
587 bool wxDisplayImplMac::ChangeMode(const wxVideoMode
& mode
)
589 unsigned long dwDMVer
;
591 Gestalt( gestaltDisplayMgrVers
, (long*)&dwDMVer
);
592 if (GetCount() == 1 || dwDMVer
>= 0x020000)
594 if (mode
== wxDefaultVideoMode
)
600 // Handle hDisplayState;
601 // if (DMBeginConfigureDisplays(&hDisplayState) != noErr)
603 // wxLogSysError(wxT("Could not lock display for display mode changing!"));
607 // wxASSERT( DMUseScreenPrefs(true, hDisplayState) == noErr);
608 // DMEndConfigureDisplays(hDisplayState);
617 //0 & NULL for params 2 & 3 of DMSetVideoMode signal it to use defaults (current mode)
618 //DM 2.0+ doesn't use params 2 & 3 of DMSetDisplayMode
619 //so we have to use this icky structure
620 VDSwitchInfoRec sMode
;
621 memset( &sMode
, 0, sizeof(VDSwitchInfoRec
) );
623 DMListIndexType nNumModes
;
625 DMDisplayModeListIteratorUPP uppMLI
;
626 DisplayIDType nDisplayID
;
629 err
= DMGetDisplayIDByGDevice(m_hndl
, &nDisplayID
, false);
632 // Create a new list...
633 err
= DMNewDisplayModeList(nDisplayID
, NULL
, NULL
, &nNumModes
, &pModes
);
634 wxASSERT_MSG(err
== noErr
, wxT("Could not create a new display mode list") );
636 uppMLI
= NewDMDisplayModeListIteratorUPP(DMModeInfoProc
);
639 DMModeInfoRec sModeInfo
;
640 sModeInfo
.bMatched
= false;
641 sModeInfo
.pMode
= &mode
;
644 for (i
= 0; i
< nNumModes
; ++i
)
646 err
= DMGetIndexedDisplayModeFromList(pModes
, i
, NULL
, uppMLI
, &sModeInfo
);
649 if (sModeInfo
.bMatched
)
651 sMode
= sModeInfo
.sMode
;
659 DisposeDMDisplayModeListIteratorUPP(uppMLI
);
661 err
= DMDisposeList(pModes
);
664 // For the really paranoid -
665 // unsigned long flags;
667 // wxASSERT(noErr == DMCheckDisplayMode(m_hndl, sMode.csData,
668 // sMode.csMode, &flags, NULL, &bok));
671 Handle hDisplayState
;
672 if (DMBeginConfigureDisplays(&hDisplayState
) != noErr
)
674 wxLogSysError(wxT("Could not lock display for display mode changing!"));
679 unsigned long dwBPP
= (unsigned long) mode
.bpp
;
680 err
= DMSetDisplayMode(
681 m_hndl
, sMode
.csData
,
682 (unsigned long*) &(dwBPP
),
683 NULL
, //(unsigned long) &sMode
688 DMEndConfigureDisplays(hDisplayState
);
689 wxLogError(wxT("Could not set the display mode"));
694 DMEndConfigureDisplays(hDisplayState
);
696 else // DM 1.0, 1.2, 1.x
700 wxT("Monitor gravitation not supported yet. dwDMVer:%u"),
701 (unsigned int) dwDMVer
));
709 // ============================================================================
710 // wxDisplay::CreateFactory()
711 // ============================================================================
713 /* static */ wxDisplayFactory
*wxDisplay::CreateFactory()
715 return new wxDisplayFactoryMac
;
720 #endif // wxUSE_DISPLAY