Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include "osl/module.h"
21 : #include "osl/process.h"
22 :
23 : #include "rtl/bootstrap.hxx"
24 : #include "rtl/process.h"
25 :
26 : #include "salinst.hxx"
27 : #include "generic/gensys.h"
28 : #include "generic/gendata.hxx"
29 : #include "headless/svpinst.hxx"
30 : #include "unx/desktops.hxx"
31 : #include "vcl/printerinfomanager.hxx"
32 : #include <config_vclplug.h>
33 :
34 : #include <cstdio>
35 : #include <unistd.h>
36 :
37 : extern "C" {
38 : typedef SalInstance*(*salFactoryProc)();
39 : }
40 :
41 : namespace {
42 :
43 : // HACK to obtain Application::IsHeadlessModeEnabled early on, before
44 : // Application::EnableHeadlessMode has potentially been called:
45 245 : bool IsHeadlessModeRequested()
46 : {
47 245 : if (Application::IsHeadlessModeEnabled()) {
48 12 : return true;
49 : }
50 233 : sal_uInt32 n = rtl_getAppCommandArgCount();
51 703 : for (sal_uInt32 i = 0; i < n; ++i) {
52 700 : OUString arg;
53 700 : rtl_getAppCommandArg(i, &arg.pData);
54 700 : if ( arg == "--headless" || arg == "-headless" ) {
55 230 : return true;
56 : }
57 470 : }
58 3 : return false;
59 : }
60 :
61 : }
62 :
63 : static oslModule pCloseModule = NULL;
64 :
65 248 : static SalInstance* tryInstance( const OUString& rModuleBase, bool bForce = false )
66 : {
67 248 : if (rModuleBase == "svp")
68 242 : return svp_create_SalInstance();
69 :
70 6 : SalInstance* pInst = NULL;
71 : // Disable gtk3 plugin for now unless explicitly requested via
72 : // SAL_USE_VCLPLUGIN=gtk3 (would ideally depend on experimental mode, but
73 : // reading the experimental mode setting requires the UNO service manager
74 : // which has not yet been instantiated):
75 6 : if (!bForce && rModuleBase == "gtk3")
76 : {
77 3 : return NULL;
78 : }
79 : OUString aModule(
80 : #ifdef SAL_DLLPREFIX
81 : SAL_DLLPREFIX
82 : #endif
83 3 : "vclplug_" + rModuleBase + "lo" SAL_DLLEXTENSION );
84 :
85 : oslModule aMod = osl_loadModuleRelative(
86 : reinterpret_cast< oslGenericFunction >( &tryInstance ), aModule.pData,
87 3 : SAL_LOADMODULE_GLOBAL );
88 3 : if( aMod )
89 : {
90 3 : salFactoryProc aProc = reinterpret_cast<salFactoryProc>(osl_getAsciiFunctionSymbol( aMod, "create_SalInstance" ));
91 3 : if( aProc )
92 : {
93 3 : pInst = aProc();
94 : SAL_INFO(
95 : "vcl.plugadapt",
96 : "sal plugin " << aModule << " produced instance " << pInst);
97 3 : if( pInst )
98 : {
99 3 : pCloseModule = aMod;
100 :
101 : #ifndef ANDROID
102 : /*
103 : * Recent GTK+ versions load their modules with RTLD_LOCAL, so we can
104 : * not access the 'gnome_accessibility_module_shutdown' anymore.
105 : * So make sure libgtk+ & co are still mapped into memory when
106 : * atk-bridge's atexit handler gets called.
107 : * #i109007# KDE3 seems to have the same problem.
108 : * And same applies for KDE4.
109 : */
110 3 : if( rModuleBase == "gtk" || rModuleBase == "gtk3" || rModuleBase == "tde" || rModuleBase == "kde" || rModuleBase == "kde4" )
111 : {
112 3 : pCloseModule = NULL;
113 : }
114 : #endif
115 3 : GetSalData()->m_pPlugin = aMod;
116 : }
117 : else
118 0 : osl_unloadModule( aMod );
119 : }
120 : else
121 : {
122 : SAL_WARN(
123 : "vcl.plugadapt",
124 : "could not load symbol create_SalInstance from shared object "
125 : << aModule);
126 0 : osl_unloadModule( aMod );
127 : }
128 : }
129 0 : else if (bForce)
130 : {
131 : SAL_WARN("vcl.plugadapt", "could not load shared object " << aModule);
132 : }
133 : else
134 : {
135 : SAL_INFO("vcl.plugadapt", "could not load shared object " << aModule);
136 : }
137 :
138 3 : return pInst;
139 : }
140 :
141 : #if !defined(ANDROID)
142 :
143 : namespace {
144 :
145 : extern "C" typedef DesktopType Fn_get_desktop_environment();
146 :
147 : }
148 :
149 6 : static DesktopType get_desktop_environment()
150 : {
151 6 : OUString aModule(DESKTOP_DETECTOR_DLL_NAME);
152 : oslModule aMod = osl_loadModuleRelative(
153 : reinterpret_cast< oslGenericFunction >( &tryInstance ), aModule.pData,
154 6 : SAL_LOADMODULE_DEFAULT );
155 6 : DesktopType ret = DESKTOP_UNKNOWN;
156 6 : if( aMod )
157 : {
158 : Fn_get_desktop_environment * pSym
159 : = reinterpret_cast<Fn_get_desktop_environment *>(
160 6 : osl_getAsciiFunctionSymbol(aMod, "get_desktop_environment"));
161 6 : if( pSym )
162 6 : ret = pSym();
163 : }
164 6 : osl_unloadModule( aMod );
165 6 : return ret;
166 : }
167 :
168 : #else
169 :
170 : #define get_desktop_environment() DESKTOP_NONE // For now...
171 :
172 : #endif
173 :
174 3 : static SalInstance* autodetect_plugin()
175 : {
176 : static const char* const pTDEFallbackList[] =
177 : {
178 : "tde",
179 : #if ENABLE_KDE4
180 : "kde4",
181 : #endif
182 : #if ENABLE_KDE
183 : "kde",
184 : #endif
185 : "gtk3", "gtk", "gen", 0
186 : };
187 :
188 : static const char* const pKDEFallbackList[] =
189 : {
190 : #if ENABLE_KDE4
191 : "kde4",
192 : #endif
193 : #if ENABLE_KDE
194 : "kde",
195 : #endif
196 : "gtk3", "gtk", "gen", 0
197 : };
198 :
199 : static const char* const pStandardFallbackList[] =
200 : {
201 : "gtk3", "gtk", "gen", 0
202 : };
203 :
204 : static const char* const pHeadlessFallbackList[] =
205 : {
206 : "svp", 0
207 : };
208 :
209 3 : DesktopType desktop = get_desktop_environment();
210 3 : const char * const * pList = pStandardFallbackList;
211 3 : int nListEntry = 0;
212 :
213 : // no server at all: dummy plugin
214 3 : if ( desktop == DESKTOP_NONE )
215 0 : pList = pHeadlessFallbackList;
216 3 : else if ( desktop == DESKTOP_GNOME ||
217 3 : desktop == DESKTOP_UNITY ||
218 3 : desktop == DESKTOP_XFCE ||
219 : desktop == DESKTOP_MATE )
220 0 : pList = pStandardFallbackList;
221 3 : else if( desktop == DESKTOP_TDE )
222 0 : pList = pTDEFallbackList;
223 3 : else if( desktop == DESKTOP_KDE )
224 : {
225 0 : pList = pKDEFallbackList;
226 0 : nListEntry = 1;
227 : }
228 3 : else if( desktop == DESKTOP_KDE4 || desktop == DESKTOP_KDE5 )
229 0 : pList = pKDEFallbackList;
230 :
231 3 : SalInstance* pInst = NULL;
232 12 : while( pList[nListEntry] && pInst == NULL )
233 : {
234 6 : OUString aTry( OUString::createFromAscii( pList[nListEntry] ) );
235 6 : pInst = tryInstance( aTry );
236 : SAL_INFO_IF(
237 : pInst, "vcl.plugadapt",
238 : "plugin autodetection: " << pList[nListEntry]);
239 6 : nListEntry++;
240 6 : }
241 :
242 3 : return pInst;
243 : }
244 :
245 245 : SalInstance *CreateSalInstance()
246 : {
247 245 : SalInstance *pInst = NULL;
248 :
249 245 : OUString aUsePlugin;
250 245 : if( IsHeadlessModeRequested() )
251 242 : aUsePlugin = "svp";
252 : else
253 : {
254 3 : rtl::Bootstrap::get( "SAL_USE_VCLPLUGIN", aUsePlugin );
255 : }
256 :
257 245 : if( !aUsePlugin.isEmpty() )
258 242 : pInst = tryInstance( aUsePlugin, true );
259 :
260 245 : if( ! pInst )
261 3 : pInst = autodetect_plugin();
262 :
263 : // fallback, try everything
264 : static const char* const pPlugin[] = {
265 : "gtk3", "gtk", "kde4", "kde", "tde", "gen" };
266 :
267 245 : for ( int i = 0; !pInst && i != SAL_N_ELEMENTS(pPlugin); ++i )
268 0 : pInst = tryInstance( OUString::createFromAscii( pPlugin[ i ] ) );
269 :
270 245 : if( ! pInst )
271 : {
272 0 : std::fprintf( stderr, "no suitable windowing system found, exiting.\n" );
273 0 : _exit( 1 );
274 : }
275 :
276 : // acquire SolarMutex
277 245 : pInst->AcquireYieldMutex( 1 );
278 :
279 245 : return pInst;
280 : }
281 :
282 242 : void DestroySalInstance( SalInstance *pInst )
283 : {
284 : // release SolarMutex
285 242 : pInst->ReleaseYieldMutex();
286 :
287 242 : delete pInst;
288 242 : if( pCloseModule )
289 0 : osl_unloadModule( pCloseModule );
290 242 : }
291 :
292 245 : void InitSalData()
293 : {
294 245 : }
295 :
296 242 : void DeInitSalData()
297 : {
298 242 : }
299 :
300 245 : void InitSalMain()
301 : {
302 245 : }
303 :
304 0 : void SalAbort( const OUString& rErrorText, bool bDumpCore )
305 : {
306 0 : if( rErrorText.isEmpty() )
307 0 : std::fprintf( stderr, "Application Error\n" );
308 : else
309 0 : std::fprintf( stderr, "%s\n", OUStringToOString(rErrorText, osl_getThreadTextEncoding()).getStr() );
310 0 : if( bDumpCore )
311 0 : abort();
312 : else
313 0 : _exit(1);
314 : }
315 :
316 43 : const OUString& SalGetDesktopEnvironment()
317 : {
318 : // Order to match desktops.hxx' DesktopType
319 : static const char * const desktop_strings[] = {
320 : "none", "unknown", "GNOME", "UNITY",
321 : "XFCE", "MATE", "TDE",
322 : "KDE", "KDE4", "KDE5" };
323 43 : static OUString aRet;
324 43 : if( aRet.isEmpty())
325 : {
326 9 : aRet = OUString::createFromAscii(
327 9 : desktop_strings[get_desktop_environment()]);
328 : }
329 43 : return aRet;
330 : }
331 :
332 245 : SalData::SalData() :
333 : m_pInstance(NULL),
334 : m_pPlugin(NULL),
335 245 : m_pPIManager(NULL)
336 : {
337 245 : }
338 :
339 0 : SalData::~SalData()
340 : {
341 0 : psp::PrinterInfoManager::release();
342 801 : }
343 :
344 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|