1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
10 * $Revision: 1.33.90.1 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_vcl.hxx"
40 #include <osl/process.h>
41 #include <osl/security.h>
43 #include <tools/prex.h>
44 #include <X11/Xatom.h>
45 #include <tools/postx.h>
47 #include <saldata.hxx>
48 #include <saldisp.hxx>
50 #include <vcl/svapp.hxx>
51 #include <vcl/window.hxx>
54 #include <osl/conditn.h>
56 #define USE_SM_EXTENSION
58 #if OSL_DEBUG_LEVEL > 1
60 static bool bFirstAssert
= true;
63 #if OSL_DEBUG_LEVEL > 1
64 inline void SMprintf( const char* pFormat
, ... )
66 inline void SMprintf( const char*, ... )
69 #if OSL_DEBUG_LEVEL > 1
70 FILE* fp
= fopen( "/tmp/sessionlog.txt", bFirstAssert
? "w" : "a" );
74 va_start( ap
, pFormat
);
75 vfprintf( fp
, pFormat
, ap
);
81 static IceSalSession
* pOneInstance
= NULL
;
83 SalSession
* X11SalInstance::CreateSalSession()
86 pOneInstance
= new IceSalSession();
94 static X11SalFrame
* pOldStyleSaveFrame
= NULL
;
96 IceSalSession::IceSalSession()
100 IceSalSession::~IceSalSession()
102 if( pOneInstance
== this )
106 void IceSalSession::queryInteraction()
108 if( ! SessionManagerClient::queryInteraction() )
110 SalSessionInteractionEvent
aEvent( false );
111 CallCallback( &aEvent
);
115 void IceSalSession::interactionDone( bool bCancelShutdown
)
117 SessionManagerClient::interactionDone( bCancelShutdown
);
120 void IceSalSession::saveDone()
122 SessionManagerClient::saveDone();
123 if( pOldStyleSaveFrame
)
125 // note: does nothing if not running in generic plugin
126 X11SalFrame::SaveYourselfDone( pOldStyleSaveFrame
);
130 void IceSalSession::handleOldX11SaveYourself( SalFrame
* pFrame
)
133 if( ! pOldStyleSaveFrame
)
135 pOldStyleSaveFrame
= static_cast<X11SalFrame
*>(pFrame
);
138 SalSessionSaveRequestEvent
aEvent( true, false );
139 pOneInstance
->CallCallback( &aEvent
);
144 extern "C" void SAL_CALL
ICEConnectionWorker( void* );
146 class ICEConnectionObserver
148 friend void SAL_CALL
ICEConnectionWorker(void*);
149 static BOOL bIsWatching
;
150 static void ICEWatchProc( IceConn connection
, IcePointer client_data
,
151 Bool opening
, IcePointer
* watch_data
);
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
;
161 static void activate();
162 static void deactivate();
164 static void unlock();
165 static void wakeup();
169 SmcConn
SessionManagerClient::aSmcConnection
= NULL
;
170 ByteString
SessionManagerClient::aClientID
;
171 BOOL
ICEConnectionObserver::bIsWatching
= FALSE
;
172 struct pollfd
* ICEConnectionObserver::pFilehandles
= NULL
;
173 IceConn
* ICEConnectionObserver::pConnections
= NULL
;
174 int ICEConnectionObserver::nConnections
= 0;
175 oslMutex
ICEConnectionObserver::ICEMutex
= NULL
;
176 oslThread
ICEConnectionObserver::ICEThread
= NULL
;
177 int ICEConnectionObserver::nWakeupFiles
[2] = { 0, 0 };
180 bool SessionManagerClient::bDocSaveDone
= false;
182 bool SessionManagerClient::bSaveDoneSent
= false;
184 static SmProp
* pSmProps
= NULL
;
185 static SmProp
** ppSmProps
= NULL
;
186 static int nSmProps
= 0;
187 static unsigned char *pSmRestartHint
= NULL
;
190 static void BuildSmPropertyList()
194 ByteString
aExec( SessionManagerClient::getExecName(), osl_getThreadTextEncoding() );
197 pSmProps
= new SmProp
[ nSmProps
];
199 pSmProps
[ 0 ].name
= const_cast<char*>(SmCloneCommand
);
200 pSmProps
[ 0 ].type
= const_cast<char*>(SmLISTofARRAY8
);
201 pSmProps
[ 0 ].num_vals
= 1;
202 pSmProps
[ 0 ].vals
= new SmPropValue
;
203 pSmProps
[ 0 ].vals
->length
= aExec
.Len()+1;
204 pSmProps
[ 0 ].vals
->value
= strdup( aExec
.GetBuffer() );
206 pSmProps
[ 1 ].name
= const_cast<char*>(SmProgram
);
207 pSmProps
[ 1 ].type
= const_cast<char*>(SmARRAY8
);
208 pSmProps
[ 1 ].num_vals
= 1;
209 pSmProps
[ 1 ].vals
= new SmPropValue
;
210 pSmProps
[ 1 ].vals
->length
= aExec
.Len()+1;
211 pSmProps
[ 1 ].vals
->value
= strdup( aExec
.GetBuffer() );
213 pSmProps
[ 2 ].name
= const_cast<char*>(SmRestartCommand
);
214 pSmProps
[ 2 ].type
= const_cast<char*>(SmLISTofARRAY8
);
215 pSmProps
[ 2 ].num_vals
= 3;
216 pSmProps
[ 2 ].vals
= new SmPropValue
[3];
217 pSmProps
[ 2 ].vals
[0].length
= aExec
.Len()+1;
218 pSmProps
[ 2 ].vals
[0].value
= strdup( aExec
.GetBuffer() );
219 ByteString
aRestartOption( "-session=" );
220 aRestartOption
.Append( SessionManagerClient::getSessionID() );
221 pSmProps
[ 2 ].vals
[1].length
= aRestartOption
.Len()+1;
222 pSmProps
[ 2 ].vals
[1].value
= strdup( aRestartOption
.GetBuffer() );
223 ByteString
aRestartOptionNoLogo( "-nologo" );
224 pSmProps
[ 2 ].vals
[2].length
= aRestartOptionNoLogo
.Len()+1;
225 pSmProps
[ 2 ].vals
[2].value
= strdup( aRestartOptionNoLogo
.GetBuffer() );
227 rtl::OUString aUserName
;
229 oslSecurity aSec
= osl_getCurrentSecurity();
232 osl_getUserName( aSec
, &aUserName
.pData
);
233 aUser
= rtl::OUStringToOString( aUserName
, osl_getThreadTextEncoding() );
234 osl_freeSecurityHandle( aSec
);
237 pSmProps
[ 3 ].name
= const_cast<char*>(SmUserID
);
238 pSmProps
[ 3 ].type
= const_cast<char*>(SmARRAY8
);
239 pSmProps
[ 3 ].num_vals
= 1;
240 pSmProps
[ 3 ].vals
= new SmPropValue
;
241 pSmProps
[ 3 ].vals
->value
= strdup( aUser
.getStr() );
242 pSmProps
[ 3 ].vals
->length
= strlen( (char *)pSmProps
[ 3 ].vals
->value
)+1;
244 pSmProps
[ 4 ].name
= const_cast<char*>(SmRestartStyleHint
);
245 pSmProps
[ 4 ].type
= const_cast<char*>(SmCARD8
);
246 pSmProps
[ 4 ].num_vals
= 1;
247 pSmProps
[ 4 ].vals
= new SmPropValue
;
248 pSmProps
[ 4 ].vals
->value
= malloc(1);
249 pSmRestartHint
= (unsigned char *)pSmProps
[ 4 ].vals
->value
;
250 *pSmRestartHint
= SmRestartIfRunning
;
251 pSmProps
[ 4 ].vals
->length
= 1;
253 ppSmProps
= new SmProp
*[ nSmProps
];
254 for( int i
= 0; i
< nSmProps
; i
++ )
255 ppSmProps
[ i
] = &pSmProps
[i
];
259 bool SessionManagerClient::checkDocumentsSaved()
264 struct SaveYourselfArgs
{
267 int nInteractionStyle
;
270 IMPL_STATIC_LINK( SessionManagerClient
, SaveYourselfHdl
, void*, EMPTYARG
)
272 SMprintf( "posting save documents event shutdown = %s\n", (pThis
!=0) ? "true" : "false" );
274 static bool bFirstShutdown
=true;
275 if (pThis
!= 0 && bFirstShutdown
) //first shutdown request
277 bFirstShutdown
= false;
279 If we have no actual frames open, e.g. we launched a quickstarter,
280 and then shutdown all our frames leaving just a quickstarter running,
281 then we don't want to launch an empty toplevel frame on the next
282 start. (The job of scheduling the restart of the quick-starter is a
283 task of the quick-starter)
285 *pSmRestartHint
= SmRestartNever
;
286 const std::list
< SalFrame
* >& rFrames
= GetX11SalData()->GetDisplay()->getFrames();
287 for( std::list
< SalFrame
* >::const_iterator it
= rFrames
.begin(); it
!= rFrames
.end(); ++it
)
289 Window
*pWindow
= (*it
)->GetWindow();
290 if (pWindow
&& pWindow
->IsVisible())
292 *pSmRestartHint
= SmRestartIfRunning
;
300 SalSessionSaveRequestEvent
aEvent( aSaveYourselfArg
.bShutdown
, aSaveYourselfArg
.nInteractionStyle
== SmInteractStyleAny
&& !aSaveYourselfArg
.bFast
);
301 pOneInstance
->CallCallback( &aEvent
);
309 IMPL_STATIC_LINK_NOINSTANCE( SessionManagerClient
, InteractionHdl
, void*, EMPTYARG
)
311 SMprintf( "interaction link\n" );
315 SalSessionInteractionEvent
aEvent( true );
316 pOneInstance
->CallCallback( &aEvent
);
322 IMPL_STATIC_LINK_NOINSTANCE( SessionManagerClient
, ShutDownCancelHdl
, void*, EMPTYARG
)
324 SMprintf( "shutdown cancel\n" );
327 SalSessionShutdownCancelEvent aEvent
;
328 pOneInstance
->CallCallback( &aEvent
);
337 void SessionManagerClient::SaveYourselfProc(
346 SMprintf( "Session: save yourself, save_type = %s, shutdown = %s, interact_style = %s, fast = %s\n",
347 save_type
== SmSaveLocal
? "SmcSaveLocal" :
348 ( save_type
== SmSaveGlobal
? "SmcSaveGlobal" :
349 ( save_type
== SmSaveBoth
? "SmcSaveBoth" : "<unknown>" ) ),
350 shutdown
? "true" : "false",
351 interact_style
== SmInteractStyleNone
? "SmInteractStyleNone" :
352 ( interact_style
== SmInteractStyleErrors
? "SmInteractStyleErrors" :
353 ( interact_style
== SmInteractStyleAny
? "SmInteractStyleAny" : "<unknown>" ) ),
354 fast
? "true" : "false"
356 bSaveDoneSent
= false;
357 BuildSmPropertyList();
358 #ifdef USE_SM_EXTENSION
359 bDocSaveDone
= false;
360 /* #i49875# some session managers send a "die" message if the
361 * saveDone does not come early enough for their convenience
362 * this can occasionally happen on startup, especially the first
363 * startup. So shortcut the "not shutting down" case since the
364 * upper layers are currently not interested in that event anyway.
368 SessionManagerClient::saveDone();
372 aSaveYourselfArg
.bShutdown
= shutdown
;
373 aSaveYourselfArg
.nInteractionStyle
= interact_style
;
374 aSaveYourselfArg
.bFast
= fast
;
375 Application::PostUserEvent( STATIC_LINK( NULL
, SessionManagerClient
, SaveYourselfHdl
) );
377 SMprintf( "waiting for save yourself event to be processed\n" );
381 IMPL_STATIC_LINK_NOINSTANCE( SessionManagerClient
, ShutDownHdl
, void*, EMPTYARG
)
383 const std::list
< SalFrame
* >& rFrames
= GetX11SalData()->GetDisplay()->getFrames();
384 SMprintf( rFrames
.begin() != rFrames
.end() ? "shutdown on first frame\n" : "shutdown event but no frame\n" );
385 if( rFrames
.begin() != rFrames
.end() )
386 rFrames
.front()->CallCallback( SALEVENT_SHUTDOWN
, 0 );
390 void SessionManagerClient::DieProc(
395 SMprintf( "Session: die\n" );
396 if( connection
== aSmcConnection
)
398 Application::PostUserEvent( STATIC_LINK( NULL
, SessionManagerClient
, ShutDownHdl
) );
399 SMprintf( "waiting for shutdown event to be processed\n" );
403 void SessionManagerClient::SaveCompleteProc(
408 SMprintf( "Session: save complete\n" );
411 void SessionManagerClient::ShutdownCanceledProc(
415 SMprintf( "Session: shutdown canceled\n" );
416 if( connection
== aSmcConnection
)
417 Application::PostUserEvent( STATIC_LINK( NULL
, SessionManagerClient
, ShutDownCancelHdl
) );
420 void SessionManagerClient::InteractProc(
424 SMprintf( "Session: interaction request completed\n" );
425 if( connection
== aSmcConnection
)
426 Application::PostUserEvent( STATIC_LINK( NULL
, SessionManagerClient
, InteractionHdl
) );
429 void SessionManagerClient::saveDone( bool bSuccess
)
433 ICEConnectionObserver::lock();
435 SmcSetProperties( aSmcConnection
, nSmProps
, ppSmProps
);
436 SmcSaveYourselfDone( aSmcConnection
, bSuccess
);
437 SMprintf( "sent SaveYourselfDone SmRestartHint of %d\n", *pSmRestartHint
);
438 bDocSaveDone
= bSuccess
;
439 bSaveDoneSent
= true;
440 ICEConnectionObserver::unlock();
445 void SessionManagerClient::open()
447 static SmcCallbacks aCallbacks
;
449 #ifdef USE_SM_EXTENSION
450 // this is the way Xt does it, so we can too
451 if( ! aSmcConnection
&& getenv( "SESSION_MANAGER" ) )
454 ICEConnectionObserver::activate();
455 ICEConnectionObserver::lock();
457 char* pClientID
= NULL
;
458 const ByteString
& rPrevId( getPreviousSessionID() );
460 aCallbacks
.save_yourself
.callback
= SaveYourselfProc
;
461 aCallbacks
.save_yourself
.client_data
= NULL
;
462 aCallbacks
.die
.callback
= DieProc
;
463 aCallbacks
.die
.client_data
= NULL
;
464 aCallbacks
.save_complete
.callback
= SaveCompleteProc
;
465 aCallbacks
.save_complete
.client_data
= NULL
;
466 aCallbacks
.shutdown_cancelled
.callback
= ShutdownCanceledProc
;
467 aCallbacks
.shutdown_cancelled
.client_data
= NULL
;
468 aSmcConnection
= SmcOpenConnection( NULL
,
472 SmcSaveYourselfProcMask
|
474 SmcSaveCompleteProcMask
|
475 SmcShutdownCancelledProcMask
,
477 rPrevId
.Len() ? const_cast<char*>(rPrevId
.GetBuffer()) : NULL
,
481 if( ! aSmcConnection
)
482 SMprintf( "SmcOpenConnection failed: %s\n", aErrBuf
);
484 SMprintf( "SmcOpenConnection succeeded, client ID is \"%s\"\n", pClientID
);
485 aClientID
= ByteString( pClientID
);
488 ICEConnectionObserver::unlock();
490 SalDisplay
* pDisp
= GetX11SalData()->GetDisplay();
491 if( pDisp
->GetDrawable( pDisp
->GetDefaultScreenNumber() ) && aClientID
.Len() )
493 XChangeProperty( pDisp
->GetDisplay(),
494 pDisp
->GetDrawable( pDisp
->GetDefaultScreenNumber() ),
495 XInternAtom( pDisp
->GetDisplay(), "SM_CLIENT_ID", False
),
499 (unsigned char*)aClientID
.GetBuffer(),
504 else if( ! aSmcConnection
)
505 SMprintf( "no SESSION_MANAGER\n" );
509 const ByteString
& SessionManagerClient::getSessionID()
514 void SessionManagerClient::close()
518 #ifdef USE_SM_EXTENSION
519 ICEConnectionObserver::lock();
520 SMprintf( "attempting SmcCloseConnection\n" );
521 SmcCloseConnection( aSmcConnection
, 0, NULL
);
522 SMprintf( "SmcConnection closed\n" );
523 ICEConnectionObserver::unlock();
524 ICEConnectionObserver::deactivate();
526 aSmcConnection
= NULL
;
530 bool SessionManagerClient::queryInteraction()
535 ICEConnectionObserver::lock();
536 if( SmcInteractRequest( aSmcConnection
, SmDialogNormal
, InteractProc
, NULL
) )
538 ICEConnectionObserver::unlock();
543 void SessionManagerClient::interactionDone( bool bCancelShutdown
)
547 ICEConnectionObserver::lock();
548 SmcInteractDone( aSmcConnection
, bCancelShutdown
);
549 ICEConnectionObserver::unlock();
554 String
SessionManagerClient::getExecName()
556 rtl::OUString aExec
, aSysExec
;
557 osl_getExecutableFile( &aExec
.pData
);
558 osl_getSystemPathFromFileURL( aExec
.pData
, &aSysExec
.pData
);
560 int nPos
= aSysExec
.indexOf( rtl::OUString::createFromAscii( ".bin" ) );
562 aSysExec
= aSysExec
.copy( 0, nPos
);
567 const ByteString
& SessionManagerClient::getPreviousSessionID()
569 static ByteString aPrevId
;
571 int nCommands
= osl_getCommandArgCount();
572 for( int i
= 0; i
< nCommands
; i
++ )
574 ::rtl::OUString aArg
;
575 osl_getCommandArg( i
, &aArg
.pData
);
576 if( aArg
.compareToAscii( "-session=", 9 ) == 0 )
578 aPrevId
= ByteString( ::rtl::OUStringToOString( aArg
.copy( 9 ), osl_getThreadTextEncoding() ) );
582 SMprintf( "previous ID = \"%s\"\n", aPrevId
.GetBuffer() );
586 void ICEConnectionObserver::lock()
588 osl_acquireMutex( ICEMutex
);
591 void ICEConnectionObserver::unlock()
593 osl_releaseMutex( ICEMutex
);
596 void ICEConnectionObserver::activate()
600 nWakeupFiles
[0] = nWakeupFiles
[1] = 0;
601 ICEMutex
= osl_createMutex();
603 #ifdef USE_SM_EXTENSION
604 IceAddConnectionWatch( ICEWatchProc
, NULL
);
609 void ICEConnectionObserver::deactivate()
615 #ifdef USE_SM_EXTENSION
616 IceRemoveConnectionWatch( ICEWatchProc
, NULL
);
621 osl_terminateThread( ICEThread
);
627 osl_joinWithThread( ICEThread
);
628 osl_destroyThread( ICEThread
);
629 close( nWakeupFiles
[1] );
630 close( nWakeupFiles
[0] );
633 osl_destroyMutex( ICEMutex
);
638 void ICEConnectionObserver::wakeup()
641 write( nWakeupFiles
[1], &cChar
, 1 );
644 void ICEConnectionWorker( void* )
646 #ifdef USE_SM_EXTENSION
647 while( osl_scheduleThread(ICEConnectionObserver::ICEThread
) && ICEConnectionObserver::nConnections
)
649 ICEConnectionObserver::lock();
650 int nConnectionsBefore
= ICEConnectionObserver::nConnections
;
651 int nBytes
= sizeof( struct pollfd
)*(nConnectionsBefore
+1);
652 struct pollfd
* pLocalFD
= (struct pollfd
*)rtl_allocateMemory( nBytes
);
653 rtl_copyMemory( pLocalFD
, ICEConnectionObserver::pFilehandles
, nBytes
);
654 ICEConnectionObserver::unlock();
656 int nRet
= poll( pLocalFD
,nConnectionsBefore
+1,-1 );
657 bool bWakeup
= (pLocalFD
[0].revents
& POLLIN
);
658 rtl_freeMemory( pLocalFD
);
667 while( read( ICEConnectionObserver::nWakeupFiles
[0], buf
, sizeof( buf
) ) > 0 )
669 SMprintf( "file handles active in wakeup: %d\n", nRet
);
674 // check fd's after we obtained the lock
675 ICEConnectionObserver::lock();
676 if( ICEConnectionObserver::nConnections
> 0 && ICEConnectionObserver::nConnections
== nConnectionsBefore
)
678 nRet
= poll( ICEConnectionObserver::pFilehandles
+1, ICEConnectionObserver::nConnections
, 0 );
681 SMprintf( "IceProcessMessages\n" );
683 for( int i
= 0; i
< ICEConnectionObserver::nConnections
; i
++ )
684 if( ICEConnectionObserver::pFilehandles
[i
+1].revents
& POLLIN
)
685 IceProcessMessages( ICEConnectionObserver::pConnections
[i
], NULL
, &bReply
);
688 ICEConnectionObserver::unlock();
691 SMprintf( "shutting donw ICE dispatch thread\n" );
694 void ICEConnectionObserver::ICEWatchProc(
701 // note: this is a callback function for ICE
702 // this implicitly means that a call into ICE lib is calling this
703 // so the ICEMutex MUST already be locked by the caller
705 #ifdef USE_SM_EXTENSION
708 int fd
= IceConnectionNumber( connection
);
710 pConnections
= (IceConn
*)rtl_reallocateMemory( pConnections
, sizeof( IceConn
)*nConnections
);
711 pFilehandles
= (struct pollfd
*)rtl_reallocateMemory( pFilehandles
, sizeof( struct pollfd
)*(nConnections
+1) );
712 pConnections
[ nConnections
-1 ] = connection
;
713 pFilehandles
[ nConnections
].fd
= fd
;
714 pFilehandles
[ nConnections
].events
= POLLIN
;
715 if( nConnections
== 1 )
717 if( ! pipe( nWakeupFiles
) )
720 pFilehandles
[0].fd
= nWakeupFiles
[0];
721 pFilehandles
[0].events
= POLLIN
;
722 // set close-on-exec and nonblock descriptor flag.
723 if ((flags
= fcntl (nWakeupFiles
[0], F_GETFD
)) != -1)
726 fcntl (nWakeupFiles
[0], F_SETFD
, flags
);
728 if ((flags
= fcntl (nWakeupFiles
[0], F_GETFL
)) != -1)
731 fcntl (nWakeupFiles
[0], F_SETFL
, flags
);
733 // set close-on-exec and nonblock descriptor flag.
734 if ((flags
= fcntl (nWakeupFiles
[1], F_GETFD
)) != -1)
737 fcntl (nWakeupFiles
[1], F_SETFD
, flags
);
739 if ((flags
= fcntl (nWakeupFiles
[1], F_GETFL
)) != -1)
742 fcntl (nWakeupFiles
[1], F_SETFL
, flags
);
744 ICEThread
= osl_createSuspendedThread( ICEConnectionWorker
, NULL
);
745 osl_resumeThread( ICEThread
);
751 for( int i
= 0; i
< nConnections
; i
++ )
753 if( pConnections
[i
] == connection
)
755 if( i
< nConnections
-1 )
757 rtl_moveMemory( pConnections
+i
, pConnections
+i
+1, sizeof( IceConn
)*(nConnections
-i
-1) );
758 rtl_moveMemory( pFilehandles
+i
+1, pFilehandles
+i
+2, sizeof( struct pollfd
)*(nConnections
-i
-1) );
761 pConnections
= (IceConn
*)rtl_reallocateMemory( pConnections
, sizeof( IceConn
)*nConnections
);
762 pFilehandles
= (struct pollfd
*)rtl_reallocateMemory( pFilehandles
, sizeof( struct pollfd
)*(nConnections
+1) );
766 if( nConnections
== 0 && ICEThread
)
768 SMprintf( "terminating ICEThread\n" );
769 osl_terminateThread( ICEThread
);
771 // must release the mutex here
772 osl_releaseMutex( ICEMutex
);
773 osl_joinWithThread( ICEThread
);
774 osl_destroyThread( ICEThread
);
775 close( nWakeupFiles
[1] );
776 close( nWakeupFiles
[0] );
780 SMprintf( "ICE connection on %d %s\n",
781 IceConnectionNumber( connection
),
782 opening
? "inserted" : "removed" );
783 SMprintf( "Display connection is %d\n", ConnectionNumber( GetX11SalData()->GetDisplay()->GetDisplay() ) );