blob: 1e51ec3616b47a1472c7f949cb6590d36013ef1c [file] [log] [blame]
/**************************************************************
*
* 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;
}