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 <string.h> 28 #include <stdio.h> 29 #include <stdlib.h> 30 31 #include "osl/module.hxx" 32 #include "tools/solarmutex.hxx" 33 #include "vos/mutex.hxx" 34 35 36 #include "unx/salunx.h" 37 #include "unx/saldata.hxx" 38 #include "unx/saldisp.hxx" 39 #include "unx/salinst.h" 40 #include "unx/salframe.h" 41 #include "unx/dtint.hxx" 42 #include "unx/salprn.h" 43 #include "unx/sm.hxx" 44 45 #include "vcl/apptypes.hxx" 46 #include "vcl/helper.hxx" 47 48 #include "salwtype.hxx" 49 50 // ------------------------------------------------------------------------- 51 // 52 // SalYieldMutex 53 // 54 // ------------------------------------------------------------------------- 55 56 SalYieldMutex::SalYieldMutex() 57 { 58 mnCount = 0; 59 mnThreadId = 0; 60 ::tools::SolarMutex::SetSolarMutex( this ); 61 } 62 63 void SalYieldMutex::acquire() 64 { 65 OMutex::acquire(); 66 mnThreadId = vos::OThread::getCurrentIdentifier(); 67 mnCount++; 68 } 69 70 void SalYieldMutex::release() 71 { 72 if ( mnThreadId == vos::OThread::getCurrentIdentifier() ) 73 { 74 if ( mnCount == 1 ) 75 mnThreadId = 0; 76 mnCount--; 77 } 78 OMutex::release(); 79 } 80 81 sal_Bool SalYieldMutex::tryToAcquire() 82 { 83 if ( OMutex::tryToAcquire() ) 84 { 85 mnThreadId = vos::OThread::getCurrentIdentifier(); 86 mnCount++; 87 return True; 88 } 89 else 90 return False; 91 } 92 93 //---------------------------------------------------------------------------- 94 95 // -=-= SalInstance =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 96 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 97 98 // plugin factory function 99 extern "C" 100 { 101 VCLPLUG_GEN_PUBLIC SalInstance* create_SalInstance() 102 { 103 /* #i92121# workaround deadlocks in the X11 implementation 104 */ 105 static const char* pNoXInitThreads = getenv( "SAL_NO_XINITTHREADS" ); 106 /* #i90094# 107 from now on we know that an X connection will be 108 established, so protect X against itself 109 */ 110 if( ! ( pNoXInitThreads && *pNoXInitThreads ) ) 111 XInitThreads(); 112 113 X11SalInstance* pInstance = new X11SalInstance( new SalYieldMutex() ); 114 115 // initialize SalData 116 X11SalData *pSalData = new X11SalData; 117 SetSalData( pSalData ); 118 pSalData->m_pInstance = pInstance; 119 pSalData->Init(); 120 121 return pInstance; 122 } 123 } 124 125 X11SalInstance::~X11SalInstance() 126 { 127 // close session management 128 SessionManagerClient::close(); 129 130 // dispose SalDisplay list from SalData 131 // would be done in a static destructor else which is 132 // a little late 133 134 X11SalData *pSalData = GetX11SalData(); 135 pSalData->deInitNWF(); 136 delete pSalData; 137 SetSalData( NULL ); 138 139 ::tools::SolarMutex::SetSolarMutex( 0 ); 140 delete mpSalYieldMutex; 141 } 142 143 144 // -------------------------------------------------------- 145 // AnyInput from sv/mow/source/app/svapp.cxx 146 147 struct PredicateReturn 148 { 149 sal_uInt16 nType; 150 sal_Bool bRet; 151 }; 152 153 extern "C" { 154 Bool ImplPredicateEvent( Display *, XEvent *pEvent, char *pData ) 155 { 156 PredicateReturn *pPre = (PredicateReturn *)pData; 157 158 if ( pPre->bRet ) 159 return False; 160 161 sal_uInt16 nType; 162 163 switch( pEvent->type ) 164 { 165 case ButtonPress: 166 case ButtonRelease: 167 case MotionNotify: 168 case EnterNotify: 169 case LeaveNotify: 170 nType = INPUT_MOUSE; 171 break; 172 173 case XLIB_KeyPress: 174 //case KeyRelease: 175 nType = INPUT_KEYBOARD; 176 break; 177 case Expose: 178 case GraphicsExpose: 179 case NoExpose: 180 nType = INPUT_PAINT; 181 break; 182 default: 183 nType = 0; 184 } 185 186 if ( (nType & pPre->nType) || ( ! nType && (pPre->nType & INPUT_OTHER) ) ) 187 pPre->bRet = sal_True; 188 189 return False; 190 } 191 } 192 193 bool X11SalInstance::AnyInput(sal_uInt16 nType) 194 { 195 X11SalData *pSalData = GetX11SalData(); 196 Display *pDisplay = pSalData->GetDisplay()->GetDisplay(); 197 sal_Bool bRet = sal_False; 198 199 if( (nType & INPUT_TIMER) && 200 pSalData->GetDisplay()->GetXLib()->CheckTimeout( false ) ) 201 { 202 bRet = sal_True; 203 } 204 else if (XPending(pDisplay) ) 205 { 206 PredicateReturn aInput; 207 XEvent aEvent; 208 209 aInput.bRet = sal_False; 210 aInput.nType = nType; 211 212 XCheckIfEvent(pDisplay, &aEvent, ImplPredicateEvent, 213 (char *)&aInput ); 214 215 bRet = aInput.bRet; 216 } 217 return bRet; 218 } 219 220 vos::IMutex* X11SalInstance::GetYieldMutex() 221 { 222 return mpSalYieldMutex; 223 } 224 225 // ----------------------------------------------------------------------- 226 227 sal_uLong X11SalInstance::ReleaseYieldMutex() 228 { 229 SalYieldMutex* pYieldMutex = mpSalYieldMutex; 230 if ( pYieldMutex->GetThreadId() == 231 vos::OThread::getCurrentIdentifier() ) 232 { 233 sal_uLong nCount = pYieldMutex->GetAcquireCount(); 234 sal_uLong n = nCount; 235 while ( n ) 236 { 237 pYieldMutex->release(); 238 n--; 239 } 240 241 return nCount; 242 } 243 else 244 return 0; 245 } 246 247 // ----------------------------------------------------------------------- 248 249 void X11SalInstance::AcquireYieldMutex( sal_uLong nCount ) 250 { 251 SalYieldMutex* pYieldMutex = mpSalYieldMutex; 252 while ( nCount ) 253 { 254 pYieldMutex->acquire(); 255 nCount--; 256 } 257 } 258 259 // ----------------------------------------------------------------------- 260 261 bool X11SalInstance::CheckYieldMutex() 262 { 263 bool bRet = true; 264 265 SalYieldMutex* pYieldMutex = mpSalYieldMutex; 266 if ( pYieldMutex->GetThreadId() != 267 vos::OThread::getCurrentIdentifier() ) 268 { 269 bRet = false; 270 } 271 272 return bRet; 273 } 274 275 // ----------------------------------------------------------------------- 276 277 void X11SalInstance::Yield( bool bWait, bool bHandleAllCurrentEvents ) 278 { GetX11SalData()->GetLib()->Yield( bWait, bHandleAllCurrentEvents ); } 279 280 void* X11SalInstance::GetConnectionIdentifier( ConnectionIdentifierType& rReturnedType, int& rReturnedBytes ) 281 { 282 static const char* pDisplay = getenv( "DISPLAY" ); 283 rReturnedType = AsciiCString; 284 rReturnedBytes = pDisplay ? strlen( pDisplay )+1 : 1; 285 return pDisplay ? (void*)pDisplay : (void*)""; 286 } 287 288 SalFrame *X11SalInstance::CreateFrame( SalFrame *pParent, sal_uLong nSalFrameStyle ) 289 { 290 SalFrame *pFrame = new X11SalFrame( pParent, nSalFrameStyle ); 291 292 return pFrame; 293 } 294 295 SalFrame* X11SalInstance::CreateChildFrame( SystemParentData* pParentData, sal_uLong nStyle ) 296 { 297 SalFrame* pFrame = new X11SalFrame( NULL, nStyle, pParentData ); 298 299 return pFrame; 300 } 301 302 void X11SalInstance::DestroyFrame( SalFrame* pFrame ) 303 { 304 delete pFrame; 305 } 306 307 static void getServerDirectories( std::list< rtl::OString >& o_rFontPaths ) 308 { 309 #ifdef LINUX 310 /* 311 * chkfontpath exists on some (RH derived) Linux distributions 312 */ 313 static const char* pCommands[] = { 314 "/usr/sbin/chkfontpath 2>/dev/null", "chkfontpath 2>/dev/null" 315 }; 316 ::std::list< ByteString > aLines; 317 318 for( unsigned int i = 0; i < sizeof(pCommands)/sizeof(pCommands[0]); i++ ) 319 { 320 FILE* pPipe = popen( pCommands[i], "r" ); 321 aLines.clear(); 322 if( pPipe ) 323 { 324 char line[1024]; 325 char* pSearch; 326 while( fgets( line, sizeof(line), pPipe ) ) 327 { 328 int nLen = strlen( line ); 329 if( line[nLen-1] == '\n' ) 330 line[nLen-1] = 0; 331 pSearch = strstr( line, ": " ); 332 if( pSearch ) 333 aLines.push_back( pSearch+2 ); 334 } 335 if( ! pclose( pPipe ) ) 336 break; 337 } 338 } 339 340 for( ::std::list< ByteString >::iterator it = aLines.begin(); it != aLines.end(); ++it ) 341 { 342 if( ! access( it->GetBuffer(), F_OK ) ) 343 { 344 o_rFontPaths.push_back( *it ); 345 #if OSL_DEBUG_LEVEL > 1 346 fprintf( stderr, "adding fs dir %s\n", it->GetBuffer() ); 347 #endif 348 } 349 } 350 #else 351 (void)o_rFontPaths; 352 #endif 353 } 354 355 356 357 void X11SalInstance::FillFontPathList( std::list< rtl::OString >& o_rFontPaths ) 358 { 359 Display *pDisplay = GetX11SalData()->GetDisplay()->GetDisplay(); 360 361 DBG_ASSERT( pDisplay, "No Display !" ); 362 if( pDisplay ) 363 { 364 // get font paths to look for fonts 365 int nPaths = 0, i; 366 char** pPaths = XGetFontPath( pDisplay, &nPaths ); 367 368 bool bServerDirs = false; 369 for( i = 0; i < nPaths; i++ ) 370 { 371 OString aPath( pPaths[i] ); 372 sal_Int32 nPos = 0; 373 if( ! bServerDirs 374 && ( nPos = aPath.indexOf( ':' ) ) > 0 375 && ( !aPath.copy(nPos).equals( ":unscaled" ) ) ) 376 { 377 bServerDirs = true; 378 getServerDirectories( o_rFontPaths ); 379 } 380 else 381 { 382 psp::normPath( aPath ); 383 o_rFontPaths.push_back( aPath ); 384 } 385 } 386 387 if( nPaths ) 388 XFreeFontPath( pPaths ); 389 } 390 391 // insert some standard directories 392 o_rFontPaths.push_back( "/usr/openwin/lib/X11/fonts/TrueType" ); 393 o_rFontPaths.push_back( "/usr/openwin/lib/X11/fonts/Type1" ); 394 o_rFontPaths.push_back( "/usr/openwin/lib/X11/fonts/Type1/sun" ); 395 o_rFontPaths.push_back( "/usr/X11R6/lib/X11/fonts/truetype" ); 396 o_rFontPaths.push_back( "/usr/X11R6/lib/X11/fonts/Type1" ); 397 398 #ifdef SOLARIS 399 /* cde specials, from /usr/dt/bin/Xsession: here are the good fonts, 400 the OWfontpath file may contain as well multiple lines as a comma 401 separated list of fonts in each line. to make it even more weird 402 environment variables are allowed as well */ 403 404 const char* lang = getenv("LANG"); 405 if ( lang != NULL ) 406 { 407 String aOpenWinDir( String::CreateFromAscii( "/usr/openwin/lib/locale/" ) ); 408 aOpenWinDir.AppendAscii( lang ); 409 aOpenWinDir.AppendAscii( "/OWfontpath" ); 410 411 SvFileStream aStream( aOpenWinDir, STREAM_READ ); 412 413 // TODO: replace environment variables 414 while( aStream.IsOpen() && ! aStream.IsEof() ) 415 { 416 ByteString aLine; 417 aStream.ReadLine( aLine ); 418 // need an OString for normpath 419 OString aNLine( aLine ); 420 psp::normPath( aNLine ); 421 aLine = aNLine; 422 // try to avoid bad fonts in some cases 423 static bool bAvoid = (strncasecmp( lang, "ar", 2 ) == 0) || (strncasecmp( lang, "he", 2 ) == 0) || strncasecmp( lang, "iw", 2 ) == 0 || (strncasecmp( lang, "hi", 2 ) == 0); 424 if( bAvoid && aLine.Search( "iso_8859" ) != STRING_NOTFOUND ) 425 continue; 426 o_rFontPaths.push_back( aLine ); 427 } 428 } 429 #endif /* SOLARIS */ 430 } 431 432 extern "C" { static void SAL_CALL thisModule() {} } 433 434 void X11SalInstance::AddToRecentDocumentList(const rtl::OUString& rFileUrl, const rtl::OUString& rMimeType) 435 { 436 const rtl::OUString SYM_ADD_TO_RECENTLY_USED_FILE_LIST(RTL_CONSTASCII_USTRINGPARAM("add_to_recently_used_file_list")); 437 const rtl::OUString LIB_RECENT_FILE(RTL_CONSTASCII_USTRINGPARAM("librecentfile.so")); 438 typedef void (*PFUNC_ADD_TO_RECENTLY_USED_LIST)(const rtl::OUString&, const rtl::OUString&); 439 440 PFUNC_ADD_TO_RECENTLY_USED_LIST add_to_recently_used_file_list = 0; 441 442 osl::Module module; 443 module.loadRelative( &thisModule, LIB_RECENT_FILE ); 444 if (module.is()) 445 add_to_recently_used_file_list = (PFUNC_ADD_TO_RECENTLY_USED_LIST)module.getFunctionSymbol(SYM_ADD_TO_RECENTLY_USED_FILE_LIST); 446 if (add_to_recently_used_file_list) 447 add_to_recently_used_file_list(rFileUrl, rMimeType); 448 } 449