]> git.saurik.com Git - wxWidgets.git/blame - src/mac/classic/display.cpp
great copy ctor/assignment operators cleanup by Paul Cornett (patch 1307665)
[wxWidgets.git] / src / mac / classic / display.cpp
CommitLineData
2646f485
SC
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$
77ffb593 8// Copyright: (c) wxWidgets team
65571936 9// Licence: wxWindows licence
2646f485
SC
10/////////////////////////////////////////////////////////////////////////////
11
2646f485
SC
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
45class wxDisplayMacPriv
46{
47public:
48 GDHandle m_hndl;
49};
50
51size_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
64int 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
85wxDisplay::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
102wxRect 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
111int 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
126wxString wxDisplay::GetName() const
127{
128 // Macs don't name their displays...
129 return wxEmptyString;
130}
131
132struct DMModeIteratorRec
133{
134 wxArrayVideoModes* pModes;
135 const wxVideoMode* pMatchMode;
136};
137
138pascal 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
165struct DMModeInfoRec
166{
167 const wxVideoMode* pMode;
168 VDSwitchInfoRec sMode;
169 bool bMatched;
170};
171
172pascal 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
197struct DMModeTransRec
198{
199 wxVideoMode Mode;
200 const VDSwitchInfoRec* psMode;
201 bool bMatched;
202};
203
204pascal 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
226wxArrayVideoModes
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
273wxVideoMode 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
333bool 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
433wxDisplay::~wxDisplay()
434{
435 if ( m_priv )
436 {
437 delete m_priv;
438 m_priv = 0;
439 }
440}
441
442#endif // wxUSE_DISPLAY