commit 1e3d72d962b8b736741747a5ec4595e08965ef49 (HEAD, refs/remotes/origin/master) Author: Michael Albinus Date: Tue Nov 5 15:57:42 2024 +0100 Several Tramp cleanups * lisp/net/tramp-adb.el (tramp-adb-maybe-open-connection): Move setting of sentinel up. * lisp/net/tramp-cache.el (tramp-get-connection-property) (tramp-set-connection-property): Don't raise a debug message for the `tramp-cache-version' key. * lisp/net/tramp.el (tramp-convert-file-attributes): Don't cache "file-attributes-ID-FORMAT". * test/lisp/net/tramp-tests.el (tramp--test-enabled): Cleanup also `tramp-compat-temporary-file-directory'. (tramp-test32-shell-command): Use `async-shell-command-width' of 512. (tramp-test36-vc-registered): Remove double let* entry. diff --git a/lisp/net/tramp-adb.el b/lisp/net/tramp-adb.el index 72b37b894cc..83d9ebb6c63 100644 --- a/lisp/net/tramp-adb.el +++ b/lisp/net/tramp-adb.el @@ -1126,6 +1126,11 @@ connection if a previous connection has died for some reason." tramp-adb-program args))) (prompt (md5 (concat (prin1-to-string process-environment) (current-time-string))))) + + ;; Set sentinel. Initialize variables. + (set-process-sentinel p #'tramp-process-sentinel) + (tramp-post-process-creation p vec) + ;; Wait for initial prompt. On some devices, it needs ;; an initial RET, in order to get it. (sleep-for 0.1) @@ -1134,10 +1139,6 @@ connection if a previous connection has died for some reason." (unless (process-live-p p) (tramp-error vec 'file-error "Terminated!")) - ;; Set sentinel. Initialize variables. - (set-process-sentinel p #'tramp-process-sentinel) - (tramp-post-process-creation p vec) - ;; Set connection-local variables. (tramp-set-connection-local-variables vec) diff --git a/lisp/net/tramp-cache.el b/lisp/net/tramp-cache.el index a7ff0283c2b..aa953c70582 100644 --- a/lisp/net/tramp-cache.el +++ b/lisp/net/tramp-cache.el @@ -396,7 +396,8 @@ the connection, return DEFAULT." (not (and (processp key) (not (process-live-p key))))) (setq value cached cache-used t)) - (tramp-message key 7 "%s %s; cache used: %s" property value cache-used) + (unless (eq key tramp-cache-version) + (tramp-message key 7 "%s %s; cache used: %s" property value cache-used)) value)) ;;;###tramp-autoload @@ -413,7 +414,8 @@ Return VALUE." (puthash property value hash)) (setq tramp-cache-data-changed (or tramp-cache-data-changed (tramp-file-name-p key))) - (tramp-message key 7 "%s %s" property value) + (unless (eq key tramp-cache-version) + (tramp-message key 7 "%s %s" property value)) value) ;;;###tramp-autoload diff --git a/lisp/net/tramp.el b/lisp/net/tramp.el index 0e73410fef5..a137b5aeadc 100644 --- a/lisp/net/tramp.el +++ b/lisp/net/tramp.el @@ -6382,12 +6382,10 @@ Convert file mode bits to string and set virtual device number. Set file uid and gid according to ID-FORMAT. LOCALNAME is used to cache the result. Return the modified ATTR." (declare (indent 3) (debug t)) - `(with-tramp-file-property - ,vec ,localname (format "file-attributes-%s" (or ,id-format 'integer)) - (when-let* - ((attr ,attr) - (result - (with-tramp-file-property ,vec ,localname "file-attributes" + `(when-let* + ((result + (with-tramp-file-property ,vec ,localname "file-attributes" + (when-let* ((attr ,attr)) (save-match-data ;; Remove ANSI control escape sequences from symlink. (when (stringp (car attr)) @@ -6480,14 +6478,14 @@ to cache the result. Return the modified ATTR." (split-string (nth 12 attr) ":" 'omit))) ;; Remove optional entries. (setcdr (nthcdr 11 attr) nil) - attr)))) - - ;; Return normalized result. - (append (tramp-compat-take 2 result) - (if (eq ,id-format 'string) - (list (car (nth 2 result)) (car (nth 3 result))) - (list (cdr (nth 2 result)) (cdr (nth 3 result)))) - (nthcdr 4 result))))) + attr))))) + + ;; Return normalized result. + (append (tramp-compat-take 2 result) + (if (eq ,id-format 'string) + (list (car (nth 2 result)) (car (nth 3 result))) + (list (cdr (nth 2 result)) (cdr (nth 3 result)))) + (nthcdr 4 result)))) (defun tramp-get-home-directory (vec &optional user) "The remote home directory for connection VEC as local file name. diff --git a/test/lisp/net/tramp-tests.el b/test/lisp/net/tramp-tests.el index fed55ae4586..32f65621aa4 100644 --- a/test/lisp/net/tramp-tests.el +++ b/test/lisp/net/tramp-tests.el @@ -158,6 +158,7 @@ being the result.") (when (cdr tramp--test-enabled-checked) ;; Remove old test files. (dolist (dir `(,temporary-file-directory + ,tramp-compat-temporary-file-directory ,ert-remote-temporary-file-directory)) (dolist (file (directory-files dir 'full (rx bos (? ".#") "tramp-test"))) (ignore-errors @@ -5404,7 +5405,7 @@ If UNSTABLE is non-nil, the test is tagged as `:unstable'." direct-async-process-profile) connection-local-criteria-alist))) (skip-unless (tramp-direct-async-process-p)) - (when-let ((result (ert-test-most-recent-result ert-test))) + (when-let* ((result (ert-test-most-recent-result ert-test))) (skip-unless (< (ert-test-result-duration result) 300))) ;; We do expect an established connection already, ;; `file-truename' does it by side-effect. Suppress @@ -5944,7 +5945,9 @@ INPUT, if non-nil, is a string sent to the process." ;; Test `async-shell-command-width'. (when (and (tramp--test-asynchronous-processes-p) (tramp--test-sh-p)) - (let* ((async-shell-command-width 1024) + (let* (;; Since Fedora 41, this seems to be the upper limit. Used + ;; to be 1024 before. + (async-shell-command-width 512) (default-directory ert-remote-temporary-file-directory) (cols (ignore-errors (read (tramp--test-shell-command-to-string-asynchronously @@ -6464,6 +6467,7 @@ INPUT, if non-nil, is a string sent to the process." (tmp-name1 (tramp--test-make-temp-name nil quoted)) (tmp-name2 (expand-file-name "foo" tmp-name1)) (tramp-remote-process-environment tramp-remote-process-environment) + ;; Suppress nasty messages. (inhibit-message t) (vc-handled-backends (cond @@ -6486,9 +6490,7 @@ INPUT, if non-nil, is a string sent to the process." (tramp-cleanup-connection tramp-test-vec 'keep-debug 'keep-password) '(Bzr)) - (t nil))) - ;; Suppress nasty messages. - (inhibit-message t)) + (t nil)))) (skip-unless vc-handled-backends) (unless quoted (tramp--test-message "%s" vc-handled-backends)) @@ -8258,7 +8260,6 @@ If INTERACTIVE is non-nil, the tests are run interactively." ;; * file-equal-p (partly done in `tramp-test21-file-links') ;; * file-in-directory-p ;; * file-name-case-insensitive-p -;; * memory-info ;; * tramp-get-home-directory ;; * tramp-set-file-uid-gid commit 3ff92054483ff92b19d3fe4b1ccf65a513fe58ca Author: Eli Zaretskii Date: Tue Nov 5 14:40:13 2024 +0200 ; * etc/NEWS: Fix wording of last added entry. diff --git a/etc/NEWS b/etc/NEWS index c58b4d3e1ae..af6259a68c8 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -839,8 +839,9 @@ current buffer, if the major mode supports it. (Support for '--without-native-image-api'.) --- -** Images on MS-Windows now support the :transform-smoothing flag. -Bilinear interpolation with GDI+ is used to smooth images. +** Images on MS-Windows now support the ':transform-smoothing' flag. +Transformed images are smoothed using the bilinear interpolation by +means of the GDI+ library. ---------------------------------------------------------------------- commit 4e8bf2977e6d1abf6d3cf82e9c1ae3dee5bfcda0 Author: Cecilio Pardo Date: Mon Nov 4 18:58:40 2024 +0100 Support :transform-smoothing on images (MS-Windows) (bug#57166) * src/dispextern.h (struct image): Add field 'smoothing' for NTGUI. * src/image.c (image_set_transform): Assign the 'smoothing' field of the image struct. * src/w32gdiplus.h: Add references to more GDI+ functions. * src/w32image.c (gdiplus_init): Add references to more GDI+ functions. * src/w32term.c (w32_draw_image_foreground): If the image is marked for smoothing and GDI+ is available, draw it with GDI+ bilinear interpolation. * etc/NEWS: New entry for this change. diff --git a/etc/NEWS b/etc/NEWS index 3fbc935c7e4..c58b4d3e1ae 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -838,6 +838,9 @@ current buffer, if the major mode supports it. (Support for 'yank-media' will be unavailable on MS-Windows if Emacs was configured '--without-native-image-api'.) +--- +** Images on MS-Windows now support the :transform-smoothing flag. +Bilinear interpolation with GDI+ is used to smooth images. ---------------------------------------------------------------------- diff --git a/src/dispextern.h b/src/dispextern.h index cc248a4472e..004eb82d87a 100644 --- a/src/dispextern.h +++ b/src/dispextern.h @@ -3172,6 +3172,7 @@ struct image #endif /* HAVE_ANDROID */ #ifdef HAVE_NTGUI XFORM xform; + bool smoothing; #endif #ifdef HAVE_HAIKU /* The affine transformation to apply to this image. */ diff --git a/src/image.c b/src/image.c index 34936977a40..db7f6acd171 100644 --- a/src/image.c +++ b/src/image.c @@ -3049,12 +3049,10 @@ image_set_transform (struct frame *f, struct image *img) flip = !NILP (image_spec_value (img->spec, QCflip, NULL)); # if defined USE_CAIRO || defined HAVE_XRENDER || defined HAVE_NS || defined HAVE_HAIKU \ - || defined HAVE_ANDROID + || defined HAVE_ANDROID || defined HAVE_NTGUI /* We want scale up operations to use a nearest neighbor filter to show real pixels instead of munging them, but scale down - operations to use a blended filter, to avoid aliasing and the like. - - TODO: implement for Windows. */ + operations to use a blended filter, to avoid aliasing and the like. */ bool smoothing; Lisp_Object s = image_spec_value (img->spec, QCtransform_smoothing, NULL); if (NILP (s)) @@ -3067,6 +3065,10 @@ image_set_transform (struct frame *f, struct image *img) img->use_bilinear_filtering = smoothing; #endif +#ifdef HAVE_NTGUI + img->smoothing = smoothing; +#endif + /* Perform scale transformation. */ matrix3x3 matrix diff --git a/src/w32gdiplus.h b/src/w32gdiplus.h index 9d05ae6c190..b438b1a64f8 100644 --- a/src/w32gdiplus.h +++ b/src/w32gdiplus.h @@ -2,6 +2,9 @@ typedef GpStatus (WINGDIPAPI *GdiplusStartup_Proc) (ULONG_PTR *, GdiplusStartupInput *, GdiplusStartupOutput *); typedef VOID (WINGDIPAPI *GdiplusShutdown_Proc) (ULONG_PTR); +typedef GpStatus (WINGDIPAPI *GdipCreateFromHDC_Proc) + (HDC hdc, GpGraphics **graphics); +typedef GpStatus (WINGDIPAPI *GdipDeleteGraphics_Proc) (GpGraphics *graphics); typedef GpStatus (WINGDIPAPI *GdipGetPropertyItemSize_Proc) (GpImage *, PROPID, UINT *); typedef GpStatus (WINGDIPAPI *GdipGetPropertyItem_Proc) @@ -20,6 +23,15 @@ typedef GpStatus (WINGDIPAPI *GdipCreateBitmapFromStream_Proc) (IStream *, GpBitmap **); typedef GpStatus (WINGDIPAPI *GdipCreateBitmapFromScan0_Proc) (INT, INT, INT, PixelFormat, BYTE*, GpBitmap**); +typedef GpStatus (WINGDIPAPI *GdipCreateBitmapFromHBITMAP_Proc) + (HBITMAP hbm, HPALETTE hpal, GpBitmap** bitmap); +typedef GpStatus (WINGDIPAPI *GdipSetInterpolationMode_Proc) + (GpGraphics *graphics, InterpolationMode interpolationMode); +typedef GpStatus (WINGDIPAPI *GdipDrawImageRectRectI_Proc) + (GpGraphics *graphics, GpImage *image, INT dstx, INT dsty, INT dstwidth, + INT dstheight, INT srcx, INT srcy, INT srcwidth, INT srcheight, + GpUnit srcUnit, GDIPCONST GpImageAttributes* imageAttributes, + DrawImageAbort callback, VOID * callbackData); typedef IStream * (WINAPI *SHCreateMemStream_Proc) (const BYTE *, UINT); typedef GpStatus (WINGDIPAPI *GdipCreateHBITMAPFromBitmap_Proc) (GpBitmap *, HBITMAP *, ARGB); @@ -41,6 +53,8 @@ typedef GpStatus (WINGDIPAPI *GdipImageRotateFlip_Proc) extern GdiplusStartup_Proc fn_GdiplusStartup; extern GdiplusShutdown_Proc fn_GdiplusShutdown; +extern GdipCreateFromHDC_Proc fn_GdipCreateFromHDC; +extern GdipDeleteGraphics_Proc fn_GdipDeleteGraphics; extern GdipGetPropertyItemSize_Proc fn_GdipGetPropertyItemSize; extern GdipGetPropertyItem_Proc fn_GdipGetPropertyItem; extern GdipImageGetFrameDimensionsCount_Proc fn_GdipImageGetFrameDimensionsCount; @@ -49,6 +63,9 @@ extern GdipImageGetFrameCount_Proc fn_GdipImageGetFrameCount; extern GdipImageSelectActiveFrame_Proc fn_GdipImageSelectActiveFrame; extern GdipCreateBitmapFromFile_Proc fn_GdipCreateBitmapFromFile; extern GdipCreateBitmapFromStream_Proc fn_GdipCreateBitmapFromStream; +extern GdipCreateBitmapFromHBITMAP_Proc fn_GdipCreateBitmapFromHBITMAP; +extern GdipDrawImageRectRectI_Proc fn_GdipDrawImageRectRectI; +extern GdipSetInterpolationMode_Proc fn_GdipSetInterpolationMode; extern GdipCreateBitmapFromScan0_Proc fn_GdipCreateBitmapFromScan0; extern SHCreateMemStream_Proc fn_SHCreateMemStream; extern GdipCreateHBITMAPFromBitmap_Proc fn_GdipCreateHBITMAPFromBitmap; @@ -73,6 +90,11 @@ extern GdipImageRotateFlip_Proc fn_GdipImageRotateFlip; # undef GdipCreateBitmapFromFile # undef GdipCreateBitmapFromStream # undef GdipCreateBitmapFromScan0 +# undef GdipCreateBitmapFromHBITMAP +# undef GdipCreateFromHDC +# undef GdipDrawImageRectRectI +# undef GdipSetInterpolationMode +# undef GdipDeleteGraphics # undef SHCreateMemStream # undef GdipCreateHBITMAPFromBitmap # undef GdipDisposeImage @@ -96,6 +118,11 @@ extern GdipImageRotateFlip_Proc fn_GdipImageRotateFlip; # define GdipCreateBitmapFromFile fn_GdipCreateBitmapFromFile # define GdipCreateBitmapFromStream fn_GdipCreateBitmapFromStream # define GdipCreateBitmapFromScan0 fn_GdipCreateBitmapFromScan0 +# define GdipCreateBitmapFromHBITMAP fn_GdipCreateBitmapFromHBITMAP +# define GdipCreateFromHDC fn_GdipCreateFromHDC +# define GdipDrawImageRectRectI fn_GdipDrawImageRectRectI +# define GdipSetInterpolationMode fn_GdipSetInterpolationMode +# define GdipDeleteGraphics fn_GdipDeleteGraphics # define SHCreateMemStream fn_SHCreateMemStream # define GdipCreateHBITMAPFromBitmap fn_GdipCreateHBITMAPFromBitmap # define GdipDisposeImage fn_GdipDisposeImage diff --git a/src/w32image.c b/src/w32image.c index 44eed087528..da4d6843ba9 100644 --- a/src/w32image.c +++ b/src/w32image.c @@ -42,6 +42,8 @@ along with GNU Emacs. If not, see . */ #ifdef WINDOWSNT GdiplusStartup_Proc fn_GdiplusStartup; GdiplusShutdown_Proc fn_GdiplusShutdown; +GdipCreateFromHDC_Proc fn_GdipCreateFromHDC; +GdipDeleteGraphics_Proc fn_GdipDeleteGraphics; GdipGetPropertyItemSize_Proc fn_GdipGetPropertyItemSize; GdipGetPropertyItem_Proc fn_GdipGetPropertyItem; GdipImageGetFrameDimensionsCount_Proc fn_GdipImageGetFrameDimensionsCount; @@ -53,6 +55,9 @@ GdipCreateBitmapFromStream_Proc fn_GdipCreateBitmapFromStream; GdipCreateBitmapFromScan0_Proc fn_GdipCreateBitmapFromScan0; SHCreateMemStream_Proc fn_SHCreateMemStream; GdipCreateHBITMAPFromBitmap_Proc fn_GdipCreateHBITMAPFromBitmap; +GdipCreateBitmapFromHBITMAP_Proc fn_GdipCreateBitmapFromHBITMAP; +GdipDrawImageRectRectI_Proc fn_GdipDrawImageRectRectI; +GdipSetInterpolationMode_Proc fn_GdipSetInterpolationMode; GdipDisposeImage_Proc fn_GdipDisposeImage; GdipGetImageHeight_Proc fn_GdipGetImageHeight; GdipGetImageWidth_Proc fn_GdipGetImageWidth; @@ -80,6 +85,14 @@ gdiplus_init (void) get_proc_addr (gdiplus_lib, "GdiplusShutdown"); if (!fn_GdiplusShutdown) return false; + fn_GdipCreateFromHDC = (GdipCreateFromHDC_Proc) + get_proc_addr (gdiplus_lib, "GdipCreateFromHDC"); + if (!fn_GdipCreateFromHDC) + return false; + fn_GdipDeleteGraphics = (GdipDeleteGraphics_Proc) + get_proc_addr (gdiplus_lib, "GdipDeleteGraphics"); + if (!fn_GdipDeleteGraphics) + return false; fn_GdipGetPropertyItemSize = (GdipGetPropertyItemSize_Proc) get_proc_addr (gdiplus_lib, "GdipGetPropertyItemSize"); if (!fn_GdipGetPropertyItemSize) @@ -120,6 +133,18 @@ gdiplus_init (void) get_proc_addr (gdiplus_lib, "GdipCreateHBITMAPFromBitmap"); if (!fn_GdipCreateHBITMAPFromBitmap) return false; + fn_GdipCreateBitmapFromHBITMAP = (GdipCreateBitmapFromHBITMAP_Proc) + get_proc_addr (gdiplus_lib, "GdipCreateBitmapFromHBITMAP"); + if (!fn_GdipCreateBitmapFromHBITMAP) + return false; + fn_GdipDrawImageRectRectI = (GdipDrawImageRectRectI_Proc) + get_proc_addr (gdiplus_lib, "GdipDrawImageRectRectI"); + if (!fn_GdipDrawImageRectRectI) + return false; + fn_GdipSetInterpolationMode = (GdipSetInterpolationMode_Proc) + get_proc_addr (gdiplus_lib, "GdipSetInterpolationMode"); + if (!fn_GdipSetInterpolationMode) + return false; fn_GdipDisposeImage = (GdipDisposeImage_Proc) get_proc_addr (gdiplus_lib, "GdipDisposeImage"); if (!fn_GdipDisposeImage) diff --git a/src/w32term.c b/src/w32term.c index 88622700386..e18f39dd2a8 100644 --- a/src/w32term.c +++ b/src/w32term.c @@ -24,6 +24,9 @@ along with GNU Emacs. If not, see . */ #include "blockinput.h" #include "w32term.h" #include "w32common.h" /* for OS version info */ +#include +#include +#include "w32gdiplus.h" #include #include @@ -2106,16 +2109,53 @@ w32_draw_image_foreground (struct glyph_string *s) compat_hdc, s->slice.x, s->slice.y, SRCCOPY); else { - int pmode = 0; - /* Windows 9X doesn't support HALFTONE. */ - if (os_subtype == OS_SUBTYPE_NT - && (pmode = SetStretchBltMode (s->hdc, HALFTONE)) != 0) - SetBrushOrgEx (s->hdc, 0, 0, NULL); - StretchBlt (s->hdc, x, y, s->slice.width, s->slice.height, - compat_hdc, orig_slice_x, orig_slice_y, - orig_slice_width, orig_slice_height, SRCCOPY); - if (pmode) - SetStretchBltMode (s->hdc, pmode); +#ifdef HAVE_NATIVE_IMAGE_API + if (s->img->smoothing && w32_gdiplus_startup ()) + { + GpGraphics *graphics; + if (GdipCreateFromHDC (s->hdc, &graphics) == Ok) + { + GpBitmap *gp_bitmap; + /* Can't create a GpBitmap from a HBITMAP that was + ever selected into a DC, so we need to copy. */ + HBITMAP copy + = CopyImage (GetCurrentObject (compat_hdc, OBJ_BITMAP), + IMAGE_BITMAP, 0, 0, 0); + if (GdipCreateBitmapFromHBITMAP (copy, NULL, + &gp_bitmap) == Ok) + { + GdipSetInterpolationMode (graphics, + InterpolationModeHighQualityBilinear); + GdipDrawImageRectRectI (graphics, + gp_bitmap, x, y, + s->slice.width, + s->slice.height, + orig_slice_x, + orig_slice_y, + orig_slice_width, + orig_slice_height, + UnitPixel, + NULL, NULL, NULL); + GdipDisposeImage (gp_bitmap); + } + DeleteObject (copy); + GdipDeleteGraphics (graphics); + } + } + else +#endif + { + int pmode = 0; + /* Windows 9X doesn't support HALFTONE. */ + if (os_subtype == OS_SUBTYPE_NT + && (pmode = SetStretchBltMode (s->hdc, HALFTONE)) != 0) + SetBrushOrgEx (s->hdc, 0, 0, NULL); + StretchBlt (s->hdc, x, y, s->slice.width, s->slice.height, + compat_hdc, orig_slice_x, orig_slice_y, + orig_slice_width, orig_slice_height, SRCCOPY); + if (pmode) + SetStretchBltMode (s->hdc, pmode); + } } /* When the image has a mask, we can expect that at commit 8a7910fb67e3b89de430d3b3e5009b145ec0c602 Author: Eli Zaretskii Date: Tue Nov 5 14:29:02 2024 +0200 Make 'yank-media' on MS-Windows require native image APIs * src/w32select.c (convert_dibv5_to_png) [!HAVE_NATIVE_IMAGE_API]: Fail if GDI+ cannot be used. Patch by Cecilio Pardo . (Bug#71909) * etc/NEWS: Mention this dependency. diff --git a/etc/NEWS b/etc/NEWS index 1df8b1b794d..3fbc935c7e4 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -834,7 +834,9 @@ color Emoji font installed on your system for the 'emoji' script. +++ ** Emacs on MS-Windows now supports 'yank-media'. This command inserts clipboard data of different formats into the -current buffer, if the major mode supports it. +current buffer, if the major mode supports it. (Support for +'yank-media' will be unavailable on MS-Windows if Emacs was configured +'--without-native-image-api'.) diff --git a/src/w32select.c b/src/w32select.c index 7e8dc3f0702..646c8faf634 100644 --- a/src/w32select.c +++ b/src/w32select.c @@ -825,6 +825,7 @@ static const char *stdfmt_name[] = { static bool convert_dibv5_to_png (char *data, int size, char *temp_file) { +#ifdef HAVE_NATIVE_IMAGE_API CLSID clsid_png; if (!w32_gdiplus_startup () @@ -858,6 +859,9 @@ convert_dibv5_to_png (char *data, int size, char *temp_file) if (status != Ok) return false; return true; +#else /* !HAVE_NATIVE_IMAGE_API */ + return false; +#endif } static int