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