--- a/widget/gtk/nsWindow.cpp
+++ b/widget/gtk/nsWindow.cpp
@@ -118,16 +118,18 @@ extern "C" {
#include "nsShmImage.h"
#include "nsIDOMWheelEvent.h"
#include "NativeKeyBindings.h"
#include "nsWindow.h"
+#include <dlfcn.h>
+
#include "mozilla/layers/APZCTreeManager.h"
using namespace mozilla;
using namespace mozilla::gfx;
using namespace mozilla::widget;
using namespace mozilla::layers;
using mozilla::gl::GLContext;
@@ -468,16 +470,19 @@ nsWindow::DispatchResized(int32_t aWidth
nsresult
nsWindow::DispatchEvent(WidgetGUIEvent* aEvent, nsEventStatus& aStatus)
{
#ifdef DEBUG
debug_DumpEvent(stdout, aEvent->widget, aEvent,
nsAutoCString("something"), 0);
#endif
+ // Translate the mouse event into device pixels.
+ aEvent->refPoint.x = GdkCoordToDevicePixels(aEvent->refPoint.x);
+ aEvent->refPoint.y = GdkCoordToDevicePixels(aEvent->refPoint.y);
aStatus = nsEventStatus_eIgnore;
nsIWidgetListener* listener =
mAttachedWidgetListener ? mAttachedWidgetListener : mWidgetListener;
if (listener) {
aStatus = listener->HandleEvent(aEvent, mUseAttachedEvents);
}
@@ -726,16 +731,22 @@ nsWindow::GetDPI()
double heightInches = DisplayHeightMM(dpy, defaultScreen)/MM_PER_INCH_FLOAT;
if (heightInches < 0.25) {
// Something's broken, but we'd better not crash.
return 96.0f;
}
return float(DisplayHeight(dpy, defaultScreen)/heightInches);
}
+double
+nsWindow::GetDefaultScaleInternal()
+{
+ return GdkScaleFactor();
+}
+
NS_IMETHODIMP
nsWindow::SetParent(nsIWidget *aNewParent)
{
if (mContainer || !mGdkWindow) {
NS_NOTREACHED("nsWindow::SetParent called illegally");
return NS_ERROR_NOT_IMPLEMENTED;
}
@@ -824,18 +835,19 @@ nsWindow::ReparentNativeWidgetInternal(n
SetWidgetForHierarchy(mGdkWindow, aOldContainer, aNewContainer);
if (aOldContainer == gInvisibleContainer) {
CheckDestroyInvisibleContainer();
}
}
if (!mIsTopLevel) {
- gdk_window_reparent(mGdkWindow, aNewParentWindow, mBounds.x,
- mBounds.y);
+ gdk_window_reparent(mGdkWindow, aNewParentWindow,
+ DevicePixelsToGdkCoordRoundDown(mBounds.x),
+ DevicePixelsToGdkCoordRoundDown(mBounds.y));
}
}
nsWindow* newParent = static_cast<nsWindow*>(aNewParent);
bool parentHasMappedToplevel =
newParent && newParent->mHasMappedToplevel;
if (mHasMappedToplevel != parentHasMappedToplevel) {
SetHasMappedToplevel(parentHasMappedToplevel);
@@ -860,52 +872,56 @@ nsWindow::IsVisible() const
{
return mIsShown;
}
NS_IMETHODIMP
nsWindow::ConstrainPosition(bool aAllowSlop, int32_t *aX, int32_t *aY)
{
if (mIsTopLevel && mShell) {
- int32_t screenWidth = gdk_screen_width();
- int32_t screenHeight = gdk_screen_height();
+ int width = GdkCoordToDevicePixels(gdk_screen_width());
+ int height = GdkCoordToDevicePixels(gdk_screen_height());
if (aAllowSlop) {
if (*aX < (kWindowPositionSlop - mBounds.width))
*aX = kWindowPositionSlop - mBounds.width;
- if (*aX > (screenWidth - kWindowPositionSlop))
- *aX = screenWidth - kWindowPositionSlop;
+ if (*aX > (width - kWindowPositionSlop))
+ *aX = width - kWindowPositionSlop;
if (*aY < (kWindowPositionSlop - mBounds.height))
*aY = kWindowPositionSlop - mBounds.height;
- if (*aY > (screenHeight - kWindowPositionSlop))
- *aY = screenHeight - kWindowPositionSlop;
+ if (*aY > (height - kWindowPositionSlop))
+ *aY = height - kWindowPositionSlop;
} else {
if (*aX < 0)
*aX = 0;
- if (*aX > (screenWidth - mBounds.width))
- *aX = screenWidth - mBounds.width;
+ if (*aX > (width - mBounds.width))
+ *aX = width - mBounds.width;
if (*aY < 0)
*aY = 0;
- if (*aY > (screenHeight - mBounds.height))
- *aY = screenHeight - mBounds.height;
+ if (*aY > (height - mBounds.height))
+ *aY = height - mBounds.height;
}
}
return NS_OK;
}
void nsWindow::SetSizeConstraints(const SizeConstraints& aConstraints)
{
mSizeConstraints.mMinSize = GetSafeWindowSize(aConstraints.mMinSize);
mSizeConstraints.mMaxSize = GetSafeWindowSize(aConstraints.mMaxSize);
if (mShell) {
GdkGeometry geometry;
- geometry.min_width = mSizeConstraints.mMinSize.width;
- geometry.min_height = mSizeConstraints.mMinSize.height;
- geometry.max_width = mSizeConstraints.mMaxSize.width;
- geometry.max_height = mSizeConstraints.mMaxSize.height;
+ geometry.min_width = DevicePixelsToGdkCoordRoundUp(
+ mSizeConstraints.mMinSize.width);
+ geometry.min_height = DevicePixelsToGdkCoordRoundUp(
+ mSizeConstraints.mMinSize.height);
+ geometry.max_width = DevicePixelsToGdkCoordRoundDown(
+ mSizeConstraints.mMaxSize.width);
+ geometry.max_height = DevicePixelsToGdkCoordRoundDown(
+ mSizeConstraints.mMaxSize.height);
uint32_t hints = GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE;
gtk_window_set_geometry_hints(GTK_WINDOW(mShell), nullptr,
&geometry, GdkWindowHints(hints));
}
}
NS_IMETHODIMP
@@ -1158,21 +1174,23 @@ nsWindow::Move(double aX, double aY)
mBounds.x = x;
mBounds.y = y;
if (!mCreated)
return NS_OK;
mNeedsMove = false;
+ GdkPoint point = DevicePixelsToGdkPointRoundDown(nsIntPoint(x, y));
+
if (mIsTopLevel) {
- gtk_window_move(GTK_WINDOW(mShell), x, y);
+ gtk_window_move(GTK_WINDOW(mShell), point.x, point.y);
}
else if (mGdkWindow) {
- gdk_window_move(mGdkWindow, x, y);
+ gdk_window_move(mGdkWindow, point.x, point.y);
}
NotifyRollupGeometryChange();
return NS_OK;
}
NS_IMETHODIMP
nsWindow::PlaceBehind(nsTopLevelWidgetZPlacement aPlacement,
@@ -1429,17 +1447,17 @@ nsWindow::SetFocus(bool aRaise)
NS_IMETHODIMP
nsWindow::GetScreenBounds(nsIntRect &aRect)
{
if (mIsTopLevel && mContainer) {
// use the point including window decorations
gint x, y;
gdk_window_get_root_origin(gtk_widget_get_window(GTK_WIDGET(mContainer)), &x, &y);
- aRect.MoveTo(x, y);
+ aRect.MoveTo(GdkPointToDevicePixels({ x, y }));
}
else {
aRect.MoveTo(WidgetToScreenOffset());
}
// mBounds.Size() is the window bounds, not the window-manager frame
// bounds (bug 581863). gdk_window_get_frame_extents would give the
// frame bounds, but mBounds.Size() is returned here for consistency
// with Resize.
@@ -1599,27 +1617,22 @@ nsWindow::SetCursor(imgIContainer* aCurs
}
NS_IMETHODIMP
nsWindow::Invalidate(const nsIntRect &aRect)
{
if (!mGdkWindow)
return NS_OK;
- GdkRectangle rect;
- rect.x = aRect.x;
- rect.y = aRect.y;
- rect.width = aRect.width;
- rect.height = aRect.height;
+ GdkRectangle rect = DevicePixelsToGdkRectRoundOut(aRect);
+ gdk_window_invalidate_rect(mGdkWindow, &rect, FALSE);
LOGDRAW(("Invalidate (rect) [%p]: %d %d %d %d\n", (void *)this,
rect.x, rect.y, rect.width, rect.height));
- gdk_window_invalidate_rect(mGdkWindow, &rect, FALSE);
-
return NS_OK;
}
void*
nsWindow::GetNativeData(uint32_t aDataType)
{
switch (aDataType) {
case NS_NATIVE_WINDOW:
@@ -1747,17 +1760,17 @@ nsIntPoint
nsWindow::WidgetToScreenOffset()
{
gint x = 0, y = 0;
if (mGdkWindow) {
gdk_window_get_origin(mGdkWindow, &x, &y);
}
- return nsIntPoint(x, y);
+ return GdkPointToDevicePixels({ x, y });
}
NS_IMETHODIMP
nsWindow::EnableDragDrop(bool aEnable)
{
return NS_OK;
}
@@ -2039,17 +2052,19 @@ nsWindow::OnExposeEvent(cairo_t *cr)
#if (MOZ_WIDGET_GTK == 2)
if (!exposeRegion.Init(aEvent)) {
#else
if (!exposeRegion.Init(cr)) {
#endif
return FALSE;
}
- nsIntRegion ®ion = exposeRegion.mRegion;
+ gint scale = GdkScaleFactor();
+ nsIntRegion& region = exposeRegion.mRegion;
+ region.ScaleRoundOut(scale, scale);
ClientLayerManager *clientLayers =
(GetLayerManager()->GetBackendType() == LayersBackend::LAYERS_CLIENT)
? static_cast<ClientLayerManager*>(GetLayerManager())
: nullptr;
if (clientLayers && mCompositorParent) {
// We need to paint to the screen even if nothing changed, since if we
@@ -2379,31 +2394,34 @@ nsWindow::OnContainerUnrealize()
void
nsWindow::OnSizeAllocate(GtkAllocation *aAllocation)
{
LOG(("size_allocate [%p] %d %d %d %d\n",
(void *)this, aAllocation->x, aAllocation->y,
aAllocation->width, aAllocation->height));
- nsIntSize size(aAllocation->width, aAllocation->height);
+ nsIntSize size = GdkRectToDevicePixels(*aAllocation).Size();
+
if (mBounds.Size() == size)
return;
+ nsIntRect rect;
+
// Invalidate the new part of the window now for the pending paint to
// minimize background flashes (GDK does not do this for external resizes
// of toplevels.)
if (mBounds.width < size.width) {
- GdkRectangle rect =
- { mBounds.width, 0, size.width - mBounds.width, size.height };
+ GdkRectangle rect = DevicePixelsToGdkRectRoundOut(
+ { mBounds.width, 0, size.width - mBounds.width, size.height });
gdk_window_invalidate_rect(mGdkWindow, &rect, FALSE);
}
if (mBounds.height < size.height) {
- GdkRectangle rect =
- { 0, mBounds.height, size.width, size.height - mBounds.height };
+ GdkRectangle rect = DevicePixelsToGdkRectRoundOut(
+ { 0, mBounds.height, size.width, size.height - mBounds.height });
gdk_window_invalidate_rect(mGdkWindow, &rect, FALSE);
}
mBounds.SizeTo(size);
if (!mGdkWindow)
return;
@@ -3856,67 +3874,75 @@ nsWindow::SetWindowClass(const nsAString
nsMemory::Free(res_name);
return NS_OK;
}
void
nsWindow::NativeResize(int32_t aWidth, int32_t aHeight, bool aRepaint)
{
+ gint width = DevicePixelsToGdkCoordRoundUp(aWidth);
+ gint height = DevicePixelsToGdkCoordRoundUp(aHeight);
+
LOG(("nsWindow::NativeResize [%p] %d %d\n", (void *)this,
- aWidth, aHeight));
+ width, height));
// clear our resize flag
mNeedsResize = false;
if (mIsTopLevel) {
- gtk_window_resize(GTK_WINDOW(mShell), aWidth, aHeight);
+ gtk_window_resize(GTK_WINDOW(mShell), width, height);
}
else if (mContainer) {
GtkWidget *widget = GTK_WIDGET(mContainer);
GtkAllocation allocation, prev_allocation;
gtk_widget_get_allocation(widget, &prev_allocation);
allocation.x = prev_allocation.x;
allocation.y = prev_allocation.y;
- allocation.width = aWidth;
- allocation.height = aHeight;
+ allocation.width = width;
+ allocation.height = height;
gtk_widget_size_allocate(widget, &allocation);
}
else if (mGdkWindow) {
- gdk_window_resize(mGdkWindow, aWidth, aHeight);
+ gdk_window_resize(mGdkWindow, width, height);
}
}
void
nsWindow::NativeResize(int32_t aX, int32_t aY,
int32_t aWidth, int32_t aHeight,
bool aRepaint)
{
+ gint width = DevicePixelsToGdkCoordRoundUp(aWidth);
+ gint height = DevicePixelsToGdkCoordRoundUp(aHeight);
+ gint x = DevicePixelsToGdkCoordRoundDown(aX);
+ gint y = DevicePixelsToGdkCoordRoundDown(aY);
+
mNeedsResize = false;
mNeedsMove = false;
LOG(("nsWindow::NativeResize [%p] %d %d %d %d\n", (void *)this,
- aX, aY, aWidth, aHeight));
+ x, y, width, height));
if (mIsTopLevel) {
- // aX and aY give the position of the window manager frame top-left.
- gtk_window_move(GTK_WINDOW(mShell), aX, aY);
+ // x and y give the position of the window manager frame top-left.
+ gtk_window_move(GTK_WINDOW(mShell), x, y);
// This sets the client window size.
- gtk_window_resize(GTK_WINDOW(mShell), aWidth, aHeight);
+ gtk_window_resize(GTK_WINDOW(mShell), width, height);
}
else if (mContainer) {
GtkAllocation allocation;
- allocation.x = aX;
- allocation.y = aY;
- allocation.width = aWidth;
- allocation.height = aHeight;
+ allocation.x = x;
+ allocation.y = y;
+ allocation.width = width;
+ allocation.height = height;
gtk_widget_size_allocate(GTK_WIDGET(mContainer), &allocation);
}
else if (mGdkWindow) {
- gdk_window_move_resize(mGdkWindow, aX, aY, aWidth, aHeight);
+ gdk_window_move_resize(mGdkWindow, x, y, width, height);
}
}
void
nsWindow::NativeShow(bool aAction)
{
if (aAction) {
// unset our flag now that our window has been shown
@@ -6186,18 +6212,18 @@ nsWindow::GetThebesSurface(cairo_t *cr)
return nullptr;
#ifdef MOZ_X11
gint width, height;
#if (MOZ_WIDGET_GTK == 2)
gdk_drawable_get_size(GDK_DRAWABLE(mGdkWindow), &width, &height);
#else
- width = gdk_window_get_width(mGdkWindow);
- height = gdk_window_get_height(mGdkWindow);
+ width = GdkCoordToDevicePixels(gdk_window_get_width(mGdkWindow));
+ height = GdkCoordToDevicePixels(gdk_window_get_height(mGdkWindow));
#endif
// Owen Taylor says this is the right thing to do!
width = std::min(32767, width);
height = std::min(32767, height);
gfxIntSize size(width, height);
GdkVisual *gdkVisual = gdk_window_get_visual(mGdkWindow);
@@ -6213,35 +6239,21 @@ nsWindow::GetThebesSurface(cairo_t *cr)
nsShmImage::EnsureShmImage(size,
visual, gdk_visual_get_depth(gdkVisual),
mShmImage);
usingShm = mThebesSurface != nullptr;
}
if (!usingShm)
# endif // MOZ_HAVE_SHMIMAGE
{
-#if (MOZ_WIDGET_GTK == 3)
-#if MOZ_TREE_CAIRO
-#error "cairo-gtk3 target must be built with --enable-system-cairo"
-#else
- if (cr) {
- cairo_surface_t *surf = cairo_get_target(cr);
- if (cairo_surface_status(surf) != CAIRO_STATUS_SUCCESS) {
- NS_NOTREACHED("Missing cairo target?");
- return nullptr;
- }
- mThebesSurface = gfxASurface::Wrap(surf);
- } else
-#endif
-#endif // (MOZ_WIDGET_GTK == 3)
- mThebesSurface = new gfxXlibSurface
- (GDK_WINDOW_XDISPLAY(mGdkWindow),
- gdk_x11_window_get_xid(mGdkWindow),
- visual,
- size);
+ mThebesSurface = new gfxXlibSurface
+ (GDK_WINDOW_XDISPLAY(mGdkWindow),
+ gdk_x11_window_get_xid(mGdkWindow),
+ visual,
+ size);
}
#endif // MOZ_X11
// if the surface creation is reporting an error, then
// we don't have a surface to give back
if (mThebesSurface && mThebesSurface->CairoStatus() != 0) {
mThebesSurface = nullptr;
}
@@ -6299,16 +6311,18 @@ nsWindow::BeginMoveDrag(WidgetMouseEvent
GdkWindow *gdk_window;
gint button, screenX, screenY;
if (!GetDragInfo(aEvent, &gdk_window, &button, &screenX, &screenY)) {
return NS_ERROR_FAILURE;
}
// tell the window manager to start the move
+ screenX = DevicePixelsToGdkCoordRoundDown(screenX);
+ screenY = DevicePixelsToGdkCoordRoundDown(screenY);
gdk_window_begin_move_drag(gdk_window, button, screenX, screenY,
aEvent->time);
return NS_OK;
}
NS_IMETHODIMP
nsWindow::BeginResizeDrag(WidgetGUIEvent* aEvent,
@@ -6390,16 +6404,79 @@ nsWindow::ClearCachedResources()
for (GList* list = children; list; list = list->next) {
nsWindow* window = get_window_for_gdk_window(GDK_WINDOW(list->data));
if (window) {
window->ClearCachedResources();
}
}
}
+gint
+nsWindow::GdkScaleFactor()
+{
+#if (MOZ_WIDGET_GTK >= 3)
+ // Available as of GTK 3.10+
+ static auto sGdkWindowGetScaleFactorPtr = (gint (*)(GdkWindow*))
+ dlsym(RTLD_DEFAULT, "gdk_window_get_scale_factor");
+ if (sGdkWindowGetScaleFactorPtr)
+ return (*sGdkWindowGetScaleFactorPtr)(mGdkWindow);
+#endif
+ return 1;
+}
+
+
+gint
+nsWindow::DevicePixelsToGdkCoordRoundUp(int pixels) {
+ gint scale = GdkScaleFactor();
+ return (pixels + scale - 1) / scale;
+}
+
+gint
+nsWindow::DevicePixelsToGdkCoordRoundDown(int pixels) {
+ gint scale = GdkScaleFactor();
+ return pixels / scale;
+}
+
+GdkPoint
+nsWindow::DevicePixelsToGdkPointRoundDown(nsIntPoint point) {
+ gint scale = GdkScaleFactor();
+ return { point.x / scale, point.y / scale };
+}
+
+GdkRectangle
+nsWindow::DevicePixelsToGdkRectRoundOut(nsIntRect rect) {
+ gint scale = GdkScaleFactor();
+ int x = rect.x / scale;
+ int y = rect.y / scale;
+ int right = (rect.x + rect.width + scale - 1) / scale;
+ int bottom = (rect.y + rect.height + scale - 1) / scale;
+ return { x, y, right - x, bottom - y };
+}
+
+int
+nsWindow::GdkCoordToDevicePixels(gint coord) {
+ return coord * GdkScaleFactor();
+}
+
+nsIntPoint
+nsWindow::GdkPointToDevicePixels(GdkPoint point) {
+ gint scale = GdkScaleFactor();
+ return nsIntPoint(point.x * scale,
+ point.y * scale);
+}
+
+nsIntRect
+nsWindow::GdkRectToDevicePixels(GdkRectangle rect) {
+ gint scale = GdkScaleFactor();
+ return nsIntRect(rect.x * scale,
+ rect.y * scale,
+ rect.width * scale,
+ rect.height * scale);
+}
+
nsresult
nsWindow::SynthesizeNativeMouseEvent(nsIntPoint aPoint,
uint32_t aNativeMessage,
uint32_t aModifierFlags)
{
if (!mGdkWindow) {
return NS_OK;
}