799 lines
26 KiB
Diff
799 lines
26 KiB
Diff
|
# HG changeset patch
|
||
|
# Parent 7b33ee7fd162d784f382250d3fa811e86a1b7348
|
||
|
# User Andrew Comminos <andrew@morlunk.com>
|
||
|
Bug 975919 - Added support for HiDPI on GTK 3.10+
|
||
|
|
||
|
diff --git a/widget/gtk/nsGtkUtils.h b/widget/gtk/nsGtkUtils.h
|
||
|
--- a/widget/gtk/nsGtkUtils.h
|
||
|
+++ b/widget/gtk/nsGtkUtils.h
|
||
|
@@ -4,16 +4,17 @@
|
||
|
/* 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 nsGtkUtils_h__
|
||
|
#define nsGtkUtils_h__
|
||
|
|
||
|
#include <glib.h>
|
||
|
+#include <dlfcn.h>
|
||
|
|
||
|
// Some gobject functions expect functions for gpointer arguments.
|
||
|
// gpointer is void* but C++ doesn't like casting functions to void*.
|
||
|
template<class T> static inline gpointer
|
||
|
FuncToGpointer(T aFunction)
|
||
|
{
|
||
|
return reinterpret_cast<gpointer>
|
||
|
(reinterpret_cast<uintptr_t>
|
||
|
diff --git a/widget/gtk/nsLookAndFeel.cpp b/widget/gtk/nsLookAndFeel.cpp
|
||
|
--- a/widget/gtk/nsLookAndFeel.cpp
|
||
|
+++ b/widget/gtk/nsLookAndFeel.cpp
|
||
|
@@ -728,16 +728,27 @@ GetSystemFontInfo(GtkWidget *aWidget,
|
||
|
|
||
|
// |size| is now either pixels or pango-points (not Mozilla-points!)
|
||
|
|
||
|
if (!pango_font_description_get_size_is_absolute(desc)) {
|
||
|
// |size| is in pango-points, so convert to pixels.
|
||
|
size *= float(gfxPlatformGtk::GetDPI()) / POINTS_PER_INCH_FLOAT;
|
||
|
}
|
||
|
|
||
|
+ // Scale fonts up on HiDPI displays.
|
||
|
+ // This would be done automatically with cairo, but we manually manage
|
||
|
+ // the display scale for platform consistency.
|
||
|
+ static gint (*GdkScreenGetMonitorScaleFactorPtr)(GdkScreen*,gint) =
|
||
|
+ (gint (*)(GdkScreen*,gint)) dlsym(RTLD_DEFAULT,
|
||
|
+ "gdk_screen_get_monitor_scale_factor");
|
||
|
+ if (GdkScreenGetMonitorScaleFactorPtr) {
|
||
|
+ GdkScreen *screen = gdk_screen_get_default();
|
||
|
+ size *= (*GdkScreenGetMonitorScaleFactorPtr)(screen, 0);
|
||
|
+ }
|
||
|
+
|
||
|
// |size| is now pixels
|
||
|
|
||
|
aFontStyle->size = size;
|
||
|
|
||
|
pango_font_description_free(desc);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
diff --git a/widget/gtk/nsScreenGtk.cpp b/widget/gtk/nsScreenGtk.cpp
|
||
|
--- a/widget/gtk/nsScreenGtk.cpp
|
||
|
+++ b/widget/gtk/nsScreenGtk.cpp
|
||
|
@@ -6,20 +6,20 @@
|
||
|
#include "nsScreenGtk.h"
|
||
|
|
||
|
#include <gdk/gdk.h>
|
||
|
#ifdef MOZ_X11
|
||
|
#include <gdk/gdkx.h>
|
||
|
#include <X11/Xatom.h>
|
||
|
#endif
|
||
|
#include <gtk/gtk.h>
|
||
|
+#include <dlfcn.h>
|
||
|
|
||
|
static uint32_t sScreenId = 0;
|
||
|
|
||
|
-
|
||
|
nsScreenGtk :: nsScreenGtk ( )
|
||
|
: mScreenNum(0),
|
||
|
mRect(0, 0, 0, 0),
|
||
|
mAvailRect(0, 0, 0, 0),
|
||
|
mId(++sScreenId)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
@@ -35,37 +35,68 @@ nsScreenGtk :: GetId(uint32_t *aId)
|
||
|
*aId = mId;
|
||
|
return NS_OK;
|
||
|
} // GetId
|
||
|
|
||
|
|
||
|
NS_IMETHODIMP
|
||
|
nsScreenGtk :: GetRect(int32_t *outLeft, int32_t *outTop, int32_t *outWidth, int32_t *outHeight)
|
||
|
{
|
||
|
+ double scale;
|
||
|
+ GetContentsScaleFactor(&scale);
|
||
|
+
|
||
|
+ *outLeft = NSToIntRound(mRect.x * scale);
|
||
|
+ *outTop = NSToIntRound(mRect.y * scale);
|
||
|
+ *outWidth = NSToIntRound(mRect.width * scale);
|
||
|
+ *outHeight = NSToIntRound(mRect.height * scale);
|
||
|
+
|
||
|
+ return NS_OK;
|
||
|
+
|
||
|
+} // GetRect
|
||
|
+
|
||
|
+
|
||
|
+NS_IMETHODIMP
|
||
|
+nsScreenGtk :: GetAvailRect(int32_t *outLeft, int32_t *outTop, int32_t *outWidth, int32_t *outHeight)
|
||
|
+{
|
||
|
+ double scale;
|
||
|
+ GetContentsScaleFactor(&scale);
|
||
|
+
|
||
|
+ *outLeft = NSToIntRound(mAvailRect.x * scale);
|
||
|
+ *outTop = NSToIntRound(mAvailRect.y * scale);
|
||
|
+ *outWidth = NSToIntRound(mAvailRect.width * scale);
|
||
|
+ *outHeight = NSToIntRound(mAvailRect.height * scale);
|
||
|
+
|
||
|
+ return NS_OK;
|
||
|
+
|
||
|
+} // GetAvailRect
|
||
|
+
|
||
|
+NS_IMETHODIMP
|
||
|
+nsScreenGtk :: GetRectDisplayPix(int32_t *outLeft, int32_t *outTop, int32_t *outWidth, int32_t *outHeight)
|
||
|
+{
|
||
|
*outLeft = mRect.x;
|
||
|
*outTop = mRect.y;
|
||
|
*outWidth = mRect.width;
|
||
|
*outHeight = mRect.height;
|
||
|
|
||
|
return NS_OK;
|
||
|
|
||
|
-} // GetRect
|
||
|
+} // GetRectDisplayPix
|
||
|
|
||
|
|
||
|
NS_IMETHODIMP
|
||
|
-nsScreenGtk :: GetAvailRect(int32_t *outLeft, int32_t *outTop, int32_t *outWidth, int32_t *outHeight)
|
||
|
+nsScreenGtk :: GetAvailRectDisplayPix(int32_t *outLeft, int32_t *outTop, int32_t *outWidth, int32_t *outHeight)
|
||
|
{
|
||
|
*outLeft = mAvailRect.x;
|
||
|
*outTop = mAvailRect.y;
|
||
|
*outWidth = mAvailRect.width;
|
||
|
*outHeight = mAvailRect.height;
|
||
|
|
||
|
return NS_OK;
|
||
|
|
||
|
-} // GetAvailRect
|
||
|
+} // GetAvailRectDisplayPix
|
||
|
|
||
|
|
||
|
NS_IMETHODIMP
|
||
|
nsScreenGtk :: GetPixelDepth(int32_t *aPixelDepth)
|
||
|
{
|
||
|
GdkVisual * visual = gdk_screen_get_system_visual(gdk_screen_get_default());
|
||
|
*aPixelDepth = gdk_visual_get_depth(visual);
|
||
|
|
||
|
@@ -77,16 +108,33 @@ nsScreenGtk :: GetPixelDepth(int32_t *aP
|
||
|
NS_IMETHODIMP
|
||
|
nsScreenGtk :: GetColorDepth(int32_t *aColorDepth)
|
||
|
{
|
||
|
return GetPixelDepth ( aColorDepth );
|
||
|
|
||
|
} // GetColorDepth
|
||
|
|
||
|
|
||
|
+NS_IMETHODIMP
|
||
|
+nsScreenGtk :: GetContentsScaleFactor(double* aContentsScaleFactor)
|
||
|
+{
|
||
|
+ static gint (*GdkScreenGetMonitorScaleFactorPtr)(GdkScreen*,gint) =
|
||
|
+ (gint (*)(GdkScreen*,gint)) dlsym(RTLD_DEFAULT,
|
||
|
+ "gdk_screen_get_monitor_scale_factor");
|
||
|
+ if (GdkScreenGetMonitorScaleFactorPtr) {
|
||
|
+ GdkScreen *screen = gdk_screen_get_default();
|
||
|
+ *aContentsScaleFactor = (*GdkScreenGetMonitorScaleFactorPtr)
|
||
|
+ (screen, mScreenNum);
|
||
|
+ } else {
|
||
|
+ *aContentsScaleFactor = 1;
|
||
|
+ }
|
||
|
+ return NS_OK;
|
||
|
+}
|
||
|
+
|
||
|
+
|
||
|
void
|
||
|
nsScreenGtk :: Init (GdkWindow *aRootWindow)
|
||
|
{
|
||
|
// We listen for configure events on the root window to pick up
|
||
|
// changes to this rect. We could listen for "size_changed" signals
|
||
|
// on the default screen to do this, except that doesn't work with
|
||
|
// versions of GDK predating the GdkScreen object. See bug 256646.
|
||
|
mAvailRect = mRect = nsIntRect(0, 0, gdk_screen_width(), gdk_screen_height());
|
||
|
diff --git a/widget/gtk/nsScreenGtk.h b/widget/gtk/nsScreenGtk.h
|
||
|
--- a/widget/gtk/nsScreenGtk.h
|
||
|
+++ b/widget/gtk/nsScreenGtk.h
|
||
|
@@ -28,18 +28,21 @@ class nsScreenGtk : public nsBaseScreen
|
||
|
{
|
||
|
public:
|
||
|
nsScreenGtk();
|
||
|
~nsScreenGtk();
|
||
|
|
||
|
NS_IMETHOD GetId(uint32_t* aId);
|
||
|
NS_IMETHOD GetRect(int32_t* aLeft, int32_t* aTop, int32_t* aWidth, int32_t* aHeight);
|
||
|
NS_IMETHOD GetAvailRect(int32_t* aLeft, int32_t* aTop, int32_t* aWidth, int32_t* aHeight);
|
||
|
+ NS_IMETHOD GetRectDisplayPix(int32_t* aLeft, int32_t* aTop, int32_t* aWidth, int32_t* aHeight);
|
||
|
+ NS_IMETHOD GetAvailRectDisplayPix(int32_t* aLeft, int32_t* aTop, int32_t* aWidth, int32_t* aHeight);
|
||
|
NS_IMETHOD GetPixelDepth(int32_t* aPixelDepth);
|
||
|
NS_IMETHOD GetColorDepth(int32_t* aColorDepth);
|
||
|
+ NS_IMETHOD GetContentsScaleFactor(double* aContentsScaleFactor);
|
||
|
|
||
|
void Init(GdkWindow *aRootWindow);
|
||
|
#ifdef MOZ_X11
|
||
|
void Init(XineramaScreenInfo *aScreenInfo);
|
||
|
#endif /* MOZ_X11 */
|
||
|
|
||
|
private:
|
||
|
uint32_t mScreenNum;
|
||
|
diff --git a/widget/gtk/nsWindow.cpp b/widget/gtk/nsWindow.cpp
|
||
|
--- a/widget/gtk/nsWindow.cpp
|
||
|
+++ b/widget/gtk/nsWindow.cpp
|
||
|
@@ -466,16 +466,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);
|
||
|
}
|
||
|
|
||
|
@@ -724,16 +727,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;
|
||
|
}
|
||
|
|
||
|
@@ -822,18 +831,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);
|
||
|
@@ -858,52 +868,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 = DevicePixelsToGdkCoordRoundUp(
|
||
|
+ mSizeConstraints.mMaxSize.width);
|
||
|
+ geometry.max_height = DevicePixelsToGdkCoordRoundUp(
|
||
|
+ 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
|
||
|
@@ -1156,21 +1170,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,
|
||
|
@@ -1427,17 +1443,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.
|
||
|
@@ -1597,27 +1613,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:
|
||
|
@@ -1745,17 +1756,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;
|
||
|
}
|
||
|
|
||
|
@@ -2037,17 +2048,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
|
||
|
@@ -2377,31 +2390,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;
|
||
|
|
||
|
@@ -3843,67 +3859,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
|
||
|
@@ -6178,18 +6202,18 @@ nsWindow::GetThebesSurface(cairo_t *cr)
|
||
|
#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);
|
||
|
#endif
|
||
|
|
||
|
// Owen Taylor says this is the right thing to do!
|
||
|
- width = std::min(32767, width);
|
||
|
- height = std::min(32767, height);
|
||
|
+ width = std::min(32767, (int)std::ceil(GdkCoordToDevicePixels(width)));
|
||
|
+ height = std::min(32767, (int)std::ceil(GdkCoordToDevicePixels(height)));
|
||
|
gfxIntSize size(width, height);
|
||
|
|
||
|
GdkVisual *gdkVisual = gdk_window_get_visual(mGdkWindow);
|
||
|
Visual* visual = gdk_x11_visual_get_xvisual(gdkVisual);
|
||
|
|
||
|
# ifdef MOZ_HAVE_SHMIMAGE
|
||
|
bool usingShm = false;
|
||
|
if (nsShmImage::UseShm()) {
|
||
|
@@ -6204,18 +6228,27 @@ nsWindow::GetThebesSurface(cairo_t *cr)
|
||
|
}
|
||
|
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
|
||
|
+ // Available as of Cairo 1.14
|
||
|
+ static void (*CairoSurfaceSetDeviceScalePtr) (cairo_surface_t*,double,double) =
|
||
|
+ (void (*)(cairo_surface_t*,double,double)) dlsym(RTLD_DEFAULT,
|
||
|
+ "cairo_surface_set_device_scale");
|
||
|
+
|
||
|
if (cr) {
|
||
|
cairo_surface_t *surf = cairo_get_target(cr);
|
||
|
+ if (GdkScaleFactor() > 1) {
|
||
|
+ // Disable auto-scaling on HiDPI devices, let mozilla manage it.
|
||
|
+ (*CairoSurfaceSetDeviceScalePtr)(surf, 1, 1);
|
||
|
+ }
|
||
|
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)
|
||
|
@@ -6286,16 +6319,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,
|
||
|
@@ -6377,16 +6412,80 @@ 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 gint (*GdkWindowGetScaleFactorPtr) (GdkWindow*) =
|
||
|
+ (gint (*)(GdkWindow*)) dlsym(RTLD_DEFAULT,
|
||
|
+ "gdk_window_get_scale_factor");
|
||
|
+ if (GdkWindowGetScaleFactorPtr)
|
||
|
+ return (*GdkWindowGetScaleFactorPtr)(mGdkWindow);
|
||
|
+#endif
|
||
|
+ return 1;
|
||
|
+}
|
||
|
+
|
||
|
+
|
||
|
+gint
|
||
|
+nsWindow::DevicePixelsToGdkCoordRoundUp(int pixels) {
|
||
|
+ return NSToIntCeil(float(pixels)/float(GdkScaleFactor()));
|
||
|
+}
|
||
|
+
|
||
|
+gint
|
||
|
+nsWindow::DevicePixelsToGdkCoordRoundDown(int pixels) {
|
||
|
+ return NSToIntFloor(float(pixels)/float(GdkScaleFactor()));
|
||
|
+}
|
||
|
+
|
||
|
+GdkPoint
|
||
|
+nsWindow::DevicePixelsToGdkPointRoundDown(nsIntPoint point) {
|
||
|
+ float scale = GdkScaleFactor();
|
||
|
+ return { NSToIntFloor(float(point.x)/scale),
|
||
|
+ NSToIntFloor(float(point.y)/scale) };
|
||
|
+}
|
||
|
+
|
||
|
+GdkRectangle
|
||
|
+nsWindow::DevicePixelsToGdkRectRoundOut(nsIntRect rect) {
|
||
|
+ gint scale = GdkScaleFactor();
|
||
|
+ nsIntRect scaledRect = rect;
|
||
|
+ scaledRect.ScaleInverseRoundOut(scale);
|
||
|
+ return { scaledRect.x,
|
||
|
+ scaledRect.y,
|
||
|
+ scaledRect.width,
|
||
|
+ scaledRect.height };
|
||
|
+}
|
||
|
+
|
||
|
+int
|
||
|
+nsWindow::GdkCoordToDevicePixels(gint coords) {
|
||
|
+ return coords * 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;
|
||
|
}
|
||
|
diff --git a/widget/gtk/nsWindow.h b/widget/gtk/nsWindow.h
|
||
|
--- a/widget/gtk/nsWindow.h
|
||
|
+++ b/widget/gtk/nsWindow.h
|
||
|
@@ -92,16 +92,17 @@ public:
|
||
|
NS_IMETHOD Create(nsIWidget *aParent,
|
||
|
nsNativeWidget aNativeParent,
|
||
|
const nsIntRect &aRect,
|
||
|
nsDeviceContext *aContext,
|
||
|
nsWidgetInitData *aInitData);
|
||
|
NS_IMETHOD Destroy(void);
|
||
|
virtual nsIWidget *GetParent();
|
||
|
virtual float GetDPI();
|
||
|
+ virtual double GetDefaultScaleInternal();
|
||
|
virtual nsresult SetParent(nsIWidget* aNewParent);
|
||
|
NS_IMETHOD SetModal(bool aModal);
|
||
|
virtual bool IsVisible() const;
|
||
|
NS_IMETHOD ConstrainPosition(bool aAllowSlop,
|
||
|
int32_t *aX,
|
||
|
int32_t *aY);
|
||
|
virtual void SetSizeConstraints(const SizeConstraints& aConstraints);
|
||
|
NS_IMETHOD Move(double aX,
|
||
|
@@ -468,16 +469,30 @@ private:
|
||
|
* The instance is created when the top level widget is created. And when
|
||
|
* the widget is destroyed, it's released. All child windows refer its
|
||
|
* ancestor widget's instance. So, one set of IM contexts is created for
|
||
|
* all windows in a hierarchy. If the children are released after the top
|
||
|
* level window is released, the children still have a valid pointer,
|
||
|
* however, IME doesn't work at that time.
|
||
|
*/
|
||
|
nsRefPtr<nsGtkIMModule> mIMModule;
|
||
|
+
|
||
|
+ // HiDPI scale conversion
|
||
|
+ gint GdkScaleFactor();
|
||
|
+
|
||
|
+ // To GDK
|
||
|
+ gint DevicePixelsToGdkCoordRoundUp(int pixels);
|
||
|
+ gint DevicePixelsToGdkCoordRoundDown(int pixels);
|
||
|
+ GdkPoint DevicePixelsToGdkPointRoundDown(nsIntPoint point);
|
||
|
+ GdkRectangle DevicePixelsToGdkRectRoundOut(nsIntRect rect);
|
||
|
+
|
||
|
+ // From GDK
|
||
|
+ int GdkCoordToDevicePixels(gint coords);
|
||
|
+ nsIntPoint GdkPointToDevicePixels(GdkPoint point);
|
||
|
+ nsIntRect GdkRectToDevicePixels(GdkRectangle rect);
|
||
|
};
|
||
|
|
||
|
class nsChildWindow : public nsWindow {
|
||
|
public:
|
||
|
nsChildWindow();
|
||
|
~nsChildWindow();
|
||
|
};
|
||
|
|