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