1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 24 // MARKER(update_precomp.py): autogen include statement, do not remove 25 #include "precompiled_vcl.hxx" 26 27 #include "osl/module.h" 28 #include "osl/process.h" 29 30 #include "rtl/ustrbuf.hxx" 31 32 #include "salinst.hxx" 33 #include "unx/saldata.hxx" 34 #include "vcl/printerinfomanager.hxx" 35 36 #include <cstdio> 37 #include <unistd.h> 38 39 using namespace rtl; 40 41 extern "C" { 42 typedef SalInstance*(*salFactoryProc)( oslModule pModule); 43 } 44 45 static oslModule pCloseModule = NULL; 46 47 enum { 48 DESKTOP_NONE = 0, 49 DESKTOP_UNKNOWN, 50 DESKTOP_GNOME, 51 DESKTOP_KDE, 52 DESKTOP_KDE4, 53 DESKTOP_CDE 54 }; 55 56 static const char * desktop_strings[] = { "none", "unknown", "GNOME", "KDE", "KDE4", "CDE" }; 57 58 static SalInstance* tryInstance( const OUString& rModuleBase ) 59 { 60 SalInstance* pInst = NULL; 61 62 OUStringBuffer aModName( 128 ); 63 aModName.appendAscii( SAL_DLLPREFIX"vclplug_" ); 64 aModName.append( rModuleBase ); 65 aModName.appendAscii( SAL_DLLPOSTFIX ); 66 aModName.appendAscii( SAL_DLLEXTENSION ); 67 OUString aModule = aModName.makeStringAndClear(); 68 69 oslModule aMod = osl_loadModuleRelative( 70 reinterpret_cast< oslGenericFunction >( &tryInstance ), aModule.pData, 71 SAL_LOADMODULE_DEFAULT ); 72 if( aMod ) 73 { 74 salFactoryProc aProc = (salFactoryProc)osl_getAsciiFunctionSymbol( aMod, "create_SalInstance" ); 75 if( aProc ) 76 { 77 pInst = aProc( aMod ); 78 #if OSL_DEBUG_LEVEL > 1 79 std::fprintf( stderr, "sal plugin %s produced instance %p\n", 80 OUStringToOString( aModule, RTL_TEXTENCODING_ASCII_US ).getStr(), 81 pInst ); 82 #endif 83 if( pInst ) 84 { 85 pCloseModule = aMod; 86 87 /* 88 * Recent GTK+ versions load their modules with RTLD_LOCAL, so we can 89 * not access the 'gnome_accessibility_module_shutdown' anymore. 90 * So make sure libgtk+ & co are still mapped into memory when 91 * atk-bridge's atexit handler gets called. 92 */ 93 if( rModuleBase.equalsAscii("gtk") ) 94 { 95 pCloseModule = NULL; 96 } 97 /* 98 * #i109007# KDE3 seems to have the same problem; an atexit cleanup 99 * handler, which cannot be resolved anymore if the plugin is already unloaded. 100 */ 101 else if( rModuleBase.equalsAscii("kde") ) 102 { 103 pCloseModule = NULL; 104 } 105 106 GetSalData()->m_pPlugin = aMod; 107 } 108 else 109 osl_unloadModule( aMod ); 110 } 111 else 112 { 113 #if OSL_DEBUG_LEVEL > 1 114 std::fprintf( stderr, "could not load symbol %s from shared object %s\n", 115 "create_SalInstance", 116 OUStringToOString( aModule, RTL_TEXTENCODING_ASCII_US ).getStr() ); 117 #endif 118 osl_unloadModule( aMod ); 119 } 120 } 121 #if OSL_DEBUG_LEVEL > 1 122 else 123 std::fprintf( stderr, "could not load shared object %s\n", 124 OUStringToOString( aModule, RTL_TEXTENCODING_ASCII_US ).getStr() ); 125 #endif 126 127 return pInst; 128 } 129 130 static const rtl::OUString& get_desktop_environment() 131 { 132 static rtl::OUString aRet; 133 if( ! aRet.getLength() ) 134 { 135 OUStringBuffer aModName( 128 ); 136 aModName.appendAscii( SAL_DLLPREFIX"desktop_detector" ); 137 aModName.appendAscii( SAL_DLLPOSTFIX ); 138 aModName.appendAscii( SAL_DLLEXTENSION ); 139 OUString aModule = aModName.makeStringAndClear(); 140 141 oslModule aMod = osl_loadModuleRelative( 142 reinterpret_cast< oslGenericFunction >( &tryInstance ), aModule.pData, 143 SAL_LOADMODULE_DEFAULT ); 144 if( aMod ) 145 { 146 rtl::OUString (*pSym)() = (rtl::OUString(*)()) 147 osl_getAsciiFunctionSymbol( aMod, "get_desktop_environment" ); 148 if( pSym ) 149 aRet = pSym(); 150 } 151 osl_unloadModule( aMod ); 152 } 153 return aRet; 154 } 155 156 static SalInstance* autodetect_plugin() 157 { 158 static const char* pKDEFallbackList[] = 159 { 160 "kde4", "kde", "gtk", "gen", 0 161 }; 162 163 static const char* pStandardFallbackList[] = 164 { 165 "gtk", "gen", 0 166 }; 167 168 static const char* pHeadlessFallbackList[] = 169 { 170 "svp", 0 171 }; 172 173 const rtl::OUString& desktop( get_desktop_environment() ); 174 const char ** pList = pStandardFallbackList; 175 int nListEntry = 0; 176 177 // no server at all: dummy plugin 178 if ( desktop.equalsAscii( desktop_strings[DESKTOP_NONE] ) ) 179 pList = pHeadlessFallbackList; 180 else if ( desktop.equalsAscii( desktop_strings[DESKTOP_GNOME] ) ) 181 pList = pStandardFallbackList; 182 else if( desktop.equalsAscii( desktop_strings[DESKTOP_KDE] ) ) 183 { 184 pList = pKDEFallbackList; 185 nListEntry = 1; 186 } 187 else if( desktop.equalsAscii( desktop_strings[DESKTOP_KDE4] ) ) 188 pList = pKDEFallbackList; 189 190 SalInstance* pInst = NULL; 191 while( pList[nListEntry] && pInst == NULL ) 192 { 193 rtl::OUString aTry( rtl::OUString::createFromAscii( pList[nListEntry] ) ); 194 pInst = tryInstance( aTry ); 195 #if OSL_DEBUG_LEVEL > 1 196 if( pInst ) 197 std::fprintf( stderr, "plugin autodetection: %s\n", pList[nListEntry] ); 198 #endif 199 nListEntry++; 200 } 201 202 return pInst; 203 } 204 205 static SalInstance* check_headless_plugin() 206 { 207 int nParams = osl_getCommandArgCount(); 208 OUString aParam; 209 for( int i = 0; i < nParams; i++ ) 210 { 211 osl_getCommandArg( i, &aParam.pData ); 212 if( aParam.equalsAscii( "-headless" ) ) 213 return tryInstance( OUString( RTL_CONSTASCII_USTRINGPARAM( "svp" ) ) ); 214 } 215 return NULL; 216 } 217 218 SalInstance *CreateSalInstance() 219 { 220 SalInstance* pInst = NULL; 221 222 static const char* pUsePlugin = getenv( "SAL_USE_VCLPLUGIN" ); 223 224 if( !(pUsePlugin && *pUsePlugin) ) 225 pInst = check_headless_plugin(); 226 else 227 pInst = tryInstance( OUString::createFromAscii( pUsePlugin ) ); 228 229 if( ! pInst ) 230 pInst = autodetect_plugin(); 231 232 // fallback to gen 233 if( ! pInst ) 234 pInst = tryInstance( OUString( RTL_CONSTASCII_USTRINGPARAM( "gen" ) ) ); 235 236 if( ! pInst ) 237 { 238 std::fprintf( stderr, "no suitable windowing system found, exiting.\n" ); 239 _exit( 1 ); 240 } 241 242 // acquire SolarMutex 243 pInst->AcquireYieldMutex( 1 ); 244 245 return pInst; 246 } 247 248 void DestroySalInstance( SalInstance *pInst ) 249 { 250 // release SolarMutex 251 pInst->ReleaseYieldMutex(); 252 253 delete pInst; 254 if( pCloseModule ) 255 osl_unloadModule( pCloseModule ); 256 } 257 258 void InitSalData() 259 { 260 } 261 262 void DeInitSalData() 263 { 264 } 265 266 void InitSalMain() 267 { 268 } 269 270 void DeInitSalMain() 271 { 272 } 273 274 void SalAbort( const XubString& rErrorText ) 275 { 276 if( !rErrorText.Len() ) 277 std::fprintf( stderr, "Application Error" ); 278 else 279 std::fprintf( stderr, ByteString( rErrorText, gsl_getSystemTextEncoding() ).GetBuffer() ); 280 abort(); 281 } 282 283 const OUString& SalGetDesktopEnvironment() 284 { 285 return get_desktop_environment(); 286 } 287 288 SalData::SalData() : 289 m_pInstance(NULL), 290 m_pPlugin(NULL), 291 m_pPIManager(NULL) 292 { 293 } 294 295 SalData::~SalData() 296 { 297 psp::PrinterInfoManager::release(); 298 } 299