mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 975919 - Add support for HiDPI on GTK 3.10+. r=karlt
This commit is contained in:
parent
928ad5250c
commit
b44f7fe3c2
@ -22,6 +22,9 @@
|
||||
#include "gtkdrawing.h"
|
||||
#include "nsStyleConsts.h"
|
||||
#include "gfxFontConstants.h"
|
||||
|
||||
#include <dlfcn.h>
|
||||
|
||||
#include "mozilla/gfx/2D.h"
|
||||
|
||||
using mozilla::LookAndFeel;
|
||||
@ -733,6 +736,16 @@ GetSystemFontInfo(GtkWidget *aWidget,
|
||||
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 auto sGdkScreenGetMonitorScaleFactorPtr = (gint (*)(GdkScreen*,gint))
|
||||
dlsym(RTLD_DEFAULT, "gdk_screen_get_monitor_scale_factor");
|
||||
if (sGdkScreenGetMonitorScaleFactorPtr) {
|
||||
GdkScreen *screen = gdk_screen_get_default();
|
||||
size *= (*sGdkScreenGetMonitorScaleFactorPtr)(screen, 0);
|
||||
}
|
||||
|
||||
// |size| is now pixels
|
||||
|
||||
aFontStyle->size = size;
|
||||
|
@ -123,6 +123,8 @@ extern "C" {
|
||||
#include "NativeKeyBindings.h"
|
||||
#include "nsWindow.h"
|
||||
|
||||
#include <dlfcn.h>
|
||||
|
||||
#include "mozilla/layers/APZCTreeManager.h"
|
||||
|
||||
using namespace mozilla;
|
||||
@ -473,6 +475,9 @@ nsWindow::DispatchEvent(WidgetGUIEvent* aEvent, nsEventStatus& aStatus)
|
||||
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 =
|
||||
@ -731,6 +736,12 @@ nsWindow::GetDPI()
|
||||
return float(DisplayHeight(dpy, defaultScreen)/heightInches);
|
||||
}
|
||||
|
||||
double
|
||||
nsWindow::GetDefaultScaleInternal()
|
||||
{
|
||||
return GdkScaleFactor();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsWindow::SetParent(nsIWidget *aNewParent)
|
||||
{
|
||||
@ -829,8 +840,9 @@ nsWindow::ReparentNativeWidgetInternal(nsIWidget* aNewParent,
|
||||
}
|
||||
|
||||
if (!mIsTopLevel) {
|
||||
gdk_window_reparent(mGdkWindow, aNewParentWindow, mBounds.x,
|
||||
mBounds.y);
|
||||
gdk_window_reparent(mGdkWindow, aNewParentWindow,
|
||||
DevicePixelsToGdkCoordRoundDown(mBounds.x),
|
||||
DevicePixelsToGdkCoordRoundDown(mBounds.y));
|
||||
}
|
||||
}
|
||||
|
||||
@ -865,26 +877,26 @@ 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;
|
||||
@ -897,10 +909,14 @@ void nsWindow::SetSizeConstraints(const SizeConstraints& aConstraints)
|
||||
|
||||
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,
|
||||
@ -1163,11 +1179,13 @@ nsWindow::Move(double aX, double aY)
|
||||
|
||||
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();
|
||||
@ -1434,7 +1452,7 @@ nsWindow::GetScreenBounds(nsIntRect &aRect)
|
||||
// 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());
|
||||
@ -1604,17 +1622,12 @@ 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;
|
||||
}
|
||||
|
||||
@ -1752,7 +1765,7 @@ nsWindow::WidgetToScreenOffset()
|
||||
gdk_window_get_origin(mGdkWindow, &x, &y);
|
||||
}
|
||||
|
||||
return nsIntPoint(x, y);
|
||||
return GdkPointToDevicePixels({ x, y });
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
@ -2044,7 +2057,9 @@ nsWindow::OnExposeEvent(cairo_t *cr)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
nsIntRegion ®ion = exposeRegion.mRegion;
|
||||
gint scale = GdkScaleFactor();
|
||||
nsIntRegion& region = exposeRegion.mRegion;
|
||||
region.ScaleRoundOut(scale, scale);
|
||||
|
||||
ClientLayerManager *clientLayers =
|
||||
(GetLayerManager()->GetBackendType() == LayersBackend::LAYERS_CLIENT)
|
||||
@ -2384,21 +2399,24 @@ nsWindow::OnSizeAllocate(GtkAllocation *aAllocation)
|
||||
(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);
|
||||
}
|
||||
|
||||
@ -3861,14 +3879,17 @@ nsWindow::SetWindowClass(const nsAString &xulWinType)
|
||||
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);
|
||||
@ -3876,12 +3897,12 @@ nsWindow::NativeResize(int32_t aWidth, int32_t aHeight, bool aRepaint)
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3890,28 +3911,33 @@ 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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -6191,8 +6217,8 @@ 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);
|
||||
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!
|
||||
@ -6218,25 +6244,11 @@ 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
|
||||
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
|
||||
|
||||
@ -6304,6 +6316,8 @@ nsWindow::BeginMoveDrag(WidgetMouseEvent* aEvent)
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
||||
@ -6395,6 +6409,69 @@ nsWindow::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,
|
||||
|
@ -97,6 +97,7 @@ public:
|
||||
NS_IMETHOD Destroy(void) MOZ_OVERRIDE;
|
||||
virtual nsIWidget *GetParent() MOZ_OVERRIDE;
|
||||
virtual float GetDPI() MOZ_OVERRIDE;
|
||||
virtual double GetDefaultScaleInternal() MOZ_OVERRIDE;
|
||||
virtual nsresult SetParent(nsIWidget* aNewParent) MOZ_OVERRIDE;
|
||||
NS_IMETHOD SetModal(bool aModal) MOZ_OVERRIDE;
|
||||
virtual bool IsVisible() const MOZ_OVERRIDE;
|
||||
@ -475,6 +476,20 @@ private:
|
||||
* 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 coord);
|
||||
nsIntPoint GdkPointToDevicePixels(GdkPoint point);
|
||||
nsIntRect GdkRectToDevicePixels(GdkRectangle rect);
|
||||
};
|
||||
|
||||
class nsChildWindow : public nsWindow {
|
||||
|
Loading…
Reference in New Issue
Block a user