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