Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : : /*************************************************************************
3 : : *
4 : : * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 : : *
6 : : * Copyright 2000, 2010 Oracle and/or its affiliates.
7 : : *
8 : : * OpenOffice.org - a multi-platform office productivity suite
9 : : *
10 : : * This file is part of OpenOffice.org.
11 : : *
12 : : * OpenOffice.org is free software: you can redistribute it and/or modify
13 : : * it under the terms of the GNU Lesser General Public License version 3
14 : : * only, as published by the Free Software Foundation.
15 : : *
16 : : * OpenOffice.org is distributed in the hope that it will be useful,
17 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : : * GNU Lesser General Public License version 3 for more details
20 : : * (a copy is included in the LICENSE file that accompanied this code).
21 : : *
22 : : * You should have received a copy of the GNU Lesser General Public License
23 : : * version 3 along with OpenOffice.org. If not, see
24 : : * <http://www.openoffice.org/license.html>
25 : : * for a copy of the LGPLv3 License.
26 : : *
27 : : ************************************************************************/
28 : :
29 : : #include "sal/config.h"
30 : :
31 : : #include <cassert>
32 : :
33 : : #include <string.h>
34 : : #include <unistd.h>
35 : : #include <sys/poll.h>
36 : : #include <fcntl.h>
37 : :
38 : : #include <stdio.h>
39 : :
40 : : #include <rtl/strbuf.hxx>
41 : :
42 : : #include <rtl/process.h>
43 : : #include <osl/security.h>
44 : : #include <osl/conditn.h>
45 : :
46 : : #include <tools/prex.h>
47 : : #include <X11/Xatom.h>
48 : : #include <tools/postx.h>
49 : :
50 : : #include <unx/sm.hxx>
51 : : #include <unx/saldata.hxx>
52 : : #include <unx/saldisp.hxx>
53 : : #include <unx/salframe.h>
54 : : #include <unx/salinst.h>
55 : :
56 : : #include <vcl/svapp.hxx>
57 : : #include <vcl/window.hxx>
58 : :
59 : : #include "salsession.hxx"
60 : :
61 : : namespace {
62 : :
63 : : class IceSalSession : public SalSession
64 : : {
65 : : public:
66 : 0 : IceSalSession() {}
67 : :
68 : : private:
69 : 0 : virtual ~IceSalSession() {}
70 : :
71 : : virtual void queryInteraction();
72 : : virtual void interactionDone();
73 : : virtual void saveDone();
74 : : virtual bool cancelShutdown();
75 : : };
76 : :
77 : : }
78 : :
79 : 0 : SalSession* X11SalInstance::CreateSalSession()
80 : : {
81 : 0 : SalSession * p = new IceSalSession;
82 : 0 : SessionManagerClient::open(p);
83 : 0 : return p;
84 : : }
85 : :
86 : 0 : void IceSalSession::queryInteraction()
87 : : {
88 : 0 : if( ! SessionManagerClient::queryInteraction() )
89 : : {
90 : 0 : SalSessionInteractionEvent aEvent( false );
91 : 0 : CallCallback( &aEvent );
92 : : }
93 : 0 : }
94 : :
95 : 0 : void IceSalSession::interactionDone()
96 : : {
97 : 0 : SessionManagerClient::interactionDone( false );
98 : 0 : }
99 : :
100 : 0 : void IceSalSession::saveDone()
101 : : {
102 : 0 : SessionManagerClient::saveDone();
103 : 0 : }
104 : :
105 : 0 : bool IceSalSession::cancelShutdown()
106 : : {
107 : 0 : SessionManagerClient::interactionDone( true );
108 : 0 : return false;
109 : : }
110 : :
111 : : extern "C" void ICEWatchProc(
112 : : IceConn ice_conn, IcePointer client_data, Bool opening,
113 : : IcePointer * watch_data);
114 : :
115 : : extern "C" void SAL_CALL ICEConnectionWorker(void * data);
116 : :
117 : 0 : class ICEConnectionObserver
118 : : {
119 : : friend void ICEWatchProc(IceConn, IcePointer, Bool, IcePointer *);
120 : :
121 : : friend void ICEConnectionWorker(void *);
122 : :
123 : : struct pollfd* m_pFilehandles;
124 : : int m_nConnections;
125 : : IceConn* m_pConnections;
126 : : int m_nWakeupFiles[2];
127 : : oslThread m_ICEThread;
128 : : IceIOErrorHandler m_origIOErrorHandler;
129 : : IceErrorHandler m_origErrorHandler;
130 : :
131 : : void wakeup();
132 : :
133 : : public:
134 : : osl::Mutex m_ICEMutex;
135 : :
136 : 0 : ICEConnectionObserver():
137 : : m_pFilehandles(NULL), m_nConnections(0), m_pConnections(NULL),
138 : 0 : m_ICEThread(NULL)
139 : 0 : { m_nWakeupFiles[0] = m_nWakeupFiles[1] = 0; }
140 : :
141 : : void activate();
142 : : void deactivate();
143 : : void terminate(oslThread iceThread);
144 : : };
145 : :
146 : : SalSession * SessionManagerClient::m_pSession = NULL;
147 : : boost::scoped_ptr< ICEConnectionObserver >
148 : 0 : SessionManagerClient::m_pICEConnectionObserver;
149 : : SmcConn SessionManagerClient::m_pSmcConnection = NULL;
150 : 0 : rtl::OString SessionManagerClient::m_aClientID;
151 : : bool SessionManagerClient::m_bDocSaveDone = false; // HACK
152 : :
153 : : extern "C" {
154 : :
155 : 0 : static void IgnoreIceErrors(
156 : : SAL_UNUSED_PARAMETER IceConn, SAL_UNUSED_PARAMETER Bool,
157 : : SAL_UNUSED_PARAMETER int, SAL_UNUSED_PARAMETER unsigned long,
158 : : SAL_UNUSED_PARAMETER int, SAL_UNUSED_PARAMETER int,
159 : : SAL_UNUSED_PARAMETER IcePointer)
160 : 0 : {}
161 : :
162 : 0 : static void IgnoreIceIOErrors(SAL_UNUSED_PARAMETER IceConn) {}
163 : :
164 : : }
165 : :
166 : : static SmProp* pSmProps = NULL;
167 : : static SmProp** ppSmProps = NULL;
168 : : static int nSmProps = 0;
169 : : static unsigned char *pSmRestartHint = NULL;
170 : :
171 : :
172 : 0 : static void BuildSmPropertyList()
173 : : {
174 : 0 : if( ! pSmProps )
175 : : {
176 : 0 : rtl::OString aExec(rtl::OUStringToOString(SessionManagerClient::getExecName(), osl_getThreadTextEncoding()));
177 : :
178 : 0 : nSmProps = 5;
179 : 0 : pSmProps = new SmProp[ nSmProps ];
180 : :
181 : 0 : pSmProps[ 0 ].name = const_cast<char*>(SmCloneCommand);
182 : 0 : pSmProps[ 0 ].type = const_cast<char*>(SmLISTofARRAY8);
183 : 0 : pSmProps[ 0 ].num_vals = 1;
184 : 0 : pSmProps[ 0 ].vals = new SmPropValue;
185 : 0 : pSmProps[ 0 ].vals->length = aExec.getLength()+1;
186 : 0 : pSmProps[ 0 ].vals->value = strdup( aExec.getStr() );
187 : :
188 : 0 : pSmProps[ 1 ].name = const_cast<char*>(SmProgram);
189 : 0 : pSmProps[ 1 ].type = const_cast<char*>(SmARRAY8);
190 : 0 : pSmProps[ 1 ].num_vals = 1;
191 : 0 : pSmProps[ 1 ].vals = new SmPropValue;
192 : 0 : pSmProps[ 1 ].vals->length = aExec.getLength()+1;
193 : 0 : pSmProps[ 1 ].vals->value = strdup( aExec.getStr() );
194 : :
195 : 0 : pSmProps[ 2 ].name = const_cast<char*>(SmRestartCommand);
196 : 0 : pSmProps[ 2 ].type = const_cast<char*>(SmLISTofARRAY8);
197 : 0 : pSmProps[ 2 ].num_vals = 3;
198 : 0 : pSmProps[ 2 ].vals = new SmPropValue[3];
199 : 0 : pSmProps[ 2 ].vals[0].length = aExec.getLength()+1;
200 : 0 : pSmProps[ 2 ].vals[0].value = strdup( aExec.getStr() );
201 : 0 : rtl::OStringBuffer aRestartOption;
202 : 0 : aRestartOption.append(RTL_CONSTASCII_STRINGPARAM("--session="));
203 : 0 : aRestartOption.append(SessionManagerClient::getSessionID());
204 : 0 : pSmProps[ 2 ].vals[1].length = aRestartOption.getLength()+1;
205 : 0 : pSmProps[ 2 ].vals[1].value = strdup(aRestartOption.getStr());
206 : 0 : rtl::OString aRestartOptionNoLogo(RTL_CONSTASCII_STRINGPARAM("--nologo"));
207 : 0 : pSmProps[ 2 ].vals[2].length = aRestartOptionNoLogo.getLength()+1;
208 : 0 : pSmProps[ 2 ].vals[2].value = strdup(aRestartOptionNoLogo.getStr());
209 : :
210 : 0 : rtl::OUString aUserName;
211 : 0 : rtl::OString aUser;
212 : 0 : oslSecurity aSec = osl_getCurrentSecurity();
213 : 0 : if( aSec )
214 : : {
215 : 0 : osl_getUserName( aSec, &aUserName.pData );
216 : 0 : aUser = rtl::OUStringToOString( aUserName, osl_getThreadTextEncoding() );
217 : 0 : osl_freeSecurityHandle( aSec );
218 : : }
219 : :
220 : 0 : pSmProps[ 3 ].name = const_cast<char*>(SmUserID);
221 : 0 : pSmProps[ 3 ].type = const_cast<char*>(SmARRAY8);
222 : 0 : pSmProps[ 3 ].num_vals = 1;
223 : 0 : pSmProps[ 3 ].vals = new SmPropValue;
224 : 0 : pSmProps[ 3 ].vals->value = strdup( aUser.getStr() );
225 : 0 : pSmProps[ 3 ].vals->length = rtl_str_getLength( (char *)pSmProps[ 3 ].vals->value )+1;
226 : :
227 : 0 : pSmProps[ 4 ].name = const_cast<char*>(SmRestartStyleHint);
228 : 0 : pSmProps[ 4 ].type = const_cast<char*>(SmCARD8);
229 : 0 : pSmProps[ 4 ].num_vals = 1;
230 : 0 : pSmProps[ 4 ].vals = new SmPropValue;
231 : 0 : pSmProps[ 4 ].vals->value = malloc(1);
232 : 0 : pSmRestartHint = (unsigned char *)pSmProps[ 4 ].vals->value;
233 : 0 : *pSmRestartHint = SmRestartIfRunning;
234 : 0 : pSmProps[ 4 ].vals->length = 1;
235 : :
236 : 0 : ppSmProps = new SmProp*[ nSmProps ];
237 : 0 : for( int i = 0; i < nSmProps; i++ )
238 : 0 : ppSmProps[ i ] = &pSmProps[i];
239 : : }
240 : 0 : }
241 : :
242 : 0 : bool SessionManagerClient::checkDocumentsSaved()
243 : : {
244 : 0 : return m_bDocSaveDone;
245 : : }
246 : :
247 : 0 : IMPL_STATIC_LINK_NOINSTANCE( SessionManagerClient, SaveYourselfHdl, void*, pStateVal )
248 : : {
249 : : // Decode argument smuggled in as void*:
250 : 0 : sal_uIntPtr nStateVal = reinterpret_cast< sal_uIntPtr >(pStateVal);
251 : 0 : Bool shutdown = nStateVal != 0;
252 : :
253 : : SAL_INFO("vcl.sm", "posting save documents event shutdown = " << (shutdown ? "true" : "false" ));
254 : :
255 : : static bool bFirstShutdown=true;
256 : 0 : if (shutdown && bFirstShutdown) //first shutdown request
257 : : {
258 : 0 : bFirstShutdown = false;
259 : : /*
260 : : If we have no actual frames open, e.g. we launched a quickstarter,
261 : : and then shutdown all our frames leaving just a quickstarter running,
262 : : then we don't want to launch an empty toplevel frame on the next
263 : : start. (The job of scheduling the restart of the quick-starter is a
264 : : task of the quick-starter)
265 : : */
266 : 0 : *pSmRestartHint = SmRestartNever;
267 : 0 : const std::list< SalFrame* >& rFrames = GetGenericData()->GetSalDisplay()->getFrames();
268 : 0 : for( std::list< SalFrame* >::const_iterator it = rFrames.begin(); it != rFrames.end(); ++it )
269 : : {
270 : 0 : Window *pWindow = (*it)->GetWindow();
271 : 0 : if (pWindow && pWindow->IsVisible())
272 : : {
273 : 0 : *pSmRestartHint = SmRestartIfRunning;
274 : 0 : break;
275 : : }
276 : : }
277 : : }
278 : :
279 : 0 : if( m_pSession )
280 : : {
281 : 0 : SalSessionSaveRequestEvent aEvent( shutdown, false );
282 : 0 : m_pSession->CallCallback( &aEvent );
283 : : }
284 : : else
285 : 0 : saveDone();
286 : :
287 : 0 : return 0;
288 : : }
289 : :
290 : 0 : IMPL_STATIC_LINK_NOINSTANCE( SessionManagerClient, InteractionHdl, void*, EMPTYARG )
291 : : {
292 : : SAL_INFO("vcl.sm", "interaction link");
293 : 0 : if( m_pSession )
294 : : {
295 : 0 : SalSessionInteractionEvent aEvent( true );
296 : 0 : m_pSession->CallCallback( &aEvent );
297 : : }
298 : :
299 : 0 : return 0;
300 : : }
301 : :
302 : 0 : IMPL_STATIC_LINK_NOINSTANCE( SessionManagerClient, ShutDownCancelHdl, void*, EMPTYARG )
303 : : {
304 : : SAL_INFO("vcl.sm", "shutdown cancel");
305 : 0 : if( m_pSession )
306 : : {
307 : 0 : SalSessionShutdownCancelEvent aEvent;
308 : 0 : m_pSession->CallCallback( &aEvent );
309 : : }
310 : :
311 : 0 : return 0;
312 : : }
313 : :
314 : 0 : void SessionManagerClient::SaveYourselfProc(
315 : : SmcConn,
316 : : SmPointer,
317 : : int save_type,
318 : : Bool shutdown,
319 : : int interact_style,
320 : : Bool
321 : : )
322 : : {
323 : : SAL_INFO("vcl.sm", "Session: save yourself," <<
324 : : "save_type " <<
325 : : " local: " << (save_type == SmSaveLocal) <<
326 : : " global: " << (save_type == SmSaveGlobal) <<
327 : : " both: " << (save_type == SmSaveBoth) <<
328 : : " shutdown: " << shutdown <<
329 : : " interact_style: " <<
330 : : " SmInteractStyleNone: " << (interact_style == SmInteractStyleNone) <<
331 : : " SmInteractStyleErrors: " << (interact_style == SmInteractStyleErrors) <<
332 : : " SmInteractStyleErrors: " << (interact_style == SmInteractStyleAny));
333 : 0 : BuildSmPropertyList();
334 : 0 : m_bDocSaveDone = false;
335 : : /* #i49875# some session managers send a "die" message if the
336 : : * saveDone does not come early enough for their convenience
337 : : * this can occasionally happen on startup, especially the first
338 : : * startup. So shortcut the "not shutting down" case since the
339 : : * upper layers are currently not interested in that event anyway.
340 : : */
341 : 0 : if( ! shutdown )
342 : : {
343 : 0 : SessionManagerClient::saveDone();
344 : 0 : return;
345 : : }
346 : : // Smuggle argument in as void*:
347 : 0 : sal_uIntPtr nStateVal = shutdown;
348 : 0 : Application::PostUserEvent( STATIC_LINK( 0, SessionManagerClient, SaveYourselfHdl ), reinterpret_cast< void * >(nStateVal) );
349 : : SAL_INFO("vcl.sm", "waiting for save yourself event to be processed" );
350 : : }
351 : :
352 : 0 : IMPL_STATIC_LINK_NOINSTANCE( SessionManagerClient, ShutDownHdl, void*, EMPTYARG )
353 : : {
354 : 0 : if( m_pSession )
355 : : {
356 : 0 : SalSessionQuitEvent aEvent;
357 : 0 : m_pSession->CallCallback( &aEvent );
358 : : }
359 : :
360 : 0 : const std::list< SalFrame* >& rFrames = GetGenericData()->GetSalDisplay()->getFrames();
361 : : SAL_INFO("vcl.sm", (rFrames.begin() != rFrames.end() ? "shutdown on first frame" : "shutdown event but no frame"));
362 : 0 : if( rFrames.begin() != rFrames.end() )
363 : 0 : rFrames.front()->CallCallback( SALEVENT_SHUTDOWN, 0 );
364 : 0 : return 0;
365 : : }
366 : :
367 : 0 : void SessionManagerClient::DieProc(
368 : : SmcConn connection,
369 : : SmPointer
370 : : )
371 : : {
372 : : SAL_INFO("vcl.sm", "Session: die");
373 : 0 : if( connection == m_pSmcConnection )
374 : : {
375 : 0 : Application::PostUserEvent( STATIC_LINK( NULL, SessionManagerClient, ShutDownHdl ) );
376 : : SAL_INFO("vcl.sm", "waiting for shutdown event to be processed" );
377 : : }
378 : 0 : }
379 : :
380 : 0 : void SessionManagerClient::SaveCompleteProc(
381 : : SmcConn,
382 : : SmPointer
383 : : )
384 : : {
385 : : SAL_INFO("vcl.sm", "Session: save complete");
386 : 0 : }
387 : :
388 : 0 : void SessionManagerClient::ShutdownCanceledProc(
389 : : SmcConn connection,
390 : : SmPointer )
391 : : {
392 : : SAL_INFO("vcl.sm", "Session: shutdown canceled" );
393 : 0 : if( connection == m_pSmcConnection )
394 : 0 : Application::PostUserEvent( STATIC_LINK( NULL, SessionManagerClient, ShutDownCancelHdl ) );
395 : 0 : }
396 : :
397 : 0 : void SessionManagerClient::InteractProc(
398 : : SmcConn connection,
399 : : SmPointer )
400 : : {
401 : : SAL_INFO("vcl.sm", "Session: interaction request completed" );
402 : 0 : if( connection == m_pSmcConnection )
403 : 0 : Application::PostUserEvent( STATIC_LINK( NULL, SessionManagerClient, InteractionHdl ) );
404 : 0 : }
405 : :
406 : 0 : void SessionManagerClient::saveDone()
407 : : {
408 : 0 : if( m_pSmcConnection )
409 : : {
410 : : assert(m_pICEConnectionObserver);
411 : 0 : osl::MutexGuard g(m_pICEConnectionObserver->m_ICEMutex);
412 : 0 : SmcSetProperties( m_pSmcConnection, nSmProps, ppSmProps );
413 : 0 : SmcSaveYourselfDone( m_pSmcConnection, True );
414 : : SAL_INFO("vcl.sm", "sent SaveYourselfDone SmRestartHint of " << *pSmRestartHint );
415 : 0 : m_bDocSaveDone = true;
416 : : }
417 : 0 : }
418 : :
419 : :
420 : 0 : void SessionManagerClient::open(SalSession * pSession)
421 : : {
422 : : assert(!m_pSession && !m_pICEConnectionObserver && !m_pSmcConnection);
423 : : // must only be called once
424 : 0 : m_pSession = pSession;
425 : : // This is the way Xt does it, so we can too:
426 : 0 : if( getenv( "SESSION_MANAGER" ) )
427 : : {
428 : 0 : m_pICEConnectionObserver.reset(new ICEConnectionObserver);
429 : 0 : m_pICEConnectionObserver->activate();
430 : :
431 : : {
432 : 0 : osl::MutexGuard g(m_pICEConnectionObserver->m_ICEMutex);
433 : :
434 : : static SmcCallbacks aCallbacks; // does this need to be static?
435 : 0 : aCallbacks.save_yourself.callback = SaveYourselfProc;
436 : 0 : aCallbacks.save_yourself.client_data = NULL;
437 : 0 : aCallbacks.die.callback = DieProc;
438 : 0 : aCallbacks.die.client_data = NULL;
439 : 0 : aCallbacks.save_complete.callback = SaveCompleteProc;
440 : 0 : aCallbacks.save_complete.client_data = NULL;
441 : 0 : aCallbacks.shutdown_cancelled.callback = ShutdownCanceledProc;
442 : 0 : aCallbacks.shutdown_cancelled.client_data = NULL;
443 : 0 : rtl::OString aPrevId(getPreviousSessionID());
444 : 0 : char* pClientID = NULL;
445 : : char aErrBuf[1024];
446 : : m_pSmcConnection = SmcOpenConnection( NULL,
447 : : NULL,
448 : : SmProtoMajor,
449 : : SmProtoMinor,
450 : : SmcSaveYourselfProcMask |
451 : : SmcDieProcMask |
452 : : SmcSaveCompleteProcMask |
453 : : SmcShutdownCancelledProcMask ,
454 : : &aCallbacks,
455 : 0 : aPrevId.isEmpty() ? NULL : const_cast<char*>(aPrevId.getStr()),
456 : : &pClientID,
457 : : sizeof( aErrBuf ),
458 : 0 : aErrBuf );
459 : 0 : if( !m_pSmcConnection )
460 : : SAL_INFO("vcl.sm", "SmcOpenConnection failed: " << aErrBuf);
461 : : else
462 : : SAL_INFO("vcl.sm", "SmcOpenConnection succeeded, client ID is " << pClientID );
463 : 0 : m_aClientID = rtl::OString(pClientID);
464 : 0 : free( pClientID );
465 : 0 : pClientID = NULL;
466 : : }
467 : :
468 : 0 : SalDisplay* pDisp = GetGenericData()->GetSalDisplay();
469 : 0 : if( pDisp->GetDrawable(pDisp->GetDefaultXScreen()) && !m_aClientID.isEmpty() )
470 : : {
471 : : XChangeProperty( pDisp->GetDisplay(),
472 : : pDisp->GetDrawable( pDisp->GetDefaultXScreen() ),
473 : : XInternAtom( pDisp->GetDisplay(), "SM_CLIENT_ID", False ),
474 : : XA_STRING,
475 : : 8,
476 : : PropModeReplace,
477 : 0 : (unsigned char*)m_aClientID.getStr(),
478 : 0 : m_aClientID.getLength()
479 : 0 : );
480 : : }
481 : : }
482 : : else
483 : : {
484 : : SAL_INFO("vcl.sm", "no SESSION_MANAGER");
485 : : }
486 : 0 : }
487 : :
488 : 0 : rtl::OString SessionManagerClient::getSessionID()
489 : : {
490 : 0 : return m_aClientID;
491 : : }
492 : :
493 : 0 : void SessionManagerClient::close()
494 : : {
495 : 0 : if( m_pSmcConnection )
496 : : {
497 : : assert(m_pICEConnectionObserver);
498 : : {
499 : 0 : osl::MutexGuard g(m_pICEConnectionObserver->m_ICEMutex);
500 : : SAL_INFO("vcl.sm", "attempting SmcCloseConnection");
501 : 0 : SmcCloseConnection( m_pSmcConnection, 0, NULL );
502 : 0 : SAL_INFO("vcl.sm", "SmcConnection closed");
503 : : }
504 : 0 : m_pICEConnectionObserver->deactivate();
505 : 0 : m_pICEConnectionObserver.reset();
506 : 0 : m_pSmcConnection = NULL;
507 : : }
508 : 0 : }
509 : :
510 : 0 : bool SessionManagerClient::queryInteraction()
511 : : {
512 : 0 : bool bRet = false;
513 : 0 : if( m_pSmcConnection )
514 : : {
515 : : assert(m_pICEConnectionObserver);
516 : 0 : osl::MutexGuard g(m_pICEConnectionObserver->m_ICEMutex);
517 : 0 : if( SmcInteractRequest( m_pSmcConnection, SmDialogNormal, InteractProc, NULL ) )
518 : 0 : bRet = true;
519 : : }
520 : 0 : return bRet;
521 : : }
522 : :
523 : 0 : void SessionManagerClient::interactionDone( bool bCancelShutdown )
524 : : {
525 : 0 : if( m_pSmcConnection )
526 : : {
527 : : assert(m_pICEConnectionObserver);
528 : 0 : osl::MutexGuard g(m_pICEConnectionObserver->m_ICEMutex);
529 : 0 : SmcInteractDone( m_pSmcConnection, bCancelShutdown ? True : False );
530 : : }
531 : 0 : }
532 : :
533 : :
534 : 0 : rtl::OUString SessionManagerClient::getExecName()
535 : : {
536 : 0 : rtl::OUString aExec, aSysExec;
537 : 0 : osl_getExecutableFile( &aExec.pData );
538 : 0 : osl_getSystemPathFromFileURL( aExec.pData, &aSysExec.pData );
539 : :
540 : 0 : if( aSysExec.endsWith(".bin") )
541 : 0 : aSysExec = aSysExec.copy( 0, aSysExec.getLength() - RTL_CONSTASCII_LENGTH(".bin") );
542 : 0 : return aSysExec;
543 : : }
544 : :
545 : :
546 : 0 : rtl::OString SessionManagerClient::getPreviousSessionID()
547 : : {
548 : 0 : rtl::OString aPrevId;
549 : :
550 : 0 : sal_uInt32 n = rtl_getAppCommandArgCount();
551 : 0 : for (sal_uInt32 i = 0; i != n; ++i)
552 : : {
553 : 0 : ::rtl::OUString aArg;
554 : 0 : rtl_getAppCommandArg( i, &aArg.pData );
555 : 0 : if(aArg.match("--session="))
556 : : {
557 : : aPrevId = rtl::OUStringToOString(
558 : : aArg.copy(RTL_CONSTASCII_LENGTH("--session=")),
559 : 0 : osl_getThreadTextEncoding());
560 : : break;
561 : : }
562 : 0 : }
563 : :
564 : : SAL_INFO("vcl.sm", "previous ID = " << aPrevId.getStr());
565 : 0 : return aPrevId;
566 : : }
567 : :
568 : 0 : void ICEConnectionObserver::activate()
569 : : {
570 : : /*
571 : : * Default handlers call exit, we don't care that strongly if something
572 : : * happens to fail
573 : : */
574 : 0 : m_origIOErrorHandler = IceSetIOErrorHandler( IgnoreIceIOErrors );
575 : 0 : m_origErrorHandler = IceSetErrorHandler( IgnoreIceErrors );
576 : 0 : IceAddConnectionWatch( ICEWatchProc, this );
577 : 0 : }
578 : :
579 : 0 : void ICEConnectionObserver::deactivate()
580 : : {
581 : : oslThread t;
582 : : {
583 : 0 : osl::MutexGuard g(m_ICEMutex);
584 : 0 : IceRemoveConnectionWatch( ICEWatchProc, this );
585 : 0 : IceSetErrorHandler( m_origErrorHandler );
586 : 0 : IceSetIOErrorHandler( m_origIOErrorHandler );
587 : 0 : m_nConnections = 0;
588 : 0 : t = m_ICEThread;
589 : 0 : m_ICEThread = NULL;
590 : : }
591 : 0 : if (t)
592 : : {
593 : 0 : terminate(t);
594 : : }
595 : 0 : }
596 : :
597 : 0 : void ICEConnectionObserver::wakeup()
598 : : {
599 : 0 : char cChar = 'w';
600 : 0 : OSL_VERIFY(write(m_nWakeupFiles[1], &cChar, 1) == 1);
601 : 0 : }
602 : :
603 : 0 : void ICEConnectionObserver::terminate(oslThread iceThread)
604 : : {
605 : 0 : osl_terminateThread(iceThread);
606 : 0 : wakeup();
607 : 0 : osl_joinWithThread(iceThread);
608 : 0 : osl_destroyThread(iceThread);
609 : 0 : close(m_nWakeupFiles[1]);
610 : 0 : close(m_nWakeupFiles[0]);
611 : 0 : }
612 : :
613 : 0 : void ICEConnectionWorker(void * data)
614 : : {
615 : : ICEConnectionObserver * pThis = static_cast< ICEConnectionObserver * >(
616 : 0 : data);
617 : 0 : for (;;)
618 : : {
619 : : oslThread t;
620 : : {
621 : 0 : osl::MutexGuard g(pThis->m_ICEMutex);
622 : 0 : if (pThis->m_ICEThread == NULL || pThis->m_nConnections == 0)
623 : : {
624 : : break;
625 : : }
626 : 0 : t = pThis->m_ICEThread;
627 : : }
628 : 0 : if (!osl_scheduleThread(t))
629 : : {
630 : : break;
631 : : }
632 : :
633 : : int nConnectionsBefore;
634 : : struct pollfd* pLocalFD;
635 : : {
636 : 0 : osl::MutexGuard g(pThis->m_ICEMutex);
637 : 0 : nConnectionsBefore = pThis->m_nConnections;
638 : 0 : int nBytes = sizeof( struct pollfd )*(nConnectionsBefore+1);
639 : 0 : pLocalFD = (struct pollfd*)rtl_allocateMemory( nBytes );
640 : 0 : memcpy( pLocalFD, pThis->m_pFilehandles, nBytes );
641 : : }
642 : :
643 : 0 : int nRet = poll( pLocalFD,nConnectionsBefore+1,-1 );
644 : 0 : bool bWakeup = (pLocalFD[0].revents & POLLIN);
645 : 0 : rtl_freeMemory( pLocalFD );
646 : :
647 : 0 : if( nRet < 1 )
648 : 0 : continue;
649 : :
650 : : // clear wakeup pipe
651 : 0 : if( bWakeup )
652 : : {
653 : : char buf[4];
654 : 0 : while( read( pThis->m_nWakeupFiles[0], buf, sizeof( buf ) ) > 0 )
655 : : ;
656 : : SAL_INFO("vcl.sm", "file handles active in wakeup: " << nRet);
657 : 0 : if( nRet == 1 )
658 : 0 : continue;
659 : : }
660 : :
661 : : // check fd's after we obtained the lock
662 : 0 : osl::MutexGuard g(pThis->m_ICEMutex);
663 : 0 : if( pThis->m_nConnections > 0 && pThis->m_nConnections == nConnectionsBefore )
664 : : {
665 : 0 : nRet = poll( pThis->m_pFilehandles+1, pThis->m_nConnections, 0 );
666 : 0 : if( nRet > 0 )
667 : : {
668 : : SAL_INFO("vcl.sm", "IceProcessMessages");
669 : : Bool bReply;
670 : 0 : for( int i = 0; i < pThis->m_nConnections; i++ )
671 : 0 : if( pThis->m_pFilehandles[i+1].revents & POLLIN )
672 : 0 : IceProcessMessages( pThis->m_pConnections[i], NULL, &bReply );
673 : : }
674 : : }
675 : 0 : }
676 : : SAL_INFO("vcl.sm", "shutting down ICE dispatch thread");
677 : 0 : }
678 : :
679 : 0 : void ICEWatchProc(
680 : : IceConn ice_conn, IcePointer client_data, Bool opening,
681 : : SAL_UNUSED_PARAMETER IcePointer *)
682 : : {
683 : : // Note: This is a callback function for ICE; this implicitly means that a
684 : : // call into ICE lib is calling this, so the m_ICEMutex MUST already be
685 : : // locked by the caller.
686 : : ICEConnectionObserver * pThis = static_cast< ICEConnectionObserver * >(
687 : 0 : client_data);
688 : 0 : if( opening )
689 : : {
690 : 0 : int fd = IceConnectionNumber( ice_conn );
691 : 0 : pThis->m_nConnections++;
692 : 0 : pThis->m_pConnections = (IceConn*)rtl_reallocateMemory( pThis->m_pConnections, sizeof( IceConn )*pThis->m_nConnections );
693 : 0 : pThis->m_pFilehandles = (struct pollfd*)rtl_reallocateMemory( pThis->m_pFilehandles, sizeof( struct pollfd )*(pThis->m_nConnections+1) );
694 : 0 : pThis->m_pConnections[ pThis->m_nConnections-1 ] = ice_conn;
695 : 0 : pThis->m_pFilehandles[ pThis->m_nConnections ].fd = fd;
696 : 0 : pThis->m_pFilehandles[ pThis->m_nConnections ].events = POLLIN;
697 : 0 : if( pThis->m_nConnections == 1 )
698 : : {
699 : 0 : if (!pipe(pThis->m_nWakeupFiles))
700 : : {
701 : : int flags;
702 : 0 : pThis->m_pFilehandles[0].fd = pThis->m_nWakeupFiles[0];
703 : 0 : pThis->m_pFilehandles[0].events = POLLIN;
704 : : // set close-on-exec and nonblock descriptor flag.
705 : 0 : if ((flags = fcntl(pThis->m_nWakeupFiles[0], F_GETFD)) != -1)
706 : : {
707 : 0 : flags |= FD_CLOEXEC;
708 : 0 : fcntl(pThis->m_nWakeupFiles[0], F_SETFD, flags);
709 : : }
710 : 0 : if ((flags = fcntl(pThis->m_nWakeupFiles[0], F_GETFL)) != -1)
711 : : {
712 : 0 : flags |= O_NONBLOCK;
713 : 0 : fcntl(pThis->m_nWakeupFiles[0], F_SETFL, flags);
714 : : }
715 : : // set close-on-exec and nonblock descriptor flag.
716 : 0 : if ((flags = fcntl(pThis->m_nWakeupFiles[1], F_GETFD)) != -1)
717 : : {
718 : 0 : flags |= FD_CLOEXEC;
719 : 0 : fcntl(pThis->m_nWakeupFiles[1], F_SETFD, flags);
720 : : }
721 : 0 : if ((flags = fcntl(pThis->m_nWakeupFiles[1], F_GETFL)) != -1)
722 : : {
723 : 0 : flags |= O_NONBLOCK;
724 : 0 : fcntl(pThis->m_nWakeupFiles[1], F_SETFL, flags);
725 : : }
726 : : pThis->m_ICEThread = osl_createThread(
727 : 0 : ICEConnectionWorker, pThis);
728 : : }
729 : : }
730 : : }
731 : : else // closing
732 : : {
733 : 0 : for( int i = 0; i < pThis->m_nConnections; i++ )
734 : : {
735 : 0 : if( pThis->m_pConnections[i] == ice_conn )
736 : : {
737 : 0 : if( i < pThis->m_nConnections-1 )
738 : : {
739 : 0 : rtl_moveMemory( pThis->m_pConnections+i, pThis->m_pConnections+i+1, sizeof( IceConn )*(pThis->m_nConnections-i-1) );
740 : 0 : rtl_moveMemory( pThis->m_pFilehandles+i+1, pThis->m_pFilehandles+i+2, sizeof( struct pollfd )*(pThis->m_nConnections-i-1) );
741 : : }
742 : 0 : pThis->m_nConnections--;
743 : 0 : pThis->m_pConnections = (IceConn*)rtl_reallocateMemory( pThis->m_pConnections, sizeof( IceConn )*pThis->m_nConnections );
744 : 0 : pThis->m_pFilehandles = (struct pollfd*)rtl_reallocateMemory( pThis->m_pFilehandles, sizeof( struct pollfd )*(pThis->m_nConnections+1) );
745 : 0 : break;
746 : : }
747 : : }
748 : 0 : if( pThis->m_nConnections == 0 && pThis->m_ICEThread )
749 : : {
750 : : SAL_INFO("vcl.sm", "terminating ICEThread");
751 : 0 : oslThread t = pThis->m_ICEThread;
752 : 0 : pThis->m_ICEThread = NULL;
753 : :
754 : : // must release the mutex here
755 : 0 : pThis->m_ICEMutex.release();
756 : :
757 : 0 : pThis->terminate(t);
758 : :
759 : : // acquire the mutex again, because the caller does not expect
760 : : // it to be released when calling into SM
761 : 0 : pThis->m_ICEMutex.acquire();
762 : : }
763 : : }
764 : : SAL_INFO( "vcl.sm", "ICE connection on " << IceConnectionNumber( ice_conn ) << " " << (opening ? "inserted" : "removed"));
765 : : SAL_INFO( "vcl.sm", "Display connection is " << ConnectionNumber( GetGenericData()->GetSalDisplay()->GetDisplay() ) );
766 : 0 : }
767 : :
768 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|