Version 6.4.0.0.beta1, tag libreoffice-6.4.0.0.beta1
[LibreOffice.git] / vcl / source / app / salplug.cxx
blob1868853e93b8399883cc3368c86615b799d714e4
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <osl/module.hxx>
22 #include <rtl/bootstrap.hxx>
23 #include <rtl/process.h>
24 #include <sal/log.hxx>
26 #include <salframe.hxx>
27 #include <salinst.hxx>
28 #include <config_vclplug.h>
29 #include <desktop/crashreport.hxx>
31 #ifndef _WIN32
32 #include <headless/svpinst.hxx>
33 #include <printerinfomanager.hxx>
34 #include <unx/desktops.hxx>
36 #include <unistd.h>
37 #else
38 #include <saldatabasic.hxx>
39 #include <Windows.h>
40 #endif
42 #include <cstdio>
44 #ifdef ANDROID
45 #error "Android has no plugin infrastructure!"
46 #endif
48 #if !(defined _WIN32 || defined MACOSX)
49 #define DESKTOPDETECT
50 #define HEADLESS_VCLPLUG
51 #endif
53 extern "C" {
54 typedef SalInstance*(*salFactoryProc)();
57 namespace {
59 oslModule pCloseModule = nullptr;
61 SalInstance* tryInstance( const OUString& rModuleBase, bool bForce = false )
63 #ifdef HEADLESS_VCLPLUG
64 if (rModuleBase == "svp")
65 return svp_create_SalInstance();
66 #endif
68 SalInstance* pInst = nullptr;
69 OUString aUsedModuleBase(rModuleBase);
70 if (aUsedModuleBase == "kde5")
71 aUsedModuleBase = "kf5";
72 OUString aModule(
73 #ifdef SAL_DLLPREFIX
74 SAL_DLLPREFIX
75 #endif
76 "vclplug_" + aUsedModuleBase + "lo" SAL_DLLEXTENSION );
78 osl::Module aMod;
79 if (aMod.loadRelative(reinterpret_cast<oslGenericFunction>(&tryInstance), aModule, SAL_LOADMODULE_GLOBAL))
81 salFactoryProc aProc = reinterpret_cast<salFactoryProc>(aMod.getFunctionSymbol("create_SalInstance"));
82 if (aProc)
84 pInst = aProc();
85 SAL_INFO(
86 "vcl.plugadapt",
87 "sal plugin " << aModule << " produced instance " << pInst);
88 if (pInst)
90 pCloseModule = static_cast<oslModule>(aMod);
91 aMod.release();
94 * Recent GTK+ versions load their modules with RTLD_LOCAL, so we can
95 * not access the 'gnome_accessibility_module_shutdown' anymore.
96 * So make sure libgtk+ & co are still mapped into memory when
97 * atk-bridge's atexit handler gets called.
99 if( aUsedModuleBase == "gtk3" || aUsedModuleBase == "gtk3_kde5" || aUsedModuleBase == "win" )
101 pCloseModule = nullptr;
105 else
107 SAL_WARN(
108 "vcl.plugadapt",
109 "could not load symbol create_SalInstance from shared object "
110 << aModule);
113 else if (bForce)
115 SAL_WARN("vcl.plugadapt", "could not load shared object " << aModule);
117 else
119 SAL_INFO("vcl.plugadapt", "could not load shared object " << aModule);
122 // coverity[leaked_storage] - this is on purpose
123 return pInst;
126 #ifdef DESKTOPDETECT
127 extern "C" typedef DesktopType Fn_get_desktop_environment();
129 DesktopType get_desktop_environment()
131 OUString aModule(DESKTOP_DETECTOR_DLL_NAME);
132 oslModule aMod = osl_loadModuleRelative(
133 reinterpret_cast< oslGenericFunction >( &tryInstance ), aModule.pData,
134 SAL_LOADMODULE_DEFAULT );
135 DesktopType ret = DESKTOP_UNKNOWN;
136 if( aMod )
138 Fn_get_desktop_environment * pSym
139 = reinterpret_cast<Fn_get_desktop_environment *>(
140 osl_getAsciiFunctionSymbol(aMod, "get_desktop_environment"));
141 if( pSym )
142 ret = pSym();
144 osl_unloadModule( aMod );
145 return ret;
148 SalInstance* autodetect_plugin()
150 static const char* const pKDEFallbackList[] =
152 #if ENABLE_KF5
153 "kf5",
154 #endif
155 #if ENABLE_GTK3_KDE5
156 "gtk3_kde5",
157 #endif
158 "gtk3", "gen", nullptr
161 static const char* const pStandardFallbackList[] =
163 "gtk3", "gen", nullptr
166 #ifdef HEADLESS_VCLPLUG
167 static const char* const pHeadlessFallbackList[] =
169 "svp", nullptr
171 #endif
173 DesktopType desktop = get_desktop_environment();
174 const char * const * pList = pStandardFallbackList;
175 int nListEntry = 0;
177 #ifdef HEADLESS_VCLPLUG
178 // no server at all: dummy plugin
179 if ( desktop == DESKTOP_NONE )
180 pList = pHeadlessFallbackList;
181 else
182 #endif
183 if ( desktop == DESKTOP_GNOME ||
184 desktop == DESKTOP_UNITY ||
185 desktop == DESKTOP_XFCE ||
186 desktop == DESKTOP_MATE )
187 pList = pStandardFallbackList;
188 else if (desktop == DESKTOP_PLASMA5 || desktop == DESKTOP_LXQT)
189 pList = pKDEFallbackList;
191 SalInstance* pInst = nullptr;
192 while( pList[nListEntry] && pInst == nullptr )
194 OUString aTry( OUString::createFromAscii( pList[nListEntry] ) );
195 pInst = tryInstance( aTry );
196 SAL_INFO_IF(
197 pInst, "vcl.plugadapt",
198 "plugin autodetection: " << pList[nListEntry]);
199 nListEntry++;
202 return pInst;
204 #endif // DESKTOPDETECT
206 #ifdef HEADLESS_VCLPLUG
207 // HACK to obtain Application::IsHeadlessModeEnabled early on, before
208 // Application::EnableHeadlessMode has potentially been called:
209 bool IsHeadlessModeRequested()
211 if (Application::IsHeadlessModeEnabled()) {
212 return true;
214 sal_uInt32 n = rtl_getAppCommandArgCount();
215 for (sal_uInt32 i = 0; i < n; ++i) {
216 OUString arg;
217 rtl_getAppCommandArg(i, &arg.pData);
218 if ( arg == "--headless" || arg == "-headless" ) {
219 return true;
222 return false;
224 #endif
226 } // anonymous namespace
228 SalInstance *CreateSalInstance()
230 SalInstance *pInst = nullptr;
232 OUString aUsePlugin;
233 rtl::Bootstrap::get("SAL_USE_VCLPLUGIN", aUsePlugin);
234 SAL_INFO_IF(!aUsePlugin.isEmpty(), "vcl", "Requested VCL plugin: " << aUsePlugin);
235 #ifdef HEADLESS_VCLPLUG
236 if (Application::IsBitmapRendering() || (aUsePlugin.isEmpty() && IsHeadlessModeRequested()))
237 aUsePlugin = "svp";
238 #endif
240 if (aUsePlugin == "svp")
242 Application::EnableBitmapRendering();
243 #ifndef HEADLESS_VCLPLUG
244 aUsePlugin.clear();
245 #endif
247 if( !aUsePlugin.isEmpty() )
248 pInst = tryInstance( aUsePlugin, true );
250 #ifdef DESKTOPDETECT
251 if( ! pInst )
252 pInst = autodetect_plugin();
253 #endif
255 // fallback, try everything
256 static const char* const pPlugin[] = {
257 #ifdef _WIN32
258 "win"
259 #else
260 #ifdef MACOSX
261 "osx"
262 #else
263 "gtk3", "kf5", "gen"
264 #endif
265 #endif
268 for ( int i = 0; !pInst && i != SAL_N_ELEMENTS(pPlugin); ++i )
269 pInst = tryInstance( OUString::createFromAscii( pPlugin[ i ] ) );
271 if( ! pInst )
273 std::fprintf( stderr, "no suitable windowing system found, exiting.\n" );
274 _exit( 1 );
277 // acquire SolarMutex
278 pInst->AcquireYieldMutex();
280 return pInst;
283 void DestroySalInstance( SalInstance *pInst )
285 // release SolarMutex
286 pInst->ReleaseYieldMutexAll();
288 delete pInst;
289 if( pCloseModule )
290 osl_unloadModule( pCloseModule );
293 void SalAbort( const OUString& rErrorText, bool bDumpCore )
295 if( rErrorText.isEmpty() )
296 std::fprintf( stderr, "Application Error\n" );
297 else
299 CrashReporter::addKeyValue("AbortMessage", rErrorText, CrashReporter::Write);
300 std::fprintf( stderr, "%s\n", OUStringToOString(rErrorText, osl_getThreadTextEncoding()).getStr() );
302 if( bDumpCore )
303 abort();
304 else
305 _exit(1);
308 const OUString& SalGetDesktopEnvironment()
310 #ifdef _WIN32
311 static OUString aDesktopEnvironment( "Windows" );
313 #else
314 #ifdef MACOSX
315 static OUString aDesktopEnvironment( "MacOSX" );
316 #else
317 // Order to match desktops.hxx' DesktopType
318 static const char * const desktop_strings[] = {
319 "none", "unknown", "GNOME", "UNITY",
320 "XFCE", "MATE", "PLASMA5", "LXQT" };
321 static OUString aDesktopEnvironment;
322 if( aDesktopEnvironment.isEmpty())
324 aDesktopEnvironment = OUString::createFromAscii(
325 desktop_strings[get_desktop_environment()]);
327 #endif
328 #endif
329 return aDesktopEnvironment;
332 SalData::SalData() :
333 m_pInstance(nullptr),
334 m_pPIManager(nullptr)
338 SalData::~SalData() COVERITY_NOEXCEPT_FALSE
340 #if (defined UNX && !defined MACOSX)
341 psp::PrinterInfoManager::release();
342 #endif
345 #ifdef _WIN32
346 bool HasAtHook()
348 BOOL bIsRunning = FALSE;
349 // pvParam must be BOOL
350 return SystemParametersInfoW(SPI_GETSCREENREADER, 0, &bIsRunning, 0)
351 && bIsRunning;
353 #endif
355 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */