Merge mozilla-central and fx-team

This commit is contained in:
Ed Morley 2013-09-06 16:25:48 +01:00
commit 95ac4ccc34
27 changed files with 779 additions and 551 deletions

View File

@ -4,6 +4,7 @@
"use strict"; "use strict";
function test() { function test() {
requestLongerTimeout(2);
waitForExplicitFinish(); waitForExplicitFinish();
try { try {

View File

@ -60,7 +60,7 @@ AppValidator.prototype._fetchManifest = function (manifestURL) {
try { try {
manifest = JSON.parse(req.responseText); manifest = JSON.parse(req.responseText);
} catch(e) { } catch(e) {
this.error(strings.formatStringFromName("validator.invalidManifestJSON", [manifestURL, e], 2)); this.error(strings.formatStringFromName("validator.invalidManifestJSON", [e, manifestURL], 2));
} }
deferred.resolve(manifest); deferred.resolve(manifest);
}).bind(this); }).bind(this);
@ -109,7 +109,7 @@ AppValidator.prototype.validateManifest = function (manifest) {
if (!manifest.icons || Object.keys(manifest.icons).length == 0) { if (!manifest.icons || Object.keys(manifest.icons).length == 0) {
this.warning(strings.GetStringFromName("validator.missIconsManifestProperty")); this.warning(strings.GetStringFromName("validator.missIconsManifestProperty"));
} else if (!manifest.icons["128"]) { } else if (!manifest.icons["128"]) {
this.warning(strings.GetStringFromName("validator.missIconForMarketplace")); this.warning(strings.GetStringFromName("validator.missIconMarketplace"));
} }
} }

View File

@ -2,22 +2,32 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this # License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/. # file, You can obtain one at http://mozilla.org/MPL/2.0/.
# LOCALIZATION NOTE (device.deviceSize): %1$S is the device's width, %2$S is
# the device's height, %3$S is the device's pixel density.
# Example: 800x480 (86 DPI).
device.deviceSize=Device size: %1$Sx%2$S (%3$S DPI) device.deviceSize=Device size: %1$Sx%2$S (%3$S DPI)
# LOCALIZATION NOTE (connection.connectedToDevice, connection.connectTo):
# %1$S is the host name, %2$S is the port number.
connection.connectedToDevice=Connected to %1$S connection.connectedToDevice=Connected to %1$S
connection.connectTo=Connect to %1$S:%2$S connection.connectTo=Connect to %1$S:%2$S
project.filePickerTitle=Select a webapp folder project.filePickerTitle=Select a webapp folder
validator.nonExistingFolder=The project folder doesn't exists validator.nonExistingFolder=The project folder doesn't exists
validator.expectProjectFolder=The project folder ends up being a file validator.expectProjectFolder=The project folder ends up being a file
validator.wrongManifestFileName=Packaged apps require a manifest file that can only be named 'manifest.webapp' at project root folder validator.wrongManifestFileName=Packaged apps require a manifest file that can only be named 'manifest.webapp' at project root folder
validator.invalidManifestURL=Invalid manifest URL '%S' validator.invalidManifestURL=Invalid manifest URL '%S'
# LOCALIZATION NOTE (validator.invalidManifestJSON, validator.noAccessManifestURL):
# %1$S is the error message, %2$S is the URI of the manifest.
validator.invalidManifestJSON=The webapp manifest isn't a valid JSON file: %1$S at: %2$S validator.invalidManifestJSON=The webapp manifest isn't a valid JSON file: %1$S at: %2$S
validator.noAccessManifestURL=Unable to read manifest file: %1$S at: %2$S validator.noAccessManifestURL=Unable to read manifest file: %1$S at: %2$S
# LOCALIZATION NOTE (validator.invalidHostedManifestURL): %1$S is the URI of
# the manifest, %2$S is the error message.
validator.invalidHostedManifestURL=Invalid hosted manifest URL '%1$S': %2$S validator.invalidHostedManifestURL=Invalid hosted manifest URL '%1$S': %2$S
validator.invalidProjectType=Unknown project type '%S' validator.invalidProjectType=Unknown project type '%S'
# LOCALIZATION NOTE (validator.missNameManifestProperty, validator.missIconsManifestProperty):
# don't translate 'icons' and 'name'.
validator.missNameManifestProperty=Missing mandatory 'name' in Manifest. validator.missNameManifestProperty=Missing mandatory 'name' in Manifest.
validator.missIconsManifestProperty=Missing 'icons' in Manifest. validator.missIconsManifestProperty=Missing 'icons' in Manifest.
validator.missIconForMarketplace=app submission to the Marketplace needs at least an 128 icon validator.missIconMarketplace=app submission to the Marketplace needs at least a 128px icon
validator.invalidAppType=Unknown app type: '%S'. validator.invalidAppType=Unknown app type: '%S'.
validator.invalidHostedPriviledges=Hosted App can't be type '%S'. validator.invalidHostedPriviledges=Hosted App can't be type '%S'.
validator.noCertifiedSupport='certified' apps are not fully supported on the App manager. validator.noCertifiedSupport='certified' apps are not fully supported on the App manager.

View File

@ -649,37 +649,41 @@ function test_info() {
let stop = new Date(); let stop = new Date();
// We round down/up by 1s as file system precision is lower than Date precision // We round down/up by 1s as file system precision is lower than
// (no clear specifications about that, but it seems that this can be a little // Date precision (no clear specifications about that, but it seems
// over 1 second under ext3 and 2 seconds under FAT) // that this can be a little over 1 second under ext3 and 2 seconds
let startMs = start.getTime() - 2500; // under FAT).
let stopMs = stop.getTime() + 2500; let SLOPPY_FILE_SYSTEM_ADJUSTMENT = 3000;
let startMs = start.getTime() - SLOPPY_FILE_SYSTEM_ADJUSTMENT;
let stopMs = stop.getTime() + SLOPPY_FILE_SYSTEM_ADJUSTMENT;
info("Testing stat with bounds [ " + startMs + ", " + stopMs +" ]");
(function() { (function() {
let birth; let birth;
if ("winBirthDate" in info) { if ("winBirthDate" in stat) {
birth = info.winBirthDate; birth = stat.winBirthDate;
} else if ("macBirthDate" in info) { } else if ("macBirthDate" in stat) {
birth = info.macBirthDate; birth = stat.macBirthDate;
} else { } else {
ok(true, "Skipping birthdate test"); ok(true, "Skipping birthdate test");
return; return;
} }
ok(birth.getTime() <= stopMs, ok(birth.getTime() <= stopMs,
"test_info: file was created before now - " + stop + ", " + birth); "test_info: platformBirthDate is consistent");
// Note: Previous versions of this test checked whether the file has // Note: Previous versions of this test checked whether the file
// been created after the start of the test. Unfortunately, this sometimes // has been created after the start of the test. Unfortunately,
// failed under Windows, in specific circumstances: if the file has been // this sometimes failed under Windows, in specific circumstances:
// removed at the start of the test and recreated immediately, the Windows // if the file has been removed at the start of the test and
// file system detects this and decides that the file was actually truncated // recreated immediately, the Windows file system detects this and
// rather than recreated, hence that it should keep its previous creation date. // decides that the file was actually truncated rather than
// Debugging hilarity ensues. // recreated, hence that it should keep its previous creation
// date. Debugging hilarity ensues.
}); });
let change = stat.lastModificationDate; let change = stat.lastModificationDate;
ok(change.getTime() >= startMs info("Testing lastModificationDate: " + change);
&& change.getTime() <= stopMs, ok(change.getTime() >= startMs && change.getTime() <= stopMs,
"test_info: file has changed between the start of the test and now - " + start + ", " + stop + ", " + change); "test_info: lastModificationDate is consistent");
// Test OS.File.prototype.stat on new file // Test OS.File.prototype.stat on new file
file = OS.File.open(filename); file = OS.File.open(filename);
@ -696,23 +700,20 @@ function test_info() {
stop = new Date(); stop = new Date();
// We round down/up by 1s as file system precision is lower than Date precision // Round up/down as above
startMs = start.getTime() - 1000; startMs = start.getTime() - SLOPPY_FILE_SYSTEM_ADJUSTMENT;
stopMs = stop.getTime() + 1000; stopMs = stop.getTime() + SLOPPY_FILE_SYSTEM_ADJUSTMENT;
info("Testing stat 2 with bounds [ " + startMs + ", " + stopMs +" ]");
let birth = stat.creationDate;
ok(birth.getTime() <= stopMs,
"test_info: file 2 was created between the start of the test and now - " + start + ", " + stop + ", " + birth);
let access = stat.lastAccessDate; let access = stat.lastAccessDate;
ok(access.getTime() >= startMs info("Testing lastAccessDate: " + access);
&& access.getTime() <= stopMs, ok(access.getTime() >= startMs && access.getTime() <= stopMs,
"test_info: file 2 was accessed between the start of the test and now - " + start + ", " + stop + ", " + access); "test_info: lastAccessDate is consistent");
change = stat.lastModificationDate; change = stat.lastModificationDate;
ok(change.getTime() >= startMs info("Testing lastModificationDate 2: " + change);
&& change.getTime() <= stopMs, ok(change.getTime() >= startMs && change.getTime() <= stopMs,
"test_info: file 2 has changed between the start of the test and now - " + start + ", " + stop + ", " + change); "test_info: lastModificationDate 2 is consistent");
// Test OS.File.stat on directory // Test OS.File.stat on directory
stat = OS.File.stat(OS.File.getCurrentDirectory()); stat = OS.File.stat(OS.File.getCurrentDirectory());

View File

@ -114,6 +114,10 @@ const N_STATUS = Name("status");
const N_VALUE = Name("value"); const N_VALUE = Name("value");
const N_HANDLERS = Name("handlers"); const N_HANDLERS = Name("handlers");
// The following error types are considered programmer errors, which should be
// reported (possibly redundantly) so as to let programmers fix their code.
const ERRORS_TO_REPORT = ["EvalError", "RangeError", "ReferenceError", "TypeError"];
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
//// Promise //// Promise
@ -572,7 +576,27 @@ Handler.prototype = {
nextStatus = STATUS_RESOLVED; nextStatus = STATUS_RESOLVED;
} }
} catch (ex) { } catch (ex) {
// If an exception occurred in the handler, reject the next promise.
// An exception has occurred in the handler.
if (ex && typeof ex == "object" && "name" in ex &&
ERRORS_TO_REPORT.indexOf(ex.name) != -1) {
// We suspect that the exception is a programmer error, so we now
// display it using dump(). Note that we do not use Cu.reportError as
// we assume that this is a programming error, so we do not want end
// users to see it. Also, if the programmer handles errors correctly,
// they will either treat the error or log them somewhere.
dump("A coding exception was thrown in a Promise " +
((nextStatus == STATUS_RESOLVED) ? "resolution":"rejection") +
" callback.\n");
dump("Full message: " + ex + "\n");
dump("See https://developer.mozilla.org/Mozilla/JavaScript_code_modules/Promise.jsm/Promise\n");
dump("Full stack: " + (("stack" in ex)?ex.stack:"not available") + "\n");
}
// Additionally, reject the next promise.
nextStatus = STATUS_REJECTED; nextStatus = STATUS_REJECTED;
nextValue = ex; nextValue = ex;
} }

View File

@ -97,6 +97,10 @@ const Cr = Components.results;
Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js"); Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js");
// The following error types are considered programmer errors, which should be
// reported (possibly redundantly) so as to let programmers fix their code.
const ERRORS_TO_REPORT = ["EvalError", "RangeError", "ReferenceError", "TypeError"];
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
//// Task //// Task
@ -226,6 +230,21 @@ TaskImpl.prototype = {
this.deferred.resolve(); this.deferred.resolve();
} catch (ex) { } catch (ex) {
// The generator function failed with an uncaught exception. // The generator function failed with an uncaught exception.
if (ex && typeof ex == "object" && "name" in ex &&
ERRORS_TO_REPORT.indexOf(ex.name) != -1) {
// We suspect that the exception is a programmer error, so we now
// display it using dump(). Note that we do not use Cu.reportError as
// we assume that this is a programming error, so we do not want end
// users to see it. Also, if the programmer handles errors correctly,
// they will either treat the error or log them somewhere.
dump("A coding exception was thrown and uncaught in a Task.\n");
dump("Full message: " + ex + "\n");
dump("Full stack: " + (("stack" in ex)?ex.stack:"not available") + "\n");
}
this.deferred.reject(ex); this.deferred.reject(ex);
} }
} }

View File

@ -1152,7 +1152,8 @@ public:
keyCode(0), charCode(0), keyCode(0), charCode(0),
location(nsIDOMKeyEvent::DOM_KEY_LOCATION_STANDARD), isChar(0), location(nsIDOMKeyEvent::DOM_KEY_LOCATION_STANDARD), isChar(0),
mKeyNameIndex(mozilla::widget::KEY_NAME_INDEX_Unidentified), mKeyNameIndex(mozilla::widget::KEY_NAME_INDEX_Unidentified),
mNativeKeyEvent(nullptr) mNativeKeyEvent(nullptr),
mUniqueId(0)
{ {
} }
@ -1171,6 +1172,11 @@ public:
mozilla::widget::KeyNameIndex mKeyNameIndex; mozilla::widget::KeyNameIndex mKeyNameIndex;
// OS-specific native event can optionally be preserved // OS-specific native event can optionally be preserved
void* mNativeKeyEvent; void* mNativeKeyEvent;
// Unique id associated with a keydown / keypress event. Used in identifing
// keypress events for removal from async event dispatch queue in metrofx
// after preventDefault is called on keydown events. It's ok if this wraps
// over long periods.
uint32_t mUniqueId;
void GetDOMKeyName(nsAString& aKeyName) void GetDOMKeyName(nsAString& aKeyName)
{ {
@ -1205,6 +1211,7 @@ public:
// Don't copy mNativeKeyEvent because it may be referred after its instance // Don't copy mNativeKeyEvent because it may be referred after its instance
// is destroyed. // is destroyed.
mNativeKeyEvent = nullptr; mNativeKeyEvent = nullptr;
mUniqueId = aEvent.mUniqueId;
} }
}; };

View File

@ -261,6 +261,7 @@ struct ParamTraits<nsKeyEvent>
WriteParam(aMsg, aParam.charCode); WriteParam(aMsg, aParam.charCode);
WriteParam(aMsg, aParam.isChar); WriteParam(aMsg, aParam.isChar);
WriteParam(aMsg, aParam.location); WriteParam(aMsg, aParam.location);
WriteParam(aMsg, aParam.mUniqueId);
// An OS-specific native event might be attached in |mNativeKeyEvent|, but // An OS-specific native event might be attached in |mNativeKeyEvent|, but
// that cannot be copied across process boundaries. // that cannot be copied across process boundaries.
} }
@ -273,7 +274,8 @@ struct ParamTraits<nsKeyEvent>
ReadParam(aMsg, aIter, &aResult->keyCode) && ReadParam(aMsg, aIter, &aResult->keyCode) &&
ReadParam(aMsg, aIter, &aResult->charCode) && ReadParam(aMsg, aIter, &aResult->charCode) &&
ReadParam(aMsg, aIter, &aResult->isChar) && ReadParam(aMsg, aIter, &aResult->isChar) &&
ReadParam(aMsg, aIter, &aResult->location)) ReadParam(aMsg, aIter, &aResult->location) &&
ReadParam(aMsg, aIter, &aResult->mUniqueId))
{ {
aResult->mKeyNameIndex = static_cast<mozilla::widget::KeyNameIndex>(keyNameIndex); aResult->mKeyNameIndex = static_cast<mozilla::widget::KeyNameIndex>(keyNameIndex);
aResult->mNativeKeyEvent = NULL; aResult->mNativeKeyEvent = NULL;

View File

@ -41,6 +41,11 @@
namespace mozilla { namespace mozilla {
namespace widget { namespace widget {
// Unique id counter associated with a keydown / keypress events. Used in
// identifing keypress events for removal from async event dispatch queue
// in metrofx after preventDefault is called on keydown events.
static uint32_t sUniqueKeyEventId = 0;
struct DeadKeyEntry struct DeadKeyEntry
{ {
PRUnichar BaseChar; PRUnichar BaseChar;
@ -756,6 +761,9 @@ NativeKey::InitKeyEvent(nsKeyEvent& aKeyEvent,
switch (aKeyEvent.message) { switch (aKeyEvent.message) {
case NS_KEY_DOWN: case NS_KEY_DOWN:
aKeyEvent.keyCode = mDOMKeyCode; aKeyEvent.keyCode = mDOMKeyCode;
// Unique id for this keydown event and its associated keypress.
sUniqueKeyEventId++;
aKeyEvent.mUniqueId = sUniqueKeyEventId;
break; break;
case NS_KEY_UP: case NS_KEY_UP:
aKeyEvent.keyCode = mDOMKeyCode; aKeyEvent.keyCode = mDOMKeyCode;
@ -768,6 +776,7 @@ NativeKey::InitKeyEvent(nsKeyEvent& aKeyEvent,
(mOriginalVirtualKeyCode == VK_MENU && mMsg.message != WM_SYSKEYUP); (mOriginalVirtualKeyCode == VK_MENU && mMsg.message != WM_SYSKEYUP);
break; break;
case NS_KEY_PRESS: case NS_KEY_PRESS:
aKeyEvent.mUniqueId = sUniqueKeyEventId;
break; break;
default: default:
MOZ_CRASH("Invalid event message"); MOZ_CRASH("Invalid event message");
@ -797,7 +806,7 @@ NativeKey::DispatchKeyEvent(nsKeyEvent& aKeyEvent,
aKeyEvent.pluginEvent = static_cast<void*>(&pluginEvent); aKeyEvent.pluginEvent = static_cast<void*>(&pluginEvent);
} }
return (mWidget->DispatchWindowEvent(&aKeyEvent) || mWidget->Destroyed()); return (mWidget->DispatchKeyboardEvent(&aKeyEvent) || mWidget->Destroyed());
} }
bool bool

View File

@ -147,6 +147,27 @@ MouseScrollHandler::~MouseScrollHandler()
delete mSynthesizingEvent; delete mSynthesizingEvent;
} }
/* static */
bool
MouseScrollHandler::NeedsMessage(UINT aMsg)
{
switch (aMsg) {
case WM_SETTINGCHANGE:
case WM_MOUSEWHEEL:
case WM_MOUSEHWHEEL:
case WM_HSCROLL:
case WM_VSCROLL:
case MOZ_WM_MOUSEVWHEEL:
case MOZ_WM_MOUSEHWHEEL:
case MOZ_WM_HSCROLL:
case MOZ_WM_VSCROLL:
case WM_KEYDOWN:
case WM_KEYUP:
return true;
}
return false;
}
/* static */ /* static */
bool bool
MouseScrollHandler::ProcessMessage(nsWindowBase* aWidget, UINT msg, MouseScrollHandler::ProcessMessage(nsWindowBase* aWidget, UINT msg,

View File

@ -32,6 +32,7 @@ public:
static void Initialize(); static void Initialize();
static void Shutdown(); static void Shutdown();
static bool NeedsMessage(UINT aMsg);
static bool ProcessMessage(nsWindowBase* aWidget, static bool ProcessMessage(nsWindowBase* aWidget,
UINT msg, UINT msg,
WPARAM wParam, WPARAM wParam,

View File

@ -34,6 +34,24 @@ struct KeyPair;
namespace mozilla { namespace mozilla {
namespace widget { namespace widget {
// More complete QS definitions for MsgWaitForMultipleObjects() and
// GetQueueStatus() that include newer win8 specific defines.
#ifndef QS_RAWINPUT
#define QS_RAWINPUT 0x0400
#endif
#ifndef QS_TOUCH
#define QS_TOUCH 0x0800
#define QS_POINTER 0x1000
#endif
#define MOZ_QS_ALLEVENT (QS_KEY | QS_MOUSEMOVE | QS_MOUSEBUTTON | \
QS_POSTMESSAGE | QS_TIMER | QS_PAINT | \
QS_SENDMESSAGE | QS_HOTKEY | \
QS_ALLPOSTMESSAGE | QS_RAWINPUT | \
QS_TOUCH | QS_POINTER)
class myDownloadObserver MOZ_FINAL : public nsIDownloadObserver class myDownloadObserver MOZ_FINAL : public nsIDownloadObserver
{ {
public: public:

View File

@ -3662,6 +3662,13 @@ bool nsWindow::DispatchStandardEvent(uint32_t aMsg)
return result; return result;
} }
bool nsWindow::DispatchKeyboardEvent(nsGUIEvent* event)
{
nsEventStatus status;
DispatchEvent(event, status);
return ConvertStatus(status);
}
bool nsWindow::DispatchWindowEvent(nsGUIEvent* event) bool nsWindow::DispatchWindowEvent(nsGUIEvent* event)
{ {
nsEventStatus status; nsEventStatus status;

View File

@ -87,6 +87,7 @@ public:
// nsWindowBase // nsWindowBase
virtual void InitEvent(nsGUIEvent& aEvent, nsIntPoint* aPoint = nullptr) MOZ_OVERRIDE; virtual void InitEvent(nsGUIEvent& aEvent, nsIntPoint* aPoint = nullptr) MOZ_OVERRIDE;
virtual bool DispatchWindowEvent(nsGUIEvent* aEvent) MOZ_OVERRIDE; virtual bool DispatchWindowEvent(nsGUIEvent* aEvent) MOZ_OVERRIDE;
virtual bool DispatchKeyboardEvent(nsGUIEvent* aEvent) MOZ_OVERRIDE;
virtual nsWindowBase* GetParentWindowBase(bool aIncludeOwner) MOZ_OVERRIDE; virtual nsWindowBase* GetParentWindowBase(bool aIncludeOwner) MOZ_OVERRIDE;
virtual bool IsTopLevelWidget() MOZ_OVERRIDE { return mIsTopWidgetWindow; } virtual bool IsTopLevelWidget() MOZ_OVERRIDE { return mIsTopWidgetWindow; }

View File

@ -49,9 +49,16 @@ public:
virtual bool DispatchWindowEvent(nsGUIEvent* aEvent) = 0; virtual bool DispatchWindowEvent(nsGUIEvent* aEvent) = 0;
/* /*
* Dispatch a plugin event with the message. * Dispatch a gecko keyboard event for this widget. This
* is called by KeyboardLayout to dispatch gecko events.
* Returns true if it's consumed. Otherwise, false.
*/ */
virtual bool DispatchPluginEvent(const MSG &aMsg) MOZ_FINAL virtual bool DispatchKeyboardEvent(nsGUIEvent* aEvent) = 0;
/*
* Default dispatch of a plugin event.
*/
virtual bool DispatchPluginEvent(const MSG &aMsg)
{ {
if (!PluginHasFocus()) { if (!PluginHasFocus()) {
return false; return false;

View File

@ -32,12 +32,6 @@ using namespace ABI::Windows::Foundation;
using namespace Microsoft::WRL; using namespace Microsoft::WRL;
using namespace Microsoft::WRL::Wrappers; using namespace Microsoft::WRL::Wrappers;
/*
* Due to issues on older platforms with linking the winrt runtime lib we
* can't have ref new winrt variables in the global scope. Everything should
* be encapsulated in a class. See toolkit/library/nsDllMain for the details.
*/
namespace mozilla { namespace mozilla {
namespace widget { namespace widget {
namespace winrt { namespace winrt {
@ -57,7 +51,6 @@ FrameworkView::FrameworkView(MetroApp* aMetroApp) :
mWinVisible(false), mWinVisible(false),
mWinActiveState(false) mWinActiveState(false)
{ {
mPainting = false;
memset(&sKeyboardRect, 0, sizeof(Rect)); memset(&sKeyboardRect, 0, sizeof(Rect));
sSettingsArray = new nsTArray<nsString>(); sSettingsArray = new nsTArray<nsString>();
LogFunction(); LogFunction();
@ -84,27 +77,6 @@ FrameworkView::Initialize(ICoreApplicationView* aAppView)
HRESULT HRESULT
FrameworkView::Uninitialize() FrameworkView::Uninitialize()
{ {
LogFunction();
mShuttingDown = true;
if (mAutomationProvider) {
ComPtr<IUIABridge> provider;
mAutomationProvider.As(&provider);
if (provider) {
provider->Disconnect();
}
}
mAutomationProvider = nullptr;
mMetroInput = nullptr;
mD2DWindowSurface = nullptr;
delete sSettingsArray;
sSettingsArray = nullptr;
mWidget = nullptr;
mMetroApp = nullptr;
mDispatcher = nullptr;
mWindow = nullptr;
return S_OK; return S_OK;
} }
@ -114,34 +86,41 @@ FrameworkView::Load(HSTRING aEntryPoint)
return S_OK; return S_OK;
} }
// called by winrt on startup
HRESULT HRESULT
FrameworkView::Run() FrameworkView::Run()
{ {
LogFunction(); LogFunction();
// XPCOM is initialized here. mWidget is also created. // Initialize XPCOM, create mWidget and go! We get a
mMetroApp->Initialize(); // callback in MetroAppShell::Run, in which we kick
// off normal browser execution / event dispatching.
mMetroApp->Run();
ProcessLaunchArguments(); // Gecko is completely shut down at this point.
Log("Exiting FrameworkView::Run()");
// Activate the window return S_OK;
mWindow->Activate(); }
HRESULT
FrameworkView::ActivateView()
{
LogFunction();
UpdateWidgetSizeAndPosition(); UpdateWidgetSizeAndPosition();
MetroUtils::GetViewState(mViewState); MetroUtils::GetViewState(mViewState);
// Get the metro event dispatcher nsIntRegion region(nsIntRect(0, 0, mWindowBounds.width, mWindowBounds.height));
HRESULT hr = mWindow->get_Dispatcher(&mDispatcher); mWidget->Paint(region);
AssertRetHRESULT(hr, hr);
// Needs mDispatcher // Activate the window, this kills the splash screen
mWindow->Activate();
ProcessLaunchArguments();
AddEventHandlers(); AddEventHandlers();
SetupContracts();
// Drop into the main metro event loop
mDispatcher->ProcessEvents(ABI::Windows::UI::Core::CoreProcessEventsOption::CoreProcessEventsOption_ProcessUntilQuit);
Log("Exiting FrameworkView::Run()");
return S_OK; return S_OK;
} }
@ -165,12 +144,9 @@ void
FrameworkView::AddEventHandlers() { FrameworkView::AddEventHandlers() {
NS_ASSERTION(mWindow, "SetWindow must be called before AddEventHandlers!"); NS_ASSERTION(mWindow, "SetWindow must be called before AddEventHandlers!");
NS_ASSERTION(mWidget, "SetWidget must be called before AddEventHAndlers!"); NS_ASSERTION(mWidget, "SetWidget must be called before AddEventHAndlers!");
NS_ASSERTION(mDispatcher, "Must have a valid CoreDispatcher before "
"calling AddEventHAndlers!");
mMetroInput = Make<MetroInput>(mWidget.Get(), mMetroInput = Make<MetroInput>(mWidget.Get(),
mWindow.Get(), mWindow.Get());
mDispatcher.Get());
mWindow->add_VisibilityChanged(Callback<__FITypedEventHandler_2_Windows__CUI__CCore__CCoreWindow_Windows__CUI__CCore__CVisibilityChangedEventArgs>( mWindow->add_VisibilityChanged(Callback<__FITypedEventHandler_2_Windows__CUI__CCore__CCoreWindow_Windows__CUI__CCore__CVisibilityChangedEventArgs>(
this, &FrameworkView::OnWindowVisibilityChanged).Get(), &mWindowVisibilityChanged); this, &FrameworkView::OnWindowVisibilityChanged).Get(), &mWindowVisibilityChanged);
@ -208,7 +184,25 @@ FrameworkView::AddEventHandlers() {
void void
FrameworkView::ShutdownXPCOM() FrameworkView::ShutdownXPCOM()
{ {
Uninitialize(); LogFunction();
mShuttingDown = true;
if (mAutomationProvider) {
ComPtr<IUIABridge> provider;
mAutomationProvider.As(&provider);
if (provider) {
provider->Disconnect();
}
}
mAutomationProvider = nullptr;
mMetroInput = nullptr;
mD2DWindowSurface = nullptr;
delete sSettingsArray;
sSettingsArray = nullptr;
mWidget = nullptr;
mMetroApp = nullptr;
mWindow = nullptr;
} }
void void
@ -289,6 +283,8 @@ FrameworkView::IsVisible() const
void FrameworkView::SetDpi(float aDpi) void FrameworkView::SetDpi(float aDpi)
{ {
if (aDpi != mDPI) { if (aDpi != mDPI) {
LogFunction();
mDPI = aDpi; mDPI = aDpi;
// Often a DPI change implies a window size change. // Often a DPI change implies a window size change.
NS_ASSERTION(mWindow, "SetWindow must be called before SetDpi!"); NS_ASSERTION(mWindow, "SetWindow must be called before SetDpi!");
@ -346,8 +342,6 @@ FrameworkView::OnActivated(ICoreApplicationView* aApplicationView,
IActivatedEventArgs* aArgs) IActivatedEventArgs* aArgs)
{ {
LogFunction(); LogFunction();
// If we're on startup, we want to wait for FrameworkView::Run to run because
// XPCOM is not initialized yet and and we can't use nsICommandLineRunner
ApplicationExecutionState state; ApplicationExecutionState state;
aArgs->get_PreviousExecutionState(&state); aArgs->get_PreviousExecutionState(&state);
@ -452,11 +446,6 @@ FrameworkView::OnWindowActivated(ICoreWindow* aSender, IWindowActivatedEventArgs
aArgs->get_WindowActivationState(&state); aArgs->get_WindowActivationState(&state);
mWinActiveState = !(state == CoreWindowActivationState::CoreWindowActivationState_Deactivated); mWinActiveState = !(state == CoreWindowActivationState::CoreWindowActivationState_Deactivated);
SendActivationEvent(); SendActivationEvent();
// Flush out all remaining events so base widget doesn't process other stuff
// earlier which would lead to a white flash of a second at startup.
MetroAppShell::ProcessAllNativeEventsPresent();
return S_OK; return S_OK;
} }
@ -465,7 +454,9 @@ FrameworkView::OnLogicalDpiChanged(IInspectable* aSender)
{ {
LogFunction(); LogFunction();
UpdateLogicalDPI(); UpdateLogicalDPI();
Render(); if (mWidget) {
mWidget->Invalidate();
}
return S_OK; return S_OK;
} }

View File

@ -78,10 +78,10 @@ public:
STDMETHODIMP Run(); STDMETHODIMP Run();
STDMETHODIMP Uninitialize(); STDMETHODIMP Uninitialize();
HRESULT ActivateView();
// Public apis for MetroWidget // Public apis for MetroWidget
void ShutdownXPCOM(); void ShutdownXPCOM();
bool Render();
bool Render(const nsIntRegion& aInvalidRegion);
float GetDPI() { return mDPI; } float GetDPI() { return mDPI; }
ICoreWindow* GetCoreWindow() { return mWindow.Get(); } ICoreWindow* GetCoreWindow() { return mWindow.Get(); }
void SetWidget(MetroWidget* aWidget); void SetWidget(MetroWidget* aWidget);
@ -180,7 +180,6 @@ private:
nsIntRect mWindowBounds; // in device-pixel coordinates nsIntRect mWindowBounds; // in device-pixel coordinates
float mDPI; float mDPI;
bool mShuttingDown; bool mShuttingDown;
bool mPainting;
nsAutoString mActivationURI; nsAutoString mActivationURI;
nsAutoString mActivationCommandLine; nsAutoString mActivationCommandLine;
Microsoft::WRL::ComPtr<IInspectable> mAutomationProvider; Microsoft::WRL::ComPtr<IInspectable> mAutomationProvider;
@ -190,7 +189,6 @@ private:
//Microsoft::WRL::ComPtr<IWICImagingFactory2> mWicFactory; //Microsoft::WRL::ComPtr<IWICImagingFactory2> mWicFactory;
Microsoft::WRL::ComPtr<MetroApp> mMetroApp; Microsoft::WRL::ComPtr<MetroApp> mMetroApp;
Microsoft::WRL::ComPtr<ICoreWindow> mWindow; Microsoft::WRL::ComPtr<ICoreWindow> mWindow;
Microsoft::WRL::ComPtr<ICoreDispatcher> mDispatcher;
Microsoft::WRL::ComPtr<MetroWidget> mWidget; Microsoft::WRL::ComPtr<MetroWidget> mWidget;
Microsoft::WRL::ComPtr<MetroInput> mMetroInput; Microsoft::WRL::ComPtr<MetroInput> mMetroInput;
static bool sKeyboardIsVisible; static bool sKeyboardIsVisible;

View File

@ -1,78 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "base/basictypes.h"
#include "FrameworkView.h"
#include "MetroWidget.h"
#include "mozilla/AutoRestore.h"
#include "MetroUtils.h"
#include "nsIWidgetListener.h"
#include <windows.ui.xaml.media.dxinterop.h>
using namespace mozilla::gfx;
namespace mozilla {
namespace widget {
namespace winrt {
static bool
IsRenderMode(gfxWindowsPlatform::RenderMode aRMode)
{
return gfxWindowsPlatform::GetPlatform()->GetRenderMode() == aRMode;
}
bool
FrameworkView::Render()
{
Rect msrect;
mWindow->get_Bounds(&msrect);
nsIntRegion region(nsIntRect(0, 0, (uint32_t)ceil(msrect.Width),
(uint32_t)ceil(msrect.Height)));
return Render(region);
}
bool
FrameworkView::Render(const nsIntRegion& aInvalidRegion)
{
NS_ABORT_IF_FALSE(NS_IsMainThread(), "not main thread");
if (mShuttingDown || mPainting || !mWidget) {
return false;
}
// If we haven't created the layer manager, then create it now.
// The swap buffer will be resized automatically by the layer manager.
if (!mWidget->mLayerManager) {
(void)mWidget->GetLayerManager();
if (!mWidget->mLayerManager) {
NS_WARNING("mWidget->GetLayerManager() failed!");
return false;
}
}
// If OMTC is not in use, then we only support D2D rendering
if (!mWidget->ShouldUseOffMainThreadCompositing()) {
if (IsRenderMode(gfxWindowsPlatform::RENDER_GDI) ||
IsRenderMode(gfxWindowsPlatform::RENDER_IMAGE_STRETCH32) ||
IsRenderMode(gfxWindowsPlatform::RENDER_IMAGE_STRETCH24)) {
NS_WARNING("Unsupported render mode, can't draw. Needs to be D2D.");
return false;
}
}
if (mWidget->GetTransparencyMode() != eTransparencyOpaque) {
NS_WARNING("transparency modes other than eTransparencyOpaque unsupported, can't draw.");
return false;
}
AutoRestore<bool> painting(mPainting);
mPainting = true;
gfxWindowsPlatform::GetPlatform()->UpdateRenderMode();
mWidget->Paint(aInvalidRegion);
return true;
}
} } }

View File

@ -60,28 +60,12 @@ MetroApp::CreateView(ABI::Windows::ApplicationModel::Core::IFrameworkView **aVie
//////////////////////////////////////////////////// ////////////////////////////////////////////////////
// MetroApp impl. // MetroApp impl.
// called after FrameworkView::Run() drops into the event dispatch loop
void void
MetroApp::Initialize() MetroApp::Run()
{ {
HRESULT hr;
LogThread(); LogThread();
static bool xpcomInit; HRESULT hr;
if (!xpcomInit) {
xpcomInit = true;
Log("XPCOM startup initialization began");
nsresult rv = XRE_metroStartup(true);
Log("XPCOM startup initialization complete");
if (NS_FAILED(rv)) {
Log("XPCOM startup initialization failed, bailing. rv=%X", rv);
CoreExit();
return;
}
}
sFrameworkView->SetupContracts();
hr = sCoreApp->add_Suspending(Callback<__FIEventHandler_1_Windows__CApplicationModel__CSuspendingEventArgs_t>( hr = sCoreApp->add_Suspending(Callback<__FIEventHandler_1_Windows__CApplicationModel__CSuspendingEventArgs_t>(
this, &MetroApp::OnSuspending).Get(), &mSuspendEvent); this, &MetroApp::OnSuspending).Get(), &mSuspendEvent);
AssertHRESULT(hr); AssertHRESULT(hr);
@ -90,7 +74,13 @@ MetroApp::Initialize()
this, &MetroApp::OnResuming).Get(), &mResumeEvent); this, &MetroApp::OnResuming).Get(), &mResumeEvent);
AssertHRESULT(hr); AssertHRESULT(hr);
mozilla::widget::StartAudioSession(); Log("XPCOM startup initialization began");
nsresult rv = XRE_metroStartup(true);
Log("XPCOM startup initialization complete");
if (NS_FAILED(rv)) {
Log("XPCOM startup initialization failed, bailing. rv=%X", rv);
CoreExit();
}
} }
// Free all xpcom related resources before calling the xre shutdown call. // Free all xpcom related resources before calling the xre shutdown call.
@ -100,8 +90,6 @@ MetroApp::ShutdownXPCOM()
{ {
LogThread(); LogThread();
mozilla::widget::StopAudioSession();
if (sCoreApp) { if (sCoreApp) {
sCoreApp->remove_Suspending(mSuspendEvent); sCoreApp->remove_Suspending(mSuspendEvent);
sCoreApp->remove_Resuming(mResumeEvent); sCoreApp->remove_Resuming(mResumeEvent);

View File

@ -42,7 +42,7 @@ public:
// nsIWinMetroUtils tile related async callbacks // nsIWinMetroUtils tile related async callbacks
HRESULT OnAsyncTileCreated(ABI::Windows::Foundation::IAsyncOperation<bool>* aOperation, AsyncStatus aStatus); HRESULT OnAsyncTileCreated(ABI::Windows::Foundation::IAsyncOperation<bool>* aOperation, AsyncStatus aStatus);
void Initialize(); void Run();
void CoreExit(); void CoreExit();
void ShutdownXPCOM(); void ShutdownXPCOM();

View File

@ -8,10 +8,13 @@
#include "mozilla/widget/AudioSession.h" #include "mozilla/widget/AudioSession.h"
#include "MetroUtils.h" #include "MetroUtils.h"
#include "MetroApp.h" #include "MetroApp.h"
#include "FrameworkView.h"
#include "nsIObserverService.h" #include "nsIObserverService.h"
#include "nsServiceManagerUtils.h" #include "nsServiceManagerUtils.h"
#include "mozilla/AutoRestore.h"
#include "WinUtils.h" #include "WinUtils.h"
using namespace mozilla;
using namespace mozilla::widget; using namespace mozilla::widget;
using namespace mozilla::widget::winrt; using namespace mozilla::widget::winrt;
using namespace Microsoft::WRL; using namespace Microsoft::WRL;
@ -19,10 +22,14 @@ using namespace Microsoft::WRL::Wrappers;
using namespace ABI::Windows::UI::Core; using namespace ABI::Windows::UI::Core;
using namespace ABI::Windows::Foundation; using namespace ABI::Windows::Foundation;
// ProcessNextNativeEvent message wait timeout, see bug 907410.
#define MSG_WAIT_TIMEOUT 250
namespace mozilla { namespace mozilla {
namespace widget { namespace widget {
namespace winrt { namespace winrt {
extern ComPtr<MetroApp> sMetroApp; extern ComPtr<MetroApp> sMetroApp;
extern ComPtr<FrameworkView> sFrameworkView;
} } } } } }
namespace mozilla { namespace mozilla {
@ -32,6 +39,7 @@ extern UINT sAppShellGeckoMsgId;
} } } }
static ComPtr<ICoreWindowStatic> sCoreStatic; static ComPtr<ICoreWindowStatic> sCoreStatic;
static bool sIsDispatching = false;
MetroAppShell::~MetroAppShell() MetroAppShell::~MetroAppShell()
{ {
@ -101,7 +109,16 @@ MetroAppShell::Run(void)
rv = NS_ERROR_NOT_IMPLEMENTED; rv = NS_ERROR_NOT_IMPLEMENTED;
break; break;
case GeckoProcessType_Default: case GeckoProcessType_Default:
// Nothing to do, just return. mozilla::widget::StartAudioSession();
sFrameworkView->ActivateView();
rv = nsBaseAppShell::Run();
mozilla::widget::StopAudioSession();
// This calls XRE_metroShutdown() in xre. This will also destroy
// MessagePump.
sMetroApp->ShutdownXPCOM();
// This will free the real main thread in CoreApplication::Run()
// once winrt cleans up this thread.
sMetroApp->CoreExit();
break; break;
} }
@ -128,50 +145,29 @@ ProcessNativeEvents(CoreProcessEventsOption eventOption)
} }
// static // static
void bool
MetroAppShell::ProcessOneNativeEventIfPresent() MetroAppShell::ProcessOneNativeEventIfPresent()
{ {
if (sIsDispatching) {
NS_RUNTIMEABORT("Reentrant call into process events, this is not allowed in Winrt land. Goodbye!");
}
AutoRestore<bool> dispatching(sIsDispatching);
ProcessNativeEvents(CoreProcessEventsOption::CoreProcessEventsOption_ProcessOneIfPresent); ProcessNativeEvents(CoreProcessEventsOption::CoreProcessEventsOption_ProcessOneIfPresent);
} return !!HIWORD(::GetQueueStatus(MOZ_QS_ALLEVENT));
// static
void
MetroAppShell::ProcessAllNativeEventsPresent()
{
ProcessNativeEvents(CoreProcessEventsOption::CoreProcessEventsOption_ProcessAllIfPresent);
} }
bool bool
MetroAppShell::ProcessNextNativeEvent(bool mayWait) MetroAppShell::ProcessNextNativeEvent(bool mayWait)
{ {
MSG msg; if (ProcessOneNativeEventIfPresent()) {
return true;
}
if (mayWait) { if (mayWait) {
if (!WinUtils::PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) { DWORD result = ::MsgWaitForMultipleObjectsEx(0, NULL, MSG_WAIT_TIMEOUT, MOZ_QS_ALLEVENT,
WinUtils::WaitForMessage(); MWMO_INPUTAVAILABLE|MWMO_ALERTABLE);
} NS_WARN_IF_FALSE(result != WAIT_FAILED, "Wait failed");
ProcessOneNativeEventIfPresent();
return true;
} }
return ProcessOneNativeEventIfPresent();
if (WinUtils::PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) {
ProcessOneNativeEventIfPresent();
return true;
}
return false;
}
// Results from a call to appstartup->quit, which fires a final nsAppExitEvent
// event which calls us here. This is on the metro main thread. We want to
// call xpcom shutdown here, but we need to wait until the runnable that fires
// this is off the stack. See NativeEventCallback below.
NS_IMETHODIMP
MetroAppShell::Exit(void)
{
LogFunction();
mExiting = true;
return NS_OK;
} }
void void
@ -179,22 +175,6 @@ MetroAppShell::NativeCallback()
{ {
NS_ASSERTION(NS_IsMainThread(), "Native callbacks must be on the metro main thread"); NS_ASSERTION(NS_IsMainThread(), "Native callbacks must be on the metro main thread");
NativeEventCallback(); NativeEventCallback();
// Handle shutdown after Exit() is called and unwinds.
if (mExiting) {
// shutdown fires events, don't recurse
static bool sShutdown = false;
if (sShutdown)
return;
sShutdown = true;
if (sMetroApp) {
// This calls XRE_metroShutdown() in xre
sMetroApp->ShutdownXPCOM();
// This will free the real main thread in CoreApplication::Run()
// once winrt cleans up this thread.
sMetroApp->CoreExit();
}
}
} }
// static // static

View File

@ -15,26 +15,27 @@ class MetroAppShell : public nsBaseAppShell
public: public:
NS_DECL_NSIOBSERVER NS_DECL_NSIOBSERVER
MetroAppShell() : mEventWnd(NULL), mExiting(false), mPowerRequestCount(0) MetroAppShell() :
{} mEventWnd(NULL),
mPowerRequestCount(0)
{
}
nsresult Init(); nsresult Init();
void DoProcessMoreGeckoEvents(); void DoProcessMoreGeckoEvents();
void NativeCallback(); void NativeCallback();
static LRESULT CALLBACK EventWindowProc(HWND, UINT, WPARAM, LPARAM); static LRESULT CALLBACK EventWindowProc(HWND, UINT, WPARAM, LPARAM);
static void ProcessAllNativeEventsPresent(); static bool ProcessOneNativeEventIfPresent();
static void ProcessOneNativeEventIfPresent();
protected: protected:
HWND mEventWnd;
bool mExiting;
nsAutoHandle mPowerRequest;
ULONG mPowerRequestCount;
NS_IMETHOD Run(); NS_IMETHOD Run();
NS_IMETHOD Exit();
virtual void ScheduleNativeEventCallback(); virtual void ScheduleNativeEventCallback();
virtual bool ProcessNextNativeEvent(bool mayWait); virtual bool ProcessNextNativeEvent(bool mayWait);
virtual ~MetroAppShell(); virtual ~MetroAppShell();
HWND mEventWnd;
nsAutoHandle mPowerRequest;
ULONG mPowerRequestCount;
}; };

View File

@ -153,12 +153,9 @@ namespace widget {
namespace winrt { namespace winrt {
MetroInput::MetroInput(MetroWidget* aWidget, MetroInput::MetroInput(MetroWidget* aWidget,
UI::Core::ICoreWindow* aWindow, UI::Core::ICoreWindow* aWindow)
UI::Core::ICoreDispatcher* aDispatcher)
: mWidget(aWidget), : mWidget(aWidget),
mWindow(aWindow), mWindow(aWindow)
mDispatcher(aDispatcher),
mTouchEvent(true, NS_TOUCH_MOVE, aWidget)
{ {
LogFunction(); LogFunction();
NS_ASSERTION(aWidget, "Attempted to create MetroInput for null widget!"); NS_ASSERTION(aWidget, "Attempted to create MetroInput for null widget!");
@ -220,6 +217,7 @@ MetroInput::OnEdgeGestureStarted(UI::Input::IEdgeGesture* sender,
geckoEvent.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH; geckoEvent.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH;
// Safe
DispatchEventIgnoreStatus(&geckoEvent); DispatchEventIgnoreStatus(&geckoEvent);
return S_OK; return S_OK;
} }
@ -251,6 +249,7 @@ MetroInput::OnEdgeGestureCanceled(UI::Input::IEdgeGesture* sender,
geckoEvent.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH; geckoEvent.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH;
// Safe
DispatchEventIgnoreStatus(&geckoEvent); DispatchEventIgnoreStatus(&geckoEvent);
return S_OK; return S_OK;
} }
@ -288,6 +287,7 @@ MetroInput::OnEdgeGestureCompleted(UI::Input::IEdgeGesture* sender,
geckoEvent.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH; geckoEvent.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH;
} }
// Safe
DispatchEventIgnoreStatus(&geckoEvent); DispatchEventIgnoreStatus(&geckoEvent);
return S_OK; return S_OK;
} }
@ -309,43 +309,51 @@ MetroInput::OnPointerNonTouch(UI::Input::IPointerPoint* aPoint) {
aPoint->get_Properties(props.GetAddressOf()); aPoint->get_Properties(props.GetAddressOf());
props->get_PointerUpdateKind(&pointerUpdateKind); props->get_PointerUpdateKind(&pointerUpdateKind);
nsMouseEvent mouseEvent(true, nsMouseEvent* event =
NS_MOUSE_MOVE, new nsMouseEvent(true,
mWidget.Get(), NS_MOUSE_MOVE,
nsMouseEvent::eReal, mWidget.Get(),
nsMouseEvent::eNormal); nsMouseEvent::eReal,
nsMouseEvent::eNormal);
switch (pointerUpdateKind) { switch (pointerUpdateKind) {
case UI::Input::PointerUpdateKind::PointerUpdateKind_LeftButtonPressed: case UI::Input::PointerUpdateKind::PointerUpdateKind_LeftButtonPressed:
// We don't bother setting mouseEvent.button because it is already // We don't bother setting mouseEvent.button because it is already
// set to nsMouseEvent::buttonType::eLeftButton whose value is 0. // set to nsMouseEvent::buttonType::eLeftButton whose value is 0.
mouseEvent.message = NS_MOUSE_BUTTON_DOWN; event->message = NS_MOUSE_BUTTON_DOWN;
break; break;
case UI::Input::PointerUpdateKind::PointerUpdateKind_MiddleButtonPressed: case UI::Input::PointerUpdateKind::PointerUpdateKind_MiddleButtonPressed:
mouseEvent.button = nsMouseEvent::buttonType::eMiddleButton; event->button = nsMouseEvent::buttonType::eMiddleButton;
mouseEvent.message = NS_MOUSE_BUTTON_DOWN; event->message = NS_MOUSE_BUTTON_DOWN;
break; break;
case UI::Input::PointerUpdateKind::PointerUpdateKind_RightButtonPressed: case UI::Input::PointerUpdateKind::PointerUpdateKind_RightButtonPressed:
mouseEvent.button = nsMouseEvent::buttonType::eRightButton; event->button = nsMouseEvent::buttonType::eRightButton;
mouseEvent.message = NS_MOUSE_BUTTON_DOWN; event->message = NS_MOUSE_BUTTON_DOWN;
break; break;
case UI::Input::PointerUpdateKind::PointerUpdateKind_LeftButtonReleased: case UI::Input::PointerUpdateKind::PointerUpdateKind_LeftButtonReleased:
// We don't bother setting mouseEvent.button because it is already // We don't bother setting mouseEvent.button because it is already
// set to nsMouseEvent::buttonType::eLeftButton whose value is 0. // set to nsMouseEvent::buttonType::eLeftButton whose value is 0.
mouseEvent.message = NS_MOUSE_BUTTON_UP; event->message = NS_MOUSE_BUTTON_UP;
break; break;
case UI::Input::PointerUpdateKind::PointerUpdateKind_MiddleButtonReleased: case UI::Input::PointerUpdateKind::PointerUpdateKind_MiddleButtonReleased:
mouseEvent.button = nsMouseEvent::buttonType::eMiddleButton; event->button = nsMouseEvent::buttonType::eMiddleButton;
mouseEvent.message = NS_MOUSE_BUTTON_UP; event->message = NS_MOUSE_BUTTON_UP;
break; break;
case UI::Input::PointerUpdateKind::PointerUpdateKind_RightButtonReleased: case UI::Input::PointerUpdateKind::PointerUpdateKind_RightButtonReleased:
mouseEvent.button = nsMouseEvent::buttonType::eRightButton; event->button = nsMouseEvent::buttonType::eRightButton;
mouseEvent.message = NS_MOUSE_BUTTON_UP; event->message = NS_MOUSE_BUTTON_UP;
break; break;
} }
InitGeckoMouseEventFromPointerPoint(mouseEvent, aPoint); InitGeckoMouseEventFromPointerPoint(event, aPoint);
DispatchEventIgnoreStatus(&mouseEvent); DispatchAsyncEventIgnoreStatus(event);
return; }
void
MetroInput::InitTouchEventTouchList(nsTouchEvent* aEvent)
{
MOZ_ASSERT(aEvent);
mTouches.Enumerate(&AppendToTouchList,
static_cast<void*>(&aEvent->touches));
} }
// This event is raised when the user pushes the left mouse button, presses a // This event is raised when the user pushes the left mouse button, presses a
@ -381,104 +389,40 @@ MetroInput::OnPointerPressed(UI::Core::ICoreWindow* aSender,
nsRefPtr<Touch> touch = CreateDOMTouch(currentPoint.Get()); nsRefPtr<Touch> touch = CreateDOMTouch(currentPoint.Get());
touch->mChanged = true; touch->mChanged = true;
mTouches.Put(pointerId, touch); mTouches.Put(pointerId, touch);
mTouchEvent.message = NS_TOUCH_START;
// If this is the first touchstart of a touch session, nsTouchEvent* touchEvent =
// dispatch it now so we can see if preventDefault gets called on it. new nsTouchEvent(true, NS_TOUCH_START, mWidget.Get());
if (mTouches.Count() == 1) { if (mTouches.Count() == 1) {
nsEventStatus status; // If this is the first touchstart of a touch session reset some
DispatchPendingTouchEvent(status, true); // tracking flags and dispatch the event with a custom callback
mTouchStartDefaultPrevented = (nsEventStatus_eConsumeNoDefault == status); // so we can check preventDefault result.
// If the first touchstart event has preventDefault called on it, then mTouchStartDefaultPrevented = false;
// we will not perform any default actions associated with any touch mTouchMoveDefaultPrevented = false;
// events for this session, including touchmove events. mIsFirstTouchMove = true;
// Thus, mTouchStartDefaultPrevented implies mTouchMoveDefaultPrevented. InitTouchEventTouchList(touchEvent);
mTouchMoveDefaultPrevented = mTouchStartDefaultPrevented; DispatchAsyncTouchEventWithCallback(touchEvent, &MetroInput::OnPointerPressedCallback);
mIsFirstTouchMove = !mTouchStartDefaultPrevented; } else {
InitTouchEventTouchList(touchEvent);
DispatchAsyncTouchEventIgnoreStatus(touchEvent);
} }
// If the first touchstart of this touch session had its preventDefault
// called on it, we will not perform any default actions for any of the
// touches in this touch session.
if (!mTouchStartDefaultPrevented) { if (!mTouchStartDefaultPrevented) {
mGestureRecognizer->ProcessDownEvent(currentPoint.Get()); mGestureRecognizer->ProcessDownEvent(currentPoint.Get());
} }
return S_OK; return S_OK;
} }
// This event is raised when the user lifts the left mouse button, lifts a void
// pen from the surface, or lifts her/his finger from a touch screen. MetroInput::OnPointerPressedCallback()
HRESULT
MetroInput::OnPointerReleased(UI::Core::ICoreWindow* aSender,
UI::Core::IPointerEventArgs* aArgs)
{ {
#ifdef DEBUG_INPUT nsEventStatus status = DeliverNextQueuedTouchEvent();
LogFunction(); mTouchStartDefaultPrevented = (nsEventStatus_eConsumeNoDefault == status);
#endif // If content cancelled the first touchstart don't generate any gesture based
// input - clear the recognizer state without sending any events.
WRL::ComPtr<UI::Input::IPointerPoint> currentPoint; if (mTouchStartDefaultPrevented) {
WRL::ComPtr<Devices::Input::IPointerDevice> device; mGestureRecognizer->CompleteGesture();
Devices::Input::PointerDeviceType deviceType;
aArgs->get_CurrentPoint(currentPoint.GetAddressOf());
currentPoint->get_PointerDevice(device.GetAddressOf());
device->get_PointerDeviceType(&deviceType);
// For mouse and pen input, simply call our helper function
if (deviceType !=
Devices::Input::PointerDeviceType::PointerDeviceType_Touch) {
OnPointerNonTouch(currentPoint.Get());
mGestureRecognizer->ProcessUpEvent(currentPoint.Get());
return S_OK;
} }
// This is touch input.
// Get the touch associated with this touch point.
uint32_t pointerId;
currentPoint->get_PointerId(&pointerId);
nsRefPtr<Touch> touch = mTouches.Get(pointerId);
// We are about to dispatch a touchend. Before we do that, we should make
// sure that we don't have a touchmove or touchstart sitting around for this
// point.
if (touch->mChanged) {
DispatchPendingTouchEvent(true);
}
mTouches.Remove(pointerId);
// touchend events only have a single touch; the touch that has been removed
mTouchEvent.message = NS_TOUCH_END;
mTouchEvent.touches.Clear();
mTouchEvent.touches.AppendElement(CreateDOMTouch(currentPoint.Get()));
mTouchEvent.time = ::GetMessageTime();
mModifierKeyState.Update();
mModifierKeyState.InitInputEvent(mTouchEvent);
nsEventStatus status;
mWidget->DispatchEvent(&mTouchEvent, status);
if (status != nsEventStatus_eConsumeNoDefault) {
MultiTouchInput inputData(mTouchEvent);
if (MetroWidget::sAPZC) {
status = MetroWidget::sAPZC->ReceiveInputEvent(inputData);
}
}
// mTouchEvent.message should always be set to NS_TOUCH_MOVE
mTouchEvent.message = NS_TOUCH_MOVE;
// If the first touchstart of this touch session had its preventDefault
// called on it, we will not perform any default actions for any of the
// touches in this touch session. Note that we don't check
// mTouchMoveDefaultPrevented here. The reason is that, even if
// preventDefault was called on the first touchmove event, we might still
// want to dispatch a click (mousemove, mousedown, mouseup) in response to
// this touch.
if (!mTouchStartDefaultPrevented) {
mGestureRecognizer->ProcessUpEvent(currentPoint.Get());
}
return S_OK;
} }
// This event is raised when the user moves the mouse, moves a pen that is // This event is raised when the user moves the mouse, moves a pen that is
@ -525,42 +469,119 @@ MetroInput::OnPointerMoved(UI::Core::ICoreWindow* aSender,
return S_OK; return S_OK;
} }
// If we're modifying a touch entry that has a pending update, go through // If we've accumulated a batch of pointer moves and we're now on a new batch
// with the update. // at a new position send the previous batch. (perf opt)
if (touch->mChanged) { if (touch->mChanged) {
DispatchPendingTouchEvent(true); nsTouchEvent* touchEvent =
new nsTouchEvent(true, NS_TOUCH_MOVE, mWidget.Get());
InitTouchEventTouchList(touchEvent);
DispatchAsyncTouchEventIgnoreStatus(touchEvent);
} }
touch = CreateDOMTouch(currentPoint.Get()); touch = CreateDOMTouch(currentPoint.Get());
touch->mChanged = true; touch->mChanged = true;
// replacing old touch point in mTouches map
mTouches.Put(pointerId, touch); mTouches.Put(pointerId, touch);
// If this is the first touch move of our session, we should dispatch it nsTouchEvent* touchEvent =
// and store our mTouchMoveDefaultPrevented value new nsTouchEvent(true, NS_TOUCH_MOVE, mWidget.Get());
// If this is the first touch move of our session, we should check the result.
// Note we may lose some touch move data here for the recognizer since we want
// to wait until we have the result of the first touchmove dispatch. For gesture
// based events this shouldn't break anything.
if (mIsFirstTouchMove) { if (mIsFirstTouchMove) {
nsEventStatus status; InitTouchEventTouchList(touchEvent);
DispatchPendingTouchEvent(status, true); DispatchAsyncTouchEventWithCallback(touchEvent, &MetroInput::OnFirstPointerMoveCallback);
mTouchMoveDefaultPrevented = (nsEventStatus_eConsumeNoDefault == status);
mIsFirstTouchMove = false; mIsFirstTouchMove = false;
} else {
// Only feed move input to the recognizer if the first touchstart and
// subsequent touchmove return results were not eConsumeNoDefault.
if (!mTouchStartDefaultPrevented && !mTouchMoveDefaultPrevented) {
WRL::ComPtr<Foundation::Collections::IVector<UI::Input::PointerPoint*>>
pointerPoints;
aArgs->GetIntermediatePoints(pointerPoints.GetAddressOf());
mGestureRecognizer->ProcessMoveEvents(pointerPoints.Get());
}
} }
// We will perform default actions for touchmove events only if return S_OK;
// preventDefault was not called on the first touchmove event and }
// preventDefault was not called on the first touchstart event. Checking
// mTouchMoveDefaultPrevented is enough here because it will be set if void
// mTouchStartDefaultPrevented is true. MetroInput::OnFirstPointerMoveCallback()
if (!mTouchMoveDefaultPrevented) { {
WRL::ComPtr<Foundation::Collections::IVector<UI::Input::PointerPoint*>> nsTouchEvent* event = static_cast<nsTouchEvent*>(mInputEventQueue.PopFront());
pointerPoints; MOZ_ASSERT(event);
aArgs->GetIntermediatePoints(pointerPoints.GetAddressOf()); nsEventStatus status;
mGestureRecognizer->ProcessMoveEvents(pointerPoints.Get()); mWidget->DispatchEvent(event, status);
mTouchMoveDefaultPrevented = (nsEventStatus_eConsumeNoDefault == status);
delete event;
}
// This event is raised when the user lifts the left mouse button, lifts a
// pen from the surface, or lifts her/his finger from a touch screen.
HRESULT
MetroInput::OnPointerReleased(UI::Core::ICoreWindow* aSender,
UI::Core::IPointerEventArgs* aArgs)
{
#ifdef DEBUG_INPUT
LogFunction();
#endif
WRL::ComPtr<UI::Input::IPointerPoint> currentPoint;
WRL::ComPtr<Devices::Input::IPointerDevice> device;
Devices::Input::PointerDeviceType deviceType;
aArgs->get_CurrentPoint(currentPoint.GetAddressOf());
currentPoint->get_PointerDevice(device.GetAddressOf());
device->get_PointerDeviceType(&deviceType);
// For mouse and pen input, simply call our helper function
if (deviceType !=
Devices::Input::PointerDeviceType::PointerDeviceType_Touch) {
OnPointerNonTouch(currentPoint.Get());
mGestureRecognizer->ProcessUpEvent(currentPoint.Get());
return S_OK;
} }
// This is touch input.
// Get the touch associated with this touch point.
uint32_t pointerId;
currentPoint->get_PointerId(&pointerId);
nsRefPtr<Touch> touch = mTouches.Get(pointerId);
// Purge any pending moves for this pointer
if (touch->mChanged) {
nsTouchEvent* touchEvent =
new nsTouchEvent(true, NS_TOUCH_MOVE, mWidget.Get());
InitTouchEventTouchList(touchEvent);
DispatchAsyncTouchEventIgnoreStatus(touchEvent);
}
// Remove this touch point from our map. Eventually all touch points are
// removed for this session since we receive released events for every
// point.
mTouches.Remove(pointerId);
// touchend events only have a single touch; the touch that has been removed
nsTouchEvent* touchEvent =
new nsTouchEvent(true, NS_TOUCH_END, mWidget.Get());
touchEvent->touches.AppendElement(CreateDOMTouch(currentPoint.Get()));
DispatchAsyncTouchEventIgnoreStatus(touchEvent);
// If content didn't cancel the first touchstart feed touchend data to the
// recognizer.
if (!mTouchStartDefaultPrevented) {
mGestureRecognizer->ProcessUpEvent(currentPoint.Get());
}
return S_OK; return S_OK;
} }
void void
MetroInput::InitGeckoMouseEventFromPointerPoint( MetroInput::InitGeckoMouseEventFromPointerPoint(
nsMouseEvent& aEvent, nsMouseEvent* aEvent,
UI::Input::IPointerPoint* aPointerPoint) { UI::Input::IPointerPoint* aPointerPoint) {
NS_ASSERTION(aPointerPoint, "InitGeckoMouseEventFromPointerPoint " NS_ASSERTION(aPointerPoint, "InitGeckoMouseEventFromPointerPoint "
"called with null PointerPoint!"); "called with null PointerPoint!");
@ -581,19 +602,16 @@ MetroInput::InitGeckoMouseEventFromPointerPoint(
props->get_Pressure(&pressure); props->get_Pressure(&pressure);
mGestureRecognizer->CanBeDoubleTap(aPointerPoint, &canBeDoubleTap); mGestureRecognizer->CanBeDoubleTap(aPointerPoint, &canBeDoubleTap);
mModifierKeyState.Update(); aEvent->refPoint = LayoutDeviceIntPoint::FromUntyped(MetroUtils::LogToPhys(position));
mModifierKeyState.InitInputEvent(aEvent);
aEvent.refPoint = LayoutDeviceIntPoint::FromUntyped(MetroUtils::LogToPhys(position));
aEvent.time = timestamp;
if (!canBeDoubleTap) { if (!canBeDoubleTap) {
aEvent.clickCount = 1; aEvent->clickCount = 1;
} else { } else {
aEvent.clickCount = 2; aEvent->clickCount = 2;
} }
aEvent.pressure = pressure; aEvent->pressure = pressure;
MozInputSourceFromDeviceType(deviceType, aEvent.inputSource); MozInputSourceFromDeviceType(deviceType, aEvent->inputSource);
} }
// This event is raised when a precise pointer moves into the bounding box of // This event is raised when a precise pointer moves into the bounding box of
@ -618,13 +636,13 @@ MetroInput::OnPointerEntered(UI::Core::ICoreWindow* aSender,
// We only dispatch mouseenter and mouseexit events for mouse and pen input. // We only dispatch mouseenter and mouseexit events for mouse and pen input.
if (deviceType != if (deviceType !=
Devices::Input::PointerDeviceType::PointerDeviceType_Touch) { Devices::Input::PointerDeviceType::PointerDeviceType_Touch) {
nsMouseEvent mouseEvent(true, nsMouseEvent* event = new nsMouseEvent(true,
NS_MOUSE_ENTER, NS_MOUSE_ENTER,
mWidget.Get(), mWidget.Get(),
nsMouseEvent::eReal, nsMouseEvent::eReal,
nsMouseEvent::eNormal); nsMouseEvent::eNormal);
InitGeckoMouseEventFromPointerPoint(mouseEvent, currentPoint.Get()); InitGeckoMouseEventFromPointerPoint(event, currentPoint.Get());
DispatchEventIgnoreStatus(&mouseEvent); DispatchAsyncEventIgnoreStatus(event);
} }
return S_OK; return S_OK;
} }
@ -651,13 +669,13 @@ MetroInput::OnPointerExited(UI::Core::ICoreWindow* aSender,
// We only dispatch mouseenter and mouseexit events for mouse and pen input. // We only dispatch mouseenter and mouseexit events for mouse and pen input.
if (deviceType != if (deviceType !=
Devices::Input::PointerDeviceType::PointerDeviceType_Touch) { Devices::Input::PointerDeviceType::PointerDeviceType_Touch) {
nsMouseEvent mouseEvent(true, nsMouseEvent* event = new nsMouseEvent(true,
NS_MOUSE_EXIT, NS_MOUSE_EXIT,
mWidget.Get(), mWidget.Get(),
nsMouseEvent::eReal, nsMouseEvent::eReal,
nsMouseEvent::eNormal); nsMouseEvent::eNormal);
InitGeckoMouseEventFromPointerPoint(mouseEvent, currentPoint.Get()); InitGeckoMouseEventFromPointerPoint(event, currentPoint.Get());
DispatchEventIgnoreStatus(&mouseEvent); DispatchAsyncEventIgnoreStatus(event);
} }
return S_OK; return S_OK;
} }
@ -691,33 +709,27 @@ MetroInput::ProcessManipulationDelta(
} }
// Send a gecko event indicating the magnification since the last update. // Send a gecko event indicating the magnification since the last update.
nsSimpleGestureEvent magEvent(true, nsSimpleGestureEvent* magEvent =
aMagEventType, new nsSimpleGestureEvent(true, aMagEventType, mWidget.Get(), 0, 0.0);
mWidget.Get(), 0, 0.0);
magEvent.delta = aDelta.Expansion; magEvent->delta = aDelta.Expansion;
mModifierKeyState.Update(); magEvent->inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH;
mModifierKeyState.InitInputEvent(magEvent); magEvent->refPoint = LayoutDeviceIntPoint::FromUntyped(MetroUtils::LogToPhys(aPosition));
magEvent.time = ::GetMessageTime(); DispatchAsyncEventIgnoreStatus(magEvent);
magEvent.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH;
magEvent.refPoint = LayoutDeviceIntPoint::FromUntyped(MetroUtils::LogToPhys(aPosition));
DispatchEventIgnoreStatus(&magEvent);
// Send a gecko event indicating the rotation since the last update. // Send a gecko event indicating the rotation since the last update.
nsSimpleGestureEvent rotEvent(true, nsSimpleGestureEvent* rotEvent =
aRotEventType, new nsSimpleGestureEvent(true, aRotEventType, mWidget.Get(), 0, 0.0);
mWidget.Get(), 0, 0.0);
rotEvent.delta = aDelta.Rotation; rotEvent->delta = aDelta.Rotation;
mModifierKeyState.Update(); rotEvent->inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH;
mModifierKeyState.InitInputEvent(rotEvent); rotEvent->refPoint = LayoutDeviceIntPoint::FromUntyped(MetroUtils::LogToPhys(aPosition));
rotEvent.time = ::GetMessageTime(); if (rotEvent->delta >= 0) {
rotEvent.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH; rotEvent->direction = nsIDOMSimpleGestureEvent::ROTATION_COUNTERCLOCKWISE;
rotEvent.refPoint = LayoutDeviceIntPoint::FromUntyped(MetroUtils::LogToPhys(aPosition));
if (rotEvent.delta >= 0) {
rotEvent.direction = nsIDOMSimpleGestureEvent::ROTATION_COUNTERCLOCKWISE;
} else { } else {
rotEvent.direction = nsIDOMSimpleGestureEvent::ROTATION_CLOCKWISE; rotEvent->direction = nsIDOMSimpleGestureEvent::ROTATION_CLOCKWISE;
} }
DispatchEventIgnoreStatus(&rotEvent); DispatchAsyncEventIgnoreStatus(rotEvent);
} }
// This event is raised when a gesture is detected to have started. The // This event is raised when a gesture is detected to have started. The
@ -837,33 +849,29 @@ MetroInput::OnManipulationCompleted(
} }
if (isHorizontalSwipe) { if (isHorizontalSwipe) {
nsSimpleGestureEvent swipeEvent(true, NS_SIMPLE_GESTURE_SWIPE, nsSimpleGestureEvent* swipeEvent =
mWidget.Get(), 0, 0.0); new nsSimpleGestureEvent(true, NS_SIMPLE_GESTURE_SWIPE,
swipeEvent.direction = delta.Translation.X > 0 mWidget.Get(), 0, 0.0);
swipeEvent->direction = delta.Translation.X > 0
? nsIDOMSimpleGestureEvent::DIRECTION_RIGHT ? nsIDOMSimpleGestureEvent::DIRECTION_RIGHT
: nsIDOMSimpleGestureEvent::DIRECTION_LEFT; : nsIDOMSimpleGestureEvent::DIRECTION_LEFT;
swipeEvent.delta = delta.Translation.X; swipeEvent->delta = delta.Translation.X;
mModifierKeyState.Update(); swipeEvent->inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH;
mModifierKeyState.InitInputEvent(swipeEvent); swipeEvent->refPoint = LayoutDeviceIntPoint::FromUntyped(MetroUtils::LogToPhys(position));
swipeEvent.time = ::GetMessageTime(); DispatchAsyncEventIgnoreStatus(swipeEvent);
swipeEvent.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH;
swipeEvent.refPoint = LayoutDeviceIntPoint::FromUntyped(MetroUtils::LogToPhys(position));
DispatchEventIgnoreStatus(&swipeEvent);
} }
if (isVerticalSwipe) { if (isVerticalSwipe) {
nsSimpleGestureEvent swipeEvent(true, NS_SIMPLE_GESTURE_SWIPE, nsSimpleGestureEvent* swipeEvent =
mWidget.Get(), 0, 0.0); new nsSimpleGestureEvent(true, NS_SIMPLE_GESTURE_SWIPE,
swipeEvent.direction = delta.Translation.Y > 0 mWidget.Get(), 0, 0.0);
swipeEvent->direction = delta.Translation.Y > 0
? nsIDOMSimpleGestureEvent::DIRECTION_DOWN ? nsIDOMSimpleGestureEvent::DIRECTION_DOWN
: nsIDOMSimpleGestureEvent::DIRECTION_UP; : nsIDOMSimpleGestureEvent::DIRECTION_UP;
swipeEvent.delta = delta.Translation.Y; swipeEvent->delta = delta.Translation.Y;
mModifierKeyState.Update(); swipeEvent->inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH;
mModifierKeyState.InitInputEvent(swipeEvent); swipeEvent->refPoint = LayoutDeviceIntPoint::FromUntyped(MetroUtils::LogToPhys(position));
swipeEvent.time = ::GetMessageTime(); DispatchAsyncEventIgnoreStatus(swipeEvent);
swipeEvent.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH;
swipeEvent.refPoint = LayoutDeviceIntPoint::FromUntyped(MetroUtils::LogToPhys(position));
DispatchEventIgnoreStatus(&swipeEvent);
} }
return S_OK; return S_OK;
@ -927,15 +935,18 @@ MetroInput::HandleDoubleTap(const LayoutDeviceIntPoint& aPoint)
#ifdef DEBUG_INPUT #ifdef DEBUG_INPUT
LogFunction(); LogFunction();
#endif #endif
nsSimpleGestureEvent geckoEvent(true, NS_SIMPLE_GESTURE_TAP, mWidget.Get(), 0, 0.0); nsSimpleGestureEvent* tapEvent =
mModifierKeyState.Update(); new nsSimpleGestureEvent(true,
mModifierKeyState.InitInputEvent(geckoEvent); NS_SIMPLE_GESTURE_TAP,
geckoEvent.time = ::GetMessageTime(); mWidget.Get(),
geckoEvent.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH; 0,
geckoEvent.refPoint = aPoint; 0.0);
geckoEvent.clickCount = 2;
geckoEvent.pressure = 1; tapEvent->inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH;
DispatchEventIgnoreStatus(&geckoEvent); tapEvent->refPoint = aPoint;
tapEvent->clickCount = 2;
tapEvent->pressure = 1;
DispatchAsyncEventIgnoreStatus(tapEvent);
} }
void void
@ -945,31 +956,39 @@ MetroInput::HandleSingleTap(const LayoutDeviceIntPoint& aPoint)
LogFunction(); LogFunction();
#endif #endif
// Set up the mouse event that we'll reuse for mousemove, mousedown, and // send mousemove
// mouseup nsMouseEvent* mouseEvent = new nsMouseEvent(true,
nsMouseEvent mouseEvent(true, NS_MOUSE_MOVE,
NS_MOUSE_MOVE, mWidget.Get(),
mWidget.Get(), nsMouseEvent::eReal,
nsMouseEvent::eReal, nsMouseEvent::eNormal);
nsMouseEvent::eNormal); mouseEvent->refPoint = aPoint;
mModifierKeyState.Update(); mouseEvent->clickCount = 1;
mModifierKeyState.InitInputEvent(mouseEvent); mouseEvent->inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH;
mouseEvent.refPoint = aPoint; DispatchAsyncEventIgnoreStatus(mouseEvent);
mouseEvent.time = ::GetMessageTime();
mouseEvent.clickCount = 1;
mouseEvent.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH;
// Send the mousemove
DispatchEventIgnoreStatus(&mouseEvent);
// Send the mousedown // Send the mousedown
mouseEvent.message = NS_MOUSE_BUTTON_DOWN; mouseEvent = new nsMouseEvent(true,
mouseEvent.button = nsMouseEvent::buttonType::eLeftButton; NS_MOUSE_BUTTON_DOWN,
DispatchEventIgnoreStatus(&mouseEvent); mWidget.Get(),
nsMouseEvent::eReal,
nsMouseEvent::eNormal);
mouseEvent->refPoint = aPoint;
mouseEvent->clickCount = 1;
mouseEvent->inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH;
mouseEvent->button = nsMouseEvent::buttonType::eLeftButton;
DispatchAsyncEventIgnoreStatus(mouseEvent);
// Send the mouseup mouseEvent = new nsMouseEvent(true,
mouseEvent.message = NS_MOUSE_BUTTON_UP; NS_MOUSE_BUTTON_UP,
DispatchEventIgnoreStatus(&mouseEvent); mWidget.Get(),
nsMouseEvent::eReal,
nsMouseEvent::eNormal);
mouseEvent->refPoint = aPoint;
mouseEvent->clickCount = 1;
mouseEvent->inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH;
mouseEvent->button = nsMouseEvent::buttonType::eLeftButton;
DispatchAsyncEventIgnoreStatus(mouseEvent);
// Send one more mousemove to avoid getting a hover state. // Send one more mousemove to avoid getting a hover state.
// In the Metro environment for any application, a tap does not imply a // In the Metro environment for any application, a tap does not imply a
@ -978,10 +997,15 @@ MetroInput::HandleSingleTap(const LayoutDeviceIntPoint& aPoint)
POINT point; POINT point;
if (GetCursorPos(&point)) { if (GetCursorPos(&point)) {
ScreenToClient((HWND)mWidget->GetNativeData(NS_NATIVE_WINDOW), &point); ScreenToClient((HWND)mWidget->GetNativeData(NS_NATIVE_WINDOW), &point);
mouseEvent.refPoint = LayoutDeviceIntPoint(point.x, point.y); mouseEvent = new nsMouseEvent(true,
mouseEvent.message = NS_MOUSE_MOVE; NS_MOUSE_MOVE,
mouseEvent.button = 0; mWidget.Get(),
DispatchEventIgnoreStatus(&mouseEvent); nsMouseEvent::eReal,
nsMouseEvent::eNormal);
mouseEvent->refPoint = LayoutDeviceIntPoint(point.x, point.y);
mouseEvent->clickCount = 1;
mouseEvent->inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH;
DispatchAsyncEventIgnoreStatus(mouseEvent);
} }
} }
@ -993,17 +1017,14 @@ MetroInput::HandleLongTap(const LayoutDeviceIntPoint& aPoint)
LogFunction(); LogFunction();
#endif #endif
nsMouseEvent contextMenu(true, nsMouseEvent* contextEvent = new nsMouseEvent(true,
NS_CONTEXTMENU, NS_CONTEXTMENU,
mWidget.Get(), mWidget.Get(),
nsMouseEvent::eReal, nsMouseEvent::eReal,
nsMouseEvent::eNormal); nsMouseEvent::eNormal);
mModifierKeyState.Update(); contextEvent->refPoint = aPoint;
mModifierKeyState.InitInputEvent(contextMenu); contextEvent->inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH;
contextMenu.refPoint = aPoint; DispatchAsyncEventIgnoreStatus(contextEvent);
contextMenu.time = ::GetMessageTime();
contextMenu.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH;
DispatchEventIgnoreStatus(&contextMenu);
} }
/** /**
@ -1011,39 +1032,82 @@ MetroInput::HandleLongTap(const LayoutDeviceIntPoint& aPoint)
*/ */
nsEventStatus MetroInput::sThrowawayStatus; nsEventStatus MetroInput::sThrowawayStatus;
// This function allows us to call MetroWidget's DispatchEvent function void
// without passing in a status. It uses a static nsEventStatus whose value MetroInput::DispatchAsyncEventIgnoreStatus(nsInputEvent* aEvent)
// is never read. This allows us to avoid the (admittedly small) overhead {
// of creating a new nsEventStatus every time we dispatch an event. aEvent->time = ::GetMessageTime();
mModifierKeyState.Update();
mModifierKeyState.InitInputEvent(*aEvent);
mInputEventQueue.Push(aEvent);
nsCOMPtr<nsIRunnable> runnable =
NS_NewRunnableMethod(this, &MetroInput::DeliverNextQueuedEventIgnoreStatus);
NS_DispatchToCurrentThread(runnable);
}
void
MetroInput::DeliverNextQueuedEventIgnoreStatus()
{
nsGUIEvent* event = static_cast<nsGUIEvent*>(mInputEventQueue.PopFront());
MOZ_ASSERT(event);
DispatchEventIgnoreStatus(event);
delete event;
}
nsEventStatus
MetroInput::DeliverNextQueuedEvent()
{
nsGUIEvent* event = static_cast<nsGUIEvent*>(mInputEventQueue.PopFront());
MOZ_ASSERT(event);
nsEventStatus status;
mWidget->DispatchEvent(event, status);
delete event;
return status;
}
void
MetroInput::DispatchAsyncTouchEventIgnoreStatus(nsTouchEvent* aEvent)
{
aEvent->time = ::GetMessageTime();
mModifierKeyState.Update();
mModifierKeyState.InitInputEvent(*aEvent);
mInputEventQueue.Push(aEvent);
nsCOMPtr<nsIRunnable> runnable =
NS_NewRunnableMethod(this, &MetroInput::DeliverNextQueuedTouchEvent);
NS_DispatchToCurrentThread(runnable);
}
nsEventStatus
MetroInput::DeliverNextQueuedTouchEvent()
{
nsTouchEvent* event = static_cast<nsTouchEvent*>(mInputEventQueue.PopFront());
MOZ_ASSERT(event);
nsEventStatus status;
mWidget->DispatchEvent(event, status);
if (status != nsEventStatus_eConsumeNoDefault && MetroWidget::sAPZC) {
MultiTouchInput inputData(*event);
MetroWidget::sAPZC->ReceiveInputEvent(inputData);
}
delete event;
return status;
}
void
MetroInput::DispatchAsyncTouchEventWithCallback(nsTouchEvent* aEvent, void (MetroInput::*Callback)())
{
aEvent->time = ::GetMessageTime();
mModifierKeyState.Update();
mModifierKeyState.InitInputEvent(*aEvent);
mInputEventQueue.Push(aEvent);
nsCOMPtr<nsIRunnable> runnable =
NS_NewRunnableMethod(this, Callback);
NS_DispatchToCurrentThread(runnable);
}
void void
MetroInput::DispatchEventIgnoreStatus(nsGUIEvent *aEvent) { MetroInput::DispatchEventIgnoreStatus(nsGUIEvent *aEvent) {
mWidget->DispatchEvent(aEvent, sThrowawayStatus); mWidget->DispatchEvent(aEvent, sThrowawayStatus);
} }
void
MetroInput::DispatchPendingTouchEvent(nsEventStatus& aStatus, bool aDispatchToAPZC) {
mTouchEvent.touches.Clear();
mTouches.Enumerate(&AppendToTouchList,
static_cast<void*>(&mTouchEvent.touches));
mTouchEvent.time = ::GetMessageTime();
mModifierKeyState.Update();
mModifierKeyState.InitInputEvent(mTouchEvent);
mWidget->DispatchEvent(&mTouchEvent, aStatus);
if (aStatus != nsEventStatus_eConsumeNoDefault && aDispatchToAPZC && MetroWidget::sAPZC) {
MultiTouchInput inputData(mTouchEvent);
aStatus = MetroWidget::sAPZC->ReceiveInputEvent(inputData);
}
// mTouchEvent.message should always be set to NS_TOUCH_MOVE
mTouchEvent.message = NS_TOUCH_MOVE;
}
void
MetroInput::DispatchPendingTouchEvent(bool aDispatchToAPZC) {
DispatchPendingTouchEvent(sThrowawayStatus, aDispatchToAPZC);
}
void void
MetroInput::UnregisterInputEvents() { MetroInput::UnregisterInputEvents() {
// Unregister ourselves for the edge swipe event // Unregister ourselves for the edge swipe event
@ -1085,8 +1149,6 @@ MetroInput::RegisterInputEvents()
NS_ASSERTION(mWindow, "Must have a window to register for input events!"); NS_ASSERTION(mWindow, "Must have a window to register for input events!");
NS_ASSERTION(mGestureRecognizer, NS_ASSERTION(mGestureRecognizer,
"Must have a GestureRecognizer for input events!"); "Must have a GestureRecognizer for input events!");
NS_ASSERTION(mDispatcher,
"Must have a CoreDispatcher to register for input events!");
// Register for edge swipe // Register for edge swipe
WRL::ComPtr<UI::Input::IEdgeGestureStatics> edgeStatics; WRL::ComPtr<UI::Input::IEdgeGestureStatics> edgeStatics;
Foundation::GetActivationFactory( Foundation::GetActivationFactory(

View File

@ -11,6 +11,7 @@
#include "nsGUIEvent.h" // mTouchEvent (nsTouchEvent) #include "nsGUIEvent.h" // mTouchEvent (nsTouchEvent)
#include "nsHashKeys.h" // type of key for mTouches #include "nsHashKeys.h" // type of key for mTouches
#include "mozwrlbase.h" #include "mozwrlbase.h"
#include "nsDeque.h"
// System headers (alphabetical) // System headers (alphabetical)
#include <EventToken.h> // EventRegistrationToken #include <EventToken.h> // EventRegistrationToken
@ -44,7 +45,6 @@ namespace ABI {
namespace UI { namespace UI {
namespace Core { namespace Core {
struct ICoreWindow; struct ICoreWindow;
struct ICoreDispatcher;
struct IAcceleratorKeyEventArgs; struct IAcceleratorKeyEventArgs;
struct IKeyEventArgs; struct IKeyEventArgs;
struct IPointerEventArgs; struct IPointerEventArgs;
@ -84,7 +84,6 @@ private:
typedef ABI::Windows::UI::Core::ICoreWindow ICoreWindow; typedef ABI::Windows::UI::Core::ICoreWindow ICoreWindow;
typedef ABI::Windows::UI::Core::IAcceleratorKeyEventArgs \ typedef ABI::Windows::UI::Core::IAcceleratorKeyEventArgs \
IAcceleratorKeyEventArgs; IAcceleratorKeyEventArgs;
typedef ABI::Windows::UI::Core::ICoreDispatcher ICoreDispatcher;
typedef ABI::Windows::UI::Core::IKeyEventArgs IKeyEventArgs; typedef ABI::Windows::UI::Core::IKeyEventArgs IKeyEventArgs;
typedef ABI::Windows::UI::Core::IPointerEventArgs IPointerEventArgs; typedef ABI::Windows::UI::Core::IPointerEventArgs IPointerEventArgs;
@ -105,8 +104,7 @@ private:
public: public:
MetroInput(MetroWidget* aWidget, MetroInput(MetroWidget* aWidget,
ICoreWindow* aWindow, ICoreWindow* aWindow);
ICoreDispatcher* aDispatcher);
virtual ~MetroInput(); virtual ~MetroInput();
// These input events are received from our window. These are basic // These input events are received from our window. These are basic
@ -157,7 +155,6 @@ public:
private: private:
Microsoft::WRL::ComPtr<ICoreWindow> mWindow; Microsoft::WRL::ComPtr<ICoreWindow> mWindow;
Microsoft::WRL::ComPtr<MetroWidget> mWidget; Microsoft::WRL::ComPtr<MetroWidget> mWidget;
Microsoft::WRL::ComPtr<ICoreDispatcher> mDispatcher;
Microsoft::WRL::ComPtr<IGestureRecognizer> mGestureRecognizer; Microsoft::WRL::ComPtr<IGestureRecognizer> mGestureRecognizer;
ModifierKeyState mModifierKeyState; ModifierKeyState mModifierKeyState;
@ -168,16 +165,13 @@ private:
// Event processing helpers. See function definitions for more info. // Event processing helpers. See function definitions for more info.
void OnPointerNonTouch(IPointerPoint* aPoint); void OnPointerNonTouch(IPointerPoint* aPoint);
void InitGeckoMouseEventFromPointerPoint(nsMouseEvent& aEvent, void InitGeckoMouseEventFromPointerPoint(nsMouseEvent* aEvent,
IPointerPoint* aPoint); IPointerPoint* aPoint);
void ProcessManipulationDelta(ManipulationDelta const& aDelta, void ProcessManipulationDelta(ManipulationDelta const& aDelta,
Point const& aPosition, Point const& aPosition,
uint32_t aMagEventType, uint32_t aMagEventType,
uint32_t aRotEventType); uint32_t aRotEventType);
void DispatchEventIgnoreStatus(nsGUIEvent *aEvent);
static nsEventStatus sThrowawayStatus;
// The W3C spec states that "whether preventDefault has been called" should // The W3C spec states that "whether preventDefault has been called" should
// be tracked on a per-touchpoint basis, but it also states that touchstart // be tracked on a per-touchpoint basis, but it also states that touchstart
// and touchmove events can contain multiple changed points. At the time of // and touchmove events can contain multiple changed points. At the time of
@ -224,10 +218,7 @@ private:
// the updated touchpoint info and record the fact that the touchpoint // the updated touchpoint info and record the fact that the touchpoint
// has changed. If ever we try to update a touchpoint has already // has changed. If ever we try to update a touchpoint has already
// changed, we dispatch a touch event containing all the changed touches. // changed, we dispatch a touch event containing all the changed touches.
nsEventStatus mTouchEventStatus; void InitTouchEventTouchList(nsTouchEvent* aEvent);
nsTouchEvent mTouchEvent;
void DispatchPendingTouchEvent(bool aDispatchToAPZC);
void DispatchPendingTouchEvent(nsEventStatus& status, bool aDispatchToAPZC);
nsBaseHashtable<nsUint32HashKey, nsBaseHashtable<nsUint32HashKey,
nsRefPtr<mozilla::dom::Touch>, nsRefPtr<mozilla::dom::Touch>,
nsRefPtr<mozilla::dom::Touch> > mTouches; nsRefPtr<mozilla::dom::Touch> > mTouches;
@ -257,6 +248,34 @@ private:
EventRegistrationToken mTokenManipulationCompleted; EventRegistrationToken mTokenManipulationCompleted;
EventRegistrationToken mTokenTapped; EventRegistrationToken mTokenTapped;
EventRegistrationToken mTokenRightTapped; EventRegistrationToken mTokenRightTapped;
// Due to a limitation added in 8.1 the ui thread can't re-enter the main
// native event dispatcher in MetroAppShell. So all events delivered to us
// on the ui thread via a native event dispatch call get bounced through
// the gecko thread event queue using runnables. Most events can be sent
// async without the need to see the status result. Those that do have
// specialty callbacks. Note any event that arrives to us on the ui thread
// that originates from another thread is safe to send sync.
// Async event dispatching
void DispatchAsyncEventIgnoreStatus(nsInputEvent* aEvent);
void DispatchAsyncTouchEventIgnoreStatus(nsTouchEvent* aEvent);
void DispatchAsyncTouchEventWithCallback(nsTouchEvent* aEvent, void (MetroInput::*Callback)());
// Async event callbacks
void DeliverNextQueuedEventIgnoreStatus();
nsEventStatus DeliverNextQueuedEvent();
nsEventStatus DeliverNextQueuedTouchEvent();
// Misc. specialty async callbacks
void OnPointerPressedCallback();
void OnFirstPointerMoveCallback();
// Sync event dispatching
void DispatchEventIgnoreStatus(nsGUIEvent *aEvent);
nsDeque mInputEventQueue;
static nsEventStatus sThrowawayStatus;
}; };
} } } } } }

View File

@ -562,6 +562,124 @@ CloseGesture()
} }
} }
// Async event sending for mouse and keyboard input.
// Simple Windows message wrapper for dispatching async events.
class DispatchMsg
{
public:
DispatchMsg(UINT aMsg, WPARAM aWParam, LPARAM aLParam) :
mMsg(aMsg),
mWParam(aWParam),
mLParam(aLParam)
{
}
~DispatchMsg()
{
}
UINT mMsg;
WPARAM mWParam;
LPARAM mLParam;
};
DispatchMsg*
MetroWidget::CreateDispatchMsg(UINT aMsg, WPARAM aWParam, LPARAM aLParam)
{
switch (aMsg) {
case WM_SETTINGCHANGE:
case WM_MOUSEWHEEL:
case WM_MOUSEHWHEEL:
case WM_HSCROLL:
case WM_VSCROLL:
case MOZ_WM_HSCROLL:
case MOZ_WM_VSCROLL:
case WM_KEYDOWN:
case WM_KEYUP:
// MOZ_WM events are plugin specific, we keep them for completness
case MOZ_WM_MOUSEVWHEEL:
case MOZ_WM_MOUSEHWHEEL:
return new DispatchMsg(aMsg, aWParam, aLParam);
default:
MOZ_CRASH("Unknown event being passed to CreateDispatchMsg.");
return nullptr;
}
}
void
MetroWidget::DispatchAsyncScrollEvent(DispatchMsg* aEvent)
{
mMsgEventQueue.Push(aEvent);
nsCOMPtr<nsIRunnable> runnable =
NS_NewRunnableMethod(this, &MetroWidget::DeliverNextScrollEvent);
NS_DispatchToCurrentThread(runnable);
}
void
MetroWidget::DeliverNextScrollEvent()
{
DispatchMsg* msg = static_cast<DispatchMsg*>(mMsgEventQueue.PopFront());
MOZ_ASSERT(msg);
MSGResult msgResult;
MouseScrollHandler::ProcessMessage(this, msg->mMsg, msg->mWParam, msg->mLParam, msgResult);
delete msg;
}
// defined in nsWiondowBase, called from shared module KeyboardLayout.
bool
MetroWidget::DispatchKeyboardEvent(nsGUIEvent* aEvent)
{
MOZ_ASSERT(aEvent);
nsKeyEvent* oldKeyEvent = static_cast<nsKeyEvent*>(aEvent);
nsKeyEvent* keyEvent =
new nsKeyEvent(oldKeyEvent->mFlags.mIsTrusted, oldKeyEvent->message, oldKeyEvent->widget);
// XXX note this leaves pluginEvent null, which is fine for now.
keyEvent->AssignKeyEventData(*oldKeyEvent, true);
mKeyEventQueue.Push(keyEvent);
nsCOMPtr<nsIRunnable> runnable =
NS_NewRunnableMethod(this, &MetroWidget::DeliverNextKeyboardEvent);
NS_DispatchToCurrentThread(runnable);
return false;
}
// Used in conjunction with mKeyEventQueue to find a keypress event
// that should not be delivered due to the return result of the
// preceeding keydown.
class KeyQueryIdAndCancel : public nsDequeFunctor {
public:
KeyQueryIdAndCancel(uint32_t aIdToCancel) :
mId(aIdToCancel) {
}
virtual void* operator() (void* aObject) {
nsKeyEvent* event = static_cast<nsKeyEvent*>(aObject);
if (event->mUniqueId == mId) {
event->mFlags.mPropagationStopped = true;
}
return nullptr;
}
protected:
uint32_t mId;
};
void
MetroWidget::DeliverNextKeyboardEvent()
{
nsKeyEvent* event = static_cast<nsKeyEvent*>(mKeyEventQueue.PopFront());
if (event->mFlags.mPropagationStopped) {
// This can happen if a keypress was previously cancelled.
delete event;
return;
}
if (DispatchWindowEvent(event) && event->message == NS_KEY_DOWN) {
// keydown events may be followed by multiple keypress events which
// shouldn't be sent if preventDefault is called on keydown.
KeyQueryIdAndCancel query(event->mUniqueId);
mKeyEventQueue.ForEach(query);
}
delete event;
}
// static // static
LRESULT CALLBACK LRESULT CALLBACK
MetroWidget::StaticWindowProcedure(HWND aWnd, UINT aMsg, WPARAM aWParam, LPARAM aLParam) MetroWidget::StaticWindowProcedure(HWND aWnd, UINT aMsg, WPARAM aWParam, LPARAM aLParam)
@ -589,10 +707,14 @@ MetroWidget::WindowProcedure(HWND aWnd, UINT aMsg, WPARAM aWParam, LPARAM aLPara
// The result returned if we do not do default processing. // The result returned if we do not do default processing.
LRESULT processResult = 0; LRESULT processResult = 0;
MSGResult msgResult(&processResult); // We ignore return results from the scroll module and pass everything
MouseScrollHandler::ProcessMessage(this, aMsg, aWParam, aLParam, msgResult); // to mMetroWndProc. These fall through to winrt handlers that generate
if (msgResult.mConsumed) { // input events in MetroInput. Since we have no listeners for scroll
return processResult; // events no processing should occur. For now processDefault must be left
// true since the mouse module consumes non-mouse wheel related events.
if (MouseScrollHandler::NeedsMessage(aMsg)) {
DispatchMsg* msg = CreateDispatchMsg(aMsg, aWParam, aLParam);
DispatchAsyncScrollEvent(msg);
} }
switch (aMsg) { switch (aMsg) {
@ -604,7 +726,7 @@ MetroWidget::WindowProcedure(HWND aWnd, UINT aMsg, WPARAM aWParam, LPARAM aLPara
DeleteObject(rgn); DeleteObject(rgn);
if (region.IsEmpty()) if (region.IsEmpty())
break; break;
mView->Render(region); Paint(region);
break; break;
} }
@ -624,6 +746,9 @@ MetroWidget::WindowProcedure(HWND aWnd, UINT aMsg, WPARAM aWParam, LPARAM aLPara
break; break;
} }
// Keyboard handling is passed to KeyboardLayout, which delivers gecko events
// via DispatchKeyboardEvent.
case WM_KEYDOWN: case WM_KEYDOWN:
case WM_SYSKEYDOWN: case WM_SYSKEYDOWN:
{ {
@ -983,6 +1108,8 @@ MetroWidget::GetPaintListener()
void MetroWidget::Paint(const nsIntRegion& aInvalidRegion) void MetroWidget::Paint(const nsIntRegion& aInvalidRegion)
{ {
gfxWindowsPlatform::GetPlatform()->UpdateRenderMode();
nsIWidgetListener* listener = GetPaintListener(); nsIWidgetListener* listener = GetPaintListener();
if (!listener) if (!listener)
return; return;

View File

@ -45,6 +45,8 @@ class FrameworkView;
} } } } } }
class DispatchMsg;
class MetroWidget : public nsWindowBase, class MetroWidget : public nsWindowBase,
public mozilla::layers::GeckoContentController, public mozilla::layers::GeckoContentController,
public nsIObserver public nsIObserver
@ -73,6 +75,8 @@ public:
// nsWindowBase // nsWindowBase
virtual bool DispatchWindowEvent(nsGUIEvent* aEvent) MOZ_OVERRIDE; virtual bool DispatchWindowEvent(nsGUIEvent* aEvent) MOZ_OVERRIDE;
virtual bool DispatchKeyboardEvent(nsGUIEvent* aEvent) MOZ_OVERRIDE;
virtual bool DispatchPluginEvent(const MSG &aMsg) MOZ_OVERRIDE { return false; }
virtual bool IsTopLevelWidget() MOZ_OVERRIDE { return true; } virtual bool IsTopLevelWidget() MOZ_OVERRIDE { return true; }
virtual nsWindowBase* GetParentWindowBase(bool aIncludeOwner) MOZ_OVERRIDE { return nullptr; } virtual nsWindowBase* GetParentWindowBase(bool aIncludeOwner) MOZ_OVERRIDE { return nullptr; }
// InitEvent assumes physical coordinates and is used by shared win32 code. Do // InitEvent assumes physical coordinates and is used by shared win32 code. Do
@ -248,6 +252,15 @@ protected:
mozilla::layers::FrameMetrics mFrameMetrics; mozilla::layers::FrameMetrics mFrameMetrics;
uint64_t mRootLayerTreeId; uint64_t mRootLayerTreeId;
// Async event dispatching
void DispatchAsyncScrollEvent(DispatchMsg* aEvent);
void DeliverNextScrollEvent();
void DeliverNextKeyboardEvent();
DispatchMsg* CreateDispatchMsg(UINT aMsg, WPARAM aWParam, LPARAM aLParam);
nsDeque mMsgEventQueue;
nsDeque mKeyEventQueue;
public: public:
static nsRefPtr<mozilla::layers::APZCTreeManager> sAPZC; static nsRefPtr<mozilla::layers::APZCTreeManager> sAPZC;
}; };

View File

@ -8,7 +8,6 @@ MODULE = 'widget'
CPP_SOURCES += [ CPP_SOURCES += [
'FrameworkView.cpp', 'FrameworkView.cpp',
'FrameworkViewGfx.cpp',
'MetroApp.cpp', 'MetroApp.cpp',
'MetroAppShell.cpp', 'MetroAppShell.cpp',
'MetroContracts.cpp', 'MetroContracts.cpp',