mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge mozilla-central and fx-team
This commit is contained in:
commit
80a1b74dd0
@ -4,6 +4,7 @@
|
||||
"use strict";
|
||||
|
||||
function test() {
|
||||
requestLongerTimeout(2);
|
||||
waitForExplicitFinish();
|
||||
|
||||
try {
|
||||
|
@ -60,7 +60,7 @@ AppValidator.prototype._fetchManifest = function (manifestURL) {
|
||||
try {
|
||||
manifest = JSON.parse(req.responseText);
|
||||
} catch(e) {
|
||||
this.error(strings.formatStringFromName("validator.invalidManifestJSON", [manifestURL, e], 2));
|
||||
this.error(strings.formatStringFromName("validator.invalidManifestJSON", [e, manifestURL], 2));
|
||||
}
|
||||
deferred.resolve(manifest);
|
||||
}).bind(this);
|
||||
@ -109,7 +109,7 @@ AppValidator.prototype.validateManifest = function (manifest) {
|
||||
if (!manifest.icons || Object.keys(manifest.icons).length == 0) {
|
||||
this.warning(strings.GetStringFromName("validator.missIconsManifestProperty"));
|
||||
} else if (!manifest.icons["128"]) {
|
||||
this.warning(strings.GetStringFromName("validator.missIconForMarketplace"));
|
||||
this.warning(strings.GetStringFromName("validator.missIconMarketplace"));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,22 +2,32 @@
|
||||
# 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/.
|
||||
|
||||
# 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)
|
||||
# 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.connectTo=Connect to %1$S:%2$S
|
||||
project.filePickerTitle=Select a webapp folder
|
||||
|
||||
validator.nonExistingFolder=The project folder doesn't exists
|
||||
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.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.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.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.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.invalidHostedPriviledges=Hosted App can't be type '%S'.
|
||||
validator.noCertifiedSupport='certified' apps are not fully supported on the App manager.
|
||||
|
@ -649,37 +649,41 @@ function test_info() {
|
||||
|
||||
let stop = new Date();
|
||||
|
||||
// We round down/up by 1s as file system precision is lower than Date precision
|
||||
// (no clear specifications about that, but it seems that this can be a little
|
||||
// over 1 second under ext3 and 2 seconds under FAT)
|
||||
let startMs = start.getTime() - 2500;
|
||||
let stopMs = stop.getTime() + 2500;
|
||||
// We round down/up by 1s as file system precision is lower than
|
||||
// Date precision (no clear specifications about that, but it seems
|
||||
// that this can be a little over 1 second under ext3 and 2 seconds
|
||||
// under FAT).
|
||||
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() {
|
||||
let birth;
|
||||
if ("winBirthDate" in info) {
|
||||
birth = info.winBirthDate;
|
||||
} else if ("macBirthDate" in info) {
|
||||
birth = info.macBirthDate;
|
||||
if ("winBirthDate" in stat) {
|
||||
birth = stat.winBirthDate;
|
||||
} else if ("macBirthDate" in stat) {
|
||||
birth = stat.macBirthDate;
|
||||
} else {
|
||||
ok(true, "Skipping birthdate test");
|
||||
return;
|
||||
}
|
||||
ok(birth.getTime() <= stopMs,
|
||||
"test_info: file was created before now - " + stop + ", " + birth);
|
||||
// Note: Previous versions of this test checked whether the file has
|
||||
// been created after the start of the test. Unfortunately, this sometimes
|
||||
// failed under Windows, in specific circumstances: if the file has been
|
||||
// removed at the start of the test and recreated immediately, the Windows
|
||||
// file system detects this and decides that the file was actually truncated
|
||||
// rather than recreated, hence that it should keep its previous creation date.
|
||||
// Debugging hilarity ensues.
|
||||
"test_info: platformBirthDate is consistent");
|
||||
// Note: Previous versions of this test checked whether the file
|
||||
// has been created after the start of the test. Unfortunately,
|
||||
// this sometimes failed under Windows, in specific circumstances:
|
||||
// if the file has been removed at the start of the test and
|
||||
// recreated immediately, the Windows file system detects this and
|
||||
// decides that the file was actually truncated rather than
|
||||
// recreated, hence that it should keep its previous creation
|
||||
// date. Debugging hilarity ensues.
|
||||
});
|
||||
|
||||
let change = stat.lastModificationDate;
|
||||
ok(change.getTime() >= startMs
|
||||
&& change.getTime() <= stopMs,
|
||||
"test_info: file has changed between the start of the test and now - " + start + ", " + stop + ", " + change);
|
||||
info("Testing lastModificationDate: " + change);
|
||||
ok(change.getTime() >= startMs && change.getTime() <= stopMs,
|
||||
"test_info: lastModificationDate is consistent");
|
||||
|
||||
// Test OS.File.prototype.stat on new file
|
||||
file = OS.File.open(filename);
|
||||
@ -696,23 +700,20 @@ function test_info() {
|
||||
|
||||
stop = new Date();
|
||||
|
||||
// We round down/up by 1s as file system precision is lower than Date precision
|
||||
startMs = start.getTime() - 1000;
|
||||
stopMs = stop.getTime() + 1000;
|
||||
|
||||
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);
|
||||
// Round up/down as above
|
||||
startMs = start.getTime() - SLOPPY_FILE_SYSTEM_ADJUSTMENT;
|
||||
stopMs = stop.getTime() + SLOPPY_FILE_SYSTEM_ADJUSTMENT;
|
||||
info("Testing stat 2 with bounds [ " + startMs + ", " + stopMs +" ]");
|
||||
|
||||
let access = stat.lastAccessDate;
|
||||
ok(access.getTime() >= startMs
|
||||
&& access.getTime() <= stopMs,
|
||||
"test_info: file 2 was accessed between the start of the test and now - " + start + ", " + stop + ", " + access);
|
||||
info("Testing lastAccessDate: " + access);
|
||||
ok(access.getTime() >= startMs && access.getTime() <= stopMs,
|
||||
"test_info: lastAccessDate is consistent");
|
||||
|
||||
change = stat.lastModificationDate;
|
||||
ok(change.getTime() >= startMs
|
||||
&& change.getTime() <= stopMs,
|
||||
"test_info: file 2 has changed between the start of the test and now - " + start + ", " + stop + ", " + change);
|
||||
info("Testing lastModificationDate 2: " + change);
|
||||
ok(change.getTime() >= startMs && change.getTime() <= stopMs,
|
||||
"test_info: lastModificationDate 2 is consistent");
|
||||
|
||||
// Test OS.File.stat on directory
|
||||
stat = OS.File.stat(OS.File.getCurrentDirectory());
|
||||
|
@ -114,6 +114,10 @@ const N_STATUS = Name("status");
|
||||
const N_VALUE = Name("value");
|
||||
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
|
||||
|
||||
@ -572,7 +576,27 @@ Handler.prototype = {
|
||||
nextStatus = STATUS_RESOLVED;
|
||||
}
|
||||
} 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;
|
||||
nextValue = ex;
|
||||
}
|
||||
|
@ -97,6 +97,10 @@ const Cr = Components.results;
|
||||
|
||||
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
|
||||
|
||||
@ -226,6 +230,21 @@ TaskImpl.prototype = {
|
||||
this.deferred.resolve();
|
||||
} catch (ex) {
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
@ -1152,7 +1152,8 @@ public:
|
||||
keyCode(0), charCode(0),
|
||||
location(nsIDOMKeyEvent::DOM_KEY_LOCATION_STANDARD), isChar(0),
|
||||
mKeyNameIndex(mozilla::widget::KEY_NAME_INDEX_Unidentified),
|
||||
mNativeKeyEvent(nullptr)
|
||||
mNativeKeyEvent(nullptr),
|
||||
mUniqueId(0)
|
||||
{
|
||||
}
|
||||
|
||||
@ -1171,6 +1172,11 @@ public:
|
||||
mozilla::widget::KeyNameIndex mKeyNameIndex;
|
||||
// OS-specific native event can optionally be preserved
|
||||
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)
|
||||
{
|
||||
@ -1205,6 +1211,7 @@ public:
|
||||
// Don't copy mNativeKeyEvent because it may be referred after its instance
|
||||
// is destroyed.
|
||||
mNativeKeyEvent = nullptr;
|
||||
mUniqueId = aEvent.mUniqueId;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -261,6 +261,7 @@ struct ParamTraits<nsKeyEvent>
|
||||
WriteParam(aMsg, aParam.charCode);
|
||||
WriteParam(aMsg, aParam.isChar);
|
||||
WriteParam(aMsg, aParam.location);
|
||||
WriteParam(aMsg, aParam.mUniqueId);
|
||||
// An OS-specific native event might be attached in |mNativeKeyEvent|, but
|
||||
// that cannot be copied across process boundaries.
|
||||
}
|
||||
@ -273,7 +274,8 @@ struct ParamTraits<nsKeyEvent>
|
||||
ReadParam(aMsg, aIter, &aResult->keyCode) &&
|
||||
ReadParam(aMsg, aIter, &aResult->charCode) &&
|
||||
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->mNativeKeyEvent = NULL;
|
||||
|
@ -41,6 +41,11 @@
|
||||
namespace mozilla {
|
||||
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
|
||||
{
|
||||
PRUnichar BaseChar;
|
||||
@ -756,6 +761,9 @@ NativeKey::InitKeyEvent(nsKeyEvent& aKeyEvent,
|
||||
switch (aKeyEvent.message) {
|
||||
case NS_KEY_DOWN:
|
||||
aKeyEvent.keyCode = mDOMKeyCode;
|
||||
// Unique id for this keydown event and its associated keypress.
|
||||
sUniqueKeyEventId++;
|
||||
aKeyEvent.mUniqueId = sUniqueKeyEventId;
|
||||
break;
|
||||
case NS_KEY_UP:
|
||||
aKeyEvent.keyCode = mDOMKeyCode;
|
||||
@ -768,6 +776,7 @@ NativeKey::InitKeyEvent(nsKeyEvent& aKeyEvent,
|
||||
(mOriginalVirtualKeyCode == VK_MENU && mMsg.message != WM_SYSKEYUP);
|
||||
break;
|
||||
case NS_KEY_PRESS:
|
||||
aKeyEvent.mUniqueId = sUniqueKeyEventId;
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("Invalid event message");
|
||||
@ -797,7 +806,7 @@ NativeKey::DispatchKeyEvent(nsKeyEvent& aKeyEvent,
|
||||
aKeyEvent.pluginEvent = static_cast<void*>(&pluginEvent);
|
||||
}
|
||||
|
||||
return (mWidget->DispatchWindowEvent(&aKeyEvent) || mWidget->Destroyed());
|
||||
return (mWidget->DispatchKeyboardEvent(&aKeyEvent) || mWidget->Destroyed());
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -147,6 +147,27 @@ MouseScrollHandler::~MouseScrollHandler()
|
||||
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 */
|
||||
bool
|
||||
MouseScrollHandler::ProcessMessage(nsWindowBase* aWidget, UINT msg,
|
||||
|
@ -32,6 +32,7 @@ public:
|
||||
static void Initialize();
|
||||
static void Shutdown();
|
||||
|
||||
static bool NeedsMessage(UINT aMsg);
|
||||
static bool ProcessMessage(nsWindowBase* aWidget,
|
||||
UINT msg,
|
||||
WPARAM wParam,
|
||||
|
@ -34,6 +34,24 @@ struct KeyPair;
|
||||
namespace mozilla {
|
||||
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
|
||||
{
|
||||
public:
|
||||
|
@ -3662,6 +3662,13 @@ bool nsWindow::DispatchStandardEvent(uint32_t aMsg)
|
||||
return result;
|
||||
}
|
||||
|
||||
bool nsWindow::DispatchKeyboardEvent(nsGUIEvent* event)
|
||||
{
|
||||
nsEventStatus status;
|
||||
DispatchEvent(event, status);
|
||||
return ConvertStatus(status);
|
||||
}
|
||||
|
||||
bool nsWindow::DispatchWindowEvent(nsGUIEvent* event)
|
||||
{
|
||||
nsEventStatus status;
|
||||
|
@ -87,6 +87,7 @@ public:
|
||||
// nsWindowBase
|
||||
virtual void InitEvent(nsGUIEvent& aEvent, nsIntPoint* aPoint = nullptr) MOZ_OVERRIDE;
|
||||
virtual bool DispatchWindowEvent(nsGUIEvent* aEvent) MOZ_OVERRIDE;
|
||||
virtual bool DispatchKeyboardEvent(nsGUIEvent* aEvent) MOZ_OVERRIDE;
|
||||
virtual nsWindowBase* GetParentWindowBase(bool aIncludeOwner) MOZ_OVERRIDE;
|
||||
virtual bool IsTopLevelWidget() MOZ_OVERRIDE { return mIsTopWidgetWindow; }
|
||||
|
||||
|
@ -49,9 +49,16 @@ public:
|
||||
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()) {
|
||||
return false;
|
||||
|
@ -32,12 +32,6 @@ using namespace ABI::Windows::Foundation;
|
||||
using namespace Microsoft::WRL;
|
||||
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 widget {
|
||||
namespace winrt {
|
||||
@ -57,7 +51,6 @@ FrameworkView::FrameworkView(MetroApp* aMetroApp) :
|
||||
mWinVisible(false),
|
||||
mWinActiveState(false)
|
||||
{
|
||||
mPainting = false;
|
||||
memset(&sKeyboardRect, 0, sizeof(Rect));
|
||||
sSettingsArray = new nsTArray<nsString>();
|
||||
LogFunction();
|
||||
@ -84,27 +77,6 @@ FrameworkView::Initialize(ICoreApplicationView* aAppView)
|
||||
HRESULT
|
||||
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;
|
||||
}
|
||||
|
||||
@ -114,34 +86,41 @@ FrameworkView::Load(HSTRING aEntryPoint)
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
// called by winrt on startup
|
||||
HRESULT
|
||||
FrameworkView::Run()
|
||||
{
|
||||
LogFunction();
|
||||
|
||||
// XPCOM is initialized here. mWidget is also created.
|
||||
mMetroApp->Initialize();
|
||||
// Initialize XPCOM, create mWidget and go! We get a
|
||||
// callback in MetroAppShell::Run, in which we kick
|
||||
// off normal browser execution / event dispatching.
|
||||
mMetroApp->Run();
|
||||
|
||||
ProcessLaunchArguments();
|
||||
// Gecko is completely shut down at this point.
|
||||
Log("Exiting FrameworkView::Run()");
|
||||
|
||||
// Activate the window
|
||||
mWindow->Activate();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
FrameworkView::ActivateView()
|
||||
{
|
||||
LogFunction();
|
||||
|
||||
UpdateWidgetSizeAndPosition();
|
||||
|
||||
MetroUtils::GetViewState(mViewState);
|
||||
|
||||
// Get the metro event dispatcher
|
||||
HRESULT hr = mWindow->get_Dispatcher(&mDispatcher);
|
||||
AssertRetHRESULT(hr, hr);
|
||||
nsIntRegion region(nsIntRect(0, 0, mWindowBounds.width, mWindowBounds.height));
|
||||
mWidget->Paint(region);
|
||||
|
||||
// Needs mDispatcher
|
||||
// Activate the window, this kills the splash screen
|
||||
mWindow->Activate();
|
||||
|
||||
ProcessLaunchArguments();
|
||||
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;
|
||||
}
|
||||
|
||||
@ -165,12 +144,9 @@ void
|
||||
FrameworkView::AddEventHandlers() {
|
||||
NS_ASSERTION(mWindow, "SetWindow 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(),
|
||||
mWindow.Get(),
|
||||
mDispatcher.Get());
|
||||
mWindow.Get());
|
||||
|
||||
mWindow->add_VisibilityChanged(Callback<__FITypedEventHandler_2_Windows__CUI__CCore__CCoreWindow_Windows__CUI__CCore__CVisibilityChangedEventArgs>(
|
||||
this, &FrameworkView::OnWindowVisibilityChanged).Get(), &mWindowVisibilityChanged);
|
||||
@ -208,7 +184,25 @@ FrameworkView::AddEventHandlers() {
|
||||
void
|
||||
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
|
||||
@ -289,6 +283,8 @@ FrameworkView::IsVisible() const
|
||||
void FrameworkView::SetDpi(float aDpi)
|
||||
{
|
||||
if (aDpi != mDPI) {
|
||||
LogFunction();
|
||||
|
||||
mDPI = aDpi;
|
||||
// Often a DPI change implies a window size change.
|
||||
NS_ASSERTION(mWindow, "SetWindow must be called before SetDpi!");
|
||||
@ -346,8 +342,6 @@ FrameworkView::OnActivated(ICoreApplicationView* aApplicationView,
|
||||
IActivatedEventArgs* aArgs)
|
||||
{
|
||||
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;
|
||||
aArgs->get_PreviousExecutionState(&state);
|
||||
@ -452,11 +446,6 @@ FrameworkView::OnWindowActivated(ICoreWindow* aSender, IWindowActivatedEventArgs
|
||||
aArgs->get_WindowActivationState(&state);
|
||||
mWinActiveState = !(state == CoreWindowActivationState::CoreWindowActivationState_Deactivated);
|
||||
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;
|
||||
}
|
||||
|
||||
@ -465,7 +454,9 @@ FrameworkView::OnLogicalDpiChanged(IInspectable* aSender)
|
||||
{
|
||||
LogFunction();
|
||||
UpdateLogicalDPI();
|
||||
Render();
|
||||
if (mWidget) {
|
||||
mWidget->Invalidate();
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
@ -78,10 +78,10 @@ public:
|
||||
STDMETHODIMP Run();
|
||||
STDMETHODIMP Uninitialize();
|
||||
|
||||
HRESULT ActivateView();
|
||||
|
||||
// Public apis for MetroWidget
|
||||
void ShutdownXPCOM();
|
||||
bool Render();
|
||||
bool Render(const nsIntRegion& aInvalidRegion);
|
||||
float GetDPI() { return mDPI; }
|
||||
ICoreWindow* GetCoreWindow() { return mWindow.Get(); }
|
||||
void SetWidget(MetroWidget* aWidget);
|
||||
@ -180,7 +180,6 @@ private:
|
||||
nsIntRect mWindowBounds; // in device-pixel coordinates
|
||||
float mDPI;
|
||||
bool mShuttingDown;
|
||||
bool mPainting;
|
||||
nsAutoString mActivationURI;
|
||||
nsAutoString mActivationCommandLine;
|
||||
Microsoft::WRL::ComPtr<IInspectable> mAutomationProvider;
|
||||
@ -190,7 +189,6 @@ private:
|
||||
//Microsoft::WRL::ComPtr<IWICImagingFactory2> mWicFactory;
|
||||
Microsoft::WRL::ComPtr<MetroApp> mMetroApp;
|
||||
Microsoft::WRL::ComPtr<ICoreWindow> mWindow;
|
||||
Microsoft::WRL::ComPtr<ICoreDispatcher> mDispatcher;
|
||||
Microsoft::WRL::ComPtr<MetroWidget> mWidget;
|
||||
Microsoft::WRL::ComPtr<MetroInput> mMetroInput;
|
||||
static bool sKeyboardIsVisible;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
} } }
|
@ -60,28 +60,12 @@ MetroApp::CreateView(ABI::Windows::ApplicationModel::Core::IFrameworkView **aVie
|
||||
////////////////////////////////////////////////////
|
||||
// MetroApp impl.
|
||||
|
||||
// called after FrameworkView::Run() drops into the event dispatch loop
|
||||
void
|
||||
MetroApp::Initialize()
|
||||
MetroApp::Run()
|
||||
{
|
||||
HRESULT hr;
|
||||
LogThread();
|
||||
|
||||
static bool xpcomInit;
|
||||
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();
|
||||
|
||||
HRESULT hr;
|
||||
hr = sCoreApp->add_Suspending(Callback<__FIEventHandler_1_Windows__CApplicationModel__CSuspendingEventArgs_t>(
|
||||
this, &MetroApp::OnSuspending).Get(), &mSuspendEvent);
|
||||
AssertHRESULT(hr);
|
||||
@ -90,7 +74,13 @@ MetroApp::Initialize()
|
||||
this, &MetroApp::OnResuming).Get(), &mResumeEvent);
|
||||
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.
|
||||
@ -100,8 +90,6 @@ MetroApp::ShutdownXPCOM()
|
||||
{
|
||||
LogThread();
|
||||
|
||||
mozilla::widget::StopAudioSession();
|
||||
|
||||
if (sCoreApp) {
|
||||
sCoreApp->remove_Suspending(mSuspendEvent);
|
||||
sCoreApp->remove_Resuming(mResumeEvent);
|
||||
|
@ -42,7 +42,7 @@ public:
|
||||
// nsIWinMetroUtils tile related async callbacks
|
||||
HRESULT OnAsyncTileCreated(ABI::Windows::Foundation::IAsyncOperation<bool>* aOperation, AsyncStatus aStatus);
|
||||
|
||||
void Initialize();
|
||||
void Run();
|
||||
void CoreExit();
|
||||
|
||||
void ShutdownXPCOM();
|
||||
|
@ -8,10 +8,13 @@
|
||||
#include "mozilla/widget/AudioSession.h"
|
||||
#include "MetroUtils.h"
|
||||
#include "MetroApp.h"
|
||||
#include "FrameworkView.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "mozilla/AutoRestore.h"
|
||||
#include "WinUtils.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::widget;
|
||||
using namespace mozilla::widget::winrt;
|
||||
using namespace Microsoft::WRL;
|
||||
@ -19,10 +22,14 @@ using namespace Microsoft::WRL::Wrappers;
|
||||
using namespace ABI::Windows::UI::Core;
|
||||
using namespace ABI::Windows::Foundation;
|
||||
|
||||
// ProcessNextNativeEvent message wait timeout, see bug 907410.
|
||||
#define MSG_WAIT_TIMEOUT 250
|
||||
|
||||
namespace mozilla {
|
||||
namespace widget {
|
||||
namespace winrt {
|
||||
extern ComPtr<MetroApp> sMetroApp;
|
||||
extern ComPtr<FrameworkView> sFrameworkView;
|
||||
} } }
|
||||
|
||||
namespace mozilla {
|
||||
@ -32,6 +39,7 @@ extern UINT sAppShellGeckoMsgId;
|
||||
} }
|
||||
|
||||
static ComPtr<ICoreWindowStatic> sCoreStatic;
|
||||
static bool sIsDispatching = false;
|
||||
|
||||
MetroAppShell::~MetroAppShell()
|
||||
{
|
||||
@ -101,7 +109,16 @@ MetroAppShell::Run(void)
|
||||
rv = NS_ERROR_NOT_IMPLEMENTED;
|
||||
break;
|
||||
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;
|
||||
}
|
||||
|
||||
@ -128,50 +145,29 @@ ProcessNativeEvents(CoreProcessEventsOption eventOption)
|
||||
}
|
||||
|
||||
// static
|
||||
void
|
||||
bool
|
||||
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);
|
||||
}
|
||||
|
||||
// static
|
||||
void
|
||||
MetroAppShell::ProcessAllNativeEventsPresent()
|
||||
{
|
||||
ProcessNativeEvents(CoreProcessEventsOption::CoreProcessEventsOption_ProcessAllIfPresent);
|
||||
return !!HIWORD(::GetQueueStatus(MOZ_QS_ALLEVENT));
|
||||
}
|
||||
|
||||
bool
|
||||
MetroAppShell::ProcessNextNativeEvent(bool mayWait)
|
||||
{
|
||||
MSG msg;
|
||||
|
||||
if (ProcessOneNativeEventIfPresent()) {
|
||||
return true;
|
||||
}
|
||||
if (mayWait) {
|
||||
if (!WinUtils::PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) {
|
||||
WinUtils::WaitForMessage();
|
||||
}
|
||||
ProcessOneNativeEventIfPresent();
|
||||
return true;
|
||||
DWORD result = ::MsgWaitForMultipleObjectsEx(0, NULL, MSG_WAIT_TIMEOUT, MOZ_QS_ALLEVENT,
|
||||
MWMO_INPUTAVAILABLE|MWMO_ALERTABLE);
|
||||
NS_WARN_IF_FALSE(result != WAIT_FAILED, "Wait failed");
|
||||
}
|
||||
|
||||
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;
|
||||
return ProcessOneNativeEventIfPresent();
|
||||
}
|
||||
|
||||
void
|
||||
@ -179,22 +175,6 @@ MetroAppShell::NativeCallback()
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Native callbacks must be on the metro main thread");
|
||||
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
|
||||
|
@ -15,26 +15,27 @@ class MetroAppShell : public nsBaseAppShell
|
||||
public:
|
||||
NS_DECL_NSIOBSERVER
|
||||
|
||||
MetroAppShell() : mEventWnd(NULL), mExiting(false), mPowerRequestCount(0)
|
||||
{}
|
||||
MetroAppShell() :
|
||||
mEventWnd(NULL),
|
||||
mPowerRequestCount(0)
|
||||
{
|
||||
}
|
||||
|
||||
nsresult Init();
|
||||
void DoProcessMoreGeckoEvents();
|
||||
void NativeCallback();
|
||||
|
||||
static LRESULT CALLBACK EventWindowProc(HWND, UINT, WPARAM, LPARAM);
|
||||
static void ProcessAllNativeEventsPresent();
|
||||
static void ProcessOneNativeEventIfPresent();
|
||||
static bool ProcessOneNativeEventIfPresent();
|
||||
|
||||
protected:
|
||||
HWND mEventWnd;
|
||||
bool mExiting;
|
||||
nsAutoHandle mPowerRequest;
|
||||
ULONG mPowerRequestCount;
|
||||
|
||||
NS_IMETHOD Run();
|
||||
NS_IMETHOD Exit();
|
||||
|
||||
virtual void ScheduleNativeEventCallback();
|
||||
virtual bool ProcessNextNativeEvent(bool mayWait);
|
||||
virtual ~MetroAppShell();
|
||||
|
||||
HWND mEventWnd;
|
||||
nsAutoHandle mPowerRequest;
|
||||
ULONG mPowerRequestCount;
|
||||
};
|
||||
|
@ -153,12 +153,9 @@ namespace widget {
|
||||
namespace winrt {
|
||||
|
||||
MetroInput::MetroInput(MetroWidget* aWidget,
|
||||
UI::Core::ICoreWindow* aWindow,
|
||||
UI::Core::ICoreDispatcher* aDispatcher)
|
||||
UI::Core::ICoreWindow* aWindow)
|
||||
: mWidget(aWidget),
|
||||
mWindow(aWindow),
|
||||
mDispatcher(aDispatcher),
|
||||
mTouchEvent(true, NS_TOUCH_MOVE, aWidget)
|
||||
mWindow(aWindow)
|
||||
{
|
||||
LogFunction();
|
||||
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;
|
||||
|
||||
// Safe
|
||||
DispatchEventIgnoreStatus(&geckoEvent);
|
||||
return S_OK;
|
||||
}
|
||||
@ -251,6 +249,7 @@ MetroInput::OnEdgeGestureCanceled(UI::Input::IEdgeGesture* sender,
|
||||
|
||||
geckoEvent.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH;
|
||||
|
||||
// Safe
|
||||
DispatchEventIgnoreStatus(&geckoEvent);
|
||||
return S_OK;
|
||||
}
|
||||
@ -288,6 +287,7 @@ MetroInput::OnEdgeGestureCompleted(UI::Input::IEdgeGesture* sender,
|
||||
geckoEvent.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH;
|
||||
}
|
||||
|
||||
// Safe
|
||||
DispatchEventIgnoreStatus(&geckoEvent);
|
||||
return S_OK;
|
||||
}
|
||||
@ -309,43 +309,51 @@ MetroInput::OnPointerNonTouch(UI::Input::IPointerPoint* aPoint) {
|
||||
aPoint->get_Properties(props.GetAddressOf());
|
||||
props->get_PointerUpdateKind(&pointerUpdateKind);
|
||||
|
||||
nsMouseEvent mouseEvent(true,
|
||||
NS_MOUSE_MOVE,
|
||||
mWidget.Get(),
|
||||
nsMouseEvent::eReal,
|
||||
nsMouseEvent::eNormal);
|
||||
nsMouseEvent* event =
|
||||
new nsMouseEvent(true,
|
||||
NS_MOUSE_MOVE,
|
||||
mWidget.Get(),
|
||||
nsMouseEvent::eReal,
|
||||
nsMouseEvent::eNormal);
|
||||
|
||||
switch (pointerUpdateKind) {
|
||||
case UI::Input::PointerUpdateKind::PointerUpdateKind_LeftButtonPressed:
|
||||
// We don't bother setting mouseEvent.button because it is already
|
||||
// set to nsMouseEvent::buttonType::eLeftButton whose value is 0.
|
||||
mouseEvent.message = NS_MOUSE_BUTTON_DOWN;
|
||||
event->message = NS_MOUSE_BUTTON_DOWN;
|
||||
break;
|
||||
case UI::Input::PointerUpdateKind::PointerUpdateKind_MiddleButtonPressed:
|
||||
mouseEvent.button = nsMouseEvent::buttonType::eMiddleButton;
|
||||
mouseEvent.message = NS_MOUSE_BUTTON_DOWN;
|
||||
event->button = nsMouseEvent::buttonType::eMiddleButton;
|
||||
event->message = NS_MOUSE_BUTTON_DOWN;
|
||||
break;
|
||||
case UI::Input::PointerUpdateKind::PointerUpdateKind_RightButtonPressed:
|
||||
mouseEvent.button = nsMouseEvent::buttonType::eRightButton;
|
||||
mouseEvent.message = NS_MOUSE_BUTTON_DOWN;
|
||||
event->button = nsMouseEvent::buttonType::eRightButton;
|
||||
event->message = NS_MOUSE_BUTTON_DOWN;
|
||||
break;
|
||||
case UI::Input::PointerUpdateKind::PointerUpdateKind_LeftButtonReleased:
|
||||
// We don't bother setting mouseEvent.button because it is already
|
||||
// set to nsMouseEvent::buttonType::eLeftButton whose value is 0.
|
||||
mouseEvent.message = NS_MOUSE_BUTTON_UP;
|
||||
event->message = NS_MOUSE_BUTTON_UP;
|
||||
break;
|
||||
case UI::Input::PointerUpdateKind::PointerUpdateKind_MiddleButtonReleased:
|
||||
mouseEvent.button = nsMouseEvent::buttonType::eMiddleButton;
|
||||
mouseEvent.message = NS_MOUSE_BUTTON_UP;
|
||||
event->button = nsMouseEvent::buttonType::eMiddleButton;
|
||||
event->message = NS_MOUSE_BUTTON_UP;
|
||||
break;
|
||||
case UI::Input::PointerUpdateKind::PointerUpdateKind_RightButtonReleased:
|
||||
mouseEvent.button = nsMouseEvent::buttonType::eRightButton;
|
||||
mouseEvent.message = NS_MOUSE_BUTTON_UP;
|
||||
event->button = nsMouseEvent::buttonType::eRightButton;
|
||||
event->message = NS_MOUSE_BUTTON_UP;
|
||||
break;
|
||||
}
|
||||
InitGeckoMouseEventFromPointerPoint(mouseEvent, aPoint);
|
||||
DispatchEventIgnoreStatus(&mouseEvent);
|
||||
return;
|
||||
InitGeckoMouseEventFromPointerPoint(event, aPoint);
|
||||
DispatchAsyncEventIgnoreStatus(event);
|
||||
}
|
||||
|
||||
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
|
||||
@ -381,104 +389,40 @@ MetroInput::OnPointerPressed(UI::Core::ICoreWindow* aSender,
|
||||
nsRefPtr<Touch> touch = CreateDOMTouch(currentPoint.Get());
|
||||
touch->mChanged = true;
|
||||
mTouches.Put(pointerId, touch);
|
||||
mTouchEvent.message = NS_TOUCH_START;
|
||||
|
||||
// If this is the first touchstart of a touch session,
|
||||
// dispatch it now so we can see if preventDefault gets called on it.
|
||||
nsTouchEvent* touchEvent =
|
||||
new nsTouchEvent(true, NS_TOUCH_START, mWidget.Get());
|
||||
|
||||
if (mTouches.Count() == 1) {
|
||||
nsEventStatus status;
|
||||
DispatchPendingTouchEvent(status, true);
|
||||
mTouchStartDefaultPrevented = (nsEventStatus_eConsumeNoDefault == status);
|
||||
// If the first touchstart event has preventDefault called on it, then
|
||||
// we will not perform any default actions associated with any touch
|
||||
// events for this session, including touchmove events.
|
||||
// Thus, mTouchStartDefaultPrevented implies mTouchMoveDefaultPrevented.
|
||||
mTouchMoveDefaultPrevented = mTouchStartDefaultPrevented;
|
||||
mIsFirstTouchMove = !mTouchStartDefaultPrevented;
|
||||
// If this is the first touchstart of a touch session reset some
|
||||
// tracking flags and dispatch the event with a custom callback
|
||||
// so we can check preventDefault result.
|
||||
mTouchStartDefaultPrevented = false;
|
||||
mTouchMoveDefaultPrevented = false;
|
||||
mIsFirstTouchMove = true;
|
||||
InitTouchEventTouchList(touchEvent);
|
||||
DispatchAsyncTouchEventWithCallback(touchEvent, &MetroInput::OnPointerPressedCallback);
|
||||
} 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) {
|
||||
mGestureRecognizer->ProcessDownEvent(currentPoint.Get());
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
// 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)
|
||||
void
|
||||
MetroInput::OnPointerPressedCallback()
|
||||
{
|
||||
#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;
|
||||
nsEventStatus status = DeliverNextQueuedTouchEvent();
|
||||
mTouchStartDefaultPrevented = (nsEventStatus_eConsumeNoDefault == status);
|
||||
// If content cancelled the first touchstart don't generate any gesture based
|
||||
// input - clear the recognizer state without sending any events.
|
||||
if (mTouchStartDefaultPrevented) {
|
||||
mGestureRecognizer->CompleteGesture();
|
||||
}
|
||||
|
||||
// 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
|
||||
@ -525,42 +469,119 @@ MetroInput::OnPointerMoved(UI::Core::ICoreWindow* aSender,
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
// If we're modifying a touch entry that has a pending update, go through
|
||||
// with the update.
|
||||
// If we've accumulated a batch of pointer moves and we're now on a new batch
|
||||
// at a new position send the previous batch. (perf opt)
|
||||
if (touch->mChanged) {
|
||||
DispatchPendingTouchEvent(true);
|
||||
nsTouchEvent* touchEvent =
|
||||
new nsTouchEvent(true, NS_TOUCH_MOVE, mWidget.Get());
|
||||
InitTouchEventTouchList(touchEvent);
|
||||
DispatchAsyncTouchEventIgnoreStatus(touchEvent);
|
||||
}
|
||||
|
||||
touch = CreateDOMTouch(currentPoint.Get());
|
||||
touch->mChanged = true;
|
||||
// replacing old touch point in mTouches map
|
||||
mTouches.Put(pointerId, touch);
|
||||
|
||||
// If this is the first touch move of our session, we should dispatch it
|
||||
// and store our mTouchMoveDefaultPrevented value
|
||||
nsTouchEvent* touchEvent =
|
||||
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) {
|
||||
nsEventStatus status;
|
||||
DispatchPendingTouchEvent(status, true);
|
||||
mTouchMoveDefaultPrevented = (nsEventStatus_eConsumeNoDefault == status);
|
||||
InitTouchEventTouchList(touchEvent);
|
||||
DispatchAsyncTouchEventWithCallback(touchEvent, &MetroInput::OnFirstPointerMoveCallback);
|
||||
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
|
||||
// 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
|
||||
// mTouchStartDefaultPrevented is true.
|
||||
if (!mTouchMoveDefaultPrevented) {
|
||||
WRL::ComPtr<Foundation::Collections::IVector<UI::Input::PointerPoint*>>
|
||||
pointerPoints;
|
||||
aArgs->GetIntermediatePoints(pointerPoints.GetAddressOf());
|
||||
mGestureRecognizer->ProcessMoveEvents(pointerPoints.Get());
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void
|
||||
MetroInput::OnFirstPointerMoveCallback()
|
||||
{
|
||||
nsTouchEvent* event = static_cast<nsTouchEvent*>(mInputEventQueue.PopFront());
|
||||
MOZ_ASSERT(event);
|
||||
nsEventStatus status;
|
||||
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;
|
||||
}
|
||||
|
||||
void
|
||||
MetroInput::InitGeckoMouseEventFromPointerPoint(
|
||||
nsMouseEvent& aEvent,
|
||||
nsMouseEvent* aEvent,
|
||||
UI::Input::IPointerPoint* aPointerPoint) {
|
||||
NS_ASSERTION(aPointerPoint, "InitGeckoMouseEventFromPointerPoint "
|
||||
"called with null PointerPoint!");
|
||||
@ -581,19 +602,16 @@ MetroInput::InitGeckoMouseEventFromPointerPoint(
|
||||
props->get_Pressure(&pressure);
|
||||
mGestureRecognizer->CanBeDoubleTap(aPointerPoint, &canBeDoubleTap);
|
||||
|
||||
mModifierKeyState.Update();
|
||||
mModifierKeyState.InitInputEvent(aEvent);
|
||||
aEvent.refPoint = LayoutDeviceIntPoint::FromUntyped(MetroUtils::LogToPhys(position));
|
||||
aEvent.time = timestamp;
|
||||
aEvent->refPoint = LayoutDeviceIntPoint::FromUntyped(MetroUtils::LogToPhys(position));
|
||||
|
||||
if (!canBeDoubleTap) {
|
||||
aEvent.clickCount = 1;
|
||||
aEvent->clickCount = 1;
|
||||
} 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
|
||||
@ -618,13 +636,13 @@ MetroInput::OnPointerEntered(UI::Core::ICoreWindow* aSender,
|
||||
// We only dispatch mouseenter and mouseexit events for mouse and pen input.
|
||||
if (deviceType !=
|
||||
Devices::Input::PointerDeviceType::PointerDeviceType_Touch) {
|
||||
nsMouseEvent mouseEvent(true,
|
||||
NS_MOUSE_ENTER,
|
||||
mWidget.Get(),
|
||||
nsMouseEvent::eReal,
|
||||
nsMouseEvent::eNormal);
|
||||
InitGeckoMouseEventFromPointerPoint(mouseEvent, currentPoint.Get());
|
||||
DispatchEventIgnoreStatus(&mouseEvent);
|
||||
nsMouseEvent* event = new nsMouseEvent(true,
|
||||
NS_MOUSE_ENTER,
|
||||
mWidget.Get(),
|
||||
nsMouseEvent::eReal,
|
||||
nsMouseEvent::eNormal);
|
||||
InitGeckoMouseEventFromPointerPoint(event, currentPoint.Get());
|
||||
DispatchAsyncEventIgnoreStatus(event);
|
||||
}
|
||||
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.
|
||||
if (deviceType !=
|
||||
Devices::Input::PointerDeviceType::PointerDeviceType_Touch) {
|
||||
nsMouseEvent mouseEvent(true,
|
||||
NS_MOUSE_EXIT,
|
||||
mWidget.Get(),
|
||||
nsMouseEvent::eReal,
|
||||
nsMouseEvent::eNormal);
|
||||
InitGeckoMouseEventFromPointerPoint(mouseEvent, currentPoint.Get());
|
||||
DispatchEventIgnoreStatus(&mouseEvent);
|
||||
nsMouseEvent* event = new nsMouseEvent(true,
|
||||
NS_MOUSE_EXIT,
|
||||
mWidget.Get(),
|
||||
nsMouseEvent::eReal,
|
||||
nsMouseEvent::eNormal);
|
||||
InitGeckoMouseEventFromPointerPoint(event, currentPoint.Get());
|
||||
DispatchAsyncEventIgnoreStatus(event);
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
@ -691,33 +709,27 @@ MetroInput::ProcessManipulationDelta(
|
||||
}
|
||||
|
||||
// Send a gecko event indicating the magnification since the last update.
|
||||
nsSimpleGestureEvent magEvent(true,
|
||||
aMagEventType,
|
||||
mWidget.Get(), 0, 0.0);
|
||||
magEvent.delta = aDelta.Expansion;
|
||||
mModifierKeyState.Update();
|
||||
mModifierKeyState.InitInputEvent(magEvent);
|
||||
magEvent.time = ::GetMessageTime();
|
||||
magEvent.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH;
|
||||
magEvent.refPoint = LayoutDeviceIntPoint::FromUntyped(MetroUtils::LogToPhys(aPosition));
|
||||
DispatchEventIgnoreStatus(&magEvent);
|
||||
nsSimpleGestureEvent* magEvent =
|
||||
new nsSimpleGestureEvent(true, aMagEventType, mWidget.Get(), 0, 0.0);
|
||||
|
||||
magEvent->delta = aDelta.Expansion;
|
||||
magEvent->inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH;
|
||||
magEvent->refPoint = LayoutDeviceIntPoint::FromUntyped(MetroUtils::LogToPhys(aPosition));
|
||||
DispatchAsyncEventIgnoreStatus(magEvent);
|
||||
|
||||
// Send a gecko event indicating the rotation since the last update.
|
||||
nsSimpleGestureEvent rotEvent(true,
|
||||
aRotEventType,
|
||||
mWidget.Get(), 0, 0.0);
|
||||
rotEvent.delta = aDelta.Rotation;
|
||||
mModifierKeyState.Update();
|
||||
mModifierKeyState.InitInputEvent(rotEvent);
|
||||
rotEvent.time = ::GetMessageTime();
|
||||
rotEvent.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH;
|
||||
rotEvent.refPoint = LayoutDeviceIntPoint::FromUntyped(MetroUtils::LogToPhys(aPosition));
|
||||
if (rotEvent.delta >= 0) {
|
||||
rotEvent.direction = nsIDOMSimpleGestureEvent::ROTATION_COUNTERCLOCKWISE;
|
||||
nsSimpleGestureEvent* rotEvent =
|
||||
new nsSimpleGestureEvent(true, aRotEventType, mWidget.Get(), 0, 0.0);
|
||||
|
||||
rotEvent->delta = aDelta.Rotation;
|
||||
rotEvent->inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH;
|
||||
rotEvent->refPoint = LayoutDeviceIntPoint::FromUntyped(MetroUtils::LogToPhys(aPosition));
|
||||
if (rotEvent->delta >= 0) {
|
||||
rotEvent->direction = nsIDOMSimpleGestureEvent::ROTATION_COUNTERCLOCKWISE;
|
||||
} 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
|
||||
@ -837,33 +849,29 @@ MetroInput::OnManipulationCompleted(
|
||||
}
|
||||
|
||||
if (isHorizontalSwipe) {
|
||||
nsSimpleGestureEvent swipeEvent(true, NS_SIMPLE_GESTURE_SWIPE,
|
||||
mWidget.Get(), 0, 0.0);
|
||||
swipeEvent.direction = delta.Translation.X > 0
|
||||
nsSimpleGestureEvent* swipeEvent =
|
||||
new nsSimpleGestureEvent(true, NS_SIMPLE_GESTURE_SWIPE,
|
||||
mWidget.Get(), 0, 0.0);
|
||||
swipeEvent->direction = delta.Translation.X > 0
|
||||
? nsIDOMSimpleGestureEvent::DIRECTION_RIGHT
|
||||
: nsIDOMSimpleGestureEvent::DIRECTION_LEFT;
|
||||
swipeEvent.delta = delta.Translation.X;
|
||||
mModifierKeyState.Update();
|
||||
mModifierKeyState.InitInputEvent(swipeEvent);
|
||||
swipeEvent.time = ::GetMessageTime();
|
||||
swipeEvent.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH;
|
||||
swipeEvent.refPoint = LayoutDeviceIntPoint::FromUntyped(MetroUtils::LogToPhys(position));
|
||||
DispatchEventIgnoreStatus(&swipeEvent);
|
||||
swipeEvent->delta = delta.Translation.X;
|
||||
swipeEvent->inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH;
|
||||
swipeEvent->refPoint = LayoutDeviceIntPoint::FromUntyped(MetroUtils::LogToPhys(position));
|
||||
DispatchAsyncEventIgnoreStatus(swipeEvent);
|
||||
}
|
||||
|
||||
if (isVerticalSwipe) {
|
||||
nsSimpleGestureEvent swipeEvent(true, NS_SIMPLE_GESTURE_SWIPE,
|
||||
mWidget.Get(), 0, 0.0);
|
||||
swipeEvent.direction = delta.Translation.Y > 0
|
||||
nsSimpleGestureEvent* swipeEvent =
|
||||
new nsSimpleGestureEvent(true, NS_SIMPLE_GESTURE_SWIPE,
|
||||
mWidget.Get(), 0, 0.0);
|
||||
swipeEvent->direction = delta.Translation.Y > 0
|
||||
? nsIDOMSimpleGestureEvent::DIRECTION_DOWN
|
||||
: nsIDOMSimpleGestureEvent::DIRECTION_UP;
|
||||
swipeEvent.delta = delta.Translation.Y;
|
||||
mModifierKeyState.Update();
|
||||
mModifierKeyState.InitInputEvent(swipeEvent);
|
||||
swipeEvent.time = ::GetMessageTime();
|
||||
swipeEvent.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH;
|
||||
swipeEvent.refPoint = LayoutDeviceIntPoint::FromUntyped(MetroUtils::LogToPhys(position));
|
||||
DispatchEventIgnoreStatus(&swipeEvent);
|
||||
swipeEvent->delta = delta.Translation.Y;
|
||||
swipeEvent->inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH;
|
||||
swipeEvent->refPoint = LayoutDeviceIntPoint::FromUntyped(MetroUtils::LogToPhys(position));
|
||||
DispatchAsyncEventIgnoreStatus(swipeEvent);
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
@ -927,15 +935,18 @@ MetroInput::HandleDoubleTap(const LayoutDeviceIntPoint& aPoint)
|
||||
#ifdef DEBUG_INPUT
|
||||
LogFunction();
|
||||
#endif
|
||||
nsSimpleGestureEvent geckoEvent(true, NS_SIMPLE_GESTURE_TAP, mWidget.Get(), 0, 0.0);
|
||||
mModifierKeyState.Update();
|
||||
mModifierKeyState.InitInputEvent(geckoEvent);
|
||||
geckoEvent.time = ::GetMessageTime();
|
||||
geckoEvent.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH;
|
||||
geckoEvent.refPoint = aPoint;
|
||||
geckoEvent.clickCount = 2;
|
||||
geckoEvent.pressure = 1;
|
||||
DispatchEventIgnoreStatus(&geckoEvent);
|
||||
nsSimpleGestureEvent* tapEvent =
|
||||
new nsSimpleGestureEvent(true,
|
||||
NS_SIMPLE_GESTURE_TAP,
|
||||
mWidget.Get(),
|
||||
0,
|
||||
0.0);
|
||||
|
||||
tapEvent->inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH;
|
||||
tapEvent->refPoint = aPoint;
|
||||
tapEvent->clickCount = 2;
|
||||
tapEvent->pressure = 1;
|
||||
DispatchAsyncEventIgnoreStatus(tapEvent);
|
||||
}
|
||||
|
||||
void
|
||||
@ -945,31 +956,39 @@ MetroInput::HandleSingleTap(const LayoutDeviceIntPoint& aPoint)
|
||||
LogFunction();
|
||||
#endif
|
||||
|
||||
// Set up the mouse event that we'll reuse for mousemove, mousedown, and
|
||||
// mouseup
|
||||
nsMouseEvent mouseEvent(true,
|
||||
NS_MOUSE_MOVE,
|
||||
mWidget.Get(),
|
||||
nsMouseEvent::eReal,
|
||||
nsMouseEvent::eNormal);
|
||||
mModifierKeyState.Update();
|
||||
mModifierKeyState.InitInputEvent(mouseEvent);
|
||||
mouseEvent.refPoint = aPoint;
|
||||
mouseEvent.time = ::GetMessageTime();
|
||||
mouseEvent.clickCount = 1;
|
||||
mouseEvent.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH;
|
||||
|
||||
// Send the mousemove
|
||||
DispatchEventIgnoreStatus(&mouseEvent);
|
||||
// send mousemove
|
||||
nsMouseEvent* mouseEvent = new nsMouseEvent(true,
|
||||
NS_MOUSE_MOVE,
|
||||
mWidget.Get(),
|
||||
nsMouseEvent::eReal,
|
||||
nsMouseEvent::eNormal);
|
||||
mouseEvent->refPoint = aPoint;
|
||||
mouseEvent->clickCount = 1;
|
||||
mouseEvent->inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH;
|
||||
DispatchAsyncEventIgnoreStatus(mouseEvent);
|
||||
|
||||
// Send the mousedown
|
||||
mouseEvent.message = NS_MOUSE_BUTTON_DOWN;
|
||||
mouseEvent.button = nsMouseEvent::buttonType::eLeftButton;
|
||||
DispatchEventIgnoreStatus(&mouseEvent);
|
||||
mouseEvent = new nsMouseEvent(true,
|
||||
NS_MOUSE_BUTTON_DOWN,
|
||||
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.message = NS_MOUSE_BUTTON_UP;
|
||||
DispatchEventIgnoreStatus(&mouseEvent);
|
||||
mouseEvent = new nsMouseEvent(true,
|
||||
NS_MOUSE_BUTTON_UP,
|
||||
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.
|
||||
// In the Metro environment for any application, a tap does not imply a
|
||||
@ -978,10 +997,15 @@ MetroInput::HandleSingleTap(const LayoutDeviceIntPoint& aPoint)
|
||||
POINT point;
|
||||
if (GetCursorPos(&point)) {
|
||||
ScreenToClient((HWND)mWidget->GetNativeData(NS_NATIVE_WINDOW), &point);
|
||||
mouseEvent.refPoint = LayoutDeviceIntPoint(point.x, point.y);
|
||||
mouseEvent.message = NS_MOUSE_MOVE;
|
||||
mouseEvent.button = 0;
|
||||
DispatchEventIgnoreStatus(&mouseEvent);
|
||||
mouseEvent = new nsMouseEvent(true,
|
||||
NS_MOUSE_MOVE,
|
||||
mWidget.Get(),
|
||||
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();
|
||||
#endif
|
||||
|
||||
nsMouseEvent contextMenu(true,
|
||||
NS_CONTEXTMENU,
|
||||
mWidget.Get(),
|
||||
nsMouseEvent::eReal,
|
||||
nsMouseEvent::eNormal);
|
||||
mModifierKeyState.Update();
|
||||
mModifierKeyState.InitInputEvent(contextMenu);
|
||||
contextMenu.refPoint = aPoint;
|
||||
contextMenu.time = ::GetMessageTime();
|
||||
contextMenu.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH;
|
||||
DispatchEventIgnoreStatus(&contextMenu);
|
||||
nsMouseEvent* contextEvent = new nsMouseEvent(true,
|
||||
NS_CONTEXTMENU,
|
||||
mWidget.Get(),
|
||||
nsMouseEvent::eReal,
|
||||
nsMouseEvent::eNormal);
|
||||
contextEvent->refPoint = aPoint;
|
||||
contextEvent->inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH;
|
||||
DispatchAsyncEventIgnoreStatus(contextEvent);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1011,39 +1032,82 @@ MetroInput::HandleLongTap(const LayoutDeviceIntPoint& aPoint)
|
||||
*/
|
||||
nsEventStatus MetroInput::sThrowawayStatus;
|
||||
|
||||
// This function allows us to call MetroWidget's DispatchEvent function
|
||||
// without passing in a status. It uses a static nsEventStatus whose value
|
||||
// is never read. This allows us to avoid the (admittedly small) overhead
|
||||
// of creating a new nsEventStatus every time we dispatch an event.
|
||||
void
|
||||
MetroInput::DispatchAsyncEventIgnoreStatus(nsInputEvent* aEvent)
|
||||
{
|
||||
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
|
||||
MetroInput::DispatchEventIgnoreStatus(nsGUIEvent *aEvent) {
|
||||
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
|
||||
MetroInput::UnregisterInputEvents() {
|
||||
// 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(mGestureRecognizer,
|
||||
"Must have a GestureRecognizer for input events!");
|
||||
NS_ASSERTION(mDispatcher,
|
||||
"Must have a CoreDispatcher to register for input events!");
|
||||
// Register for edge swipe
|
||||
WRL::ComPtr<UI::Input::IEdgeGestureStatics> edgeStatics;
|
||||
Foundation::GetActivationFactory(
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "nsGUIEvent.h" // mTouchEvent (nsTouchEvent)
|
||||
#include "nsHashKeys.h" // type of key for mTouches
|
||||
#include "mozwrlbase.h"
|
||||
#include "nsDeque.h"
|
||||
|
||||
// System headers (alphabetical)
|
||||
#include <EventToken.h> // EventRegistrationToken
|
||||
@ -44,7 +45,6 @@ namespace ABI {
|
||||
namespace UI {
|
||||
namespace Core {
|
||||
struct ICoreWindow;
|
||||
struct ICoreDispatcher;
|
||||
struct IAcceleratorKeyEventArgs;
|
||||
struct IKeyEventArgs;
|
||||
struct IPointerEventArgs;
|
||||
@ -84,7 +84,6 @@ private:
|
||||
typedef ABI::Windows::UI::Core::ICoreWindow ICoreWindow;
|
||||
typedef ABI::Windows::UI::Core::IAcceleratorKeyEventArgs \
|
||||
IAcceleratorKeyEventArgs;
|
||||
typedef ABI::Windows::UI::Core::ICoreDispatcher ICoreDispatcher;
|
||||
typedef ABI::Windows::UI::Core::IKeyEventArgs IKeyEventArgs;
|
||||
typedef ABI::Windows::UI::Core::IPointerEventArgs IPointerEventArgs;
|
||||
|
||||
@ -105,8 +104,7 @@ private:
|
||||
|
||||
public:
|
||||
MetroInput(MetroWidget* aWidget,
|
||||
ICoreWindow* aWindow,
|
||||
ICoreDispatcher* aDispatcher);
|
||||
ICoreWindow* aWindow);
|
||||
virtual ~MetroInput();
|
||||
|
||||
// These input events are received from our window. These are basic
|
||||
@ -157,7 +155,6 @@ public:
|
||||
private:
|
||||
Microsoft::WRL::ComPtr<ICoreWindow> mWindow;
|
||||
Microsoft::WRL::ComPtr<MetroWidget> mWidget;
|
||||
Microsoft::WRL::ComPtr<ICoreDispatcher> mDispatcher;
|
||||
Microsoft::WRL::ComPtr<IGestureRecognizer> mGestureRecognizer;
|
||||
|
||||
ModifierKeyState mModifierKeyState;
|
||||
@ -168,16 +165,13 @@ private:
|
||||
|
||||
// Event processing helpers. See function definitions for more info.
|
||||
void OnPointerNonTouch(IPointerPoint* aPoint);
|
||||
void InitGeckoMouseEventFromPointerPoint(nsMouseEvent& aEvent,
|
||||
void InitGeckoMouseEventFromPointerPoint(nsMouseEvent* aEvent,
|
||||
IPointerPoint* aPoint);
|
||||
void ProcessManipulationDelta(ManipulationDelta const& aDelta,
|
||||
Point const& aPosition,
|
||||
uint32_t aMagEventType,
|
||||
uint32_t aRotEventType);
|
||||
|
||||
void DispatchEventIgnoreStatus(nsGUIEvent *aEvent);
|
||||
static nsEventStatus sThrowawayStatus;
|
||||
|
||||
// The W3C spec states that "whether preventDefault has been called" should
|
||||
// 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
|
||||
@ -224,10 +218,7 @@ private:
|
||||
// the updated touchpoint info and record the fact that the touchpoint
|
||||
// has changed. If ever we try to update a touchpoint has already
|
||||
// changed, we dispatch a touch event containing all the changed touches.
|
||||
nsEventStatus mTouchEventStatus;
|
||||
nsTouchEvent mTouchEvent;
|
||||
void DispatchPendingTouchEvent(bool aDispatchToAPZC);
|
||||
void DispatchPendingTouchEvent(nsEventStatus& status, bool aDispatchToAPZC);
|
||||
void InitTouchEventTouchList(nsTouchEvent* aEvent);
|
||||
nsBaseHashtable<nsUint32HashKey,
|
||||
nsRefPtr<mozilla::dom::Touch>,
|
||||
nsRefPtr<mozilla::dom::Touch> > mTouches;
|
||||
@ -257,6 +248,34 @@ private:
|
||||
EventRegistrationToken mTokenManipulationCompleted;
|
||||
EventRegistrationToken mTokenTapped;
|
||||
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;
|
||||
};
|
||||
|
||||
} } }
|
||||
|
@ -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
|
||||
LRESULT CALLBACK
|
||||
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.
|
||||
LRESULT processResult = 0;
|
||||
|
||||
MSGResult msgResult(&processResult);
|
||||
MouseScrollHandler::ProcessMessage(this, aMsg, aWParam, aLParam, msgResult);
|
||||
if (msgResult.mConsumed) {
|
||||
return processResult;
|
||||
// We ignore return results from the scroll module and pass everything
|
||||
// to mMetroWndProc. These fall through to winrt handlers that generate
|
||||
// input events in MetroInput. Since we have no listeners for scroll
|
||||
// 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) {
|
||||
@ -604,7 +726,7 @@ MetroWidget::WindowProcedure(HWND aWnd, UINT aMsg, WPARAM aWParam, LPARAM aLPara
|
||||
DeleteObject(rgn);
|
||||
if (region.IsEmpty())
|
||||
break;
|
||||
mView->Render(region);
|
||||
Paint(region);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -624,6 +746,9 @@ MetroWidget::WindowProcedure(HWND aWnd, UINT aMsg, WPARAM aWParam, LPARAM aLPara
|
||||
break;
|
||||
}
|
||||
|
||||
// Keyboard handling is passed to KeyboardLayout, which delivers gecko events
|
||||
// via DispatchKeyboardEvent.
|
||||
|
||||
case WM_KEYDOWN:
|
||||
case WM_SYSKEYDOWN:
|
||||
{
|
||||
@ -983,6 +1108,8 @@ MetroWidget::GetPaintListener()
|
||||
|
||||
void MetroWidget::Paint(const nsIntRegion& aInvalidRegion)
|
||||
{
|
||||
gfxWindowsPlatform::GetPlatform()->UpdateRenderMode();
|
||||
|
||||
nsIWidgetListener* listener = GetPaintListener();
|
||||
if (!listener)
|
||||
return;
|
||||
|
@ -45,6 +45,8 @@ class FrameworkView;
|
||||
|
||||
} } }
|
||||
|
||||
class DispatchMsg;
|
||||
|
||||
class MetroWidget : public nsWindowBase,
|
||||
public mozilla::layers::GeckoContentController,
|
||||
public nsIObserver
|
||||
@ -73,6 +75,8 @@ public:
|
||||
|
||||
// nsWindowBase
|
||||
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 nsWindowBase* GetParentWindowBase(bool aIncludeOwner) MOZ_OVERRIDE { return nullptr; }
|
||||
// InitEvent assumes physical coordinates and is used by shared win32 code. Do
|
||||
@ -248,6 +252,15 @@ protected:
|
||||
mozilla::layers::FrameMetrics mFrameMetrics;
|
||||
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:
|
||||
static nsRefPtr<mozilla::layers::APZCTreeManager> sAPZC;
|
||||
};
|
||||
|
@ -8,7 +8,6 @@ MODULE = 'widget'
|
||||
|
||||
CPP_SOURCES += [
|
||||
'FrameworkView.cpp',
|
||||
'FrameworkViewGfx.cpp',
|
||||
'MetroApp.cpp',
|
||||
'MetroAppShell.cpp',
|
||||
'MetroContracts.cpp',
|
||||
|
Loading…
Reference in New Issue
Block a user