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 .
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>
37 #include <quartz/salbmp.h>
38 #include <quartz/salgdi.h>
39 #include <quartz/salvd.h>
41 #include <headless/svpbmp.hxx>
42 #include <headless/svpgdi.hxx>
44 #include "salframe.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
)
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);
78 SvpSalInstance::SvpSalInstance( SalYieldMutex
*pMutex
) :
79 SalGenericInstance( pMutex
)
81 m_aTimeout
.tv_sec
= 0;
82 m_aTimeout
.tv_usec
= 0;
86 m_pTimeoutFDS
[0] = m_pTimeoutFDS
[1] = -1;
87 CreateWakeupPipe(true);
89 if( s_pDefaultInstance
== nullptr )
90 s_pDefaultInstance
= this;
91 #if !defined(ANDROID) && !defined(IOS)
92 pthread_atfork(nullptr, nullptr, atfork_child
);
96 SvpSalInstance::~SvpSalInstance()
98 if( s_pDefaultInstance
== this )
99 s_pDefaultInstance
= nullptr;
101 CloseWakeupPipe(true);
107 void SvpSalInstance::CloseWakeupPipe(bool log
)
109 if (m_pTimeoutFDS
[0] != -1)
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)
127 SAL_WARN("vcl.headless", "Could not create wakeup pipe: " << strerror(errno
));
134 SAL_INFO("vcl.headless", "CreateWakeupPipe: Created wakeup pipe: [" << m_pTimeoutFDS
[0] << "," << m_pTimeoutFDS
[1] << "]");
137 // initialize 'wakeup' pipe.
140 // set close-on-exec descriptor flag.
141 if ((flags
= fcntl (m_pTimeoutFDS
[0], F_GETFD
)) != -1)
144 (void)fcntl(m_pTimeoutFDS
[0], F_SETFD
, flags
);
146 if ((flags
= fcntl (m_pTimeoutFDS
[1], F_GETFD
)) != -1)
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)
156 (void)fcntl(m_pTimeoutFDS
[0], F_SETFL
, flags
);
158 if ((flags
= fcntl(m_pTimeoutFDS
[1], F_GETFL
)) != -1)
161 (void)fcntl(m_pTimeoutFDS
[1], F_SETFL
, flags
);
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
) );
178 bool SvpSalInstance::PostedEventsInQueue()
182 osl::MutexGuard
g(m_aEventGuard
);
183 result
= m_aUserEvents
.size() > 0;
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
)
206 it
= m_aUserEvents
.erase( it
);
210 } while( it
!= m_aUserEvents
.end() );
214 void SvpSalInstance::Wakeup()
217 OSL_VERIFY(write (m_pTimeoutFDS
[1], "", 1) == 1);
221 bool SvpSalInstance::CheckTimeout( bool bExecuteTimers
)
224 if( m_aTimeout
.tv_sec
) // timer is started
227 gettimeofday( &aTimeOfDay
, nullptr );
228 if( aTimeOfDay
>= m_aTimeout
)
233 // timed out, update timeout
234 m_aTimeout
= aTimeOfDay
;
235 m_aTimeout
+= m_nTimeoutMS
;
237 osl::Guard
< comphelper::SolarMutex
> aGuard( mpSalYieldMutex
.get() );
240 ImplSVData
* pSVData
= ImplGetSVData();
241 if( pSVData
->mpSalTimer
)
243 bool idle
= true; // TODO
244 pSVData
->mpSalTimer
->CallCallback( idle
);
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
)
267 SalObject
* SvpSalInstance::CreateObject( SalFrame
*, SystemWindowData
*, bool )
269 return new SvpSalObject();
272 void SvpSalInstance::DestroyObject( SalObject
* pObject
)
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
);
291 SalTimer
* SvpSalInstance::CreateSalTimer()
293 return new SvpSalTimer( this );
296 SalSystem
* SvpSalInstance::CreateSalSystem()
298 return new SvpSalSystem();
301 SalBitmap
* SvpSalInstance::CreateSalBitmap()
304 return new QuartzSalBitmap();
306 return new SvpSalBitmap();
310 SalYieldResult
SvpSalInstance::DoYield(bool bWait
, bool bHandleAllCurrentEvents
, sal_uLong
const 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();
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();
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
)
361 if (m_aTimeout
.tv_sec
) // Timer is started.
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;
372 nTimeoutMS
= -1; // wait until something happens
374 DoReleaseYield(nTimeoutMS
);
377 return bEvent
? SalYieldResult::EVENT
:
378 SalYieldResult::TIMEOUT
;
381 void SvpSalInstance::DoReleaseYield( int nTimeoutMS
)
385 aPoll
.fd
= m_pTimeoutFDS
[0];
386 aPoll
.events
= POLLIN
;
389 // release yield mutex
390 sal_uLong nAcquireCount
= ReleaseYieldMutex();
392 (void)poll( &aPoll
, 1, nTimeoutMS
);
394 // acquire yield mutex again
395 AcquireYieldMutex( nAcquireCount
);
398 if( (aPoll
.revents
& POLLIN
) != 0 )
401 while (read (m_pTimeoutFDS
[0], &buffer
, sizeof(buffer
)) > 0)
406 bool SvpSalInstance::AnyInput( VclInputFlags nType
)
408 if( nType
& VclInputFlags::TIMER
)
409 return CheckTimeout( false );
413 SalSession
* SvpSalInstance::CreateSalSession()
418 OUString
SvpSalInstance::GetConnectionIdentifier()
423 void SvpSalInstance::StopTimer()
425 m_aTimeout
.tv_sec
= 0;
426 m_aTimeout
.tv_usec
= 0;
430 void SvpSalInstance::StartTimer( sal_uLong nMS
)
432 timeval
aPrevTimeout (m_aTimeout
);
433 gettimeofday (&m_aTimeout
, nullptr);
436 m_aTimeout
+= m_nTimeoutMS
;
438 if ((aPrevTimeout
> m_aTimeout
) || (aPrevTimeout
.tv_sec
== 0))
440 // Wakeup from previous timeout (or stopped timer).
445 void SvpSalInstance::AddToRecentDocumentList(const OUString
&, const OUString
&, const OUString
&)
449 //obviously doesn't actually do anything, its just a nonfunctional stub
453 class SvpOpenGLContext
457 OpenGLContext
* SvpSalInstance::CreateOpenGLContext()
464 class SvpOpenGLContext
: public OpenGLContext
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
;
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: */