1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        src/osx/core/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 // Copyright:   (c) wxWidgets team
8 // Licence:     wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
10 
11 // ============================================================================
12 // declarations
13 // ============================================================================
14 
15 // ----------------------------------------------------------------------------
16 // headers
17 // ----------------------------------------------------------------------------
18 
19 #include "wx/wxprec.h"
20 
21 #ifdef __BORLANDC__
22     #pragma hdrstop
23 #endif
24 
25 #if wxUSE_DISPLAY
26 
27 #include "wx/display.h"
28 
29 #ifndef WX_PRECOMP
30     #include "wx/dynarray.h"
31     #include "wx/log.h"
32     #include "wx/string.h"
33     #include "wx/gdicmn.h"
34 #endif
35 
36 #include "wx/display_impl.h"
37 #include "wx/osx/private.h"
38 
39 #if wxOSX_USE_COCOA_OR_CARBON
40 
41 // ----------------------------------------------------------------------------
42 // display classes implementation
43 // ----------------------------------------------------------------------------
44 
45 class wxDisplayImplMacOSX : public wxDisplayImpl
46 {
47 public:
wxDisplayImplMacOSX(unsigned n,CGDirectDisplayID id)48     wxDisplayImplMacOSX(unsigned n, CGDirectDisplayID id)
49         : wxDisplayImpl(n),
50           m_id(id)
51     {
52     }
53 
54     virtual wxRect GetGeometry() const;
55     virtual wxRect GetClientArea() const;
GetName() const56     virtual wxString GetName() const { return wxString(); }
57 
58     virtual wxArrayVideoModes GetModes(const wxVideoMode& mode) const;
59     virtual wxVideoMode GetCurrentMode() const;
60     virtual bool ChangeMode(const wxVideoMode& mode);
61 
62     virtual bool IsPrimary() const;
63 
64 private:
65     CGDirectDisplayID m_id;
66 
67     wxDECLARE_NO_COPY_CLASS(wxDisplayImplMacOSX);
68 };
69 
70 class wxDisplayFactoryMacOSX : public wxDisplayFactory
71 {
72 public:
wxDisplayFactoryMacOSX()73     wxDisplayFactoryMacOSX() {}
74 
75     virtual wxDisplayImpl *CreateDisplay(unsigned n);
76     virtual unsigned GetCount();
77     virtual int GetFromPoint(const wxPoint& pt);
78 
79 protected:
80     wxDECLARE_NO_COPY_CLASS(wxDisplayFactoryMacOSX);
81 };
82 
83 // ============================================================================
84 // wxDisplayFactoryMacOSX implementation
85 // ============================================================================
86 
87 // gets all displays that are not mirror displays
88 
wxOSXGetDisplayList(CGDisplayCount maxDisplays,CGDirectDisplayID * displays,CGDisplayCount * displayCount)89 static CGDisplayErr wxOSXGetDisplayList(CGDisplayCount maxDisplays,
90                                    CGDirectDisplayID *displays,
91                                    CGDisplayCount *displayCount)
92 {
93     CGDisplayErr error = kCGErrorSuccess;
94     CGDisplayCount onlineCount;
95 
96     error = CGGetOnlineDisplayList(0,NULL,&onlineCount);
97     if ( error == kCGErrorSuccess )
98     {
99         *displayCount = 0;
100         if ( onlineCount > 0 )
101         {
102             CGDirectDisplayID *onlineDisplays = new CGDirectDisplayID[onlineCount];
103             error = CGGetOnlineDisplayList(onlineCount,onlineDisplays,&onlineCount);
104             if ( error == kCGErrorSuccess )
105             {
106                 for ( CGDisplayCount i = 0; i < onlineCount; ++i )
107                 {
108                     if ( CGDisplayMirrorsDisplay(onlineDisplays[i]) != kCGNullDirectDisplay )
109                         continue;
110 
111                     if ( displays == NULL )
112                         *displayCount += 1;
113                     else
114                     {
115                         if ( *displayCount < maxDisplays )
116                         {
117                             displays[*displayCount] = onlineDisplays[i];
118                             *displayCount += 1;
119                         }
120                     }
121                 }
122             }
123             delete[] onlineDisplays;
124         }
125 
126     }
127     return error;
128 }
129 
GetCount()130 unsigned wxDisplayFactoryMacOSX::GetCount()
131 {
132     CGDisplayCount count;
133     CGDisplayErr err = wxOSXGetDisplayList(0, NULL, &count);
134 
135     wxCHECK_MSG( err == CGDisplayNoErr, 0, "wxOSXGetDisplayList() failed" );
136 
137     return count;
138 }
139 
GetFromPoint(const wxPoint & p)140 int wxDisplayFactoryMacOSX::GetFromPoint(const wxPoint& p)
141 {
142     CGPoint thePoint = {(float)p.x, (float)p.y};
143     CGDirectDisplayID theID;
144     CGDisplayCount theCount;
145     CGDisplayErr err = CGGetDisplaysWithPoint(thePoint, 1, &theID, &theCount);
146     wxASSERT(err == CGDisplayNoErr);
147 
148     int nWhich = wxNOT_FOUND;
149 
150     if (theCount)
151     {
152         theCount = GetCount();
153         CGDirectDisplayID* theIDs = new CGDirectDisplayID[theCount];
154         err = wxOSXGetDisplayList(theCount, theIDs, &theCount);
155         wxASSERT(err == CGDisplayNoErr);
156 
157         for (nWhich = 0; nWhich < (int) theCount; ++nWhich)
158         {
159             if (theIDs[nWhich] == theID)
160                 break;
161         }
162 
163         delete [] theIDs;
164 
165         if (nWhich == (int) theCount)
166         {
167             wxFAIL_MSG(wxT("Failed to find display in display list"));
168             nWhich = wxNOT_FOUND;
169         }
170     }
171 
172     return nWhich;
173 }
174 
CreateDisplay(unsigned n)175 wxDisplayImpl *wxDisplayFactoryMacOSX::CreateDisplay(unsigned n)
176 {
177     CGDisplayCount theCount = GetCount();
178     CGDirectDisplayID* theIDs = new CGDirectDisplayID[theCount];
179 
180     CGDisplayErr err = wxOSXGetDisplayList(theCount, theIDs, &theCount);
181     wxCHECK_MSG( err == CGDisplayNoErr, NULL, "wxOSXGetDisplayList() failed" );
182 
183     wxASSERT( n < theCount );
184 
185     wxDisplayImplMacOSX *display = new wxDisplayImplMacOSX(n, theIDs[n]);
186 
187     delete [] theIDs;
188 
189     return display;
190 }
191 
192 // ============================================================================
193 // wxDisplayImplMacOSX implementation
194 // ============================================================================
195 
IsPrimary() const196 bool wxDisplayImplMacOSX::IsPrimary() const
197 {
198     return CGDisplayIsMain(m_id);
199 }
200 
GetGeometry() const201 wxRect wxDisplayImplMacOSX::GetGeometry() const
202 {
203     CGRect theRect = CGDisplayBounds(m_id);
204     return wxRect( (int)theRect.origin.x,
205                    (int)theRect.origin.y,
206                    (int)theRect.size.width,
207                    (int)theRect.size.height ); //floats
208 }
209 
GetClientArea() const210 wxRect wxDisplayImplMacOSX::GetClientArea() const
211 {
212     // VZ: I don't know how to get client area for arbitrary display but
213     //     wxGetClientDisplayRect() does work correctly for at least the main
214     //     one (TODO: do it correctly for the other displays too)
215     if ( IsPrimary() )
216         return wxGetClientDisplayRect();
217 
218     return wxDisplayImpl::GetClientArea();
219 }
220 
wxCFDictKeyToInt(CFDictionaryRef desc,CFStringRef key)221 static int wxCFDictKeyToInt( CFDictionaryRef desc, CFStringRef key )
222 {
223     CFNumberRef value = (CFNumberRef) CFDictionaryGetValue( desc, key );
224     if (value == NULL)
225         return 0;
226 
227     int num = 0;
228     CFNumberGetValue( value, kCFNumberIntType, &num );
229 
230     return num;
231 }
232 
GetModes(const wxVideoMode & mode) const233 wxArrayVideoModes wxDisplayImplMacOSX::GetModes(const wxVideoMode& mode) const
234 {
235     wxArrayVideoModes resultModes;
236 
237     CFArrayRef theArray = CGDisplayAvailableModes( m_id );
238 
239     for (CFIndex i = 0; i < CFArrayGetCount(theArray); ++i)
240     {
241         CFDictionaryRef theValue = (CFDictionaryRef) CFArrayGetValueAtIndex( theArray, i );
242 
243         wxVideoMode theMode(
244             wxCFDictKeyToInt( theValue, kCGDisplayWidth ),
245             wxCFDictKeyToInt( theValue, kCGDisplayHeight ),
246             wxCFDictKeyToInt( theValue, kCGDisplayBitsPerPixel ),
247             wxCFDictKeyToInt( theValue, kCGDisplayRefreshRate ));
248 
249         if (theMode.Matches( mode ))
250             resultModes.Add( theMode );
251     }
252 
253     return resultModes;
254 }
255 
GetCurrentMode() const256 wxVideoMode wxDisplayImplMacOSX::GetCurrentMode() const
257 {
258     CFDictionaryRef theValue = CGDisplayCurrentMode( m_id );
259 
260     return wxVideoMode(
261         wxCFDictKeyToInt( theValue, kCGDisplayWidth ),
262         wxCFDictKeyToInt( theValue, kCGDisplayHeight ),
263         wxCFDictKeyToInt( theValue, kCGDisplayBitsPerPixel ),
264         wxCFDictKeyToInt( theValue, kCGDisplayRefreshRate ));
265 }
266 
ChangeMode(const wxVideoMode & mode)267 bool wxDisplayImplMacOSX::ChangeMode( const wxVideoMode& mode )
268 {
269 #ifndef __WXOSX_IPHONE__
270     if (mode == wxDefaultVideoMode)
271     {
272         CGRestorePermanentDisplayConfiguration();
273         return true;
274     }
275 #endif
276 
277     boolean_t bExactMatch;
278     CFDictionaryRef theCGMode = CGDisplayBestModeForParametersAndRefreshRate(
279         m_id,
280         (size_t)mode.GetDepth(),
281         (size_t)mode.GetWidth(),
282         (size_t)mode.GetHeight(),
283         (double)mode.GetRefresh(),
284         &bExactMatch );
285 
286     bool bOK = bExactMatch;
287 
288     if (bOK)
289         bOK = CGDisplaySwitchToMode( m_id, theCGMode ) == CGDisplayNoErr;
290 
291     return bOK;
292 }
293 
294 // ============================================================================
295 // wxDisplay::CreateFactory()
296 // ============================================================================
297 
CreateFactory()298 /* static */ wxDisplayFactory *wxDisplay::CreateFactory()
299 {
300     return new wxDisplayFactoryMacOSX;
301 }
302 
303 #else
304 
CreateFactory()305 /* static */ wxDisplayFactory *wxDisplay::CreateFactory()
306 {
307     return new wxDisplayFactorySingle;
308 }
309 
310 #endif
311 
312 #endif // wxUSE_DISPLAY
313