1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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>
32 #include <headless/svpinst.hxx>
33 #include <printerinfomanager.hxx>
34 #include <unx/desktops.hxx>
38 #include <saldatabasic.hxx>
45 #error "Android has no plugin infrastructure!"
48 #if !(defined _WIN32 || defined MACOSX)
50 #define HEADLESS_VCLPLUG
54 typedef SalInstance
*(*salFactoryProc
)();
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();
68 SalInstance
* pInst
= nullptr;
69 OUString
aUsedModuleBase(rModuleBase
);
70 if (aUsedModuleBase
== "kde5")
71 aUsedModuleBase
= "kf5";
76 "vclplug_" + aUsedModuleBase
+ "lo" SAL_DLLEXTENSION
);
79 if (aMod
.loadRelative(reinterpret_cast<oslGenericFunction
>(&tryInstance
), aModule
, SAL_LOADMODULE_GLOBAL
))
81 salFactoryProc aProc
= reinterpret_cast<salFactoryProc
>(aMod
.getFunctionSymbol("create_SalInstance"));
87 "sal plugin " << aModule
<< " produced instance " << pInst
);
90 pCloseModule
= static_cast<oslModule
>(aMod
);
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;
109 "could not load symbol create_SalInstance from shared object "
115 SAL_WARN("vcl.plugadapt", "could not load shared object " << aModule
);
119 SAL_INFO("vcl.plugadapt", "could not load shared object " << aModule
);
122 // coverity[leaked_storage] - this is on purpose
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
;
138 Fn_get_desktop_environment
* pSym
139 = reinterpret_cast<Fn_get_desktop_environment
*>(
140 osl_getAsciiFunctionSymbol(aMod
, "get_desktop_environment"));
144 osl_unloadModule( aMod
);
148 SalInstance
* autodetect_plugin()
150 static const char* const pKDEFallbackList
[] =
158 "gtk3", "gen", nullptr
161 static const char* const pStandardFallbackList
[] =
163 "gtk3", "gen", nullptr
166 #ifdef HEADLESS_VCLPLUG
167 static const char* const pHeadlessFallbackList
[] =
173 DesktopType desktop
= get_desktop_environment();
174 const char * const * pList
= pStandardFallbackList
;
177 #ifdef HEADLESS_VCLPLUG
178 // no server at all: dummy plugin
179 if ( desktop
== DESKTOP_NONE
)
180 pList
= pHeadlessFallbackList
;
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
);
197 pInst
, "vcl.plugadapt",
198 "plugin autodetection: " << pList
[nListEntry
]);
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()) {
214 sal_uInt32 n
= rtl_getAppCommandArgCount();
215 for (sal_uInt32 i
= 0; i
< n
; ++i
) {
217 rtl_getAppCommandArg(i
, &arg
.pData
);
218 if ( arg
== "--headless" || arg
== "-headless" ) {
226 } // anonymous namespace
228 SalInstance
*CreateSalInstance()
230 SalInstance
*pInst
= nullptr;
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()))
240 if (aUsePlugin
== "svp")
242 Application::EnableBitmapRendering();
243 #ifndef HEADLESS_VCLPLUG
247 if( !aUsePlugin
.isEmpty() )
248 pInst
= tryInstance( aUsePlugin
, true );
252 pInst
= autodetect_plugin();
255 // fallback, try everything
256 static const char* const pPlugin
[] = {
268 for ( int i
= 0; !pInst
&& i
!= SAL_N_ELEMENTS(pPlugin
); ++i
)
269 pInst
= tryInstance( OUString::createFromAscii( pPlugin
[ i
] ) );
273 std::fprintf( stderr
, "no suitable windowing system found, exiting.\n" );
277 // acquire SolarMutex
278 pInst
->AcquireYieldMutex();
283 void DestroySalInstance( SalInstance
*pInst
)
285 // release SolarMutex
286 pInst
->ReleaseYieldMutexAll();
290 osl_unloadModule( pCloseModule
);
293 void SalAbort( const OUString
& rErrorText
, bool bDumpCore
)
295 if( rErrorText
.isEmpty() )
296 std::fprintf( stderr
, "Application Error\n" );
299 CrashReporter::addKeyValue("AbortMessage", rErrorText
, CrashReporter::Write
);
300 std::fprintf( stderr
, "%s\n", OUStringToOString(rErrorText
, osl_getThreadTextEncoding()).getStr() );
308 const OUString
& SalGetDesktopEnvironment()
311 static OUString
aDesktopEnvironment( "Windows" );
315 static OUString
aDesktopEnvironment( "MacOSX" );
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()]);
329 return aDesktopEnvironment
;
333 m_pInstance(nullptr),
334 m_pPIManager(nullptr)
338 SalData::~SalData() COVERITY_NOEXCEPT_FALSE
340 #if (defined UNX && !defined MACOSX)
341 psp::PrinterInfoManager::release();
348 BOOL bIsRunning
= FALSE
;
349 // pvParam must be BOOL
350 return SystemParametersInfoW(SPI_GETSCREENREADER
, 0, &bIsRunning
, 0)
355 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */