xref: /aoo41x/main/vcl/unx/generic/app/randrwrapper.cxx (revision cdf0e10c)
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