From 1c7268802fac322b28bf88f8b6c68363eb7325c1 Mon Sep 17 00:00:00 2001 From: Bill McCloskey Date: Mon, 26 Oct 2015 13:33:13 -0700 Subject: [PATCH] Bug 1218552 - Fix GTK drag-and-drop coordinate scaling on HiDPI displays (r=karlt) --- widget/gtk/nsDragService.cpp | 25 +++++++++++++++---------- widget/gtk/nsDragService.h | 10 +++++----- widget/gtk/nsWindow.cpp | 12 ++++++++---- widget/gtk/nsWindow.h | 2 +- widget/nsBaseDragService.cpp | 4 ++-- widget/nsBaseDragService.h | 11 +++++++++-- 6 files changed, 40 insertions(+), 24 deletions(-) diff --git a/widget/gtk/nsDragService.cpp b/widget/gtk/nsDragService.cpp index 827563704495..a220b913068a 100644 --- a/widget/gtk/nsDragService.cpp +++ b/widget/gtk/nsDragService.cpp @@ -237,8 +237,12 @@ OnSourceGrabEventAfter(GtkWidget *widget, GdkEvent *event, gpointer user_data) // Update the cursor position. The last of these recorded gets used for // the eDragEnd event. nsDragService *dragService = static_cast(user_data); - dragService->SetDragEndPoint(nsIntPoint(event->motion.x_root, - event->motion.y_root)); + gint scale = nsScreenGtk::GetGtkMonitorScaleFactor(); + LayoutDeviceIntPoint p = { + floor(event->motion.x_root * scale + 0.5), + floor(event->motion.y_root * scale + 0.5) + }; + dragService->SetDragEndPoint(p); } else if (sMotionEvent && (event->type == GDK_KEY_PRESS || event->type == GDK_KEY_RELEASE)) { // Update modifier state from key events. @@ -396,7 +400,7 @@ nsDragService::InvokeDragSessionImpl(nsISupportsArray* aArrayTransferables, G_CALLBACK(OnSourceGrabEventAfter), this); } // We don't have a drag end point yet. - mEndDragPoint = nsIntPoint(-1, -1); + mEndDragPoint = LayoutDeviceIntPoint(-1, -1); rv = NS_OK; } else { @@ -1413,8 +1417,9 @@ nsDragService::SourceEndDragSession(GdkDragContext *aContext, gint x, y; GdkDisplay* display = gdk_display_get_default(); if (display) { + gint scale = nsScreenGtk::GetGtkMonitorScaleFactor(); gdk_display_get_pointer(display, nullptr, &x, &y, nullptr); - SetDragEndPoint(nsIntPoint(x, y)); + SetDragEndPoint(LayoutDeviceIntPoint(x * scale, y * scale)); } } @@ -1462,7 +1467,7 @@ nsDragService::SourceEndDragSession(GdkDragContext *aContext, } // Schedule the appropriate drag end dom events. - Schedule(eDragTaskSourceEnd, nullptr, nullptr, nsIntPoint(), 0); + Schedule(eDragTaskSourceEnd, nullptr, nullptr, LayoutDeviceIntPoint(), 0); } static void @@ -1783,7 +1788,7 @@ invisibleSourceDragEnd(GtkWidget *aWidget, gboolean nsDragService::ScheduleMotionEvent(nsWindow *aWindow, GdkDragContext *aDragContext, - nsIntPoint aWindowPoint, guint aTime) + LayoutDeviceIntPoint aWindowPoint, guint aTime) { if (mScheduledTask == eDragTaskMotion) { // The drag source has sent another motion message before we've @@ -1806,7 +1811,7 @@ nsDragService::ScheduleLeaveEvent() // We don't know at this stage whether a drop signal will immediately // follow. If the drop signal gets sent it will happen before we return // to the main loop and the scheduled leave task will be replaced. - if (!Schedule(eDragTaskLeave, nullptr, nullptr, nsIntPoint(), 0)) { + if (!Schedule(eDragTaskLeave, nullptr, nullptr, LayoutDeviceIntPoint(), 0)) { NS_WARNING("Drag leave after drop"); } } @@ -1814,7 +1819,7 @@ nsDragService::ScheduleLeaveEvent() gboolean nsDragService::ScheduleDropEvent(nsWindow *aWindow, GdkDragContext *aDragContext, - nsIntPoint aWindowPoint, guint aTime) + LayoutDeviceIntPoint aWindowPoint, guint aTime) { if (!Schedule(eDragTaskDrop, aWindow, aDragContext, aWindowPoint, aTime)) { @@ -1822,7 +1827,7 @@ nsDragService::ScheduleDropEvent(nsWindow *aWindow, return FALSE; } - SetDragEndPoint(aWindowPoint + aWindow->WidgetToScreenOffsetUntyped()); + SetDragEndPoint(aWindowPoint + aWindow->WidgetToScreenOffset()); // We'll reply with gtk_drag_finish(). return TRUE; @@ -1831,7 +1836,7 @@ nsDragService::ScheduleDropEvent(nsWindow *aWindow, gboolean nsDragService::Schedule(DragTask aTask, nsWindow *aWindow, GdkDragContext *aDragContext, - nsIntPoint aWindowPoint, guint aTime) + LayoutDeviceIntPoint aWindowPoint, guint aTime) { // If there is an existing leave or motion task scheduled, then that // will be replaced. When the new task is run, it will dispatch diff --git a/widget/gtk/nsDragService.h b/widget/gtk/nsDragService.h index 162986f09848..1850d2059385 100644 --- a/widget/gtk/nsDragService.h +++ b/widget/gtk/nsDragService.h @@ -96,12 +96,12 @@ public: gboolean ScheduleMotionEvent(nsWindow *aWindow, GdkDragContext *aDragContext, - nsIntPoint aWindowPoint, + mozilla::LayoutDeviceIntPoint aWindowPoint, guint aTime); void ScheduleLeaveEvent(); gboolean ScheduleDropEvent(nsWindow *aWindow, GdkDragContext *aDragContext, - nsIntPoint aWindowPoint, + mozilla::LayoutDeviceIntPoint aWindowPoint, guint aTime); nsWindow* GetMostRecentDestWindow() @@ -154,7 +154,7 @@ private: // when the scheduled task is run. mPendingWindow and mPendingDragContext // will be nullptr if the scheduled task is eDragTaskLeave. RefPtr mPendingWindow; - nsIntPoint mPendingWindowPoint; + mozilla::LayoutDeviceIntPoint mPendingWindowPoint; nsCountedRef mPendingDragContext; guint mPendingTime; @@ -162,7 +162,7 @@ private: // eDragTaskMotion or eDragTaskDrop task that was run or is still running. // mTargetWindow is cleared once the drag has completed or left. RefPtr mTargetWindow; - nsIntPoint mTargetWindowPoint; + mozilla::LayoutDeviceIntPoint mTargetWindowPoint; // mTargetWidget and mTargetDragContext are set only while dispatching // motion or drop events. mTime records the corresponding timestamp. nsCountedRef mTargetWidget; @@ -210,7 +210,7 @@ private: gboolean Schedule(DragTask aTask, nsWindow *aWindow, GdkDragContext *aDragContext, - nsIntPoint aWindowPoint, guint aTime); + mozilla::LayoutDeviceIntPoint aWindowPoint, guint aTime); // Callback for g_idle_add_full() to run mScheduledTask. static gboolean TaskDispatchCallback(gpointer data); diff --git a/widget/gtk/nsWindow.cpp b/widget/gtk/nsWindow.cpp index 0a56db4948b8..8fd401ce5c34 100644 --- a/widget/gtk/nsWindow.cpp +++ b/widget/gtk/nsWindow.cpp @@ -3331,7 +3331,7 @@ nsWindow::ThemeChanged() } void -nsWindow::DispatchDragEvent(EventMessage aMsg, const nsIntPoint& aRefPoint, +nsWindow::DispatchDragEvent(EventMessage aMsg, const LayoutDeviceIntPoint& aRefPoint, guint aTime) { WidgetDragEvent event(true, aMsg, this); @@ -3340,7 +3340,7 @@ nsWindow::DispatchDragEvent(EventMessage aMsg, const nsIntPoint& aRefPoint, InitDragEvent(event); } - event.refPoint = LayoutDeviceIntPoint::FromUntyped(aRefPoint); + event.refPoint = aRefPoint; event.time = aTime; event.timeStamp = GetEventTimeStamp(aTime); @@ -5978,9 +5978,11 @@ drag_motion_event_cb(GtkWidget *aWidget, LOGDRAG(("nsWindow drag-motion signal for %p\n", (void*)innerMostWindow)); + LayoutDeviceIntPoint point = window->GdkPointToDevicePixels({ retx, rety }); + return nsDragService::GetInstance()-> ScheduleMotionEvent(innerMostWindow, aDragContext, - nsIntPoint(retx, rety), aTime); + point, aTime); } static void @@ -6048,9 +6050,11 @@ drag_drop_event_cb(GtkWidget *aWidget, LOGDRAG(("nsWindow drag-drop signal for %p\n", (void*)innerMostWindow)); + LayoutDeviceIntPoint point = window->GdkPointToDevicePixels({ retx, rety }); + return nsDragService::GetInstance()-> ScheduleDropEvent(innerMostWindow, aDragContext, - nsIntPoint(retx, rety), aTime); + point, aTime); } static void diff --git a/widget/gtk/nsWindow.h b/widget/gtk/nsWindow.h index e3765e2f3e4d..02e0dddc802d 100644 --- a/widget/gtk/nsWindow.h +++ b/widget/gtk/nsWindow.h @@ -269,7 +269,7 @@ public: bool IsDestroyed() { return mIsDestroyed; } void DispatchDragEvent(mozilla::EventMessage aMsg, - const nsIntPoint& aRefPoint, + const mozilla::LayoutDeviceIntPoint& aRefPoint, guint aTime); static void UpdateDragStatus (GdkDragContext *aDragContext, nsIDragService *aDragService); diff --git a/widget/nsBaseDragService.cpp b/widget/nsBaseDragService.cpp index aed2b8b8ad17..ddddb4f141a5 100644 --- a/widget/nsBaseDragService.cpp +++ b/widget/nsBaseDragService.cpp @@ -217,7 +217,7 @@ nsBaseDragService::InvokeDragSession(nsIDOMNode *aDOMNode, // stash the document of the dom node aDOMNode->GetOwnerDocument(getter_AddRefs(mSourceDocument)); mSourceNode = aDOMNode; - mEndDragPoint = nsIntPoint(0, 0); + mEndDragPoint = LayoutDeviceIntPoint(0, 0); // When the mouse goes down, the selection code starts a mouse // capture. However, this gets in the way of determining drag @@ -413,7 +413,7 @@ nsBaseDragService::EndDragSession(bool aDoneDrag) mImageOffset = CSSIntPoint(); mScreenX = -1; mScreenY = -1; - mEndDragPoint = nsIntPoint(0, 0); + mEndDragPoint = LayoutDeviceIntPoint(0, 0); mInputSource = nsIDOMMouseEvent::MOZ_SOURCE_MOUSE; return NS_OK; diff --git a/widget/nsBaseDragService.h b/widget/nsBaseDragService.h index 0502869b588b..74fed11e994e 100644 --- a/widget/nsBaseDragService.h +++ b/widget/nsBaseDragService.h @@ -54,7 +54,14 @@ public: NS_DECL_NSIDRAGSERVICE NS_DECL_NSIDRAGSESSION - void SetDragEndPoint(nsIntPoint aEndDragPoint) { mEndDragPoint = aEndDragPoint; } + void SetDragEndPoint(nsIntPoint aEndDragPoint) + { + mEndDragPoint = mozilla::LayoutDeviceIntPoint::FromUntyped(aEndDragPoint); + } + void SetDragEndPoint(mozilla::LayoutDeviceIntPoint aEndDragPoint) + { + mEndDragPoint = aEndDragPoint; + } uint16_t GetInputSource() { return mInputSource; } @@ -171,7 +178,7 @@ protected: int32_t mScreenY; // the screen position where the drag ended - nsIntPoint mEndDragPoint; + mozilla::LayoutDeviceIntPoint mEndDragPoint; uint32_t mSuppressLevel;