michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* vim: set ts=8 sts=2 et sw=2 tw=80: */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "ContentHelper.h" michael@0: #include "LayerManagerD3D10.h" michael@0: #include "MetroWidget.h" michael@0: #include "MetroApp.h" michael@0: #include "mozilla/Preferences.h" michael@0: #include "nsToolkit.h" michael@0: #include "KeyboardLayout.h" michael@0: #include "MetroUtils.h" michael@0: #include "WinUtils.h" michael@0: #include "nsToolkitCompsCID.h" michael@0: #include "nsIAppStartup.h" michael@0: #include "../resource.h" michael@0: #include "nsIWidgetListener.h" michael@0: #include "nsIPresShell.h" michael@0: #include "nsPrintfCString.h" michael@0: #include "nsWindowDefs.h" michael@0: #include "FrameworkView.h" michael@0: #include "nsTextStore.h" michael@0: #include "Layers.h" michael@0: #include "ClientLayerManager.h" michael@0: #include "BasicLayers.h" michael@0: #include "FrameMetrics.h" michael@0: #include michael@0: #include "Windows.Graphics.Display.h" michael@0: #include "DisplayInfo_sdk81.h" michael@0: #include "nsNativeDragTarget.h" michael@0: #ifdef MOZ_CRASHREPORTER michael@0: #include "nsExceptionHandler.h" michael@0: #endif michael@0: #include "UIABridgePrivate.h" michael@0: #include "WinMouseScrollHandler.h" michael@0: #include "InputData.h" michael@0: #include "mozilla/TextEvents.h" michael@0: #include "mozilla/TouchEvents.h" michael@0: #include "mozilla/MiscEvents.h" michael@0: michael@0: using namespace Microsoft::WRL; michael@0: using namespace Microsoft::WRL::Wrappers; michael@0: michael@0: using namespace mozilla; michael@0: using namespace mozilla::widget; michael@0: using namespace mozilla::layers; michael@0: using namespace mozilla::widget::winrt; michael@0: michael@0: using namespace ABI::Windows::ApplicationModel; michael@0: using namespace ABI::Windows::ApplicationModel::Core; michael@0: using namespace ABI::Windows::ApplicationModel::Activation; michael@0: using namespace ABI::Windows::UI::Input; michael@0: using namespace ABI::Windows::Devices::Input; michael@0: using namespace ABI::Windows::UI::Core; michael@0: using namespace ABI::Windows::System; michael@0: using namespace ABI::Windows::Foundation; michael@0: using namespace ABI::Windows::Foundation::Collections; michael@0: using namespace ABI::Windows::Graphics::Display; michael@0: michael@0: #ifdef PR_LOGGING michael@0: extern PRLogModuleInfo* gWindowsLog; michael@0: #endif michael@0: michael@0: #if !defined(SM_CONVERTIBLESLATEMODE) michael@0: #define SM_CONVERTIBLESLATEMODE 0x2003 michael@0: #endif michael@0: michael@0: static uint32_t gInstanceCount = 0; michael@0: const char16_t* kMetroSubclassThisProp = L"MetroSubclassThisProp"; michael@0: HWND MetroWidget::sICoreHwnd = nullptr; michael@0: michael@0: namespace mozilla { michael@0: namespace widget { michael@0: UINT sDefaultBrowserMsgId = RegisterWindowMessageW(L"DefaultBrowserClosing"); michael@0: } } michael@0: michael@0: // WM_GETOBJECT id pulled from uia headers michael@0: #define UiaRootObjectId -25 michael@0: michael@0: namespace mozilla { michael@0: namespace widget { michael@0: namespace winrt { michael@0: extern ComPtr sMetroApp; michael@0: extern ComPtr gProviderRoot; michael@0: } } } michael@0: michael@0: namespace { michael@0: michael@0: void SendInputs(uint32_t aModifiers, INPUT* aExtraInputs, uint32_t aExtraInputsLen) michael@0: { michael@0: // keySequence holds the virtual key values of each of the keys we intend michael@0: // to press michael@0: nsAutoTArray keySequence; michael@0: for (uint32_t i = 0; i < ArrayLength(sModifierKeyMap); ++i) { michael@0: const uint32_t* map = sModifierKeyMap[i]; michael@0: if (aModifiers & map[0]) { michael@0: keySequence.AppendElement(KeyPair(map[1], map[2])); michael@0: } michael@0: } michael@0: michael@0: uint32_t const len = keySequence.Length() * 2 + aExtraInputsLen; michael@0: michael@0: // The `inputs` array is a sequence of input events that will happen michael@0: // serially. We set the array up so that each modifier key is pressed michael@0: // down, then the additional input events happen, michael@0: // then each modifier key is released in reverse order of when michael@0: // it was pressed down. We pass this array to `SendInput`. michael@0: // michael@0: // inputs[0]: modifier key (e.g. shift, ctrl, etc) down michael@0: // ... ... michael@0: // inputs[keySequence.Length()-1]: modifier key (e.g. shift, ctrl, etc) down michael@0: // inputs[keySequence.Length()]: aExtraInputs[0] michael@0: // inputs[keySequence.Length()+1]: aExtraInputs[1] michael@0: // ... ... michael@0: // inputs[keySequence.Length() + aExtraInputsLen - 1]: aExtraInputs[aExtraInputsLen - 1] michael@0: // inputs[keySequence.Length() + aExtraInputsLen]: modifier key (e.g. shift, ctrl, etc) up michael@0: // ... ... michael@0: // inputs[len-1]: modifier key (e.g. shift, ctrl, etc) up michael@0: INPUT* inputs = new INPUT[len]; michael@0: memset(inputs, 0, len * sizeof(INPUT)); michael@0: for (uint32_t i = 0; i < keySequence.Length(); ++i) { michael@0: inputs[i].type = inputs[len-i-1].type = INPUT_KEYBOARD; michael@0: inputs[i].ki.wVk = inputs[len-i-1].ki.wVk = keySequence[i].mSpecific michael@0: ? keySequence[i].mSpecific michael@0: : keySequence[i].mGeneral; michael@0: inputs[len-i-1].ki.dwFlags |= KEYEVENTF_KEYUP; michael@0: } michael@0: for (uint32_t i = 0; i < aExtraInputsLen; i++) { michael@0: inputs[keySequence.Length()+i] = aExtraInputs[i]; michael@0: } michael@0: WinUtils::Log(" Sending inputs"); michael@0: for (uint32_t i = 0; i < len; i++) { michael@0: if (inputs[i].type == INPUT_KEYBOARD) { michael@0: WinUtils::Log(" Key press: 0x%x %s", michael@0: inputs[i].ki.wVk, michael@0: inputs[i].ki.dwFlags & KEYEVENTF_KEYUP michael@0: ? "UP" michael@0: : "DOWN"); michael@0: } else if(inputs[i].type == INPUT_MOUSE) { michael@0: WinUtils::Log(" Mouse input: 0x%x 0x%x", michael@0: inputs[i].mi.dwFlags, michael@0: inputs[i].mi.mouseData); michael@0: } else { michael@0: WinUtils::Log(" Unknown input type!"); michael@0: } michael@0: } michael@0: ::SendInput(len, inputs, sizeof(INPUT)); michael@0: delete[] inputs; michael@0: michael@0: // The inputs have been sent, and the WM_* messages they generate are michael@0: // waiting to be processed by our event loop. Now we manually pump michael@0: // those messages so that, upon our return, all the inputs have been michael@0: // processed. michael@0: WinUtils::Log(" Inputs sent. Waiting for input messages to clear"); michael@0: MSG msg; michael@0: while (WinUtils::PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE)) { michael@0: if (nsTextStore::ProcessRawKeyMessage(msg)) { michael@0: continue; // the message is consumed by TSF michael@0: } michael@0: ::TranslateMessage(&msg); michael@0: ::DispatchMessage(&msg); michael@0: WinUtils::Log(" Dispatched 0x%x 0x%x 0x%x", msg.message, msg.wParam, msg.lParam); michael@0: } michael@0: WinUtils::Log(" No more input messages"); michael@0: } michael@0: } michael@0: michael@0: NS_IMPL_ISUPPORTS_INHERITED0(MetroWidget, nsBaseWidget) michael@0: michael@0: MetroWidget::MetroWidget() : michael@0: mTransparencyMode(eTransparencyOpaque), michael@0: mWnd(nullptr), michael@0: mMetroWndProc(nullptr), michael@0: mTempBasicLayerInUse(false), michael@0: mRootLayerTreeId(), michael@0: nsWindowBase() michael@0: { michael@0: // Global initialization michael@0: if (!gInstanceCount) { michael@0: UserActivity(); michael@0: nsTextStore::Initialize(); michael@0: MouseScrollHandler::Initialize(); michael@0: KeyboardLayout::GetInstance()->OnLayoutChange(::GetKeyboardLayout(0)); michael@0: } // !gInstanceCount michael@0: gInstanceCount++; michael@0: } michael@0: michael@0: MetroWidget::~MetroWidget() michael@0: { michael@0: LogThis(); michael@0: michael@0: gInstanceCount--; michael@0: michael@0: // Global shutdown michael@0: if (!gInstanceCount) { michael@0: APZController::sAPZC = nullptr; michael@0: nsTextStore::Terminate(); michael@0: } // !gInstanceCount michael@0: } michael@0: michael@0: static bool gTopLevelAssigned = false; michael@0: NS_IMETHODIMP michael@0: MetroWidget::Create(nsIWidget *aParent, michael@0: nsNativeWidget aNativeParent, michael@0: const nsIntRect &aRect, michael@0: nsDeviceContext *aContext, michael@0: nsWidgetInitData *aInitData) michael@0: { michael@0: LogFunction(); michael@0: michael@0: nsWidgetInitData defaultInitData; michael@0: if (!aInitData) michael@0: aInitData = &defaultInitData; michael@0: michael@0: mWindowType = aInitData->mWindowType; michael@0: michael@0: // Ensure that the toolkit is created. michael@0: nsToolkit::GetToolkit(); michael@0: michael@0: BaseCreate(aParent, aRect, aContext, aInitData); michael@0: michael@0: if (mWindowType != eWindowType_toplevel) { michael@0: switch(mWindowType) { michael@0: case eWindowType_dialog: michael@0: WinUtils::Log("eWindowType_dialog window requested, returning failure."); michael@0: break; michael@0: case eWindowType_child: michael@0: WinUtils::Log("eWindowType_child window requested, returning failure."); michael@0: break; michael@0: case eWindowType_popup: michael@0: WinUtils::Log("eWindowType_popup window requested, returning failure."); michael@0: break; michael@0: case eWindowType_plugin: michael@0: WinUtils::Log("eWindowType_plugin window requested, returning failure."); michael@0: break; michael@0: // we should support toolkit's eWindowType_invisible at some point. michael@0: case eWindowType_invisible: michael@0: WinUtils::Log("eWindowType_invisible window requested, this doesn't actually exist!"); michael@0: return NS_OK; michael@0: } michael@0: NS_WARNING("Invalid window type requested."); michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: if (gTopLevelAssigned) { michael@0: // Need to accept so that the mochitest-chrome test harness window michael@0: // can be created. michael@0: NS_WARNING("New eWindowType_toplevel window requested after FrameworkView widget created."); michael@0: NS_WARNING("Widget created but the physical window does not exist! Fix me!"); michael@0: return NS_OK; michael@0: } michael@0: michael@0: // the main widget gets created first michael@0: gTopLevelAssigned = true; michael@0: sMetroApp->SetWidget(this); michael@0: WinUtils::SetNSWindowBasePtr(mWnd, this); michael@0: michael@0: if (mWidgetListener) { michael@0: mWidgetListener->WindowActivated(); michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: void michael@0: MetroWidget::SetView(FrameworkView* aView) michael@0: { michael@0: mView = aView; michael@0: // If we've already set this up, it points to a useless michael@0: // layer manager, so reset it. michael@0: mLayerManager = nullptr; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: MetroWidget::Destroy() michael@0: { michael@0: if (mOnDestroyCalled) michael@0: return NS_OK; michael@0: WinUtils::Log("[%X] %s mWnd=%X type=%d", this, __FUNCTION__, mWnd, mWindowType); michael@0: mOnDestroyCalled = true; michael@0: michael@0: nsCOMPtr kungFuDeathGrip(this); michael@0: michael@0: if (ShouldUseAPZC()) { michael@0: nsresult rv; michael@0: nsCOMPtr observerService = do_GetService("@mozilla.org/observer-service;1", &rv); michael@0: if (NS_SUCCEEDED(rv)) { michael@0: observerService->RemoveObserver(this, "apzc-scroll-offset-changed"); michael@0: observerService->RemoveObserver(this, "apzc-zoom-to-rect"); michael@0: observerService->RemoveObserver(this, "apzc-disable-zoom"); michael@0: } michael@0: } michael@0: michael@0: RemoveSubclass(); michael@0: NotifyWindowDestroyed(); michael@0: michael@0: // Prevent the widget from sending additional events. michael@0: mWidgetListener = nullptr; michael@0: mAttachedWidgetListener = nullptr; michael@0: michael@0: // Release references to children, device context, toolkit, and app shell. michael@0: nsBaseWidget::Destroy(); michael@0: nsBaseWidget::OnDestroy(); michael@0: WinUtils::SetNSWindowBasePtr(mWnd, nullptr); michael@0: michael@0: if (mLayerManager) { michael@0: mLayerManager->Destroy(); michael@0: } michael@0: michael@0: mLayerManager = nullptr; michael@0: mView = nullptr; michael@0: mIdleService = nullptr; michael@0: mWnd = nullptr; michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: MetroWidget::SetParent(nsIWidget *aNewParent) michael@0: { michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: MetroWidget::Show(bool bState) michael@0: { michael@0: return NS_OK; michael@0: } michael@0: michael@0: uint32_t michael@0: MetroWidget::GetMaxTouchPoints() const michael@0: { michael@0: ComPtr deviceStatics; michael@0: michael@0: HRESULT hr = GetActivationFactory( michael@0: HStringReference(RuntimeClass_Windows_Devices_Input_PointerDevice).Get(), michael@0: deviceStatics.GetAddressOf()); michael@0: michael@0: if (FAILED(hr)) { michael@0: return 0; michael@0: } michael@0: michael@0: ComPtr< IVectorView > deviceList; michael@0: hr = deviceStatics->GetPointerDevices(&deviceList); michael@0: michael@0: if (FAILED(hr)) { michael@0: return 0; michael@0: } michael@0: michael@0: uint32_t deviceNum = 0; michael@0: deviceList->get_Size(&deviceNum); michael@0: michael@0: uint32_t maxTouchPoints = 0; michael@0: for (uint32_t index = 0; index < deviceNum; ++index) { michael@0: ComPtr device; michael@0: PointerDeviceType deviceType; michael@0: michael@0: if (FAILED(deviceList->GetAt(index, device.GetAddressOf()))) { michael@0: continue; michael@0: } michael@0: michael@0: if (FAILED(device->get_PointerDeviceType(&deviceType))) { michael@0: continue; michael@0: } michael@0: michael@0: if (deviceType == PointerDeviceType_Touch) { michael@0: uint32_t deviceMaxTouchPoints = 0; michael@0: device->get_MaxContacts(&deviceMaxTouchPoints); michael@0: maxTouchPoints = std::max(maxTouchPoints, deviceMaxTouchPoints); michael@0: } michael@0: } michael@0: michael@0: return maxTouchPoints; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: MetroWidget::IsVisible(bool & aState) michael@0: { michael@0: aState = mView->IsVisible(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: bool michael@0: MetroWidget::IsVisible() const michael@0: { michael@0: if (!mView) michael@0: return false; michael@0: return mView->IsVisible(); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: MetroWidget::EnableDragDrop(bool aEnable) { michael@0: if (aEnable) { michael@0: if (nullptr == mNativeDragTarget) { michael@0: mNativeDragTarget = new nsNativeDragTarget(this); michael@0: if (!mNativeDragTarget) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: } michael@0: michael@0: HRESULT hr = ::RegisterDragDrop(mWnd, static_cast(mNativeDragTarget)); michael@0: return SUCCEEDED(hr) ? NS_OK : NS_ERROR_FAILURE; michael@0: } else { michael@0: if (nullptr == mNativeDragTarget) { michael@0: return NS_OK; michael@0: } michael@0: michael@0: HRESULT hr = ::RevokeDragDrop(mWnd); michael@0: return SUCCEEDED(hr) ? NS_OK : NS_ERROR_FAILURE; michael@0: } michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: MetroWidget::IsEnabled(bool *aState) michael@0: { michael@0: *aState = mView->IsEnabled(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: bool michael@0: MetroWidget::IsEnabled() const michael@0: { michael@0: if (!mView) michael@0: return false; michael@0: return mView->IsEnabled(); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: MetroWidget::Enable(bool bState) michael@0: { michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: MetroWidget::GetBounds(nsIntRect &aRect) michael@0: { michael@0: if (mView) { michael@0: mView->GetBounds(aRect); michael@0: } else { michael@0: nsIntRect rect(0,0,0,0); michael@0: aRect = rect; michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: MetroWidget::GetScreenBounds(nsIntRect &aRect) michael@0: { michael@0: if (mView) { michael@0: mView->GetBounds(aRect); michael@0: } else { michael@0: nsIntRect rect(0,0,0,0); michael@0: aRect = rect; michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: MetroWidget::GetClientBounds(nsIntRect &aRect) michael@0: { michael@0: if (mView) { michael@0: mView->GetBounds(aRect); michael@0: } else { michael@0: nsIntRect rect(0,0,0,0); michael@0: aRect = rect; michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: MetroWidget::SetCursor(nsCursor aCursor) michael@0: { michael@0: if (!mView) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: switch (aCursor) { michael@0: case eCursor_select: michael@0: mView->SetCursor(CoreCursorType::CoreCursorType_IBeam); michael@0: break; michael@0: case eCursor_wait: michael@0: mView->SetCursor(CoreCursorType::CoreCursorType_Wait); michael@0: break; michael@0: case eCursor_hyperlink: michael@0: mView->SetCursor(CoreCursorType::CoreCursorType_Hand); michael@0: break; michael@0: case eCursor_standard: michael@0: mView->SetCursor(CoreCursorType::CoreCursorType_Arrow); michael@0: break; michael@0: case eCursor_n_resize: michael@0: case eCursor_s_resize: michael@0: mView->SetCursor(CoreCursorType::CoreCursorType_SizeNorthSouth); michael@0: break; michael@0: case eCursor_w_resize: michael@0: case eCursor_e_resize: michael@0: mView->SetCursor(CoreCursorType::CoreCursorType_SizeWestEast); michael@0: break; michael@0: case eCursor_nw_resize: michael@0: case eCursor_se_resize: michael@0: mView->SetCursor(CoreCursorType::CoreCursorType_SizeNorthwestSoutheast); michael@0: break; michael@0: case eCursor_ne_resize: michael@0: case eCursor_sw_resize: michael@0: mView->SetCursor(CoreCursorType::CoreCursorType_SizeNortheastSouthwest); michael@0: break; michael@0: case eCursor_crosshair: michael@0: mView->SetCursor(CoreCursorType::CoreCursorType_Cross); michael@0: break; michael@0: case eCursor_move: michael@0: mView->SetCursor(CoreCursorType::CoreCursorType_SizeAll); michael@0: break; michael@0: case eCursor_help: michael@0: mView->SetCursor(CoreCursorType::CoreCursorType_Help); michael@0: break; michael@0: // CSS3 custom cursors michael@0: case eCursor_copy: michael@0: mView->SetCursor(CoreCursorType::CoreCursorType_Custom, IDC_COPY); michael@0: break; michael@0: case eCursor_alias: michael@0: mView->SetCursor(CoreCursorType::CoreCursorType_Custom, IDC_ALIAS); michael@0: break; michael@0: case eCursor_cell: michael@0: mView->SetCursor(CoreCursorType::CoreCursorType_Custom, IDC_CELL); michael@0: break; michael@0: case eCursor_grab: michael@0: mView->SetCursor(CoreCursorType::CoreCursorType_Custom, IDC_GRAB); michael@0: break; michael@0: case eCursor_grabbing: michael@0: mView->SetCursor(CoreCursorType::CoreCursorType_Custom, IDC_GRABBING); michael@0: break; michael@0: case eCursor_spinning: michael@0: mView->SetCursor(CoreCursorType::CoreCursorType_Wait); michael@0: break; michael@0: case eCursor_context_menu: michael@0: mView->SetCursor(CoreCursorType::CoreCursorType_Arrow); michael@0: break; michael@0: case eCursor_zoom_in: michael@0: mView->SetCursor(CoreCursorType::CoreCursorType_Custom, IDC_ZOOMIN); michael@0: break; michael@0: case eCursor_zoom_out: michael@0: mView->SetCursor(CoreCursorType::CoreCursorType_Custom, IDC_ZOOMOUT); michael@0: break; michael@0: case eCursor_not_allowed: michael@0: case eCursor_no_drop: michael@0: mView->SetCursor(CoreCursorType::CoreCursorType_UniversalNo); michael@0: break; michael@0: case eCursor_col_resize: michael@0: mView->SetCursor(CoreCursorType::CoreCursorType_Custom, IDC_COLRESIZE); michael@0: break; michael@0: case eCursor_row_resize: michael@0: mView->SetCursor(CoreCursorType::CoreCursorType_Custom, IDC_ROWRESIZE); michael@0: break; michael@0: case eCursor_vertical_text: michael@0: mView->SetCursor(CoreCursorType::CoreCursorType_Custom, IDC_VERTICALTEXT); michael@0: break; michael@0: case eCursor_all_scroll: michael@0: mView->SetCursor(CoreCursorType::CoreCursorType_SizeAll); michael@0: break; michael@0: case eCursor_nesw_resize: michael@0: mView->SetCursor(CoreCursorType::CoreCursorType_SizeNortheastSouthwest); michael@0: break; michael@0: case eCursor_nwse_resize: michael@0: mView->SetCursor(CoreCursorType::CoreCursorType_SizeNorthwestSoutheast); michael@0: break; michael@0: case eCursor_ns_resize: michael@0: mView->SetCursor(CoreCursorType::CoreCursorType_SizeNorthSouth); michael@0: break; michael@0: case eCursor_ew_resize: michael@0: mView->SetCursor(CoreCursorType::CoreCursorType_SizeWestEast); michael@0: break; michael@0: case eCursor_none: michael@0: mView->ClearCursor(); michael@0: break; michael@0: default: michael@0: NS_WARNING("Invalid cursor type"); michael@0: break; michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult michael@0: MetroWidget::SynthesizeNativeKeyEvent(int32_t aNativeKeyboardLayout, michael@0: int32_t aNativeKeyCode, michael@0: uint32_t aModifierFlags, michael@0: const nsAString& aCharacters, michael@0: const nsAString& aUnmodifiedCharacters) michael@0: { michael@0: KeyboardLayout* keyboardLayout = KeyboardLayout::GetInstance(); michael@0: return keyboardLayout->SynthesizeNativeKeyEvent( michael@0: this, aNativeKeyboardLayout, aNativeKeyCode, aModifierFlags, michael@0: aCharacters, aUnmodifiedCharacters); michael@0: } michael@0: michael@0: nsresult michael@0: MetroWidget::SynthesizeNativeMouseEvent(nsIntPoint aPoint, michael@0: uint32_t aNativeMessage, michael@0: uint32_t aModifierFlags) michael@0: { michael@0: WinUtils::Log("ENTERED SynthesizeNativeMouseEvent"); michael@0: michael@0: INPUT inputs[2]; michael@0: memset(inputs, 0, 2*sizeof(INPUT)); michael@0: inputs[0].type = inputs[1].type = INPUT_MOUSE; michael@0: inputs[0].mi.dwFlags = MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE; michael@0: // Inexplicably, the x and y coordinates that we want to move the mouse to michael@0: // are specified as values in the range (0, 65535). (0,0) represents the michael@0: // top left of the primary monitor and (65535, 65535) represents the michael@0: // bottom right of the primary monitor. michael@0: inputs[0].mi.dx = (aPoint.x * 65535) / ::GetSystemMetrics(SM_CXSCREEN); michael@0: inputs[0].mi.dy = (aPoint.y * 65535) / ::GetSystemMetrics(SM_CYSCREEN); michael@0: inputs[1].mi.dwFlags = aNativeMessage; michael@0: SendInputs(aModifierFlags, inputs, 2); michael@0: michael@0: WinUtils::Log("Exiting SynthesizeNativeMouseEvent"); michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult michael@0: MetroWidget::SynthesizeNativeMouseScrollEvent(nsIntPoint aPoint, michael@0: uint32_t aNativeMessage, michael@0: double aDeltaX, michael@0: double aDeltaY, michael@0: double aDeltaZ, michael@0: uint32_t aModifierFlags, michael@0: uint32_t aAdditionalFlags) michael@0: { michael@0: return MouseScrollHandler::SynthesizeNativeMouseScrollEvent( michael@0: this, aPoint, aNativeMessage, michael@0: (aNativeMessage == WM_MOUSEWHEEL || aNativeMessage == WM_VSCROLL) ? michael@0: static_cast(aDeltaY) : static_cast(aDeltaX), michael@0: aModifierFlags, aAdditionalFlags); michael@0: } michael@0: michael@0: static void michael@0: CloseGesture() michael@0: { michael@0: LogFunction(); michael@0: nsCOMPtr appStartup = michael@0: do_GetService(NS_APPSTARTUP_CONTRACTID); michael@0: if (appStartup) { michael@0: appStartup->Quit(nsIAppStartup::eForceQuit); michael@0: } michael@0: } michael@0: michael@0: // Async event sending for mouse and keyboard input. michael@0: michael@0: // defined in nsWindowBase, called from shared module WinMouseScrollHandler. michael@0: bool michael@0: MetroWidget::DispatchScrollEvent(mozilla::WidgetGUIEvent* aEvent) michael@0: { michael@0: WidgetGUIEvent* newEvent = nullptr; michael@0: switch(aEvent->eventStructType) { michael@0: case NS_WHEEL_EVENT: michael@0: { michael@0: WidgetWheelEvent* oldEvent = aEvent->AsWheelEvent(); michael@0: WidgetWheelEvent* wheelEvent = michael@0: new WidgetWheelEvent(oldEvent->mFlags.mIsTrusted, oldEvent->message, oldEvent->widget); michael@0: wheelEvent->AssignWheelEventData(*oldEvent, true); michael@0: newEvent = static_cast(wheelEvent); michael@0: } michael@0: break; michael@0: case NS_CONTENT_COMMAND_EVENT: michael@0: { michael@0: WidgetContentCommandEvent* oldEvent = aEvent->AsContentCommandEvent(); michael@0: WidgetContentCommandEvent* cmdEvent = michael@0: new WidgetContentCommandEvent(oldEvent->mFlags.mIsTrusted, oldEvent->message, oldEvent->widget); michael@0: cmdEvent->AssignContentCommandEventData(*oldEvent, true); michael@0: newEvent = static_cast(cmdEvent); michael@0: } michael@0: break; michael@0: default: michael@0: MOZ_CRASH("unknown event in DispatchScrollEvent"); michael@0: break; michael@0: } michael@0: mEventQueue.Push(newEvent); michael@0: nsCOMPtr runnable = michael@0: NS_NewRunnableMethod(this, &MetroWidget::DeliverNextScrollEvent); michael@0: NS_DispatchToCurrentThread(runnable); michael@0: return false; michael@0: } michael@0: michael@0: void michael@0: MetroWidget::DeliverNextScrollEvent() michael@0: { michael@0: WidgetGUIEvent* event = michael@0: static_cast(mEventQueue.PopFront()); michael@0: DispatchWindowEvent(event); michael@0: delete event; michael@0: } michael@0: michael@0: // defined in nsWindowBase, called from shared module KeyboardLayout. michael@0: bool michael@0: MetroWidget::DispatchKeyboardEvent(WidgetGUIEvent* aEvent) michael@0: { michael@0: MOZ_ASSERT(aEvent); michael@0: WidgetKeyboardEvent* oldKeyEvent = aEvent->AsKeyboardEvent(); michael@0: WidgetKeyboardEvent* keyEvent = michael@0: new WidgetKeyboardEvent(oldKeyEvent->mFlags.mIsTrusted, michael@0: oldKeyEvent->message, oldKeyEvent->widget); michael@0: // XXX note this leaves pluginEvent null, which is fine for now. michael@0: keyEvent->AssignKeyEventData(*oldKeyEvent, true); michael@0: mKeyEventQueue.Push(keyEvent); michael@0: nsCOMPtr runnable = michael@0: NS_NewRunnableMethod(this, &MetroWidget::DeliverNextKeyboardEvent); michael@0: NS_DispatchToCurrentThread(runnable); michael@0: return false; michael@0: } michael@0: michael@0: // Used in conjunction with mKeyEventQueue to find a keypress event michael@0: // that should not be delivered due to the return result of the michael@0: // preceeding keydown. michael@0: class KeyQueryIdAndCancel : public nsDequeFunctor { michael@0: public: michael@0: KeyQueryIdAndCancel(uint32_t aIdToCancel) : michael@0: mId(aIdToCancel) { michael@0: } michael@0: virtual void* operator() (void* aObject) { michael@0: WidgetKeyboardEvent* event = static_cast(aObject); michael@0: if (event->mUniqueId == mId) { michael@0: event->mFlags.mPropagationStopped = true; michael@0: } michael@0: return nullptr; michael@0: } michael@0: protected: michael@0: uint32_t mId; michael@0: }; michael@0: michael@0: void michael@0: MetroWidget::DeliverNextKeyboardEvent() michael@0: { michael@0: WidgetKeyboardEvent* event = michael@0: static_cast(mKeyEventQueue.PopFront()); michael@0: if (event->mFlags.mPropagationStopped) { michael@0: // This can happen if a keypress was previously cancelled. michael@0: delete event; michael@0: return; michael@0: } michael@0: michael@0: if (DispatchWindowEvent(event) && event->message == NS_KEY_DOWN) { michael@0: // keydown events may be followed by multiple keypress events which michael@0: // shouldn't be sent if preventDefault is called on keydown. michael@0: KeyQueryIdAndCancel query(event->mUniqueId); michael@0: mKeyEventQueue.ForEach(query); michael@0: } michael@0: delete event; michael@0: } michael@0: michael@0: // static michael@0: LRESULT CALLBACK michael@0: MetroWidget::StaticWindowProcedure(HWND aWnd, UINT aMsg, WPARAM aWParam, LPARAM aLParam) michael@0: { michael@0: MetroWidget* self = reinterpret_cast( michael@0: GetProp(aWnd, kMetroSubclassThisProp)); michael@0: if (!self) { michael@0: NS_NOTREACHED("Missing 'this' prop on subclassed metro window, this is bad."); michael@0: return 0; michael@0: } michael@0: return self->WindowProcedure(aWnd, aMsg, aWParam, aLParam); michael@0: } michael@0: michael@0: LRESULT michael@0: MetroWidget::WindowProcedure(HWND aWnd, UINT aMsg, WPARAM aWParam, LPARAM aLParam) michael@0: { michael@0: if(sDefaultBrowserMsgId == aMsg) { michael@0: CloseGesture(); michael@0: } else if (WM_SETTINGCHANGE == aMsg) { michael@0: if (aLParam && !wcsicmp(L"ConvertibleSlateMode", (wchar_t*)aLParam)) { michael@0: // If we're switching away from slate mode, switch to Desktop for michael@0: // hardware that supports this feature if the pref is set. michael@0: if (GetSystemMetrics(SM_CONVERTIBLESLATEMODE) != 0 && michael@0: Preferences::GetBool("browser.shell.metro-auto-switch-enabled", michael@0: false)) { michael@0: nsCOMPtr appStartup(do_GetService(NS_APPSTARTUP_CONTRACTID)); michael@0: if (appStartup) { michael@0: appStartup->Quit(nsIAppStartup::eForceQuit | nsIAppStartup::eRestart); michael@0: } michael@0: } michael@0: } michael@0: } michael@0: michael@0: // Indicates if we should hand messages to the default windows michael@0: // procedure for processing. michael@0: bool processDefault = true; michael@0: michael@0: // The result returned if we do not do default processing. michael@0: LRESULT processResult = 0; michael@0: michael@0: MSGResult msgResult(&processResult); michael@0: MouseScrollHandler::ProcessMessage(this, aMsg, aWParam, aLParam, msgResult); michael@0: if (msgResult.mConsumed) { michael@0: return processResult; michael@0: } michael@0: michael@0: nsTextStore::ProcessMessage(this, aMsg, aWParam, aLParam, msgResult); michael@0: if (msgResult.mConsumed) { michael@0: return processResult; michael@0: } michael@0: michael@0: switch (aMsg) { michael@0: case WM_POWERBROADCAST: michael@0: { michael@0: switch (aWParam) michael@0: { michael@0: case PBT_APMSUSPEND: michael@0: MetroApp::PostSleepWakeNotification(true); michael@0: break; michael@0: case PBT_APMRESUMEAUTOMATIC: michael@0: case PBT_APMRESUMECRITICAL: michael@0: case PBT_APMRESUMESUSPEND: michael@0: MetroApp::PostSleepWakeNotification(false); michael@0: break; michael@0: } michael@0: break; michael@0: } michael@0: michael@0: // Keyboard handling is passed to KeyboardLayout, which delivers gecko events michael@0: // via DispatchKeyboardEvent. michael@0: michael@0: case WM_KEYDOWN: michael@0: case WM_SYSKEYDOWN: michael@0: { michael@0: MSG msg = WinUtils::InitMSG(aMsg, aWParam, aLParam, aWnd); michael@0: // If this method doesn't call NativeKey::HandleKeyDownMessage(), this michael@0: // method must clean up the redirected message information itself. For michael@0: // more information, see above comment of michael@0: // RedirectedKeyDownMessageManager::AutoFlusher class definition in michael@0: // KeyboardLayout.h. michael@0: RedirectedKeyDownMessageManager::AutoFlusher michael@0: redirectedMsgFlusher(this, msg); michael@0: michael@0: if (nsTextStore::IsComposingOn(this)) { michael@0: break; michael@0: } michael@0: michael@0: ModifierKeyState modKeyState; michael@0: NativeKey nativeKey(this, msg, modKeyState); michael@0: processDefault = !nativeKey.HandleKeyDownMessage(); michael@0: // HandleKeyDownMessage cleaned up the redirected message information michael@0: // itself, so, we should do nothing. michael@0: redirectedMsgFlusher.Cancel(); michael@0: break; michael@0: } michael@0: michael@0: case WM_KEYUP: michael@0: case WM_SYSKEYUP: michael@0: { michael@0: if (nsTextStore::IsComposingOn(this)) { michael@0: break; michael@0: } michael@0: michael@0: MSG msg = WinUtils::InitMSG(aMsg, aWParam, aLParam, aWnd); michael@0: ModifierKeyState modKeyState; michael@0: NativeKey nativeKey(this, msg, modKeyState); michael@0: processDefault = !nativeKey.HandleKeyUpMessage(); michael@0: break; michael@0: } michael@0: michael@0: case WM_CHAR: michael@0: case WM_SYSCHAR: michael@0: { michael@0: if (nsTextStore::IsComposingOn(this)) { michael@0: nsTextStore::CommitComposition(false); michael@0: } michael@0: michael@0: MSG msg = WinUtils::InitMSG(aMsg, aWParam, aLParam, aWnd); michael@0: ModifierKeyState modKeyState; michael@0: NativeKey nativeKey(this, msg, modKeyState); michael@0: processDefault = !nativeKey.HandleCharMessage(msg); michael@0: break; michael@0: } michael@0: michael@0: case WM_INPUTLANGCHANGE: michael@0: { michael@0: KeyboardLayout::GetInstance()-> michael@0: OnLayoutChange(reinterpret_cast(aLParam)); michael@0: processResult = 1; michael@0: break; michael@0: } michael@0: michael@0: case WM_APPCOMMAND: michael@0: processDefault = HandleAppCommandMsg(aWParam, aLParam, &processResult); michael@0: break; michael@0: michael@0: case WM_GETOBJECT: michael@0: { michael@0: DWORD dwObjId = (LPARAM)(DWORD) aLParam; michael@0: // Passing this to CallWindowProc can result in a failure due to a timing issue michael@0: // in winrt core window server code, so we call it directly here. Also, it's not michael@0: // clear Windows::UI::Core::WindowServer::OnAutomationProviderRequestedEvent is michael@0: // compatible with metro enabled desktop browsers, it makes an initial call to michael@0: // UiaReturnRawElementProvider passing the return result from FrameworkView michael@0: // OnAutomationProviderRequested as the hwnd (me scratches head) which results in michael@0: // GetLastError always being set to invalid handle (6) after CallWindowProc returns. michael@0: if (dwObjId == UiaRootObjectId && gProviderRoot) { michael@0: ComPtr simple; michael@0: gProviderRoot.As(&simple); michael@0: if (simple) { michael@0: LRESULT res = UiaReturnRawElementProvider(aWnd, aWParam, aLParam, simple.Get()); michael@0: if (res) { michael@0: return res; michael@0: } michael@0: NS_ASSERTION(res, "UiaReturnRawElementProvider failed!"); michael@0: WinUtils::Log("UiaReturnRawElementProvider failed! GetLastError=%X", GetLastError()); michael@0: } michael@0: } michael@0: break; michael@0: } michael@0: michael@0: default: michael@0: { michael@0: break; michael@0: } michael@0: } michael@0: michael@0: if (processDefault) { michael@0: return CallWindowProc(mMetroWndProc, aWnd, aMsg, aWParam, michael@0: aLParam); michael@0: } michael@0: return processResult; michael@0: } michael@0: michael@0: static BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam) michael@0: { michael@0: WCHAR className[56]; michael@0: if (GetClassNameW(hwnd, className, sizeof(className)/sizeof(WCHAR)) && michael@0: !wcscmp(L"Windows.UI.Core.CoreWindow", className)) { michael@0: DWORD processID = 0; michael@0: GetWindowThreadProcessId(hwnd, &processID); michael@0: if (processID && processID == GetCurrentProcessId()) { michael@0: *((HWND*)lParam) = hwnd; michael@0: return FALSE; michael@0: } michael@0: } michael@0: return TRUE; michael@0: } michael@0: michael@0: void michael@0: MetroWidget::FindMetroWindow() michael@0: { michael@0: LogFunction(); michael@0: if (mWnd) michael@0: return; michael@0: EnumWindows(EnumWindowsProc, (LPARAM)&mWnd); michael@0: NS_ASSERTION(mWnd, "Couldn't find our metro CoreWindow, this is bad."); michael@0: michael@0: // subclass it michael@0: SetSubclass(); michael@0: sICoreHwnd = mWnd; michael@0: return; michael@0: } michael@0: michael@0: void michael@0: MetroWidget::SetSubclass() michael@0: { michael@0: if (!mWnd) { michael@0: NS_NOTREACHED("SetSubclass called without a valid hwnd."); michael@0: return; michael@0: } michael@0: michael@0: WNDPROC wndProc = reinterpret_cast( michael@0: GetWindowLongPtr(mWnd, GWLP_WNDPROC)); michael@0: if (wndProc != StaticWindowProcedure) { michael@0: if (!SetPropW(mWnd, kMetroSubclassThisProp, this)) { michael@0: NS_NOTREACHED("SetProp failed, can't continue."); michael@0: return; michael@0: } michael@0: mMetroWndProc = michael@0: reinterpret_cast( michael@0: SetWindowLongPtr(mWnd, GWLP_WNDPROC, michael@0: reinterpret_cast(StaticWindowProcedure))); michael@0: NS_ASSERTION(mMetroWndProc != StaticWindowProcedure, "WTF?"); michael@0: } michael@0: } michael@0: michael@0: void michael@0: MetroWidget::RemoveSubclass() michael@0: { michael@0: if (!mWnd) michael@0: return; michael@0: WNDPROC wndProc = reinterpret_cast( michael@0: GetWindowLongPtr(mWnd, GWLP_WNDPROC)); michael@0: if (wndProc == StaticWindowProcedure) { michael@0: NS_ASSERTION(mMetroWndProc, "Should have old proc here."); michael@0: SetWindowLongPtr(mWnd, GWLP_WNDPROC, michael@0: reinterpret_cast(mMetroWndProc)); michael@0: mMetroWndProc = nullptr; michael@0: } michael@0: RemovePropW(mWnd, kMetroSubclassThisProp); michael@0: } michael@0: michael@0: bool michael@0: MetroWidget::ShouldUseOffMainThreadCompositing() michael@0: { michael@0: // Either we're not initialized yet, or this is the toolkit widget michael@0: if (!mView) { michael@0: return false; michael@0: } michael@0: // toolkit or test widgets can't use omtc, they don't have ICoreWindow. michael@0: return (CompositorParent::CompositorLoop() && mWindowType == eWindowType_toplevel); michael@0: } michael@0: michael@0: bool michael@0: MetroWidget::ShouldUseMainThreadD3D10Manager() michael@0: { michael@0: // Either we're not initialized yet, or this is the toolkit widget michael@0: if (!mView) { michael@0: return false; michael@0: } michael@0: return (!CompositorParent::CompositorLoop() && mWindowType == eWindowType_toplevel); michael@0: } michael@0: michael@0: bool michael@0: MetroWidget::ShouldUseBasicManager() michael@0: { michael@0: // toolkit or test widgets fall back on empty shadow layers michael@0: return (mWindowType != eWindowType_toplevel); michael@0: } michael@0: michael@0: bool michael@0: MetroWidget::ShouldUseAPZC() michael@0: { michael@0: const char* kPrefName = "layers.async-pan-zoom.enabled"; michael@0: return ShouldUseOffMainThreadCompositing() && michael@0: Preferences::GetBool(kPrefName, false); michael@0: } michael@0: michael@0: void michael@0: MetroWidget::SetWidgetListener(nsIWidgetListener* aWidgetListener) michael@0: { michael@0: mWidgetListener = aWidgetListener; michael@0: if (mController) { michael@0: mController->SetWidgetListener(aWidgetListener); michael@0: } michael@0: } michael@0: michael@0: CompositorParent* MetroWidget::NewCompositorParent(int aSurfaceWidth, int aSurfaceHeight) michael@0: { michael@0: CompositorParent *compositor = nsBaseWidget::NewCompositorParent(aSurfaceWidth, aSurfaceHeight); michael@0: michael@0: if (ShouldUseAPZC()) { michael@0: mRootLayerTreeId = compositor->RootLayerTreeId(); michael@0: michael@0: mController = new APZController(); michael@0: mController->SetWidgetListener(mWidgetListener); michael@0: michael@0: CompositorParent::SetControllerForLayerTree(mRootLayerTreeId, mController); michael@0: michael@0: APZController::sAPZC = CompositorParent::GetAPZCTreeManager(compositor->RootLayerTreeId()); michael@0: APZController::sAPZC->SetDPI(GetDPI()); michael@0: michael@0: nsresult rv; michael@0: nsCOMPtr observerService = do_GetService("@mozilla.org/observer-service;1", &rv); michael@0: if (NS_SUCCEEDED(rv)) { michael@0: observerService->AddObserver(this, "apzc-scroll-offset-changed", false); michael@0: observerService->AddObserver(this, "apzc-zoom-to-rect", false); michael@0: observerService->AddObserver(this, "apzc-disable-zoom", false); michael@0: } michael@0: } michael@0: michael@0: return compositor; michael@0: } michael@0: michael@0: MetroWidget::TouchBehaviorFlags michael@0: MetroWidget::ContentGetAllowedTouchBehavior(const nsIntPoint& aPoint) michael@0: { michael@0: return ContentHelper::GetAllowedTouchBehavior(this, aPoint); michael@0: } michael@0: michael@0: void michael@0: MetroWidget::ApzcGetAllowedTouchBehavior(WidgetInputEvent* aTransformedEvent, michael@0: nsTArray& aOutBehaviors) michael@0: { michael@0: LogFunction(); michael@0: return APZController::sAPZC->GetAllowedTouchBehavior(aTransformedEvent, aOutBehaviors); michael@0: } michael@0: michael@0: void michael@0: MetroWidget::ApzcSetAllowedTouchBehavior(const ScrollableLayerGuid& aGuid, michael@0: nsTArray& aBehaviors) michael@0: { michael@0: LogFunction(); michael@0: if (!APZController::sAPZC) { michael@0: return; michael@0: } michael@0: APZController::sAPZC->SetAllowedTouchBehavior(aGuid, aBehaviors); michael@0: } michael@0: michael@0: void michael@0: MetroWidget::ApzContentConsumingTouch(const ScrollableLayerGuid& aGuid) michael@0: { michael@0: LogFunction(); michael@0: if (!mController) { michael@0: return; michael@0: } michael@0: mController->ContentReceivedTouch(aGuid, true); michael@0: } michael@0: michael@0: void michael@0: MetroWidget::ApzContentIgnoringTouch(const ScrollableLayerGuid& aGuid) michael@0: { michael@0: LogFunction(); michael@0: if (!mController) { michael@0: return; michael@0: } michael@0: mController->ContentReceivedTouch(aGuid, false); michael@0: } michael@0: michael@0: bool michael@0: MetroWidget::ApzHitTest(ScreenIntPoint& pt) michael@0: { michael@0: if (!mController) { michael@0: return false; michael@0: } michael@0: return mController->HitTestAPZC(pt); michael@0: } michael@0: michael@0: void michael@0: MetroWidget::ApzTransformGeckoCoordinate(const ScreenIntPoint& aPoint, michael@0: LayoutDeviceIntPoint* aRefPointOut) michael@0: { michael@0: if (!mController) { michael@0: return; michael@0: } michael@0: mController->TransformCoordinateToGecko(aPoint, aRefPointOut); michael@0: } michael@0: michael@0: nsEventStatus michael@0: MetroWidget::ApzReceiveInputEvent(WidgetInputEvent* aEvent, michael@0: ScrollableLayerGuid* aOutTargetGuid) michael@0: { michael@0: MOZ_ASSERT(aEvent); michael@0: michael@0: if (!mController) { michael@0: return nsEventStatus_eIgnore; michael@0: } michael@0: return mController->ReceiveInputEvent(aEvent, aOutTargetGuid); michael@0: } michael@0: michael@0: LayerManager* michael@0: MetroWidget::GetLayerManager(PLayerTransactionChild* aShadowManager, michael@0: LayersBackend aBackendHint, michael@0: LayerManagerPersistence aPersistence, michael@0: bool* aAllowRetaining) michael@0: { michael@0: bool retaining = true; michael@0: michael@0: // If we initialized earlier than the view, recreate the layer manager now michael@0: if (mLayerManager && michael@0: mTempBasicLayerInUse && michael@0: ShouldUseOffMainThreadCompositing()) { michael@0: mLayerManager = nullptr; michael@0: mTempBasicLayerInUse = false; michael@0: retaining = false; michael@0: } michael@0: michael@0: // If the backend device has changed, create a new manager (pulled from nswindow) michael@0: if (mLayerManager) { michael@0: if (mLayerManager->GetBackendType() == LayersBackend::LAYERS_D3D10) { michael@0: LayerManagerD3D10 *layerManagerD3D10 = michael@0: static_cast(mLayerManager.get()); michael@0: if (layerManagerD3D10->device() != michael@0: gfxWindowsPlatform::GetPlatform()->GetD3D10Device()) { michael@0: MOZ_ASSERT(!mLayerManager->IsInTransaction()); michael@0: michael@0: mLayerManager->Destroy(); michael@0: mLayerManager = nullptr; michael@0: retaining = false; michael@0: } michael@0: } michael@0: } michael@0: michael@0: HRESULT hr = S_OK; michael@0: michael@0: // Create a layer manager: try to use an async compositor first, if enabled. michael@0: // Otherwise fall back on the main thread d3d manager. michael@0: if (!mLayerManager) { michael@0: if (ShouldUseOffMainThreadCompositing()) { michael@0: NS_ASSERTION(aShadowManager == nullptr, "Async Compositor not supported with e10s"); michael@0: CreateCompositor(); michael@0: } else if (ShouldUseMainThreadD3D10Manager()) { michael@0: nsRefPtr layerManager = michael@0: new mozilla::layers::LayerManagerD3D10(this); michael@0: if (layerManager->Initialize(true, &hr)) { michael@0: mLayerManager = layerManager; michael@0: } michael@0: } else if (ShouldUseBasicManager()) { michael@0: mLayerManager = CreateBasicLayerManager(); michael@0: } michael@0: // Either we're not ready to initialize yet due to a missing view pointer, michael@0: // or something has gone wrong. michael@0: if (!mLayerManager) { michael@0: if (!mView) { michael@0: NS_WARNING("Using temporary basic layer manager."); michael@0: mLayerManager = new BasicLayerManager(this); michael@0: mTempBasicLayerInUse = true; michael@0: } else { michael@0: #ifdef MOZ_CRASHREPORTER michael@0: if (FAILED(hr)) { michael@0: char errorBuf[10]; michael@0: errorBuf[0] = '\0'; michael@0: _snprintf_s(errorBuf, sizeof(errorBuf), _TRUNCATE, "%X", hr); michael@0: CrashReporter:: michael@0: AnnotateCrashReport(NS_LITERAL_CSTRING("HRESULT"), michael@0: nsDependentCString(errorBuf)); michael@0: } michael@0: #endif michael@0: NS_RUNTIMEABORT("Couldn't create layer manager"); michael@0: } michael@0: } michael@0: } michael@0: michael@0: if (aAllowRetaining) { michael@0: *aAllowRetaining = retaining; michael@0: } michael@0: michael@0: return mLayerManager; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: MetroWidget::Invalidate(bool aEraseBackground, michael@0: bool aUpdateNCArea, michael@0: bool aIncludeChildren) michael@0: { michael@0: nsIntRect rect; michael@0: if (mView) { michael@0: mView->GetBounds(rect); michael@0: } michael@0: Invalidate(rect); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: MetroWidget::Invalidate(const nsIntRect & aRect) michael@0: { michael@0: if (mWnd) { michael@0: RECT rect; michael@0: rect.left = aRect.x; michael@0: rect.top = aRect.y; michael@0: rect.right = aRect.x + aRect.width; michael@0: rect.bottom = aRect.y + aRect.height; michael@0: InvalidateRect(mWnd, &rect, FALSE); michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsTransparencyMode michael@0: MetroWidget::GetTransparencyMode() michael@0: { michael@0: return mTransparencyMode; michael@0: } michael@0: michael@0: void michael@0: MetroWidget::SetTransparencyMode(nsTransparencyMode aMode) michael@0: { michael@0: mTransparencyMode = aMode; michael@0: } michael@0: michael@0: nsIWidgetListener* michael@0: MetroWidget::GetPaintListener() michael@0: { michael@0: if (mOnDestroyCalled) michael@0: return nullptr; michael@0: return mAttachedWidgetListener ? mAttachedWidgetListener : michael@0: mWidgetListener; michael@0: } michael@0: michael@0: void MetroWidget::Paint(const nsIntRegion& aInvalidRegion) michael@0: { michael@0: gfxWindowsPlatform::GetPlatform()->UpdateRenderMode(); michael@0: michael@0: nsIWidgetListener* listener = GetPaintListener(); michael@0: if (!listener) michael@0: return; michael@0: michael@0: listener->WillPaintWindow(this); michael@0: michael@0: // Refresh since calls like WillPaintWindow can destroy the widget michael@0: listener = GetPaintListener(); michael@0: if (!listener) michael@0: return; michael@0: michael@0: listener->PaintWindow(this, aInvalidRegion); michael@0: michael@0: listener = GetPaintListener(); michael@0: if (!listener) michael@0: return; michael@0: michael@0: listener->DidPaintWindow(); michael@0: } michael@0: michael@0: void MetroWidget::UserActivity() michael@0: { michael@0: // Check if we have the idle service, if not we try to get it. michael@0: if (!mIdleService) { michael@0: mIdleService = do_GetService("@mozilla.org/widget/idleservice;1"); michael@0: } michael@0: michael@0: // Check that we now have the idle service. michael@0: if (mIdleService) { michael@0: mIdleService->ResetIdleTimeOut(0); michael@0: } michael@0: } michael@0: michael@0: // InitEvent assumes physical coordinates and is used by shared win32 code. Do michael@0: // not hand winrt event coordinates to this routine. michael@0: void michael@0: MetroWidget::InitEvent(WidgetGUIEvent& event, nsIntPoint* aPoint) michael@0: { michael@0: if (!aPoint) { michael@0: event.refPoint.x = event.refPoint.y = 0; michael@0: } else { michael@0: event.refPoint.x = aPoint->x; michael@0: event.refPoint.y = aPoint->y; michael@0: } michael@0: event.time = ::GetMessageTime(); michael@0: } michael@0: michael@0: bool michael@0: MetroWidget::DispatchWindowEvent(WidgetGUIEvent* aEvent) michael@0: { michael@0: MOZ_ASSERT(aEvent); michael@0: nsEventStatus status = nsEventStatus_eIgnore; michael@0: DispatchEvent(aEvent, status); michael@0: return (status == nsEventStatus_eConsumeNoDefault); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: MetroWidget::DispatchEvent(WidgetGUIEvent* event, nsEventStatus & aStatus) michael@0: { michael@0: if (event->AsInputEvent()) { michael@0: UserActivity(); michael@0: } michael@0: michael@0: aStatus = nsEventStatus_eIgnore; michael@0: michael@0: // Top level windows can have a view attached which requires events be sent michael@0: // to the underlying base window and the view. Added when we combined the michael@0: // base chrome window with the main content child for nc client area (title michael@0: // bar) rendering. michael@0: if (mAttachedWidgetListener) { michael@0: aStatus = mAttachedWidgetListener->HandleEvent(event, mUseAttachedEvents); michael@0: } michael@0: else if (mWidgetListener) { michael@0: aStatus = mWidgetListener->HandleEvent(event, mUseAttachedEvents); michael@0: } michael@0: michael@0: // the window can be destroyed during processing of seemingly innocuous events like, say, michael@0: // mousedowns due to the magic of scripting. mousedowns will return nsEventStatus_eIgnore, michael@0: // which causes problems with the deleted window. therefore: michael@0: if (mOnDestroyCalled) michael@0: aStatus = nsEventStatus_eConsumeNoDefault; michael@0: return NS_OK; michael@0: } michael@0: michael@0: #ifdef ACCESSIBILITY michael@0: mozilla::a11y::Accessible* michael@0: MetroWidget::GetAccessible() michael@0: { michael@0: // We want the ability to forcibly disable a11y on windows, because michael@0: // some non-a11y-related components attempt to bring it up. See bug michael@0: // 538530 for details; we have a pref here that allows it to be disabled michael@0: // for performance and testing resons. michael@0: // michael@0: // This pref is checked only once, and the browser needs a restart to michael@0: // pick up any changes. michael@0: static int accForceDisable = -1; michael@0: michael@0: if (accForceDisable == -1) { michael@0: const char* kPrefName = "accessibility.win32.force_disabled"; michael@0: if (Preferences::GetBool(kPrefName, false)) { michael@0: accForceDisable = 1; michael@0: } else { michael@0: accForceDisable = 0; michael@0: } michael@0: } michael@0: michael@0: // If the pref was true, return null here, disabling a11y. michael@0: if (accForceDisable) michael@0: return nullptr; michael@0: michael@0: return GetRootAccessible(); michael@0: } michael@0: #endif michael@0: michael@0: double michael@0: MetroWidget::GetDefaultScaleInternal() michael@0: { michael@0: return MetroUtils::ScaleFactor(); michael@0: } michael@0: michael@0: LayoutDeviceIntPoint michael@0: MetroWidget::CSSIntPointToLayoutDeviceIntPoint(const CSSIntPoint &aCSSPoint) michael@0: { michael@0: CSSToLayoutDeviceScale scale = GetDefaultScale(); michael@0: LayoutDeviceIntPoint devPx(int32_t(NS_round(scale.scale * aCSSPoint.x)), michael@0: int32_t(NS_round(scale.scale * aCSSPoint.y))); michael@0: return devPx; michael@0: } michael@0: michael@0: float michael@0: MetroWidget::GetDPI() michael@0: { michael@0: if (!mView) { michael@0: return 96.0; michael@0: } michael@0: return mView->GetDPI(); michael@0: } michael@0: michael@0: void michael@0: MetroWidget::ChangedDPI() michael@0: { michael@0: if (mWidgetListener) { michael@0: nsIPresShell* presShell = mWidgetListener->GetPresShell(); michael@0: if (presShell) { michael@0: presShell->BackingScaleFactorChanged(); michael@0: } michael@0: } michael@0: } michael@0: michael@0: already_AddRefed michael@0: MetroWidget::GetPresShell() michael@0: { michael@0: if (mWidgetListener) { michael@0: nsCOMPtr ps = mWidgetListener->GetPresShell(); michael@0: return ps.forget(); michael@0: } michael@0: return nullptr; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: MetroWidget::ConstrainPosition(bool aAllowSlop, int32_t *aX, int32_t *aY) michael@0: { michael@0: return NS_OK; michael@0: } michael@0: michael@0: void michael@0: MetroWidget::SizeModeChanged() michael@0: { michael@0: if (mWidgetListener) { michael@0: mWidgetListener->SizeModeChanged(nsSizeMode_Normal); michael@0: } michael@0: } michael@0: michael@0: void michael@0: MetroWidget::Activated(bool aActiveated) michael@0: { michael@0: if (mWidgetListener) { michael@0: aActiveated ? michael@0: mWidgetListener->WindowActivated() : michael@0: mWidgetListener->WindowDeactivated(); michael@0: } michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: MetroWidget::Move(double aX, double aY) michael@0: { michael@0: NotifyWindowMoved(aX, aY); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: MetroWidget::Resize(double aWidth, double aHeight, bool aRepaint) michael@0: { michael@0: return Resize(0, 0, aWidth, aHeight, aRepaint); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: MetroWidget::Resize(double aX, double aY, double aWidth, double aHeight, bool aRepaint) michael@0: { michael@0: WinUtils::Log("Resize: %f %f %f %f", aX, aY, aWidth, aHeight); michael@0: if (mAttachedWidgetListener) { michael@0: mAttachedWidgetListener->WindowResized(this, aWidth, aHeight); michael@0: } michael@0: if (mWidgetListener) { michael@0: mWidgetListener->WindowResized(this, aWidth, aHeight); michael@0: } michael@0: Invalidate(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: MetroWidget::SetFocus(bool aRaise) michael@0: { michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult michael@0: MetroWidget::ConfigureChildren(const nsTArray& aConfigurations) michael@0: { michael@0: return NS_OK; michael@0: } michael@0: michael@0: void* michael@0: MetroWidget::GetNativeData(uint32_t aDataType) michael@0: { michael@0: switch(aDataType) { michael@0: case NS_NATIVE_WINDOW: michael@0: return mWnd; michael@0: case NS_NATIVE_ICOREWINDOW: michael@0: if (mView) { michael@0: return reinterpret_cast(mView->GetCoreWindow()); michael@0: } michael@0: break; michael@0: case NS_NATIVE_TSF_THREAD_MGR: michael@0: case NS_NATIVE_TSF_CATEGORY_MGR: michael@0: case NS_NATIVE_TSF_DISPLAY_ATTR_MGR: michael@0: return nsTextStore::GetNativeData(aDataType); michael@0: } michael@0: return nullptr; michael@0: } michael@0: michael@0: void michael@0: MetroWidget::FreeNativeData(void * data, uint32_t aDataType) michael@0: { michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: MetroWidget::SetTitle(const nsAString& aTitle) michael@0: { michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsIntPoint michael@0: MetroWidget::WidgetToScreenOffset() michael@0: { michael@0: return nsIntPoint(0,0); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: MetroWidget::CaptureRollupEvents(nsIRollupListener * aListener, michael@0: bool aDoCapture) michael@0: { michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP_(void) michael@0: MetroWidget::SetInputContext(const InputContext& aContext, michael@0: const InputContextAction& aAction) michael@0: { michael@0: mInputContext = aContext; michael@0: nsTextStore::SetInputContext(this, mInputContext, aAction); michael@0: bool enable = (mInputContext.mIMEState.mEnabled == IMEState::ENABLED || michael@0: mInputContext.mIMEState.mEnabled == IMEState::PLUGIN); michael@0: if (enable && michael@0: mInputContext.mIMEState.mOpen != IMEState::DONT_CHANGE_OPEN_STATE) { michael@0: bool open = (mInputContext.mIMEState.mOpen == IMEState::OPEN); michael@0: nsTextStore::SetIMEOpenState(open); michael@0: } michael@0: } michael@0: michael@0: NS_IMETHODIMP_(nsIWidget::InputContext) michael@0: MetroWidget::GetInputContext() michael@0: { michael@0: return mInputContext; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: MetroWidget::NotifyIME(const IMENotification& aIMENotification) michael@0: { michael@0: switch (aIMENotification.mMessage) { michael@0: case REQUEST_TO_COMMIT_COMPOSITION: michael@0: nsTextStore::CommitComposition(false); michael@0: return NS_OK; michael@0: case REQUEST_TO_CANCEL_COMPOSITION: michael@0: nsTextStore::CommitComposition(true); michael@0: return NS_OK; michael@0: case NOTIFY_IME_OF_FOCUS: michael@0: return nsTextStore::OnFocusChange(true, this, michael@0: mInputContext.mIMEState.mEnabled); michael@0: case NOTIFY_IME_OF_BLUR: michael@0: return nsTextStore::OnFocusChange(false, this, michael@0: mInputContext.mIMEState.mEnabled); michael@0: case NOTIFY_IME_OF_SELECTION_CHANGE: michael@0: return nsTextStore::OnSelectionChange(); michael@0: case NOTIFY_IME_OF_TEXT_CHANGE: michael@0: return nsTextStore::OnTextChange(aIMENotification); michael@0: case NOTIFY_IME_OF_POSITION_CHANGE: michael@0: return nsTextStore::OnLayoutChange(); michael@0: default: michael@0: return NS_ERROR_NOT_IMPLEMENTED; michael@0: } michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: MetroWidget::GetToggledKeyState(uint32_t aKeyCode, bool* aLEDState) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aLEDState); michael@0: *aLEDState = (::GetKeyState(aKeyCode) & 1) != 0; michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsIMEUpdatePreference michael@0: MetroWidget::GetIMEUpdatePreference() michael@0: { michael@0: return nsTextStore::GetIMEUpdatePreference(); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: MetroWidget::ReparentNativeWidget(nsIWidget* aNewParent) michael@0: { michael@0: return NS_OK; michael@0: } michael@0: michael@0: void michael@0: MetroWidget::SuppressBlurEvents(bool aSuppress) michael@0: { michael@0: } michael@0: michael@0: bool michael@0: MetroWidget::BlurEventsSuppressed() michael@0: { michael@0: return false; michael@0: } michael@0: michael@0: void michael@0: MetroWidget::PickerOpen() michael@0: { michael@0: } michael@0: michael@0: void michael@0: MetroWidget::PickerClosed() michael@0: { michael@0: } michael@0: michael@0: bool michael@0: MetroWidget::HasPendingInputEvent() michael@0: { michael@0: if (HIWORD(GetQueueStatus(QS_INPUT))) michael@0: return true; michael@0: return false; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: MetroWidget::Observe(nsISupports *subject, const char *topic, const char16_t *data) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(topic); michael@0: if (!strcmp(topic, "apzc-zoom-to-rect")) { michael@0: CSSRect rect = CSSRect(); michael@0: uint64_t viewId = 0; michael@0: int32_t presShellId = 0; michael@0: michael@0: int reScan = swscanf(data, L"%f,%f,%f,%f,%d,%llu", michael@0: &rect.x, &rect.y, &rect.width, &rect.height, michael@0: &presShellId, &viewId); michael@0: if(reScan != 6) { michael@0: NS_WARNING("Malformed apzc-zoom-to-rect message"); michael@0: } michael@0: michael@0: ScrollableLayerGuid guid = ScrollableLayerGuid(mRootLayerTreeId, presShellId, viewId); michael@0: APZController::sAPZC->ZoomToRect(guid, rect); michael@0: } michael@0: else if (!strcmp(topic, "apzc-disable-zoom")) { michael@0: uint64_t viewId = 0; michael@0: int32_t presShellId = 0; michael@0: michael@0: int reScan = swscanf(data, L"%d,%llu", michael@0: &presShellId, &viewId); michael@0: if (reScan != 2) { michael@0: NS_WARNING("Malformed apzc-disable-zoom message"); michael@0: } michael@0: michael@0: ScrollableLayerGuid guid = ScrollableLayerGuid(mRootLayerTreeId, presShellId, viewId); michael@0: APZController::sAPZC->UpdateZoomConstraints(guid, michael@0: ZoomConstraints(false, false, CSSToScreenScale(1.0f), CSSToScreenScale(1.0f))); michael@0: } michael@0: return NS_OK; michael@0: }