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 301755 2f909d41108b1d3d3b266a75673c82a28e468b26
parent 301754 9b6a1fffd32622aeef4a9f16a873efe68e63dfe8
child 301756 670b49ddf4e5252ffce174fdbade2ebf888eaa5e
push id6505
push userdburns@mozilla.com
push dateMon, 19 Oct 2015 20:51:25 +0000
reviewerskarlt
bugs978679
milestone44.0a1
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 };