| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| #ifdef USE_RANDR |
| |
| #include <tools/prex.h> |
| #include <X11/extensions/Xrandr.h> |
| #include <tools/postx.h> |
| |
| #include "osl/module.h" |
| #include "rtl/ustring.hxx" |
| |
| namespace |
| { |
| |
| # ifdef XRANDR_DLOPEN |
| |
| class RandRWrapper |
| { |
| oslModule m_pRandRLib; |
| |
| // function pointers |
| Bool(*m_pXRRQueryExtension)(Display*,int*,int*); |
| Status(*m_pXRRQueryVersion)(Display*,int*,int*); |
| XRRScreenConfiguration*(*m_pXRRGetScreenInfo)(Display*,Drawable); |
| void(*m_pXRRFreeScreenConfigInfo)(XRRScreenConfiguration*); |
| void(*m_pXRRSelectInput)(Display*,XLIB_Window,int); |
| int(*m_pXRRUpdateConfiguration)(XEvent*); |
| XRRScreenSize*(*m_pXRRSizes)(Display*,int,int*); |
| XRRScreenSize*(*m_pXRRConfigSizes)(XRRScreenConfiguration*,int*); |
| SizeID(*m_pXRRConfigCurrentConfiguration)(XRRScreenConfiguration*,Rotation*); |
| int(*m_pXRRRootToScreen)(Display*, XLIB_Window); |
| |
| bool m_bValid; |
| |
| void initFromModule(); |
| |
| RandRWrapper(Display*); |
| ~RandRWrapper(); |
| public: |
| static RandRWrapper& get(Display*); |
| static void releaseWrapper(); |
| |
| Bool XRRQueryExtension(Display* i_pDisp, int* o_event_base, int* o_error_base ) |
| { |
| Bool bRet = False; |
| if( m_bValid ) |
| bRet = m_pXRRQueryExtension( i_pDisp, o_event_base, o_error_base ); |
| return bRet; |
| } |
| Status XRRQueryVersion( Display* i_pDisp, int* o_major, int* o_minor ) |
| { |
| return m_bValid ? m_pXRRQueryVersion( i_pDisp, o_major, o_minor ) : 0; |
| } |
| XRRScreenConfiguration* XRRGetScreenInfo( Display* i_pDisp, Drawable i_aDrawable ) |
| { |
| return m_bValid ? m_pXRRGetScreenInfo( i_pDisp, i_aDrawable ) : NULL; |
| } |
| void XRRFreeScreenConfigInfo( XRRScreenConfiguration* i_pConfig ) |
| { |
| if( m_bValid ) |
| m_pXRRFreeScreenConfigInfo( i_pConfig ); |
| } |
| void XRRSelectInput( Display* i_pDisp, XLIB_Window i_window, int i_nMask ) |
| { |
| if( m_bValid ) |
| m_pXRRSelectInput( i_pDisp, i_window, i_nMask ); |
| } |
| int XRRUpdateConfiguration( XEvent* i_pEvent ) |
| { |
| return m_bValid ? m_pXRRUpdateConfiguration( i_pEvent ) : 0; |
| } |
| XRRScreenSize* XRRSizes( Display* i_pDisp, int i_screen, int* o_nscreens ) |
| { |
| return m_bValid ? m_pXRRSizes( i_pDisp, i_screen, o_nscreens ) : NULL; |
| } |
| XRRScreenSize* XRRConfigSizes( XRRScreenConfiguration* i_pConfig, int* o_nSizes ) |
| { |
| return m_bValid ? m_pXRRConfigSizes( i_pConfig, o_nSizes ) : NULL; |
| } |
| SizeID XRRConfigCurrentConfiguration( XRRScreenConfiguration* i_pConfig, Rotation* o_pRot ) |
| { |
| return m_bValid ? m_pXRRConfigCurrentConfiguration( i_pConfig, o_pRot ) : 0; |
| } |
| int XRRRootToScreen( Display *dpy, XLIB_Window root ) |
| { |
| return m_bValid ? m_pXRRRootToScreen( dpy, root ) : -1; |
| } |
| }; |
| |
| void RandRWrapper::initFromModule() |
| { |
| m_pXRRQueryExtension = (Bool(*)(Display*,int*,int*))osl_getAsciiFunctionSymbol( m_pRandRLib, "XRRQueryExtension" ); |
| m_pXRRQueryVersion = (Status(*)(Display*,int*,int*))osl_getAsciiFunctionSymbol( m_pRandRLib, "XRRQueryVersion" ); |
| m_pXRRGetScreenInfo = (XRRScreenConfiguration*(*)(Display*,Drawable))osl_getAsciiFunctionSymbol( m_pRandRLib, "XRRGetScreenInfo" ); |
| m_pXRRFreeScreenConfigInfo = (void(*)(XRRScreenConfiguration*))osl_getAsciiFunctionSymbol( m_pRandRLib, "XRRFreeScreenConfigInfo" ); |
| m_pXRRSelectInput = (void(*)(Display*,XLIB_Window,int))osl_getAsciiFunctionSymbol( m_pRandRLib, "XRRSelectInput" ); |
| m_pXRRUpdateConfiguration = (int(*)(XEvent*))osl_getAsciiFunctionSymbol( m_pRandRLib, "XRRUpdateConfiguration" ); |
| m_pXRRSizes = (XRRScreenSize*(*)(Display*,int,int*))osl_getAsciiFunctionSymbol( m_pRandRLib, "XRRSizes" ); |
| m_pXRRConfigSizes = (XRRScreenSize*(*)(XRRScreenConfiguration*,int*))osl_getAsciiFunctionSymbol( m_pRandRLib, "XRRConfigSizes" ); |
| m_pXRRConfigCurrentConfiguration = (SizeID(*)(XRRScreenConfiguration*,Rotation*))osl_getAsciiFunctionSymbol( m_pRandRLib, "XRRConfigCurrentConfiguration" ); |
| m_pXRRRootToScreen = (int(*)(Display*,XLIB_Window))osl_getAsciiFunctionSymbol( m_pRandRLib, "XRRRootToScreen" ); |
| |
| m_bValid = m_pXRRQueryExtension && |
| m_pXRRQueryVersion && |
| m_pXRRGetScreenInfo && |
| m_pXRRFreeScreenConfigInfo && |
| m_pXRRSelectInput && |
| m_pXRRUpdateConfiguration && |
| m_pXRRSizes && |
| m_pXRRConfigSizes && |
| m_pXRRConfigCurrentConfiguration && |
| m_pXRRRootToScreen |
| ; |
| } |
| |
| RandRWrapper::RandRWrapper( Display* pDisplay ) : |
| m_pRandRLib( NULL ), |
| m_pXRRQueryExtension( NULL ), |
| m_pXRRQueryVersion( NULL ), |
| m_pXRRGetScreenInfo( NULL ), |
| m_pXRRFreeScreenConfigInfo( NULL ), |
| m_pXRRSelectInput( NULL ), |
| m_pXRRUpdateConfiguration( NULL ), |
| m_pXRRSizes( NULL ), |
| m_pXRRConfigSizes( NULL ), |
| m_pXRRConfigCurrentConfiguration( NULL ), |
| m_pXRRRootToScreen( NULL ), |
| m_bValid( false ) |
| { |
| // first try in process space (e.g. gtk links that ?) |
| initFromModule(); |
| if( ! m_bValid ) |
| { |
| // load and resolve dependencies immediately |
| // rationale: there are older distributions where libXrandr.so.2 is not linked |
| // with libXext.so, resulting in a missing symbol and terminating the office |
| // obviously they expected libXext to be linked in global symbolspace (that is |
| // linked by the application), which is not the case with us (because we want |
| // to be able to run in headless mode even without an installed X11 library) |
| m_pRandRLib = osl_loadAsciiModule( "libXrandr.so.2", SAL_LOADMODULE_DEFAULT | SAL_LOADMODULE_NOW ); |
| initFromModule(); |
| } |
| if( m_bValid ) |
| { |
| int nEventBase = 0, nErrorBase = 0; |
| if( ! m_pXRRQueryExtension( pDisplay, &nEventBase, &nErrorBase ) ) |
| m_bValid = false; |
| } |
| } |
| |
| RandRWrapper::~RandRWrapper() |
| { |
| if( m_pRandRLib ) |
| osl_unloadModule( m_pRandRLib ); |
| } |
| |
| static RandRWrapper* pWrapper = NULL; |
| |
| RandRWrapper& RandRWrapper::get( Display* i_pDisplay ) |
| { |
| if( ! pWrapper ) |
| pWrapper = new RandRWrapper( i_pDisplay ); |
| return *pWrapper; |
| } |
| |
| void RandRWrapper::releaseWrapper() |
| { |
| delete pWrapper; |
| pWrapper = NULL; |
| } |
| |
| # else |
| |
| class RandRWrapper |
| { |
| bool m_bValid; |
| |
| RandRWrapper(Display*); |
| public: |
| static RandRWrapper& get(Display*); |
| static void releaseWrapper(); |
| |
| Bool XRRQueryExtension(Display* i_pDisp, int* o_event_base, int* o_error_base ) |
| { |
| Bool bRet = False; |
| if( m_bValid ) |
| bRet = ::XRRQueryExtension( i_pDisp, o_event_base, o_error_base ); |
| return bRet; |
| } |
| Status XRRQueryVersion( Display* i_pDisp, int* o_major, int* o_minor ) |
| { |
| return m_bValid ? ::XRRQueryVersion( i_pDisp, o_major, o_minor ) : 0; |
| } |
| XRRScreenConfiguration* XRRGetScreenInfo( Display* i_pDisp, Drawable i_aDrawable ) |
| { |
| return m_bValid ? ::XRRGetScreenInfo( i_pDisp, i_aDrawable ) : NULL; |
| } |
| void XRRFreeScreenConfigInfo( XRRScreenConfiguration* i_pConfig ) |
| { |
| if( m_bValid ) |
| ::XRRFreeScreenConfigInfo( i_pConfig ); |
| } |
| void XRRSelectInput( Display* i_pDisp, XLIB_Window i_window, int i_nMask ) |
| { |
| if( m_bValid ) |
| ::XRRSelectInput( i_pDisp, i_window, i_nMask ); |
| } |
| int XRRUpdateConfiguration( XEvent* i_pEvent ) |
| { |
| return m_bValid ? ::XRRUpdateConfiguration( i_pEvent ) : 0; |
| } |
| XRRScreenSize* XRRSizes( Display* i_pDisp, int i_screen, int* o_nscreens ) |
| { |
| return m_bValid ? ::XRRSizes( i_pDisp, i_screen, o_nscreens ) : NULL; |
| } |
| XRRScreenSize* XRRConfigSizes( XRRScreenConfiguration* i_pConfig, int* o_nSizes ) |
| { |
| return m_bValid ? ::XRRConfigSizes( i_pConfig, o_nSizes ) : NULL; |
| } |
| SizeID XRRConfigCurrentConfiguration( XRRScreenConfiguration* i_pConfig, Rotation* o_pRot ) |
| { |
| return m_bValid ? ::XRRConfigCurrentConfiguration( i_pConfig, o_pRot ) : 0; |
| } |
| int XRRRootToScreen( Display *dpy, XLIB_Window root ) |
| { |
| return m_bValid ? ::XRRRootToScreen( dpy, root ) : -1; |
| } |
| }; |
| |
| RandRWrapper::RandRWrapper( Display* pDisplay ) : |
| m_bValid( true ) |
| { |
| int nEventBase = 0, nErrorBase = 0; |
| if( !XRRQueryExtension( pDisplay, &nEventBase, &nErrorBase ) ) |
| m_bValid = false; |
| } |
| |
| static RandRWrapper* pWrapper = NULL; |
| |
| RandRWrapper& RandRWrapper::get( Display* i_pDisplay ) |
| { |
| if( ! pWrapper ) |
| pWrapper = new RandRWrapper( i_pDisplay ); |
| return *pWrapper; |
| } |
| |
| void RandRWrapper::releaseWrapper() |
| { |
| delete pWrapper; |
| pWrapper = NULL; |
| } |
| |
| #endif |
| |
| } // namespace |
| |
| #endif |
| |
| #include "unx/saldisp.hxx" |
| #include "unx/salframe.h" |
| #if OSL_DEBUG_LEVEL > 1 |
| #include <cstdio> |
| #endif |
| |
| void SalDisplay::InitRandR( XLIB_Window aRoot ) const |
| { |
| #ifdef USE_RANDR |
| if( m_bUseRandRWrapper ) |
| RandRWrapper::get( GetDisplay() ).XRRSelectInput( GetDisplay(), aRoot, RRScreenChangeNotifyMask ); |
| #else |
| (void)aRoot; |
| #endif |
| } |
| |
| void SalDisplay::DeInitRandR() |
| { |
| #ifdef USE_RANDR |
| if( m_bUseRandRWrapper ) |
| RandRWrapper::releaseWrapper(); |
| #if OSL_DEBUG_LEVEL > 1 |
| fprintf( stderr, "SalDisplay::DeInitRandR()\n" ); |
| #endif |
| #endif |
| } |
| |
| int SalDisplay::processRandREvent( XEvent* pEvent ) |
| { |
| int nRet = 0; |
| #ifdef USE_RANDR |
| XConfigureEvent* pCnfEvent=(XConfigureEvent*)pEvent; |
| if( m_bUseRandRWrapper && pWrapper && pWrapper->XRRRootToScreen(GetDisplay(),pCnfEvent->window) != -1 ) |
| { |
| nRet = pWrapper->XRRUpdateConfiguration( pEvent ); |
| if( nRet == 1 && pEvent->type != ConfigureNotify) // this should then be a XRRScreenChangeNotifyEvent |
| { |
| // update screens |
| bool bNotify = false; |
| for( size_t i = 0; i < m_aScreens.size(); i++ ) |
| { |
| if( m_aScreens[i].m_bInit ) |
| { |
| XRRScreenConfiguration *pConfig = NULL; |
| XRRScreenSize *pSizes = NULL; |
| int nSizes = 0; |
| Rotation nRot = 0; |
| SizeID nId = 0; |
| |
| pConfig = pWrapper->XRRGetScreenInfo( GetDisplay(), m_aScreens[i].m_aRoot ); |
| nId = pWrapper->XRRConfigCurrentConfiguration( pConfig, &nRot ); |
| pSizes = pWrapper->XRRConfigSizes( pConfig, &nSizes ); |
| XRRScreenSize *pTargetSize = pSizes + nId; |
| |
| bNotify = bNotify || |
| m_aScreens[i].m_aSize.Width() != pTargetSize->width || |
| m_aScreens[i].m_aSize.Height() != pTargetSize->height; |
| |
| m_aScreens[i].m_aSize = Size( pTargetSize->width, pTargetSize->height ); |
| |
| pWrapper->XRRFreeScreenConfigInfo( pConfig ); |
| |
| #if OSL_DEBUG_LEVEL > 1 |
| fprintf( stderr, "screen %d changed to size %dx%d\n", (int)i, (int)pTargetSize->width, (int)pTargetSize->height ); |
| #endif |
| } |
| } |
| if( bNotify && ! m_aFrames.empty() ) |
| m_aFrames.front()->CallCallback( SALEVENT_DISPLAYCHANGED, 0 ); |
| } |
| } |
| #else |
| (void)pEvent; |
| #endif |
| return nRet; |
| } |