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
XRRQueryExtension(Display * i_pDisp,int * o_event_base,int * o_error_base)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 }
XRRQueryVersion(Display * i_pDisp,int * o_major,int * o_minor)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 }
XRRGetScreenInfo(Display * i_pDisp,Drawable i_aDrawable)75 XRRScreenConfiguration* XRRGetScreenInfo( Display* i_pDisp, Drawable i_aDrawable )
76 {
77 return m_bValid ? m_pXRRGetScreenInfo( i_pDisp, i_aDrawable ) : NULL;
78 }
XRRFreeScreenConfigInfo(XRRScreenConfiguration * i_pConfig)79 void XRRFreeScreenConfigInfo( XRRScreenConfiguration* i_pConfig )
80 {
81 if( m_bValid )
82 m_pXRRFreeScreenConfigInfo( i_pConfig );
83 }
XRRSelectInput(Display * i_pDisp,XLIB_Window i_window,int i_nMask)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 }
XRRUpdateConfiguration(XEvent * i_pEvent)89 int XRRUpdateConfiguration( XEvent* i_pEvent )
90 {
91 return m_bValid ? m_pXRRUpdateConfiguration( i_pEvent ) : 0;
92 }
XRRSizes(Display * i_pDisp,int i_screen,int * o_nscreens)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 }
XRRConfigSizes(XRRScreenConfiguration * i_pConfig,int * o_nSizes)97 XRRScreenSize* XRRConfigSizes( XRRScreenConfiguration* i_pConfig, int* o_nSizes )
98 {
99 return m_bValid ? m_pXRRConfigSizes( i_pConfig, o_nSizes ) : NULL;
100 }
XRRConfigCurrentConfiguration(XRRScreenConfiguration * i_pConfig,Rotation * o_pRot)101 SizeID XRRConfigCurrentConfiguration( XRRScreenConfiguration* i_pConfig, Rotation* o_pRot )
102 {
103 return m_bValid ? m_pXRRConfigCurrentConfiguration( i_pConfig, o_pRot ) : 0;
104 }
XRRRootToScreen(Display * dpy,XLIB_Window root)105 int XRRRootToScreen( Display *dpy, XLIB_Window root )
106 {
107 return m_bValid ? m_pXRRRootToScreen( dpy, root ) : -1;
108 }
109 };
110
initFromModule()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
RandRWrapper(Display * pDisplay)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
~RandRWrapper()172 RandRWrapper::~RandRWrapper()
173 {
174 if( m_pRandRLib )
175 osl_unloadModule( m_pRandRLib );
176 }
177
178 static RandRWrapper* pWrapper = NULL;
179
get(Display * i_pDisplay)180 RandRWrapper& RandRWrapper::get( Display* i_pDisplay )
181 {
182 if( ! pWrapper )
183 pWrapper = new RandRWrapper( i_pDisplay );
184 return *pWrapper;
185 }
186
releaseWrapper()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
InitRandR(XLIB_Window aRoot) const286 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
DeInitRandR()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
processRandREvent(XEvent * pEvent)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