xref: /trunk/main/vcl/unx/generic/plugadapt/salplug.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 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_vcl.hxx"
30 
31 #include "osl/module.h"
32 #include "osl/process.h"
33 
34 #include "rtl/ustrbuf.hxx"
35 
36 #include "salinst.hxx"
37 #include "unx/saldata.hxx"
38 #include "vcl/printerinfomanager.hxx"
39 
40 #include <cstdio>
41 #include <unistd.h>
42 
43 using namespace rtl;
44 
45 extern "C" {
46 typedef SalInstance*(*salFactoryProc)( oslModule pModule);
47 }
48 
49 static oslModule pCloseModule = NULL;
50 
51 enum {
52     DESKTOP_NONE = 0,
53     DESKTOP_UNKNOWN,
54     DESKTOP_GNOME,
55     DESKTOP_KDE,
56     DESKTOP_KDE4,
57     DESKTOP_CDE
58 };
59 
60 static const char * desktop_strings[] = { "none", "unknown", "GNOME", "KDE", "KDE4", "CDE" };
61 
62 static SalInstance* tryInstance( const OUString& rModuleBase )
63 {
64     SalInstance* pInst = NULL;
65 
66     OUStringBuffer aModName( 128 );
67     aModName.appendAscii( SAL_DLLPREFIX"vclplug_" );
68     aModName.append( rModuleBase );
69     aModName.appendAscii( SAL_DLLPOSTFIX );
70     OUString aModule = aModName.makeStringAndClear();
71 
72     oslModule aMod = osl_loadModuleRelative(
73         reinterpret_cast< oslGenericFunction >( &tryInstance ), aModule.pData,
74         SAL_LOADMODULE_DEFAULT );
75     if( aMod )
76     {
77         salFactoryProc aProc = (salFactoryProc)osl_getAsciiFunctionSymbol( aMod, "create_SalInstance" );
78         if( aProc )
79         {
80             pInst = aProc( aMod );
81 #if OSL_DEBUG_LEVEL > 1
82             std::fprintf( stderr, "sal plugin %s produced instance %p\n",
83                      OUStringToOString( aModule, RTL_TEXTENCODING_ASCII_US ).getStr(),
84                      pInst );
85 #endif
86             if( pInst )
87             {
88                 pCloseModule = aMod;
89 
90                 /*
91                  * Recent GTK+ versions load their modules with RTLD_LOCAL, so we can
92                  * not access the 'gnome_accessibility_module_shutdown' anymore.
93                  * So make sure libgtk+ & co are still mapped into memory when
94                  * atk-bridge's atexit handler gets called.
95                  */
96                 if( rModuleBase.equalsAscii("gtk") )
97                 {
98                     pCloseModule = NULL;
99                 }
100                 /*
101                  * #i109007# KDE3 seems to have the same problem; an atexit cleanup
102                  * handler, which cannot be resolved anymore if the plugin is already unloaded.
103                  */
104                 else if( rModuleBase.equalsAscii("kde") )
105                 {
106                     pCloseModule = NULL;
107                 }
108 
109                 GetSalData()->m_pPlugin = aMod;
110             }
111             else
112                 osl_unloadModule( aMod );
113         }
114         else
115         {
116 #if OSL_DEBUG_LEVEL > 1
117             std::fprintf( stderr, "could not load symbol %s from shared object %s\n",
118                      "create_SalInstance",
119                      OUStringToOString( aModule, RTL_TEXTENCODING_ASCII_US ).getStr() );
120 #endif
121             osl_unloadModule( aMod );
122         }
123     }
124 #if OSL_DEBUG_LEVEL > 1
125     else
126         std::fprintf( stderr, "could not load shared object %s\n",
127                  OUStringToOString( aModule, RTL_TEXTENCODING_ASCII_US ).getStr() );
128 #endif
129 
130     return pInst;
131 }
132 
133 static const rtl::OUString& get_desktop_environment()
134 {
135     static rtl::OUString aRet;
136     if( ! aRet.getLength() )
137     {
138         OUStringBuffer aModName( 128 );
139         aModName.appendAscii( SAL_DLLPREFIX"desktop_detector" );
140         aModName.appendAscii( SAL_DLLPOSTFIX );
141         aModName.appendAscii( SAL_DLLEXTENSION );
142         OUString aModule = aModName.makeStringAndClear();
143 
144         oslModule aMod = osl_loadModuleRelative(
145             reinterpret_cast< oslGenericFunction >( &tryInstance ), aModule.pData,
146             SAL_LOADMODULE_DEFAULT );
147         if( aMod )
148         {
149             rtl::OUString (*pSym)() = (rtl::OUString(*)())
150                 osl_getAsciiFunctionSymbol( aMod, "get_desktop_environment" );
151             if( pSym )
152                 aRet = pSym();
153         }
154         osl_unloadModule( aMod );
155     }
156     return aRet;
157 }
158 
159 static SalInstance* autodetect_plugin()
160 {
161     static const char* pKDEFallbackList[] =
162     {
163         "kde4", "kde", "gtk", "gen", 0
164     };
165 
166     static const char* pStandardFallbackList[] =
167     {
168         "gtk", "gen", 0
169     };
170 
171     static const char* pHeadlessFallbackList[] =
172     {
173         "svp", 0
174     };
175 
176     const rtl::OUString& desktop( get_desktop_environment() );
177     const char ** pList = pStandardFallbackList;
178     int nListEntry = 0;
179 
180     // no server at all: dummy plugin
181     if ( desktop.equalsAscii( desktop_strings[DESKTOP_NONE] ) )
182         pList = pHeadlessFallbackList;
183     else if ( desktop.equalsAscii( desktop_strings[DESKTOP_GNOME] ) )
184         pList = pStandardFallbackList;
185     else if( desktop.equalsAscii( desktop_strings[DESKTOP_KDE] ) )
186     {
187         pList = pKDEFallbackList;
188         nListEntry = 1;
189     }
190     else if( desktop.equalsAscii( desktop_strings[DESKTOP_KDE4] ) )
191         pList = pKDEFallbackList;
192 
193     SalInstance* pInst = NULL;
194     while( pList[nListEntry] && pInst == NULL )
195     {
196         rtl::OUString aTry( rtl::OUString::createFromAscii( pList[nListEntry] ) );
197         pInst = tryInstance( aTry );
198         #if OSL_DEBUG_LEVEL > 1
199         if( pInst )
200             std::fprintf( stderr, "plugin autodetection: %s\n", pList[nListEntry] );
201         #endif
202         nListEntry++;
203     }
204 
205     return pInst;
206 }
207 
208 static SalInstance* check_headless_plugin()
209 {
210     int nParams = osl_getCommandArgCount();
211     OUString aParam;
212     for( int i = 0; i < nParams; i++ )
213     {
214         osl_getCommandArg( i, &aParam.pData );
215         if( aParam.equalsAscii( "-headless" ) )
216             return tryInstance( OUString( RTL_CONSTASCII_USTRINGPARAM( "svp" ) ) );
217     }
218     return NULL;
219 }
220 
221 SalInstance *CreateSalInstance()
222 {
223     SalInstance*	pInst = NULL;
224 
225     static const char* pUsePlugin = getenv( "SAL_USE_VCLPLUGIN" );
226 
227     if( !(pUsePlugin && *pUsePlugin) )
228         pInst = check_headless_plugin();
229     else
230         pInst = tryInstance( OUString::createFromAscii( pUsePlugin ) );
231 
232     if( ! pInst )
233         pInst = autodetect_plugin();
234 
235     // fallback to gen
236     if( ! pInst )
237         pInst = tryInstance( OUString( RTL_CONSTASCII_USTRINGPARAM( "gen" ) ) );
238 
239     if( ! pInst )
240     {
241         std::fprintf( stderr, "no suitable windowing system found, exiting.\n" );
242         _exit( 1 );
243     }
244 
245     // acquire SolarMutex
246     pInst->AcquireYieldMutex( 1 );
247 
248 	return pInst;
249 }
250 
251 void DestroySalInstance( SalInstance *pInst )
252 {
253     // release SolarMutex
254     pInst->ReleaseYieldMutex();
255 
256 	delete pInst;
257     if( pCloseModule )
258         osl_unloadModule( pCloseModule );
259 }
260 
261 void InitSalData()
262 {
263 }
264 
265 void DeInitSalData()
266 {
267 }
268 
269 void InitSalMain()
270 {
271 }
272 
273 void DeInitSalMain()
274 {
275 }
276 
277 void SalAbort( const XubString& rErrorText )
278 {
279 	if( !rErrorText.Len() )
280 		std::fprintf( stderr, "Application Error" );
281 	else
282 		std::fprintf( stderr, ByteString( rErrorText, gsl_getSystemTextEncoding() ).GetBuffer() );
283 	abort();
284 }
285 
286 const OUString& SalGetDesktopEnvironment()
287 {
288     return get_desktop_environment();
289 }
290 
291 SalData::SalData() :
292     m_pInstance(NULL),
293     m_pPlugin(NULL),
294     m_pPIManager(NULL)
295 {
296 }
297 
298 SalData::~SalData()
299 {
300     psp::PrinterInfoManager::release();
301 }
302