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