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