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