Wed, 31 Dec 2014 07:22:50 +0100
Correct previous dual key logic pending first delivery installment.
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "ContentHelper.h"
8 #include "LayerManagerD3D10.h"
9 #include "MetroWidget.h"
10 #include "MetroApp.h"
11 #include "mozilla/Preferences.h"
12 #include "nsToolkit.h"
13 #include "KeyboardLayout.h"
14 #include "MetroUtils.h"
15 #include "WinUtils.h"
16 #include "nsToolkitCompsCID.h"
17 #include "nsIAppStartup.h"
18 #include "../resource.h"
19 #include "nsIWidgetListener.h"
20 #include "nsIPresShell.h"
21 #include "nsPrintfCString.h"
22 #include "nsWindowDefs.h"
23 #include "FrameworkView.h"
24 #include "nsTextStore.h"
25 #include "Layers.h"
26 #include "ClientLayerManager.h"
27 #include "BasicLayers.h"
28 #include "FrameMetrics.h"
29 #include <windows.devices.input.h>
30 #include "Windows.Graphics.Display.h"
31 #include "DisplayInfo_sdk81.h"
32 #include "nsNativeDragTarget.h"
33 #ifdef MOZ_CRASHREPORTER
34 #include "nsExceptionHandler.h"
35 #endif
36 #include "UIABridgePrivate.h"
37 #include "WinMouseScrollHandler.h"
38 #include "InputData.h"
39 #include "mozilla/TextEvents.h"
40 #include "mozilla/TouchEvents.h"
41 #include "mozilla/MiscEvents.h"
43 using namespace Microsoft::WRL;
44 using namespace Microsoft::WRL::Wrappers;
46 using namespace mozilla;
47 using namespace mozilla::widget;
48 using namespace mozilla::layers;
49 using namespace mozilla::widget::winrt;
51 using namespace ABI::Windows::ApplicationModel;
52 using namespace ABI::Windows::ApplicationModel::Core;
53 using namespace ABI::Windows::ApplicationModel::Activation;
54 using namespace ABI::Windows::UI::Input;
55 using namespace ABI::Windows::Devices::Input;
56 using namespace ABI::Windows::UI::Core;
57 using namespace ABI::Windows::System;
58 using namespace ABI::Windows::Foundation;
59 using namespace ABI::Windows::Foundation::Collections;
60 using namespace ABI::Windows::Graphics::Display;
62 #ifdef PR_LOGGING
63 extern PRLogModuleInfo* gWindowsLog;
64 #endif
66 #if !defined(SM_CONVERTIBLESLATEMODE)
67 #define SM_CONVERTIBLESLATEMODE 0x2003
68 #endif
70 static uint32_t gInstanceCount = 0;
71 const char16_t* kMetroSubclassThisProp = L"MetroSubclassThisProp";
72 HWND MetroWidget::sICoreHwnd = nullptr;
74 namespace mozilla {
75 namespace widget {
76 UINT sDefaultBrowserMsgId = RegisterWindowMessageW(L"DefaultBrowserClosing");
77 } }
79 // WM_GETOBJECT id pulled from uia headers
80 #define UiaRootObjectId -25
82 namespace mozilla {
83 namespace widget {
84 namespace winrt {
85 extern ComPtr<MetroApp> sMetroApp;
86 extern ComPtr<IUIABridge> gProviderRoot;
87 } } }
89 namespace {
91 void SendInputs(uint32_t aModifiers, INPUT* aExtraInputs, uint32_t aExtraInputsLen)
92 {
93 // keySequence holds the virtual key values of each of the keys we intend
94 // to press
95 nsAutoTArray<KeyPair,32> keySequence;
96 for (uint32_t i = 0; i < ArrayLength(sModifierKeyMap); ++i) {
97 const uint32_t* map = sModifierKeyMap[i];
98 if (aModifiers & map[0]) {
99 keySequence.AppendElement(KeyPair(map[1], map[2]));
100 }
101 }
103 uint32_t const len = keySequence.Length() * 2 + aExtraInputsLen;
105 // The `inputs` array is a sequence of input events that will happen
106 // serially. We set the array up so that each modifier key is pressed
107 // down, then the additional input events happen,
108 // then each modifier key is released in reverse order of when
109 // it was pressed down. We pass this array to `SendInput`.
110 //
111 // inputs[0]: modifier key (e.g. shift, ctrl, etc) down
112 // ... ...
113 // inputs[keySequence.Length()-1]: modifier key (e.g. shift, ctrl, etc) down
114 // inputs[keySequence.Length()]: aExtraInputs[0]
115 // inputs[keySequence.Length()+1]: aExtraInputs[1]
116 // ... ...
117 // inputs[keySequence.Length() + aExtraInputsLen - 1]: aExtraInputs[aExtraInputsLen - 1]
118 // inputs[keySequence.Length() + aExtraInputsLen]: modifier key (e.g. shift, ctrl, etc) up
119 // ... ...
120 // inputs[len-1]: modifier key (e.g. shift, ctrl, etc) up
121 INPUT* inputs = new INPUT[len];
122 memset(inputs, 0, len * sizeof(INPUT));
123 for (uint32_t i = 0; i < keySequence.Length(); ++i) {
124 inputs[i].type = inputs[len-i-1].type = INPUT_KEYBOARD;
125 inputs[i].ki.wVk = inputs[len-i-1].ki.wVk = keySequence[i].mSpecific
126 ? keySequence[i].mSpecific
127 : keySequence[i].mGeneral;
128 inputs[len-i-1].ki.dwFlags |= KEYEVENTF_KEYUP;
129 }
130 for (uint32_t i = 0; i < aExtraInputsLen; i++) {
131 inputs[keySequence.Length()+i] = aExtraInputs[i];
132 }
133 WinUtils::Log(" Sending inputs");
134 for (uint32_t i = 0; i < len; i++) {
135 if (inputs[i].type == INPUT_KEYBOARD) {
136 WinUtils::Log(" Key press: 0x%x %s",
137 inputs[i].ki.wVk,
138 inputs[i].ki.dwFlags & KEYEVENTF_KEYUP
139 ? "UP"
140 : "DOWN");
141 } else if(inputs[i].type == INPUT_MOUSE) {
142 WinUtils::Log(" Mouse input: 0x%x 0x%x",
143 inputs[i].mi.dwFlags,
144 inputs[i].mi.mouseData);
145 } else {
146 WinUtils::Log(" Unknown input type!");
147 }
148 }
149 ::SendInput(len, inputs, sizeof(INPUT));
150 delete[] inputs;
152 // The inputs have been sent, and the WM_* messages they generate are
153 // waiting to be processed by our event loop. Now we manually pump
154 // those messages so that, upon our return, all the inputs have been
155 // processed.
156 WinUtils::Log(" Inputs sent. Waiting for input messages to clear");
157 MSG msg;
158 while (WinUtils::PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE)) {
159 if (nsTextStore::ProcessRawKeyMessage(msg)) {
160 continue; // the message is consumed by TSF
161 }
162 ::TranslateMessage(&msg);
163 ::DispatchMessage(&msg);
164 WinUtils::Log(" Dispatched 0x%x 0x%x 0x%x", msg.message, msg.wParam, msg.lParam);
165 }
166 WinUtils::Log(" No more input messages");
167 }
168 }
170 NS_IMPL_ISUPPORTS_INHERITED0(MetroWidget, nsBaseWidget)
172 MetroWidget::MetroWidget() :
173 mTransparencyMode(eTransparencyOpaque),
174 mWnd(nullptr),
175 mMetroWndProc(nullptr),
176 mTempBasicLayerInUse(false),
177 mRootLayerTreeId(),
178 nsWindowBase()
179 {
180 // Global initialization
181 if (!gInstanceCount) {
182 UserActivity();
183 nsTextStore::Initialize();
184 MouseScrollHandler::Initialize();
185 KeyboardLayout::GetInstance()->OnLayoutChange(::GetKeyboardLayout(0));
186 } // !gInstanceCount
187 gInstanceCount++;
188 }
190 MetroWidget::~MetroWidget()
191 {
192 LogThis();
194 gInstanceCount--;
196 // Global shutdown
197 if (!gInstanceCount) {
198 APZController::sAPZC = nullptr;
199 nsTextStore::Terminate();
200 } // !gInstanceCount
201 }
203 static bool gTopLevelAssigned = false;
204 NS_IMETHODIMP
205 MetroWidget::Create(nsIWidget *aParent,
206 nsNativeWidget aNativeParent,
207 const nsIntRect &aRect,
208 nsDeviceContext *aContext,
209 nsWidgetInitData *aInitData)
210 {
211 LogFunction();
213 nsWidgetInitData defaultInitData;
214 if (!aInitData)
215 aInitData = &defaultInitData;
217 mWindowType = aInitData->mWindowType;
219 // Ensure that the toolkit is created.
220 nsToolkit::GetToolkit();
222 BaseCreate(aParent, aRect, aContext, aInitData);
224 if (mWindowType != eWindowType_toplevel) {
225 switch(mWindowType) {
226 case eWindowType_dialog:
227 WinUtils::Log("eWindowType_dialog window requested, returning failure.");
228 break;
229 case eWindowType_child:
230 WinUtils::Log("eWindowType_child window requested, returning failure.");
231 break;
232 case eWindowType_popup:
233 WinUtils::Log("eWindowType_popup window requested, returning failure.");
234 break;
235 case eWindowType_plugin:
236 WinUtils::Log("eWindowType_plugin window requested, returning failure.");
237 break;
238 // we should support toolkit's eWindowType_invisible at some point.
239 case eWindowType_invisible:
240 WinUtils::Log("eWindowType_invisible window requested, this doesn't actually exist!");
241 return NS_OK;
242 }
243 NS_WARNING("Invalid window type requested.");
244 return NS_ERROR_FAILURE;
245 }
247 if (gTopLevelAssigned) {
248 // Need to accept so that the mochitest-chrome test harness window
249 // can be created.
250 NS_WARNING("New eWindowType_toplevel window requested after FrameworkView widget created.");
251 NS_WARNING("Widget created but the physical window does not exist! Fix me!");
252 return NS_OK;
253 }
255 // the main widget gets created first
256 gTopLevelAssigned = true;
257 sMetroApp->SetWidget(this);
258 WinUtils::SetNSWindowBasePtr(mWnd, this);
260 if (mWidgetListener) {
261 mWidgetListener->WindowActivated();
262 }
264 return NS_OK;
265 }
267 void
268 MetroWidget::SetView(FrameworkView* aView)
269 {
270 mView = aView;
271 // If we've already set this up, it points to a useless
272 // layer manager, so reset it.
273 mLayerManager = nullptr;
274 }
276 NS_IMETHODIMP
277 MetroWidget::Destroy()
278 {
279 if (mOnDestroyCalled)
280 return NS_OK;
281 WinUtils::Log("[%X] %s mWnd=%X type=%d", this, __FUNCTION__, mWnd, mWindowType);
282 mOnDestroyCalled = true;
284 nsCOMPtr<nsIWidget> kungFuDeathGrip(this);
286 if (ShouldUseAPZC()) {
287 nsresult rv;
288 nsCOMPtr<nsIObserverService> observerService = do_GetService("@mozilla.org/observer-service;1", &rv);
289 if (NS_SUCCEEDED(rv)) {
290 observerService->RemoveObserver(this, "apzc-scroll-offset-changed");
291 observerService->RemoveObserver(this, "apzc-zoom-to-rect");
292 observerService->RemoveObserver(this, "apzc-disable-zoom");
293 }
294 }
296 RemoveSubclass();
297 NotifyWindowDestroyed();
299 // Prevent the widget from sending additional events.
300 mWidgetListener = nullptr;
301 mAttachedWidgetListener = nullptr;
303 // Release references to children, device context, toolkit, and app shell.
304 nsBaseWidget::Destroy();
305 nsBaseWidget::OnDestroy();
306 WinUtils::SetNSWindowBasePtr(mWnd, nullptr);
308 if (mLayerManager) {
309 mLayerManager->Destroy();
310 }
312 mLayerManager = nullptr;
313 mView = nullptr;
314 mIdleService = nullptr;
315 mWnd = nullptr;
317 return NS_OK;
318 }
320 NS_IMETHODIMP
321 MetroWidget::SetParent(nsIWidget *aNewParent)
322 {
323 return NS_OK;
324 }
326 NS_IMETHODIMP
327 MetroWidget::Show(bool bState)
328 {
329 return NS_OK;
330 }
332 uint32_t
333 MetroWidget::GetMaxTouchPoints() const
334 {
335 ComPtr<IPointerDeviceStatics> deviceStatics;
337 HRESULT hr = GetActivationFactory(
338 HStringReference(RuntimeClass_Windows_Devices_Input_PointerDevice).Get(),
339 deviceStatics.GetAddressOf());
341 if (FAILED(hr)) {
342 return 0;
343 }
345 ComPtr< IVectorView<PointerDevice*> > deviceList;
346 hr = deviceStatics->GetPointerDevices(&deviceList);
348 if (FAILED(hr)) {
349 return 0;
350 }
352 uint32_t deviceNum = 0;
353 deviceList->get_Size(&deviceNum);
355 uint32_t maxTouchPoints = 0;
356 for (uint32_t index = 0; index < deviceNum; ++index) {
357 ComPtr<IPointerDevice> device;
358 PointerDeviceType deviceType;
360 if (FAILED(deviceList->GetAt(index, device.GetAddressOf()))) {
361 continue;
362 }
364 if (FAILED(device->get_PointerDeviceType(&deviceType))) {
365 continue;
366 }
368 if (deviceType == PointerDeviceType_Touch) {
369 uint32_t deviceMaxTouchPoints = 0;
370 device->get_MaxContacts(&deviceMaxTouchPoints);
371 maxTouchPoints = std::max(maxTouchPoints, deviceMaxTouchPoints);
372 }
373 }
375 return maxTouchPoints;
376 }
378 NS_IMETHODIMP
379 MetroWidget::IsVisible(bool & aState)
380 {
381 aState = mView->IsVisible();
382 return NS_OK;
383 }
385 bool
386 MetroWidget::IsVisible() const
387 {
388 if (!mView)
389 return false;
390 return mView->IsVisible();
391 }
393 NS_IMETHODIMP
394 MetroWidget::EnableDragDrop(bool aEnable) {
395 if (aEnable) {
396 if (nullptr == mNativeDragTarget) {
397 mNativeDragTarget = new nsNativeDragTarget(this);
398 if (!mNativeDragTarget) {
399 return NS_ERROR_FAILURE;
400 }
401 }
403 HRESULT hr = ::RegisterDragDrop(mWnd, static_cast<LPDROPTARGET>(mNativeDragTarget));
404 return SUCCEEDED(hr) ? NS_OK : NS_ERROR_FAILURE;
405 } else {
406 if (nullptr == mNativeDragTarget) {
407 return NS_OK;
408 }
410 HRESULT hr = ::RevokeDragDrop(mWnd);
411 return SUCCEEDED(hr) ? NS_OK : NS_ERROR_FAILURE;
412 }
413 }
415 NS_IMETHODIMP
416 MetroWidget::IsEnabled(bool *aState)
417 {
418 *aState = mView->IsEnabled();
419 return NS_OK;
420 }
422 bool
423 MetroWidget::IsEnabled() const
424 {
425 if (!mView)
426 return false;
427 return mView->IsEnabled();
428 }
430 NS_IMETHODIMP
431 MetroWidget::Enable(bool bState)
432 {
433 return NS_OK;
434 }
436 NS_IMETHODIMP
437 MetroWidget::GetBounds(nsIntRect &aRect)
438 {
439 if (mView) {
440 mView->GetBounds(aRect);
441 } else {
442 nsIntRect rect(0,0,0,0);
443 aRect = rect;
444 }
445 return NS_OK;
446 }
448 NS_IMETHODIMP
449 MetroWidget::GetScreenBounds(nsIntRect &aRect)
450 {
451 if (mView) {
452 mView->GetBounds(aRect);
453 } else {
454 nsIntRect rect(0,0,0,0);
455 aRect = rect;
456 }
457 return NS_OK;
458 }
460 NS_IMETHODIMP
461 MetroWidget::GetClientBounds(nsIntRect &aRect)
462 {
463 if (mView) {
464 mView->GetBounds(aRect);
465 } else {
466 nsIntRect rect(0,0,0,0);
467 aRect = rect;
468 }
469 return NS_OK;
470 }
472 NS_IMETHODIMP
473 MetroWidget::SetCursor(nsCursor aCursor)
474 {
475 if (!mView)
476 return NS_ERROR_FAILURE;
478 switch (aCursor) {
479 case eCursor_select:
480 mView->SetCursor(CoreCursorType::CoreCursorType_IBeam);
481 break;
482 case eCursor_wait:
483 mView->SetCursor(CoreCursorType::CoreCursorType_Wait);
484 break;
485 case eCursor_hyperlink:
486 mView->SetCursor(CoreCursorType::CoreCursorType_Hand);
487 break;
488 case eCursor_standard:
489 mView->SetCursor(CoreCursorType::CoreCursorType_Arrow);
490 break;
491 case eCursor_n_resize:
492 case eCursor_s_resize:
493 mView->SetCursor(CoreCursorType::CoreCursorType_SizeNorthSouth);
494 break;
495 case eCursor_w_resize:
496 case eCursor_e_resize:
497 mView->SetCursor(CoreCursorType::CoreCursorType_SizeWestEast);
498 break;
499 case eCursor_nw_resize:
500 case eCursor_se_resize:
501 mView->SetCursor(CoreCursorType::CoreCursorType_SizeNorthwestSoutheast);
502 break;
503 case eCursor_ne_resize:
504 case eCursor_sw_resize:
505 mView->SetCursor(CoreCursorType::CoreCursorType_SizeNortheastSouthwest);
506 break;
507 case eCursor_crosshair:
508 mView->SetCursor(CoreCursorType::CoreCursorType_Cross);
509 break;
510 case eCursor_move:
511 mView->SetCursor(CoreCursorType::CoreCursorType_SizeAll);
512 break;
513 case eCursor_help:
514 mView->SetCursor(CoreCursorType::CoreCursorType_Help);
515 break;
516 // CSS3 custom cursors
517 case eCursor_copy:
518 mView->SetCursor(CoreCursorType::CoreCursorType_Custom, IDC_COPY);
519 break;
520 case eCursor_alias:
521 mView->SetCursor(CoreCursorType::CoreCursorType_Custom, IDC_ALIAS);
522 break;
523 case eCursor_cell:
524 mView->SetCursor(CoreCursorType::CoreCursorType_Custom, IDC_CELL);
525 break;
526 case eCursor_grab:
527 mView->SetCursor(CoreCursorType::CoreCursorType_Custom, IDC_GRAB);
528 break;
529 case eCursor_grabbing:
530 mView->SetCursor(CoreCursorType::CoreCursorType_Custom, IDC_GRABBING);
531 break;
532 case eCursor_spinning:
533 mView->SetCursor(CoreCursorType::CoreCursorType_Wait);
534 break;
535 case eCursor_context_menu:
536 mView->SetCursor(CoreCursorType::CoreCursorType_Arrow);
537 break;
538 case eCursor_zoom_in:
539 mView->SetCursor(CoreCursorType::CoreCursorType_Custom, IDC_ZOOMIN);
540 break;
541 case eCursor_zoom_out:
542 mView->SetCursor(CoreCursorType::CoreCursorType_Custom, IDC_ZOOMOUT);
543 break;
544 case eCursor_not_allowed:
545 case eCursor_no_drop:
546 mView->SetCursor(CoreCursorType::CoreCursorType_UniversalNo);
547 break;
548 case eCursor_col_resize:
549 mView->SetCursor(CoreCursorType::CoreCursorType_Custom, IDC_COLRESIZE);
550 break;
551 case eCursor_row_resize:
552 mView->SetCursor(CoreCursorType::CoreCursorType_Custom, IDC_ROWRESIZE);
553 break;
554 case eCursor_vertical_text:
555 mView->SetCursor(CoreCursorType::CoreCursorType_Custom, IDC_VERTICALTEXT);
556 break;
557 case eCursor_all_scroll:
558 mView->SetCursor(CoreCursorType::CoreCursorType_SizeAll);
559 break;
560 case eCursor_nesw_resize:
561 mView->SetCursor(CoreCursorType::CoreCursorType_SizeNortheastSouthwest);
562 break;
563 case eCursor_nwse_resize:
564 mView->SetCursor(CoreCursorType::CoreCursorType_SizeNorthwestSoutheast);
565 break;
566 case eCursor_ns_resize:
567 mView->SetCursor(CoreCursorType::CoreCursorType_SizeNorthSouth);
568 break;
569 case eCursor_ew_resize:
570 mView->SetCursor(CoreCursorType::CoreCursorType_SizeWestEast);
571 break;
572 case eCursor_none:
573 mView->ClearCursor();
574 break;
575 default:
576 NS_WARNING("Invalid cursor type");
577 break;
578 }
579 return NS_OK;
580 }
582 nsresult
583 MetroWidget::SynthesizeNativeKeyEvent(int32_t aNativeKeyboardLayout,
584 int32_t aNativeKeyCode,
585 uint32_t aModifierFlags,
586 const nsAString& aCharacters,
587 const nsAString& aUnmodifiedCharacters)
588 {
589 KeyboardLayout* keyboardLayout = KeyboardLayout::GetInstance();
590 return keyboardLayout->SynthesizeNativeKeyEvent(
591 this, aNativeKeyboardLayout, aNativeKeyCode, aModifierFlags,
592 aCharacters, aUnmodifiedCharacters);
593 }
595 nsresult
596 MetroWidget::SynthesizeNativeMouseEvent(nsIntPoint aPoint,
597 uint32_t aNativeMessage,
598 uint32_t aModifierFlags)
599 {
600 WinUtils::Log("ENTERED SynthesizeNativeMouseEvent");
602 INPUT inputs[2];
603 memset(inputs, 0, 2*sizeof(INPUT));
604 inputs[0].type = inputs[1].type = INPUT_MOUSE;
605 inputs[0].mi.dwFlags = MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE;
606 // Inexplicably, the x and y coordinates that we want to move the mouse to
607 // are specified as values in the range (0, 65535). (0,0) represents the
608 // top left of the primary monitor and (65535, 65535) represents the
609 // bottom right of the primary monitor.
610 inputs[0].mi.dx = (aPoint.x * 65535) / ::GetSystemMetrics(SM_CXSCREEN);
611 inputs[0].mi.dy = (aPoint.y * 65535) / ::GetSystemMetrics(SM_CYSCREEN);
612 inputs[1].mi.dwFlags = aNativeMessage;
613 SendInputs(aModifierFlags, inputs, 2);
615 WinUtils::Log("Exiting SynthesizeNativeMouseEvent");
616 return NS_OK;
617 }
619 nsresult
620 MetroWidget::SynthesizeNativeMouseScrollEvent(nsIntPoint aPoint,
621 uint32_t aNativeMessage,
622 double aDeltaX,
623 double aDeltaY,
624 double aDeltaZ,
625 uint32_t aModifierFlags,
626 uint32_t aAdditionalFlags)
627 {
628 return MouseScrollHandler::SynthesizeNativeMouseScrollEvent(
629 this, aPoint, aNativeMessage,
630 (aNativeMessage == WM_MOUSEWHEEL || aNativeMessage == WM_VSCROLL) ?
631 static_cast<int32_t>(aDeltaY) : static_cast<int32_t>(aDeltaX),
632 aModifierFlags, aAdditionalFlags);
633 }
635 static void
636 CloseGesture()
637 {
638 LogFunction();
639 nsCOMPtr<nsIAppStartup> appStartup =
640 do_GetService(NS_APPSTARTUP_CONTRACTID);
641 if (appStartup) {
642 appStartup->Quit(nsIAppStartup::eForceQuit);
643 }
644 }
646 // Async event sending for mouse and keyboard input.
648 // defined in nsWindowBase, called from shared module WinMouseScrollHandler.
649 bool
650 MetroWidget::DispatchScrollEvent(mozilla::WidgetGUIEvent* aEvent)
651 {
652 WidgetGUIEvent* newEvent = nullptr;
653 switch(aEvent->eventStructType) {
654 case NS_WHEEL_EVENT:
655 {
656 WidgetWheelEvent* oldEvent = aEvent->AsWheelEvent();
657 WidgetWheelEvent* wheelEvent =
658 new WidgetWheelEvent(oldEvent->mFlags.mIsTrusted, oldEvent->message, oldEvent->widget);
659 wheelEvent->AssignWheelEventData(*oldEvent, true);
660 newEvent = static_cast<WidgetGUIEvent*>(wheelEvent);
661 }
662 break;
663 case NS_CONTENT_COMMAND_EVENT:
664 {
665 WidgetContentCommandEvent* oldEvent = aEvent->AsContentCommandEvent();
666 WidgetContentCommandEvent* cmdEvent =
667 new WidgetContentCommandEvent(oldEvent->mFlags.mIsTrusted, oldEvent->message, oldEvent->widget);
668 cmdEvent->AssignContentCommandEventData(*oldEvent, true);
669 newEvent = static_cast<WidgetGUIEvent*>(cmdEvent);
670 }
671 break;
672 default:
673 MOZ_CRASH("unknown event in DispatchScrollEvent");
674 break;
675 }
676 mEventQueue.Push(newEvent);
677 nsCOMPtr<nsIRunnable> runnable =
678 NS_NewRunnableMethod(this, &MetroWidget::DeliverNextScrollEvent);
679 NS_DispatchToCurrentThread(runnable);
680 return false;
681 }
683 void
684 MetroWidget::DeliverNextScrollEvent()
685 {
686 WidgetGUIEvent* event =
687 static_cast<WidgetInputEvent*>(mEventQueue.PopFront());
688 DispatchWindowEvent(event);
689 delete event;
690 }
692 // defined in nsWindowBase, called from shared module KeyboardLayout.
693 bool
694 MetroWidget::DispatchKeyboardEvent(WidgetGUIEvent* aEvent)
695 {
696 MOZ_ASSERT(aEvent);
697 WidgetKeyboardEvent* oldKeyEvent = aEvent->AsKeyboardEvent();
698 WidgetKeyboardEvent* keyEvent =
699 new WidgetKeyboardEvent(oldKeyEvent->mFlags.mIsTrusted,
700 oldKeyEvent->message, oldKeyEvent->widget);
701 // XXX note this leaves pluginEvent null, which is fine for now.
702 keyEvent->AssignKeyEventData(*oldKeyEvent, true);
703 mKeyEventQueue.Push(keyEvent);
704 nsCOMPtr<nsIRunnable> runnable =
705 NS_NewRunnableMethod(this, &MetroWidget::DeliverNextKeyboardEvent);
706 NS_DispatchToCurrentThread(runnable);
707 return false;
708 }
710 // Used in conjunction with mKeyEventQueue to find a keypress event
711 // that should not be delivered due to the return result of the
712 // preceeding keydown.
713 class KeyQueryIdAndCancel : public nsDequeFunctor {
714 public:
715 KeyQueryIdAndCancel(uint32_t aIdToCancel) :
716 mId(aIdToCancel) {
717 }
718 virtual void* operator() (void* aObject) {
719 WidgetKeyboardEvent* event = static_cast<WidgetKeyboardEvent*>(aObject);
720 if (event->mUniqueId == mId) {
721 event->mFlags.mPropagationStopped = true;
722 }
723 return nullptr;
724 }
725 protected:
726 uint32_t mId;
727 };
729 void
730 MetroWidget::DeliverNextKeyboardEvent()
731 {
732 WidgetKeyboardEvent* event =
733 static_cast<WidgetKeyboardEvent*>(mKeyEventQueue.PopFront());
734 if (event->mFlags.mPropagationStopped) {
735 // This can happen if a keypress was previously cancelled.
736 delete event;
737 return;
738 }
740 if (DispatchWindowEvent(event) && event->message == NS_KEY_DOWN) {
741 // keydown events may be followed by multiple keypress events which
742 // shouldn't be sent if preventDefault is called on keydown.
743 KeyQueryIdAndCancel query(event->mUniqueId);
744 mKeyEventQueue.ForEach(query);
745 }
746 delete event;
747 }
749 // static
750 LRESULT CALLBACK
751 MetroWidget::StaticWindowProcedure(HWND aWnd, UINT aMsg, WPARAM aWParam, LPARAM aLParam)
752 {
753 MetroWidget* self = reinterpret_cast<MetroWidget*>(
754 GetProp(aWnd, kMetroSubclassThisProp));
755 if (!self) {
756 NS_NOTREACHED("Missing 'this' prop on subclassed metro window, this is bad.");
757 return 0;
758 }
759 return self->WindowProcedure(aWnd, aMsg, aWParam, aLParam);
760 }
762 LRESULT
763 MetroWidget::WindowProcedure(HWND aWnd, UINT aMsg, WPARAM aWParam, LPARAM aLParam)
764 {
765 if(sDefaultBrowserMsgId == aMsg) {
766 CloseGesture();
767 } else if (WM_SETTINGCHANGE == aMsg) {
768 if (aLParam && !wcsicmp(L"ConvertibleSlateMode", (wchar_t*)aLParam)) {
769 // If we're switching away from slate mode, switch to Desktop for
770 // hardware that supports this feature if the pref is set.
771 if (GetSystemMetrics(SM_CONVERTIBLESLATEMODE) != 0 &&
772 Preferences::GetBool("browser.shell.metro-auto-switch-enabled",
773 false)) {
774 nsCOMPtr<nsIAppStartup> appStartup(do_GetService(NS_APPSTARTUP_CONTRACTID));
775 if (appStartup) {
776 appStartup->Quit(nsIAppStartup::eForceQuit | nsIAppStartup::eRestart);
777 }
778 }
779 }
780 }
782 // Indicates if we should hand messages to the default windows
783 // procedure for processing.
784 bool processDefault = true;
786 // The result returned if we do not do default processing.
787 LRESULT processResult = 0;
789 MSGResult msgResult(&processResult);
790 MouseScrollHandler::ProcessMessage(this, aMsg, aWParam, aLParam, msgResult);
791 if (msgResult.mConsumed) {
792 return processResult;
793 }
795 nsTextStore::ProcessMessage(this, aMsg, aWParam, aLParam, msgResult);
796 if (msgResult.mConsumed) {
797 return processResult;
798 }
800 switch (aMsg) {
801 case WM_POWERBROADCAST:
802 {
803 switch (aWParam)
804 {
805 case PBT_APMSUSPEND:
806 MetroApp::PostSleepWakeNotification(true);
807 break;
808 case PBT_APMRESUMEAUTOMATIC:
809 case PBT_APMRESUMECRITICAL:
810 case PBT_APMRESUMESUSPEND:
811 MetroApp::PostSleepWakeNotification(false);
812 break;
813 }
814 break;
815 }
817 // Keyboard handling is passed to KeyboardLayout, which delivers gecko events
818 // via DispatchKeyboardEvent.
820 case WM_KEYDOWN:
821 case WM_SYSKEYDOWN:
822 {
823 MSG msg = WinUtils::InitMSG(aMsg, aWParam, aLParam, aWnd);
824 // If this method doesn't call NativeKey::HandleKeyDownMessage(), this
825 // method must clean up the redirected message information itself. For
826 // more information, see above comment of
827 // RedirectedKeyDownMessageManager::AutoFlusher class definition in
828 // KeyboardLayout.h.
829 RedirectedKeyDownMessageManager::AutoFlusher
830 redirectedMsgFlusher(this, msg);
832 if (nsTextStore::IsComposingOn(this)) {
833 break;
834 }
836 ModifierKeyState modKeyState;
837 NativeKey nativeKey(this, msg, modKeyState);
838 processDefault = !nativeKey.HandleKeyDownMessage();
839 // HandleKeyDownMessage cleaned up the redirected message information
840 // itself, so, we should do nothing.
841 redirectedMsgFlusher.Cancel();
842 break;
843 }
845 case WM_KEYUP:
846 case WM_SYSKEYUP:
847 {
848 if (nsTextStore::IsComposingOn(this)) {
849 break;
850 }
852 MSG msg = WinUtils::InitMSG(aMsg, aWParam, aLParam, aWnd);
853 ModifierKeyState modKeyState;
854 NativeKey nativeKey(this, msg, modKeyState);
855 processDefault = !nativeKey.HandleKeyUpMessage();
856 break;
857 }
859 case WM_CHAR:
860 case WM_SYSCHAR:
861 {
862 if (nsTextStore::IsComposingOn(this)) {
863 nsTextStore::CommitComposition(false);
864 }
866 MSG msg = WinUtils::InitMSG(aMsg, aWParam, aLParam, aWnd);
867 ModifierKeyState modKeyState;
868 NativeKey nativeKey(this, msg, modKeyState);
869 processDefault = !nativeKey.HandleCharMessage(msg);
870 break;
871 }
873 case WM_INPUTLANGCHANGE:
874 {
875 KeyboardLayout::GetInstance()->
876 OnLayoutChange(reinterpret_cast<HKL>(aLParam));
877 processResult = 1;
878 break;
879 }
881 case WM_APPCOMMAND:
882 processDefault = HandleAppCommandMsg(aWParam, aLParam, &processResult);
883 break;
885 case WM_GETOBJECT:
886 {
887 DWORD dwObjId = (LPARAM)(DWORD) aLParam;
888 // Passing this to CallWindowProc can result in a failure due to a timing issue
889 // in winrt core window server code, so we call it directly here. Also, it's not
890 // clear Windows::UI::Core::WindowServer::OnAutomationProviderRequestedEvent is
891 // compatible with metro enabled desktop browsers, it makes an initial call to
892 // UiaReturnRawElementProvider passing the return result from FrameworkView
893 // OnAutomationProviderRequested as the hwnd (me scratches head) which results in
894 // GetLastError always being set to invalid handle (6) after CallWindowProc returns.
895 if (dwObjId == UiaRootObjectId && gProviderRoot) {
896 ComPtr<IRawElementProviderSimple> simple;
897 gProviderRoot.As(&simple);
898 if (simple) {
899 LRESULT res = UiaReturnRawElementProvider(aWnd, aWParam, aLParam, simple.Get());
900 if (res) {
901 return res;
902 }
903 NS_ASSERTION(res, "UiaReturnRawElementProvider failed!");
904 WinUtils::Log("UiaReturnRawElementProvider failed! GetLastError=%X", GetLastError());
905 }
906 }
907 break;
908 }
910 default:
911 {
912 break;
913 }
914 }
916 if (processDefault) {
917 return CallWindowProc(mMetroWndProc, aWnd, aMsg, aWParam,
918 aLParam);
919 }
920 return processResult;
921 }
923 static BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam)
924 {
925 WCHAR className[56];
926 if (GetClassNameW(hwnd, className, sizeof(className)/sizeof(WCHAR)) &&
927 !wcscmp(L"Windows.UI.Core.CoreWindow", className)) {
928 DWORD processID = 0;
929 GetWindowThreadProcessId(hwnd, &processID);
930 if (processID && processID == GetCurrentProcessId()) {
931 *((HWND*)lParam) = hwnd;
932 return FALSE;
933 }
934 }
935 return TRUE;
936 }
938 void
939 MetroWidget::FindMetroWindow()
940 {
941 LogFunction();
942 if (mWnd)
943 return;
944 EnumWindows(EnumWindowsProc, (LPARAM)&mWnd);
945 NS_ASSERTION(mWnd, "Couldn't find our metro CoreWindow, this is bad.");
947 // subclass it
948 SetSubclass();
949 sICoreHwnd = mWnd;
950 return;
951 }
953 void
954 MetroWidget::SetSubclass()
955 {
956 if (!mWnd) {
957 NS_NOTREACHED("SetSubclass called without a valid hwnd.");
958 return;
959 }
961 WNDPROC wndProc = reinterpret_cast<WNDPROC>(
962 GetWindowLongPtr(mWnd, GWLP_WNDPROC));
963 if (wndProc != StaticWindowProcedure) {
964 if (!SetPropW(mWnd, kMetroSubclassThisProp, this)) {
965 NS_NOTREACHED("SetProp failed, can't continue.");
966 return;
967 }
968 mMetroWndProc =
969 reinterpret_cast<WNDPROC>(
970 SetWindowLongPtr(mWnd, GWLP_WNDPROC,
971 reinterpret_cast<LONG_PTR>(StaticWindowProcedure)));
972 NS_ASSERTION(mMetroWndProc != StaticWindowProcedure, "WTF?");
973 }
974 }
976 void
977 MetroWidget::RemoveSubclass()
978 {
979 if (!mWnd)
980 return;
981 WNDPROC wndProc = reinterpret_cast<WNDPROC>(
982 GetWindowLongPtr(mWnd, GWLP_WNDPROC));
983 if (wndProc == StaticWindowProcedure) {
984 NS_ASSERTION(mMetroWndProc, "Should have old proc here.");
985 SetWindowLongPtr(mWnd, GWLP_WNDPROC,
986 reinterpret_cast<LONG_PTR>(mMetroWndProc));
987 mMetroWndProc = nullptr;
988 }
989 RemovePropW(mWnd, kMetroSubclassThisProp);
990 }
992 bool
993 MetroWidget::ShouldUseOffMainThreadCompositing()
994 {
995 // Either we're not initialized yet, or this is the toolkit widget
996 if (!mView) {
997 return false;
998 }
999 // toolkit or test widgets can't use omtc, they don't have ICoreWindow.
1000 return (CompositorParent::CompositorLoop() && mWindowType == eWindowType_toplevel);
1001 }
1003 bool
1004 MetroWidget::ShouldUseMainThreadD3D10Manager()
1005 {
1006 // Either we're not initialized yet, or this is the toolkit widget
1007 if (!mView) {
1008 return false;
1009 }
1010 return (!CompositorParent::CompositorLoop() && mWindowType == eWindowType_toplevel);
1011 }
1013 bool
1014 MetroWidget::ShouldUseBasicManager()
1015 {
1016 // toolkit or test widgets fall back on empty shadow layers
1017 return (mWindowType != eWindowType_toplevel);
1018 }
1020 bool
1021 MetroWidget::ShouldUseAPZC()
1022 {
1023 const char* kPrefName = "layers.async-pan-zoom.enabled";
1024 return ShouldUseOffMainThreadCompositing() &&
1025 Preferences::GetBool(kPrefName, false);
1026 }
1028 void
1029 MetroWidget::SetWidgetListener(nsIWidgetListener* aWidgetListener)
1030 {
1031 mWidgetListener = aWidgetListener;
1032 if (mController) {
1033 mController->SetWidgetListener(aWidgetListener);
1034 }
1035 }
1037 CompositorParent* MetroWidget::NewCompositorParent(int aSurfaceWidth, int aSurfaceHeight)
1038 {
1039 CompositorParent *compositor = nsBaseWidget::NewCompositorParent(aSurfaceWidth, aSurfaceHeight);
1041 if (ShouldUseAPZC()) {
1042 mRootLayerTreeId = compositor->RootLayerTreeId();
1044 mController = new APZController();
1045 mController->SetWidgetListener(mWidgetListener);
1047 CompositorParent::SetControllerForLayerTree(mRootLayerTreeId, mController);
1049 APZController::sAPZC = CompositorParent::GetAPZCTreeManager(compositor->RootLayerTreeId());
1050 APZController::sAPZC->SetDPI(GetDPI());
1052 nsresult rv;
1053 nsCOMPtr<nsIObserverService> observerService = do_GetService("@mozilla.org/observer-service;1", &rv);
1054 if (NS_SUCCEEDED(rv)) {
1055 observerService->AddObserver(this, "apzc-scroll-offset-changed", false);
1056 observerService->AddObserver(this, "apzc-zoom-to-rect", false);
1057 observerService->AddObserver(this, "apzc-disable-zoom", false);
1058 }
1059 }
1061 return compositor;
1062 }
1064 MetroWidget::TouchBehaviorFlags
1065 MetroWidget::ContentGetAllowedTouchBehavior(const nsIntPoint& aPoint)
1066 {
1067 return ContentHelper::GetAllowedTouchBehavior(this, aPoint);
1068 }
1070 void
1071 MetroWidget::ApzcGetAllowedTouchBehavior(WidgetInputEvent* aTransformedEvent,
1072 nsTArray<TouchBehaviorFlags>& aOutBehaviors)
1073 {
1074 LogFunction();
1075 return APZController::sAPZC->GetAllowedTouchBehavior(aTransformedEvent, aOutBehaviors);
1076 }
1078 void
1079 MetroWidget::ApzcSetAllowedTouchBehavior(const ScrollableLayerGuid& aGuid,
1080 nsTArray<TouchBehaviorFlags>& aBehaviors)
1081 {
1082 LogFunction();
1083 if (!APZController::sAPZC) {
1084 return;
1085 }
1086 APZController::sAPZC->SetAllowedTouchBehavior(aGuid, aBehaviors);
1087 }
1089 void
1090 MetroWidget::ApzContentConsumingTouch(const ScrollableLayerGuid& aGuid)
1091 {
1092 LogFunction();
1093 if (!mController) {
1094 return;
1095 }
1096 mController->ContentReceivedTouch(aGuid, true);
1097 }
1099 void
1100 MetroWidget::ApzContentIgnoringTouch(const ScrollableLayerGuid& aGuid)
1101 {
1102 LogFunction();
1103 if (!mController) {
1104 return;
1105 }
1106 mController->ContentReceivedTouch(aGuid, false);
1107 }
1109 bool
1110 MetroWidget::ApzHitTest(ScreenIntPoint& pt)
1111 {
1112 if (!mController) {
1113 return false;
1114 }
1115 return mController->HitTestAPZC(pt);
1116 }
1118 void
1119 MetroWidget::ApzTransformGeckoCoordinate(const ScreenIntPoint& aPoint,
1120 LayoutDeviceIntPoint* aRefPointOut)
1121 {
1122 if (!mController) {
1123 return;
1124 }
1125 mController->TransformCoordinateToGecko(aPoint, aRefPointOut);
1126 }
1128 nsEventStatus
1129 MetroWidget::ApzReceiveInputEvent(WidgetInputEvent* aEvent,
1130 ScrollableLayerGuid* aOutTargetGuid)
1131 {
1132 MOZ_ASSERT(aEvent);
1134 if (!mController) {
1135 return nsEventStatus_eIgnore;
1136 }
1137 return mController->ReceiveInputEvent(aEvent, aOutTargetGuid);
1138 }
1140 LayerManager*
1141 MetroWidget::GetLayerManager(PLayerTransactionChild* aShadowManager,
1142 LayersBackend aBackendHint,
1143 LayerManagerPersistence aPersistence,
1144 bool* aAllowRetaining)
1145 {
1146 bool retaining = true;
1148 // If we initialized earlier than the view, recreate the layer manager now
1149 if (mLayerManager &&
1150 mTempBasicLayerInUse &&
1151 ShouldUseOffMainThreadCompositing()) {
1152 mLayerManager = nullptr;
1153 mTempBasicLayerInUse = false;
1154 retaining = false;
1155 }
1157 // If the backend device has changed, create a new manager (pulled from nswindow)
1158 if (mLayerManager) {
1159 if (mLayerManager->GetBackendType() == LayersBackend::LAYERS_D3D10) {
1160 LayerManagerD3D10 *layerManagerD3D10 =
1161 static_cast<LayerManagerD3D10*>(mLayerManager.get());
1162 if (layerManagerD3D10->device() !=
1163 gfxWindowsPlatform::GetPlatform()->GetD3D10Device()) {
1164 MOZ_ASSERT(!mLayerManager->IsInTransaction());
1166 mLayerManager->Destroy();
1167 mLayerManager = nullptr;
1168 retaining = false;
1169 }
1170 }
1171 }
1173 HRESULT hr = S_OK;
1175 // Create a layer manager: try to use an async compositor first, if enabled.
1176 // Otherwise fall back on the main thread d3d manager.
1177 if (!mLayerManager) {
1178 if (ShouldUseOffMainThreadCompositing()) {
1179 NS_ASSERTION(aShadowManager == nullptr, "Async Compositor not supported with e10s");
1180 CreateCompositor();
1181 } else if (ShouldUseMainThreadD3D10Manager()) {
1182 nsRefPtr<mozilla::layers::LayerManagerD3D10> layerManager =
1183 new mozilla::layers::LayerManagerD3D10(this);
1184 if (layerManager->Initialize(true, &hr)) {
1185 mLayerManager = layerManager;
1186 }
1187 } else if (ShouldUseBasicManager()) {
1188 mLayerManager = CreateBasicLayerManager();
1189 }
1190 // Either we're not ready to initialize yet due to a missing view pointer,
1191 // or something has gone wrong.
1192 if (!mLayerManager) {
1193 if (!mView) {
1194 NS_WARNING("Using temporary basic layer manager.");
1195 mLayerManager = new BasicLayerManager(this);
1196 mTempBasicLayerInUse = true;
1197 } else {
1198 #ifdef MOZ_CRASHREPORTER
1199 if (FAILED(hr)) {
1200 char errorBuf[10];
1201 errorBuf[0] = '\0';
1202 _snprintf_s(errorBuf, sizeof(errorBuf), _TRUNCATE, "%X", hr);
1203 CrashReporter::
1204 AnnotateCrashReport(NS_LITERAL_CSTRING("HRESULT"),
1205 nsDependentCString(errorBuf));
1206 }
1207 #endif
1208 NS_RUNTIMEABORT("Couldn't create layer manager");
1209 }
1210 }
1211 }
1213 if (aAllowRetaining) {
1214 *aAllowRetaining = retaining;
1215 }
1217 return mLayerManager;
1218 }
1220 NS_IMETHODIMP
1221 MetroWidget::Invalidate(bool aEraseBackground,
1222 bool aUpdateNCArea,
1223 bool aIncludeChildren)
1224 {
1225 nsIntRect rect;
1226 if (mView) {
1227 mView->GetBounds(rect);
1228 }
1229 Invalidate(rect);
1230 return NS_OK;
1231 }
1233 NS_IMETHODIMP
1234 MetroWidget::Invalidate(const nsIntRect & aRect)
1235 {
1236 if (mWnd) {
1237 RECT rect;
1238 rect.left = aRect.x;
1239 rect.top = aRect.y;
1240 rect.right = aRect.x + aRect.width;
1241 rect.bottom = aRect.y + aRect.height;
1242 InvalidateRect(mWnd, &rect, FALSE);
1243 }
1245 return NS_OK;
1246 }
1248 nsTransparencyMode
1249 MetroWidget::GetTransparencyMode()
1250 {
1251 return mTransparencyMode;
1252 }
1254 void
1255 MetroWidget::SetTransparencyMode(nsTransparencyMode aMode)
1256 {
1257 mTransparencyMode = aMode;
1258 }
1260 nsIWidgetListener*
1261 MetroWidget::GetPaintListener()
1262 {
1263 if (mOnDestroyCalled)
1264 return nullptr;
1265 return mAttachedWidgetListener ? mAttachedWidgetListener :
1266 mWidgetListener;
1267 }
1269 void MetroWidget::Paint(const nsIntRegion& aInvalidRegion)
1270 {
1271 gfxWindowsPlatform::GetPlatform()->UpdateRenderMode();
1273 nsIWidgetListener* listener = GetPaintListener();
1274 if (!listener)
1275 return;
1277 listener->WillPaintWindow(this);
1279 // Refresh since calls like WillPaintWindow can destroy the widget
1280 listener = GetPaintListener();
1281 if (!listener)
1282 return;
1284 listener->PaintWindow(this, aInvalidRegion);
1286 listener = GetPaintListener();
1287 if (!listener)
1288 return;
1290 listener->DidPaintWindow();
1291 }
1293 void MetroWidget::UserActivity()
1294 {
1295 // Check if we have the idle service, if not we try to get it.
1296 if (!mIdleService) {
1297 mIdleService = do_GetService("@mozilla.org/widget/idleservice;1");
1298 }
1300 // Check that we now have the idle service.
1301 if (mIdleService) {
1302 mIdleService->ResetIdleTimeOut(0);
1303 }
1304 }
1306 // InitEvent assumes physical coordinates and is used by shared win32 code. Do
1307 // not hand winrt event coordinates to this routine.
1308 void
1309 MetroWidget::InitEvent(WidgetGUIEvent& event, nsIntPoint* aPoint)
1310 {
1311 if (!aPoint) {
1312 event.refPoint.x = event.refPoint.y = 0;
1313 } else {
1314 event.refPoint.x = aPoint->x;
1315 event.refPoint.y = aPoint->y;
1316 }
1317 event.time = ::GetMessageTime();
1318 }
1320 bool
1321 MetroWidget::DispatchWindowEvent(WidgetGUIEvent* aEvent)
1322 {
1323 MOZ_ASSERT(aEvent);
1324 nsEventStatus status = nsEventStatus_eIgnore;
1325 DispatchEvent(aEvent, status);
1326 return (status == nsEventStatus_eConsumeNoDefault);
1327 }
1329 NS_IMETHODIMP
1330 MetroWidget::DispatchEvent(WidgetGUIEvent* event, nsEventStatus & aStatus)
1331 {
1332 if (event->AsInputEvent()) {
1333 UserActivity();
1334 }
1336 aStatus = nsEventStatus_eIgnore;
1338 // Top level windows can have a view attached which requires events be sent
1339 // to the underlying base window and the view. Added when we combined the
1340 // base chrome window with the main content child for nc client area (title
1341 // bar) rendering.
1342 if (mAttachedWidgetListener) {
1343 aStatus = mAttachedWidgetListener->HandleEvent(event, mUseAttachedEvents);
1344 }
1345 else if (mWidgetListener) {
1346 aStatus = mWidgetListener->HandleEvent(event, mUseAttachedEvents);
1347 }
1349 // the window can be destroyed during processing of seemingly innocuous events like, say,
1350 // mousedowns due to the magic of scripting. mousedowns will return nsEventStatus_eIgnore,
1351 // which causes problems with the deleted window. therefore:
1352 if (mOnDestroyCalled)
1353 aStatus = nsEventStatus_eConsumeNoDefault;
1354 return NS_OK;
1355 }
1357 #ifdef ACCESSIBILITY
1358 mozilla::a11y::Accessible*
1359 MetroWidget::GetAccessible()
1360 {
1361 // We want the ability to forcibly disable a11y on windows, because
1362 // some non-a11y-related components attempt to bring it up. See bug
1363 // 538530 for details; we have a pref here that allows it to be disabled
1364 // for performance and testing resons.
1365 //
1366 // This pref is checked only once, and the browser needs a restart to
1367 // pick up any changes.
1368 static int accForceDisable = -1;
1370 if (accForceDisable == -1) {
1371 const char* kPrefName = "accessibility.win32.force_disabled";
1372 if (Preferences::GetBool(kPrefName, false)) {
1373 accForceDisable = 1;
1374 } else {
1375 accForceDisable = 0;
1376 }
1377 }
1379 // If the pref was true, return null here, disabling a11y.
1380 if (accForceDisable)
1381 return nullptr;
1383 return GetRootAccessible();
1384 }
1385 #endif
1387 double
1388 MetroWidget::GetDefaultScaleInternal()
1389 {
1390 return MetroUtils::ScaleFactor();
1391 }
1393 LayoutDeviceIntPoint
1394 MetroWidget::CSSIntPointToLayoutDeviceIntPoint(const CSSIntPoint &aCSSPoint)
1395 {
1396 CSSToLayoutDeviceScale scale = GetDefaultScale();
1397 LayoutDeviceIntPoint devPx(int32_t(NS_round(scale.scale * aCSSPoint.x)),
1398 int32_t(NS_round(scale.scale * aCSSPoint.y)));
1399 return devPx;
1400 }
1402 float
1403 MetroWidget::GetDPI()
1404 {
1405 if (!mView) {
1406 return 96.0;
1407 }
1408 return mView->GetDPI();
1409 }
1411 void
1412 MetroWidget::ChangedDPI()
1413 {
1414 if (mWidgetListener) {
1415 nsIPresShell* presShell = mWidgetListener->GetPresShell();
1416 if (presShell) {
1417 presShell->BackingScaleFactorChanged();
1418 }
1419 }
1420 }
1422 already_AddRefed<nsIPresShell>
1423 MetroWidget::GetPresShell()
1424 {
1425 if (mWidgetListener) {
1426 nsCOMPtr<nsIPresShell> ps = mWidgetListener->GetPresShell();
1427 return ps.forget();
1428 }
1429 return nullptr;
1430 }
1432 NS_IMETHODIMP
1433 MetroWidget::ConstrainPosition(bool aAllowSlop, int32_t *aX, int32_t *aY)
1434 {
1435 return NS_OK;
1436 }
1438 void
1439 MetroWidget::SizeModeChanged()
1440 {
1441 if (mWidgetListener) {
1442 mWidgetListener->SizeModeChanged(nsSizeMode_Normal);
1443 }
1444 }
1446 void
1447 MetroWidget::Activated(bool aActiveated)
1448 {
1449 if (mWidgetListener) {
1450 aActiveated ?
1451 mWidgetListener->WindowActivated() :
1452 mWidgetListener->WindowDeactivated();
1453 }
1454 }
1456 NS_IMETHODIMP
1457 MetroWidget::Move(double aX, double aY)
1458 {
1459 NotifyWindowMoved(aX, aY);
1460 return NS_OK;
1461 }
1463 NS_IMETHODIMP
1464 MetroWidget::Resize(double aWidth, double aHeight, bool aRepaint)
1465 {
1466 return Resize(0, 0, aWidth, aHeight, aRepaint);
1467 }
1469 NS_IMETHODIMP
1470 MetroWidget::Resize(double aX, double aY, double aWidth, double aHeight, bool aRepaint)
1471 {
1472 WinUtils::Log("Resize: %f %f %f %f", aX, aY, aWidth, aHeight);
1473 if (mAttachedWidgetListener) {
1474 mAttachedWidgetListener->WindowResized(this, aWidth, aHeight);
1475 }
1476 if (mWidgetListener) {
1477 mWidgetListener->WindowResized(this, aWidth, aHeight);
1478 }
1479 Invalidate();
1480 return NS_OK;
1481 }
1483 NS_IMETHODIMP
1484 MetroWidget::SetFocus(bool aRaise)
1485 {
1486 return NS_OK;
1487 }
1489 nsresult
1490 MetroWidget::ConfigureChildren(const nsTArray<Configuration>& aConfigurations)
1491 {
1492 return NS_OK;
1493 }
1495 void*
1496 MetroWidget::GetNativeData(uint32_t aDataType)
1497 {
1498 switch(aDataType) {
1499 case NS_NATIVE_WINDOW:
1500 return mWnd;
1501 case NS_NATIVE_ICOREWINDOW:
1502 if (mView) {
1503 return reinterpret_cast<IUnknown*>(mView->GetCoreWindow());
1504 }
1505 break;
1506 case NS_NATIVE_TSF_THREAD_MGR:
1507 case NS_NATIVE_TSF_CATEGORY_MGR:
1508 case NS_NATIVE_TSF_DISPLAY_ATTR_MGR:
1509 return nsTextStore::GetNativeData(aDataType);
1510 }
1511 return nullptr;
1512 }
1514 void
1515 MetroWidget::FreeNativeData(void * data, uint32_t aDataType)
1516 {
1517 }
1519 NS_IMETHODIMP
1520 MetroWidget::SetTitle(const nsAString& aTitle)
1521 {
1522 return NS_OK;
1523 }
1525 nsIntPoint
1526 MetroWidget::WidgetToScreenOffset()
1527 {
1528 return nsIntPoint(0,0);
1529 }
1531 NS_IMETHODIMP
1532 MetroWidget::CaptureRollupEvents(nsIRollupListener * aListener,
1533 bool aDoCapture)
1534 {
1535 return NS_OK;
1536 }
1538 NS_IMETHODIMP_(void)
1539 MetroWidget::SetInputContext(const InputContext& aContext,
1540 const InputContextAction& aAction)
1541 {
1542 mInputContext = aContext;
1543 nsTextStore::SetInputContext(this, mInputContext, aAction);
1544 bool enable = (mInputContext.mIMEState.mEnabled == IMEState::ENABLED ||
1545 mInputContext.mIMEState.mEnabled == IMEState::PLUGIN);
1546 if (enable &&
1547 mInputContext.mIMEState.mOpen != IMEState::DONT_CHANGE_OPEN_STATE) {
1548 bool open = (mInputContext.mIMEState.mOpen == IMEState::OPEN);
1549 nsTextStore::SetIMEOpenState(open);
1550 }
1551 }
1553 NS_IMETHODIMP_(nsIWidget::InputContext)
1554 MetroWidget::GetInputContext()
1555 {
1556 return mInputContext;
1557 }
1559 NS_IMETHODIMP
1560 MetroWidget::NotifyIME(const IMENotification& aIMENotification)
1561 {
1562 switch (aIMENotification.mMessage) {
1563 case REQUEST_TO_COMMIT_COMPOSITION:
1564 nsTextStore::CommitComposition(false);
1565 return NS_OK;
1566 case REQUEST_TO_CANCEL_COMPOSITION:
1567 nsTextStore::CommitComposition(true);
1568 return NS_OK;
1569 case NOTIFY_IME_OF_FOCUS:
1570 return nsTextStore::OnFocusChange(true, this,
1571 mInputContext.mIMEState.mEnabled);
1572 case NOTIFY_IME_OF_BLUR:
1573 return nsTextStore::OnFocusChange(false, this,
1574 mInputContext.mIMEState.mEnabled);
1575 case NOTIFY_IME_OF_SELECTION_CHANGE:
1576 return nsTextStore::OnSelectionChange();
1577 case NOTIFY_IME_OF_TEXT_CHANGE:
1578 return nsTextStore::OnTextChange(aIMENotification);
1579 case NOTIFY_IME_OF_POSITION_CHANGE:
1580 return nsTextStore::OnLayoutChange();
1581 default:
1582 return NS_ERROR_NOT_IMPLEMENTED;
1583 }
1584 }
1586 NS_IMETHODIMP
1587 MetroWidget::GetToggledKeyState(uint32_t aKeyCode, bool* aLEDState)
1588 {
1589 NS_ENSURE_ARG_POINTER(aLEDState);
1590 *aLEDState = (::GetKeyState(aKeyCode) & 1) != 0;
1591 return NS_OK;
1592 }
1594 nsIMEUpdatePreference
1595 MetroWidget::GetIMEUpdatePreference()
1596 {
1597 return nsTextStore::GetIMEUpdatePreference();
1598 }
1600 NS_IMETHODIMP
1601 MetroWidget::ReparentNativeWidget(nsIWidget* aNewParent)
1602 {
1603 return NS_OK;
1604 }
1606 void
1607 MetroWidget::SuppressBlurEvents(bool aSuppress)
1608 {
1609 }
1611 bool
1612 MetroWidget::BlurEventsSuppressed()
1613 {
1614 return false;
1615 }
1617 void
1618 MetroWidget::PickerOpen()
1619 {
1620 }
1622 void
1623 MetroWidget::PickerClosed()
1624 {
1625 }
1627 bool
1628 MetroWidget::HasPendingInputEvent()
1629 {
1630 if (HIWORD(GetQueueStatus(QS_INPUT)))
1631 return true;
1632 return false;
1633 }
1635 NS_IMETHODIMP
1636 MetroWidget::Observe(nsISupports *subject, const char *topic, const char16_t *data)
1637 {
1638 NS_ENSURE_ARG_POINTER(topic);
1639 if (!strcmp(topic, "apzc-zoom-to-rect")) {
1640 CSSRect rect = CSSRect();
1641 uint64_t viewId = 0;
1642 int32_t presShellId = 0;
1644 int reScan = swscanf(data, L"%f,%f,%f,%f,%d,%llu",
1645 &rect.x, &rect.y, &rect.width, &rect.height,
1646 &presShellId, &viewId);
1647 if(reScan != 6) {
1648 NS_WARNING("Malformed apzc-zoom-to-rect message");
1649 }
1651 ScrollableLayerGuid guid = ScrollableLayerGuid(mRootLayerTreeId, presShellId, viewId);
1652 APZController::sAPZC->ZoomToRect(guid, rect);
1653 }
1654 else if (!strcmp(topic, "apzc-disable-zoom")) {
1655 uint64_t viewId = 0;
1656 int32_t presShellId = 0;
1658 int reScan = swscanf(data, L"%d,%llu",
1659 &presShellId, &viewId);
1660 if (reScan != 2) {
1661 NS_WARNING("Malformed apzc-disable-zoom message");
1662 }
1664 ScrollableLayerGuid guid = ScrollableLayerGuid(mRootLayerTreeId, presShellId, viewId);
1665 APZController::sAPZC->UpdateZoomConstraints(guid,
1666 ZoomConstraints(false, false, CSSToScreenScale(1.0f), CSSToScreenScale(1.0f)));
1667 }
1668 return NS_OK;
1669 }