Version 5.4.3.2, tag libreoffice-5.4.3.2
[LibreOffice.git] / vcl / headless / svpinst.cxx
blob8e9cdbc9543cbf609123222bdbfe10b735f37df5
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 <unistd.h>
21 #include <errno.h>
22 #include <fcntl.h>
23 #include <pthread.h>
24 #include <sys/time.h>
25 #include <sys/poll.h>
27 #include <sal/types.h>
29 #include <vcl/inputtypes.hxx>
30 #include <vcl/opengl/OpenGLContext.hxx>
32 #include <headless/svpinst.hxx>
33 #include <headless/svpframe.hxx>
34 #include <headless/svpdummies.hxx>
35 #include <headless/svpvd.hxx>
36 #ifdef IOS
37 #include <quartz/salbmp.h>
38 #include <quartz/salgdi.h>
39 #include <quartz/salvd.h>
40 #endif
41 #include <headless/svpbmp.hxx>
42 #include <headless/svpgdi.hxx>
44 #include "salframe.hxx"
45 #include "svdata.hxx"
46 #include "unx/gendata.hxx"
47 // FIXME: remove when we re-work the svp mainloop
48 #include "unx/salunxtime.h"
50 bool SvpSalInstance::isFrameAlive( const SalFrame* pFrame ) const
52 for( std::list< SalFrame* >::const_iterator it = m_aFrames.begin();
53 it != m_aFrames.end(); ++it )
55 if( *it == pFrame )
57 return true;
60 return false;
63 SvpSalInstance* SvpSalInstance::s_pDefaultInstance = nullptr;
65 #if !defined(ANDROID) && !defined(IOS)
67 static void atfork_child()
69 if (SvpSalInstance::s_pDefaultInstance != nullptr)
71 SvpSalInstance::s_pDefaultInstance->CloseWakeupPipe(false);
72 SvpSalInstance::s_pDefaultInstance->CreateWakeupPipe(false);
76 #endif
78 SvpSalInstance::SvpSalInstance( SalYieldMutex *pMutex ) :
79 SalGenericInstance( pMutex )
81 m_aTimeout.tv_sec = 0;
82 m_aTimeout.tv_usec = 0;
83 m_nTimeoutMS = 0;
85 #ifndef IOS
86 m_pTimeoutFDS[0] = m_pTimeoutFDS[1] = -1;
87 CreateWakeupPipe(true);
88 #endif
89 if( s_pDefaultInstance == nullptr )
90 s_pDefaultInstance = this;
91 #if !defined(ANDROID) && !defined(IOS)
92 pthread_atfork(nullptr, nullptr, atfork_child);
93 #endif
96 SvpSalInstance::~SvpSalInstance()
98 if( s_pDefaultInstance == this )
99 s_pDefaultInstance = nullptr;
100 #ifndef IOS
101 CloseWakeupPipe(true);
102 #endif
105 #ifndef IOS
107 void SvpSalInstance::CloseWakeupPipe(bool log)
109 if (m_pTimeoutFDS[0] != -1)
111 if (log)
113 SAL_INFO("vcl.headless", "CloseWakeupPipe: Closing inherited wakeup pipe: [" << m_pTimeoutFDS[0] << "," << m_pTimeoutFDS[1] << "]");
115 close (m_pTimeoutFDS[0]);
116 close (m_pTimeoutFDS[1]);
117 m_pTimeoutFDS[0] = m_pTimeoutFDS[1] = -1;
121 void SvpSalInstance::CreateWakeupPipe(bool log)
123 if (pipe (m_pTimeoutFDS) == -1)
125 if (log)
127 SAL_WARN("vcl.headless", "Could not create wakeup pipe: " << strerror(errno));
130 else
132 if (log)
134 SAL_INFO("vcl.headless", "CreateWakeupPipe: Created wakeup pipe: [" << m_pTimeoutFDS[0] << "," << m_pTimeoutFDS[1] << "]");
137 // initialize 'wakeup' pipe.
138 int flags;
140 // set close-on-exec descriptor flag.
141 if ((flags = fcntl (m_pTimeoutFDS[0], F_GETFD)) != -1)
143 flags |= FD_CLOEXEC;
144 (void)fcntl(m_pTimeoutFDS[0], F_SETFD, flags);
146 if ((flags = fcntl (m_pTimeoutFDS[1], F_GETFD)) != -1)
148 flags |= FD_CLOEXEC;
149 (void)fcntl(m_pTimeoutFDS[1], F_SETFD, flags);
152 // set non-blocking I/O flag.
153 if ((flags = fcntl(m_pTimeoutFDS[0], F_GETFL)) != -1)
155 flags |= O_NONBLOCK;
156 (void)fcntl(m_pTimeoutFDS[0], F_SETFL, flags);
158 if ((flags = fcntl(m_pTimeoutFDS[1], F_GETFL)) != -1)
160 flags |= O_NONBLOCK;
161 (void)fcntl(m_pTimeoutFDS[1], F_SETFL, flags);
166 #endif
168 void SvpSalInstance::PostEvent(const SalFrame* pFrame, ImplSVEvent* pData, SalEvent nEvent)
171 osl::MutexGuard g(m_aEventGuard);
172 m_aUserEvents.push_back( SalUserEvent( pFrame, pData, nEvent ) );
174 Wakeup();
177 #ifdef ANDROID
178 bool SvpSalInstance::PostedEventsInQueue()
180 bool result = false;
182 osl::MutexGuard g(m_aEventGuard);
183 result = m_aUserEvents.size() > 0;
185 return result;
187 #endif
189 void SvpSalInstance::deregisterFrame( SalFrame* pFrame )
191 m_aFrames.remove( pFrame );
193 osl::MutexGuard g(m_aEventGuard);
194 // cancel outstanding events for this frame
195 if( ! m_aUserEvents.empty() )
197 std::list< SalUserEvent >::iterator it = m_aUserEvents.begin();
200 if( it->m_pFrame == pFrame )
202 if (it->m_nEvent == SalEvent::UserEvent)
204 delete it->m_pData;
206 it = m_aUserEvents.erase( it );
208 else
209 ++it;
210 } while( it != m_aUserEvents.end() );
214 void SvpSalInstance::Wakeup()
216 #ifndef IOS
217 OSL_VERIFY(write (m_pTimeoutFDS[1], "", 1) == 1);
218 #endif
221 bool SvpSalInstance::CheckTimeout( bool bExecuteTimers )
223 bool bRet = false;
224 if( m_aTimeout.tv_sec ) // timer is started
226 timeval aTimeOfDay;
227 gettimeofday( &aTimeOfDay, nullptr );
228 if( aTimeOfDay >= m_aTimeout )
230 bRet = true;
231 if( bExecuteTimers )
233 // timed out, update timeout
234 m_aTimeout = aTimeOfDay;
235 m_aTimeout += m_nTimeoutMS;
237 osl::Guard< comphelper::SolarMutex > aGuard( mpSalYieldMutex.get() );
239 // notify
240 ImplSVData* pSVData = ImplGetSVData();
241 if( pSVData->mpSalTimer )
243 bool idle = true; // TODO
244 pSVData->mpSalTimer->CallCallback( idle );
249 return bRet;
252 SalFrame* SvpSalInstance::CreateChildFrame( SystemParentData* /*pParent*/, SalFrameStyleFlags nStyle )
254 return new SvpSalFrame( this, nullptr, nStyle );
257 SalFrame* SvpSalInstance::CreateFrame( SalFrame* pParent, SalFrameStyleFlags nStyle )
259 return new SvpSalFrame( this, pParent, nStyle );
262 void SvpSalInstance::DestroyFrame( SalFrame* pFrame )
264 delete pFrame;
267 SalObject* SvpSalInstance::CreateObject( SalFrame*, SystemWindowData*, bool )
269 return new SvpSalObject();
272 void SvpSalInstance::DestroyObject( SalObject* pObject )
274 delete pObject;
277 #ifndef IOS
279 SalVirtualDevice* SvpSalInstance::CreateVirtualDevice( SalGraphics* /* pGraphics */,
280 long &nDX, long &nDY,
281 DeviceFormat eFormat,
282 const SystemGraphicsData* /* pData */ )
284 SvpSalVirtualDevice* pNew = new SvpSalVirtualDevice(eFormat, 1);
285 pNew->SetSize( nDX, nDY );
286 return pNew;
289 #endif
291 SalTimer* SvpSalInstance::CreateSalTimer()
293 return new SvpSalTimer( this );
296 SalSystem* SvpSalInstance::CreateSalSystem()
298 return new SvpSalSystem();
301 SalBitmap* SvpSalInstance::CreateSalBitmap()
303 #ifdef IOS
304 return new QuartzSalBitmap();
305 #else
306 return new SvpSalBitmap();
307 #endif
310 SalYieldResult SvpSalInstance::DoYield(bool bWait, bool bHandleAllCurrentEvents, sal_uLong const nReleased)
312 (void) nReleased;
313 assert(nReleased == 0); // not implemented
314 // first, check for already queued events.
316 // release yield mutex
317 std::list< SalUserEvent > aEvents;
318 sal_uLong nAcquireCount = ReleaseYieldMutex();
320 osl::MutexGuard g(m_aEventGuard);
321 if( ! m_aUserEvents.empty() )
323 if( bHandleAllCurrentEvents )
325 aEvents = m_aUserEvents;
326 m_aUserEvents.clear();
328 else
330 aEvents.push_back( m_aUserEvents.front() );
331 m_aUserEvents.pop_front();
335 // acquire yield mutex again
336 AcquireYieldMutex( nAcquireCount );
338 bool bEvent = !aEvents.empty();
339 if( bEvent )
341 for( std::list<SalUserEvent>::const_iterator it = aEvents.begin(); it != aEvents.end(); ++it )
343 if ( isFrameAlive( it->m_pFrame ) )
345 it->m_pFrame->CallCallback( it->m_nEvent, it->m_pData );
346 if( it->m_nEvent == SalEvent::Resize )
348 // this would be a good time to post a paint
349 const SvpSalFrame* pSvpFrame = static_cast<const SvpSalFrame*>(it->m_pFrame);
350 pSvpFrame->PostPaint();
356 bEvent = CheckTimeout() || bEvent;
358 if (bWait && ! bEvent )
360 int nTimeoutMS = 0;
361 if (m_aTimeout.tv_sec) // Timer is started.
363 timeval Timeout;
364 // determine remaining timeout.
365 gettimeofday (&Timeout, nullptr);
366 nTimeoutMS = (m_aTimeout.tv_sec - Timeout.tv_sec) * 1000
367 + m_aTimeout.tv_usec/1000 - Timeout.tv_usec/1000;
368 if( nTimeoutMS < 0 )
369 nTimeoutMS = 0;
371 else
372 nTimeoutMS = -1; // wait until something happens
374 DoReleaseYield(nTimeoutMS);
377 return bEvent ? SalYieldResult::EVENT :
378 SalYieldResult::TIMEOUT;
381 void SvpSalInstance::DoReleaseYield( int nTimeoutMS )
383 // poll
384 struct pollfd aPoll;
385 aPoll.fd = m_pTimeoutFDS[0];
386 aPoll.events = POLLIN;
387 aPoll.revents = 0;
389 // release yield mutex
390 sal_uLong nAcquireCount = ReleaseYieldMutex();
392 (void)poll( &aPoll, 1, nTimeoutMS );
394 // acquire yield mutex again
395 AcquireYieldMutex( nAcquireCount );
397 // clean up pipe
398 if( (aPoll.revents & POLLIN) != 0 )
400 int buffer;
401 while (read (m_pTimeoutFDS[0], &buffer, sizeof(buffer)) > 0)
402 continue;
406 bool SvpSalInstance::AnyInput( VclInputFlags nType )
408 if( nType & VclInputFlags::TIMER )
409 return CheckTimeout( false );
410 return false;
413 SalSession* SvpSalInstance::CreateSalSession()
415 return nullptr;
418 OUString SvpSalInstance::GetConnectionIdentifier()
420 return OUString();
423 void SvpSalInstance::StopTimer()
425 m_aTimeout.tv_sec = 0;
426 m_aTimeout.tv_usec = 0;
427 m_nTimeoutMS = 0;
430 void SvpSalInstance::StartTimer( sal_uLong nMS )
432 timeval aPrevTimeout (m_aTimeout);
433 gettimeofday (&m_aTimeout, nullptr);
435 m_nTimeoutMS = nMS;
436 m_aTimeout += m_nTimeoutMS;
438 if ((aPrevTimeout > m_aTimeout) || (aPrevTimeout.tv_sec == 0))
440 // Wakeup from previous timeout (or stopped timer).
441 Wakeup();
445 void SvpSalInstance::AddToRecentDocumentList(const OUString&, const OUString&, const OUString&)
449 //obviously doesn't actually do anything, its just a nonfunctional stub
451 #ifdef LIBO_HEADLESS
453 class SvpOpenGLContext
457 OpenGLContext* SvpSalInstance::CreateOpenGLContext()
459 return nullptr;
462 #else
464 class SvpOpenGLContext : public OpenGLContext
466 GLWindow m_aGLWin;
467 private:
468 virtual const GLWindow& getOpenGLWindow() const override { return m_aGLWin; }
469 virtual GLWindow& getModifiableOpenGLWindow() override { return m_aGLWin; }
472 OpenGLContext* SvpSalInstance::CreateOpenGLContext()
474 return new SvpOpenGLContext;
477 #endif
479 SvpSalTimer::~SvpSalTimer()
483 void SvpSalTimer::Stop()
485 m_pInstance->StopTimer();
488 void SvpSalTimer::Start( sal_uLong nMS )
490 m_pInstance->StartTimer( nMS );
493 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */