Attachment "0006-Aqua-X11-emulation-support-Retina-window-source.patch" to
ticket [685ac307]
added by
chrstphrchvz
2020-08-18 02:00:14.
From cb4a783dafd197e9caf1ce9361d605f0a33a6ba7 Mon Sep 17 00:00:00 2001
From: Christopher Chavez <[email protected]>
Date: Fri, 14 Aug 2020 08:48:06 -0500
Subject: [PATCH 6/6] Aqua X11 emulation: support Retina window source
Existing programs/libraries expect XGetImage() to return either an
XImage with the requested width and height, or NULL. This means that
a capture of a real window on a Retina display must be downscaled
before being returned by XGetImage() for compatibility.
To support this, a parameter force_1x_scale is added to
TkMacOSXCreateCGImageFromDrawableRect(), which if true will downscale
the returned CGImage to the requested width and height. Otherwise,
capturing a window on a Retina display will return a CGImage having
twice the requested width and height.
If programs should be able to retrieve unscaled captures of windows on
Retina displays, then a separate API is needed. See
https://core.tcl-lang.org/tk/info/fcd6717d8b
Not fully tested. Would be particularly interested in a way to test
XCopyArea() between non-pixmaps. XCopyPlane() might be unfinished.
---
macosx/tkMacOSXDraw.c | 34 +++++++++++++++++++++++++++++++++-
macosx/tkMacOSXImage.c | 2 +-
macosx/tkMacOSXPrivate.h | 1 +
3 files changed, 35 insertions(+), 2 deletions(-)
diff --git macosx/tkMacOSXDraw.c macosx/tkMacOSXDraw.c
index 339a527cf..2d3ef9f17 100644
--- macosx/tkMacOSXDraw.c
+++ macosx/tkMacOSXDraw.c
@@ -123,6 +123,11 @@ TkMacOSXInitCGDrawing(
* with origin at the top left, as used by XImage and CGImage, not bottom
* left as used by NSView.
*
+ * If force_1x_scale is true, then the returned CGImage will be downscaled
+ * if necessary to have the requested width and height. Othewise, for
+ * windows on Retina displays, the width and height of the returned CGImage
+ * will be twice the requested width and height.
+ *
* Side effects:
* If successful, allocates a new CGImage.
*
@@ -132,6 +137,7 @@ TkMacOSXInitCGDrawing(
CGImageRef
TkMacOSXCreateCGImageFromDrawableRect(
Drawable drawable,
+ int force_1x_scale,
int x,
int y,
unsigned int width,
@@ -156,6 +162,9 @@ TkMacOSXCreateCGImageFromDrawableRect(
CGImageRelease(cg_image);
}
} else if ((view = TkMacOSXDrawableView(mac_drawable)) != nil) {
+ int scaleFactor = TkMacOSXNSWindowBackingScaleFactor(
+ [view window]);
+
/*
* Convert Tk top-left to NSView bottom-left coordinates.
*/
@@ -192,6 +201,28 @@ TkMacOSXCreateCGImageFromDrawableRect(
sub_cg_image = [bitmap_rep CGImage];
CGImageRetain(sub_cg_image);
[bitmap_rep release];
+ if (force_1x_scale && (scaleFactor != 1)) {
+ cg_image = sub_cg_image;
+ sub_cg_image = NULL;
+ // See http://blog.foundry376.com/2008/07/scaling-a-cgimage/#comment-200
+ // create context, keeping original image properties
+ CGColorSpaceRef colorspace = CGImageGetColorSpace(cg_image);
+ cg_context = CGBitmapContextCreate(NULL, width, height,
+ CGImageGetBitsPerComponent(cg_image),
+ CGImageGetBytesPerRow(cg_image),
+ colorspace,
+ CGImageGetAlphaInfo(cg_image));
+ CGColorSpaceRelease(colorspace);
+ if (cg_context) {
+ // draw image to context (resizing it)
+ CGContextDrawImage(cg_context, CGRectMake(0, 0, width, height),
+ cg_image);
+ // extract resulting image from context
+ sub_cg_image = CGBitmapContextCreateImage(cg_context);
+ CGContextRelease(cg_context);
+ }
+ CGImageRelease(cg_image);
+ }
} else {
TkMacOSXDbgMsg("Invalid source drawable");
}
@@ -288,7 +319,8 @@ XCopyArea(
return BadDrawable;
}
- img = TkMacOSXCreateCGImageFromDrawableRect(src,
+ // Use unscaled source (TkMacOSXDrawCGImage() will implicitly downscale)
+ img = TkMacOSXCreateCGImageFromDrawableRect(src, 0,
src_x, src_y, width, height);
if (img) {
diff --git macosx/tkMacOSXImage.c macosx/tkMacOSXImage.c
index 0654825a5..855122e69 100644
--- macosx/tkMacOSXImage.c
+++ macosx/tkMacOSXImage.c
@@ -178,7 +178,7 @@ XGetImage(
}
CGImageRef cg_image = TkMacOSXCreateCGImageFromDrawableRect(
- drawable, x, y, width, height);
+ drawable, 1, x, y, width, height);
if (!cg_image) {
TkMacOSXDbgMsg("XGetImage: Failed to get CGImage");
return NULL;
diff --git macosx/tkMacOSXPrivate.h macosx/tkMacOSXPrivate.h
index 2b71434d1..032f7443a 100644
--- macosx/tkMacOSXPrivate.h
+++ macosx/tkMacOSXPrivate.h
@@ -268,6 +268,7 @@ MODULE_SCOPE int TkMacOSXIsWindowZoomed(TkWindow *winPtr);
MODULE_SCOPE int TkGenerateButtonEventForXPointer(Window window);
MODULE_SCOPE EventModifiers TkMacOSXModifierState(void);
MODULE_SCOPE CGImageRef TkMacOSXCreateCGImageFromDrawableRect(Drawable drawable,
+ int force_1x_scale,
int x, int y, unsigned int width, unsigned int height);
MODULE_SCOPE CGImageRef TkMacOSXCreateCGImageWithXImage(XImage *image);
MODULE_SCOPE void TkMacOSXDrawCGImage(Drawable d, GC gc, CGContextRef context,
--
2.28.0