/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ #include "Qt5Instance.hxx" #include #include "Qt5Frame.hxx" #include "Qt5Data.hxx" #include "Qt5Timer.hxx" #include "Qt5VirtualDevice.hxx" #include "Qt5Object.hxx" #include "Qt5Bitmap.hxx" #include #include #include #include #include #include #include #include #include #include Qt5Instance::Qt5Instance( SalYieldMutex* pMutex, bool bUseCairo ) : SalGenericInstance( pMutex ) , m_postUserEventId( -1 ) , m_bUseCairo( bUseCairo ) { m_postUserEventId = QEvent::registerEventType(); // this one needs to be blocking, so that the handling in main thread // is processed before the thread emitting the signal continues connect( this, SIGNAL( ImplYieldSignal( bool, bool )), this, SLOT( ImplYield( bool, bool )), Qt::BlockingQueuedConnection ); } Qt5Instance::~Qt5Instance() { // force freeing the QApplication before freeing the arguments, // as it uses references to the provided arguments! m_pQApplication.reset(); for( int i = 0; i < *m_pFakeArgc; i++ ) free( m_pFakeArgvFreeable[i] ); } SalFrame* Qt5Instance::CreateChildFrame( SystemParentData* /*pParent*/, SalFrameStyleFlags nStyle ) { return new Qt5Frame( nullptr, nStyle, m_bUseCairo ); } SalFrame* Qt5Instance::CreateFrame( SalFrame* pParent, SalFrameStyleFlags nStyle ) { assert( !pParent || dynamic_cast( pParent ) ); return new Qt5Frame( static_cast( pParent ), nStyle, m_bUseCairo ); } void Qt5Instance::DestroyFrame( SalFrame* pFrame ) { delete pFrame; } SalObject* Qt5Instance::CreateObject( SalFrame* pParent, SystemWindowData*, bool bShow ) { assert( !pParent || dynamic_cast( pParent ) ); return new Qt5Object( static_cast( pParent ), bShow ); } void Qt5Instance::DestroyObject( SalObject* pObject ) { delete pObject; } SalVirtualDevice* Qt5Instance::CreateVirtualDevice( SalGraphics* /* pGraphics */, long &nDX, long &nDY, DeviceFormat eFormat, const SystemGraphicsData* /* pData */ ) { if ( m_bUseCairo ) { SvpSalVirtualDevice *pVD = new SvpSalVirtualDevice( eFormat, 1 ); pVD->SetSize( nDX, nDY ); return pVD; } else { Qt5VirtualDevice* pVD = new Qt5VirtualDevice( eFormat, 1 ); pVD->SetSize( nDX, nDY ); return pVD; } } SalTimer* Qt5Instance::CreateSalTimer() { return new Qt5Timer(); } SalSystem* Qt5Instance::CreateSalSystem() { return new SvpSalSystem(); } SalBitmap* Qt5Instance::CreateSalBitmap() { if ( m_bUseCairo ) return new SvpSalBitmap(); else return new Qt5Bitmap(); } bool Qt5Instance::ImplYield( bool bWait, bool bHandleAllCurrentEvents ) { bool wasEvent = DispatchUserEvents( bHandleAllCurrentEvents ); if ( !bHandleAllCurrentEvents && wasEvent ) return true; /** * Quoting the Qt docs: [QAbstractEventDispatcher::processEvents] processes * pending events that match flags until there are no more events to process. */ QAbstractEventDispatcher* dispatcher = QAbstractEventDispatcher::instance( qApp->thread()); if ( bWait && !wasEvent ) wasEvent = dispatcher->processEvents( QEventLoop::WaitForMoreEvents ); else wasEvent = dispatcher->processEvents( QEventLoop::AllEvents ) || wasEvent; return wasEvent; } bool Qt5Instance::DoYield(bool bWait, bool bHandleAllCurrentEvents) { bool bWasEvent = false; if( qApp->thread() == QThread::currentThread() ) { bWasEvent = ImplYield( bWait, bHandleAllCurrentEvents ); if ( bWasEvent ) m_aWaitingYieldCond.set(); } else { { SolarMutexReleaser aReleaser; bWasEvent = Q_EMIT ImplYieldSignal( false, bHandleAllCurrentEvents ); } if ( !bWasEvent && bWait ) { m_aWaitingYieldCond.reset(); SolarMutexReleaser aReleaser; m_aWaitingYieldCond.wait(); bWasEvent = true; } } return bWasEvent; } bool Qt5Instance::AnyInput( VclInputFlags nType ) { return false; } SalSession* Qt5Instance::CreateSalSession() { return nullptr; } OUString Qt5Instance::GetConnectionIdentifier() { return OUString(); } void Qt5Instance::AddToRecentDocumentList(const OUString&, const OUString&, const OUString&) { } OpenGLContext* Qt5Instance::CreateOpenGLContext() { return nullptr; } bool Qt5Instance::IsMainThread() const { return qApp->thread() != QThread::currentThread(); } void Qt5Instance::TriggerUserEventProcessing() { QApplication::postEvent(this, new QEvent(QEvent::Type( m_postUserEventId ))); } void Qt5Instance::ProcessEvent( SalUserEvent aEvent ) { aEvent.m_pFrame->CallCallback( aEvent.m_nEvent, aEvent.m_pData ); } extern "C" { VCLPLUG_QT5_PUBLIC SalInstance* create_SalInstance() { OString aVersion( qVersion() ); SAL_INFO( "vcl.qt5", "qt version string is " << aVersion ); QApplication *pQApplication; char **pFakeArgvFreeable = nullptr; int nFakeArgc = 2; const sal_uInt32 nParams = osl_getCommandArgCount(); OString aDisplay; OUString aParam, aBin; for ( sal_uInt32 nIdx = 0; nIdx < nParams; ++nIdx ) { osl_getCommandArg( nIdx, &aParam.pData ); if ( aParam != "-display" ) continue; if ( !pFakeArgvFreeable ) { pFakeArgvFreeable = new char*[ nFakeArgc + 2 ]; pFakeArgvFreeable[ nFakeArgc++ ] = strdup( "-display" ); } else free( pFakeArgvFreeable[ nFakeArgc ] ); ++nIdx; osl_getCommandArg( nIdx, &aParam.pData ); aDisplay = OUStringToOString( aParam, osl_getThreadTextEncoding() ); pFakeArgvFreeable[ nFakeArgc ] = strdup( aDisplay.getStr() ); } if ( !pFakeArgvFreeable ) pFakeArgvFreeable = new char*[ nFakeArgc ]; else nFakeArgc++; osl_getExecutableFile( &aParam.pData ); osl_getSystemPathFromFileURL( aParam.pData, &aBin.pData ); OString aExec = OUStringToOString( aBin, osl_getThreadTextEncoding() ); pFakeArgvFreeable[ 0 ] = strdup( aExec.getStr() ); pFakeArgvFreeable[ 1 ] = strdup( "--nocrashhandler" ); char **pFakeArgv = new char*[ nFakeArgc ]; for( int i = 0; i < nFakeArgc; i++ ) pFakeArgv[ i ] = pFakeArgvFreeable[ i ]; char* session_manager = nullptr; if( getenv( "SESSION_MANAGER" ) != nullptr ) { session_manager = strdup( getenv( "SESSION_MANAGER" )); unsetenv( "SESSION_MANAGER" ); } int * pFakeArgc = new int; *pFakeArgc = nFakeArgc; pQApplication = new QApplication( *pFakeArgc, pFakeArgv ); if( session_manager != nullptr ) { // coverity[tainted_string] - trusted source for setenv setenv( "SESSION_MANAGER", session_manager, 1 ); free( session_manager ); } QApplication::setQuitOnLastWindowClosed(false); const bool bUseCairo = (nullptr != getenv( "SAL_VCL_QT5_USE_CAIRO" )); Qt5Instance* pInstance = new Qt5Instance( new SalYieldMutex(), bUseCairo ); // initialize SalData new Qt5Data( pInstance ); pInstance->m_pQApplication.reset( pQApplication ); pInstance->m_pFakeArgvFreeable.reset( pFakeArgvFreeable ); pInstance->m_pFakeArgv.reset( pFakeArgv ); pInstance->m_pFakeArgc.reset( pFakeArgc ); return pInstance; } } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */