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