wxwidgets/src/osx/core/display.cpp
Vadim Zeitlin c2162792cf Implement wxDisplaySize() and wxClientDisplayRect() via wxDisplay
Instead of forwarding to these functions from wxDisplay implementation
in wxUSE_DISPLAY==0 case, make the functions themselves wrappers around
wxDisplay, which may, or not, depending on the platform, have a simpler
implementation in wxUSE_DISPLAY==0 case, but is always available in any
case.

As part of this change, only use src/osx/core/display.cpp in macOS
builds, not iOS ones and update the Xcode project accordingly too.

This cuts down on code duplication, especially in wxGTK, and facilitates
further additions to wxDisplay API.
2018-09-30 23:07:45 +02:00

359 lines
11 KiB
C++

/////////////////////////////////////////////////////////////////////////////
// Name: src/osx/core/display.cpp
// Purpose: Mac implementation of wxDisplay class
// Author: Ryan Norton & Brian Victor
// Modified by: Royce Mitchell III, Vadim Zeitlin
// Created: 06/21/02
// Copyright: (c) wxWidgets team
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
// ============================================================================
// declarations
// ============================================================================
// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#include "wx/private/display.h"
#ifndef WX_PRECOMP
#include "wx/dynarray.h"
#include "wx/log.h"
#include "wx/string.h"
#include "wx/gdicmn.h"
#endif
#include "wx/osx/private.h"
// ----------------------------------------------------------------------------
// common helpers compiled even in wxUSE_DISPLAY==0 case
// ----------------------------------------------------------------------------
// This one is defined in Objective C++ code.
extern wxRect wxOSXGetMainDisplayClientArea();
namespace
{
wxRect wxGetDisplayGeometry(CGDirectDisplayID id)
{
CGRect theRect = CGDisplayBounds(id);
return wxRect( (int)theRect.origin.x,
(int)theRect.origin.y,
(int)theRect.size.width,
(int)theRect.size.height ); //floats
}
} // anonymous namespace
#if wxUSE_DISPLAY
#include "wx/scopedarray.h"
// ----------------------------------------------------------------------------
// display classes implementation
// ----------------------------------------------------------------------------
class wxDisplayImplMacOSX : public wxDisplayImpl
{
public:
wxDisplayImplMacOSX(unsigned n, CGDirectDisplayID id)
: wxDisplayImpl(n),
m_id(id)
{
}
virtual wxRect GetGeometry() const wxOVERRIDE;
virtual wxRect GetClientArea() const wxOVERRIDE;
virtual wxString GetName() const wxOVERRIDE { return wxString(); }
virtual wxArrayVideoModes GetModes(const wxVideoMode& mode) const wxOVERRIDE;
virtual wxVideoMode GetCurrentMode() const wxOVERRIDE;
virtual bool ChangeMode(const wxVideoMode& mode) wxOVERRIDE;
virtual bool IsPrimary() const wxOVERRIDE;
private:
CGDirectDisplayID m_id;
wxDECLARE_NO_COPY_CLASS(wxDisplayImplMacOSX);
};
class wxDisplayFactoryMacOSX : public wxDisplayFactory
{
public:
wxDisplayFactoryMacOSX() {}
virtual wxDisplayImpl *CreateDisplay(unsigned n) wxOVERRIDE;
virtual unsigned GetCount() wxOVERRIDE;
virtual int GetFromPoint(const wxPoint& pt) wxOVERRIDE;
protected:
wxDECLARE_NO_COPY_CLASS(wxDisplayFactoryMacOSX);
};
// ============================================================================
// wxDisplayFactoryMacOSX implementation
// ============================================================================
// gets all displays that are not mirror displays
static CGDisplayErr wxOSXGetDisplayList(CGDisplayCount maxDisplays,
CGDirectDisplayID *displays,
CGDisplayCount *displayCount)
{
CGDisplayErr error = kCGErrorSuccess;
CGDisplayCount onlineCount;
error = CGGetOnlineDisplayList(0,NULL,&onlineCount);
if ( error == kCGErrorSuccess )
{
*displayCount = 0;
if ( onlineCount > 0 )
{
CGDirectDisplayID *onlineDisplays = new CGDirectDisplayID[onlineCount];
error = CGGetOnlineDisplayList(onlineCount,onlineDisplays,&onlineCount);
if ( error == kCGErrorSuccess )
{
for ( CGDisplayCount i = 0; i < onlineCount; ++i )
{
if ( CGDisplayMirrorsDisplay(onlineDisplays[i]) != kCGNullDirectDisplay )
continue;
if ( displays == NULL )
*displayCount += 1;
else
{
if ( *displayCount < maxDisplays )
{
displays[*displayCount] = onlineDisplays[i];
*displayCount += 1;
}
}
}
}
delete[] onlineDisplays;
}
}
return error;
}
unsigned wxDisplayFactoryMacOSX::GetCount()
{
CGDisplayCount count;
CGDisplayErr err = wxOSXGetDisplayList(0, NULL, &count);
wxCHECK_MSG( err == CGDisplayNoErr, 0, "wxOSXGetDisplayList() failed" );
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 = wxOSXGetDisplayList(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(unsigned n)
{
CGDisplayCount theCount = GetCount();
wxScopedArray<CGDirectDisplayID> theIDs(theCount);
CGDisplayErr err = wxOSXGetDisplayList(theCount, theIDs.get(), &theCount);
wxCHECK_MSG( err == CGDisplayNoErr, NULL, "wxOSXGetDisplayList() failed" );
wxCHECK_MSG( n < theCount, NULL, wxS("Invalid display index") );
return new wxDisplayImplMacOSX(n, theIDs[n]);
}
// ============================================================================
// wxDisplayImplMacOSX implementation
// ============================================================================
bool wxDisplayImplMacOSX::IsPrimary() const
{
return CGDisplayIsMain(m_id);
}
wxRect wxDisplayImplMacOSX::GetGeometry() const
{
return wxGetDisplayGeometry(m_id);
}
wxRect wxDisplayImplMacOSX::GetClientArea() const
{
// VZ: I don't know how to get client area for arbitrary display but
// wxGetClientDisplayRect() does work correctly for at least the main
// one (TODO: do it correctly for the other displays too)
if ( IsPrimary() )
return wxOSXGetMainDisplayClientArea();
return wxDisplayImpl::GetClientArea();
}
static int wxOSXCGDisplayModeGetBitsPerPixel( CGDisplayModeRef theValue )
{
wxCFRef<CFStringRef> pixelEncoding( CGDisplayModeCopyPixelEncoding(theValue) );
int depth = 0;
if ( CFStringCompare( pixelEncoding, CFSTR(IO32BitDirectPixels) , kCFCompareCaseInsensitive) == kCFCompareEqualTo )
depth = 32;
else if ( CFStringCompare( pixelEncoding, CFSTR(IO16BitDirectPixels) , kCFCompareCaseInsensitive) == kCFCompareEqualTo )
depth = 16;
else if ( CFStringCompare( pixelEncoding, CFSTR(IO8BitIndexedPixels) , kCFCompareCaseInsensitive) == kCFCompareEqualTo )
depth = 8;
return depth;
}
wxArrayVideoModes wxDisplayImplMacOSX::GetModes(const wxVideoMode& mode) const
{
wxArrayVideoModes resultModes;
wxCFRef<CFArrayRef> theArray(CGDisplayCopyAllDisplayModes( m_id ,NULL ) );
for (CFIndex i = 0; i < CFArrayGetCount(theArray); ++i)
{
CGDisplayModeRef theValue = (CGDisplayModeRef) CFArrayGetValueAtIndex( theArray, i );
wxVideoMode theMode(
CGDisplayModeGetWidth(theValue),
CGDisplayModeGetHeight(theValue),
wxOSXCGDisplayModeGetBitsPerPixel(theValue),
CGDisplayModeGetRefreshRate(theValue));
if (theMode.Matches( mode ))
resultModes.Add( theMode );
}
return resultModes;
}
wxVideoMode wxDisplayImplMacOSX::GetCurrentMode() const
{
wxCFRef<CGDisplayModeRef> theValue( CGDisplayCopyDisplayMode( m_id ) );
return wxVideoMode(
CGDisplayModeGetWidth(theValue),
CGDisplayModeGetHeight(theValue),
wxOSXCGDisplayModeGetBitsPerPixel(theValue),
CGDisplayModeGetRefreshRate(theValue));
}
bool wxDisplayImplMacOSX::ChangeMode( const wxVideoMode& mode )
{
#ifndef __WXOSX_IPHONE__
if (mode == wxDefaultVideoMode)
{
CGRestorePermanentDisplayConfiguration();
return true;
}
#endif
wxCHECK_MSG( mode.GetWidth() && mode.GetHeight(), false,
wxT("at least the width and height must be specified") );
bool bOK = false;
wxCFRef<CFArrayRef> theArray(CGDisplayCopyAllDisplayModes( m_id ,NULL ) );
for (CFIndex i = 0; i < CFArrayGetCount(theArray); ++i)
{
CGDisplayModeRef theValue = (CGDisplayModeRef) CFArrayGetValueAtIndex( theArray, i );
wxVideoMode theMode(
CGDisplayModeGetWidth(theValue),
CGDisplayModeGetHeight(theValue),
wxOSXCGDisplayModeGetBitsPerPixel(theValue),
CGDisplayModeGetRefreshRate(theValue));
if ( theMode.GetWidth() == mode.GetWidth() && theMode.GetHeight() == mode.GetHeight() &&
( mode.GetDepth() == 0 || theMode.GetDepth() == mode.GetDepth() ) &&
( mode.GetRefresh() == 0 || theMode.GetRefresh() == mode.GetRefresh() ) )
{
CGDisplaySetDisplayMode( m_id, theValue , NULL );
bOK = true;
break;
}
}
return bOK;
}
// ============================================================================
// wxDisplay::CreateFactory()
// ============================================================================
/* static */ wxDisplayFactory *wxDisplay::CreateFactory()
{
return new wxDisplayFactoryMacOSX;
}
#else // !wxUSE_DISPLAY
class wxDisplayImplSingleMacOSX : public wxDisplayImplSingle
{
public:
virtual wxRect GetGeometry() const wxOVERRIDE
{
return wxGetDisplayGeometry(CGMainDisplayID());
}
virtual wxRect GetClientArea() const wxOVERRIDE
{
return wxOSXGetMainDisplayClientArea();
}
};
class wxDisplayFactorySingleMacOSX : public wxDisplayFactorySingle
{
protected:
virtual wxDisplayImpl *CreateSingleDisplay() wxOVERRIDE
{
return new wxDisplayImplSingleMacOSX;
}
};
/* static */ wxDisplayFactory *wxDisplay::CreateFactory()
{
return new wxDisplayFactorySingleMacOSX;
}
#endif // wxUSE_DISPLAY