commit 2a8cf3ca5f91036c9731ab3b062426a56b1d8195 (HEAD, refs/remotes/origin/master) Author: Eli Zaretskii Date: Thu Mar 6 09:43:11 2025 +0200 ; * doc/emacs/maintaining.texi (Managing Projects): Fix wording. diff --git a/doc/emacs/maintaining.texi b/doc/emacs/maintaining.texi index 84f5382e20a..f233b118976 100644 --- a/doc/emacs/maintaining.texi +++ b/doc/emacs/maintaining.texi @@ -2043,12 +2043,12 @@ it from the file. @vindex project-list-exclude The user option @code{project-list-exclude} may be set to always -ignore certain projects from being remembered, and saved to -@code{project-list-file}. It is a list of regexps and predicates for -project roots and objects. The regexp specified is matched against the -project root, and the predicate should take the project object as the -only argument and should return non-@code{nil} if the project should not -be saved to @code{project-list-file}. +ignore certain projects from being remembered and saved to +@code{project-list-file}. It is a list of regular expressions and +predicate functions for project roots and objects. The regexp is +matched against the project root, and the predicate should take the +project object as the only argument and return non-@code{nil} if the +project should @emph{not} be saved to @code{project-list-file}. @node Change Log @section Change Logs commit 6aa60038ee999d25184a639ce0ac76b614e3afb6 Author: Visuwesh Date: Mon Mar 3 13:56:04 2025 +0530 Add new user option to exclude projects from being remembered * lisp/progmodes/project.el (project-list-exclude): Add new user option to exclude projects from being remembered. (project-remember-project): Consider the user option above. (project-switch-project): Use 'project-remember-project' instead. * doc/emacs/maintaining.texi (Managing Projects): Mention the new user option. * etc/NEWS: Announce the change. (Bug#76587) diff --git a/doc/emacs/maintaining.texi b/doc/emacs/maintaining.texi index dc61cb008fa..84f5382e20a 100644 --- a/doc/emacs/maintaining.texi +++ b/doc/emacs/maintaining.texi @@ -2041,6 +2041,15 @@ the available projects. @kbd{M-x project-forget-project} prompts you to choose one of the available projects, and then removes it from the file. +@vindex project-list-exclude + The user option @code{project-list-exclude} may be set to always +ignore certain projects from being remembered, and saved to +@code{project-list-file}. It is a list of regexps and predicates for +project roots and objects. The regexp specified is matched against the +project root, and the predicate should take the project object as the +only argument and should return non-@code{nil} if the project should not +be saved to @code{project-list-file}. + @node Change Log @section Change Logs diff --git a/etc/NEWS b/etc/NEWS index da26870f2b1..78a241abfd3 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -336,6 +336,13 @@ It can be used when switching between projects with similar file trees (such as Git worktrees of the same repository). It supports being invoked standalone or from the 'project-switch-commands' dispatch menu. ++++ +*** New user option 'project-list-exclude'. +This user option describes projects that should always be skipped by +'project-remember-project'. + +*** + ** Registers *** New functions 'buffer-to-register' and 'file-to-register'. diff --git a/lisp/progmodes/project.el b/lisp/progmodes/project.el index 35bf66c9ffb..a077e647db3 100644 --- a/lisp/progmodes/project.el +++ b/lisp/progmodes/project.el @@ -1837,6 +1837,16 @@ Also see the `project-kill-buffers-display-buffer-list' variable." :version "28.1" :group 'project) +(defcustom project-list-exclude nil + "Exclude projects from being remembered by `project-remember-project'. +It should be a list of regexps and predicates for project roots and +objects to always exclude from being remembered. The predicate should +take one argument, the project object, and should return non-nil if the +project should not be remembered." + :type '(repeat (choice regexp function)) + :version "31.1" + :group 'project) + (defvar project--list 'unset "List structure containing root directories of known projects. With some possible metadata (to be decided).") @@ -1902,9 +1912,16 @@ has changed, and NO-WRITE is nil." ;;;###autoload (defun project-remember-project (pr &optional no-write) "Add project PR to the front of the project list. +If project PR satisfies `project-list-exclude', then nothing is done. Save the result in `project-list-file' if the list of projects has changed, and NO-WRITE is nil." - (project--remember-dir (project-root pr) no-write)) + (let ((root (project-root pr))) + (unless (seq-some (lambda (r) + (if (functionp r) + (funcall r pr) + (string-match-p r root))) + project-list-exclude) + (project--remember-dir root no-write)))) (defun project--remove-from-project-list (project-root report-message) "Remove directory PROJECT-ROOT of a missing project from the project list. @@ -2274,7 +2291,7 @@ made from `project-switch-commands'. When called in a program, it will use the project corresponding to directory DIR." (interactive (list (funcall project-prompter))) - (project--remember-dir dir) + (project-remember-project (project-current nil dir)) (let ((command (if (symbolp project-switch-commands) project-switch-commands (project--switch-project-command dir))) commit 4b5cc0bfc6d25ff4b7cd16c840e325e9fada4593 Author: Stefan Kangas Date: Wed Mar 5 05:08:48 2025 +0100 Rewrite cl--parsing-keywords using backtick * lisp/emacs-lisp/cl-seq.el (cl--parsing-keywords): Rewrite using backtick. diff --git a/lisp/emacs-lisp/cl-seq.el b/lisp/emacs-lisp/cl-seq.el index f6be1dfd0c6..33f14df0291 100644 --- a/lisp/emacs-lisp/cl-seq.el +++ b/lisp/emacs-lisp/cl-seq.el @@ -47,7 +47,7 @@ ;; This is special-cased here so that we can compile ;; this file independent from cl-macs. -(defmacro cl--parsing-keywords (kwords other-keys &rest body) +(defmacro cl--parsing-keywords (keywords other-keys &rest body) (declare (indent 2) (debug (sexp sexp &rest form))) `(let* ,(mapcar (lambda (x) @@ -59,26 +59,22 @@ (setq mem `(and ,mem (setq cl-if ,mem) t))) (list (intern (format "cl-%s" (substring (symbol-name var) 1))) - (if (consp x) `(or ,mem ,(car (cdr x))) mem)))) - kwords) + (if (consp x) `(or ,mem ,(cadr x)) mem)))) + keywords) ,@(append (and (not (eq other-keys t)) - (list - (list 'let '((cl-keys-temp cl-keys)) - (list 'while 'cl-keys-temp - (list 'or (list 'memq '(car cl-keys-temp) - (list 'quote - (mapcar - (lambda (x) - (if (consp x) - (car x) x)) - (append kwords - other-keys)))) - '(car (cdr (memq (quote :allow-other-keys) - cl-keys))) - '(error "Bad keyword argument %s" - (car cl-keys-temp))) - '(setq cl-keys-temp (cdr (cdr cl-keys-temp))))))) + `((let ((cl-keys-temp cl-keys)) + (while cl-keys-temp + (or (memq (car cl-keys-temp) + (quote ,(mapcar + (lambda (x) + (if (consp x) + (car x) x)) + (append keywords other-keys)))) + (cadr (memq :allow-other-keys cl-keys)) + (error "Bad keyword argument %s" + (car cl-keys-temp))) + (setq cl-keys-temp (cddr cl-keys-temp)))))) body))) (defmacro cl--check-key (x) ;Expects `cl-key' in context of generated code. commit af44c7630cafba832a8b7c3b302dd0b16c4f271c Author: Stefan Kangas Date: Thu Mar 6 00:34:39 2025 +0100 Remove more redundant 'cl-' prefixes * lisp/emacs-lisp/cl-seq.el (cl-substitute-if, cl-substitute-if-not) (cl-count, cl-sort): Remove more redundant 'cl-' prefixes from arguments and let-bound variables. diff --git a/lisp/emacs-lisp/cl-seq.el b/lisp/emacs-lisp/cl-seq.el index 934c1658ca2..f6be1dfd0c6 100644 --- a/lisp/emacs-lisp/cl-seq.el +++ b/lisp/emacs-lisp/cl-seq.el @@ -445,24 +445,24 @@ to avoid corrupting the original SEQ. :start i cl-keys)))))) ;;;###autoload -(defun cl-substitute-if (new pred cl-list &rest cl-keys) +(defun cl-substitute-if (new pred seq &rest cl-keys) "Substitute NEW for all items satisfying PREDICATE in SEQ. This is a non-destructive function; it makes a copy of SEQ if necessary to avoid corrupting the original SEQ. \nKeywords supported: :key :count :start :end :from-end \n(fn NEW PREDICATE SEQ [KEYWORD VALUE]...)" (declare (important-return-value t)) - (apply #'cl-substitute new nil cl-list :if pred cl-keys)) + (apply #'cl-substitute new nil seq :if pred cl-keys)) ;;;###autoload -(defun cl-substitute-if-not (new pred cl-list &rest cl-keys) +(defun cl-substitute-if-not (new pred seq &rest cl-keys) "Substitute NEW for all items not satisfying PREDICATE in SEQ. This is a non-destructive function; it makes a copy of SEQ if necessary to avoid corrupting the original SEQ. \nKeywords supported: :key :count :start :end :from-end \n(fn NEW PREDICATE SEQ [KEYWORD VALUE]...)" (declare (important-return-value t)) - (apply #'cl-substitute new nil cl-list :if-not pred cl-keys)) + (apply #'cl-substitute new nil seq :if-not pred cl-keys)) ;;;###autoload (defun cl-nsubstitute (new old seq &rest cl-keys) @@ -603,12 +603,12 @@ Return the index of the matching item, or nil if not found. \n(fn ITEM SEQ [KEYWORD VALUE]...)" (declare (important-return-value t)) (cl--parsing-keywords (:test :test-not :key :if :if-not (:start 0) :end) () - (let ((count 0) cl-x) + (let ((count 0) x) (or cl-end (setq cl-end (length seq))) (if (consp seq) (setq seq (nthcdr cl-start seq))) (while (< cl-start cl-end) - (setq cl-x (if (consp seq) (pop seq) (aref seq cl-start))) - (if (cl--check-test item cl-x) (setq count (1+ count))) + (setq x (if (consp seq) (pop seq) (aref seq cl-start))) + (if (cl--check-test item x) (incf count)) (setq cl-start (1+ cl-start))) count))) @@ -705,9 +705,9 @@ This is a destructive function; it reuses the storage of SEQ if possible. (cl--parsing-keywords (:key) () (if (memq cl-key '(nil identity)) (sort seq pred) - (sort seq (lambda (cl-x cl-y) - (funcall pred (funcall cl-key cl-x) - (funcall cl-key cl-y)))))))) + (sort seq (lambda (x y) + (funcall pred (funcall cl-key x) + (funcall cl-key y)))))))) ;;;###autoload (defun cl-stable-sort (seq pred &rest cl-keys) commit 679966b5a091106d37a2e2e769d9e87f3fb92a63 Author: Stefan Kangas Date: Thu Mar 6 00:33:21 2025 +0100 New user option checkdoc-arguments-missing-flag * lisp/emacs-lisp/checkdoc.el (checkdoc-arguments-missing-flag): New user option. (checkdoc-this-string-valid-engine): Use above new option. (checkdoc--argument-missing-flag): Make into obsolete variable alias for above new option. diff --git a/etc/NEWS b/etc/NEWS index ef4cacb20f9..da26870f2b1 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -930,6 +930,11 @@ those versions can't install packages where that line is missing. This change affects both 'M-x checkdoc' and the corresponding flymake backend. +--- +*** New user option 'checkdoc-arguments-missing-flag'. +Set this to nil to disable warnings for function arguments that are not +documented in docstrings. + --- *** Checkdoc will now flag incorrect formatting in warnings. This affects calls to 'warn', 'lwarn', 'display-warning', and diff --git a/lisp/emacs-lisp/checkdoc.el b/lisp/emacs-lisp/checkdoc.el index 95fa3a2027e..c3b43b6a97b 100644 --- a/lisp/emacs-lisp/checkdoc.el +++ b/lisp/emacs-lisp/checkdoc.el @@ -353,19 +353,19 @@ See Info node `(elisp) Documentation Tips' for background." ;; This is how you can use checkdoc to make mass fixes on the Emacs ;; source tree: ;; -;; (setq checkdoc--argument-missing-flag nil) ; optional +;; (setq checkdoc-arguments-missing-flag nil) ; optional ;; (setq checkdoc--disambiguate-symbol-flag nil) ; optional ;; (setq checkdoc--interactive-docstring-flag nil) ; optional ;; (setq checkdoc-permit-comma-termination-flag t) ; optional -;; (setq checkdoc-verb-check-experimental-flag nil) ;; Then use `M-x find-dired' ("-name '*.el'") and `M-x checkdoc-dired' -(defvar checkdoc--argument-missing-flag t - "Non-nil means warn if arguments are missing from docstring. -This variable is intended for use on Emacs itself, where the -large number of libraries means it is impractical to fix all -of these warnings en masse. In almost any other case, setting -this to anything but t is likely to be counter-productive.") +(define-obsolete-variable-alias 'checkdoc--argument-missing-flag + 'checkdoc-arguments-missing-flag "31.1") +(defcustom checkdoc-arguments-missing-flag t + "Non-nil means warn if function arguments are missing from docstring." + :type 'boolean + :version "31.1") +;;;###autoload(put 'checkdoc-arguments-missing-flag 'safe-local-variable 'booleanp) (defvar checkdoc--disambiguate-symbol-flag t "Non-nil means ask to disambiguate Lisp symbol. @@ -1852,7 +1852,7 @@ function,command,variable,option or symbol." ms1)))))) (looking-at "[.?!]"))) (insert ".")) nil) - (when checkdoc--argument-missing-flag + (when checkdoc-arguments-missing-flag (checkdoc-create-error (format-message "Argument `%s' should appear (as %s) in the doc string" commit fac9097b16310cf7af058ef5ff26c86697b24a32 Author: Stefan Kangas Date: Wed Mar 5 18:40:00 2025 +0100 Add more tests for cl-seq.el * test/lisp/emacs-lisp/cl-seq-tests.el (cl--oddp-safe) (cl-subst-if-test, cl-subst-if-not-test, cl-nsubst-test) (cl-nsubst-if-test, cl-nsubst-if-not-test, cl-sublis-test) (cl-nsublis-test, cl-tree-equal-test): New tests. diff --git a/test/lisp/emacs-lisp/cl-seq-tests.el b/test/lisp/emacs-lisp/cl-seq-tests.el index 6d9cec6f76c..ff875953cc4 100644 --- a/test/lisp/emacs-lisp/cl-seq-tests.el +++ b/test/lisp/emacs-lisp/cl-seq-tests.el @@ -1067,5 +1067,94 @@ Additionally register an `ert-info' to help identify test failures." (should (cl-subsetp '(1 2) '(1 2 3 2))) (should (cl-subsetp () ()))) +(defun cl--oddp-safe (x) + (and (numberp x) (oddp x))) + +(ert-deftest cl-subst-if-test () + (should (equal (cl-subst-if 'X #'cl--oddp-safe '(1 2 (3 4 5) 6)) + '(X 2 (X 4 X) 6))) + (should (equal (cl-subst-if 'X #'cl--oddp-safe '(1 2 (3 4 5) 6) + :key (lambda (x) (and (numberp x) (1+ x)))) + '(1 X (3 X 5) X)))) + +(ert-deftest cl-subst-if-not-test () + (should (equal (cl-subst-if-not 'X (lambda (x) (or (not (numberp x)) (oddp x))) + '(1 2 (3 4 5) 6)) + '(1 X (3 X 5) X))) + (should (equal (cl-subst-if-not 'X (lambda (x) (or (not (numberp x)) (oddp x))) + '(1 2 (3 4 5) 6) + :key (lambda (x) (and (numberp x) (1+ x)))) + '(X 2 (X 4 X) 6)))) + +(ert-deftest cl-nsubst-test () + (should (equal (let ((tree (list 'a 'b (list 'c 'd 'a) 'e))) + (cl-nsubst 'X 'a tree)) + '(X b (c d X) e))) + (should (equal (let ((tree (list 'a 'b (list 'c 'd 'a) 'e))) + (cl-nsubst 'X 'a tree + :test #'eq)) + '(X b (c d X) e))) + (should (equal (let ((tree (list 'a 'b (list 'c 'd 'a) 'e))) + (cl-nsubst 'X 'a tree + :test-not (lambda (a b) (or (consp b) (eq a b))))) + '(a X (X X a . X) X . X))) + (should (equal (let ((tree (list (cons 1 'a) (cons 2 'b) (cons 3 'a)))) + (cl-nsubst 'X 'a tree + :key #'cdr-safe)) + '(X (2 . b) X)))) + +(ert-deftest cl-nsubst-if-test () + (should (equal (let ((tree (list 1 2 (list 3 4 5) 6))) + (cl-nsubst-if 'X #'cl--oddp-safe tree)) + '(X 2 (X 4 X) 6))) + (should (equal (let ((tree (list 1 2 (list 3 4 5) 6))) + (cl-nsubst-if 'X #'cl--oddp-safe tree + :key (lambda (x) (and (numberp x) (1+ x))))) + '(1 X (3 X 5) X)))) + +(ert-deftest cl-nsubst-if-not-test () + (should (equal (let ((tree (list 1 2 (list 3 4 5) 6))) + (cl-nsubst-if-not 'X + (lambda (x) (or (not (numberp x)) (oddp x))) + tree)) + '(1 X (3 X 5) X))) + (should (equal (let ((tree (list 1 2 (list 3 4 5) 6))) + (cl-nsubst-if-not 'X + (lambda (x) (or (not (numberp x)) (oddp x))) + tree + :key (lambda (x) (and (numberp x) (1+ x))))) + '(X 2 (X 4 X) 6)))) + +(ert-deftest cl-sublis-test () + (should (equal (cl-sublis '((a . x) (b . y)) '(a b (a c))) + '(x y (x c)))) + (should (equal (cl-sublis '((1 . x) (2 . y)) '(1 2 (3 4)) + :key (lambda (x) (and (numberp x) (1- x)))) + '(1 x (y 4)))) + (should (equal (cl-sublis '(("a" . x) ("b" . y)) '("a" "b" ("a" "c")) + :test #'equal) + '(x y (x "c")))) + (should (equal (cl-sublis '(("a" . x) ("b" . y)) '("a" "b" ("a" "c")) + :test-not #'equal) + 'x))) + +(ert-deftest cl-nsublis-test () + (should (equal (let ((tree (list 'a 'b '(a c)))) + (cl-nsublis '((a . x) (b . y)) tree)) + '(x y (x c)))) + (should (equal (let ((tree (list '(1 . a) '(2 . b) '(3 . c)))) + (cl-nsublis '((a . x) (b . y)) tree)) + '((1 . x) (2 . y) (3 . c))))) + +(ert-deftest cl-tree-equal-test () + (should (cl-tree-equal '(1 (2 3) 4) '(1 (2 3) 4))) + (should-not (cl-tree-equal '(1 (2 3) 4) '(1 (2 3) 5))) + (should (cl-tree-equal '(("a" . 1) ("b" . 2)) '(("a" . 1) ("b" . 2)) :test #'equal)) + (should-not (cl-tree-equal '(("a" . 1) ("b" . 2)) '(("a" . 1) ("b" . 3)) :test #'equal)) + (should (cl-tree-equal '(1 2 3) '(1 2 3) :key (lambda (x) (and x (1+ x))))) + (should (cl-tree-equal '(a b c) '(a b c) :key #'symbol-name :test #'equal)) + (should-not (cl-tree-equal '(1 2 3) '(1 2 3) :test-not #'eq)) + (should (cl-tree-equal '(1 2 3) '(1 2 3) :key #'identity :test #'eq))) + (provide 'cl-seq-tests) ;;; cl-seq-tests.el ends here commit 25de262bd95b587beb757e1a82828ad4fffbf168 Author: Stefan Monnier Date: Wed Mar 5 18:35:35 2025 -0500 (pp-fill): Fix bug#76715 * lisp/emacs-lisp/pp.el (pp-fill): Don't break before `.` within symbols. * test/lisp/emacs-lisp/pp-tests.el (pp-tests--bug76715): New test. diff --git a/lisp/emacs-lisp/pp.el b/lisp/emacs-lisp/pp.el index 3e75807f757..c183f442d8d 100644 --- a/lisp/emacs-lisp/pp.el +++ b/lisp/emacs-lisp/pp.el @@ -208,7 +208,14 @@ it inserts and pretty-prints that arg at point." (while (progn (funcall avoid-unbreakable) - (not (zerop (skip-chars-backward " \t({[',."))))) + (let ((pos (point))) + (skip-chars-backward " \t({[',.") + (while (and (memq (char-after) '(?\. ?\{)) + (not (memq (char-before) + '(nil ?\n ?\) \" ?\])))) + ;; `.' and `{' within symbols? (Bug#76715) + (forward-char 1)) + (not (eql pos (point)))))) (if (bolp) ;; The sexp already starts on its own line. (progn (goto-char beg) nil) diff --git a/test/lisp/emacs-lisp/pp-tests.el b/test/lisp/emacs-lisp/pp-tests.el index 68095ea08c8..d964ed38986 100644 --- a/test/lisp/emacs-lisp/pp-tests.el +++ b/test/lisp/emacs-lisp/pp-tests.el @@ -85,4 +85,13 @@ (signal (car err) (cdr err)) )))))))) +(ert-deftest pp-tests--bug76715 () + (with-temp-buffer + (let ((pp-default-function #'pp-fill) + (fill-column 8) + (val '(x. y{ z. a{ b. x. y{ z. a{ b.))) + (pp val (current-buffer)) + (goto-char (point-min)) + (should (equal (read (current-buffer)) val))))) + ;;; pp-tests.el ends here. commit 70d0da3fe0b73f7a8757a155feb5efa52e2a1c3a Author: Juri Linkov Date: Wed Mar 5 19:47:31 2025 +0200 Improve treesit settings for java-ts-mode (bug#73404, bug#76493) * lisp/progmodes/java-ts-mode.el (java-ts-mode): Add the 'list' thing to 'treesit-thing-settings'. Set 'treesit-outline-predicate'. diff --git a/lisp/progmodes/java-ts-mode.el b/lisp/progmodes/java-ts-mode.el index 826bdb12ca6..602c2553592 100644 --- a/lisp/progmodes/java-ts-mode.el +++ b/lisp/progmodes/java-ts-mode.el @@ -415,6 +415,26 @@ Return nil if there is no name or if NODE is not a defun node." "_type" "true" "false"))) + (list ,(rx bos (or "inferred_parameters" + "parenthesized_expression" + "argument_list" + "type_arguments" + "switch_block" + "record_pattern_body" + "block" + "resource_specification" + "annotation_argument_list" + "element_value_array_initializer" + "module_body" + "enum_body" + "type_parameters" + "class_body" + "constructor_body" + "annotation_type_body" + "interface_body" + "array_initializer" + "formal_parameters") + eos)) (sentence ,(rx (or "statement" "local_variable_declaration" "field_declaration" @@ -450,6 +470,14 @@ Return nil if there is no name or if NODE is not a defun node." ("Interface" "\\`interface_declaration\\'" nil nil) ("Enum" "\\`record_declaration\\'" nil nil) ("Method" "\\`method_declaration\\'" nil nil))) + ;; Outline minor mode + (setq-local treesit-outline-predicate + (rx bos (or "class_declaration" + "interface_declaration" + "method_declaration" + "constructor_declaration") + eos)) + (treesit-major-mode-setup)) (derived-mode-add-parents 'java-ts-mode '(java-mode)) commit 68def672e61a5b25ec5bdee69493c09d79632ce2 Author: Juri Linkov Date: Wed Mar 5 19:44:44 2025 +0200 Improve treesit settings for typescript/tsx-ts-mode (bug#73404) * lisp/progmodes/typescript-ts-mode.el (typescript-ts-mode--font-lock-settings): Add @font-lock-type-face for 'internal_module' with 'identifier'. (typescript-ts-mode--defun-type-regexp): New variable with "internal_module" and "interface_declaration". (typescript-ts-mode--defun-name): New function that uses 'js--treesit-defun-name' and adds "internal_module" and "interface_declaration". (typescript-ts-mode--simple-imenu-settings): New variable like in 'js-ts-mode' with "Namespace" and "Interface" sections. (typescript-ts-mode--outline-predicate): New variable. (typescript-ts-base-mode): Set treesit-defun-type-regexp to typescript-ts-mode--defun-type-regexp, treesit-defun-name-function to typescript-ts-mode--defun-name, treesit-simple-imenu-settings to typescript-ts-mode--simple-imenu-settings, treesit-outline-predicate to typescript-ts-mode--outline-predicate. Use js--regexp-opt-symbol for treesit-thing-settings. (tsx-ts-mode): For 'sentence' thing use the same nodes as js--treesit-sentence-nodes. Use js--regexp-opt-symbol for treesit-thing-settings. * lisp/progmodes/js.el (js--treesit-sentence-nodes): Add "jsx_opening_element" and "jsx_closing_element" like in html. * lisp/progmodes/c-ts-mode.el (c-ts-mode--outline-predicate): Add outline headings for C++ "namespace_definition" and "class_specifier". diff --git a/lisp/progmodes/c-ts-mode.el b/lisp/progmodes/c-ts-mode.el index 499c2ad66d4..fa5f8567b60 100644 --- a/lisp/progmodes/c-ts-mode.el +++ b/lisp/progmodes/c-ts-mode.el @@ -1048,7 +1048,9 @@ Return nil if NODE is not a defun node or doesn't have a name." (treesit-parent-until node "function_definition")) ;; DEFUNs in Emacs sources. (and c-ts-mode-emacs-sources-support - (c-ts-mode--emacs-defun-p node)))) + (c-ts-mode--emacs-defun-p node)) + (member (treesit-node-type node) '("namespace_definition" + "class_specifier")))) ;;; Defun navigation diff --git a/lisp/progmodes/js.el b/lisp/progmodes/js.el index e5dae4eed5f..d0e0f6f6774 100644 --- a/lisp/progmodes/js.el +++ b/lisp/progmodes/js.el @@ -3866,7 +3866,9 @@ Currently there are `js-mode' and `js-ts-mode'." "labeled_statement" "variable_declaration" "lexical_declaration" - "jsx_attribute") + "jsx_opening_element" + "jsx_attribute" + "jsx_closing_element") "Nodes that designate sentences in JavaScript. See `treesit-thing-settings' for more information.") @@ -3958,10 +3960,10 @@ See `treesit-thing-settings' for more information.") (defvar js-ts-mode--outline-predicate `(or (and "\\`class\\'" named) - ,(rx bos (or"class_declaration" - "method_definition" - "function_declaration" - "function_expression") + ,(rx bos (or "class_declaration" + "method_definition" + "function_declaration" + "function_expression") eos))) (defvar js--treesit-defun-type-regexp @@ -4009,9 +4011,7 @@ See `treesit-thing-settings' for more information.") (setq-local treesit-simple-indent-rules js--treesit-indent-rules) ;; Navigation. (setq-local treesit-defun-type-regexp js--treesit-defun-type-regexp) - (setq-local treesit-defun-name-function #'js--treesit-defun-name) - (setq-local treesit-thing-settings js--treesit-thing-settings) ;; Fontification. diff --git a/lisp/progmodes/typescript-ts-mode.el b/lisp/progmodes/typescript-ts-mode.el index 759578d7b9d..67b59a321ad 100644 --- a/lisp/progmodes/typescript-ts-mode.el +++ b/lisp/progmodes/typescript-ts-mode.el @@ -317,6 +317,8 @@ Argument LANGUAGE is either `typescript' or `tsx'." object: (identifier) @font-lock-type-face property: (property_identifier) @font-lock-type-face)) + (internal_module (identifier) @font-lock-type-face) + (arrow_function parameter: (identifier) @font-lock-variable-name-face) @@ -509,6 +511,49 @@ See `treesit-thing-settings' for more information.") "Nodes that designate lists in TypeScript. See `treesit-thing-settings' for more information.") +(defvar typescript-ts-mode--defun-type-regexp + (rx bos (or "internal_module" + "interface_declaration" + "class_declaration" + "method_definition" + "function_declaration" + "lexical_declaration") + eos) + "Settings for `treesit-defun-type-regexp'.") + +(defun typescript-ts-mode--defun-name (node) + "Return the defun name of NODE. +Return nil if there is no name or if NODE is not a defun node." + (or (js--treesit-defun-name node) + (treesit-node-text + (pcase (treesit-node-type node) + ("internal_module" + (treesit-node-child node 1)) + ("interface_declaration" + (treesit-node-child-by-field-name node "name"))) + t))) + +(defvar typescript-ts-mode--simple-imenu-settings + `(("Namespace" "\\`internal_module\\'" nil nil) + ("Interface" "\\`interface_declaration\\'" nil nil) + ("Class" "\\`class_declaration\\'" nil nil) + ("Method" "\\`method_definition\\'" nil nil) + ("Function" "\\`function_declaration\\'" nil nil) + ("Variable" ,(rx bos (or "lexical_declaration" + "variable_declaration") + eos) + ,#'js--treesit-valid-imenu-entry nil)) + "Settings for `treesit-simple-imenu'.") + +(defvar typescript-ts-mode--outline-predicate + (rx bos (or "internal_module" + "interface_declaration" + "class_declaration" + "method_definition" + "function_declaration" + "function_expression") + eos)) + ;;;###autoload (define-derived-mode typescript-ts-base-mode prog-mode "TypeScript" "Generic major mode for editing TypeScript. @@ -526,33 +571,21 @@ This mode is intended to be inherited by concrete major modes." (setq-local electric-layout-rules '((?\; . after) (?\{ . after) (?\} . before))) ;; Navigation. - (setq-local treesit-defun-type-regexp - (regexp-opt '("class_declaration" - "method_definition" - "function_declaration" - "lexical_declaration"))) - (setq-local treesit-defun-name-function #'js--treesit-defun-name) + (setq-local treesit-defun-type-regexp typescript-ts-mode--defun-type-regexp) + (setq-local treesit-defun-name-function #'typescript-ts-mode--defun-name) (setq-local treesit-thing-settings `((typescript - (sexp ,(regexp-opt typescript-ts-mode--sexp-nodes 'symbols)) - (list ,(regexp-opt typescript-ts-mode--list-nodes - 'symbols)) - (sentence ,(regexp-opt - typescript-ts-mode--sentence-nodes 'symbols)) - (text ,(regexp-opt '("comment" - "template_string") - 'symbols))))) - - ;; Imenu (same as in `js-ts-mode'). + (sexp ,(js--regexp-opt-symbol typescript-ts-mode--sexp-nodes)) + (list ,(js--regexp-opt-symbol typescript-ts-mode--list-nodes)) + (sentence ,(js--regexp-opt-symbol typescript-ts-mode--sentence-nodes)) + (text ,(js--regexp-opt-symbol '("comment" "template_string")))))) + + ;; Imenu (same as in `js-ts-mode') + namespace/interface. (setq-local treesit-simple-imenu-settings - `(("Function" "\\`function_declaration\\'" nil nil) - ("Variable" "\\`lexical_declaration\\'" - js--treesit-valid-imenu-entry nil) - ("Class" ,(rx bos (or "class_declaration" - "method_definition") - eos) - nil nil)))) + typescript-ts-mode--simple-imenu-settings) + ;; Outline minor mode + (setq-local treesit-outline-predicate typescript-ts-mode--outline-predicate)) ;;;###autoload (define-derived-mode typescript-ts-mode typescript-ts-base-mode "TypeScript" @@ -618,24 +651,21 @@ at least 3 (which is the default value)." (setq-local treesit-thing-settings `((tsx - (sexp ,(regexp-opt + (sexp ,(js--regexp-opt-symbol (append typescript-ts-mode--sexp-nodes '("jsx")))) - (list ,(concat "^" - (regexp-opt - (append typescript-ts-mode--list-nodes - '( - "jsx_element" - "jsx_self_closing_element" - "jsx_expression"))) - "$")) - (sentence ,(regexp-opt + (list ,(js--regexp-opt-symbol + (append typescript-ts-mode--list-nodes + '("jsx_element" + "jsx_self_closing_element" + "jsx_expression")))) + (sentence ,(js--regexp-opt-symbol (append typescript-ts-mode--sentence-nodes - '("jsx_element" - "jsx_self_closing_element")))) - (text ,(regexp-opt '("comment" - "template_string")) - 'symbols)))) + '("jsx_opening_element" + "jsx_attribute" + "jsx_closing_element")))) + (text ,(js--regexp-opt-symbol '("comment" + "template_string")))))) ;; Font-lock. (setq-local treesit-font-lock-settings commit 98ca8b46e692998c13dac19c3806d9d4cf501409 Author: Po Lu Date: Wed Mar 5 15:00:58 2025 +0800 ; * java/AndroidManifest.xml.in (Version-code): Update for Emacs 31. diff --git a/java/AndroidManifest.xml.in b/java/AndroidManifest.xml.in index 66b26e65088..ceec7a97b98 100644 --- a/java/AndroidManifest.xml.in +++ b/java/AndroidManifest.xml.in @@ -350,6 +350,6 @@ repositories require an incrementing numeric version code to detect upgrades, which is provided here and is altered by admin/admin.el. Refer to e.g. https://forum.f-droid.org/t/emacs-packaging/30424/25. -Version-code: 300050000 +Version-code: 310050000 --> commit b06d605bc0d7fd76dc76ba04d3ac8719f9bce5c5 Merge: f5730e02518 121371a7064 Author: Po Lu Date: Wed Mar 5 15:00:22 2025 +0800 Merge from savannah/emacs-30 121371a7064 Move java/incrementing-version-code to AndroidManifest.xm... 8099dc6e3ae Provide an Android version code derived from the Emacs ve... 59fcb2aa1b2 ; * lisp/register.el (register-use-preview): Doc fix (bug... 0383937a701 ; Improve documentation of 'shortdoc' commit f5730e02518ec9758744267fd4866e2240491be9 Merge: 3d7cc22d25c d6288eeb429 Author: Po Lu Date: Wed Mar 5 15:00:22 2025 +0800 ; Merge from savannah/emacs-30 The following commit was skipped: d6288eeb429 image-dired: Don't croak on file names with regexp charac... commit 3d7cc22d25cef88464f18e5cc69eb696f8c8a4a2 Author: Po Lu Date: Wed Mar 5 14:32:34 2025 +0800 Permit executing programs with >1024 args on Android * src/android.c (MAXARGS): Delete enumerator. (android_rewrite_spawn_argv): Don't mandate a maximum number of arguments. diff --git a/src/android.c b/src/android.c index b7d68def467..6a6996a438b 100644 --- a/src/android.c +++ b/src/android.c @@ -7389,12 +7389,6 @@ android_free_cursor (android_cursor cursor) application data directory to manually load executables and replace the `execve' system call. */ -enum - { - /* Maximum number of arguments available. */ - MAXARGS = 1024, - }; - /* Rewrite the command line given in *ARGV to utilize the `exec1' bootstrap binary if necessary. @@ -7406,9 +7400,11 @@ enum int android_rewrite_spawn_argv (const char ***argv) { - static const char *new_args[MAXARGS]; - static char exec1_name[PATH_MAX], loader_name[PATH_MAX]; + static const char **new_args; + static size_t n_new_args; + static char exec1_name[PATH_MAX + 1], loader_name[PATH_MAX + 1]; size_t i, nargs; + int n; /* This isn't required on Android 9 or earlier. */ @@ -7428,22 +7424,25 @@ android_rewrite_spawn_argv (const char ***argv) while ((*argv)[nargs]) ++nargs; - /* nargs now holds the number of arguments in argv. If it's larger - than MAXARGS, return failure. */ - - if (nargs + 2 > MAXARGS) + /* Allocate a buffer in which to save the rewritten argument + array. */ + if (n_new_args != nargs) { - errno = E2BIG; - return 1; + new_args = xrealloc (new_args, sizeof *new_args * (nargs + 3)); + n_new_args = nargs + 2; } /* Fill in the name of `libexec1.so'. */ - snprintf (exec1_name, PATH_MAX, "%s/libexec1.so", - android_lib_dir); + n = snprintf (exec1_name, PATH_MAX + 1, "%s/libexec1.so", + android_lib_dir); + if (n >= PATH_MAX) + goto name_too_long; /* And libloader.so. */ - snprintf (loader_name, PATH_MAX, "%s/libloader.so", - android_lib_dir); + n = snprintf (loader_name, PATH_MAX + 1, "%s/libloader.so", + android_lib_dir); + if (n >= PATH_MAX) + goto name_too_long; /* Now fill in the first two arguments. */ new_args[0] = exec1_name; @@ -7458,6 +7457,10 @@ android_rewrite_spawn_argv (const char ***argv) /* Return success. */ return 0; + + name_too_long: + errno = ENAMETOOLONG; + return 0; } commit 336cc32f2aa83a06dbbde42463a99e2f5c94f8ff Author: Po Lu Date: Wed Mar 5 14:17:06 2025 +0800 ; * src/nsterm.m (syms_of_nsterm): Fix typo in comment. diff --git a/src/nsterm.m b/src/nsterm.m index fcd9377646f..f6fd43a1889 100644 --- a/src/nsterm.m +++ b/src/nsterm.m @@ -11300,10 +11300,9 @@ Nil means use fullscreen the old (< 10.7) way. The old way works better with doc: /* SKIP: real doc in xterm.c. */); x_underline_at_descent_line = 0; - // TODO: add an "auto" mode that passes clicks through to "utility" UI - // elements, selectis windows, and so on, but doesn't pass them - // through for commands in general --- consistent with - // other applications. + /* TODO: add an "auto" mode that passes clicks through to "utility" UI + elements, selects windows, and so on, but doesn't pass them through + for commands in general--as with other applications. */ DEFVAR_BOOL ("ns-click-through", ns_click_through, commit 121371a706491fde8c06d95b13c16703d53f6fa3 Author: Po Lu Date: Wed Mar 5 14:59:19 2025 +0800 Move java/incrementing-version-code to AndroidManifest.xml.in * admin/admin.el (admin-android-version-code-regexp): New variable. (set-version): Modify AndroidManifest.xml.in instead. * java/AndroidManifest.xml.in (Version-code): Define version code. * java/incrementing-version-code: Delete file. diff --git a/admin/admin.el b/admin/admin.el index 12891bc8c48..0f02ac8d9b1 100644 --- a/admin/admin.el +++ b/admin/admin.el @@ -98,6 +98,10 @@ Optional argument DATE is the release date, default today." (defvar admin-git-command (executable-find "git") "The `git' program to use.") +(defvar admin-android-version-code-regexp + "\\bAuto-incrementing version code\\(?:.\\|\n\\)*\\([[:digit:]]\\{9\\}\\)$" + "Regexp with which to detect the version code in AndroidManifest.xml.") + (defun set-version (root version) "Set Emacs version to VERSION in relevant files under ROOT. Root must be the root of an Emacs source tree." @@ -122,13 +126,11 @@ Root must be the root of an Emacs source tree." (rx (and "AC_INIT" (1+ (not (in ?,))) ?, (0+ space) ?\[ (submatch (1+ (in "0-9.")))))) - (set-version-in-file root "java/incrementing-version-code" + (set-version-in-file root "java/AndroidManifest.xml.in" (apply #'format "%02d%02d%02d000" (mapcar #'string-to-number (split-string version "\\."))) - (rx (and line-start - (submatch (1+ (in digit))) - line-end))) + admin-android-version-code-regexp) (set-version-in-file root "nt/README.W32" version (rx (and "version" (1+ space) (submatch (1+ (in "0-9.")))))) diff --git a/java/AndroidManifest.xml.in b/java/AndroidManifest.xml.in index 6243c5e13ba..92b63925ef4 100644 --- a/java/AndroidManifest.xml.in +++ b/java/AndroidManifest.xml.in @@ -338,3 +338,18 @@ along with GNU Emacs. If not, see . --> android:label="GNU Emacs service"/> + + diff --git a/java/incrementing-version-code b/java/incrementing-version-code index fed5b627275..e69de29bb2d 100644 --- a/java/incrementing-version-code +++ b/java/incrementing-version-code @@ -1,12 +0,0 @@ -; This file contains an Android version code -; (https://developer.android.com/studio/publish/versioning#versioningsettings) -; corresponding to the current Emacs version. -; -; The version code in AndroidManifest.xml.in is hard-coded to a fixed -; value, to make package downgrades possible. Where an incrementing -; version code is required (for example, for automated F-Droid package -; builds (https://f-droid.org/packages/org.gnu.emacs/)), the version -; code in this file should be referred to and patched in to -; AndroidManifest.xml. - -300093000 commit 8099dc6e3aeae5bfd8a4115deed88022500362e1 Author: Peter Oliver Date: Mon Jan 27 10:59:19 2025 +0000 Provide an Android version code derived from the Emacs version The version code is intended to be an integer that increments for each Android package release (https://developer.android.com/studio/publish/versioning#versioningsettings). If we keep this updated under version control, then F-Droid (a third-party Android package repository), can watch for that, and use it to automatically build Emacs packages for Android each time a new Emacs release is tagged (https://f-droid.org/en/docs/Build_Metadata_Reference/#UpdateCheckData). * admin/admin.el (set-version): Update version code in java/incrementing-version-code * java/incrementing-version-code: New file containing an Android version code corresponding to the current Emacs version. (bug#75809) diff --git a/admin/admin.el b/admin/admin.el index 8fc970ed430..12891bc8c48 100644 --- a/admin/admin.el +++ b/admin/admin.el @@ -122,6 +122,13 @@ Root must be the root of an Emacs source tree." (rx (and "AC_INIT" (1+ (not (in ?,))) ?, (0+ space) ?\[ (submatch (1+ (in "0-9.")))))) + (set-version-in-file root "java/incrementing-version-code" + (apply #'format "%02d%02d%02d000" + (mapcar #'string-to-number + (split-string version "\\."))) + (rx (and line-start + (submatch (1+ (in digit))) + line-end))) (set-version-in-file root "nt/README.W32" version (rx (and "version" (1+ space) (submatch (1+ (in "0-9.")))))) diff --git a/java/incrementing-version-code b/java/incrementing-version-code new file mode 100644 index 00000000000..fed5b627275 --- /dev/null +++ b/java/incrementing-version-code @@ -0,0 +1,12 @@ +; This file contains an Android version code +; (https://developer.android.com/studio/publish/versioning#versioningsettings) +; corresponding to the current Emacs version. +; +; The version code in AndroidManifest.xml.in is hard-coded to a fixed +; value, to make package downgrades possible. Where an incrementing +; version code is required (for example, for automated F-Droid package +; builds (https://f-droid.org/packages/org.gnu.emacs/)), the version +; code in this file should be referred to and patched in to +; AndroidManifest.xml. + +300093000 commit 7ba62284137ba162df16f55c75bda4d56da7dfe7 Author: Stefan Kangas Date: Wed Mar 5 03:36:04 2025 +0100 Make byte-compile-cond-use-jump-table obsolete This user option was introduced in 2017, with the rationale: "This is a workaround for when `byte-compile-cond-jump-table' accidentally generates wrong code (hasn't happened so far in my tests), and should be removed once we're sure there are no issues with it." https://lists.gnu.org/r/emacs-devel/2017-02/msg00223.html There hasn't been any bugs in this area within the last 6 years, and the few we did see before that were quickly resolved. Let's declare this variable obsolete now, while keeping its behavior when set to nil. We can always revert the obsoletion if it turns out to be needed after all. * lisp/emacs-lisp/bytecomp.el (byte-compile-cond-use-jump-table): Declare obsolete. diff --git a/etc/NEWS b/etc/NEWS index dac447d1ba5..ef4cacb20f9 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -362,6 +362,8 @@ Setting this variable to a non-nil value reduces performance and leads to wrong results in some cases. We believe that it is no longer useful; please contact us if you still need it for some reason. +** 'byte-compile-cond-use-jump-table' is now obsolete. + * Editing Changes in Emacs 31.1 diff --git a/lisp/emacs-lisp/bytecomp.el b/lisp/emacs-lisp/bytecomp.el index 66407774007..1807f8674fb 100644 --- a/lisp/emacs-lisp/bytecomp.el +++ b/lisp/emacs-lisp/bytecomp.el @@ -242,6 +242,7 @@ This includes variable references and calls to functions such as `car'." "Compile `cond' clauses to a jump table implementation (using a hash-table)." :version "26.1" :type 'boolean) +(make-obsolete-variable 'byte-compile-cond-use-jump-table nil "31.1") (defvar byte-compile-dynamic nil "Formerly used to compile function bodies so they load lazily. commit 8c8ff13e7bdaab1446873d3401fe1a53a827198d Author: Stefan Kangas Date: Wed Mar 5 02:42:10 2025 +0100 Clean up 'cl-' prefixes for local variables The 'cl-' prefixes used for let-bound variables and argument names is a holdover from the dynbind days. They are no longer necessary, and make the code hard to read. This was partially cleaned up in the past; let's finish the job now. * lisp/emacs-lisp/cl-extra.el (cl--mapcar-many, cl-map, cl-maplist) (cl-mapc, cl-mapl, cl-mapcan, cl-mapcon, cl-some, cl-every, cl-notany) (cl-notevery, cl--map-keymap-recursively, cl--map-intervals) (cl--map-overlays): * lisp/emacs-lisp/cl-lib.el (cl-mapcar, cl-adjoin, cl-subst) (cl--do-subst): * lisp/emacs-lisp/cl-macs.el (cl--parse-loop-clause): * lisp/emacs-lisp/cl-seq.el (cl-reduce, cl-fill, cl-replace, cl-remove) (cl-remove-if, cl-remove-if-not, cl-delete, cl-delete-if) (cl-delete-if-not, cl-remove-duplicates, cl-delete-duplicates) (cl--delete-duplicates, cl-substitute, cl-substitute-if) (cl-substitute-if-not, cl-nsubstitute, cl-nsubstitute-if) (cl-nsubstitute-if-not, cl-find, cl-find-if, cl-find-if-not) (cl-position, cl--position, cl-position-if, cl-position-if-not) (cl-count, cl-count-if, cl-count-if-not, cl-mismatch, cl-search) (cl-sort, cl-stable-sort, cl-merge, cl-member, cl-member-if) (cl-member-if-not, cl--adjoin, cl-assoc, cl-assoc-if, cl-assoc-if-not) (cl-rassoc, cl-rassoc-if, cl-rassoc-if-not, cl-union, cl-nunion) (cl-intersection, cl-nintersection, cl-set-difference) (cl-nset-difference, cl-set-exclusive-or, cl-nset-exclusive-or) (cl-subsetp, cl-subst-if, cl-subst-if-not, cl-nsubst, cl-nsubst-if) (cl-nsubst-if-not, cl-sublis, cl--sublis-rec, cl-nsublis) (cl--nsublis-rec, cl-tree-equal, cl--tree-equal-rec): Clean up 'cl-' prefixes for let-bound variables and arguments. diff --git a/lisp/emacs-lisp/cl-extra.el b/lisp/emacs-lisp/cl-extra.el index 0e77b4543bd..6390d17a5b7 100644 --- a/lisp/emacs-lisp/cl-extra.el +++ b/lisp/emacs-lisp/cl-extra.el @@ -91,120 +91,120 @@ strings case-insensitively." ;;; Control structures. ;;;###autoload -(defun cl--mapcar-many (cl-func cl-seqs &optional acc) - (if (cdr (cdr cl-seqs)) - (let* ((cl-res nil) - (cl-n (apply #'min (mapcar #'length cl-seqs))) - (cl-i 0) - (cl-args (copy-sequence cl-seqs)) - cl-p1 cl-p2) - (setq cl-seqs (copy-sequence cl-seqs)) - (while (< cl-i cl-n) - (setq cl-p1 cl-seqs cl-p2 cl-args) - (while cl-p1 - (setcar cl-p2 - (if (consp (car cl-p1)) - (prog1 (car (car cl-p1)) - (setcar cl-p1 (cdr (car cl-p1)))) - (aref (car cl-p1) cl-i))) - (setq cl-p1 (cdr cl-p1) cl-p2 (cdr cl-p2))) +(defun cl--mapcar-many (func seqs &optional acc) + (if (cdr (cdr seqs)) + (let* ((res nil) + (n (apply #'min (mapcar #'length seqs))) + (i 0) + (args (copy-sequence seqs)) + p1 p2) + (setq seqs (copy-sequence seqs)) + (while (< i n) + (setq p1 seqs p2 args) + (while p1 + (setcar p2 + (if (consp (car p1)) + (prog1 (car (car p1)) + (setcar p1 (cdr (car p1)))) + (aref (car p1) i))) + (setq p1 (cdr p1) p2 (cdr p2))) (if acc - (push (apply cl-func cl-args) cl-res) - (apply cl-func cl-args)) - (setq cl-i (1+ cl-i))) - (and acc (nreverse cl-res))) - (let ((cl-res nil) - (cl-x (car cl-seqs)) - (cl-y (nth 1 cl-seqs))) - (let ((cl-n (min (length cl-x) (length cl-y))) - (cl-i -1)) - (while (< (setq cl-i (1+ cl-i)) cl-n) - (let ((val (funcall cl-func - (if (consp cl-x) (pop cl-x) (aref cl-x cl-i)) - (if (consp cl-y) (pop cl-y) (aref cl-y cl-i))))) + (push (apply func args) res) + (apply func args)) + (setq i (1+ i))) + (and acc (nreverse res))) + (let ((res nil) + (x (car seqs)) + (y (nth 1 seqs))) + (let ((n (min (length x) (length y))) + (i -1)) + (while (< (setq i (1+ i)) n) + (let ((val (funcall func + (if (consp x) (pop x) (aref x i)) + (if (consp y) (pop y) (aref y i))))) (when acc - (push val cl-res))))) - (and acc (nreverse cl-res))))) + (push val res))))) + (and acc (nreverse res))))) ;;;###autoload -(defsubst cl-map (cl-type cl-func cl-seq &rest cl-rest) +(defsubst cl-map (type func seq &rest rest) "Map a FUNCTION across one or more SEQUENCEs, returning a sequence. TYPE is the sequence type to return. \n(fn TYPE FUNCTION SEQUENCE...)" (declare (important-return-value t)) - (let ((cl-res (apply 'cl-mapcar cl-func cl-seq cl-rest))) - (and cl-type (cl-coerce cl-res cl-type)))) + (let ((res (apply 'cl-mapcar func seq rest))) + (and type (cl-coerce res type)))) ;;;###autoload -(defun cl-maplist (cl-func cl-list &rest cl-rest) +(defun cl-maplist (func list &rest rest) "Map FUNCTION to each sublist of LIST or LISTs. Like `cl-mapcar', except applies to lists and their cdr's rather than to the elements themselves. \n(fn FUNCTION LIST...)" (declare (important-return-value t)) - (if cl-rest - (let ((cl-res nil) - (cl-args (cons cl-list (copy-sequence cl-rest))) - cl-p) - (while (not (memq nil cl-args)) - (push (apply cl-func cl-args) cl-res) - (setq cl-p cl-args) - (while cl-p (setcar cl-p (cdr (pop cl-p))))) - (nreverse cl-res)) - (let ((cl-res nil)) - (while cl-list - (push (funcall cl-func cl-list) cl-res) - (setq cl-list (cdr cl-list))) - (nreverse cl-res)))) - -;;;###autoload -(defun cl-mapc (cl-func cl-seq &rest cl-rest) + (if rest + (let ((res nil) + (args (cons list (copy-sequence rest))) + p) + (while (not (memq nil args)) + (push (apply func args) res) + (setq p args) + (while p (setcar p (cdr (pop p))))) + (nreverse res)) + (let ((res nil)) + (while list + (push (funcall func list) res) + (setq list (cdr list))) + (nreverse res)))) + +;;;###autoload +(defun cl-mapc (func seq &rest rest) "Like `cl-mapcar', but does not accumulate values returned by the function. \n(fn FUNCTION SEQUENCE...)" - (if cl-rest - (if (or (cdr cl-rest) (nlistp cl-seq) (nlistp (car cl-rest))) + (if rest + (if (or (cdr rest) (nlistp seq) (nlistp (car rest))) (progn - (cl--mapcar-many cl-func (cons cl-seq cl-rest)) - cl-seq) - (let ((cl-x cl-seq) (cl-y (car cl-rest))) - (while (and cl-x cl-y) - (funcall cl-func (pop cl-x) (pop cl-y))) - cl-seq)) - (mapc cl-func cl-seq))) + (cl--mapcar-many func (cons seq rest)) + seq) + (let ((x seq) (y (car rest))) + (while (and x y) + (funcall func (pop x) (pop y))) + seq)) + (mapc func seq))) ;;;###autoload -(defun cl-mapl (cl-func cl-list &rest cl-rest) +(defun cl-mapl (func list &rest rest) "Like `cl-maplist', but does not accumulate values returned by the function. \n(fn FUNCTION LIST...)" - (if cl-rest - (let ((cl-args (cons cl-list (copy-sequence cl-rest))) - cl-p) - (while (not (memq nil cl-args)) - (apply cl-func cl-args) - (setq cl-p cl-args) - (while cl-p (setcar cl-p (cdr (pop cl-p)))))) - (let ((cl-p cl-list)) - (while cl-p (funcall cl-func cl-p) (setq cl-p (cdr cl-p))))) - cl-list) - -;;;###autoload -(defun cl-mapcan (cl-func cl-seq &rest cl-rest) + (if rest + (let ((args (cons list (copy-sequence rest))) + p) + (while (not (memq nil args)) + (apply func args) + (setq p args) + (while p (setcar p (cdr (pop p)))))) + (let ((p list)) + (while p (funcall func p) (setq p (cdr p))))) + list) + +;;;###autoload +(defun cl-mapcan (func seq &rest rest) "Like `cl-mapcar', but nconc's together the values returned by the function. \n(fn FUNCTION SEQUENCE...)" (declare (important-return-value t)) - (if cl-rest - (apply #'nconc (apply #'cl-mapcar cl-func cl-seq cl-rest)) - (mapcan cl-func cl-seq))) + (if rest + (apply #'nconc (apply #'cl-mapcar func seq rest)) + (mapcan func seq))) ;;;###autoload -(defun cl-mapcon (cl-func cl-list &rest cl-rest) +(defun cl-mapcon (func list &rest rest) "Like `cl-maplist', but nconc's together the values returned by the function. \n(fn FUNCTION LIST...)" (declare (important-return-value t)) - (apply #'nconc (apply #'cl-maplist cl-func cl-list cl-rest))) + (apply #'nconc (apply #'cl-maplist func list rest))) ;;;###autoload -(defun cl-some (cl-pred cl-seq &rest cl-rest) +(defun cl-some (pred seq &rest rest) "Say whether PREDICATE is true for any element in the SEQ sequences. More specifically, the return value of this function will be the same as the first return value of PREDICATE where PREDICATE has a @@ -212,105 +212,105 @@ non-nil value. \n(fn PREDICATE SEQ...)" (declare (important-return-value t)) - (if (or cl-rest (nlistp cl-seq)) + (if (or rest (nlistp seq)) (catch 'cl-some (apply #'cl-map nil - (lambda (&rest cl-x) - (let ((cl-res (apply cl-pred cl-x))) - (if cl-res (throw 'cl-some cl-res)))) - cl-seq cl-rest) nil) - (let ((cl-x nil)) - (while (and cl-seq (not (setq cl-x (funcall cl-pred (pop cl-seq)))))) - cl-x))) + (lambda (&rest x) + (let ((res (apply pred x))) + (if res (throw 'cl-some res)))) + seq rest) nil) + (let ((x nil)) + (while (and seq (not (setq x (funcall pred (pop seq)))))) + x))) ;;;###autoload -(defun cl-every (cl-pred cl-seq &rest cl-rest) +(defun cl-every (pred seq &rest rest) "Return true if PREDICATE is true of every element of SEQ or SEQs. \n(fn PREDICATE SEQ...)" (declare (important-return-value t)) - (if (or cl-rest (nlistp cl-seq)) + (if (or rest (nlistp seq)) (catch 'cl-every (apply #'cl-map nil - (lambda (&rest cl-x) - (or (apply cl-pred cl-x) (throw 'cl-every nil))) - cl-seq cl-rest) t) - (while (and cl-seq (funcall cl-pred (car cl-seq))) - (setq cl-seq (cdr cl-seq))) - (null cl-seq))) + (lambda (&rest x) + (or (apply pred x) (throw 'cl-every nil))) + seq rest) t) + (while (and seq (funcall pred (car seq))) + (setq seq (cdr seq))) + (null seq))) ;;;###autoload -(defsubst cl-notany (cl-pred cl-seq &rest cl-rest) +(defsubst cl-notany (pred seq &rest rest) "Return true if PREDICATE is false of every element of SEQ or SEQs. \n(fn PREDICATE SEQ...)" (declare (important-return-value t)) - (not (apply #'cl-some cl-pred cl-seq cl-rest))) + (not (apply #'cl-some pred seq rest))) ;;;###autoload -(defsubst cl-notevery (cl-pred cl-seq &rest cl-rest) +(defsubst cl-notevery (pred seq &rest rest) "Return true if PREDICATE is false of some element of SEQ or SEQs. \n(fn PREDICATE SEQ...)" (declare (important-return-value t)) - (not (apply #'cl-every cl-pred cl-seq cl-rest))) + (not (apply #'cl-every pred seq rest))) ;;;###autoload -(defun cl--map-keymap-recursively (cl-func-rec cl-map &optional cl-base) - (or cl-base - (setq cl-base (copy-sequence [0]))) +(defun cl--map-keymap-recursively (func-rec map &optional base) + (or base + (setq base (copy-sequence [0]))) (map-keymap - (lambda (cl-key cl-bind) - (aset cl-base (1- (length cl-base)) cl-key) - (if (keymapp cl-bind) + (lambda (key bind) + (aset base (1- (length base)) key) + (if (keymapp bind) (cl--map-keymap-recursively - cl-func-rec cl-bind - (vconcat cl-base (list 0))) - (funcall cl-func-rec cl-base cl-bind))) - cl-map)) - -;;;###autoload -(defun cl--map-intervals (cl-func &optional cl-what cl-prop cl-start cl-end) - (or cl-what (setq cl-what (current-buffer))) - (if (bufferp cl-what) - (let (cl-mark cl-mark2 (cl-next t) cl-next2) - (with-current-buffer cl-what - (setq cl-mark (copy-marker (or cl-start (point-min)))) - (setq cl-mark2 (and cl-end (copy-marker cl-end)))) - (while (and cl-next (or (not cl-mark2) (< cl-mark cl-mark2))) - (setq cl-next (if cl-prop (next-single-property-change - cl-mark cl-prop cl-what) - (next-property-change cl-mark cl-what)) - cl-next2 (or cl-next (with-current-buffer cl-what - (point-max)))) - (funcall cl-func (prog1 (marker-position cl-mark) - (set-marker cl-mark cl-next2)) - (if cl-mark2 (min cl-next2 cl-mark2) cl-next2))) - (set-marker cl-mark nil) (if cl-mark2 (set-marker cl-mark2 nil))) - (or cl-start (setq cl-start 0)) - (or cl-end (setq cl-end (length cl-what))) - (while (< cl-start cl-end) - (let ((cl-next (or (if cl-prop (next-single-property-change - cl-start cl-prop cl-what) - (next-property-change cl-start cl-what)) - cl-end))) - (funcall cl-func cl-start (min cl-next cl-end)) - (setq cl-start cl-next))))) - -;;;###autoload -(defun cl--map-overlays (cl-func &optional cl-buffer cl-start cl-end cl-arg) - (or cl-buffer (setq cl-buffer (current-buffer))) - (let (cl-ovl) - (with-current-buffer cl-buffer - (setq cl-ovl (overlay-lists)) - (if cl-start (setq cl-start (copy-marker cl-start))) - (if cl-end (setq cl-end (copy-marker cl-end)))) - (setq cl-ovl (nconc (car cl-ovl) (cdr cl-ovl))) - (while (and cl-ovl - (or (not (overlay-start (car cl-ovl))) - (and cl-end (>= (overlay-start (car cl-ovl)) cl-end)) - (and cl-start (<= (overlay-end (car cl-ovl)) cl-start)) - (not (funcall cl-func (car cl-ovl) cl-arg)))) - (setq cl-ovl (cdr cl-ovl))) - (if cl-start (set-marker cl-start nil)) - (if cl-end (set-marker cl-end nil)))) + func-rec bind + (vconcat base (list 0))) + (funcall func-rec base bind))) + map)) + +;;;###autoload +(defun cl--map-intervals (func &optional what prop start end) + (or what (setq what (current-buffer))) + (if (bufferp what) + (let (mark mark2 (next t) next2) + (with-current-buffer what + (setq mark (copy-marker (or start (point-min)))) + (setq mark2 (and end (copy-marker end)))) + (while (and next (or (not mark2) (< mark mark2))) + (setq next (if prop (next-single-property-change + mark prop what) + (next-property-change mark what)) + next2 (or next (with-current-buffer what + (point-max)))) + (funcall func (prog1 (marker-position mark) + (set-marker mark next2)) + (if mark2 (min next2 mark2) next2))) + (set-marker mark nil) (if mark2 (set-marker mark2 nil))) + (or start (setq start 0)) + (or end (setq end (length what))) + (while (< start end) + (let ((next (or (if prop (next-single-property-change + start prop what) + (next-property-change start what)) + end))) + (funcall func start (min next end)) + (setq start next))))) + +;;;###autoload +(defun cl--map-overlays (func &optional buffer start end arg) + (or buffer (setq buffer (current-buffer))) + (let (ovl) + (with-current-buffer buffer + (setq ovl (overlay-lists)) + (if start (setq start (copy-marker start))) + (if end (setq end (copy-marker end)))) + (setq ovl (nconc (car ovl) (cdr ovl))) + (while (and ovl + (or (not (overlay-start (car ovl))) + (and end (>= (overlay-start (car ovl)) end)) + (and start (<= (overlay-end (car ovl)) start)) + (not (funcall func (car ovl) arg)))) + (setq ovl (cdr ovl))) + (if start (set-marker start nil)) + (if end (set-marker end nil)))) ;;; Support for `setf'. ;;;###autoload diff --git a/lisp/emacs-lisp/cl-lib.el b/lisp/emacs-lisp/cl-lib.el index 2bab451dd0c..4208160bd12 100644 --- a/lisp/emacs-lisp/cl-lib.el +++ b/lisp/emacs-lisp/cl-lib.el @@ -362,7 +362,7 @@ Call `cl-float-limits' to set this.") (declare-function cl--mapcar-many "cl-extra" (cl-func cl-seqs &optional acc)) -(defun cl-mapcar (cl-func cl-x &rest cl-rest) +(defun cl-mapcar (func x &rest rest) "Apply FUNCTION to each element of SEQ, and make a list of the results. If there are several SEQs, FUNCTION is called with that many arguments, and mapping stops as soon as the shortest list runs out. With just one @@ -370,14 +370,14 @@ SEQ, this is like `mapcar'. With several, it is like the Common Lisp `mapcar' function extended to arbitrary sequence types. \n(fn FUNCTION SEQ...)" (declare (important-return-value t)) - (if cl-rest - (if (or (cdr cl-rest) (nlistp cl-x) (nlistp (car cl-rest))) - (cl--mapcar-many cl-func (cons cl-x cl-rest) 'accumulate) - (let ((cl-res nil) (cl-y (car cl-rest))) - (while (and cl-x cl-y) - (push (funcall cl-func (pop cl-x) (pop cl-y)) cl-res)) - (nreverse cl-res))) - (mapcar cl-func cl-x))) + (if rest + (if (or (cdr rest) (nlistp x) (nlistp (car rest))) + (cl--mapcar-many func (cons x rest) 'accumulate) + (let ((res nil) (y (car rest))) + (while (and x y) + (push (funcall func (pop x) (pop y)) res)) + (nreverse res))) + (mapcar func x))) (cl--defalias 'cl-svref #'aref) @@ -502,38 +502,38 @@ The elements of LIST are not copied, just the list structure itself." (declare-function cl-round "cl-extra" (x &optional y)) (declare-function cl-mod "cl-extra" (x y)) -(defun cl-adjoin (cl-item cl-list &rest cl-keys) +(defun cl-adjoin (item list &rest keys) "Return ITEM consed onto the front of LIST only if it's not already there. Otherwise, return LIST unmodified. \nKeywords supported: :test :test-not :key \n(fn ITEM LIST [KEYWORD VALUE]...)" (declare (important-return-value t) (compiler-macro cl--compiler-macro-adjoin)) - (cond ((or (equal cl-keys '(:test eq)) - (and (null cl-keys) (not (numberp cl-item)))) - (if (memq cl-item cl-list) cl-list (cons cl-item cl-list))) - ((or (equal cl-keys '(:test equal)) (null cl-keys)) - (if (member cl-item cl-list) cl-list (cons cl-item cl-list))) - (t (apply 'cl--adjoin cl-item cl-list cl-keys)))) - -(defun cl-subst (cl-new cl-old cl-tree &rest cl-keys) + (cond ((or (equal keys '(:test eq)) + (and (null keys) (not (numberp item)))) + (if (memq item list) list (cons item list))) + ((or (equal keys '(:test equal)) (null keys)) + (if (member item list) list (cons item list))) + (t (apply 'cl--adjoin item list keys)))) + +(defun cl-subst (new old tree &rest keys) "Substitute NEW for OLD everywhere in TREE (non-destructively). Return a copy of TREE with all elements `eql' to OLD replaced by NEW. \nKeywords supported: :test :test-not :key \n(fn NEW OLD TREE [KEYWORD VALUE]...)" (declare (important-return-value t)) - (if (or cl-keys (and (numberp cl-old) (not (integerp cl-old)))) - (apply 'cl-sublis (list (cons cl-old cl-new)) cl-tree cl-keys) - (cl--do-subst cl-new cl-old cl-tree))) - -(defun cl--do-subst (cl-new cl-old cl-tree) - (cond ((eq cl-tree cl-old) cl-new) - ((consp cl-tree) - (let ((a (cl--do-subst cl-new cl-old (car cl-tree))) - (d (cl--do-subst cl-new cl-old (cdr cl-tree)))) - (if (and (eq a (car cl-tree)) (eq d (cdr cl-tree))) - cl-tree (cons a d)))) - (t cl-tree))) + (if (or keys (and (numberp old) (not (integerp old)))) + (apply 'cl-sublis (list (cons old new)) tree keys) + (cl--do-subst new old tree))) + +(defun cl--do-subst (new old tree) + (cond ((eq tree old) new) + ((consp tree) + (let ((a (cl--do-subst new old (car tree))) + (d (cl--do-subst new old (cdr tree)))) + (if (and (eq a (car tree)) (eq d (cdr tree))) + tree (cons a d)))) + (t tree))) (defsubst cl-acons (key value alist) "Add KEY and VALUE to ALIST. diff --git a/lisp/emacs-lisp/cl-macs.el b/lisp/emacs-lisp/cl-macs.el index d3d4524028d..2a12aa8f7b0 100644 --- a/lisp/emacs-lisp/cl-macs.el +++ b/lisp/emacs-lisp/cl-macs.el @@ -1481,7 +1481,7 @@ For more details, see Info node `(cl)Loop Facility'. ((memq word key-types) (or (memq (car cl--loop-args) '(in of)) (error "Expected `of'")) - (let ((cl-map (cl--pop2 cl--loop-args)) + (let ((map (cl--pop2 cl--loop-args)) (other (if (eq (car cl--loop-args) 'using) (if (and (= (length (cadr cl--loop-args)) 2) @@ -1496,7 +1496,7 @@ For more details, see Info node `(cl)Loop Facility'. 'keys (lambda (body) `(,(if (memq word '(key-seq key-seqs)) 'cl--map-keymap-recursively 'map-keymap) - (lambda (,var ,other) . ,body) ,cl-map))))) + (lambda (,var ,other) . ,body) ,map))))) ((memq word '(frame frames screen screens)) (let ((temp (make-symbol "--cl-var--"))) diff --git a/lisp/emacs-lisp/cl-seq.el b/lisp/emacs-lisp/cl-seq.el index 6e51b895b46..934c1658ca2 100644 --- a/lisp/emacs-lisp/cl-seq.el +++ b/lisp/emacs-lisp/cl-seq.el @@ -120,7 +120,7 @@ Signal an error if X is not a list." (null x)) ;;;###autoload -(defun cl-reduce (cl-func cl-seq &rest cl-keys) +(defun cl-reduce (func seq &rest cl-keys) "Reduce two-argument FUNCTION across SEQ. \nKeywords supported: :start :end :from-end :initial-value :key @@ -147,549 +147,549 @@ FUNCTION is also reversed. \n(fn FUNCTION SEQ [KEYWORD VALUE]...)" (declare (important-return-value t)) (cl--parsing-keywords (:from-end (:start 0) :end :initial-value :key) () - (or (listp cl-seq) (setq cl-seq (append cl-seq nil))) - (setq cl-seq (cl-subseq cl-seq cl-start cl-end)) - (if cl-from-end (setq cl-seq (nreverse cl-seq))) - (let ((cl-accum (cond ((memq :initial-value cl-keys) cl-initial-value) - (cl-seq (cl--check-key (pop cl-seq))) - (t (funcall cl-func))))) + (or (listp seq) (setq seq (append seq nil))) + (setq seq (cl-subseq seq cl-start cl-end)) + (if cl-from-end (setq seq (nreverse seq))) + (let ((accum (cond ((memq :initial-value cl-keys) cl-initial-value) + (seq (cl--check-key (pop seq))) + (t (funcall func))))) (if cl-from-end - (while cl-seq - (setq cl-accum (funcall cl-func (cl--check-key (pop cl-seq)) - cl-accum))) - (while cl-seq - (setq cl-accum (funcall cl-func cl-accum - (cl--check-key (pop cl-seq)))))) - cl-accum))) + (while seq + (setq accum (funcall func (cl--check-key (pop seq)) + accum))) + (while seq + (setq accum (funcall func accum + (cl--check-key (pop seq)))))) + accum))) ;;;###autoload -(defun cl-fill (cl-seq cl-item &rest cl-keys) +(defun cl-fill (seq item &rest cl-keys) "Fill the elements of SEQ with ITEM. \nKeywords supported: :start :end \n(fn SEQ ITEM [KEYWORD VALUE]...)" (cl--parsing-keywords ((:start 0) :end) () - (if (listp cl-seq) - (let ((p (nthcdr cl-start cl-seq)) + (if (listp seq) + (let ((p (nthcdr cl-start seq)) (n (and cl-end (- cl-end cl-start)))) (while (and p (or (null n) (>= (decf n) 0))) - (setcar p cl-item) + (setcar p item) (setq p (cdr p)))) - (or cl-end (setq cl-end (length cl-seq))) - (if (and (= cl-start 0) (= cl-end (length cl-seq))) - (fillarray cl-seq cl-item) + (or cl-end (setq cl-end (length seq))) + (if (and (= cl-start 0) (= cl-end (length seq))) + (fillarray seq item) (while (< cl-start cl-end) - (aset cl-seq cl-start cl-item) + (aset seq cl-start item) (setq cl-start (1+ cl-start))))) - cl-seq)) + seq)) ;;;###autoload -(defun cl-replace (cl-seq1 cl-seq2 &rest cl-keys) +(defun cl-replace (seq1 seq2 &rest cl-keys) "Replace the elements of SEQ1 with the elements of SEQ2. SEQ1 is destructively modified, then returned. \nKeywords supported: :start1 :end1 :start2 :end2 \n(fn SEQ1 SEQ2 [KEYWORD VALUE]...)" (cl--parsing-keywords ((:start1 0) :end1 (:start2 0) :end2) () - (if (and (eq cl-seq1 cl-seq2) (<= cl-start2 cl-start1)) + (if (and (eq seq1 seq2) (<= cl-start2 cl-start1)) (or (= cl-start1 cl-start2) - (let* ((cl-len (length cl-seq1)) - (cl-n (min (- (or cl-end1 cl-len) cl-start1) - (- (or cl-end2 cl-len) cl-start2)))) - (while (>= (setq cl-n (1- cl-n)) 0) - (setf (elt cl-seq1 (+ cl-start1 cl-n)) - (elt cl-seq2 (+ cl-start2 cl-n)))))) - (if (listp cl-seq1) - (let ((cl-p1 (nthcdr cl-start1 cl-seq1)) - (cl-n1 (and cl-end1 (- cl-end1 cl-start1)))) - (if (listp cl-seq2) - (let ((cl-p2 (nthcdr cl-start2 cl-seq2)) - (cl-n (cond ((and cl-n1 cl-end2) - (min cl-n1 (- cl-end2 cl-start2))) - ((and cl-n1 (null cl-end2)) cl-n1) - ((and (null cl-n1) cl-end2) (- cl-end2 cl-start2))))) - (while (and cl-p1 cl-p2 (or (null cl-n) (>= (decf cl-n) 0))) - (setcar cl-p1 (car cl-p2)) - (setq cl-p1 (cdr cl-p1) cl-p2 (cdr cl-p2)))) - (setq cl-end2 (if (null cl-n1) - (or cl-end2 (length cl-seq2)) - (min (or cl-end2 (length cl-seq2)) - (+ cl-start2 cl-n1)))) - (while (and cl-p1 (< cl-start2 cl-end2)) - (setcar cl-p1 (aref cl-seq2 cl-start2)) - (setq cl-p1 (cdr cl-p1) cl-start2 (1+ cl-start2))))) - (setq cl-end1 (min (or cl-end1 (length cl-seq1)) - (+ cl-start1 (- (or cl-end2 (length cl-seq2)) + (let* ((len (length seq1)) + (n (min (- (or cl-end1 len) cl-start1) + (- (or cl-end2 len) cl-start2)))) + (while (>= (setq n (1- n)) 0) + (setf (elt seq1 (+ cl-start1 n)) + (elt seq2 (+ cl-start2 n)))))) + (if (listp seq1) + (let ((p1 (nthcdr cl-start1 seq1)) + (n1 (and cl-end1 (- cl-end1 cl-start1)))) + (if (listp seq2) + (let ((p2 (nthcdr cl-start2 seq2)) + (n (cond ((and n1 cl-end2) + (min n1 (- cl-end2 cl-start2))) + ((and n1 (null cl-end2)) n1) + ((and (null n1) cl-end2) (- cl-end2 cl-start2))))) + (while (and p1 p2 (or (null n) (>= (decf n) 0))) + (setcar p1 (car p2)) + (setq p1 (cdr p1) p2 (cdr p2)))) + (setq cl-end2 (if (null n1) + (or cl-end2 (length seq2)) + (min (or cl-end2 (length seq2)) + (+ cl-start2 n1)))) + (while (and p1 (< cl-start2 cl-end2)) + (setcar p1 (aref seq2 cl-start2)) + (setq p1 (cdr p1) cl-start2 (1+ cl-start2))))) + (setq cl-end1 (min (or cl-end1 (length seq1)) + (+ cl-start1 (- (or cl-end2 (length seq2)) cl-start2)))) - (if (listp cl-seq2) - (let ((cl-p2 (nthcdr cl-start2 cl-seq2))) + (if (listp seq2) + (let ((p2 (nthcdr cl-start2 seq2))) (while (< cl-start1 cl-end1) - (aset cl-seq1 cl-start1 (car cl-p2)) - (setq cl-p2 (cdr cl-p2) cl-start1 (1+ cl-start1)))) + (aset seq1 cl-start1 (car p2)) + (setq p2 (cdr p2) cl-start1 (1+ cl-start1)))) (while (< cl-start1 cl-end1) - (aset cl-seq1 cl-start1 (aref cl-seq2 cl-start2)) + (aset seq1 cl-start1 (aref seq2 cl-start2)) (setq cl-start2 (1+ cl-start2) cl-start1 (1+ cl-start1)))))) - cl-seq1)) + seq1)) ;;;###autoload -(defun cl-remove (cl-item cl-seq &rest cl-keys) +(defun cl-remove (item seq &rest cl-keys) "Remove all occurrences of ITEM in SEQ. This is a non-destructive function; it makes a copy of SEQ if necessary to avoid corrupting the original SEQ. \nKeywords supported: :test :test-not :key :count :start :end :from-end \n(fn ITEM SEQ [KEYWORD VALUE]...)" (declare (important-return-value t)) - (cl--parsing-keywords (:test :test-not :key :if :if-not :count :from-end - (:start 0) :end) () - (let ((len (length cl-seq))) + (cl--parsing-keywords ( :test :test-not :key :if :if-not :count :from-end + (:start 0) :end) () + (let ((len (length seq))) (if (<= (or cl-count (setq cl-count len)) 0) - cl-seq - (if (or (nlistp cl-seq) (and cl-from-end (< cl-count (/ len 2)))) - (let ((cl-i (cl--position cl-item cl-seq cl-start cl-end - cl-from-end))) - (if cl-i - (let ((cl-res (apply 'cl-delete cl-item (append cl-seq nil) - (append (if cl-from-end - (list :end (1+ cl-i)) - (list :start cl-i)) - cl-keys)))) - (if (listp cl-seq) cl-res - (if (stringp cl-seq) (concat cl-res) (vconcat cl-res)))) - cl-seq)) + seq + (if (or (nlistp seq) (and cl-from-end (< cl-count (/ len 2)))) + (let ((i (cl--position item seq cl-start cl-end + cl-from-end))) + (if i + (let ((res (apply #'cl-delete item (append seq nil) + (append (if cl-from-end + (list :end (1+ i)) + (list :start i)) + cl-keys)))) + (if (listp seq) res + (if (stringp seq) (concat res) (vconcat res)))) + seq)) (setq cl-end (- (or cl-end len) cl-start)) - (if (= cl-start 0) - (while (and cl-seq (> cl-end 0) - (cl--check-test cl-item (car cl-seq)) - (setq cl-end (1- cl-end) cl-seq (cdr cl-seq)) - (> (setq cl-count (1- cl-count)) 0)))) - (if (and (> cl-count 0) (> cl-end 0)) - (let ((cl-p (if (> cl-start 0) (nthcdr cl-start cl-seq) - (setq cl-end (1- cl-end)) (cdr cl-seq)))) - (while (and cl-p (> cl-end 0) - (not (cl--check-test cl-item (car cl-p)))) - (setq cl-p (cdr cl-p) cl-end (1- cl-end))) - (if (and cl-p (> cl-end 0)) - (nconc (cl-ldiff cl-seq cl-p) - (if (= cl-count 1) (cdr cl-p) - (and (cdr cl-p) - (apply 'cl-delete cl-item - (copy-sequence (cdr cl-p)) - :start 0 :end (1- cl-end) - :count (1- cl-count) cl-keys)))) - cl-seq)) - cl-seq)))))) + (if (= cl-start 0) + (while (and seq (> cl-end 0) + (cl--check-test item (car seq)) + (setq cl-end (1- cl-end) seq (cdr seq)) + (> (setq cl-count (1- cl-count)) 0)))) + (if (and (> cl-count 0) (> cl-end 0)) + (let ((p (if (> cl-start 0) (nthcdr cl-start seq) + (setq cl-end (1- cl-end)) (cdr seq)))) + (while (and p (> cl-end 0) + (not (cl--check-test item (car p)))) + (setq p (cdr p) cl-end (1- cl-end))) + (if (and p (> cl-end 0)) + (nconc (cl-ldiff seq p) + (if (= cl-count 1) (cdr p) + (and (cdr p) + (apply #'cl-delete item + (copy-sequence (cdr p)) + :start 0 :end (1- cl-end) + :count (1- cl-count) cl-keys)))) + seq)) + seq)))))) ;;;###autoload -(defun cl-remove-if (cl-pred cl-list &rest cl-keys) +(defun cl-remove-if (pred list &rest cl-keys) "Remove all items satisfying PREDICATE in SEQ. This is a non-destructive function; it makes a copy of SEQ if necessary to avoid corrupting the original SEQ. \nKeywords supported: :key :count :start :end :from-end \n(fn PREDICATE SEQ [KEYWORD VALUE]...)" (declare (important-return-value t)) - (apply 'cl-remove nil cl-list :if cl-pred cl-keys)) + (apply #'cl-remove nil list :if pred cl-keys)) ;;;###autoload -(defun cl-remove-if-not (cl-pred cl-list &rest cl-keys) +(defun cl-remove-if-not (pred list &rest cl-keys) "Remove all items not satisfying PREDICATE in SEQ. This is a non-destructive function; it makes a copy of SEQ if necessary to avoid corrupting the original SEQ. \nKeywords supported: :key :count :start :end :from-end \n(fn PREDICATE SEQ [KEYWORD VALUE]...)" (declare (important-return-value t)) - (apply 'cl-remove nil cl-list :if-not cl-pred cl-keys)) + (apply #'cl-remove nil list :if-not pred cl-keys)) ;;;###autoload -(defun cl-delete (cl-item cl-seq &rest cl-keys) +(defun cl-delete (item seq &rest cl-keys) "Remove all occurrences of ITEM in SEQ. This is a destructive function; it reuses the storage of SEQ whenever possible. \nKeywords supported: :test :test-not :key :count :start :end :from-end \n(fn ITEM SEQ [KEYWORD VALUE]...)" (declare (important-return-value t)) - (cl--parsing-keywords (:test :test-not :key :if :if-not :count :from-end - (:start 0) :end) () - (let ((len (length cl-seq))) + (cl--parsing-keywords ( :test :test-not :key :if :if-not :count :from-end + (:start 0) :end) () + (let ((len (length seq))) (if (<= (or cl-count (setq cl-count len)) 0) - cl-seq - (if (listp cl-seq) - (if (and cl-from-end (< cl-count (/ len 2))) - (let (cl-i) - (while (and (>= (setq cl-count (1- cl-count)) 0) - (setq cl-i (cl--position cl-item cl-seq cl-start - cl-end cl-from-end))) - (if (= cl-i 0) (setq cl-seq (cdr cl-seq)) - (let ((cl-tail (nthcdr (1- cl-i) cl-seq))) - (setcdr cl-tail (cdr (cdr cl-tail))))) - (setq cl-end cl-i)) - cl-seq) - (setq cl-end (- (or cl-end len) cl-start)) - (if (= cl-start 0) - (progn - (while (and cl-seq - (> cl-end 0) - (cl--check-test cl-item (car cl-seq)) - (setq cl-end (1- cl-end) cl-seq (cdr cl-seq)) - (> (setq cl-count (1- cl-count)) 0))) - (setq cl-end (1- cl-end))) - (setq cl-start (1- cl-start))) - (if (and (> cl-count 0) (> cl-end 0)) - (let ((cl-p (nthcdr cl-start cl-seq))) - (while (and (cdr cl-p) (> cl-end 0)) - (if (cl--check-test cl-item (car (cdr cl-p))) - (progn - (setcdr cl-p (cdr (cdr cl-p))) - (if (= (setq cl-count (1- cl-count)) 0) - (setq cl-end 1))) - (setq cl-p (cdr cl-p))) - (setq cl-end (1- cl-end))))) - cl-seq) - (apply 'cl-remove cl-item cl-seq cl-keys)))))) + seq + (if (listp seq) + (if (and cl-from-end (< cl-count (/ len 2))) + (let (i) + (while (and (>= (setq cl-count (1- cl-count)) 0) + (setq i (cl--position item seq cl-start + cl-end cl-from-end))) + (if (= i 0) (setq seq (cdr seq)) + (let ((tail (nthcdr (1- i) seq))) + (setcdr tail (cdr (cdr tail))))) + (setq cl-end i)) + seq) + (setq cl-end (- (or cl-end len) cl-start)) + (if (= cl-start 0) + (progn + (while (and seq + (> cl-end 0) + (cl--check-test item (car seq)) + (setq cl-end (1- cl-end) seq (cdr seq)) + (> (setq cl-count (1- cl-count)) 0))) + (setq cl-end (1- cl-end))) + (setq cl-start (1- cl-start))) + (if (and (> cl-count 0) (> cl-end 0)) + (let ((p (nthcdr cl-start seq))) + (while (and (cdr p) (> cl-end 0)) + (if (cl--check-test item (car (cdr p))) + (progn + (setcdr p (cdr (cdr p))) + (if (= (setq cl-count (1- cl-count)) 0) + (setq cl-end 1))) + (setq p (cdr p))) + (setq cl-end (1- cl-end))))) + seq) + (apply #'cl-remove item seq cl-keys)))))) ;;;###autoload -(defun cl-delete-if (cl-pred cl-list &rest cl-keys) +(defun cl-delete-if (pred list &rest cl-keys) "Remove all items satisfying PREDICATE in SEQ. This is a destructive function; it reuses the storage of SEQ whenever possible. \nKeywords supported: :key :count :start :end :from-end \n(fn PREDICATE SEQ [KEYWORD VALUE]...)" (declare (important-return-value t)) - (apply 'cl-delete nil cl-list :if cl-pred cl-keys)) + (apply #'cl-delete nil list :if pred cl-keys)) ;;;###autoload -(defun cl-delete-if-not (cl-pred cl-list &rest cl-keys) +(defun cl-delete-if-not (pred list &rest cl-keys) "Remove all items not satisfying PREDICATE in SEQ. This is a destructive function; it reuses the storage of SEQ whenever possible. \nKeywords supported: :key :count :start :end :from-end \n(fn PREDICATE SEQ [KEYWORD VALUE]...)" (declare (important-return-value t)) - (apply 'cl-delete nil cl-list :if-not cl-pred cl-keys)) + (apply #'cl-delete nil list :if-not pred cl-keys)) ;;;###autoload -(defun cl-remove-duplicates (cl-seq &rest cl-keys) +(defun cl-remove-duplicates (seq &rest cl-keys) "Return a copy of SEQ with all duplicate elements removed. \nKeywords supported: :test :test-not :key :start :end :from-end \n(fn SEQ [KEYWORD VALUE]...)" (declare (important-return-value t)) - (cl--delete-duplicates cl-seq cl-keys t)) + (cl--delete-duplicates seq cl-keys t)) ;;;###autoload -(defun cl-delete-duplicates (cl-seq &rest cl-keys) +(defun cl-delete-duplicates (seq &rest cl-keys) "Remove all duplicate elements from SEQ (destructively). \nKeywords supported: :test :test-not :key :start :end :from-end \n(fn SEQ [KEYWORD VALUE]...)" (declare (important-return-value t)) - (cl--delete-duplicates cl-seq cl-keys nil)) + (cl--delete-duplicates seq cl-keys nil)) -(defun cl--delete-duplicates (cl-seq cl-keys cl-copy) - (if (listp cl-seq) +(defun cl--delete-duplicates (seq cl-keys copy) + (if (listp seq) (cl--parsing-keywords ;; We need to parse :if, otherwise `cl-if' is unbound. (:test :test-not :key (:start 0) :end :from-end :if) () (if cl-from-end - (let ((cl-p (nthcdr cl-start cl-seq)) cl-i) - (setq cl-end (- (or cl-end (length cl-seq)) cl-start)) + (let ((p (nthcdr cl-start seq)) i) + (setq cl-end (- (or cl-end (length seq)) cl-start)) (while (> cl-end 1) - (setq cl-i 0) - (while (setq cl-i (cl--position (cl--check-key (car cl-p)) - (cdr cl-p) cl-i (1- cl-end))) - (if cl-copy (setq cl-seq (copy-sequence cl-seq) - cl-p (nthcdr cl-start cl-seq) cl-copy nil)) - (let ((cl-tail (nthcdr cl-i cl-p))) - (setcdr cl-tail (cdr (cdr cl-tail)))) + (setq i 0) + (while (setq i (cl--position (cl--check-key (car p)) + (cdr p) i (1- cl-end))) + (if copy (setq seq (copy-sequence seq) + p (nthcdr cl-start seq) copy nil)) + (let ((tail (nthcdr i p))) + (setcdr tail (cdr (cdr tail)))) (setq cl-end (1- cl-end))) - (setq cl-p (cdr cl-p) cl-end (1- cl-end) + (setq p (cdr p) cl-end (1- cl-end) cl-start (1+ cl-start))) - cl-seq) - (setq cl-end (- (or cl-end (length cl-seq)) cl-start)) - (while (and (cdr cl-seq) (= cl-start 0) (> cl-end 1) - (cl--position (cl--check-key (car cl-seq)) - (cdr cl-seq) 0 (1- cl-end))) - (setq cl-seq (cdr cl-seq) cl-end (1- cl-end))) - (let ((cl-p (if (> cl-start 0) (nthcdr (1- cl-start) cl-seq) - (setq cl-end (1- cl-end) cl-start 1) cl-seq))) - (while (and (cdr (cdr cl-p)) (> cl-end 1)) - (if (cl--position (cl--check-key (car (cdr cl-p))) - (cdr (cdr cl-p)) 0 (1- cl-end)) + seq) + (setq cl-end (- (or cl-end (length seq)) cl-start)) + (while (and (cdr seq) (= cl-start 0) (> cl-end 1) + (cl--position (cl--check-key (car seq)) + (cdr seq) 0 (1- cl-end))) + (setq seq (cdr seq) cl-end (1- cl-end))) + (let ((p (if (> cl-start 0) (nthcdr (1- cl-start) seq) + (setq cl-end (1- cl-end) cl-start 1) seq))) + (while (and (cdr (cdr p)) (> cl-end 1)) + (if (cl--position (cl--check-key (car (cdr p))) + (cdr (cdr p)) 0 (1- cl-end)) (progn - (if cl-copy (setq cl-seq (copy-sequence cl-seq) - cl-p (nthcdr (1- cl-start) cl-seq) - cl-copy nil)) - (setcdr cl-p (cdr (cdr cl-p)))) - (setq cl-p (cdr cl-p))) + (if copy (setq seq (copy-sequence seq) + p (nthcdr (1- cl-start) seq) + copy nil)) + (setcdr p (cdr (cdr p)))) + (setq p (cdr p))) (setq cl-end (1- cl-end) cl-start (1+ cl-start))) - cl-seq))) - (let ((cl-res (cl--delete-duplicates (append cl-seq nil) cl-keys nil))) - (if (stringp cl-seq) (concat cl-res) (vconcat cl-res))))) + seq))) + (let ((res (cl--delete-duplicates (append seq nil) cl-keys nil))) + (if (stringp seq) (concat res) (vconcat res))))) ;;;###autoload -(defun cl-substitute (cl-new cl-old cl-seq &rest cl-keys) +(defun cl-substitute (new old seq &rest cl-keys) "Substitute NEW for OLD in SEQ. This is a non-destructive function; it makes a copy of SEQ if necessary to avoid corrupting the original SEQ. \nKeywords supported: :test :test-not :key :count :start :end :from-end \n(fn NEW OLD SEQ [KEYWORD VALUE]...)" (declare (important-return-value t)) - (cl--parsing-keywords (:test :test-not :key :if :if-not :count - (:start 0) :end :from-end) () - (if (or (eq cl-old cl-new) + (cl--parsing-keywords ( :test :test-not :key :if :if-not :count + (:start 0) :end :from-end) () + (if (or (eq old new) (<= (or cl-count (setq cl-from-end nil - cl-count (length cl-seq))) 0)) - cl-seq - (let ((cl-i (cl--position cl-old cl-seq cl-start cl-end))) - (if (not cl-i) - cl-seq - (setq cl-seq (copy-sequence cl-seq)) + cl-count (length seq))) 0)) + seq + (let ((i (cl--position old seq cl-start cl-end))) + (if (not i) + seq + (setq seq (copy-sequence seq)) (unless cl-from-end - (setf (elt cl-seq cl-i) cl-new) - (incf cl-i) + (setf (elt seq i) new) + (incf i) (decf cl-count)) - (apply 'cl-nsubstitute cl-new cl-old cl-seq :count cl-count - :start cl-i cl-keys)))))) + (apply #'cl-nsubstitute new old seq :count cl-count + :start i cl-keys)))))) ;;;###autoload -(defun cl-substitute-if (cl-new cl-pred cl-list &rest cl-keys) +(defun cl-substitute-if (new pred cl-list &rest cl-keys) "Substitute NEW for all items satisfying PREDICATE in SEQ. This is a non-destructive function; it makes a copy of SEQ if necessary to avoid corrupting the original SEQ. \nKeywords supported: :key :count :start :end :from-end \n(fn NEW PREDICATE SEQ [KEYWORD VALUE]...)" (declare (important-return-value t)) - (apply 'cl-substitute cl-new nil cl-list :if cl-pred cl-keys)) + (apply #'cl-substitute new nil cl-list :if pred cl-keys)) ;;;###autoload -(defun cl-substitute-if-not (cl-new cl-pred cl-list &rest cl-keys) +(defun cl-substitute-if-not (new pred cl-list &rest cl-keys) "Substitute NEW for all items not satisfying PREDICATE in SEQ. This is a non-destructive function; it makes a copy of SEQ if necessary to avoid corrupting the original SEQ. \nKeywords supported: :key :count :start :end :from-end \n(fn NEW PREDICATE SEQ [KEYWORD VALUE]...)" (declare (important-return-value t)) - (apply 'cl-substitute cl-new nil cl-list :if-not cl-pred cl-keys)) + (apply #'cl-substitute new nil cl-list :if-not pred cl-keys)) ;;;###autoload -(defun cl-nsubstitute (cl-new cl-old seq &rest cl-keys) +(defun cl-nsubstitute (new old seq &rest cl-keys) "Substitute NEW for OLD in SEQ. This is a destructive function; it reuses the storage of SEQ whenever possible. \nKeywords supported: :test :test-not :key :count :start :end :from-end \n(fn NEW OLD SEQ [KEYWORD VALUE]...)" (declare (important-return-value t)) - (cl--parsing-keywords (:test :test-not :key :if :if-not :count - (:start 0) :end :from-end) () - (let* ((cl-seq (if (stringp seq) (string-to-vector seq) seq)) - (len (length cl-seq))) - (or (eq cl-old cl-new) (<= (or cl-count (setq cl-count len)) 0) - (if (and (listp cl-seq) (or (not cl-from-end) (> cl-count (/ len 2)))) - (let ((cl-p (nthcdr cl-start cl-seq))) - (setq cl-end (- (or cl-end len) cl-start)) - (while (and cl-p (> cl-end 0) (> cl-count 0)) - (if (cl--check-test cl-old (car cl-p)) - (progn - (setcar cl-p cl-new) - (setq cl-count (1- cl-count)))) - (setq cl-p (cdr cl-p) cl-end (1- cl-end)))) + (cl--parsing-keywords ( :test :test-not :key :if :if-not :count + (:start 0) :end :from-end) () + (let* ((seq (if (stringp seq) (string-to-vector seq) seq)) + (len (length seq))) + (or (eq old new) (<= (or cl-count (setq cl-count len)) 0) + (if (and (listp seq) (or (not cl-from-end) (> cl-count (/ len 2)))) + (let ((p (nthcdr cl-start seq))) + (setq cl-end (- (or cl-end len) cl-start)) + (while (and p (> cl-end 0) (> cl-count 0)) + (if (cl--check-test old (car p)) + (progn + (setcar p new) + (setq cl-count (1- cl-count)))) + (setq p (cdr p) cl-end (1- cl-end)))) (or cl-end (setq cl-end len)) - (if cl-from-end - (while (and (< cl-start cl-end) (> cl-count 0)) - (setq cl-end (1- cl-end)) - (if (cl--check-test cl-old (elt cl-seq cl-end)) - (progn - (setf (elt cl-seq cl-end) cl-new) - (setq cl-count (1- cl-count))))) - (while (and (< cl-start cl-end) (> cl-count 0)) - (if (cl--check-test cl-old (aref cl-seq cl-start)) - (progn - (aset cl-seq cl-start cl-new) - (setq cl-count (1- cl-count)))) - (setq cl-start (1+ cl-start)))))) - (if (stringp seq) (concat cl-seq) cl-seq)))) + (if cl-from-end + (while (and (< cl-start cl-end) (> cl-count 0)) + (setq cl-end (1- cl-end)) + (if (cl--check-test old (elt seq cl-end)) + (progn + (setf (elt seq cl-end) new) + (setq cl-count (1- cl-count))))) + (while (and (< cl-start cl-end) (> cl-count 0)) + (if (cl--check-test old (aref seq cl-start)) + (progn + (aset seq cl-start new) + (setq cl-count (1- cl-count)))) + (setq cl-start (1+ cl-start)))))) + (if (stringp seq) (concat seq) seq)))) ;;;###autoload -(defun cl-nsubstitute-if (cl-new cl-pred cl-list &rest cl-keys) +(defun cl-nsubstitute-if (new pred list &rest cl-keys) "Substitute NEW for all items satisfying PREDICATE in SEQ. This is a destructive function; it reuses the storage of SEQ whenever possible. \nKeywords supported: :key :count :start :end :from-end \n(fn NEW PREDICATE SEQ [KEYWORD VALUE]...)" (declare (important-return-value t)) - (apply 'cl-nsubstitute cl-new nil cl-list :if cl-pred cl-keys)) + (apply #'cl-nsubstitute new nil list :if pred cl-keys)) ;;;###autoload -(defun cl-nsubstitute-if-not (cl-new cl-pred cl-list &rest cl-keys) +(defun cl-nsubstitute-if-not (new pred list &rest cl-keys) "Substitute NEW for all items not satisfying PREDICATE in SEQ. This is a destructive function; it reuses the storage of SEQ whenever possible. \nKeywords supported: :key :count :start :end :from-end \n(fn NEW PREDICATE SEQ [KEYWORD VALUE]...)" (declare (important-return-value t)) - (apply 'cl-nsubstitute cl-new nil cl-list :if-not cl-pred cl-keys)) + (apply #'cl-nsubstitute new nil list :if-not pred cl-keys)) ;;;###autoload -(defun cl-find (cl-item cl-seq &rest cl-keys) +(defun cl-find (item seq &rest cl-keys) "Find the first occurrence of ITEM in SEQ. Return the matching ITEM, or nil if not found. \nKeywords supported: :test :test-not :key :start :end :from-end \n(fn ITEM SEQ [KEYWORD VALUE]...)" (declare (important-return-value t)) - (let ((cl-pos (apply 'cl-position cl-item cl-seq cl-keys))) - (and cl-pos (elt cl-seq cl-pos)))) + (let ((pos (apply #'cl-position item seq cl-keys))) + (and pos (elt seq pos)))) ;;;###autoload -(defun cl-find-if (cl-pred cl-list &rest cl-keys) +(defun cl-find-if (pred list &rest cl-keys) "Find the first item satisfying PREDICATE in SEQ. Return the matching item, or nil if not found. \nKeywords supported: :key :start :end :from-end \n(fn PREDICATE SEQ [KEYWORD VALUE]...)" (declare (important-return-value t)) - (apply 'cl-find nil cl-list :if cl-pred cl-keys)) + (apply #'cl-find nil list :if pred cl-keys)) ;;;###autoload -(defun cl-find-if-not (cl-pred cl-list &rest cl-keys) +(defun cl-find-if-not (pred list &rest cl-keys) "Find the first item not satisfying PREDICATE in SEQ. Return the matching item, or nil if not found. \nKeywords supported: :key :start :end :from-end \n(fn PREDICATE SEQ [KEYWORD VALUE]...)" (declare (important-return-value t)) - (apply 'cl-find nil cl-list :if-not cl-pred cl-keys)) + (apply #'cl-find nil list :if-not pred cl-keys)) ;;;###autoload -(defun cl-position (cl-item cl-seq &rest cl-keys) +(defun cl-position (item seq &rest cl-keys) "Find the first occurrence of ITEM in SEQ. Return the index of the matching item, or nil if not found. \nKeywords supported: :test :test-not :key :start :end :from-end \n(fn ITEM SEQ [KEYWORD VALUE]...)" (declare (important-return-value t)) - (cl--parsing-keywords (:test :test-not :key :if :if-not - (:start 0) :end :from-end) () - (cl--position cl-item cl-seq cl-start cl-end cl-from-end))) - -(defun cl--position (cl-item cl-seq cl-start &optional cl-end cl-from-end) - (if (listp cl-seq) - (let ((cl-p (nthcdr cl-start cl-seq)) - cl-res) - (while (and cl-p (or (null cl-end) (< cl-start cl-end)) (or (null cl-res) cl-from-end)) - (if (cl--check-test cl-item (car cl-p)) - (setq cl-res cl-start)) - (setq cl-p (cdr cl-p) cl-start (1+ cl-start))) - cl-res) - (or cl-end (setq cl-end (length cl-seq))) - (if cl-from-end + (cl--parsing-keywords ( :test :test-not :key :if :if-not + (:start 0) :end :from-end) () + (cl--position item seq cl-start cl-end cl-from-end))) + +(defun cl--position (item seq start &optional end from-end) + (if (listp seq) + (let ((p (nthcdr start seq)) + res) + (while (and p (or (null end) (< start end)) (or (null res) from-end)) + (if (cl--check-test item (car p)) + (setq res start)) + (setq p (cdr p) start (1+ start))) + res) + (or end (setq end (length seq))) + (if from-end (progn - (while (and (>= (setq cl-end (1- cl-end)) cl-start) - (not (cl--check-test cl-item (aref cl-seq cl-end))))) - (and (>= cl-end cl-start) cl-end)) - (while (and (< cl-start cl-end) - (not (cl--check-test cl-item (aref cl-seq cl-start)))) - (setq cl-start (1+ cl-start))) - (and (< cl-start cl-end) cl-start)))) + (while (and (>= (setq end (1- end)) start) + (not (cl--check-test item (aref seq end))))) + (and (>= end start) end)) + (while (and (< start end) + (not (cl--check-test item (aref seq start)))) + (setq start (1+ start))) + (and (< start end) start)))) ;;;###autoload -(defun cl-position-if (cl-pred cl-list &rest cl-keys) +(defun cl-position-if (pred list &rest cl-keys) "Find the first item satisfying PREDICATE in SEQ. Return the index of the matching item, or nil if not found. \nKeywords supported: :key :start :end :from-end \n(fn PREDICATE SEQ [KEYWORD VALUE]...)" (declare (important-return-value t)) - (apply 'cl-position nil cl-list :if cl-pred cl-keys)) + (apply #'cl-position nil list :if pred cl-keys)) ;;;###autoload -(defun cl-position-if-not (cl-pred cl-list &rest cl-keys) +(defun cl-position-if-not (pred list &rest cl-keys) "Find the first item not satisfying PREDICATE in SEQ. Return the index of the matching item, or nil if not found. \nKeywords supported: :key :start :end :from-end \n(fn PREDICATE SEQ [KEYWORD VALUE]...)" (declare (important-return-value t)) - (apply 'cl-position nil cl-list :if-not cl-pred cl-keys)) + (apply #'cl-position nil list :if-not pred cl-keys)) ;;;###autoload -(defun cl-count (cl-item cl-seq &rest cl-keys) +(defun cl-count (item seq &rest cl-keys) "Count the number of occurrences of ITEM in SEQ. \nKeywords supported: :test :test-not :key :start :end \n(fn ITEM SEQ [KEYWORD VALUE]...)" (declare (important-return-value t)) (cl--parsing-keywords (:test :test-not :key :if :if-not (:start 0) :end) () - (let ((cl-count 0) cl-x) - (or cl-end (setq cl-end (length cl-seq))) - (if (consp cl-seq) (setq cl-seq (nthcdr cl-start cl-seq))) + (let ((count 0) cl-x) + (or cl-end (setq cl-end (length seq))) + (if (consp seq) (setq seq (nthcdr cl-start seq))) (while (< cl-start cl-end) - (setq cl-x (if (consp cl-seq) (pop cl-seq) (aref cl-seq cl-start))) - (if (cl--check-test cl-item cl-x) (setq cl-count (1+ cl-count))) + (setq cl-x (if (consp seq) (pop seq) (aref seq cl-start))) + (if (cl--check-test item cl-x) (setq count (1+ count))) (setq cl-start (1+ cl-start))) - cl-count))) + count))) ;;;###autoload -(defun cl-count-if (cl-pred cl-list &rest cl-keys) +(defun cl-count-if (pred list &rest cl-keys) "Count the number of items satisfying PREDICATE in SEQ. \nKeywords supported: :key :start :end \n(fn PREDICATE SEQ [KEYWORD VALUE]...)" (declare (important-return-value t)) - (apply 'cl-count nil cl-list :if cl-pred cl-keys)) + (apply #'cl-count nil list :if pred cl-keys)) ;;;###autoload -(defun cl-count-if-not (cl-pred cl-list &rest cl-keys) +(defun cl-count-if-not (pred list &rest cl-keys) "Count the number of items not satisfying PREDICATE in SEQ. \nKeywords supported: :key :start :end \n(fn PREDICATE SEQ [KEYWORD VALUE]...)" (declare (important-return-value t)) - (apply 'cl-count nil cl-list :if-not cl-pred cl-keys)) + (apply #'cl-count nil list :if-not pred cl-keys)) ;;;###autoload -(defun cl-mismatch (cl-seq1 cl-seq2 &rest cl-keys) +(defun cl-mismatch (seq1 seq2 &rest cl-keys) "Compare SEQ1 with SEQ2, return index of first mismatching element. Return nil if the sequences match. If one sequence is a prefix of the other, the return value indicates the end of the shorter sequence. \nKeywords supported: :test :test-not :key :start1 :end1 :start2 :end2 :from-end \n(fn SEQ1 SEQ2 [KEYWORD VALUE]...)" (declare (important-return-value t)) - (cl--parsing-keywords (:test :test-not :key :from-end - (:start1 0) :end1 (:start2 0) :end2) () - (or cl-end1 (setq cl-end1 (length cl-seq1))) - (or cl-end2 (setq cl-end2 (length cl-seq2))) + (cl--parsing-keywords ( :test :test-not :key :from-end + (:start1 0) :end1 (:start2 0) :end2) () + (or cl-end1 (setq cl-end1 (length seq1))) + (or cl-end2 (setq cl-end2 (length seq2))) (if cl-from-end (progn (while (and (< cl-start1 cl-end1) (< cl-start2 cl-end2) - (cl--check-match (elt cl-seq1 (1- cl-end1)) - (elt cl-seq2 (1- cl-end2)))) + (cl--check-match (elt seq1 (1- cl-end1)) + (elt seq2 (1- cl-end2)))) (setq cl-end1 (1- cl-end1) cl-end2 (1- cl-end2))) (and (or (< cl-start1 cl-end1) (< cl-start2 cl-end2)) (1- cl-end1))) - (let ((cl-p1 (and (listp cl-seq1) (nthcdr cl-start1 cl-seq1))) - (cl-p2 (and (listp cl-seq2) (nthcdr cl-start2 cl-seq2)))) + (let ((p1 (and (listp seq1) (nthcdr cl-start1 seq1))) + (p2 (and (listp seq2) (nthcdr cl-start2 seq2)))) (while (and (< cl-start1 cl-end1) (< cl-start2 cl-end2) - (cl--check-match (if cl-p1 (car cl-p1) - (aref cl-seq1 cl-start1)) - (if cl-p2 (car cl-p2) - (aref cl-seq2 cl-start2)))) - (setq cl-p1 (cdr cl-p1) cl-p2 (cdr cl-p2) + (cl--check-match (if p1 (car p1) + (aref seq1 cl-start1)) + (if p2 (car p2) + (aref seq2 cl-start2)))) + (setq p1 (cdr p1) p2 (cdr p2) cl-start1 (1+ cl-start1) cl-start2 (1+ cl-start2))) (and (or (< cl-start1 cl-end1) (< cl-start2 cl-end2)) cl-start1))))) ;;;###autoload -(defun cl-search (cl-seq1 cl-seq2 &rest cl-keys) +(defun cl-search (seq1 seq2 &rest cl-keys) "Search for SEQ1 as a subsequence of SEQ2. Return the index of the leftmost element of the first match found; return nil if there are no matches. \nKeywords supported: :test :test-not :key :start1 :end1 :start2 :end2 :from-end \n(fn SEQ1 SEQ2 [KEYWORD VALUE]...)" (declare (important-return-value t)) - (cl--parsing-keywords (:test :test-not :key :from-end - (:start1 0) :end1 (:start2 0) :end2) () - (or cl-end1 (setq cl-end1 (length cl-seq1))) - (or cl-end2 (setq cl-end2 (length cl-seq2))) + (cl--parsing-keywords ( :test :test-not :key :from-end + (:start1 0) :end1 (:start2 0) :end2) () + (or cl-end1 (setq cl-end1 (length seq1))) + (or cl-end2 (setq cl-end2 (length seq2))) (if (>= cl-start1 cl-end1) (if cl-from-end cl-end2 cl-start2) - (let* ((cl-len (- cl-end1 cl-start1)) - (cl-first (cl--check-key (elt cl-seq1 cl-start1))) - (cl-if nil) cl-pos) - (setq cl-end2 (- cl-end2 (1- cl-len))) + (let* ((len (- cl-end1 cl-start1)) + (first (cl--check-key (elt seq1 cl-start1))) + (cl-if nil) pos) + (setq cl-end2 (- cl-end2 (1- len))) (while (and (< cl-start2 cl-end2) - (setq cl-pos (cl--position cl-first cl-seq2 - cl-start2 cl-end2 cl-from-end)) - (apply 'cl-mismatch cl-seq1 cl-seq2 + (setq pos (cl--position first seq2 + cl-start2 cl-end2 cl-from-end)) + (apply #'cl-mismatch seq1 seq2 :start1 (1+ cl-start1) :end1 cl-end1 - :start2 (1+ cl-pos) :end2 (+ cl-pos cl-len) + :start2 (1+ pos) :end2 (+ pos len) :from-end nil cl-keys)) - (if cl-from-end (setq cl-end2 cl-pos) (setq cl-start2 (1+ cl-pos)))) - (and (< cl-start2 cl-end2) cl-pos))))) + (if cl-from-end (setq cl-end2 pos) (setq cl-start2 (1+ pos)))) + (and (< cl-start2 cl-end2) pos))))) ;;;###autoload -(defun cl-sort (cl-seq cl-pred &rest cl-keys) +(defun cl-sort (seq pred &rest cl-keys) "Sort the argument SEQ according to PREDICATE. This is a destructive function; it reuses the storage of SEQ if possible. \nKeywords supported: :key @@ -697,20 +697,20 @@ This is a destructive function; it reuses the storage of SEQ if possible. ;; It's safe to ignore the return value when used on arrays, ;; but most calls pass lists. (declare (important-return-value t)) - (if (nlistp cl-seq) - (if (stringp cl-seq) - (concat (apply #'cl-sort (vconcat cl-seq) cl-pred cl-keys)) - (cl-replace cl-seq - (apply #'cl-sort (append cl-seq nil) cl-pred cl-keys))) + (if (nlistp seq) + (if (stringp seq) + (concat (apply #'cl-sort (vconcat seq) pred cl-keys)) + (cl-replace seq + (apply #'cl-sort (append seq nil) pred cl-keys))) (cl--parsing-keywords (:key) () (if (memq cl-key '(nil identity)) - (sort cl-seq cl-pred) - (sort cl-seq (lambda (cl-x cl-y) - (funcall cl-pred (funcall cl-key cl-x) - (funcall cl-key cl-y)))))))) + (sort seq pred) + (sort seq (lambda (cl-x cl-y) + (funcall pred (funcall cl-key cl-x) + (funcall cl-key cl-y)))))))) ;;;###autoload -(defun cl-stable-sort (cl-seq cl-pred &rest cl-keys) +(defun cl-stable-sort (seq pred &rest cl-keys) "Sort the argument SEQ stably according to PREDICATE. This is a destructive function; it reuses the storage of SEQ if possible. \nKeywords supported: :key @@ -718,29 +718,29 @@ This is a destructive function; it reuses the storage of SEQ if possible. ;; It's safe to ignore the return value when used on arrays, ;; but most calls pass lists. (declare (important-return-value t)) - (apply 'cl-sort cl-seq cl-pred cl-keys)) + (apply #'cl-sort seq pred cl-keys)) ;;;###autoload -(defun cl-merge (cl-type cl-seq1 cl-seq2 cl-pred &rest cl-keys) +(defun cl-merge (type seq1 seq2 pred &rest cl-keys) "Destructively merge the two sequences to produce a new sequence. TYPE is the sequence type to return, SEQ1 and SEQ2 are the two argument sequences, and PREDICATE is a `less-than' predicate on the elements. \nKeywords supported: :key \n(fn TYPE SEQ1 SEQ2 PREDICATE [KEYWORD VALUE]...)" (declare (important-return-value t)) - (or (listp cl-seq1) (setq cl-seq1 (append cl-seq1 nil))) - (or (listp cl-seq2) (setq cl-seq2 (append cl-seq2 nil))) + (or (listp seq1) (setq seq1 (append seq1 nil))) + (or (listp seq2) (setq seq2 (append seq2 nil))) (cl--parsing-keywords (:key) () - (let ((cl-res nil)) - (while (and cl-seq1 cl-seq2) - (if (funcall cl-pred (cl--check-key (car cl-seq2)) - (cl--check-key (car cl-seq1))) - (push (pop cl-seq2) cl-res) - (push (pop cl-seq1) cl-res))) - (cl-coerce (nconc (nreverse cl-res) cl-seq1 cl-seq2) cl-type)))) + (let ((res nil)) + (while (and seq1 seq2) + (if (funcall pred (cl--check-key (car seq2)) + (cl--check-key (car seq1))) + (push (pop seq2) res) + (push (pop seq1) res))) + (cl-coerce (nconc (nreverse res) seq1 seq2) type)))) ;;;###autoload -(defun cl-member (cl-item cl-list &rest cl-keys) +(defun cl-member (item list &rest cl-keys) "Find the first occurrence of ITEM in LIST. Return the sublist of LIST whose car is ITEM. \nKeywords supported: :test :test-not :key @@ -749,39 +749,39 @@ Return the sublist of LIST whose car is ITEM. (compiler-macro cl--compiler-macro-member)) (if cl-keys (cl--parsing-keywords (:test :test-not :key :if :if-not) () - (while (and cl-list (not (cl--check-test cl-item (car cl-list)))) - (setq cl-list (cdr cl-list))) - cl-list) - (memql cl-item cl-list))) + (while (and list (not (cl--check-test item (car list)))) + (setq list (cdr list))) + list) + (memql item list))) (autoload 'cl--compiler-macro-member "cl-macs") ;;;###autoload -(defun cl-member-if (cl-pred cl-list &rest cl-keys) +(defun cl-member-if (pred list &rest cl-keys) "Find the first item satisfying PREDICATE in LIST. Return the sublist of LIST whose car matches. \nKeywords supported: :key \n(fn PREDICATE LIST [KEYWORD VALUE]...)" (declare (important-return-value t)) - (apply 'cl-member nil cl-list :if cl-pred cl-keys)) + (apply #'cl-member nil list :if pred cl-keys)) ;;;###autoload -(defun cl-member-if-not (cl-pred cl-list &rest cl-keys) +(defun cl-member-if-not (pred list &rest cl-keys) "Find the first item not satisfying PREDICATE in LIST. Return the sublist of LIST whose car matches. \nKeywords supported: :key \n(fn PREDICATE LIST [KEYWORD VALUE]...)" (declare (important-return-value t)) - (apply 'cl-member nil cl-list :if-not cl-pred cl-keys)) + (apply #'cl-member nil list :if-not pred cl-keys)) ;;;###autoload -(defun cl--adjoin (cl-item cl-list &rest cl-keys) +(defun cl--adjoin (item list &rest cl-keys) (if (cl--parsing-keywords (:key) t - (apply 'cl-member (cl--check-key cl-item) cl-list cl-keys)) - cl-list - (cons cl-item cl-list))) + (apply #'cl-member (cl--check-key item) list cl-keys)) + list + (cons item list))) ;;;###autoload -(defun cl-assoc (cl-item cl-alist &rest cl-keys) +(defun cl-assoc (item alist &rest cl-keys) "Find the first item whose car matches ITEM in LIST. \nKeywords supported: :test :test-not :key \n(fn ITEM LIST [KEYWORD VALUE]...)" @@ -789,65 +789,65 @@ Return the sublist of LIST whose car matches. (compiler-macro cl--compiler-macro-assoc)) (if cl-keys (cl--parsing-keywords (:test :test-not :key :if :if-not) () - (while (and cl-alist - (or (not (consp (car cl-alist))) - (not (cl--check-test cl-item (car (car cl-alist)))))) - (setq cl-alist (cdr cl-alist))) - (and cl-alist (car cl-alist))) - (if (and (numberp cl-item) (not (fixnump cl-item))) - (assoc cl-item cl-alist) - (assq cl-item cl-alist)))) + (while (and alist + (or (not (consp (car alist))) + (not (cl--check-test item (car (car alist)))))) + (setq alist (cdr alist))) + (and alist (car alist))) + (if (and (numberp item) (not (fixnump item))) + (assoc item alist) + (assq item alist)))) (autoload 'cl--compiler-macro-assoc "cl-macs") ;;;###autoload -(defun cl-assoc-if (cl-pred cl-list &rest cl-keys) +(defun cl-assoc-if (pred list &rest cl-keys) "Find the first item whose car satisfies PREDICATE in LIST. \nKeywords supported: :key \n(fn PREDICATE LIST [KEYWORD VALUE]...)" (declare (important-return-value t)) - (apply 'cl-assoc nil cl-list :if cl-pred cl-keys)) + (apply #'cl-assoc nil list :if pred cl-keys)) ;;;###autoload -(defun cl-assoc-if-not (cl-pred cl-list &rest cl-keys) +(defun cl-assoc-if-not (pred list &rest cl-keys) "Find the first item whose car does not satisfy PREDICATE in LIST. \nKeywords supported: :key \n(fn PREDICATE LIST [KEYWORD VALUE]...)" (declare (important-return-value t)) - (apply 'cl-assoc nil cl-list :if-not cl-pred cl-keys)) + (apply #'cl-assoc nil list :if-not pred cl-keys)) ;;;###autoload -(defun cl-rassoc (cl-item cl-alist &rest cl-keys) +(defun cl-rassoc (item alist &rest cl-keys) "Find the first item whose cdr matches ITEM in LIST. \nKeywords supported: :test :test-not :key \n(fn ITEM LIST [KEYWORD VALUE]...)" (declare (important-return-value t)) - (if (or cl-keys (numberp cl-item)) + (if (or cl-keys (numberp item)) (cl--parsing-keywords (:test :test-not :key :if :if-not) () - (while (and cl-alist - (or (not (consp (car cl-alist))) - (not (cl--check-test cl-item (cdr (car cl-alist)))))) - (setq cl-alist (cdr cl-alist))) - (and cl-alist (car cl-alist))) - (rassq cl-item cl-alist))) + (while (and alist + (or (not (consp (car alist))) + (not (cl--check-test item (cdr (car alist)))))) + (setq alist (cdr alist))) + (and alist (car alist))) + (rassq item alist))) ;;;###autoload -(defun cl-rassoc-if (cl-pred cl-list &rest cl-keys) +(defun cl-rassoc-if (pred list &rest cl-keys) "Find the first item whose cdr satisfies PREDICATE in LIST. \nKeywords supported: :key \n(fn PREDICATE LIST [KEYWORD VALUE]...)" (declare (important-return-value t)) - (apply 'cl-rassoc nil cl-list :if cl-pred cl-keys)) + (apply #'cl-rassoc nil list :if pred cl-keys)) ;;;###autoload -(defun cl-rassoc-if-not (cl-pred cl-list &rest cl-keys) +(defun cl-rassoc-if-not (pred list &rest cl-keys) "Find the first item whose cdr does not satisfy PREDICATE in LIST. \nKeywords supported: :key \n(fn PREDICATE LIST [KEYWORD VALUE]...)" (declare (important-return-value t)) - (apply 'cl-rassoc nil cl-list :if-not cl-pred cl-keys)) + (apply #'cl-rassoc nil list :if-not pred cl-keys)) ;;;###autoload -(defun cl-union (cl-list1 cl-list2 &rest cl-keys) +(defun cl-union (list1 list2 &rest cl-keys) "Combine LIST1 and LIST2 using a set-union operation. The resulting list contains all items that appear in either LIST1 or LIST2. This is a non-destructive function; it makes a copy of the data if necessary @@ -855,22 +855,22 @@ to avoid corrupting the original LIST1 and LIST2. \nKeywords supported: :test :test-not :key \n(fn LIST1 LIST2 [KEYWORD VALUE]...)" (declare (important-return-value t)) - (cond ((null cl-list1) cl-list2) ((null cl-list2) cl-list1) - ((and (not cl-keys) (equal cl-list1 cl-list2)) cl-list1) + (cond ((null list1) list2) ((null list2) list1) + ((and (not cl-keys) (equal list1 list2)) list1) (t - (or (>= (length cl-list1) (length cl-list2)) - (setq cl-list1 (prog1 cl-list2 (setq cl-list2 cl-list1)))) - (while cl-list2 - (if (or cl-keys (numberp (car cl-list2))) - (setq cl-list1 - (apply 'cl-adjoin (car cl-list2) cl-list1 cl-keys)) - (or (memq (car cl-list2) cl-list1) - (push (car cl-list2) cl-list1))) - (pop cl-list2)) - cl-list1))) + (or (>= (length list1) (length list2)) + (setq list1 (prog1 list2 (setq list2 list1)))) + (while list2 + (if (or cl-keys (numberp (car list2))) + (setq list1 + (apply #'cl-adjoin (car list2) list1 cl-keys)) + (or (memq (car list2) list1) + (push (car list2) list1))) + (pop list2)) + list1))) ;;;###autoload -(defun cl-nunion (cl-list1 cl-list2 &rest cl-keys) +(defun cl-nunion (list1 list2 &rest cl-keys) "Combine LIST1 and LIST2 using a set-union operation. The resulting list contains all items that appear in either LIST1 or LIST2. This is a destructive function; it reuses the storage of LIST1 and LIST2 @@ -878,11 +878,11 @@ whenever possible. \nKeywords supported: :test :test-not :key \n(fn LIST1 LIST2 [KEYWORD VALUE]...)" (declare (important-return-value t)) - (cond ((null cl-list1) cl-list2) ((null cl-list2) cl-list1) - (t (apply 'cl-union cl-list1 cl-list2 cl-keys)))) + (cond ((null list1) list2) ((null list2) list1) + (t (apply #'cl-union list1 list2 cl-keys)))) ;;;###autoload -(defun cl-intersection (cl-list1 cl-list2 &rest cl-keys) +(defun cl-intersection (list1 list2 &rest cl-keys) "Combine LIST1 and LIST2 using a set-intersection operation. The resulting list contains all items that appear in both LIST1 and LIST2. This is a non-destructive function; it makes a copy of the data if necessary @@ -890,23 +890,23 @@ to avoid corrupting the original LIST1 and LIST2. \nKeywords supported: :test :test-not :key \n(fn LIST1 LIST2 [KEYWORD VALUE]...)" (declare (important-return-value t)) - (and cl-list1 cl-list2 - (if (equal cl-list1 cl-list2) cl-list1 + (and list1 list2 + (if (equal list1 list2) list1 (cl--parsing-keywords (:key) (:test :test-not) - (let ((cl-res nil)) - (or (>= (length cl-list1) (length cl-list2)) - (setq cl-list1 (prog1 cl-list2 (setq cl-list2 cl-list1)))) - (while cl-list2 - (if (if (or cl-keys (numberp (car cl-list2))) - (apply 'cl-member (cl--check-key (car cl-list2)) - cl-list1 cl-keys) - (memq (car cl-list2) cl-list1)) - (push (car cl-list2) cl-res)) - (pop cl-list2)) - cl-res))))) + (let ((res nil)) + (or (>= (length list1) (length list2)) + (setq list1 (prog1 list2 (setq list2 list1)))) + (while list2 + (if (if (or cl-keys (numberp (car list2))) + (apply #'cl-member (cl--check-key (car list2)) + list1 cl-keys) + (memq (car list2) list1)) + (push (car list2) res)) + (pop list2)) + res))))) ;;;###autoload -(defun cl-nintersection (cl-list1 cl-list2 &rest cl-keys) +(defun cl-nintersection (list1 list2 &rest cl-keys) "Combine LIST1 and LIST2 using a set-intersection operation. The resulting list contains all items that appear in both LIST1 and LIST2. This is a destructive function; it reuses the storage of LIST1 (but not @@ -914,10 +914,10 @@ LIST2) whenever possible. \nKeywords supported: :test :test-not :key \n(fn LIST1 LIST2 [KEYWORD VALUE]...)" (declare (important-return-value t)) - (and cl-list1 cl-list2 (apply 'cl-intersection cl-list1 cl-list2 cl-keys))) + (and list1 list2 (apply #'cl-intersection list1 list2 cl-keys))) ;;;###autoload -(defun cl-set-difference (cl-list1 cl-list2 &rest cl-keys) +(defun cl-set-difference (list1 list2 &rest cl-keys) "Combine LIST1 and LIST2 using a set-difference operation. The resulting list contains all items that appear in LIST1 but not LIST2. This is a non-destructive function; it makes a copy of the data if necessary @@ -925,20 +925,20 @@ to avoid corrupting the original LIST1 and LIST2. \nKeywords supported: :test :test-not :key \n(fn LIST1 LIST2 [KEYWORD VALUE]...)" (declare (important-return-value t)) - (if (or (null cl-list1) (null cl-list2)) cl-list1 + (if (or (null list1) (null list2)) list1 (cl--parsing-keywords (:key) (:test :test-not) - (let ((cl-res nil)) - (while cl-list1 - (or (if (or cl-keys (numberp (car cl-list1))) - (apply 'cl-member (cl--check-key (car cl-list1)) - cl-list2 cl-keys) - (memq (car cl-list1) cl-list2)) - (push (car cl-list1) cl-res)) - (pop cl-list1)) - (nreverse cl-res))))) + (let ((res nil)) + (while list1 + (or (if (or cl-keys (numberp (car list1))) + (apply #'cl-member (cl--check-key (car list1)) + list2 cl-keys) + (memq (car list1) list2)) + (push (car list1) res)) + (pop list1)) + (nreverse res))))) ;;;###autoload -(defun cl-nset-difference (cl-list1 cl-list2 &rest cl-keys) +(defun cl-nset-difference (list1 list2 &rest cl-keys) "Combine LIST1 and LIST2 using a set-difference operation. The resulting list contains all items that appear in LIST1 but not LIST2. This is a destructive function; it reuses the storage of LIST1 (but not @@ -946,11 +946,11 @@ LIST2) whenever possible. \nKeywords supported: :test :test-not :key \n(fn LIST1 LIST2 [KEYWORD VALUE]...)" (declare (important-return-value t)) - (if (or (null cl-list1) (null cl-list2)) cl-list1 - (apply 'cl-set-difference cl-list1 cl-list2 cl-keys))) + (if (or (null list1) (null list2)) list1 + (apply #'cl-set-difference list1 list2 cl-keys))) ;;;###autoload -(defun cl-set-exclusive-or (cl-list1 cl-list2 &rest cl-keys) +(defun cl-set-exclusive-or (list1 list2 &rest cl-keys) "Combine LIST1 and LIST2 using a set-exclusive-or operation. The resulting list contains all items appearing in exactly one of LIST1, LIST2. This is a non-destructive function; it makes a copy of the data if necessary @@ -958,13 +958,13 @@ to avoid corrupting the original LIST1 and LIST2. \nKeywords supported: :test :test-not :key \n(fn LIST1 LIST2 [KEYWORD VALUE]...)" (declare (important-return-value t)) - (cond ((null cl-list1) cl-list2) ((null cl-list2) cl-list1) - ((equal cl-list1 cl-list2) nil) - (t (append (apply 'cl-set-difference cl-list1 cl-list2 cl-keys) - (apply 'cl-set-difference cl-list2 cl-list1 cl-keys))))) + (cond ((null list1) list2) ((null list2) list1) + ((equal list1 list2) nil) + (t (append (apply #'cl-set-difference list1 list2 cl-keys) + (apply #'cl-set-difference list2 list1 cl-keys))))) ;;;###autoload -(defun cl-nset-exclusive-or (cl-list1 cl-list2 &rest cl-keys) +(defun cl-nset-exclusive-or (list1 list2 &rest cl-keys) "Combine LIST1 and LIST2 using a set-exclusive-or operation. The resulting list contains all items appearing in exactly one of LIST1, LIST2. This is a destructive function; it reuses the storage of LIST1 and LIST2 @@ -972,141 +972,143 @@ whenever possible. \nKeywords supported: :test :test-not :key \n(fn LIST1 LIST2 [KEYWORD VALUE]...)" (declare (important-return-value t)) - (cond ((null cl-list1) cl-list2) ((null cl-list2) cl-list1) - ((equal cl-list1 cl-list2) nil) - (t (nconc (apply 'cl-nset-difference cl-list1 cl-list2 cl-keys) - (apply 'cl-nset-difference cl-list2 cl-list1 cl-keys))))) + (cond ((null list1) list2) ((null list2) list1) + ((equal list1 list2) nil) + (t (nconc (apply #'cl-nset-difference list1 list2 cl-keys) + (apply #'cl-nset-difference list2 list1 cl-keys))))) ;;;###autoload -(defun cl-subsetp (cl-list1 cl-list2 &rest cl-keys) +(defun cl-subsetp (list1 list2 &rest cl-keys) "Return true if LIST1 is a subset of LIST2. I.e., if every element of LIST1 also appears in LIST2. \nKeywords supported: :test :test-not :key \n(fn LIST1 LIST2 [KEYWORD VALUE]...)" (declare (important-return-value t)) - (cond ((null cl-list1) t) ((null cl-list2) nil) - ((equal cl-list1 cl-list2) t) + (cond ((null list1) t) ((null list2) nil) + ((equal list1 list2) t) (t (cl--parsing-keywords (:key) (:test :test-not) - (while (and cl-list1 - (apply 'cl-member (cl--check-key (car cl-list1)) - cl-list2 cl-keys)) - (pop cl-list1)) - (null cl-list1))))) + (while (and list1 + (apply #'cl-member (cl--check-key (car list1)) + list2 cl-keys)) + (pop list1)) + (null list1))))) ;;;###autoload -(defun cl-subst-if (cl-new cl-pred cl-tree &rest cl-keys) +(defun cl-subst-if (new pred tree &rest cl-keys) "Substitute NEW for elements matching PREDICATE in TREE (non-destructively). Return a copy of TREE with all matching elements replaced by NEW. \nKeywords supported: :key \n(fn NEW PREDICATE TREE [KEYWORD VALUE]...)" (declare (important-return-value t)) - (apply 'cl-sublis (list (cons nil cl-new)) cl-tree :if cl-pred cl-keys)) + (apply #'cl-sublis (list (cons nil new)) tree :if pred cl-keys)) ;;;###autoload -(defun cl-subst-if-not (cl-new cl-pred cl-tree &rest cl-keys) +(defun cl-subst-if-not (new pred tree &rest cl-keys) "Substitute NEW for elts not matching PREDICATE in TREE (non-destructively). Return a copy of TREE with all non-matching elements replaced by NEW. \nKeywords supported: :key \n(fn NEW PREDICATE TREE [KEYWORD VALUE]...)" (declare (important-return-value t)) - (apply 'cl-sublis (list (cons nil cl-new)) cl-tree :if-not cl-pred cl-keys)) + (apply #'cl-sublis (list (cons nil new)) tree :if-not pred cl-keys)) ;;;###autoload -(defun cl-nsubst (cl-new cl-old cl-tree &rest cl-keys) +(defun cl-nsubst (new old tree &rest cl-keys) "Substitute NEW for OLD everywhere in TREE (destructively). Any element of TREE which is `eql' to OLD is changed to NEW (via a call to `setcar'). \nKeywords supported: :test :test-not :key \n(fn NEW OLD TREE [KEYWORD VALUE]...)" (declare (important-return-value t)) - (apply 'cl-nsublis (list (cons cl-old cl-new)) cl-tree cl-keys)) + (apply #'cl-nsublis (list (cons old new)) tree cl-keys)) ;;;###autoload -(defun cl-nsubst-if (cl-new cl-pred cl-tree &rest cl-keys) +(defun cl-nsubst-if (new pred tree &rest cl-keys) "Substitute NEW for elements matching PREDICATE in TREE (destructively). Any element of TREE which matches is changed to NEW (via a call to `setcar'). \nKeywords supported: :key \n(fn NEW PREDICATE TREE [KEYWORD VALUE]...)" (declare (important-return-value t)) - (apply 'cl-nsublis (list (cons nil cl-new)) cl-tree :if cl-pred cl-keys)) + (apply #'cl-nsublis (list (cons nil new)) tree :if pred cl-keys)) ;;;###autoload -(defun cl-nsubst-if-not (cl-new cl-pred cl-tree &rest cl-keys) +(defun cl-nsubst-if-not (new pred tree &rest cl-keys) "Substitute NEW for elements not matching PREDICATE in TREE (destructively). Any element of TREE which matches is changed to NEW (via a call to `setcar'). \nKeywords supported: :key \n(fn NEW PREDICATE TREE [KEYWORD VALUE]...)" (declare (important-return-value t)) - (apply 'cl-nsublis (list (cons nil cl-new)) cl-tree :if-not cl-pred cl-keys)) + (apply #'cl-nsublis (list (cons nil new)) tree :if-not pred cl-keys)) (defvar cl--alist) ;;;###autoload -(defun cl-sublis (cl-alist cl-tree &rest cl-keys) +(defun cl-sublis (alist tree &rest cl-keys) "Perform substitutions indicated by ALIST in TREE (non-destructively). Return a copy of TREE with all matching elements replaced. \nKeywords supported: :test :test-not :key \n(fn ALIST TREE [KEYWORD VALUE]...)" (declare (important-return-value t)) (cl--parsing-keywords (:test :test-not :key :if :if-not) () - (let ((cl--alist cl-alist)) - (cl--sublis-rec cl-tree)))) - -(defun cl--sublis-rec (cl-tree) ;Uses cl--alist cl-key/test*/if*. - (let ((cl-temp (cl--check-key cl-tree)) (cl-p cl--alist)) - (while (and cl-p (not (cl--check-test-nokey (car (car cl-p)) cl-temp))) - (setq cl-p (cdr cl-p))) - (if cl-p (cdr (car cl-p)) - (if (consp cl-tree) - (let ((cl-a (cl--sublis-rec (car cl-tree))) - (cl-d (cl--sublis-rec (cdr cl-tree)))) - (if (and (eq cl-a (car cl-tree)) (eq cl-d (cdr cl-tree))) - cl-tree - (cons cl-a cl-d))) - cl-tree)))) + (let ((cl--alist alist)) + (cl--sublis-rec tree)))) + +(defun cl--sublis-rec (tree) ;Uses cl--alist cl-key/test*/if*. + (let ((temp (cl--check-key tree)) + (p cl--alist)) + (while (and p (not (cl--check-test-nokey (car (car p)) temp))) + (setq p (cdr p))) + (if p (cdr (car p)) + (if (consp tree) + (let ((a (cl--sublis-rec (car tree))) + (d (cl--sublis-rec (cdr tree)))) + (if (and (eq a (car tree)) (eq d (cdr tree))) + tree + (cons a d))) + tree)))) ;;;###autoload -(defun cl-nsublis (cl-alist cl-tree &rest cl-keys) +(defun cl-nsublis (alist tree &rest cl-keys) "Perform substitutions indicated by ALIST in TREE (destructively). Any matching element of TREE is changed via a call to `setcar'. \nKeywords supported: :test :test-not :key \n(fn ALIST TREE [KEYWORD VALUE]...)" (declare (important-return-value t)) (cl--parsing-keywords (:test :test-not :key :if :if-not) () - (let ((cl-hold (list cl-tree)) - (cl--alist cl-alist)) - (cl--nsublis-rec cl-hold) - (car cl-hold)))) - -(defun cl--nsublis-rec (cl-tree) ;Uses cl--alist cl-key/test*/if*. - (while (consp cl-tree) - (let ((cl-temp (cl--check-key (car cl-tree))) (cl-p cl--alist)) - (while (and cl-p (not (cl--check-test-nokey (car (car cl-p)) cl-temp))) - (setq cl-p (cdr cl-p))) - (if cl-p (setcar cl-tree (cdr (car cl-p))) - (if (consp (car cl-tree)) (cl--nsublis-rec (car cl-tree)))) - (setq cl-temp (cl--check-key (cdr cl-tree)) cl-p cl--alist) - (while (and cl-p (not (cl--check-test-nokey (car (car cl-p)) cl-temp))) - (setq cl-p (cdr cl-p))) - (if cl-p - (progn (setcdr cl-tree (cdr (car cl-p))) (setq cl-tree nil)) - (setq cl-tree (cdr cl-tree)))))) + (let ((hold (list tree)) + (cl--alist alist)) + (cl--nsublis-rec hold) + (car hold)))) + +(defun cl--nsublis-rec (tree) ;Uses cl--alist cl-key/test*/if*. + (while (consp tree) + (let ((temp (cl--check-key (car tree))) + (p cl--alist)) + (while (and p (not (cl--check-test-nokey (car (car p)) temp))) + (setq p (cdr p))) + (if p (setcar tree (cdr (car p))) + (if (consp (car tree)) (cl--nsublis-rec (car tree)))) + (setq temp (cl--check-key (cdr tree)) p cl--alist) + (while (and p (not (cl--check-test-nokey (car (car p)) temp))) + (setq p (cdr p))) + (if p + (progn (setcdr tree (cdr (car p))) (setq tree nil)) + (setq tree (cdr tree)))))) ;;;###autoload -(defun cl-tree-equal (cl-x cl-y &rest cl-keys) +(defun cl-tree-equal (x y &rest cl-keys) "Return t if trees TREE1 and TREE2 have `eql' leaves. Atoms are compared by `eql'; cons cells are compared recursively. \nKeywords supported: :test :test-not :key \n(fn TREE1 TREE2 [KEYWORD VALUE]...)" (declare (important-return-value t)) (cl--parsing-keywords (:test :test-not :key) () - (cl--tree-equal-rec cl-x cl-y))) + (cl--tree-equal-rec x y))) -(defun cl--tree-equal-rec (cl-x cl-y) ;Uses cl-key/test*. - (while (and (consp cl-x) (consp cl-y) - (cl--tree-equal-rec (car cl-x) (car cl-y))) - (setq cl-x (cdr cl-x) cl-y (cdr cl-y))) - (and (not (consp cl-x)) (not (consp cl-y)) (cl--check-match cl-x cl-y))) +(defun cl--tree-equal-rec (x y) ;Uses cl-key/test*. + (while (and (consp x) (consp y) + (cl--tree-equal-rec (car x) (car y))) + (setq x (cdr x) y (cdr y))) + (and (not (consp x)) (not (consp y)) (cl--check-match x y))) (make-obsolete-variable 'cl-seq-load-hook commit 22308762658b3dae69731d1f9a30e97c24d75f89 Author: Stefan Kangas Date: Wed Mar 5 02:23:15 2025 +0100 ; * etc/symbol-releases.eld: Add cl-defun. diff --git a/etc/symbol-releases.eld b/etc/symbol-releases.eld index bed8c448a43..4d5ba1ca606 100644 --- a/etc/symbol-releases.eld +++ b/etc/symbol-releases.eld @@ -42,6 +42,7 @@ ("26.1" fun cdddar) ("26.1" fun cddddr) ("24.4" fun set-transient-map) + ("24.3" fun cl-defun) ("22.1" fun clear-string) ("22.1" fun version=) ("22.1" fun version<) @@ -56,8 +57,8 @@ ;; damaged. See ;; https://github.com/larsbrinkhoff/emacs-history/tree/sources/decuslib.com/decus/vax85b/gnuemax - ("19.7" fun defsubst) ("19.34" fun make-directory) + ("19.7" fun defsubst) ("18.59" fun mark) ("13.8" fun nthcdr) ("13.8" fun nreverse) commit 7678047a8ad4e6fbf84a64b1cf56b504f1cdaa38 Author: Po Lu Date: Wed Mar 5 09:03:50 2025 +0800 ; * etc/NEWS: Rearrange lightly. diff --git a/etc/NEWS b/etc/NEWS index 39c62756085..dac447d1ba5 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -29,19 +29,7 @@ applies, and please also update docstrings as needed. The traditional unexec dumper, deprecated since Emacs 27, has been removed. - -* MacOS/NS Changes in Emacs 31.1 - --- -** New user option 'ns-click-through' controls whether activation clicks -are passed through to Emacs commands. -When nil, clicking on an inactive Emacs frame will only activate it. -When t (the default), the click will both activate the frame and be interpreted -as a command. - -+++ -** On Cocoa builds, stipples now render with color. (Bug#73384) - ** Changed GCC default options on 32-bit x86 systems. When using GCC 4 or later to build Emacs on 32-bit x86 systems, 'configure' now defaults to using the GCC options '-mfpmath=sse' (if the @@ -1407,6 +1395,13 @@ It is believed to no longer be useful as a method to fight spam. --- *** kermit.el is now obsolete. +--- +*** New user option 'ns-click-through' on Nextstep (GNUstep/Mac OS). +This controls whether activation clicks are passed through to Emacs +commands. When nil, clicking on an inactive Emacs frame will only +activate it. When t (the default), the click will both activate the +frame and be interpreted as a command. + * New Modes and Packages in Emacs 31.1 @@ -1823,6 +1818,9 @@ Accordingly, we have revised our recommendations for a suitable DJGPP toolchain to GCC 14.2.0 and Binutils 2.35.1 in lieu of GCC 3.4.x and Binutils 2.26. ++++ +** On Mac OS X, stipples now render with color. + ---------------------------------------------------------------------- This file is part of GNU Emacs. commit c18089a6585b319786894262ae0a9034dfbcbcd4 Author: Stefan Kangas Date: Tue Mar 4 22:47:59 2025 +0100 Avoid rare warning when byte-compiling cl-loaddefs.el * lisp/emacs-lisp/cl-extra.el: Add autoloaded declare-function to avoid rare byte-compilation warning. Problem reported by Eli Zaretskii . diff --git a/lisp/emacs-lisp/cl-extra.el b/lisp/emacs-lisp/cl-extra.el index 584945dae59..0e77b4543bd 100644 --- a/lisp/emacs-lisp/cl-extra.el +++ b/lisp/emacs-lisp/cl-extra.el @@ -124,7 +124,7 @@ strings case-insensitively." (if (consp cl-y) (pop cl-y) (aref cl-y cl-i))))) (when acc (push val cl-res))))) - (and acc (nreverse cl-res))))) + (and acc (nreverse cl-res))))) ;;;###autoload (defsubst cl-map (cl-type cl-func cl-seq &rest cl-rest) @@ -132,7 +132,7 @@ strings case-insensitively." TYPE is the sequence type to return. \n(fn TYPE FUNCTION SEQUENCE...)" (declare (important-return-value t)) - (let ((cl-res (apply #'cl-mapcar cl-func cl-seq cl-rest))) + (let ((cl-res (apply 'cl-mapcar cl-func cl-seq cl-rest))) (and cl-type (cl-coerce cl-res cl-type)))) ;;;###autoload commit e978737f57ef8447bba5796dd945ac185fcadffa Author: Philipp Stephani Date: Tue Mar 4 20:50:50 2025 +0100 Make Emacs buildable with -std=c11. With -std=c11, GCC doesn't recognize 'asm' as a keyword, see https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html and https://gcc.gnu.org/onlinedocs/gcc/Alternate-Keywords.html. Use __asm__ instead. * src/lisp.h (flush_stack_call_func): Use __asm__ instead of asm. diff --git a/src/lisp.h b/src/lisp.h index 46844be1eca..bd5029f7a6f 100644 --- a/src/lisp.h +++ b/src/lisp.h @@ -4465,7 +4465,7 @@ flush_stack_call_func (void (*func) (void *arg), void *arg) '__builtin_unwind_init' ineffective (bug#65727). See . */ #if defined __GNUC__ && !defined __clang__ && !defined __OBJC__ - asm (""); + __asm__ (""); #endif } commit 4be2574851b96f6adff6b621a159c1afa710b1ee Author: F. Jason Park Date: Sat Mar 1 06:26:33 2025 -0800 ; Use ert-skip instead of skip-when in erc-match test * test/lisp/erc/erc-match-tests.el (erc-add-entry-to-list): The local macro `skip-when' first appeared in Emacs 30, but ERC supports Emacs 27+ and runs its test suite on all supported versions. * test/lisp/erc/erc-scenarios-keep-place-indicator.el (erc-scenarios-keep-place-indicator--follow): Temporarily tag as :unstable in all CI environments. diff --git a/test/lisp/erc/erc-match-tests.el b/test/lisp/erc/erc-match-tests.el index 7c960fc7f0a..09a5394fb3c 100644 --- a/test/lisp/erc/erc-match-tests.el +++ b/test/lisp/erc/erc-match-tests.el @@ -29,7 +29,9 @@ (ert-deftest erc-add-entry-to-list () ;; These tests currently freeze in Android. - (skip-when (featurep 'android)) + (when (featurep 'android) + (ert-skip "Freezes on Android as of 31.0.50")) + (let ((erc-pals '("z")) (erc-match-quote-when-adding 'ask)) diff --git a/test/lisp/erc/erc-scenarios-keep-place-indicator.el b/test/lisp/erc/erc-scenarios-keep-place-indicator.el index e89560ae772..cb82e3ff84a 100644 --- a/test/lisp/erc/erc-scenarios-keep-place-indicator.el +++ b/test/lisp/erc/erc-scenarios-keep-place-indicator.el @@ -31,7 +31,7 @@ ;; away, the indicator is updated if it's earlier in the buffer. (ert-deftest erc-scenarios-keep-place-indicator--follow () :tags `(:expensive-test - ,@(and (getenv "EMACS_EMBA_CI") '(:unstable)) + ,@(and (getenv "CI") '(:unstable)) ,@(and (getenv "ERC_TESTS_GRAPHICAL") '(:erc--graphical))) (when (version< emacs-version "29") (ert-skip "Times out")) ;; XXX verify that this continues to be the case ^. commit 3a8ce5ac9c4652eb87bf0bce835d82083061a28b Author: Daniel Colascione Date: Tue Mar 4 08:14:43 2025 -0800 Add ns-click-through option to control activation click handling * src/nsterm.m (acceptsFirstMouse): Use ns_click_through variable instead of always returning YES. (syms_of_nsterm): Define ns-click-through variable. * lisp/cus-start.el: Add customization definition for ns-click-through. * etc/NEWS: Document the new option. diff --git a/etc/NEWS b/etc/NEWS index 67f9ed84bdf..39c62756085 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -29,6 +29,19 @@ applies, and please also update docstrings as needed. The traditional unexec dumper, deprecated since Emacs 27, has been removed. + +* MacOS/NS Changes in Emacs 31.1 + +--- +** New user option 'ns-click-through' controls whether activation clicks +are passed through to Emacs commands. +When nil, clicking on an inactive Emacs frame will only activate it. +When t (the default), the click will both activate the frame and be interpreted +as a command. + ++++ +** On Cocoa builds, stipples now render with color. (Bug#73384) + ** Changed GCC default options on 32-bit x86 systems. When using GCC 4 or later to build Emacs on 32-bit x86 systems, 'configure' now defaults to using the GCC options '-mfpmath=sse' (if the diff --git a/lisp/cus-start.el b/lisp/cus-start.el index c6e4da6790e..c6cdd5cc2e7 100644 --- a/lisp/cus-start.el +++ b/lisp/cus-start.el @@ -582,6 +582,12 @@ Leaving \"Default\" unchecked is equivalent with specifying a default of (ns-use-fullscreen-animation ns boolean "25.1") (ns-use-srgb-colorspace ns boolean "24.4") (ns-scroll-event-delta-factor ns float "29.1") + + (ns-click-through + ns (choice (const :tag "Never (nil)" :value nil) + (const :tag "Always (t)" :value t)) + "31.1") + ;; process.c (delete-exited-processes processes-basics boolean) (process-error-pause-time processes-basics integer "29.1") diff --git a/src/nsterm.m b/src/nsterm.m index e7108c817c8..fcd9377646f 100644 --- a/src/nsterm.m +++ b/src/nsterm.m @@ -6891,7 +6891,7 @@ - (BOOL)acceptsFirstMouse:(NSEvent *)theEvent { NSTRACE_MSG ("First mouse event: type=%ld, clickCount=%ld", [theEvent type], [theEvent clickCount]); - return YES; + return ns_click_through; } - (void)resetCursorRects { @@ -11300,6 +11300,21 @@ Nil means use fullscreen the old (< 10.7) way. The old way works better with doc: /* SKIP: real doc in xterm.c. */); x_underline_at_descent_line = 0; + // TODO: add an "auto" mode that passes clicks through to "utility" UI + // elements, selectis windows, and so on, but doesn't pass them + // through for commands in general --- consistent with + // other applications. + + DEFVAR_BOOL ("ns-click-through", + ns_click_through, + doc: /* Whether to pass activation clicks through to Emacs. +When nil, if Emacs is not focused, the click that focuses Emacs will not +be interpreted as a common. If t, it will be. For example, when nil, +if Emacs is inactive, two clicks are needed to move point: the first to +activate Emacs and the second to activate the mouse-1 binding. When t, +only a single click is needed. */); + ns_click_through = YES; + DEFSYM (Qx_underline_at_descent_line, "x-underline-at-descent-line"); DEFVAR_LISP ("ns-scroll-event-delta-factor", Vns_scroll_event_delta_factor, commit 59fcb2aa1b2a827f1822b3bc2c9024f5a47338e7 Author: Eli Zaretskii Date: Tue Mar 4 17:23:16 2025 +0200 ; * lisp/register.el (register-use-preview): Doc fix (bug#76739). diff --git a/lisp/register.el b/lisp/register.el index 31214ae3ba0..b0ee759ec5b 100644 --- a/lisp/register.el +++ b/lisp/register.el @@ -146,7 +146,10 @@ all; the preview buffer is still accessible with `help-char' (\\`C-h'). When set to `traditional' (the default), provide a more basic preview according to `register-preview-delay'; this preserves the traditional -behavior of Emacs 29 and before." +behavior of Emacs 29 and before. + +Setting this variable with `setq' has no effect; use either `setopt' +or `customize-option' to change its value." :type '(choice (const :tag "Use preview" t) (const :tag "Use preview and exit by pressing register name" insist) commit 0383937a7014934e7a9b3cf0c33c2d1f46e83901 Author: Eli Zaretskii Date: Tue Mar 4 16:01:32 2025 +0200 ; Improve documentation of 'shortdoc' * lisp/emacs-lisp/shortdoc.el (shortdoc-display-group): Fix doc string and wording of prompt. (Bug#76723) diff --git a/lisp/emacs-lisp/shortdoc.el b/lisp/emacs-lisp/shortdoc.el index 230df47821c..e74167cb1c7 100644 --- a/lisp/emacs-lisp/shortdoc.el +++ b/lisp/emacs-lisp/shortdoc.el @@ -1468,10 +1468,12 @@ A FUNC form can have any number of `:no-eval' (or `:no-value'), ;;;###autoload (defun shortdoc-display-group (group &optional function same-window) "Pop to a buffer with short documentation summary for functions in GROUP. +Interactively, prompt for GROUP. If FUNCTION is non-nil, place point on the entry for FUNCTION (if any). If SAME-WINDOW, don't pop to a new window." - (interactive (list (completing-read "Show summary for functions in: " - (mapcar #'car shortdoc--groups)))) + (interactive (list (completing-read + "Group of functions for which to show summary: " + (mapcar #'car shortdoc--groups)))) (when (stringp group) (setq group (intern group))) (unless (assq group shortdoc--groups) commit a382bfdfa4b8692bcb971eec1516e37a58b3fc2f Author: Eli Zaretskii Date: Tue Mar 4 15:45:33 2025 +0200 Fix 'etc/DOC' for a few functions/variables * src/term.c (Ftty_frame_at): * src/menu.c (syms_of_menu) : * src/dispnew.c (Fredisplay): Fix "doc:". The extra blank was preventing 'make-docfile' from recognizing the functions and variables and extracting their documentation to 'etc/DOC'. (Bug#76722) diff --git a/src/dispnew.c b/src/dispnew.c index 511cf5634e5..4f4dcdf1dfb 100644 --- a/src/dispnew.c +++ b/src/dispnew.c @@ -6948,7 +6948,7 @@ sit_for (Lisp_Object timeout, bool reading, int display_option) DEFUN ("redisplay", Fredisplay, Sredisplay, 0, 1, 0, - doc : /* Perform redisplay. + doc: /* Perform redisplay. Optional arg FORCE exists for historical reasons and is ignored. Value is t if redisplay has been performed, nil if executing a keyboard macro. */) diff --git a/src/menu.c b/src/menu.c index d98135afbfd..ec6b9286982 100644 --- a/src/menu.c +++ b/src/menu.c @@ -1628,7 +1628,7 @@ won't be run if `x-popup-menu' fails or returns for some other reason Vx_pre_popup_menu_hook = Qnil; DEFVAR_LISP ("x-popup-menu-function", Vx_popup_menu_function, - doc : /* Function to call to pop up a menu. + doc: /* Function to call to pop up a menu. The function is called like `x-popup-menu'. This is currently only used for frames on text terminals. */); Vx_popup_menu_function = Qnil; diff --git a/src/term.c b/src/term.c index cd4c1f45426..6990978ecfb 100644 --- a/src/term.c +++ b/src/term.c @@ -2673,7 +2673,7 @@ tty_frame_at (int x, int y, int *cx, int *cy) } DEFUN ("tty-frame-at", Ftty_frame_at, Stty_frame_at, 2, 2, 0, - doc : /* Return tty frame containing absolute pixel position (X, Y). + doc: /* Return tty frame containing absolute pixel position (X, Y). Value is nil if no frame found. Otherwise it is a list (FRAME CX CY), where FRAME is the frame containing (X, Y) and CX and CY are X and Y relative to FRAME. */) commit 25e2656dd9246672353c5f635b365005cb0e0546 Author: Po Lu Date: Tue Mar 4 21:10:36 2025 +0800 ; * src/nsterm.m (ns_draw_stretch_glyph_string): One more spelling fix. diff --git a/src/nsterm.m b/src/nsterm.m index 55e248ca1c2..e7108c817c8 100644 --- a/src/nsterm.m +++ b/src/nsterm.m @@ -4223,7 +4223,7 @@ Function modeled after x_draw_glyph_string_box (). CGContextClipToRect (context, bounds); CGContextScaleCTM (context, 1, -1); - /* Stamp the foreground colour using the stipple mask. */ + /* Stamp the foreground color using the stipple mask. */ [[NSColor colorWithUnsignedLong:s->face->foreground] set]; CGRect imageSize = CGRectMake (0, 0, CGImageGetWidth (mask), CGImageGetHeight (mask)); commit cd0a8c00a7dbb5a3bff653404a9f970b37c7db78 Author: Po Lu Date: Tue Mar 4 21:09:47 2025 +0800 ; Fix style and language in src/nsterm.m * src/nsterm.m (ns_maybe_dumpglyphs_background) (ns_draw_stretch_glyph_string): Fix coding style. Use American English spelling. diff --git a/src/nsterm.m b/src/nsterm.m index 745addfc46c..55e248ca1c2 100644 --- a/src/nsterm.m +++ b/src/nsterm.m @@ -3826,8 +3826,8 @@ Function modeled after x_draw_glyph_string_box (). s->height - 2 * box_line_width); NSRectFill (r); s->background_filled_p = 1; - CGImageRef mask = - [dpyinfo->bitmaps[face->stipple - 1].img stippleMask]; + CGImageRef mask + = [dpyinfo->bitmaps[face->stipple - 1].img stippleMask]; /* This part could possibly be improved, the author is unfamiliar with NS/CoreGraphics and isn't sure if it's @@ -4205,25 +4205,25 @@ Function modeled after x_draw_glyph_string_box (). #ifdef NS_IMPL_COCOA /* On cocoa emacs the stipple is stored as a mask CGImage. First we want to clear the background with the bg - colour */ + color. */ [[NSColor colorWithUnsignedLong:s->face->background] set]; NSRectFill (NSMakeRect (x, s->y, background_width, s->height)); /* This part could possibly be improved, the author is unfamiliar with NS/CoreGraphics and isn't sure if it's - possible to do this with NSImage */ + possible to do this with NSImage. */ CGImageRef mask = [dpyinfo->bitmaps[s->face->stipple - 1].img stippleMask]; CGRect bounds = CGRectMake (s->x, s->y, s->background_width, s->height); /* Checkpoint the graphics state and then focus in on the - area we're going to fill */ + area we're going to fill. */ NSGraphicsContext *ctx = [NSGraphicsContext currentContext]; [ctx saveGraphicsState]; CGContextRef context = [ctx CGContext]; - CGContextClipToRect(context, bounds); + CGContextClipToRect (context, bounds); CGContextScaleCTM (context, 1, -1); - /* Stamp the foreground colour using the stipple mask */ + /* Stamp the foreground colour using the stipple mask. */ [[NSColor colorWithUnsignedLong:s->face->foreground] set]; CGRect imageSize = CGRectMake (0, 0, CGImageGetWidth (mask), CGImageGetHeight (mask)); commit 9cbbdcee132588a11dc03c3da371176aaa13927c Author: Ben Simms Date: Sun Jan 5 20:03:53 2025 +0100 Support colored stipples on Cocoa NS (Bug#73384) On Cocoa builds of NS Emacs, stipples are now rendered using masked CGImages instead of patterned NSColors so that stipples now render with color. * src/nsimage.m ([EmacsImage stippleMask:]): Use a CGImageMask to store the stipple mask when building for Cocoa. * src/nsterm.m (ns_maybe_dumpglyphs_background): Perform a masked fill to draw stipples when building for Cocoa. (ns_draw_stretch_glyph_string): Perform a masked fill to draw stipples when building for Cocoa. diff --git a/src/nsimage.m b/src/nsimage.m index e8c82269bce..8f1653d085a 100644 --- a/src/nsimage.m +++ b/src/nsimage.m @@ -35,6 +35,9 @@ Updated by Christian Limpach (chris@nice.ch) #include "frame.h" #include "coding.h" +#ifdef NS_IMPL_COCOA +#include +#endif #if defined (NS_IMPL_GNUSTEP) || MAC_OS_X_VERSION_MAX_ALLOWED < 1070 # define COLORSPACE_NAME NSCalibratedRGBColorSpace @@ -289,7 +292,11 @@ + (instancetype)allocInitFromFile: (Lisp_Object)file - (void)dealloc { +#ifdef NS_IMPL_COCOA + CGImageRelease(stippleMask); +#else [stippleMask release]; +#endif [bmRep release]; [transform release]; [super dealloc]; @@ -300,7 +307,11 @@ - (id)copyWithZone:(NSZone *)zone { EmacsImage *copy = [super copyWithZone:zone]; +#ifdef NS_IMPL_COCOA + copy->stippleMask = CGImageCreateCopy(stippleMask); +#else copy->stippleMask = [stippleMask copyWithZone:zone]; +#endif /* NS_IMPL_COCOA */ copy->bmRep = [bmRep copyWithZone:zone]; copy->transform = [transform copyWithZone:zone]; @@ -509,6 +520,25 @@ - (void) setAlphaAtX: (int) x Y: (int) y to: (unsigned char) a } } +#ifdef NS_IMPL_COCOA +/* Returns a cached CGImageMask of the stipple pattern */ +- (CGImageRef)stippleMask +{ + if (stippleMask == nil) + { + CGDataProviderRef provider = CGDataProviderCreateWithData (NULL, [bmRep bitmapData], + [self sizeInBytes], NULL); + CGImageRef mask = CGImageMaskCreate([self size].width, + [self size].height, + 8, 8, [self size].width, + provider, NULL, 0); + + CGDataProviderRelease(provider); + stippleMask = CGImageRetain(mask); + } + return stippleMask; +} +#else /* Returns a pattern color, which is cached here. */ - (NSColor *)stippleMask { @@ -516,6 +546,7 @@ - (NSColor *)stippleMask stippleMask = [[NSColor colorWithPatternImage: self] retain]; return stippleMask; } +#endif /* NS_IMPL_COCOA */ /* Find the first NSBitmapImageRep which has multiple frames. */ - (NSBitmapImageRep *)getAnimatedBitmapImageRep diff --git a/src/nsterm.h b/src/nsterm.h index d03908eb521..0009f1ab2bf 100644 --- a/src/nsterm.h +++ b/src/nsterm.h @@ -671,7 +671,11 @@ enum ns_return_frame_mode { NSBitmapImageRep *bmRep; /* used for accessing pixel data */ unsigned char *pixmapData[5]; /* shortcut to access pixel data */ +#ifdef NS_IMPL_COCOA + CGImageRef stippleMask; +#else NSColor *stippleMask; +#endif /* NS_IMPL_COCOA */ @public NSAffineTransform *transform; BOOL smoothing; @@ -688,7 +692,11 @@ enum ns_return_frame_mode green: (unsigned char)g blue: (unsigned char)b alpha:(unsigned char)a; - (void)setAlphaAtX: (int)x Y: (int)y to: (unsigned char)a; +#ifdef NS_IMPL_COCOA +- (CGImageRef)stippleMask; +#else - (NSColor *)stippleMask; +#endif /* NS_IMPL_COCOA */ - (Lisp_Object)getMetadata; - (BOOL)setFrame: (unsigned int) index; - (void)setTransform: (double[3][3]) m; diff --git a/src/nsterm.m b/src/nsterm.m index 12141dfac44..745addfc46c 100644 --- a/src/nsterm.m +++ b/src/nsterm.m @@ -3817,8 +3817,41 @@ Function modeled after x_draw_glyph_string_box (). if (s->stippled_p) { struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (s->f); +#ifdef NS_IMPL_COCOA + /* On cocoa emacs the stipple is stored as a mask CGImage. + First we want to clear the background with the bg colour */ + [[NSColor colorWithUnsignedLong:face->background] set]; + r = NSMakeRect (s->x, s->y + box_line_width, + s->background_width, + s->height - 2 * box_line_width); + NSRectFill (r); + s->background_filled_p = 1; + CGImageRef mask = + [dpyinfo->bitmaps[face->stipple - 1].img stippleMask]; + + /* This part could possibly be improved, the author is + unfamiliar with NS/CoreGraphics and isn't sure if it's + possible to do this with NSImage */ + NSGraphicsContext *ctx = [NSGraphicsContext currentContext]; + [ctx saveGraphicsState]; + /* Checkpoint the graphics state and then focus in on the area + we're going to fill */ + CGContextRef context = [ctx CGContext]; + CGContextClipToRect (context, r); + CGContextScaleCTM (context, 1, -1); + + /* Stamp the foreground colour using the stipple mask */ + [[NSColor colorWithUnsignedLong:face->foreground] set]; + CGRect imageSize = CGRectMake (0, 0, CGImageGetWidth (mask), + CGImageGetHeight (mask)); + CGContextDrawTiledImage (context, imageSize, mask); + + [[NSGraphicsContext currentContext] restoreGraphicsState]; +#else [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set]; goto fill; +#endif /* NS_IMPL_COCOA */ + } else if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width /* When xdisp.c ignores FONT_HEIGHT, we cannot trust font @@ -3841,7 +3874,9 @@ Function modeled after x_draw_glyph_string_box (). else [FRAME_CURSOR_COLOR (s->f) set]; +#ifndef NS_IMPL_COCOA fill: +#endif /* !NS_IMPL_COCOA */ r = NSMakeRect (s->x, s->y + box_line_width, s->background_width, s->height - 2 * box_line_width); @@ -4166,7 +4201,38 @@ Function modeled after x_draw_glyph_string_box (). if (s->hl == DRAW_CURSOR) [FRAME_CURSOR_COLOR (s->f) set]; else if (s->stippled_p) - [[dpyinfo->bitmaps[s->face->stipple - 1].img stippleMask] set]; + { +#ifdef NS_IMPL_COCOA + /* On cocoa emacs the stipple is stored as a mask CGImage. + First we want to clear the background with the bg + colour */ + [[NSColor colorWithUnsignedLong:s->face->background] set]; + NSRectFill (NSMakeRect (x, s->y, background_width, s->height)); + + /* This part could possibly be improved, the author is + unfamiliar with NS/CoreGraphics and isn't sure if it's + possible to do this with NSImage */ + CGImageRef mask = [dpyinfo->bitmaps[s->face->stipple - 1].img stippleMask]; + CGRect bounds = CGRectMake (s->x, s->y, s->background_width, s->height); + + /* Checkpoint the graphics state and then focus in on the + area we're going to fill */ + NSGraphicsContext *ctx = [NSGraphicsContext currentContext]; + [ctx saveGraphicsState]; + CGContextRef context = [ctx CGContext]; + CGContextClipToRect(context, bounds); + CGContextScaleCTM (context, 1, -1); + + /* Stamp the foreground colour using the stipple mask */ + [[NSColor colorWithUnsignedLong:s->face->foreground] set]; + CGRect imageSize = CGRectMake (0, 0, CGImageGetWidth (mask), + CGImageGetHeight (mask)); + CGContextDrawTiledImage (context, imageSize, mask); + [[NSGraphicsContext currentContext] restoreGraphicsState]; +#else + [[dpyinfo->bitmaps[s->face->stipple - 1].img stippleMask] set]; +#endif /* NS_IMPL_COCOA */ + } else [[NSColor colorWithUnsignedLong: s->face->background] set]; commit d6288eeb429e8e5774b3b248fd62bb4549779b67 Author: Vitaliy Chepelev Date: Tue Sep 24 04:25:13 2024 +0000 image-dired: Don't croak on file names with regexp characters * lisp/image/image-dired-dired.el (image-dired-mark-tagged-files): * lisp/image/image-dired-tags.el (image-dired-get-comment) (image-dired-write-comments, image-dired-list-tags) (image-dired-remove-tag, image-dired-write-tags): Quote file name for search-forward-regexp. (Bug#73445) Copyright-paperwork-exempt: yes (cherry picked from commit 7930fe2f44f50b6a7abf5fbe1218dcc15e85b28d) diff --git a/lisp/image/image-dired-dired.el b/lisp/image/image-dired-dired.el index 8b68a5c069b..c7994cd4096 100644 --- a/lisp/image/image-dired-dired.el +++ b/lisp/image/image-dired-dired.el @@ -383,7 +383,7 @@ matching tag will be marked in the Dired buffer." (file-name-directory curr-file))) (setq curr-file (file-name-nondirectory curr-file)) (goto-char (point-min)) - (when (search-forward-regexp (format "\\s %s[*@]?$" curr-file) nil t) + (when (search-forward-regexp (format "\\s %s[*@]?$" (regexp-quote curr-file)) nil t) (setq hits (+ hits 1)) (dired-mark 1)))) (message "%d files with matching tag marked" hits))) diff --git a/lisp/image/image-dired-tags.el b/lisp/image/image-dired-tags.el index 8be2bfe4218..eccab48e0fe 100644 --- a/lisp/image/image-dired-tags.el +++ b/lisp/image/image-dired-tags.el @@ -79,7 +79,7 @@ FILE-TAGS is an alist in the following form: (setq file (car elt) tag (cdr elt)) (goto-char (point-min)) - (if (search-forward-regexp (format "^%s.*$" file) nil t) + (if (search-forward-regexp (format "^%s.*$" (regexp-quote file)) nil t) (progn (setq end (point)) (beginning-of-line) @@ -103,7 +103,7 @@ FILES can be a name of a single file (a string) or a list of file names." (error "Files must be a string or a list of strings!"))) (dolist (file files) (goto-char (point-min)) - (when (search-forward-regexp (format "^%s;" file) nil t) + (when (search-forward-regexp (format "^%s;" (regexp-quote file)) nil t) (end-of-line) (setq end (point)) (beginning-of-line) @@ -125,7 +125,7 @@ Value is a list of all tags for FILE." (image-dired-sane-db-file) (image-dired--with-db-file (let (end (tags "")) - (when (search-forward-regexp (format "^%s" file) nil t) + (when (search-forward-regexp (format "^%s" (regexp-quote file)) nil t) (end-of-line) (setq end (point)) (beginning-of-line) @@ -179,7 +179,7 @@ FILE-COMMENTS is an alist on the following form: (setq file (car elt) comment (cdr elt)) (goto-char (point-min)) - (if (search-forward-regexp (format "^%s.*$" file) nil t) + (if (search-forward-regexp (format "^%s.*$" (regexp-quote file)) nil t) (progn (setq end (point)) (beginning-of-line) @@ -236,7 +236,7 @@ Optionally use old comment from FILE as initial value." (image-dired-sane-db-file) (image-dired--with-db-file (let (end comment-beg-pos comment-end-pos comment) - (when (search-forward-regexp (format "^%s" file) nil t) + (when (search-forward-regexp (format "^%s" (regexp-quote file)) nil t) (end-of-line) (setq end (point)) (beginning-of-line) commit fe7a8c92be6269f8fc7933eb6c190178839d0f8a Merge: d9f93e8fdcc 1b80bc67aad Author: Po Lu Date: Tue Mar 4 14:32:48 2025 +0800 Merge from savannah/emacs-30 1b80bc67aad ; * doc/emacs/android.texi (Android Software): Minor mark... dcfbf7d1863 ; * etc/PROBLEMS: Document the same problem here. b09bbf22afd Document requirements respecting XDG MIME databases on An... 365a91622e0 ; (completion-preview--try-table): Propagate extra proper... # Conflicts: # lisp/completion-preview.el commit d9f93e8fdcc00ab81b678c6f7d3f9b67cb14bd6d Merge: 9daab9be343 828e08a9961 Author: Po Lu Date: Tue Mar 4 14:32:33 2025 +0800 ; Merge from savannah/emacs-30 The following commit was skipped: 828e08a9961 Improve instructions for running with -fsanitize=address ... commit 9daab9be343f930c8db4c33881abc96e65c01bd7 Merge: 9415941a9c6 7dcf9b71e6f Author: Po Lu Date: Tue Mar 4 14:32:33 2025 +0800 Merge from savannah/emacs-30 7dcf9b71e6f ; Don't document package-x.el a5fd518d524 ; Document spurious warnings on macOS 15 625ed68aeaa Fix the use of xref-window-local-history together with Xr... 80917727676 completing-read-multiple: Fix support for ":" as separator 38cc36a3753 ; Improve docstring of cl-check-type commit 1b80bc67aadd01de00b7911ae32bf5d91b262a8a Author: Po Lu Date: Tue Mar 4 14:30:31 2025 +0800 ; * doc/emacs/android.texi (Android Software): Minor markup nits. diff --git a/doc/emacs/android.texi b/doc/emacs/android.texi index 560c348db49..c318373536a 100644 --- a/doc/emacs/android.texi +++ b/doc/emacs/android.texi @@ -1219,7 +1219,7 @@ temporary directory on a GNU/Linux or Unix system, before transferring the same to the recipient Android device. With the latest release of @code{shared-mime-info} installed, create a temporary directory in which to generate the MIME database, copy the default -@file{freedesktop.org.in} MIME catalog to a folder named +@file{freedesktop.org.in} MIME catalog to a directory named @file{packages}, and execute @code{update-mime-info} to generate the database: @@ -1233,7 +1233,7 @@ This may print a series of notices stating that the MIME database specified is not in the search path on your host system, which are of no consequence. Proceed by transferring the contents of the MIME database to the recipient system, e.g., to -@code{/sdcard/Download/my-mime-database.tar.gz}: +@file{/sdcard/Download/my-mime-database.tar.gz}: @example $ cd; mkdir -p .local/share commit dcfbf7d1863fdba0329dcefa73c6ec15eb8046cf Author: Po Lu Date: Tue Mar 4 14:29:35 2025 +0800 ; * etc/PROBLEMS: Document the same problem here. diff --git a/etc/PROBLEMS b/etc/PROBLEMS index 748d712c843..b76c7789e54 100644 --- a/etc/PROBLEMS +++ b/etc/PROBLEMS @@ -3849,6 +3849,16 @@ executing: $ adb shell appops set --uid org.gnu.emacs MANAGE_EXTERNAL_STORAGE allow +** Images embedded in SVG files are invisible. + +This is a product of librsvg's failing to locate a suitable MIME +database enabling it automatically to detect image file formats. The +procedure by which to obtain such a database is documented in the node +'(emacs)Android Software' in the Emacs manual; you may also download a +pre-compiled MIME database from this SourceForge repository: + + https://sourceforge.net/projects/android-ports-for-gnu-emacs/files/mime-database.tar.gz/download + * Build-time problems ** Configuration commit b09bbf22afda57cbf96870c68eb31264a4ced482 Author: Po Lu Date: Tue Mar 4 14:24:56 2025 +0800 Document requirements respecting XDG MIME databases on Android * doc/emacs/android.texi (Android Software): State that librsvg requires a MIME database to display embedded images, and how to acquire such a database. diff --git a/doc/emacs/android.texi b/doc/emacs/android.texi index 568fd8022d1..560c348db49 100644 --- a/doc/emacs/android.texi +++ b/doc/emacs/android.texi @@ -1203,3 +1203,45 @@ installation within Emacs's home directory. In addition to the projects mentioned above, statically linked binaries for most Linux kernel-based systems can also be run on Android. + +@cindex XDG MIME database, Android +@cindex displaying SVG images with embeds, Android + Emacs can be configured with support for viewing SVG image files by +means of the @code{librsvg} library. In SVG files, there may be +references to other images on the file-system, whose format +@code{librsvg} cannot detect by default, and which will be rendered as +blank squares unless an XDG-compliant @dfn{MIME database} is installed +into the directory @file{.local/share/mime} within your home directory. + + As the XDG @code{shared-mime-info} tools must be available to generate +such a database, it is recommended to produce this database in a +temporary directory on a GNU/Linux or Unix system, before transferring +the same to the recipient Android device. With the latest release of +@code{shared-mime-info} installed, create a temporary directory in which +to generate the MIME database, copy the default +@file{freedesktop.org.in} MIME catalog to a folder named +@file{packages}, and execute @code{update-mime-info} to generate the +database: + +@example +$ mkdir -p my-mime-database/packages +$ cp /usr/share/mime/packages/freedesktop.org.xml my-mime-database/packages +$ update-mime-info my-mime-database +@end example + +This may print a series of notices stating that the MIME database +specified is not in the search path on your host system, which are of no +consequence. Proceed by transferring the contents of the MIME database +to the recipient system, e.g., to +@code{/sdcard/Download/my-mime-database.tar.gz}: + +@example +$ cd; mkdir -p .local/share +$ tar xfz /sdcard/Download/my-mime-database.tar.gz +$ mv my-mime-database .local/share/mime +$ rm /sdcard/Download/my-mime-database.tar.gz +@end example + +If your Emacs session has already attempted to display an SVG image with +embeds, Emacs must be restarted before the new MIME database will enter +into effect. commit 9415941a9c65b72a3bc20ae0ec1765f3c0ed657d Author: Paul Eggert Date: Mon Mar 3 22:20:08 2025 -0800 Revert “Avoid some union buffered_input_event uses” Revert my commit 29a9fd4f4ba17822eca0f00c2037da3868bd874e and the following commit 1ec0889e7b786d79351cee3ed4964d82295f059f. This fixes a bug where ‘emacs -nw’ would sometimes freeze when Emacs is configured with ‘--with-pgtk --enable-link-time-optimization --disable-gc-mark-trace’ on GNU/Linux x86-64 (Bug#76729). As it is not yet clear whether this freeze is due to an Emacs bug that I introduced, or due to GCC bug 117423 , play it safe for now and revert to the previous state. diff --git a/src/androidterm.c b/src/androidterm.c index 7fd61ee6d1c..884d8f8d718 100644 --- a/src/androidterm.c +++ b/src/androidterm.c @@ -841,7 +841,7 @@ handle_one_android_event (struct android_display_info *dpyinfo, union android_event configureEvent; struct frame *f, *any, *mouse_frame; Mouse_HLInfo *hlinfo; - struct input_event inev; + union buffered_input_event inev; int modifiers, count, do_help; struct android_touch_point *touchpoint, **last; Lisp_Object window; @@ -865,7 +865,7 @@ handle_one_android_event (struct android_display_info *dpyinfo, if (any && any->wait_event_type == event->type) any->wait_event_type = 0; /* Indicates we got it. */ - EVENT_INIT (inev); + EVENT_INIT (inev.ie); switch (event->type) { @@ -936,8 +936,8 @@ handle_one_android_event (struct android_display_info *dpyinfo, if (!FRAME_TOOLTIP_P (f) && (old_left != f->left_pos || old_top != f->top_pos)) { - inev.kind = MOVE_FRAME_EVENT; - XSETFRAME (inev.frame_or_window, f); + inev.ie.kind = MOVE_FRAME_EVENT; + XSETFRAME (inev.ie.frame_or_window, f); } if (f && FRAME_OUTPUT_DATA (f)->need_cursor_updates) @@ -996,10 +996,10 @@ handle_one_android_event (struct android_display_info *dpyinfo, memset (&compose_status, 0, sizeof (compose_status)); /* Common for all keysym input events. */ - XSETFRAME (inev.frame_or_window, any); - inev.modifiers + XSETFRAME (inev.ie.frame_or_window, any); + inev.ie.modifiers = android_android_to_emacs_modifiers (dpyinfo, modifiers); - inev.timestamp = event->xkey.time; + inev.ie.timestamp = event->xkey.time; keysym = event->xkey.keycode; @@ -1033,8 +1033,8 @@ handle_one_android_event (struct android_display_info *dpyinfo, if (event->xkey.keycode == (uint32_t) -1) { - inev.kind = PREEDIT_TEXT_EVENT; - inev.arg = Qnil; + inev.ie.kind = PREEDIT_TEXT_EVENT; + inev.ie.arg = Qnil; /* If text was looked up, decode it and make it the preedit text. */ @@ -1042,7 +1042,7 @@ handle_one_android_event (struct android_display_info *dpyinfo, if (status_return == ANDROID_LOOKUP_CHARS && nchars) { copy_bufptr[nchars] = 0; - inev.arg = from_unicode_buffer (copy_bufptr); + inev.ie.arg = from_unicode_buffer (copy_bufptr); } goto done_keysym; @@ -1061,11 +1061,11 @@ handle_one_android_event (struct android_display_info *dpyinfo, /* Deal with characters. */ if (copy_bufptr[0] < 128) - inev.kind = ASCII_KEYSTROKE_EVENT; + inev.ie.kind = ASCII_KEYSTROKE_EVENT; else - inev.kind = MULTIBYTE_CHAR_KEYSTROKE_EVENT; + inev.ie.kind = MULTIBYTE_CHAR_KEYSTROKE_EVENT; - inev.code = copy_bufptr[0]; + inev.ie.code = copy_bufptr[0]; } else if (nchars < 2 && keysym) { @@ -1075,8 +1075,8 @@ handle_one_android_event (struct android_display_info *dpyinfo, /* Next, deal with special ``characters'' by giving the keycode to keyboard.c. */ - inev.kind = NON_ASCII_KEYSTROKE_EVENT; - inev.code = keysym; + inev.ie.kind = NON_ASCII_KEYSTROKE_EVENT; + inev.ie.code = keysym; } else { @@ -1084,25 +1084,25 @@ handle_one_android_event (struct android_display_info *dpyinfo, for (i = 0; i < nchars; ++i) { - inev.kind = (SINGLE_BYTE_CHAR_P (copy_bufptr[i]) - ? ASCII_KEYSTROKE_EVENT - : MULTIBYTE_CHAR_KEYSTROKE_EVENT); - inev.code = copy_bufptr[i]; + inev.ie.kind = (SINGLE_BYTE_CHAR_P (copy_bufptr[i]) + ? ASCII_KEYSTROKE_EVENT + : MULTIBYTE_CHAR_KEYSTROKE_EVENT); + inev.ie.code = copy_bufptr[i]; /* If the character is actually '\n', then change this to RET. */ if (copy_bufptr[i] == '\n') { - inev.kind = NON_ASCII_KEYSTROKE_EVENT; - inev.code = 66; + inev.ie.kind = NON_ASCII_KEYSTROKE_EVENT; + inev.ie.code = 66; } - kbd_buffer_store_event_hold (&inev, hold_quit); + kbd_buffer_store_buffered_event (&inev, hold_quit); } count += nchars; - inev.kind = NO_EVENT; /* Already stored above. */ + inev.ie.kind = NO_EVENT; /* Already stored above. */ } goto done_keysym; @@ -1122,7 +1122,7 @@ handle_one_android_event (struct android_display_info *dpyinfo, case ANDROID_FOCUS_IN: case ANDROID_FOCUS_OUT: - android_detect_focus_change (dpyinfo, any, event, &inev); + android_detect_focus_change (dpyinfo, any, event, &inev.ie); goto OTHER; case ANDROID_WINDOW_ACTION: @@ -1150,8 +1150,8 @@ handle_one_android_event (struct android_display_info *dpyinfo, if (!f) goto OTHER; - inev.kind = DELETE_WINDOW_EVENT; - XSETFRAME (inev.frame_or_window, f); + inev.ie.kind = DELETE_WINDOW_EVENT; + XSETFRAME (inev.ie.frame_or_window, f); } } @@ -1210,8 +1210,8 @@ handle_one_android_event (struct android_display_info *dpyinfo, && !EQ (window, last_mouse_window) && !EQ (window, selected_window)) { - inev.kind = SELECT_WINDOW_EVENT; - inev.frame_or_window = window; + inev.ie.kind = SELECT_WINDOW_EVENT; + inev.ie.frame_or_window = window; } /* Remember the last window where we saw the mouse. */ @@ -1392,10 +1392,10 @@ handle_one_android_event (struct android_display_info *dpyinfo, if (!(tab_bar_p && NILP (tab_bar_arg)) && !tool_bar_p) if (! popup_activated ()) { - android_construct_mouse_click (&inev, &event->xbutton, f); + android_construct_mouse_click (&inev.ie, &event->xbutton, f); if (!NILP (tab_bar_arg)) - inev.arg = tab_bar_arg; + inev.ie.arg = tab_bar_arg; } } @@ -1438,8 +1438,8 @@ handle_one_android_event (struct android_display_info *dpyinfo, /* Simply update the tool position and send an update. */ touchpoint->x = event->touch.x; touchpoint->y = event->touch.y; - android_update_tools (any, &inev); - inev.timestamp = event->touch.time; + android_update_tools (any, &inev.ie); + inev.ie.timestamp = event->touch.time; goto OTHER; } @@ -1512,12 +1512,12 @@ handle_one_android_event (struct android_display_info *dpyinfo, } /* Now generate the Emacs event. */ - inev.kind = TOUCHSCREEN_BEGIN_EVENT; - inev.timestamp = event->touch.time; - XSETFRAME (inev.frame_or_window, any); - XSETINT (inev.x, event->touch.x); - XSETINT (inev.y, event->touch.y); - XSETINT (inev.arg, event->touch.pointer_id); + inev.ie.kind = TOUCHSCREEN_BEGIN_EVENT; + inev.ie.timestamp = event->touch.time; + XSETFRAME (inev.ie.frame_or_window, any); + XSETINT (inev.ie.x, event->touch.x); + XSETINT (inev.ie.y, event->touch.y); + XSETINT (inev.ie.arg, event->touch.pointer_id); goto OTHER; @@ -1540,8 +1540,8 @@ handle_one_android_event (struct android_display_info *dpyinfo, touchpoint->x = event->touch.x; touchpoint->y = event->touch.y; - android_update_tools (any, &inev); - inev.timestamp = event->touch.time; + android_update_tools (any, &inev.ie); + inev.ie.timestamp = event->touch.time; goto OTHER; @@ -1583,18 +1583,18 @@ handle_one_android_event (struct android_display_info *dpyinfo, grabbed by the tool bar). */ xfree (touchpoint); - inev.kind = TOUCHSCREEN_END_EVENT; - inev.timestamp = event->touch.time; + inev.ie.kind = TOUCHSCREEN_END_EVENT; + inev.ie.timestamp = event->touch.time; /* Report whether the sequence has been canceled. */ if (event->touch.flags & ANDROID_TOUCH_SEQUENCE_CANCELED) - inev.modifiers = 1; + inev.ie.modifiers = 1; - XSETFRAME (inev.frame_or_window, any); - XSETINT (inev.x, event->touch.x); - XSETINT (inev.y, event->touch.y); - XSETINT (inev.arg, event->touch.pointer_id); + XSETFRAME (inev.ie.frame_or_window, any); + XSETINT (inev.ie.x, event->touch.x); + XSETINT (inev.ie.y, event->touch.y); + XSETINT (inev.ie.arg, event->touch.pointer_id); /* Break out of the loop. */ goto OTHER; @@ -1643,24 +1643,24 @@ handle_one_android_event (struct android_display_info *dpyinfo, } /* Determine what kind of event to send. */ - inev.kind = ((fabs (wheel_event_y) + inev.ie.kind = ((fabs (wheel_event_y) >= fabs (wheel_event_x)) ? WHEEL_EVENT : HORIZ_WHEEL_EVENT); - inev.timestamp = event->wheel.time; + inev.ie.timestamp = event->wheel.time; /* Set the event coordinates. */ - XSETINT (inev.x, event->wheel.x); - XSETINT (inev.y, event->wheel.y); + XSETINT (inev.ie.x, event->wheel.x); + XSETINT (inev.ie.y, event->wheel.y); /* Set the frame. */ - XSETFRAME (inev.frame_or_window, any); + XSETFRAME (inev.ie.frame_or_window, any); /* Figure out the scroll direction. */ - inev.modifiers = (signbit ((fabs (wheel_event_x) - >= fabs (wheel_event_y)) - ? wheel_event_x - : wheel_event_y) - ? down_modifier : up_modifier); + inev.ie.modifiers = (signbit ((fabs (wheel_event_x) + >= fabs (wheel_event_y)) + ? wheel_event_x + : wheel_event_y) + ? down_modifier : up_modifier); /* Figure out how much to scale the deltas by. */ window = window_from_coordinates (any, event->wheel.x, @@ -1678,14 +1678,16 @@ handle_one_android_event (struct android_display_info *dpyinfo, scroll_unit = pow (scroll_height, 2.0 / 3.0); /* Add the keyboard modifiers. */ - inev.modifiers + inev.ie.modifiers |= android_android_to_emacs_modifiers (dpyinfo, event->wheel.state); /* Finally include the scroll deltas. */ - inev.arg = list3 (Qnil, - make_float (wheel_event_x * scroll_unit), - make_float (wheel_event_y * scroll_unit)); + inev.ie.arg = list3 (Qnil, + make_float (wheel_event_x + * scroll_unit), + make_float (wheel_event_y + * scroll_unit)); wheel_event_x = 0.0; wheel_event_y = 0.0; @@ -1705,8 +1707,8 @@ handle_one_android_event (struct android_display_info *dpyinfo, SET_FRAME_VISIBLE (any, false); SET_FRAME_ICONIFIED (any, true); - inev.kind = ICONIFY_EVENT; - XSETFRAME (inev.frame_or_window, any); + inev.ie.kind = ICONIFY_EVENT; + XSETFRAME (inev.ie.frame_or_window, any); goto OTHER; case ANDROID_DEICONIFIED: @@ -1720,8 +1722,8 @@ handle_one_android_event (struct android_display_info *dpyinfo, SET_FRAME_VISIBLE (any, true); SET_FRAME_ICONIFIED (any, false); - inev.kind = DEICONIFY_EVENT; - XSETFRAME (inev.frame_or_window, any); + inev.ie.kind = DEICONIFY_EVENT; + XSETFRAME (inev.ie.frame_or_window, any); goto OTHER; /* Context menu handling. */ @@ -1769,12 +1771,12 @@ handle_one_android_event (struct android_display_info *dpyinfo, goto OTHER; /* Generate a drag and drop event to convey its position. */ - inev.kind = DRAG_N_DROP_EVENT; - XSETFRAME (inev.frame_or_window, any); - inev.timestamp = ANDROID_CURRENT_TIME; - XSETINT (inev.x, event->dnd.x); - XSETINT (inev.y, event->dnd.y); - inev.arg = Fcons (inev.x, inev.y); + inev.ie.kind = DRAG_N_DROP_EVENT; + XSETFRAME (inev.ie.frame_or_window, any); + inev.ie.timestamp = ANDROID_CURRENT_TIME; + XSETINT (inev.ie.x, event->dnd.x); + XSETINT (inev.ie.y, event->dnd.y); + inev.ie.arg = Fcons (inev.ie.x, inev.ie.y); goto OTHER; case ANDROID_DND_URI_EVENT: @@ -1790,15 +1792,15 @@ handle_one_android_event (struct android_display_info *dpyinfo, content or file URI or a string to be inserted. Generate an event with this information. */ - inev.kind = DRAG_N_DROP_EVENT; - XSETFRAME (inev.frame_or_window, any); - inev.timestamp = ANDROID_CURRENT_TIME; - XSETINT (inev.x, event->dnd.x); - XSETINT (inev.y, event->dnd.y); - inev.arg = Fcons ((event->type == ANDROID_DND_TEXT_EVENT - ? Qtext : Quri), - android_decode_utf16 (event->dnd.uri_or_string, - event->dnd.length)); + inev.ie.kind = DRAG_N_DROP_EVENT; + XSETFRAME (inev.ie.frame_or_window, any); + inev.ie.timestamp = ANDROID_CURRENT_TIME; + XSETINT (inev.ie.x, event->dnd.x); + XSETINT (inev.ie.y, event->dnd.y); + inev.ie.arg = Fcons ((event->type == ANDROID_DND_TEXT_EVENT + ? Qtext : Quri), + android_decode_utf16 (event->dnd.uri_or_string, + event->dnd.length)); free (event->dnd.uri_or_string); goto OTHER; @@ -1806,14 +1808,15 @@ handle_one_android_event (struct android_display_info *dpyinfo, case ANDROID_NOTIFICATION_ACTION: if (event->notification.type == ANDROID_NOTIFICATION_DELETED) - android_notification_deleted (&event->notification, &inev); + android_notification_deleted (&event->notification, &inev.ie); else { Lisp_Object action; action = android_decode_utf16 (event->notification.action, event->notification.length); - android_notification_action (&event->notification, &inev, action); + android_notification_action (&event->notification, &inev.ie, + action); } /* Free dynamically allocated data. */ @@ -1826,9 +1829,9 @@ handle_one_android_event (struct android_display_info *dpyinfo, } OTHER: - if (inev.kind != NO_EVENT) + if (inev.ie.kind != NO_EVENT) { - kbd_buffer_store_event_hold (&inev, hold_quit); + kbd_buffer_store_buffered_event (&inev, hold_quit); count++; } diff --git a/src/gtkutil.c b/src/gtkutil.c index 164531aaeb3..0770874eb40 100644 --- a/src/gtkutil.c +++ b/src/gtkutil.c @@ -6382,7 +6382,7 @@ xg_widget_key_press_event_cb (GtkWidget *widget, GdkEvent *event, { Lisp_Object tail, tem; struct frame *f = NULL; - struct input_event inev; + union buffered_input_event inev; guint keysym = event->key.keyval; unsigned int xstate; gunichar uc; @@ -6419,15 +6419,15 @@ xg_widget_key_press_event_cb (GtkWidget *widget, GdkEvent *event, && !FRAME_DISPLAY_INFO (f)->prefer_native_input) return true; - EVENT_INIT (inev); - XSETFRAME (inev.frame_or_window, f); + EVENT_INIT (inev.ie); + XSETFRAME (inev.ie.frame_or_window, f); xstate = xg_virtual_mods_to_x (FRAME_DISPLAY_INFO (f), event->key.state); - inev.modifiers + inev.ie.modifiers |= x_x_to_emacs_modifiers (FRAME_DISPLAY_INFO (f), xstate); - inev.timestamp = event->key.time; + inev.ie.timestamp = event->key.time; #ifdef HAVE_XINPUT2 if (event->key.time == pending_keystroke_time) @@ -6436,7 +6436,7 @@ xg_widget_key_press_event_cb (GtkWidget *widget, GdkEvent *event, FRAME_DISPLAY_INFO (f)->pending_keystroke_source); if (source) - inev.device = source->name; + inev.ie.device = source->name; } #endif @@ -6455,8 +6455,8 @@ xg_widget_key_press_event_cb (GtkWidget *widget, GdkEvent *event, if (keysym >= 32 && keysym < 128) /* Avoid explicitly decoding each ASCII character. */ { - inev.kind = ASCII_KEYSTROKE_EVENT; - inev.code = keysym; + inev.ie.kind = ASCII_KEYSTROKE_EVENT; + inev.ie.code = keysym; goto done; } @@ -6464,10 +6464,10 @@ xg_widget_key_press_event_cb (GtkWidget *widget, GdkEvent *event, if (keysym >= 0x01000000 && keysym <= 0x0110FFFF) { if (keysym < 0x01000080) - inev.kind = ASCII_KEYSTROKE_EVENT; + inev.ie.kind = ASCII_KEYSTROKE_EVENT; else - inev.kind = MULTIBYTE_CHAR_KEYSTROKE_EVENT; - inev.code = keysym & 0xFFFFFF; + inev.ie.kind = MULTIBYTE_CHAR_KEYSTROKE_EVENT; + inev.ie.code = keysym & 0xFFFFFF; goto done; } @@ -6523,8 +6523,8 @@ xg_widget_key_press_event_cb (GtkWidget *widget, GdkEvent *event, /* Any "vendor-specific" key is ok. */ || (keysym & (1 << 28)))) { - inev.kind = NON_ASCII_KEYSTROKE_EVENT; - inev.code = keysym; + inev.ie.kind = NON_ASCII_KEYSTROKE_EVENT; + inev.ie.code = keysym; goto done; } @@ -6532,22 +6532,22 @@ xg_widget_key_press_event_cb (GtkWidget *widget, GdkEvent *event, if (uc) { - inev.kind = (SINGLE_BYTE_CHAR_P (uc) - ? ASCII_KEYSTROKE_EVENT - : MULTIBYTE_CHAR_KEYSTROKE_EVENT); - inev.code = uc; + inev.ie.kind = (SINGLE_BYTE_CHAR_P (uc) + ? ASCII_KEYSTROKE_EVENT + : MULTIBYTE_CHAR_KEYSTROKE_EVENT); + inev.ie.code = uc; } else { - inev.kind = NON_ASCII_KEYSTROKE_EVENT; - inev.code = keysym; + inev.ie.kind = NON_ASCII_KEYSTROKE_EVENT; + inev.ie.code = keysym; } done: - if (inev.kind != NO_EVENT) + if (inev.ie.kind != NO_EVENT) { xg_pending_quit_event.kind = NO_EVENT; - kbd_buffer_store_event_hold (&inev, &xg_pending_quit_event); + kbd_buffer_store_buffered_event (&inev, &xg_pending_quit_event); } XNoOp (FRAME_X_DISPLAY (f)); diff --git a/src/keyboard.c b/src/keyboard.c index e1a7be355f2..b22814d702d 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -408,7 +408,7 @@ static void timer_resume_idle (void); static void deliver_user_signal (int); static char *find_user_signal_name (int); static void store_user_signal_events (void); -static bool is_ignored_event_kind (enum event_kind); +static bool is_ignored_event (union buffered_input_event *); /* Advance or retreat a buffered input event pointer. */ @@ -3629,7 +3629,7 @@ readable_events (int flags) && (event->kind == FOCUS_IN_EVENT || event->kind == FOCUS_OUT_EVENT)) || (input_pending_p_filter_events - && is_ignored_event_kind (event->kind)))) + && is_ignored_event (event)))) #ifdef USE_TOOLKIT_SCROLL_BARS && !((flags & READABLE_EVENTS_IGNORE_SQUEEZABLES) && (event->kind == SCROLL_BAR_CLICK_EVENT @@ -3714,31 +3714,6 @@ kbd_buffer_store_event (register struct input_event *event) kbd_buffer_store_event_hold (event, 0); } -static void -beware_long_paste (void) -{ -#ifdef subprocesses - if (! (kbd_buffer_nr_stored () <= KBD_BUFFER_SIZE / 2 - && kbd_on_hold_p ())) - { - /* Don't read keyboard input until we have processed kbd_buffer. - This happens when pasting text longer than KBD_BUFFER_SIZE/2. */ - hold_keyboard_input (); - unrequest_sigio (); - stop_polling (); - } -#endif -} - -/* If we're inside while-no-input, and this event qualifies - as input, set quit-flag to cause an interrupt. */ -static void -maybe_quit_while_no_input (enum event_kind kind) -{ - if (!NILP (Vthrow_on_input) && !is_ignored_event_kind (kind)) - Vquit_flag = Vthrow_on_input; -} - /* Store EVENT obtained at interrupt level into kbd_buffer, fifo. If HOLD_QUIT is 0, just stuff EVENT into the fifo. @@ -3750,8 +3725,8 @@ maybe_quit_while_no_input (enum event_kind kind) subsequent input events have been parsed (and discarded). */ void -kbd_buffer_store_event_hold (struct input_event *event, - struct input_event *hold_quit) +kbd_buffer_store_buffered_event (union buffered_input_event *event, + struct input_event *hold_quit) { if (event->kind == NO_EVENT) emacs_abort (); @@ -3761,23 +3736,23 @@ kbd_buffer_store_event_hold (struct input_event *event, if (event->kind == ASCII_KEYSTROKE_EVENT) { - int c = event->code & 0377; + int c = event->ie.code & 0377; - if (event->modifiers & ctrl_modifier) + if (event->ie.modifiers & ctrl_modifier) c = make_ctrl_char (c); - c |= (event->modifiers + c |= (event->ie.modifiers & (meta_modifier | alt_modifier | hyper_modifier | super_modifier)); if (c == quit_char) { - KBOARD *kb = FRAME_KBOARD (XFRAME (event->frame_or_window)); + KBOARD *kb = FRAME_KBOARD (XFRAME (event->ie.frame_or_window)); if (single_kboard && kb != current_kboard) { kset_kbd_queue - (kb, list2 (make_lispy_switch_frame (event->frame_or_window), + (kb, list2 (make_lispy_switch_frame (event->ie.frame_or_window), make_fixnum (c))); kb->kbd_queue_has_data = true; @@ -3796,7 +3771,7 @@ kbd_buffer_store_event_hold (struct input_event *event, if (hold_quit) { - *hold_quit = *event; + *hold_quit = event->ie; return; } @@ -3807,9 +3782,9 @@ kbd_buffer_store_event_hold (struct input_event *event, { Lisp_Object focus; - focus = FRAME_FOCUS_FRAME (XFRAME (event->frame_or_window)); + focus = FRAME_FOCUS_FRAME (XFRAME (event->ie.frame_or_window)); if (NILP (focus)) - focus = event->frame_or_window; + focus = event->ie.frame_or_window; internal_last_event_frame = focus; Vlast_event_frame = focus; } @@ -3832,46 +3807,27 @@ kbd_buffer_store_event_hold (struct input_event *event, union buffered_input_event *next_slot = next_kbd_event (kbd_store_ptr); if (kbd_fetch_ptr != next_slot) { - kbd_store_ptr->ie = *event; - kbd_store_ptr = next_slot; - beware_long_paste (); - } - - maybe_quit_while_no_input (event->kind); -} - -#if defined HAVE_X11 || defined HAVE_PGTK -/* Store EVENT obtained at interrupt level into kbd_buffer, fifo. - This is like kbd_buffer_store_event_hold, but for struct - selection_input_event instead of struct input_event. - - If HOLD_QUIT && HOLD_QUIT->kind != NO_EVENT, discard EVENT. - - This is used to postpone the processing of the quit event until all - subsequent input events have been parsed (and discarded). */ - -void -kbd_buffer_store_selection_event_hold (struct selection_input_event *event, - struct input_event *hold_quit) -{ - if (hold_quit && hold_quit->kind != NO_EVENT) - return; - - /* Don't let the very last slot in the buffer become full, - since that would make the two pointers equal, - and that is indistinguishable from an empty buffer. - Discard the event if it would fill the last slot. */ - union buffered_input_event *next_slot = next_kbd_event (kbd_store_ptr); - if (kbd_fetch_ptr != next_slot) - { - kbd_store_ptr->sie = *event; + *kbd_store_ptr = *event; kbd_store_ptr = next_slot; - beware_long_paste (); +#ifdef subprocesses + if (kbd_buffer_nr_stored () > KBD_BUFFER_SIZE / 2 + && ! kbd_on_hold_p ()) + { + /* Don't read keyboard input until we have processed kbd_buffer. + This happens when pasting text longer than KBD_BUFFER_SIZE/2. */ + hold_keyboard_input (); + unrequest_sigio (); + stop_polling (); + } +#endif /* subprocesses */ } - maybe_quit_while_no_input (event->kind); + /* If we're inside while-no-input, and this event qualifies + as input, set quit-flag to cause an interrupt. */ + if (!NILP (Vthrow_on_input) + && !is_ignored_event (event)) + Vquit_flag = Vthrow_on_input; } -#endif /* HAVE_X11 || HAVE_PGTK */ /* Limit help event positions to this range, to avoid overflow problems. */ #define INPUT_EVENT_POS_MAX \ @@ -12921,11 +12877,11 @@ init_while_no_input_ignore_events (void) } static bool -is_ignored_event_kind (enum event_kind kind) +is_ignored_event (union buffered_input_event *event) { Lisp_Object ignore_event; - switch (kind) + switch (event->kind) { case FOCUS_IN_EVENT: ignore_event = Qfocus_in; break; case FOCUS_OUT_EVENT: ignore_event = Qfocus_out; break; diff --git a/src/keyboard.h b/src/keyboard.h index 1dd56d92a8f..5e04b54eb74 100644 --- a/src/keyboard.h +++ b/src/keyboard.h @@ -499,12 +499,17 @@ extern void clear_waiting_for_input (void); extern void swallow_events (bool); extern bool lucid_event_type_list_p (Lisp_Object); extern void kbd_buffer_store_event (struct input_event *); -extern void kbd_buffer_store_event_hold (struct input_event *, - struct input_event *); -#if defined HAVE_X11 || defined HAVE_PGTK -extern void kbd_buffer_store_selection_event_hold (struct selection_input_event *, - struct input_event *); -#endif +extern void kbd_buffer_store_buffered_event (union buffered_input_event *, + struct input_event *); +INLINE void +kbd_buffer_store_event_hold (struct input_event *event, + struct input_event *hold_quit) +{ + static_assert (alignof (struct input_event) == alignof (union buffered_input_event) + && sizeof (struct input_event) == sizeof (union buffered_input_event)); + kbd_buffer_store_buffered_event ((union buffered_input_event *) event, + hold_quit); +} extern void poll_for_input_1 (void); extern void show_help_echo (Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object); diff --git a/src/pgtkterm.c b/src/pgtkterm.c index 0ef6084d2f4..00377ff73a0 100644 --- a/src/pgtkterm.c +++ b/src/pgtkterm.c @@ -286,8 +286,12 @@ flip_cr_context (struct frame *f) static void -evq_grow_if_needed (struct event_queue_t *evq) +evq_enqueue (union buffered_input_event *ev) { + struct event_queue_t *evq = &event_q; + struct frame *frame; + struct pgtk_display_info *dpyinfo; + if (evq->cap == 0) { evq->cap = 4; @@ -299,44 +303,28 @@ evq_grow_if_needed (struct event_queue_t *evq) evq->cap += evq->cap / 2; evq->q = xrealloc (evq->q, sizeof *evq->q * evq->cap); } -} - -static void -evq_enqueue (struct input_event const *ev) -{ - struct event_queue_t *evq = &event_q; - struct frame *frame; - struct pgtk_display_info *dpyinfo; - - evq_grow_if_needed (evq); - evq->q[evq->nr++].ie = *ev; - frame = NULL; + evq->q[evq->nr++] = *ev; - if (WINDOWP (ev->frame_or_window)) - frame = WINDOW_XFRAME (XWINDOW (ev->frame_or_window)); - - if (FRAMEP (ev->frame_or_window)) - frame = XFRAME (ev->frame_or_window); - - if (frame) + if (ev->ie.kind != SELECTION_REQUEST_EVENT + && ev->ie.kind != SELECTION_CLEAR_EVENT) { - dpyinfo = FRAME_DISPLAY_INFO (frame); + frame = NULL; - if (dpyinfo->last_user_time < ev->timestamp) - dpyinfo->last_user_time = ev->timestamp; - } + if (WINDOWP (ev->ie.frame_or_window)) + frame = WINDOW_XFRAME (XWINDOW (ev->ie.frame_or_window)); - raise (SIGIO); -} + if (FRAMEP (ev->ie.frame_or_window)) + frame = XFRAME (ev->ie.frame_or_window); -static void -evq_selection_enqueue (struct selection_input_event const *ev) -{ - struct event_queue_t *evq = &event_q; + if (frame) + { + dpyinfo = FRAME_DISPLAY_INFO (frame); - evq_grow_if_needed (evq); - evq->q[evq->nr++].sie = *ev; + if (dpyinfo->last_user_time < ev->ie.timestamp) + dpyinfo->last_user_time = ev->ie.timestamp; + } + } raise (SIGIO); } @@ -349,27 +337,17 @@ evq_flush (struct input_event *hold_quit) while (evq->nr > 0) { - /* Because kbd_buffer_store_event_hold and - kbd_buffer_store_selection_event_hold may do longjmp, - we need to shift event queue before passing a pointer - to a copy of the event, so that events in + /* kbd_buffer_store_buffered_event may do longjmp, so + we need to shift event queue first and pass the event + to kbd_buffer_store_buffered_event so that events in queue are not processed twice. Bug#52941 */ + union buffered_input_event ev = evq->q[0]; + int i; + for (i = 1; i < evq->nr; i++) + evq->q[i - 1] = evq->q[i]; evq->nr--; - if (evq->q[0].kind == SELECTION_REQUEST_EVENT - || evq->q[0].kind == SELECTION_CLEAR_EVENT) - { - struct selection_input_event sinev = evq->q[0].sie; - memmove (&evq->q[0], &evq->q[1], evq->nr * sizeof evq->q[0]); - kbd_buffer_store_selection_event_hold (&sinev, hold_quit); - } - else - { - struct input_event inev = evq->q[0].ie; - memmove (&evq->q[0], &evq->q[1], evq->nr * sizeof evq->q[0]); - kbd_buffer_store_event_hold (&inev, hold_quit); - } - + kbd_buffer_store_buffered_event (&ev, hold_quit); n++; } @@ -3950,21 +3928,21 @@ static void pgtk_send_scroll_bar_event (Lisp_Object window, enum scroll_bar_part part, int portion, int whole, bool horizontal) { - struct input_event inev; + union buffered_input_event inev; - EVENT_INIT (inev); + EVENT_INIT (inev.ie); - inev.kind = (horizontal - ? HORIZONTAL_SCROLL_BAR_CLICK_EVENT - : SCROLL_BAR_CLICK_EVENT); - inev.frame_or_window = window; - inev.arg = Qnil; - inev.timestamp = 0; - inev.code = 0; - inev.part = part; - inev.x = make_fixnum (portion); - inev.y = make_fixnum (whole); - inev.modifiers = 0; + inev.ie.kind = (horizontal + ? HORIZONTAL_SCROLL_BAR_CLICK_EVENT + : SCROLL_BAR_CLICK_EVENT); + inev.ie.frame_or_window = window; + inev.ie.arg = Qnil; + inev.ie.timestamp = 0; + inev.ie.code = 0; + inev.ie.part = part; + inev.ie.x = make_fixnum (portion); + inev.ie.y = make_fixnum (whole); + inev.ie.modifiers = 0; evq_enqueue (&inev); } @@ -4964,6 +4942,7 @@ static gboolean pgtk_handle_event (GtkWidget *widget, GdkEvent *event, gpointer *data) { struct frame *f; + union buffered_input_event inev; GtkWidget *frame_widget; gint x, y; @@ -4980,18 +4959,18 @@ pgtk_handle_event (GtkWidget *widget, GdkEvent *event, gpointer *data) &x, &y); if (f) { - struct input_event inev; - inev.kind = PINCH_EVENT; - XSETFRAME (inev.frame_or_window, f); - XSETINT (inev.x, x); - XSETINT (inev.y, y); - inev.arg = list4 (make_float (event->touchpad_pinch.dx), - make_float (event->touchpad_pinch.dy), - make_float (event->touchpad_pinch.scale), - make_float (event->touchpad_pinch.angle_delta)); - inev.modifiers = pgtk_gtk_to_emacs_modifiers (FRAME_DISPLAY_INFO (f), + + inev.ie.kind = PINCH_EVENT; + XSETFRAME (inev.ie.frame_or_window, f); + XSETINT (inev.ie.x, x); + XSETINT (inev.ie.y, y); + inev.ie.arg = list4 (make_float (event->touchpad_pinch.dx), + make_float (event->touchpad_pinch.dy), + make_float (event->touchpad_pinch.scale), + make_float (event->touchpad_pinch.angle_delta)); + inev.ie.modifiers = pgtk_gtk_to_emacs_modifiers (FRAME_DISPLAY_INFO (f), event->touchpad_pinch.state); - inev.device + inev.ie.device = pgtk_get_device_for_event (FRAME_DISPLAY_INFO (f), event); evq_enqueue (&inev); } @@ -5209,17 +5188,17 @@ pgtk_enqueue_string (struct frame *f, gchar *str) return; for (; *ustr != 0; ustr++) { - struct input_event inev; + union buffered_input_event inev; Lisp_Object c = make_fixnum (*ustr); - EVENT_INIT (inev); - inev.kind = (SINGLE_BYTE_CHAR_P (XFIXNAT (c)) - ? ASCII_KEYSTROKE_EVENT - : MULTIBYTE_CHAR_KEYSTROKE_EVENT); - inev.arg = Qnil; - inev.code = XFIXNAT (c); - XSETFRAME (inev.frame_or_window, f); - inev.modifiers = 0; - inev.timestamp = 0; + EVENT_INIT (inev.ie); + inev.ie.kind = (SINGLE_BYTE_CHAR_P (XFIXNAT (c)) + ? ASCII_KEYSTROKE_EVENT + : MULTIBYTE_CHAR_KEYSTROKE_EVENT); + inev.ie.arg = Qnil; + inev.ie.code = XFIXNAT (c); + XSETFRAME (inev.ie.frame_or_window, f); + inev.ie.modifiers = 0; + inev.ie.timestamp = 0; evq_enqueue (&inev); } @@ -5229,28 +5208,28 @@ pgtk_enqueue_string (struct frame *f, gchar *str) void pgtk_enqueue_preedit (struct frame *f, Lisp_Object preedit) { - struct input_event inev; - EVENT_INIT (inev); - inev.kind = PREEDIT_TEXT_EVENT; - inev.arg = preedit; - inev.code = 0; - XSETFRAME (inev.frame_or_window, f); - inev.modifiers = 0; - inev.timestamp = 0; + union buffered_input_event inev; + EVENT_INIT (inev.ie); + inev.ie.kind = PREEDIT_TEXT_EVENT; + inev.ie.arg = preedit; + inev.ie.code = 0; + XSETFRAME (inev.ie.frame_or_window, f); + inev.ie.modifiers = 0; + inev.ie.timestamp = 0; evq_enqueue (&inev); } static gboolean key_press_event (GtkWidget *widget, GdkEvent *event, gpointer *user_data) { - struct input_event inev; + union buffered_input_event inev; ptrdiff_t nbytes; Mouse_HLInfo *hlinfo; struct frame *f; struct pgtk_display_info *dpyinfo; f = pgtk_any_window_to_frame (gtk_widget_get_window (widget)); - EVENT_INIT (inev); + EVENT_INIT (inev.ie); hlinfo = MOUSE_HL_INFO (f); nbytes = 0; @@ -5321,20 +5300,20 @@ key_press_event (GtkWidget *widget, GdkEvent *event, gpointer *user_data) orig_keysym = keysym; /* Common for all keysym input events. */ - XSETFRAME (inev.frame_or_window, f); - inev.modifiers + XSETFRAME (inev.ie.frame_or_window, f); + inev.ie.modifiers = pgtk_gtk_to_emacs_modifiers (FRAME_DISPLAY_INFO (f), modifiers); - inev.timestamp = event->key.time; + inev.ie.timestamp = event->key.time; /* First deal with keysyms which have defined translations to characters. */ if (keysym >= 32 && keysym < 128) /* Avoid explicitly decoding each ASCII character. */ { - inev.kind = ASCII_KEYSTROKE_EVENT; - inev.code = keysym; + inev.ie.kind = ASCII_KEYSTROKE_EVENT; + inev.ie.code = keysym; - inev.device + inev.ie.device = pgtk_get_device_for_event (FRAME_DISPLAY_INFO (f), event); goto done; } @@ -5343,12 +5322,12 @@ key_press_event (GtkWidget *widget, GdkEvent *event, gpointer *user_data) if (keysym >= 0x01000000 && keysym <= 0x0110FFFF) { if (keysym < 0x01000080) - inev.kind = ASCII_KEYSTROKE_EVENT; + inev.ie.kind = ASCII_KEYSTROKE_EVENT; else - inev.kind = MULTIBYTE_CHAR_KEYSTROKE_EVENT; - inev.code = keysym & 0xFFFFFF; + inev.ie.kind = MULTIBYTE_CHAR_KEYSTROKE_EVENT; + inev.ie.code = keysym & 0xFFFFFF; - inev.device + inev.ie.device = pgtk_get_device_for_event (FRAME_DISPLAY_INFO (f), event); goto done; } @@ -5358,12 +5337,12 @@ key_press_event (GtkWidget *widget, GdkEvent *event, gpointer *user_data) && (c = Fgethash (make_fixnum (keysym), Vpgtk_keysym_table, Qnil), FIXNATP (c))) { - inev.kind = (SINGLE_BYTE_CHAR_P (XFIXNAT (c)) - ? ASCII_KEYSTROKE_EVENT - : MULTIBYTE_CHAR_KEYSTROKE_EVENT); - inev.code = XFIXNAT (c); + inev.ie.kind = (SINGLE_BYTE_CHAR_P (XFIXNAT (c)) + ? ASCII_KEYSTROKE_EVENT + : MULTIBYTE_CHAR_KEYSTROKE_EVENT); + inev.ie.code = XFIXNAT (c); - inev.device + inev.ie.device = pgtk_get_device_for_event (FRAME_DISPLAY_INFO (f), event); goto done; } @@ -5442,18 +5421,18 @@ key_press_event (GtkWidget *widget, GdkEvent *event, gpointer *user_data) { /* make_lispy_event will convert this to a symbolic key. */ - inev.kind = NON_ASCII_KEYSTROKE_EVENT; - inev.code = keysym; + inev.ie.kind = NON_ASCII_KEYSTROKE_EVENT; + inev.ie.code = keysym; - inev.device + inev.ie.device = pgtk_get_device_for_event (FRAME_DISPLAY_INFO (f), event); goto done; } { - inev.kind = MULTIBYTE_CHAR_KEYSTROKE_EVENT; - inev.arg = make_unibyte_string ((char *) copy_bufptr, nbytes); - inev.device + inev.ie.kind = MULTIBYTE_CHAR_KEYSTROKE_EVENT; + inev.ie.arg = make_unibyte_string ((char *) copy_bufptr, nbytes); + inev.ie.device = pgtk_get_device_for_event (FRAME_DISPLAY_INFO (f), event); if (keysym == GDK_KEY_VoidSymbol) @@ -5462,9 +5441,9 @@ key_press_event (GtkWidget *widget, GdkEvent *event, gpointer *user_data) } done: - if (inev.kind != NO_EVENT) + if (inev.ie.kind != NO_EVENT) { - XSETFRAME (inev.frame_or_window, f); + XSETFRAME (inev.ie.frame_or_window, f); evq_enqueue (&inev); } @@ -5543,11 +5522,11 @@ map_event (GtkWidget *widget, gpointer *user_data) { struct frame *f = pgtk_any_window_to_frame (event->any.window); - struct input_event inev; + union buffered_input_event inev; - EVENT_INIT (inev); - inev.kind = NO_EVENT; - inev.arg = Qnil; + EVENT_INIT (inev.ie); + inev.ie.kind = NO_EVENT; + inev.ie.arg = Qnil; if (f) { @@ -5574,12 +5553,12 @@ map_event (GtkWidget *widget, if (iconified) { - inev.kind = DEICONIFY_EVENT; - XSETFRAME (inev.frame_or_window, f); + inev.ie.kind = DEICONIFY_EVENT; + XSETFRAME (inev.ie.frame_or_window, f); } } - if (inev.kind != NO_EVENT) + if (inev.ie.kind != NO_EVENT) evq_enqueue (&inev); return FALSE; } @@ -5591,13 +5570,13 @@ window_state_event (GtkWidget *widget, { struct frame *f = pgtk_any_window_to_frame (event->window_state.window); GdkWindowState new_state; - struct input_event inev; + union buffered_input_event inev; new_state = event->window_state.new_window_state; - EVENT_INIT (inev); - inev.kind = NO_EVENT; - inev.arg = Qnil; + EVENT_INIT (inev.ie); + inev.ie.kind = NO_EVENT; + inev.ie.arg = Qnil; if (new_state & GDK_WINDOW_STATE_FULLSCREEN) store_frame_param (f, Qfullscreen, Qfullboth); @@ -5643,8 +5622,8 @@ window_state_event (GtkWidget *widget, else { FRAME_X_OUTPUT (f)->has_been_visible = true; - inev.kind = DEICONIFY_EVENT; - XSETFRAME (inev.frame_or_window, f); + inev.ie.kind = DEICONIFY_EVENT; + XSETFRAME (inev.ie.frame_or_window, f); SET_FRAME_ICONIFIED (f, false); SET_FRAME_VISIBLE (f, true); } @@ -5654,7 +5633,7 @@ window_state_event (GtkWidget *widget, else store_frame_param (f, Qsticky, Qnil); - if (inev.kind != NO_EVENT) + if (inev.ie.kind != NO_EVENT) evq_enqueue (&inev); return FALSE; } @@ -5664,19 +5643,19 @@ delete_event (GtkWidget *widget, GdkEvent *event, gpointer *user_data) { struct frame *f = pgtk_any_window_to_frame (event->any.window); - struct input_event inev; + union buffered_input_event inev; - EVENT_INIT (inev); - inev.kind = NO_EVENT; - inev.arg = Qnil; + EVENT_INIT (inev.ie); + inev.ie.kind = NO_EVENT; + inev.ie.arg = Qnil; if (f) { - inev.kind = DELETE_WINDOW_EVENT; - XSETFRAME (inev.frame_or_window, f); + inev.ie.kind = DELETE_WINDOW_EVENT; + XSETFRAME (inev.ie.frame_or_window, f); } - if (inev.kind != NO_EVENT) + if (inev.ie.kind != NO_EVENT) evq_enqueue (&inev); return TRUE; } @@ -5693,7 +5672,7 @@ delete_event (GtkWidget *widget, static void pgtk_focus_changed (gboolean is_enter, int state, struct pgtk_display_info *dpyinfo, struct frame *frame, - struct input_event *bufp) + union buffered_input_event *bufp) { if (is_enter) { @@ -5705,13 +5684,13 @@ pgtk_focus_changed (gboolean is_enter, int state, /* Don't stop displaying the initial startup message for a switch-frame event we don't need. */ /* When run as a daemon, Vterminal_frame is always NIL. */ - bufp->arg = (((NILP (Vterminal_frame) - || !FRAME_PGTK_P (XFRAME (Vterminal_frame)) - || EQ (Fdaemonp (), Qt)) - && CONSP (Vframe_list) - && !NILP (XCDR (Vframe_list))) ? Qt : Qnil); - bufp->kind = FOCUS_IN_EVENT; - XSETFRAME (bufp->frame_or_window, frame); + bufp->ie.arg = (((NILP (Vterminal_frame) + || !FRAME_PGTK_P (XFRAME (Vterminal_frame)) + || EQ (Fdaemonp (), Qt)) + && CONSP (Vframe_list) + && !NILP (XCDR (Vframe_list))) ? Qt : Qnil); + bufp->ie.kind = FOCUS_IN_EVENT; + XSETFRAME (bufp->ie.frame_or_window, frame); } frame->output_data.pgtk->focus_state |= state; @@ -5726,8 +5705,8 @@ pgtk_focus_changed (gboolean is_enter, int state, dpyinfo->x_focus_event_frame = 0; pgtk_new_focus_frame (dpyinfo, NULL); - bufp->kind = FOCUS_OUT_EVENT; - XSETFRAME (bufp->frame_or_window, frame); + bufp->ie.kind = FOCUS_OUT_EVENT; + XSETFRAME (bufp->ie.frame_or_window, frame); } if (frame->pointer_invisible) @@ -5739,7 +5718,7 @@ static gboolean enter_notify_event (GtkWidget *widget, GdkEvent *event, gpointer *user_data) { - struct input_event inev; + union buffered_input_event inev; struct frame *frame = pgtk_any_window_to_frame (gtk_widget_get_window (widget)); @@ -5751,14 +5730,14 @@ enter_notify_event (GtkWidget *widget, GdkEvent *event, int focus_state = focus_frame ? focus_frame->output_data.pgtk->focus_state : 0; - EVENT_INIT (inev); - inev.kind = NO_EVENT; - inev.arg = Qnil; + EVENT_INIT (inev.ie); + inev.ie.kind = NO_EVENT; + inev.ie.arg = Qnil; if (event->crossing.detail != GDK_NOTIFY_INFERIOR && event->crossing.focus && !(focus_state & FOCUS_EXPLICIT)) pgtk_focus_changed (TRUE, FOCUS_IMPLICIT, dpyinfo, frame, &inev); - if (inev.kind != NO_EVENT) + if (inev.ie.kind != NO_EVENT) evq_enqueue (&inev); return TRUE; } @@ -5767,7 +5746,7 @@ static gboolean leave_notify_event (GtkWidget *widget, GdkEvent *event, gpointer *user_data) { - struct input_event inev; + union buffered_input_event inev; struct frame *frame = pgtk_any_window_to_frame (gtk_widget_get_window (widget)); @@ -5788,9 +5767,9 @@ leave_notify_event (GtkWidget *widget, GdkEvent *event, hlinfo->mouse_face_mouse_frame = 0; } - EVENT_INIT (inev); - inev.kind = NO_EVENT; - inev.arg = Qnil; + EVENT_INIT (inev.ie); + inev.ie.kind = NO_EVENT; + inev.ie.arg = Qnil; if (event->crossing.detail != GDK_NOTIFY_INFERIOR && event->crossing.focus && !(focus_state & FOCUS_EXPLICIT)) @@ -5807,7 +5786,7 @@ leave_notify_event (GtkWidget *widget, GdkEvent *event, } } - if (inev.kind != NO_EVENT) + if (inev.ie.kind != NO_EVENT) evq_enqueue (&inev); return TRUE; } @@ -5815,20 +5794,20 @@ leave_notify_event (GtkWidget *widget, GdkEvent *event, static gboolean focus_in_event (GtkWidget *widget, GdkEvent *event, gpointer *user_data) { - struct input_event inev; + union buffered_input_event inev; struct frame *frame = pgtk_any_window_to_frame (gtk_widget_get_window (widget)); if (frame == NULL) return TRUE; - EVENT_INIT (inev); - inev.kind = NO_EVENT; - inev.arg = Qnil; + EVENT_INIT (inev.ie); + inev.ie.kind = NO_EVENT; + inev.ie.arg = Qnil; pgtk_focus_changed (TRUE, FOCUS_EXPLICIT, FRAME_DISPLAY_INFO (frame), frame, &inev); - if (inev.kind != NO_EVENT) + if (inev.ie.kind != NO_EVENT) evq_enqueue (&inev); pgtk_im_focus_in (frame); @@ -5839,20 +5818,20 @@ focus_in_event (GtkWidget *widget, GdkEvent *event, gpointer *user_data) static gboolean focus_out_event (GtkWidget *widget, GdkEvent *event, gpointer *user_data) { - struct input_event inev; + union buffered_input_event inev; struct frame *frame = pgtk_any_window_to_frame (gtk_widget_get_window (widget)); if (frame == NULL) return TRUE; - EVENT_INIT (inev); - inev.kind = NO_EVENT; - inev.arg = Qnil; + EVENT_INIT (inev.ie); + inev.ie.kind = NO_EVENT; + inev.ie.arg = Qnil; pgtk_focus_changed (FALSE, FOCUS_EXPLICIT, FRAME_DISPLAY_INFO (frame), frame, &inev); - if (inev.kind != NO_EVENT) + if (inev.ie.kind != NO_EVENT) evq_enqueue (&inev); pgtk_im_focus_out (frame); @@ -5922,7 +5901,7 @@ static gboolean motion_notify_event (GtkWidget *widget, GdkEvent *event, gpointer *user_data) { - struct input_event inev; + union buffered_input_event inev; struct frame *f, *frame; struct pgtk_display_info *dpyinfo; Mouse_HLInfo *hlinfo; @@ -5938,9 +5917,9 @@ motion_notify_event (GtkWidget *widget, GdkEvent *event, && (gdk_device_get_source (device) == GDK_SOURCE_TOUCHSCREEN))) return FALSE; - EVENT_INIT (inev); - inev.kind = NO_EVENT; - inev.arg = Qnil; + EVENT_INIT (inev.ie); + inev.ie.kind = NO_EVENT; + inev.ie.arg = Qnil; previous_help_echo_string = help_echo_string; help_echo_string = Qnil; @@ -5991,8 +5970,8 @@ motion_notify_event (GtkWidget *widget, GdkEvent *event, && !EQ (window, last_mouse_window) && !EQ (window, selected_window)) { - inev.kind = SELECT_WINDOW_EVENT; - inev.frame_or_window = window; + inev.ie.kind = SELECT_WINDOW_EVENT; + inev.ie.frame_or_window = window; } /* Remember the last window where we saw the mouse. */ @@ -6013,7 +5992,7 @@ motion_notify_event (GtkWidget *widget, GdkEvent *event, if (!NILP (help_echo_string) || !NILP (previous_help_echo_string)) do_help = 1; - if (inev.kind != NO_EVENT) + if (inev.ie.kind != NO_EVENT) evq_enqueue (&inev); if (do_help > 0) @@ -6066,7 +6045,7 @@ static gboolean button_event (GtkWidget *widget, GdkEvent *event, gpointer *user_data) { - struct input_event inev; + union buffered_input_event inev; struct frame *f, *frame; struct pgtk_display_info *dpyinfo; @@ -6087,9 +6066,9 @@ button_event (GtkWidget *widget, GdkEvent *event, && (gdk_device_get_source (device) == GDK_SOURCE_TOUCHSCREEN))) return FALSE; - EVENT_INIT (inev); - inev.kind = NO_EVENT; - inev.arg = Qnil; + EVENT_INIT (inev.ie); + inev.ie.kind = NO_EVENT; + inev.ie.arg = Qnil; /* ignore double click and triple click. */ if (event->type != GDK_BUTTON_PRESS && event->type != GDK_BUTTON_RELEASE) @@ -6158,16 +6137,16 @@ button_event (GtkWidget *widget, GdkEvent *event, && event->button.time > ignore_next_mouse_click_timeout) { ignore_next_mouse_click_timeout = 0; - construct_mouse_click (&inev, &event->button, f); + construct_mouse_click (&inev.ie, &event->button, f); } if (event->type == GDK_BUTTON_RELEASE) ignore_next_mouse_click_timeout = 0; } else - construct_mouse_click (&inev, &event->button, f); + construct_mouse_click (&inev.ie, &event->button, f); if (!NILP (tab_bar_arg)) - inev.arg = tab_bar_arg; + inev.ie.arg = tab_bar_arg; } } @@ -6189,7 +6168,7 @@ button_event (GtkWidget *widget, GdkEvent *event, if (f != 0) f->mouse_moved = false; - if (inev.kind != NO_EVENT) + if (inev.ie.kind != NO_EVENT) evq_enqueue (&inev); return TRUE; } @@ -6197,15 +6176,15 @@ button_event (GtkWidget *widget, GdkEvent *event, static gboolean scroll_event (GtkWidget *widget, GdkEvent *event, gpointer *user_data) { - struct input_event inev; + union buffered_input_event inev; struct frame *f, *frame; struct pgtk_display_info *dpyinfo; GdkScrollDirection dir; double delta_x, delta_y; - EVENT_INIT (inev); - inev.kind = NO_EVENT; - inev.arg = Qnil; + EVENT_INIT (inev.ie); + inev.ie.kind = NO_EVENT; + inev.ie.arg = Qnil; frame = pgtk_any_window_to_frame (gtk_widget_get_window (widget)); dpyinfo = FRAME_DISPLAY_INFO (frame); @@ -6215,19 +6194,19 @@ scroll_event (GtkWidget *widget, GdkEvent *event, gpointer *user_data) else f = pgtk_any_window_to_frame (gtk_widget_get_window (widget)); - inev.kind = NO_EVENT; - inev.timestamp = event->scroll.time; - inev.modifiers + inev.ie.kind = NO_EVENT; + inev.ie.timestamp = event->scroll.time; + inev.ie.modifiers = pgtk_gtk_to_emacs_modifiers (FRAME_DISPLAY_INFO (f), event->scroll.state); - XSETINT (inev.x, event->scroll.x); - XSETINT (inev.y, event->scroll.y); - XSETFRAME (inev.frame_or_window, f); - inev.arg = Qnil; + XSETINT (inev.ie.x, event->scroll.x); + XSETINT (inev.ie.y, event->scroll.y); + XSETFRAME (inev.ie.frame_or_window, f); + inev.ie.arg = Qnil; if (gdk_event_is_scroll_stop_event (event)) { - inev.kind = TOUCH_END_EVENT; - inev.device + inev.ie.kind = TOUCH_END_EVENT; + inev.ie.device = pgtk_get_device_for_event (FRAME_DISPLAY_INFO (f), event); evq_enqueue (&inev); return TRUE; @@ -6238,20 +6217,20 @@ scroll_event (GtkWidget *widget, GdkEvent *event, gpointer *user_data) switch (dir) { case GDK_SCROLL_UP: - inev.kind = WHEEL_EVENT; - inev.modifiers |= up_modifier; + inev.ie.kind = WHEEL_EVENT; + inev.ie.modifiers |= up_modifier; break; case GDK_SCROLL_DOWN: - inev.kind = WHEEL_EVENT; - inev.modifiers |= down_modifier; + inev.ie.kind = WHEEL_EVENT; + inev.ie.modifiers |= down_modifier; break; case GDK_SCROLL_LEFT: - inev.kind = HORIZ_WHEEL_EVENT; - inev.modifiers |= up_modifier; + inev.ie.kind = HORIZ_WHEEL_EVENT; + inev.ie.modifiers |= up_modifier; break; case GDK_SCROLL_RIGHT: - inev.kind = HORIZ_WHEEL_EVENT; - inev.modifiers |= down_modifier; + inev.ie.kind = HORIZ_WHEEL_EVENT; + inev.ie.modifiers |= down_modifier; break; case GDK_SCROLL_SMOOTH: /* shut up warning */ break; @@ -6261,14 +6240,14 @@ scroll_event (GtkWidget *widget, GdkEvent *event, gpointer *user_data) { if (!mwheel_coalesce_scroll_events) { - inev.kind = ((fabs (delta_x) > fabs (delta_y)) - ? HORIZ_WHEEL_EVENT - : WHEEL_EVENT); - inev.modifiers |= (inev.kind == HORIZ_WHEEL_EVENT - ? (delta_x >= 0 ? up_modifier : down_modifier) - : (delta_y >= 0 ? down_modifier : up_modifier)); - inev.arg = list3 (Qnil, make_float (-delta_x * 100), - make_float (-delta_y * 100)); + inev.ie.kind = ((fabs (delta_x) > fabs (delta_y)) + ? HORIZ_WHEEL_EVENT + : WHEEL_EVENT); + inev.ie.modifiers |= (inev.ie.kind == HORIZ_WHEEL_EVENT + ? (delta_x >= 0 ? up_modifier : down_modifier) + : (delta_y >= 0 ? down_modifier : up_modifier)); + inev.ie.arg = list3 (Qnil, make_float (-delta_x * 100), + make_float (-delta_y * 100)); } else { @@ -6277,21 +6256,21 @@ scroll_event (GtkWidget *widget, GdkEvent *event, gpointer *user_data) if (dpyinfo->scroll.acc_y >= dpyinfo->scroll.y_per_line) { int nlines = dpyinfo->scroll.acc_y / dpyinfo->scroll.y_per_line; - inev.kind = WHEEL_EVENT; - inev.modifiers |= down_modifier; - inev.arg = list3 (make_fixnum (nlines), - make_float (-dpyinfo->scroll.acc_x * 100), - make_float (-dpyinfo->scroll.acc_y * 100)); + inev.ie.kind = WHEEL_EVENT; + inev.ie.modifiers |= down_modifier; + inev.ie.arg = list3 (make_fixnum (nlines), + make_float (-dpyinfo->scroll.acc_x * 100), + make_float (-dpyinfo->scroll.acc_y * 100)); dpyinfo->scroll.acc_y -= dpyinfo->scroll.y_per_line * nlines; } else if (dpyinfo->scroll.acc_y <= -dpyinfo->scroll.y_per_line) { int nlines = -dpyinfo->scroll.acc_y / dpyinfo->scroll.y_per_line; - inev.kind = WHEEL_EVENT; - inev.modifiers |= up_modifier; - inev.arg = list3 (make_fixnum (nlines), - make_float (-dpyinfo->scroll.acc_x * 100), - make_float (-dpyinfo->scroll.acc_y * 100)); + inev.ie.kind = WHEEL_EVENT; + inev.ie.modifiers |= up_modifier; + inev.ie.arg = list3 (make_fixnum (nlines), + make_float (-dpyinfo->scroll.acc_x * 100), + make_float (-dpyinfo->scroll.acc_y * 100)); dpyinfo->scroll.acc_y -= -dpyinfo->scroll.y_per_line * nlines; } @@ -6299,31 +6278,31 @@ scroll_event (GtkWidget *widget, GdkEvent *event, gpointer *user_data) || !mwheel_coalesce_scroll_events) { int nchars = dpyinfo->scroll.acc_x / dpyinfo->scroll.x_per_char; - inev.kind = HORIZ_WHEEL_EVENT; - inev.modifiers |= up_modifier; - inev.arg = list3 (make_fixnum (nchars), - make_float (-dpyinfo->scroll.acc_x * 100), - make_float (-dpyinfo->scroll.acc_y * 100)); + inev.ie.kind = HORIZ_WHEEL_EVENT; + inev.ie.modifiers |= up_modifier; + inev.ie.arg = list3 (make_fixnum (nchars), + make_float (-dpyinfo->scroll.acc_x * 100), + make_float (-dpyinfo->scroll.acc_y * 100)); dpyinfo->scroll.acc_x -= dpyinfo->scroll.x_per_char * nchars; } else if (dpyinfo->scroll.acc_x <= -dpyinfo->scroll.x_per_char) { int nchars = -dpyinfo->scroll.acc_x / dpyinfo->scroll.x_per_char; - inev.kind = HORIZ_WHEEL_EVENT; - inev.modifiers |= down_modifier; - inev.arg = list3 (make_fixnum (nchars), - make_float (-dpyinfo->scroll.acc_x * 100), - make_float (-dpyinfo->scroll.acc_y * 100)); + inev.ie.kind = HORIZ_WHEEL_EVENT; + inev.ie.modifiers |= down_modifier; + inev.ie.arg = list3 (make_fixnum (nchars), + make_float (-dpyinfo->scroll.acc_x * 100), + make_float (-dpyinfo->scroll.acc_y * 100)); dpyinfo->scroll.acc_x -= -dpyinfo->scroll.x_per_char * nchars; } } } - if (inev.kind != NO_EVENT) + if (inev.ie.kind != NO_EVENT) { - inev.device + inev.ie.device = pgtk_get_device_for_event (FRAME_DISPLAY_INFO (f), event); evq_enqueue (&inev); } @@ -6418,7 +6397,7 @@ drag_leave (GtkWidget *widget, GdkDragContext *context, guint time, gpointer user_data) { struct frame *f; - struct input_event inev; + union buffered_input_event inev; f = pgtk_any_window_to_frame (gtk_widget_get_window (widget)); @@ -6432,16 +6411,16 @@ drag_leave (GtkWidget *widget, GdkDragContext *context, g_object_unref); } - EVENT_INIT (inev); + EVENT_INIT (inev.ie); - inev.kind = DRAG_N_DROP_EVENT; - inev.modifiers = 0; - inev.arg = Qnil; - inev.timestamp = time; + inev.ie.kind = DRAG_N_DROP_EVENT; + inev.ie.modifiers = 0; + inev.ie.arg = Qnil; + inev.ie.timestamp = time; - XSETINT (inev.x, 0); - XSETINT (inev.y, 0); - XSETFRAME (inev.frame_or_window, f); + XSETINT (inev.ie.x, 0); + XSETINT (inev.ie.y, 0); + XSETFRAME (inev.ie.frame_or_window, f); evq_enqueue (&inev); } @@ -6452,7 +6431,7 @@ drag_motion (GtkWidget *widget, GdkDragContext *context, { struct frame *f; - struct input_event inev; + union buffered_input_event inev; GdkAtom name; GdkDragAction suggestion; @@ -6478,18 +6457,18 @@ drag_motion (GtkWidget *widget, GdkDragContext *context, name = gdk_drag_get_selection (context); suggestion = gdk_drag_context_get_suggested_action (context); - EVENT_INIT (inev); + EVENT_INIT (inev.ie); - inev.kind = DRAG_N_DROP_EVENT; - inev.modifiers = 0; - inev.arg = list4 (Qlambda, intern (gdk_atom_name (name)), - make_uint (time), - drag_action_to_symbol (suggestion)); - inev.timestamp = time; + inev.ie.kind = DRAG_N_DROP_EVENT; + inev.ie.modifiers = 0; + inev.ie.arg = list4 (Qlambda, intern (gdk_atom_name (name)), + make_uint (time), + drag_action_to_symbol (suggestion)); + inev.ie.timestamp = time; - XSETINT (inev.x, x); - XSETINT (inev.y, y); - XSETFRAME (inev.frame_or_window, f); + XSETINT (inev.ie.x, x); + XSETINT (inev.ie.y, y); + XSETFRAME (inev.ie.frame_or_window, f); evq_enqueue (&inev); @@ -6501,7 +6480,7 @@ drag_drop (GtkWidget *widget, GdkDragContext *context, int x, int y, guint time, gpointer user_data) { struct frame *f; - struct input_event inev; + union buffered_input_event inev; GdkAtom name; GdkDragAction selected_action; @@ -6527,18 +6506,18 @@ drag_drop (GtkWidget *widget, GdkDragContext *context, name = gdk_drag_get_selection (context); selected_action = gdk_drag_context_get_selected_action (context); - EVENT_INIT (inev); + EVENT_INIT (inev.ie); - inev.kind = DRAG_N_DROP_EVENT; - inev.modifiers = 0; - inev.arg = list4 (Qquote, intern (gdk_atom_name (name)), - make_uint (time), - drag_action_to_symbol (selected_action)); - inev.timestamp = time; + inev.ie.kind = DRAG_N_DROP_EVENT; + inev.ie.modifiers = 0; + inev.ie.arg = list4 (Qquote, intern (gdk_atom_name (name)), + make_uint (time), + drag_action_to_symbol (selected_action)); + inev.ie.timestamp = time; - XSETINT (inev.x, x); - XSETINT (inev.y, y); - XSETFRAME (inev.frame_or_window, f); + XSETINT (inev.ie.x, x); + XSETINT (inev.ie.y, y); + XSETFRAME (inev.ie.frame_or_window, f); evq_enqueue (&inev); @@ -6666,12 +6645,12 @@ touch_event_cb (GtkWidget *self, GdkEvent *event, gpointer user_data) struct pgtk_display_info *dpyinfo; struct frame *f; EMACS_INT local_detail; - struct input_event inev; + union buffered_input_event inev; struct pgtk_touch_point *touchpoint; Lisp_Object arg = Qnil; int state; - EVENT_INIT (inev); + EVENT_INIT (inev.ie); f = pgtk_any_window_to_frame (gtk_widget_get_window (self)); eassert (f); @@ -6690,12 +6669,12 @@ touch_event_cb (GtkWidget *self, GdkEvent *event, gpointer user_data) event->touch.x, event->touch.y, f); /* Generate the input event. */ - inev.kind = TOUCHSCREEN_BEGIN_EVENT; - inev.timestamp = event->touch.time; - XSETFRAME (inev.frame_or_window, f); - XSETINT (inev.x, lrint (event->touch.x)); - XSETINT (inev.y, lrint (event->touch.y)); - XSETINT (inev.arg, local_detail); + inev.ie.kind = TOUCHSCREEN_BEGIN_EVENT; + inev.ie.timestamp = event->touch.time; + XSETFRAME (inev.ie.frame_or_window, f); + XSETINT (inev.ie.x, lrint (event->touch.x)); + XSETINT (inev.ie.y, lrint (event->touch.y)); + XSETINT (inev.ie.arg, local_detail); break; case GDK_TOUCH_UPDATE: @@ -6712,9 +6691,9 @@ touch_event_cb (GtkWidget *self, GdkEvent *event, gpointer user_data) /* Construct the input event. */ touchpoint->x = lrint (event->touch.x); touchpoint->y = lrint (event->touch.y); - inev.kind = TOUCHSCREEN_UPDATE_EVENT; - inev.timestamp = event->touch.time; - XSETFRAME (inev.frame_or_window, f); + inev.ie.kind = TOUCHSCREEN_UPDATE_EVENT; + inev.ie.timestamp = event->touch.time; + XSETFRAME (inev.ie.frame_or_window, f); for (touchpoint = dpyinfo->touchpoints; touchpoint; touchpoint = touchpoint->next) @@ -6725,7 +6704,7 @@ touch_event_cb (GtkWidget *self, GdkEvent *event, gpointer user_data) arg); } - inev.arg = arg; + inev.ie.arg = arg; break; case GDK_TOUCH_END: @@ -6738,14 +6717,14 @@ touch_event_cb (GtkWidget *self, GdkEvent *event, gpointer user_data) if (state) { /* ... generate a suitable event. */ - inev.kind = TOUCHSCREEN_END_EVENT; - inev.timestamp = event->touch.time; - inev.modifiers = (event->type != GDK_TOUCH_END); - - XSETFRAME (inev.frame_or_window, f); - XSETINT (inev.x, lrint (event->touch.x)); - XSETINT (inev.y, lrint (event->touch.y)); - XSETINT (inev.arg, local_detail); + inev.ie.kind = TOUCHSCREEN_END_EVENT; + inev.ie.timestamp = event->touch.time; + inev.ie.modifiers = (event->type != GDK_TOUCH_END); + + XSETFRAME (inev.ie.frame_or_window, f); + XSETINT (inev.ie.x, lrint (event->touch.x)); + XSETINT (inev.ie.y, lrint (event->touch.y)); + XSETINT (inev.ie.arg, local_detail); } break; @@ -6756,9 +6735,9 @@ touch_event_cb (GtkWidget *self, GdkEvent *event, gpointer user_data) /* If the above produced a workable event, report the name of the device that gave rise to it. */ - if (inev.kind != NO_EVENT) + if (inev.ie.kind != NO_EVENT) { - inev.device = pgtk_get_device_for_event (dpyinfo, event); + inev.ie.device = pgtk_get_device_for_event (dpyinfo, event); evq_enqueue (&inev); /* Next, save this event for future menu activations, unless it is @@ -6771,7 +6750,7 @@ touch_event_cb (GtkWidget *self, GdkEvent *event, gpointer user_data) } } - return inev.kind != NO_EVENT; + return inev.ie.kind != NO_EVENT; } @@ -6782,12 +6761,12 @@ static void pgtk_monitors_changed_cb (GdkScreen *screen, gpointer user_data) { struct terminal *terminal; - struct input_event inev; + union buffered_input_event inev; - EVENT_INIT (inev); + EVENT_INIT (inev.ie); terminal = user_data; - inev.kind = MONITORS_CHANGED_EVENT; - XSETTERMINAL (inev.arg, terminal); + inev.ie.kind = MONITORS_CHANGED_EVENT; + XSETTERMINAL (inev.ie.arg, terminal); evq_enqueue (&inev); } @@ -6949,6 +6928,7 @@ pgtk_selection_event (GtkWidget *widget, GdkEvent *event, gpointer user_data) { struct frame *f; + union buffered_input_event inev; if (event->type == GDK_PROPERTY_NOTIFY) pgtk_handle_property_notify (&event->property); @@ -6959,15 +6939,15 @@ pgtk_selection_event (GtkWidget *widget, GdkEvent *event, if (f) { - struct selection_input_event sinev = {0}; + EVENT_INIT (inev.ie); - sinev.kind = (event->type == GDK_SELECTION_CLEAR + inev.sie.kind = (event->type == GDK_SELECTION_CLEAR ? SELECTION_CLEAR_EVENT : SELECTION_REQUEST_EVENT); - SELECTION_EVENT_DPYINFO (&sinev) = FRAME_DISPLAY_INFO (f); - SELECTION_EVENT_SELECTION (&sinev) = event->selection.selection; - SELECTION_EVENT_TIME (&sinev) = event->selection.time; + SELECTION_EVENT_DPYINFO (&inev.sie) = FRAME_DISPLAY_INFO (f); + SELECTION_EVENT_SELECTION (&inev.sie) = event->selection.selection; + SELECTION_EVENT_TIME (&inev.sie) = event->selection.time; if (event->type == GDK_SELECTION_REQUEST) { @@ -6977,12 +6957,12 @@ pgtk_selection_event (GtkWidget *widget, GdkEvent *event, It would make sense to wait for the transfer to complete. But I don't know if GDK actually does that. */ - SELECTION_EVENT_REQUESTOR (&sinev) = event->selection.requestor; - SELECTION_EVENT_TARGET (&sinev) = event->selection.target; - SELECTION_EVENT_PROPERTY (&sinev) = event->selection.property; + SELECTION_EVENT_REQUESTOR (&inev.sie) = event->selection.requestor; + SELECTION_EVENT_TARGET (&inev.sie) = event->selection.target; + SELECTION_EVENT_PROPERTY (&inev.sie) = event->selection.property; } - evq_selection_enqueue (&sinev); + evq_enqueue (&inev); return TRUE; } } diff --git a/src/xterm.c b/src/xterm.c index aa2116a4b9f..2ccf267bbd3 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -18881,7 +18881,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, #endif int *finish, struct input_event *hold_quit) { - struct input_event inev; + union buffered_input_event inev; int count = 0; int do_help = 0; #ifdef HAVE_XINPUT2 @@ -18924,9 +18924,9 @@ handle_one_xevent (struct x_display_info *dpyinfo, *finish = X_EVENT_NORMAL; - EVENT_INIT (inev); - inev.kind = NO_EVENT; - inev.arg = Qnil; + EVENT_INIT (inev.ie); + inev.ie.kind = NO_EVENT; + inev.ie.arg = Qnil; #ifdef HAVE_XINPUT2 gen_help_device = NULL; #endif @@ -19257,9 +19257,9 @@ handle_one_xevent (struct x_display_info *dpyinfo, if (!f) goto OTHER; /* May be a dialog that is to be removed */ - inev.kind = DELETE_WINDOW_EVENT; - inev.timestamp = event->xclient.data.l[1]; - XSETFRAME (inev.frame_or_window, f); + inev.ie.kind = DELETE_WINDOW_EVENT; + inev.ie.timestamp = event->xclient.data.l[1]; + XSETFRAME (inev.ie.frame_or_window, f); goto done; } @@ -19413,7 +19413,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, /* Convert the scroll bar event to an input event using the first window entered into the scroll bar event queue. */ - x_scroll_bar_to_input_event (dpyinfo, event, &inev); + x_scroll_bar_to_input_event (dpyinfo, event, &inev.ie); *finish = X_EVENT_GOTO_OUT; goto done; @@ -19423,7 +19423,8 @@ handle_one_xevent (struct x_display_info *dpyinfo, /* Convert the horizontal scroll bar event to an input event using the first window entered into the scroll bar event queue. */ - x_horizontal_scroll_bar_to_input_event (dpyinfo, event, &inev); + x_horizontal_scroll_bar_to_input_event (dpyinfo, event, + &inev.ie); *finish = X_EVENT_GOTO_OUT; goto done; @@ -19435,7 +19436,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, { enum xembed_message msg = event->xclient.data.l[1]; if (msg == XEMBED_FOCUS_IN || msg == XEMBED_FOCUS_OUT) - x_detect_focus_change (dpyinfo, any, event, &inev); + x_detect_focus_change (dpyinfo, any, event, &inev.ie); *finish = X_EVENT_GOTO_OUT; goto done; @@ -19474,7 +19475,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, rc = x_coords_from_dnd_message (dpyinfo, (XEvent *) event, &dx, &dy); - if (x_handle_dnd_message (f, &event->xclient, dpyinfo, &inev, + if (x_handle_dnd_message (f, &event->xclient, dpyinfo, &inev.ie, rc, dx, dy)) *finish = X_EVENT_DROP; } @@ -19510,18 +19511,15 @@ handle_one_xevent (struct x_display_info *dpyinfo, || dpyinfo->motif_drag_atom_time <= eventp->time)) dpyinfo->motif_drag_atom = None; - struct selection_input_event sinev = {0}; - sinev.kind = SELECTION_CLEAR_EVENT; - SELECTION_EVENT_DPYINFO (&sinev) = dpyinfo; - SELECTION_EVENT_SELECTION (&sinev) = eventp->selection; - SELECTION_EVENT_TIME (&sinev) = eventp->time; + inev.sie.kind = SELECTION_CLEAR_EVENT; + SELECTION_EVENT_DPYINFO (&inev.sie) = dpyinfo; + SELECTION_EVENT_SELECTION (&inev.sie) = eventp->selection; + SELECTION_EVENT_TIME (&inev.sie) = eventp->time; if (x_use_pending_selection_requests) - x_push_selection_request (&sinev); - else { - kbd_buffer_store_selection_event_hold (&sinev, hold_quit); - count++; + x_push_selection_request (&inev.sie); + EVENT_INIT (inev.ie); } } break; @@ -19537,25 +19535,22 @@ handle_one_xevent (struct x_display_info *dpyinfo, { const XSelectionRequestEvent *eventp = &event->xselectionrequest; - struct selection_input_event sinev; - sinev.kind = SELECTION_REQUEST_EVENT; - SELECTION_EVENT_DPYINFO (&sinev) = dpyinfo; - SELECTION_EVENT_REQUESTOR (&sinev) = eventp->requestor; - SELECTION_EVENT_SELECTION (&sinev) = eventp->selection; - SELECTION_EVENT_TARGET (&sinev) = eventp->target; - SELECTION_EVENT_PROPERTY (&sinev) = eventp->property; - SELECTION_EVENT_TIME (&sinev) = eventp->time; + inev.sie.kind = SELECTION_REQUEST_EVENT; + SELECTION_EVENT_DPYINFO (&inev.sie) = dpyinfo; + SELECTION_EVENT_REQUESTOR (&inev.sie) = eventp->requestor; + SELECTION_EVENT_SELECTION (&inev.sie) = eventp->selection; + SELECTION_EVENT_TARGET (&inev.sie) = eventp->target; + SELECTION_EVENT_PROPERTY (&inev.sie) = eventp->property; + SELECTION_EVENT_TIME (&inev.sie) = eventp->time; /* If drag-and-drop or another modal dialog/menu is in progress, handle SelectionRequest events immediately, by pushing it onto the selection queue. */ if (x_use_pending_selection_requests) - x_push_selection_request (&sinev); - else { - kbd_buffer_store_selection_event_hold (&sinev, hold_quit); - count++; + x_push_selection_request (&inev.sie); + EVENT_INIT (inev.ie); } if (x_dnd_waiting_for_finish @@ -19654,7 +19649,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, SET_FRAME_ICONIFIED (f, false); f->output_data.x->has_been_visible = true; - inev.kind = DEICONIFY_EVENT; + inev.ie.kind = DEICONIFY_EVENT; #if defined USE_GTK && defined HAVE_GTK3 /* If GTK3 wants to impose some old size here (Bug#24526), tell it that the current size is what we want. */ @@ -19665,7 +19660,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, f->was_invisible = false; } #endif - XSETFRAME (inev.frame_or_window, f); + XSETFRAME (inev.ie.frame_or_window, f); } else if (!not_hidden && !FRAME_ICONIFIED_P (f)) { @@ -19675,8 +19670,8 @@ handle_one_xevent (struct x_display_info *dpyinfo, SET_FRAME_VISIBLE (f, 0); SET_FRAME_ICONIFIED (f, true); - inev.kind = ICONIFY_EVENT; - XSETFRAME (inev.frame_or_window, f); + inev.ie.kind = ICONIFY_EVENT; + XSETFRAME (inev.ie.frame_or_window, f); } } @@ -19691,7 +19686,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, set. Handling UnmapNotify also checks for _NET_WM_STATE_HIDDEN, and thus suffers from the same problem. */ - x_handle_wm_state (f, &inev); + x_handle_wm_state (f, &inev.ie); if (f && FRAME_X_OUTPUT (f)->alpha_identical_p && (event->xproperty.atom @@ -20093,8 +20088,8 @@ handle_one_xevent (struct x_display_info *dpyinfo, (f, build_string ("UnmapNotify, visible | iconified")); SET_FRAME_ICONIFIED (f, true); - inev.kind = ICONIFY_EVENT; - XSETFRAME (inev.frame_or_window, f); + inev.ie.kind = ICONIFY_EVENT; + XSETFRAME (inev.ie.frame_or_window, f); } else if (CONSP (frame_size_history)) frame_size_history_plain @@ -20203,8 +20198,8 @@ handle_one_xevent (struct x_display_info *dpyinfo, if ((not_hidden || FRAME_X_EMBEDDED_P (f)) && iconified) { - inev.kind = DEICONIFY_EVENT; - XSETFRAME (inev.frame_or_window, f); + inev.ie.kind = DEICONIFY_EVENT; + XSETFRAME (inev.ie.frame_or_window, f); } } goto OTHER; @@ -20470,17 +20465,18 @@ handle_one_xevent (struct x_display_info *dpyinfo, orig_keysym = keysym; /* Common for all keysym input events. */ - XSETFRAME (inev.frame_or_window, f); - inev.modifiers = x_x_to_emacs_modifiers (dpyinfo, modifiers); - inev.timestamp = xkey.time; + XSETFRAME (inev.ie.frame_or_window, f); + inev.ie.modifiers + = x_x_to_emacs_modifiers (dpyinfo, modifiers); + inev.ie.timestamp = xkey.time; /* First deal with keysyms which have defined translations to characters. */ if (keysym >= 32 && keysym < 128) /* Avoid explicitly decoding each ASCII character. */ { - inev.kind = ASCII_KEYSTROKE_EVENT; - inev.code = keysym; + inev.ie.kind = ASCII_KEYSTROKE_EVENT; + inev.ie.code = keysym; #ifdef HAVE_XINPUT2 if (event->xkey.time == pending_keystroke_time) @@ -20489,7 +20485,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, dpyinfo->pending_keystroke_source); if (source) - inev.device = source->name; + inev.ie.device = source->name; } #endif @@ -20500,10 +20496,10 @@ handle_one_xevent (struct x_display_info *dpyinfo, if (keysym >= 0x01000000 && keysym <= 0x0110FFFF) { if (keysym < 0x01000080) - inev.kind = ASCII_KEYSTROKE_EVENT; + inev.ie.kind = ASCII_KEYSTROKE_EVENT; else - inev.kind = MULTIBYTE_CHAR_KEYSTROKE_EVENT; - inev.code = keysym & 0xFFFFFF; + inev.ie.kind = MULTIBYTE_CHAR_KEYSTROKE_EVENT; + inev.ie.code = keysym & 0xFFFFFF; #ifdef HAVE_XINPUT2 if (event->xkey.time == pending_keystroke_time) @@ -20512,7 +20508,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, dpyinfo->pending_keystroke_source); if (source) - inev.device = source->name; + inev.ie.device = source->name; } #endif @@ -20526,10 +20522,10 @@ handle_one_xevent (struct x_display_info *dpyinfo, Qnil), FIXNATP (c))) { - inev.kind = (SINGLE_BYTE_CHAR_P (XFIXNAT (c)) - ? ASCII_KEYSTROKE_EVENT - : MULTIBYTE_CHAR_KEYSTROKE_EVENT); - inev.code = XFIXNAT (c); + inev.ie.kind = (SINGLE_BYTE_CHAR_P (XFIXNAT (c)) + ? ASCII_KEYSTROKE_EVENT + : MULTIBYTE_CHAR_KEYSTROKE_EVENT); + inev.ie.code = XFIXNAT (c); #ifdef HAVE_XINPUT2 if (event->xkey.time == pending_keystroke_time) @@ -20538,7 +20534,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, dpyinfo->pending_keystroke_source); if (source) - inev.device = source->name; + inev.ie.device = source->name; } #endif @@ -20644,8 +20640,8 @@ handle_one_xevent (struct x_display_info *dpyinfo, STORE_KEYSYM_FOR_DEBUG (keysym); /* make_lispy_event will convert this to a symbolic key. */ - inev.kind = NON_ASCII_KEYSTROKE_EVENT; - inev.code = keysym; + inev.ie.kind = NON_ASCII_KEYSTROKE_EVENT; + inev.ie.code = keysym; #ifdef HAVE_XINPUT2 if (event->xkey.time == pending_keystroke_time) @@ -20654,7 +20650,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, dpyinfo->pending_keystroke_source); if (source) - inev.device = source->name; + inev.ie.device = source->name; } #endif @@ -20671,11 +20667,11 @@ handle_one_xevent (struct x_display_info *dpyinfo, if (nbytes) { - inev.kind = MULTIBYTE_CHAR_KEYSTROKE_EVENT; - inev.arg = make_unibyte_string ((char *) copy_bufptr, nbytes); + inev.ie.kind = MULTIBYTE_CHAR_KEYSTROKE_EVENT; + inev.ie.arg = make_unibyte_string ((char *) copy_bufptr, nbytes); Fput_text_property (make_fixnum (0), make_fixnum (nbytes), - Qcoding, coding, inev.arg); + Qcoding, coding, inev.ie.arg); #ifdef HAVE_XINPUT2 if (event->xkey.time == pending_keystroke_time @@ -20689,7 +20685,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, dpyinfo->pending_keystroke_source); if (source) - inev.device = source->name; + inev.ie.device = source->name; } #endif } @@ -20764,7 +20760,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, to treat implicit focus correctly. (bug#65919) */ #if defined USE_X_TOOLKIT || (defined USE_GTK && !defined HAVE_GTK3) if (x_top_window_to_frame (dpyinfo, event->xcrossing.window)) - x_detect_focus_change (dpyinfo, any, event, &inev); + x_detect_focus_change (dpyinfo, any, event, &inev.ie); #endif /* defined USE_X_TOOLKIT || (defined USE_GTK && !defined HAVE_GTK3) */ #ifdef HAVE_XINPUT2 @@ -20783,7 +20779,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, builds. */ #if !defined USE_X_TOOLKIT || (!defined USE_GTK || defined HAVE_GTK3) if (x_top_window_to_frame (dpyinfo, event->xcrossing.window)) - x_detect_focus_change (dpyinfo, any, event, &inev); + x_detect_focus_change (dpyinfo, any, event, &inev.ie); #endif /* !defined USE_X_TOOLKIT || (!defined USE_GTK || defined HAVE_GTK3) */ f = any; @@ -20857,12 +20853,12 @@ handle_one_xevent (struct x_display_info *dpyinfo, SET_FRAME_VISIBLE (f, 1); SET_FRAME_ICONIFIED (f, false); f->output_data.x->has_been_visible = true; - inev.kind = DEICONIFY_EVENT; - XSETFRAME (inev.frame_or_window, f); + inev.ie.kind = DEICONIFY_EVENT; + XSETFRAME (inev.ie.frame_or_window, f); } } - x_detect_focus_change (dpyinfo, any, event, &inev); + x_detect_focus_change (dpyinfo, any, event, &inev.ie); goto OTHER; case LeaveNotify: @@ -20874,7 +20870,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, to treat implicit focus correctly. */ #if defined USE_X_TOOLKIT || (defined USE_GTK && !defined HAVE_GTK3) if (x_top_window_to_frame (dpyinfo, event->xcrossing.window)) - x_detect_focus_change (dpyinfo, any, event, &inev); + x_detect_focus_change (dpyinfo, any, event, &inev.ie); #endif /* defined USE_X_TOOLKIT || (defined USE_GTK && !defined HAVE_GTK3) */ #ifdef HAVE_XINPUT2 @@ -20906,7 +20902,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, builds. */ #if !defined USE_X_TOOLKIT || (!defined USE_GTK || defined HAVE_GTK3) if (x_top_window_to_frame (dpyinfo, event->xcrossing.window)) - x_detect_focus_change (dpyinfo, any, event, &inev); + x_detect_focus_change (dpyinfo, any, event, &inev.ie); #endif /* !defined USE_X_TOOLKIT || (!defined USE_GTK || defined HAVE_GTK3) */ #ifdef HAVE_XWIDGETS @@ -21007,7 +21003,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, if (dpyinfo->supports_xi2) goto OTHER; #endif - x_detect_focus_change (dpyinfo, any, event, &inev); + x_detect_focus_change (dpyinfo, any, event, &inev.ie); goto OTHER; case MotionNotify: @@ -21317,8 +21313,8 @@ handle_one_xevent (struct x_display_info *dpyinfo, && !EQ (window, last_mouse_window) && !EQ (window, selected_window)) { - inev.kind = SELECT_WINDOW_EVENT; - inev.frame_or_window = window; + inev.ie.kind = SELECT_WINDOW_EVENT; + inev.ie.frame_or_window = window; } /* Remember the last window where we saw the mouse. */ @@ -21409,13 +21405,13 @@ handle_one_xevent (struct x_display_info *dpyinfo, hook. */ if (!x_find_monitors_changed_event (dpyinfo)) { - inev.kind = MONITORS_CHANGED_EVENT; - XSETTERMINAL (inev.arg, dpyinfo->terminal); + inev.ie.kind = MONITORS_CHANGED_EVENT; + XSETTERMINAL (inev.ie.arg, dpyinfo->terminal); - /* Store this event now since inev.type could be set to + /* Store this event now since inev.ie.type could be set to MOVE_FRAME_EVENT later. */ - kbd_buffer_store_event (&inev); - inev.kind = NO_EVENT; + kbd_buffer_store_event (&inev.ie); + inev.ie.kind = NO_EVENT; } /* Also update the position of the drag-and-drop @@ -21682,8 +21678,8 @@ handle_one_xevent (struct x_display_info *dpyinfo, if (!FRAME_TOOLTIP_P (f) && (old_left != f->left_pos || old_top != f->top_pos)) { - inev.kind = MOVE_FRAME_EVENT; - XSETFRAME (inev.frame_or_window, f); + inev.ie.kind = MOVE_FRAME_EVENT; + XSETFRAME (inev.ie.frame_or_window, f); } } @@ -21749,8 +21745,8 @@ handle_one_xevent (struct x_display_info *dpyinfo, if (!EQ (selected_window, xvw->w) && (event->xbutton.button < 4)) { - inev.kind = SELECT_WINDOW_EVENT; - inev.frame_or_window = xvw->w; + inev.ie.kind = SELECT_WINDOW_EVENT; + inev.ie.frame_or_window = xvw->w; } *finish = X_EVENT_DROP; @@ -22006,14 +22002,14 @@ handle_one_xevent (struct x_display_info *dpyinfo, && event->xbutton.time > ignore_next_mouse_click_timeout) { ignore_next_mouse_click_timeout = 0; - x_construct_mouse_click (&inev, &event->xbutton, + x_construct_mouse_click (&inev.ie, &event->xbutton, f, false); } if (event->type == ButtonRelease) ignore_next_mouse_click_timeout = 0; } else - x_construct_mouse_click (&inev, &event->xbutton, f, false); + x_construct_mouse_click (&inev.ie, &event->xbutton, f, false); *finish = X_EVENT_DROP; goto OTHER; @@ -22083,18 +22079,18 @@ handle_one_xevent (struct x_display_info *dpyinfo, && event->xbutton.time > ignore_next_mouse_click_timeout) { ignore_next_mouse_click_timeout = 0; - x_construct_mouse_click (&inev, &event->xbutton, + x_construct_mouse_click (&inev.ie, &event->xbutton, f, false); } if (event->type == ButtonRelease) ignore_next_mouse_click_timeout = 0; } else - x_construct_mouse_click (&inev, &event->xbutton, + x_construct_mouse_click (&inev.ie, &event->xbutton, f, false); if (!NILP (tab_bar_arg)) - inev.arg = tab_bar_arg; + inev.ie.arg = tab_bar_arg; } if (FRAME_X_EMBEDDED_P (f) @@ -22113,12 +22109,12 @@ handle_one_xevent (struct x_display_info *dpyinfo, scroll bars. */ if (bar && event->xbutton.state & ControlMask) { - x_scroll_bar_handle_click (bar, event, &inev, Qnil); + x_scroll_bar_handle_click (bar, event, &inev.ie, Qnil); *finish = X_EVENT_DROP; } #else /* not USE_TOOLKIT_SCROLL_BARS */ if (bar) - x_scroll_bar_handle_click (bar, event, &inev, Qnil); + x_scroll_bar_handle_click (bar, event, &inev.ie, Qnil); #endif /* not USE_TOOLKIT_SCROLL_BARS */ } @@ -22175,8 +22171,8 @@ handle_one_xevent (struct x_display_info *dpyinfo, if (!f->output_data.x->saved_menu_event) f->output_data.x->saved_menu_event = xmalloc (sizeof *event); *f->output_data.x->saved_menu_event = *event; - inev.kind = MENU_BAR_ACTIVATE_EVENT; - XSETFRAME (inev.frame_or_window, f); + inev.ie.kind = MENU_BAR_ACTIVATE_EVENT; + XSETFRAME (inev.ie.frame_or_window, f); *finish = X_EVENT_DROP; #ifdef USE_MOTIF } @@ -22327,8 +22323,8 @@ handle_one_xevent (struct x_display_info *dpyinfo, SET_FRAME_VISIBLE (f, 1); SET_FRAME_ICONIFIED (f, false); f->output_data.x->has_been_visible = true; - inev.kind = DEICONIFY_EVENT; - XSETFRAME (inev.frame_or_window, f); + inev.ie.kind = DEICONIFY_EVENT; + XSETFRAME (inev.ie.frame_or_window, f); } } @@ -22878,36 +22874,36 @@ handle_one_xevent (struct x_display_info *dpyinfo, if (fabs (total_x) > 0 || fabs (total_y) > 0) { - inev.kind = (fabs (total_y) >= fabs (total_x) - ? WHEEL_EVENT : HORIZ_WHEEL_EVENT); - inev.timestamp = xev->time; - - XSETINT (inev.x, lrint (real_x)); - XSETINT (inev.y, lrint (real_y)); - XSETFRAME (inev.frame_or_window, f); - - inev.modifiers = (signbit (fabs (total_y) >= fabs (total_x) - ? total_y : total_x) - ? down_modifier : up_modifier); - inev.modifiers + inev.ie.kind = (fabs (total_y) >= fabs (total_x) + ? WHEEL_EVENT : HORIZ_WHEEL_EVENT); + inev.ie.timestamp = xev->time; + + XSETINT (inev.ie.x, lrint (real_x)); + XSETINT (inev.ie.y, lrint (real_y)); + XSETFRAME (inev.ie.frame_or_window, f); + + inev.ie.modifiers = (signbit (fabs (total_y) >= fabs (total_x) + ? total_y : total_x) + ? down_modifier : up_modifier); + inev.ie.modifiers |= x_x_to_emacs_modifiers (dpyinfo, xev->mods.effective); - inev.arg = list3 (Qnil, - make_float (total_x), - make_float (total_y)); + inev.ie.arg = list3 (Qnil, + make_float (total_x), + make_float (total_y)); } else { - inev.kind = TOUCH_END_EVENT; - inev.timestamp = xev->time; + inev.ie.kind = TOUCH_END_EVENT; + inev.ie.timestamp = xev->time; - XSETINT (inev.x, lrint (real_x)); - XSETINT (inev.y, lrint (real_y)); - XSETFRAME (inev.frame_or_window, f); + XSETINT (inev.ie.x, lrint (real_x)); + XSETINT (inev.ie.y, lrint (real_y)); + XSETFRAME (inev.ie.frame_or_window, f); } if (source && !NILP (source->name)) - inev.device = source->name; + inev.ie.device = source->name; if (!other_valuators_found) goto XI_OTHER; @@ -23248,11 +23244,11 @@ handle_one_xevent (struct x_display_info *dpyinfo, && !EQ (window, last_mouse_window) && !EQ (window, selected_window)) { - inev.kind = SELECT_WINDOW_EVENT; - inev.frame_or_window = window; + inev.ie.kind = SELECT_WINDOW_EVENT; + inev.ie.frame_or_window = window; if (source) - inev.device = source->name; + inev.ie.device = source->name; } /* Remember the last window where we saw the mouse. */ @@ -23640,11 +23636,11 @@ handle_one_xevent (struct x_display_info *dpyinfo, if (!EQ (selected_window, xvw->w) && (xev->detail < 4)) { - inev.kind = SELECT_WINDOW_EVENT; - inev.frame_or_window = xvw->w; + inev.ie.kind = SELECT_WINDOW_EVENT; + inev.ie.frame_or_window = xvw->w; if (source) - inev.device = source->name; + inev.ie.device = source->name; } *finish = X_EVENT_DROP; @@ -23743,24 +23739,24 @@ handle_one_xevent (struct x_display_info *dpyinfo, &real_x, &real_y); if (xev->detail <= 5) - inev.kind = WHEEL_EVENT; + inev.ie.kind = WHEEL_EVENT; else - inev.kind = HORIZ_WHEEL_EVENT; + inev.ie.kind = HORIZ_WHEEL_EVENT; if (source) - inev.device = source->name; + inev.ie.device = source->name; - inev.timestamp = xev->time; + inev.ie.timestamp = xev->time; - XSETINT (inev.x, real_x); - XSETINT (inev.y, real_y); - XSETFRAME (inev.frame_or_window, f); + XSETINT (inev.ie.x, real_x); + XSETINT (inev.ie.y, real_y); + XSETFRAME (inev.ie.frame_or_window, f); - inev.modifiers + inev.ie.modifiers |= x_x_to_emacs_modifiers (dpyinfo, xev->mods.effective); - inev.modifiers |= xev->detail % 2 ? down_modifier : up_modifier; + inev.ie.modifiers |= xev->detail % 2 ? down_modifier : up_modifier; } *finish = X_EVENT_DROP; @@ -23781,24 +23777,24 @@ handle_one_xevent (struct x_display_info *dpyinfo, if (xev->evtype == XI_ButtonRelease) { if (xev->detail <= 5) - inev.kind = WHEEL_EVENT; + inev.ie.kind = WHEEL_EVENT; else - inev.kind = HORIZ_WHEEL_EVENT; + inev.ie.kind = HORIZ_WHEEL_EVENT; if (source) - inev.device = source->name; + inev.ie.device = source->name; - inev.timestamp = xev->time; + inev.ie.timestamp = xev->time; - XSETINT (inev.x, lrint (xev->event_x)); - XSETINT (inev.y, lrint (xev->event_y)); - XSETFRAME (inev.frame_or_window, f); + XSETINT (inev.ie.x, lrint (xev->event_x)); + XSETINT (inev.ie.y, lrint (xev->event_y)); + XSETFRAME (inev.ie.frame_or_window, f); - inev.modifiers + inev.ie.modifiers |= x_x_to_emacs_modifiers (dpyinfo, xev->mods.effective); - inev.modifiers |= xev->detail % 2 ? down_modifier : up_modifier; + inev.ie.modifiers |= xev->detail % 2 ? down_modifier : up_modifier; } goto XI_OTHER; @@ -23867,16 +23863,16 @@ handle_one_xevent (struct x_display_info *dpyinfo, && xev->time > ignore_next_mouse_click_timeout) { ignore_next_mouse_click_timeout = 0; - x_construct_mouse_click (&inev, &bv, f, true); + x_construct_mouse_click (&inev.ie, &bv, f, true); } if (xev->evtype == XI_ButtonRelease) ignore_next_mouse_click_timeout = 0; } else - x_construct_mouse_click (&inev, &bv, f, true); + x_construct_mouse_click (&inev.ie, &bv, f, true); if (!NILP (tab_bar_arg)) - inev.arg = tab_bar_arg; + inev.ie.arg = tab_bar_arg; } if (FRAME_X_EMBEDDED_P (f) @@ -23892,14 +23888,14 @@ handle_one_xevent (struct x_display_info *dpyinfo, #ifndef USE_TOOLKIT_SCROLL_BARS if (bar) - x_scroll_bar_handle_click (bar, (XEvent *) &bv, &inev, + x_scroll_bar_handle_click (bar, (XEvent *) &bv, &inev.ie, source ? source->name : Qnil); #else /* Make the "Ctrl-Mouse-2 splits window" work for toolkit scroll bars. */ if (bar && xev->mods.effective & ControlMask) { - x_scroll_bar_handle_click (bar, (XEvent *) &bv, &inev, + x_scroll_bar_handle_click (bar, (XEvent *) &bv, &inev.ie, source ? source->name : Qnil); *finish = X_EVENT_DROP; } @@ -23925,8 +23921,8 @@ handle_one_xevent (struct x_display_info *dpyinfo, device->grab &= ~(1 << xev->detail); } - if (source && inev.kind != NO_EVENT) - inev.device = source->name; + if (source && inev.ie.kind != NO_EVENT) + inev.ie.device = source->name; if (f) f->mouse_moved = false; @@ -24247,8 +24243,8 @@ handle_one_xevent (struct x_display_info *dpyinfo, *finish = X_EVENT_DROP; #endif /* USE_GTK */ - XSETFRAME (inev.frame_or_window, f); - inev.timestamp = xev->time; + XSETFRAME (inev.ie.frame_or_window, f); + inev.ie.timestamp = xev->time; #ifdef HAVE_X_I18N if (FRAME_XIC (f)) @@ -24360,7 +24356,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, } } - inev.modifiers = x_x_to_emacs_modifiers (dpyinfo, state); + inev.ie.modifiers = x_x_to_emacs_modifiers (dpyinfo, state); #ifdef XK_F1 if (x_dnd_in_progress @@ -24398,11 +24394,11 @@ handle_one_xevent (struct x_display_info *dpyinfo, if (keysym >= 32 && keysym < 128) /* Avoid explicitly decoding each ASCII character. */ { - inev.kind = ASCII_KEYSTROKE_EVENT; - inev.code = keysym; + inev.ie.kind = ASCII_KEYSTROKE_EVENT; + inev.ie.code = keysym; if (source) - inev.device = source->name; + inev.ie.device = source->name; goto xi_done_keysym; } @@ -24411,14 +24407,14 @@ handle_one_xevent (struct x_display_info *dpyinfo, if (keysym >= 0x01000000 && keysym <= 0x0110FFFF) { if (keysym < 0x01000080) - inev.kind = ASCII_KEYSTROKE_EVENT; + inev.ie.kind = ASCII_KEYSTROKE_EVENT; else - inev.kind = MULTIBYTE_CHAR_KEYSTROKE_EVENT; + inev.ie.kind = MULTIBYTE_CHAR_KEYSTROKE_EVENT; if (source) - inev.device = source->name; + inev.ie.device = source->name; - inev.code = keysym & 0xFFFFFF; + inev.ie.code = keysym & 0xFFFFFF; goto xi_done_keysym; } @@ -24429,13 +24425,13 @@ handle_one_xevent (struct x_display_info *dpyinfo, Qnil), FIXNATP (c))) { - inev.kind = (SINGLE_BYTE_CHAR_P (XFIXNAT (c)) + inev.ie.kind = (SINGLE_BYTE_CHAR_P (XFIXNAT (c)) ? ASCII_KEYSTROKE_EVENT : MULTIBYTE_CHAR_KEYSTROKE_EVENT); - inev.code = XFIXNAT (c); + inev.ie.code = XFIXNAT (c); if (source) - inev.device = source->name; + inev.ie.device = source->name; goto xi_done_keysym; } @@ -24539,11 +24535,11 @@ handle_one_xevent (struct x_display_info *dpyinfo, STORE_KEYSYM_FOR_DEBUG (keysym); /* make_lispy_event will convert this to a symbolic key. */ - inev.kind = NON_ASCII_KEYSTROKE_EVENT; - inev.code = keysym; + inev.ie.kind = NON_ASCII_KEYSTROKE_EVENT; + inev.ie.code = keysym; if (source) - inev.device = source->name; + inev.ie.device = source->name; goto xi_done_keysym; } @@ -24555,14 +24551,14 @@ handle_one_xevent (struct x_display_info *dpyinfo, if (nbytes) { - inev.kind = MULTIBYTE_CHAR_KEYSTROKE_EVENT; - inev.arg = make_unibyte_string (copy_bufptr, nbytes); + inev.ie.kind = MULTIBYTE_CHAR_KEYSTROKE_EVENT; + inev.ie.arg = make_unibyte_string (copy_bufptr, nbytes); Fput_text_property (make_fixnum (0), make_fixnum (nbytes), - Qcoding, coding, inev.arg); + Qcoding, coding, inev.ie.arg); if (source) - inev.device = source->name; + inev.ie.device = source->name; } goto xi_done_keysym; } @@ -24916,15 +24912,15 @@ handle_one_xevent (struct x_display_info *dpyinfo, xev->event_x, xev->event_y, f); - inev.kind = TOUCHSCREEN_BEGIN_EVENT; - inev.timestamp = xev->time; - XSETFRAME (inev.frame_or_window, f); - XSETINT (inev.x, lrint (xev->event_x)); - XSETINT (inev.y, lrint (xev->event_y)); - XSETINT (inev.arg, local_detail); + inev.ie.kind = TOUCHSCREEN_BEGIN_EVENT; + inev.ie.timestamp = xev->time; + XSETFRAME (inev.ie.frame_or_window, f); + XSETINT (inev.ie.x, lrint (xev->event_x)); + XSETINT (inev.ie.y, lrint (xev->event_y)); + XSETINT (inev.ie.arg, local_detail); if (source) - inev.device = source->name; + inev.ie.device = source->name; } x_uncatch_errors (); @@ -25030,9 +25026,9 @@ handle_one_xevent (struct x_display_info *dpyinfo, if (f && device->direct_p) { - inev.kind = TOUCHSCREEN_UPDATE_EVENT; - inev.timestamp = xev->time; - XSETFRAME (inev.frame_or_window, f); + inev.ie.kind = TOUCHSCREEN_UPDATE_EVENT; + inev.ie.timestamp = xev->time; + XSETFRAME (inev.ie.frame_or_window, f); for (touchpoint = device->touchpoints; touchpoint; touchpoint = touchpoint->next) @@ -25044,9 +25040,9 @@ handle_one_xevent (struct x_display_info *dpyinfo, } if (source) - inev.device = source->name; + inev.ie.device = source->name; - inev.arg = arg; + inev.ie.arg = arg; } goto XI_OTHER; @@ -25081,17 +25077,17 @@ handle_one_xevent (struct x_display_info *dpyinfo, if (f && device->direct_p) { - inev.kind = TOUCHSCREEN_END_EVENT; - inev.timestamp = xev->time; - inev.modifiers = state != 2; + inev.ie.kind = TOUCHSCREEN_END_EVENT; + inev.ie.timestamp = xev->time; + inev.ie.modifiers = state != 2; - XSETFRAME (inev.frame_or_window, f); - XSETINT (inev.x, lrint (xev->event_x)); - XSETINT (inev.y, lrint (xev->event_y)); - XSETINT (inev.arg, local_detail); + XSETFRAME (inev.ie.frame_or_window, f); + XSETINT (inev.ie.x, lrint (xev->event_x)); + XSETINT (inev.ie.y, lrint (xev->event_y)); + XSETINT (inev.ie.arg, local_detail); if (source) - inev.device = source->name; + inev.ie.device = source->name; } } @@ -25160,20 +25156,20 @@ handle_one_xevent (struct x_display_info *dpyinfo, if (pev->event == FRAME_X_WINDOW (any)) xi_compute_root_window_offset_pinch (any, pev); - inev.kind = PINCH_EVENT; - inev.modifiers + inev.ie.kind = PINCH_EVENT; + inev.ie.modifiers = x_x_to_emacs_modifiers (dpyinfo, pev->mods.effective); - XSETINT (inev.x, lrint (pev->event_x)); - XSETINT (inev.y, lrint (pev->event_y)); - XSETFRAME (inev.frame_or_window, any); - inev.arg = list4 (make_float (pev->delta_x), - make_float (pev->delta_y), - make_float (pev->scale), - make_float (pev->delta_angle)); + XSETINT (inev.ie.x, lrint (pev->event_x)); + XSETINT (inev.ie.y, lrint (pev->event_y)); + XSETFRAME (inev.ie.frame_or_window, any); + inev.ie.arg = list4 (make_float (pev->delta_x), + make_float (pev->delta_y), + make_float (pev->scale), + make_float (pev->delta_angle)); if (source) - inev.device = source->name; + inev.ie.device = source->name; } /* Once again GTK seems to crash when confronted by @@ -25528,26 +25524,26 @@ handle_one_xevent (struct x_display_info *dpyinfo, already an undelivered event on the queue. */ goto OTHER; - inev.kind = MONITORS_CHANGED_EVENT; - inev.timestamp = timestamp; - XSETTERMINAL (inev.arg, dpyinfo->terminal); + inev.ie.kind = MONITORS_CHANGED_EVENT; + inev.ie.timestamp = timestamp; + XSETTERMINAL (inev.ie.arg, dpyinfo->terminal); /* Also don't do anything if the monitor configuration didn't really change. */ current_monitors - = Fx_display_monitor_attributes_list (inev.arg); + = Fx_display_monitor_attributes_list (inev.ie.arg); if (!NILP (Fequal (current_monitors, dpyinfo->last_monitor_attributes_list))) - inev.kind = NO_EVENT; + inev.ie.kind = NO_EVENT; dpyinfo->last_monitor_attributes_list = current_monitors; if (x_dnd_in_progress && x_dnd_update_tooltip) x_dnd_monitors = current_monitors; - if (inev.kind != NO_EVENT) + if (inev.ie.kind != NO_EVENT) x_dnd_update_tooltip_now (); } #endif @@ -25595,9 +25591,9 @@ handle_one_xevent (struct x_display_info *dpyinfo, } done: - if (inev.kind != NO_EVENT) + if (inev.ie.kind != NO_EVENT) { - kbd_buffer_store_event_hold (&inev, hold_quit); + kbd_buffer_store_buffered_event (&inev, hold_quit); count++; } commit 3e39b2418b3d015d94e2d24e003f47cae8c21c37 Author: Philipp Stephani Date: Tue Mar 4 06:12:58 2025 +0100 ; * src/eval.c (Fdefvar_1, Fdefconst_1): Properly quote apostrophe. diff --git a/src/eval.c b/src/eval.c index 70f533842b9..046d86dc5ac 100644 --- a/src/eval.c +++ b/src/eval.c @@ -918,7 +918,7 @@ usage: (defvar SYMBOL &optional INITVALUE DOCSTRING) */) DEFUN ("defvar-1", Fdefvar_1, Sdefvar_1, 2, 3, 0, doc: /* Like `defvar' but as a function. -More specifically behaves like (defvar SYM 'INITVALUE DOCSTRING). */) +More specifically behaves like (defvar SYM \\='INITVALUE DOCSTRING). */) (Lisp_Object sym, Lisp_Object initvalue, Lisp_Object docstring) { return defvar (sym, initvalue, docstring, false); @@ -959,7 +959,7 @@ usage: (defconst SYMBOL INITVALUE [DOCSTRING]) */) DEFUN ("defconst-1", Fdefconst_1, Sdefconst_1, 2, 3, 0, doc: /* Like `defconst' but as a function. -More specifically, behaves like (defconst SYM 'INITVALUE DOCSTRING). */) +More specifically, behaves like (defconst SYM \\='INITVALUE DOCSTRING). */) (Lisp_Object sym, Lisp_Object initvalue, Lisp_Object docstring) { CHECK_SYMBOL (sym); commit a38ed1618d7c6293e38ffdc76fb2c16f8ef33874 Author: Sean Whitton Date: Tue Mar 4 11:58:15 2025 +0800 Fix unwanted revert file prompt after repeated vc-ediff (bug#11605) * lisp/vc/ediff-vers.el (vc-find-revision-no-save): Declare. (ediff-vc-internal, ediff-vc-merge-internal): Bind vc-find-revision-no-save instead of calling ediff-delete-version-file (bug#11605). (ediff-delete-version-file): Delete. diff --git a/lisp/vc/ediff-vers.el b/lisp/vc/ediff-vers.el index c90fcf8afdb..60ea5ae1cd8 100644 --- a/lisp/vc/ediff-vers.el +++ b/lisp/vc/ediff-vers.el @@ -58,29 +58,26 @@ comparison or merge operations are being performed." )) +(defvar vc-find-revision-no-save) + (defun ediff-vc-internal (rev1 rev2 &optional startup-hooks) ;; Run Ediff on versions of the current buffer. ;; If REV1 is "", use the latest version of the current buffer's file. ;; If REV2 is "" then compare current buffer with REV1. ;; If the current buffer is named `F', the version is named `F.~REV~'. ;; If `F.~REV~' already exists, it is used instead of being re-created. - (let (file1 file2 rev1buf rev2buf) + (let ((vc-find-revision-no-save (not ediff-keep-tmp-versions)) + rev1buf rev2buf) (if (string= rev1 "") (setq rev1 (ediff-vc-latest-version (buffer-file-name)))) (save-window-excursion (save-excursion (vc-revision-other-window rev1) - (setq rev1buf (current-buffer) - file1 (buffer-file-name))) + (setq rev1buf (current-buffer))) (save-excursion (or (string= rev2 "") ; use current buffer (vc-revision-other-window rev2)) - (setq rev2buf (current-buffer) - file2 (buffer-file-name))) - (push (lambda () - (ediff-delete-version-file file1) - (or (string= rev2 "") (ediff-delete-version-file file2))) - startup-hooks)) + (setq rev2buf (current-buffer)))) (ediff-buffers rev1buf rev2buf startup-hooks @@ -143,7 +140,8 @@ With prefix argument, prompts for a revision name." (defun ediff-vc-merge-internal (rev1 rev2 ancestor-rev &optional startup-hooks merge-buffer-file) ;; If ANCESTOR-REV non-nil, merge with ancestor - (let (buf1 buf2 ancestor-buf) + (let ((vc-find-revision-no-save t) + buf1 buf2 ancestor-buf) (save-window-excursion (save-excursion (vc-revision-other-window rev1) @@ -158,17 +156,7 @@ With prefix argument, prompts for a revision name." (setq ancestor-rev (vc-working-revision buffer-file-name))) (vc-revision-other-window ancestor-rev) - (setq ancestor-buf (current-buffer)))) - (push (let ((f1 (buffer-file-name buf1)) - (f2 (unless (string= rev2 "") (buffer-file-name buf2))) - (fa (unless (or (string= ancestor-rev "") - (not ancestor-rev)) - (buffer-file-name ancestor-buf)))) - (lambda () - (ediff-delete-version-file f1) - (if f2 (ediff-delete-version-file f2)) - (if fa (ediff-delete-version-file fa)))) - startup-hooks)) + (setq ancestor-buf (current-buffer))))) (if ancestor-rev (ediff-merge-buffers-with-ancestor buf1 buf2 ancestor-buf @@ -201,10 +189,5 @@ With prefix argument, prompts for a revision name." buf1 buf2 startup-hooks 'ediff-merge-revisions merge-buffer-file)))) -;; delete version file on exit unless ediff-keep-tmp-versions is true -(defun ediff-delete-version-file (file) - (or ediff-keep-tmp-versions (delete-file file))) - - (provide 'ediff-vers) ;;; ediff-vers.el ends here commit 035077febe34b0df871bb3b6e1c81fc2bfdc4059 Author: Stefan Monnier Date: Mon Mar 3 22:18:02 2025 -0500 (advice--make-nadvice-docstring): Rename * lisp/emacs-lisp/nadvice.el (advice--make-nadvice-docstring): Rename from `nadvice--make-docstring`, to stick to the `advice-` namespace. Update all callers. diff --git a/lisp/emacs-lisp/nadvice.el b/lisp/emacs-lisp/nadvice.el index 150332c4c5d..1172338e7ca 100644 --- a/lisp/emacs-lisp/nadvice.el +++ b/lisp/emacs-lisp/nadvice.el @@ -151,7 +151,8 @@ DOC is a string where \"FUNCTION\" and \"OLDFUN\" are expected.") ;; definition is loaded]", bug#21299 (if (stringp arglist) t (help--make-usage-docstring function arglist))) - (setq origdoc (cdr usage)) (car usage))) + (setq origdoc (cdr usage)) + (car usage))) (help-add-fundoc-usage (with-temp-buffer (when before @@ -319,7 +320,10 @@ These functions act like the t special value in buffer-local hooks.") ((symbolp place) `(default-value ',place)) (t place)))) -(defun nadvice--make-docstring (sym) +(defun advice--make-nadvice-docstring (sym) + "Make docstring for a nadvice function. +Modifies the function's docstring by replacing \"<<>>\" with the +description of the possible HOWs." (let* ((main (documentation (symbol-function sym) 'raw)) (ud (help-split-fundoc main 'pcase)) (doc (or (cdr ud) main)) @@ -340,7 +344,7 @@ These functions act like the t special value in buffer-local hooks.") (if ud (help-add-fundoc-usage combined-doc (car ud)) combined-doc))) (put 'add-function 'function-documentation - '(nadvice--make-docstring 'add-function)) + '(advice--make-nadvice-docstring 'add-function)) ;;;###autoload (defmacro add-function (how place function &optional props) @@ -498,7 +502,7 @@ of the piece of advice." (funcall fsetfun symbol newdef)))) (put 'advice-add 'function-documentation - '(nadvice--make-docstring 'advice-add)) + '(advice--make-nadvice-docstring 'advice-add)) ;;;###autoload (defun advice-add (symbol how function &optional props) commit 93c3a269ca45f6165b4181de2386517e95d07116 Author: Stefan Kangas Date: Tue Mar 4 03:05:03 2025 +0100 ; Fix copyright years of the Spanish translations These translations were created in 2025, so that is the correct copyright year, even if the source material was created earlier. diff --git a/etc/refcards/es-dired-ref.tex b/etc/refcards/es-dired-ref.tex index d9b7b3c4d05..d8a065d4692 100644 --- a/etc/refcards/es-dired-ref.tex +++ b/etc/refcards/es-dired-ref.tex @@ -1,6 +1,6 @@ % Reference Card for Dired -% Copyright (C) 2000--2025 Free Software Foundation, Inc. +% Copyright (C) 2025 Free Software Foundation, Inc. % Author: Evgeny Roubinchtein % Spanish translation: Elias Gabriel Perez diff --git a/etc/refcards/es-refcard.tex b/etc/refcards/es-refcard.tex index 971c8bb80f0..22343fe1aeb 100644 --- a/etc/refcards/es-refcard.tex +++ b/etc/refcards/es-refcard.tex @@ -1,7 +1,6 @@ % Reference Card for GNU Emacs -% Copyright (C) 1987, 1993, 1996--1997, 2001--2025 Free Software -% Foundation, Inc. +% Copyright (C) 2025 Free Software Foundation, Inc. % Author: Stephen Gildea % Spanish translation: Elias Gabriel Perez diff --git a/etc/refcards/es-survival.tex b/etc/refcards/es-survival.tex index e2d8aed56de..f0e64717fc4 100644 --- a/etc/refcards/es-survival.tex +++ b/etc/refcards/es-survival.tex @@ -1,7 +1,7 @@ %&tex % Title: GNU Emacs Survival Card -% Copyright (C) 2000--2025 Free Software Foundation, Inc. +% Copyright (C) 2025 Free Software Foundation, Inc. % Author: Włodek Bzyl % Spanish translation: Elias Gabriel Perez commit 50baeb95c68eedbefd70b0814eeb9b384826cfa8 Author: Stefan Kangas Date: Tue Mar 4 02:59:03 2025 +0100 Update Makefile and docs for new Spanish refcards * etc/refcards/Makefile (PDF_SPANISH, PS_SPANISH): New variables. (PDF_TARGETS): Use above new variables. (spanish, spanish-ps): New targets for Spanish translation. (Bug#76300) * admin/release-process: * etc/refcards/README: Document new Spanish translation. diff --git a/admin/release-process b/admin/release-process index 7240ff10a29..64b022c8aef 100644 --- a/admin/release-process +++ b/admin/release-process @@ -205,6 +205,7 @@ Emacs 22 translators: LANG Translator Status cs Pavel Janík de Sven Joachim +es Elias Gabriel Perez fr Eric Jacoboni pl Włodek Bzyl pt-br Rodrigo Real diff --git a/etc/refcards/Makefile b/etc/refcards/Makefile index eba7be03814..727ed18e2e3 100644 --- a/etc/refcards/Makefile +++ b/etc/refcards/Makefile @@ -54,8 +54,14 @@ PDF_SLOVAKIAN = \ sk-refcard.pdf \ sk-survival.pdf +PDF_SPANISH = \ + es-dired-ref.pdf \ + es-refcard.pdf \ + es-survival.pdf + PDF_TARGETS = $(PDF_ENGLISH) $(PDF_CZECH) $(PDF_FRENCH) $(PDF_GERMAN) \ - $(PDF_POLISH) $(PDF_PORTUGUESE) $(PDF_RUSSIAN) $(PDF_SLOVAKIAN) + $(PDF_POLISH) $(PDF_PORTUGUESE) $(PDF_RUSSIAN) $(PDF_SLOVAKIAN) \ + $(PDF_SPANISH) PS_ENGLISH = $(PDF_ENGLISH:.pdf=.ps) PS_CZECH = $(PDF_CZECH:.pdf=.ps) @@ -65,6 +71,7 @@ PS_POLISH = $(PDF_POLISH:.pdf=.ps) PS_PORTUGUESE = $(PDF_PORTUGUESE:.pdf=.ps) PS_RUSSIAN = $(PDF_RUSSIAN:.pdf=.ps) PS_SLOVAKIAN = $(PDF_SLOVAKIAN:.pdf=.ps) +PS_SPANISH = $(PDF_SPANISH:.pdf=.ps) PS_TARGETS = $(PDF_TARGETS:.pdf=.ps) @@ -80,7 +87,7 @@ pdf: $(PDF_TARGETS) ps: $(PS_TARGETS) -.PHONY: english czech french german polish portuguese russian slovakian +.PHONY: english czech french german polish portuguese russian slovakian spanish english: $(PDF_ENGLISH) czech: $(PDF_CZECH) french: $(PDF_FRENCH) @@ -89,6 +96,7 @@ polish: $(PDF_POLISH) portuguese: $(PDF_PORTUGUESE) russian: $(PDF_RUSSIAN) slovakian: $(PDF_SLOVAKIAN) +spanish: $(PDF_SPANISH) .PHONY: english-ps czech-ps french-ps german-ps polish-ps portuguese-ps russian-ps slovakian-ps english-ps: $(PS_ENGLISH) @@ -99,6 +107,7 @@ polish-ps: $(PS_POLISH) portuguese-ps: $(PS_PORTUGUESE) russian-ps: $(PS_RUSSIAN) slovakian-ps: $(PS_SLOVAKIAN) +spanish-ps: $(PS_SPANISH) ## Default for file that do not use a different paper size. @@ -289,6 +298,31 @@ sk-survival.dvi: $(sk_survival_deps) sk-survival.ps: sk-survival.dvi dvips -t a4 -o $@ sk-survival.dvi +es_dired_ref_deps = es-dired-ref.tex emacsver.tex pdflayout.sty +es-dired-ref.pdf: $(es_dired_ref_deps) + input=es-dired-ref.tex; $(make_cs) +es-dired-ref.dvi: $(es_dired_ref_deps) + $(ENVADD) csplain es-dired-ref.tex +es-dired-ref.ps: es-dired-ref.dvi + dvips -t a4 -o $@ es-dired-ref.dvi + +es_refcard_deps = es-refcard.tex emacsver.tex pdflayout.sty +es-refcard.pdf: $(es_refcard_deps) + input=es-refcard.tex; $(make_cs) +es-refcard.dvi: $(es_refcard_deps) + $(ENVADD) csplain es-refcard.tex +es-refcard.ps: es-refcard.dvi + dvips -t a4 -o $@ es-refcard.dvi + +es_survival_deps = es-survival.tex emacsver.tex pdflayout.sty +es-survival.pdf: $(es_survival_deps) + input=es-survival.tex; $(make_cs) +es-survival.dvi: $(es_survival_deps) + $(ENVADD) csplain es-survival.tex +es-survival.ps: es-survival.dvi + dvips -t a4 -o $@ es-survival.dvi + + survival_deps = survival.tex emacsver.tex pdflayout.sty survival.pdf: $(survival_deps) $(ENVADD) pdftex survival.tex diff --git a/etc/refcards/README b/etc/refcards/README index 03e122d56b1..d344f82d3a4 100644 --- a/etc/refcards/README +++ b/etc/refcards/README @@ -68,6 +68,12 @@ Slovak sk-refcard.pdf Emacs Reference Card (sk) sk-survival.pdf Emacs Survival Card (sk) +Spanish + + es-dired-ref.pdf Dired Reference Card (es) + es-refcard.pdf Emacs Reference Card (es) + es-survival.pdf Emacs Survival Card (es) + COPYRIGHT AND LICENSE INFORMATION FOR IMAGE FILES commit 05f0f14068bcdd83cfd8f131e4d1dde4342f8d71 Author: Elías Gabriel Pérez Date: Sat Feb 22 12:06:19 2025 -0600 Add Spanish translation for survival.tex * etc/refcards/es-survival.tex: New file. (Bug#76300) diff --git a/etc/refcards/es-survival.tex b/etc/refcards/es-survival.tex new file mode 100644 index 00000000000..e2d8aed56de --- /dev/null +++ b/etc/refcards/es-survival.tex @@ -0,0 +1,425 @@ +%&tex +% Title: GNU Emacs Survival Card + +% Copyright (C) 2000--2025 Free Software Foundation, Inc. + +% Author: Włodek Bzyl +% Spanish translation: Elias Gabriel Perez + +% This document is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% As a special additional permission, you may distribute reference cards +% printed, or formatted for printing, with the notice "Released under +% the terms of the GNU General Public License version 3 or later" +% instead of the usual distributed-under-the-GNU-GPL notice, and without +% a copy of the GPL itself. + +% This document is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. + +% You should have received a copy of the GNU General Public License +% along with GNU Emacs. If not, see . + +% Thanks to Cecilio Pardo, Mauro Aranda and Stephen Berman for +% the suggestions. + +%**start of header + +% User interface is `plain.tex' and macros described below +% +% \title{CARD TITLE}{for version 23} +% \section{NAME} +% optional paragraphs separated with \askip amount of vertical space +% \key{KEY-NAME} description of key or +% \mkey{M-x LONG-LISP-NAME} description of Elisp function +% +% \kbd{ARG} -- argument is typed literally + +\def\plainfmtname{plain} +\ifx\fmtname\plainfmtname +\else + \errmessage{This file requires `plain' format to be typeset correctly} + \endinput +\fi + +% PDF output layout. 0 for A4, 1 for letter (US), a `l' is added for +% a landscape layout. +\input pdflayout.sty +\pdflayout=(1) + +\input emacsver.tex + +\def\copyrightnotice{\penalty-1\vfill + \vbox{\smallfont\baselineskip=0.8\baselineskip\raggedcenter + Copyright \copyright\ \year\ Free Software Foundation, Inc.\break + For GNU Emacs version \versionemacs\break + Author W{\l}odek Bzyl (matwb@univ.gda.pl) + Translated by Elias Gabriel P{\'e}rez + + Released under the terms of the GNU General Public License + version 3 or later. + + For more Emacs documentation, and the \TeX{} source for this card, + see the Emacs distribution, + or {\tt https://www.gnu.org/software/emacs}\par}} + +\hsize 3.2in +\vsize 7.95in +\font\titlefont=cmss10 scaled 1200 +\font\headingfont=cmss10 +\font\smallfont=cmr6 +\font\smallsy=cmsy6 +\font\eightrm=cmr8 +\font\eightbf=cmbx8 +\font\eightit=cmti8 +\font\eighttt=cmtt8 +\font\eightmi=cmmi8 +\font\eightsy=cmsy8 +\font\eightss=cmss8 +\textfont0=\eightrm +\textfont1=\eightmi +\textfont2=\eightsy +\def\rm{\eightrm} \rm +\def\bf{\eightbf} +\def\it{\eightit} +\def\tt{\eighttt} +\def\ss{\eightss} +\baselineskip=0.8\baselineskip + +\newdimen\intercolumnskip % horizontal space between columns +\intercolumnskip=0.5in + +% The TeXbook, p. 257 +\let\lr=L \newbox\leftcolumn +\output={\if L\lr + \global\setbox\leftcolumn\columnbox \global\let\lr=R + \else + \doubleformat \global\let\lr=L\fi} +\def\doubleformat{\shipout\vbox{\makeheadline + \leftline{\box\leftcolumn\hskip\intercolumnskip\columnbox} + \makefootline} + \advancepageno} +\def\columnbox{\leftline{\pagebody}} + +\def\newcolumn{\vfil\eject} + +\def\bye{\par\vfil\supereject + \if R\lr \null\vfil\eject\fi + \end} + +\outer\def\title#1#2{{\titlefont\centerline{#1}}\vskip 1ex plus 0.5ex + \centerline{\ss#2} + \vskip2\baselineskip} + +\outer\def\section#1{\filbreak + \bskip + \leftline{\headingfont #1} + \askip} +\def\bskip{\vskip 2.5ex plus 0.25ex } +\def\askip{\vskip 0.75ex plus 0.25ex} + +\newdimen\defwidth \defwidth=0.25\hsize +\def\hang{\hangindent\defwidth} + +\def\textindent#1{\noindent\llap{\hbox to \defwidth{\tt#1\hfil}}\ignorespaces} +\def\key{\par\hangafter=0\hang\textindent} + +\def\mtextindent#1{\noindent\hbox{\tt#1\quad}\ignorespaces} +\def\mkey{\par\hangafter=1\hang\mtextindent} + +\def\kbd#{\bgroup\tt \let\next= } + +\newdimen\raggedstretch +\newskip\raggedparfill \raggedparfill=0pt plus 1fil +\def\nohyphens + {\hyphenpenalty10000\exhyphenpenalty10000\pretolerance10000} +\def\raggedspaces + {\spaceskip=0.3333em\relax + \xspaceskip=0.5em\relax} +\def\raggedright + {\raggedstretch=6em + \nohyphens + \rightskip=0pt plus \raggedstretch + \raggedspaces + \parfillskip=\raggedparfill + \relax} +\def\raggedcenter + {\raggedstretch=6em + \nohyphens + \rightskip=0pt plus \raggedstretch + \leftskip=\rightskip + \raggedspaces + \parfillskip=0pt + \relax} + +\chardef\\=`\\ + +\raggedright +\nopagenumbers +\parindent 0pt +\interlinepenalty=10000 +\hoffset -0.2in +%\voffset 0.2in + +%**end of header + + +\title{Tarjeta\ de\ Supervivencia\ para\ GNU\ \ Emacs}{para la versi{\'o}n \versionemacs} + +A continuaci{\'o}n, \kbd{C-z} significa presionar la tecla `\kbd{z}' mientras +mantienes presionada la tecla {\it Ctrl}. \kbd{M-z} significa +presionar la tecla `\kbd{z}' mientras mantienes presionada la tecla +{\it Meta\/} (tambi{\'e}n llamada {\it Alt\/} en algunos teclados) +o despu{\'e}s de presionar la tecla {\it Esc\/}. + +\section{Abrir Emacs} + +Para Abrir GNU Emacs, solo escriba su nombre: \kbd{emacs}. +Emacs divide sus marcos en varias {\'a}reas: + la barra del men{\'u}, + el {\'a}rea del buffer donde se edita el texto, + la barra modal (mode-line) describiendo el buffer en la ventana que est{\'a} encima de {\'e}l, + y en la {\'u}ltima l{\'i}nea el {\'a}rea del minibuffer o de mensajes. +\askip +\key{C-x C-c} salir de Emacs +\key{C-x C-f} editar archivo; este comando usa el minibuffer para leer + el nombre del archivo; usa este para crear nuevos archivos con tan solo + escribir el nombre del nuevo archivo que desee. +\key{C-x C-s} guardar archivo +\key{C-x k} eliminar un buffer +\key{C-g} en la mayor{\'i}a de los casos: cancela, detiene, aborta parcialmente + algo escrito o un comando ejecut{\'a}ndose +\key{C-x u} deshacer + +\section{Moverse} + +\key{C-l} desplazar l{\'i}nea actual al centro de la ventana +\key{C-x b} cambiar a otro buffer +\key{M-<} ir al comienzo del buffer +\key{M->} ir al final del buffer +\key{M-g M-g} ir a un n{\'u}mero de l{\'i}nea dado + +\section{M{\'u}ltiples Ventanas} + +\key{C-x 0} remover la ventana actual +\key{C-x 1} hacer que la ventana activa sea la {\'u}nica +\key{C-x 2} dividir ventana horizontalmente +\key{C-x 3} dividir ventana verticalmente +\key{C-x o} ir a otra ventana + +\section{Regiones} + +Emacs define una `regi{\'o}n' como el espacio entre la selecci{\'o}n y el +punto. Una selecci{\'o}n se establece con \kbd{C-{\it espacio}}. +El punto esta en la posici{\'o}n del cursor. +\askip +\key{M-h} seleccionar p{\'a}rrafo +\key{C-x h} seleccionar todo el buffer + +\section{Cortar y Pegar} + +\key{C-w} cortar regi{\'o}n +\key{M-w} copiar regi{\'o}n (al kill-ring) +\key{C-k} cortar desde el cursor hasta el final de la l{\'i}nea +\key{M-DEL} cortar palabra +\key{C-y} volver a pegar lo {\'u}ltimo que se cort{\'o} (\kbd{C-w C-y} la + combinaci{\'o}n podr{\'i}a usarse +para mover el texto) +\key{M-y} remplazar {\'u}ltimo pegado con la cortada anterior + +\section{Buscar} + +\key{C-s} buscar un texto +\key{C-r} buscar hacia atr{\'a}s un texto +\key{RET} salir de la b{\'u}squeda +\key{M-C-s} buscar con una expresi{\'o}n regular +\key{M-C-r} buscar hacia atr{\'a}s con una expresi{\'o}n regular +\askip +Usa otra vez \kbd{C-s} o \kbd{C-r} para repetir la b{\'u}squeda en +cualquier direcci{\'o}n. + +\section{Etiquetas} + +La tabla de etiquetas guarda la localizaci{\'o}n de funciones y definiciones +de procedimientos, variables globales, tipos de datos y cualquier otra +cosa conveniente. Para crear un archivo de tablas de etiquetas, escriba +`{\tt etags} {\it archivos\_a\_ingresar}' como un comando de shell. +\askip +\key{M-.} encontrar una definici{\'o}n +\key{M-,} volver a donde \kbd{M-.} fue invocado por {\'u}ltima vez +\mkey{M-x tags-query-replace} ejecutar query-replace en todos los archivos + registrados en la tabla de etiquetas + +\section{Compilar} + +\key{M-x compile} compilar c{\'o}digo en la ventana activa +\key{C-c C-c} ir al siguiente error del compilador, cuando est{\'e} + en la ventana de compilaci{\'o}n o +\key{C-x `} cuando est{\'e} en la ventana con el c{\'o}digo fuente + +\section{Dired, El Editor de Directorios} + +\key{C-x d} invocar Dired +\key{d} marcar este archivo para eliminaci{\'o}n +\key{\~{}} marcar todos los archivos de respaldo para eliminaci{\'o}n +\key{u} quitar marca de eliminaci{\'o}n +\key{x} eliminar los archivos marcados para eliminaci{\'o}n +\key{C} copiar archivo +\key{g} actualizar el buffer de Dired +\key{f} abrir el archivo descrito en la l{\'i}nea actual +\key{s} cambiar entre el orden alfab{\'e}tico de fecha y hora + +\section{Lectura y env{\'i}o de correo electr{\'o}nico} + +\key{M-x rmail} empezar a leer el correo +\key{q} dejar de leer el correo +\key{h} mostrar encabezados +\key{d} marcar el mensaje actual para eliminaci{\'o}n +\key{x} eliminar todos los mensajes marcados para eliminaci{\'o}n + +\key{C-x m} redactar un mensaje +\key{C-c C-c} enviar el mensaje y cambiar a otro buffer +\key{C-c C-f C-c} ir al campo de encabezado 'Cc' y crea uno + si no hay ninguno + +\section{Miscel{\'a}neos} + +\key{M-q} rellenar p{\'a}rrafo +\key{M-/} expandir la palabra anterior din{\'a}micamente +\key{C-z} minimizar (suspender) Emacs cuando se est{\'a} ejecutando + gr{\'a}ficamente o en terminal, respectivamente +\mkey{M-x revert-buffer} actualizar texto del buffer acorde al archivo + guardado + +\section{Buscar y Remplazar} + +\key{M-\%} buscar y remplazar de forma interactiva +\key{M-C-\%} buscar usando expresiones regulares +\askip +Las respuestas v{\'a}lidas en query-replace son +\askip +\key{SPC} remplazar este y pasa al siguiente +\key{,} remplazar este pero no te muevas +\key{DEL} saltar al siguiente sin remplazar +\key{!} remplazar todas las coincidencias restantes +\key{\^{}} volver a la coincidencia anterior +\key{RET} salir de query-replace +\key{C-r} entrar a la edici{\'o}n recursiva (\kbd{M-C-c} para salir) + +\section{Expresiones regulares} + +\key{. {\rm(dot)}} cualquier car{\'a}cter individual excepto una nueva l{\'i}nea +\key{*} cero o m{\'a}s repeticiones +\key{+} una o m{\'a}s repeticiones +\key{?} cero o una repetici{\'o}n +\key{[$\ldots$]} denota una clase de car{\'a}cter a coincidir +\key{[\^{}$\ldots$]} niega la clase + +\key{\\{\it c}} mantener caracteres que de otra manera tendr{\'i}an un + significado especial en expresiones regulares + +\key{$\ldots$\\|$\ldots$\\|$\ldots$} coincide con una de las + alternativas (``or'') +\key{\\( $\ldots$ \\)} agrupa una serie de patrones de elementos a un + solo elemento +\key{\\{\it n}} mismo texto como del grupo n{\'u}mero {\it n\/} + +\key{\^{}} coincidencias con el inicio de la l{\'i}nea +\key{\$} coincidencias al final de la l{\'i}nea + +\key{\\w} encuentra un car{\'a}cter de una palabra +\key{\\W} encuentra un car{\'a}cter de una palabra +\key{\\<} encuentra al comienzo de una palabra +\key{\\>} encuentra al final de una palabra +\key{\\b} encuentra en el salto de palabra +\key{\\B} encuentra en un no salto de palabra + +\section{Registros} + +\key{C-x r s} guardar selecci{\'o}n en el registro +\key{C-x r i} insertar el contenido del registro en el buffer + +\key{C-x r SPC} guardar el valor del cursor en el registro +\key{C-x r j} saltar al punto guardado en el registro + +\section{Rect{\'a}ngulos} + +\key{C-x r r} copiar rect{\'a}ngulo al registro +\key{C-x r k} cortar rect{\'a}ngulo +\key{C-x r y} pegar rect{\'a}ngulo +\key{C-x r t} a{\~n}adir un prefijo a cada l{\'i}nea con un texto + +\key{C-x r o} abrir rect{\'a}ngulo, desplazar el texto hacia la derecha +\key{C-x r c} dejar rect{\'a}ngulo en blanco + +\section{Shells} + +\key{M-x shell} iniciar un shell dentro de Emacs +\key{M-!} ejecutar un comando de shell dentro de Emacs +\key{M-|} ejecutar un comando de shell de una regi{\'o}n +\key{C-u M-|} filtrar regi{\'o}n a trav{\'e}s de un comando de shell + +\section{Revisi{\'o}n Ortogr{\'a}fica} + +\key{M-\$} comprobar la ortograf{\'i}a de la palabra en el cursor +\mkey{M-x ispell-region} comprobar la ortograf{\'i}a de todas las palabras de + la selecci{\'o}n +\mkey{M-x ispell-buffer} comprobar la ortograf{\'i}a de todo el buffer + +\section{Caracteres Internacionales} + +\key{C-x RET C-\\} seleccionar y activar el m{\'e}todo de entrada para el + buffer actual +\key{C-\\} activar o desactivar el m{\'e}todo de entrada +\mkey{M-x list-input-methods} mostrar todos los m{\'e}todos de entrada +\mkey{M-x set-language-environment} especificar idioma principal + +\key{C-x RET c} establecer el sistema de codificaci{\'o}n para el siguiente comando +\mkey{M-x find-file-literally} abrir archivo sin conversi{\'o}n + de ning{\'u}n tipo + +\mkey{M-x list-coding-systems} mostrar todos los sistemas de codificaci{\'o}n +\mkey{M-x prefer-coding-system} escoger el sistema de codificaci{\'o}n preferido + +\section{Macros del teclado} + +\key{C-x (} empezar a definir una macro +\key{C-x )} terminar de definir la macro +\key{C-x e} ejecutar la {\'u}ltima macro definida +\key{C-u C-x (} a{\~n}adir a la {\'u}ltima macro definida +\mkey{M-x name-last-kbd-macro} nombrar {\'u}ltima macro definida + +\section{Personalizaci{\'o}n sencilla} + +\key{M-x customize} personalizar variables y caras + +\section{Obtener Ayuda} + +Emacs completa los comandos por usted. Escribiendo \kbd{M-x} +{\it tab\/} o {\it espacio\/} proporciona una lista de comandos de Emacs. +\askip +\key{C-h} ayuda de Emacs +\key{C-h t} ejecutar el tutorial de Emacs +\key{C-h i} entrar a Info, el navegador de documentaci{\'o}n +\key{C-h a} mostrar comandos que coinciden con una string (apropos) +\key{C-h k} mostrar documentaci{\'o}n de la funci{\'o}n invocada por la + pulsaci{\'o}n de tecla +\askip +Emacs se mete en diferentes {\it modos}, cada uno de los cuales personaliza +Emacs para editar texto de un tipo particular. La l{\'i}nea modal (mode-line) +contiene los nombres de los modos actuales, entre par{\'e}ntesis. +\askip +\key{C-h m} obtener informaci{\'o}n espec{\'i}fica del modo + +\copyrightnotice + +\bye + +% Local variables: +% compile-command: "pdftex survival" +% End: commit 00ff7d7503e301aa1c005988d37555fe9add7a6a Author: Elías Gabriel Pérez Date: Sat Feb 22 12:06:19 2025 -0600 Add Spanish translation for refcard.tex * etc/refcards/es-refcard.tex: New file. (Bug#76300) diff --git a/etc/refcards/es-refcard.tex b/etc/refcards/es-refcard.tex new file mode 100644 index 00000000000..971c8bb80f0 --- /dev/null +++ b/etc/refcards/es-refcard.tex @@ -0,0 +1,717 @@ +% Reference Card for GNU Emacs + +% Copyright (C) 1987, 1993, 1996--1997, 2001--2025 Free Software +% Foundation, Inc. + +% Author: Stephen Gildea +% Spanish translation: Elias Gabriel Perez + +% This document is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% As a special additional permission, you may distribute reference cards +% printed, or formatted for printing, with the notice "Released under +% the terms of the GNU General Public License version 3 or later" +% instead of the usual distributed-under-the-GNU-GPL notice, and without +% a copy of the GPL itself. + +% This document is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. + +% You should have received a copy of the GNU General Public License +% along with GNU Emacs. If not, see . + + +% This file is intended to be processed by plain TeX (TeX82). +% +% The final reference card has six columns, three on each side. +% This file can be used to produce it in any of three ways: +% 1 column per page +% produces six separate pages, each of which needs to be reduced to 80%. +% This gives the best resolution. +% 2 columns per page +% produces three already-reduced pages. +% You will still need to cut and paste. +% 3 columns per page +% produces two pages which must be printed sideways to make a +% ready-to-use 8.5 x 11 inch reference card. +% For this you need a dvi device driver that can print sideways. +% Which mode to use is controlled by setting \columnsperpage. +% +% To compile and print this document: +% tex refcard.tex +% dvips -t landscape refcard.dvi + +% Thanks to Cecilio Pardo, Mauro Aranda and Stephen Berman for +% the suggestions. + +%**start of header +\newcount\columnsperpage +\newcount\letterpaper + +% This file can be printed with 1, 2, or 3 columns per page. +% Specify how many you want here. +\columnsperpage=3 + +% Set letterpaper to 0 for A4 paper, 1 for letter (US) paper. Useful +% only when columnsperpage is 2 or 3. +\letterpaper=1 + +% PDF output layout. 0 for A4, 1 for letter (US), a `l' is added for +% a landscape layout. +\input pdflayout.sty +\pdflayout=(1l) + +% Nothing else needs to be changed below this line. + +\input emacsver.tex + +\def\shortcopyrightnotice{\vskip 1ex plus 2 fill + \centerline{\small \copyright\ \year\ Free Software Foundation, Inc. + Permissions on back.}} + +\def\copyrightnotice{ +\vskip 1ex plus 2 fill\begingroup\small +\centerline{Copyright \copyright\ \year\ Free Software Foundation, Inc.} +\centerline{For GNU Emacs version \versionemacs} +\centerline{Designed by Stephen Gildea} +\centerline{Translated by Elias Gabriel P{\'e}rez} + +Released under the terms of the GNU General Public License version 3 or later. + +For more Emacs documentation, and the \TeX{} source for this card, +see the Emacs distribution, or {\tt https://www.gnu.org/software/emacs} +\endgroup} + +% make \bye not \outer so that the \def\bye in the \else clause below +% can be scanned without complaint. +\def\bye{\par\vfill\supereject\end} + +\newdimen\intercolumnskip %horizontal space between columns +\newbox\columna %boxes to hold columns already built +\newbox\columnb + +\def\ncolumns{\the\columnsperpage} + +\message{[\ncolumns\space + column\if 1\ncolumns\else s\fi\space per page]} + +\def\scaledmag#1{ scaled \magstep #1} + +% This multi-way format was designed by Stephen Gildea October 1986. +% Note that the 1-column format is fontfamily-independent. +\if 1\ncolumns %one-column format uses normal size + \hsize 4in + \vsize 10in + \voffset -.7in + \font\titlefont=\fontname\tenbf \scaledmag3 + \font\headingfont=\fontname\tenbf \scaledmag2 + \font\smallfont=\fontname\sevenrm + \font\smallsy=\fontname\sevensy + + \footline{\hss\folio} + \def\makefootline{\baselineskip10pt\hsize6.5in\line{\the\footline}} +\else %2 or 3 columns uses prereduced size + \hsize 3.2in + \if 1\the\letterpaper + \vsize 7.95in + \else + \vsize 7.65in + \fi + \hoffset -.75in + \voffset -.745in + \font\titlefont=cmbx10 \scaledmag2 + \font\headingfont=cmbx10 \scaledmag1 + \font\smallfont=cmr6 + \font\smallsy=cmsy6 + \font\eightrm=cmr8 + \font\eightbf=cmbx8 + \font\eightit=cmti8 + \font\eighttt=cmtt8 + \font\eightmi=cmmi8 + \font\eightsy=cmsy8 + \textfont0=\eightrm + \textfont1=\eightmi + \textfont2=\eightsy + \def\rm{\eightrm} + \def\bf{\eightbf} + \def\it{\eightit} + \def\tt{\eighttt} + \if 1\the\letterpaper + \normalbaselineskip=.8\normalbaselineskip + \else + \normalbaselineskip=.7\normalbaselineskip + \fi + \normallineskip=.8\normallineskip + \normallineskiplimit=.8\normallineskiplimit + \normalbaselines\rm %make definitions take effect + + \if 2\ncolumns + \let\maxcolumn=b + \footline{\hss\rm\folio\hss} + \def\makefootline{\vskip 2in \hsize=6.86in\line{\the\footline}} + \else \if 3\ncolumns + \let\maxcolumn=c + \nopagenumbers + \else + \errhelp{You must set \columnsperpage equal to 1, 2, or 3.} + \errmessage{Illegal number of columns per page} + \fi\fi + + \intercolumnskip=.46in + \def\abc{a} + \output={% %see The TeXbook page 257 + % This next line is useful when designing the layout. + %\immediate\write16{Column \folio\abc\space starts with \firstmark} + \if \maxcolumn\abc \multicolumnformat \global\def\abc{a} + \else\if a\abc + \global\setbox\columna\columnbox \global\def\abc{b} + %% in case we never use \columnb (two-column mode) + \global\setbox\columnb\hbox to -\intercolumnskip{} + \else + \global\setbox\columnb\columnbox \global\def\abc{c}\fi\fi} + \def\multicolumnformat{\shipout\vbox{\makeheadline + \hbox{\box\columna\hskip\intercolumnskip + \box\columnb\hskip\intercolumnskip\columnbox} + \makefootline}\advancepageno} + \def\columnbox{\leftline{\pagebody}} + + \def\bye{\par\vfill\supereject + \if a\abc \else\null\vfill\eject\fi + \if a\abc \else\null\vfill\eject\fi + \end} +\fi + +% we won't be using math mode much, so redefine some of the characters +% we might want to talk about +\catcode`\^=12 +\catcode`\_=12 + +\chardef\\=`\\ +\chardef\{=`\{ +\chardef\}=`\} + +\hyphenation{mini-buf-fer} + +\parindent 0pt +\parskip 1ex plus .5ex minus .5ex + +\def\small{\smallfont\textfont2=\smallsy\baselineskip=.8\baselineskip} + +% newcolumn - force a new column. Use sparingly, probably only for +% the first column of a page, which should have a title anyway. +\outer\def\newcolumn{\vfill\eject} + +% title - page title. Argument is title text. +\outer\def\title#1{{\titlefont\centerline{#1}}\vskip 1ex plus .5ex} + +% section - new major section. Argument is section name. +\outer\def\section#1{\par\filbreak + \vskip 3ex plus 2ex minus 2ex {\headingfont #1}\mark{#1}% + \vskip 2ex plus 1ex minus 1.5ex} + +\newdimen\keyindent + +% beginindentedkeys...endindentedkeys - key definitions will be +% indented, but running text, typically used as headings to group +% definitions, will not. +\def\beginindentedkeys{\keyindent=1em} +\def\endindentedkeys{\keyindent=0em} +\endindentedkeys + +% paralign - begin paragraph containing an alignment. +% If an \halign is entered while in vertical mode, a parskip is never +% inserted. Using \paralign instead of \halign solves this problem. +\def\paralign{\vskip\parskip\halign} + +% \<...> - surrounds a variable name in a code example +\def\<#1>{{\it #1\/}} + +% kbd - argument is characters typed literally. Like the Texinfo command. +\def\kbd#1{{\tt#1}\null} %\null so not an abbrev even if period follows + +% beginexample...endexample - surrounds literal text, such a code example. +% typeset in a typewriter font with line breaks preserved +\def\beginexample{\par\leavevmode\begingroup + \obeylines\obeyspaces\parskip0pt\tt} +{\obeyspaces\global\let =\ } +\def\endexample{\endgroup} + +% key - definition of a key. +% \key{description of key}{key-name} +% prints the description left-justified, and the key-name in a \kbd +% form near the right margin. +\def\key#1#2{\leavevmode\hbox to \hsize{\vtop + {\hsize=.75\hsize\rightskip=1em + \hskip\keyindent\relax#1}\kbd{#2}\hfil}} + +\newbox\metaxbox +\setbox\metaxbox\hbox{\kbd{M-x }} +\newdimen\metaxwidth +\metaxwidth=\wd\metaxbox + +% metax - definition of a M-x command. +% \metax{description of command}{M-x command-name} +% Tries to justify the beginning of the command name at the same place +% as \key starts the key name. (The "M-x " sticks out to the left.) +\def\metax#1#2{\leavevmode\hbox to \hsize{\hbox to .75\hsize + {\hskip\keyindent\relax#1\hfil}% + \hskip -\metaxwidth minus 1fil + \kbd{#2}\hfil}} + +% threecol - like "key" but with two key names. +% for example, one for doing the action backward, and one for forward. +\def\threecol#1#2#3{\hskip\keyindent\relax#1\hfil&\kbd{#2}\hfil\quad + &\kbd{#3}\hfil\quad\cr} + +%**end of header + + +\title{GNU Emacs: Tarjeta de referencia} + +\centerline{(para la versi{\'o}n: \versionemacs)} + +\section{Notaci{\'o}n de combinaciones de teclas} + +Las notaciones de combinaciones de teclas en Emacs, \kbd{C-x} +es \kbd{Ctrl+X}; \kbd{M-x} es usualmente \kbd{Alt+X}; \kbd{S-x} es +\kbd{Shift+X}; y \kbd{C-M-x} es \kbd{Ctrl+Alt+X}, etc. + +\section{Saliendo de Emacs} + +\key{minimizar (o suspender en la terminal)}{C-z} +\key{cerrar Emacs}{C-x C-c} + +\section{Archivos} + +\key{{\bf abrir} un archivo en Emacs}{C-x C-f} +\key{{\bf guardar} un archivo (en el disco)}{C-x C-s} +\key{guardar {\bf todos} los archivos}{C-x s} +\key{{\bf insertar} contenidos de otro archivo en este buffer}{C-x i} +\key{remplazar archivo por otro}{C-x C-v} +\key{guardar buffer a un archivo en especifico}{C-x C-w} +\key{alternar el estado de solo-lectura del buffer}{C-x C-q} + +\section{Obtener Ayuda} + +El sistema de ayuda es simple. Teclee \kbd{C-h} (o \kbd{F1}) y siga +las opciones. Si est{\'a} usted empezando, teclee \kbd{C-h t} para ir al +{\bf tutorial}. + +\key{quitar ventana de ayuda}{C-x 1} +\key{desplazarse por la ventana de ayuda}{C-M-v} + +\key{apropos: mostrar comandos que coinciden con una cadena caracteres (string)}{C-h a} +\key{describir la funci{\'o}n asociada a una tecla}{C-h k} +\key{describir una funci{\'o}n}{C-h f} +\key{obtener informaci{\'o}n espec{\'i}fica del modo}{C-h m} + +\section{Recuperaci{\'o}n de errores} + +\key{{\bf abortar} acci{\'o}n o un comando ejecut{\'a}ndose}{C-g} +\metax{{\bf recuperar} archivos perdidos}{M-x recover-session} +\key{por cierre inesperado}{} +\metax{{\bf deshacer} un cambio no deseado}{C-x u, C-_ {\rm o} C-/} +\metax{restaurar buffer a su contenido actual}{M-x revert-buffer} +\key{recentrar pantalla}{C-l} + +\section{B{\'u}squeda incremental} + +\key{buscar hacia adelante}{C-s} +\key{buscar hacia atr{\'a}s}{C-r} +\key{buscar una expresi{\'o}n regular}{C-M-s} +\key{buscar inversamente una expresi{\'o}n regular}{C-M-r} + +\key{seleccionar anterior cadena de caracteres de la b{\'u}squeda}{M-p} +\key{seleccionar siguiente cadena de caracteres de la b{\'u}squeda}{M-n} +\key{salir de la b{\'u}squeda incremental}{RET} +\key{deshacer efecto del {\'u}ltimo car{\'a}cter}{DEL} +\key{abortar b{\'u}squeda actual}{C-g} + +Usa \kbd{C-s} o \kbd{C-r} de nuevo para repetir la b{\'u}squeda en cualquier posici{\'o}n. +Si Emacs sigue buscando, \kbd{C-g} cancela solo la parte no coincidente. + +\shortcopyrightnotice + +\newcolumn +\section{Movimiento} + +\paralign to \hsize{#\tabskip=10pt plus 1 fil&#\tabskip=0pt&#\cr +\threecol{{\bf entidad a trasladar}}{{\bf atr{\'a}s}}{{\bf adelante}} +\threecol{car{\'a}cter}{C-b}{C-f} +\threecol{palabra}{M-b}{M-f} +\threecol{l{\'i}nea}{C-p}{C-n} +\threecol{ir al comienzo de la l{\'i}nea (o hacia al final)}{C-a}{C-e} +\threecol{oraci{\'o}n}{M-a}{M-e} +\threecol{p{\'a}rrafo}{M-\{}{M-\}} +\threecol{p{\'a}gina}{C-x [}{C-x ]} +\threecol{expresi{\'o}n s (sexp)}{C-M-b}{C-M-f} +\threecol{funci{\'o}n}{C-M-a}{C-M-e} +\threecol{ir al comienzo del buffer (o hacia al final)}{M-<}{M->} +} + +\key{desplazarse hacia la siguiente pantalla}{C-v} +\key{desplazarse hacia la anterior pantalla}{M-v} +\key{desplazarse hacia la izquierda}{C-x <} +\key{desplazarse hacia la derecha}{C-x >} +\key{desplazar l{\'i}nea actual hacia el centro, arriba o abajo}{C-l} + +\key{ir hacia una l{\'i}nea}{M-g g} +\key{ir hacia un car{\'a}cter}{M-g c} +\key{volver a la sangr{\'i}a}{M-m} + +\section{Cortar y Eliminar} + +\paralign to \hsize{#\tabskip=10pt plus 1 fil&#\tabskip=0pt&#\cr +\threecol{{\bf entidad a cortar}}{{\bf hacia atr{\'a}s}}{{\bf hacia adelante}} +\threecol{car{\'a}cter (eliminar, no cortar)}{DEL}{C-d} +\threecol{palabra}{M-DEL}{M-d} +\threecol{l{\'i}nea (hasta el final)}{M-0 C-k}{C-k} +\threecol{sentencia}{C-x DEL}{M-k} +\threecol{expresi{\'o}n s (sexp)}{M-- C-M-k}{C-M-k} +} + +\key{cortar {\bf regi{\'o}n}}{C-w} +\key{copiar regi{\'o}n}{M-w} +\key{cortar a la siguiente ocurrencia del {\it car{\'a}cter}}{M-z {\it car{\'a}cter}} + +\key{pegar de nuevo lo {\'u}ltimo que se cort{\'o}}{C-y} +\key{remplazar pegado reci{\'e}n con lo {\'u}ltimo que se cort{\'o}}{M-y} + +\section{Selecci{\'o}n} + +\key{poner selecci{\'o}n aqu{\'i}}{C-@ {\rm o} C-SPC} +\key{intercambiar la posici{\'o}n del cursor y de la selecci{\'o}n}{C-x C-x} + +\key{poner selecci{\'o}n {\it arg\/} {\bf palabras} delante}{M-@} +\key{seleccionar {\bf p{\'a}rrafo}}{M-h} +\key{seleccionar {\bf p{\'a}gina}}{C-x C-p} +\key{seleccionar {\bf sexp}}{C-M-@} +\key{seleccionar {\bf funci{\'o}n}}{C-M-h} +\key{seleccionar todo el {\bf buffer}}{C-x h} + +\section{Buscar y Reemplazar} + +\key{remplazar interactivamente un texto (string)}{M-\%} +% query-replace-regexp is bound to C-M-% but that can't be typed on +% consoles. +\metax{usando expresiones regulares}{M-x query-replace-regexp} + +Las respuestas v{\'a}lidas en el modo query-replace son: + +\key{{\bf remplazar} este, ve hacia el siguiente}{SPC {\rm o} y} +\key{remplazar este, no te muevas}{,} +\key{{\bf saltar} al siguiente sin remplazar}{DEL {\rm or} n} +\key{remplazar todas las coincidencias restantes}{!} +\key{{\bf volver} a la coincidencia anterior}{^} +\key{{\bf salir} de query-replace}{RET} +\key{editar recursivamente(\kbd{C-M-c} para salir)}{C-r} + +\newcolumn +\section{M{\'u}ltiple Ventanas} + +Cuando dos comandos son mostrados, el segundo es un comando similar para +un frame que para una ventana. + +{\setbox0=\hbox{\kbd{0}}\advance\hsize by 0\wd0 +\paralign to \hsize{#\tabskip=10pt plus 1 fil&#\tabskip=0pt&#\cr +\threecol{eliminar todas las otras ventanas}{C-x 1\ \ \ \ }{C-x 5 1} +\threecol{dividir ventana, por debajo y encima}{C-x 2\ \ \ \ }{C-x 5 2} +\threecol{eliminar esta ventana}{C-x 0\ \ \ \ }{C-x 5 0} +}} +\key{dividir ventana a la mitad}{C-x 3} + +\key{desplazar otra ventana}{C-M-v} + +{\setbox0=\hbox{\kbd{0}}\advance\hsize by 0\wd0 +\paralign to \hsize{#\tabskip=10pt plus 1 fil&#\tabskip=0pt&#\cr +\threecol{cambiar cursor a otra ventana}{C-x o}{C-x 5 o} + +\threecol{seleccionar buffer en otra ventana}{C-x 4 b}{C-x 5 b} +\threecol{mostrar buffer en otra ventana}{C-x 4 C-o}{C-x 5 C-o} +\threecol{buscar archivo en otra ventana}{C-x 4 f}{C-x 5 f} +\threecol{buscar archivo de solo-lectura}{C-x 4 r}{C-x 5 r} +\threecol{en otra ventana}{}{} +\threecol{abrir Dired en otra ventana}{C-x 4 d}{C-x 5 d} +\threecol{buscar etiqueta en otra ventana}{C-x 4 .}{C-x 5 .} +}} + +\key{hacer la ventana m{\'a}s alta}{C-x ^} +\key{hacer la ventana m{\'a}s estrecha}{C-x \{} +\key{hacer la ventana m{\'a}s ancha}{C-x \}} + +\section{Formato y Sangr{\'i}as} + +\key{sangrar {\bf l{\'i}nea} actual (dependiente del modo)}{TAB} +\key{sangrar {\bf regi{\'o}n} (dependiente del modo)}{C-M-\\} +\key{sangrar {\bf sexp} (dependiente del modo)}{C-M-q} +\key{sangrar regi{\'o}n r{\'i}gidamente en {\it arg\/} columnas}{C-x TAB} +\key{sangrar para comentar}{M-;} + +\key{insertar una nueva l{\'i}nea delante del cursor}{C-o} +\key{mover resto de la l{\'i}nea verticalmente hacia abajo}{C-M-o} +\key{eliminar l{\'i}neas en blanco alrededor del cursor}{C-x C-o} +\key{unir l{\'i}nea con la anterior (con arg, next)}{M-^} +\key{eliminar todos los espacios en blanco alrededor del cursor}{M-\\} +\key{poner exactamente un espacio en el cursor}{M-SPC} + +\key{rellenar p{\'a}rrafo}{M-q} +\key{establecer la columna de relleno en {\it arg}}{C-x f} +\key{establecer el prefijo con el que comienza cada l{\'i}nea}{C-x .} + +\section{Cambio de Case} + +\key{poner la palabra en may{\'u}sculas}{M-u} +\key{poner la palabra en min{\'u}sculas}{M-l} +\key{poner la palabra con may{\'u}scula inicial}{M-c} + +\key{poner la regi{\'o}n en may{\'u}sculas}{C-x C-u} +\key{poner la regi{\'o}n en min{\'u}sculas}{C-x C-l} + +\newcolumn +\title{GNU Emacs: Tarjeta de referencia} + +\section{El Minibuffer} + +Las siguientes teclas est{\'a}n definidas en el minibuffer. + +\key{completar tanto sea posible}{TAB} +\key{completar hasta una palabra}{SPC} +\key{completar y ejecutar}{RET} +\key{mostrar posibles candidatos}{?} +\key{recuperar la entrada anterior del minibuffer}{M-p} +\key{recuperar la entrada posterior del minibuffer o la predeterminada}{M-n} +\key{buscar hacia atr{\'a}s con regexp a trav{\'e}s del historial}{M-r} +\key{buscar hacia adelante con regexp a trav{\'e}s del historial}{M-s} +\key{abortar comando}{C-g} + +Presiona \kbd{C-x ESC ESC} para editar y repetir el {\'u}ltimo comando que us{\'o} +el minibuffer. Presiona \kbd{F10} para activar los elementos de la barra del +men{\'u} en terminales de texto. + +\section{buffers} + +\key{seleccionar otro buffer}{C-x b} +\key{listar todos los buffers}{C-x C-b} +\key{eliminar un buffer}{C-x k} + +\section{Transponiendo} + +\key{transponer {\bf caracteres}}{C-t} +\key{transponer {\bf palabras}}{M-t} +\key{transponer {\bf l{\'i}neas}}{C-x C-t} +\key{transponer {\bf sexps}}{C-M-t} + +\section{Revisi{\'o}n ortogr{\'a}fica} + +\key{comprobar ortograf{\'i}a de la presente palabra}{M-\$} +\metax{comprobar ortograf{\'i}a de todas}{M-x ispell-region} +\metax{las palabras en la regi{\'o}n}{} +\metax{comprobar la ortograf{\'i}a de todo el buffer}{M-x ispell-buffer} +\metax{alternar la revisi{\'o}n ortogr{\'a}fica}{M-x flyspell-mode} + +\section{Etiquetas (Tags)} + +\key{buscar una etiqueta (una definici{\'o}n)}{M-.} +\metax{especificar un nuevo archivo}{M-x visit-tags-table} +\metax{de etiquetas}{} + +\metax{buscar con regexp en todos los}{M-x tags-search} +\metax{archivos de la tabla de etiquetas}{} +\metax{ejecutar query-replace en}{M-x tags-query-replace} +\metax{todos los archivos}{} + +\shortcopyrightnotice + +\section{Shells} + +\key{ejecutar un comando de shell}{M-!} +\key{ejecutar un comando de shell}{M-\&} +\key{asincr{\'o}nicamente}{} +\key{ejecutar un comando de shell en la regi{\'o}n}{M-|} +\key{filtrar regi{\'o}n a trav{\'e}s de un comando de shell}{C-u M-|} +\key{iniciar un shell en una ventana \kbd{*shell*}}{M-x shell} + +\section{Rect{\'a}ngulos} + +\key{copiar rect{\'a}ngulo al registro}{C-x r r} +\key{cortar rect{\'a}ngulo}{C-x r k} +\key{pegar rect{\'a}ngulo}{C-x r y} +\key{abrir rect{\'a}ngulo, desplazando el texto hacia la derecha}{C-x r o} +\key{poner rect{\'a}ngulo en blanco}{C-x r c} +\key{anteponer una cadena (string) a cada l{\'i}nea}{C-x r t} + +\section{Abreviaturas (Abbrevs)} + +\key{a{\~n}adir abreviatura global}{C-x a g} +\key{a{\~n}adir abreviatura local del modo}{C-x a l} +\key{a{\~n}adir expansi{\'o}n global}{C-x a i g} +\key{para esta abreviatura}{} +\key{a{\~n}adir expansi{\'o}n local del modo para est{\'a} abreviatura}{C-x a i l} +\key{expl{\'i}citamente expandir abreviatura}{C-x a e} + +\key{expandir palabra anterior din{\'a}micamente}{M-/} + +\section{Miscel{\'a}neos} + +\key{inserci{\'o}n num{\'e}rica}{C-u {\it num}} +\key{inserci{\'o}n negativa}{M--} +\key{inserci{\'o}n citada}{C-q {\it car}} + +\section{Expresiones regulares} + +\key{cualquier {\'u}nico c{\'a}racter excepto una nueva l{\'i}nea}{. {\rm(dot)}} +\key{ninguna o m{\'a}s repeticiones}{*} +\key{una o m{\'a}s repeticiones}{+} +\key{ninguna o una repetici{\'o}n}{?} +\key{proteger car{\'a}cteres especiales}{\\} +\key{proteger car{\'a}cter especial de expresi{\'o}n regular {\it c\/}}{\\{\it c}} +\key{alternativos (``or'')}{\\|} +\key{agrupar}{\\( {\rm$\ldots$} \\)} +\key{agrupaci{\'o}n t{\'i}mida}{\\(?: {\rm$\ldots$} \\)} +\key{agrupaci{\'o}n numerada expl{\'i}cita}{\\(?NUM: {\rm$\ldots$} \\)} +\key{mismo texto del grupo n{\'u}mero {\it n\/}}{\\{\it n}} +\key{en el salto de palabra}{\\b} +\key{no en el salto de palabra}{\\B} + +\paralign to \hsize{#\tabskip=10pt plus 1 fil&#\tabskip=0pt&#\cr +\threecol{{\bf entidad}}{{\bf comienzo}}{{\bf final}} +\threecol{l{\'i}nea}{^}{\$} +\threecol{palabra}{\\<}{\\>} +\threecol{s{\'i}mbolo}{\\_<}{\\_>} +\threecol{buffer}{\\`}{\\'} +%% FIXME: "`" and "'" isn't displayed correctly in the output PDF file + +\threecol{{\bf clase del c{\'a}racter}}{{\bf {\'e}stas}}{{\bf otras}} +\threecol{establecer expl{\'i}citamente}{[ {\rm$\ldots$} ]}{[^ {\rm$\ldots$} ]} +\threecol{car{\'a}cter de sintaxis de palabra}{\\w}{\\W} +\threecol{car{\'a}cter con sintaxis {\it c}}{\\s{\it c}}{\\S{\it c}} +\threecol{car{\'a}cter con categor{\'i}a {\it c}}{\\c{\it c}}{\\C{\it c}} +} + +\section{Caracteres internacionales} + +\key{especificar idioma principal}{C-x RET l} +\metax{mostrar todos los m{\'e}todos}{M-x list-input-methods} +\key{de entrada}{} +\key{activar o desactivar el m{\'e}todo de entrada}{C-\\} +\key{establecer el sistema de codificaci{\'o}n para el siguiente comando}{C-x RET c} +\metax{mostrar todos los sistemas}{M-x list-coding-systems} +\key{de codificaci{\'o}n}{} +\metax{elegir el sistema de codificaci{\'o}n preferido}{M-x prefer-coding-system} + +\newcolumn +\title{GNU Emacs: Tarjeta de referencia} +\section{Info} + +\key{entrar al lector de documentaci{\'o}n de Info}{C-h i} +\key{buscar funci{\'o}n o variable especificada en Info}{C-h S} +\beginindentedkeys + +Moverse dentro de un nodo: + +\key{desplazarse hacia adelante}{SPC} +\key{desplazarse en reversa}{DEL} +\key{comienzo del nodo}{b} + +Moverse entre nodos: + +\key{{\bf siguiente} nodo}{n} +\key{nodo {\bf anterior}}{p} +\key{moverse por {\bf arriba}}{u} +\key{seleccionar un elemento del men{\'u}}{m} +\key{por el nombre}{} +\key{seleccionar el elemento {\it n\/} del men{\'u}}{{\it n}} +\key{por n{\'u}mero (1--9)}{} +\key{seguir referencia cruzada (regresar con \kbd{l})}{f} +\key{regresar al {\'u}ltimo nodo que viste}{l} +\key{volver al nodo de directorio}{d} +\key{ir al nodo superior del archivo Info}{t} +\key{ir a cualquier nodo por nombre}{g} + +Otros: + +\key{ir al {\bf tutorial} de Info}{h} +\key{buscar un tema en los {\'i}ndices}{i} +\key{buscar nodos para expresiones regulares}{s} +\key{{\bf salir} de Info}{q} +\endindentedkeys + +\section{Registros} + +\key{guardar regi{\'o}n en el registro}{C-x r s} +\key{insertar contenidos del registro al buffer}{C-x r i} + +\key{guardar valor del cursor en el registro}{C-x r SPC} +\key{saltar al punto guardado en el registro}{C-x r j} + +\section{Macros del teclado} + +\key{{\bf comenzar} a definir una macro}{C-x (} +\key{{\bf terminar} la definici{\'o}n de la macro}{C-x )} +\key{{\bf ejecutar} {\'u}ltima macro definida}{C-x e} +\key{a{\~n}adir a la {\'u}ltima macro definida}{C-u C-x (} +\metax{nombrar {\'u}ltima macro definida}{M-x name-last-kbd-macro} +\metax{insertar macro como c{\'o}digo Lisp}{M-x insert-kbd-macro} +\key{en el buffer}{} + +\copyrightnotice +\newcolumn +\section{Comandos para Emacs Lisp} + +\key{evaluar {\bf sexp} antes del cursor}{C-x C-e} +\key{evaluar funci{\'o}n ({\bf defun}) actual}{C-M-x} +\metax{evaluar toda la {\bf regi{\'o}n}}{M-x eval-region} +\key{leer y evaluar en minibuffer}{M-:} +\metax{cargar una librer{\'i}a Lisp}{M-x load-library} +\key{desde {\bf load-path}}{} + +\section{Personalizaci{\'o}n sencilla} + +\metax{personalizar variables y caras}{M-x customize} + +% The intended audience here is the person who wants to make simple +% customizations and knows Lisp syntax. + +Creaci{\'o}n de combinaciones de teclas globales en Emacs Lisp (ejemplos): + +\beginexample% +(global-set-key (kbd "C-c g") 'search-forward) +(global-set-key (kbd "M-\#") 'query-replace-regexp) +\endexample + +\section{Escribiendo Comandos} + +\beginexample% +(defun \ (\) + "\" + (interactive "\") + \) +\endexample + +Un ejemplo: + +\beginexample% +(defun mover-l{\'i}nea-a-la-parte-superior (l{\'i}nea) + "Reubicar l{\'i}nea a la parte superior de la ventana. +Con el argumento de prefijo L{\'I}NEA, +colocar el cursor en L{\'I}NEA." + (interactive "P") + (recenter (if (null l{\'i}nea) + 0 + (prefix-numeric-value l{\'i}nea)))) +\endexample + +La especificaci{\'o}n \kbd{interactive} dice como leer argumentos de +forma interactiva. +Presiona \kbd{C-h f interactive RET} para m{\'a}s detalles. + +\bye + +% Local variables: +% compile-command: "pdftex refcard" +% End: commit cf0dbc34e8ef77828e2c6f8b07dddc606c44900e Author: Elías Gabriel Pérez Date: Sat Feb 22 12:05:07 2025 -0600 Add Spanish translation for dired-ref.tex * etc/refcards/es-dired-ref.tex: New file. (Bug#76300) diff --git a/etc/refcards/es-dired-ref.tex b/etc/refcards/es-dired-ref.tex new file mode 100644 index 00000000000..d9b7b3c4d05 --- /dev/null +++ b/etc/refcards/es-dired-ref.tex @@ -0,0 +1,426 @@ +% Reference Card for Dired + +% Copyright (C) 2000--2025 Free Software Foundation, Inc. + +% Author: Evgeny Roubinchtein +% Spanish translation: Elias Gabriel Perez + +% This document is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% As a special additional permission, you may distribute reference cards +% printed, or formatted for printing, with the notice "Released under +% the terms of the GNU General Public License version 3 or later" +% instead of the usual distributed-under-the-GNU-GPL notice, and without +% a copy of the GPL itself. + +% This document is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. + +% You should have received a copy of the GNU General Public License +% along with GNU Emacs. If not, see . + + +% This file is intended to be processed by plain TeX (TeX82). + +% This is a bit of a dirty hack on the GNU Emacs reference card +% to produce a Dired reference card instead. + +% I put this together because I wanted a Dired reference card, but +% couldn't find anything on the 'net. Based mostly off Dired's +% describe-mode. + +% Thanks to Cecilio Pardo, Mauro Aranda and Stephen Berman for +% the suggestions. + +%**start of header +\newcount\columnsperpage + +% This file can be printed with 1, 2, or 3 columns per page. +% Specify how many you want here. +% The reference card looks OK with 2 columns per page, portrait mode. +% I haven't tried it with 3 columns per page. +\columnsperpage=2 + +% PDF output layout. 0 for A4, 1 for letter (US), a `l' is added for +% a landscape layout. +\input pdflayout.sty +\pdflayout=(1) + +\input emacsver.tex + +% Nothing else needs to be changed. + +\def\shortcopyrightnotice{\vskip 1ex plus 2 fill + \centerline{\small \copyright\ \year\ Free Software Foundation, Inc. + Permissions on back.}} + +\def\copyrightnotice{ +\vskip 1ex plus 2 fill\begingroup\small +\centerline{Copyright \copyright\ \year\ Free Software Foundation, Inc.} +\centerline{For GNU Emacs version \versionemacs} +\centerline{Originally written May 2000 by Evgeny Roubinchtein,} +\centerline{using refcard layout designed by Stephen Gildea.} +\centerline{Translated by Elias Gabriel P{\'e}rez.} + +Released under the terms of the GNU General Public License version 3 or later. + +For more Emacs documentation, and the \TeX{} source for this card, +see the Emacs distribution, or {\tt https://www.gnu.org/software/emacs} +\endgroup} + +% make \bye not \outer so that the \def\bye in the \else clause below +% can be scanned without complaint. +\def\bye{\par\vfill\supereject\end} + +\newdimen\intercolumnskip %horizontal space between columns +\newbox\columna %boxes to hold columns already built +\newbox\columnb + +\def\ncolumns{\the\columnsperpage} + +\message{[\ncolumns\space + column\if 1\ncolumns\else s\fi\space per page]} + +\def\scaledmag#1{ scaled \magstep #1} + +% This multi-way format was designed by Stephen Gildea October 1986. +% Note that the 1-column format is fontfamily-independent. +\if 1\ncolumns %one-column format uses normal size + \hsize 4in + \vsize 10in + \voffset -.7in + \font\titlefont=\fontname\tenbf \scaledmag3 + \font\headingfont=\fontname\tenbf \scaledmag2 + \font\smallfont=\fontname\sevenrm + \font\smallsy=\fontname\sevensy + + \footline{\hss\folio} + \def\makefootline{\baselineskip10pt\hsize6.5in\line{\the\footline}} +\else %2 or 3 columns uses prereduced size + \hsize 3.4in + \vsize 9.2in + \hoffset -.75in + \voffset -.745in + \font\titlefont=cmbx10 \scaledmag2 + \font\headingfont=cmbx10 \scaledmag1 + \font\smallfont=cmr6 + \font\smallsy=cmsy6 + \font\eightrm=cmr8 + \font\eightbf=cmbx8 + \font\eightit=cmti8 + \font\eighttt=cmtt8 + \font\eightmi=cmmi8 + \font\eightsy=cmsy8 + \textfont0=\eightrm + \textfont1=\eightmi + \textfont2=\eightsy + \def\rm{\eightrm} + \def\bf{\eightbf} + \def\it{\eightit} + \def\tt{\eighttt} + \normalbaselineskip=.8\normalbaselineskip + \normallineskip=.8\normallineskip + \normallineskiplimit=.8\normallineskiplimit + \normalbaselines\rm %make definitions take effect + + \if 2\ncolumns + \let\maxcolumn=b + \footline{\hss\rm\folio\hss} + \def\makefootline{\vskip 2in \hsize=6.86in\line{\the\footline}} + \else \if 3\ncolumns + \let\maxcolumn=c + \nopagenumbers + \else + \errhelp{You must set \columnsperpage equal to 1, 2, or 3.} + \errmessage{Illegal number of columns per page} + \fi\fi + + \intercolumnskip=.46in + \def\abc{a} + \output={% %see The TeXbook page 257 + % This next line is useful when designing the layout. + %\immediate\write16{Column \folio\abc\space starts with \firstmark} + \if \maxcolumn\abc \multicolumnformat \global\def\abc{a} + \else\if a\abc + \global\setbox\columna\columnbox \global\def\abc{b} + %% in case we never use \columnb (two-column mode) + \global\setbox\columnb\hbox to -\intercolumnskip{} + \else + \global\setbox\columnb\columnbox \global\def\abc{c}\fi\fi} + \def\multicolumnformat{\shipout\vbox{\makeheadline + \hbox{\box\columna\hskip\intercolumnskip + \box\columnb\hskip\intercolumnskip\columnbox} + \makefootline}\advancepageno} + \def\columnbox{\leftline{\pagebody}} + + \def\bye{\par\vfill\supereject + \if a\abc \else\null\vfill\eject\fi + \if a\abc \else\null\vfill\eject\fi + \end} +\fi + +% we won't be using math mode much, so redefine some of the characters +% we might want to talk about +\catcode`\^=12 +\catcode`\_=12 + +\chardef\\=`\\ +\chardef\{=`\{ +\chardef\}=`\} + +\hyphenation{mini-buf-fer} +\hyphenation{de-le-tion} + +\parindent 0pt +\parskip 1ex plus .5ex minus .5ex + +\def\small{\smallfont\textfont2=\smallsy\baselineskip=.8\baselineskip} + +% newcolumn - force a new column. Use sparingly, probably only for +% the first column of a page, which should have a title anyway. +\outer\def\newcolumn{\vfill\eject} + +% title - page title. Argument is title text. +\outer\def\title#1{{\titlefont\centerline{#1}}\vskip 1ex plus .5ex} + +% section - new major section. Argument is section name. +\outer\def\section#1{\par\filbreak + \vskip 3ex plus 2ex minus 2ex {\headingfont #1}\mark{#1}% + \vskip 2ex plus 1ex minus 1.5ex} + +\newdimen\keyindent + +% beginindentedkeys...endindentedkeys - key definitions will be +% indented, but running text, typically used as headings to group +% definitions, will not. +\def\beginindentedkeys{\keyindent=1em} +\def\endindentedkeys{\keyindent=0em} +\endindentedkeys + +% paralign - begin paragraph containing an alignment. +% If an \halign is entered while in vertical mode, a parskip is never +% inserted. Using \paralign instead of \halign solves this problem. +\def\paralign{\vskip\parskip\halign} + +% \<...> - surrounds a variable name in a code example +\def\<#1>{{\it #1\/}} + +% kbd - argument is characters typed literally. Like the Texinfo command. +\def\kbd#1{{\tt#1}\null} %\null so not an abbrev even if period follows + +% beginexample...endexample - surrounds literal text, such a code example. +% typeset in a typewriter font with line breaks preserved +\def\beginexample{\par\leavevmode\begingroup + \obeylines\obeyspaces\parskip0pt\tt} +{\obeyspaces\global\let =\ } +\def\endexample{\endgroup} + +% key - definition of a key. +% \key{description of key}{key-name} +% prints the description left-justified, and the key-name in a \kbd +% form near the right margin. +\def\key#1#2{\leavevmode\hbox to \hsize{\vtop + {\hsize=.75\hsize\rightskip=1em + \hskip\keyindent\relax#1}\kbd{#2}\hfil}} + +\newbox\metaxbox +\setbox\metaxbox\hbox{\kbd{M-x }} +\newdimen\metaxwidth +\metaxwidth=\wd\metaxbox + +% metax - definition of a M-x command. +% \metax{description of command}{M-x command-name} +% Tries to justify the beginning of the command name at the same place +% as \key starts the key name. (The "M-x " sticks out to the left.) +\def\metax#1#2{\leavevmode\hbox to \hsize{\hbox to .75\hsize + {\hskip\keyindent\relax#1\hfil}% + \hskip -\metaxwidth minus 1fil + \kbd{#2}\hfil}} + +% threecol - like "key" but with two key names. +% for example, one for doing the action backward, and one for forward. +\def\threecol#1#2#3{\hskip\keyindent\relax#1\hfil&\kbd{#2}\hfil\quad + &\kbd{#3}\hfil\quad\cr} + +% I cannot figure out how to make all dired-x +% commands fit on a page in two-column format +\def\dx{{\bf (DX)}} + +\nopagenumbers + +%**end of header + + +\title{Tarjeta de referencia de Dired} + +\centerline{(basado en Dired de la version \versionemacs{} de GNU Emacs)} +\centerline{Los comandos marcados con \dx{} requieren de dired-x} + +% trim this down to fit everything on one page +% \section{General} +% In dired, you can edit a list of the files in a directory (and optionally +% its subdirectories in the `ls -lR' format). + +% Editing a directory means that you can visit, rename, copy, compress, +% load, byte-compile files. You can change files' attributes, run shell +% commands on files, or insert subdirectories into the edit buffer. You can +% "flag" files for deletion or "mark" files for later commands, either one +% file at a time or by all files matching certain criteria (e.g., files that +% match a certain regexp). + +% You move throughout the buffer using the usual cursor motion commands. +% Letters no longer insert themselves, but execute commands instead. The +% digits (0-9) are prefix arguments. + +% Most commands operate either on all marked files or on the current file if +% no files are marked. Use a numeric prefix argument to operate on the next +% ARG files (or previous ARG if ARG $<$ 0). Use the prefix argument `1' to +% operate on the current file only. Prefix arguments override marks. Commands +% which run a sub-process on a group of files will display a list of files +% for which the sub-process failed. Typing y will try to tell +% you what went wrong. + +% When editing several directories in one buffer, each directory acts as a +% page, so C-x [ and C-x ] can be used to move between directories. + +\section{Entrando y Saliendo de Dired} + +\key{ejecutar dired}{C-x d} +\key{entrar con dired al directorio del archivo que est{\'a}s editando}{C-x C-j \dx} +\key{salir de dired}{q} + +\section{Comandos de movimiento} + +\key{subir a la l{\'i}nea anterior}{p} +\key{bajar a la siguiente l{\'i}nea}{n} +\key{subir a la l{\'i}nea de la carpeta anterior}{<} +\key{bajar a la l{\'i}nea de la siguiente carpeta}{>} +\key{subir al anterior archivo marcado}{M-\{} +\key{bajar al siguiente archivo marcado}{M-\}} +\key{subir al subdirectorio anterior}{M-C-p} +\key{bajar al siguiente subdirectorio}{M-C-n} +\key{moverse al directorio principal}{^} +\key{moverse al primer subdirectorio secundario}{M-C-d} + +\section{Comandos para el Rat{\'o}n (Mouse)} +\metax{visitar archivo o directorio}{Mouse_Button_2 (bot{\'o}n central)} + +\section{Acciones inmediatas sobre los archivos} + +\key{abrir archivo actual}{f} +\key{ver archivo actual}{v} +\key{abrir archivo actual en otra ventana}{o} +%% Huh? +%% \key{visit current file in other frame}{w} +%% Huh? +%%\key{display current file}{C-u o} +\key{crear un subdirectorio nuevo}{+} +\key{comparar archivo del cursor con el otro marcado}{=} + +\section{Seleccionar y Deseleccionar Archivos} + +\key{seleccionar un archivo o subdirectorio para comandos posteriores}{m} +\key{deseleccionar un archivo o todos los archivos de un subdirectorio}{u} +\key{deseleccionar todos los archivos seleccionados en un buffer}{M-delete} +\key{seleccionar archivos con una extensi{\'o}n determinada}{* .} +\key{seleccionar todos los directorios}{* /} +\key{seleccionar todos los enlaces simb{\'o}licos}{* @} +\key{seleccionar todos los ejecutables}{* *} +\key{invertir selecci{\'o}n}{t} +\key{seleccionar todos los archivos en el subdirectorio actual}{* s} +\key{seleccionar los nombres de archivos que coinciden con una expresi{\'o}n regular}{* \%} +\key{cambiar las selecciones a un car{\'a}cter diferente}{* c} +\key{seleccionar archivos para los cuales la expresi{\'o}n Elisp retorne t}{* ( \dx} + +\shortcopyrightnotice +\section{Modificaci{\'o}n del buffer Dired} + +\key{insertar un subdirectorio en este buffer}{i} +\key{eliminar archivos seleccionados}{k} +\key{eliminar un archivo o directorio inmediatamente}{C-u k} +\key{volver a leer todos los directorios (conserva todas las selecciones)}{g} +\key{alternar el orden del subdirectorio actual por nombre/fecha}{s} +\key{editar los argumentos de ls}{C-u s} +\key{deshacer acci{\'o}n (restaurar selecci{\'o}n, l{\'i}neas ocultas + y dem{\'a}s)}{C-_} +\key{ocultar todos los subdirectorios}{M-\$} +\key{mostrar u ocultar subdirectorio}{\$} + +\section{Comandos en Archivos Marcados o especificados por el Prefijo} + +\key{copiar archivo(s)}{C} +\key{cambiar nombre a archivo o moverlo a otro directorio}{R} +\key{cambiar propiedad del(los) archivo(s)}{O} +\key{cambiar el grupo del(los) archivo(s)}{G} +\key{cambiar el modo del(los) archivo(s)}{M} +\key{imprimir archivo(s)}{P} +\key{convertir nombre del(los) archivo(s)}{\% l} +\key{a min{\'u}sculas}{} +\key{convertir nombre del(los) archivo(s)}{\% u} +\key{a may{\'u}sculas}{} +\key{eliminar archivo(s) seleccionado(s) (en contraposici{\'o}n a marcados + para eliminaci{\'o}n)}{D} +%% Huh? +%%\key{uuencode or uudecode file(s)}{U} +\key{comprimir o descomprimir archivo(s)}{Z} +%% Only uses the current file. +\key{ejecutar info en archivo}{I \dx} +\key{crear enlace(s) simb{\'o}lico(s)}{S} +\key{crear enlace(s) simb{\'o}lico(s) relativos}{Y} +\key{crear enlace(s) duro(s) (hard link)}{H} +\key{buscar archivos con una expresi{\'o}n regular}{A} +\key{buscar y remplazar con una expresi{\'o}n regular sobre los archivos + seleccionados}{Q} +\key{compilar a bytes este archivo(s)}{B} +\key{cargar archivo(s)}{L} +\key{ejecutar comando de shell en este archivo(s)}{!} +\key{ejecutar asincr{\'o}nicamente comando de shell en este(estos) archivo(s)}{\&} + +\section{Marcar archivos para Eliminaci{\'o}n} +\leftline{\bf Los comandos de deselecci{\'o}n remueve las marcas de eliminaci{\'o}n} +\key{marcar archivo para eliminaci{\'o}n}{d} +%% Huh? +%%\key{backup and remove deletion flag}{delete} +\key{marcar todos los archivos de respaldo (los nombres de archivos que + terminan en \~{})}{\~{}} +\key{marcar los archivos de guardado autom{\'a}tico}{\#} +\key{marcar varios archivos intermedios}{\% \&} +\key{marcar archivos de respaldo num{\'e}ricos (terminando en .\~{}1\~{}, .\~{}2\~{}, etc.)}{.} +\key{eliminar todos los archivos marcados para eliminaci{\'o}n}{x} +\key{marcar archivos que coinciden con la expresi{\'o}n regular}{\% d} + +\section{Comandos de Expresiones Regulares} + +\key{seleccionar nombres de archivos que coinciden con una expresi{\'o}n + regular}{\% m} +\key{copiar archivos seleccionados por una expresi{\'o}n regular}{\% C} +\key{renombrar archivos marcados por una expresi{\'o}n regular}{\% R} +\key{hacer un enlace duro (hardlink)}{\% H} +\key{hacer un enlace simb{\'o}lico}{\% S} +\key{hacer un enlace simb{\'o}lico, con rutas relativas}{\% Y} +\key{seleccionar para eliminar}{\% d} + +\newcolumn +\title{Tarjeta de referencia de Dired} + +\section{Dired y Find} +\metax{encontrar con find archivo(s) cuyo}{M-x find-name-dired} +\key{nombre coincida con un patr{\'o}n}{} +\metax{encontrar con find archivo(s) cuyo}{M-x find-grep-dired} +\key{nombre contenga un patr{\'o}n}{} +\metax{encontrar con find archivo(s) basado}{M-x find-dired} +\key{en la salida de \kbd{find}}{} + +\section{Obtener Ayuda} + +\key{ayuda de dired}{h} +\key{resumen de instrucciones (ayuda breve) y registro de errores}{?} + +\copyrightnotice + +\bye commit 144b268a84e6be81f59669b77651b4522a2f2805 Author: Po Lu Date: Tue Mar 4 09:46:48 2025 +0800 Render Android hourglass cursor mechanics more consistent with X * src/androidterm.c (android_show_hourglass): Always define the hourglass cursor, but... (android_hide_hourglass): ... restore the invisible cursor subsequently, if need be. (android_toggle_visible_pointer): Do not hide the current cursor if it is an hourglass. diff --git a/src/androidterm.c b/src/androidterm.c index 79ee374f2ca..7fd61ee6d1c 100644 --- a/src/androidterm.c +++ b/src/androidterm.c @@ -125,22 +125,39 @@ android_show_hourglass (struct frame *f) x->hourglass = true; - if (!f->pointer_invisible) - android_define_cursor (FRAME_ANDROID_WINDOW (f), - x->hourglass_cursor); + /* An hourglass cursor ought to be visible whether or not the standard + cursor is invisible. */ + android_define_cursor (FRAME_ANDROID_WINDOW (f), + x->hourglass_cursor); +} + +static android_cursor +make_invisible_cursor (struct android_display_info *dpyinfo) +{ + return android_create_font_cursor (ANDROID_XC_NULL); } static void android_hide_hourglass (struct frame *f) { struct android_output *x; + struct android_display_info *dpyinfo; x = FRAME_ANDROID_OUTPUT (f); + dpyinfo = FRAME_DISPLAY_INFO (f); x->hourglass = false; if (!f->pointer_invisible) android_define_cursor (FRAME_ANDROID_WINDOW (f), x->current_cursor); + else + { + if (!dpyinfo->invisible_cursor) + dpyinfo->invisible_cursor = make_invisible_cursor (dpyinfo); + + android_define_cursor (FRAME_ANDROID_WINDOW (f), + dpyinfo->invisible_cursor); + } } static void @@ -259,12 +276,6 @@ android_ring_bell (struct frame *f) } } -static android_cursor -make_invisible_cursor (struct android_display_info *dpyinfo) -{ - return android_create_font_cursor (ANDROID_XC_NULL); -} - static void android_toggle_visible_pointer (struct frame *f, bool invisible) { @@ -272,6 +283,10 @@ android_toggle_visible_pointer (struct frame *f, bool invisible) dpyinfo = FRAME_DISPLAY_INFO (f); + /* An hourglass cursor overrides invisibility. */ + if (FRAME_ANDROID_OUTPUT (f)->hourglass) + goto set_invisibility; + if (!dpyinfo->invisible_cursor) dpyinfo->invisible_cursor = make_invisible_cursor (dpyinfo); @@ -280,10 +295,9 @@ android_toggle_visible_pointer (struct frame *f, bool invisible) dpyinfo->invisible_cursor); else android_define_cursor (FRAME_ANDROID_WINDOW (f), - (FRAME_ANDROID_OUTPUT (f)->hourglass - ? f->output_data.android->hourglass_cursor - : f->output_data.android->current_cursor)); + f->output_data.android->current_cursor); + set_invisibility: f->pointer_invisible = invisible; } commit d6aea7cc948f13615237a91d347b0383a3089a8a Author: Po Lu Date: Tue Mar 4 09:36:19 2025 +0800 Circumvent another styling issue in Android 15 QPR1 * java/org/gnu/emacs/EmacsView.java (popupMenu): On Android 15 and later, reload the default theme before displaying popup menus. diff --git a/java/org/gnu/emacs/EmacsView.java b/java/org/gnu/emacs/EmacsView.java index 938e2a21d1a..8f16dbad257 100644 --- a/java/org/gnu/emacs/EmacsView.java +++ b/java/org/gnu/emacs/EmacsView.java @@ -707,6 +707,8 @@ else if (child.getVisibility () != GONE) popupMenu (EmacsContextMenu menu, int xPosition, int yPosition, boolean force) { + ContextThemeWrapper context; + if (popupActive && !force) return false; @@ -720,6 +722,16 @@ else if (child.getVisibility () != GONE) contextMenu = menu; popupActive = true; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM) + { + context = (ContextThemeWrapper) getContext (); + /* It is necessary to reload the current theme before attempting + to display a new popup menu, or any previously applied system + theme will continue to apply to it. */ + context.setTheme (R.style.EmacsStyleOpen); + context.setTheme (R.style.EmacsStyle); + } + /* Use showContextMenu (float, float) on N to get actual popup behavior. */ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) commit ec517d1dcf3260b2cf1684566b5e3bf3979eaceb Author: Matthew Bauer Date: Tue Mar 4 02:33:15 2025 +0100 Replace anonymous lambda timers with named functions * lisp/emacs-lisp/eldoc.el (eldoc--update, eldoc-schedule-timer): * lisp/jit-lock.el (jit-lock-context--update) (jit-lock--antiblink-update): New functions broken out from... * lisp/emacs-lisp/eldoc.el (eldoc-schedule-timer): * lisp/jit-lock.el (jit-lock-mode, jit-lock--antiblink-post-command): ...here. Use them as values for timers, to give them readable names in 'M-x list-timers'. (Bug#71354) diff --git a/lisp/emacs-lisp/eldoc.el b/lisp/emacs-lisp/eldoc.el index 81890268dd7..966158024dd 100644 --- a/lisp/emacs-lisp/eldoc.el +++ b/lisp/emacs-lisp/eldoc.el @@ -267,6 +267,14 @@ See `eldoc-documentation-strategy' for more detail." (eldoc-mode 1))) +(defun eldoc--update () + (when (or eldoc-mode + (and global-eldoc-mode + (eldoc--supported-p))) + ;; Don't ignore, but also don't full-on signal errors + (with-demoted-errors "eldoc error: %s" + (eldoc-print-current-symbol-info)) )) + (defun eldoc-schedule-timer () "Ensure `eldoc-timer' is running. @@ -277,13 +285,7 @@ reflect the change." (setq eldoc-timer (run-with-idle-timer eldoc-idle-delay nil - (lambda () - (when (or eldoc-mode - (and global-eldoc-mode - (eldoc--supported-p))) - ;; Don't ignore, but also don't full-on signal errors - (with-demoted-errors "eldoc error: %s" - (eldoc-print-current-symbol-info)) ))))) + #'eldoc--update))) ;; If user has changed the idle delay, update the timer. (cond ((not (= eldoc-idle-delay eldoc-current-idle-delay)) diff --git a/lisp/jit-lock.el b/lisp/jit-lock.el index 4b2b640905c..711d7ca8cac 100644 --- a/lisp/jit-lock.el +++ b/lisp/jit-lock.el @@ -179,6 +179,10 @@ If nil, contextual fontification is disabled.") ;;; JIT lock mode +(defun jit-lock-context--update () + (unless jit-lock--antiblink-grace-timer + (jit-lock-context-fontify))) + (defun jit-lock-mode (arg) "Toggle Just-in-time Lock mode. Turn Just-in-time Lock mode on if and only if ARG is non-nil. @@ -255,10 +259,7 @@ If you need to debug code run from jit-lock, see `jit-lock-debug-mode'." (when (eq jit-lock-contextually t) (unless jit-lock-context-timer (setq jit-lock-context-timer - (run-with-idle-timer jit-lock-context-time t - (lambda () - (unless jit-lock--antiblink-grace-timer - (jit-lock-context-fontify)))))) + (run-with-idle-timer jit-lock-context-time t #'jit-lock-context--update))) (add-hook 'post-command-hook #'jit-lock--antiblink-post-command nil t) (setq jit-lock-context-unfontify-pos (or jit-lock-context-unfontify-pos (point-max)))) @@ -706,6 +707,10 @@ will take place when text is fontified stealthily." ;; buffer, only jit-lock-context-* will re-fontify it. (min jit-lock-context-unfontify-pos jit-lock-start)))))) +(defun jit-lock--antiblink-update () + (jit-lock-context-fontify) + (setq jit-lock--antiblink-grace-timer nil)) + (defun jit-lock--antiblink-post-command () (let* ((new-l-b-p (copy-marker (syntax--lbp))) (l-b-p-2 (syntax--lbp 2)) @@ -722,11 +727,7 @@ will take place when text is fontified stealthily." (and same-line (null jit-lock--antiblink-string-or-comment) new-s-o-c) (setq jit-lock--antiblink-grace-timer - (run-with-idle-timer jit-lock-antiblink-grace nil - (lambda () - (jit-lock-context-fontify) - (setq jit-lock--antiblink-grace-timer - nil))))) + (run-with-idle-timer jit-lock-antiblink-grace nil #'jit-lock--antiblink-update))) (;; Closed an unterminated multiline string. (and same-line (null new-s-o-c) jit-lock--antiblink-string-or-comment) commit d9218651b6103267f7282997b75d19effdc02613 Author: Stefan Kangas Date: Tue Mar 4 02:42:27 2025 +0100 ; Fix my last commit * test/lisp/emacs-lisp/package-tests.el (package-test-install-single-from-archive/string-type): Delete test. diff --git a/test/lisp/emacs-lisp/package-tests.el b/test/lisp/emacs-lisp/package-tests.el index ed778049dcb..d8e260319bd 100644 --- a/test/lisp/emacs-lisp/package-tests.el +++ b/test/lisp/emacs-lisp/package-tests.el @@ -450,13 +450,6 @@ but with a different end of line convention (bug#48137)." (package-refresh-contents) (package-install 'simple-single))) -(ert-deftest package-test-install-single-from-archive/string-type () - "Install a single package from a package archive, using string argument." - (with-package-test () - (package-initialize) - (package-refresh-contents) - (package-install "simple-single"))) - (ert-deftest package-test-install-prioritized () "Install a lower version from a higher-prioritized archive." (with-package-test () commit 5dd8b7e75259663415523f3ebe35ba2f97b5b103 Author: Stefan Kangas Date: Tue Mar 4 01:51:16 2025 +0100 Don't accept strings in package-(install|upgrade) * lisp/emacs-lisp/package.el (package-install): Revert recent change to accept string PKG argument. (package-upgrade): No longer accept string NAME argument. (Bug#72160) diff --git a/etc/NEWS b/etc/NEWS index 6ae648ab8cf..67f9ed84bdf 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -1322,6 +1322,10 @@ will not prompt the user for confirmation before installing packages. Refreshing the package index will no longer block when invoked interactively. +--- +*** 'package-upgrade' no longer accepts a string argument. +When called from Lisp, it now only accepts a symbol. + +++ *** package-x.el is now obsolete. diff --git a/lisp/emacs-lisp/package.el b/lisp/emacs-lisp/package.el index cfe57fb9e35..8d498c216dc 100644 --- a/lisp/emacs-lisp/package.el +++ b/lisp/emacs-lisp/package.el @@ -2197,8 +2197,8 @@ built-in package with a (possibly newer) version from a package archive." (defun package-install (pkg &optional dont-select) "Install the package PKG. -PKG can be a `package-desc', or a symbol or string naming one of the -available packages in an archive in `package-archives'. +PKG can be a `package-desc', or a symbol naming one of the available +packages in an archive in `package-archives'. Mark the installed package as selected by adding it to `package-selected-packages'. @@ -2230,8 +2230,7 @@ had been enabled." package-archive-contents) nil t)) nil))) - (cl-check-type pkg (or string symbol package-desc)) - (if (stringp pkg) (setq pkg (intern pkg))) + (cl-check-type pkg (or symbol package-desc)) (package--archives-initialize) (add-hook 'post-command-hook #'package-menu--post-refresh) (let ((name (if (package-desc-p pkg) @@ -2261,21 +2260,19 @@ had been enabled." (defun package-upgrade (name) "Upgrade package NAME if a newer version exists. -NAME can be either a symbol or a string." +NAME should be a symbol." (interactive - (list (completing-read - "Upgrade package: " (package--upgradeable-packages t) nil t))) - (let* ((package (if (symbolp name) - name - (intern name))) - (pkg-desc (cadr (assq package package-alist))) + (list (intern (completing-read + "Upgrade package: " + (package--upgradeable-packages t) nil t)))) + (let* ((pkg-desc (cadr (assq name package-alist))) (package-install-upgrade-built-in (not pkg-desc))) ;; `pkg-desc' will be nil when the package is an "active built-in". (if (and pkg-desc (package-vc-p pkg-desc)) (package-vc-upgrade pkg-desc) (when pkg-desc (package-delete pkg-desc 'force 'dont-unselect)) - (package-install package + (package-install name ;; An active built-in has never been "selected" ;; before. Mark it as installed explicitly. (and pkg-desc 'dont-select))))) commit c116dad608afcf28384651101e8b6c6b7999f56e Author: Eli Zaretskii Date: Mon Mar 3 21:29:45 2025 +0200 Avoid crashes on MS-Windows on repeated client connections * src/w32uniscribe.c (uniscribe_close): Zero out dwrite cache. Suggested by Richard Copley . (Bug#76121) diff --git a/src/w32uniscribe.c b/src/w32uniscribe.c index 9986c9dc2f9..b412be6f2e1 100644 --- a/src/w32uniscribe.c +++ b/src/w32uniscribe.c @@ -204,6 +204,7 @@ uniscribe_close (struct font *font) #ifdef HAVE_HARFBUZZ w32_dwrite_free_cached_face (uniscribe_font->dwrite_cache); + uniscribe_font->dwrite_cache = NULL; if (uniscribe_font->w32_font.font.driver == &harfbuzz_font_driver && uniscribe_font->cache) hb_font_destroy ((hb_font_t *) uniscribe_font->cache); commit 1ec0889e7b786d79351cee3ed4964d82295f059f Author: Eli Zaretskii Date: Mon Mar 3 21:08:35 2025 +0200 Fix MS-Windows build broken by buffered_input_event changes * src/keyboard.c (kbd_buffer_store_selection_event_hold): * src/keyboard.h (kbd_buffer_store_selection_event_hold): Declare and define only for (HAVE_X11 || HAVE_PGTK). diff --git a/src/keyboard.c b/src/keyboard.c index fd0ac01755e..e1a7be355f2 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -3840,6 +3840,7 @@ kbd_buffer_store_event_hold (struct input_event *event, maybe_quit_while_no_input (event->kind); } +#if defined HAVE_X11 || defined HAVE_PGTK /* Store EVENT obtained at interrupt level into kbd_buffer, fifo. This is like kbd_buffer_store_event_hold, but for struct selection_input_event instead of struct input_event. @@ -3870,6 +3871,7 @@ kbd_buffer_store_selection_event_hold (struct selection_input_event *event, maybe_quit_while_no_input (event->kind); } +#endif /* HAVE_X11 || HAVE_PGTK */ /* Limit help event positions to this range, to avoid overflow problems. */ #define INPUT_EVENT_POS_MAX \ diff --git a/src/keyboard.h b/src/keyboard.h index ddbb1c3729e..1dd56d92a8f 100644 --- a/src/keyboard.h +++ b/src/keyboard.h @@ -501,8 +501,10 @@ extern bool lucid_event_type_list_p (Lisp_Object); extern void kbd_buffer_store_event (struct input_event *); extern void kbd_buffer_store_event_hold (struct input_event *, struct input_event *); +#if defined HAVE_X11 || defined HAVE_PGTK extern void kbd_buffer_store_selection_event_hold (struct selection_input_event *, struct input_event *); +#endif extern void poll_for_input_1 (void); extern void show_help_echo (Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object); commit dbc0e5a52d855773a495e0ca89b738f8f2246df9 Author: Juri Linkov Date: Mon Mar 3 20:38:40 2025 +0200 Improve treesit settings for js-ts-mode (bug#73404) * lisp/progmodes/js.el (js--treesit-font-lock-settings): Add 'class' alongside 'class_declaration'. (js--treesit-defun-name): Add "variable_declaration" alongside "lexical_declaration". (js--treesit-valid-imenu-entry): Add "variable_declaration" and provide the predicate to 'treesit-node-top-level'. (js--treesit-sentence-nodes): Add "jsx_attribute" like in html-ts-mode instead of jsx elements matched in 'js--treesit-list-nodes'. (js--treesit-list-nodes): Add "jsx_element" and "jsx_self_closing_element" instead of "_jsx_string". (js--treesit-simple-imenu-settings): Move "method_definition" to separate section "Method" from the "Class" section. Add "variable_declaration" to the "Variable" section. (js-ts-mode--outline-predicate): New variable. (js--treesit-defun-type-regexp): Add bos/eos. (js--treesit-jsdoc-comment-regexp): Add bos/eos. (js-ts-mode): Set treesit-outline-predicate to 'js-ts-mode--outline-predicate'. * lisp/textmodes/mhtml-ts-mode.el (mhtml-ts-mode--html-defun-name): Remove unused function. (mhtml-ts-mode): Use 'js-ts-mode--outline-predicate' in 'treesit-aggregated-outline-predicate'. * lisp/textmodes/yaml-ts-mode.el (yaml-ts-mode--outline-predicate): Use 'treesit-node-top-level' instead of 'treesit-parent-until'. diff --git a/lisp/progmodes/js.el b/lisp/progmodes/js.el index 1142786ffaa..e5dae4eed5f 100644 --- a/lisp/progmodes/js.el +++ b/lisp/progmodes/js.el @@ -3544,6 +3544,9 @@ Check if a node type is available, then return the right indent rules." :feature 'definition `(,@(js--treesit-font-lock-compatibility-definition-feature) + (class + name: (identifier) @font-lock-type-face) + (class_declaration name: (identifier) @font-lock-type-face) @@ -3708,7 +3711,7 @@ Return nil if there is no name or if NODE is not a defun node." (treesit-node-text (treesit-node-child-by-field-name (pcase (treesit-node-type node) - ("lexical_declaration" + ((or "lexical_declaration" "variable_declaration") (treesit-search-subtree node "variable_declarator" nil nil 1)) ((or "function_declaration" "method_definition" "class_declaration") node)) @@ -3716,9 +3719,15 @@ Return nil if there is no name or if NODE is not a defun node." t)) (defun js--treesit-valid-imenu-entry (node) - "Return nil if NODE is a non-top-level \"lexical_declaration\"." + "Return nil if NODE is a non-top-level lexical/variable declaration." (pcase (treesit-node-type node) - ("lexical_declaration" (treesit-node-top-level node)) + ((or "lexical_declaration" "variable_declaration") + (not (treesit-node-top-level + node (rx bos (or "class_declaration" + "method_definition" + "function_declaration" + "function_expression") + eos)))) (_ t))) (defun js--treesit-language-at-point (point) @@ -3857,8 +3866,7 @@ Currently there are `js-mode' and `js-ts-mode'." "labeled_statement" "variable_declaration" "lexical_declaration" - "jsx_element" - "jsx_self_closing_element") + "jsx_attribute") "Nodes that designate sentences in JavaScript. See `treesit-thing-settings' for more information.") @@ -3906,8 +3914,9 @@ See `treesit-thing-settings' for more information.") "object_pattern" "array" "array_pattern" + "jsx_element" "jsx_expression" - "_jsx_string" + "jsx_self_closing_element" "string" "regex" "arguments" @@ -3938,24 +3947,34 @@ See `treesit-thing-settings' for more information.") "Settings for `treesit-font-lock-feature-list'.") (defvar js--treesit-simple-imenu-settings - `(("Function" "\\`function_declaration\\'" nil nil) - ("Variable" "\\`lexical_declaration\\'" - js--treesit-valid-imenu-entry nil) - ("Class" ,(rx bos (or "class_declaration" - "method_definition") - eos) - nil nil)) + `(("Class" "\\`class_declaration\\'" nil nil) + ("Method" "\\`method_definition\\'" nil nil) + ("Function" "\\`function_declaration\\'" nil nil) + ("Variable" ,(rx bos (or "lexical_declaration" + "variable_declaration") + eos) + ,#'js--treesit-valid-imenu-entry nil)) "Settings for `treesit-simple-imenu'.") +(defvar js-ts-mode--outline-predicate + `(or (and "\\`class\\'" named) + ,(rx bos (or"class_declaration" + "method_definition" + "function_declaration" + "function_expression") + eos))) + (defvar js--treesit-defun-type-regexp - (rx (or "class_declaration" - "method_definition" - "function_declaration" - "lexical_declaration")) + (rx bos (or "class_declaration" + "method_definition" + "function_declaration" + "lexical_declaration" + "variable_declaration") + eos) "Settings for `treesit-defun-type-regexp'.") (defvar js--treesit-jsdoc-comment-regexp - (rx (or "comment" "line_comment" "block_comment" "description")) + (rx bos (or "comment" "line_comment" "block_comment" "description") eos) "Regexp for `c-ts-common--comment-regexp'.") ;;;###autoload @@ -4011,6 +4030,8 @@ See `treesit-thing-settings' for more information.") ;; Imenu (setq-local treesit-simple-imenu-settings js--treesit-simple-imenu-settings) + ;; Outline minor mode + (setq-local treesit-outline-predicate js-ts-mode--outline-predicate) (treesit-major-mode-setup) diff --git a/lisp/textmodes/mhtml-ts-mode.el b/lisp/textmodes/mhtml-ts-mode.el index 4d538514f1c..5c4f90cd193 100644 --- a/lisp/textmodes/mhtml-ts-mode.el +++ b/lisp/textmodes/mhtml-ts-mode.el @@ -367,15 +367,6 @@ NODE and PARENT are ignored." (defvar mhtml-ts-mode--prettify-symbols-alist js--prettify-symbols-alist "Alist of symbol prettifications for various supported languages.") -(defun mhtml-ts-mode--html-defun-name (node) - "Return the defun name of NODE. -Return nil if there is no name or if NODE is not a defun node." - (when (string-match-p "element" (treesit-node-type node)) - (treesit-node-text - node - ;; (treesit-search-subtree node "\\`tag_name\\'" nil nil 2) - t))) - ;; In order to support `which-fuction-mode' we should define ;; a function that return the defun name. ;; In a multilingual treesit mode, this can be implemented simply by @@ -584,8 +575,7 @@ Powered by tree-sitter." (setq-local treesit-aggregated-outline-predicate `((html . ,#'html-ts-mode--outline-predicate) - ;; TODO: add a predicate like for html above - (javascript . "\\`function_declaration\\'") + (javascript . ,js-ts-mode--outline-predicate) (css . ,css-ts-mode--outline-predicate))) (treesit-major-mode-setup) diff --git a/lisp/textmodes/yaml-ts-mode.el b/lisp/textmodes/yaml-ts-mode.el index 9b211902e14..7d11223aefa 100644 --- a/lisp/textmodes/yaml-ts-mode.el +++ b/lisp/textmodes/yaml-ts-mode.el @@ -154,7 +154,7 @@ Return nil if there is no name or if NODE is not a defun node." "Limit outlines to top-level mappings." (let ((regexp (rx (or "block_mapping_pair" "block_sequence_item")))) (when (string-match-p regexp (treesit-node-type node)) - (not (treesit-parent-until node regexp))))) + (not (treesit-node-top-level node regexp))))) ;;;###autoload (define-derived-mode yaml-ts-mode text-mode "YAML" commit 10abb87f0519b3d53d6b7078703d3a0120e3aaa8 Author: Stefan Kangas Date: Mon Mar 3 18:37:43 2025 +0100 Fix fontification outside hunks in Git patches * lisp/vc/diff-mode.el (diff-font-lock-keywords): Don't fontify lines in Git patches starting with + or - as added/removed, if they are either before the first hunk, or in the email signature. (Bug#75884) (diff-buffer-type): Move definition up. (diff--indicator-added-re, diff--indicator-removed-re): New variables. (diff--git-preamble-end, diff--git-footer-start) (diff--indicator-matcher-helper, diff--indicator-added-matcher) (diff--indicator-removed-matcher): New functions. * test/lisp/vc/diff-mode-tests.el (diff-mode-test-git-patch) (diff-mode-test-git-patch/before-first-hunk) (diff-mode-test-git-patch/signature): New tests. * test/lisp/vc/diff-mode-resources/git.patch: New file. diff --git a/lisp/vc/diff-mode.el b/lisp/vc/diff-mode.el index 16e696b6609..ed531204c15 100644 --- a/lisp/vc/diff-mode.el +++ b/lisp/vc/diff-mode.el @@ -481,6 +481,59 @@ If non-nil, use the face `diff-changed-unspecified'. Otherwise, use the face `diff-removed' for removed lines, and the face `diff-added' for added lines.") +(defvar diff-buffer-type nil) + +(defvar diff--indicator-added-re + (rx bol + (group (any "+>")) + (group (zero-or-more nonl) "\n"))) + +(defvar diff--indicator-removed-re + (rx bol + (group (any "<-")) + (group (zero-or-more nonl) "\n"))) + +(defun diff--git-preamble-end () + (save-excursion + (goto-char (point-min)) + (re-search-forward "^diff --git .+ .+$" nil t) + (forward-line 2) + (point))) + +(defun diff--git-footer-start () + (save-excursion + (goto-char (point-max)) + (re-search-backward "^-- $" nil t) + (point))) + +(defun diff--indicator-matcher-helper (limit regexp) + "Fontify added/removed lines from point to LIMIT using REGEXP. + +If this is a Git patch, don't fontify lines before the first hunk, or in +the email signature at the end." + (catch 'return + (when (eq diff-buffer-type 'git) + (let ((preamble-end (diff--git-preamble-end)) + (footer-start (diff--git-footer-start)) + (beg (point)) + (end limit)) + (cond ((or (<= end preamble-end) + (>= beg footer-start)) + (throw 'return nil)) + ;; end is after preamble, adjust beg: + ((< beg preamble-end) + (goto-char preamble-end)) + ;; beg is before footer, adjust end: + ((> end footer-start) + (setq limit footer-start))))) + (re-search-forward regexp limit t))) + +(defun diff--indicator-added-matcher (limit) + (diff--indicator-matcher-helper limit diff--indicator-added-re)) + +(defun diff--indicator-removed-matcher (limit) + (diff--indicator-matcher-helper limit diff--indicator-removed-re)) + (defvar diff-font-lock-keywords `((,(concat "\\(" diff-hunk-header-re-unified "\\)\\(.*\\)$") (1 'diff-hunk-header) (6 'diff-function)) @@ -495,9 +548,9 @@ use the face `diff-removed' for removed lines, and the face ("^\\(---\\|\\+\\+\\+\\|\\*\\*\\*\\) \\([^\t\n]+?\\)\\(?:\t.*\\| \\(\\*\\*\\*\\*\\|----\\)\\)?\n" (0 'diff-header) (2 (if (not (match-end 3)) 'diff-file-header) prepend)) - ("^\\([-<]\\)\\(.*\n\\)" + (diff--indicator-removed-matcher (1 diff-indicator-removed-face) (2 'diff-removed)) - ("^\\([+>]\\)\\(.*\n\\)" + (diff--indicator-added-matcher (1 diff-indicator-added-face) (2 'diff-added)) ("^\\(!\\)\\(.*\n\\)" (1 (if diff-use-changed-face @@ -562,7 +615,6 @@ See https://lists.gnu.org/r/emacs-devel/2007-11/msg01990.html") (defconst diff-separator-re "^--+ ?$") (defvar diff-narrowed-to nil) -(defvar diff-buffer-type nil) (defun diff-hunk-style (&optional style) (when (looking-at diff-hunk-header-re) diff --git a/test/lisp/vc/diff-mode-resources/git.patch b/test/lisp/vc/diff-mode-resources/git.patch new file mode 100644 index 00000000000..05ec90d105c --- /dev/null +++ b/test/lisp/vc/diff-mode-resources/git.patch @@ -0,0 +1,51 @@ +From 1234567890abcdef1234567890abcdef12345678 Mon Sep 17 00:00:00 2001 +From: Alyssa P. Hacker +Date: Sun, 3 Mar 2025 10:30:00 -0400 +Subject: [PATCH] Subtle bug fixes and slight improvements + +- This is not a removed line ++ This is not an added line + +--- + src/main.py | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/src/main.py b/src/main.py +index 9f6c5fe43e47eab441232e54456c5c2b06297b65..7b3f91a8b4ed923c8f43183276e3ab36fe04f6c9 100644 +--- a/src/main.py ++++ b/src/main.py +@@ -2,25 +2,24 @@ + + def main(): + # Initialize the magic number generator +- magic_number = 42 +- print("Magic number: ", magic_number) + +- # TODO: Fix the infinite loop +- while True: +- print("This loop will never end") ++ magic_number = 73 # After reconsidering, 73 seems more appropriate ++ print("Updated magic number: ", magic_number) + ++ # The infinite loop was probably not the best approach ++ # while True: ++ # print("This loop will never end.") + + # This part of the code handles other important tasks + print("Processing other tasks...") + + # Error handling has been updated for clarity +- if not fixed_it_yet: +- print("ERROR: Still broken!") ++ if not fixed_it_yet: # This should be fine now ++ print("ERROR: No longer an issue.") + + # Exiting the function on a positive note +- print("Goodbye, cruel world!") ++ print("Goodbye, world!") + + if __name__ == "__main__": + main() + +-- +2.40.0 diff --git a/test/lisp/vc/diff-mode-tests.el b/test/lisp/vc/diff-mode-tests.el index cd3f613f532..bbd66824e48 100644 --- a/test/lisp/vc/diff-mode-tests.el +++ b/test/lisp/vc/diff-mode-tests.el @@ -557,5 +557,45 @@ baz")))) +1 "))))) +(ert-deftest diff-mode-test-git-patch () + (let ((file (ert-resource-file "git.patch"))) + (with-temp-buffer + (insert-file-contents file) + (diff-mode) + (font-lock-ensure) + (goto-char (point-min)) + (re-search-forward "magic_number = 42") + (should (eq (get-text-property (match-beginning 0) 'face) + 'diff-removed)) + (re-search-forward "magic_number = 73") + (should (eq (get-text-property (match-beginning 0) 'face) + 'diff-added))))) + +(ert-deftest diff-mode-test-git-patch/before-first-hunk () + (let ((file (ert-resource-file "git.patch"))) + (with-temp-buffer + (insert-file-contents file) + (diff-mode) + (font-lock-ensure) + (goto-char (point-min)) + (re-search-forward "This is not a removed line") + (should (eq (get-text-property (match-beginning 0) 'face) + 'diff-context)) + (re-search-forward "This is not an added line") + (font-lock-ensure) + (should (eq (get-text-property (match-beginning 0) 'face) + 'diff-context))))) + +(ert-deftest diff-mode-test-git-patch/signature () + (let ((file (ert-resource-file "git.patch"))) + (with-temp-buffer + (insert-file-contents file) + (diff-mode) + (font-lock-ensure) + (goto-char (point-max)) + (re-search-backward "^-- $") + (should (eq (get-text-property (match-beginning 0) 'face) + 'diff-context))))) + (provide 'diff-mode-tests) ;;; diff-mode-tests.el ends here commit eeda2a8ab1f06da5b51dc98e57ae8b4a4faa1f72 Author: Stefan Kangas Date: Mon Mar 3 18:37:39 2025 +0100 Improve argument type error in load-theme * lisp/custom.el (load-theme): Improve error message when passing in a non-symbol THEME argument. diff --git a/lisp/custom.el b/lisp/custom.el index dee55d9ed11..5360c397c59 100644 --- a/lisp/custom.el +++ b/lisp/custom.el @@ -1326,6 +1326,8 @@ Return t if THEME was successfully loaded, nil otherwise." (mapcar #'symbol-name (custom-available-themes)))) nil nil)) + (unless (symbolp theme) + (signal 'wrong-type-argument (list 'symbolp theme))) (unless (custom-theme-name-valid-p theme) (error "Invalid theme name `%s'" theme)) ;; If THEME is already enabled, re-enable it after loading, even if commit 29a9fd4f4ba17822eca0f00c2037da3868bd874e Author: Paul Eggert Date: Mon Mar 3 09:32:08 2025 -0800 Avoid some union buffered_input_event uses Simplify by using separate local vars for struct input_event and struct selection_input_event, rather than a single local var that is the union of the two. This makes the code easier to follow by the human reader, and should help avoid GCC bug 117423 and therefore work around Emacs bug 76559 . * src/androidterm.c (handle_one_android_event): * src/gtkutil.c (xg_widget_key_press_event_cb): * src/pgtkterm.c (evq_flush): * src/xterm.c (handle_one_xevent): Use struct input_event and kbd_buffer_store_event_hold, or struct selection_input_event and kbd_buffer_store_selection_event_hold, rather than union buffered_input_event and union buffered_input_event. * src/keyboard.c (beware_long_paste, maybe_quit_while_no_input): New functions, broken out from kbd_buffer_store_buffered_event. (kbd_buffer_store_event_hold): Define here, with a simplified version of the body of the old kbd_buffer_store_buffered_event, rather than defining in keyboard.h. Specialize to struct input_event. (kbd_buffer_store_selection_event_hold): New function; it is a simplified version of the old kbd_buffer_store_buffered_event, specialized to struct selection_input_event. (is_ignored_event_kind): Accept enum event_kind instead of union buffered_input_event. All callers changed. * src/keyboard.h (kbd_buffer_store_event_hold): Remove definition, as keyboard.c now defines it. * src/pgtkterm.c (evq_grow_if_needed): New function. (evq_enqueue, evq_selection_enqueue): Two functions now, not one. Args are now struct input_event const * or struct selection_input_event const *, not union buffered_input_event *. All callers changed. This lets us simplify the callers so that they need not use the union. diff --git a/src/androidterm.c b/src/androidterm.c index 3cb9eab3606..79ee374f2ca 100644 --- a/src/androidterm.c +++ b/src/androidterm.c @@ -827,7 +827,7 @@ handle_one_android_event (struct android_display_info *dpyinfo, union android_event configureEvent; struct frame *f, *any, *mouse_frame; Mouse_HLInfo *hlinfo; - union buffered_input_event inev; + struct input_event inev; int modifiers, count, do_help; struct android_touch_point *touchpoint, **last; Lisp_Object window; @@ -851,7 +851,7 @@ handle_one_android_event (struct android_display_info *dpyinfo, if (any && any->wait_event_type == event->type) any->wait_event_type = 0; /* Indicates we got it. */ - EVENT_INIT (inev.ie); + EVENT_INIT (inev); switch (event->type) { @@ -922,8 +922,8 @@ handle_one_android_event (struct android_display_info *dpyinfo, if (!FRAME_TOOLTIP_P (f) && (old_left != f->left_pos || old_top != f->top_pos)) { - inev.ie.kind = MOVE_FRAME_EVENT; - XSETFRAME (inev.ie.frame_or_window, f); + inev.kind = MOVE_FRAME_EVENT; + XSETFRAME (inev.frame_or_window, f); } if (f && FRAME_OUTPUT_DATA (f)->need_cursor_updates) @@ -982,10 +982,10 @@ handle_one_android_event (struct android_display_info *dpyinfo, memset (&compose_status, 0, sizeof (compose_status)); /* Common for all keysym input events. */ - XSETFRAME (inev.ie.frame_or_window, any); - inev.ie.modifiers + XSETFRAME (inev.frame_or_window, any); + inev.modifiers = android_android_to_emacs_modifiers (dpyinfo, modifiers); - inev.ie.timestamp = event->xkey.time; + inev.timestamp = event->xkey.time; keysym = event->xkey.keycode; @@ -1019,8 +1019,8 @@ handle_one_android_event (struct android_display_info *dpyinfo, if (event->xkey.keycode == (uint32_t) -1) { - inev.ie.kind = PREEDIT_TEXT_EVENT; - inev.ie.arg = Qnil; + inev.kind = PREEDIT_TEXT_EVENT; + inev.arg = Qnil; /* If text was looked up, decode it and make it the preedit text. */ @@ -1028,7 +1028,7 @@ handle_one_android_event (struct android_display_info *dpyinfo, if (status_return == ANDROID_LOOKUP_CHARS && nchars) { copy_bufptr[nchars] = 0; - inev.ie.arg = from_unicode_buffer (copy_bufptr); + inev.arg = from_unicode_buffer (copy_bufptr); } goto done_keysym; @@ -1047,11 +1047,11 @@ handle_one_android_event (struct android_display_info *dpyinfo, /* Deal with characters. */ if (copy_bufptr[0] < 128) - inev.ie.kind = ASCII_KEYSTROKE_EVENT; + inev.kind = ASCII_KEYSTROKE_EVENT; else - inev.ie.kind = MULTIBYTE_CHAR_KEYSTROKE_EVENT; + inev.kind = MULTIBYTE_CHAR_KEYSTROKE_EVENT; - inev.ie.code = copy_bufptr[0]; + inev.code = copy_bufptr[0]; } else if (nchars < 2 && keysym) { @@ -1061,8 +1061,8 @@ handle_one_android_event (struct android_display_info *dpyinfo, /* Next, deal with special ``characters'' by giving the keycode to keyboard.c. */ - inev.ie.kind = NON_ASCII_KEYSTROKE_EVENT; - inev.ie.code = keysym; + inev.kind = NON_ASCII_KEYSTROKE_EVENT; + inev.code = keysym; } else { @@ -1070,25 +1070,25 @@ handle_one_android_event (struct android_display_info *dpyinfo, for (i = 0; i < nchars; ++i) { - inev.ie.kind = (SINGLE_BYTE_CHAR_P (copy_bufptr[i]) - ? ASCII_KEYSTROKE_EVENT - : MULTIBYTE_CHAR_KEYSTROKE_EVENT); - inev.ie.code = copy_bufptr[i]; + inev.kind = (SINGLE_BYTE_CHAR_P (copy_bufptr[i]) + ? ASCII_KEYSTROKE_EVENT + : MULTIBYTE_CHAR_KEYSTROKE_EVENT); + inev.code = copy_bufptr[i]; /* If the character is actually '\n', then change this to RET. */ if (copy_bufptr[i] == '\n') { - inev.ie.kind = NON_ASCII_KEYSTROKE_EVENT; - inev.ie.code = 66; + inev.kind = NON_ASCII_KEYSTROKE_EVENT; + inev.code = 66; } - kbd_buffer_store_buffered_event (&inev, hold_quit); + kbd_buffer_store_event_hold (&inev, hold_quit); } count += nchars; - inev.ie.kind = NO_EVENT; /* Already stored above. */ + inev.kind = NO_EVENT; /* Already stored above. */ } goto done_keysym; @@ -1108,7 +1108,7 @@ handle_one_android_event (struct android_display_info *dpyinfo, case ANDROID_FOCUS_IN: case ANDROID_FOCUS_OUT: - android_detect_focus_change (dpyinfo, any, event, &inev.ie); + android_detect_focus_change (dpyinfo, any, event, &inev); goto OTHER; case ANDROID_WINDOW_ACTION: @@ -1136,8 +1136,8 @@ handle_one_android_event (struct android_display_info *dpyinfo, if (!f) goto OTHER; - inev.ie.kind = DELETE_WINDOW_EVENT; - XSETFRAME (inev.ie.frame_or_window, f); + inev.kind = DELETE_WINDOW_EVENT; + XSETFRAME (inev.frame_or_window, f); } } @@ -1196,8 +1196,8 @@ handle_one_android_event (struct android_display_info *dpyinfo, && !EQ (window, last_mouse_window) && !EQ (window, selected_window)) { - inev.ie.kind = SELECT_WINDOW_EVENT; - inev.ie.frame_or_window = window; + inev.kind = SELECT_WINDOW_EVENT; + inev.frame_or_window = window; } /* Remember the last window where we saw the mouse. */ @@ -1378,10 +1378,10 @@ handle_one_android_event (struct android_display_info *dpyinfo, if (!(tab_bar_p && NILP (tab_bar_arg)) && !tool_bar_p) if (! popup_activated ()) { - android_construct_mouse_click (&inev.ie, &event->xbutton, f); + android_construct_mouse_click (&inev, &event->xbutton, f); if (!NILP (tab_bar_arg)) - inev.ie.arg = tab_bar_arg; + inev.arg = tab_bar_arg; } } @@ -1424,8 +1424,8 @@ handle_one_android_event (struct android_display_info *dpyinfo, /* Simply update the tool position and send an update. */ touchpoint->x = event->touch.x; touchpoint->y = event->touch.y; - android_update_tools (any, &inev.ie); - inev.ie.timestamp = event->touch.time; + android_update_tools (any, &inev); + inev.timestamp = event->touch.time; goto OTHER; } @@ -1498,12 +1498,12 @@ handle_one_android_event (struct android_display_info *dpyinfo, } /* Now generate the Emacs event. */ - inev.ie.kind = TOUCHSCREEN_BEGIN_EVENT; - inev.ie.timestamp = event->touch.time; - XSETFRAME (inev.ie.frame_or_window, any); - XSETINT (inev.ie.x, event->touch.x); - XSETINT (inev.ie.y, event->touch.y); - XSETINT (inev.ie.arg, event->touch.pointer_id); + inev.kind = TOUCHSCREEN_BEGIN_EVENT; + inev.timestamp = event->touch.time; + XSETFRAME (inev.frame_or_window, any); + XSETINT (inev.x, event->touch.x); + XSETINT (inev.y, event->touch.y); + XSETINT (inev.arg, event->touch.pointer_id); goto OTHER; @@ -1526,8 +1526,8 @@ handle_one_android_event (struct android_display_info *dpyinfo, touchpoint->x = event->touch.x; touchpoint->y = event->touch.y; - android_update_tools (any, &inev.ie); - inev.ie.timestamp = event->touch.time; + android_update_tools (any, &inev); + inev.timestamp = event->touch.time; goto OTHER; @@ -1569,18 +1569,18 @@ handle_one_android_event (struct android_display_info *dpyinfo, grabbed by the tool bar). */ xfree (touchpoint); - inev.ie.kind = TOUCHSCREEN_END_EVENT; - inev.ie.timestamp = event->touch.time; + inev.kind = TOUCHSCREEN_END_EVENT; + inev.timestamp = event->touch.time; /* Report whether the sequence has been canceled. */ if (event->touch.flags & ANDROID_TOUCH_SEQUENCE_CANCELED) - inev.ie.modifiers = 1; + inev.modifiers = 1; - XSETFRAME (inev.ie.frame_or_window, any); - XSETINT (inev.ie.x, event->touch.x); - XSETINT (inev.ie.y, event->touch.y); - XSETINT (inev.ie.arg, event->touch.pointer_id); + XSETFRAME (inev.frame_or_window, any); + XSETINT (inev.x, event->touch.x); + XSETINT (inev.y, event->touch.y); + XSETINT (inev.arg, event->touch.pointer_id); /* Break out of the loop. */ goto OTHER; @@ -1629,24 +1629,24 @@ handle_one_android_event (struct android_display_info *dpyinfo, } /* Determine what kind of event to send. */ - inev.ie.kind = ((fabs (wheel_event_y) + inev.kind = ((fabs (wheel_event_y) >= fabs (wheel_event_x)) ? WHEEL_EVENT : HORIZ_WHEEL_EVENT); - inev.ie.timestamp = event->wheel.time; + inev.timestamp = event->wheel.time; /* Set the event coordinates. */ - XSETINT (inev.ie.x, event->wheel.x); - XSETINT (inev.ie.y, event->wheel.y); + XSETINT (inev.x, event->wheel.x); + XSETINT (inev.y, event->wheel.y); /* Set the frame. */ - XSETFRAME (inev.ie.frame_or_window, any); + XSETFRAME (inev.frame_or_window, any); /* Figure out the scroll direction. */ - inev.ie.modifiers = (signbit ((fabs (wheel_event_x) - >= fabs (wheel_event_y)) - ? wheel_event_x - : wheel_event_y) - ? down_modifier : up_modifier); + inev.modifiers = (signbit ((fabs (wheel_event_x) + >= fabs (wheel_event_y)) + ? wheel_event_x + : wheel_event_y) + ? down_modifier : up_modifier); /* Figure out how much to scale the deltas by. */ window = window_from_coordinates (any, event->wheel.x, @@ -1664,16 +1664,14 @@ handle_one_android_event (struct android_display_info *dpyinfo, scroll_unit = pow (scroll_height, 2.0 / 3.0); /* Add the keyboard modifiers. */ - inev.ie.modifiers + inev.modifiers |= android_android_to_emacs_modifiers (dpyinfo, event->wheel.state); /* Finally include the scroll deltas. */ - inev.ie.arg = list3 (Qnil, - make_float (wheel_event_x - * scroll_unit), - make_float (wheel_event_y - * scroll_unit)); + inev.arg = list3 (Qnil, + make_float (wheel_event_x * scroll_unit), + make_float (wheel_event_y * scroll_unit)); wheel_event_x = 0.0; wheel_event_y = 0.0; @@ -1693,8 +1691,8 @@ handle_one_android_event (struct android_display_info *dpyinfo, SET_FRAME_VISIBLE (any, false); SET_FRAME_ICONIFIED (any, true); - inev.ie.kind = ICONIFY_EVENT; - XSETFRAME (inev.ie.frame_or_window, any); + inev.kind = ICONIFY_EVENT; + XSETFRAME (inev.frame_or_window, any); goto OTHER; case ANDROID_DEICONIFIED: @@ -1708,8 +1706,8 @@ handle_one_android_event (struct android_display_info *dpyinfo, SET_FRAME_VISIBLE (any, true); SET_FRAME_ICONIFIED (any, false); - inev.ie.kind = DEICONIFY_EVENT; - XSETFRAME (inev.ie.frame_or_window, any); + inev.kind = DEICONIFY_EVENT; + XSETFRAME (inev.frame_or_window, any); goto OTHER; /* Context menu handling. */ @@ -1757,12 +1755,12 @@ handle_one_android_event (struct android_display_info *dpyinfo, goto OTHER; /* Generate a drag and drop event to convey its position. */ - inev.ie.kind = DRAG_N_DROP_EVENT; - XSETFRAME (inev.ie.frame_or_window, any); - inev.ie.timestamp = ANDROID_CURRENT_TIME; - XSETINT (inev.ie.x, event->dnd.x); - XSETINT (inev.ie.y, event->dnd.y); - inev.ie.arg = Fcons (inev.ie.x, inev.ie.y); + inev.kind = DRAG_N_DROP_EVENT; + XSETFRAME (inev.frame_or_window, any); + inev.timestamp = ANDROID_CURRENT_TIME; + XSETINT (inev.x, event->dnd.x); + XSETINT (inev.y, event->dnd.y); + inev.arg = Fcons (inev.x, inev.y); goto OTHER; case ANDROID_DND_URI_EVENT: @@ -1778,15 +1776,15 @@ handle_one_android_event (struct android_display_info *dpyinfo, content or file URI or a string to be inserted. Generate an event with this information. */ - inev.ie.kind = DRAG_N_DROP_EVENT; - XSETFRAME (inev.ie.frame_or_window, any); - inev.ie.timestamp = ANDROID_CURRENT_TIME; - XSETINT (inev.ie.x, event->dnd.x); - XSETINT (inev.ie.y, event->dnd.y); - inev.ie.arg = Fcons ((event->type == ANDROID_DND_TEXT_EVENT - ? Qtext : Quri), - android_decode_utf16 (event->dnd.uri_or_string, - event->dnd.length)); + inev.kind = DRAG_N_DROP_EVENT; + XSETFRAME (inev.frame_or_window, any); + inev.timestamp = ANDROID_CURRENT_TIME; + XSETINT (inev.x, event->dnd.x); + XSETINT (inev.y, event->dnd.y); + inev.arg = Fcons ((event->type == ANDROID_DND_TEXT_EVENT + ? Qtext : Quri), + android_decode_utf16 (event->dnd.uri_or_string, + event->dnd.length)); free (event->dnd.uri_or_string); goto OTHER; @@ -1794,15 +1792,14 @@ handle_one_android_event (struct android_display_info *dpyinfo, case ANDROID_NOTIFICATION_ACTION: if (event->notification.type == ANDROID_NOTIFICATION_DELETED) - android_notification_deleted (&event->notification, &inev.ie); + android_notification_deleted (&event->notification, &inev); else { Lisp_Object action; action = android_decode_utf16 (event->notification.action, event->notification.length); - android_notification_action (&event->notification, &inev.ie, - action); + android_notification_action (&event->notification, &inev, action); } /* Free dynamically allocated data. */ @@ -1815,9 +1812,9 @@ handle_one_android_event (struct android_display_info *dpyinfo, } OTHER: - if (inev.ie.kind != NO_EVENT) + if (inev.kind != NO_EVENT) { - kbd_buffer_store_buffered_event (&inev, hold_quit); + kbd_buffer_store_event_hold (&inev, hold_quit); count++; } diff --git a/src/gtkutil.c b/src/gtkutil.c index 0770874eb40..164531aaeb3 100644 --- a/src/gtkutil.c +++ b/src/gtkutil.c @@ -6382,7 +6382,7 @@ xg_widget_key_press_event_cb (GtkWidget *widget, GdkEvent *event, { Lisp_Object tail, tem; struct frame *f = NULL; - union buffered_input_event inev; + struct input_event inev; guint keysym = event->key.keyval; unsigned int xstate; gunichar uc; @@ -6419,15 +6419,15 @@ xg_widget_key_press_event_cb (GtkWidget *widget, GdkEvent *event, && !FRAME_DISPLAY_INFO (f)->prefer_native_input) return true; - EVENT_INIT (inev.ie); - XSETFRAME (inev.ie.frame_or_window, f); + EVENT_INIT (inev); + XSETFRAME (inev.frame_or_window, f); xstate = xg_virtual_mods_to_x (FRAME_DISPLAY_INFO (f), event->key.state); - inev.ie.modifiers + inev.modifiers |= x_x_to_emacs_modifiers (FRAME_DISPLAY_INFO (f), xstate); - inev.ie.timestamp = event->key.time; + inev.timestamp = event->key.time; #ifdef HAVE_XINPUT2 if (event->key.time == pending_keystroke_time) @@ -6436,7 +6436,7 @@ xg_widget_key_press_event_cb (GtkWidget *widget, GdkEvent *event, FRAME_DISPLAY_INFO (f)->pending_keystroke_source); if (source) - inev.ie.device = source->name; + inev.device = source->name; } #endif @@ -6455,8 +6455,8 @@ xg_widget_key_press_event_cb (GtkWidget *widget, GdkEvent *event, if (keysym >= 32 && keysym < 128) /* Avoid explicitly decoding each ASCII character. */ { - inev.ie.kind = ASCII_KEYSTROKE_EVENT; - inev.ie.code = keysym; + inev.kind = ASCII_KEYSTROKE_EVENT; + inev.code = keysym; goto done; } @@ -6464,10 +6464,10 @@ xg_widget_key_press_event_cb (GtkWidget *widget, GdkEvent *event, if (keysym >= 0x01000000 && keysym <= 0x0110FFFF) { if (keysym < 0x01000080) - inev.ie.kind = ASCII_KEYSTROKE_EVENT; + inev.kind = ASCII_KEYSTROKE_EVENT; else - inev.ie.kind = MULTIBYTE_CHAR_KEYSTROKE_EVENT; - inev.ie.code = keysym & 0xFFFFFF; + inev.kind = MULTIBYTE_CHAR_KEYSTROKE_EVENT; + inev.code = keysym & 0xFFFFFF; goto done; } @@ -6523,8 +6523,8 @@ xg_widget_key_press_event_cb (GtkWidget *widget, GdkEvent *event, /* Any "vendor-specific" key is ok. */ || (keysym & (1 << 28)))) { - inev.ie.kind = NON_ASCII_KEYSTROKE_EVENT; - inev.ie.code = keysym; + inev.kind = NON_ASCII_KEYSTROKE_EVENT; + inev.code = keysym; goto done; } @@ -6532,22 +6532,22 @@ xg_widget_key_press_event_cb (GtkWidget *widget, GdkEvent *event, if (uc) { - inev.ie.kind = (SINGLE_BYTE_CHAR_P (uc) - ? ASCII_KEYSTROKE_EVENT - : MULTIBYTE_CHAR_KEYSTROKE_EVENT); - inev.ie.code = uc; + inev.kind = (SINGLE_BYTE_CHAR_P (uc) + ? ASCII_KEYSTROKE_EVENT + : MULTIBYTE_CHAR_KEYSTROKE_EVENT); + inev.code = uc; } else { - inev.ie.kind = NON_ASCII_KEYSTROKE_EVENT; - inev.ie.code = keysym; + inev.kind = NON_ASCII_KEYSTROKE_EVENT; + inev.code = keysym; } done: - if (inev.ie.kind != NO_EVENT) + if (inev.kind != NO_EVENT) { xg_pending_quit_event.kind = NO_EVENT; - kbd_buffer_store_buffered_event (&inev, &xg_pending_quit_event); + kbd_buffer_store_event_hold (&inev, &xg_pending_quit_event); } XNoOp (FRAME_X_DISPLAY (f)); diff --git a/src/keyboard.c b/src/keyboard.c index b22814d702d..fd0ac01755e 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -408,7 +408,7 @@ static void timer_resume_idle (void); static void deliver_user_signal (int); static char *find_user_signal_name (int); static void store_user_signal_events (void); -static bool is_ignored_event (union buffered_input_event *); +static bool is_ignored_event_kind (enum event_kind); /* Advance or retreat a buffered input event pointer. */ @@ -3629,7 +3629,7 @@ readable_events (int flags) && (event->kind == FOCUS_IN_EVENT || event->kind == FOCUS_OUT_EVENT)) || (input_pending_p_filter_events - && is_ignored_event (event)))) + && is_ignored_event_kind (event->kind)))) #ifdef USE_TOOLKIT_SCROLL_BARS && !((flags & READABLE_EVENTS_IGNORE_SQUEEZABLES) && (event->kind == SCROLL_BAR_CLICK_EVENT @@ -3714,6 +3714,31 @@ kbd_buffer_store_event (register struct input_event *event) kbd_buffer_store_event_hold (event, 0); } +static void +beware_long_paste (void) +{ +#ifdef subprocesses + if (! (kbd_buffer_nr_stored () <= KBD_BUFFER_SIZE / 2 + && kbd_on_hold_p ())) + { + /* Don't read keyboard input until we have processed kbd_buffer. + This happens when pasting text longer than KBD_BUFFER_SIZE/2. */ + hold_keyboard_input (); + unrequest_sigio (); + stop_polling (); + } +#endif +} + +/* If we're inside while-no-input, and this event qualifies + as input, set quit-flag to cause an interrupt. */ +static void +maybe_quit_while_no_input (enum event_kind kind) +{ + if (!NILP (Vthrow_on_input) && !is_ignored_event_kind (kind)) + Vquit_flag = Vthrow_on_input; +} + /* Store EVENT obtained at interrupt level into kbd_buffer, fifo. If HOLD_QUIT is 0, just stuff EVENT into the fifo. @@ -3725,8 +3750,8 @@ kbd_buffer_store_event (register struct input_event *event) subsequent input events have been parsed (and discarded). */ void -kbd_buffer_store_buffered_event (union buffered_input_event *event, - struct input_event *hold_quit) +kbd_buffer_store_event_hold (struct input_event *event, + struct input_event *hold_quit) { if (event->kind == NO_EVENT) emacs_abort (); @@ -3736,23 +3761,23 @@ kbd_buffer_store_buffered_event (union buffered_input_event *event, if (event->kind == ASCII_KEYSTROKE_EVENT) { - int c = event->ie.code & 0377; + int c = event->code & 0377; - if (event->ie.modifiers & ctrl_modifier) + if (event->modifiers & ctrl_modifier) c = make_ctrl_char (c); - c |= (event->ie.modifiers + c |= (event->modifiers & (meta_modifier | alt_modifier | hyper_modifier | super_modifier)); if (c == quit_char) { - KBOARD *kb = FRAME_KBOARD (XFRAME (event->ie.frame_or_window)); + KBOARD *kb = FRAME_KBOARD (XFRAME (event->frame_or_window)); if (single_kboard && kb != current_kboard) { kset_kbd_queue - (kb, list2 (make_lispy_switch_frame (event->ie.frame_or_window), + (kb, list2 (make_lispy_switch_frame (event->frame_or_window), make_fixnum (c))); kb->kbd_queue_has_data = true; @@ -3771,7 +3796,7 @@ kbd_buffer_store_buffered_event (union buffered_input_event *event, if (hold_quit) { - *hold_quit = event->ie; + *hold_quit = *event; return; } @@ -3782,9 +3807,9 @@ kbd_buffer_store_buffered_event (union buffered_input_event *event, { Lisp_Object focus; - focus = FRAME_FOCUS_FRAME (XFRAME (event->ie.frame_or_window)); + focus = FRAME_FOCUS_FRAME (XFRAME (event->frame_or_window)); if (NILP (focus)) - focus = event->ie.frame_or_window; + focus = event->frame_or_window; internal_last_event_frame = focus; Vlast_event_frame = focus; } @@ -3807,26 +3832,43 @@ kbd_buffer_store_buffered_event (union buffered_input_event *event, union buffered_input_event *next_slot = next_kbd_event (kbd_store_ptr); if (kbd_fetch_ptr != next_slot) { - *kbd_store_ptr = *event; + kbd_store_ptr->ie = *event; kbd_store_ptr = next_slot; -#ifdef subprocesses - if (kbd_buffer_nr_stored () > KBD_BUFFER_SIZE / 2 - && ! kbd_on_hold_p ()) - { - /* Don't read keyboard input until we have processed kbd_buffer. - This happens when pasting text longer than KBD_BUFFER_SIZE/2. */ - hold_keyboard_input (); - unrequest_sigio (); - stop_polling (); - } -#endif /* subprocesses */ + beware_long_paste (); } - /* If we're inside while-no-input, and this event qualifies - as input, set quit-flag to cause an interrupt. */ - if (!NILP (Vthrow_on_input) - && !is_ignored_event (event)) - Vquit_flag = Vthrow_on_input; + maybe_quit_while_no_input (event->kind); +} + +/* Store EVENT obtained at interrupt level into kbd_buffer, fifo. + This is like kbd_buffer_store_event_hold, but for struct + selection_input_event instead of struct input_event. + + If HOLD_QUIT && HOLD_QUIT->kind != NO_EVENT, discard EVENT. + + This is used to postpone the processing of the quit event until all + subsequent input events have been parsed (and discarded). */ + +void +kbd_buffer_store_selection_event_hold (struct selection_input_event *event, + struct input_event *hold_quit) +{ + if (hold_quit && hold_quit->kind != NO_EVENT) + return; + + /* Don't let the very last slot in the buffer become full, + since that would make the two pointers equal, + and that is indistinguishable from an empty buffer. + Discard the event if it would fill the last slot. */ + union buffered_input_event *next_slot = next_kbd_event (kbd_store_ptr); + if (kbd_fetch_ptr != next_slot) + { + kbd_store_ptr->sie = *event; + kbd_store_ptr = next_slot; + beware_long_paste (); + } + + maybe_quit_while_no_input (event->kind); } /* Limit help event positions to this range, to avoid overflow problems. */ @@ -12877,11 +12919,11 @@ init_while_no_input_ignore_events (void) } static bool -is_ignored_event (union buffered_input_event *event) +is_ignored_event_kind (enum event_kind kind) { Lisp_Object ignore_event; - switch (event->kind) + switch (kind) { case FOCUS_IN_EVENT: ignore_event = Qfocus_in; break; case FOCUS_OUT_EVENT: ignore_event = Qfocus_out; break; diff --git a/src/keyboard.h b/src/keyboard.h index 5e04b54eb74..ddbb1c3729e 100644 --- a/src/keyboard.h +++ b/src/keyboard.h @@ -499,17 +499,10 @@ extern void clear_waiting_for_input (void); extern void swallow_events (bool); extern bool lucid_event_type_list_p (Lisp_Object); extern void kbd_buffer_store_event (struct input_event *); -extern void kbd_buffer_store_buffered_event (union buffered_input_event *, - struct input_event *); -INLINE void -kbd_buffer_store_event_hold (struct input_event *event, - struct input_event *hold_quit) -{ - static_assert (alignof (struct input_event) == alignof (union buffered_input_event) - && sizeof (struct input_event) == sizeof (union buffered_input_event)); - kbd_buffer_store_buffered_event ((union buffered_input_event *) event, - hold_quit); -} +extern void kbd_buffer_store_event_hold (struct input_event *, + struct input_event *); +extern void kbd_buffer_store_selection_event_hold (struct selection_input_event *, + struct input_event *); extern void poll_for_input_1 (void); extern void show_help_echo (Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object); diff --git a/src/pgtkterm.c b/src/pgtkterm.c index 00377ff73a0..0ef6084d2f4 100644 --- a/src/pgtkterm.c +++ b/src/pgtkterm.c @@ -286,12 +286,8 @@ flip_cr_context (struct frame *f) static void -evq_enqueue (union buffered_input_event *ev) +evq_grow_if_needed (struct event_queue_t *evq) { - struct event_queue_t *evq = &event_q; - struct frame *frame; - struct pgtk_display_info *dpyinfo; - if (evq->cap == 0) { evq->cap = 4; @@ -303,32 +299,48 @@ evq_enqueue (union buffered_input_event *ev) evq->cap += evq->cap / 2; evq->q = xrealloc (evq->q, sizeof *evq->q * evq->cap); } +} + +static void +evq_enqueue (struct input_event const *ev) +{ + struct event_queue_t *evq = &event_q; + struct frame *frame; + struct pgtk_display_info *dpyinfo; - evq->q[evq->nr++] = *ev; + evq_grow_if_needed (evq); + evq->q[evq->nr++].ie = *ev; - if (ev->ie.kind != SELECTION_REQUEST_EVENT - && ev->ie.kind != SELECTION_CLEAR_EVENT) - { - frame = NULL; + frame = NULL; - if (WINDOWP (ev->ie.frame_or_window)) - frame = WINDOW_XFRAME (XWINDOW (ev->ie.frame_or_window)); + if (WINDOWP (ev->frame_or_window)) + frame = WINDOW_XFRAME (XWINDOW (ev->frame_or_window)); - if (FRAMEP (ev->ie.frame_or_window)) - frame = XFRAME (ev->ie.frame_or_window); + if (FRAMEP (ev->frame_or_window)) + frame = XFRAME (ev->frame_or_window); - if (frame) - { - dpyinfo = FRAME_DISPLAY_INFO (frame); + if (frame) + { + dpyinfo = FRAME_DISPLAY_INFO (frame); - if (dpyinfo->last_user_time < ev->ie.timestamp) - dpyinfo->last_user_time = ev->ie.timestamp; - } + if (dpyinfo->last_user_time < ev->timestamp) + dpyinfo->last_user_time = ev->timestamp; } raise (SIGIO); } +static void +evq_selection_enqueue (struct selection_input_event const *ev) +{ + struct event_queue_t *evq = &event_q; + + evq_grow_if_needed (evq); + evq->q[evq->nr++].sie = *ev; + + raise (SIGIO); +} + static int evq_flush (struct input_event *hold_quit) { @@ -337,17 +349,27 @@ evq_flush (struct input_event *hold_quit) while (evq->nr > 0) { - /* kbd_buffer_store_buffered_event may do longjmp, so - we need to shift event queue first and pass the event - to kbd_buffer_store_buffered_event so that events in + /* Because kbd_buffer_store_event_hold and + kbd_buffer_store_selection_event_hold may do longjmp, + we need to shift event queue before passing a pointer + to a copy of the event, so that events in queue are not processed twice. Bug#52941 */ - union buffered_input_event ev = evq->q[0]; - int i; - for (i = 1; i < evq->nr; i++) - evq->q[i - 1] = evq->q[i]; evq->nr--; - kbd_buffer_store_buffered_event (&ev, hold_quit); + if (evq->q[0].kind == SELECTION_REQUEST_EVENT + || evq->q[0].kind == SELECTION_CLEAR_EVENT) + { + struct selection_input_event sinev = evq->q[0].sie; + memmove (&evq->q[0], &evq->q[1], evq->nr * sizeof evq->q[0]); + kbd_buffer_store_selection_event_hold (&sinev, hold_quit); + } + else + { + struct input_event inev = evq->q[0].ie; + memmove (&evq->q[0], &evq->q[1], evq->nr * sizeof evq->q[0]); + kbd_buffer_store_event_hold (&inev, hold_quit); + } + n++; } @@ -3928,21 +3950,21 @@ static void pgtk_send_scroll_bar_event (Lisp_Object window, enum scroll_bar_part part, int portion, int whole, bool horizontal) { - union buffered_input_event inev; + struct input_event inev; - EVENT_INIT (inev.ie); + EVENT_INIT (inev); - inev.ie.kind = (horizontal - ? HORIZONTAL_SCROLL_BAR_CLICK_EVENT - : SCROLL_BAR_CLICK_EVENT); - inev.ie.frame_or_window = window; - inev.ie.arg = Qnil; - inev.ie.timestamp = 0; - inev.ie.code = 0; - inev.ie.part = part; - inev.ie.x = make_fixnum (portion); - inev.ie.y = make_fixnum (whole); - inev.ie.modifiers = 0; + inev.kind = (horizontal + ? HORIZONTAL_SCROLL_BAR_CLICK_EVENT + : SCROLL_BAR_CLICK_EVENT); + inev.frame_or_window = window; + inev.arg = Qnil; + inev.timestamp = 0; + inev.code = 0; + inev.part = part; + inev.x = make_fixnum (portion); + inev.y = make_fixnum (whole); + inev.modifiers = 0; evq_enqueue (&inev); } @@ -4942,7 +4964,6 @@ static gboolean pgtk_handle_event (GtkWidget *widget, GdkEvent *event, gpointer *data) { struct frame *f; - union buffered_input_event inev; GtkWidget *frame_widget; gint x, y; @@ -4959,18 +4980,18 @@ pgtk_handle_event (GtkWidget *widget, GdkEvent *event, gpointer *data) &x, &y); if (f) { - - inev.ie.kind = PINCH_EVENT; - XSETFRAME (inev.ie.frame_or_window, f); - XSETINT (inev.ie.x, x); - XSETINT (inev.ie.y, y); - inev.ie.arg = list4 (make_float (event->touchpad_pinch.dx), - make_float (event->touchpad_pinch.dy), - make_float (event->touchpad_pinch.scale), - make_float (event->touchpad_pinch.angle_delta)); - inev.ie.modifiers = pgtk_gtk_to_emacs_modifiers (FRAME_DISPLAY_INFO (f), + struct input_event inev; + inev.kind = PINCH_EVENT; + XSETFRAME (inev.frame_or_window, f); + XSETINT (inev.x, x); + XSETINT (inev.y, y); + inev.arg = list4 (make_float (event->touchpad_pinch.dx), + make_float (event->touchpad_pinch.dy), + make_float (event->touchpad_pinch.scale), + make_float (event->touchpad_pinch.angle_delta)); + inev.modifiers = pgtk_gtk_to_emacs_modifiers (FRAME_DISPLAY_INFO (f), event->touchpad_pinch.state); - inev.ie.device + inev.device = pgtk_get_device_for_event (FRAME_DISPLAY_INFO (f), event); evq_enqueue (&inev); } @@ -5188,17 +5209,17 @@ pgtk_enqueue_string (struct frame *f, gchar *str) return; for (; *ustr != 0; ustr++) { - union buffered_input_event inev; + struct input_event inev; Lisp_Object c = make_fixnum (*ustr); - EVENT_INIT (inev.ie); - inev.ie.kind = (SINGLE_BYTE_CHAR_P (XFIXNAT (c)) - ? ASCII_KEYSTROKE_EVENT - : MULTIBYTE_CHAR_KEYSTROKE_EVENT); - inev.ie.arg = Qnil; - inev.ie.code = XFIXNAT (c); - XSETFRAME (inev.ie.frame_or_window, f); - inev.ie.modifiers = 0; - inev.ie.timestamp = 0; + EVENT_INIT (inev); + inev.kind = (SINGLE_BYTE_CHAR_P (XFIXNAT (c)) + ? ASCII_KEYSTROKE_EVENT + : MULTIBYTE_CHAR_KEYSTROKE_EVENT); + inev.arg = Qnil; + inev.code = XFIXNAT (c); + XSETFRAME (inev.frame_or_window, f); + inev.modifiers = 0; + inev.timestamp = 0; evq_enqueue (&inev); } @@ -5208,28 +5229,28 @@ pgtk_enqueue_string (struct frame *f, gchar *str) void pgtk_enqueue_preedit (struct frame *f, Lisp_Object preedit) { - union buffered_input_event inev; - EVENT_INIT (inev.ie); - inev.ie.kind = PREEDIT_TEXT_EVENT; - inev.ie.arg = preedit; - inev.ie.code = 0; - XSETFRAME (inev.ie.frame_or_window, f); - inev.ie.modifiers = 0; - inev.ie.timestamp = 0; + struct input_event inev; + EVENT_INIT (inev); + inev.kind = PREEDIT_TEXT_EVENT; + inev.arg = preedit; + inev.code = 0; + XSETFRAME (inev.frame_or_window, f); + inev.modifiers = 0; + inev.timestamp = 0; evq_enqueue (&inev); } static gboolean key_press_event (GtkWidget *widget, GdkEvent *event, gpointer *user_data) { - union buffered_input_event inev; + struct input_event inev; ptrdiff_t nbytes; Mouse_HLInfo *hlinfo; struct frame *f; struct pgtk_display_info *dpyinfo; f = pgtk_any_window_to_frame (gtk_widget_get_window (widget)); - EVENT_INIT (inev.ie); + EVENT_INIT (inev); hlinfo = MOUSE_HL_INFO (f); nbytes = 0; @@ -5300,20 +5321,20 @@ key_press_event (GtkWidget *widget, GdkEvent *event, gpointer *user_data) orig_keysym = keysym; /* Common for all keysym input events. */ - XSETFRAME (inev.ie.frame_or_window, f); - inev.ie.modifiers + XSETFRAME (inev.frame_or_window, f); + inev.modifiers = pgtk_gtk_to_emacs_modifiers (FRAME_DISPLAY_INFO (f), modifiers); - inev.ie.timestamp = event->key.time; + inev.timestamp = event->key.time; /* First deal with keysyms which have defined translations to characters. */ if (keysym >= 32 && keysym < 128) /* Avoid explicitly decoding each ASCII character. */ { - inev.ie.kind = ASCII_KEYSTROKE_EVENT; - inev.ie.code = keysym; + inev.kind = ASCII_KEYSTROKE_EVENT; + inev.code = keysym; - inev.ie.device + inev.device = pgtk_get_device_for_event (FRAME_DISPLAY_INFO (f), event); goto done; } @@ -5322,12 +5343,12 @@ key_press_event (GtkWidget *widget, GdkEvent *event, gpointer *user_data) if (keysym >= 0x01000000 && keysym <= 0x0110FFFF) { if (keysym < 0x01000080) - inev.ie.kind = ASCII_KEYSTROKE_EVENT; + inev.kind = ASCII_KEYSTROKE_EVENT; else - inev.ie.kind = MULTIBYTE_CHAR_KEYSTROKE_EVENT; - inev.ie.code = keysym & 0xFFFFFF; + inev.kind = MULTIBYTE_CHAR_KEYSTROKE_EVENT; + inev.code = keysym & 0xFFFFFF; - inev.ie.device + inev.device = pgtk_get_device_for_event (FRAME_DISPLAY_INFO (f), event); goto done; } @@ -5337,12 +5358,12 @@ key_press_event (GtkWidget *widget, GdkEvent *event, gpointer *user_data) && (c = Fgethash (make_fixnum (keysym), Vpgtk_keysym_table, Qnil), FIXNATP (c))) { - inev.ie.kind = (SINGLE_BYTE_CHAR_P (XFIXNAT (c)) - ? ASCII_KEYSTROKE_EVENT - : MULTIBYTE_CHAR_KEYSTROKE_EVENT); - inev.ie.code = XFIXNAT (c); + inev.kind = (SINGLE_BYTE_CHAR_P (XFIXNAT (c)) + ? ASCII_KEYSTROKE_EVENT + : MULTIBYTE_CHAR_KEYSTROKE_EVENT); + inev.code = XFIXNAT (c); - inev.ie.device + inev.device = pgtk_get_device_for_event (FRAME_DISPLAY_INFO (f), event); goto done; } @@ -5421,18 +5442,18 @@ key_press_event (GtkWidget *widget, GdkEvent *event, gpointer *user_data) { /* make_lispy_event will convert this to a symbolic key. */ - inev.ie.kind = NON_ASCII_KEYSTROKE_EVENT; - inev.ie.code = keysym; + inev.kind = NON_ASCII_KEYSTROKE_EVENT; + inev.code = keysym; - inev.ie.device + inev.device = pgtk_get_device_for_event (FRAME_DISPLAY_INFO (f), event); goto done; } { - inev.ie.kind = MULTIBYTE_CHAR_KEYSTROKE_EVENT; - inev.ie.arg = make_unibyte_string ((char *) copy_bufptr, nbytes); - inev.ie.device + inev.kind = MULTIBYTE_CHAR_KEYSTROKE_EVENT; + inev.arg = make_unibyte_string ((char *) copy_bufptr, nbytes); + inev.device = pgtk_get_device_for_event (FRAME_DISPLAY_INFO (f), event); if (keysym == GDK_KEY_VoidSymbol) @@ -5441,9 +5462,9 @@ key_press_event (GtkWidget *widget, GdkEvent *event, gpointer *user_data) } done: - if (inev.ie.kind != NO_EVENT) + if (inev.kind != NO_EVENT) { - XSETFRAME (inev.ie.frame_or_window, f); + XSETFRAME (inev.frame_or_window, f); evq_enqueue (&inev); } @@ -5522,11 +5543,11 @@ map_event (GtkWidget *widget, gpointer *user_data) { struct frame *f = pgtk_any_window_to_frame (event->any.window); - union buffered_input_event inev; + struct input_event inev; - EVENT_INIT (inev.ie); - inev.ie.kind = NO_EVENT; - inev.ie.arg = Qnil; + EVENT_INIT (inev); + inev.kind = NO_EVENT; + inev.arg = Qnil; if (f) { @@ -5553,12 +5574,12 @@ map_event (GtkWidget *widget, if (iconified) { - inev.ie.kind = DEICONIFY_EVENT; - XSETFRAME (inev.ie.frame_or_window, f); + inev.kind = DEICONIFY_EVENT; + XSETFRAME (inev.frame_or_window, f); } } - if (inev.ie.kind != NO_EVENT) + if (inev.kind != NO_EVENT) evq_enqueue (&inev); return FALSE; } @@ -5570,13 +5591,13 @@ window_state_event (GtkWidget *widget, { struct frame *f = pgtk_any_window_to_frame (event->window_state.window); GdkWindowState new_state; - union buffered_input_event inev; + struct input_event inev; new_state = event->window_state.new_window_state; - EVENT_INIT (inev.ie); - inev.ie.kind = NO_EVENT; - inev.ie.arg = Qnil; + EVENT_INIT (inev); + inev.kind = NO_EVENT; + inev.arg = Qnil; if (new_state & GDK_WINDOW_STATE_FULLSCREEN) store_frame_param (f, Qfullscreen, Qfullboth); @@ -5622,8 +5643,8 @@ window_state_event (GtkWidget *widget, else { FRAME_X_OUTPUT (f)->has_been_visible = true; - inev.ie.kind = DEICONIFY_EVENT; - XSETFRAME (inev.ie.frame_or_window, f); + inev.kind = DEICONIFY_EVENT; + XSETFRAME (inev.frame_or_window, f); SET_FRAME_ICONIFIED (f, false); SET_FRAME_VISIBLE (f, true); } @@ -5633,7 +5654,7 @@ window_state_event (GtkWidget *widget, else store_frame_param (f, Qsticky, Qnil); - if (inev.ie.kind != NO_EVENT) + if (inev.kind != NO_EVENT) evq_enqueue (&inev); return FALSE; } @@ -5643,19 +5664,19 @@ delete_event (GtkWidget *widget, GdkEvent *event, gpointer *user_data) { struct frame *f = pgtk_any_window_to_frame (event->any.window); - union buffered_input_event inev; + struct input_event inev; - EVENT_INIT (inev.ie); - inev.ie.kind = NO_EVENT; - inev.ie.arg = Qnil; + EVENT_INIT (inev); + inev.kind = NO_EVENT; + inev.arg = Qnil; if (f) { - inev.ie.kind = DELETE_WINDOW_EVENT; - XSETFRAME (inev.ie.frame_or_window, f); + inev.kind = DELETE_WINDOW_EVENT; + XSETFRAME (inev.frame_or_window, f); } - if (inev.ie.kind != NO_EVENT) + if (inev.kind != NO_EVENT) evq_enqueue (&inev); return TRUE; } @@ -5672,7 +5693,7 @@ delete_event (GtkWidget *widget, static void pgtk_focus_changed (gboolean is_enter, int state, struct pgtk_display_info *dpyinfo, struct frame *frame, - union buffered_input_event *bufp) + struct input_event *bufp) { if (is_enter) { @@ -5684,13 +5705,13 @@ pgtk_focus_changed (gboolean is_enter, int state, /* Don't stop displaying the initial startup message for a switch-frame event we don't need. */ /* When run as a daemon, Vterminal_frame is always NIL. */ - bufp->ie.arg = (((NILP (Vterminal_frame) - || !FRAME_PGTK_P (XFRAME (Vterminal_frame)) - || EQ (Fdaemonp (), Qt)) - && CONSP (Vframe_list) - && !NILP (XCDR (Vframe_list))) ? Qt : Qnil); - bufp->ie.kind = FOCUS_IN_EVENT; - XSETFRAME (bufp->ie.frame_or_window, frame); + bufp->arg = (((NILP (Vterminal_frame) + || !FRAME_PGTK_P (XFRAME (Vterminal_frame)) + || EQ (Fdaemonp (), Qt)) + && CONSP (Vframe_list) + && !NILP (XCDR (Vframe_list))) ? Qt : Qnil); + bufp->kind = FOCUS_IN_EVENT; + XSETFRAME (bufp->frame_or_window, frame); } frame->output_data.pgtk->focus_state |= state; @@ -5705,8 +5726,8 @@ pgtk_focus_changed (gboolean is_enter, int state, dpyinfo->x_focus_event_frame = 0; pgtk_new_focus_frame (dpyinfo, NULL); - bufp->ie.kind = FOCUS_OUT_EVENT; - XSETFRAME (bufp->ie.frame_or_window, frame); + bufp->kind = FOCUS_OUT_EVENT; + XSETFRAME (bufp->frame_or_window, frame); } if (frame->pointer_invisible) @@ -5718,7 +5739,7 @@ static gboolean enter_notify_event (GtkWidget *widget, GdkEvent *event, gpointer *user_data) { - union buffered_input_event inev; + struct input_event inev; struct frame *frame = pgtk_any_window_to_frame (gtk_widget_get_window (widget)); @@ -5730,14 +5751,14 @@ enter_notify_event (GtkWidget *widget, GdkEvent *event, int focus_state = focus_frame ? focus_frame->output_data.pgtk->focus_state : 0; - EVENT_INIT (inev.ie); - inev.ie.kind = NO_EVENT; - inev.ie.arg = Qnil; + EVENT_INIT (inev); + inev.kind = NO_EVENT; + inev.arg = Qnil; if (event->crossing.detail != GDK_NOTIFY_INFERIOR && event->crossing.focus && !(focus_state & FOCUS_EXPLICIT)) pgtk_focus_changed (TRUE, FOCUS_IMPLICIT, dpyinfo, frame, &inev); - if (inev.ie.kind != NO_EVENT) + if (inev.kind != NO_EVENT) evq_enqueue (&inev); return TRUE; } @@ -5746,7 +5767,7 @@ static gboolean leave_notify_event (GtkWidget *widget, GdkEvent *event, gpointer *user_data) { - union buffered_input_event inev; + struct input_event inev; struct frame *frame = pgtk_any_window_to_frame (gtk_widget_get_window (widget)); @@ -5767,9 +5788,9 @@ leave_notify_event (GtkWidget *widget, GdkEvent *event, hlinfo->mouse_face_mouse_frame = 0; } - EVENT_INIT (inev.ie); - inev.ie.kind = NO_EVENT; - inev.ie.arg = Qnil; + EVENT_INIT (inev); + inev.kind = NO_EVENT; + inev.arg = Qnil; if (event->crossing.detail != GDK_NOTIFY_INFERIOR && event->crossing.focus && !(focus_state & FOCUS_EXPLICIT)) @@ -5786,7 +5807,7 @@ leave_notify_event (GtkWidget *widget, GdkEvent *event, } } - if (inev.ie.kind != NO_EVENT) + if (inev.kind != NO_EVENT) evq_enqueue (&inev); return TRUE; } @@ -5794,20 +5815,20 @@ leave_notify_event (GtkWidget *widget, GdkEvent *event, static gboolean focus_in_event (GtkWidget *widget, GdkEvent *event, gpointer *user_data) { - union buffered_input_event inev; + struct input_event inev; struct frame *frame = pgtk_any_window_to_frame (gtk_widget_get_window (widget)); if (frame == NULL) return TRUE; - EVENT_INIT (inev.ie); - inev.ie.kind = NO_EVENT; - inev.ie.arg = Qnil; + EVENT_INIT (inev); + inev.kind = NO_EVENT; + inev.arg = Qnil; pgtk_focus_changed (TRUE, FOCUS_EXPLICIT, FRAME_DISPLAY_INFO (frame), frame, &inev); - if (inev.ie.kind != NO_EVENT) + if (inev.kind != NO_EVENT) evq_enqueue (&inev); pgtk_im_focus_in (frame); @@ -5818,20 +5839,20 @@ focus_in_event (GtkWidget *widget, GdkEvent *event, gpointer *user_data) static gboolean focus_out_event (GtkWidget *widget, GdkEvent *event, gpointer *user_data) { - union buffered_input_event inev; + struct input_event inev; struct frame *frame = pgtk_any_window_to_frame (gtk_widget_get_window (widget)); if (frame == NULL) return TRUE; - EVENT_INIT (inev.ie); - inev.ie.kind = NO_EVENT; - inev.ie.arg = Qnil; + EVENT_INIT (inev); + inev.kind = NO_EVENT; + inev.arg = Qnil; pgtk_focus_changed (FALSE, FOCUS_EXPLICIT, FRAME_DISPLAY_INFO (frame), frame, &inev); - if (inev.ie.kind != NO_EVENT) + if (inev.kind != NO_EVENT) evq_enqueue (&inev); pgtk_im_focus_out (frame); @@ -5901,7 +5922,7 @@ static gboolean motion_notify_event (GtkWidget *widget, GdkEvent *event, gpointer *user_data) { - union buffered_input_event inev; + struct input_event inev; struct frame *f, *frame; struct pgtk_display_info *dpyinfo; Mouse_HLInfo *hlinfo; @@ -5917,9 +5938,9 @@ motion_notify_event (GtkWidget *widget, GdkEvent *event, && (gdk_device_get_source (device) == GDK_SOURCE_TOUCHSCREEN))) return FALSE; - EVENT_INIT (inev.ie); - inev.ie.kind = NO_EVENT; - inev.ie.arg = Qnil; + EVENT_INIT (inev); + inev.kind = NO_EVENT; + inev.arg = Qnil; previous_help_echo_string = help_echo_string; help_echo_string = Qnil; @@ -5970,8 +5991,8 @@ motion_notify_event (GtkWidget *widget, GdkEvent *event, && !EQ (window, last_mouse_window) && !EQ (window, selected_window)) { - inev.ie.kind = SELECT_WINDOW_EVENT; - inev.ie.frame_or_window = window; + inev.kind = SELECT_WINDOW_EVENT; + inev.frame_or_window = window; } /* Remember the last window where we saw the mouse. */ @@ -5992,7 +6013,7 @@ motion_notify_event (GtkWidget *widget, GdkEvent *event, if (!NILP (help_echo_string) || !NILP (previous_help_echo_string)) do_help = 1; - if (inev.ie.kind != NO_EVENT) + if (inev.kind != NO_EVENT) evq_enqueue (&inev); if (do_help > 0) @@ -6045,7 +6066,7 @@ static gboolean button_event (GtkWidget *widget, GdkEvent *event, gpointer *user_data) { - union buffered_input_event inev; + struct input_event inev; struct frame *f, *frame; struct pgtk_display_info *dpyinfo; @@ -6066,9 +6087,9 @@ button_event (GtkWidget *widget, GdkEvent *event, && (gdk_device_get_source (device) == GDK_SOURCE_TOUCHSCREEN))) return FALSE; - EVENT_INIT (inev.ie); - inev.ie.kind = NO_EVENT; - inev.ie.arg = Qnil; + EVENT_INIT (inev); + inev.kind = NO_EVENT; + inev.arg = Qnil; /* ignore double click and triple click. */ if (event->type != GDK_BUTTON_PRESS && event->type != GDK_BUTTON_RELEASE) @@ -6137,16 +6158,16 @@ button_event (GtkWidget *widget, GdkEvent *event, && event->button.time > ignore_next_mouse_click_timeout) { ignore_next_mouse_click_timeout = 0; - construct_mouse_click (&inev.ie, &event->button, f); + construct_mouse_click (&inev, &event->button, f); } if (event->type == GDK_BUTTON_RELEASE) ignore_next_mouse_click_timeout = 0; } else - construct_mouse_click (&inev.ie, &event->button, f); + construct_mouse_click (&inev, &event->button, f); if (!NILP (tab_bar_arg)) - inev.ie.arg = tab_bar_arg; + inev.arg = tab_bar_arg; } } @@ -6168,7 +6189,7 @@ button_event (GtkWidget *widget, GdkEvent *event, if (f != 0) f->mouse_moved = false; - if (inev.ie.kind != NO_EVENT) + if (inev.kind != NO_EVENT) evq_enqueue (&inev); return TRUE; } @@ -6176,15 +6197,15 @@ button_event (GtkWidget *widget, GdkEvent *event, static gboolean scroll_event (GtkWidget *widget, GdkEvent *event, gpointer *user_data) { - union buffered_input_event inev; + struct input_event inev; struct frame *f, *frame; struct pgtk_display_info *dpyinfo; GdkScrollDirection dir; double delta_x, delta_y; - EVENT_INIT (inev.ie); - inev.ie.kind = NO_EVENT; - inev.ie.arg = Qnil; + EVENT_INIT (inev); + inev.kind = NO_EVENT; + inev.arg = Qnil; frame = pgtk_any_window_to_frame (gtk_widget_get_window (widget)); dpyinfo = FRAME_DISPLAY_INFO (frame); @@ -6194,19 +6215,19 @@ scroll_event (GtkWidget *widget, GdkEvent *event, gpointer *user_data) else f = pgtk_any_window_to_frame (gtk_widget_get_window (widget)); - inev.ie.kind = NO_EVENT; - inev.ie.timestamp = event->scroll.time; - inev.ie.modifiers + inev.kind = NO_EVENT; + inev.timestamp = event->scroll.time; + inev.modifiers = pgtk_gtk_to_emacs_modifiers (FRAME_DISPLAY_INFO (f), event->scroll.state); - XSETINT (inev.ie.x, event->scroll.x); - XSETINT (inev.ie.y, event->scroll.y); - XSETFRAME (inev.ie.frame_or_window, f); - inev.ie.arg = Qnil; + XSETINT (inev.x, event->scroll.x); + XSETINT (inev.y, event->scroll.y); + XSETFRAME (inev.frame_or_window, f); + inev.arg = Qnil; if (gdk_event_is_scroll_stop_event (event)) { - inev.ie.kind = TOUCH_END_EVENT; - inev.ie.device + inev.kind = TOUCH_END_EVENT; + inev.device = pgtk_get_device_for_event (FRAME_DISPLAY_INFO (f), event); evq_enqueue (&inev); return TRUE; @@ -6217,20 +6238,20 @@ scroll_event (GtkWidget *widget, GdkEvent *event, gpointer *user_data) switch (dir) { case GDK_SCROLL_UP: - inev.ie.kind = WHEEL_EVENT; - inev.ie.modifiers |= up_modifier; + inev.kind = WHEEL_EVENT; + inev.modifiers |= up_modifier; break; case GDK_SCROLL_DOWN: - inev.ie.kind = WHEEL_EVENT; - inev.ie.modifiers |= down_modifier; + inev.kind = WHEEL_EVENT; + inev.modifiers |= down_modifier; break; case GDK_SCROLL_LEFT: - inev.ie.kind = HORIZ_WHEEL_EVENT; - inev.ie.modifiers |= up_modifier; + inev.kind = HORIZ_WHEEL_EVENT; + inev.modifiers |= up_modifier; break; case GDK_SCROLL_RIGHT: - inev.ie.kind = HORIZ_WHEEL_EVENT; - inev.ie.modifiers |= down_modifier; + inev.kind = HORIZ_WHEEL_EVENT; + inev.modifiers |= down_modifier; break; case GDK_SCROLL_SMOOTH: /* shut up warning */ break; @@ -6240,14 +6261,14 @@ scroll_event (GtkWidget *widget, GdkEvent *event, gpointer *user_data) { if (!mwheel_coalesce_scroll_events) { - inev.ie.kind = ((fabs (delta_x) > fabs (delta_y)) - ? HORIZ_WHEEL_EVENT - : WHEEL_EVENT); - inev.ie.modifiers |= (inev.ie.kind == HORIZ_WHEEL_EVENT - ? (delta_x >= 0 ? up_modifier : down_modifier) - : (delta_y >= 0 ? down_modifier : up_modifier)); - inev.ie.arg = list3 (Qnil, make_float (-delta_x * 100), - make_float (-delta_y * 100)); + inev.kind = ((fabs (delta_x) > fabs (delta_y)) + ? HORIZ_WHEEL_EVENT + : WHEEL_EVENT); + inev.modifiers |= (inev.kind == HORIZ_WHEEL_EVENT + ? (delta_x >= 0 ? up_modifier : down_modifier) + : (delta_y >= 0 ? down_modifier : up_modifier)); + inev.arg = list3 (Qnil, make_float (-delta_x * 100), + make_float (-delta_y * 100)); } else { @@ -6256,21 +6277,21 @@ scroll_event (GtkWidget *widget, GdkEvent *event, gpointer *user_data) if (dpyinfo->scroll.acc_y >= dpyinfo->scroll.y_per_line) { int nlines = dpyinfo->scroll.acc_y / dpyinfo->scroll.y_per_line; - inev.ie.kind = WHEEL_EVENT; - inev.ie.modifiers |= down_modifier; - inev.ie.arg = list3 (make_fixnum (nlines), - make_float (-dpyinfo->scroll.acc_x * 100), - make_float (-dpyinfo->scroll.acc_y * 100)); + inev.kind = WHEEL_EVENT; + inev.modifiers |= down_modifier; + inev.arg = list3 (make_fixnum (nlines), + make_float (-dpyinfo->scroll.acc_x * 100), + make_float (-dpyinfo->scroll.acc_y * 100)); dpyinfo->scroll.acc_y -= dpyinfo->scroll.y_per_line * nlines; } else if (dpyinfo->scroll.acc_y <= -dpyinfo->scroll.y_per_line) { int nlines = -dpyinfo->scroll.acc_y / dpyinfo->scroll.y_per_line; - inev.ie.kind = WHEEL_EVENT; - inev.ie.modifiers |= up_modifier; - inev.ie.arg = list3 (make_fixnum (nlines), - make_float (-dpyinfo->scroll.acc_x * 100), - make_float (-dpyinfo->scroll.acc_y * 100)); + inev.kind = WHEEL_EVENT; + inev.modifiers |= up_modifier; + inev.arg = list3 (make_fixnum (nlines), + make_float (-dpyinfo->scroll.acc_x * 100), + make_float (-dpyinfo->scroll.acc_y * 100)); dpyinfo->scroll.acc_y -= -dpyinfo->scroll.y_per_line * nlines; } @@ -6278,31 +6299,31 @@ scroll_event (GtkWidget *widget, GdkEvent *event, gpointer *user_data) || !mwheel_coalesce_scroll_events) { int nchars = dpyinfo->scroll.acc_x / dpyinfo->scroll.x_per_char; - inev.ie.kind = HORIZ_WHEEL_EVENT; - inev.ie.modifiers |= up_modifier; - inev.ie.arg = list3 (make_fixnum (nchars), - make_float (-dpyinfo->scroll.acc_x * 100), - make_float (-dpyinfo->scroll.acc_y * 100)); + inev.kind = HORIZ_WHEEL_EVENT; + inev.modifiers |= up_modifier; + inev.arg = list3 (make_fixnum (nchars), + make_float (-dpyinfo->scroll.acc_x * 100), + make_float (-dpyinfo->scroll.acc_y * 100)); dpyinfo->scroll.acc_x -= dpyinfo->scroll.x_per_char * nchars; } else if (dpyinfo->scroll.acc_x <= -dpyinfo->scroll.x_per_char) { int nchars = -dpyinfo->scroll.acc_x / dpyinfo->scroll.x_per_char; - inev.ie.kind = HORIZ_WHEEL_EVENT; - inev.ie.modifiers |= down_modifier; - inev.ie.arg = list3 (make_fixnum (nchars), - make_float (-dpyinfo->scroll.acc_x * 100), - make_float (-dpyinfo->scroll.acc_y * 100)); + inev.kind = HORIZ_WHEEL_EVENT; + inev.modifiers |= down_modifier; + inev.arg = list3 (make_fixnum (nchars), + make_float (-dpyinfo->scroll.acc_x * 100), + make_float (-dpyinfo->scroll.acc_y * 100)); dpyinfo->scroll.acc_x -= -dpyinfo->scroll.x_per_char * nchars; } } } - if (inev.ie.kind != NO_EVENT) + if (inev.kind != NO_EVENT) { - inev.ie.device + inev.device = pgtk_get_device_for_event (FRAME_DISPLAY_INFO (f), event); evq_enqueue (&inev); } @@ -6397,7 +6418,7 @@ drag_leave (GtkWidget *widget, GdkDragContext *context, guint time, gpointer user_data) { struct frame *f; - union buffered_input_event inev; + struct input_event inev; f = pgtk_any_window_to_frame (gtk_widget_get_window (widget)); @@ -6411,16 +6432,16 @@ drag_leave (GtkWidget *widget, GdkDragContext *context, g_object_unref); } - EVENT_INIT (inev.ie); + EVENT_INIT (inev); - inev.ie.kind = DRAG_N_DROP_EVENT; - inev.ie.modifiers = 0; - inev.ie.arg = Qnil; - inev.ie.timestamp = time; + inev.kind = DRAG_N_DROP_EVENT; + inev.modifiers = 0; + inev.arg = Qnil; + inev.timestamp = time; - XSETINT (inev.ie.x, 0); - XSETINT (inev.ie.y, 0); - XSETFRAME (inev.ie.frame_or_window, f); + XSETINT (inev.x, 0); + XSETINT (inev.y, 0); + XSETFRAME (inev.frame_or_window, f); evq_enqueue (&inev); } @@ -6431,7 +6452,7 @@ drag_motion (GtkWidget *widget, GdkDragContext *context, { struct frame *f; - union buffered_input_event inev; + struct input_event inev; GdkAtom name; GdkDragAction suggestion; @@ -6457,18 +6478,18 @@ drag_motion (GtkWidget *widget, GdkDragContext *context, name = gdk_drag_get_selection (context); suggestion = gdk_drag_context_get_suggested_action (context); - EVENT_INIT (inev.ie); + EVENT_INIT (inev); - inev.ie.kind = DRAG_N_DROP_EVENT; - inev.ie.modifiers = 0; - inev.ie.arg = list4 (Qlambda, intern (gdk_atom_name (name)), - make_uint (time), - drag_action_to_symbol (suggestion)); - inev.ie.timestamp = time; + inev.kind = DRAG_N_DROP_EVENT; + inev.modifiers = 0; + inev.arg = list4 (Qlambda, intern (gdk_atom_name (name)), + make_uint (time), + drag_action_to_symbol (suggestion)); + inev.timestamp = time; - XSETINT (inev.ie.x, x); - XSETINT (inev.ie.y, y); - XSETFRAME (inev.ie.frame_or_window, f); + XSETINT (inev.x, x); + XSETINT (inev.y, y); + XSETFRAME (inev.frame_or_window, f); evq_enqueue (&inev); @@ -6480,7 +6501,7 @@ drag_drop (GtkWidget *widget, GdkDragContext *context, int x, int y, guint time, gpointer user_data) { struct frame *f; - union buffered_input_event inev; + struct input_event inev; GdkAtom name; GdkDragAction selected_action; @@ -6506,18 +6527,18 @@ drag_drop (GtkWidget *widget, GdkDragContext *context, name = gdk_drag_get_selection (context); selected_action = gdk_drag_context_get_selected_action (context); - EVENT_INIT (inev.ie); + EVENT_INIT (inev); - inev.ie.kind = DRAG_N_DROP_EVENT; - inev.ie.modifiers = 0; - inev.ie.arg = list4 (Qquote, intern (gdk_atom_name (name)), - make_uint (time), - drag_action_to_symbol (selected_action)); - inev.ie.timestamp = time; + inev.kind = DRAG_N_DROP_EVENT; + inev.modifiers = 0; + inev.arg = list4 (Qquote, intern (gdk_atom_name (name)), + make_uint (time), + drag_action_to_symbol (selected_action)); + inev.timestamp = time; - XSETINT (inev.ie.x, x); - XSETINT (inev.ie.y, y); - XSETFRAME (inev.ie.frame_or_window, f); + XSETINT (inev.x, x); + XSETINT (inev.y, y); + XSETFRAME (inev.frame_or_window, f); evq_enqueue (&inev); @@ -6645,12 +6666,12 @@ touch_event_cb (GtkWidget *self, GdkEvent *event, gpointer user_data) struct pgtk_display_info *dpyinfo; struct frame *f; EMACS_INT local_detail; - union buffered_input_event inev; + struct input_event inev; struct pgtk_touch_point *touchpoint; Lisp_Object arg = Qnil; int state; - EVENT_INIT (inev.ie); + EVENT_INIT (inev); f = pgtk_any_window_to_frame (gtk_widget_get_window (self)); eassert (f); @@ -6669,12 +6690,12 @@ touch_event_cb (GtkWidget *self, GdkEvent *event, gpointer user_data) event->touch.x, event->touch.y, f); /* Generate the input event. */ - inev.ie.kind = TOUCHSCREEN_BEGIN_EVENT; - inev.ie.timestamp = event->touch.time; - XSETFRAME (inev.ie.frame_or_window, f); - XSETINT (inev.ie.x, lrint (event->touch.x)); - XSETINT (inev.ie.y, lrint (event->touch.y)); - XSETINT (inev.ie.arg, local_detail); + inev.kind = TOUCHSCREEN_BEGIN_EVENT; + inev.timestamp = event->touch.time; + XSETFRAME (inev.frame_or_window, f); + XSETINT (inev.x, lrint (event->touch.x)); + XSETINT (inev.y, lrint (event->touch.y)); + XSETINT (inev.arg, local_detail); break; case GDK_TOUCH_UPDATE: @@ -6691,9 +6712,9 @@ touch_event_cb (GtkWidget *self, GdkEvent *event, gpointer user_data) /* Construct the input event. */ touchpoint->x = lrint (event->touch.x); touchpoint->y = lrint (event->touch.y); - inev.ie.kind = TOUCHSCREEN_UPDATE_EVENT; - inev.ie.timestamp = event->touch.time; - XSETFRAME (inev.ie.frame_or_window, f); + inev.kind = TOUCHSCREEN_UPDATE_EVENT; + inev.timestamp = event->touch.time; + XSETFRAME (inev.frame_or_window, f); for (touchpoint = dpyinfo->touchpoints; touchpoint; touchpoint = touchpoint->next) @@ -6704,7 +6725,7 @@ touch_event_cb (GtkWidget *self, GdkEvent *event, gpointer user_data) arg); } - inev.ie.arg = arg; + inev.arg = arg; break; case GDK_TOUCH_END: @@ -6717,14 +6738,14 @@ touch_event_cb (GtkWidget *self, GdkEvent *event, gpointer user_data) if (state) { /* ... generate a suitable event. */ - inev.ie.kind = TOUCHSCREEN_END_EVENT; - inev.ie.timestamp = event->touch.time; - inev.ie.modifiers = (event->type != GDK_TOUCH_END); - - XSETFRAME (inev.ie.frame_or_window, f); - XSETINT (inev.ie.x, lrint (event->touch.x)); - XSETINT (inev.ie.y, lrint (event->touch.y)); - XSETINT (inev.ie.arg, local_detail); + inev.kind = TOUCHSCREEN_END_EVENT; + inev.timestamp = event->touch.time; + inev.modifiers = (event->type != GDK_TOUCH_END); + + XSETFRAME (inev.frame_or_window, f); + XSETINT (inev.x, lrint (event->touch.x)); + XSETINT (inev.y, lrint (event->touch.y)); + XSETINT (inev.arg, local_detail); } break; @@ -6735,9 +6756,9 @@ touch_event_cb (GtkWidget *self, GdkEvent *event, gpointer user_data) /* If the above produced a workable event, report the name of the device that gave rise to it. */ - if (inev.ie.kind != NO_EVENT) + if (inev.kind != NO_EVENT) { - inev.ie.device = pgtk_get_device_for_event (dpyinfo, event); + inev.device = pgtk_get_device_for_event (dpyinfo, event); evq_enqueue (&inev); /* Next, save this event for future menu activations, unless it is @@ -6750,7 +6771,7 @@ touch_event_cb (GtkWidget *self, GdkEvent *event, gpointer user_data) } } - return inev.ie.kind != NO_EVENT; + return inev.kind != NO_EVENT; } @@ -6761,12 +6782,12 @@ static void pgtk_monitors_changed_cb (GdkScreen *screen, gpointer user_data) { struct terminal *terminal; - union buffered_input_event inev; + struct input_event inev; - EVENT_INIT (inev.ie); + EVENT_INIT (inev); terminal = user_data; - inev.ie.kind = MONITORS_CHANGED_EVENT; - XSETTERMINAL (inev.ie.arg, terminal); + inev.kind = MONITORS_CHANGED_EVENT; + XSETTERMINAL (inev.arg, terminal); evq_enqueue (&inev); } @@ -6928,7 +6949,6 @@ pgtk_selection_event (GtkWidget *widget, GdkEvent *event, gpointer user_data) { struct frame *f; - union buffered_input_event inev; if (event->type == GDK_PROPERTY_NOTIFY) pgtk_handle_property_notify (&event->property); @@ -6939,15 +6959,15 @@ pgtk_selection_event (GtkWidget *widget, GdkEvent *event, if (f) { - EVENT_INIT (inev.ie); + struct selection_input_event sinev = {0}; - inev.sie.kind = (event->type == GDK_SELECTION_CLEAR + sinev.kind = (event->type == GDK_SELECTION_CLEAR ? SELECTION_CLEAR_EVENT : SELECTION_REQUEST_EVENT); - SELECTION_EVENT_DPYINFO (&inev.sie) = FRAME_DISPLAY_INFO (f); - SELECTION_EVENT_SELECTION (&inev.sie) = event->selection.selection; - SELECTION_EVENT_TIME (&inev.sie) = event->selection.time; + SELECTION_EVENT_DPYINFO (&sinev) = FRAME_DISPLAY_INFO (f); + SELECTION_EVENT_SELECTION (&sinev) = event->selection.selection; + SELECTION_EVENT_TIME (&sinev) = event->selection.time; if (event->type == GDK_SELECTION_REQUEST) { @@ -6957,12 +6977,12 @@ pgtk_selection_event (GtkWidget *widget, GdkEvent *event, It would make sense to wait for the transfer to complete. But I don't know if GDK actually does that. */ - SELECTION_EVENT_REQUESTOR (&inev.sie) = event->selection.requestor; - SELECTION_EVENT_TARGET (&inev.sie) = event->selection.target; - SELECTION_EVENT_PROPERTY (&inev.sie) = event->selection.property; + SELECTION_EVENT_REQUESTOR (&sinev) = event->selection.requestor; + SELECTION_EVENT_TARGET (&sinev) = event->selection.target; + SELECTION_EVENT_PROPERTY (&sinev) = event->selection.property; } - evq_enqueue (&inev); + evq_selection_enqueue (&sinev); return TRUE; } } diff --git a/src/xterm.c b/src/xterm.c index 2ccf267bbd3..aa2116a4b9f 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -18881,7 +18881,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, #endif int *finish, struct input_event *hold_quit) { - union buffered_input_event inev; + struct input_event inev; int count = 0; int do_help = 0; #ifdef HAVE_XINPUT2 @@ -18924,9 +18924,9 @@ handle_one_xevent (struct x_display_info *dpyinfo, *finish = X_EVENT_NORMAL; - EVENT_INIT (inev.ie); - inev.ie.kind = NO_EVENT; - inev.ie.arg = Qnil; + EVENT_INIT (inev); + inev.kind = NO_EVENT; + inev.arg = Qnil; #ifdef HAVE_XINPUT2 gen_help_device = NULL; #endif @@ -19257,9 +19257,9 @@ handle_one_xevent (struct x_display_info *dpyinfo, if (!f) goto OTHER; /* May be a dialog that is to be removed */ - inev.ie.kind = DELETE_WINDOW_EVENT; - inev.ie.timestamp = event->xclient.data.l[1]; - XSETFRAME (inev.ie.frame_or_window, f); + inev.kind = DELETE_WINDOW_EVENT; + inev.timestamp = event->xclient.data.l[1]; + XSETFRAME (inev.frame_or_window, f); goto done; } @@ -19413,7 +19413,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, /* Convert the scroll bar event to an input event using the first window entered into the scroll bar event queue. */ - x_scroll_bar_to_input_event (dpyinfo, event, &inev.ie); + x_scroll_bar_to_input_event (dpyinfo, event, &inev); *finish = X_EVENT_GOTO_OUT; goto done; @@ -19423,8 +19423,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, /* Convert the horizontal scroll bar event to an input event using the first window entered into the scroll bar event queue. */ - x_horizontal_scroll_bar_to_input_event (dpyinfo, event, - &inev.ie); + x_horizontal_scroll_bar_to_input_event (dpyinfo, event, &inev); *finish = X_EVENT_GOTO_OUT; goto done; @@ -19436,7 +19435,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, { enum xembed_message msg = event->xclient.data.l[1]; if (msg == XEMBED_FOCUS_IN || msg == XEMBED_FOCUS_OUT) - x_detect_focus_change (dpyinfo, any, event, &inev.ie); + x_detect_focus_change (dpyinfo, any, event, &inev); *finish = X_EVENT_GOTO_OUT; goto done; @@ -19475,7 +19474,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, rc = x_coords_from_dnd_message (dpyinfo, (XEvent *) event, &dx, &dy); - if (x_handle_dnd_message (f, &event->xclient, dpyinfo, &inev.ie, + if (x_handle_dnd_message (f, &event->xclient, dpyinfo, &inev, rc, dx, dy)) *finish = X_EVENT_DROP; } @@ -19511,15 +19510,18 @@ handle_one_xevent (struct x_display_info *dpyinfo, || dpyinfo->motif_drag_atom_time <= eventp->time)) dpyinfo->motif_drag_atom = None; - inev.sie.kind = SELECTION_CLEAR_EVENT; - SELECTION_EVENT_DPYINFO (&inev.sie) = dpyinfo; - SELECTION_EVENT_SELECTION (&inev.sie) = eventp->selection; - SELECTION_EVENT_TIME (&inev.sie) = eventp->time; + struct selection_input_event sinev = {0}; + sinev.kind = SELECTION_CLEAR_EVENT; + SELECTION_EVENT_DPYINFO (&sinev) = dpyinfo; + SELECTION_EVENT_SELECTION (&sinev) = eventp->selection; + SELECTION_EVENT_TIME (&sinev) = eventp->time; if (x_use_pending_selection_requests) + x_push_selection_request (&sinev); + else { - x_push_selection_request (&inev.sie); - EVENT_INIT (inev.ie); + kbd_buffer_store_selection_event_hold (&sinev, hold_quit); + count++; } } break; @@ -19535,22 +19537,25 @@ handle_one_xevent (struct x_display_info *dpyinfo, { const XSelectionRequestEvent *eventp = &event->xselectionrequest; - inev.sie.kind = SELECTION_REQUEST_EVENT; - SELECTION_EVENT_DPYINFO (&inev.sie) = dpyinfo; - SELECTION_EVENT_REQUESTOR (&inev.sie) = eventp->requestor; - SELECTION_EVENT_SELECTION (&inev.sie) = eventp->selection; - SELECTION_EVENT_TARGET (&inev.sie) = eventp->target; - SELECTION_EVENT_PROPERTY (&inev.sie) = eventp->property; - SELECTION_EVENT_TIME (&inev.sie) = eventp->time; + struct selection_input_event sinev; + sinev.kind = SELECTION_REQUEST_EVENT; + SELECTION_EVENT_DPYINFO (&sinev) = dpyinfo; + SELECTION_EVENT_REQUESTOR (&sinev) = eventp->requestor; + SELECTION_EVENT_SELECTION (&sinev) = eventp->selection; + SELECTION_EVENT_TARGET (&sinev) = eventp->target; + SELECTION_EVENT_PROPERTY (&sinev) = eventp->property; + SELECTION_EVENT_TIME (&sinev) = eventp->time; /* If drag-and-drop or another modal dialog/menu is in progress, handle SelectionRequest events immediately, by pushing it onto the selection queue. */ if (x_use_pending_selection_requests) + x_push_selection_request (&sinev); + else { - x_push_selection_request (&inev.sie); - EVENT_INIT (inev.ie); + kbd_buffer_store_selection_event_hold (&sinev, hold_quit); + count++; } if (x_dnd_waiting_for_finish @@ -19649,7 +19654,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, SET_FRAME_ICONIFIED (f, false); f->output_data.x->has_been_visible = true; - inev.ie.kind = DEICONIFY_EVENT; + inev.kind = DEICONIFY_EVENT; #if defined USE_GTK && defined HAVE_GTK3 /* If GTK3 wants to impose some old size here (Bug#24526), tell it that the current size is what we want. */ @@ -19660,7 +19665,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, f->was_invisible = false; } #endif - XSETFRAME (inev.ie.frame_or_window, f); + XSETFRAME (inev.frame_or_window, f); } else if (!not_hidden && !FRAME_ICONIFIED_P (f)) { @@ -19670,8 +19675,8 @@ handle_one_xevent (struct x_display_info *dpyinfo, SET_FRAME_VISIBLE (f, 0); SET_FRAME_ICONIFIED (f, true); - inev.ie.kind = ICONIFY_EVENT; - XSETFRAME (inev.ie.frame_or_window, f); + inev.kind = ICONIFY_EVENT; + XSETFRAME (inev.frame_or_window, f); } } @@ -19686,7 +19691,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, set. Handling UnmapNotify also checks for _NET_WM_STATE_HIDDEN, and thus suffers from the same problem. */ - x_handle_wm_state (f, &inev.ie); + x_handle_wm_state (f, &inev); if (f && FRAME_X_OUTPUT (f)->alpha_identical_p && (event->xproperty.atom @@ -20088,8 +20093,8 @@ handle_one_xevent (struct x_display_info *dpyinfo, (f, build_string ("UnmapNotify, visible | iconified")); SET_FRAME_ICONIFIED (f, true); - inev.ie.kind = ICONIFY_EVENT; - XSETFRAME (inev.ie.frame_or_window, f); + inev.kind = ICONIFY_EVENT; + XSETFRAME (inev.frame_or_window, f); } else if (CONSP (frame_size_history)) frame_size_history_plain @@ -20198,8 +20203,8 @@ handle_one_xevent (struct x_display_info *dpyinfo, if ((not_hidden || FRAME_X_EMBEDDED_P (f)) && iconified) { - inev.ie.kind = DEICONIFY_EVENT; - XSETFRAME (inev.ie.frame_or_window, f); + inev.kind = DEICONIFY_EVENT; + XSETFRAME (inev.frame_or_window, f); } } goto OTHER; @@ -20465,18 +20470,17 @@ handle_one_xevent (struct x_display_info *dpyinfo, orig_keysym = keysym; /* Common for all keysym input events. */ - XSETFRAME (inev.ie.frame_or_window, f); - inev.ie.modifiers - = x_x_to_emacs_modifiers (dpyinfo, modifiers); - inev.ie.timestamp = xkey.time; + XSETFRAME (inev.frame_or_window, f); + inev.modifiers = x_x_to_emacs_modifiers (dpyinfo, modifiers); + inev.timestamp = xkey.time; /* First deal with keysyms which have defined translations to characters. */ if (keysym >= 32 && keysym < 128) /* Avoid explicitly decoding each ASCII character. */ { - inev.ie.kind = ASCII_KEYSTROKE_EVENT; - inev.ie.code = keysym; + inev.kind = ASCII_KEYSTROKE_EVENT; + inev.code = keysym; #ifdef HAVE_XINPUT2 if (event->xkey.time == pending_keystroke_time) @@ -20485,7 +20489,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, dpyinfo->pending_keystroke_source); if (source) - inev.ie.device = source->name; + inev.device = source->name; } #endif @@ -20496,10 +20500,10 @@ handle_one_xevent (struct x_display_info *dpyinfo, if (keysym >= 0x01000000 && keysym <= 0x0110FFFF) { if (keysym < 0x01000080) - inev.ie.kind = ASCII_KEYSTROKE_EVENT; + inev.kind = ASCII_KEYSTROKE_EVENT; else - inev.ie.kind = MULTIBYTE_CHAR_KEYSTROKE_EVENT; - inev.ie.code = keysym & 0xFFFFFF; + inev.kind = MULTIBYTE_CHAR_KEYSTROKE_EVENT; + inev.code = keysym & 0xFFFFFF; #ifdef HAVE_XINPUT2 if (event->xkey.time == pending_keystroke_time) @@ -20508,7 +20512,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, dpyinfo->pending_keystroke_source); if (source) - inev.ie.device = source->name; + inev.device = source->name; } #endif @@ -20522,10 +20526,10 @@ handle_one_xevent (struct x_display_info *dpyinfo, Qnil), FIXNATP (c))) { - inev.ie.kind = (SINGLE_BYTE_CHAR_P (XFIXNAT (c)) - ? ASCII_KEYSTROKE_EVENT - : MULTIBYTE_CHAR_KEYSTROKE_EVENT); - inev.ie.code = XFIXNAT (c); + inev.kind = (SINGLE_BYTE_CHAR_P (XFIXNAT (c)) + ? ASCII_KEYSTROKE_EVENT + : MULTIBYTE_CHAR_KEYSTROKE_EVENT); + inev.code = XFIXNAT (c); #ifdef HAVE_XINPUT2 if (event->xkey.time == pending_keystroke_time) @@ -20534,7 +20538,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, dpyinfo->pending_keystroke_source); if (source) - inev.ie.device = source->name; + inev.device = source->name; } #endif @@ -20640,8 +20644,8 @@ handle_one_xevent (struct x_display_info *dpyinfo, STORE_KEYSYM_FOR_DEBUG (keysym); /* make_lispy_event will convert this to a symbolic key. */ - inev.ie.kind = NON_ASCII_KEYSTROKE_EVENT; - inev.ie.code = keysym; + inev.kind = NON_ASCII_KEYSTROKE_EVENT; + inev.code = keysym; #ifdef HAVE_XINPUT2 if (event->xkey.time == pending_keystroke_time) @@ -20650,7 +20654,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, dpyinfo->pending_keystroke_source); if (source) - inev.ie.device = source->name; + inev.device = source->name; } #endif @@ -20667,11 +20671,11 @@ handle_one_xevent (struct x_display_info *dpyinfo, if (nbytes) { - inev.ie.kind = MULTIBYTE_CHAR_KEYSTROKE_EVENT; - inev.ie.arg = make_unibyte_string ((char *) copy_bufptr, nbytes); + inev.kind = MULTIBYTE_CHAR_KEYSTROKE_EVENT; + inev.arg = make_unibyte_string ((char *) copy_bufptr, nbytes); Fput_text_property (make_fixnum (0), make_fixnum (nbytes), - Qcoding, coding, inev.ie.arg); + Qcoding, coding, inev.arg); #ifdef HAVE_XINPUT2 if (event->xkey.time == pending_keystroke_time @@ -20685,7 +20689,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, dpyinfo->pending_keystroke_source); if (source) - inev.ie.device = source->name; + inev.device = source->name; } #endif } @@ -20760,7 +20764,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, to treat implicit focus correctly. (bug#65919) */ #if defined USE_X_TOOLKIT || (defined USE_GTK && !defined HAVE_GTK3) if (x_top_window_to_frame (dpyinfo, event->xcrossing.window)) - x_detect_focus_change (dpyinfo, any, event, &inev.ie); + x_detect_focus_change (dpyinfo, any, event, &inev); #endif /* defined USE_X_TOOLKIT || (defined USE_GTK && !defined HAVE_GTK3) */ #ifdef HAVE_XINPUT2 @@ -20779,7 +20783,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, builds. */ #if !defined USE_X_TOOLKIT || (!defined USE_GTK || defined HAVE_GTK3) if (x_top_window_to_frame (dpyinfo, event->xcrossing.window)) - x_detect_focus_change (dpyinfo, any, event, &inev.ie); + x_detect_focus_change (dpyinfo, any, event, &inev); #endif /* !defined USE_X_TOOLKIT || (!defined USE_GTK || defined HAVE_GTK3) */ f = any; @@ -20853,12 +20857,12 @@ handle_one_xevent (struct x_display_info *dpyinfo, SET_FRAME_VISIBLE (f, 1); SET_FRAME_ICONIFIED (f, false); f->output_data.x->has_been_visible = true; - inev.ie.kind = DEICONIFY_EVENT; - XSETFRAME (inev.ie.frame_or_window, f); + inev.kind = DEICONIFY_EVENT; + XSETFRAME (inev.frame_or_window, f); } } - x_detect_focus_change (dpyinfo, any, event, &inev.ie); + x_detect_focus_change (dpyinfo, any, event, &inev); goto OTHER; case LeaveNotify: @@ -20870,7 +20874,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, to treat implicit focus correctly. */ #if defined USE_X_TOOLKIT || (defined USE_GTK && !defined HAVE_GTK3) if (x_top_window_to_frame (dpyinfo, event->xcrossing.window)) - x_detect_focus_change (dpyinfo, any, event, &inev.ie); + x_detect_focus_change (dpyinfo, any, event, &inev); #endif /* defined USE_X_TOOLKIT || (defined USE_GTK && !defined HAVE_GTK3) */ #ifdef HAVE_XINPUT2 @@ -20902,7 +20906,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, builds. */ #if !defined USE_X_TOOLKIT || (!defined USE_GTK || defined HAVE_GTK3) if (x_top_window_to_frame (dpyinfo, event->xcrossing.window)) - x_detect_focus_change (dpyinfo, any, event, &inev.ie); + x_detect_focus_change (dpyinfo, any, event, &inev); #endif /* !defined USE_X_TOOLKIT || (!defined USE_GTK || defined HAVE_GTK3) */ #ifdef HAVE_XWIDGETS @@ -21003,7 +21007,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, if (dpyinfo->supports_xi2) goto OTHER; #endif - x_detect_focus_change (dpyinfo, any, event, &inev.ie); + x_detect_focus_change (dpyinfo, any, event, &inev); goto OTHER; case MotionNotify: @@ -21313,8 +21317,8 @@ handle_one_xevent (struct x_display_info *dpyinfo, && !EQ (window, last_mouse_window) && !EQ (window, selected_window)) { - inev.ie.kind = SELECT_WINDOW_EVENT; - inev.ie.frame_or_window = window; + inev.kind = SELECT_WINDOW_EVENT; + inev.frame_or_window = window; } /* Remember the last window where we saw the mouse. */ @@ -21405,13 +21409,13 @@ handle_one_xevent (struct x_display_info *dpyinfo, hook. */ if (!x_find_monitors_changed_event (dpyinfo)) { - inev.ie.kind = MONITORS_CHANGED_EVENT; - XSETTERMINAL (inev.ie.arg, dpyinfo->terminal); + inev.kind = MONITORS_CHANGED_EVENT; + XSETTERMINAL (inev.arg, dpyinfo->terminal); - /* Store this event now since inev.ie.type could be set to + /* Store this event now since inev.type could be set to MOVE_FRAME_EVENT later. */ - kbd_buffer_store_event (&inev.ie); - inev.ie.kind = NO_EVENT; + kbd_buffer_store_event (&inev); + inev.kind = NO_EVENT; } /* Also update the position of the drag-and-drop @@ -21678,8 +21682,8 @@ handle_one_xevent (struct x_display_info *dpyinfo, if (!FRAME_TOOLTIP_P (f) && (old_left != f->left_pos || old_top != f->top_pos)) { - inev.ie.kind = MOVE_FRAME_EVENT; - XSETFRAME (inev.ie.frame_or_window, f); + inev.kind = MOVE_FRAME_EVENT; + XSETFRAME (inev.frame_or_window, f); } } @@ -21745,8 +21749,8 @@ handle_one_xevent (struct x_display_info *dpyinfo, if (!EQ (selected_window, xvw->w) && (event->xbutton.button < 4)) { - inev.ie.kind = SELECT_WINDOW_EVENT; - inev.ie.frame_or_window = xvw->w; + inev.kind = SELECT_WINDOW_EVENT; + inev.frame_or_window = xvw->w; } *finish = X_EVENT_DROP; @@ -22002,14 +22006,14 @@ handle_one_xevent (struct x_display_info *dpyinfo, && event->xbutton.time > ignore_next_mouse_click_timeout) { ignore_next_mouse_click_timeout = 0; - x_construct_mouse_click (&inev.ie, &event->xbutton, + x_construct_mouse_click (&inev, &event->xbutton, f, false); } if (event->type == ButtonRelease) ignore_next_mouse_click_timeout = 0; } else - x_construct_mouse_click (&inev.ie, &event->xbutton, f, false); + x_construct_mouse_click (&inev, &event->xbutton, f, false); *finish = X_EVENT_DROP; goto OTHER; @@ -22079,18 +22083,18 @@ handle_one_xevent (struct x_display_info *dpyinfo, && event->xbutton.time > ignore_next_mouse_click_timeout) { ignore_next_mouse_click_timeout = 0; - x_construct_mouse_click (&inev.ie, &event->xbutton, + x_construct_mouse_click (&inev, &event->xbutton, f, false); } if (event->type == ButtonRelease) ignore_next_mouse_click_timeout = 0; } else - x_construct_mouse_click (&inev.ie, &event->xbutton, + x_construct_mouse_click (&inev, &event->xbutton, f, false); if (!NILP (tab_bar_arg)) - inev.ie.arg = tab_bar_arg; + inev.arg = tab_bar_arg; } if (FRAME_X_EMBEDDED_P (f) @@ -22109,12 +22113,12 @@ handle_one_xevent (struct x_display_info *dpyinfo, scroll bars. */ if (bar && event->xbutton.state & ControlMask) { - x_scroll_bar_handle_click (bar, event, &inev.ie, Qnil); + x_scroll_bar_handle_click (bar, event, &inev, Qnil); *finish = X_EVENT_DROP; } #else /* not USE_TOOLKIT_SCROLL_BARS */ if (bar) - x_scroll_bar_handle_click (bar, event, &inev.ie, Qnil); + x_scroll_bar_handle_click (bar, event, &inev, Qnil); #endif /* not USE_TOOLKIT_SCROLL_BARS */ } @@ -22171,8 +22175,8 @@ handle_one_xevent (struct x_display_info *dpyinfo, if (!f->output_data.x->saved_menu_event) f->output_data.x->saved_menu_event = xmalloc (sizeof *event); *f->output_data.x->saved_menu_event = *event; - inev.ie.kind = MENU_BAR_ACTIVATE_EVENT; - XSETFRAME (inev.ie.frame_or_window, f); + inev.kind = MENU_BAR_ACTIVATE_EVENT; + XSETFRAME (inev.frame_or_window, f); *finish = X_EVENT_DROP; #ifdef USE_MOTIF } @@ -22323,8 +22327,8 @@ handle_one_xevent (struct x_display_info *dpyinfo, SET_FRAME_VISIBLE (f, 1); SET_FRAME_ICONIFIED (f, false); f->output_data.x->has_been_visible = true; - inev.ie.kind = DEICONIFY_EVENT; - XSETFRAME (inev.ie.frame_or_window, f); + inev.kind = DEICONIFY_EVENT; + XSETFRAME (inev.frame_or_window, f); } } @@ -22874,36 +22878,36 @@ handle_one_xevent (struct x_display_info *dpyinfo, if (fabs (total_x) > 0 || fabs (total_y) > 0) { - inev.ie.kind = (fabs (total_y) >= fabs (total_x) - ? WHEEL_EVENT : HORIZ_WHEEL_EVENT); - inev.ie.timestamp = xev->time; - - XSETINT (inev.ie.x, lrint (real_x)); - XSETINT (inev.ie.y, lrint (real_y)); - XSETFRAME (inev.ie.frame_or_window, f); - - inev.ie.modifiers = (signbit (fabs (total_y) >= fabs (total_x) - ? total_y : total_x) - ? down_modifier : up_modifier); - inev.ie.modifiers + inev.kind = (fabs (total_y) >= fabs (total_x) + ? WHEEL_EVENT : HORIZ_WHEEL_EVENT); + inev.timestamp = xev->time; + + XSETINT (inev.x, lrint (real_x)); + XSETINT (inev.y, lrint (real_y)); + XSETFRAME (inev.frame_or_window, f); + + inev.modifiers = (signbit (fabs (total_y) >= fabs (total_x) + ? total_y : total_x) + ? down_modifier : up_modifier); + inev.modifiers |= x_x_to_emacs_modifiers (dpyinfo, xev->mods.effective); - inev.ie.arg = list3 (Qnil, - make_float (total_x), - make_float (total_y)); + inev.arg = list3 (Qnil, + make_float (total_x), + make_float (total_y)); } else { - inev.ie.kind = TOUCH_END_EVENT; - inev.ie.timestamp = xev->time; + inev.kind = TOUCH_END_EVENT; + inev.timestamp = xev->time; - XSETINT (inev.ie.x, lrint (real_x)); - XSETINT (inev.ie.y, lrint (real_y)); - XSETFRAME (inev.ie.frame_or_window, f); + XSETINT (inev.x, lrint (real_x)); + XSETINT (inev.y, lrint (real_y)); + XSETFRAME (inev.frame_or_window, f); } if (source && !NILP (source->name)) - inev.ie.device = source->name; + inev.device = source->name; if (!other_valuators_found) goto XI_OTHER; @@ -23244,11 +23248,11 @@ handle_one_xevent (struct x_display_info *dpyinfo, && !EQ (window, last_mouse_window) && !EQ (window, selected_window)) { - inev.ie.kind = SELECT_WINDOW_EVENT; - inev.ie.frame_or_window = window; + inev.kind = SELECT_WINDOW_EVENT; + inev.frame_or_window = window; if (source) - inev.ie.device = source->name; + inev.device = source->name; } /* Remember the last window where we saw the mouse. */ @@ -23636,11 +23640,11 @@ handle_one_xevent (struct x_display_info *dpyinfo, if (!EQ (selected_window, xvw->w) && (xev->detail < 4)) { - inev.ie.kind = SELECT_WINDOW_EVENT; - inev.ie.frame_or_window = xvw->w; + inev.kind = SELECT_WINDOW_EVENT; + inev.frame_or_window = xvw->w; if (source) - inev.ie.device = source->name; + inev.device = source->name; } *finish = X_EVENT_DROP; @@ -23739,24 +23743,24 @@ handle_one_xevent (struct x_display_info *dpyinfo, &real_x, &real_y); if (xev->detail <= 5) - inev.ie.kind = WHEEL_EVENT; + inev.kind = WHEEL_EVENT; else - inev.ie.kind = HORIZ_WHEEL_EVENT; + inev.kind = HORIZ_WHEEL_EVENT; if (source) - inev.ie.device = source->name; + inev.device = source->name; - inev.ie.timestamp = xev->time; + inev.timestamp = xev->time; - XSETINT (inev.ie.x, real_x); - XSETINT (inev.ie.y, real_y); - XSETFRAME (inev.ie.frame_or_window, f); + XSETINT (inev.x, real_x); + XSETINT (inev.y, real_y); + XSETFRAME (inev.frame_or_window, f); - inev.ie.modifiers + inev.modifiers |= x_x_to_emacs_modifiers (dpyinfo, xev->mods.effective); - inev.ie.modifiers |= xev->detail % 2 ? down_modifier : up_modifier; + inev.modifiers |= xev->detail % 2 ? down_modifier : up_modifier; } *finish = X_EVENT_DROP; @@ -23777,24 +23781,24 @@ handle_one_xevent (struct x_display_info *dpyinfo, if (xev->evtype == XI_ButtonRelease) { if (xev->detail <= 5) - inev.ie.kind = WHEEL_EVENT; + inev.kind = WHEEL_EVENT; else - inev.ie.kind = HORIZ_WHEEL_EVENT; + inev.kind = HORIZ_WHEEL_EVENT; if (source) - inev.ie.device = source->name; + inev.device = source->name; - inev.ie.timestamp = xev->time; + inev.timestamp = xev->time; - XSETINT (inev.ie.x, lrint (xev->event_x)); - XSETINT (inev.ie.y, lrint (xev->event_y)); - XSETFRAME (inev.ie.frame_or_window, f); + XSETINT (inev.x, lrint (xev->event_x)); + XSETINT (inev.y, lrint (xev->event_y)); + XSETFRAME (inev.frame_or_window, f); - inev.ie.modifiers + inev.modifiers |= x_x_to_emacs_modifiers (dpyinfo, xev->mods.effective); - inev.ie.modifiers |= xev->detail % 2 ? down_modifier : up_modifier; + inev.modifiers |= xev->detail % 2 ? down_modifier : up_modifier; } goto XI_OTHER; @@ -23863,16 +23867,16 @@ handle_one_xevent (struct x_display_info *dpyinfo, && xev->time > ignore_next_mouse_click_timeout) { ignore_next_mouse_click_timeout = 0; - x_construct_mouse_click (&inev.ie, &bv, f, true); + x_construct_mouse_click (&inev, &bv, f, true); } if (xev->evtype == XI_ButtonRelease) ignore_next_mouse_click_timeout = 0; } else - x_construct_mouse_click (&inev.ie, &bv, f, true); + x_construct_mouse_click (&inev, &bv, f, true); if (!NILP (tab_bar_arg)) - inev.ie.arg = tab_bar_arg; + inev.arg = tab_bar_arg; } if (FRAME_X_EMBEDDED_P (f) @@ -23888,14 +23892,14 @@ handle_one_xevent (struct x_display_info *dpyinfo, #ifndef USE_TOOLKIT_SCROLL_BARS if (bar) - x_scroll_bar_handle_click (bar, (XEvent *) &bv, &inev.ie, + x_scroll_bar_handle_click (bar, (XEvent *) &bv, &inev, source ? source->name : Qnil); #else /* Make the "Ctrl-Mouse-2 splits window" work for toolkit scroll bars. */ if (bar && xev->mods.effective & ControlMask) { - x_scroll_bar_handle_click (bar, (XEvent *) &bv, &inev.ie, + x_scroll_bar_handle_click (bar, (XEvent *) &bv, &inev, source ? source->name : Qnil); *finish = X_EVENT_DROP; } @@ -23921,8 +23925,8 @@ handle_one_xevent (struct x_display_info *dpyinfo, device->grab &= ~(1 << xev->detail); } - if (source && inev.ie.kind != NO_EVENT) - inev.ie.device = source->name; + if (source && inev.kind != NO_EVENT) + inev.device = source->name; if (f) f->mouse_moved = false; @@ -24243,8 +24247,8 @@ handle_one_xevent (struct x_display_info *dpyinfo, *finish = X_EVENT_DROP; #endif /* USE_GTK */ - XSETFRAME (inev.ie.frame_or_window, f); - inev.ie.timestamp = xev->time; + XSETFRAME (inev.frame_or_window, f); + inev.timestamp = xev->time; #ifdef HAVE_X_I18N if (FRAME_XIC (f)) @@ -24356,7 +24360,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, } } - inev.ie.modifiers = x_x_to_emacs_modifiers (dpyinfo, state); + inev.modifiers = x_x_to_emacs_modifiers (dpyinfo, state); #ifdef XK_F1 if (x_dnd_in_progress @@ -24394,11 +24398,11 @@ handle_one_xevent (struct x_display_info *dpyinfo, if (keysym >= 32 && keysym < 128) /* Avoid explicitly decoding each ASCII character. */ { - inev.ie.kind = ASCII_KEYSTROKE_EVENT; - inev.ie.code = keysym; + inev.kind = ASCII_KEYSTROKE_EVENT; + inev.code = keysym; if (source) - inev.ie.device = source->name; + inev.device = source->name; goto xi_done_keysym; } @@ -24407,14 +24411,14 @@ handle_one_xevent (struct x_display_info *dpyinfo, if (keysym >= 0x01000000 && keysym <= 0x0110FFFF) { if (keysym < 0x01000080) - inev.ie.kind = ASCII_KEYSTROKE_EVENT; + inev.kind = ASCII_KEYSTROKE_EVENT; else - inev.ie.kind = MULTIBYTE_CHAR_KEYSTROKE_EVENT; + inev.kind = MULTIBYTE_CHAR_KEYSTROKE_EVENT; if (source) - inev.ie.device = source->name; + inev.device = source->name; - inev.ie.code = keysym & 0xFFFFFF; + inev.code = keysym & 0xFFFFFF; goto xi_done_keysym; } @@ -24425,13 +24429,13 @@ handle_one_xevent (struct x_display_info *dpyinfo, Qnil), FIXNATP (c))) { - inev.ie.kind = (SINGLE_BYTE_CHAR_P (XFIXNAT (c)) + inev.kind = (SINGLE_BYTE_CHAR_P (XFIXNAT (c)) ? ASCII_KEYSTROKE_EVENT : MULTIBYTE_CHAR_KEYSTROKE_EVENT); - inev.ie.code = XFIXNAT (c); + inev.code = XFIXNAT (c); if (source) - inev.ie.device = source->name; + inev.device = source->name; goto xi_done_keysym; } @@ -24535,11 +24539,11 @@ handle_one_xevent (struct x_display_info *dpyinfo, STORE_KEYSYM_FOR_DEBUG (keysym); /* make_lispy_event will convert this to a symbolic key. */ - inev.ie.kind = NON_ASCII_KEYSTROKE_EVENT; - inev.ie.code = keysym; + inev.kind = NON_ASCII_KEYSTROKE_EVENT; + inev.code = keysym; if (source) - inev.ie.device = source->name; + inev.device = source->name; goto xi_done_keysym; } @@ -24551,14 +24555,14 @@ handle_one_xevent (struct x_display_info *dpyinfo, if (nbytes) { - inev.ie.kind = MULTIBYTE_CHAR_KEYSTROKE_EVENT; - inev.ie.arg = make_unibyte_string (copy_bufptr, nbytes); + inev.kind = MULTIBYTE_CHAR_KEYSTROKE_EVENT; + inev.arg = make_unibyte_string (copy_bufptr, nbytes); Fput_text_property (make_fixnum (0), make_fixnum (nbytes), - Qcoding, coding, inev.ie.arg); + Qcoding, coding, inev.arg); if (source) - inev.ie.device = source->name; + inev.device = source->name; } goto xi_done_keysym; } @@ -24912,15 +24916,15 @@ handle_one_xevent (struct x_display_info *dpyinfo, xev->event_x, xev->event_y, f); - inev.ie.kind = TOUCHSCREEN_BEGIN_EVENT; - inev.ie.timestamp = xev->time; - XSETFRAME (inev.ie.frame_or_window, f); - XSETINT (inev.ie.x, lrint (xev->event_x)); - XSETINT (inev.ie.y, lrint (xev->event_y)); - XSETINT (inev.ie.arg, local_detail); + inev.kind = TOUCHSCREEN_BEGIN_EVENT; + inev.timestamp = xev->time; + XSETFRAME (inev.frame_or_window, f); + XSETINT (inev.x, lrint (xev->event_x)); + XSETINT (inev.y, lrint (xev->event_y)); + XSETINT (inev.arg, local_detail); if (source) - inev.ie.device = source->name; + inev.device = source->name; } x_uncatch_errors (); @@ -25026,9 +25030,9 @@ handle_one_xevent (struct x_display_info *dpyinfo, if (f && device->direct_p) { - inev.ie.kind = TOUCHSCREEN_UPDATE_EVENT; - inev.ie.timestamp = xev->time; - XSETFRAME (inev.ie.frame_or_window, f); + inev.kind = TOUCHSCREEN_UPDATE_EVENT; + inev.timestamp = xev->time; + XSETFRAME (inev.frame_or_window, f); for (touchpoint = device->touchpoints; touchpoint; touchpoint = touchpoint->next) @@ -25040,9 +25044,9 @@ handle_one_xevent (struct x_display_info *dpyinfo, } if (source) - inev.ie.device = source->name; + inev.device = source->name; - inev.ie.arg = arg; + inev.arg = arg; } goto XI_OTHER; @@ -25077,17 +25081,17 @@ handle_one_xevent (struct x_display_info *dpyinfo, if (f && device->direct_p) { - inev.ie.kind = TOUCHSCREEN_END_EVENT; - inev.ie.timestamp = xev->time; - inev.ie.modifiers = state != 2; + inev.kind = TOUCHSCREEN_END_EVENT; + inev.timestamp = xev->time; + inev.modifiers = state != 2; - XSETFRAME (inev.ie.frame_or_window, f); - XSETINT (inev.ie.x, lrint (xev->event_x)); - XSETINT (inev.ie.y, lrint (xev->event_y)); - XSETINT (inev.ie.arg, local_detail); + XSETFRAME (inev.frame_or_window, f); + XSETINT (inev.x, lrint (xev->event_x)); + XSETINT (inev.y, lrint (xev->event_y)); + XSETINT (inev.arg, local_detail); if (source) - inev.ie.device = source->name; + inev.device = source->name; } } @@ -25156,20 +25160,20 @@ handle_one_xevent (struct x_display_info *dpyinfo, if (pev->event == FRAME_X_WINDOW (any)) xi_compute_root_window_offset_pinch (any, pev); - inev.ie.kind = PINCH_EVENT; - inev.ie.modifiers + inev.kind = PINCH_EVENT; + inev.modifiers = x_x_to_emacs_modifiers (dpyinfo, pev->mods.effective); - XSETINT (inev.ie.x, lrint (pev->event_x)); - XSETINT (inev.ie.y, lrint (pev->event_y)); - XSETFRAME (inev.ie.frame_or_window, any); - inev.ie.arg = list4 (make_float (pev->delta_x), - make_float (pev->delta_y), - make_float (pev->scale), - make_float (pev->delta_angle)); + XSETINT (inev.x, lrint (pev->event_x)); + XSETINT (inev.y, lrint (pev->event_y)); + XSETFRAME (inev.frame_or_window, any); + inev.arg = list4 (make_float (pev->delta_x), + make_float (pev->delta_y), + make_float (pev->scale), + make_float (pev->delta_angle)); if (source) - inev.ie.device = source->name; + inev.device = source->name; } /* Once again GTK seems to crash when confronted by @@ -25524,26 +25528,26 @@ handle_one_xevent (struct x_display_info *dpyinfo, already an undelivered event on the queue. */ goto OTHER; - inev.ie.kind = MONITORS_CHANGED_EVENT; - inev.ie.timestamp = timestamp; - XSETTERMINAL (inev.ie.arg, dpyinfo->terminal); + inev.kind = MONITORS_CHANGED_EVENT; + inev.timestamp = timestamp; + XSETTERMINAL (inev.arg, dpyinfo->terminal); /* Also don't do anything if the monitor configuration didn't really change. */ current_monitors - = Fx_display_monitor_attributes_list (inev.ie.arg); + = Fx_display_monitor_attributes_list (inev.arg); if (!NILP (Fequal (current_monitors, dpyinfo->last_monitor_attributes_list))) - inev.ie.kind = NO_EVENT; + inev.kind = NO_EVENT; dpyinfo->last_monitor_attributes_list = current_monitors; if (x_dnd_in_progress && x_dnd_update_tooltip) x_dnd_monitors = current_monitors; - if (inev.ie.kind != NO_EVENT) + if (inev.kind != NO_EVENT) x_dnd_update_tooltip_now (); } #endif @@ -25591,9 +25595,9 @@ handle_one_xevent (struct x_display_info *dpyinfo, } done: - if (inev.ie.kind != NO_EVENT) + if (inev.kind != NO_EVENT) { - kbd_buffer_store_buffered_event (&inev, hold_quit); + kbd_buffer_store_event_hold (&inev, hold_quit); count++; } commit 96d26b493618f59bbdd4de86be65e784735541c8 Author: Po Lu Date: Mon Mar 3 21:57:05 2025 +0800 Fix styling issues on Android 15 QPR1 * java/org/gnu/emacs/EmacsView.java (EmacsView): Guarantee that frame views are created with the correct theme. * java/res/values-v20/style.xml (EmacsStyle): * java/res/values-v29/style.xml (EmacsStyle): Disable a swiping gesture enabled on certain Android systems. * java/res/values-v35/style.xml: Rename from `styles'.xml. diff --git a/java/org/gnu/emacs/EmacsView.java b/java/org/gnu/emacs/EmacsView.java index 5abea711506..938e2a21d1a 100644 --- a/java/org/gnu/emacs/EmacsView.java +++ b/java/org/gnu/emacs/EmacsView.java @@ -24,10 +24,11 @@ import android.text.InputType; import android.view.ContextMenu; +import android.view.ContextThemeWrapper; import android.view.DragEvent; -import android.view.View; import android.view.KeyEvent; import android.view.MotionEvent; +import android.view.View; import android.view.ViewGroup; import android.view.ViewTreeObserver; import android.view.WindowInsets; @@ -127,32 +128,36 @@ public final class EmacsView extends ViewGroup public EmacsView (EmacsWindow window) { - super (EmacsService.SERVICE); - - Object tem; - Context context; + /* This is required to guarantee that popup menus respect the + default style. */ + super (new ContextThemeWrapper (EmacsService.SERVICE, + R.style.EmacsStyle)); + { + Object tem; + Context context; - this.window = window; - this.damageRegion = new Region (); + this.window = window; + this.damageRegion = new Region (); - setFocusable (true); - setFocusableInTouchMode (true); + setFocusable (true); + setFocusableInTouchMode (true); - /* Create the surface view. */ - this.surfaceView = new EmacsSurfaceView (this); - addView (this.surfaceView); + /* Create the surface view. */ + this.surfaceView = new EmacsSurfaceView (this); + addView (this.surfaceView); - /* Get rid of the default focus highlight. */ - if (Build.VERSION.SDK_INT > Build.VERSION_CODES.O) - setDefaultFocusHighlightEnabled (false); + /* Get rid of the default focus highlight. */ + if (Build.VERSION.SDK_INT > Build.VERSION_CODES.O) + setDefaultFocusHighlightEnabled (false); - /* Obtain the input method manager. */ - context = getContext (); - tem = context.getSystemService (Context.INPUT_METHOD_SERVICE); - imManager = (InputMethodManager) tem; + /* Obtain the input method manager. */ + context = getContext (); + tem = context.getSystemService (Context.INPUT_METHOD_SERVICE); + imManager = (InputMethodManager) tem; - /* Add this view as its own global layout listener. */ - getViewTreeObserver ().addOnGlobalLayoutListener (this); + /* Add this view as its own global layout listener. */ + getViewTreeObserver ().addOnGlobalLayoutListener (this); + } } private void diff --git a/java/res/values-v20/style.xml b/java/res/values-v20/style.xml new file mode 100644 index 00000000000..285cd61ced6 --- /dev/null +++ b/java/res/values-v20/style.xml @@ -0,0 +1,30 @@ + + + + + +