/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* 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/. */ #include "FrameworkView.h" #include "MetroAppShell.h" #include "MetroWidget.h" #include "mozilla/AutoRestore.h" #include "MetroUtils.h" #include "MetroApp.h" #include "UIABridgePublic.h" #include "KeyboardLayout.h" // generated #include "UIABridge.h" using namespace mozilla; using namespace mozilla::widget::winrt; #ifdef ACCESSIBILITY using namespace mozilla::a11y; #endif using namespace ABI::Windows::ApplicationModel; using namespace ABI::Windows::ApplicationModel::Core; using namespace ABI::Windows::ApplicationModel::Activation; using namespace ABI::Windows::UI::Core; using namespace ABI::Windows::UI::ViewManagement; using namespace ABI::Windows::UI::Input; using namespace ABI::Windows::Devices::Input; using namespace ABI::Windows::System; using namespace ABI::Windows::Foundation; using namespace Microsoft::WRL; using namespace Microsoft::WRL::Wrappers; namespace mozilla { namespace widget { namespace winrt { // statics bool FrameworkView::sKeyboardIsVisible = false; Rect FrameworkView::sKeyboardRect; nsTArray* sSettingsArray; FrameworkView::FrameworkView(MetroApp* aMetroApp) : mDPI(-1.0f), mWidget(nullptr), mShuttingDown(false), mMetroApp(aMetroApp), mWindow(nullptr), mMetroInput(nullptr), mWinVisible(false), mWinActiveState(false) { memset(&sKeyboardRect, 0, sizeof(Rect)); sSettingsArray = new nsTArray(); LogFunction(); } //////////////////////////////////////////////////// // IFrameworkView impl. HRESULT FrameworkView::Initialize(ICoreApplicationView* aAppView) { LogFunction(); if (mShuttingDown) return E_FAIL; aAppView->add_Activated(Callback<__FITypedEventHandler_2_Windows__CApplicationModel__CCore__CCoreApplicationView_Windows__CApplicationModel__CActivation__CIActivatedEventArgs_t>( this, &FrameworkView::OnActivated).Get(), &mActivated); //CoCreateInstance(CLSID_WICImagingFactory, nullptr, // CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&mWicFactory)); return S_OK; } HRESULT FrameworkView::Uninitialize() { return S_OK; } HRESULT FrameworkView::Load(HSTRING aEntryPoint) { return S_OK; } // called by winrt on startup HRESULT FrameworkView::Run() { LogFunction(); // Initialize XPCOM, create mWidget and go! We get a // callback in MetroAppShell::Run, in which we kick // off normal browser execution / event dispatching. mMetroApp->Run(); // Gecko is completely shut down at this point. WinUtils::Log("Exiting FrameworkView::Run()"); return S_OK; } HRESULT FrameworkView::ActivateView() { LogFunction(); UpdateWidgetSizeAndPosition(); nsIntRegion region(nsIntRect(0, 0, mWindowBounds.width, mWindowBounds.height)); mWidget->Paint(region); // Activate the window, this kills the splash screen mWindow->Activate(); ProcessLaunchArguments(); AddEventHandlers(); SetupContracts(); return S_OK; } HRESULT FrameworkView::SetWindow(ICoreWindow* aWindow) { LogFunction(); NS_ASSERTION(!mWindow, "Attempting to set a window on a view that already has a window!"); NS_ASSERTION(aWindow, "Attempting to set a null window on a view!"); mWindow = aWindow; UpdateLogicalDPI(); return S_OK; } //////////////////////////////////////////////////// // FrameworkView impl. void FrameworkView::AddEventHandlers() { NS_ASSERTION(mWindow, "SetWindow must be called before AddEventHandlers!"); NS_ASSERTION(mWidget, "SetWidget must be called before AddEventHAndlers!"); mMetroInput = Make(mWidget.Get(), mWindow.Get()); mWindow->add_VisibilityChanged(Callback<__FITypedEventHandler_2_Windows__CUI__CCore__CCoreWindow_Windows__CUI__CCore__CVisibilityChangedEventArgs>( this, &FrameworkView::OnWindowVisibilityChanged).Get(), &mWindowVisibilityChanged); mWindow->add_Activated(Callback<__FITypedEventHandler_2_Windows__CUI__CCore__CCoreWindow_Windows__CUI__CCore__CWindowActivatedEventArgs_t>( this, &FrameworkView::OnWindowActivated).Get(), &mWindowActivated); mWindow->add_Closed(Callback<__FITypedEventHandler_2_Windows__CUI__CCore__CCoreWindow_Windows__CUI__CCore__CCoreWindowEventArgs_t>( this, &FrameworkView::OnWindowClosed).Get(), &mWindowClosed); mWindow->add_SizeChanged(Callback<__FITypedEventHandler_2_Windows__CUI__CCore__CCoreWindow_Windows__CUI__CCore__CWindowSizeChangedEventArgs_t>( this, &FrameworkView::OnWindowSizeChanged).Get(), &mWindowSizeChanged); mWindow->add_AutomationProviderRequested(Callback<__FITypedEventHandler_2_Windows__CUI__CCore__CCoreWindow_Windows__CUI__CCore__CAutomationProviderRequestedEventArgs_t>( this, &FrameworkView::OnAutomationProviderRequested).Get(), &mAutomationProviderRequested); HRESULT hr; ComPtr dispProps; if (SUCCEEDED(GetActivationFactory(HStringReference(RuntimeClass_Windows_Graphics_Display_DisplayProperties).Get(), dispProps.GetAddressOf()))) { hr = dispProps->add_LogicalDpiChanged(Callback( this, &FrameworkView::OnLogicalDpiChanged).Get(), &mDisplayPropertiesChanged); LogHRESULT(hr); } ComPtr inputStatic; if (SUCCEEDED(hr = GetActivationFactory(HStringReference(RuntimeClass_Windows_UI_ViewManagement_InputPane).Get(), inputStatic.GetAddressOf()))) { ComPtr inputPane; if (SUCCEEDED(inputStatic->GetForCurrentView(inputPane.GetAddressOf()))) { inputPane->add_Hiding(Callback<__FITypedEventHandler_2_Windows__CUI__CViewManagement__CInputPane_Windows__CUI__CViewManagement__CInputPaneVisibilityEventArgs_t>( this, &FrameworkView::OnSoftkeyboardHidden).Get(), &mSoftKeyboardHidden); inputPane->add_Showing(Callback<__FITypedEventHandler_2_Windows__CUI__CViewManagement__CInputPane_Windows__CUI__CViewManagement__CInputPaneVisibilityEventArgs_t>( this, &FrameworkView::OnSoftkeyboardShown).Get(), &mSoftKeyboardShown); } } } // Called by MetroApp void FrameworkView::ShutdownXPCOM() { LogFunction(); mShuttingDown = true; if (mAutomationProvider) { ComPtr provider; mAutomationProvider.As(&provider); if (provider) { provider->Disconnect(); } } mAutomationProvider = nullptr; mMetroInput = nullptr; delete sSettingsArray; sSettingsArray = nullptr; mWidget = nullptr; mMetroApp = nullptr; mWindow = nullptr; } void FrameworkView::SetCursor(CoreCursorType aCursorType, DWORD aCustomId) { if (mShuttingDown) { return; } NS_ASSERTION(mWindow, "SetWindow must be called before SetCursor!"); ComPtr factory; AssertHRESULT(GetActivationFactory(HStringReference(RuntimeClass_Windows_UI_Core_CoreCursor).Get(), factory.GetAddressOf())); ComPtr cursor; AssertHRESULT(factory->CreateCursor(aCursorType, aCustomId, cursor.GetAddressOf())); mWindow->put_PointerCursor(cursor.Get()); } void FrameworkView::ClearCursor() { if (mShuttingDown) { return; } NS_ASSERTION(mWindow, "SetWindow must be called before ClearCursor!"); mWindow->put_PointerCursor(nullptr); } void FrameworkView::UpdateLogicalDPI() { ComPtr dispProps; HRESULT hr = GetActivationFactory(HStringReference(RuntimeClass_Windows_Graphics_Display_DisplayProperties).Get(), dispProps.GetAddressOf()); AssertHRESULT(hr); FLOAT value; AssertHRESULT(dispProps->get_LogicalDpi(&value)); SetDpi(value); } void FrameworkView::GetBounds(nsIntRect &aRect) { // May be called by compositor thread if (mShuttingDown) { return; } aRect = mWindowBounds; } void FrameworkView::UpdateWidgetSizeAndPosition() { if (mShuttingDown) return; NS_ASSERTION(mWindow, "SetWindow must be called before UpdateWidgetSizeAndPosition!"); NS_ASSERTION(mWidget, "SetWidget must be called before UpdateWidgetSizeAndPosition!"); UpdateBounds(); mWidget->Move(0, 0); mWidget->Resize(0, 0, mWindowBounds.width, mWindowBounds.height, true); mWidget->SizeModeChanged(); } bool FrameworkView::IsEnabled() const { return mWinActiveState; } bool FrameworkView::IsVisible() const { // we could check the wnd in MetroWidget for this, but // generally we don't let nsIWidget control visibility // or activation. return mWinVisible; } void FrameworkView::SetDpi(float aDpi) { if (aDpi != mDPI) { LogFunction(); mDPI = aDpi; // notify the widget that dpi has changed if (mWidget) { mWidget->ChangedDPI(); UpdateBounds(); } } } void FrameworkView::UpdateBounds() { if (!mWidget) return; RECT winRect; GetClientRect(mWidget->GetICoreWindowHWND(), &winRect); mWindowBounds = nsIntRect(winRect.left, winRect.top, winRect.right - winRect.left, winRect.bottom - winRect.top); } void FrameworkView::SetWidget(MetroWidget* aWidget) { NS_ASSERTION(!mWidget, "Attempting to set a widget for a view that already has a widget!"); NS_ASSERTION(aWidget, "Attempting to set a null widget for a view!"); LogFunction(); mWidget = aWidget; mWidget->FindMetroWindow(); UpdateBounds(); } //////////////////////////////////////////////////// // Event handlers void FrameworkView::SendActivationEvent() { if (mShuttingDown) { return; } NS_ASSERTION(mWindow, "SetWindow must be called before SendActivationEvent!"); mWidget->Activated(mWinActiveState); UpdateWidgetSizeAndPosition(); EnsureAutomationProviderCreated(); } HRESULT FrameworkView::OnWindowVisibilityChanged(ICoreWindow* aWindow, IVisibilityChangedEventArgs* aArgs) { // If we're visible, or we can't determine if we're visible, just store // that we are visible. boolean visible; mWinVisible = FAILED(aArgs->get_Visible(&visible)) || visible; return S_OK; } HRESULT FrameworkView::OnActivated(ICoreApplicationView* aApplicationView, IActivatedEventArgs* aArgs) { LogFunction(); aArgs->get_PreviousExecutionState(&mPreviousExecutionState); bool startup = mPreviousExecutionState == ApplicationExecutionState::ApplicationExecutionState_Terminated || mPreviousExecutionState == ApplicationExecutionState::ApplicationExecutionState_ClosedByUser || mPreviousExecutionState == ApplicationExecutionState::ApplicationExecutionState_NotRunning; ProcessActivationArgs(aArgs, startup); return S_OK; } int FrameworkView::GetPreviousExecutionState() { return mPreviousExecutionState; } HRESULT FrameworkView::OnSoftkeyboardHidden(IInputPane* aSender, IInputPaneVisibilityEventArgs* aArgs) { LogFunction(); if (mShuttingDown) return S_OK; sKeyboardIsVisible = false; memset(&sKeyboardRect, 0, sizeof(Rect)); MetroUtils::FireObserver("metro_softkeyboard_hidden"); aArgs->put_EnsuredFocusedElementInView(true); return S_OK; } HRESULT FrameworkView::OnSoftkeyboardShown(IInputPane* aSender, IInputPaneVisibilityEventArgs* aArgs) { LogFunction(); if (mShuttingDown) return S_OK; sKeyboardIsVisible = true; aSender->get_OccludedRect(&sKeyboardRect); MetroUtils::FireObserver("metro_softkeyboard_shown"); aArgs->put_EnsuredFocusedElementInView(true); return S_OK; } HRESULT FrameworkView::OnWindowClosed(ICoreWindow* aSender, ICoreWindowEventArgs* aArgs) { // this doesn't seem very reliable return S_OK; } HRESULT FrameworkView::OnWindowSizeChanged(ICoreWindow* aSender, IWindowSizeChangedEventArgs* aArgs) { LogFunction(); if (mShuttingDown) { return S_OK; } UpdateWidgetSizeAndPosition(); return S_OK; } HRESULT FrameworkView::OnWindowActivated(ICoreWindow* aSender, IWindowActivatedEventArgs* aArgs) { LogFunction(); if (mShuttingDown || !mWidget) return S_OK; CoreWindowActivationState state; aArgs->get_WindowActivationState(&state); mWinActiveState = !(state == CoreWindowActivationState::CoreWindowActivationState_Deactivated); SendActivationEvent(); return S_OK; } HRESULT FrameworkView::OnLogicalDpiChanged(IInspectable* aSender) { LogFunction(); UpdateLogicalDPI(); if (mWidget) { mWidget->Invalidate(); } return S_OK; } bool FrameworkView::EnsureAutomationProviderCreated() { #ifdef ACCESSIBILITY if (!mWidget || mShuttingDown) return false; if (mAutomationProvider) { return true; } Accessible *rootAccessible = mWidget->GetRootAccessible(); if (rootAccessible) { IInspectable* inspectable; HRESULT hr; AssertRetHRESULT(hr = UIABridge_CreateInstance(&inspectable), hr); // Addref IUIABridge* bridge = nullptr; inspectable->QueryInterface(IID_IUIABridge, (void**)&bridge); // Addref if (bridge) { bridge->Init(this, mWindow.Get(), (ULONG)rootAccessible); mAutomationProvider = inspectable; inspectable->Release(); return true; } } #endif return false; } HRESULT FrameworkView::OnAutomationProviderRequested(ICoreWindow* aSender, IAutomationProviderRequestedEventArgs* aArgs) { LogFunction(); if (!EnsureAutomationProviderCreated()) return E_FAIL; HRESULT hr = aArgs->put_AutomationProvider(mAutomationProvider.Get()); if (FAILED(hr)) { WinUtils::Log("put failed? %X", hr); } return S_OK; } } } }