/////////////////////////////////////////////////////////////////////////// // Name: src/unix/displayx11.cpp // Purpose: Unix/X11 implementation of wxDisplay class // Author: Brian Victor, Vadim Zeitlin // Modified by: // Created: 12/05/02 // Copyright: (c) wxWidgets team // Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// // ============================================================================ // declarations // ============================================================================ // ---------------------------------------------------------------------------- // headers // ---------------------------------------------------------------------------- // For compilers that support precompilation, includes "wx.h". #include "wx/wxprec.h" #ifdef __BORLANDC__ #pragma hdrstop #endif #ifndef WX_PRECOMP #include "wx/utils.h" #include "wx/intl.h" #include "wx/log.h" #endif /* WX_PRECOMP */ #ifdef __WXGTK20__ #include // GDK_WINDOWING_X11 #endif #if !defined(__WXGTK20__) || defined(GDK_WINDOWING_X11) #include #include #endif #include "wx/private/display.h" #ifndef __WXGTK20__ static wxRect wxGetMainScreenWorkArea(); class wxDisplayImplSingleX11 : public wxDisplayImplSingle { public: virtual wxRect GetGeometry() const wxOVERRIDE { Display* const dpy = wxGetX11Display(); return wxRect(0, 0, DisplayWidth(dpy, DefaultScreen (dpy)), DisplayHeight(dpy, DefaultScreen (dpy))); } virtual wxRect GetClientArea() const wxOVERRIDE { return wxGetMainScreenWorkArea(); } }; class wxDisplayFactorySingleX11 : public wxDisplayFactorySingle { protected: virtual wxDisplayImpl *CreateSingleDisplay() { return new wxDisplayImplSingleX11; } }; #endif // !__WXGTK20__ #if wxUSE_DISPLAY #ifndef __WXGTK20__ #include typedef XineramaScreenInfo ScreenInfo; // ---------------------------------------------------------------------------- // helper class storing information about all screens // ---------------------------------------------------------------------------- class ScreensInfoBase { public: operator const ScreenInfo *() const { return m_screens; } unsigned GetCount() const { return static_cast(m_num); } protected: ScreenInfo *m_screens; int m_num; }; class ScreensInfo : public ScreensInfoBase { public: ScreensInfo() { m_screens = XineramaQueryScreens((Display *)wxGetDisplay(), &m_num); } ~ScreensInfo() { XFree(m_screens); } }; // ---------------------------------------------------------------------------- // display and display factory classes // ---------------------------------------------------------------------------- class wxDisplayImplX11 : public wxDisplayImpl { public: wxDisplayImplX11(unsigned n, const ScreenInfo& info) : wxDisplayImpl(n), m_rect(info.x_org, info.y_org, info.width, info.height) { } virtual wxRect GetGeometry() const wxOVERRIDE { return m_rect; } virtual wxRect GetClientArea() const wxOVERRIDE { // we intentionally don't cache the result here because the client // display area may change (e.g. the user resized or hid a panel) and // we don't currently react to its changes return IsPrimary() ? wxGetMainScreenWorkArea() : m_rect; } virtual wxArrayVideoModes GetModes(const wxVideoMode& mode) const wxOVERRIDE; virtual wxVideoMode GetCurrentMode() const wxOVERRIDE; virtual bool ChangeMode(const wxVideoMode& mode) wxOVERRIDE; private: wxRect m_rect; int m_depth; wxDECLARE_NO_COPY_CLASS(wxDisplayImplX11); }; class wxDisplayFactoryX11 : public wxDisplayFactory { public: wxDisplayFactoryX11() { } virtual wxDisplayImpl *CreateDisplay(unsigned n) wxOVERRIDE; virtual unsigned GetCount() wxOVERRIDE; virtual int GetFromPoint(const wxPoint& pt) wxOVERRIDE; protected: wxDECLARE_NO_COPY_CLASS(wxDisplayFactoryX11); }; // ============================================================================ // wxDisplayFactoryX11 implementation // ============================================================================ unsigned wxDisplayFactoryX11::GetCount() { return ScreensInfo().GetCount(); } int wxDisplayFactoryX11::GetFromPoint(const wxPoint& p) { ScreensInfo screens; const unsigned numscreens(screens.GetCount()); for ( unsigned i = 0; i < numscreens; ++i ) { const ScreenInfo& s = screens[i]; if ( p.x >= s.x_org && p.x < s.x_org + s.width && p.y >= s.y_org && p.y < s.y_org + s.height ) { return i; } } return wxNOT_FOUND; } wxDisplayImpl *wxDisplayFactoryX11::CreateDisplay(unsigned n) { ScreensInfo screens; return n < screens.GetCount() ? new wxDisplayImplX11(n, screens[n]) : NULL; } #endif // !__WXGTK20__ // ============================================================================ // wxDisplayImplX11 implementation // ============================================================================ #if !defined(__WXGTK20__) || defined(GDK_WINDOWING_X11) #ifdef HAVE_X11_EXTENSIONS_XF86VMODE_H #include // // See (http://www.xfree86.org/4.2.0/XF86VidModeDeleteModeLine.3.html) for more // info about xf86 video mode extensions // //free private data common to x (usually s3) servers #define wxClearXVM(vm) if(vm.privsize) XFree(vm.c_private) // Correct res rate from GLFW #define wxCRR2(v,dc) (int) (((1000.0f * (float) dc) /*PIXELS PER SECOND */) / ((float) v.htotal * v.vtotal /*PIXELS PER FRAME*/) + 0.5f) #define wxCRR(v) wxCRR2(v,v.dotclock) #define wxCVM2(v, dc, display, nScreen) wxVideoMode(v.hdisplay, v.vdisplay, DefaultDepth(display, nScreen), wxCRR2(v,dc)) #define wxCVM(v, display, nScreen) wxCVM2(v, v.dotclock, display, nScreen) wxArrayVideoModes wxXF86VidMode_GetModes(const wxVideoMode& mode, Display* display, int nScreen) { XF86VidModeModeInfo** ppXModes; //Enumerated Modes (Don't forget XFree() :)) int nNumModes; //Number of modes enumerated.... wxArrayVideoModes Modes; //modes to return... if (XF86VidModeGetAllModeLines(display, nScreen, &nNumModes, &ppXModes)) { for (int i = 0; i < nNumModes; ++i) { XF86VidModeModeInfo& info = *ppXModes[i]; const wxVideoMode vm = wxCVM(info, display, nScreen); if (vm.Matches(mode)) { Modes.Add(vm); } wxClearXVM(info); // XFree(ppXModes[i]); //supposed to free? } XFree(ppXModes); } else //OOPS! { wxLogSysError(_("Failed to enumerate video modes")); } return Modes; } wxVideoMode wxXF86VidMode_GetCurrentMode(Display* display, int nScreen) { XF86VidModeModeLine VM; int nDotClock; if ( !XF86VidModeGetModeLine(display, nScreen, &nDotClock, &VM) ) return wxVideoMode(); wxClearXVM(VM); return wxCVM2(VM, nDotClock, display, nScreen); } bool wxXF86VidMode_ChangeMode(const wxVideoMode& mode, Display* display, int nScreen) { XF86VidModeModeInfo** ppXModes; //Enumerated Modes (Don't forget XFree() :)) int nNumModes; //Number of modes enumerated.... if(!XF86VidModeGetAllModeLines(display, nScreen, &nNumModes, &ppXModes)) { wxLogSysError(_("Failed to change video mode")); return false; } bool bRet = false; if (mode == wxDefaultVideoMode) { bRet = XF86VidModeSwitchToMode(display, nScreen, ppXModes[0]) != 0; for (int i = 0; i < nNumModes; ++i) { wxClearXVM((*ppXModes[i])); // XFree(ppXModes[i]); //supposed to free? } } else { for (int i = 0; i < nNumModes; ++i) { if (!bRet && ppXModes[i]->hdisplay == mode.GetWidth() && ppXModes[i]->vdisplay == mode.GetHeight() && wxCRR((*ppXModes[i])) == mode.GetRefresh()) { //switch! bRet = XF86VidModeSwitchToMode(display, nScreen, ppXModes[i]) != 0; } wxClearXVM((*ppXModes[i])); // XFree(ppXModes[i]); //supposed to free? } } XFree(ppXModes); return bRet; } #ifndef __WXGTK20__ wxArrayVideoModes wxDisplayImplX11::GetModes(const wxVideoMode& modeMatch) const { Display* display = static_cast(wxGetDisplay()); int nScreen = DefaultScreen(display); return wxXF86VidMode_GetModes(modeMatch, display, nScreen); } wxVideoMode wxDisplayImplX11::GetCurrentMode() const { Display* display = static_cast(wxGetDisplay()); int nScreen = DefaultScreen(display); return wxXF86VidMode_GetCurrentMode(display, nScreen); } bool wxDisplayImplX11::ChangeMode(const wxVideoMode& mode) { Display* display = static_cast(wxGetDisplay()); int nScreen = DefaultScreen(display); return wxXF86VidMode_ChangeMode(mode, display, nScreen); } #endif // !__WXGTK20__ #else // !HAVE_X11_EXTENSIONS_XF86VMODE_H wxArrayVideoModes wxX11_GetModes(const wxDisplayImpl* impl, const wxVideoMode& modeMatch, Display* display) { int count_return; int* depths = XListDepths(display, 0, &count_return); wxArrayVideoModes modes; if ( depths ) { const wxRect rect = impl->GetGeometry(); for ( int x = 0; x < count_return; ++x ) { wxVideoMode mode(rect.width, rect.height, depths[x]); if ( mode.Matches(modeMatch) ) { modes.Add(mode); } } XFree(depths); } return modes; } #ifndef __WXGTK20__ wxArrayVideoModes wxDisplayImplX11::GetModes(const wxVideoMode& modeMatch) const { Display* display = static_cast(wxGetDisplay()); return wxX11_GetModes(this, modeMatch, display); } wxVideoMode wxDisplayImplX11::GetCurrentMode() const { // Not implemented return wxVideoMode(); } bool wxDisplayImplX11::ChangeMode(const wxVideoMode& WXUNUSED(mode)) { // Not implemented return false; } #endif // !__WXGTK20__ #endif // !HAVE_X11_EXTENSIONS_XF86VMODE_H #endif // !defined(__WXGTK20__) || defined(GDK_WINDOWING_X11) #endif // wxUSE_DISPLAY // ============================================================================ // wxDisplay::CreateFactory() // ============================================================================ #ifndef __WXGTK20__ /* static */ wxDisplayFactory *wxDisplay::CreateFactory() { #if wxUSE_DISPLAY if ( XineramaIsActive((Display*)wxGetDisplay()) ) return new wxDisplayFactoryX11; #endif // wxUSE_DISPLAY return new wxDisplayFactorySingleX11; } #endif #if !defined(__WXGTK20__) || defined(GDK_WINDOWING_X11) void wxGetWorkAreaX11(Screen* screen, int& x, int& y, int& width, int& height) { Display* display = DisplayOfScreen(screen); Atom property = XInternAtom(display, "_NET_WORKAREA", true); if (property) { Atom actual_type; int actual_format; unsigned long nitems; unsigned long bytes_after; unsigned char* data = NULL; Status status = XGetWindowProperty( display, RootWindowOfScreen(screen), property, 0, 4, false, XA_CARDINAL, &actual_type, &actual_format, &nitems, &bytes_after, &data); if (status == Success && actual_type == XA_CARDINAL && actual_format == 32 && nitems == 4) { const long* p = (long*)data; x = p[0]; y = p[1]; width = p[2]; height = p[3]; } if (data) XFree(data); } } #endif // !defined(__WXGTK20__) || defined(GDK_WINDOWING_X11) #ifndef __WXGTK20__ wxRect wxGetMainScreenWorkArea() { wxRect rect; Display * const dpy = wxGetX11Display(); wxCHECK_MSG( dpy, rect, "can't be called before initializing the GUI" ); wxGetWorkAreaX11(DefaultScreenOfDisplay(dpy), rect.x, rect.y, rect.width, rect.height); const wxRect rectFull = wxDisplay().GetGeometry(); if ( !rect.width || !rect.height ) { // _NET_WORKAREA not available or didn't work, fall back to the total // display size. rect = rectFull; } else { // Although _NET_WORKAREA is supposed to return the client size of the // screen, not all implementations are conforming, apparently, see // #14419, so make sure we return a subset of the primary display. rect = rect.Intersect(rectFull); } return rect; } #endif // !__WXGTK20__