commit 50e3bce315eb499917c1d208f87f84315f1a8b4e (HEAD, refs/remotes/origin/master) Author: Alan Third Date: Mon May 26 20:27:39 2025 +0100 Fix NS port screen geometry report (bug#76051) * src/nsfns.m (Fns_display_monitor_attributes_list): Fix the arithmetic to calculate the origin of the visible frame. diff --git a/src/nsfns.m b/src/nsfns.m index b219064cdd1..41400e8883f 100644 --- a/src/nsfns.m +++ b/src/nsfns.m @@ -2692,41 +2692,28 @@ Frames are listed from topmost (first) to bottommost (last). */) struct MonitorInfo *m = &monitors[i]; NSRect fr = [s frame]; NSRect vfr = [s visibleFrame]; - short y, vy; #ifdef NS_IMPL_COCOA NSDictionary *dict = [s deviceDescription]; NSNumber *nid = [dict objectForKey:@"NSScreenNumber"]; CGDirectDisplayID did = [nid unsignedIntValue]; #endif + + /* The primary display is always the first in the array. */ if (i == 0) - { - primary_display_height = fr.size.height; - y = (short) fr.origin.y; - vy = (short) vfr.origin.y; - } - else - { - /* Flip y coordinate as NS screen coordinates originate from - the bottom. */ - y = (short) (primary_display_height - fr.size.height - fr.origin.y); - vy = (short) (primary_display_height - - vfr.size.height - vfr.origin.y); - } + primary_display_height = fr.size.height; + + /* Flip y coordinate as NS screen coordinates originate from + the bottom. */ m->geom.x = (short) fr.origin.x; - m->geom.y = y; + m->geom.y = (short) (primary_display_height - NSMaxY(fr)); m->geom.width = (unsigned short) fr.size.width; m->geom.height = (unsigned short) fr.size.height; + /* The work area excludes the menu bar and the dock. */ m->work.x = (short) vfr.origin.x; - /* y is flipped on NS, so vy - y are pixels missing at the - bottom, and fr.size.height - vfr.size.height are pixels - missing in total. - - Pixels missing at top are fr.size.height - vfr.size.height - - vy + y. work.y is then pixels missing at top + y. */ - m->work.y = (short) (fr.size.height - vfr.size.height) - vy + y + y; + m->work.y = (short) (primary_display_height - NSMaxY(vfr)); m->work.width = (unsigned short) vfr.size.width; m->work.height = (unsigned short) vfr.size.height; commit 9cc5f1c697c1a47470651ff4293f335eaa10ea9a Author: shipmints Date: Tue Mar 4 09:56:56 2025 -0500 Fix ns_make_monitor_attribute_list (bug#76691) This is the NS implementation for 'display-monitor-attributes-list'. Change implementation from IORegistry to direct introspection of NSScreen. * src/nsfns.m (ns_make_monitor_attribute_list): Use localizedName selector on NSScreen. For anonymous displays, synthesize names of the form ("%dx%d@%d,%d" width height x y). (ns_get_name_from_ioreg) (ns_screen_name): Removed. diff --git a/src/nsfns.m b/src/nsfns.m index b1ed0eff58a..b219064cdd1 100644 --- a/src/nsfns.m +++ b/src/nsfns.m @@ -2612,100 +2612,6 @@ Frames are listed from topmost (first) to bottommost (last). */) return make_fixnum (ns_display_pixel_height (dpyinfo)); } -#ifdef NS_IMPL_COCOA - -/* Returns the name for the screen that OBJ represents, or NULL. - Caller must free return value. -*/ - -static char * -ns_get_name_from_ioreg (io_object_t obj) -{ - char *name = NULL; - - NSDictionary *info = (NSDictionary *) - IODisplayCreateInfoDictionary (obj, kIODisplayOnlyPreferredName); - NSDictionary *names = [info objectForKey: - [NSString stringWithUTF8String: - kDisplayProductName]]; - - if ([names count] > 0) - { - NSString *n = [names objectForKey: [[names allKeys] - objectAtIndex:0]]; - if (n != nil) name = xstrdup ([n UTF8String]); - } - - [info release]; - - return name; -} - -/* Returns the name for the screen that DID came from, or NULL. - Caller must free return value. -*/ - -static char * -ns_screen_name (CGDirectDisplayID did) -{ - char *name = NULL; - -#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1090 -#if MAC_OS_X_VERSION_MIN_REQUIRED < 1090 - if (CGDisplayIOServicePort == NULL) -#endif - { - mach_port_t masterPort; - io_iterator_t it; - io_object_t obj; - - /* CGDisplayIOServicePort is deprecated. Do it another (harder) way. - - Is this code OK for macOS < 10.9, and GNUstep? I suspect it is, - in which case is it worth keeping the other method in here? */ - - if (IOMasterPort (MACH_PORT_NULL, &masterPort) != kIOReturnSuccess - || IOServiceGetMatchingServices (masterPort, - IOServiceMatching ("IONDRVDevice"), - &it) != kIOReturnSuccess) - return name; - - /* Must loop until we find a name. Many devices can have the same unit - number (represents different GPU parts), but only one has a name. */ - while (! name && (obj = IOIteratorNext (it))) - { - CFMutableDictionaryRef props; - const void *val; - - if (IORegistryEntryCreateCFProperties (obj, - &props, - kCFAllocatorDefault, - kNilOptions) == kIOReturnSuccess - && props != nil - && (val = CFDictionaryGetValue(props, @"IOFBDependentIndex"))) - { - unsigned nr = [(NSNumber *)val unsignedIntegerValue]; - if (nr == CGDisplayUnitNumber (did)) - name = ns_get_name_from_ioreg (obj); - } - - CFRelease (props); - IOObjectRelease (obj); - } - - IOObjectRelease (it); - } -#if MAC_OS_X_VERSION_MIN_REQUIRED < 1090 - else -#endif -#endif /* #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1090 */ -#if MAC_OS_X_VERSION_MIN_REQUIRED < 1090 - name = ns_get_name_from_ioreg (CGDisplayIOServicePort (did)); -#endif - return name; -} -#endif /* NS_IMPL_COCOA */ - static Lisp_Object ns_make_monitor_attribute_list (struct MonitorInfo *monitors, int n_monitors, @@ -2825,7 +2731,25 @@ Frames are listed from topmost (first) to bottommost (last). */) m->work.height = (unsigned short) vfr.size.height; #ifdef NS_IMPL_COCOA - m->name = ns_screen_name (did); + m->name = NULL; + if ([s respondsToSelector:@selector(localizedName)]) + { + NSString *name = [s valueForKey:@"localizedName"]; + if (name != NULL) + { + m->name = xmalloc ([name lengthOfBytesUsingEncoding: NSUTF8StringEncoding] + 1); + strcpy(m->name, [name UTF8String]); + } + } + /* If necessary, synthesize a name of the following form: + %dx%d@%d,%d width height x y. */ + if (m->name == NULL) + { + char buf[25]; /* sufficient for 12345x78901@34567,90123 */ + snprintf (buf, sizeof(buf), "%ux%u@%d,%d", + m->work.width, m->work.height, m->work.x, m->work.y); + m->name = xstrdup (buf); + } { CGSize mms = CGDisplayScreenSize (did); commit 55691c61d4af972b999bb97bffb46cb8571c912c Author: Michael Albinus Date: Mon Jun 2 11:44:43 2025 +0200 Tramp: Do not raise an error when not connected (Bug#78572) * lisp/net/tramp-cmds.el (tramp-cleanup-connection): Use read syntax #' for `tramp-timeout-session', * lisp/net/tramp.el (tramp-barf-if-file-missing): Do not raise an error when not connected. (Bug#78572) (tramp-file-name-handler): Do not force the backtrace. (tramp-connectable-p): Check also, whether initial handshake is finished. (tramp-skeleton-directory-files) (tramp-skeleton-directory-files-and-attributes) (tramp-skeleton-set-file-modes-times-uid-gid): Rearrange sending `file-missing' error. (tramp-handle-access-file, tramp-handle-unlock-file): Use `tramp-connectable-p'. * test/lisp/net/tramp-tests.el (project-mode-line-format) (project-mode-line): Declare. (tramp-test48-session-timeout): New test. (tramp-test49-auto-load, tramp-test49-delay-load) (tramp-test49-recursive-load, tramp-test49-remote-load-path) (tramp-test50-without-remote-files, tramp-test51-unload): Rename. diff --git a/lisp/net/tramp-cmds.el b/lisp/net/tramp-cmds.el index 098e39ccf7c..62dff3d8d46 100644 --- a/lisp/net/tramp-cmds.el +++ b/lisp/net/tramp-cmds.el @@ -177,7 +177,7 @@ interactively, a Tramp connection has to be selected." ;; Cancel timer. (dolist (timer timer-list) - (when (and (eq (timer--function timer) 'tramp-timeout-session) + (when (and (eq (timer--function timer) #'tramp-timeout-session) (tramp-file-name-equal-p vec (car (timer--args timer)))) (cancel-timer timer))) diff --git a/lisp/net/tramp-sh.el b/lisp/net/tramp-sh.el index 679d76d0f57..46666b8657e 100644 --- a/lisp/net/tramp-sh.el +++ b/lisp/net/tramp-sh.el @@ -5162,6 +5162,7 @@ If there is just some editing, retry it after 5 seconds." Does not do anything if a connection is already open, but re-opens the connection if a previous connection has died for some reason." ;; During completion, don't reopen a new connection. + ;; Same for slide-in timer or process-{filter,sentinel}. (unless (tramp-connectable-p vec) (throw 'non-essential 'non-essential)) diff --git a/lisp/net/tramp.el b/lisp/net/tramp.el index 24298e8e09a..0f7b945f84a 100644 --- a/lisp/net/tramp.el +++ b/lisp/net/tramp.el @@ -2105,10 +2105,11 @@ does not exist, otherwise propagate the error." (declare (indent 2) (debug (symbolp form body))) (let ((err (make-symbol "err"))) `(condition-case ,err - (progn ,@body) + (let (signal-hook-function) ,@body) (error (if (not (or (file-exists-p ,filename) (file-symlink-p ,filename))) - (tramp-error ,vec 'file-missing ,filename) + (when (tramp-connectable-p ,vec) + (tramp-error ,vec 'file-missing ,filename)) (signal (car ,err) (cdr ,err))))))) ;; This function provides traces in case of errors not triggered by @@ -2561,7 +2562,7 @@ Fall back to normal file name handler if no Tramp file name handler exists." (tramp-message v 5 "Non-essential received in operation %s" (cons operation args)) - (let ((tramp-verbose 10)) (tramp-backtrace v)) + (tramp-backtrace v) (tramp-run-real-handler operation args)) ((eq result 'suppress) (let ((inhibit-message t)) @@ -2793,13 +2794,15 @@ They are completed by `M-x TAB' only if there's an active connection or buffer." "Check if it is possible to connect the remote host without side-effects. This is true, if either the remote host is already connected, or if we are not in completion mode." - (let ((tramp-verbose 0) - (vec (tramp-ensure-dissected-file-name vec-or-filename))) - (or ;; We check this for the process related to - ;; `tramp-buffer-name'; otherwise `make-process' wouldn't run - ;; ever when `non-essential' is non-nil. - (process-live-p (tramp-get-process vec)) - (not non-essential)))) + (or (not non-essential) + ;; We check this for the process related to `tramp-buffer-name'; + ;; otherwise `make-process' wouldn't run ever when + ;; `non-essential' is non-nil. + (and-let* ((tramp-verbose 0) + (vec (tramp-ensure-dissected-file-name vec-or-filename)) + (p (tramp-get-process vec)) + ((process-live-p p)) + ((tramp-get-connection-property p "connected")))))) (defun tramp-completion-handle-expand-file-name (filename &optional directory) "Like `expand-file-name' for partial Tramp files." @@ -3470,79 +3473,69 @@ BODY is the backend specific code." "Skeleton for `tramp-*-handle-directory-files'. BODY is the backend specific code." (declare (indent 5) (debug t)) - `(or - (with-parsed-tramp-file-name (expand-file-name ,directory) nil - (tramp-barf-if-file-missing v ,directory - (when (file-directory-p ,directory) - (setf ,directory - (file-name-as-directory (expand-file-name ,directory))) - (let ((temp - (with-tramp-file-property v localname "directory-files" ,@body)) - result item) - (while temp - (setq item (directory-file-name (pop temp))) - (when (or (null ,match) (string-match-p ,match item)) - (push (if ,full (concat ,directory item) item) - result))) - (unless ,nosort - (setq result (sort result #'string<))) - (when (and (natnump ,count) (> ,count 0)) - (setq result (tramp-compat-ntake ,count result))) - result)))) - - ;; Error handling. - (if (not (file-exists-p ,directory)) - (tramp-error - (tramp-dissect-file-name ,directory) 'file-missing ,directory) - nil))) + `(with-parsed-tramp-file-name (expand-file-name ,directory) nil + (tramp-barf-if-file-missing v ,directory + (if (not (file-directory-p ,directory)) + ;; Trigger the `file-missing' error. + (signal 'error nil) + (setf ,directory + (file-name-as-directory (expand-file-name ,directory))) + (let ((temp + (with-tramp-file-property v localname "directory-files" ,@body)) + result item) + (while temp + (setq item (directory-file-name (pop temp))) + (when (or (null ,match) (string-match-p ,match item)) + (push (if ,full (concat ,directory item) item) + result))) + (unless ,nosort + (setq result (sort result #'string<))) + (when (and (natnump ,count) (> ,count 0)) + (setq result (tramp-compat-ntake ,count result))) + result))))) (defmacro tramp-skeleton-directory-files-and-attributes (directory &optional full match nosort id-format count &rest body) "Skeleton for `tramp-*-handle-directory-files-and-attributes'. BODY is the backend specific code." (declare (indent 6) (debug t)) - `(or - (with-parsed-tramp-file-name (expand-file-name ,directory) nil - (tramp-barf-if-file-missing v ,directory - (when (file-directory-p ,directory) - (let ((temp - (copy-tree - (mapcar - (lambda (x) - (cons - (car x) - (tramp-convert-file-attributes - v (expand-file-name (car x) localname) - ,id-format (cdr x)))) - (with-tramp-file-property - v localname "directory-files-and-attributes" - ,@body)))) - result item) - - (while temp - (setq item (pop temp)) - (when (or (null ,match) (string-match-p ,match (car item))) - (when ,full - (setcar item (expand-file-name (car item) ,directory))) - (push item result))) - - (unless ,nosort - (setq result - (sort result (lambda (x y) (string< (car x) (car y)))))) - - (when (and (natnump ,count) (> ,count 0)) - (setq result (tramp-compat-ntake ,count result))) - - (or result - ;; The scripts could fail, for example with huge file size. - (tramp-handle-directory-files-and-attributes - ,directory ,full ,match ,nosort ,id-format ,count)))))) - - ;; Error handling. - (if (not (file-exists-p ,directory)) - (tramp-error - (tramp-dissect-file-name ,directory) 'file-missing ,directory) - nil))) + `(with-parsed-tramp-file-name (expand-file-name ,directory) nil + (tramp-barf-if-file-missing v ,directory + (if (not (file-directory-p ,directory)) + ;; Trigger the `file-missing' error. + (signal 'error nil) + (let ((temp + (copy-tree + (mapcar + (lambda (x) + (cons + (car x) + (tramp-convert-file-attributes + v (expand-file-name (car x) localname) + ,id-format (cdr x)))) + (with-tramp-file-property + v localname "directory-files-and-attributes" + ,@body)))) + result item) + + (while temp + (setq item (pop temp)) + (when (or (null ,match) (string-match-p ,match (car item))) + (when ,full + (setcar item (expand-file-name (car item) ,directory))) + (push item result))) + + (unless ,nosort + (setq result + (sort result (lambda (x y) (string< (car x) (car y)))))) + + (when (and (natnump ,count) (> ,count 0)) + (setq result (tramp-compat-ntake ,count result))) + + (or result + ;; The scripts could fail, for example with huge file size. + (tramp-handle-directory-files-and-attributes + ,directory ,full ,match ,nosort ,id-format ,count))))))) (defcustom tramp-use-file-attributes t "Whether to use \"file-attributes\" connection property for check. @@ -3850,20 +3843,23 @@ BODY is the backend specific code." BODY is the backend specific code." (declare (indent 1) (debug t)) `(with-parsed-tramp-file-name (expand-file-name ,filename) nil - (when (not (file-exists-p ,filename)) - (tramp-error v 'file-missing ,filename)) - (with-tramp-saved-file-properties - v localname - ;; We cannot add "file-attributes", "file-executable-p", - ;; "file-ownership-preserved-p", "file-readable-p", - ;; "file-writable-p". - '("file-directory-p" "file-exists-p" "file-symlink-p" "file-truename") - (tramp-flush-file-properties v localname)) - (condition-case err - (progn ,@body) - (error (if tramp-inhibit-errors-if-setting-file-attributes-fail - (display-warning 'tramp (error-message-string err)) - (signal (car err) (cdr err))))))) + (tramp-barf-if-file-missing v ,filename + (if (not (file-exists-p ,filename)) + ;; Trigger the `file-missing' error. + (signal 'error nil) + (with-tramp-saved-file-properties + v localname + ;; We cannot add "file-attributes", "file-executable-p", + ;; "file-ownership-preserved-p", "file-readable-p", + ;; "file-writable-p". + '("file-directory-p" "file-exists-p" + "file-symlink-p" "file-truename") + (tramp-flush-file-properties v localname)) + (condition-case err + (progn ,@body) + (error (if tramp-inhibit-errors-if-setting-file-attributes-fail + (display-warning 'tramp (error-message-string err)) + (signal (car err) (cdr err))))))))) (defmacro tramp-skeleton-write-region (start end filename append visit lockname mustbenew &rest body) @@ -4051,9 +4047,7 @@ Let-bind it when necessary.") (tramp-dont-suspend-timers t)) (with-tramp-timeout (timeout - (unless (and-let* ((p (tramp-get-connection-process v)) - ((process-live-p p)) - ((tramp-get-connection-property p "connected")))) + (unless (and (not non-essential) (tramp-connectable-p v)) (tramp-cleanup-connection v 'keep-debug 'keep-password)) (tramp-error v 'file-error @@ -4939,6 +4933,7 @@ Do not set it manually, it is used buffer-local in `tramp-get-lock-pid'.") ;; functions like `kill-buffer' would try to reestablish the ;; connection. See Bug#61663. (if-let* ((v (tramp-dissect-file-name file)) + ((tramp-connectable-p v)) ((process-live-p (tramp-get-process v))) (lockname (make-lock-file-name file))) (delete-file lockname) diff --git a/test/lisp/net/tramp-tests.el b/test/lisp/net/tramp-tests.el index b60b29fc3e6..f67a33467de 100644 --- a/test/lisp/net/tramp-tests.el +++ b/test/lisp/net/tramp-tests.el @@ -67,6 +67,7 @@ (require 'vc-git) (require 'vc-hg) +(declare-function project-mode-line-format "project") (declare-function tramp-check-remote-uname "tramp-sh") (declare-function tramp-find-executable "tramp-sh") (declare-function tramp-get-remote-chmod-h "tramp-sh") @@ -89,6 +90,7 @@ (defvar tramp-use-connection-share) ;; Declared in Emacs 30.1. +(defvar project-mode-line) (defvar remote-file-name-access-timeout) (defvar remote-file-name-inhibit-delete-by-moving-to-trash) @@ -8374,8 +8376,52 @@ process sentinels. They shall not disturb each other." ;; Cleanup. (tramp-cleanup-connection tramp-test-vec 'keep-debug)) +;; This test is inspired by Bug#78572. +(ert-deftest tramp-test48-session-timeout () + "Check that Tramp handles a session timeout properly." + (skip-unless (tramp--test-enabled)) + (skip-unless + (tramp-get-method-parameter tramp-test-vec 'tramp-session-timeout)) + + ;; We want to see the timeout message. + (tramp--test-instrument-test-case 3 + (let ((remote-file-name-inhibit-cache t) + (tmp-name (tramp--test-make-temp-name))) + (unwind-protect + (progn + (should-not (file-exists-p tmp-name)) + (write-region "foo" nil tmp-name) + (should (file-exists-p tmp-name)) + + (tramp-timeout-session tramp-test-vec) + (should (file-exists-p tmp-name)) + (should (directory-files (file-name-directory tmp-name))) + + ;; `project-mode-line' was introduced in Emacs 30.1. + (when (boundp 'project-mode-line) + (require 'project) + (ert-with-message-capture captured-messages + (let ((project-mode-line t)) + (with-temp-buffer + (set-visited-file-name tmp-name) + (insert "foo") + (should (buffer-modified-p)) + (tramp-timeout-session tramp-test-vec) + ;; This calls `file-directory-p' and + ;; `directory-files'. Shouldn't raise an error when + ;; not connected. + (project-mode-line-format) + ;; Steal the file lock. + (cl-letf (((symbol-function #'ask-user-about-lock) #'always)) + (save-buffer))) + (should-not + (string-match-p "File is missing:" captured-messages)))))) + + ;; Cleanup. + (ignore-errors (delete-file tmp-name)))))) + ;; This test is inspired by Bug#29163. -(ert-deftest tramp-test48-auto-load () +(ert-deftest tramp-test49-auto-load () "Check that Tramp autoloads properly." ;; If we use another syntax but `default', Tramp is already loaded ;; due to the `tramp-change-syntax' call. @@ -8400,7 +8446,7 @@ process sentinels. They shall not disturb each other." (mapconcat #'shell-quote-argument load-path " -L ") (shell-quote-argument code))))))) -(ert-deftest tramp-test48-delay-load () +(ert-deftest tramp-test49-delay-load () "Check that Tramp is loaded lazily, only when needed." ;; Tramp is neither loaded at Emacs startup, nor when completing a ;; non-Tramp file name like "/foo". Completing a Tramp-alike file @@ -8430,7 +8476,7 @@ process sentinels. They shall not disturb each other." (mapconcat #'shell-quote-argument load-path " -L ") (shell-quote-argument (format code tm))))))))) -(ert-deftest tramp-test48-recursive-load () +(ert-deftest tramp-test49-recursive-load () "Check that Tramp does not fail due to recursive load." (skip-unless (tramp--test-enabled)) @@ -8454,7 +8500,7 @@ process sentinels. They shall not disturb each other." (mapconcat #'shell-quote-argument load-path " -L ") (shell-quote-argument code)))))))) -(ert-deftest tramp-test48-remote-load-path () +(ert-deftest tramp-test49-remote-load-path () "Check that Tramp autoloads its packages with remote `load-path'." ;; `tramp-cleanup-all-connections' is autoloaded from tramp-cmds.el. ;; It shall still work, when a remote file name is in the @@ -8479,7 +8525,7 @@ process sentinels. They shall not disturb each other." (mapconcat #'shell-quote-argument load-path " -L ") (shell-quote-argument code))))))) -(ert-deftest tramp-test49-without-remote-files () +(ert-deftest tramp-test50-without-remote-files () "Check that Tramp can be suppressed." (skip-unless (tramp--test-enabled)) @@ -8494,7 +8540,7 @@ process sentinels. They shall not disturb each other." (setq tramp-mode t) (should (file-remote-p ert-remote-temporary-file-directory))) -(ert-deftest tramp-test50-unload () +(ert-deftest tramp-test51-unload () "Check that Tramp and its subpackages unload completely. Since it unloads Tramp, it shall be the last test to run." :tags '(:expensive-test) commit 1b03a348f7e7a01961108867985006fdfcc0a8cf Author: Collin Funk Date: Sun Jun 1 18:01:33 2025 -0700 Pacify Clang's -Wformat-signedness. * configure.ac: Enable -Wno-format-signedness if Clang is being used. diff --git a/configure.ac b/configure.ac index bafbb748149..d7c27dae734 100644 --- a/configure.ac +++ b/configure.ac @@ -1870,6 +1870,7 @@ AS_IF([test $gl_gcc_warnings = no], # clang is unduly picky about some things. if test "$emacs_cv_clang" = yes; then gl_WARN_ADD([-Wno-bitwise-instead-of-logical]) + gl_WARN_ADD([-Wno-format-signedness]) gl_WARN_ADD([-Wno-missing-braces]) gl_WARN_ADD([-Wno-null-pointer-arithmetic]) gl_WARN_ADD([-Wno-implicit-const-int-float-conversion])