1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <sal/config.h>
30 #include <rtl/strbuf.hxx>
31 #include <sal/log.hxx>
33 #include <rtl/process.h>
34 #include <osl/security.h>
37 #include <X11/Xatom.h>
40 #include <unx/saldisp.hxx>
41 #include <unx/salinst.h>
43 #include <vcl/svapp.hxx>
44 #include <vcl/window.hxx>
46 #include <salframe.hxx>
47 #include <salsession.hxx>
51 class IceSalSession
: public SalSession
57 virtual ~IceSalSession() override
{}
59 virtual void queryInteraction() override
;
60 virtual void interactionDone() override
;
61 virtual void saveDone() override
;
62 virtual bool cancelShutdown() override
;
67 std::unique_ptr
<SalSession
> X11SalInstance::CreateSalSession()
69 SAL_INFO("vcl.sm", "X11SalInstance::CreateSalSession");
71 std::unique_ptr
<SalSession
> p(new IceSalSession
);
72 SessionManagerClient::open(p
.get());
76 void IceSalSession::queryInteraction()
78 SAL_INFO("vcl.sm", "IceSalSession::queryInteraction");
80 if( ! SessionManagerClient::queryInteraction() )
82 SAL_INFO("vcl.sm.debug", " call SalSessionInteractionEvent");
83 SalSessionInteractionEvent
aEvent( false );
84 CallCallback( &aEvent
);
88 void IceSalSession::interactionDone()
90 SAL_INFO("vcl.sm", "IceSalSession::interactionDone");
92 SessionManagerClient::interactionDone( false );
95 void IceSalSession::saveDone()
97 SAL_INFO("vcl.sm", "IceSalSession::saveDone");
99 SessionManagerClient::saveDone();
102 bool IceSalSession::cancelShutdown()
104 SAL_INFO("vcl.sm", "IceSalSession::cancelShutdown");
106 SessionManagerClient::interactionDone( true );
112 static void ICEWatchProc(
113 IceConn ice_conn
, IcePointer client_data
, Bool opening
,
114 IcePointer
* watch_data
);
116 static void ICEConnectionWorker(void * data
);
120 class ICEConnectionObserver
122 friend void ICEWatchProc(IceConn
, IcePointer
, Bool
, IcePointer
*);
124 friend void ICEConnectionWorker(void *);
126 struct pollfd
* m_pFilehandles
;
128 IceConn
* m_pConnections
;
129 int m_nWakeupFiles
[2];
130 oslThread m_ICEThread
;
131 IceIOErrorHandler m_origIOErrorHandler
;
132 IceErrorHandler m_origErrorHandler
;
137 osl::Mutex m_ICEMutex
;
139 ICEConnectionObserver()
140 : m_pFilehandles(nullptr)
142 , m_pConnections(nullptr)
143 , m_ICEThread(nullptr)
144 , m_origIOErrorHandler(nullptr)
145 , m_origErrorHandler(nullptr)
147 SAL_INFO("vcl.sm", "ICEConnectionObserver::ICEConnectionObserver");
149 m_nWakeupFiles
[0] = m_nWakeupFiles
[1] = 0;
154 void terminate(oslThread iceThread
);
157 SalSession
* SessionManagerClient::m_pSession
= nullptr;
158 std::unique_ptr
< ICEConnectionObserver
>
159 SessionManagerClient::m_xICEConnectionObserver
;
160 SmcConn
SessionManagerClient::m_pSmcConnection
= nullptr;
161 OString
SessionManagerClient::m_aClientID
= "";
162 OString
SessionManagerClient::m_aTimeID
= "";
163 OString
SessionManagerClient::m_aClientTimeID
= "";
164 bool SessionManagerClient::m_bDocSaveDone
= false; // HACK
168 static void IgnoreIceErrors(
169 SAL_UNUSED_PARAMETER IceConn
, SAL_UNUSED_PARAMETER Bool
,
170 SAL_UNUSED_PARAMETER
int, SAL_UNUSED_PARAMETER
unsigned long,
171 SAL_UNUSED_PARAMETER
int, SAL_UNUSED_PARAMETER
int,
172 SAL_UNUSED_PARAMETER IcePointer
)
175 static void IgnoreIceIOErrors(SAL_UNUSED_PARAMETER IceConn
) {}
179 static SmProp
* pSmProps
= nullptr;
180 static SmProp
** ppSmProps
= nullptr;
181 static char ** ppSmDel
= nullptr;
183 static int nSmProps
= 0;
184 static int nSmDel
= 0;
185 static unsigned char *pSmRestartHint
= nullptr;
188 enum { eCloneCommand
, eProgram
, eRestartCommand
, eUserId
, eRestartStyleHint
};
189 enum { eDiscardCommand
};
192 static void BuildSmPropertyList()
194 SAL_INFO("vcl.sm", "BuildSmPropertyList");
200 pSmProps
= new SmProp
[ nSmProps
];
201 ppSmProps
= new SmProp
*[ nSmProps
];
202 ppSmDel
= new char*[ nSmDel
];
205 OString
aExec(OUStringToOString(SessionManagerClient::getExecName(), osl_getThreadTextEncoding()));
207 pSmProps
[ eCloneCommand
].name
= const_cast<char*>(SmCloneCommand
);
208 pSmProps
[ eCloneCommand
].type
= const_cast<char*>(SmLISTofARRAY8
);
209 pSmProps
[ eCloneCommand
].num_vals
= 1;
210 pSmProps
[ eCloneCommand
].vals
= new SmPropValue
;
211 pSmProps
[ eCloneCommand
].vals
->length
= aExec
.getLength()+1;
212 pSmProps
[ eCloneCommand
].vals
->value
= strdup( aExec
.getStr() );
214 pSmProps
[ eProgram
].name
= const_cast<char*>(SmProgram
);
215 pSmProps
[ eProgram
].type
= const_cast<char*>(SmARRAY8
);
216 pSmProps
[ eProgram
].num_vals
= 1;
217 pSmProps
[ eProgram
].vals
= new SmPropValue
;
218 pSmProps
[ eProgram
].vals
->length
= aExec
.getLength()+1;
219 pSmProps
[ eProgram
].vals
->value
= strdup( aExec
.getStr() );
221 pSmProps
[ eRestartCommand
].name
= const_cast<char*>(SmRestartCommand
);
222 pSmProps
[ eRestartCommand
].type
= const_cast<char*>(SmLISTofARRAY8
);
223 pSmProps
[ eRestartCommand
].num_vals
= 3;
224 pSmProps
[ eRestartCommand
].vals
= new SmPropValue
[3];
225 pSmProps
[ eRestartCommand
].vals
[0].length
= aExec
.getLength()+1;
226 pSmProps
[ eRestartCommand
].vals
[0].value
= strdup( aExec
.getStr() );
227 OString aRestartOption
= "--session=" + SessionManagerClient::getSessionID();
228 pSmProps
[ eRestartCommand
].vals
[1].length
= aRestartOption
.getLength()+1;
229 pSmProps
[ eRestartCommand
].vals
[1].value
= strdup(aRestartOption
.getStr());
230 OString
aRestartOptionNoLogo("--nologo");
231 pSmProps
[ eRestartCommand
].vals
[2].length
= aRestartOptionNoLogo
.getLength()+1;
232 pSmProps
[ eRestartCommand
].vals
[2].value
= strdup(aRestartOptionNoLogo
.getStr());
236 oslSecurity aSec
= osl_getCurrentSecurity();
239 osl_getUserName( aSec
, &aUserName
.pData
);
240 aUser
= OUStringToOString( aUserName
, osl_getThreadTextEncoding() );
241 osl_freeSecurityHandle( aSec
);
244 pSmProps
[ eUserId
].name
= const_cast<char*>(SmUserID
);
245 pSmProps
[ eUserId
].type
= const_cast<char*>(SmARRAY8
);
246 pSmProps
[ eUserId
].num_vals
= 1;
247 pSmProps
[ eUserId
].vals
= new SmPropValue
;
248 pSmProps
[ eUserId
].vals
->value
= strdup( aUser
.getStr() );
249 pSmProps
[ eUserId
].vals
->length
= rtl_str_getLength( static_cast<char *>(pSmProps
[ 3 ].vals
->value
) )+1;
251 pSmProps
[ eRestartStyleHint
].name
= const_cast<char*>(SmRestartStyleHint
);
252 pSmProps
[ eRestartStyleHint
].type
= const_cast<char*>(SmCARD8
);
253 pSmProps
[ eRestartStyleHint
].num_vals
= 1;
254 pSmProps
[ eRestartStyleHint
].vals
= new SmPropValue
;
255 pSmProps
[ eRestartStyleHint
].vals
->value
= malloc(1);
256 pSmRestartHint
= static_cast<unsigned char *>(pSmProps
[ 4 ].vals
->value
);
257 *pSmRestartHint
= SmRestartIfRunning
;
258 pSmProps
[ eRestartStyleHint
].vals
->length
= 1;
260 for( int i
= 0; i
< nSmProps
; i
++ )
261 ppSmProps
[ i
] = &pSmProps
[i
];
263 ppSmDel
[eDiscardCommand
] = const_cast<char*>(SmDiscardCommand
);
266 bool SessionManagerClient::checkDocumentsSaved()
268 SAL_INFO("vcl.sm", "SessionManagerClient::checkDocumentsSaved");
270 SAL_INFO("vcl.sm.debug", " m_bcheckDocumentsSaved = " << (m_bDocSaveDone
? "true" : "false" ));
271 return m_bDocSaveDone
;
274 IMPL_STATIC_LINK( SessionManagerClient
, SaveYourselfHdl
, void*, pStateVal
, void )
276 SAL_INFO("vcl.sm", "SessionManagerClient, SaveYourselfHdl");
278 // Decode argument smuggled in as void*:
279 sal_uIntPtr nStateVal
= reinterpret_cast< sal_uIntPtr
>(pStateVal
);
280 bool shutdown
= nStateVal
!= 0;
282 static bool bFirstShutdown
=true;
284 SAL_INFO("vcl.sm.debug", " shutdown = " << (shutdown
? "true" : "false" ) <<
285 ", bFirstShutdown = " << (bFirstShutdown
? "true" : "false" ));
286 if (shutdown
&& bFirstShutdown
) //first shutdown request
288 bFirstShutdown
= false;
290 If we have no actual frames open, e.g. we launched a quickstarter,
291 and then shutdown all our frames leaving just a quickstarter running,
292 then we don't want to launch an empty toplevel frame on the next
293 start. (The job of scheduling the restart of the quick-starter is a
294 task of the quick-starter)
296 *pSmRestartHint
= SmRestartNever
;
297 for (auto pSalFrame
: vcl_sal::getSalDisplay(GetGenericUnixSalData())->getFrames() )
299 vcl::Window
*pWindow
= pSalFrame
->GetWindow();
300 if (pWindow
&& pWindow
->IsVisible())
302 *pSmRestartHint
= SmRestartIfRunning
;
303 SAL_INFO("vcl.sm.debug", " pSmRestartHint = SmRestartIfRunning");
311 SalSessionSaveRequestEvent
aEvent( shutdown
);
312 m_pSession
->CallCallback( &aEvent
);
318 IMPL_STATIC_LINK_NOARG( SessionManagerClient
, InteractionHdl
, void*, void )
320 SAL_INFO("vcl.sm", "SessionManagerClient, InteractionHdl");
324 SalSessionInteractionEvent
aEvent( true );
325 m_pSession
->CallCallback( &aEvent
);
329 IMPL_STATIC_LINK_NOARG( SessionManagerClient
, ShutDownCancelHdl
, void*, void )
331 SAL_INFO("vcl.sm", "SessionManagerClient, ShutDownCancelHdl");
335 SalSessionShutdownCancelEvent aEvent
;
336 m_pSession
->CallCallback( &aEvent
);
340 void SessionManagerClient::SaveYourselfProc(
349 SAL_INFO("vcl.sm", "SessionManagerClient::SaveYourselfProc");
352 osl_getSystemTime(&now
);
354 SAL_INFO("vcl.sm", " save_type = " << ((save_type
== SmSaveLocal
) ? "local" :
355 (save_type
== SmSaveGlobal
) ? "global" : "both") <<
356 ", shutdown = " << (shutdown
? "true" : "false" ) <<
357 ", interact_style = " << ((interact_style
== SmInteractStyleNone
) ? "SmInteractStyleNone" :
358 (interact_style
== SmInteractStyleErrors
) ? "SmInteractStyleErrors" :
359 "SmInteractStyleAny"));
361 snprintf(num
, sizeof(num
), "_%" SAL_PRIuUINT32
"_%" SAL_PRIuUINT32
, now
.Seconds
, (now
.Nanosec
/ 1001));
362 m_aTimeID
= OString(num
);
364 BuildSmPropertyList();
366 SmcSetProperties( m_pSmcConnection
, 1, &ppSmProps
[ eProgram
] );
367 SmcSetProperties( m_pSmcConnection
, 1, &ppSmProps
[ eUserId
] );
370 m_bDocSaveDone
= false;
371 /* #i49875# some session managers send a "die" message if the
372 * saveDone does not come early enough for their convenience
373 * this can occasionally happen on startup, especially the first
374 * startup. So shortcut the "not shutting down" case since the
375 * upper layers are currently not interested in that event anyway.
379 SessionManagerClient::saveDone();
382 // Smuggle argument in as void*:
383 sal_uIntPtr nStateVal
= shutdown
;
384 Application::PostUserEvent( LINK( nullptr, SessionManagerClient
, SaveYourselfHdl
), reinterpret_cast< void * >(nStateVal
) );
387 IMPL_STATIC_LINK_NOARG( SessionManagerClient
, ShutDownHdl
, void*, void )
389 SAL_INFO("vcl.sm", "SessionManagerClient, ShutDownHdl");
393 SalSessionQuitEvent aEvent
;
394 m_pSession
->CallCallback( &aEvent
);
397 SalFrame
*pAnyFrame
= vcl_sal::getSalDisplay(GetGenericUnixSalData())->anyFrame();
398 SAL_INFO("vcl.sm.debug", " rFrames.empty() = " << (pAnyFrame
? "true" : "false"));
400 pAnyFrame
->CallCallback( SalEvent::Shutdown
, nullptr );
403 void SessionManagerClient::DieProc(
408 SAL_INFO("vcl.sm", "SessionManagerClient::DieProc");
410 if( connection
== m_pSmcConnection
)
412 SAL_INFO("vcl.sm.debug", " connection == m_pSmcConnection" );
413 Application::PostUserEvent( LINK( nullptr, SessionManagerClient
, ShutDownHdl
) );
417 void SessionManagerClient::SaveCompleteProc(
422 SAL_INFO("vcl.sm", "SessionManagerClient::SaveCompleteProc");
425 void SessionManagerClient::ShutdownCanceledProc(
429 SAL_INFO("vcl.sm", "SessionManagerClient::ShutdownCanceledProc" );
431 SAL_INFO("vcl.sm.debug", " connection == m_pSmcConnection = " << (( connection
== m_pSmcConnection
) ? "true" : "false"));
432 if( connection
== m_pSmcConnection
)
433 Application::PostUserEvent( LINK( nullptr, SessionManagerClient
, ShutDownCancelHdl
) );
436 void SessionManagerClient::InteractProc(
440 SAL_INFO("vcl.sm", "SessionManagerClient::InteractProc" );
442 SAL_INFO("vcl.sm.debug", " connection == m_pSmcConnection = " << (( connection
== m_pSmcConnection
) ? "true" : "false"));
443 if( connection
== m_pSmcConnection
)
444 Application::PostUserEvent( LINK( nullptr, SessionManagerClient
, InteractionHdl
) );
447 void SessionManagerClient::saveDone()
449 SAL_INFO("vcl.sm", "SessionManagerClient::saveDone");
451 if( !m_pSmcConnection
)
454 assert(m_xICEConnectionObserver
);
455 osl::MutexGuard
g(m_xICEConnectionObserver
->m_ICEMutex
);
456 //SmcSetProperties( m_pSmcConnection, 1, &ppSmProps[ eCloneCommand ] );
457 // this message-handling is now equal to kate and plasma desktop
458 SmcSetProperties( m_pSmcConnection
, 1, &ppSmProps
[ eRestartCommand
] );
459 SmcDeleteProperties( m_pSmcConnection
, 1, &ppSmDel
[ eDiscardCommand
] );
460 SmcSetProperties( m_pSmcConnection
, 1, &ppSmProps
[ eRestartStyleHint
] );
462 SmcSaveYourselfDone( m_pSmcConnection
, True
);
463 SAL_INFO("vcl.sm.debug", " sent SmRestartHint = " << (*pSmRestartHint
) );
464 m_bDocSaveDone
= true;
467 void SessionManagerClient::open(SalSession
* pSession
)
469 SAL_INFO("vcl.sm", "SessionManagerClient::open");
471 assert(!m_pSession
&& !m_xICEConnectionObserver
&& !m_pSmcConnection
);
472 // must only be called once
473 m_pSession
= pSession
;
474 // This is the way Xt does it, so we can too:
475 if( getenv( "SESSION_MANAGER" ) )
477 SAL_INFO("vcl.sm.debug", " getenv( SESSION_MANAGER ) = true");
478 m_xICEConnectionObserver
.reset(new ICEConnectionObserver
);
479 m_xICEConnectionObserver
->activate();
482 osl::MutexGuard
g(m_xICEConnectionObserver
->m_ICEMutex
);
484 static SmcCallbacks aCallbacks
; // does this need to be static?
485 aCallbacks
.save_yourself
.callback
= SaveYourselfProc
;
486 aCallbacks
.save_yourself
.client_data
= nullptr;
487 aCallbacks
.die
.callback
= DieProc
;
488 aCallbacks
.die
.client_data
= nullptr;
489 aCallbacks
.save_complete
.callback
= SaveCompleteProc
;
490 aCallbacks
.save_complete
.client_data
= nullptr;
491 aCallbacks
.shutdown_cancelled
.callback
= ShutdownCanceledProc
;
492 aCallbacks
.shutdown_cancelled
.client_data
= nullptr;
493 OString
aPrevId(getPreviousSessionID());
494 char* pClientID
= nullptr;
496 m_pSmcConnection
= SmcOpenConnection( nullptr,
500 SmcSaveYourselfProcMask
|
502 SmcSaveCompleteProcMask
|
503 SmcShutdownCancelledProcMask
,
505 aPrevId
.isEmpty() ? nullptr : const_cast<char*>(aPrevId
.getStr()),
509 if( !m_pSmcConnection
)
510 SAL_INFO("vcl.sm.debug", " SmcOpenConnection failed: " << aErrBuf
);
512 SAL_INFO("vcl.sm.debug", " SmcOpenConnection succeeded, client ID is " << pClientID
);
513 m_aClientID
= OString(pClientID
);
518 SalDisplay
* pDisp
= vcl_sal::getSalDisplay(GetGenericUnixSalData());
519 if( pDisp
->GetDrawable(pDisp
->GetDefaultXScreen()) && !m_aClientID
.isEmpty() )
521 SAL_INFO("vcl.sm.debug", " SmcOpenConnection open: pDisp->GetDrawable = true");
522 XChangeProperty( pDisp
->GetDisplay(),
523 pDisp
->GetDrawable( pDisp
->GetDefaultXScreen() ),
524 XInternAtom( pDisp
->GetDisplay(), "SM_CLIENT_ID", False
),
528 reinterpret_cast<unsigned char const *>(m_aClientID
.getStr()),
529 m_aClientID
.getLength()
535 SAL_INFO("vcl.sm.debug", " getenv( SESSION_MANAGER ) = false");
539 const OString
& SessionManagerClient::getSessionID()
541 SAL_INFO("vcl.sm", "SessionManagerClient::getSessionID");
543 m_aClientTimeID
= m_aClientID
+ m_aTimeID
;
545 SAL_INFO("vcl.sm", " SessionID = " << m_aClientTimeID
);
547 return m_aClientTimeID
;
550 void SessionManagerClient::close()
552 SAL_INFO("vcl.sm", "SessionManagerClient::close");
554 if( !m_pSmcConnection
)
557 SAL_INFO("vcl.sm.debug", " attempting SmcCloseConnection");
558 assert(m_xICEConnectionObserver
);
560 osl::MutexGuard
g(m_xICEConnectionObserver
->m_ICEMutex
);
561 SmcCloseConnection( m_pSmcConnection
, 0, nullptr );
562 SAL_INFO("vcl.sm", " SmcCloseConnection closed");
564 m_xICEConnectionObserver
->deactivate();
565 m_xICEConnectionObserver
.reset();
566 m_pSmcConnection
= nullptr;
569 bool SessionManagerClient::queryInteraction()
571 SAL_INFO("vcl.sm", "SessionManagerClient::queryInteraction");
574 if( m_pSmcConnection
)
576 assert(m_xICEConnectionObserver
);
577 osl::MutexGuard
g(m_xICEConnectionObserver
->m_ICEMutex
);
578 SAL_INFO("vcl.sm.debug", " SmcInteractRequest" );
579 if( SmcInteractRequest( m_pSmcConnection
, SmDialogNormal
, InteractProc
, nullptr ) )
585 void SessionManagerClient::interactionDone( bool bCancelShutdown
)
587 SAL_INFO("vcl.sm", "SessionManagerClient::interactionDone");
589 if( m_pSmcConnection
)
591 assert(m_xICEConnectionObserver
);
592 osl::MutexGuard
g(m_xICEConnectionObserver
->m_ICEMutex
);
593 SAL_INFO("vcl.sm.debug", " SmcInteractDone = " << (bCancelShutdown
? "true" : "false") );
594 SmcInteractDone( m_pSmcConnection
, bCancelShutdown
? True
: False
);
598 OUString
SessionManagerClient::getExecName()
600 SAL_INFO("vcl.sm", "SessionManagerClient::getExecName");
602 OUString aExec
, aSysExec
;
603 osl_getExecutableFile( &aExec
.pData
);
604 osl_getSystemPathFromFileURL( aExec
.pData
, &aSysExec
.pData
);
606 if( aSysExec
.endsWith(".bin") )
607 aSysExec
= aSysExec
.copy( 0, aSysExec
.getLength() - RTL_CONSTASCII_LENGTH(".bin") );
609 SAL_INFO("vcl.sm.debug", " aSysExec = " << aSysExec
);
613 OString
SessionManagerClient::getPreviousSessionID()
615 SAL_INFO("vcl.sm", "SessionManagerClient::getPreviousSessionID");
619 sal_uInt32 n
= rtl_getAppCommandArgCount();
620 for (sal_uInt32 i
= 0; i
!= n
; ++i
)
623 rtl_getAppCommandArg( i
, &aArg
.pData
);
624 if(aArg
.match("--session="))
626 aPrevId
= OUStringToOString(
627 aArg
.subView(RTL_CONSTASCII_LENGTH("--session=")),
628 osl_getThreadTextEncoding());
633 SAL_INFO("vcl.sm.debug", " previous ID = " << aPrevId
);
637 void ICEConnectionObserver::activate()
639 SAL_INFO("vcl.sm", "ICEConnectionObserver::activate");
642 * Default handlers call exit, we don't care that strongly if something
645 m_origIOErrorHandler
= IceSetIOErrorHandler( IgnoreIceIOErrors
);
646 m_origErrorHandler
= IceSetErrorHandler( IgnoreIceErrors
);
647 IceAddConnectionWatch( ICEWatchProc
, this );
650 void ICEConnectionObserver::deactivate()
652 SAL_INFO("vcl.sm", "ICEConnectionObserver::deactivate");
656 osl::MutexGuard
g(m_ICEMutex
);
657 IceRemoveConnectionWatch( ICEWatchProc
, this );
658 IceSetErrorHandler( m_origErrorHandler
);
659 IceSetIOErrorHandler( m_origIOErrorHandler
);
662 m_ICEThread
= nullptr;
666 SAL_INFO("vcl.sm.debug", " terminate");
671 void ICEConnectionObserver::wakeup()
673 SAL_INFO("vcl.sm", "ICEConnectionObserver::wakeup");
676 OSL_VERIFY(write(m_nWakeupFiles
[1], &cChar
, 1) == 1);
679 void ICEConnectionObserver::terminate(oslThread iceThread
)
681 SAL_INFO("vcl.sm", "ICEConnectionObserver::terminate");
683 osl_terminateThread(iceThread
);
685 osl_joinWithThread(iceThread
);
686 osl_destroyThread(iceThread
);
687 close(m_nWakeupFiles
[1]);
688 close(m_nWakeupFiles
[0]);
691 void ICEConnectionWorker(void * data
)
693 SAL_INFO("vcl.sm", "ICEConnectionWorker");
695 osl::Thread::setName("ICEConnectionWorker");
696 ICEConnectionObserver
* pThis
= static_cast< ICEConnectionObserver
* >(
702 osl::MutexGuard
g(pThis
->m_ICEMutex
);
703 if (pThis
->m_ICEThread
== nullptr || pThis
->m_nConnections
== 0)
707 t
= pThis
->m_ICEThread
;
709 if (!osl_scheduleThread(t
))
714 int nConnectionsBefore
;
715 struct pollfd
* pLocalFD
;
717 osl::MutexGuard
g(pThis
->m_ICEMutex
);
718 nConnectionsBefore
= pThis
->m_nConnections
;
719 int nBytes
= sizeof( struct pollfd
)*(nConnectionsBefore
+1);
720 pLocalFD
= static_cast<struct pollfd
*>(std::malloc( nBytes
));
721 memcpy( pLocalFD
, pThis
->m_pFilehandles
, nBytes
);
724 int nRet
= poll( pLocalFD
,nConnectionsBefore
+1,-1 );
725 bool bWakeup
= (pLocalFD
[0].revents
& POLLIN
);
726 std::free( pLocalFD
);
735 while( read( pThis
->m_nWakeupFiles
[0], buf
, sizeof( buf
) ) > 0 )
737 SAL_INFO("vcl.sm.debug", " file handles active in wakeup: " << nRet
);
742 // check fd's after we obtained the lock
743 osl::MutexGuard
g(pThis
->m_ICEMutex
);
744 if( pThis
->m_nConnections
> 0 && pThis
->m_nConnections
== nConnectionsBefore
)
746 nRet
= poll( pThis
->m_pFilehandles
+1, pThis
->m_nConnections
, 0 );
749 SAL_INFO("vcl.sm.debug", " IceProcessMessages");
751 for( int i
= 0; i
< pThis
->m_nConnections
; i
++ )
752 if( pThis
->m_pFilehandles
[i
+1].revents
& POLLIN
)
753 IceProcessMessages( pThis
->m_pConnections
[i
], nullptr, &bReply
);
758 SAL_INFO("vcl.sm.debug", " shutting down ICE dispatch thread");
762 IceConn ice_conn
, IcePointer client_data
, Bool opening
,
763 SAL_UNUSED_PARAMETER IcePointer
*)
765 SAL_INFO("vcl.sm", "ICEWatchProc");
767 // Note: This is a callback function for ICE; this implicitly means that a
768 // call into ICE lib is calling this, so the m_ICEMutex MUST already be
769 // locked by the caller.
770 ICEConnectionObserver
* pThis
= static_cast< ICEConnectionObserver
* >(
774 SAL_INFO("vcl.sm.debug", " opening");
775 int fd
= IceConnectionNumber( ice_conn
);
776 pThis
->m_nConnections
++;
777 pThis
->m_pConnections
= static_cast<IceConn
*>(std::realloc( pThis
->m_pConnections
, sizeof( IceConn
)*pThis
->m_nConnections
));
778 pThis
->m_pFilehandles
= static_cast<struct pollfd
*>(std::realloc( pThis
->m_pFilehandles
, sizeof( struct pollfd
)*(pThis
->m_nConnections
+1) ));
779 pThis
->m_pConnections
[ pThis
->m_nConnections
-1 ] = ice_conn
;
780 pThis
->m_pFilehandles
[ pThis
->m_nConnections
].fd
= fd
;
781 pThis
->m_pFilehandles
[ pThis
->m_nConnections
].events
= POLLIN
;
782 if( pThis
->m_nConnections
== 1 )
784 SAL_INFO("vcl.sm.debug", " First connection");
785 if (!pipe(pThis
->m_nWakeupFiles
))
788 pThis
->m_pFilehandles
[0].fd
= pThis
->m_nWakeupFiles
[0];
789 pThis
->m_pFilehandles
[0].events
= POLLIN
;
790 // set close-on-exec and nonblock descriptor flag.
791 if ((flags
= fcntl(pThis
->m_nWakeupFiles
[0], F_GETFD
)) != -1)
794 (void)fcntl(pThis
->m_nWakeupFiles
[0], F_SETFD
, flags
);
796 if ((flags
= fcntl(pThis
->m_nWakeupFiles
[0], F_GETFL
)) != -1)
799 (void)fcntl(pThis
->m_nWakeupFiles
[0], F_SETFL
, flags
);
801 // set close-on-exec and nonblock descriptor flag.
802 if ((flags
= fcntl(pThis
->m_nWakeupFiles
[1], F_GETFD
)) != -1)
805 (void)fcntl(pThis
->m_nWakeupFiles
[1], F_SETFD
, flags
);
807 if ((flags
= fcntl(pThis
->m_nWakeupFiles
[1], F_GETFL
)) != -1)
810 (void)fcntl(pThis
->m_nWakeupFiles
[1], F_SETFL
, flags
);
812 pThis
->m_ICEThread
= osl_createThread(
813 ICEConnectionWorker
, pThis
);
819 SAL_INFO("vcl.sm.debug", " closing");
820 for( int i
= 0; i
< pThis
->m_nConnections
; i
++ )
822 if( pThis
->m_pConnections
[i
] == ice_conn
)
824 if( i
< pThis
->m_nConnections
-1 )
826 memmove( pThis
->m_pConnections
+i
, pThis
->m_pConnections
+i
+1, sizeof( IceConn
)*(pThis
->m_nConnections
-i
-1) );
827 memmove( pThis
->m_pFilehandles
+i
+1, pThis
->m_pFilehandles
+i
+2, sizeof( struct pollfd
)*(pThis
->m_nConnections
-i
-1) );
829 pThis
->m_nConnections
--;
830 pThis
->m_pConnections
= static_cast<IceConn
*>(std::realloc( pThis
->m_pConnections
, sizeof( IceConn
)*pThis
->m_nConnections
));
831 pThis
->m_pFilehandles
= static_cast<struct pollfd
*>(std::realloc( pThis
->m_pFilehandles
, sizeof( struct pollfd
)*(pThis
->m_nConnections
+1) ));
835 if( pThis
->m_nConnections
== 0 && pThis
->m_ICEThread
)
837 SAL_INFO("vcl.sm.debug", " terminating ICEThread");
838 oslThread t
= pThis
->m_ICEThread
;
839 pThis
->m_ICEThread
= nullptr;
841 // must release the mutex here
842 pThis
->m_ICEMutex
.release();
846 // acquire the mutex again, because the caller does not expect
847 // it to be released when calling into SM
848 pThis
->m_ICEMutex
.acquire();
852 SAL_INFO( "vcl.sm.debug", " ICE connection on " << IceConnectionNumber( ice_conn
) );
853 SAL_INFO( "vcl.sm.debug", " Display connection is " << ConnectionNumber( vcl_sal::getSalDisplay(GetGenericUnixSalData())->GetDisplay() ) );
856 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */