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