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