1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 #ifdef USE_RANDR 29 30 #include <tools/prex.h> 31 #include <X11/extensions/Xrandr.h> 32 #include <tools/postx.h> 33 34 #include "osl/module.h" 35 #include "rtl/ustring.hxx" 36 37 namespace 38 { 39 40 # ifdef XRANDR_DLOPEN 41 42 class RandRWrapper 43 { 44 oslModule m_pRandRLib; 45 46 // function pointers 47 Bool(*m_pXRRQueryExtension)(Display*,int*,int*); 48 Status(*m_pXRRQueryVersion)(Display*,int*,int*); 49 XRRScreenConfiguration*(*m_pXRRGetScreenInfo)(Display*,Drawable); 50 void(*m_pXRRFreeScreenConfigInfo)(XRRScreenConfiguration*); 51 void(*m_pXRRSelectInput)(Display*,XLIB_Window,int); 52 int(*m_pXRRUpdateConfiguration)(XEvent*); 53 XRRScreenSize*(*m_pXRRSizes)(Display*,int,int*); 54 XRRScreenSize*(*m_pXRRConfigSizes)(XRRScreenConfiguration*,int*); 55 SizeID(*m_pXRRConfigCurrentConfiguration)(XRRScreenConfiguration*,Rotation*); 56 int(*m_pXRRRootToScreen)(Display*, XLIB_Window); 57 58 bool m_bValid; 59 60 void initFromModule(); 61 62 RandRWrapper(Display*); 63 ~RandRWrapper(); 64 public: 65 static RandRWrapper& get(Display*); 66 static void releaseWrapper(); 67 68 Bool XRRQueryExtension(Display* i_pDisp, int* o_event_base, int* o_error_base ) 69 { 70 Bool bRet = False; 71 if( m_bValid ) 72 bRet = m_pXRRQueryExtension( i_pDisp, o_event_base, o_error_base ); 73 return bRet; 74 } 75 Status XRRQueryVersion( Display* i_pDisp, int* o_major, int* o_minor ) 76 { 77 return m_bValid ? m_pXRRQueryVersion( i_pDisp, o_major, o_minor ) : 0; 78 } 79 XRRScreenConfiguration* XRRGetScreenInfo( Display* i_pDisp, Drawable i_aDrawable ) 80 { 81 return m_bValid ? m_pXRRGetScreenInfo( i_pDisp, i_aDrawable ) : NULL; 82 } 83 void XRRFreeScreenConfigInfo( XRRScreenConfiguration* i_pConfig ) 84 { 85 if( m_bValid ) 86 m_pXRRFreeScreenConfigInfo( i_pConfig ); 87 } 88 void XRRSelectInput( Display* i_pDisp, XLIB_Window i_window, int i_nMask ) 89 { 90 if( m_bValid ) 91 m_pXRRSelectInput( i_pDisp, i_window, i_nMask ); 92 } 93 int XRRUpdateConfiguration( XEvent* i_pEvent ) 94 { 95 return m_bValid ? m_pXRRUpdateConfiguration( i_pEvent ) : 0; 96 } 97 XRRScreenSize* XRRSizes( Display* i_pDisp, int i_screen, int* o_nscreens ) 98 { 99 return m_bValid ? m_pXRRSizes( i_pDisp, i_screen, o_nscreens ) : NULL; 100 } 101 XRRScreenSize* XRRConfigSizes( XRRScreenConfiguration* i_pConfig, int* o_nSizes ) 102 { 103 return m_bValid ? m_pXRRConfigSizes( i_pConfig, o_nSizes ) : NULL; 104 } 105 SizeID XRRConfigCurrentConfiguration( XRRScreenConfiguration* i_pConfig, Rotation* o_pRot ) 106 { 107 return m_bValid ? m_pXRRConfigCurrentConfiguration( i_pConfig, o_pRot ) : 0; 108 } 109 int XRRRootToScreen( Display *dpy, XLIB_Window root ) 110 { 111 return m_bValid ? m_pXRRRootToScreen( dpy, root ) : -1; 112 } 113 }; 114 115 void RandRWrapper::initFromModule() 116 { 117 m_pXRRQueryExtension = (Bool(*)(Display*,int*,int*))osl_getAsciiFunctionSymbol( m_pRandRLib, "XRRQueryExtension" ); 118 m_pXRRQueryVersion = (Status(*)(Display*,int*,int*))osl_getAsciiFunctionSymbol( m_pRandRLib, "XRRQueryVersion" ); 119 m_pXRRGetScreenInfo = (XRRScreenConfiguration*(*)(Display*,Drawable))osl_getAsciiFunctionSymbol( m_pRandRLib, "XRRGetScreenInfo" ); 120 m_pXRRFreeScreenConfigInfo = (void(*)(XRRScreenConfiguration*))osl_getAsciiFunctionSymbol( m_pRandRLib, "XRRFreeScreenConfigInfo" ); 121 m_pXRRSelectInput = (void(*)(Display*,XLIB_Window,int))osl_getAsciiFunctionSymbol( m_pRandRLib, "XRRSelectInput" ); 122 m_pXRRUpdateConfiguration = (int(*)(XEvent*))osl_getAsciiFunctionSymbol( m_pRandRLib, "XRRUpdateConfiguration" ); 123 m_pXRRSizes = (XRRScreenSize*(*)(Display*,int,int*))osl_getAsciiFunctionSymbol( m_pRandRLib, "XRRSizes" ); 124 m_pXRRConfigSizes = (XRRScreenSize*(*)(XRRScreenConfiguration*,int*))osl_getAsciiFunctionSymbol( m_pRandRLib, "XRRConfigSizes" ); 125 m_pXRRConfigCurrentConfiguration = (SizeID(*)(XRRScreenConfiguration*,Rotation*))osl_getAsciiFunctionSymbol( m_pRandRLib, "XRRConfigCurrentConfiguration" ); 126 m_pXRRRootToScreen = (int(*)(Display*,XLIB_Window))osl_getAsciiFunctionSymbol( m_pRandRLib, "XRRRootToScreen" ); 127 128 m_bValid = m_pXRRQueryExtension && 129 m_pXRRQueryVersion && 130 m_pXRRGetScreenInfo && 131 m_pXRRFreeScreenConfigInfo && 132 m_pXRRSelectInput && 133 m_pXRRUpdateConfiguration && 134 m_pXRRSizes && 135 m_pXRRConfigSizes && 136 m_pXRRConfigCurrentConfiguration && 137 m_pXRRRootToScreen 138 ; 139 } 140 141 RandRWrapper::RandRWrapper( Display* pDisplay ) : 142 m_pRandRLib( NULL ), 143 m_pXRRQueryExtension( NULL ), 144 m_pXRRQueryVersion( NULL ), 145 m_pXRRGetScreenInfo( NULL ), 146 m_pXRRFreeScreenConfigInfo( NULL ), 147 m_pXRRSelectInput( NULL ), 148 m_pXRRUpdateConfiguration( NULL ), 149 m_pXRRSizes( NULL ), 150 m_pXRRConfigSizes( NULL ), 151 m_pXRRConfigCurrentConfiguration( NULL ), 152 m_pXRRRootToScreen( NULL ), 153 m_bValid( false ) 154 { 155 // first try in process space (e.g. gtk links that ?) 156 initFromModule(); 157 if( ! m_bValid ) 158 { 159 rtl::OUString aLibName( RTL_CONSTASCII_USTRINGPARAM( "libXrandr.so.2" ) ); 160 // load and resolve dependencies immediately 161 // rationale: there are older distributions where libXrandr.so.2 is not linked 162 // with libXext.so, resulting in a missing symbol and terminating the office 163 // obviously they expected libXext to be linked in global symbolspace (that is 164 // linked by the application), which is not the case with us (because we want 165 // to be able to run in headless mode even without an installed X11 library) 166 m_pRandRLib = osl_loadModule( aLibName.pData, SAL_LOADMODULE_DEFAULT | SAL_LOADMODULE_NOW ); 167 initFromModule(); 168 } 169 if( m_bValid ) 170 { 171 int nEventBase = 0, nErrorBase = 0; 172 if( ! m_pXRRQueryExtension( pDisplay, &nEventBase, &nErrorBase ) ) 173 m_bValid = false; 174 } 175 } 176 177 RandRWrapper::~RandRWrapper() 178 { 179 if( m_pRandRLib ) 180 osl_unloadModule( m_pRandRLib ); 181 } 182 183 static RandRWrapper* pWrapper = NULL; 184 185 RandRWrapper& RandRWrapper::get( Display* i_pDisplay ) 186 { 187 if( ! pWrapper ) 188 pWrapper = new RandRWrapper( i_pDisplay ); 189 return *pWrapper; 190 } 191 192 void RandRWrapper::releaseWrapper() 193 { 194 delete pWrapper; 195 pWrapper = NULL; 196 } 197 198 # else 199 200 class RandRWrapper 201 { 202 bool m_bValid; 203 204 RandRWrapper(Display*); 205 public: 206 static RandRWrapper& get(Display*); 207 static void releaseWrapper(); 208 209 Bool XRRQueryExtension(Display* i_pDisp, int* o_event_base, int* o_error_base ) 210 { 211 Bool bRet = False; 212 if( m_bValid ) 213 bRet = ::XRRQueryExtension( i_pDisp, o_event_base, o_error_base ); 214 return bRet; 215 } 216 Status XRRQueryVersion( Display* i_pDisp, int* o_major, int* o_minor ) 217 { 218 return m_bValid ? ::XRRQueryVersion( i_pDisp, o_major, o_minor ) : 0; 219 } 220 XRRScreenConfiguration* XRRGetScreenInfo( Display* i_pDisp, Drawable i_aDrawable ) 221 { 222 return m_bValid ? ::XRRGetScreenInfo( i_pDisp, i_aDrawable ) : NULL; 223 } 224 void XRRFreeScreenConfigInfo( XRRScreenConfiguration* i_pConfig ) 225 { 226 if( m_bValid ) 227 ::XRRFreeScreenConfigInfo( i_pConfig ); 228 } 229 void XRRSelectInput( Display* i_pDisp, XLIB_Window i_window, int i_nMask ) 230 { 231 if( m_bValid ) 232 ::XRRSelectInput( i_pDisp, i_window, i_nMask ); 233 } 234 int XRRUpdateConfiguration( XEvent* i_pEvent ) 235 { 236 return m_bValid ? ::XRRUpdateConfiguration( i_pEvent ) : 0; 237 } 238 XRRScreenSize* XRRSizes( Display* i_pDisp, int i_screen, int* o_nscreens ) 239 { 240 return m_bValid ? ::XRRSizes( i_pDisp, i_screen, o_nscreens ) : NULL; 241 } 242 XRRScreenSize* XRRConfigSizes( XRRScreenConfiguration* i_pConfig, int* o_nSizes ) 243 { 244 return m_bValid ? ::XRRConfigSizes( i_pConfig, o_nSizes ) : NULL; 245 } 246 SizeID XRRConfigCurrentConfiguration( XRRScreenConfiguration* i_pConfig, Rotation* o_pRot ) 247 { 248 return m_bValid ? ::XRRConfigCurrentConfiguration( i_pConfig, o_pRot ) : 0; 249 } 250 int XRRRootToScreen( Display *dpy, XLIB_Window root ) 251 { 252 return m_bValid ? ::XRRRootToScreen( dpy, root ) : -1; 253 } 254 }; 255 256 RandRWrapper::RandRWrapper( Display* pDisplay ) : 257 m_bValid( true ) 258 { 259 int nEventBase = 0, nErrorBase = 0; 260 if( !XRRQueryExtension( pDisplay, &nEventBase, &nErrorBase ) ) 261 m_bValid = false; 262 } 263 264 static RandRWrapper* pWrapper = NULL; 265 266 RandRWrapper& RandRWrapper::get( Display* i_pDisplay ) 267 { 268 if( ! pWrapper ) 269 pWrapper = new RandRWrapper( i_pDisplay ); 270 return *pWrapper; 271 } 272 273 void RandRWrapper::releaseWrapper() 274 { 275 delete pWrapper; 276 pWrapper = NULL; 277 } 278 279 #endif 280 281 } // namespace 282 283 #endif 284 285 #include "unx/saldisp.hxx" 286 #include "unx/salframe.h" 287 #if OSL_DEBUG_LEVEL > 1 288 #include <cstdio> 289 #endif 290 291 void SalDisplay::InitRandR( XLIB_Window aRoot ) const 292 { 293 #ifdef USE_RANDR 294 if( m_bUseRandRWrapper ) 295 RandRWrapper::get( GetDisplay() ).XRRSelectInput( GetDisplay(), aRoot, RRScreenChangeNotifyMask ); 296 #else 297 (void)aRoot; 298 #endif 299 } 300 301 void SalDisplay::DeInitRandR() 302 { 303 #ifdef USE_RANDR 304 if( m_bUseRandRWrapper ) 305 RandRWrapper::releaseWrapper(); 306 #if OSL_DEBUG_LEVEL > 1 307 fprintf( stderr, "SalDisplay::DeInitRandR()\n" ); 308 #endif 309 #endif 310 } 311 312 int SalDisplay::processRandREvent( XEvent* pEvent ) 313 { 314 int nRet = 0; 315 #ifdef USE_RANDR 316 XConfigureEvent* pCnfEvent=(XConfigureEvent*)pEvent; 317 if( m_bUseRandRWrapper && pWrapper && pWrapper->XRRRootToScreen(GetDisplay(),pCnfEvent->window) != -1 ) 318 { 319 nRet = pWrapper->XRRUpdateConfiguration( pEvent ); 320 if( nRet == 1 && pEvent->type != ConfigureNotify) // this should then be a XRRScreenChangeNotifyEvent 321 { 322 // update screens 323 bool bNotify = false; 324 for( size_t i = 0; i < m_aScreens.size(); i++ ) 325 { 326 if( m_aScreens[i].m_bInit ) 327 { 328 XRRScreenConfiguration *pConfig = NULL; 329 XRRScreenSize *pSizes = NULL; 330 int nSizes = 0; 331 Rotation nRot = 0; 332 SizeID nId = 0; 333 334 pConfig = pWrapper->XRRGetScreenInfo( GetDisplay(), m_aScreens[i].m_aRoot ); 335 nId = pWrapper->XRRConfigCurrentConfiguration( pConfig, &nRot ); 336 pSizes = pWrapper->XRRConfigSizes( pConfig, &nSizes ); 337 XRRScreenSize *pTargetSize = pSizes + nId; 338 339 bNotify = bNotify || 340 m_aScreens[i].m_aSize.Width() != pTargetSize->width || 341 m_aScreens[i].m_aSize.Height() != pTargetSize->height; 342 343 m_aScreens[i].m_aSize = Size( pTargetSize->width, pTargetSize->height ); 344 345 pWrapper->XRRFreeScreenConfigInfo( pConfig ); 346 347 #if OSL_DEBUG_LEVEL > 1 348 fprintf( stderr, "screen %d changed to size %dx%d\n", (int)i, (int)pTargetSize->width, (int)pTargetSize->height ); 349 #endif 350 } 351 } 352 if( bNotify && ! m_aFrames.empty() ) 353 m_aFrames.front()->CallCallback( SALEVENT_DISPLAYCHANGED, 0 ); 354 } 355 } 356 #else 357 (void)pEvent; 358 #endif 359 return nRet; 360 } 361