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: display.cpp 39797 2006-06-19 20:18:46Z ABX $ 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 54class wxDisplayImplMac : public wxDisplayImpl 55{ 56public: 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 70private: 71 GDHandle m_hndl; 72 73 DECLARE_NO_COPY_CLASS(wxDisplayImplMac) 74}; 75 76class wxDisplayFactoryMac : public wxDisplayFactory 77{ 78public: 79 wxDisplayFactoryMac(); 80 81 virtual wxDisplayImpl *CreateDisplay(size_t n); 82 virtual size_t GetCount(); 83 virtual int GetFromPoint(const wxPoint& pt); 84 85protected: 86 DECLARE_NO_COPY_CLASS(wxDisplayFactoryMac) 87}; 88 89// ============================================================================ 90// wxDisplayFactoryMac implementation 91// ============================================================================ 92 93size_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 105int 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 126wxDisplayImpl *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 148wxRect 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 156struct DMModeIteratorRec 157{ 158 wxArrayVideoModes* pModes; 159 const wxVideoMode* pMatchMode; 160}; 161 162pascal 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 189struct DMModeInfoRec 190{ 191 const wxVideoMode* pMode; 192 VDSwitchInfoRec sMode; 193 bool bMatched; 194}; 195 196pascal 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 221struct DMModeTransRec 222{ 223 wxVideoMode Mode; 224 const VDSwitchInfoRec* psMode; 225 bool bMatched; 226}; 227 228pascal 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 250wxArrayVideoModes 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 295wxVideoMode 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 355bool 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 465