Fixes #202 This PR fixes code style for the project files. The Problem Different files in the project use different code style. That is not consistent and leads to harder maintenance of the project. Description of the changes: Have investigated and determined the most used code style across the given codebase Have configured IDE and applied code style to all project files. Have crafted clang-formatter config. see https://clang.llvm.org/docs/ClangFormat.html https://clang.llvm.org/docs/ClangFormatStyleOptions.html Some cases were fixed manually How changes were validated: manual/ad-hoc testing, automated testing All tests pass as before because these are only code style changes. Additional Please review, and let me know if I have any mistake in the code style. In case of any mistake, I will change the configuration and re-apply it to the project.
477 lines
19 KiB
C++
477 lines
19 KiB
C++
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
// Licensed under the MIT License.
|
|
|
|
//
|
|
// App.xaml.cpp
|
|
// Implementation of the App class.
|
|
//
|
|
|
|
#include "pch.h"
|
|
#include "App.xaml.h"
|
|
#include "CalcViewModel/Common/TraceLogger.h"
|
|
#include "CalcViewModel/Common/Automation/NarratorNotifier.h"
|
|
#include "CalcViewModel/Common/AppResourceProvider.h"
|
|
#include "CalcViewModel/Common/LocalizationSettings.h"
|
|
#include "CalcViewModel/ViewState.h"
|
|
#include "Views/MainPage.xaml.h"
|
|
|
|
using namespace CalculatorApp;
|
|
using namespace CalculatorApp::Common;
|
|
using namespace CalculatorApp::Common::Automation;
|
|
|
|
using namespace Concurrency;
|
|
using namespace Microsoft::WRL;
|
|
using namespace Platform;
|
|
using namespace Windows::ApplicationModel;
|
|
using namespace Windows::ApplicationModel::Activation;
|
|
using namespace Windows::ApplicationModel::Core;
|
|
using namespace Windows::ApplicationModel::Resources;
|
|
using namespace Windows::Foundation;
|
|
using namespace Windows::Foundation::Collections;
|
|
using namespace Windows::Storage;
|
|
using namespace Windows::System;
|
|
using namespace Windows::UI::Core;
|
|
using namespace Windows::UI::Popups;
|
|
using namespace Windows::UI::StartScreen;
|
|
using namespace Windows::UI::ViewManagement;
|
|
using namespace Windows::UI::Xaml;
|
|
using namespace Windows::UI::Xaml::Controls;
|
|
using namespace Windows::UI::Xaml::Controls::Primitives;
|
|
using namespace Windows::UI::Xaml::Data;
|
|
using namespace Windows::UI::Xaml::Input;
|
|
using namespace Windows::UI::Xaml::Interop;
|
|
using namespace Windows::UI::Xaml::Media;
|
|
using namespace Windows::UI::Xaml::Media::Animation;
|
|
using namespace Windows::UI::Xaml::Navigation;
|
|
using namespace Windows::ApplicationModel::Activation;
|
|
|
|
namespace CalculatorApp
|
|
{
|
|
namespace ApplicationResourceKeys
|
|
{
|
|
StringReference AppMinWindowHeight(L"AppMinWindowHeight");
|
|
StringReference AppMinWindowWidth(L"AppMinWindowWidth");
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Initializes the singleton application object. This is the first line of authored code
|
|
/// executed, and as such is the logical equivalent of main() or WinMain().
|
|
/// </summary>
|
|
App::App()
|
|
{
|
|
TraceLogger::GetInstance().LogAppLaunchStart();
|
|
InitializeComponent();
|
|
|
|
m_preLaunched = false;
|
|
|
|
RegisterDependencyProperties();
|
|
|
|
// TODO: MSFT 14645325: Set this directly from XAML.
|
|
// Currently this is bugged so the property is only respected from code-behind.
|
|
this->HighContrastAdjustment = ApplicationHighContrastAdjustment::None;
|
|
|
|
#if _DEBUG
|
|
this->DebugSettings->IsBindingTracingEnabled = true;
|
|
this->DebugSettings->BindingFailed += ref new BindingFailedEventHandler([](_In_ Object ^ /*sender*/, _In_ BindingFailedEventArgs ^ e) {
|
|
if (IsDebuggerPresent())
|
|
{
|
|
::Platform::String ^ errorMessage = e->Message;
|
|
__debugbreak();
|
|
}
|
|
});
|
|
#endif
|
|
}
|
|
|
|
bool App::m_isAnimationEnabled = true;
|
|
|
|
/// <summary>
|
|
/// Return True if animation is enabled by user setting.
|
|
/// </summary>
|
|
bool App::IsAnimationEnabled()
|
|
{
|
|
return App::m_isAnimationEnabled;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Return the current application view state. The value
|
|
/// will match one of the constants in the ViewState namespace.
|
|
/// </summary>
|
|
String ^ App::GetAppViewState()
|
|
{
|
|
String ^ newViewState;
|
|
CoreWindow ^ window = CoreWindow::GetForCurrentThread();
|
|
if ((window->Bounds.Width >= 560) && (window->Bounds.Height >= 356))
|
|
{
|
|
newViewState = ViewState::DockedView;
|
|
}
|
|
else
|
|
{
|
|
newViewState = ViewState::Snap;
|
|
}
|
|
|
|
return newViewState;
|
|
}
|
|
|
|
void App::AddWindowToMap(_In_ WindowFrameService ^ frameService)
|
|
{
|
|
reader_writer_lock::scoped_lock lock(m_windowsMapLock);
|
|
m_secondaryWindows[frameService->GetViewId()] = frameService;
|
|
TraceLogger::GetInstance().UpdateWindowCount(m_secondaryWindows.size());
|
|
}
|
|
|
|
WindowFrameService ^ App::GetWindowFromMap(int viewId)
|
|
{
|
|
reader_writer_lock::scoped_lock_read lock(m_windowsMapLock);
|
|
auto windowMapEntry = m_secondaryWindows.find(viewId);
|
|
if (windowMapEntry != m_secondaryWindows.end())
|
|
{
|
|
return windowMapEntry->second;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
void App::RemoveWindowFromMap(int viewId)
|
|
{
|
|
reader_writer_lock::scoped_lock lock(m_windowsMapLock);
|
|
auto iter = m_secondaryWindows.find(viewId);
|
|
assert(iter != m_secondaryWindows.end() && "Window does not exist in the list");
|
|
m_secondaryWindows.erase(viewId);
|
|
}
|
|
|
|
void App::RemoveWindow(_In_ WindowFrameService ^ frameService)
|
|
{
|
|
// Shell does not allow killing the main window.
|
|
if (m_mainViewId != frameService->GetViewId())
|
|
{
|
|
HandleViewReleaseAndRemoveWindowFromMap(frameService);
|
|
}
|
|
}
|
|
|
|
task<void> App::HandleViewReleaseAndRemoveWindowFromMap(_In_ WindowFrameService ^ frameService)
|
|
{
|
|
WeakReference weak(this);
|
|
|
|
// Unregister the event handler of the Main Page
|
|
auto frame = safe_cast<Frame ^>(Window::Current->Content);
|
|
auto mainPage = safe_cast<MainPage ^>(frame->Content);
|
|
mainPage->UnregisterEventHandlers();
|
|
|
|
return frameService->HandleViewRelease().then(
|
|
[weak, frameService]() {
|
|
auto that = weak.Resolve<App>();
|
|
that->RemoveWindowFromMap(frameService->GetViewId());
|
|
},
|
|
task_continuation_context::use_arbitrary());
|
|
}
|
|
|
|
task<void> App::SetupJumpList()
|
|
{
|
|
try
|
|
{
|
|
auto calculatorOptions = NavCategoryGroup::CreateCalculatorCategory();
|
|
|
|
auto jumpList = co_await JumpList::LoadCurrentAsync();
|
|
jumpList->SystemGroupKind = JumpListSystemGroupKind::None;
|
|
jumpList->Items->Clear();
|
|
|
|
for (NavCategory ^ option : calculatorOptions->Categories)
|
|
{
|
|
ViewMode mode = option->Mode;
|
|
auto item = JumpListItem::CreateWithArguments(((int)mode).ToString(), L"ms-resource:///Resources/" + NavCategory::GetNameResourceKey(mode));
|
|
item->Description = L"ms-resource:///Resources/" + NavCategory::GetNameResourceKey(mode);
|
|
item->GroupName = L"ms-resource:///Resources/" + NavCategoryGroup::GetHeaderResourceKey(calculatorOptions->GroupType);
|
|
item->Logo = ref new Uri("ms-appx:///Assets/" + mode.ToString() + ".png");
|
|
|
|
jumpList->Items->Append(item);
|
|
}
|
|
|
|
co_await jumpList->SaveAsync();
|
|
}
|
|
catch (...)
|
|
{
|
|
}
|
|
}
|
|
|
|
void App::RemoveSecondaryWindow(_In_ WindowFrameService ^ frameService)
|
|
{
|
|
// Shell does not allow killing the main window.
|
|
if (m_mainViewId != frameService->GetViewId())
|
|
{
|
|
RemoveWindowFromMap(frameService->GetViewId());
|
|
}
|
|
}
|
|
|
|
Frame ^ App::CreateFrame()
|
|
{
|
|
auto frame = ref new Frame();
|
|
frame->FlowDirection = LocalizationService::GetInstance()->GetFlowDirection();
|
|
|
|
return frame;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Invoked when the application is launched normally by the end user. Other entry points
|
|
/// will be used when the application is launched to open a specific file, to display
|
|
/// search results, and so forth.
|
|
/// </summary>
|
|
/// <param name="e">Details about the launch request and process.</param>
|
|
void App::OnLaunched(LaunchActivatedEventArgs ^ args)
|
|
{
|
|
TraceLogger::GetInstance().LogWindowLaunched();
|
|
if (args->PrelaunchActivated)
|
|
{
|
|
// If the app got pre-launch activated, then save that state in a flag
|
|
m_preLaunched = true;
|
|
TraceLogger::GetInstance().LogAppPrelaunchedBySystem();
|
|
}
|
|
OnAppLaunch(args, args->Arguments);
|
|
}
|
|
|
|
void App::OnAppLaunch(IActivatedEventArgs ^ args, String ^ argument)
|
|
{
|
|
auto previousExecutionState = args->PreviousExecutionState;
|
|
|
|
TraceLogger::GetInstance().LogOnAppLaunch(previousExecutionState.ToString()->Data());
|
|
|
|
// Uncomment the following lines to display frame-rate and per-frame CPU usage info.
|
|
//#if _DEBUG
|
|
// if (IsDebuggerPresent())
|
|
// {
|
|
// DebugSettings->EnableFrameRateCounter = true;
|
|
// }
|
|
//#endif
|
|
|
|
auto userSettings = ref new Windows::UI::ViewManagement::UISettings();
|
|
m_isAnimationEnabled = userSettings->AnimationsEnabled;
|
|
|
|
args->SplashScreen->Dismissed += ref new TypedEventHandler<SplashScreen ^, Object ^>(this, &App::DismissedEventHandler);
|
|
|
|
auto rootFrame = dynamic_cast<Frame ^>(Window::Current->Content);
|
|
WeakReference weak(this);
|
|
|
|
float minWindowWidth = static_cast<float>(static_cast<double>(this->Resources->Lookup(ApplicationResourceKeys::AppMinWindowWidth)));
|
|
float minWindowHeight = static_cast<float>(static_cast<double>(this->Resources->Lookup(ApplicationResourceKeys::AppMinWindowHeight)));
|
|
Size minWindowSize = SizeHelper::FromDimensions(minWindowWidth, minWindowHeight);
|
|
|
|
ApplicationView ^ appView = ApplicationView::GetForCurrentView();
|
|
ApplicationDataContainer ^ localSettings = ApplicationData::Current->LocalSettings;
|
|
// For very first launch, set the size of the calc as size of the default standard mode
|
|
if (!localSettings->Values->HasKey(L"VeryFirstLaunch"))
|
|
{
|
|
localSettings->Values->Insert(ref new String(L"VeryFirstLaunch"), false);
|
|
appView->SetPreferredMinSize(minWindowSize);
|
|
appView->TryResizeView(minWindowSize);
|
|
}
|
|
else
|
|
{
|
|
appView->PreferredLaunchWindowingMode = ApplicationViewWindowingMode::Auto;
|
|
}
|
|
|
|
// Do not repeat app initialization when the Window already has content,
|
|
// just ensure that the window is active
|
|
if (rootFrame == nullptr)
|
|
{
|
|
if (!Windows::Foundation::Metadata::ApiInformation::IsTypePresent("Windows.Phone.UI.Input.HardwareButtons")) // PC Family
|
|
{
|
|
// Disable the system view activation policy during the first launch of the app
|
|
// only for PC family devices and not for phone family devices
|
|
try
|
|
{
|
|
ApplicationViewSwitcher::DisableSystemViewActivationPolicy();
|
|
}
|
|
catch (Exception ^ e)
|
|
{
|
|
// Log that DisableSystemViewActionPolicy didn't work
|
|
}
|
|
}
|
|
|
|
// Create a Frame to act as the navigation context
|
|
rootFrame = App::CreateFrame();
|
|
|
|
// When the navigation stack isn't restored navigate to the first page,
|
|
// configuring the new page by passing required information as a navigation
|
|
// parameter
|
|
if (!rootFrame->Navigate(MainPage::typeid, argument))
|
|
{
|
|
// We couldn't navigate to the main page, kill the app so we have a good
|
|
// stack to debug
|
|
throw std::bad_exception();
|
|
}
|
|
|
|
SetMinWindowSizeAndActivate(rootFrame, minWindowSize);
|
|
m_mainViewId = ApplicationView::GetForCurrentView()->Id;
|
|
AddWindowToMap(WindowFrameService::CreateNewWindowFrameService(rootFrame, false, weak));
|
|
}
|
|
else
|
|
{
|
|
// For first launch, LaunchStart is logged in constructor, this is for subsequent launches.
|
|
TraceLogger::GetInstance().LogAppLaunchStart();
|
|
|
|
// !Phone check is required because even in continuum mode user interaction mode is Mouse not Touch
|
|
if ((UIViewSettings::GetForCurrentView()->UserInteractionMode == UserInteractionMode::Mouse)
|
|
&& (!Windows::Foundation::Metadata::ApiInformation::IsTypePresent("Windows.Phone.UI.Input.HardwareButtons")))
|
|
{
|
|
// If the pre-launch hasn't happened then allow for the new window/view creation
|
|
if (!m_preLaunched)
|
|
{
|
|
auto newCoreAppView = CoreApplication::CreateNewView();
|
|
newCoreAppView->Dispatcher->RunAsync(
|
|
CoreDispatcherPriority::Normal, ref new DispatchedHandler([args, argument, minWindowSize, weak]() {
|
|
TraceLogger::GetInstance().LogNewWindowCreationBegin(ApplicationView::GetApplicationViewIdForWindow(CoreWindow::GetForCurrentThread()));
|
|
auto that = weak.Resolve<App>();
|
|
if (that != nullptr)
|
|
{
|
|
auto rootFrame = App::CreateFrame();
|
|
SetMinWindowSizeAndActivate(rootFrame, minWindowSize);
|
|
|
|
if (!rootFrame->Navigate(MainPage::typeid, argument))
|
|
{
|
|
// We couldn't navigate to the main page, kill the app so we have a good
|
|
// stack to debug
|
|
throw std::bad_exception();
|
|
}
|
|
|
|
auto frameService = WindowFrameService::CreateNewWindowFrameService(rootFrame, true, weak);
|
|
that->AddWindowToMap(frameService);
|
|
|
|
auto dispatcher = CoreWindow::GetForCurrentThread()->Dispatcher;
|
|
auto safeFrameServiceCreation = std::make_shared<SafeFrameWindowCreation>(frameService, that);
|
|
int newWindowId = ApplicationView::GetApplicationViewIdForWindow(CoreWindow::GetForCurrentThread());
|
|
|
|
ActivationViewSwitcher ^ activationViewSwitcher;
|
|
auto activateEventArgs = dynamic_cast<IViewSwitcherProvider ^>(args);
|
|
if (activateEventArgs != nullptr)
|
|
{
|
|
activationViewSwitcher = activateEventArgs->ViewSwitcher;
|
|
}
|
|
|
|
if (activationViewSwitcher != nullptr)
|
|
{
|
|
activationViewSwitcher->ShowAsStandaloneAsync(newWindowId, ViewSizePreference::Default);
|
|
safeFrameServiceCreation->SetOperationSuccess(true);
|
|
}
|
|
else
|
|
{
|
|
auto activatedEventArgs = dynamic_cast<IApplicationViewActivatedEventArgs ^>(args);
|
|
if ((activatedEventArgs != nullptr) && (activatedEventArgs->CurrentlyShownApplicationViewId != 0))
|
|
{
|
|
create_task(ApplicationViewSwitcher::TryShowAsStandaloneAsync(frameService->GetViewId(), ViewSizePreference::Default,
|
|
activatedEventArgs->CurrentlyShownApplicationViewId,
|
|
ViewSizePreference::Default))
|
|
.then(
|
|
[safeFrameServiceCreation](bool viewShown) {
|
|
// SafeFrameServiceCreation is used to automatically remove the frame
|
|
// from the list of frames if something goes bad.
|
|
safeFrameServiceCreation->SetOperationSuccess(viewShown);
|
|
},
|
|
task_continuation_context::use_current());
|
|
}
|
|
}
|
|
}
|
|
TraceLogger::GetInstance().LogNewWindowCreationEnd(ApplicationView::GetApplicationViewIdForWindow(CoreWindow::GetForCurrentThread()));
|
|
}));
|
|
}
|
|
else
|
|
{
|
|
TraceLogger::GetInstance().LogNewWindowCreationBegin(ApplicationView::GetApplicationViewIdForWindow(CoreWindow::GetForCurrentThread()));
|
|
|
|
ActivationViewSwitcher ^ activationViewSwitcher;
|
|
auto activateEventArgs = dynamic_cast<IViewSwitcherProvider ^>(args);
|
|
if (activateEventArgs != nullptr)
|
|
{
|
|
activationViewSwitcher = activateEventArgs->ViewSwitcher;
|
|
}
|
|
|
|
if (activationViewSwitcher != nullptr)
|
|
{
|
|
activationViewSwitcher->ShowAsStandaloneAsync(ApplicationView::GetApplicationViewIdForWindow(CoreWindow::GetForCurrentThread()),
|
|
ViewSizePreference::Default);
|
|
TraceLogger::GetInstance().LogNewWindowCreationEnd(ApplicationView::GetApplicationViewIdForWindow(CoreWindow::GetForCurrentThread()));
|
|
TraceLogger::GetInstance().LogPrelaunchedAppActivatedByUser();
|
|
}
|
|
else
|
|
{
|
|
TraceLogger::GetInstance().LogError(L"Null_ActivationViewSwitcher");
|
|
}
|
|
}
|
|
// Set the preLaunched flag to false
|
|
m_preLaunched = false;
|
|
}
|
|
else // for touch devices
|
|
{
|
|
if (rootFrame->Content == nullptr)
|
|
{
|
|
// When the navigation stack isn't restored navigate to the first page,
|
|
// configuring the new page by passing required information as a navigation
|
|
// parameter
|
|
if (!rootFrame->Navigate(MainPage::typeid, argument))
|
|
{
|
|
// We couldn't navigate to the main page,
|
|
// kill the app so we have a good stack to debug
|
|
throw std::bad_exception();
|
|
}
|
|
}
|
|
if (!Windows::Foundation::Metadata::ApiInformation::IsTypePresent("Windows.Phone.UI.Input.HardwareButtons"))
|
|
{
|
|
// for tablet mode: since system view activation policy is disabled so do ShowAsStandaloneAsync if activationViewSwitcher exists in
|
|
// activationArgs
|
|
ActivationViewSwitcher ^ activationViewSwitcher;
|
|
auto activateEventArgs = dynamic_cast<IViewSwitcherProvider ^>(args);
|
|
if (activateEventArgs != nullptr)
|
|
{
|
|
activationViewSwitcher = activateEventArgs->ViewSwitcher;
|
|
}
|
|
if (activationViewSwitcher != nullptr)
|
|
{
|
|
auto viewId = safe_cast<IApplicationViewActivatedEventArgs ^>(args)->CurrentlyShownApplicationViewId;
|
|
if (viewId != 0)
|
|
{
|
|
activationViewSwitcher->ShowAsStandaloneAsync(viewId);
|
|
}
|
|
}
|
|
}
|
|
// Ensure the current window is active
|
|
Window::Current->Activate();
|
|
}
|
|
}
|
|
}
|
|
|
|
void App::SetMinWindowSizeAndActivate(Frame ^ rootFrame, Size minWindowSize)
|
|
{
|
|
// SetPreferredMinSize should always be called before Window::Activate
|
|
ApplicationView ^ appView = ApplicationView::GetForCurrentView();
|
|
appView->SetPreferredMinSize(minWindowSize);
|
|
|
|
// Place the frame in the current Window
|
|
Window::Current->Content = rootFrame;
|
|
Window::Current->Activate();
|
|
}
|
|
|
|
void App::RegisterDependencyProperties()
|
|
{
|
|
NarratorNotifier::RegisterDependencyProperties();
|
|
}
|
|
|
|
void App::OnActivated(IActivatedEventArgs ^ args)
|
|
{
|
|
if (args->Kind == ActivationKind::Protocol)
|
|
{
|
|
TraceLogger::GetInstance().LogWindowActivated();
|
|
// We currently don't pass the uri as an argument,
|
|
// and handle any protocol launch as a normal app launch.
|
|
OnAppLaunch(args, nullptr);
|
|
}
|
|
}
|
|
|
|
void App::DismissedEventHandler(SplashScreen ^ sender, Object ^ e)
|
|
{
|
|
SetupJumpList();
|
|
}
|
|
|
|
float App::GetAppWindowHeight()
|
|
{
|
|
CoreWindow ^ window = CoreWindow::GetForCurrentThread();
|
|
return window->Bounds.Height;
|
|
}
|