]> git.saurik.com Git - wxWidgets.git/blob - src/mac/classic/display.cpp
61eb2d44e2f4107d0faf55d30af30c2517573dcc
[wxWidgets.git] / src / mac / classic / display.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/mac/classic/display.cpp
3 // Purpose: Mac implementation of wxDisplay class
4 // Author: Brian Victor
5 // Modified by: Royce Mitchell III & Ryan Norton, 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 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
22
23 #ifdef __BORLANDC__
24 #pragma hdrstop
25 #endif
26
27 #if wxUSE_DISPLAY
28
29 #ifndef WX_PRECOMP
30 #include "wx/dynarray.h"
31 #include "wx/log.h"
32 #endif
33
34 #ifdef __DARWIN__
35 #include <Carbon/Carbon.h>
36 #else
37 #include <Gestalt.h>
38 #include <Displays.h>
39 #include <Quickdraw.h>
40 #include <Video.h> //for VDSwitchInfoRec
41 #include <FixMath.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 implementation classes
51 // ----------------------------------------------------------------------------
52
53 class wxDisplayImplMac : public wxDisplayImpl
54 {
55 public:
56 wxDisplayImplMac(GDHandle hndl) : m_hndl(hndl) { }
57
58 virtual wxRect GetGeometry() const;
59 virtual wxString GetName() const { return wxString(); }
60
61 virtual wxArrayVideoModes GetModes(const wxVideoMode& mode) const;
62 virtual wxVideoMode GetCurrentMode() const;
63 virtual bool ChangeMode(const wxVideoMode& mode);
64
65 private:
66 GDHandle m_hndl;
67
68 DECLARE_NO_COPY_CLASS(wxDisplayImplMac)
69 };
70
71 class wxDisplayFactoryMac : public wxDisplayFactory
72 {
73 public:
74 wxDisplayFactoryMac();
75
76 virtual wxDisplayImpl *CreateDisplay(size_t n);
77 virtual size_t GetCount();
78 virtual int GetFromPoint(const wxPoint& pt);
79
80 protected:
81 DECLARE_NO_COPY_CLASS(wxDisplayFactoryMac)
82 };
83
84 // ============================================================================
85 // wxDisplayFactoryMac implementation
86 // ============================================================================
87
88 size_t wxDisplayFactoryMac::GetCount()
89 {
90 size_t num = 0;
91 GDHandle hndl = DMGetFirstScreenDevice(true);
92 while(hndl)
93 {
94 num++;
95 hndl = DMGetNextScreenDevice(hndl, true);
96 }
97 return num;
98 }
99
100 int wxDisplayFactoryMac::GetFromPoint(const wxPoint &p)
101 {
102 size_t num = 0;
103 GDHandle hndl = DMGetFirstScreenDevice(true);
104 while(hndl)
105 {
106 Rect screenrect = (*hndl)->gdRect;
107 if (p.x >= screenrect.left &&
108 p.x <= screenrect.right &&
109 p.y >= screenrect.top &&
110 p.y <= screenrect.bottom)
111 {
112 return num;
113 }
114 num++;
115 hndl = DMGetNextScreenDevice(hndl, true);
116 }
117
118 return wxNOT_FOUND;
119 }
120
121 wxDisplayImpl *wxDisplayFactoryMac::CreateDisplay(size_t n)
122 {
123 GDHandle hndl = DMGetFirstScreenDevice(true);
124 while(hndl)
125 {
126 if (n == 0)
127 {
128 return new wxDisplayImplMac(hndl);
129 }
130 n--;
131 hndl = DMGetNextScreenDevice(hndl, true);
132 }
133
134 return NULL;
135 }
136
137 // ============================================================================
138 // wxDisplayImplMac implementation
139 // ============================================================================
140
141 wxRect wxDisplayImplMac::GetGeometry() const
142 {
143 Rect screenrect = (*m_hndl)->gdRect;
144 return wxRect(screenrect.left, screenrect.top,
145 screenrect.right - screenrect.left,
146 screenrect.bottom - screenrect.top);
147 }
148
149 struct DMModeIteratorRec
150 {
151 wxArrayVideoModes* pModes;
152 const wxVideoMode* pMatchMode;
153 };
154
155 pascal void DMModeListIteratorProc ( void* pData,
156 DMListIndexType nIndex,
157 DMDisplayModeListEntryPtr pInfo)
158 {
159 DMModeIteratorRec* pInfoData = (DMModeIteratorRec*) pData;
160
161 //Note that in testing the refresh rate is always 0 on my ibook - RN
162 int refresh = (int) Fix2Long(pInfo->displayModeResolutionInfo->csRefreshRate);
163
164 for(unsigned long i = 0; i < pInfo->displayModeDepthBlockInfo->depthBlockCount; ++i)
165 {
166 #define pDBI pInfo->displayModeDepthBlockInfo->depthVPBlock[i].depthVPBlock
167
168 if (wxVideoMode((int) pInfo->displayModeResolutionInfo->csHorizontalPixels,
169 (int) pInfo->displayModeResolutionInfo->csVerticalLines,
170 (int) pDBI->vpPixelSize,
171 refresh).Matches(*pInfoData->pMatchMode) )
172 {
173 pInfoData->pModes->Add(wxVideoMode((int) pInfo->displayModeResolutionInfo->csHorizontalPixels,
174 (int) pInfo->displayModeResolutionInfo->csVerticalLines,
175 (int) pDBI->vpPixelSize,
176 refresh));
177 }
178 #undef pDBI
179 }
180 }
181
182 struct DMModeInfoRec
183 {
184 const wxVideoMode* pMode;
185 VDSwitchInfoRec sMode;
186 bool bMatched;
187 };
188
189 pascal void DMModeInfoProc ( void* pData,
190 DMListIndexType nIndex,
191 DMDisplayModeListEntryPtr pInfo)
192 {
193 DMModeInfoRec* pInfoData = (DMModeInfoRec*) pData;
194 Fixed refresh = Long2Fix(pInfoData->pMode->refresh);
195
196 for(unsigned long i = 0; i < pInfo->displayModeDepthBlockInfo->depthBlockCount; ++i)
197 {
198 #define pDBI pInfo->displayModeDepthBlockInfo->depthVPBlock[i].depthVPBlock
199 if (pInfoData->pMode->w == (int&) pInfo->displayModeResolutionInfo->csHorizontalPixels &&
200 pInfoData->pMode->h == (int&) pInfo->displayModeResolutionInfo->csVerticalLines &&
201 pInfoData->pMode->bpp == (int) pDBI->vpPixelSize &&
202 refresh == pInfo->displayModeResolutionInfo->csRefreshRate)
203 {
204 memcpy(&pInfoData->sMode, pInfo->displayModeDepthBlockInfo->depthVPBlock[i].depthSwitchInfo,
205 sizeof(VDSwitchInfoRec));
206 pInfoData->sMode.csMode = pDBI->vpPixelSize;
207 pInfoData->bMatched = true;
208 break;
209 }
210 #undef pDBI
211 }
212 }
213
214 struct DMModeTransRec
215 {
216 wxVideoMode Mode;
217 const VDSwitchInfoRec* psMode;
218 bool bMatched;
219 };
220
221 pascal void DMModeTransProc ( void* pData,
222 DMListIndexType nIndex,
223 DMDisplayModeListEntryPtr pInfo)
224 {
225 DMModeTransRec* pInfoData = (DMModeTransRec*) pData;
226
227 for(unsigned long i = 0; i < pInfo->displayModeDepthBlockInfo->depthBlockCount; ++i)
228 {
229 #define pDBI pInfo->displayModeDepthBlockInfo->depthVPBlock[i].depthVPBlock
230 if (pInfoData->psMode->csData == pInfo->displayModeDepthBlockInfo->depthVPBlock[i].depthSwitchInfo->csData)
231 {
232 pInfoData->Mode = wxVideoMode((int) pInfo->displayModeResolutionInfo->csHorizontalPixels,
233 (int) pInfo->displayModeResolutionInfo->csVerticalLines,
234 (int) pDBI->vpPixelSize,
235 (int) Fix2Long(pInfo->displayModeResolutionInfo->csRefreshRate) );
236 pInfoData->bMatched = true;
237 break;
238 }
239 #undef pDBI
240 }
241 }
242
243 wxArrayVideoModes wxDisplayImplMac::GetModes(const wxVideoMode& mode) const
244 {
245 wxArrayVideoModes Modes;
246
247 unsigned long dwDMVer;
248 Gestalt(gestaltDisplayMgrVers, (long*) &dwDMVer);
249
250 //Check DM version (for backward compatibility only - 7.5.3+ use 2.0)
251 if (dwDMVer >= 0x020000) //version 2?
252 {
253
254 DMListIndexType nNumModes;
255 DMListType pModes;
256 DMDisplayModeListIteratorUPP uppMLI;
257 DisplayIDType nDisplayID;
258
259 wxASSERT(DMGetDisplayIDByGDevice(m_hndl, &nDisplayID, false) == noErr);
260 //Create a new list...
261 wxASSERT_MSG(DMNewDisplayModeList(nDisplayID, NULL, NULL, &nNumModes, &pModes) == noErr, wxT("Could not create a new display mode list") );
262
263 uppMLI = NewDMDisplayModeListIteratorUPP(DMModeListIteratorProc);
264 wxASSERT(uppMLI);
265
266 DMModeIteratorRec sModeInfo;
267 sModeInfo.pModes = &Modes;
268 sModeInfo.pMatchMode = &mode;
269 for (DMListIndexType i = 0; i < nNumModes; ++i)
270 {
271 wxASSERT(DMGetIndexedDisplayModeFromList(pModes, i, NULL,
272 uppMLI, &sModeInfo) == noErr);
273 }
274 DisposeDMDisplayModeListIteratorUPP(uppMLI);
275 wxASSERT(DMDisposeList(pModes) == noErr);
276 }
277 else //DM 1.0, 1.2, 1.x
278 {
279 wxLogSysError(wxString::Format(wxT("Display Manager Version %u Not Supported! Present? %s"),
280 (unsigned int) dwDMVer / 0x10000,
281 (dwDMVer & (1 << gestaltDisplayMgrPresent) ? wxT("Yes") : wxT("No")) )
282 );
283 }
284
285 return Modes;
286 }
287
288 wxVideoMode wxDisplayImplMac::GetCurrentMode() const
289 {
290 unsigned long dwDMVer;
291 wxVideoMode RetMode;
292
293 Gestalt(gestaltDisplayMgrVers, (long*) &dwDMVer);
294 //Check DM version (for backward compatibility only - 7.5.3+ use 2.0)
295 if (dwDMVer >= 0x020000) //version 2?
296 {
297 VDSwitchInfoRec sMode; //Note - csMode member also contains the bit depth
298 if (DMGetDisplayMode(m_hndl, &sMode) == noErr)
299 {
300 DMListIndexType nNumModes;
301 DMListType pModes;
302 DMDisplayModeListIteratorUPP uppMLI;
303 DisplayIDType nDisplayID;
304
305 wxASSERT(DMGetDisplayIDByGDevice(m_hndl, &nDisplayID, false) == noErr);
306 //Create a new list...
307 wxASSERT_MSG(DMNewDisplayModeList(nDisplayID, NULL, NULL, &nNumModes, &pModes) == noErr,
308 wxT("Could not create a new display mode list") );
309
310 uppMLI = NewDMDisplayModeListIteratorUPP(DMModeTransProc);
311 wxASSERT(uppMLI);
312
313 DMModeTransRec sModeInfo;
314 sModeInfo.bMatched = false;
315 sModeInfo.psMode = &sMode;
316 for (DMListIndexType i = 0; i < nNumModes; ++i)
317 {
318 wxASSERT(DMGetIndexedDisplayModeFromList(pModes, i, NULL,
319 uppMLI, &sModeInfo) == noErr);
320
321 if ( sModeInfo.bMatched == true )
322 {
323 RetMode = sModeInfo.Mode;
324 break;
325 }
326 }
327
328 DisposeDMDisplayModeListIteratorUPP(uppMLI);
329 wxASSERT(DMDisposeList(pModes) == noErr);
330 }
331 else //Can't get current mode?
332 {
333 wxLogSysError(wxString::Format(wxT("Couldn't obtain current display mode!!!\ndwDMVer:%u"),
334 (unsigned int) dwDMVer));
335 }
336 }
337 else //DM ver 1
338 {
339 wxLogSysError(wxString::Format(wxT("Display Manager Version %u Not Supported! Present? %s"),
340 (unsigned int) dwDMVer / 0x10000,
341 (dwDMVer & (1 << gestaltDisplayMgrPresent) ? wxT("Yes") : wxT("No")) )
342 );
343 }
344
345 return RetMode;
346 }
347
348 bool wxDisplayImplMac::ChangeMode(const wxVideoMode& mode)
349 {
350 unsigned long dwDMVer;
351 Gestalt(gestaltDisplayMgrVers, (long*)&dwDMVer);
352 if (GetCount() == 1 || dwDMVer >= 0x020000)
353 {
354 if (mode == wxDefaultVideoMode)
355 {
356 //#ifndef __DARWIN__
357 // Handle hDisplayState;
358 // if (DMBeginConfigureDisplays(&hDisplayState) != noErr)
359 // {
360 // wxLogSysError(wxT("Could not lock display for display mode changing!"));
361 // return false;
362 // }
363 // wxASSERT( DMUseScreenPrefs(true, hDisplayState) == noErr);
364 // DMEndConfigureDisplays(hDisplayState);
365 // return true;
366 //#else
367 //hmmmmm....
368 return true;
369 //#endif
370 }
371
372 //0 & NULL for params 2 & 3 of DMSetVideoMode signal it to use defaults (current mode)
373 //DM 2.0+ doesn't use params 2 & 3 of DMSetDisplayMode
374 //so we have to use this icky structure
375 VDSwitchInfoRec sMode;
376 memset(&sMode, 0, sizeof(VDSwitchInfoRec) );
377
378 DMListIndexType nNumModes;
379 DMListType pModes;
380 DMDisplayModeListIteratorUPP uppMLI;
381 DisplayIDType nDisplayID;
382
383 wxASSERT(DMGetDisplayIDByGDevice(m_hndl, &nDisplayID, false) == noErr);
384 //Create a new list...
385 wxASSERT_MSG(DMNewDisplayModeList(nDisplayID, NULL, NULL, &nNumModes, &pModes) == noErr,
386 wxT("Could not create a new display mode list") );
387
388 uppMLI = NewDMDisplayModeListIteratorUPP(DMModeInfoProc);
389 wxASSERT(uppMLI);
390
391 DMModeInfoRec sModeInfo;
392 sModeInfo.bMatched = false;
393 sModeInfo.pMode = &mode;
394 unsigned int i;
395 for(i = 0; i < nNumModes; ++i)
396 {
397 wxASSERT(DMGetIndexedDisplayModeFromList(pModes, i, NULL,
398 uppMLI, &sModeInfo) == noErr);
399 if (sModeInfo.bMatched == true)
400 {
401 sMode = sModeInfo.sMode;
402 break;
403 }
404 }
405 if(i == nNumModes)
406 return false;
407
408 DisposeDMDisplayModeListIteratorUPP(uppMLI);
409 wxASSERT(DMDisposeList(pModes) == noErr);
410
411 // For the really paranoid -
412 // unsigned long flags;
413 // Boolean bok;
414 // wxASSERT(noErr == DMCheckDisplayMode(m_hndl, sMode.csData,
415 // sMode.csMode, &flags, NULL, &bok));
416 // wxASSERT(bok);
417
418 Handle hDisplayState;
419 if (DMBeginConfigureDisplays(&hDisplayState) != noErr)
420 {
421 wxLogSysError(wxT("Could not lock display for display mode changing!"));
422 return false;
423 }
424
425 unsigned long dwBPP = (unsigned long) mode.bpp;
426 if (DMSetDisplayMode(m_hndl, sMode.csData,
427 (unsigned long*) &(dwBPP), NULL
428 //(unsigned long) &sMode
429 , hDisplayState
430 ) != noErr)
431 {
432 DMEndConfigureDisplays(hDisplayState);
433 wxLogError(wxT("Could not set the display mode"));
434 return false;
435 }
436 DMEndConfigureDisplays(hDisplayState);
437 }
438 else //DM 1.0, 1.2, 1.x
439 {
440 wxLogSysError(wxString::Format(wxT("Monitor gravitation not supported yet. dwDMVer:%u"),
441 (unsigned int) dwDMVer));
442 return false;
443 }
444
445 return true;
446 }
447
448 // ============================================================================
449 // wxDisplay::CreateFactory()
450 // ============================================================================
451
452 /* static */ wxDisplayFactory *wxDisplay::CreateFactory()
453 {
454 return new wxDisplayFactoryMac;
455 }
456
457 #endif // wxUSE_DISPLAY