X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/e40298d54ecd5b109222a7c60aa2ef084a304d69..923d28da0eed674dfd7f4a497568ac14a29f0189:/src/mac/carbon/display.cpp diff --git a/src/mac/carbon/display.cpp b/src/mac/carbon/display.cpp index 3502ac55f5..aa3e320d34 100644 --- a/src/mac/carbon/display.cpp +++ b/src/mac/carbon/display.cpp @@ -1,19 +1,22 @@ ///////////////////////////////////////////////////////////////////////////// -// Name: display.cpp +// Name: src/mac/carbon/display.cpp // Purpose: Mac implementation of wxDisplay class -// Author: Brian Victor -// Modified by: Royce Mitchell III +// Author: Ryan Norton & Brian Victor +// Modified by: Royce Mitchell III, Vadim Zeitlin // Created: 06/21/02 // RCS-ID: $Id$ -// Copyright: (c) wxWindows team +// Copyright: (c) wxWidgets team // Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// -#ifdef __GNUG__ - #pragma implementation "display.h" -#endif +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- -// For compilers that support precompilation, includes "wx.h". #include "wx/wxprec.h" #ifdef __BORLANDC__ @@ -22,36 +25,277 @@ #if wxUSE_DISPLAY +#include "wx/display.h" + #ifndef WX_PRECOMP - #include "wx/dynarray.h" + #include "wx/dynarray.h" + #include "wx/log.h" + #include "wx/string.h" #endif #ifdef __DARWIN__ #include #else + #include #include #include + #include // for VDSwitchInfoRec + #include + #include #endif -#include "wx/display.h" +#include "wx/display_impl.h" #include "wx/gdicmn.h" -#include "wx/string.h" // ---------------------------------------------------------------------------- -// private classes +// display classes implementation // ---------------------------------------------------------------------------- -class wxDisplayMacPriv +#ifdef __WXMAC_OSX__ + +class wxDisplayImplMacOSX : public wxDisplayImpl +{ +public: + wxDisplayImplMacOSX(size_t n, CGDirectDisplayID id) + : wxDisplayImpl(n), + m_id(id) + { + } + + virtual wxRect GetGeometry() const; + virtual wxString GetName() const { return wxString(); } + + virtual wxArrayVideoModes GetModes(const wxVideoMode& mode) const; + virtual wxVideoMode GetCurrentMode() const; + virtual bool ChangeMode(const wxVideoMode& mode); + +private: + CGDirectDisplayID m_id; + + DECLARE_NO_COPY_CLASS(wxDisplayImplMacOSX) +}; + +class wxDisplayFactoryMacOSX : public wxDisplayFactory +{ +public: + wxDisplayFactoryMacOSX() {} + + virtual wxDisplayImpl *CreateDisplay(size_t n); + virtual size_t GetCount(); + virtual int GetFromPoint(const wxPoint& pt); + +protected: + DECLARE_NO_COPY_CLASS(wxDisplayFactoryMacOSX) +}; + +// ============================================================================ +// wxDisplayFactoryMacOSX implementation +// ============================================================================ + +size_t wxDisplayFactoryMacOSX::GetCount() +{ + CGDisplayCount count; +#ifdef __WXDEBUG__ + CGDisplayErr err = +#endif + CGGetActiveDisplayList(0, NULL, &count); + + wxASSERT(err == CGDisplayNoErr); + + return count; +} + +int wxDisplayFactoryMacOSX::GetFromPoint(const wxPoint& p) +{ + CGPoint thePoint = {(float)p.x, (float)p.y}; + CGDirectDisplayID theID; + CGDisplayCount theCount; + CGDisplayErr err = CGGetDisplaysWithPoint(thePoint, 1, &theID, &theCount); + wxASSERT(err == CGDisplayNoErr); + + int nWhich = wxNOT_FOUND; + + if (theCount) + { + theCount = GetCount(); + CGDirectDisplayID* theIDs = new CGDirectDisplayID[theCount]; + err = CGGetActiveDisplayList(theCount, theIDs, &theCount); + wxASSERT(err == CGDisplayNoErr); + + for (nWhich = 0; nWhich < (int) theCount; ++nWhich) + { + if (theIDs[nWhich] == theID) + break; + } + + delete [] theIDs; + + if (nWhich == (int) theCount) + { + wxFAIL_MSG(wxT("Failed to find display in display list")); + nWhich = wxNOT_FOUND; + } + } + + return nWhich; +} + +wxDisplayImpl *wxDisplayFactoryMacOSX::CreateDisplay(size_t n) +{ + CGDisplayCount theCount = GetCount(); + CGDirectDisplayID* theIDs = new CGDirectDisplayID[theCount]; + +#ifdef __WXDEBUG__ + CGDisplayErr err = +#endif + CGGetActiveDisplayList(theCount, theIDs, &theCount); + + wxASSERT( err == CGDisplayNoErr ); + wxASSERT( n < theCount ); + + wxDisplayImplMacOSX *display = new wxDisplayImplMacOSX(n, theIDs[n]); + + delete [] theIDs; + + return display; +} + +// ============================================================================ +// wxDisplayImplMacOSX implementation +// ============================================================================ + +wxRect wxDisplayImplMacOSX::GetGeometry() const +{ + CGRect theRect = CGDisplayBounds(m_id); + return wxRect( (int)theRect.origin.x, + (int)theRect.origin.y, + (int)theRect.size.width, + (int)theRect.size.height ); //floats +} + +static int wxCFDictKeyToInt( CFDictionaryRef desc, CFStringRef key ) +{ + CFNumberRef value = (CFNumberRef) CFDictionaryGetValue( desc, key ); + if (value == NULL) + return 0; + + int num = 0; + CFNumberGetValue( value, kCFNumberIntType, &num ); + + return num; +} + +wxArrayVideoModes wxDisplayImplMacOSX::GetModes(const wxVideoMode& mode) const +{ + wxArrayVideoModes resultModes; + + CFArrayRef theArray = CGDisplayAvailableModes( m_id ); + + for (CFIndex i = 0; i < CFArrayGetCount(theArray); ++i) + { + CFDictionaryRef theValue = (CFDictionaryRef) CFArrayGetValueAtIndex( theArray, i ); + + wxVideoMode theMode( + wxCFDictKeyToInt( theValue, kCGDisplayWidth ), + wxCFDictKeyToInt( theValue, kCGDisplayHeight ), + wxCFDictKeyToInt( theValue, kCGDisplayBitsPerPixel ), + wxCFDictKeyToInt( theValue, kCGDisplayRefreshRate )); + + if (theMode.Matches( mode )) + resultModes.Add( theMode ); + } + + return resultModes; +} + +wxVideoMode wxDisplayImplMacOSX::GetCurrentMode() const +{ + CFDictionaryRef theValue = CGDisplayCurrentMode( m_id ); + + return wxVideoMode( + wxCFDictKeyToInt( theValue, kCGDisplayWidth ), + wxCFDictKeyToInt( theValue, kCGDisplayHeight ), + wxCFDictKeyToInt( theValue, kCGDisplayBitsPerPixel ), + wxCFDictKeyToInt( theValue, kCGDisplayRefreshRate )); +} + +bool wxDisplayImplMacOSX::ChangeMode( const wxVideoMode& mode ) +{ + // Changing to default mode (wxDefaultVideoMode) doesn't + // work because we don't have access to the system's 'scrn' + // resource which holds the user's mode which the system + // will return to after this app is done + boolean_t bExactMatch; + CFDictionaryRef theCGMode = CGDisplayBestModeForParametersAndRefreshRate( + m_id, + (size_t)mode.bpp, + (size_t)mode.w, + (size_t)mode.h, + (double)mode.refresh, + &bExactMatch ); + + bool bOK = bExactMatch; + + if (bOK) + bOK = CGDisplaySwitchToMode( m_id, theCGMode ) == CGDisplayNoErr; + + return bOK; +} + +// ============================================================================ +// wxDisplay::CreateFactory() +// ============================================================================ + +/* static */ wxDisplayFactory *wxDisplay::CreateFactory() +{ + return new wxDisplayFactoryMacOSX; +} + +#else // !__WXMAC_OSX__ + +class wxDisplayImplMac : public wxDisplayImpl { public: + wxDisplayImplMac(size_t n, GDHandle hndl) + : wxDisplayImpl(n), + m_hndl(hndl) + { + } + + virtual wxRect GetGeometry() const; + virtual wxString GetName() const { return wxString(); } + + virtual wxArrayVideoModes GetModes(const wxVideoMode& mode) const; + virtual wxVideoMode GetCurrentMode() const; + virtual bool ChangeMode(const wxVideoMode& mode); + +private: GDHandle m_hndl; + + DECLARE_NO_COPY_CLASS(wxDisplayImplMac) }; -size_t wxDisplayBase::GetCount() +class wxDisplayFactoryMac : public wxDisplayFactory +{ +public: + wxDisplayFactoryMac(); + + virtual wxDisplayImpl *CreateDisplay(size_t n); + virtual size_t GetCount(); + virtual int GetFromPoint(const wxPoint& pt); + +protected: + DECLARE_NO_COPY_CLASS(wxDisplayFactoryMac) +}; + +// ============================================================================ +// wxDisplayFactoryMac implementation +// ============================================================================ + +size_t wxDisplayFactoryMac::GetCount() { - GDHandle hndl; size_t num = 0; - hndl = DMGetFirstScreenDevice(true); + GDHandle hndl = DMGetFirstScreenDevice(true); while(hndl) { num++; @@ -60,11 +304,10 @@ size_t wxDisplayBase::GetCount() return num; } -int wxDisplayBase::GetFromPoint(const wxPoint &p) +int wxDisplayFactoryMac::GetFromPoint(const wxPoint &p) { - GDHandle hndl; size_t num = 0; - hndl = DMGetFirstScreenDevice(true); + GDHandle hndl = DMGetFirstScreenDevice(true); while(hndl) { Rect screenrect = (*hndl)->gdRect; @@ -78,58 +321,400 @@ int wxDisplayBase::GetFromPoint(const wxPoint &p) num++; hndl = DMGetNextScreenDevice(hndl, true); } - return -1; + + return wxNOT_FOUND; } -wxDisplay::wxDisplay(size_t index) : wxDisplayBase ( index ), - m_priv ( new wxDisplayMacPriv() ) +wxDisplayImpl *wxDisplayFactoryMac::CreateDisplay(size_t n) { - GDHandle hndl; - hndl = DMGetFirstScreenDevice(true); - m_priv->m_hndl = NULL; + size_t nOrig = n; + + GDHandle hndl = DMGetFirstScreenDevice(true); while(hndl) { - if (index == 0) + if (n == 0) { - m_priv->m_hndl = hndl; + return new wxDisplayImplMac(nOrig, hndl); } - index--; + n--; hndl = DMGetNextScreenDevice(hndl, true); } + + return NULL; } -wxRect wxDisplay::GetGeometry() const +// ============================================================================ +// wxDisplayImplMac implementation +// ============================================================================ + +wxRect wxDisplayImplMac::GetGeometry() const { - if (!(m_priv)) return wxRect(0, 0, 0, 0); - if (!(m_priv->m_hndl)) return wxRect(0, 0, 0, 0); - Rect screenrect = (*(m_priv->m_hndl))->gdRect; - return wxRect( screenrect.left, screenrect.top, - screenrect.right - screenrect.left, screenrect.bottom - screenrect.top); + Rect screenrect = (*m_hndl)->gdRect; + return wxRect(screenrect.left, screenrect.top, + screenrect.right - screenrect.left, + screenrect.bottom - screenrect.top); } -int wxDisplay::GetDepth() const +struct DMModeIteratorRec { - if (!(m_priv)) return 0; - if (!(m_priv->m_hndl)) return 0; + wxArrayVideoModes* pModes; + const wxVideoMode* pMatchMode; +}; - // This cryptic looking code is based on Apple's sample code: - // http://developer.apple.com/samplecode/Sample_Code/Graphics_2D/GDevVideo/Gen.cp.htm - return ((*(*(m_priv->m_hndl))->gdPMap)->pixelSize) & 0x0000FFFF; +pascal void DMModeListIteratorProc( + void* pData, + DMListIndexType nIndex, + DMDisplayModeListEntryPtr pInfo) +{ + DMModeIteratorRec* pInfoData = (DMModeIteratorRec*) pData; + + // Note that in testing the refresh rate is always 0 on my ibook - RN + int refresh = (int) Fix2Long(pInfo->displayModeResolutionInfo->csRefreshRate); + +#define pDBI pInfo->displayModeDepthBlockInfo->depthVPBlock[i].depthVPBlock + + for (unsigned long i = 0; i < pInfo->displayModeDepthBlockInfo->depthBlockCount; ++i) + { + if (wxVideoMode( (int) pInfo->displayModeResolutionInfo->csHorizontalPixels, + (int) pInfo->displayModeResolutionInfo->csVerticalLines, + (int) pDBI->vpPixelSize, + refresh).Matches(*pInfoData->pMatchMode) ) + { + pInfoData->pModes->Add( + wxVideoMode( + (int) pInfo->displayModeResolutionInfo->csHorizontalPixels, + (int) pInfo->displayModeResolutionInfo->csVerticalLines, + (int) pDBI->vpPixelSize, + refresh ) ); + } + } + +#undef pDBI } -wxString wxDisplay::GetName() const +struct DMModeInfoRec { - // Macs don't name their displays... - return wxT(""); + const wxVideoMode* pMode; + VDSwitchInfoRec sMode; + bool bMatched; +}; + +pascal void DMModeInfoProc( + void* pData, + DMListIndexType nIndex, + DMDisplayModeListEntryPtr pInfo ) +{ + DMModeInfoRec* pInfoData = (DMModeInfoRec*) pData; + Fixed refresh = Long2Fix(pInfoData->pMode->refresh); + +#define pDBI pInfo->displayModeDepthBlockInfo->depthVPBlock[i].depthVPBlock + + for (unsigned long i = 0; i < pInfo->displayModeDepthBlockInfo->depthBlockCount; ++i) + { + if (pInfoData->pMode->w == (int&) pInfo->displayModeResolutionInfo->csHorizontalPixels && + pInfoData->pMode->h == (int&) pInfo->displayModeResolutionInfo->csVerticalLines && + pInfoData->pMode->bpp == (int) pDBI->vpPixelSize && + refresh == pInfo->displayModeResolutionInfo->csRefreshRate) + { + memcpy( + &pInfoData->sMode, + pInfo->displayModeDepthBlockInfo->depthVPBlock[i].depthSwitchInfo, + sizeof(VDSwitchInfoRec)); + pInfoData->sMode.csMode = pDBI->vpPixelSize; + pInfoData->bMatched = true; + break; + } + } + +#undef pDBI +} + +struct DMModeTransRec +{ + wxVideoMode Mode; + const VDSwitchInfoRec* psMode; + bool bMatched; +}; + +pascal void DMModeTransProc( + void* pData, + DMListIndexType nIndex, + DMDisplayModeListEntryPtr pInfo) +{ + DMModeTransRec* pInfoData = (DMModeTransRec*) pData; + +#define pDBI pInfo->displayModeDepthBlockInfo->depthVPBlock[i].depthVPBlock + + for (unsigned long i = 0; i < pInfo->displayModeDepthBlockInfo->depthBlockCount; ++i) + { + if (pInfoData->psMode->csData == pInfo->displayModeDepthBlockInfo->depthVPBlock[i].depthSwitchInfo->csData) + { + pInfoData->Mode = wxVideoMode( + (int) pInfo->displayModeResolutionInfo->csHorizontalPixels, + (int) pInfo->displayModeResolutionInfo->csVerticalLines, + (int) pDBI->vpPixelSize, + (int) Fix2Long(pInfo->displayModeResolutionInfo->csRefreshRate) ); + pInfoData->bMatched = true; + break; + } + } + +#undef pDBI } -wxDisplay::~wxDisplay() +wxArrayVideoModes wxDisplayImplMac::GetModes(const wxVideoMode& mode) const { - if ( m_priv ) + wxArrayVideoModes Modes; + unsigned long dwDMVer; + + // Check DM version == 2 + // (for backward compatibility only - 7.5.3+ use 2.0) + Gestalt( gestaltDisplayMgrVers, (long*) &dwDMVer ); + if (dwDMVer >= 0x020000) { - delete m_priv; - m_priv = 0; + DMListIndexType nNumModes; + DMListType pModes; + DMDisplayModeListIteratorUPP uppMLI; + DisplayIDType nDisplayID; + OSErr err; + + err = DMGetDisplayIDByGDevice(m_hndl, &nDisplayID, false); + verify_noerr( err ); + + // Create a new list... + err = DMNewDisplayModeList(nDisplayID, NULL, NULL, &nNumModes, &pModes); + wxASSERT_MSG( err == noErr, wxT("Could not create a new display mode list") ); + + uppMLI = NewDMDisplayModeListIteratorUPP(DMModeListIteratorProc); + wxASSERT( uppMLI ); + + DMModeIteratorRec sModeInfo; + sModeInfo.pModes = &Modes; + sModeInfo.pMatchMode = &mode; + + for (DMListIndexType i = 0; i < nNumModes; ++i) + { + err = DMGetIndexedDisplayModeFromList(pModes, i, NULL, uppMLI, &sModeInfo); + verify_noerr( err ); + } + + DisposeDMDisplayModeListIteratorUPP(uppMLI); + err = DMDisposeList(pModes); + verify_noerr( err ); } + else // DM 1.0, 1.2, 1.x + { + wxLogSysError( + wxString::Format( + wxT("Display Manager Version %u Not Supported! Present? %s"), + (unsigned int) dwDMVer / 0x10000, + (dwDMVer & (1 << gestaltDisplayMgrPresent) ? wxT("Yes") : wxT("No")) ) ); + } + + return Modes; } +wxVideoMode wxDisplayImplMac::GetCurrentMode() const +{ + unsigned long dwDMVer; + wxVideoMode RetMode; + + // Check DM version == 2 + // (for backward compatibility only - 7.5.3+ use 2.0) + Gestalt( gestaltDisplayMgrVers, (long*) &dwDMVer ); + if (dwDMVer >= 0x020000) + { + VDSwitchInfoRec sMode; // Note: csMode member also contains the bit depth + OSErr err; + + err = DMGetDisplayMode( m_hndl, &sMode ); + if (err == noErr) + { + DMListIndexType nNumModes; + DMListType pModes; + DMDisplayModeListIteratorUPP uppMLI; + DisplayIDType nDisplayID; + + err = DMGetDisplayIDByGDevice(m_hndl, &nDisplayID, false); + verify_noerr( err ); + + // Create a new list... + err = DMNewDisplayModeList(nDisplayID, NULL, NULL, &nNumModes, &pModes); + wxASSERT_MSG( err == noErr, wxT("Could not create a new display mode list") ); + + uppMLI = NewDMDisplayModeListIteratorUPP(DMModeTransProc); + wxASSERT( uppMLI ); + + DMModeTransRec sModeInfo; + sModeInfo.bMatched = false; + sModeInfo.psMode = &sMode; + for (DMListIndexType i = 0; i < nNumModes; ++i) + { + err = DMGetIndexedDisplayModeFromList(pModes, i, NULL, uppMLI, &sModeInfo); + verify_noerr( err ); + + if ( sModeInfo.bMatched ) + { + RetMode = sModeInfo.Mode; + break; + } + } + + DisposeDMDisplayModeListIteratorUPP(uppMLI); + err = DMDisposeList(pModes); + verify_noerr( err ); + } + else // Can't get current mode? + { + wxLogSysError( + wxString::Format( + wxT("Couldn't obtain current display mode!!!\ndwDMVer:%u"), + (unsigned int) dwDMVer)); + } + } + else // DM ver 1 + { + wxLogSysError( + wxString::Format( + wxT("Display Manager Version %u Not Supported! Present? %s"), + (unsigned int) dwDMVer / 0x10000, + (dwDMVer & (1 << gestaltDisplayMgrPresent) ? wxT("Yes") : wxT("No")) ) ); + } + + return RetMode; +} + +bool wxDisplayImplMac::ChangeMode(const wxVideoMode& mode) +{ + unsigned long dwDMVer; + + Gestalt( gestaltDisplayMgrVers, (long*)&dwDMVer ); + if (GetCount() == 1 || dwDMVer >= 0x020000) + { + if (mode == wxDefaultVideoMode) + { + return true; + +#if 0 +//#ifndef __DARWIN__ +// Handle hDisplayState; +// if (DMBeginConfigureDisplays(&hDisplayState) != noErr) +// { +// wxLogSysError(wxT("Could not lock display for display mode changing!")); +// return false; +// } +// +// wxASSERT( DMUseScreenPrefs(true, hDisplayState) == noErr); +// DMEndConfigureDisplays(hDisplayState); +// return true; +//#else + // hmmmmm.... +// return true; +//#endif +#endif + } + + //0 & NULL for params 2 & 3 of DMSetVideoMode signal it to use defaults (current mode) + //DM 2.0+ doesn't use params 2 & 3 of DMSetDisplayMode + //so we have to use this icky structure + VDSwitchInfoRec sMode; + memset( &sMode, 0, sizeof(VDSwitchInfoRec) ); + + DMListIndexType nNumModes; + DMListType pModes; + DMDisplayModeListIteratorUPP uppMLI; + DisplayIDType nDisplayID; + OSErr err; + + err = DMGetDisplayIDByGDevice(m_hndl, &nDisplayID, false); + verify_noerr( err ); + + // Create a new list... + err = DMNewDisplayModeList(nDisplayID, NULL, NULL, &nNumModes, &pModes); + wxASSERT_MSG(err == noErr, wxT("Could not create a new display mode list") ); + + uppMLI = NewDMDisplayModeListIteratorUPP(DMModeInfoProc); + wxASSERT(uppMLI); + + DMModeInfoRec sModeInfo; + sModeInfo.bMatched = false; + sModeInfo.pMode = &mode; + unsigned int i; + + for (i = 0; i < nNumModes; ++i) + { + err = DMGetIndexedDisplayModeFromList(pModes, i, NULL, uppMLI, &sModeInfo); + verify_noerr( err ); + + if (sModeInfo.bMatched) + { + sMode = sModeInfo.sMode; + break; + } + } + + if (i == nNumModes) + return false; + + DisposeDMDisplayModeListIteratorUPP(uppMLI); + + err = DMDisposeList(pModes); + verify_noerr( err ); + + // For the really paranoid - + // unsigned long flags; + // Boolean bok; + // wxASSERT(noErr == DMCheckDisplayMode(m_hndl, sMode.csData, + // sMode.csMode, &flags, NULL, &bok)); + // wxASSERT(bok); + + Handle hDisplayState; + if (DMBeginConfigureDisplays(&hDisplayState) != noErr) + { + wxLogSysError(wxT("Could not lock display for display mode changing!")); + + return false; + } + + unsigned long dwBPP = (unsigned long) mode.bpp; + err = DMSetDisplayMode( + m_hndl, sMode.csData, + (unsigned long*) &(dwBPP), + NULL, //(unsigned long) &sMode + hDisplayState ); + + if (err != noErr) + { + DMEndConfigureDisplays(hDisplayState); + wxLogError(wxT("Could not set the display mode")); + + return false; + } + + DMEndConfigureDisplays(hDisplayState); + } + else // DM 1.0, 1.2, 1.x + { + wxLogSysError( + wxString::Format( + wxT("Monitor gravitation not supported yet. dwDMVer:%u"), + (unsigned int) dwDMVer)); + + return false; + } + + return true; +} + +// ============================================================================ +// wxDisplay::CreateFactory() +// ============================================================================ + +/* static */ wxDisplayFactory *wxDisplay::CreateFactory() +{ + return new wxDisplayFactoryMac; +} + +#endif // !OSX + #endif // wxUSE_DISPLAY