calc: on editing invalidation of view with different zoom is wrong
[LibreOffice.git] / vcl / unx / generic / app / sm.cxx
blobb6a4c4ad474f7c6fcd6015f74ced12b243b7ca54
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 .
20 #include <memory>
21 #include <sal/config.h>
23 #include <cassert>
25 #include <string.h>
26 #include <unistd.h>
27 #include <poll.h>
28 #include <fcntl.h>
30 #include <rtl/strbuf.hxx>
31 #include <sal/log.hxx>
33 #include <rtl/process.h>
34 #include <osl/security.h>
36 #include <X11/Xlib.h>
37 #include <X11/Xatom.h>
39 #include <unx/sm.hxx>
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>
49 namespace {
51 class IceSalSession : public SalSession
53 public:
54 IceSalSession() {}
56 private:
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());
73 return p;
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 );
107 return false;
110 extern "C" {
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;
127 int m_nConnections;
128 IceConn* m_pConnections;
129 int m_nWakeupFiles[2];
130 oslThread m_ICEThread;
131 IceIOErrorHandler m_origIOErrorHandler;
132 IceErrorHandler m_origErrorHandler;
134 void wakeup();
136 public:
137 osl::Mutex m_ICEMutex;
139 ICEConnectionObserver()
140 : m_pFilehandles(nullptr)
141 , m_nConnections(0)
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;
152 void activate();
153 void deactivate();
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
166 extern "C" {
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");
196 if( ! pSmProps )
198 nSmProps = 5;
199 nSmDel = 1;
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());
234 OUString aUserName;
235 OString aUser;
236 oslSecurity aSec = osl_getCurrentSecurity();
237 if( aSec )
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");
304 break;
309 if( m_pSession )
311 SalSessionSaveRequestEvent aEvent( shutdown );
312 m_pSession->CallCallback( &aEvent );
314 else
315 saveDone();
318 IMPL_STATIC_LINK_NOARG( SessionManagerClient, InteractionHdl, void*, void )
320 SAL_INFO("vcl.sm", "SessionManagerClient, InteractionHdl");
322 if( m_pSession )
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");
333 if( m_pSession )
335 SalSessionShutdownCancelEvent aEvent;
336 m_pSession->CallCallback( &aEvent );
340 void SessionManagerClient::SaveYourselfProc(
341 SmcConn,
342 SmPointer,
343 int save_type,
344 Bool shutdown,
345 int interact_style,
346 Bool
349 SAL_INFO("vcl.sm", "SessionManagerClient::SaveYourselfProc");
351 TimeValue now;
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"));
360 char num[100];
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.
377 if( ! shutdown )
379 SessionManagerClient::saveDone();
380 return;
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");
391 if( m_pSession )
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"));
399 if( pAnyFrame )
400 pAnyFrame->CallCallback( SalEvent::Shutdown, nullptr );
403 void SessionManagerClient::DieProc(
404 SmcConn connection,
405 SmPointer
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(
418 SmcConn,
419 SmPointer
422 SAL_INFO("vcl.sm", "SessionManagerClient::SaveCompleteProc");
425 void SessionManagerClient::ShutdownCanceledProc(
426 SmcConn connection,
427 SmPointer )
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(
437 SmcConn connection,
438 SmPointer )
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 )
452 return;
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;
495 char aErrBuf[1024];
496 m_pSmcConnection = SmcOpenConnection( nullptr,
497 nullptr,
498 SmProtoMajor,
499 SmProtoMinor,
500 SmcSaveYourselfProcMask |
501 SmcDieProcMask |
502 SmcSaveCompleteProcMask |
503 SmcShutdownCancelledProcMask ,
504 &aCallbacks,
505 aPrevId.isEmpty() ? nullptr : const_cast<char*>(aPrevId.getStr()),
506 &pClientID,
507 sizeof( aErrBuf ),
508 aErrBuf );
509 if( !m_pSmcConnection )
510 SAL_INFO("vcl.sm.debug", " SmcOpenConnection failed: " << aErrBuf);
511 else
512 SAL_INFO("vcl.sm.debug", " SmcOpenConnection succeeded, client ID is " << pClientID );
513 m_aClientID = OString(pClientID);
514 free( pClientID );
515 pClientID = nullptr;
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 ),
525 XA_STRING,
527 PropModeReplace,
528 reinterpret_cast<unsigned char const *>(m_aClientID.getStr()),
529 m_aClientID.getLength()
533 else
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 )
555 return;
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");
573 bool bRet = false;
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 ) )
580 bRet = true;
582 return bRet;
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);
610 return aSysExec;
613 OString SessionManagerClient::getPreviousSessionID()
615 SAL_INFO("vcl.sm", "SessionManagerClient::getPreviousSessionID");
617 OString aPrevId;
619 sal_uInt32 n = rtl_getAppCommandArgCount();
620 for (sal_uInt32 i = 0; i != n; ++i)
622 OUString aArg;
623 rtl_getAppCommandArg( i, &aArg.pData );
624 if(aArg.match("--session="))
626 aPrevId = OUStringToOString(
627 aArg.subView(RTL_CONSTASCII_LENGTH("--session=")),
628 osl_getThreadTextEncoding());
629 break;
633 SAL_INFO("vcl.sm.debug", " previous ID = " << aPrevId);
634 return 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
643 * happens to fail
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");
654 oslThread t;
656 osl::MutexGuard g(m_ICEMutex);
657 IceRemoveConnectionWatch( ICEWatchProc, this );
658 IceSetErrorHandler( m_origErrorHandler );
659 IceSetIOErrorHandler( m_origIOErrorHandler );
660 m_nConnections = 0;
661 t = m_ICEThread;
662 m_ICEThread = nullptr;
664 if (t)
666 SAL_INFO("vcl.sm.debug", " terminate");
667 terminate(t);
671 void ICEConnectionObserver::wakeup()
673 SAL_INFO("vcl.sm", "ICEConnectionObserver::wakeup");
675 char cChar = 'w';
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);
684 wakeup();
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 * >(
697 data);
698 for (;;)
700 oslThread t;
702 osl::MutexGuard g(pThis->m_ICEMutex);
703 if (pThis->m_ICEThread == nullptr || pThis->m_nConnections == 0)
705 break;
707 t = pThis->m_ICEThread;
709 if (!osl_scheduleThread(t))
711 break;
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 );
728 if( nRet < 1 )
729 continue;
731 // clear wakeup pipe
732 if( bWakeup )
734 char buf[4];
735 while( read( pThis->m_nWakeupFiles[0], buf, sizeof( buf ) ) > 0 )
737 SAL_INFO("vcl.sm.debug", " file handles active in wakeup: " << nRet);
738 if( nRet == 1 )
739 continue;
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 );
747 if( nRet > 0 )
749 SAL_INFO("vcl.sm.debug", " IceProcessMessages");
750 Bool bReply;
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");
761 void ICEWatchProc(
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 * >(
771 client_data);
772 if( opening )
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))
787 int flags;
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)
793 flags |= FD_CLOEXEC;
794 (void)fcntl(pThis->m_nWakeupFiles[0], F_SETFD, flags);
796 if ((flags = fcntl(pThis->m_nWakeupFiles[0], F_GETFL)) != -1)
798 flags |= O_NONBLOCK;
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)
804 flags |= FD_CLOEXEC;
805 (void)fcntl(pThis->m_nWakeupFiles[1], F_SETFD, flags);
807 if ((flags = fcntl(pThis->m_nWakeupFiles[1], F_GETFL)) != -1)
809 flags |= O_NONBLOCK;
810 (void)fcntl(pThis->m_nWakeupFiles[1], F_SETFL, flags);
812 pThis->m_ICEThread = osl_createThread(
813 ICEConnectionWorker, pThis);
817 else // closing
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) ));
832 break;
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();
844 pThis->terminate(t);
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: */