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(size_t n
, CGDirectDisplayID id
)
64 virtual wxRect
GetGeometry() const;
65 virtual wxString
GetName() const { return wxString(); }
67 virtual wxArrayVideoModes
GetModes(const wxVideoMode
& mode
) const;
68 virtual wxVideoMode
GetCurrentMode() const;
69 virtual bool ChangeMode(const wxVideoMode
& mode
);
72 CGDirectDisplayID m_id
;
74 DECLARE_NO_COPY_CLASS(wxDisplayImplMacOSX
)
77 class wxDisplayFactoryMacOSX
: public wxDisplayFactory
80 wxDisplayFactoryMacOSX() {}
82 virtual wxDisplayImpl
*CreateDisplay(size_t n
);
83 virtual size_t GetCount();
84 virtual int GetFromPoint(const wxPoint
& pt
);
87 DECLARE_NO_COPY_CLASS(wxDisplayFactoryMacOSX
)
90 // ============================================================================
91 // wxDisplayFactoryMacOSX implementation
92 // ============================================================================
94 size_t wxDisplayFactoryMacOSX::GetCount()
100 CGGetActiveDisplayList(0, NULL
, &count
);
102 wxASSERT(err
== CGDisplayNoErr
);
107 int wxDisplayFactoryMacOSX::GetFromPoint(const wxPoint
& p
)
109 CGPoint thePoint
= {(float)p
.x
, (float)p
.y
};
110 CGDirectDisplayID theID
;
111 CGDisplayCount theCount
;
112 CGDisplayErr err
= CGGetDisplaysWithPoint(thePoint
, 1, &theID
, &theCount
);
113 wxASSERT(err
== CGDisplayNoErr
);
115 int nWhich
= wxNOT_FOUND
;
119 theCount
= GetCount();
120 CGDirectDisplayID
* theIDs
= new CGDirectDisplayID
[theCount
];
121 err
= CGGetActiveDisplayList(theCount
, theIDs
, &theCount
);
122 wxASSERT(err
== CGDisplayNoErr
);
124 for (nWhich
= 0; nWhich
< (int) theCount
; ++nWhich
)
126 if (theIDs
[nWhich
] == theID
)
132 if (nWhich
== (int) theCount
)
134 wxFAIL_MSG(wxT("Failed to find display in display list"));
135 nWhich
= wxNOT_FOUND
;
142 wxDisplayImpl
*wxDisplayFactoryMacOSX::CreateDisplay(size_t n
)
144 CGDisplayCount theCount
= GetCount();
145 CGDirectDisplayID
* theIDs
= new CGDirectDisplayID
[theCount
];
150 CGGetActiveDisplayList(theCount
, theIDs
, &theCount
);
152 wxASSERT( err
== CGDisplayNoErr
);
153 wxASSERT( n
< theCount
);
155 wxDisplayImplMacOSX
*display
= new wxDisplayImplMacOSX(n
, theIDs
[n
]);
162 // ============================================================================
163 // wxDisplayImplMacOSX implementation
164 // ============================================================================
166 wxRect
wxDisplayImplMacOSX::GetGeometry() const
168 CGRect theRect
= CGDisplayBounds(m_id
);
169 return wxRect( (int)theRect
.origin
.x
,
170 (int)theRect
.origin
.y
,
171 (int)theRect
.size
.width
,
172 (int)theRect
.size
.height
); //floats
175 static int wxCFDictKeyToInt( CFDictionaryRef desc
, CFStringRef key
)
177 CFNumberRef value
= (CFNumberRef
) CFDictionaryGetValue( desc
, key
);
182 CFNumberGetValue( value
, kCFNumberIntType
, &num
);
187 wxArrayVideoModes
wxDisplayImplMacOSX::GetModes(const wxVideoMode
& mode
) const
189 wxArrayVideoModes resultModes
;
191 CFArrayRef theArray
= CGDisplayAvailableModes( m_id
);
193 for (CFIndex i
= 0; i
< CFArrayGetCount(theArray
); ++i
)
195 CFDictionaryRef theValue
= (CFDictionaryRef
) CFArrayGetValueAtIndex( theArray
, i
);
198 wxCFDictKeyToInt( theValue
, kCGDisplayWidth
),
199 wxCFDictKeyToInt( theValue
, kCGDisplayHeight
),
200 wxCFDictKeyToInt( theValue
, kCGDisplayBitsPerPixel
),
201 wxCFDictKeyToInt( theValue
, kCGDisplayRefreshRate
));
203 if (theMode
.Matches( mode
))
204 resultModes
.Add( theMode
);
210 wxVideoMode
wxDisplayImplMacOSX::GetCurrentMode() const
212 CFDictionaryRef theValue
= CGDisplayCurrentMode( m_id
);
215 wxCFDictKeyToInt( theValue
, kCGDisplayWidth
),
216 wxCFDictKeyToInt( theValue
, kCGDisplayHeight
),
217 wxCFDictKeyToInt( theValue
, kCGDisplayBitsPerPixel
),
218 wxCFDictKeyToInt( theValue
, kCGDisplayRefreshRate
));
221 bool wxDisplayImplMacOSX::ChangeMode( const wxVideoMode
& mode
)
223 // Changing to default mode (wxDefaultVideoMode) doesn't
224 // work because we don't have access to the system's 'scrn'
225 // resource which holds the user's mode which the system
226 // will return to after this app is done
227 boolean_t bExactMatch
;
228 CFDictionaryRef theCGMode
= CGDisplayBestModeForParametersAndRefreshRate(
233 (double)mode
.refresh
,
236 bool bOK
= bExactMatch
;
239 bOK
= CGDisplaySwitchToMode( m_id
, theCGMode
) == CGDisplayNoErr
;
244 // ============================================================================
245 // wxDisplay::CreateFactory()
246 // ============================================================================
248 /* static */ wxDisplayFactory
*wxDisplay::CreateFactory()
250 return new wxDisplayFactoryMacOSX
;
253 #else // !__WXMAC_OSX__
255 class wxDisplayImplMac
: public wxDisplayImpl
258 wxDisplayImplMac(size_t n
, GDHandle hndl
)
264 virtual wxRect
GetGeometry() const;
265 virtual wxString
GetName() const { return wxString(); }
267 virtual wxArrayVideoModes
GetModes(const wxVideoMode
& mode
) const;
268 virtual wxVideoMode
GetCurrentMode() const;
269 virtual bool ChangeMode(const wxVideoMode
& mode
);
274 DECLARE_NO_COPY_CLASS(wxDisplayImplMac
)
277 class wxDisplayFactoryMac
: public wxDisplayFactory
280 wxDisplayFactoryMac();
282 virtual wxDisplayImpl
*CreateDisplay(size_t n
);
283 virtual size_t GetCount();
284 virtual int GetFromPoint(const wxPoint
& pt
);
287 DECLARE_NO_COPY_CLASS(wxDisplayFactoryMac
)
290 // ============================================================================
291 // wxDisplayFactoryMac implementation
292 // ============================================================================
294 size_t wxDisplayFactoryMac::GetCount()
297 GDHandle hndl
= DMGetFirstScreenDevice(true);
301 hndl
= DMGetNextScreenDevice(hndl
, true);
306 int wxDisplayFactoryMac::GetFromPoint(const wxPoint
&p
)
309 GDHandle hndl
= DMGetFirstScreenDevice(true);
312 Rect screenrect
= (*hndl
)->gdRect
;
313 if (p
.x
>= screenrect
.left
&&
314 p
.x
<= screenrect
.right
&&
315 p
.y
>= screenrect
.top
&&
316 p
.y
<= screenrect
.bottom
)
321 hndl
= DMGetNextScreenDevice(hndl
, true);
327 wxDisplayImpl
*wxDisplayFactoryMac::CreateDisplay(size_t n
)
331 GDHandle hndl
= DMGetFirstScreenDevice(true);
336 return new wxDisplayImplMac(nOrig
, hndl
);
339 hndl
= DMGetNextScreenDevice(hndl
, true);
345 // ============================================================================
346 // wxDisplayImplMac implementation
347 // ============================================================================
349 wxRect
wxDisplayImplMac::GetGeometry() const
351 Rect screenrect
= (*m_hndl
)->gdRect
;
352 return wxRect(screenrect
.left
, screenrect
.top
,
353 screenrect
.right
- screenrect
.left
,
354 screenrect
.bottom
- screenrect
.top
);
357 struct DMModeIteratorRec
359 wxArrayVideoModes
* pModes
;
360 const wxVideoMode
* pMatchMode
;
363 pascal void DMModeListIteratorProc(
365 DMListIndexType nIndex
,
366 DMDisplayModeListEntryPtr pInfo
)
368 DMModeIteratorRec
* pInfoData
= (DMModeIteratorRec
*) pData
;
370 // Note that in testing the refresh rate is always 0 on my ibook - RN
371 int refresh
= (int) Fix2Long(pInfo
->displayModeResolutionInfo
->csRefreshRate
);
373 #define pDBI pInfo->displayModeDepthBlockInfo->depthVPBlock[i].depthVPBlock
375 for (unsigned long i
= 0; i
< pInfo
->displayModeDepthBlockInfo
->depthBlockCount
; ++i
)
377 if (wxVideoMode( (int) pInfo
->displayModeResolutionInfo
->csHorizontalPixels
,
378 (int) pInfo
->displayModeResolutionInfo
->csVerticalLines
,
379 (int) pDBI
->vpPixelSize
,
380 refresh
).Matches(*pInfoData
->pMatchMode
) )
382 pInfoData
->pModes
->Add(
384 (int) pInfo
->displayModeResolutionInfo
->csHorizontalPixels
,
385 (int) pInfo
->displayModeResolutionInfo
->csVerticalLines
,
386 (int) pDBI
->vpPixelSize
,
396 const wxVideoMode
* pMode
;
397 VDSwitchInfoRec sMode
;
401 pascal void DMModeInfoProc(
403 DMListIndexType nIndex
,
404 DMDisplayModeListEntryPtr pInfo
)
406 DMModeInfoRec
* pInfoData
= (DMModeInfoRec
*) pData
;
407 Fixed refresh
= Long2Fix(pInfoData
->pMode
->refresh
);
409 #define pDBI pInfo->displayModeDepthBlockInfo->depthVPBlock[i].depthVPBlock
411 for (unsigned long i
= 0; i
< pInfo
->displayModeDepthBlockInfo
->depthBlockCount
; ++i
)
413 if (pInfoData
->pMode
->w
== (int&) pInfo
->displayModeResolutionInfo
->csHorizontalPixels
&&
414 pInfoData
->pMode
->h
== (int&) pInfo
->displayModeResolutionInfo
->csVerticalLines
&&
415 pInfoData
->pMode
->bpp
== (int) pDBI
->vpPixelSize
&&
416 refresh
== pInfo
->displayModeResolutionInfo
->csRefreshRate
)
420 pInfo
->displayModeDepthBlockInfo
->depthVPBlock
[i
].depthSwitchInfo
,
421 sizeof(VDSwitchInfoRec
));
422 pInfoData
->sMode
.csMode
= pDBI
->vpPixelSize
;
423 pInfoData
->bMatched
= true;
431 struct DMModeTransRec
434 const VDSwitchInfoRec
* psMode
;
438 pascal void DMModeTransProc(
440 DMListIndexType nIndex
,
441 DMDisplayModeListEntryPtr pInfo
)
443 DMModeTransRec
* pInfoData
= (DMModeTransRec
*) pData
;
445 #define pDBI pInfo->displayModeDepthBlockInfo->depthVPBlock[i].depthVPBlock
447 for (unsigned long i
= 0; i
< pInfo
->displayModeDepthBlockInfo
->depthBlockCount
; ++i
)
449 if (pInfoData
->psMode
->csData
== pInfo
->displayModeDepthBlockInfo
->depthVPBlock
[i
].depthSwitchInfo
->csData
)
451 pInfoData
->Mode
= wxVideoMode(
452 (int) pInfo
->displayModeResolutionInfo
->csHorizontalPixels
,
453 (int) pInfo
->displayModeResolutionInfo
->csVerticalLines
,
454 (int) pDBI
->vpPixelSize
,
455 (int) Fix2Long(pInfo
->displayModeResolutionInfo
->csRefreshRate
) );
456 pInfoData
->bMatched
= true;
464 wxArrayVideoModes
wxDisplayImplMac::GetModes(const wxVideoMode
& mode
) const
466 wxArrayVideoModes Modes
;
467 unsigned long dwDMVer
;
469 // Check DM version == 2
470 // (for backward compatibility only - 7.5.3+ use 2.0)
471 Gestalt( gestaltDisplayMgrVers
, (long*) &dwDMVer
);
472 if (dwDMVer
>= 0x020000)
474 DMListIndexType nNumModes
;
476 DMDisplayModeListIteratorUPP uppMLI
;
477 DisplayIDType nDisplayID
;
480 err
= DMGetDisplayIDByGDevice(m_hndl
, &nDisplayID
, false);
483 // Create a new list...
484 err
= DMNewDisplayModeList(nDisplayID
, NULL
, NULL
, &nNumModes
, &pModes
);
485 wxASSERT_MSG( err
== noErr
, wxT("Could not create a new display mode list") );
487 uppMLI
= NewDMDisplayModeListIteratorUPP(DMModeListIteratorProc
);
490 DMModeIteratorRec sModeInfo
;
491 sModeInfo
.pModes
= &Modes
;
492 sModeInfo
.pMatchMode
= &mode
;
494 for (DMListIndexType i
= 0; i
< nNumModes
; ++i
)
496 err
= DMGetIndexedDisplayModeFromList(pModes
, i
, NULL
, uppMLI
, &sModeInfo
);
500 DisposeDMDisplayModeListIteratorUPP(uppMLI
);
501 err
= DMDisposeList(pModes
);
504 else // DM 1.0, 1.2, 1.x
508 wxT("Display Manager Version %u Not Supported! Present? %s"),
509 (unsigned int) dwDMVer
/ 0x10000,
510 (dwDMVer
& (1 << gestaltDisplayMgrPresent
) ? wxT("Yes") : wxT("No")) ) );
516 wxVideoMode
wxDisplayImplMac::GetCurrentMode() const
518 unsigned long dwDMVer
;
521 // Check DM version == 2
522 // (for backward compatibility only - 7.5.3+ use 2.0)
523 Gestalt( gestaltDisplayMgrVers
, (long*) &dwDMVer
);
524 if (dwDMVer
>= 0x020000)
526 VDSwitchInfoRec sMode
; // Note: csMode member also contains the bit depth
529 err
= DMGetDisplayMode( m_hndl
, &sMode
);
532 DMListIndexType nNumModes
;
534 DMDisplayModeListIteratorUPP uppMLI
;
535 DisplayIDType nDisplayID
;
537 err
= DMGetDisplayIDByGDevice(m_hndl
, &nDisplayID
, false);
540 // Create a new list...
541 err
= DMNewDisplayModeList(nDisplayID
, NULL
, NULL
, &nNumModes
, &pModes
);
542 wxASSERT_MSG( err
== noErr
, wxT("Could not create a new display mode list") );
544 uppMLI
= NewDMDisplayModeListIteratorUPP(DMModeTransProc
);
547 DMModeTransRec sModeInfo
;
548 sModeInfo
.bMatched
= false;
549 sModeInfo
.psMode
= &sMode
;
550 for (DMListIndexType i
= 0; i
< nNumModes
; ++i
)
552 err
= DMGetIndexedDisplayModeFromList(pModes
, i
, NULL
, uppMLI
, &sModeInfo
);
555 if ( sModeInfo
.bMatched
)
557 RetMode
= sModeInfo
.Mode
;
562 DisposeDMDisplayModeListIteratorUPP(uppMLI
);
563 err
= DMDisposeList(pModes
);
566 else // Can't get current mode?
570 wxT("Couldn't obtain current display mode!!!\ndwDMVer:%u"),
571 (unsigned int) dwDMVer
));
578 wxT("Display Manager Version %u Not Supported! Present? %s"),
579 (unsigned int) dwDMVer
/ 0x10000,
580 (dwDMVer
& (1 << gestaltDisplayMgrPresent
) ? wxT("Yes") : wxT("No")) ) );
586 bool wxDisplayImplMac::ChangeMode(const wxVideoMode
& mode
)
588 unsigned long dwDMVer
;
590 Gestalt( gestaltDisplayMgrVers
, (long*)&dwDMVer
);
591 if (GetCount() == 1 || dwDMVer
>= 0x020000)
593 if (mode
== wxDefaultVideoMode
)
599 // Handle hDisplayState;
600 // if (DMBeginConfigureDisplays(&hDisplayState) != noErr)
602 // wxLogSysError(wxT("Could not lock display for display mode changing!"));
606 // wxASSERT( DMUseScreenPrefs(true, hDisplayState) == noErr);
607 // DMEndConfigureDisplays(hDisplayState);
616 //0 & NULL for params 2 & 3 of DMSetVideoMode signal it to use defaults (current mode)
617 //DM 2.0+ doesn't use params 2 & 3 of DMSetDisplayMode
618 //so we have to use this icky structure
619 VDSwitchInfoRec sMode
;
620 memset( &sMode
, 0, sizeof(VDSwitchInfoRec
) );
622 DMListIndexType nNumModes
;
624 DMDisplayModeListIteratorUPP uppMLI
;
625 DisplayIDType nDisplayID
;
628 err
= DMGetDisplayIDByGDevice(m_hndl
, &nDisplayID
, false);
631 // Create a new list...
632 err
= DMNewDisplayModeList(nDisplayID
, NULL
, NULL
, &nNumModes
, &pModes
);
633 wxASSERT_MSG(err
== noErr
, wxT("Could not create a new display mode list") );
635 uppMLI
= NewDMDisplayModeListIteratorUPP(DMModeInfoProc
);
638 DMModeInfoRec sModeInfo
;
639 sModeInfo
.bMatched
= false;
640 sModeInfo
.pMode
= &mode
;
643 for (i
= 0; i
< nNumModes
; ++i
)
645 err
= DMGetIndexedDisplayModeFromList(pModes
, i
, NULL
, uppMLI
, &sModeInfo
);
648 if (sModeInfo
.bMatched
)
650 sMode
= sModeInfo
.sMode
;
658 DisposeDMDisplayModeListIteratorUPP(uppMLI
);
660 err
= DMDisposeList(pModes
);
663 // For the really paranoid -
664 // unsigned long flags;
666 // wxASSERT(noErr == DMCheckDisplayMode(m_hndl, sMode.csData,
667 // sMode.csMode, &flags, NULL, &bok));
670 Handle hDisplayState
;
671 if (DMBeginConfigureDisplays(&hDisplayState
) != noErr
)
673 wxLogSysError(wxT("Could not lock display for display mode changing!"));
678 unsigned long dwBPP
= (unsigned long) mode
.bpp
;
679 err
= DMSetDisplayMode(
680 m_hndl
, sMode
.csData
,
681 (unsigned long*) &(dwBPP
),
682 NULL
, //(unsigned long) &sMode
687 DMEndConfigureDisplays(hDisplayState
);
688 wxLogError(wxT("Could not set the display mode"));
693 DMEndConfigureDisplays(hDisplayState
);
695 else // DM 1.0, 1.2, 1.x
699 wxT("Monitor gravitation not supported yet. dwDMVer:%u"),
700 (unsigned int) dwDMVer
));
708 // ============================================================================
709 // wxDisplay::CreateFactory()
710 // ============================================================================
712 /* static */ wxDisplayFactory
*wxDisplay::CreateFactory()
714 return new wxDisplayFactoryMac
;
719 #endif // wxUSE_DISPLAY