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