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>
35 #include <osl/diagnose.h>
38 #include <X11/Xatom.h>
41 #include <unx/saldisp.hxx>
42 #include <unx/salinst.h>
44 #include <vcl/svapp.hxx>
45 #include <vcl/window.hxx>
47 #include <salframe.hxx>
48 #include <salsession.hxx>
52 class IceSalSession
: public SalSession
58 virtual ~IceSalSession() override
{}
60 virtual void queryInteraction() override
;
61 virtual void interactionDone() override
;
62 virtual void saveDone() override
;
63 virtual bool cancelShutdown() override
;
68 std::unique_ptr
<SalSession
> X11SalInstance::CreateSalSession()
70 SAL_INFO("vcl.sm", "X11SalInstance::CreateSalSession");
72 std::unique_ptr
<SalSession
> p(new IceSalSession
);
73 SessionManagerClient::open(p
.get());
77 void IceSalSession::queryInteraction()
79 SAL_INFO("vcl.sm", "IceSalSession::queryInteraction");
81 if( ! SessionManagerClient::queryInteraction() )
83 SAL_INFO("vcl.sm.debug", " call SalSessionInteractionEvent");
84 SalSessionInteractionEvent
aEvent( false );
85 CallCallback( &aEvent
);
89 void IceSalSession::interactionDone()
91 SAL_INFO("vcl.sm", "IceSalSession::interactionDone");
93 SessionManagerClient::interactionDone( false );
96 void IceSalSession::saveDone()
98 SAL_INFO("vcl.sm", "IceSalSession::saveDone");
100 SessionManagerClient::saveDone();
103 bool IceSalSession::cancelShutdown()
105 SAL_INFO("vcl.sm", "IceSalSession::cancelShutdown");
107 SessionManagerClient::interactionDone( true );
113 static void ICEWatchProc(
114 IceConn ice_conn
, IcePointer client_data
, Bool opening
,
115 IcePointer
* watch_data
);
117 static void ICEConnectionWorker(void * data
);
121 class ICEConnectionObserver
123 friend void ICEWatchProc(IceConn
, IcePointer
, Bool
, IcePointer
*);
125 friend void ICEConnectionWorker(void *);
127 struct pollfd
* m_pFilehandles
;
129 IceConn
* m_pConnections
;
130 int m_nWakeupFiles
[2];
131 oslThread m_ICEThread
;
132 IceIOErrorHandler m_origIOErrorHandler
;
133 IceErrorHandler m_origErrorHandler
;
138 osl::Mutex m_ICEMutex
;
140 ICEConnectionObserver()
141 : m_pFilehandles(nullptr)
143 , m_pConnections(nullptr)
144 , m_ICEThread(nullptr)
145 , m_origIOErrorHandler(nullptr)
146 , m_origErrorHandler(nullptr)
148 SAL_INFO("vcl.sm", "ICEConnectionObserver::ICEConnectionObserver");
150 m_nWakeupFiles
[0] = m_nWakeupFiles
[1] = 0;
155 void terminate(oslThread iceThread
);
158 SalSession
* SessionManagerClient::m_pSession
= nullptr;
159 std::unique_ptr
< ICEConnectionObserver
>
160 SessionManagerClient::m_xICEConnectionObserver
;
161 SmcConn
SessionManagerClient::m_pSmcConnection
= nullptr;
162 OString
SessionManagerClient::m_aClientID
= ""_ostr
;
163 OString
SessionManagerClient::m_aTimeID
= ""_ostr
;
164 OString
SessionManagerClient::m_aClientTimeID
= ""_ostr
;
165 bool SessionManagerClient::m_bDocSaveDone
= false; // HACK
169 static void IgnoreIceErrors(
170 SAL_UNUSED_PARAMETER IceConn
, SAL_UNUSED_PARAMETER Bool
,
171 SAL_UNUSED_PARAMETER
int, SAL_UNUSED_PARAMETER
unsigned long,
172 SAL_UNUSED_PARAMETER
int, SAL_UNUSED_PARAMETER
int,
173 SAL_UNUSED_PARAMETER IcePointer
)
176 static void IgnoreIceIOErrors(SAL_UNUSED_PARAMETER IceConn
) {}
180 static SmProp
* pSmProps
= nullptr;
181 static SmProp
** ppSmProps
= nullptr;
182 static char ** ppSmDel
= nullptr;
184 static int nSmProps
= 0;
185 static int nSmDel
= 0;
186 static unsigned char *pSmRestartHint
= nullptr;
189 enum { eCloneCommand
, eProgram
, eRestartCommand
, eUserId
, eRestartStyleHint
};
190 enum { eDiscardCommand
};
193 static void BuildSmPropertyList()
195 SAL_INFO("vcl.sm", "BuildSmPropertyList");
201 pSmProps
= new SmProp
[ nSmProps
];
202 ppSmProps
= new SmProp
*[ nSmProps
];
203 ppSmDel
= new char*[ nSmDel
];
206 OString
aExec(OUStringToOString(SessionManagerClient::getExecName(), osl_getThreadTextEncoding()));
208 pSmProps
[ eCloneCommand
].name
= const_cast<char*>(SmCloneCommand
);
209 pSmProps
[ eCloneCommand
].type
= const_cast<char*>(SmLISTofARRAY8
);
210 pSmProps
[ eCloneCommand
].num_vals
= 1;
211 pSmProps
[ eCloneCommand
].vals
= new SmPropValue
;
212 pSmProps
[ eCloneCommand
].vals
->length
= aExec
.getLength()+1;
213 pSmProps
[ eCloneCommand
].vals
->value
= strdup( aExec
.getStr() );
215 pSmProps
[ eProgram
].name
= const_cast<char*>(SmProgram
);
216 pSmProps
[ eProgram
].type
= const_cast<char*>(SmARRAY8
);
217 pSmProps
[ eProgram
].num_vals
= 1;
218 pSmProps
[ eProgram
].vals
= new SmPropValue
;
219 pSmProps
[ eProgram
].vals
->length
= aExec
.getLength()+1;
220 pSmProps
[ eProgram
].vals
->value
= strdup( aExec
.getStr() );
222 pSmProps
[ eRestartCommand
].name
= const_cast<char*>(SmRestartCommand
);
223 pSmProps
[ eRestartCommand
].type
= const_cast<char*>(SmLISTofARRAY8
);
224 pSmProps
[ eRestartCommand
].num_vals
= 3;
225 pSmProps
[ eRestartCommand
].vals
= new SmPropValue
[3];
226 pSmProps
[ eRestartCommand
].vals
[0].length
= aExec
.getLength()+1;
227 pSmProps
[ eRestartCommand
].vals
[0].value
= strdup( aExec
.getStr() );
228 OString aRestartOption
= "--session=" + SessionManagerClient::getSessionID();
229 pSmProps
[ eRestartCommand
].vals
[1].length
= aRestartOption
.getLength()+1;
230 pSmProps
[ eRestartCommand
].vals
[1].value
= strdup(aRestartOption
.getStr());
231 OString
aRestartOptionNoLogo("--nologo"_ostr
);
232 pSmProps
[ eRestartCommand
].vals
[2].length
= aRestartOptionNoLogo
.getLength()+1;
233 pSmProps
[ eRestartCommand
].vals
[2].value
= strdup(aRestartOptionNoLogo
.getStr());
237 oslSecurity aSec
= osl_getCurrentSecurity();
240 osl_getUserName( aSec
, &aUserName
.pData
);
241 aUser
= OUStringToOString( aUserName
, osl_getThreadTextEncoding() );
242 osl_freeSecurityHandle( aSec
);
245 pSmProps
[ eUserId
].name
= const_cast<char*>(SmUserID
);
246 pSmProps
[ eUserId
].type
= const_cast<char*>(SmARRAY8
);
247 pSmProps
[ eUserId
].num_vals
= 1;
248 pSmProps
[ eUserId
].vals
= new SmPropValue
;
249 pSmProps
[ eUserId
].vals
->value
= strdup( aUser
.getStr() );
250 pSmProps
[ eUserId
].vals
->length
= rtl_str_getLength( static_cast<char *>(pSmProps
[ 3 ].vals
->value
) )+1;
252 pSmProps
[ eRestartStyleHint
].name
= const_cast<char*>(SmRestartStyleHint
);
253 pSmProps
[ eRestartStyleHint
].type
= const_cast<char*>(SmCARD8
);
254 pSmProps
[ eRestartStyleHint
].num_vals
= 1;
255 pSmProps
[ eRestartStyleHint
].vals
= new SmPropValue
;
256 pSmProps
[ eRestartStyleHint
].vals
->value
= malloc(1);
257 pSmRestartHint
= static_cast<unsigned char *>(pSmProps
[ 4 ].vals
->value
);
258 *pSmRestartHint
= SmRestartIfRunning
;
259 pSmProps
[ eRestartStyleHint
].vals
->length
= 1;
261 for( int i
= 0; i
< nSmProps
; i
++ )
262 ppSmProps
[ i
] = &pSmProps
[i
];
264 ppSmDel
[eDiscardCommand
] = const_cast<char*>(SmDiscardCommand
);
267 bool SessionManagerClient::checkDocumentsSaved()
269 SAL_INFO("vcl.sm", "SessionManagerClient::checkDocumentsSaved");
271 SAL_INFO("vcl.sm.debug", " m_bcheckDocumentsSaved = " << (m_bDocSaveDone
? "true" : "false" ));
272 return m_bDocSaveDone
;
275 IMPL_STATIC_LINK( SessionManagerClient
, SaveYourselfHdl
, void*, pStateVal
, void )
277 SAL_INFO("vcl.sm", "SessionManagerClient, SaveYourselfHdl");
279 // Decode argument smuggled in as void*:
280 sal_uIntPtr nStateVal
= reinterpret_cast< sal_uIntPtr
>(pStateVal
);
281 bool shutdown
= nStateVal
!= 0;
283 static bool bFirstShutdown
=true;
285 SAL_INFO("vcl.sm.debug", " shutdown = " << (shutdown
? "true" : "false" ) <<
286 ", bFirstShutdown = " << (bFirstShutdown
? "true" : "false" ));
287 if (shutdown
&& bFirstShutdown
) //first shutdown request
289 bFirstShutdown
= false;
291 If we have no actual frames open, e.g. we launched a quickstarter,
292 and then shutdown all our frames leaving just a quickstarter running,
293 then we don't want to launch an empty toplevel frame on the next
294 start. (The job of scheduling the restart of the quick-starter is a
295 task of the quick-starter)
297 *pSmRestartHint
= SmRestartNever
;
298 for (auto pSalFrame
: vcl_sal::getSalDisplay(GetGenericUnixSalData())->getFrames() )
300 vcl::Window
*pWindow
= pSalFrame
->GetWindow();
301 if (pWindow
&& pWindow
->IsVisible())
303 *pSmRestartHint
= SmRestartIfRunning
;
304 SAL_INFO("vcl.sm.debug", " pSmRestartHint = SmRestartIfRunning");
312 SalSessionSaveRequestEvent
aEvent( shutdown
);
313 m_pSession
->CallCallback( &aEvent
);
319 IMPL_STATIC_LINK_NOARG( SessionManagerClient
, InteractionHdl
, void*, void )
321 SAL_INFO("vcl.sm", "SessionManagerClient, InteractionHdl");
325 SalSessionInteractionEvent
aEvent( true );
326 m_pSession
->CallCallback( &aEvent
);
330 IMPL_STATIC_LINK_NOARG( SessionManagerClient
, ShutDownCancelHdl
, void*, void )
332 SAL_INFO("vcl.sm", "SessionManagerClient, ShutDownCancelHdl");
336 SalSessionShutdownCancelEvent aEvent
;
337 m_pSession
->CallCallback( &aEvent
);
341 void SessionManagerClient::SaveYourselfProc(
350 SAL_INFO("vcl.sm", "SessionManagerClient::SaveYourselfProc");
353 osl_getSystemTime(&now
);
355 SAL_INFO("vcl.sm", " save_type = " << ((save_type
== SmSaveLocal
) ? "local" :
356 (save_type
== SmSaveGlobal
) ? "global" : "both") <<
357 ", shutdown = " << (shutdown
? "true" : "false" ) <<
358 ", interact_style = " << ((interact_style
== SmInteractStyleNone
) ? "SmInteractStyleNone" :
359 (interact_style
== SmInteractStyleErrors
) ? "SmInteractStyleErrors" :
360 "SmInteractStyleAny"));
362 snprintf(num
, sizeof(num
), "_%" SAL_PRIuUINT32
"_%" SAL_PRIuUINT32
, now
.Seconds
, (now
.Nanosec
/ 1001));
363 m_aTimeID
= OString(num
);
365 BuildSmPropertyList();
367 SmcSetProperties( m_pSmcConnection
, 1, &ppSmProps
[ eProgram
] );
368 SmcSetProperties( m_pSmcConnection
, 1, &ppSmProps
[ eUserId
] );
371 m_bDocSaveDone
= false;
372 /* #i49875# some session managers send a "die" message if the
373 * saveDone does not come early enough for their convenience
374 * this can occasionally happen on startup, especially the first
375 * startup. So shortcut the "not shutting down" case since the
376 * upper layers are currently not interested in that event anyway.
380 SessionManagerClient::saveDone();
383 // Smuggle argument in as void*:
384 sal_uIntPtr nStateVal
= shutdown
;
385 Application::PostUserEvent( LINK( nullptr, SessionManagerClient
, SaveYourselfHdl
), reinterpret_cast< void * >(nStateVal
) );
388 IMPL_STATIC_LINK_NOARG( SessionManagerClient
, ShutDownHdl
, void*, void )
390 SAL_INFO("vcl.sm", "SessionManagerClient, ShutDownHdl");
394 SalSessionQuitEvent aEvent
;
395 m_pSession
->CallCallback( &aEvent
);
398 SalFrame
*pAnyFrame
= vcl_sal::getSalDisplay(GetGenericUnixSalData())->anyFrame();
399 SAL_INFO("vcl.sm.debug", " rFrames.empty() = " << (pAnyFrame
? "true" : "false"));
401 pAnyFrame
->CallCallback( SalEvent::Shutdown
, nullptr );
404 void SessionManagerClient::DieProc(
409 SAL_INFO("vcl.sm", "SessionManagerClient::DieProc");
411 if( connection
== m_pSmcConnection
)
413 SAL_INFO("vcl.sm.debug", " connection == m_pSmcConnection" );
414 Application::PostUserEvent( LINK( nullptr, SessionManagerClient
, ShutDownHdl
) );
418 void SessionManagerClient::SaveCompleteProc(
423 SAL_INFO("vcl.sm", "SessionManagerClient::SaveCompleteProc");
426 void SessionManagerClient::ShutdownCanceledProc(
430 SAL_INFO("vcl.sm", "SessionManagerClient::ShutdownCanceledProc" );
432 SAL_INFO("vcl.sm.debug", " connection == m_pSmcConnection = " << (( connection
== m_pSmcConnection
) ? "true" : "false"));
433 if( connection
== m_pSmcConnection
)
434 Application::PostUserEvent( LINK( nullptr, SessionManagerClient
, ShutDownCancelHdl
) );
437 void SessionManagerClient::InteractProc(
441 SAL_INFO("vcl.sm", "SessionManagerClient::InteractProc" );
443 SAL_INFO("vcl.sm.debug", " connection == m_pSmcConnection = " << (( connection
== m_pSmcConnection
) ? "true" : "false"));
444 if( connection
== m_pSmcConnection
)
445 Application::PostUserEvent( LINK( nullptr, SessionManagerClient
, InteractionHdl
) );
448 void SessionManagerClient::saveDone()
450 SAL_INFO("vcl.sm", "SessionManagerClient::saveDone");
452 if( !m_pSmcConnection
)
455 assert(m_xICEConnectionObserver
);
456 osl::MutexGuard
g(m_xICEConnectionObserver
->m_ICEMutex
);
457 //SmcSetProperties( m_pSmcConnection, 1, &ppSmProps[ eCloneCommand ] );
458 // this message-handling is now equal to kate and plasma desktop
459 SmcSetProperties( m_pSmcConnection
, 1, &ppSmProps
[ eRestartCommand
] );
460 SmcDeleteProperties( m_pSmcConnection
, 1, &ppSmDel
[ eDiscardCommand
] );
461 SmcSetProperties( m_pSmcConnection
, 1, &ppSmProps
[ eRestartStyleHint
] );
463 SmcSaveYourselfDone( m_pSmcConnection
, True
);
464 SAL_INFO("vcl.sm.debug", " sent SmRestartHint = " << (*pSmRestartHint
) );
465 m_bDocSaveDone
= true;
468 void SessionManagerClient::open(SalSession
* pSession
)
470 SAL_INFO("vcl.sm", "SessionManagerClient::open");
472 assert(!m_pSession
&& !m_xICEConnectionObserver
&& !m_pSmcConnection
);
473 // must only be called once
474 m_pSession
= pSession
;
475 // This is the way Xt does it, so we can too:
476 if( getenv( "SESSION_MANAGER" ) )
478 SAL_INFO("vcl.sm.debug", " getenv( SESSION_MANAGER ) = true");
479 m_xICEConnectionObserver
.reset(new ICEConnectionObserver
);
480 m_xICEConnectionObserver
->activate();
483 osl::MutexGuard
g(m_xICEConnectionObserver
->m_ICEMutex
);
485 static SmcCallbacks aCallbacks
; // does this need to be static?
486 aCallbacks
.save_yourself
.callback
= SaveYourselfProc
;
487 aCallbacks
.save_yourself
.client_data
= nullptr;
488 aCallbacks
.die
.callback
= DieProc
;
489 aCallbacks
.die
.client_data
= nullptr;
490 aCallbacks
.save_complete
.callback
= SaveCompleteProc
;
491 aCallbacks
.save_complete
.client_data
= nullptr;
492 aCallbacks
.shutdown_cancelled
.callback
= ShutdownCanceledProc
;
493 aCallbacks
.shutdown_cancelled
.client_data
= nullptr;
494 OString
aPrevId(getPreviousSessionID());
495 char* pClientID
= nullptr;
497 m_pSmcConnection
= SmcOpenConnection( nullptr,
501 SmcSaveYourselfProcMask
|
503 SmcSaveCompleteProcMask
|
504 SmcShutdownCancelledProcMask
,
506 aPrevId
.isEmpty() ? nullptr : const_cast<char*>(aPrevId
.getStr()),
510 if( !m_pSmcConnection
)
511 SAL_INFO("vcl.sm.debug", " SmcOpenConnection failed: " << aErrBuf
);
513 SAL_INFO("vcl.sm.debug", " SmcOpenConnection succeeded, client ID is " << pClientID
);
516 m_aClientID
= OString(pClientID
);
521 SalDisplay
* pDisp
= vcl_sal::getSalDisplay(GetGenericUnixSalData());
522 if( pDisp
->GetDrawable(pDisp
->GetDefaultXScreen()) && !m_aClientID
.isEmpty() )
524 SAL_INFO("vcl.sm.debug", " SmcOpenConnection open: pDisp->GetDrawable = true");
525 XChangeProperty( pDisp
->GetDisplay(),
526 pDisp
->GetDrawable( pDisp
->GetDefaultXScreen() ),
527 XInternAtom( pDisp
->GetDisplay(), "SM_CLIENT_ID", False
),
531 reinterpret_cast<unsigned char const *>(m_aClientID
.getStr()),
532 m_aClientID
.getLength()
538 SAL_INFO("vcl.sm.debug", " getenv( SESSION_MANAGER ) = false");
542 const OString
& SessionManagerClient::getSessionID()
544 SAL_INFO("vcl.sm", "SessionManagerClient::getSessionID");
546 m_aClientTimeID
= m_aClientID
+ m_aTimeID
;
548 SAL_INFO("vcl.sm", " SessionID = " << m_aClientTimeID
);
550 return m_aClientTimeID
;
553 void SessionManagerClient::close()
555 SAL_INFO("vcl.sm", "SessionManagerClient::close");
557 if( !m_pSmcConnection
)
560 SAL_INFO("vcl.sm.debug", " attempting SmcCloseConnection");
561 assert(m_xICEConnectionObserver
);
563 osl::MutexGuard
g(m_xICEConnectionObserver
->m_ICEMutex
);
564 SmcCloseConnection( m_pSmcConnection
, 0, nullptr );
565 SAL_INFO("vcl.sm", " SmcCloseConnection closed");
567 m_xICEConnectionObserver
->deactivate();
568 m_xICEConnectionObserver
.reset();
569 m_pSmcConnection
= nullptr;
572 bool SessionManagerClient::queryInteraction()
574 SAL_INFO("vcl.sm", "SessionManagerClient::queryInteraction");
577 if( m_pSmcConnection
)
579 assert(m_xICEConnectionObserver
);
580 osl::MutexGuard
g(m_xICEConnectionObserver
->m_ICEMutex
);
581 SAL_INFO("vcl.sm.debug", " SmcInteractRequest" );
582 if( SmcInteractRequest( m_pSmcConnection
, SmDialogNormal
, InteractProc
, nullptr ) )
588 void SessionManagerClient::interactionDone( bool bCancelShutdown
)
590 SAL_INFO("vcl.sm", "SessionManagerClient::interactionDone");
592 if( m_pSmcConnection
)
594 assert(m_xICEConnectionObserver
);
595 osl::MutexGuard
g(m_xICEConnectionObserver
->m_ICEMutex
);
596 SAL_INFO("vcl.sm.debug", " SmcInteractDone = " << (bCancelShutdown
? "true" : "false") );
597 SmcInteractDone( m_pSmcConnection
, bCancelShutdown
? True
: False
);
601 OUString
SessionManagerClient::getExecName()
603 SAL_INFO("vcl.sm", "SessionManagerClient::getExecName");
605 OUString aExec
, aSysExec
;
606 osl_getExecutableFile( &aExec
.pData
);
607 osl_getSystemPathFromFileURL( aExec
.pData
, &aSysExec
.pData
);
609 if( aSysExec
.endsWith(".bin") )
610 aSysExec
= aSysExec
.copy( 0, aSysExec
.getLength() - RTL_CONSTASCII_LENGTH(".bin") );
612 SAL_INFO("vcl.sm.debug", " aSysExec = " << aSysExec
);
616 OString
SessionManagerClient::getPreviousSessionID()
618 SAL_INFO("vcl.sm", "SessionManagerClient::getPreviousSessionID");
622 sal_uInt32 n
= rtl_getAppCommandArgCount();
623 for (sal_uInt32 i
= 0; i
!= n
; ++i
)
626 rtl_getAppCommandArg( i
, &aArg
.pData
);
627 if(aArg
.match("--session="))
629 aPrevId
= OUStringToOString(
630 aArg
.subView(RTL_CONSTASCII_LENGTH("--session=")),
631 osl_getThreadTextEncoding());
636 SAL_INFO("vcl.sm.debug", " previous ID = " << aPrevId
);
640 void ICEConnectionObserver::activate()
642 SAL_INFO("vcl.sm", "ICEConnectionObserver::activate");
645 * Default handlers call exit, we don't care that strongly if something
648 m_origIOErrorHandler
= IceSetIOErrorHandler( IgnoreIceIOErrors
);
649 m_origErrorHandler
= IceSetErrorHandler( IgnoreIceErrors
);
650 IceAddConnectionWatch( ICEWatchProc
, this );
653 void ICEConnectionObserver::deactivate()
655 SAL_INFO("vcl.sm", "ICEConnectionObserver::deactivate");
659 osl::MutexGuard
g(m_ICEMutex
);
660 IceRemoveConnectionWatch( ICEWatchProc
, this );
661 IceSetErrorHandler( m_origErrorHandler
);
662 IceSetIOErrorHandler( m_origIOErrorHandler
);
665 m_ICEThread
= nullptr;
669 SAL_INFO("vcl.sm.debug", " terminate");
674 void ICEConnectionObserver::wakeup()
676 SAL_INFO("vcl.sm", "ICEConnectionObserver::wakeup");
679 OSL_VERIFY(write(m_nWakeupFiles
[1], &cChar
, 1) == 1);
682 void ICEConnectionObserver::terminate(oslThread iceThread
)
684 SAL_INFO("vcl.sm", "ICEConnectionObserver::terminate");
686 osl_terminateThread(iceThread
);
688 osl_joinWithThread(iceThread
);
689 osl_destroyThread(iceThread
);
690 close(m_nWakeupFiles
[1]);
691 close(m_nWakeupFiles
[0]);
694 void ICEConnectionWorker(void * data
)
696 SAL_INFO("vcl.sm", "ICEConnectionWorker");
698 osl::Thread::setName("ICEConnectionWorker");
699 ICEConnectionObserver
* pThis
= static_cast< ICEConnectionObserver
* >(
705 osl::MutexGuard
g(pThis
->m_ICEMutex
);
706 if (pThis
->m_ICEThread
== nullptr || pThis
->m_nConnections
== 0)
710 t
= pThis
->m_ICEThread
;
712 if (!osl_scheduleThread(t
))
717 int nConnectionsBefore
;
718 struct pollfd
* pLocalFD
;
720 osl::MutexGuard
g(pThis
->m_ICEMutex
);
721 nConnectionsBefore
= pThis
->m_nConnections
;
722 int nBytes
= sizeof( struct pollfd
)*(nConnectionsBefore
+1);
723 pLocalFD
= static_cast<struct pollfd
*>(std::malloc( nBytes
));
724 memcpy( pLocalFD
, pThis
->m_pFilehandles
, nBytes
);
727 int nRet
= poll( pLocalFD
,nConnectionsBefore
+1,-1 );
728 bool bWakeup
= (pLocalFD
[0].revents
& POLLIN
);
729 std::free( pLocalFD
);
738 while( read( pThis
->m_nWakeupFiles
[0], buf
, sizeof( buf
) ) > 0 )
740 SAL_INFO("vcl.sm.debug", " file handles active in wakeup: " << nRet
);
745 // check fd's after we obtained the lock
746 osl::MutexGuard
g(pThis
->m_ICEMutex
);
747 if( pThis
->m_nConnections
> 0 && pThis
->m_nConnections
== nConnectionsBefore
)
749 nRet
= poll( pThis
->m_pFilehandles
+1, pThis
->m_nConnections
, 0 );
752 SAL_INFO("vcl.sm.debug", " IceProcessMessages");
754 for( int i
= 0; i
< pThis
->m_nConnections
; i
++ )
755 if( pThis
->m_pFilehandles
[i
+1].revents
& POLLIN
)
756 IceProcessMessages( pThis
->m_pConnections
[i
], nullptr, &bReply
);
761 SAL_INFO("vcl.sm.debug", " shutting down ICE dispatch thread");
765 IceConn ice_conn
, IcePointer client_data
, Bool opening
,
766 SAL_UNUSED_PARAMETER IcePointer
*)
768 SAL_INFO("vcl.sm", "ICEWatchProc");
770 // Note: This is a callback function for ICE; this implicitly means that a
771 // call into ICE lib is calling this, so the m_ICEMutex MUST already be
772 // locked by the caller.
773 ICEConnectionObserver
* pThis
= static_cast< ICEConnectionObserver
* >(
777 SAL_INFO("vcl.sm.debug", " opening");
778 int fd
= IceConnectionNumber( ice_conn
);
779 pThis
->m_nConnections
++;
780 pThis
->m_pConnections
= static_cast<IceConn
*>(std::realloc( pThis
->m_pConnections
, sizeof( IceConn
)*pThis
->m_nConnections
));
781 pThis
->m_pFilehandles
= static_cast<struct pollfd
*>(std::realloc( pThis
->m_pFilehandles
, sizeof( struct pollfd
)*(pThis
->m_nConnections
+1) ));
782 pThis
->m_pConnections
[ pThis
->m_nConnections
-1 ] = ice_conn
;
783 pThis
->m_pFilehandles
[ pThis
->m_nConnections
].fd
= fd
;
784 pThis
->m_pFilehandles
[ pThis
->m_nConnections
].events
= POLLIN
;
785 if( pThis
->m_nConnections
== 1 )
787 SAL_INFO("vcl.sm.debug", " First connection");
788 if (!pipe(pThis
->m_nWakeupFiles
))
791 pThis
->m_pFilehandles
[0].fd
= pThis
->m_nWakeupFiles
[0];
792 pThis
->m_pFilehandles
[0].events
= POLLIN
;
793 // set close-on-exec and nonblock descriptor flag.
794 if ((flags
= fcntl(pThis
->m_nWakeupFiles
[0], F_GETFD
)) != -1)
797 (void)fcntl(pThis
->m_nWakeupFiles
[0], F_SETFD
, flags
);
799 if ((flags
= fcntl(pThis
->m_nWakeupFiles
[0], F_GETFL
)) != -1)
802 (void)fcntl(pThis
->m_nWakeupFiles
[0], F_SETFL
, flags
);
804 // set close-on-exec and nonblock descriptor flag.
805 if ((flags
= fcntl(pThis
->m_nWakeupFiles
[1], F_GETFD
)) != -1)
808 (void)fcntl(pThis
->m_nWakeupFiles
[1], F_SETFD
, flags
);
810 if ((flags
= fcntl(pThis
->m_nWakeupFiles
[1], F_GETFL
)) != -1)
813 (void)fcntl(pThis
->m_nWakeupFiles
[1], F_SETFL
, flags
);
815 pThis
->m_ICEThread
= osl_createThread(
816 ICEConnectionWorker
, pThis
);
822 SAL_INFO("vcl.sm.debug", " closing");
823 for( int i
= 0; i
< pThis
->m_nConnections
; i
++ )
825 if( pThis
->m_pConnections
[i
] == ice_conn
)
827 if( i
< pThis
->m_nConnections
-1 )
829 memmove( pThis
->m_pConnections
+i
, pThis
->m_pConnections
+i
+1, sizeof( IceConn
)*(pThis
->m_nConnections
-i
-1) );
830 memmove( pThis
->m_pFilehandles
+i
+1, pThis
->m_pFilehandles
+i
+2, sizeof( struct pollfd
)*(pThis
->m_nConnections
-i
-1) );
832 pThis
->m_nConnections
--;
833 pThis
->m_pConnections
= static_cast<IceConn
*>(std::realloc( pThis
->m_pConnections
, sizeof( IceConn
)*pThis
->m_nConnections
));
834 pThis
->m_pFilehandles
= static_cast<struct pollfd
*>(std::realloc( pThis
->m_pFilehandles
, sizeof( struct pollfd
)*(pThis
->m_nConnections
+1) ));
838 if( pThis
->m_nConnections
== 0 && pThis
->m_ICEThread
)
840 SAL_INFO("vcl.sm.debug", " terminating ICEThread");
841 oslThread t
= pThis
->m_ICEThread
;
842 pThis
->m_ICEThread
= nullptr;
844 // must release the mutex here
845 pThis
->m_ICEMutex
.release();
849 // acquire the mutex again, because the caller does not expect
850 // it to be released when calling into SM
851 pThis
->m_ICEMutex
.acquire();
855 SAL_INFO( "vcl.sm.debug", " ICE connection on " << IceConnectionNumber( ice_conn
) );
856 SAL_INFO( "vcl.sm.debug", " Display connection is " << ConnectionNumber( vcl_sal::getSalDisplay(GetGenericUnixSalData())->GetDisplay() ) );
859 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */