commit f55ce98975d155cd70ac2deff4d4b7e562def12a (HEAD, refs/remotes/origin/master) Author: Paul Eggert Date: Sat Aug 1 00:26:37 2015 -0700 Simplify by assuming C99 integer division * src/floatfns.c (ceiling2, floor2, truncate2): Assume C99 (i.e., Fortran) semantics for integer division. This simplifies the code. diff --git a/src/floatfns.c b/src/floatfns.c index 072e857..63d35b8 100644 --- a/src/floatfns.c +++ b/src/floatfns.c @@ -377,32 +377,22 @@ rounding_driver (Lisp_Object arg, Lisp_Object divisor, return arg; } -/* With C's /, the result is implementation-defined if either operand - is negative, so take care with negative operands in the following - integer functions. */ - static EMACS_INT ceiling2 (EMACS_INT i1, EMACS_INT i2) { - return (i2 < 0 - ? (i1 < 0 ? ((-1 - i1) / -i2) + 1 : - (i1 / -i2)) - : (i1 <= 0 ? - (-i1 / i2) : ((i1 - 1) / i2) + 1)); + return i1 / i2 + ((i1 % i2 != 0) & ((i1 < 0) == (i2 < 0))); } static EMACS_INT floor2 (EMACS_INT i1, EMACS_INT i2) { - return (i2 < 0 - ? (i1 <= 0 ? -i1 / -i2 : -1 - ((i1 - 1) / -i2)) - : (i1 < 0 ? -1 - ((-1 - i1) / i2) : i1 / i2)); + return i1 / i2 - ((i1 % i2 != 0) & ((i1 < 0) != (i2 < 0))); } static EMACS_INT truncate2 (EMACS_INT i1, EMACS_INT i2) { - return (i2 < 0 - ? (i1 < 0 ? -i1 / -i2 : - (i1 / -i2)) - : (i1 < 0 ? - (-i1 / i2) : i1 / i2)); + return i1 / i2; } static EMACS_INT commit eb0f65b4fbbea60100b53cb40a1d7138d47ad0d2 Author: Paul Eggert Date: Fri Jul 31 10:12:37 2015 -0700 Don't overflow if computing approximate percentage * lisp/align.el (align-region): * lisp/cedet/semantic.el (semantic-repeat-parse-whole-stream): * lisp/cedet/semantic/wisent.el (wisent-parse-region): * lisp/cus-edit.el (custom-buffer-create-internal): * lisp/emacs-lisp/checkdoc.el (checkdoc-interactive-ispell-loop) (checkdoc-message-interactive-ispell-loop, checkdoc-next-error) (checkdoc-next-message-error): * lisp/emacs-lisp/eieio-opt.el (eieio-display-method-list): * lisp/epa.el (epa-progress-callback-function): * lisp/erc/erc-dcc.el (erc-dcc-do-LIST-command): * lisp/ffap.el (ffap-menu-rescan): * lisp/gnus/nnbabyl.el (nnbabyl-retrieve-headers): * lisp/gnus/nndiary.el (nndiary-retrieve-headers): * lisp/gnus/nneething.el (nneething-retrieve-headers): * lisp/gnus/nnmbox.el (nnmbox-retrieve-headers): * lisp/gnus/nnmh.el (nnmh-retrieve-headers): * lisp/gnus/nnml.el (nnml-retrieve-headers): * lisp/gnus/nnspool.el (nnspool-retrieve-headers): * lisp/gnus/nntp.el (nntp-retrieve-headers) (nntp-retrieve-articles): * lisp/imenu.el (imenu--relative-position): * lisp/international/ja-dic-cnv.el (skkdic-collect-okuri-nasi) (skkdic-convert-okuri-nasi): * lisp/net/ange-ftp.el (ange-ftp-process-handle-hash): * lisp/nxml/rng-valid.el (rng-compute-mode-line-string): * lisp/org/org-list.el (org-update-checkbox-count): * lisp/org/org.el (org-table-map-tables) (org-update-parent-todo-statistics): * lisp/play/decipher.el (decipher-insert-frequency-counts) (decipher-analyze-buffer): * lisp/profiler.el (profiler-format-percent): * lisp/progmodes/cc-cmds.el (c-progress-update): * lisp/progmodes/cpp.el (cpp-highlight-buffer): * lisp/progmodes/idlwave.el (idlwave-convert-xml-system-routine-info) (idlwave-list-load-path-shadows): * lisp/progmodes/opascal.el (opascal-step-progress): * lisp/progmodes/vhdl-mode.el (vhdl-update-progress-info) (vhdl-scan-directory-contents): * lisp/textmodes/bibtex.el (bibtex-progress-message): * lisp/textmodes/flyspell.el (flyspell-small-region) (flyspell-external-point-words): * lisp/textmodes/table.el (table-recognize): Prefer (floor (* 100.0 NUMERATOR) DENOMINATOR) when calculating progress-report percentages and the like. This avoids problems if (* 100 NUMERATOR) would overflow. * lisp/gnus/gnus-registry.el (gnus-registry-import-eld): * lisp/gnus/registry.el (registry-reindex): Use (* 100.0 ...) rather than (* 100 ...) to avoid int overflow issues. * lisp/descr-text.el (describe-char): * lisp/org/org-colview.el (org-nofm-to-completion): * lisp/ps-print.el (ps-plot): * lisp/simple.el (what-cursor-position): Prefer (round (* 100.0 NUMERATOR) DENOMINATOR) to a more-complicated and less-accurate approximation. diff --git a/lisp/align.el b/lisp/align.el index 82a55b0..ad5be2a 100644 --- a/lisp/align.el +++ b/lisp/align.el @@ -1437,12 +1437,12 @@ aligner would have dealt with are." (message "Aligning `%s' (rule %d of %d) %d%%..." (symbol-name symbol) rule-index rule-count - (/ (* (- (point) real-beg) 100) - (- end-mark real-beg))) + (floor (* (- (point) real-beg) 100.0) + (- end-mark real-beg))) (message "Aligning %d%%..." - (/ (* (- (point) real-beg) 100) - (- end-mark real-beg)))))) + (floor (* (- (point) real-beg) 100.0) + (- end-mark real-beg)))))) ;; if the search ended us on the beginning of ;; the next line, move back to the end of the diff --git a/lisp/cedet/semantic.el b/lisp/cedet/semantic.el index 81a9788..290cd90 100644 --- a/lisp/cedet/semantic.el +++ b/lisp/cedet/semantic.el @@ -769,8 +769,8 @@ This function returns semantic tags without overlays." (eq semantic-working-type 'percent) (progress-reporter-update semantic--progress-reporter - (/ (* 100 (semantic-lex-token-start (car stream))) - (point-max)))))) + (floor (* 100.0 (semantic-lex-token-start (car stream))) + (point-max)))))) result)) ;;; Parsing Warnings: diff --git a/lisp/cedet/semantic/wisent.el b/lisp/cedet/semantic/wisent.el index dfa533c..761bc68 100644 --- a/lisp/cedet/semantic/wisent.el +++ b/lisp/cedet/semantic/wisent.el @@ -322,9 +322,9 @@ the standard function `semantic-parse-region'." semantic--progress-reporter (progress-reporter-update semantic--progress-reporter - (/ (* 100 (semantic-lex-token-start - (car wisent-lex-istream))) - (point-max)))))) + (floor (* 100.0 (semantic-lex-token-start + (car wisent-lex-istream))) + (point-max)))))) ;; Return parse tree (nreverse ptree))) diff --git a/lisp/cus-edit.el b/lisp/cus-edit.el index 1d9a9d6..a8d1c97 100644 --- a/lisp/cus-edit.el +++ b/lisp/cus-edit.el @@ -1709,7 +1709,7 @@ Operate on all settings in this buffer:\n")) (mapcar (lambda (entry) (prog2 (message "Creating customization items ...%2d%%" - (/ (* 100.0 count) length)) + (floor (* 100.0 count) length)) (widget-create (nth 1 entry) :tag (custom-unlispify-tag-name (nth 0 entry)) diff --git a/lisp/descr-text.el b/lisp/descr-text.el index a0b9ddf..71233d4 100644 --- a/lisp/descr-text.el +++ b/lisp/descr-text.el @@ -542,9 +542,7 @@ relevant to POS." ,(let* ((beg (point-min)) (end (point-max)) (total (buffer-size)) - (percent (if (> total 50000) ; Avoid overflow multiplying by 100 - (/ (+ (/ total 200) (1- pos)) (max (/ total 100) 1)) - (/ (+ (/ total 2) (* 100 (1- pos))) (max total 1)))) + (percent (round (* 100.0 (1- pos)) (max total 1))) (hscroll (if (= (window-hscroll) 0) "" (format ", Hscroll: %d" (window-hscroll)))) diff --git a/lisp/emacs-lisp/checkdoc.el b/lisp/emacs-lisp/checkdoc.el index 0b451ef..c22aff4 100644 --- a/lisp/emacs-lisp/checkdoc.el +++ b/lisp/emacs-lisp/checkdoc.el @@ -747,7 +747,7 @@ buffer, otherwise searching starts at START-HERE." ;; Loop over docstrings. (while (checkdoc-next-docstring) (message "Searching for doc string spell error...%d%%" - (/ (* 100 (point)) (point-max))) + (floor (* 100.0 (point)) (point-max))) (if (looking-at "\"") (checkdoc-ispell-docstring-engine (save-excursion (forward-sexp 1) (point-marker))))) @@ -767,7 +767,7 @@ buffer, otherwise searching starts at START-HERE." ;; Loop over message strings. (while (checkdoc-message-text-next-string (point-max)) (message "Searching for message string spell error...%d%%" - (/ (* 100 (point)) (point-max))) + (floor (* 100.0 (point)) (point-max))) (if (looking-at "\"") (checkdoc-ispell-docstring-engine (save-excursion (forward-sexp 1) (point-marker))))) @@ -791,7 +791,7 @@ perform the fix." (condition-case nil (while (and (not msg) (checkdoc-next-docstring)) (message "Searching for doc string error...%d%%" - (/ (* 100 (point)) (point-max))) + (floor (* 100.0 (point)) (point-max))) (if (setq msg (checkdoc-this-string-valid)) (setq msg (cons msg (point))))) ;; Quit.. restore position, Other errors, leave alone @@ -813,7 +813,7 @@ assumes that the cursor is already positioned to perform the fix." (setq type (checkdoc-message-text-next-string (point-max)))) (message "Searching for message string error...%d%%" - (/ (* 100 (point)) (point-max))) + (floor (* 100.0 (point)) (point-max))) (if (setq msg (checkdoc-message-text-engine type)) (setq msg (cons msg (point))))) ;; Quit.. restore position, Other errors, leave alone diff --git a/lisp/emacs-lisp/eieio-opt.el b/lisp/emacs-lisp/eieio-opt.el index 9ecc594..0b00336 100644 --- a/lisp/emacs-lisp/eieio-opt.el +++ b/lisp/emacs-lisp/eieio-opt.el @@ -243,13 +243,13 @@ are not abstract." (princ "Methods Primary Only: ") (prin1 primaryonly) (princ "\t") - (princ (format "%d" (* (/ (float primaryonly) (float methidx)) 100))) + (princ (format "%d" (floor (* 100.0 primaryonly) methidx))) (princ "% of total methods") (terpri) (princ "Only One Primary Impl: ") (prin1 oneprimary) (princ "\t") - (princ (format "%d" (* (/ (float oneprimary) (float primaryonly)) 100))) + (princ (format "%d" (floor (* 100.0 oneprimary) primaryonly))) (princ "% of total primary methods") (terpri) )) diff --git a/lisp/epa.el b/lisp/epa.el index d3fec73..f6d6045 100644 --- a/lisp/epa.el +++ b/lisp/epa.el @@ -658,7 +658,7 @@ If SECRET is non-nil, list secret keys instead of public keys." (if (= current total) (message "%s...done" prompt) (message "%s...%d%%" prompt - (floor (* (/ current (float total)) 100)))) + (floor (* 100.0 current) total))) (message "%s..." prompt)))) (defun epa-read-file-name (input) diff --git a/lisp/erc/erc-dcc.el b/lisp/erc/erc-dcc.el index 182f1e0..d4d005d 100644 --- a/lisp/erc/erc-dcc.el +++ b/lisp/erc/erc-dcc.el @@ -594,14 +594,9 @@ It lists the current state of `erc-dcc-list' in an easy to read manner." (get-buffer (plist-get elt :file)) (+ (buffer-size) 0.0 erc-dcc-byte-count)))) - (concat " (" - (if (= byte-count 0) - "0" - (number-to-string - (truncate - (* 100 - (/ byte-count (plist-get elt :size)))))) - "%)")))) + (format " (%d%%)" + (floor (* 100.0 byte-count) + (plist-get elt :size)))))) ?f (or (and (plist-member elt :file) (plist-get elt :file)) ""))) (erc-display-message nil 'notice 'active diff --git a/lisp/ffap.el b/lisp/ffap.el index 81cba07..c0ab1af 100644 --- a/lisp/ffap.el +++ b/lisp/ffap.el @@ -1568,7 +1568,7 @@ Applies `ffap-menu-text-plist' text properties at all matches." (add-text-properties (car ffap-string-at-point-region) (point) ffap-menu-text-plist) (message "Scanning...%2d%% <%s>" - (/ (* 100 (- (point) (point-min))) range) item))) + (floor (* 100.0 (- (point) (point-min))) range) item))) (or mod (restore-buffer-modified-p nil)))) (message "Scanning...done") ;; Remove duplicates. diff --git a/lisp/gnus/gnus-registry.el b/lisp/gnus/gnus-registry.el index 0cb5960..5044397 100644 --- a/lisp/gnus/gnus-registry.el +++ b/lisp/gnus/gnus-registry.el @@ -1100,7 +1100,7 @@ only the last one's marks are returned." (when (and (< 0 expected) (= 0 (mod count 100))) (message "importing: %d of %d (%.2f%%)" - count expected (/ (* 100 count) expected))) + count expected (/ (* 100.0 count) expected))) (setq entry (car-safe old) old (cdr-safe old)) (let* ((id (car-safe entry)) diff --git a/lisp/gnus/nnbabyl.el b/lisp/gnus/nnbabyl.el index d060c2a..ae417a0 100644 --- a/lisp/gnus/nnbabyl.el +++ b/lisp/gnus/nnbabyl.el @@ -105,7 +105,7 @@ (> number nnmail-large-newsgroup) (zerop (% (incf count) 20)) (nnheader-message 5 "nnbabyl: Receiving headers... %d%%" - (/ (* count 100) number)))) + (floor (* count 100.0) number)))) (and (numberp nnmail-large-newsgroup) (> number nnmail-large-newsgroup) diff --git a/lisp/gnus/nndiary.el b/lisp/gnus/nndiary.el index 027d888..3134438 100644 --- a/lisp/gnus/nndiary.el +++ b/lisp/gnus/nndiary.el @@ -423,7 +423,7 @@ all. This may very well take some time.") (> number nnmail-large-newsgroup) (zerop (% count 20)) (nnheader-message 6 "nndiary: Receiving headers... %d%%" - (/ (* count 100) number)))) + (floor (* count 100.0) number)))) (and (numberp nnmail-large-newsgroup) (> number nnmail-large-newsgroup) diff --git a/lisp/gnus/nneething.el b/lisp/gnus/nneething.el index 183e396..0d9044f 100644 --- a/lisp/gnus/nneething.el +++ b/lisp/gnus/nneething.el @@ -106,7 +106,7 @@ included.") (and large (zerop (% count 20)) (nnheader-message 5 "nneething: Receiving headers... %d%%" - (/ (* count 100) number)))) + (floor (* count 100.0) number)))) (when large (nnheader-message 5 "nneething: Receiving headers...done")) diff --git a/lisp/gnus/nnmbox.el b/lisp/gnus/nnmbox.el index 78983a5..a70a039 100644 --- a/lisp/gnus/nnmbox.el +++ b/lisp/gnus/nnmbox.el @@ -106,7 +106,7 @@ (> number nnmail-large-newsgroup) (zerop (% count 20)) (nnheader-message 5 "nnmbox: Receiving headers... %d%%" - (/ (* count 100) number)))) + (floor (* count 100.0) number)))) (and (numberp nnmail-large-newsgroup) (> number nnmail-large-newsgroup) diff --git a/lisp/gnus/nnmh.el b/lisp/gnus/nnmh.el index 04270a5..cdbf38a 100644 --- a/lisp/gnus/nnmh.el +++ b/lisp/gnus/nnmh.el @@ -109,7 +109,7 @@ as unread by Gnus.") (and large (zerop (% count 20)) (nnheader-message 5 "nnmh: Receiving headers... %d%%" - (/ (* count 100) number)))) + (floor (* count 100.0) number)))) (when large (nnheader-message 5 "nnmh: Receiving headers...done")) diff --git a/lisp/gnus/nnml.el b/lisp/gnus/nnml.el index 8275e19..c825e09 100644 --- a/lisp/gnus/nnml.el +++ b/lisp/gnus/nnml.el @@ -178,7 +178,7 @@ non-nil.") (> number nnmail-large-newsgroup) (zerop (% count 20)) (nnheader-message 6 "nnml: Receiving headers... %d%%" - (/ (* count 100) number)))) + (floor (* count 100.0) number)))) (and (numberp nnmail-large-newsgroup) (> number nnmail-large-newsgroup) diff --git a/lisp/gnus/nnspool.el b/lisp/gnus/nnspool.el index 9e9537a..f10b1ad 100644 --- a/lisp/gnus/nnspool.el +++ b/lisp/gnus/nnspool.el @@ -174,7 +174,7 @@ there.") (and do-message (zerop (% (incf count) 20)) (nnheader-message 5 "nnspool: Receiving headers... %d%%" - (/ (* count 100) number)))) + (floor (* count 100.0) number)))) (when do-message (nnheader-message 5 "nnspool: Receiving headers...done")) diff --git a/lisp/gnus/nntp.el b/lisp/gnus/nntp.el index 0891dba..b617a1b 100644 --- a/lisp/gnus/nntp.el +++ b/lisp/gnus/nntp.el @@ -728,7 +728,7 @@ command whose response triggered the error." (> number nntp-large-newsgroup) (zerop (% received 20)) (nnheader-message 6 "NNTP: Receiving headers... %d%%" - (/ (* received 100) number))) + (floor (* received 100.0) number))) (nntp-accept-response)))) (and (numberp nntp-large-newsgroup) (> number nntp-large-newsgroup) @@ -965,7 +965,7 @@ command whose response triggered the error." (> number nntp-large-newsgroup) (zerop (% received 20)) (nnheader-message 6 "NNTP: Receiving articles... %d%%" - (/ (* received 100) number))) + (floor (* received 100.0) number))) (nntp-accept-response)))) (and (numberp nntp-large-newsgroup) (> number nntp-large-newsgroup) diff --git a/lisp/gnus/registry.el b/lisp/gnus/registry.el index 96a89fc..7bada9f 100644 --- a/lisp/gnus/registry.el +++ b/lisp/gnus/registry.el @@ -320,7 +320,7 @@ Errors out if the key exists already." (when (and (< 0 expected) (= 0 (mod count 1000))) (message "reindexing: %d of %d (%.2f%%)" - count expected (/ (* 100 count) expected))) + count expected (/ (* 100.0 count) expected))) (dolist (val (cdr-safe (assq tr v))) (let* ((value-keys (registry-lookup-secondary-value db tr val))) (push key value-keys) diff --git a/lisp/imenu.el b/lisp/imenu.el index 65c5282..3a856b8 100644 --- a/lisp/imenu.el +++ b/lisp/imenu.el @@ -499,10 +499,7 @@ If REVERSE is non-nil then the beginning is 100 and the end is 0." (let ((pos (point)) (total (buffer-size))) (and reverse (setq pos (- total pos))) - (if (> total 50000) - ;; Avoid overflow from multiplying by 100! - (/ (1- pos) (max (/ total 100) 1)) - (/ (* 100 (1- pos)) (max total 1))))) + (floor (* 100.0 (1- pos)) (max total 1)))) (defun imenu--split (list n) "Split LIST into sublists of max length N. diff --git a/lisp/international/ja-dic-cnv.el b/lisp/international/ja-dic-cnv.el index edb6d89..d9c77bf5 100644 --- a/lisp/international/ja-dic-cnv.el +++ b/lisp/international/ja-dic-cnv.el @@ -280,7 +280,7 @@ (cons (cons kana candidates) skkdic-okuri-nasi-entries) skkdic-okuri-nasi-entries-count (1+ skkdic-okuri-nasi-entries-count)) - (setq ratio (floor (/ (* (point) 100.0) (point-max)))) + (setq ratio (floor (* (point) 100.0) (point-max))) (if (/= (/ prev-ratio 10) (/ ratio 10)) (progn (message "collected %2d%% ..." ratio) @@ -306,7 +306,7 @@ (while l (let ((kana (car (car l))) (candidates (cdr (car l)))) - (setq ratio (/ (* count 100) skkdic-okuri-nasi-entries-count) + (setq ratio (floor (* count 100.0) skkdic-okuri-nasi-entries-count) count (1+ count)) (if (/= (/ prev-ratio 10) (/ ratio 10)) (progn diff --git a/lisp/net/ange-ftp.el b/lisp/net/ange-ftp.el index 1f893a7..0685bac 100644 --- a/lisp/net/ange-ftp.el +++ b/lisp/net/ange-ftp.el @@ -1613,7 +1613,7 @@ good, skip, fatal, or unknown." -6))) (if (zerop ange-ftp-xfer-size) (ange-ftp-message "%s...%dk" ange-ftp-process-msg kbytes) - (let ((percent (/ (* 100 kbytes) ange-ftp-xfer-size))) + (let ((percent (floor (* 100.0 kbytes) ange-ftp-xfer-size))) ;; cut out the redisplay of identical %-age messages. (unless (eq percent ange-ftp-last-percent) (setq ange-ftp-last-percent percent) diff --git a/lisp/nxml/rng-valid.el b/lisp/nxml/rng-valid.el index 2bf8f1d..61a9654 100644 --- a/lisp/nxml/rng-valid.el +++ b/lisp/nxml/rng-valid.el @@ -345,17 +345,11 @@ The schema is set like `rng-auto-set-schema'." (defun rng-compute-mode-line-string () (cond (rng-validate-timer - (concat " Validated:" - (number-to-string - ;; Use floor rather than round because we want - ;; to show 99% rather than 100% for changes near - ;; the end. - (floor (if (eq (buffer-size) 0) - 0.0 - (/ (* (- rng-validate-up-to-date-end (point-min)) - 100.0) - (- (point-max) (point-min)))))) - "%%")) + (format " Validated:%d%%" + (if (= 0 (buffer-size)) + 0 + (floor (- rng-validate-up-to-date-end (point-min)) + (- (point-max) (point-min)))))) ((> rng-error-count 0) (concat " " (propertize "Invalid" diff --git a/lisp/org/org-colview.el b/lisp/org/org-colview.el index e14849f..e938ab4 100644 --- a/lisp/org/org-colview.el +++ b/lisp/org/org-colview.el @@ -1086,7 +1086,7 @@ display, or in the #+COLUMNS line of the current buffer." (defun org-nofm-to-completion (n m &optional percent) (if (not percent) (format "[%d/%d]" n m) - (format "[%d%%]"(floor (+ 0.5 (* 100. (/ (* 1.0 n) m))))))) + (format "[%d%%]" (round (* 100.0 n) m)))) (defun org-columns-string-to-number (s fmt) diff --git a/lisp/org/org-list.el b/lisp/org/org-list.el index 73f24ce..432e431 100644 --- a/lisp/org/org-list.el +++ b/lisp/org/org-list.el @@ -2555,8 +2555,8 @@ With optional prefix argument ALL, do this for the whole buffer." (checked (car (nth 3 cookie))) (total (cdr (nth 3 cookie))) (new (if percentp - (format "[%d%%]" (/ (* 100 checked) - (max 1 total))) + (format "[%d%%]" (floor (* 100.0 checked) + (max 1 total))) (format "[%d/%d]" checked total)))) (goto-char beg) (insert new) diff --git a/lisp/org/org.el b/lisp/org/org.el index e9dae19..b545f9e 100644 --- a/lisp/org/org.el +++ b/lisp/org/org.el @@ -4346,7 +4346,8 @@ If TABLE-TYPE is non-nil, also check for table.el-type tables." (goto-char (point-min)) (while (re-search-forward org-table-any-line-regexp nil t) (unless quietly - (message "Mapping tables: %d%%" (/ (* 100.0 (point)) (buffer-size)))) + (message "Mapping tables: %d%%" + (floor (* 100.0 (point)) (buffer-size)))) (beginning-of-line 1) (when (and (looking-at org-table-line-regexp) ;; Exclude tables in src/example/verbatim/clocktable blocks @@ -12679,7 +12680,8 @@ statistics everywhere." (outline-next-heading))) (setq new (if is-percent - (format "[%d%%]" (/ (* 100 cnt-done) (max 1 cnt-all))) + (format "[%d%%]" (floor (* 100.0 cnt-done) + (max 1 cnt-all))) (format "[%d/%d]" cnt-done cnt-all)) ndel (- (match-end 0) checkbox-beg)) ;; handle overlays when updating cookie from column view diff --git a/lisp/play/decipher.el b/lisp/play/decipher.el index f42ae90..c2268a9 100644 --- a/lisp/play/decipher.el +++ b/lisp/play/decipher.el @@ -793,7 +793,7 @@ TOTAL is the total number of letters in the ciphertext." (insert (caar temp-list) (format "%4d%3d%% " (cl-cadar temp-list) - (/ (* 100 (cl-cadar temp-list)) total))) + (floor (* 100.0 (cl-cadar temp-list)) total))) (setq temp-list (nthcdr 4 temp-list))) (insert ?\n) (setq freq-list (cdr freq-list) @@ -957,7 +957,7 @@ Creates the statistics buffer if it doesn't exist." ": A B C D E F G H I J K L M N O P Q R S T U V W X Y Z *" (format "%4d %4d %3d%%\n " (cl-third entry) (cl-second entry) - (/ (* 100 (cl-second entry)) total-chars)) + (floor (* 100.0 (cl-second entry)) total-chars)) (decipher--digram-counts (aref decipher--after i)) ?\n)))) (setq buffer-read-only t) (set-buffer-modified-p nil) diff --git a/lisp/profiler.el b/lisp/profiler.el index 2425d8c..f28bbfe 100644 --- a/lisp/profiler.el +++ b/lisp/profiler.el @@ -56,7 +56,7 @@ (format "%s" object)))) (defun profiler-format-percent (number divisor) - (concat (number-to-string (/ (* number 100) divisor)) "%")) + (format "%d%%" (floor (* 100.0 number) divisor))) (defun profiler-format-number (number) "Format NUMBER in human readable string." diff --git a/lisp/progmodes/cc-cmds.el b/lisp/progmodes/cc-cmds.el index 94dc34b..c9f5945 100644 --- a/lisp/progmodes/cc-cmds.el +++ b/lisp/progmodes/cc-cmds.el @@ -1809,7 +1809,7 @@ with a brace block." (c-save-buffer-state (beginning-of-defun-function end-of-defun-function where pos name-end case-fold-search) - + (save-restriction (widen) (save-excursion @@ -3412,7 +3412,7 @@ Otherwise reindent just the current line." (if (< c-progress-interval (- now lastsecs)) (progn (message "Indenting region... (%d%% complete)" - (/ (* 100 (- (point) start)) (- end start))) + (floor (* 100.0 (- (point) start)) (- end start))) (aset c-progress-info 2 now))) ))) diff --git a/lisp/progmodes/cpp.el b/lisp/progmodes/cpp.el index bf8458e..0a51add 100644 --- a/lisp/progmodes/cpp.el +++ b/lisp/progmodes/cpp.el @@ -234,7 +234,8 @@ A prefix arg suppresses display of that buffer." (cpp-progress-message "Parsing...") (while (re-search-forward cpp-parse-regexp nil t) (cpp-progress-message "Parsing...%d%%" - (/ (* 100 (- (point) (point-min))) (buffer-size))) + (floor (* 100.0 (- (point) (point-min))) + (buffer-size))) (let ((match (buffer-substring (match-beginning 0) (match-end 0)))) (cond ((or (string-equal match "'") (string-equal match "\"")) diff --git a/lisp/progmodes/idlwave.el b/lisp/progmodes/idlwave.el index 8e30aa2..d759442 100644 --- a/lisp/progmodes/idlwave.el +++ b/lisp/progmodes/idlwave.el @@ -4881,7 +4881,7 @@ Cache to disk for quick recovery." props (car (cdr elem))) (if (= (mod elem-cnt msg-cnt) 0) (message "Converting XML routine info...%2d%%" - (/ (* elem-cnt 100) nelem))) + (floor (* elem-cnt 100.0) nelem))) (cond ((eq type 'ROUTINE) (if (setq alias (assq 'alias_to props)) @@ -8694,7 +8694,7 @@ can be used to detect possible name clashes during this process." (erase-buffer) (while (setq routine (pop routines)) (if (= (mod (setq n (1+ n)) step) 0) - (message "Compiling list...(%2d%%)" (/ (* n 100) nroutines))) + (message "Compiling list...(%2d%%)" (floor (* n 100.0) nroutines))) ;; Get a list of all twins (setq twins (idlwave-routine-twins routine (or lroutines routines))) diff --git a/lisp/progmodes/opascal.el b/lisp/progmodes/opascal.el index 2eba620..ef3433f 100644 --- a/lisp/progmodes/opascal.el +++ b/lisp/progmodes/opascal.el @@ -368,7 +368,7 @@ routine.") ;; Report the percentage complete. (setq opascal-progress-last-reported-point p) (message "%s %s ... %d%%" - desc (buffer-name) (/ (* 100 p) (point-max)))))) + desc (buffer-name) (floor (* 100.0 p) (point-max)))))) (defun opascal-next-line-start (&optional from-point) ;; Returns the first point of the next line. diff --git a/lisp/progmodes/vhdl-mode.el b/lisp/progmodes/vhdl-mode.el index 5ed0ff0..16e4e8e 100644 --- a/lisp/progmodes/vhdl-mode.el +++ b/lisp/progmodes/vhdl-mode.el @@ -7383,11 +7383,11 @@ only-lines." (- (nth 1 (current-time)) (aref vhdl-progress-info 2)))) (let ((delta (- (aref vhdl-progress-info 1) (aref vhdl-progress-info 0)))) - (if (= 0 delta) - (message (concat string "... (100%s)") "%") - (message (concat string "... (%2d%s)") - (/ (* 100 (- pos (aref vhdl-progress-info 0))) - delta) "%"))) + (message "%s... (%2d%%)" string + (if (= 0 delta) + 100 + (floor (* 100.0 (- pos (aref vhdl-progress-info 0))) + delta)))) (aset vhdl-progress-info 2 (nth 1 (current-time))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -13881,10 +13881,10 @@ hierarchy otherwise.") ;; do for all files (while file-list (unless noninteractive - (message "Scanning %s %s\"%s\"... (%2d%s)" + (message "Scanning %s %s\"%s\"... (%2d%%)" (if is-directory "directory" "files") (or num-string "") name - (/ (* 100 (- no-files (length file-list))) no-files) "%")) + (floor (* 100.0 (- no-files (length file-list))) no-files))) (let ((file-name (abbreviate-file-name (car file-list))) ent-list arch-list arch-ent-list conf-list pack-list pack-body-list inst-list inst-ent-list) diff --git a/lisp/ps-print.el b/lisp/ps-print.el index e76b332..0ba470b 100644 --- a/lisp/ps-print.el +++ b/lisp/ps-print.el @@ -6043,10 +6043,7 @@ XSTART YSTART are the relative position for the first page in a sheet.") (progn (setq ps-razchunk q-done) (message "Formatting...%3d%%" - (if (< q-todo 100) - (/ (* 100 q-done) q-todo) - (/ q-done (/ q-todo 100))) - )))))) + (floor (* 100.0 q-done) q-todo))))))) (defvar ps-last-font nil) diff --git a/lisp/simple.el b/lisp/simple.el index 7eed279..1a4bcf1 100644 --- a/lisp/simple.el +++ b/lisp/simple.el @@ -1255,10 +1255,7 @@ in *Help* buffer. See also the command `describe-char'." (end (point-max)) (pos (point)) (total (buffer-size)) - (percent (if (> total 50000) - ;; Avoid overflow from multiplying by 100! - (/ (+ (/ total 200) (1- pos)) (max (/ total 100) 1)) - (/ (+ (/ total 2) (* 100 (1- pos))) (max total 1)))) + (percent (round (* 100.0 (1- pos)) (max 1 total))) (hscroll (if (= (window-hscroll) 0) "" (format " Hscroll=%d" (window-hscroll)))) diff --git a/lisp/textmodes/bibtex.el b/lisp/textmodes/bibtex.el index 9d6d19e..b1232d4 100644 --- a/lisp/textmodes/bibtex.el +++ b/lisp/textmodes/bibtex.el @@ -2099,7 +2099,7 @@ If FLAG is nil, a message is echoed if point was incremented at least (let* ((size (- (point-max) (point-min))) (perc (if (= size 0) 100 - (/ (* 100 (- (point) (point-min))) size)))) + (floor (* 100.0 (- (point) (point-min))) size)))) (when (>= perc (+ bibtex-progress-lastperc bibtex-progress-interval)) (setq bibtex-progress-lastperc perc) diff --git a/lisp/textmodes/flyspell.el b/lisp/textmodes/flyspell.el index e074918..64aa3de1 100644 --- a/lisp/textmodes/flyspell.el +++ b/lisp/textmodes/flyspell.el @@ -1350,7 +1350,7 @@ that may be included as part of a word (see `ispell-dictionary-alist')." (if (and flyspell-issue-message-flag (= count 100)) (progn (message "Spell Checking...%d%%" - (* 100 (/ (float (- (point) beg)) (- end beg)))) + (floor (* 100.0 (- (point) beg)) (- end beg))) (setq count 0)) (setq count (+ 1 count))) (flyspell-word) @@ -1403,7 +1403,7 @@ The buffer to mark them in is `flyspell-large-region-buffer'." ;; be unnecessary too. -- rms. (if flyspell-issue-message-flag (message "Spell Checking...%d%% [%s]" - (* 100 (/ (float (point)) (point-max))) + (floor (* 100.0 (point)) (point-max)) word)) (with-current-buffer flyspell-large-region-buffer (goto-char buffer-scan-pos) diff --git a/lisp/textmodes/table.el b/lisp/textmodes/table.el index edc78e5..fa9f0fa 100644 --- a/lisp/textmodes/table.el +++ b/lisp/textmodes/table.el @@ -1893,7 +1893,9 @@ all the table specific features." (while (and (re-search-forward border3 (point-max) t) (not (and (input-pending-p) table-abort-recognition-when-input-pending))) - (message "Recognizing tables...(%d%%)" (/ (* 100 (match-beginning 0)) (- (point-max) (point-min)))) + (message "Recognizing tables...(%d%%)" + (floor (* 100.0 (match-beginning 0)) + (- (point-max) (point-min)))) (let ((beg (match-beginning 0)) end) (if (re-search-forward non-border (point-max) t) commit 0f23e95b29a7a0a07bba0e9bc796cd7b7bc7232a Author: Paul Eggert Date: Fri Jul 31 09:55:49 2015 -0700 Fix some int overflows in profiler.c * src/profiler.c (make_log): Make args EMACS_INT, not int, to avoid unwanted behavior on 'int' overflow. (make_log, evict_lower_half, record_backtrace): Use ptrdiff_t, not int, for object indexes. diff --git a/src/profiler.c b/src/profiler.c index d4c98a8..efdb1d9 100644 --- a/src/profiler.c +++ b/src/profiler.c @@ -38,7 +38,7 @@ typedef struct Lisp_Hash_Table log_t; static struct hash_table_test hashtest_profiler; static Lisp_Object -make_log (int heap_size, int max_stack_depth) +make_log (EMACS_INT heap_size, EMACS_INT max_stack_depth) { /* We use a standard Elisp hash-table object, but we use it in a special way. This is OK as long as the object is not exposed @@ -53,7 +53,7 @@ make_log (int heap_size, int max_stack_depth) /* What is special about our hash-tables is that the keys are pre-filled with the vectors we'll put in them. */ - int i = ASIZE (h->key_and_value) / 2; + ptrdiff_t i = ASIZE (h->key_and_value) >> 1; while (i > 0) set_hash_key_slot (h, --i, Fmake_vector (make_number (max_stack_depth), Qnil)); @@ -120,12 +120,11 @@ static void evict_lower_half (log_t *log) Fremhash (key, tmp); } eassert (EQ (log->next_free, make_number (i))); - { - int j; - eassert (VECTORP (key)); - for (j = 0; j < ASIZE (key); j++) - ASET (key, j, Qnil); - } + + eassert (VECTORP (key)); + for (ptrdiff_t j = 0; j < ASIZE (key); j++) + ASET (key, j, Qnil); + set_hash_key_slot (log, i, key); } } @@ -165,9 +164,8 @@ record_backtrace (log_t *log, EMACS_INT count) else { /* BEWARE! hash_put in general can allocate memory. But currently it only does that if log->next_free is nil. */ - int j; eassert (!NILP (log->next_free)); - j = hash_put (log, backtrace, make_number (count), hash); + ptrdiff_t j = hash_put (log, backtrace, make_number (count), hash); /* Let's make sure we've put `backtrace' right where it already was to start with. */ eassert (index == j); commit 8a7a99e0280103e223b8e1a717107bdf9b8eabc7 Author: Paul Eggert Date: Fri Jul 31 09:46:45 2015 -0700 Port to pedantic memcpy * src/keyboard.c (menu_bar_items, tool_bar_items): * src/xrdb.c (magic_db): Port to pedantic memcpy implementations that reject memcpy (0, 0, 0). diff --git a/src/keyboard.c b/src/keyboard.c index 6bd123c..91cca8e 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -7481,18 +7481,19 @@ menu_bar_items (Lisp_Object old) properties may not work reliable, as they are only recognized when the menu-bar (or mode-line) is updated, which does not normally happen after every command. */ - Lisp_Object tem; - ptrdiff_t nminor; - nminor = current_minor_maps (NULL, &tmaps); + ptrdiff_t nminor = current_minor_maps (NULL, &tmaps); SAFE_NALLOCA (maps, 1, nminor + 4); nmaps = 0; - tem = KVAR (current_kboard, Voverriding_terminal_local_map); + Lisp_Object tem = KVAR (current_kboard, Voverriding_terminal_local_map); if (!NILP (tem) && !NILP (Voverriding_local_map_menu_flag)) maps[nmaps++] = tem; if (tem = get_local_map (PT, current_buffer, Qkeymap), !NILP (tem)) maps[nmaps++] = tem; - memcpy (maps + nmaps, tmaps, nminor * sizeof (maps[0])); - nmaps += nminor; + if (nminor != 0) + { + memcpy (maps + nmaps, tmaps, nminor * sizeof (maps[0])); + nmaps += nminor; + } maps[nmaps++] = get_local_map (PT, current_buffer, Qlocal_map); } maps[nmaps++] = current_global_map; @@ -8030,18 +8031,19 @@ tool_bar_items (Lisp_Object reuse, int *nitems) properties may not work reliable, as they are only recognized when the tool-bar (or mode-line) is updated, which does not normally happen after every command. */ - Lisp_Object tem; - ptrdiff_t nminor; - nminor = current_minor_maps (NULL, &tmaps); + ptrdiff_t nminor = current_minor_maps (NULL, &tmaps); SAFE_NALLOCA (maps, 1, nminor + 4); nmaps = 0; - tem = KVAR (current_kboard, Voverriding_terminal_local_map); + Lisp_Object tem = KVAR (current_kboard, Voverriding_terminal_local_map); if (!NILP (tem) && !NILP (Voverriding_local_map_menu_flag)) maps[nmaps++] = tem; if (tem = get_local_map (PT, current_buffer, Qkeymap), !NILP (tem)) maps[nmaps++] = tem; - memcpy (maps + nmaps, tmaps, nminor * sizeof (maps[0])); - nmaps += nminor; + if (nminor != 0) + { + memcpy (maps + nmaps, tmaps, nminor * sizeof (maps[0])); + nmaps += nminor; + } maps[nmaps++] = get_local_map (PT, current_buffer, Qlocal_map); } diff --git a/src/xrdb.c b/src/xrdb.c index 9e85e5a..2235b45 100644 --- a/src/xrdb.c +++ b/src/xrdb.c @@ -119,8 +119,8 @@ magic_db (const char *string, ptrdiff_t string_len, const char *class, while (p < string + string_len) { /* The chunk we're about to stick on the end of result. */ - const char *next = NULL; - ptrdiff_t next_len; + const char *next = p; + ptrdiff_t next_len = 1; if (*p == '%') { @@ -137,10 +137,13 @@ magic_db (const char *string, ptrdiff_t string_len, const char *class, break; case 'C': - next = (x_customization_string - ? x_customization_string - : ""); - next_len = strlen (next); + if (x_customization_string) + { + next = x_customization_string; + next_len = strlen (next); + } + else + next_len = 0; break; case 'N': @@ -176,8 +179,6 @@ magic_db (const char *string, ptrdiff_t string_len, const char *class, return NULL; } } - else - next = p, next_len = 1; /* Do we have room for this component followed by a '\0'? */ if (path_size - path_len <= next_len) commit f5fc5cd5c207a4fc3bdde381ad4f74c8fe6bb5d6 Author: Paul Eggert Date: Fri Jul 31 09:44:47 2015 -0700 Merge from gnulib This incorporates: 2015-07-29 time_rz: port to pedantic memcpy * lib/time_rz.c: Copy from gnulib. diff --git a/lib/time_rz.c b/lib/time_rz.c index cbbe2c6..f94893a 100644 --- a/lib/time_rz.c +++ b/lib/time_rz.c @@ -105,7 +105,9 @@ tzalloc (char const *name) tz->tzname_copy[0] = tz->tzname_copy[1] = NULL; #endif tz->tz_is_set = !!name; - extend_abbrs (tz->abbrs, name, name_size); + tz->abbrs[0] = '\0'; + if (name) + extend_abbrs (tz->abbrs, name, name_size); } return tz; } commit 8d332aeccab2208e6c6bd434738565e6abf12043 Author: Artur Malabarba Date: Fri Jul 31 12:51:04 2015 +0100 * lisp/emacs-lisp/tabulated-list.el (tabulated-list-print): Fix bug When updating the very last entry, tabulated-list-print would erase it and then try to look at the next one (which obviously isn't there). diff --git a/lisp/emacs-lisp/tabulated-list.el b/lisp/emacs-lisp/tabulated-list.el index 9119c3a..cd61eb9 100644 --- a/lisp/emacs-lisp/tabulated-list.el +++ b/lisp/emacs-lisp/tabulated-list.el @@ -356,10 +356,11 @@ changing `tabulated-list-sort-key'." nil) ;; If this entry sorts after id (or it's the ;; end), then just insert id and move on. - ((funcall sorter elt - ;; FIXME: Might be faster if - ;; don't construct this list. - (list local-id (tabulated-list-get-entry))) + ((or (not local-id) + (funcall sorter elt + ;; FIXME: Might be faster if + ;; don't construct this list. + (list local-id (tabulated-list-get-entry)))) (apply tabulated-list-printer elt) nil) ;; We find an entry that sorts before id, commit a246df7256ff119cc14cc9a8f8da34bf2ccc2b65 Author: Eli Zaretskii Date: Fri Jul 31 12:18:10 2015 +0300 ;* src/w32fns.c (syms_of_w32fns): Fix last commit. diff --git a/src/w32fns.c b/src/w32fns.c index 34e2720..1c72974 100644 --- a/src/w32fns.c +++ b/src/w32fns.c @@ -9149,7 +9149,7 @@ Set this to nil to get the old behavior for repainting; this should only be necessary if the default setting causes problems. */); w32_strict_painting = 1; - DEFVAR_BOOL ("w32-use-fallback-wm-chars-method" + DEFVAR_BOOL ("w32-use-fallback-wm-chars-method", w32_use_fallback_wm_chars_method, doc: /* Non-nil means use old method of processing character keys. This is intended only for debugging of the new processing method. commit e3d9ee522fce388db67f1f12007660fd3f0ef001 Author: Eli Zaretskii Date: Fri Jul 31 12:14:07 2015 +0300 Allow to use the old key processing code on MS-Windows * src/w32fns.c (syms_of_w32fns) : New variable. (w32_wnd_proc): Use it to invoke the old code that processed character keys, as fallback, when this variable is non-nil. Fix typos in comments. (Bug#19994) diff --git a/src/w32fns.c b/src/w32fns.c index fecdf7c..34e2720 100644 --- a/src/w32fns.c +++ b/src/w32fns.c @@ -2858,7 +2858,7 @@ get_wm_chars (HWND aWnd, int *buf, int buflen, int ignore_ctrl, int ctrl, || msg.message == WM_UNICHAR)) { /* We extract character payload, but in this call we handle only the - characters which comes BEFORE the next keyup/keydown message. */ + characters which come BEFORE the next keyup/keydown message. */ int dead; GetMessageW(&msg, aWnd, msg.message, msg.message); @@ -2962,7 +2962,7 @@ deliver_wm_chars (int do_translate, HWND hwnd, UINT msg, UINT wParam, The "usual" message pump calls TranslateMessage() for EVERY event. Emacs calls TranslateMessage() very selectively (is it needed for doing some tricky stuff with Win95??? With newer Windows, selectiveness is, - most probably, not needed - and harms a lot). + most probably, not needed -- and harms a lot). So, with the usual message pump, the following call to TranslateMessage() is not needed (and is going to be VERY harmful). With Emacs' message @@ -3058,7 +3058,7 @@ deliver_wm_chars (int do_translate, HWND hwnd, UINT msg, UINT wParam, Moreover: "traditional" layouts do not define distinct modifier-masks for VK_LMENU and VK_RMENU (same for VK_L/RCONTROL). Instead, they - rely on the KLLF_ALTGR bit to make the behaviour of VK_LMENU and + rely on the KLLF_ALTGR bit to make the behavior of VK_LMENU and VK_RMENU distinct. As a corollary, for such layouts, the produced character is the same for AltGr-* (=rAlt-*) and Ctrl-Alt-* (in any combination of handedness). For description of masks, see @@ -3153,7 +3153,7 @@ deliver_wm_chars (int do_translate, HWND hwnd, UINT msg, UINT wParam, /* In "traditional" layouts, Alt without Ctrl does not change the delivered character. This detects this situation; it is safe to report this as Alt-something - - as opposed to delivering the reported character + -- as opposed to delivering the reported character without modifiers. */ if (legacy_alt_meta && *b > 0x7f && ('A' <= wParam && wParam <= 'Z')) @@ -3421,6 +3421,8 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) /* Synchronize modifiers with current keystroke. */ sync_modifiers (); record_keydown (wParam, lParam); + if (w32_use_fallback_wm_chars_method) + wParam = map_keypad_keys (wParam, (lParam & 0x1000000L) != 0); windows_translate = 0; @@ -3530,7 +3532,7 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) wParam = VK_NUMLOCK; break; default: - if (w32_unicode_gui) + if (w32_unicode_gui && !w32_use_fallback_wm_chars_method) { /* If this event generates characters or deadkeys, do not interpret it as a "raw combination of modifiers @@ -3557,7 +3559,7 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) However, the keypress feeders would most probably expect the "standard" message pump, when - TranslateMessage() is called on EVERY KeyDown/Keyup + TranslateMessage() is called on EVERY KeyDown/KeyUp event. So they may feed us Down-Ctrl Down-FAKE Char-o and expect us to recognize it as Ctrl-o. Using 0 as the first argument would interfere with @@ -3566,7 +3568,7 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) #endif /* Processing the generated WM_CHAR messages *WHILE* we handle KEYDOWN/UP event is the best choice, since - withoug any fuss, we know all 3 of: scancode, virtual + without any fuss, we know all 3 of: scancode, virtual keycode, and expansion. (Additionally, one knows boundaries of expansion of different keypresses.) */ res = deliver_wm_chars (1, hwnd, msg, wParam, lParam, 1); @@ -9147,6 +9149,15 @@ Set this to nil to get the old behavior for repainting; this should only be necessary if the default setting causes problems. */); w32_strict_painting = 1; + DEFVAR_BOOL ("w32-use-fallback-wm-chars-method" + w32_use_fallback_wm_chars_method, + doc: /* Non-nil means use old method of processing character keys. +This is intended only for debugging of the new processing method. +Default is nil. + +This variable has effect only on NT family of systems, not on Windows 9X. */); + w32_use_fallback_wm_chars_method = 0; + #if 0 /* TODO: Port to W32 */ defsubr (&Sx_change_window_property); defsubr (&Sx_delete_window_property); commit 123c82e8307ca386ba7f161dc725e3953dffc5c0 Author: Ilya Zakharevich Date: Fri Jul 31 11:50:23 2015 +0300 Improve handling of Unicode keyboard input on MS-Windows * src/w32fns.c (get_wm_chars, deliver_wm_chars): New functions. (FPRINTF_WM_CHARS) [DEBUG_WM_CHARS]: New macro for debugging. (w32_wnd_proc): Call deliver_wm_chars to process non-special keys upon receiving WM_KEYDOWN or WM_SYSKEYDOWN messages. If that is successful, don't call TranslateMessage. (Bug#19994) diff --git a/src/w32fns.c b/src/w32fns.c index c742ca8..fecdf7c 100644 --- a/src/w32fns.c +++ b/src/w32fns.c @@ -270,7 +270,7 @@ check_x_display_info (Lisp_Object object) struct terminal *t = decode_live_terminal (object); if (t->type != output_w32) - error ("Terminal %d is not a W32 display", t->id); + error ("Terminal %d is not a W32 display", t->id); return t->display_info.w32; } @@ -304,7 +304,7 @@ x_window_to_frame (struct w32_display_info *dpyinfo, HWND wdesc) continue; if (FRAME_W32_WINDOW (f) == wdesc) - return f; + return f; } return 0; } @@ -366,7 +366,7 @@ w32_fullscreen_rect (HWND hwnd, int fsmode, RECT normal, RECT *rect) if (monitor_from_window_fn && get_monitor_info_fn) { HMONITOR monitor = - monitor_from_window_fn (hwnd, MONITOR_DEFAULT_TO_NEAREST); + monitor_from_window_fn (hwnd, MONITOR_DEFAULT_TO_NEAREST); get_monitor_info_fn (monitor, &mi); } else @@ -949,8 +949,8 @@ x_to_w32_color (const char * colorname) break; val = (UINT)(0x100 * value); /* We used 0x100 instead of 0xFF to give a continuous - range between 0.0 and 1.0 inclusive. The next statement - fixes the 1.0 case. */ + range between 0.0 and 1.0 inclusive. The next statement + fixes the 1.0 case. */ if (val == 0x100) val = 0xFF; colorval |= (val << pos); @@ -1060,7 +1060,7 @@ w32_map_color (struct frame *f, COLORREF color) while (list) { if (W32_COLOR (list->entry) == color) - { + { ++list->refcount; return; } @@ -1092,7 +1092,7 @@ w32_unmap_color (struct frame *f, COLORREF color) while (list) { if (W32_COLOR (list->entry) == color) - { + { if (--list->refcount == 0) { *prev = list->next; @@ -1121,9 +1121,9 @@ gamma_correct (struct frame *f, COLORREF *color) if (f->gamma) { *color = PALETTERGB ( - pow (GetRValue (*color) / 255.0, f->gamma) * 255.0 + 0.5, - pow (GetGValue (*color) / 255.0, f->gamma) * 255.0 + 0.5, - pow (GetBValue (*color) / 255.0, f->gamma) * 255.0 + 0.5); + pow (GetRValue (*color) / 255.0, f->gamma) * 255.0 + 0.5, + pow (GetGValue (*color) / 255.0, f->gamma) * 255.0 + 0.5, + pow (GetBValue (*color) / 255.0, f->gamma) * 255.0 + 0.5); } } @@ -1144,12 +1144,12 @@ w32_defined_color (struct frame *f, const char *color, XColor *color_def, if (!NILP (tem)) { if (f) - { - /* Apply gamma correction. */ - w32_color_ref = XUINT (tem); - gamma_correct (f, &w32_color_ref); - XSETINT (tem, w32_color_ref); - } + { + /* Apply gamma correction. */ + w32_color_ref = XUINT (tem); + gamma_correct (f, &w32_color_ref); + XSETINT (tem, w32_color_ref); + } /* Map this color to the palette if it is enabled. */ if (!NILP (Vw32_enable_palette)) @@ -1258,7 +1258,7 @@ x_set_foreground_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval) update_face_from_frame_parameter (f, Qforeground_color, arg); if (FRAME_VISIBLE_P (f)) - redraw_frame (f); + redraw_frame (f); } } @@ -1271,12 +1271,12 @@ x_set_background_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval) if (FRAME_W32_WINDOW (f) != 0) { SetWindowLong (FRAME_W32_WINDOW (f), WND_BACKGROUND_INDEX, - FRAME_BACKGROUND_PIXEL (f)); + FRAME_BACKGROUND_PIXEL (f)); update_face_from_frame_parameter (f, Qbackground_color, arg); if (FRAME_VISIBLE_P (f)) - redraw_frame (f); + redraw_frame (f); } } @@ -1399,9 +1399,9 @@ x_set_mouse_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval) XRecolorCursor (FRAME_W32_DISPLAY (f), mode_cursor, &fore_color, &back_color); XRecolorCursor (FRAME_W32_DISPLAY (f), hand_cursor, - &fore_color, &back_color); + &fore_color, &back_color); XRecolorCursor (FRAME_W32_DISPLAY (f), hourglass_cursor, - &fore_color, &back_color); + &fore_color, &back_color); } if (FRAME_W32_WINDOW (f) != 0) @@ -1445,7 +1445,7 @@ x_set_cursor_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval) if (!NILP (Vx_cursor_fore_pixel)) fore_pixel = x_decode_color (f, Vx_cursor_fore_pixel, - WHITE_PIX_DEFAULT (f)); + WHITE_PIX_DEFAULT (f)); else fore_pixel = FRAME_BACKGROUND_PIXEL (f); @@ -1494,7 +1494,7 @@ x_set_border_pixel (struct frame *f, int pix) if (FRAME_W32_WINDOW (f) != 0 && f->border_width > 0) { if (FRAME_VISIBLE_P (f)) - redraw_frame (f); + redraw_frame (f); } } @@ -1771,7 +1771,7 @@ w32_set_title_bar_text (struct frame *f, Lisp_Object name) block_input (); #ifdef __CYGWIN__ GUI_FN (SetWindowText) (FRAME_W32_WINDOW (f), - GUI_SDATA (GUI_ENCODE_SYSTEM (name))); + GUI_SDATA (GUI_ENCODE_SYSTEM (name))); #else /* The frame's title many times shows the name of the file visited in the selected window's buffer, so it makes sense to @@ -2319,7 +2319,7 @@ w32_get_modifiers (void) (modifier_set (VK_RWIN) ? w32_key_to_modifier (VK_RWIN) : 0) | (modifier_set (VK_APPS) ? w32_key_to_modifier (VK_APPS) : 0) | (modifier_set (VK_SCROLL) ? w32_key_to_modifier (VK_SCROLL) : 0) | - (modifier_set (VK_MENU) ? + (modifier_set (VK_MENU) ? ((NILP (Vw32_alt_is_meta)) ? alt_modifier : meta_modifier) : 0)); } @@ -2541,13 +2541,13 @@ w32_msg_pump (deferred_msg * msg_buf) /* Produced by complete_deferred_msg; just ignore. */ break; case WM_EMACS_CREATEWINDOW: - /* Initialize COM for this window. Even though we don't use it, - some third party shell extensions can cause it to be used in - system dialogs, which causes a crash if it is not initialized. - This is a known bug in Windows, which was fixed long ago, but - the patch for XP is not publicly available until XP SP3, - and older versions will never be patched. */ - CoInitialize (NULL); + /* Initialize COM for this window. Even though we don't use it, + some third party shell extensions can cause it to be used in + system dialogs, which causes a crash if it is not initialized. + This is a known bug in Windows, which was fixed long ago, but + the patch for XP is not publicly available until XP SP3, + and older versions will never be patched. */ + CoInitialize (NULL); w32_createwindow ((struct frame *) msg.wParam, (int *) msg.lParam); if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0)) @@ -2577,9 +2577,9 @@ w32_msg_pump (deferred_msg * msg_buf) if (focus_window != NULL) UnregisterHotKey (focus_window, RAW_HOTKEY_ID (msg.wParam)); /* Mark item as erased. NB: this code must be - thread-safe. The next line is okay because the cons - cell is never made into garbage and is not relocated by - GC. */ + thread-safe. The next line is okay because the cons + cell is never made into garbage and is not relocated by + GC. */ XSETCAR (make_lisp_ptr ((void *)msg.lParam, Lisp_Cons), Qnil); if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0)) emacs_abort (); @@ -2612,10 +2612,10 @@ w32_msg_pump (deferred_msg * msg_buf) } break; #ifdef MSG_DEBUG - /* Broadcast messages make it here, so you need to be looking - for something in particular for this to be useful. */ + /* Broadcast messages make it here, so you need to be looking + for something in particular for this to be useful. */ default: - DebPrint (("msg %x not expected by w32_msg_pump\n", msg.message)); + DebPrint (("msg %x not expected by w32_msg_pump\n", msg.message)); #endif } } @@ -2809,19 +2809,19 @@ post_character_message (HWND hwnd, UINT msg, signal_quit (); /* As a safety precaution, forcibly complete any deferred - messages. This is a kludge, but I don't see any particularly - clean way to handle the situation where a deferred message is - "dropped" in the lisp thread, and will thus never be - completed, eg. by the user trying to activate the menubar - when the lisp thread is busy, and then typing C-g when the - menubar doesn't open promptly (with the result that the - menubar never responds at all because the deferred - WM_INITMENU message is never completed). Another problem - situation is when the lisp thread calls SendMessage (to send - a window manager command) when a message has been deferred; - the lisp thread gets blocked indefinitely waiting for the - deferred message to be completed, which itself is waiting for - the lisp thread to respond. + messages. This is a kludge, but I don't see any particularly + clean way to handle the situation where a deferred message is + "dropped" in the lisp thread, and will thus never be + completed, eg. by the user trying to activate the menubar + when the lisp thread is busy, and then typing C-g when the + menubar doesn't open promptly (with the result that the + menubar never responds at all because the deferred + WM_INITMENU message is never completed). Another problem + situation is when the lisp thread calls SendMessage (to send + a window manager command) when a message has been deferred; + the lisp thread gets blocked indefinitely waiting for the + deferred message to be completed, which itself is waiting for + the lisp thread to respond. Note that we don't want to block the input thread waiting for a response from the lisp thread (although that would at least @@ -2836,6 +2836,407 @@ post_character_message (HWND hwnd, UINT msg, my_post_msg (&wmsg, hwnd, msg, wParam, lParam); } +static int +get_wm_chars (HWND aWnd, int *buf, int buflen, int ignore_ctrl, int ctrl, + int *ctrl_cnt, int *is_dead, int vk, int exp) +{ + MSG msg; + /* If doubled is at the end, ignore it. */ + int i = buflen, doubled = 0, code_unit; + + if (ctrl_cnt) + *ctrl_cnt = 0; + if (is_dead) + *is_dead = -1; + eassert(w32_unicode_gui); + while (buflen + /* Should be called only when w32_unicode_gui: */ + && PeekMessageW(&msg, aWnd, WM_KEYFIRST, WM_KEYLAST, + PM_NOREMOVE | PM_NOYIELD) + && (msg.message == WM_CHAR || msg.message == WM_SYSCHAR + || msg.message == WM_DEADCHAR || msg.message == WM_SYSDEADCHAR + || msg.message == WM_UNICHAR)) + { + /* We extract character payload, but in this call we handle only the + characters which comes BEFORE the next keyup/keydown message. */ + int dead; + + GetMessageW(&msg, aWnd, msg.message, msg.message); + dead = (msg.message == WM_DEADCHAR || msg.message == WM_SYSDEADCHAR); + if (is_dead) + *is_dead = (dead ? msg.wParam : -1); + if (dead) + continue; + code_unit = msg.wParam; + if (doubled) + { + /* Had surrogate. */ + if (msg.message == WM_UNICHAR + || code_unit < 0xDC00 || code_unit > 0xDFFF) + { /* Mismatched first surrogate. + Pass both code units as if they were two characters. */ + *buf++ = doubled; + if (!--buflen) + return i; /* Drop the 2nd char if at the end of the buffer. */ + } + else /* see https://en.wikipedia.org/wiki/UTF-16 */ + code_unit = (doubled << 10) + code_unit - 0x35FDC00; + doubled = 0; + } + else if (code_unit >= 0xD800 && code_unit <= 0xDBFF) + { + /* Handle mismatched 2nd surrogate the same as a normal character. */ + doubled = code_unit; + continue; + } + + /* The only "fake" characters delivered by ToUnicode() or + TranslateMessage() are: + 0x01 .. 0x1a for Ctrl-letter, Enter, Tab, Ctrl-Break, Esc, Backspace + 0x00 and 0x1b .. 0x1f for Control- []\@^_ + 0x7f for Control-BackSpace + 0x20 for Control-Space */ + if (ignore_ctrl + && (code_unit < 0x20 || code_unit == 0x7f + || (code_unit == 0x20 && ctrl))) + { + /* Non-character payload in a WM_CHAR + (Ctrl-something pressed, see above). Ignore, and report. */ + if (ctrl_cnt) + *ctrl_cnt++; + continue; + } + /* Traditionally, Emacs would ignore the character payload of VK_NUMPAD* + keys, and would treat them later via `function-key-map'. In addition + to usual 102-key NUMPAD keys, this map also treats `kp-'-variants of + space, tab, enter, separator, equal. TAB and EQUAL, apparently, + cannot be generated on Win-GUI branch. ENTER is already handled + by the code above. According to `lispy_function_keys', kp_space is + generated by not-extended VK_CLEAR. (kp-tab != VK_OEM_NEC_EQUAL!). + + We do similarly for backward-compatibility, but ignore only the + characters restorable later by `function-key-map'. */ + if (code_unit < 0x7f + && ((vk >= VK_NUMPAD0 && vk <= VK_DIVIDE) + || (exp && ((vk >= VK_PRIOR && vk <= VK_DOWN) || + vk == VK_INSERT || vk == VK_DELETE || vk == VK_CLEAR))) + && strchr("0123456789/*-+.,", code_unit)) + continue; + *buf++ = code_unit; + buflen--; + } + return i - buflen; +} + +#ifdef DBG_WM_CHARS +# define FPRINTF_WM_CHARS(ARG) fprintf ARG +#else +# define FPRINTF_WM_CHARS(ARG) 0 +#endif + +/* This is a heuristic only. This is supposed to track the state of the + finite automaton in the language environment of Windows. + + However, separate windows (if with the same different language + environments!) should have different values. Moreover, switching to a + non-Emacs window with the same language environment, and using (dead)keys + there would change the value stored in the kernel, but not this value. */ +static int after_deadkey = 0; + +int +deliver_wm_chars (int do_translate, HWND hwnd, UINT msg, UINT wParam, + UINT lParam, int legacy_alt_meta) +{ + /* An "old style" keyboard description may assign up to 125 UTF-16 code + points to a keypress. + (However, the "old style" TranslateMessage() would deliver at most 16 of + them.) Be on a safe side, and prepare to treat many more. */ + int ctrl_cnt, buf[1024], count, is_dead, after_dead = (after_deadkey != -1); + + /* Since the keypress processing logic of Windows has a lot of state, it + is important to call TranslateMessage() for every keyup/keydown, AND + do it exactly once. (The actual change of state is done by + ToUnicode[Ex](), which is called by TranslateMessage(). So one can + call ToUnicode[Ex]() instead.) + + The "usual" message pump calls TranslateMessage() for EVERY event. + Emacs calls TranslateMessage() very selectively (is it needed for doing + some tricky stuff with Win95??? With newer Windows, selectiveness is, + most probably, not needed - and harms a lot). + + So, with the usual message pump, the following call to TranslateMessage() + is not needed (and is going to be VERY harmful). With Emacs' message + pump, the call is needed. */ + if (do_translate) + { + MSG windows_msg = { hwnd, msg, wParam, lParam, 0, {0,0} }; + + windows_msg.time = GetMessageTime (); + TranslateMessage (&windows_msg); + } + count = get_wm_chars (hwnd, buf, sizeof(buf)/sizeof(*buf), 1, + /* The message may have been synthesized by + who knows what; be conservative. */ + modifier_set (VK_LCONTROL) + || modifier_set (VK_RCONTROL) + || modifier_set (VK_CONTROL), + &ctrl_cnt, &is_dead, wParam, + (lParam & 0x1000000L) != 0); + if (count) + { + W32Msg wmsg; + DWORD console_modifiers = construct_console_modifiers (); + int *b = buf, strip_Alt = 1, strip_ExtraMods = 1, hairy = 0; + char *type_CtrlAlt = NULL; + + /* XXXX In fact, there may be another case when we need to do the same: + What happens if the string defined in the LIGATURES has length + 0? Probably, we will get count==0, but the state of the finite + automaton would reset to 0??? */ + after_deadkey = -1; + + /* wParam is checked when converting CapsLock to Shift; this is a clone + of w32_get_key_modifiers (). */ + wmsg.dwModifiers = w32_kbd_mods_to_emacs (console_modifiers, wParam); + + /* What follows is just heuristics; the correct treatement requires + non-destructive ToUnicode(): + http://search.cpan.org/~ilyaz/UI-KeyboardLayout/lib/UI/KeyboardLayout.pm#Can_an_application_on_Windows_accept_keyboard_events?_Part_IV:_application-specific_modifiers + + What one needs to find is: + * which of the present modifiers AFFECT the resulting char(s) + (so should be stripped, since their EFFECT is "already + taken into account" in the string in buf), and + * which modifiers are not affecting buf, so should be reported to + the application for further treatment. + + Example: assume that we know: + (A) lCtrl+rCtrl+rAlt modifiers with VK_A key produce a Latin "f" + ("may be logical" in JCUKEN-flavored Russian keyboard flavors); + (B) removing any of lCtrl, rCtrl, rAlt changes the produced char; + (C) Win-modifier is not affecting the produced character + (this is the common case: happens with all "standard" layouts). + + Suppose the user presses Win+lCtrl+rCtrl+rAlt modifiers with VK_A. + What is the intent of the user? We need to guess the intent to decide + which event to deliver to the application. + + This looks like a reasonable logic: since Win- modifier doesn't affect + the output string, the user was pressing Win for SOME OTHER purpose. + So the user wanted to generate Win-SOMETHING event. Now, what is + something? If one takes the mantra that "character payload is more + important than the combination of keypresses which resulted in this + payload", then one should ignore lCtrl+rCtrl+rAlt, ignore VK_A, and + assume that the user wanted to generate Win-f. + + Unfortunately, without non-destructive ToUnicode(), checking (B),(C) + is out of question. So we use heuristics (hopefully, covering + 99.9999% of cases). */ + + /* Another thing to watch for is a possibility to use AltGr-* and + Ctrl-Alt-* with different semantic. + + Background: the layout defining the KLLF_ALTGR bit are treated + specially by the kernel: when VK_RMENU (=rightAlt, =AltGr) is pressed + (released), a press (release) of VK_LCONTROL is emulated (unless Ctrl + is already down). As a result, any press/release of AltGr is seen + by applications as a press/release of lCtrl AND rAlt. This is + applicable, in particular, to ToUnicode[Ex](). (Keyrepeat is covered + the same way!) + + NOTE: it IS possible to see bare rAlt even with KLLF_ALTGR; but this + requires a good finger coordination: doing (physically) + Down-lCtrl Down-rAlt Up-lCtrl Down-a + (doing quick enough, so that key repeat of rAlt [which would + generate new "fake" Down-lCtrl events] does not happens before 'a' + is down) results in no "fake" events, so the application will see + only rAlt down when 'a' is pressed. (However, fake Up-lCtrl WILL + be generated when rAlt goes UP.) + + In fact, note also that KLLF_ALTGR does not prohibit construction of + rCtrl-rAlt (just press them in this order!). + + Moreover: "traditional" layouts do not define distinct modifier-masks + for VK_LMENU and VK_RMENU (same for VK_L/RCONTROL). Instead, they + rely on the KLLF_ALTGR bit to make the behaviour of VK_LMENU and + VK_RMENU distinct. As a corollary, for such layouts, the produced + character is the same for AltGr-* (=rAlt-*) and Ctrl-Alt-* (in any + combination of handedness). For description of masks, see + + http://search.cpan.org/~ilyaz/UI-KeyboardLayout/lib/UI/KeyboardLayout.pm#Keyboard_input_on_Windows,_Part_I:_what_is_the_kernel_doing? + + By default, Emacs was using these coincidences via the following + heuristics: it was treating: + (*) keypresses with lCtrl-rAlt modifiers as if they are carrying + ONLY the character payload (no matter what the actual keyboard + was defining: if lCtrl-lAlt-b was delivering U+05df=beta, then + Emacs saw [beta]; if lCtrl-lAlt-b was undefined in the layout, + the keypress was completely ignored), and + (*) keypresses with the other combinations of handedness of Ctrl-Alt + modifiers (e.g., lCtrl-lAlt) as if they NEVER carry a character + payload (so they were reported "raw": if lCtrl-lAlt-b was + delivering beta, then Emacs saw event [C-A-b], and not [beta]). + This worked good for "traditional" layouts: users could type both + AltGr-x and Ctrl-Alt-x, and one was a character, another a bindable + event. + + However, for layouts which deliver different characters for AltGr-x + and lCtrl-lAlt-x, this scheme makes the latter character unaccessible + in Emacs. While it is easy to access functionality of [C-M-x] in + Emacs by other means (for example, by the `controlify' prefix, or + using lCtrl-rCtrl-x, or rCtrl-rAlt-x [in this order]), missing + characters cannot be reconstructed without a tedious manual work. */ + + /* These two cases are often going to be distinguishable, since at most + one of these character is defined with KBDCTRL | KBDMENU modifier + bitmap. (This heuristic breaks if both lCtrl-lAlt- AND lCtrl-rAlt- + are translated to modifier bitmaps distinct from KBDCTRL | KBDMENU, + or in the cases when lCtrl-lAlt-* and lCtrl-rAlt-* are generally + different, but lCtrl-lAlt-x and lCtrl-rAlt-x happen to deliver the + same character.) + + So we have 2 chunks of info: + (A) is it lCtrl-rAlt-, or lCtrl-lAlt, or some other combination? + (B) is the delivered character defined with KBDCTRL | KBDMENU bits? + Basing on (A) and (B), we should decide whether to ignore the + delivered character. (Before, Emacs was completely ignoring (B), and + was treating the 3-state of (A) as a bit.) This means that we have 6 + bits of customization. + + Additionally, a presence of two Ctrl down may be AltGr-rCtrl-. */ + + /* Strip all non-Shift modifiers if: + - more than one UTF-16 code point delivered (can't call VkKeyScanW ()) + - or the character is a result of combining with a prefix key. */ + if (!after_dead && count == 1 && *b < 0x10000) + { + if (console_modifiers & (RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED) + && console_modifiers & (RIGHT_CTRL_PRESSED | LEFT_CTRL_PRESSED)) + { + type_CtrlAlt = "bB"; /* generic bindable Ctrl-Alt- modifiers */ + if (console_modifiers & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED) + == (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) + /* double-Ctrl: + e.g. AltGr-rCtrl on some layouts (in this order!) */ + type_CtrlAlt = "dD"; + else if (console_modifiers + & (LEFT_CTRL_PRESSED | LEFT_ALT_PRESSED) + == (LEFT_CTRL_PRESSED | LEFT_ALT_PRESSED)) + type_CtrlAlt = "lL"; /* Ctrl-Alt- modifiers on the left */ + else if (!NILP (Vw32_recognize_altgr) + && (console_modifiers + & (RIGHT_ALT_PRESSED | LEFT_CTRL_PRESSED)) + == (RIGHT_ALT_PRESSED | LEFT_CTRL_PRESSED)) + type_CtrlAlt = "gG"; /* modifiers as in AltGr */ + } + else if (wmsg.dwModifiers & (alt_modifier | meta_modifier) + || (console_modifiers + & (RIGHT_WIN_PRESSED | RIGHT_WIN_PRESSED + | APPS_PRESSED | SCROLLLOCK_ON))) + { + /* Pure Alt (or combination of Alt, Win, APPS, scrolllock. */ + type_CtrlAlt = "aA"; + } + if (type_CtrlAlt) + { + /* Out of bound bitmap: */ + SHORT r = VkKeyScanW( *b ), bitmap = 0x1FF; + + FPRINTF_WM_CHARS((stderr, "VkKeyScanW %#06x %#04x\n", (int)r, + wParam)); + if ((r & 0xFF) == wParam) + bitmap = r>>8; /* *b is reachable via simple interface */ + if (*type_CtrlAlt == 'a') /* Simple Alt seen */ + { + if ((bitmap & ~1) == 0) /* 1: KBDSHIFT */ + { + /* In "traditional" layouts, Alt without Ctrl does not + change the delivered character. This detects this + situation; it is safe to report this as Alt-something + - as opposed to delivering the reported character + without modifiers. */ + if (legacy_alt_meta + && *b > 0x7f && ('A' <= wParam && wParam <= 'Z')) + /* For backward-compatibility with older Emacsen, let + this be processed by another branch below (which + would convert it to Alt-Latin char via wParam). */ + return 0; + } + else + hairy = 1; + } + /* Check whether the delivered character(s) is accessible via + KBDCTRL | KBDALT ( | KBDSHIFT ) modifier mask (which is 7). */ + else if ((bitmap & ~1) != 6) + { + /* The character is not accessible via plain Ctrl-Alt(-Shift) + (which is, probably, same as AltGr) modifiers. + Either it was after a prefix key, or is combined with + modifier keys which we don't see, or there is an asymmetry + between left-hand and right-hand modifiers, or other hairy + stuff. */ + hairy = 1; + } + /* The best solution is to delegate these tough (but rarely + needed) choices to the user. Temporarily (???), it is + implemented as C macros. + + Essentially, there are 3 things to do: return 0 (handle to the + legacy processing code [ignoring the character payload]; keep + some modifiers (so that they will be processed by the binding + system [on top of the character payload]; strip modifiers [so + that `self-insert' is going to be triggered with the character + payload]). + + The default below should cover 99.9999% of cases: + (a) strip Alt- in the hairy case only; + (stripping = not ignoring) + (l) for lAlt-lCtrl, ignore the char in simple cases only; + (g) for what looks like AltGr, ignore the modifiers; + (d) for what looks like lCtrl-rCtrl-Alt (probably + AltGr-rCtrl), ignore the character in simple cases only; + (b) for other cases of Ctrl-Alt, ignore the character in + simple cases only. + + Essentially, in all hairy cases, and in looks-like-AltGr case, + we keep the character, ignoring the modifiers. In all the + other cases, we ignore the delivered character. */ +#define S_TYPES_TO_IGNORE_CHARACTER_PAYLOAD "aldb" +#define S_TYPES_TO_REPORT_CHARACTER_PAYLOAD_WITH_MODIFIERS "" + if (strchr(S_TYPES_TO_IGNORE_CHARACTER_PAYLOAD, + type_CtrlAlt[hairy])) + return 0; + /* If in neither list, report all the modifiers we see COMBINED + WITH the reported character. */ + if (strchr(S_TYPES_TO_REPORT_CHARACTER_PAYLOAD_WITH_MODIFIERS, + type_CtrlAlt[hairy])) + strip_ExtraMods = 0; + } + } + if (strip_ExtraMods) + wmsg.dwModifiers = wmsg.dwModifiers & shift_modifier; + + signal_user_input (); + while (count--) + { + FPRINTF_WM_CHARS((stderr, "unichar %#06x\n", *b)); + my_post_msg (&wmsg, hwnd, WM_UNICHAR, *b++, lParam); + } + if (!ctrl_cnt) /* Process ALSO as ctrl */ + return 1; + else + FPRINTF_WM_CHARS((stderr, "extra ctrl char\n")); + return -1; + } + else if (is_dead >= 0) + { + FPRINTF_WM_CHARS((stderr, "dead %#06x\n", is_dead)); + after_deadkey = is_dead; + return 1; + } + return 0; +} + /* Main window procedure */ static LRESULT CALLBACK @@ -2869,15 +3270,15 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) f = x_window_to_frame (dpyinfo, hwnd); if (f) { - HDC hdc = get_frame_dc (f); + HDC hdc = get_frame_dc (f); GetUpdateRect (hwnd, &wmsg.rect, FALSE); w32_clear_rect (f, hdc, &wmsg.rect); - release_frame_dc (f, hdc); + release_frame_dc (f, hdc); #if defined (W32_DEBUG_DISPLAY) - DebPrint (("WM_ERASEBKGND (frame %p): erasing %d,%d-%d,%d\n", + DebPrint (("WM_ERASEBKGND (frame %p): erasing %d,%d-%d,%d\n", f, - wmsg.rect.left, wmsg.rect.top, + wmsg.rect.left, wmsg.rect.top, wmsg.rect.right, wmsg.rect.bottom)); #endif /* W32_DEBUG_DISPLAY */ } @@ -2885,7 +3286,7 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) case WM_PALETTECHANGED: /* ignore our own changes */ if ((HWND)wParam != hwnd) - { + { f = x_window_to_frame (dpyinfo, hwnd); if (f) /* get_frame_dc will realize our palette and force all @@ -2895,24 +3296,24 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) return 0; case WM_PAINT: { - PAINTSTRUCT paintStruct; - RECT update_rect; + PAINTSTRUCT paintStruct; + RECT update_rect; memset (&update_rect, 0, sizeof (update_rect)); f = x_window_to_frame (dpyinfo, hwnd); if (f == 0) { - DebPrint (("WM_PAINT received for unknown window %p\n", hwnd)); + DebPrint (("WM_PAINT received for unknown window %p\n", hwnd)); return 0; } - /* MSDN Docs say not to call BeginPaint if GetUpdateRect - fails. Apparently this can happen under some - circumstances. */ - if (GetUpdateRect (hwnd, &update_rect, FALSE) || !w32_strict_painting) - { - enter_crit (); - BeginPaint (hwnd, &paintStruct); + /* MSDN Docs say not to call BeginPaint if GetUpdateRect + fails. Apparently this can happen under some + circumstances. */ + if (GetUpdateRect (hwnd, &update_rect, FALSE) || !w32_strict_painting) + { + enter_crit (); + BeginPaint (hwnd, &paintStruct); /* The rectangles returned by GetUpdateRect and BeginPaint do not always match. Play it safe by assuming both areas @@ -2920,40 +3321,49 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) UnionRect (&(wmsg.rect), &update_rect, &(paintStruct.rcPaint)); #if defined (W32_DEBUG_DISPLAY) - DebPrint (("WM_PAINT (frame %p): painting %d,%d-%d,%d\n", + DebPrint (("WM_PAINT (frame %p): painting %d,%d-%d,%d\n", f, wmsg.rect.left, wmsg.rect.top, wmsg.rect.right, wmsg.rect.bottom)); - DebPrint ((" [update region is %d,%d-%d,%d]\n", - update_rect.left, update_rect.top, - update_rect.right, update_rect.bottom)); + DebPrint ((" [update region is %d,%d-%d,%d]\n", + update_rect.left, update_rect.top, + update_rect.right, update_rect.bottom)); #endif - EndPaint (hwnd, &paintStruct); - leave_crit (); + EndPaint (hwnd, &paintStruct); + leave_crit (); /* Change the message type to prevent Windows from combining WM_PAINT messages in the Lisp thread's queue, since Windows assumes that each message queue is dedicated to one frame and does not bother checking that hwnd matches before combining them. */ - my_post_msg (&wmsg, hwnd, WM_EMACS_PAINT, wParam, lParam); + my_post_msg (&wmsg, hwnd, WM_EMACS_PAINT, wParam, lParam); - return 0; - } + return 0; + } /* If GetUpdateRect returns 0 (meaning there is no update - region), assume the whole window needs to be repainted. */ + region), assume the whole window needs to be repainted. */ GetClientRect (hwnd, &wmsg.rect); my_post_msg (&wmsg, hwnd, msg, wParam, lParam); - return 0; + return 0; } case WM_INPUTLANGCHANGE: /* Inform lisp thread of keyboard layout changes. */ my_post_msg (&wmsg, hwnd, msg, wParam, lParam); + /* The state of the finite automaton is separate per every input + language environment (so it does not change when one switches + to a different window with the same environment). Moreover, + the experiments show that the state is not remembered when + one switches back to the pre-previous environment. */ + after_deadkey = -1; + + /* XXXX??? What follows is a COMPLETE misunderstanding of Windows! */ + /* Clear dead keys in the keyboard state; for simplicity only - preserve modifier key states. */ + preserve modifier key states. */ { int i; BYTE keystate[256]; @@ -3011,7 +3421,6 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) /* Synchronize modifiers with current keystroke. */ sync_modifiers (); record_keydown (wParam, lParam); - wParam = map_keypad_keys (wParam, (lParam & 0x1000000L) != 0); windows_translate = 0; @@ -3052,14 +3461,14 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) if (!NILP (Vw32_rwindow_modifier)) return 0; break; - case VK_APPS: + case VK_APPS: if (!NILP (Vw32_apps_modifier)) return 0; break; case VK_MENU: if (NILP (Vw32_pass_alt_to_system)) /* Prevent DefWindowProc from activating the menu bar if an - Alt key is pressed and released by itself. */ + Alt key is pressed and released by itself. */ return 0; windows_translate = 1; break; @@ -3083,9 +3492,9 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) break; disable_lock_key: /* Ensure the appropriate lock key state (and indicator light) - remains in the same state. We do this by faking another - press of the relevant key. Apparently, this really is the - only way to toggle the state of the indicator lights. */ + remains in the same state. We do this by faking another + press of the relevant key. Apparently, this really is the + only way to toggle the state of the indicator lights. */ dpyinfo->faked_key = wParam; keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0), KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0); @@ -3094,8 +3503,8 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0), KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0); /* Ensure indicator lights are updated promptly on Windows 9x - (TranslateMessage apparently does this), after forwarding - input event. */ + (TranslateMessage apparently does this), after forwarding + input event. */ post_character_message (hwnd, msg, wParam, lParam, w32_get_key_modifiers (wParam, lParam)); windows_translate = 1; @@ -3107,21 +3516,67 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) break; case VK_CANCEL: /* Windows maps Ctrl-Pause (aka Ctrl-Break) into VK_CANCEL, - which is confusing for purposes of key binding; convert + which is confusing for purposes of key binding; convert VK_CANCEL events into VK_PAUSE events. */ wParam = VK_PAUSE; break; case VK_PAUSE: /* Windows maps Ctrl-NumLock into VK_PAUSE, which is confusing - for purposes of key binding; convert these back into - VK_NUMLOCK events, at least when we want to see NumLock key - presses. (Note that there is never any possibility that - VK_PAUSE with Ctrl really is C-Pause as per above.) */ + for purposes of key binding; convert these back into + VK_NUMLOCK events, at least when we want to see NumLock key + presses. (Note that there is never any possibility that + VK_PAUSE with Ctrl really is C-Pause as per above.) */ if (NILP (Vw32_enable_num_lock) && modifier_set (VK_CONTROL)) wParam = VK_NUMLOCK; break; default: - /* If not defined as a function key, change it to a WM_CHAR message. */ + if (w32_unicode_gui) + { + /* If this event generates characters or deadkeys, do + not interpret it as a "raw combination of modifiers + and keysym". Hide deadkeys, and use the generated + character(s) instead of the keysym. (Backward + compatibility: exceptions for numpad keys generating + 0-9 . , / * - +, and for extra-Alt combined with a + non-Latin char.) + + Try to not report modifiers which have effect on + which character or deadkey is generated. + + Example (contrived): if rightAlt-? generates f (on a + Cyrillic keyboard layout), and Ctrl, leftAlt do not + affect the generated character, one wants to report + Ctrl-leftAlt-f if the user presses + Ctrl-leftAlt-rightAlt-?. */ + int res; +#if 0 + /* Some of WM_CHAR may be fed to us directly, some are + results of TranslateMessage(). Using 0 as the first + argument (in a separate call) might help us + distinguish these two cases. + + However, the keypress feeders would most probably + expect the "standard" message pump, when + TranslateMessage() is called on EVERY KeyDown/Keyup + event. So they may feed us Down-Ctrl Down-FAKE + Char-o and expect us to recognize it as Ctrl-o. + Using 0 as the first argument would interfere with + this. */ + deliver_wm_chars (0, hwnd, msg, wParam, lParam, 1); +#endif + /* Processing the generated WM_CHAR messages *WHILE* we + handle KEYDOWN/UP event is the best choice, since + withoug any fuss, we know all 3 of: scancode, virtual + keycode, and expansion. (Additionally, one knows + boundaries of expansion of different keypresses.) */ + res = deliver_wm_chars (1, hwnd, msg, wParam, lParam, 1); + windows_translate = -( res != 0 ); + if (res > 0) /* Bound to character(s) or a deadkey */ + break; + /* deliver_wm_chars may make some branches after this vestigal. */ + } + wParam = map_keypad_keys (wParam, (lParam & 0x1000000L) != 0); + /* If not defined as a function key, change it to a WM_CHAR message. */ if (wParam > 255 || !lispy_function_keys[wParam]) { DWORD modifiers = construct_console_modifiers (); @@ -3173,7 +3628,7 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) /* Forward asciified character sequence. */ post_character_message (hwnd, WM_CHAR, - (unsigned char) key.uChar.AsciiChar, lParam, + (unsigned char) key.uChar.AsciiChar, lParam, w32_get_key_modifiers (wParam, lParam)); w32_kbd_patch_key (&key, w32_keyboard_codepage); } @@ -3188,6 +3643,8 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) } } + if (windows_translate == -1) + break; translate: if (windows_translate) { @@ -3202,73 +3659,73 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) case WM_SYSCHAR: case WM_CHAR: if (wParam > 255 ) - { - W32Msg wmsg; + { + W32Msg wmsg; - wmsg.dwModifiers = w32_get_key_modifiers (wParam, lParam); - signal_user_input (); - my_post_msg (&wmsg, hwnd, WM_UNICHAR, wParam, lParam); + wmsg.dwModifiers = w32_get_key_modifiers (wParam, lParam); + signal_user_input (); + my_post_msg (&wmsg, hwnd, WM_UNICHAR, wParam, lParam); - } + } else - post_character_message (hwnd, msg, wParam, lParam, - w32_get_key_modifiers (wParam, lParam)); + post_character_message (hwnd, msg, wParam, lParam, + w32_get_key_modifiers (wParam, lParam)); break; case WM_UNICHAR: /* WM_UNICHAR looks promising from the docs, but the exact - circumstances in which TranslateMessage sends it is one of those - Microsoft secret API things that EU and US courts are supposed - to have put a stop to already. Spy++ shows it being sent to Notepad - and other MS apps, but never to Emacs. + circumstances in which TranslateMessage sends it is one of those + Microsoft secret API things that EU and US courts are supposed + to have put a stop to already. Spy++ shows it being sent to Notepad + and other MS apps, but never to Emacs. - Some third party IMEs send it in accordance with the official - documentation though, so handle it here. + Some third party IMEs send it in accordance with the official + documentation though, so handle it here. - UNICODE_NOCHAR is used to test for support for this message. - TRUE indicates that the message is supported. */ + UNICODE_NOCHAR is used to test for support for this message. + TRUE indicates that the message is supported. */ if (wParam == UNICODE_NOCHAR) - return TRUE; + return TRUE; { - W32Msg wmsg; - wmsg.dwModifiers = w32_get_key_modifiers (wParam, lParam); - signal_user_input (); - my_post_msg (&wmsg, hwnd, msg, wParam, lParam); + W32Msg wmsg; + wmsg.dwModifiers = w32_get_key_modifiers (wParam, lParam); + signal_user_input (); + my_post_msg (&wmsg, hwnd, msg, wParam, lParam); } break; case WM_IME_CHAR: /* If we can't get the IME result as Unicode, use default processing, - which will at least allow characters decodable in the system locale - get through. */ + which will at least allow characters decodable in the system locale + get through. */ if (!get_composition_string_fn) - goto dflt; + goto dflt; else if (!ignore_ime_char) - { - wchar_t * buffer; - int size, i; - W32Msg wmsg; - HIMC context = get_ime_context_fn (hwnd); - wmsg.dwModifiers = w32_get_key_modifiers (wParam, lParam); - /* Get buffer size. */ - size = get_composition_string_fn (context, GCS_RESULTSTR, NULL, 0); - buffer = alloca (size); - size = get_composition_string_fn (context, GCS_RESULTSTR, - buffer, size); + { + wchar_t * buffer; + int size, i; + W32Msg wmsg; + HIMC context = get_ime_context_fn (hwnd); + wmsg.dwModifiers = w32_get_key_modifiers (wParam, lParam); + /* Get buffer size. */ + size = get_composition_string_fn (context, GCS_RESULTSTR, NULL, 0); + buffer = alloca (size); + size = get_composition_string_fn (context, GCS_RESULTSTR, + buffer, size); release_ime_context_fn (hwnd, context); - signal_user_input (); - for (i = 0; i < size / sizeof (wchar_t); i++) - { - my_post_msg (&wmsg, hwnd, WM_UNICHAR, (WPARAM) buffer[i], - lParam); - } - /* Ignore the messages for the rest of the + signal_user_input (); + for (i = 0; i < size / sizeof (wchar_t); i++) + { + my_post_msg (&wmsg, hwnd, WM_UNICHAR, (WPARAM) buffer[i], + lParam); + } + /* Ignore the messages for the rest of the characters in the string that was output above. */ - ignore_ime_char = (size / sizeof (wchar_t)) - 1; - } + ignore_ime_char = (size / sizeof (wchar_t)) - 1; + } else ignore_ime_char--; @@ -3490,7 +3947,7 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) signal_user_input (); /* Need to return true for XBUTTON messages, false for others, - to indicate that we processed the message. */ + to indicate that we processed the message. */ return (msg == WM_XBUTTONDOWN || msg == WM_XBUTTONUP); case WM_MOUSEMOVE: @@ -3553,11 +4010,11 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) case WM_VSCROLL: if (w32_mouse_move_interval <= 0 || (msg == WM_MOUSEMOVE && button_state == 0)) - { + { wmsg.dwModifiers = w32_get_modifiers (); my_post_msg (&wmsg, hwnd, msg, wParam, lParam); return 0; - } + } /* Hang onto mouse move and scroll messages for a bit, to avoid sending such events to Emacs faster than it can process them. @@ -3588,15 +4045,15 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) case WM_APPCOMMAND: if (w32_pass_multimedia_buttons_to_system) - goto dflt; + goto dflt; /* Otherwise, pass to lisp, the same way we do with mousehwheel. */ case WM_MOUSEHWHEEL: wmsg.dwModifiers = w32_get_modifiers (); my_post_msg (&wmsg, hwnd, msg, wParam, lParam); signal_user_input (); /* Non-zero must be returned when WM_MOUSEHWHEEL messages are - handled, to prevent the system trying to handle it by faking - scroll bar events. */ + handled, to prevent the system trying to handle it by faking + scroll bar events. */ return 1; case WM_TIMER: @@ -3627,15 +4084,15 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) KillTimer (hwnd, menu_free_timer); menu_free_timer = 0; f = x_window_to_frame (dpyinfo, hwnd); - /* If a popup menu is active, don't wipe its strings. */ + /* If a popup menu is active, don't wipe its strings. */ if (menubar_in_use - && current_popup_menu == NULL) + && current_popup_menu == NULL) { /* Free memory used by owner-drawn and help-echo strings. */ w32_free_menu_strings (hwnd); if (f) f->output_data.w32->menubar_active = 0; - menubar_in_use = 0; + menubar_in_use = 0; } } return 0; @@ -3687,7 +4144,7 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) if (find_deferred_msg (hwnd, msg) != NULL) emacs_abort (); - menubar_in_use = 1; + menubar_in_use = 1; return send_deferred_msg (&msg_buf, hwnd, msg, wParam, lParam); } @@ -3698,8 +4155,8 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) /* If a menu is still active, check again after a short delay, since Windows often (always?) sends the WM_EXITMENULOOP before the corresponding WM_COMMAND message. - Don't do this if a popup menu is active, since it is only - menubar menus that require cleaning up in this way. + Don't do this if a popup menu is active, since it is only + menubar menus that require cleaning up in this way. */ if (f && menubar_in_use && current_popup_menu == NULL) menu_free_timer = SetTimer (hwnd, MENU_FREE_ID, MENU_FREE_DELAY, NULL); @@ -3744,9 +4201,9 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) menu_font = CreateFontIndirect (&menu_logfont); old_font = SelectObject (hdc, menu_font); - pMis->itemHeight = GetSystemMetrics (SM_CYMENUSIZE); - if (title) - { + pMis->itemHeight = GetSystemMetrics (SM_CYMENUSIZE); + if (title) + { if (unicode_append_menu) GetTextExtentPoint32W (hdc, (WCHAR *) title, wcslen ((WCHAR *) title), @@ -3754,12 +4211,12 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) else GetTextExtentPoint32 (hdc, title, strlen (title), &size); - pMis->itemWidth = size.cx; - if (pMis->itemHeight < size.cy) - pMis->itemHeight = size.cy; - } - else - pMis->itemWidth = 0; + pMis->itemWidth = size.cx; + if (pMis->itemHeight < size.cy) + pMis->itemHeight = size.cy; + } + else + pMis->itemWidth = 0; SelectObject (hdc, old_font); DeleteObject (menu_font); @@ -3779,17 +4236,17 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { /* Draw popup menu title. */ char * title = (char *) pDis->itemData; - if (title) - { - HDC hdc = pDis->hDC; - HFONT menu_font = GetCurrentObject (hdc, OBJ_FONT); - LOGFONT menu_logfont; - HFONT old_font; - - GetObject (menu_font, sizeof (menu_logfont), &menu_logfont); - menu_logfont.lfWeight = FW_BOLD; - menu_font = CreateFontIndirect (&menu_logfont); - old_font = SelectObject (hdc, menu_font); + if (title) + { + HDC hdc = pDis->hDC; + HFONT menu_font = GetCurrentObject (hdc, OBJ_FONT); + LOGFONT menu_logfont; + HFONT old_font; + + GetObject (menu_font, sizeof (menu_logfont), &menu_logfont); + menu_logfont.lfWeight = FW_BOLD; + menu_font = CreateFontIndirect (&menu_logfont); + old_font = SelectObject (hdc, menu_font); /* Always draw title as if not selected. */ if (unicode_append_menu) @@ -3808,9 +4265,9 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) ETO_OPAQUE, &pDis->rcItem, title, strlen (title), NULL); - SelectObject (hdc, old_font); - DeleteObject (menu_font); - } + SelectObject (hdc, old_font); + DeleteObject (menu_font); + } return TRUE; } } @@ -3891,16 +4348,16 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) /* Don't restrict the sizing of any kind of frames. If the window manager doesn't, there's no reason to do it ourselves. */ #if 0 - if (frame_resize_pixelwise || hwnd == tip_window) + if (frame_resize_pixelwise || hwnd == tip_window) #endif return 0; #if 0 /* Don't restrict the sizing of fullscreened frames, allowing them to be - flush with the sides of the screen. */ + flush with the sides of the screen. */ f = x_window_to_frame (dpyinfo, hwnd); if (f && FRAME_PREV_FSMODE (f) != FULLSCREEN_NONE) - return 0; + return 0; { WINDOWPLACEMENT wp; @@ -4049,30 +4506,30 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) case WM_EMACS_BRINGTOTOP: case WM_EMACS_SETFOREGROUND: { - HWND foreground_window; - DWORD foreground_thread, retval; + HWND foreground_window; + DWORD foreground_thread, retval; - /* On NT 5.0, and apparently Windows 98, it is necessary to - attach to the thread that currently has focus in order to - pull the focus away from it. */ - foreground_window = GetForegroundWindow (); + /* On NT 5.0, and apparently Windows 98, it is necessary to + attach to the thread that currently has focus in order to + pull the focus away from it. */ + foreground_window = GetForegroundWindow (); foreground_thread = GetWindowThreadProcessId (foreground_window, NULL); - if (!foreground_window - || foreground_thread == GetCurrentThreadId () - || !AttachThreadInput (GetCurrentThreadId (), - foreground_thread, TRUE)) - foreground_thread = 0; - - retval = SetForegroundWindow ((HWND) wParam); - if (msg == WM_EMACS_BRINGTOTOP) - retval = BringWindowToTop ((HWND) wParam); - - /* Detach from the previous foreground thread. */ - if (foreground_thread) - AttachThreadInput (GetCurrentThreadId (), - foreground_thread, FALSE); - - return retval; + if (!foreground_window + || foreground_thread == GetCurrentThreadId () + || !AttachThreadInput (GetCurrentThreadId (), + foreground_thread, TRUE)) + foreground_thread = 0; + + retval = SetForegroundWindow ((HWND) wParam); + if (msg == WM_EMACS_BRINGTOTOP) + retval = BringWindowToTop ((HWND) wParam); + + /* Detach from the previous foreground thread. */ + if (foreground_thread) + AttachThreadInput (GetCurrentThreadId (), + foreground_thread, FALSE); + + return retval; } case WM_EMACS_SETWINDOWPOS: @@ -4145,7 +4602,7 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) button_state = 0; /* Use menubar_active to indicate that WM_INITMENU is from - TrackPopupMenu below, and should be ignored. */ + TrackPopupMenu below, and should be ignored. */ f = x_window_to_frame (dpyinfo, hwnd); if (f) f->output_data.w32->menubar_active = 1; @@ -4452,20 +4909,20 @@ x_default_font_parameter (struct frame *f, Lisp_Object parms) { int i; static char *names[] - = { "Courier New-10", - "-*-Courier-normal-r-*-*-13-*-*-*-c-*-iso8859-1", - "-*-Fixedsys-normal-r-*-*-12-*-*-*-c-*-iso8859-1", - "Fixedsys", - NULL }; + = { "Courier New-10", + "-*-Courier-normal-r-*-*-13-*-*-*-c-*-iso8859-1", + "-*-Fixedsys-normal-r-*-*-12-*-*-*-c-*-iso8859-1", + "Fixedsys", + NULL }; for (i = 0; names[i]; i++) - { - font = font_open_by_name (f, build_unibyte_string (names[i])); - if (! NILP (font)) - break; - } + { + font = font_open_by_name (f, build_unibyte_string (names[i])); + if (! NILP (font)) + break; + } if (NILP (font)) - error ("No suitable font was found"); + error ("No suitable font was found"); } else if (!NILP (font_param)) { @@ -4573,7 +5030,7 @@ This function is an internal primitive--use `make-frame' instead. */) fset_icon_name (f, x_get_arg (dpyinfo, parameters, Qicon_name, "iconName", "Title", - RES_TYPE_STRING)); + RES_TYPE_STRING)); if (! STRINGP (f->icon_name)) fset_icon_name (f, Qnil); @@ -4797,7 +5254,7 @@ This function is an internal primitive--use `make-frame' instead. */) frame on this terminal. */ if (FRAME_HAS_MINIBUF_P (f) && (!FRAMEP (KVAR (kb, Vdefault_minibuffer_frame)) - || !FRAME_LIVE_P (XFRAME (KVAR (kb, Vdefault_minibuffer_frame))))) + || !FRAME_LIVE_P (XFRAME (KVAR (kb, Vdefault_minibuffer_frame))))) kset_default_minibuffer_frame (kb, frame); /* All remaining specified parameters, which have not been "used" @@ -5522,7 +5979,7 @@ If TERMINAL is omitted or nil, that stands for the selected frame's display. */ /*********************************************************************** - Window properties + Window properties ***********************************************************************/ #if 0 /* TODO : port window properties to W32 */ @@ -5658,9 +6115,9 @@ no value of TYPE (always string in the MS Windows case). */) ***********************************************************************/ static Lisp_Object x_create_tip_frame (struct w32_display_info *, - Lisp_Object, Lisp_Object); + Lisp_Object, Lisp_Object); static void compute_tip_xy (struct frame *, Lisp_Object, Lisp_Object, - Lisp_Object, int, int, int *, int *); + Lisp_Object, int, int, int *, int *); /* The frame of a currently visible tooltip. */ @@ -5868,7 +6325,7 @@ x_create_tip_frame (struct w32_display_info *dpyinfo, "cursorType", "CursorType", RES_TYPE_SYMBOL); /* Process alpha here (Bug#17344). */ x_default_parameter (f, parms, Qalpha, Qnil, - "alpha", "Alpha", RES_TYPE_NUMBER); + "alpha", "Alpha", RES_TYPE_NUMBER); /* Dimensions, especially FRAME_LINES (f), must be done via change_frame_size. Change will not be effected unless different @@ -6766,25 +7223,25 @@ value of DIR as in previous invocations; this is standard Windows behavior. */) if (file_opened) { - /* Get an Emacs string from the value Windows gave us. */ + /* Get an Emacs string from the value Windows gave us. */ #ifdef NTGUI_UNICODE - filename = from_unicode_buffer (filename_buf_w); + filename = from_unicode_buffer (filename_buf_w); #else /* !NTGUI_UNICODE */ if (use_unicode) filename_from_utf16 (filename_buf_w, fname_ret); else filename_from_ansi (filename_buf_a, fname_ret); dostounix_filename (fname_ret); - filename = DECODE_FILE (build_unibyte_string (fname_ret)); + filename = DECODE_FILE (build_unibyte_string (fname_ret)); #endif /* NTGUI_UNICODE */ #ifdef CYGWIN - filename = Fcygwin_convert_file_name_from_windows (filename, Qt); + filename = Fcygwin_convert_file_name_from_windows (filename, Qt); #endif /* CYGWIN */ - /* Strip the dummy filename off the end of the string if we - added it to select a directory. */ - if ((use_unicode && file_details_w->nFilterIndex == 2) + /* Strip the dummy filename off the end of the string if we + added it to select a directory. */ + if ((use_unicode && file_details_w->nFilterIndex == 2) #ifndef NTGUI_UNICODE || (!use_unicode && file_details_a->nFilterIndex == 2) #endif @@ -6797,14 +7254,14 @@ value of DIR as in previous invocations; this is standard Windows behavior. */) /* An error occurred, fallback on reading from the mini-buffer. */ else filename = Fcompleting_read ( - orig_prompt, - intern ("read-file-name-internal"), - orig_dir, - mustmatch, - orig_dir, - Qfile_name_history, - default_filename, - Qnil); + orig_prompt, + intern ("read-file-name-internal"), + orig_dir, + mustmatch, + orig_dir, + Qfile_name_history, + default_filename, + Qnil); UNGCPRO; } @@ -6917,7 +7374,7 @@ DEFUN ("system-move-file-to-trash", Fsystem_move_file_to_trash, /*********************************************************************** - w32 specialized functions + w32 specialized functions ***********************************************************************/ DEFUN ("w32-send-sys-command", Fw32_send_sys_command, @@ -6952,37 +7409,37 @@ handler application, but typically it is one of the following common operations: \"open\" - open DOCUMENT, which could be a file, a directory, or an - executable program (application). If it is an application, - that application is launched in the current buffer's default - directory. Otherwise, the application associated with - DOCUMENT is launched in the buffer's default directory. + executable program (application). If it is an application, + that application is launched in the current buffer's default + directory. Otherwise, the application associated with + DOCUMENT is launched in the buffer's default directory. \"opennew\" - like \"open\", but instruct the application to open - DOCUMENT in a new window. + DOCUMENT in a new window. \"openas\" - open the \"Open With\" dialog for DOCUMENT. \"print\" - print DOCUMENT, which must be a file. \"printto\" - print DOCUMENT, which must be a file, to a specified printer. - The printer should be provided in PARAMETERS, see below. + The printer should be provided in PARAMETERS, see below. \"explore\" - start the Windows Explorer on DOCUMENT. \"edit\" - launch an editor and open DOCUMENT for editing; which - editor is launched depends on the association for the - specified DOCUMENT. + editor is launched depends on the association for the + specified DOCUMENT. \"find\" - initiate search starting from DOCUMENT, which must specify - a directory. + a directory. \"delete\" - move DOCUMENT, a file or a directory, to Recycle Bin. \"copy\" - copy DOCUMENT, which must be a file or a directory, into - the clipboard. + the clipboard. \"cut\" - move DOCUMENT, a file or a directory, into the clipboard. \"paste\" - paste the file whose name is in the clipboard into DOCUMENT, - which must be a directory. + which must be a directory. \"pastelink\" - - create a shortcut in DOCUMENT (which must be a directory) - the file or directory whose name is in the clipboard. + - create a shortcut in DOCUMENT (which must be a directory) + the file or directory whose name is in the clipboard. \"runas\" - run DOCUMENT, which must be an excutable file, with - elevated privileges (a.k.a. \"as Administrator\"). + elevated privileges (a.k.a. \"as Administrator\"). \"properties\" - - open the property sheet dialog for DOCUMENT. + - open the property sheet dialog for DOCUMENT. nil - invoke the default OPERATION, or \"open\" if default is - not defined or unavailable. + not defined or unavailable. DOCUMENT is typically the name of a document file or a URL, but can also be an executable program to run, or a directory to open in the @@ -7678,7 +8135,7 @@ elements (all size values are in pixels). ? Fcons (make_number (0), make_number (0)) : Fcons (make_number (border_width), make_number (border_height)))), - Fcons (Qtitle_height, + Fcons (Qtitle_height, ((EQ (fullscreen, Qfullboth) || EQ (fullscreen, Qfullscreen)) ? make_number (0) : make_number (title_height))), @@ -8063,14 +8520,14 @@ w32_strerror (int error_no) error_no = GetLastError (); ret = FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, - error_no, - 0, /* choose most suitable language */ - buf, sizeof (buf), NULL); + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + error_no, + 0, /* choose most suitable language */ + buf, sizeof (buf), NULL); while (ret > 0 && (buf[ret - 1] == '\n' || - buf[ret - 1] == '\r' )) + buf[ret - 1] == '\r' )) --ret; buf[ret] = '\0'; if (!ret) @@ -8316,7 +8773,7 @@ w32_kbd_patch_key (KEY_EVENT_RECORD *event, int cpId) else { isdead = ToAscii (event->wVirtualKeyCode, event->wVirtualScanCode, - keystate, (LPWORD) ansi_code, 0); + keystate, (LPWORD) ansi_code, 0); } if (isdead == 0) @@ -8580,8 +9037,8 @@ system to handle them. */); w32_pass_extra_mouse_buttons_to_system = 0; DEFVAR_BOOL ("w32-pass-multimedia-buttons-to-system", - w32_pass_multimedia_buttons_to_system, - doc: /* If non-nil, media buttons are passed to Windows. + w32_pass_multimedia_buttons_to_system, + doc: /* If non-nil, media buttons are passed to Windows. Some modern keyboards contain buttons for controlling media players, web browsers and other applications. Generally these buttons are handled on a system wide basis, but by setting this to nil they are made available @@ -8669,12 +9126,12 @@ Chinese, Japanese, and Korean. */); Vx_pixel_size_width_font_regexp = Qnil; DEFVAR_LISP ("w32-bdf-filename-alist", - Vw32_bdf_filename_alist, - doc: /* List of bdf fonts and their corresponding filenames. */); + Vw32_bdf_filename_alist, + doc: /* List of bdf fonts and their corresponding filenames. */); Vw32_bdf_filename_alist = Qnil; DEFVAR_BOOL ("w32-strict-fontnames", - w32_strict_fontnames, + w32_strict_fontnames, doc: /* Non-nil means only use fonts that are exact matches for those requested. Default is nil, which allows old fontnames that are not XLFD compliant, and allows third-party CJK display to work by specifying false charset @@ -8684,7 +9141,7 @@ fontsets are automatically created. */); w32_strict_fontnames = 0; DEFVAR_BOOL ("w32-strict-painting", - w32_strict_painting, + w32_strict_painting, doc: /* Non-nil means use strict rules for repainting frames. Set this to nil to get the old behavior for repainting; this should only be necessary if the default setting causes problems. */);