Bug 978679 - Implement touch events for GTK3. r=karlt
☠☠ backed out by 56ffd8412250 ☠ ☠
authorMakato Kato <m_kato@ga2.so-net.ne.jp>
Mon, 19 Oct 2015 23:04:52 +1300
changeset 303531 2f909d41108b1d3d3b266a75673c82a28e468b26
parent 303530 9b6a1fffd32622aeef4a9f16a873efe68e63dfe8
child 303532 670b49ddf4e5252ffce174fdbade2ebf888eaa5e
push id1001
push userraliiev@mozilla.com
push dateMon, 18 Jan 2016 19:06:03 +0000
treeherdermozilla-release@8b89261f3ac4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskarlt
bugs978679
milestone44.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 978679 - Implement touch events for GTK3. r=karlt
dom/events/DataTransfer.cpp
dom/events/DataTransfer.h
dom/events/TouchEvent.cpp
dom/mobilemessage/android/SmsManager.cpp
modules/libpref/init/all.js
widget/WidgetUtils.cpp
widget/gtk/WidgetUtilsGtk.cpp
widget/gtk/WidgetUtilsGtk.h
widget/gtk/moz.build
widget/gtk/mozgtk/mozgtk.c
widget/gtk/nsLookAndFeel.cpp
widget/gtk/nsWindow.cpp
widget/gtk/nsWindow.h
widget/nsBaseWidget.cpp
widget/nsBaseWidget.h
widget/windows/nsWindow.cpp
widget/windows/nsWindow.h
--- a/dom/events/DataTransfer.cpp
+++ b/dom/events/DataTransfer.cpp
@@ -26,16 +26,17 @@
 #include "nsVariant.h"
 #include "mozilla/dom/ContentChild.h"
 #include "mozilla/dom/DataTransferBinding.h"
 #include "mozilla/dom/Directory.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/FileList.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/OSFileSystem.h"
+#include "mozilla/dom/Promise.h"
 
 namespace mozilla {
 namespace dom {
 
 inline void
 ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
                             TransferItem& aField,
                             const char* aName,
--- a/dom/events/DataTransfer.h
+++ b/dom/events/DataTransfer.h
@@ -15,32 +15,32 @@
 #include "nsIDOMElement.h"
 #include "nsIDragService.h"
 #include "nsCycleCollectionParticipant.h"
 
 #include "nsAutoPtr.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/EventForwards.h"
 #include "mozilla/dom/File.h"
-#include "mozilla/dom/Promise.h"
 
 class nsINode;
 class nsITransferable;
 class nsISupportsArray;
 class nsILoadContext;
 
 namespace mozilla {
 
 class EventStateManager;
 
 namespace dom {
 
 class DOMStringList;
 class Element;
 class FileList;
+class Promise;
 template<typename T> class Optional;
 
 /**
  * TransferItem is used to hold data for a particular format. Each piece of
  * data has a principal set from the caller which added it. This allows a
  * caller that wishes to retrieve the data to only be able to access the data
  * it is allowed to, yet still allow a chrome caller to retrieve any of the
  * data.
--- a/dom/events/TouchEvent.cpp
+++ b/dom/events/TouchEvent.cpp
@@ -181,20 +181,20 @@ TouchEvent::ChangedTouches()
 // static
 bool
 TouchEvent::PrefEnabled(JSContext* aCx, JSObject* aGlobal)
 {
   bool prefValue = false;
   int32_t flag = 0;
   if (NS_SUCCEEDED(Preferences::GetInt("dom.w3c_touch_events.enabled", &flag))) {
     if (flag == 2) {
-#ifdef XP_WIN
+#if defined(XP_WIN) || MOZ_WIDGET_GTK == 3
       static bool sDidCheckTouchDeviceSupport = false;
       static bool sIsTouchDeviceSupportPresent = false;
-      // On Windows we auto-detect based on device support.
+      // On Windows and GTK3 we auto-detect based on device support.
       if (!sDidCheckTouchDeviceSupport) {
         sDidCheckTouchDeviceSupport = true;
         sIsTouchDeviceSupportPresent = WidgetUtils::IsTouchDeviceSupportPresent();
       }
       prefValue = sIsTouchDeviceSupportPresent;
 #else
       NS_WARNING("dom.w3c_touch_events.enabled=2 not implemented!");
       prefValue = false;
--- a/dom/mobilemessage/android/SmsManager.cpp
+++ b/dom/mobilemessage/android/SmsManager.cpp
@@ -10,16 +10,17 @@
 #include "mozilla/dom/mobilemessage/SmsParent.h"
 #include "mozilla/dom/mobilemessage/SmsTypes.h"
 #include "mozilla/dom/mobilemessage/Types.h"
 #include "mozilla/dom/MobileMessageThread.h"
 #include "mozilla/dom/SmsMessage.h"
 #include "mozilla/Services.h"
 #include "nsIMobileMessageDatabaseService.h"
 #include "nsIObserverService.h"
+#include "nsThreadUtils.h"
 
 using namespace mozilla::dom;
 using namespace mozilla::dom::mobilemessage;
 
 namespace mozilla {
 
 /*static*/
 void
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -4525,21 +4525,25 @@ pref("dom.push.http2.retryInterval", 500
 // WebNetworkStats
 pref("dom.mozNetworkStats.enabled", false);
 
 // WebSettings
 pref("dom.mozSettings.enabled", false);
 pref("dom.mozPermissionSettings.enabled", false);
 
 // W3C touch events
-// 0 - disabled, 1 - enabled, 2 - autodetect (win)
+// 0 - disabled, 1 - enabled, 2 - autodetect (win/gtk3)
 #ifdef XP_WIN
 pref("dom.w3c_touch_events.enabled", 2);
 #endif
 
+#if MOZ_WIDGET_GTK == 3
+pref("dom.w3c_touch_events.enabled", 2);
+#endif
+
 // W3C draft pointer events
 pref("dom.w3c_pointer_events.enabled", false);
 
 // W3C draft ImageCapture API
 pref("dom.imagecapture.enabled", false);
 
 // W3C touch-action css property (related to touch and pointer events)
 pref("layout.css.touch_action.enabled", false);
--- a/widget/WidgetUtils.cpp
+++ b/widget/WidgetUtils.cpp
@@ -3,16 +3,18 @@
  */
 /* 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 "mozilla/WidgetUtils.h"
 #ifdef XP_WIN
 #include "WinUtils.h"
+#elif MOZ_WIDGET_GTK == 3
+#include "mozilla/WidgetUtilsGtk.h"
 #endif
 
 namespace mozilla {
 
 gfx::Matrix
 ComputeTransformForRotation(const nsIntRect& aBounds,
                               ScreenRotation aRotation)
 {
@@ -95,15 +97,17 @@ nsIntRect RotateRect(nsIntRect aRect,
 
 namespace widget {
 
 uint32_t
 WidgetUtils::IsTouchDeviceSupportPresent()
 {
 #ifdef XP_WIN
   return WinUtils::IsTouchDeviceSupportPresent();
+#elif MOZ_WIDGET_GTK == 3
+  return WidgetUtilsGTK::IsTouchDeviceSupportPresent();
 #else
   return 0;
 #endif
 }
 
 } // namespace widget
 } // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/widget/gtk/WidgetUtilsGtk.cpp
@@ -0,0 +1,47 @@
+/* -*- Mode: C++; tab-width: 2; 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 "WidgetUtilsGtk.h"
+
+namespace mozilla {
+
+namespace widget {
+
+int32_t WidgetUtilsGTK::IsTouchDeviceSupportPresent()
+{
+    int32_t result = 0;
+    GdkDisplay* display = gdk_display_get_default();
+    if (!display) {
+        return 0;
+    }
+
+    GdkDeviceManager* manager = gdk_display_get_device_manager(display);
+    if (!manager) {
+        return 0;
+    }
+
+    GList* devices =
+        gdk_device_manager_list_devices(manager, GDK_DEVICE_TYPE_SLAVE);
+    GList* list = devices;
+
+    while (devices) {
+        GdkDevice* device = static_cast<GdkDevice*>(devices->data);
+        if (gdk_device_get_source(device) == GDK_SOURCE_TOUCHSCREEN) {
+            result = 1;
+            break;
+        }
+        devices = devices->next;
+   }
+
+   if (list) {
+       g_list_free(list);
+   }
+
+   return result;
+}
+
+}  // namespace widget
+
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/widget/gtk/WidgetUtilsGtk.h
@@ -0,0 +1,25 @@
+/* -*- Mode: C++; tab-width: 2; 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/. */
+
+#ifndef WidgetUtilsGtk_h__
+#define WidgetUtilsGtk_h__
+
+#include <stdint.h>
+
+namespace mozilla {
+namespace widget {
+
+class WidgetUtilsGTK
+{
+public:
+  /* See WidgetUtils::IsTouchDeviceSupportPresent(). */
+  static int32_t IsTouchDeviceSupportPresent();
+};
+
+}  // namespace widget
+
+}  // namespace mozilla
+
+#endif // WidgetUtilsGtk_h__
--- a/widget/gtk/moz.build
+++ b/widget/gtk/moz.build
@@ -8,16 +8,20 @@ if CONFIG['MOZ_ENABLE_GTK3']:
     DIRS += ['mozgtk']
 
 EXPORTS += [
     'mozcontainer.h',
     'nsGTKToolkit.h',
     'nsIImageToPixbuf.h',
 ]
 
+EXPORTS.mozilla += [
+    'WidgetUtilsGtk.h'
+]
+
 UNIFIED_SOURCES += [
     'IMContextWrapper.cpp',
     'mozcontainer.c',
     'NativeKeyBindings.cpp',
     'nsAppShell.cpp',
     'nsBidiKeyboard.cpp',
     'nsColorPicker.cpp',
     'nsFilePicker.cpp',
@@ -27,16 +31,17 @@ UNIFIED_SOURCES += [
     'nsNativeThemeGTK.cpp',
     'nsScreenGtk.cpp',
     'nsScreenManagerGtk.cpp',
     'nsSound.cpp',
     'nsToolkit.cpp',
     'nsWidgetFactory.cpp',
     'WakeLockListener.cpp',
     'WidgetTraceEvent.cpp',
+    'WidgetUtilsGtk.cpp',
 ]
 
 SOURCES += [
     'nsWindow.cpp', # conflicts with X11 headers
 ]
 
 if CONFIG['MOZ_X11']:
     UNIFIED_SOURCES += [
--- a/widget/gtk/mozgtk/mozgtk.c
+++ b/widget/gtk/mozgtk/mozgtk.c
@@ -501,16 +501,17 @@ STUB(gtk_window_set_type_hint)
 STUB(gtk_window_set_wmclass)
 STUB(gtk_window_unfullscreen)
 STUB(gtk_window_unmaximize)
 #endif
 
 #ifdef GTK3_SYMBOLS
 STUB(gdk_device_get_source)
 STUB(gdk_device_manager_get_client_pointer)
+STUB(gdk_device_manager_list_devices)
 STUB(gdk_disable_multidevice)
 STUB(gdk_display_get_device_manager)
 STUB(gdk_error_trap_pop_ignored)
 STUB(gdk_event_get_source_device)
 STUB(gdk_window_get_type)
 STUB(gdk_x11_window_get_xid)
 STUB(gdk_x11_display_get_type)
 STUB(gtk_cairo_should_draw_window)
--- a/widget/gtk/nsLookAndFeel.cpp
+++ b/widget/gtk/nsLookAndFeel.cpp
@@ -18,16 +18,17 @@
 
 #include <fontconfig/fontconfig.h>
 #include "gfxPlatformGtk.h"
 #include "nsScreenGtk.h"
 
 #include "gtkdrawing.h"
 #include "nsStyleConsts.h"
 #include "gfxFontConstants.h"
+#include "WidgetUtilsGtk.h"
 
 #include <dlfcn.h>
 
 #include "mozilla/gfx/2D.h"
 
 using mozilla::LookAndFeel;
 
 #define GDK_COLOR_TO_NS_RGB(c) \
@@ -629,18 +630,23 @@ nsLookAndFeel::GetIntImpl(IntID aID, int
     case eIntID_WindowsClassic:
     case eIntID_WindowsDefaultTheme:
     case eIntID_WindowsThemeIdentifier:
     case eIntID_OperatingSystemVersionIdentifier:
         aResult = 0;
         res = NS_ERROR_NOT_IMPLEMENTED;
         break;
     case eIntID_TouchEnabled:
+#if MOZ_WIDGET_GTK == 3
+        aResult = mozilla::widget::WidgetUtilsGTK::IsTouchDeviceSupportPresent();
+        break;
+#else
         aResult = 0;
         res = NS_ERROR_NOT_IMPLEMENTED;
+#endif
         break;
     case eIntID_MacGraphiteTheme:
     case eIntID_MacLionTheme:
         aResult = 0;
         res = NS_ERROR_NOT_IMPLEMENTED;
         break;
     case eIntID_AlertNotificationOrigin:
         aResult = NS_ALERT_TOP;
--- a/widget/gtk/nsWindow.cpp
+++ b/widget/gtk/nsWindow.cpp
@@ -1,19 +1,21 @@
 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* vim:expandtab:shiftwidth=4:tabstop=4:
  */
 /* 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 "mozilla/ArrayUtils.h"
+#include "mozilla/EventForwards.h"
 #include "mozilla/MiscEvents.h"
 #include "mozilla/MouseEvents.h"
 #include "mozilla/TextEvents.h"
+#include "mozilla/TouchEvents.h"
 #include <algorithm>
 
 #include "GeckoProfiler.h"
 
 #include "prlink.h"
 #include "nsGTKToolkit.h"
 #include "nsIRollupListener.h"
 #include "nsIDOMNode.h"
@@ -137,19 +139,18 @@ using mozilla::gl::GLContext;
 // Don't put more than this many rects in the dirty region, just fluff
 // out to the bounding-box if there are more
 #define MAX_RECTS_IN_REGION 100
 
 const gint kEvents = GDK_EXPOSURE_MASK | GDK_STRUCTURE_MASK |
                      GDK_VISIBILITY_NOTIFY_MASK |
                      GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK |
                      GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
-#if GTK_CHECK_VERSION(3,4,0)
                      GDK_SMOOTH_SCROLL_MASK |
-#endif
+                     GDK_TOUCH_MASK |
                      GDK_SCROLL_MASK |
                      GDK_POINTER_MOTION_MASK |
                      GDK_PROPERTY_CHANGE_MASK;
 
 /* utility functions */
 static bool       is_mouse_in_window(GdkWindow* aWindow,
                                      gdouble aMouseX, gdouble aMouseY);
 static nsWindow  *get_window_for_gtk_widget(GtkWidget *widget);
@@ -209,16 +210,18 @@ static gboolean visibility_notify_event_
                                            GdkEventVisibility *event);
 static void     hierarchy_changed_cb      (GtkWidget *widget,
                                            GtkWidget *previous_toplevel);
 static gboolean window_state_event_cb     (GtkWidget *widget,
                                            GdkEventWindowState *event);
 static void     theme_changed_cb          (GtkSettings *settings,
                                            GParamSpec *pspec,
                                            nsWindow *data);
+static gboolean touch_event_cb            (GtkWidget* aWidget,
+                                           GdkEventTouch* aEvent);
 static nsWindow* GetFirstNSWindowForGDKWindow (GdkWindow *aGdkWindow);
 
 #ifdef __cplusplus
 extern "C" {
 #endif /* __cplusplus */
 #ifdef MOZ_X11
 static GdkFilterReturn popup_take_focus_filter (GdkXEvent *gdk_xevent,
                                                 GdkEvent *event,
@@ -403,16 +406,17 @@ nsWindow::nsWindow()
 {
     mIsTopLevel          = false;
     mIsDestroyed         = false;
     mListenForResizes    = false;
     mIsShown             = false;
     mNeedsShow           = false;
     mEnabled             = true;
     mCreated             = false;
+    mHandleTouchEvent    = false;
 
     mContainer           = nullptr;
     mGdkWindow           = nullptr;
     mShell               = nullptr;
     mPluginNativeWindow  = nullptr;
     mHasMappedToplevel   = false;
     mIsFullyObscured     = false;
     mRetryPointerGrab    = false;
@@ -445,19 +449,18 @@ nsWindow::nsWindow()
 #endif
 
     mIsTransparent = false;
     mTransparencyBitmap = nullptr;
 
     mTransparencyBitmapWidth  = 0;
     mTransparencyBitmapHeight = 0;
 
-#if GTK_CHECK_VERSION(3,4,0)
     mLastScrollEventTime = GDK_CURRENT_TIME;
-#endif
+    mTouchCounter = 0;
 }
 
 nsWindow::~nsWindow()
 {
     LOG(("nsWindow::~nsWindow() [%p]\n", (void *)this));
 
     delete[] mTransparencyBitmap;
     mTransparencyBitmap = nullptr;
@@ -915,16 +918,23 @@ nsWindow::SetModal(bool aModal)
 
 // nsIWidget method, which means IsShown.
 bool
 nsWindow::IsVisible() const
 {
     return mIsShown;
 }
 
+void
+nsWindow::RegisterTouchWindow()
+{
+    mHandleTouchEvent = true;
+    mTouches.Clear();
+}
+
 NS_IMETHODIMP
 nsWindow::ConstrainPosition(bool aAllowSlop, int32_t *aX, int32_t *aY)
 {
     if (!mIsTopLevel || !mShell)  
       return NS_OK;
 
     double dpiScale = GetDefaultScale().scale;
 
@@ -3120,26 +3130,23 @@ nsWindow::OnKeyReleaseEvent(GdkEventKey 
 }
 
 void
 nsWindow::OnScrollEvent(GdkEventScroll *aEvent)
 {
     // check to see if we should rollup
     if (CheckForRollup(aEvent->x_root, aEvent->y_root, true, false))
         return;
-#if GTK_CHECK_VERSION(3,4,0)
     // check for duplicate legacy scroll event, see GNOME bug 726878
     if (aEvent->direction != GDK_SCROLL_SMOOTH &&
         mLastScrollEventTime == aEvent->time)
         return; 
-#endif
     WidgetWheelEvent wheelEvent(true, eWheel, this);
     wheelEvent.deltaMode = nsIDOMWheelEvent::DOM_DELTA_LINE;
     switch (aEvent->direction) {
-#if GTK_CHECK_VERSION(3,4,0)
     case GDK_SCROLL_SMOOTH:
     {
         // As of GTK 3.4, all directional scroll events are provided by
         // the GDK_SCROLL_SMOOTH direction on XInput2 devices.
         mLastScrollEventTime = aEvent->time;
         // TODO - use a more appropriate scrolling unit than lines.
         // Multiply event deltas by 3 to emulate legacy behaviour.
         wheelEvent.deltaX = aEvent->delta_x * 3;
@@ -3151,17 +3158,16 @@ nsWindow::OnScrollEvent(GdkEventScroll *
         GdkDevice *device = gdk_event_get_source_device((GdkEvent*)aEvent);
         GdkInputSource source = gdk_device_get_source(device);
         if (source == GDK_SOURCE_TOUCHSCREEN ||
             source == GDK_SOURCE_TOUCHPAD) {
             wheelEvent.scrollType = WidgetWheelEvent::SCROLL_ASYNCHRONOUSELY;
         }
         break;
     }
-#endif
     case GDK_SCROLL_UP:
         wheelEvent.deltaY = wheelEvent.lineOrPageDeltaY = -3;
         break;
     case GDK_SCROLL_DOWN:
         wheelEvent.deltaY = wheelEvent.lineOrPageDeltaY = 3;
         break;
     case GDK_SCROLL_LEFT:
         wheelEvent.deltaX = wheelEvent.lineOrPageDeltaX = -1;
@@ -3348,16 +3354,88 @@ nsWindow::OnDragDataReceivedEvent(GtkWid
 {
     LOGDRAG(("nsWindow::OnDragDataReceived(%p)\n", (void*)this));
 
     nsDragService::GetInstance()->
         TargetDataReceived(aWidget, aDragContext, aX, aY,
                            aSelectionData, aInfo, aTime);
 }
 
+static
+PLDHashOperator
+EnumTouchToAppend(GdkEventSequence* aKey, RefPtr<dom::Touch> aData, void* aArg)
+{
+  WidgetTouchEvent* event = reinterpret_cast<WidgetTouchEvent*>(aArg);
+  event->touches.AppendElement(aData);
+
+  return PL_DHASH_NEXT;
+}
+
+gboolean
+nsWindow::OnTouchEvent(GdkEventTouch* aEvent)
+{
+    if (!mHandleTouchEvent) {
+        return FALSE;
+    }
+
+    EventMessage msg;
+
+    switch (aEvent->type) {
+    case GDK_TOUCH_BEGIN:
+        msg = eTouchStart;
+        break;
+    case GDK_TOUCH_UPDATE:
+        msg = eTouchMove;
+        break;
+    case GDK_TOUCH_END:
+        msg = eTouchEnd;
+        break;
+    case GDK_TOUCH_CANCEL:
+        msg = eTouchCancel;
+        break;
+    default:
+        return FALSE;
+    }
+
+    LayoutDeviceIntPoint touchPoint;
+    if (aEvent->window == mGdkWindow) {
+        touchPoint = LayoutDeviceIntPoint(aEvent->x, aEvent->y);
+    } else {
+        touchPoint = LayoutDeviceIntPoint(aEvent->x_root, aEvent->y_root) -
+                     WidgetToScreenOffset();
+    }
+
+    RefPtr<dom::Touch> touch;
+    int32_t id;
+    if (mTouches.Get(aEvent->sequence, &touch)) {
+        id = touch->mIdentifier;
+        mTouches.Remove(aEvent->sequence);
+    } else {
+        id = ++mTouchCounter & 0x7FFFFFFF;
+    }
+
+    touch = new dom::Touch(id, touchPoint, nsIntPoint(1,1), 0.0f, 0.0f);
+    WidgetTouchEvent event(true, msg, this);
+    KeymapWrapper::InitInputEvent(event, aEvent->state);
+    event.time = aEvent->time;
+
+    if (aEvent->type == GDK_TOUCH_BEGIN || aEvent->type == GDK_TOUCH_UPDATE) {
+        mTouches.Put(aEvent->sequence, touch);
+        // add all touch points to event object
+        mTouches.EnumerateRead(EnumTouchToAppend, &event);
+    } else if (aEvent->type == GDK_TOUCH_END ||
+               aEvent->type == GDK_TOUCH_CANCEL) {
+        event.touches.AppendElement(touch);
+    }
+
+    nsEventStatus status;
+    DispatchEvent(&event, status);
+    return TRUE;
+}
+
 static void
 GetBrandName(nsXPIDLString& brandName)
 {
     nsCOMPtr<nsIStringBundleService> bundleService =
         do_GetService(NS_STRINGBUNDLE_CONTRACTID);
 
     nsCOMPtr<nsIStringBundle> bundle;
     if (bundleService)
@@ -3814,16 +3892,18 @@ nsWindow::Create(nsIWidget        *aPare
         g_signal_connect(eventWidget, "button-press-event",
                          G_CALLBACK(button_press_event_cb), nullptr);
         g_signal_connect(eventWidget, "button-release-event",
                          G_CALLBACK(button_release_event_cb), nullptr);
         g_signal_connect(eventWidget, "property-notify-event",
                          G_CALLBACK(property_notify_event_cb), nullptr);
         g_signal_connect(eventWidget, "scroll-event",
                          G_CALLBACK(scroll_event_cb), nullptr);
+        g_signal_connect(eventWidget, "touch-event",
+                         G_CALLBACK(touch_event_cb), nullptr);
     }
 
     LOG(("nsWindow [%p]\n", (void *)this));
     if (mShell) {
         LOG(("\tmShell %p mContainer %p mGdkWindow %p 0x%lx\n",
              mShell, mContainer, mGdkWindow,
              gdk_x11_window_get_xid(mGdkWindow)));
     } else if (mContainer) {
@@ -5839,16 +5919,29 @@ window_state_event_cb (GtkWidget *widget
 
 static void
 theme_changed_cb (GtkSettings *settings, GParamSpec *pspec, nsWindow *data)
 {
     RefPtr<nsWindow> window = data;
     window->ThemeChanged();
 }
 
+static gboolean
+touch_event_cb(GtkWidget* aWidget, GdkEventTouch* aEvent)
+{
+    UpdateLastInputEventTime(aEvent);
+
+    nsWindow* window = GetFirstNSWindowForGDKWindow(aEvent->window);
+    if (!window) {
+        return FALSE;
+    }
+
+    return window->OnTouchEvent(aEvent);
+}
+
 //////////////////////////////////////////////////////////////////////
 // These are all of our drag and drop operations
 
 void
 nsWindow::InitDragEvent(WidgetDragEvent &aEvent)
 {
     // set the keyboard modifiers
     guint modifierState = KeymapWrapper::GetCurrentModifierState();
@@ -6690,34 +6783,30 @@ nsWindow::SynthesizeNativeMouseScrollEve
   event.scroll.y_root = aPoint.y;
 
   LayoutDeviceIntPoint pointInWindow = aPoint - WidgetToScreenOffset();
   event.scroll.x = pointInWindow.x;
   event.scroll.y = pointInWindow.y;
 
   // The delta values are backwards on Linux compared to Windows and Cocoa,
   // hence the negation.
-#if GTK_CHECK_VERSION(3,4,0)
-  // TODO: is this correct? I don't have GTK 3.4+ so I can't check
   event.scroll.direction = GDK_SCROLL_SMOOTH;
   event.scroll.delta_x = -aDeltaX;
   event.scroll.delta_y = -aDeltaY;
-#else
   if (aDeltaX < 0) {
     event.scroll.direction = GDK_SCROLL_RIGHT;
   } else if (aDeltaX > 0) {
     event.scroll.direction = GDK_SCROLL_LEFT;
   } else if (aDeltaY < 0) {
     event.scroll.direction = GDK_SCROLL_DOWN;
   } else if (aDeltaY > 0) {
     event.scroll.direction = GDK_SCROLL_UP;
   } else {
     return NS_OK;
   }
-#endif
 
   gdk_event_put(&event);
 
   return NS_OK;
 }
 
 int32_t
 nsWindow::RoundsWidgetCoordinatesTo()
--- a/widget/gtk/nsWindow.h
+++ b/widget/gtk/nsWindow.h
@@ -25,16 +25,17 @@
 #ifdef MOZ_X11
 #include <gdk/gdkx.h>
 #endif /* MOZ_X11 */
 
 #ifdef ACCESSIBILITY
 #include "mozilla/a11y/Accessible.h"
 #endif
 #include "mozilla/EventForwards.h"
+#include "mozilla/TouchEvents.h"
 
 #include "IMContextWrapper.h"
 
 #undef LOG
 #ifdef MOZ_LOGGING
 
 #include "mozilla/Logging.h"
 #include "nsTArray.h"
@@ -202,16 +203,17 @@ public:
                                                gint             aX,
                                                gint             aY,
                                                GtkSelectionData*aSelectionData,
                                                guint            aInfo,
                                                guint            aTime,
                                                gpointer         aData);
     gboolean           OnPropertyNotifyEvent(GtkWidget *aWidget,
                                              GdkEventProperty *aEvent);
+    gboolean           OnTouchEvent(GdkEventTouch* aEvent);
 
     virtual already_AddRefed<mozilla::gfx::DrawTarget>
                        StartRemoteDrawingInRegion(nsIntRegion& aInvalidRegion) override;
     virtual void       EndRemoteDrawingInRegion(mozilla::gfx::DrawTarget* aDrawTarget,
                                                 nsIntRegion& aInvalidRegion) override;
 
 private:
     void               UpdateAlpha(gfxPattern* aPattern, nsIntRect aBoundsRect);
@@ -342,31 +344,35 @@ protected:
     void ReparentNativeWidgetInternal(nsIWidget* aNewParent,
                                       GtkWidget* aNewContainer,
                                       GdkWindow* aNewParentWindow,
                                       GtkWidget* aOldContainer);
 
     virtual nsresult NotifyIMEInternal(
                          const IMENotification& aIMENotification) override;
 
+    virtual void RegisterTouchWindow() override;
+
     nsCOMPtr<nsIWidget> mParent;
     // Is this a toplevel window?
     bool                mIsTopLevel;
     // Has this widget been destroyed yet?
     bool                mIsDestroyed;
 
     // Should we send resize events on all resizes?
     bool                mListenForResizes;
     // This flag tracks if we're hidden or shown.
     bool                mIsShown;
     bool                mNeedsShow;
     // is this widget enabled?
     bool                mEnabled;
     // has the native window for this been created yet?
     bool                mCreated;
+    // whether we handle touch event
+    bool                mHandleTouchEvent;
 
 private:
     void               DestroyChildWindows();
     GtkWidget         *GetToplevelWidget();
     nsWindow          *GetContainerWindow();
     void               SetUrgencyHint(GtkWidget *top_window, bool state);
     void              *SetupPluginPort(void);
     void               SetDefaultIcon(void);
@@ -391,20 +397,22 @@ private:
     nsSizeMode          mSizeState;
     PluginType          mPluginType;
 
     int32_t             mTransparencyBitmapWidth;
     int32_t             mTransparencyBitmapHeight;
 
     nsIntPoint          mClientOffset;
 
-#if GTK_CHECK_VERSION(3,4,0)
     // This field omits duplicate scroll events caused by GNOME bug 726878.
     guint32             mLastScrollEventTime;
-#endif
+
+    // for touch event handling
+    nsDataHashtable<nsPtrHashKey<GdkEventSequence>, RefPtr<mozilla::dom::Touch> > mTouches;
+    uint32_t            mTouchCounter;
 
 #ifdef MOZ_X11
     Display*            mXDisplay;
     Drawable            mXWindow;
     Visual*             mXVisual;
     int                 mXDepth;
 #endif
 
--- a/widget/nsBaseWidget.cpp
+++ b/widget/nsBaseWidget.cpp
@@ -905,16 +905,24 @@ void nsBaseWidget::ConfigureAPZCTreeMana
         aInputBlockId, aFlags));
   };
 
   RefPtr<GeckoContentController> controller = CreateRootContentController();
   if (controller) {
     uint64_t rootLayerTreeId = mCompositorParent->RootLayerTreeId();
     CompositorParent::SetControllerForLayerTree(rootLayerTreeId, controller);
   }
+
+  // When APZ is enabled, we can actually enable raw touch events because we
+  // have code that can deal with them properly. If APZ is not enabled, this
+  // function doesn't get called.
+  if (Preferences::GetInt("dom.w3c_touch_events.enabled", 0) ||
+      Preferences::GetBool("dom.w3c_pointer_events.enabled", false)) {
+    RegisterTouchWindow();
+  }
 }
 
 void nsBaseWidget::ConfigureAPZControllerThread()
 {
   // By default the controller thread is the main thread.
   APZThreadUtils::SetControllerThread(MessageLoop::current());
 }
 
--- a/widget/nsBaseWidget.h
+++ b/widget/nsBaseWidget.h
@@ -468,16 +468,17 @@ protected:
   }
 
   virtual CompositorChild* GetRemoteRenderer() override;
 
   /**
    * Notify the widget that this window is being used with OMTC.
    */
   virtual void WindowUsesOMTC() {}
+  virtual void RegisterTouchWindow() {}
 
   nsIDocument* GetDocument() const;
 
 protected:
   /**
    * Starts the OMTC compositor destruction sequence.
    *
    * When this function returns, the compositor should not be 
--- a/widget/windows/nsWindow.cpp
+++ b/widget/windows/nsWindow.cpp
@@ -1324,35 +1324,20 @@ void nsWindow::SetThemeRegion()
 }
 
 /**************************************************************
  *
  * SECTION: Touch and APZ-related functions
  *
  **************************************************************/
 
-void nsWindow::ConfigureAPZCTreeManager()
-{
-  nsBaseWidget::ConfigureAPZCTreeManager();
-
-  // When APZ is enabled, we can actually enable raw touch events because we
-  // have code that can deal with them properly. If APZ is not enabled, this
-  // function doesn't get called, and |mGesture| will take care of touch-based
-  // scrolling. Note that RegisterTouchWindow may still do nothing depending
-  // on touch events prefs, and so it is possible to enable APZ without
-  // also enabling touch support.
-  RegisterTouchWindow();
-}
-
 void nsWindow::RegisterTouchWindow() {
-  if (Preferences::GetInt("dom.w3c_touch_events.enabled", 0)) {
-    mTouchWindow = true;
-    mGesture.RegisterTouchWindow(mWnd);
-    ::EnumChildWindows(mWnd, nsWindow::RegisterTouchForDescendants, 0);
-  }
+  mTouchWindow = true;
+  mGesture.RegisterTouchWindow(mWnd);
+  ::EnumChildWindows(mWnd, nsWindow::RegisterTouchForDescendants, 0);
 }
 
 BOOL CALLBACK nsWindow::RegisterTouchForDescendants(HWND aWnd, LPARAM aMsg) {
   nsWindow* win = WinUtils::GetNSWindowPtr(aWnd);
   if (win)
     win->mGesture.RegisterTouchWindow(aWnd);
   return TRUE;
 }
--- a/widget/windows/nsWindow.h
+++ b/widget/windows/nsWindow.h
@@ -292,18 +292,17 @@ public:
   virtual bool ShouldUseOffMainThreadCompositing();
 
   bool CaptureWidgetOnScreen(RefPtr<mozilla::gfx::DrawTarget> aDT);
 
 protected:
   virtual ~nsWindow();
 
   virtual void WindowUsesOMTC() override;
-  virtual void ConfigureAPZCTreeManager() override;
-  void RegisterTouchWindow();
+  virtual void RegisterTouchWindow() override;
 
   virtual nsresult NotifyIMEInternal(
                      const IMENotification& aIMENotification) override;
 
   // A magic number to identify the FAKETRACKPOINTSCROLLABLE window created
   // when the trackpoint hack is enabled.
   enum { eFakeTrackPointScrollableID = 0x46545053 };