/* -*- 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 .
*/
// keycodes handled internally by VCL
vcl::KeyCode const ReservedKeys[]
{
vcl::KeyCode(KEY_F1,0) , // Help
vcl::KeyCode(KEY_F1,KEY_SHIFT) , // Context help
vcl::KeyCode(KEY_F2,KEY_SHIFT) , // Activate extended tooltips
vcl::KeyCode(KEY_F4,KEY_MOD1) , // Close document
vcl::KeyCode(KEY_F4,KEY_MOD2) , // Close document
vcl::KeyCode(KEY_F6,0) , // Set focus to next visible subwindow
vcl::KeyCode(KEY_F6,KEY_MOD1) , // Set focus to the document canvas/data source
vcl::KeyCode(KEY_F6,KEY_SHIFT) , // Set focus to previous subwindow
vcl::KeyCode(KEY_F10,0) // Activate the first menu
};
Application::~Application()
{
ImplDeInitSVData();
ImplGetSVData()->mpApp = nullptr; #ifdef DBG_UTIL // Due to // svx/source/dialog/framelinkarray.cxx // class Cell final : public SfxPoolItem // const Cell OBJ_CELL_NONE; // being a static held SfxPoolItem which is not yet de-initialized here // number often is (1), even higher with other modules loaded (like 5). // These get de-allocated reliably in module-deinitializations, so this // is no memory loss. These counters are more to be able to have an eye // on amounts of SfxPoolItems used during office usage and to be able to // detect if an error in future changes may lead to memory losses - these // would show in dramatically higher numbers then immediately
SAL_INFO("vcl.items", "ITEM: " << getAllocatedSfxPoolItemCount() << " SfxPoolItems still allocated at shutdown");
SAL_INFO("vcl.items", "ITEM: " << getUsedSfxPoolItemCount() << " SfxPoolItems were incarnated during runtime");
// Same mechanism for SfxItemSet(s)
SAL_INFO("vcl.items", "ITEM: " << getAllocatedSfxItemSetCount() << " SfxItemSets still allocated at shutdown");
SAL_INFO("vcl.items", "ITEM: " << getUsedSfxItemSetCount() << " SfxItemSets were incarnated during runtime");
// Same mechanism for PoolItemHolder(s)
SAL_INFO("vcl.items", "ITEM: " << getAllocatedSfxPoolItemHolderCount() << " SfxPoolItemHolders still allocated at shutdown");
SAL_INFO("vcl.items", "ITEM: " << getUsedSfxPoolItemHolderCount() << " SfxPoolItemHolders were incarnated during runtime");
// Additional call to list still incarnated SfxPoolItems (under 'svl.items')
listAllocatedSfxPoolItems();
// List SfxPoolItems with highest RefCounts, these are the best // candidates to add a ItemInstanceManager mechanism
listSfxPoolItemsWithHighestUsage(20);
listSfxItemSetUsage(); #endif
}
int Application::Main()
{
SAL_WARN("vcl", "Application is a base class and should be overridden."); return EXIT_SUCCESS;
}
OUString Application::GetAppFileName()
{
ImplSVData* pSVData = ImplGetSVData();
SAL_WARN_IF( !pSVData->maAppData.mxAppFileName, "vcl", "AppFileName should be set to something after SVMain!" ); if ( pSVData->maAppData.mxAppFileName ) return *pSVData->maAppData.mxAppFileName;
/* * provide a fallback for people without initialized vcl here (like setup * in responsefile mode)
*/
OUString aAppFileName;
OUString aExeFileName;
osl_getExecutableFile(&aExeFileName.pData);
// convert path to native file format
osl::FileBase::getSystemPathFromFileURL(aExeFileName, aAppFileName);
return aAppFileName;
}
void Application::Exception( ExceptionCategory nCategory )
{ switch ( nCategory )
{ // System has precedence (so do nothing) case ExceptionCategory::System: case ExceptionCategory::UserInterface: break; default:
Abort(u"Unknown Error"_ustr); break;
}
}
void Application::Abort( const OUString& rErrorText )
{ //HACK: Dump core iff --norestore command line argument is given (assuming // this process is run by developers who are interested in cores, vs. end // users who are not): #if OSL_DEBUG_LEVEL > 0 bool dumpCore = true; #else bool dumpCore = false;
sal_uInt16 n = GetCommandLineParamCount(); for (sal_uInt16 i = 0; i != n; ++i) { if (GetCommandLineParam(i) == "--norestore") {
dumpCore = true; break;
}
} #endif
int nExitCode = 0; if (!pSVData->mpDefInst->DoExecute(nExitCode))
{ if (Application::IsUseSystemEventLoop())
{
SAL_WARN("vcl.schedule", "Can't omit DoExecute when running on system event loop!");
std::abort();
} while (!pSVData->maAppData.mbAppQuit)
{
Application::Yield();
SolarMutexReleaser releaser; // Give a chance for the waiting threads to lock the mutex
pSVData->m_inExecuteCondtion.set();
}
}
// there's a data race here on WNT only because ImplYield may be // called without SolarMutex; but the only remaining use of mnDispatchLevel // is in OSX specific code
pSVData->maAppData.mnDispatchLevel++;
// do not wait for events if application was already quit; in that // case only dispatch events already available bool bProcessedEvent = pSVData->mpDefInst->DoYield(
i_bWait && !pSVData->maAppData.mbAppQuit, i_bAllEvents );
pSVData->maAppData.mnDispatchLevel--;
DBG_TESTSOLARMUTEX(); // must be locked on return from Yield
void Scheduler::ProcessEventsToIdle()
{ #if OSL_DEBUG_LEVEL > 0 const ImplSVData* pSVData = ImplGetSVData(); if (pSVData->mpDefInst->IsMainThread())
assert(pSVData->maSchedCtx.mnIdlesLockCount == 0); #endif int nSanity = 1; while (ImplYield(false, true))
{ if (0 == ++nSanity % 1000)
{
SAL_WARN("vcl.schedule", "ProcessEventsToIdle: " << nSanity);
}
} #if OSL_DEBUG_LEVEL > 0 // If we yield from a non-main thread we just can guarantee that all idle // events were processed at some point, but our check can't prevent further // processing in the main thread, which may add new events, so skip it. if ( !pSVData->mpDefInst->IsMainThread() ) return; for (int nTaskPriority = 0; nTaskPriority < PRIO_COUNT; ++nTaskPriority)
{ const ImplSchedulerData* pSchedulerData = pSVData->maSchedCtx.mpFirstSchedulerData[nTaskPriority]; while (pSchedulerData)
{
assert(!pSchedulerData->mbInScheduler); if (pSchedulerData->mpTask)
{
Idle *pIdle = dynamic_cast<Idle*>(pSchedulerData->mpTask); if (pIdle && pIdle->IsActive())
{
SAL_WARN("vcl.schedule", "Unprocessed Idle: "
<< pIdle << " "
<< (pIdle->GetDebugName() ? pIdle->GetDebugName() : "(nullptr)"));
}
}
pSchedulerData = pSchedulerData->mpNext;
}
} #endif
}
extern"C" { /// used by unit tests that test only via the LOK API
SAL_DLLPUBLIC_EXPORT void unit_lok_process_events_to_idle()
{ const SolarMutexGuard aGuard;
Scheduler::ProcessEventsToIdle();
}
}
// If mouse was captured, or if in tracking- or in select-mode of a floatingwindow (e.g. menus // or pulldown toolboxes) another window should be created // D&D active !!! return pSVData->mpWinData->mpCaptureWin || pSVData->mpWinData->mpTrackWin
|| pSVData->mpWinData->mpFirstFloat || nImplSysDialog;
}
if( pWin && pMouseEvent )
{
Point aTransformedPos( pMouseEvent->GetPosPixel() );
// LOK uses (0, 0) as the origin of all windows; don't offset. if (!comphelper::LibreOfficeKit::isActive())
{
aTransformedPos.AdjustX(pWin->GetOutOffXPixel());
aTransformedPos.AdjustY(pWin->GetOutOffYPixel());
}
// remove this event from list of posted events, watch for destruction of internal data auto svdata = ImplGetSVData();
::std::vector< ImplPostEventPair >::iterator aIter( svdata->maAppData.maPostedEventList.begin() );
// remove all events for specific window, watch for destruction of internal data auto svdata = ImplGetSVData();
::std::vector< ImplPostEventPair >::iterator aIter( svdata->maAppData.maPostedEventList.begin() );
if (bSelection != hwEnv) {
appendDetails(u"; ", Localize(SV_APP_UIRENDER, bLocalize)); #if HAVE_FEATURE_SKIA if ( SkiaHelper::isVCLSkiaEnabled() )
{ switch(SkiaHelper::renderMethodToUse())
{ case SkiaHelper::RenderVulkan:
appendDetails(u"", Localize(SV_APP_SKIA_VULKAN, bLocalize)); break; case SkiaHelper::RenderMetal:
appendDetails(u"", Localize(SV_APP_SKIA_METAL, bLocalize)); break; case SkiaHelper::RenderRaster:
appendDetails(u"", Localize(SV_APP_SKIA_RASTER, bLocalize)); break;
}
} else #endif
appendDetails(u"", Localize(SV_APP_DEFAULT, bLocalize));
#if (defined LINUX || defined _WIN32 || defined MACOSX || defined __FreeBSD__ || defined EMSCRIPTEN)
appendDetails(u"; ", SV_APP_VCLBACKEND + GetToolkitName()); #endif
}
unsignedint Application::GetDisplayExternalScreen()
{ // This is really unpleasant, in theory we could have multiple // external displays etc. int nExternal(0); switch (GetDisplayBuiltInScreen())
{ case 0:
nExternal = 1; break; case 1:
nExternal = 0; break; default: // When the built-in display is neither 0 nor 1 // then place the full-screen presentation on the // first available screen.
nExternal = 0; break;
} return nExternal;
}
unsignedint Application::GetBestScreen( const AbsoluteScreenPixelRectangle& i_rRect )
{ constunsignedint nScreens = GetScreenCount(); unsignedint nBestMatchScreen = 0; unsignedlong nOverlap = 0; for( unsignedint i = 0; i < nScreens; i++ )
{ const AbsoluteScreenPixelRectangle aCurScreenRect( GetScreenPosSizePixel( i ) ); // if a screen contains the rectangle completely it is obviously the best screen if( aCurScreenRect.Contains( i_rRect ) ) return i; // next the screen which contains most of the area of the rect is the best
AbsoluteScreenPixelRectangle aIntersection( aCurScreenRect.GetIntersection( i_rRect ) ); if( ! aIntersection.IsEmpty() )
{ constunsignedlong nCurOverlap( aIntersection.GetWidth() * aIntersection.GetHeight() ); if( nCurOverlap > nOverlap )
{
nOverlap = nCurOverlap;
nBestMatchScreen = i;
}
}
} if( nOverlap > 0 ) return nBestMatchScreen;
// finally the screen which center is nearest to the rect is the best const AbsoluteScreenPixelPoint aCenter( (i_rRect.Left() + i_rRect.Right())/2,
(i_rRect.Top() + i_rRect.Bottom())/2 );
tools::Long nDist = std::numeric_limits<tools::Long>::max(); for( unsignedint i = 0; i < nScreens; i++ )
{ const AbsoluteScreenPixelRectangle aCurScreenRect( GetScreenPosSizePixel( i ) ); const tools::Long nCurDist( calcDistSquare( aCenter, aCurScreenRect ) ); if( nCurDist < nDist )
{
nBestMatchScreen = i;
nDist = nCurDist;
}
} return nBestMatchScreen;
}
// always use the topmost parent of the candidate // window to avoid using dialogs or floaters // as DefDialogParent
// current focus frame
vcl::Window *pWin = pSVData->mpWinData->mpFocusWin; if (pWin && !pWin->IsMenuFloatingWindow())
{ while (pWin->mpWindowImpl && pWin->mpWindowImpl->mpParent)
pWin = pWin->mpWindowImpl->mpParent;
// check for corrupted window hierarchy, #122232#, may be we now crash somewhere else if (!pWin->mpWindowImpl)
{
OSL_FAIL( "Window hierarchy corrupted!" );
pSVData->mpWinData->mpFocusWin = nullptr; // avoid further access return nullptr;
}
// last active application frame
pWin = pSVData->maFrameData.mpActiveApplicationFrame; if (pWin)
{ return pWin->mpWindowImpl->mpFrameWindow->ImplGetWindow();
}
// first visible top window (may be totally wrong...)
pWin = pSVData->maFrameData.mpFirstFrame; while (pWin)
{ if( pWin->ImplGetWindow()->IsTopWindow() &&
pWin->mpWindowImpl->mbReallyVisible &&
(pWin->mpWindowImpl->mnStyle & WB_INTROWIN) == 0
)
{ while( pWin->mpWindowImpl->mpParent )
pWin = pWin->mpWindowImpl->mpParent; return pWin->mpWindowImpl->mpFrameWindow->ImplGetWindow();
}
pWin = pWin->mpWindowImpl->mpFrameData->mpNextFrame;
}
// Not hyper-elegant - but in the case of Android & unipoll we need to detach // this thread from the JVM's clutches to avoid a crash closing document if (pSVData->mpPollClosure && pSVData->mpDefInst)
pSVData->mpDefInst->releaseMainThread();
// Just set mpPollClosure to null as that is what calling this means, that the callback data // points to an object that no longer exists. In particular, don't set // pSVData->mpPollCallback to nullptr as that is used to detect whether Unipoll is in use in // isUnipoll().
pSVData->mpPollClosure = nullptr;
}
void numberOfViewsChanged(int count)
{ if (count == 0) return;
ImplSVData * pSVData = ImplGetSVData(); auto& rCache = pSVData->maGDIData.maScaleCache; // Normally the cache size is set to 10, scale according to the number of users.
rCache.setMaxSize(count * 10);
}
#ifndef NDEBUG // lo_dumpState deliberately doesn't take SolarMutexGuard // so disable these checks during dumpState
DbgGUIDeInitSolarMutexCheck(); #endif
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.