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 // load and resolve dependencies immediately 156 // rationale: there are older distributions where libXrandr.so.2 is not linked 157 // with libXext.so, resulting in a missing symbol and terminating the office 158 // obviously they expected libXext to be linked in global symbolspace (that is 159 // linked by the application), which is not the case with us (because we want 160 // to be able to run in headless mode even without an installed X11 library) 161 m_pRandRLib = osl_loadAsciiModule( "libXrandr.so.2", SAL_LOADMODULE_DEFAULT | SAL_LOADMODULE_NOW ); 162 initFromModule(); 163 } 164 if( m_bValid ) 165 { 166 int nEventBase = 0, nErrorBase = 0; 167 if( ! m_pXRRQueryExtension( pDisplay, &nEventBase, &nErrorBase ) ) 168 m_bValid = false; 169 } 170 } 171 172 RandRWrapper::~RandRWrapper() 173 { 174 if( m_pRandRLib ) 175 osl_unloadModule( m_pRandRLib ); 176 } 177 178 static RandRWrapper* pWrapper = NULL; 179 180 RandRWrapper& RandRWrapper::get( Display* i_pDisplay ) 181 { 182 if( ! pWrapper ) 183 pWrapper = new RandRWrapper( i_pDisplay ); 184 return *pWrapper; 185 } 186 187 void RandRWrapper::releaseWrapper() 188 { 189 delete pWrapper; 190 pWrapper = NULL; 191 } 192 193 # else 194 195 class RandRWrapper 196 { 197 bool m_bValid; 198 199 RandRWrapper(Display*); 200 public: 201 static RandRWrapper& get(Display*); 202 static void releaseWrapper(); 203 204 Bool XRRQueryExtension(Display* i_pDisp, int* o_event_base, int* o_error_base ) 205 { 206 Bool bRet = False; 207 if( m_bValid ) 208 bRet = ::XRRQueryExtension( i_pDisp, o_event_base, o_error_base ); 209 return bRet; 210 } 211 Status XRRQueryVersion( Display* i_pDisp, int* o_major, int* o_minor ) 212 { 213 return m_bValid ? ::XRRQueryVersion( i_pDisp, o_major, o_minor ) : 0; 214 } 215 XRRScreenConfiguration* XRRGetScreenInfo( Display* i_pDisp, Drawable i_aDrawable ) 216 { 217 return m_bValid ? ::XRRGetScreenInfo( i_pDisp, i_aDrawable ) : NULL; 218 } 219 void XRRFreeScreenConfigInfo( XRRScreenConfiguration* i_pConfig ) 220 { 221 if( m_bValid ) 222 ::XRRFreeScreenConfigInfo( i_pConfig ); 223 } 224 void XRRSelectInput( Display* i_pDisp, XLIB_Window i_window, int i_nMask ) 225 { 226 if( m_bValid ) 227 ::XRRSelectInput( i_pDisp, i_window, i_nMask ); 228 } 229 int XRRUpdateConfiguration( XEvent* i_pEvent ) 230 { 231 return m_bValid ? ::XRRUpdateConfiguration( i_pEvent ) : 0; 232 } 233 XRRScreenSize* XRRSizes( Display* i_pDisp, int i_screen, int* o_nscreens ) 234 { 235 return m_bValid ? ::XRRSizes( i_pDisp, i_screen, o_nscreens ) : NULL; 236 } 237 XRRScreenSize* XRRConfigSizes( XRRScreenConfiguration* i_pConfig, int* o_nSizes ) 238 { 239 return m_bValid ? ::XRRConfigSizes( i_pConfig, o_nSizes ) : NULL; 240 } 241 SizeID XRRConfigCurrentConfiguration( XRRScreenConfiguration* i_pConfig, Rotation* o_pRot ) 242 { 243 return m_bValid ? ::XRRConfigCurrentConfiguration( i_pConfig, o_pRot ) : 0; 244 } 245 int XRRRootToScreen( Display *dpy, XLIB_Window root ) 246 { 247 return m_bValid ? ::XRRRootToScreen( dpy, root ) : -1; 248 } 249 }; 250 251 RandRWrapper::RandRWrapper( Display* pDisplay ) : 252 m_bValid( true ) 253 { 254 int nEventBase = 0, nErrorBase = 0; 255 if( !XRRQueryExtension( pDisplay, &nEventBase, &nErrorBase ) ) 256 m_bValid = false; 257 } 258 259 static RandRWrapper* pWrapper = NULL; 260 261 RandRWrapper& RandRWrapper::get( Display* i_pDisplay ) 262 { 263 if( ! pWrapper ) 264 pWrapper = new RandRWrapper( i_pDisplay ); 265 return *pWrapper; 266 } 267 268 void RandRWrapper::releaseWrapper() 269 { 270 delete pWrapper; 271 pWrapper = NULL; 272 } 273 274 #endif 275 276 } // namespace 277 278 #endif 279 280 #include "unx/saldisp.hxx" 281 #include "unx/salframe.h" 282 #if OSL_DEBUG_LEVEL > 1 283 #include <cstdio> 284 #endif 285 286 void SalDisplay::InitRandR( XLIB_Window aRoot ) const 287 { 288 #ifdef USE_RANDR 289 if( m_bUseRandRWrapper ) 290 RandRWrapper::get( GetDisplay() ).XRRSelectInput( GetDisplay(), aRoot, RRScreenChangeNotifyMask ); 291 #else 292 (void)aRoot; 293 #endif 294 } 295 296 void SalDisplay::DeInitRandR() 297 { 298 #ifdef USE_RANDR 299 if( m_bUseRandRWrapper ) 300 RandRWrapper::releaseWrapper(); 301 #if OSL_DEBUG_LEVEL > 1 302 fprintf( stderr, "SalDisplay::DeInitRandR()\n" ); 303 #endif 304 #endif 305 } 306 307 int SalDisplay::processRandREvent( XEvent* pEvent ) 308 { 309 int nRet = 0; 310 #ifdef USE_RANDR 311 XConfigureEvent* pCnfEvent=(XConfigureEvent*)pEvent; 312 if( m_bUseRandRWrapper && pWrapper && pWrapper->XRRRootToScreen(GetDisplay(),pCnfEvent->window) != -1 ) 313 { 314 nRet = pWrapper->XRRUpdateConfiguration( pEvent ); 315 if( nRet == 1 && pEvent->type != ConfigureNotify) // this should then be a XRRScreenChangeNotifyEvent 316 { 317 // update screens 318 bool bNotify = false; 319 for( size_t i = 0; i < m_aScreens.size(); i++ ) 320 { 321 if( m_aScreens[i].m_bInit ) 322 { 323 XRRScreenConfiguration *pConfig = NULL; 324 XRRScreenSize *pSizes = NULL; 325 int nSizes = 0; 326 Rotation nRot = 0; 327 SizeID nId = 0; 328 329 pConfig = pWrapper->XRRGetScreenInfo( GetDisplay(), m_aScreens[i].m_aRoot ); 330 nId = pWrapper->XRRConfigCurrentConfiguration( pConfig, &nRot ); 331 pSizes = pWrapper->XRRConfigSizes( pConfig, &nSizes ); 332 XRRScreenSize *pTargetSize = pSizes + nId; 333 334 bNotify = bNotify || 335 m_aScreens[i].m_aSize.Width() != pTargetSize->width || 336 m_aScreens[i].m_aSize.Height() != pTargetSize->height; 337 338 m_aScreens[i].m_aSize = Size( pTargetSize->width, pTargetSize->height ); 339 340 pWrapper->XRRFreeScreenConfigInfo( pConfig ); 341 342 #if OSL_DEBUG_LEVEL > 1 343 fprintf( stderr, "screen %d changed to size %dx%d\n", (int)i, (int)pTargetSize->width, (int)pTargetSize->height ); 344 #endif 345 } 346 } 347 if( bNotify && ! m_aFrames.empty() ) 348 m_aFrames.front()->CallCallback( SALEVENT_DISPLAYCHANGED, 0 ); 349 } 350 } 351 #else 352 (void)pEvent; 353 #endif 354 return nRet; 355 } 356