]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/mac/carbon/display.cpp
Updated list of subprojects.
[wxWidgets.git] / src / mac / carbon / display.cpp
... / ...
CommitLineData
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
6// Created: 06/21/02
7// RCS-ID: $Id$
8// Copyright: (c) wxWidgets team
9// Licence: wxWindows licence
10/////////////////////////////////////////////////////////////////////////////
11
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
20#include "wx/wxprec.h"
21
22#ifdef __BORLANDC__
23 #pragma hdrstop
24#endif
25
26#if wxUSE_DISPLAY
27
28#include "wx/display.h"
29
30#ifndef WX_PRECOMP
31 #include "wx/dynarray.h"
32 #include "wx/log.h"
33 #include "wx/string.h"
34 #include "wx/gdicmn.h"
35#endif
36
37#ifdef __DARWIN__
38 #include <Carbon/Carbon.h>
39#else
40 #include <Gestalt.h>
41 #include <Displays.h>
42 #include <Quickdraw.h>
43 #include <Video.h> // for VDSwitchInfoRec
44 #include <FixMath.h>
45 #include <Debugging.h>
46#endif
47
48#include "wx/display_impl.h"
49
50// ----------------------------------------------------------------------------
51// display classes implementation
52// ----------------------------------------------------------------------------
53
54#ifdef __WXMAC_OSX__
55
56class wxDisplayImplMacOSX : public wxDisplayImpl
57{
58public:
59 wxDisplayImplMacOSX(unsigned n, CGDirectDisplayID id)
60 : wxDisplayImpl(n),
61 m_id(id)
62 {
63 }
64
65 virtual wxRect GetGeometry() const;
66 virtual wxString GetName() const { return wxString(); }
67
68 virtual wxArrayVideoModes GetModes(const wxVideoMode& mode) const;
69 virtual wxVideoMode GetCurrentMode() const;
70 virtual bool ChangeMode(const wxVideoMode& mode);
71
72private:
73 CGDirectDisplayID m_id;
74
75 DECLARE_NO_COPY_CLASS(wxDisplayImplMacOSX)
76};
77
78class wxDisplayFactoryMacOSX : public wxDisplayFactory
79{
80public:
81 wxDisplayFactoryMacOSX() {}
82
83 virtual wxDisplayImpl *CreateDisplay(unsigned n);
84 virtual unsigned GetCount();
85 virtual int GetFromPoint(const wxPoint& pt);
86
87protected:
88 DECLARE_NO_COPY_CLASS(wxDisplayFactoryMacOSX)
89};
90
91// ============================================================================
92// wxDisplayFactoryMacOSX implementation
93// ============================================================================
94
95unsigned wxDisplayFactoryMacOSX::GetCount()
96{
97 CGDisplayCount count;
98#ifdef __WXDEBUG__
99 CGDisplayErr err =
100#endif
101 CGGetActiveDisplayList(0, NULL, &count);
102
103 wxASSERT(err == CGDisplayNoErr);
104
105 return count;
106}
107
108int wxDisplayFactoryMacOSX::GetFromPoint(const wxPoint& p)
109{
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);
115
116 int nWhich = wxNOT_FOUND;
117
118 if (theCount)
119 {
120 theCount = GetCount();
121 CGDirectDisplayID* theIDs = new CGDirectDisplayID[theCount];
122 err = CGGetActiveDisplayList(theCount, theIDs, &theCount);
123 wxASSERT(err == CGDisplayNoErr);
124
125 for (nWhich = 0; nWhich < (int) theCount; ++nWhich)
126 {
127 if (theIDs[nWhich] == theID)
128 break;
129 }
130
131 delete [] theIDs;
132
133 if (nWhich == (int) theCount)
134 {
135 wxFAIL_MSG(wxT("Failed to find display in display list"));
136 nWhich = wxNOT_FOUND;
137 }
138 }
139
140 return nWhich;
141}
142
143wxDisplayImpl *wxDisplayFactoryMacOSX::CreateDisplay(unsigned n)
144{
145 CGDisplayCount theCount = GetCount();
146 CGDirectDisplayID* theIDs = new CGDirectDisplayID[theCount];
147
148#ifdef __WXDEBUG__
149 CGDisplayErr err =
150#endif
151 CGGetActiveDisplayList(theCount, theIDs, &theCount);
152
153 wxASSERT( err == CGDisplayNoErr );
154 wxASSERT( n < theCount );
155
156 wxDisplayImplMacOSX *display = new wxDisplayImplMacOSX(n, theIDs[n]);
157
158 delete [] theIDs;
159
160 return display;
161}
162
163// ============================================================================
164// wxDisplayImplMacOSX implementation
165// ============================================================================
166
167wxRect wxDisplayImplMacOSX::GetGeometry() const
168{
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
174}
175
176static int wxCFDictKeyToInt( CFDictionaryRef desc, CFStringRef key )
177{
178 CFNumberRef value = (CFNumberRef) CFDictionaryGetValue( desc, key );
179 if (value == NULL)
180 return 0;
181
182 int num = 0;
183 CFNumberGetValue( value, kCFNumberIntType, &num );
184
185 return num;
186}
187
188wxArrayVideoModes wxDisplayImplMacOSX::GetModes(const wxVideoMode& mode) const
189{
190 wxArrayVideoModes resultModes;
191
192 CFArrayRef theArray = CGDisplayAvailableModes( m_id );
193
194 for (CFIndex i = 0; i < CFArrayGetCount(theArray); ++i)
195 {
196 CFDictionaryRef theValue = (CFDictionaryRef) CFArrayGetValueAtIndex( theArray, i );
197
198 wxVideoMode theMode(
199 wxCFDictKeyToInt( theValue, kCGDisplayWidth ),
200 wxCFDictKeyToInt( theValue, kCGDisplayHeight ),
201 wxCFDictKeyToInt( theValue, kCGDisplayBitsPerPixel ),
202 wxCFDictKeyToInt( theValue, kCGDisplayRefreshRate ));
203
204 if (theMode.Matches( mode ))
205 resultModes.Add( theMode );
206 }
207
208 return resultModes;
209}
210
211wxVideoMode wxDisplayImplMacOSX::GetCurrentMode() const
212{
213 CFDictionaryRef theValue = CGDisplayCurrentMode( m_id );
214
215 return wxVideoMode(
216 wxCFDictKeyToInt( theValue, kCGDisplayWidth ),
217 wxCFDictKeyToInt( theValue, kCGDisplayHeight ),
218 wxCFDictKeyToInt( theValue, kCGDisplayBitsPerPixel ),
219 wxCFDictKeyToInt( theValue, kCGDisplayRefreshRate ));
220}
221
222bool wxDisplayImplMacOSX::ChangeMode( const wxVideoMode& mode )
223{
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(
230 m_id,
231 (size_t)mode.bpp,
232 (size_t)mode.w,
233 (size_t)mode.h,
234 (double)mode.refresh,
235 &bExactMatch );
236
237 bool bOK = bExactMatch;
238
239 if (bOK)
240 bOK = CGDisplaySwitchToMode( m_id, theCGMode ) == CGDisplayNoErr;
241
242 return bOK;
243}
244
245// ============================================================================
246// wxDisplay::CreateFactory()
247// ============================================================================
248
249/* static */ wxDisplayFactory *wxDisplay::CreateFactory()
250{
251 return new wxDisplayFactoryMacOSX;
252}
253
254#else // !__WXMAC_OSX__
255
256class wxDisplayImplMac : public wxDisplayImpl
257{
258public:
259 wxDisplayImplMac(unsigned n, GDHandle hndl)
260 : wxDisplayImpl(n),
261 m_hndl(hndl)
262 {
263 }
264
265 virtual wxRect GetGeometry() const;
266 virtual wxString GetName() const { return wxString(); }
267
268 virtual wxArrayVideoModes GetModes(const wxVideoMode& mode) const;
269 virtual wxVideoMode GetCurrentMode() const;
270 virtual bool ChangeMode(const wxVideoMode& mode);
271
272private:
273 GDHandle m_hndl;
274
275 DECLARE_NO_COPY_CLASS(wxDisplayImplMac)
276};
277
278class wxDisplayFactoryMac : public wxDisplayFactory
279{
280public:
281 wxDisplayFactoryMac();
282
283 virtual wxDisplayImpl *CreateDisplay(unsigned n);
284 virtual unsigned GetCount();
285 virtual int GetFromPoint(const wxPoint& pt);
286
287protected:
288 DECLARE_NO_COPY_CLASS(wxDisplayFactoryMac)
289};
290
291// ============================================================================
292// wxDisplayFactoryMac implementation
293// ============================================================================
294
295unsigned wxDisplayFactoryMac::GetCount()
296{
297 unsigned num = 0;
298 GDHandle hndl = DMGetFirstScreenDevice(true);
299 while(hndl)
300 {
301 num++;
302 hndl = DMGetNextScreenDevice(hndl, true);
303 }
304 return num;
305}
306
307int wxDisplayFactoryMac::GetFromPoint(const wxPoint &p)
308{
309 unsigned num = 0;
310 GDHandle hndl = DMGetFirstScreenDevice(true);
311 while(hndl)
312 {
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)
318 {
319 return num;
320 }
321 num++;
322 hndl = DMGetNextScreenDevice(hndl, true);
323 }
324
325 return wxNOT_FOUND;
326}
327
328wxDisplayImpl *wxDisplayFactoryMac::CreateDisplay(unsigned n)
329{
330 unsigned nOrig = n;
331
332 GDHandle hndl = DMGetFirstScreenDevice(true);
333 while(hndl)
334 {
335 if (n == 0)
336 {
337 return new wxDisplayImplMac(nOrig, hndl);
338 }
339 n--;
340 hndl = DMGetNextScreenDevice(hndl, true);
341 }
342
343 return NULL;
344}
345
346// ============================================================================
347// wxDisplayImplMac implementation
348// ============================================================================
349
350wxRect wxDisplayImplMac::GetGeometry() const
351{
352 Rect screenrect = (*m_hndl)->gdRect;
353 return wxRect(screenrect.left, screenrect.top,
354 screenrect.right - screenrect.left,
355 screenrect.bottom - screenrect.top);
356}
357
358struct DMModeIteratorRec
359{
360 wxArrayVideoModes* pModes;
361 const wxVideoMode* pMatchMode;
362};
363
364pascal void DMModeListIteratorProc(
365 void* pData,
366 DMListIndexType nIndex,
367 DMDisplayModeListEntryPtr pInfo)
368{
369 DMModeIteratorRec* pInfoData = (DMModeIteratorRec*) pData;
370
371 // Note that in testing the refresh rate is always 0 on my ibook - RN
372 int refresh = (int) Fix2Long(pInfo->displayModeResolutionInfo->csRefreshRate);
373
374#define pDBI pInfo->displayModeDepthBlockInfo->depthVPBlock[i].depthVPBlock
375
376 for (unsigned long i = 0; i < pInfo->displayModeDepthBlockInfo->depthBlockCount; ++i)
377 {
378 if (wxVideoMode( (int) pInfo->displayModeResolutionInfo->csHorizontalPixels,
379 (int) pInfo->displayModeResolutionInfo->csVerticalLines,
380 (int) pDBI->vpPixelSize,
381 refresh).Matches(*pInfoData->pMatchMode) )
382 {
383 pInfoData->pModes->Add(
384 wxVideoMode(
385 (int) pInfo->displayModeResolutionInfo->csHorizontalPixels,
386 (int) pInfo->displayModeResolutionInfo->csVerticalLines,
387 (int) pDBI->vpPixelSize,
388 refresh ) );
389 }
390 }
391
392#undef pDBI
393}
394
395struct DMModeInfoRec
396{
397 const wxVideoMode* pMode;
398 VDSwitchInfoRec sMode;
399 bool bMatched;
400};
401
402pascal void DMModeInfoProc(
403 void* pData,
404 DMListIndexType nIndex,
405 DMDisplayModeListEntryPtr pInfo )
406{
407 DMModeInfoRec* pInfoData = (DMModeInfoRec*) pData;
408 Fixed refresh = Long2Fix(pInfoData->pMode->refresh);
409
410#define pDBI pInfo->displayModeDepthBlockInfo->depthVPBlock[i].depthVPBlock
411
412 for (unsigned long i = 0; i < pInfo->displayModeDepthBlockInfo->depthBlockCount; ++i)
413 {
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)
418 {
419 memcpy(
420 &pInfoData->sMode,
421 pInfo->displayModeDepthBlockInfo->depthVPBlock[i].depthSwitchInfo,
422 sizeof(VDSwitchInfoRec));
423 pInfoData->sMode.csMode = pDBI->vpPixelSize;
424 pInfoData->bMatched = true;
425 break;
426 }
427 }
428
429#undef pDBI
430}
431
432struct DMModeTransRec
433{
434 wxVideoMode Mode;
435 const VDSwitchInfoRec* psMode;
436 bool bMatched;
437};
438
439pascal void DMModeTransProc(
440 void* pData,
441 DMListIndexType nIndex,
442 DMDisplayModeListEntryPtr pInfo)
443{
444 DMModeTransRec* pInfoData = (DMModeTransRec*) pData;
445
446#define pDBI pInfo->displayModeDepthBlockInfo->depthVPBlock[i].depthVPBlock
447
448 for (unsigned long i = 0; i < pInfo->displayModeDepthBlockInfo->depthBlockCount; ++i)
449 {
450 if (pInfoData->psMode->csData == pInfo->displayModeDepthBlockInfo->depthVPBlock[i].depthSwitchInfo->csData)
451 {
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;
458 break;
459 }
460 }
461
462#undef pDBI
463}
464
465wxArrayVideoModes wxDisplayImplMac::GetModes(const wxVideoMode& mode) const
466{
467 wxArrayVideoModes Modes;
468 unsigned long dwDMVer;
469
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)
474 {
475 DMListIndexType nNumModes;
476 DMListType pModes;
477 DMDisplayModeListIteratorUPP uppMLI;
478 DisplayIDType nDisplayID;
479 OSErr err;
480
481 err = DMGetDisplayIDByGDevice(m_hndl, &nDisplayID, false);
482 verify_noerr( err );
483
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") );
487
488 uppMLI = NewDMDisplayModeListIteratorUPP(DMModeListIteratorProc);
489 wxASSERT( uppMLI );
490
491 DMModeIteratorRec sModeInfo;
492 sModeInfo.pModes = &Modes;
493 sModeInfo.pMatchMode = &mode;
494
495 for (DMListIndexType i = 0; i < nNumModes; ++i)
496 {
497 err = DMGetIndexedDisplayModeFromList(pModes, i, NULL, uppMLI, &sModeInfo);
498 verify_noerr( err );
499 }
500
501 DisposeDMDisplayModeListIteratorUPP(uppMLI);
502 err = DMDisposeList(pModes);
503 verify_noerr( err );
504 }
505 else // DM 1.0, 1.2, 1.x
506 {
507 wxLogSysError(
508 wxString::Format(
509 wxT("Display Manager Version %u Not Supported! Present? %s"),
510 (unsigned int) dwDMVer / 0x10000,
511 (dwDMVer & (1 << gestaltDisplayMgrPresent) ? wxT("Yes") : wxT("No")) ) );
512 }
513
514 return Modes;
515}
516
517wxVideoMode wxDisplayImplMac::GetCurrentMode() const
518{
519 unsigned long dwDMVer;
520 wxVideoMode RetMode;
521
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)
526 {
527 VDSwitchInfoRec sMode; // Note: csMode member also contains the bit depth
528 OSErr err;
529
530 err = DMGetDisplayMode( m_hndl, &sMode );
531 if (err == noErr)
532 {
533 DMListIndexType nNumModes;
534 DMListType pModes;
535 DMDisplayModeListIteratorUPP uppMLI;
536 DisplayIDType nDisplayID;
537
538 err = DMGetDisplayIDByGDevice(m_hndl, &nDisplayID, false);
539 verify_noerr( err );
540
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") );
544
545 uppMLI = NewDMDisplayModeListIteratorUPP(DMModeTransProc);
546 wxASSERT( uppMLI );
547
548 DMModeTransRec sModeInfo;
549 sModeInfo.bMatched = false;
550 sModeInfo.psMode = &sMode;
551 for (DMListIndexType i = 0; i < nNumModes; ++i)
552 {
553 err = DMGetIndexedDisplayModeFromList(pModes, i, NULL, uppMLI, &sModeInfo);
554 verify_noerr( err );
555
556 if ( sModeInfo.bMatched )
557 {
558 RetMode = sModeInfo.Mode;
559 break;
560 }
561 }
562
563 DisposeDMDisplayModeListIteratorUPP(uppMLI);
564 err = DMDisposeList(pModes);
565 verify_noerr( err );
566 }
567 else // Can't get current mode?
568 {
569 wxLogSysError(
570 wxString::Format(
571 wxT("Couldn't obtain current display mode!!!\ndwDMVer:%u"),
572 (unsigned int) dwDMVer));
573 }
574 }
575 else // DM ver 1
576 {
577 wxLogSysError(
578 wxString::Format(
579 wxT("Display Manager Version %u Not Supported! Present? %s"),
580 (unsigned int) dwDMVer / 0x10000,
581 (dwDMVer & (1 << gestaltDisplayMgrPresent) ? wxT("Yes") : wxT("No")) ) );
582 }
583
584 return RetMode;
585}
586
587bool wxDisplayImplMac::ChangeMode(const wxVideoMode& mode)
588{
589 unsigned long dwDMVer;
590
591 Gestalt( gestaltDisplayMgrVers, (long*)&dwDMVer );
592 if (GetCount() == 1 || dwDMVer >= 0x020000)
593 {
594 if (mode == wxDefaultVideoMode)
595 {
596 return true;
597
598#if 0
599//#ifndef __DARWIN__
600// Handle hDisplayState;
601// if (DMBeginConfigureDisplays(&hDisplayState) != noErr)
602// {
603// wxLogSysError(wxT("Could not lock display for display mode changing!"));
604// return false;
605// }
606//
607// wxASSERT( DMUseScreenPrefs(true, hDisplayState) == noErr);
608// DMEndConfigureDisplays(hDisplayState);
609// return true;
610//#else
611 // hmmmmm....
612// return true;
613//#endif
614#endif
615 }
616
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) );
622
623 DMListIndexType nNumModes;
624 DMListType pModes;
625 DMDisplayModeListIteratorUPP uppMLI;
626 DisplayIDType nDisplayID;
627 OSErr err;
628
629 err = DMGetDisplayIDByGDevice(m_hndl, &nDisplayID, false);
630 verify_noerr( err );
631
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") );
635
636 uppMLI = NewDMDisplayModeListIteratorUPP(DMModeInfoProc);
637 wxASSERT(uppMLI);
638
639 DMModeInfoRec sModeInfo;
640 sModeInfo.bMatched = false;
641 sModeInfo.pMode = &mode;
642 unsigned int i;
643
644 for (i = 0; i < nNumModes; ++i)
645 {
646 err = DMGetIndexedDisplayModeFromList(pModes, i, NULL, uppMLI, &sModeInfo);
647 verify_noerr( err );
648
649 if (sModeInfo.bMatched)
650 {
651 sMode = sModeInfo.sMode;
652 break;
653 }
654 }
655
656 if (i == nNumModes)
657 return false;
658
659 DisposeDMDisplayModeListIteratorUPP(uppMLI);
660
661 err = DMDisposeList(pModes);
662 verify_noerr( err );
663
664 // For the really paranoid -
665 // unsigned long flags;
666 // Boolean bok;
667 // wxASSERT(noErr == DMCheckDisplayMode(m_hndl, sMode.csData,
668 // sMode.csMode, &flags, NULL, &bok));
669 // wxASSERT(bok);
670
671 Handle hDisplayState;
672 if (DMBeginConfigureDisplays(&hDisplayState) != noErr)
673 {
674 wxLogSysError(wxT("Could not lock display for display mode changing!"));
675
676 return false;
677 }
678
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
684 hDisplayState );
685
686 if (err != noErr)
687 {
688 DMEndConfigureDisplays(hDisplayState);
689 wxLogError(wxT("Could not set the display mode"));
690
691 return false;
692 }
693
694 DMEndConfigureDisplays(hDisplayState);
695 }
696 else // DM 1.0, 1.2, 1.x
697 {
698 wxLogSysError(
699 wxString::Format(
700 wxT("Monitor gravitation not supported yet. dwDMVer:%u"),
701 (unsigned int) dwDMVer));
702
703 return false;
704 }
705
706 return true;
707}
708
709// ============================================================================
710// wxDisplay::CreateFactory()
711// ============================================================================
712
713/* static */ wxDisplayFactory *wxDisplay::CreateFactory()
714{
715 return new wxDisplayFactoryMac;
716}
717
718#endif // !OSX
719
720#endif // wxUSE_DISPLAY