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 #include <string.h> 31 #include <unistd.h> 32 #include <sys/poll.h> 33 #include <fcntl.h> 34 35 #include <stdio.h> 36 37 #include <osl/process.h> 38 #include <osl/security.h> 39 #include <osl/conditn.h> 40 41 #include <tools/prex.h> 42 #include <X11/Xatom.h> 43 #include <tools/postx.h> 44 45 #include <unx/sm.hxx> 46 #include <unx/saldata.hxx> 47 #include <unx/saldisp.hxx> 48 #include <unx/salframe.h> 49 #include <unx/salinst.h> 50 51 #include <vcl/svapp.hxx> 52 #include <vcl/window.hxx> 53 54 #define USE_SM_EXTENSION 55 56 #if OSL_DEBUG_LEVEL > 1 57 #include <cstdarg> 58 static bool bFirstAssert = true; 59 #endif 60 61 #if OSL_DEBUG_LEVEL > 1 62 inline void SMprintf( const char* pFormat, ... ) 63 #else 64 inline void SMprintf( const char*, ... ) 65 #endif 66 { 67 #if OSL_DEBUG_LEVEL > 1 68 FILE* fp = fopen( "/tmp/sessionlog.txt", bFirstAssert ? "w" : "a" ); 69 if(!fp) return; 70 bFirstAssert = false; 71 std::va_list ap; 72 va_start( ap, pFormat ); 73 vfprintf( fp, pFormat, ap ); 74 fclose( fp ); 75 va_end( ap ); 76 #endif 77 }; 78 79 static IceSalSession* pOneInstance = NULL; 80 81 SalSession* X11SalInstance::CreateSalSession() 82 { 83 if( ! pOneInstance ) 84 pOneInstance = new IceSalSession(); 85 return pOneInstance; 86 } 87 88 /* 89 * class IceSalSession 90 */ 91 92 static X11SalFrame* pOldStyleSaveFrame = NULL; 93 94 IceSalSession::IceSalSession() 95 { 96 } 97 98 IceSalSession::~IceSalSession() 99 { 100 if( pOneInstance == this ) 101 pOneInstance = NULL; 102 } 103 104 void IceSalSession::queryInteraction() 105 { 106 if( ! SessionManagerClient::queryInteraction() ) 107 { 108 SalSessionInteractionEvent aEvent( false ); 109 CallCallback( &aEvent ); 110 } 111 } 112 113 void IceSalSession::interactionDone() 114 { 115 SessionManagerClient::interactionDone( false ); 116 } 117 118 void IceSalSession::saveDone() 119 { 120 SessionManagerClient::saveDone(); 121 if( pOldStyleSaveFrame ) 122 { 123 // note: does nothing if not running in generic plugin 124 X11SalFrame::SaveYourselfDone( pOldStyleSaveFrame ); 125 } 126 } 127 128 bool IceSalSession::cancelShutdown() 129 { 130 SessionManagerClient::interactionDone( true ); 131 return false; 132 } 133 134 void IceSalSession::handleOldX11SaveYourself( SalFrame* pFrame ) 135 { 136 // do this only once 137 if( ! pOldStyleSaveFrame ) 138 { 139 pOldStyleSaveFrame = static_cast<X11SalFrame*>(pFrame); 140 if( pOneInstance ) 141 { 142 SalSessionSaveRequestEvent aEvent( true, false ); 143 pOneInstance->CallCallback( &aEvent ); 144 } 145 } 146 } 147 148 extern "C" void SAL_CALL ICEConnectionWorker( void* ); 149 150 class ICEConnectionObserver 151 { 152 friend void SAL_CALL ICEConnectionWorker(void*); 153 static sal_Bool bIsWatching; 154 static void ICEWatchProc( IceConn connection, IcePointer client_data, 155 Bool opening, IcePointer* watch_data ); 156 157 static struct pollfd* pFilehandles; 158 static IceConn* pConnections; 159 static int nConnections; 160 static int nWakeupFiles[2]; 161 static oslMutex ICEMutex; 162 static oslThread ICEThread; 163 #ifdef USE_SM_EXTENSION 164 static IceIOErrorHandler origIOErrorHandler; 165 static IceErrorHandler origErrorHandler; 166 #endif 167 public: 168 169 static void activate(); 170 static void deactivate(); 171 static void lock(); 172 static void unlock(); 173 static void wakeup(); 174 }; 175 176 177 SmcConn SessionManagerClient::aSmcConnection = NULL; 178 ByteString SessionManagerClient::aClientID; 179 sal_Bool ICEConnectionObserver::bIsWatching = sal_False; 180 struct pollfd* ICEConnectionObserver::pFilehandles = NULL; 181 IceConn* ICEConnectionObserver::pConnections = NULL; 182 int ICEConnectionObserver::nConnections = 0; 183 oslMutex ICEConnectionObserver::ICEMutex = NULL; 184 oslThread ICEConnectionObserver::ICEThread = NULL; 185 int ICEConnectionObserver::nWakeupFiles[2] = { 0, 0 }; 186 187 #ifdef USE_SM_EXTENSION 188 IceIOErrorHandler ICEConnectionObserver::origIOErrorHandler = NULL; 189 IceErrorHandler ICEConnectionObserver::origErrorHandler = NULL; 190 191 static void IgnoreIceErrors(IceConn, Bool, int, unsigned long, int, int, IcePointer) 192 { 193 } 194 195 static void IgnoreIceIOErrors(IceConn) 196 { 197 } 198 #endif 199 200 // HACK 201 bool SessionManagerClient::bDocSaveDone = false; 202 203 204 static SmProp* pSmProps = NULL; 205 static SmProp** ppSmProps = NULL; 206 static int nSmProps = 0; 207 static unsigned char *pSmRestartHint = NULL; 208 209 210 static void BuildSmPropertyList() 211 { 212 if( ! pSmProps ) 213 { 214 ByteString aExec( SessionManagerClient::getExecName(), osl_getThreadTextEncoding() ); 215 216 nSmProps = 5; 217 pSmProps = new SmProp[ nSmProps ]; 218 219 pSmProps[ 0 ].name = const_cast<char*>(SmCloneCommand); 220 pSmProps[ 0 ].type = const_cast<char*>(SmLISTofARRAY8); 221 pSmProps[ 0 ].num_vals = 1; 222 pSmProps[ 0 ].vals = new SmPropValue; 223 pSmProps[ 0 ].vals->length = aExec.Len()+1; 224 pSmProps[ 0 ].vals->value = strdup( aExec.GetBuffer() ); 225 226 pSmProps[ 1 ].name = const_cast<char*>(SmProgram); 227 pSmProps[ 1 ].type = const_cast<char*>(SmARRAY8); 228 pSmProps[ 1 ].num_vals = 1; 229 pSmProps[ 1 ].vals = new SmPropValue; 230 pSmProps[ 1 ].vals->length = aExec.Len()+1; 231 pSmProps[ 1 ].vals->value = strdup( aExec.GetBuffer() ); 232 233 pSmProps[ 2 ].name = const_cast<char*>(SmRestartCommand); 234 pSmProps[ 2 ].type = const_cast<char*>(SmLISTofARRAY8); 235 pSmProps[ 2 ].num_vals = 3; 236 pSmProps[ 2 ].vals = new SmPropValue[3]; 237 pSmProps[ 2 ].vals[0].length = aExec.Len()+1; 238 pSmProps[ 2 ].vals[0].value = strdup( aExec.GetBuffer() ); 239 ByteString aRestartOption( "-session=" ); 240 aRestartOption.Append( SessionManagerClient::getSessionID() ); 241 pSmProps[ 2 ].vals[1].length = aRestartOption.Len()+1; 242 pSmProps[ 2 ].vals[1].value = strdup( aRestartOption.GetBuffer() ); 243 ByteString aRestartOptionNoLogo( "-nologo" ); 244 pSmProps[ 2 ].vals[2].length = aRestartOptionNoLogo.Len()+1; 245 pSmProps[ 2 ].vals[2].value = strdup( aRestartOptionNoLogo.GetBuffer() ); 246 247 rtl::OUString aUserName; 248 rtl::OString aUser; 249 oslSecurity aSec = osl_getCurrentSecurity(); 250 if( aSec ) 251 { 252 osl_getUserName( aSec, &aUserName.pData ); 253 aUser = rtl::OUStringToOString( aUserName, osl_getThreadTextEncoding() ); 254 osl_freeSecurityHandle( aSec ); 255 } 256 257 pSmProps[ 3 ].name = const_cast<char*>(SmUserID); 258 pSmProps[ 3 ].type = const_cast<char*>(SmARRAY8); 259 pSmProps[ 3 ].num_vals = 1; 260 pSmProps[ 3 ].vals = new SmPropValue; 261 pSmProps[ 3 ].vals->value = strdup( aUser.getStr() ); 262 pSmProps[ 3 ].vals->length = strlen( (char *)pSmProps[ 3 ].vals->value )+1; 263 264 pSmProps[ 4 ].name = const_cast<char*>(SmRestartStyleHint); 265 pSmProps[ 4 ].type = const_cast<char*>(SmCARD8); 266 pSmProps[ 4 ].num_vals = 1; 267 pSmProps[ 4 ].vals = new SmPropValue; 268 pSmProps[ 4 ].vals->value = malloc(1); 269 pSmRestartHint = (unsigned char *)pSmProps[ 4 ].vals->value; 270 *pSmRestartHint = SmRestartIfRunning; 271 pSmProps[ 4 ].vals->length = 1; 272 273 ppSmProps = new SmProp*[ nSmProps ]; 274 for( int i = 0; i < nSmProps; i++ ) 275 ppSmProps[ i ] = &pSmProps[i]; 276 } 277 } 278 279 bool SessionManagerClient::checkDocumentsSaved() 280 { 281 return bDocSaveDone; 282 } 283 284 IMPL_STATIC_LINK( SessionManagerClient, SaveYourselfHdl, void*, EMPTYARG ) 285 { 286 SMprintf( "posting save documents event shutdown = %s\n", (pThis!=0) ? "true" : "false" ); 287 288 static bool bFirstShutdown=true; 289 if (pThis != 0 && bFirstShutdown) //first shutdown request 290 { 291 bFirstShutdown = false; 292 /* 293 If we have no actual frames open, e.g. we launched a quickstarter, 294 and then shutdown all our frames leaving just a quickstarter running, 295 then we don't want to launch an empty toplevel frame on the next 296 start. (The job of scheduling the restart of the quick-starter is a 297 task of the quick-starter) 298 */ 299 *pSmRestartHint = SmRestartNever; 300 const std::list< SalFrame* >& rFrames = GetX11SalData()->GetDisplay()->getFrames(); 301 for( std::list< SalFrame* >::const_iterator it = rFrames.begin(); it != rFrames.end(); ++it ) 302 { 303 Window *pWindow = (*it)->GetWindow(); 304 if (pWindow && pWindow->IsVisible()) 305 { 306 *pSmRestartHint = SmRestartIfRunning; 307 break; 308 } 309 } 310 } 311 312 if( pOneInstance ) 313 { 314 SalSessionSaveRequestEvent aEvent( pThis != 0, false ); 315 pOneInstance->CallCallback( &aEvent ); 316 } 317 else 318 saveDone(); 319 320 return 0; 321 } 322 323 IMPL_STATIC_LINK_NOINSTANCE( SessionManagerClient, InteractionHdl, void*, EMPTYARG ) 324 { 325 SMprintf( "interaction link\n" ); 326 if( pOneInstance ) 327 { 328 SalSessionInteractionEvent aEvent( true ); 329 pOneInstance->CallCallback( &aEvent ); 330 } 331 332 return 0; 333 } 334 335 IMPL_STATIC_LINK_NOINSTANCE( SessionManagerClient, ShutDownCancelHdl, void*, EMPTYARG ) 336 { 337 SMprintf( "shutdown cancel\n" ); 338 if( pOneInstance ) 339 { 340 SalSessionShutdownCancelEvent aEvent; 341 pOneInstance->CallCallback( &aEvent ); 342 } 343 344 return 0; 345 } 346 347 void SessionManagerClient::SaveYourselfProc( 348 SmcConn, 349 SmPointer, 350 int save_type, 351 Bool shutdown, 352 int interact_style, 353 Bool 354 ) 355 { 356 SMprintf( "Session: save yourself, save_type = %s, shutdown = %s, interact_style = %s, fast = %s\n", 357 save_type == SmSaveLocal ? "SmcSaveLocal" : 358 ( save_type == SmSaveGlobal ? "SmcSaveGlobal" : 359 ( save_type == SmSaveBoth ? "SmcSaveBoth" : "<unknown>" ) ), 360 shutdown ? "true" : "false", 361 interact_style == SmInteractStyleNone ? "SmInteractStyleNone" : 362 ( interact_style == SmInteractStyleErrors ? "SmInteractStyleErrors" : 363 ( interact_style == SmInteractStyleAny ? "SmInteractStyleAny" : "<unknown>" ) ), 364 false ? "true" : "false" 365 ); 366 BuildSmPropertyList(); 367 #ifdef USE_SM_EXTENSION 368 bDocSaveDone = false; 369 /* #i49875# some session managers send a "die" message if the 370 * saveDone does not come early enough for their convenience 371 * this can occasionally happen on startup, especially the first 372 * startup. So shortcut the "not shutting down" case since the 373 * upper layers are currently not interested in that event anyway. 374 */ 375 if( ! shutdown ) 376 { 377 SessionManagerClient::saveDone(); 378 return; 379 } 380 Application::PostUserEvent( STATIC_LINK( (void*)(shutdown ? 0xffffffff : 0x0), SessionManagerClient, SaveYourselfHdl ) ); 381 SMprintf( "waiting for save yourself event to be processed\n" ); 382 #endif 383 } 384 385 IMPL_STATIC_LINK_NOINSTANCE( SessionManagerClient, ShutDownHdl, void*, EMPTYARG ) 386 { 387 if( pOneInstance ) 388 { 389 SalSessionQuitEvent aEvent; 390 pOneInstance->CallCallback( &aEvent ); 391 } 392 393 const std::list< SalFrame* >& rFrames = GetX11SalData()->GetDisplay()->getFrames(); 394 SMprintf( rFrames.begin() != rFrames.end() ? "shutdown on first frame\n" : "shutdown event but no frame\n" ); 395 if( rFrames.begin() != rFrames.end() ) 396 rFrames.front()->CallCallback( SALEVENT_SHUTDOWN, 0 ); 397 return 0; 398 } 399 400 void SessionManagerClient::DieProc( 401 SmcConn connection, 402 SmPointer 403 ) 404 { 405 SMprintf( "Session: die\n" ); 406 if( connection == aSmcConnection ) 407 { 408 Application::PostUserEvent( STATIC_LINK( NULL, SessionManagerClient, ShutDownHdl ) ); 409 SMprintf( "waiting for shutdown event to be processed\n" ); 410 } 411 } 412 413 void SessionManagerClient::SaveCompleteProc( 414 SmcConn, 415 SmPointer 416 ) 417 { 418 SMprintf( "Session: save complete\n" ); 419 } 420 421 void SessionManagerClient::ShutdownCanceledProc( 422 SmcConn connection, 423 SmPointer ) 424 { 425 SMprintf( "Session: shutdown canceled\n" ); 426 if( connection == aSmcConnection ) 427 Application::PostUserEvent( STATIC_LINK( NULL, SessionManagerClient, ShutDownCancelHdl ) ); 428 } 429 430 void SessionManagerClient::InteractProc( 431 SmcConn connection, 432 SmPointer ) 433 { 434 SMprintf( "Session: interaction request completed\n" ); 435 if( connection == aSmcConnection ) 436 Application::PostUserEvent( STATIC_LINK( NULL, SessionManagerClient, InteractionHdl ) ); 437 } 438 439 void SessionManagerClient::saveDone() 440 { 441 if( aSmcConnection ) 442 { 443 ICEConnectionObserver::lock(); 444 SmcSetProperties( aSmcConnection, nSmProps, ppSmProps ); 445 SmcSaveYourselfDone( aSmcConnection, True ); 446 SMprintf( "sent SaveYourselfDone SmRestartHint of %d\n", *pSmRestartHint ); 447 bDocSaveDone = true; 448 ICEConnectionObserver::unlock(); 449 } 450 } 451 452 453 void SessionManagerClient::open() 454 { 455 static SmcCallbacks aCallbacks; 456 457 #ifdef USE_SM_EXTENSION 458 // this is the way Xt does it, so we can too 459 if( ! aSmcConnection && getenv( "SESSION_MANAGER" ) ) 460 { 461 char aErrBuf[1024]; 462 ICEConnectionObserver::activate(); 463 ICEConnectionObserver::lock(); 464 465 char* pClientID = NULL; 466 const ByteString& rPrevId( getPreviousSessionID() ); 467 468 aCallbacks.save_yourself.callback = SaveYourselfProc; 469 aCallbacks.save_yourself.client_data = NULL; 470 aCallbacks.die.callback = DieProc; 471 aCallbacks.die.client_data = NULL; 472 aCallbacks.save_complete.callback = SaveCompleteProc; 473 aCallbacks.save_complete.client_data = NULL; 474 aCallbacks.shutdown_cancelled.callback = ShutdownCanceledProc; 475 aCallbacks.shutdown_cancelled.client_data = NULL; 476 aSmcConnection = SmcOpenConnection( NULL, 477 NULL, 478 SmProtoMajor, 479 SmProtoMinor, 480 SmcSaveYourselfProcMask | 481 SmcDieProcMask | 482 SmcSaveCompleteProcMask | 483 SmcShutdownCancelledProcMask , 484 &aCallbacks, 485 rPrevId.Len() ? const_cast<char*>(rPrevId.GetBuffer()) : NULL, 486 &pClientID, 487 sizeof( aErrBuf ), 488 aErrBuf ); 489 if( ! aSmcConnection ) 490 SMprintf( "SmcOpenConnection failed: %s\n", aErrBuf ); 491 else 492 SMprintf( "SmcOpenConnection succeeded, client ID is \"%s\"\n", pClientID ); 493 aClientID = ByteString( pClientID ); 494 free( pClientID ); 495 pClientID = NULL; 496 ICEConnectionObserver::unlock(); 497 498 SalDisplay* pDisp = GetX11SalData()->GetDisplay(); 499 if( pDisp->GetDrawable( pDisp->GetDefaultScreenNumber() ) && aClientID.Len() ) 500 { 501 XChangeProperty( pDisp->GetDisplay(), 502 pDisp->GetDrawable( pDisp->GetDefaultScreenNumber() ), 503 XInternAtom( pDisp->GetDisplay(), "SM_CLIENT_ID", False ), 504 XA_STRING, 505 8, 506 PropModeReplace, 507 (unsigned char*)aClientID.GetBuffer(), 508 aClientID.Len() 509 ); 510 } 511 } 512 else if( ! aSmcConnection ) 513 SMprintf( "no SESSION_MANAGER\n" ); 514 #endif 515 } 516 517 const ByteString& SessionManagerClient::getSessionID() 518 { 519 return aClientID; 520 } 521 522 void SessionManagerClient::close() 523 { 524 if( aSmcConnection ) 525 { 526 #ifdef USE_SM_EXTENSION 527 ICEConnectionObserver::lock(); 528 SMprintf( "attempting SmcCloseConnection\n" ); 529 SmcCloseConnection( aSmcConnection, 0, NULL ); 530 SMprintf( "SmcConnection closed\n" ); 531 ICEConnectionObserver::unlock(); 532 ICEConnectionObserver::deactivate(); 533 #endif 534 aSmcConnection = NULL; 535 } 536 } 537 538 bool SessionManagerClient::queryInteraction() 539 { 540 bool bRet = false; 541 if( aSmcConnection ) 542 { 543 ICEConnectionObserver::lock(); 544 if( SmcInteractRequest( aSmcConnection, SmDialogNormal, InteractProc, NULL ) ) 545 bRet = true; 546 ICEConnectionObserver::unlock(); 547 } 548 return bRet; 549 } 550 551 void SessionManagerClient::interactionDone( bool bCancelShutdown ) 552 { 553 if( aSmcConnection ) 554 { 555 ICEConnectionObserver::lock(); 556 SmcInteractDone( aSmcConnection, bCancelShutdown ? True : False ); 557 ICEConnectionObserver::unlock(); 558 } 559 } 560 561 562 String SessionManagerClient::getExecName() 563 { 564 rtl::OUString aExec, aSysExec; 565 osl_getExecutableFile( &aExec.pData ); 566 osl_getSystemPathFromFileURL( aExec.pData, &aSysExec.pData ); 567 568 int nPos = aSysExec.indexOf( rtl::OUString::createFromAscii( ".bin" ) ); 569 if( nPos != -1 ) 570 aSysExec = aSysExec.copy( 0, nPos ); 571 return aSysExec; 572 } 573 574 575 const ByteString& SessionManagerClient::getPreviousSessionID() 576 { 577 static ByteString aPrevId; 578 579 int nCommands = osl_getCommandArgCount(); 580 for( int i = 0; i < nCommands; i++ ) 581 { 582 ::rtl::OUString aArg; 583 osl_getCommandArg( i, &aArg.pData ); 584 if( aArg.compareToAscii( "-session=", 9 ) == 0 ) 585 { 586 aPrevId = ByteString( ::rtl::OUStringToOString( aArg.copy( 9 ), osl_getThreadTextEncoding() ) ); 587 break; 588 } 589 } 590 SMprintf( "previous ID = \"%s\"\n", aPrevId.GetBuffer() ); 591 return aPrevId; 592 } 593 594 void ICEConnectionObserver::lock() 595 { 596 osl_acquireMutex( ICEMutex ); 597 } 598 599 void ICEConnectionObserver::unlock() 600 { 601 osl_releaseMutex( ICEMutex ); 602 } 603 604 void ICEConnectionObserver::activate() 605 { 606 if( ! bIsWatching ) 607 { 608 nWakeupFiles[0] = nWakeupFiles[1] = 0; 609 ICEMutex = osl_createMutex(); 610 bIsWatching = sal_True; 611 #ifdef USE_SM_EXTENSION 612 /* 613 * Default handlers call exit, we don't care that strongly if something 614 * happens to fail 615 */ 616 origIOErrorHandler = IceSetIOErrorHandler( IgnoreIceIOErrors ); 617 origErrorHandler = IceSetErrorHandler( IgnoreIceErrors ); 618 IceAddConnectionWatch( ICEWatchProc, NULL ); 619 #endif 620 } 621 } 622 623 void ICEConnectionObserver::deactivate() 624 { 625 if( bIsWatching ) 626 { 627 lock(); 628 bIsWatching = sal_False; 629 #ifdef USE_SM_EXTENSION 630 IceRemoveConnectionWatch( ICEWatchProc, NULL ); 631 IceSetErrorHandler( origErrorHandler ); 632 IceSetIOErrorHandler( origIOErrorHandler ); 633 #endif 634 nConnections = 0; 635 if( ICEThread ) 636 { 637 osl_terminateThread( ICEThread ); 638 wakeup(); 639 } 640 unlock(); 641 if( ICEThread ) 642 { 643 osl_joinWithThread( ICEThread ); 644 osl_destroyThread( ICEThread ); 645 close( nWakeupFiles[1] ); 646 close( nWakeupFiles[0] ); 647 ICEThread = NULL; 648 } 649 osl_destroyMutex( ICEMutex ); 650 ICEMutex = NULL; 651 } 652 } 653 654 void ICEConnectionObserver::wakeup() 655 { 656 char cChar = 'w'; 657 write( nWakeupFiles[1], &cChar, 1 ); 658 } 659 660 void ICEConnectionWorker( void* ) 661 { 662 #ifdef USE_SM_EXTENSION 663 while( osl_scheduleThread(ICEConnectionObserver::ICEThread) && ICEConnectionObserver::nConnections ) 664 { 665 ICEConnectionObserver::lock(); 666 int nConnectionsBefore = ICEConnectionObserver::nConnections; 667 int nBytes = sizeof( struct pollfd )*(nConnectionsBefore+1); 668 struct pollfd* pLocalFD = (struct pollfd*)rtl_allocateMemory( nBytes ); 669 rtl_copyMemory( pLocalFD, ICEConnectionObserver::pFilehandles, nBytes ); 670 ICEConnectionObserver::unlock(); 671 672 int nRet = poll( pLocalFD,nConnectionsBefore+1,-1 ); 673 bool bWakeup = (pLocalFD[0].revents & POLLIN); 674 rtl_freeMemory( pLocalFD ); 675 676 if( nRet < 1 ) 677 continue; 678 679 // clear wakeup pipe 680 if( bWakeup ) 681 { 682 char buf[4]; 683 while( read( ICEConnectionObserver::nWakeupFiles[0], buf, sizeof( buf ) ) > 0 ) 684 ; 685 SMprintf( "file handles active in wakeup: %d\n", nRet ); 686 if( nRet == 1 ) 687 continue; 688 } 689 690 // check fd's after we obtained the lock 691 ICEConnectionObserver::lock(); 692 if( ICEConnectionObserver::nConnections > 0 && ICEConnectionObserver::nConnections == nConnectionsBefore ) 693 { 694 nRet = poll( ICEConnectionObserver::pFilehandles+1, ICEConnectionObserver::nConnections, 0 ); 695 if( nRet > 0 ) 696 { 697 SMprintf( "IceProcessMessages\n" ); 698 Bool bReply; 699 for( int i = 0; i < ICEConnectionObserver::nConnections; i++ ) 700 if( ICEConnectionObserver::pFilehandles[i+1].revents & POLLIN ) 701 IceProcessMessages( ICEConnectionObserver::pConnections[i], NULL, &bReply ); 702 } 703 } 704 ICEConnectionObserver::unlock(); 705 } 706 #endif 707 SMprintf( "shutting donw ICE dispatch thread\n" ); 708 } 709 710 void ICEConnectionObserver::ICEWatchProc( 711 IceConn connection, 712 IcePointer, 713 Bool opening, 714 IcePointer* 715 ) 716 { 717 // note: this is a callback function for ICE 718 // this implicitly means that a call into ICE lib is calling this 719 // so the ICEMutex MUST already be locked by the caller 720 721 #ifdef USE_SM_EXTENSION 722 if( opening ) 723 { 724 int fd = IceConnectionNumber( connection ); 725 nConnections++; 726 pConnections = (IceConn*)rtl_reallocateMemory( pConnections, sizeof( IceConn )*nConnections ); 727 pFilehandles = (struct pollfd*)rtl_reallocateMemory( pFilehandles, sizeof( struct pollfd )*(nConnections+1) ); 728 pConnections[ nConnections-1 ] = connection; 729 pFilehandles[ nConnections ].fd = fd; 730 pFilehandles[ nConnections ].events = POLLIN; 731 if( nConnections == 1 ) 732 { 733 if( ! pipe( nWakeupFiles ) ) 734 { 735 int flags; 736 pFilehandles[0].fd = nWakeupFiles[0]; 737 pFilehandles[0].events = POLLIN; 738 // set close-on-exec and nonblock descriptor flag. 739 if ((flags = fcntl (nWakeupFiles[0], F_GETFD)) != -1) 740 { 741 flags |= FD_CLOEXEC; 742 fcntl (nWakeupFiles[0], F_SETFD, flags); 743 } 744 if ((flags = fcntl (nWakeupFiles[0], F_GETFL)) != -1) 745 { 746 flags |= O_NONBLOCK; 747 fcntl (nWakeupFiles[0], F_SETFL, flags); 748 } 749 // set close-on-exec and nonblock descriptor flag. 750 if ((flags = fcntl (nWakeupFiles[1], F_GETFD)) != -1) 751 { 752 flags |= FD_CLOEXEC; 753 fcntl (nWakeupFiles[1], F_SETFD, flags); 754 } 755 if ((flags = fcntl (nWakeupFiles[1], F_GETFL)) != -1) 756 { 757 flags |= O_NONBLOCK; 758 fcntl (nWakeupFiles[1], F_SETFL, flags); 759 } 760 ICEThread = osl_createSuspendedThread( ICEConnectionWorker, NULL ); 761 osl_resumeThread( ICEThread ); 762 } 763 } 764 } 765 else 766 { 767 for( int i = 0; i < nConnections; i++ ) 768 { 769 if( pConnections[i] == connection ) 770 { 771 if( i < nConnections-1 ) 772 { 773 rtl_moveMemory( pConnections+i, pConnections+i+1, sizeof( IceConn )*(nConnections-i-1) ); 774 rtl_moveMemory( pFilehandles+i+1, pFilehandles+i+2, sizeof( struct pollfd )*(nConnections-i-1) ); 775 } 776 nConnections--; 777 pConnections = (IceConn*)rtl_reallocateMemory( pConnections, sizeof( IceConn )*nConnections ); 778 pFilehandles = (struct pollfd*)rtl_reallocateMemory( pFilehandles, sizeof( struct pollfd )*(nConnections+1) ); 779 break; 780 } 781 } 782 if( nConnections == 0 && ICEThread ) 783 { 784 SMprintf( "terminating ICEThread\n" ); 785 osl_terminateThread( ICEThread ); 786 wakeup(); 787 // must release the mutex here 788 osl_releaseMutex( ICEMutex ); 789 osl_joinWithThread( ICEThread ); 790 osl_destroyThread( ICEThread ); 791 close( nWakeupFiles[1] ); 792 close( nWakeupFiles[0] ); 793 ICEThread = NULL; 794 } 795 } 796 SMprintf( "ICE connection on %d %s\n", 797 IceConnectionNumber( connection ), 798 opening ? "inserted" : "removed" ); 799 SMprintf( "Display connection is %d\n", ConnectionNumber( GetX11SalData()->GetDisplay()->GetDisplay() ) ); 800 #endif 801 } 802