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