commit dcec731abfc110f719f0890fd0769e099393af7d (HEAD, refs/remotes/origin/master) Author: Fabián Ezequiel Gallina Date: Sun Feb 8 01:31:12 2015 -0300 python.el: Fix completion-at-point. Fixes: debbugs:19667 * lisp/progmodes/python.el (python-shell-completion-native-get-completions): Force process buffer. (python-shell-completion-at-point): Handle case where call is not in a shell buffer. diff --git a/lisp/ChangeLog b/lisp/ChangeLog index f14a984..5911f13 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog @@ -1,5 +1,15 @@ 2015-02-08 Fabián Ezequiel Gallina + python.el: Fix completion-at-point. (Bug#19667) + + * progmodes/python.el + (python-shell-completion-native-get-completions): Force process + buffer. + (python-shell-completion-at-point): Handle case where call is not + in a shell buffer. + +2015-02-08 Fabián Ezequiel Gallina + python.el: Fix shell font-lock multiline input. (Bug#19744) * progmodes/python.el diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el index c87b1f3..303c36c 100644 --- a/lisp/progmodes/python.el +++ b/lisp/progmodes/python.el @@ -3150,67 +3150,68 @@ With argument MSG show activation/deactivation message." "Get completions using native readline for PROCESS. When IMPORT is non-nil takes precedence over INPUT for completion." - (when (and python-shell-completion-native-enable - (python-util-comint-last-prompt) - (>= (point) (cdr (python-util-comint-last-prompt)))) - (let* ((input (or import input)) - (original-filter-fn (process-filter process)) - (redirect-buffer (get-buffer-create - python-shell-completion-native-redirect-buffer)) - (separators (python-rx - (or whitespace open-paren close-paren))) - (trigger "\t\t\t") - (new-input (concat input trigger)) - (input-length - (save-excursion - (+ (- (point-max) (comint-bol)) (length new-input)))) - (delete-line-command (make-string input-length ?\b)) - (input-to-send (concat new-input delete-line-command))) - ;; Ensure restoring the process filter, even if the user quits - ;; or there's some other error. - (unwind-protect - (with-current-buffer redirect-buffer - ;; Cleanup the redirect buffer - (delete-region (point-min) (point-max)) - ;; Mimic `comint-redirect-send-command', unfortunately it - ;; can't be used here because it expects a newline in the - ;; command and that's exactly what we are trying to avoid. - (let ((comint-redirect-echo-input nil) - (comint-redirect-verbose nil) - (comint-redirect-perform-sanity-check nil) - (comint-redirect-insert-matching-regexp nil) - ;; Feed it some regex that will never match. - (comint-redirect-finished-regexp "^\\'$") - (comint-redirect-output-buffer redirect-buffer)) - ;; Compatibility with Emacs 24.x. Comint changed and - ;; now `comint-redirect-filter' gets 3 args. This - ;; checks which version of `comint-redirect-filter' is - ;; in use based on its args and uses `apply-partially' - ;; to make it up for the 3 args case. - (if (= (length - (help-function-arglist 'comint-redirect-filter)) 3) - (set-process-filter - process (apply-partially - #'comint-redirect-filter original-filter-fn)) - (set-process-filter process #'comint-redirect-filter)) - (process-send-string process input-to-send) - (accept-process-output - process - python-shell-completion-native-output-timeout) - ;; XXX: can't use `python-shell-accept-process-output' - ;; here because there are no guarantees on how output - ;; ends. The workaround here is to call - ;; `accept-process-output' until we don't find anything - ;; else to accept. - (while (accept-process-output - process - python-shell-completion-native-output-timeout)) - (cl-remove-duplicates - (split-string - (buffer-substring-no-properties - (point-min) (point-max)) - separators t)))) - (set-process-filter process original-filter-fn))))) + (with-current-buffer (process-buffer process) + (when (and python-shell-completion-native-enable + (python-util-comint-last-prompt) + (>= (point) (cdr (python-util-comint-last-prompt)))) + (let* ((input (or import input)) + (original-filter-fn (process-filter process)) + (redirect-buffer (get-buffer-create + python-shell-completion-native-redirect-buffer)) + (separators (python-rx + (or whitespace open-paren close-paren))) + (trigger "\t\t\t") + (new-input (concat input trigger)) + (input-length + (save-excursion + (+ (- (point-max) (comint-bol)) (length new-input)))) + (delete-line-command (make-string input-length ?\b)) + (input-to-send (concat new-input delete-line-command))) + ;; Ensure restoring the process filter, even if the user quits + ;; or there's some other error. + (unwind-protect + (with-current-buffer redirect-buffer + ;; Cleanup the redirect buffer + (delete-region (point-min) (point-max)) + ;; Mimic `comint-redirect-send-command', unfortunately it + ;; can't be used here because it expects a newline in the + ;; command and that's exactly what we are trying to avoid. + (let ((comint-redirect-echo-input nil) + (comint-redirect-verbose nil) + (comint-redirect-perform-sanity-check nil) + (comint-redirect-insert-matching-regexp nil) + ;; Feed it some regex that will never match. + (comint-redirect-finished-regexp "^\\'$") + (comint-redirect-output-buffer redirect-buffer)) + ;; Compatibility with Emacs 24.x. Comint changed and + ;; now `comint-redirect-filter' gets 3 args. This + ;; checks which version of `comint-redirect-filter' is + ;; in use based on its args and uses `apply-partially' + ;; to make it up for the 3 args case. + (if (= (length + (help-function-arglist 'comint-redirect-filter)) 3) + (set-process-filter + process (apply-partially + #'comint-redirect-filter original-filter-fn)) + (set-process-filter process #'comint-redirect-filter)) + (process-send-string process input-to-send) + (accept-process-output + process + python-shell-completion-native-output-timeout) + ;; XXX: can't use `python-shell-accept-process-output' + ;; here because there are no guarantees on how output + ;; ends. The workaround here is to call + ;; `accept-process-output' until we don't find anything + ;; else to accept. + (while (accept-process-output + process + python-shell-completion-native-output-timeout)) + (cl-remove-duplicates + (split-string + (buffer-substring-no-properties + (point-min) (point-max)) + separators t)))) + (set-process-filter process original-filter-fn)))))) (defun python-shell-completion-get-completions (process import input) "Do completion at point using PROCESS for IMPORT or INPUT. @@ -3253,20 +3254,23 @@ completion." Optional argument PROCESS forces completions to be retrieved using that one instead of current buffer's process." (setq process (or process (get-buffer-process (current-buffer)))) - (let* ((last-prompt-end (cdr (python-util-comint-last-prompt))) + (let* ((line-start (if (derived-mode-p 'inferior-python-mode) + ;; Working on a shell buffer: use prompt end. + (cdr (python-util-comint-last-prompt)) + (line-beginning-position))) (import-statement (when (string-match-p (rx (* space) word-start (or "from" "import") word-end space) - (buffer-substring-no-properties last-prompt-end (point))) - (buffer-substring-no-properties last-prompt-end (point)))) + (buffer-substring-no-properties line-start (point))) + (buffer-substring-no-properties line-start (point)))) (start (save-excursion (if (not (re-search-backward (python-rx (or whitespace open-paren close-paren string-delimiter)) - last-prompt-end + line-start t 1)) - last-prompt-end + line-start (forward-char (length (match-string-no-properties 0))) (point)))) (end (point)) commit 67dfbd60573f6df8f0b096e5e2ec7f54fdff94bf Author: Fabián Ezequiel Gallina Date: Sun Feb 8 00:36:30 2015 -0300 python.el: Fix shell font-lock multiline input. Fixes: debbugs:19744 * lisp/progmodes/python.el (python-shell-font-lock-post-command-hook): Handle multiline input. diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 3b0bdd5..f14a984 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog @@ -1,5 +1,13 @@ 2015-02-08 Fabián Ezequiel Gallina + python.el: Fix shell font-lock multiline input. (Bug#19744) + + * progmodes/python.el + (python-shell-font-lock-post-command-hook): Handle multiline + input. + +2015-02-08 Fabián Ezequiel Gallina + python.el: Make shell font-lock respect markers. (Bug#19650) * progmodes/python.el (python-shell-font-lock-cleanup-buffer): Use diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el index 897af2c..c87b1f3 100644 --- a/lisp/progmodes/python.el +++ b/lisp/progmodes/python.el @@ -2359,13 +2359,15 @@ goes wrong and syntax highlighting in the shell gets messed up." (let ((input (buffer-substring-no-properties (cdr (python-util-comint-last-prompt)) (point-max))) (pos (point)) - (buffer-undo-list t)) + (buffer-undo-list t) + (font-lock-buffer-pos nil)) ;; Keep all markers untouched, this prevents `hippie-expand' and ;; others from getting confused. Bug#19650. (insert-before-markers (python-shell-font-lock-with-font-lock-buffer (delete-region (line-beginning-position) - (line-end-position)) + (point-max)) + (setq font-lock-buffer-pos (point)) (insert input) ;; Ensure buffer is fontified, keeping it ;; compatible with Emacs < 24.4. @@ -2376,8 +2378,8 @@ goes wrong and syntax highlighting in the shell gets messed up." ;; they are not overwritten by comint buffer's font lock. (python-util-text-properties-replace-name 'face 'font-lock-face) - (buffer-substring (line-beginning-position) - (line-end-position)))) + (buffer-substring font-lock-buffer-pos + (point-max)))) ;; Remove non-fontified original text. (delete-region pos (cdr (python-util-comint-last-prompt))) ;; Point should be already at pos, this is for extra safety. commit 52df70a887ae8b187decb6c92cad32cf11f4c788 Author: Fabián Ezequiel Gallina Date: Sun Feb 8 00:25:20 2015 -0300 python.el: Make shell font-lock respect markers. Fixes: debbugs:19650 * lisp/progmodes/python.el (python-shell-font-lock-cleanup-buffer): Use `erase-buffer`. (python-shell-font-lock-comint-output-filter-function): Handle newlines. (python-shell-font-lock-post-command-hook): Respect markers on text fontification. diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 29fa965..3b0bdd5 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog @@ -1,3 +1,14 @@ +2015-02-08 Fabián Ezequiel Gallina + + python.el: Make shell font-lock respect markers. (Bug#19650) + + * progmodes/python.el (python-shell-font-lock-cleanup-buffer): Use + `erase-buffer`. + (python-shell-font-lock-comint-output-filter-function): Handle + newlines. + (python-shell-font-lock-post-command-hook): Respect markers on + text fontification. + 2015-02-07 Fabián Ezequiel Gallina python.el: Keep eldoc visible while typing args. (Bug#19637) diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el index 72a76a4..897af2c 100644 --- a/lisp/progmodes/python.el +++ b/lisp/progmodes/python.el @@ -2333,57 +2333,55 @@ goes wrong and syntax highlighting in the shell gets messed up." (interactive) (python-shell-with-shell-buffer (python-shell-font-lock-with-font-lock-buffer - (delete-region (point-min) (point-max))))) + (erase-buffer)))) (defun python-shell-font-lock-comint-output-filter-function (output) "Clean up the font-lock buffer after any OUTPUT." - (when (and (not (string= "" output)) - ;; Is end of output and is not just a prompt. - (not (member - (python-shell-comint-end-of-output-p - (ansi-color-filter-apply output)) - '(nil 0)))) - ;; If output is other than an input prompt then "real" output has - ;; been received and the font-lock buffer must be cleaned up. - (python-shell-font-lock-cleanup-buffer)) + (if (and (not (string= "" output)) + ;; Is end of output and is not just a prompt. + (not (member + (python-shell-comint-end-of-output-p + (ansi-color-filter-apply output)) + '(nil 0)))) + ;; If output is other than an input prompt then "real" output has + ;; been received and the font-lock buffer must be cleaned up. + (python-shell-font-lock-cleanup-buffer) + ;; Otherwise just add a newline. + (python-shell-font-lock-with-font-lock-buffer + (goto-char (point-max)) + (newline))) output) (defun python-shell-font-lock-post-command-hook () "Fontifies current line in shell buffer." - (if (eq this-command 'comint-send-input) - ;; Add a newline when user sends input as this may be a block. - (python-shell-font-lock-with-font-lock-buffer - (goto-char (line-end-position)) - (newline)) - (when (and (python-util-comint-last-prompt) - (> (point) (cdr (python-util-comint-last-prompt)))) - (let ((input (buffer-substring-no-properties - (cdr (python-util-comint-last-prompt)) (point-max))) - (old-input (python-shell-font-lock-with-font-lock-buffer - (buffer-substring-no-properties - (line-beginning-position) (point-max)))) - (current-point (point)) - (buffer-undo-list t)) - ;; When input hasn't changed, do nothing. - (when (not (string= input old-input)) - (delete-region (cdr (python-util-comint-last-prompt)) (point-max)) - (insert - (python-shell-font-lock-with-font-lock-buffer - (delete-region (line-beginning-position) - (line-end-position)) - (insert input) - ;; Ensure buffer is fontified, keeping it - ;; compatible with Emacs < 24.4. - (if (fboundp 'font-lock-ensure) - (funcall 'font-lock-ensure) - (font-lock-default-fontify-buffer)) - ;; Replace FACE text properties with FONT-LOCK-FACE so - ;; they are not overwritten by comint buffer's font lock. - (python-util-text-properties-replace-name - 'face 'font-lock-face) - (buffer-substring (line-beginning-position) - (line-end-position)))) - (goto-char current-point)))))) + (when (and (python-util-comint-last-prompt) + (> (point) (cdr (python-util-comint-last-prompt)))) + (let ((input (buffer-substring-no-properties + (cdr (python-util-comint-last-prompt)) (point-max))) + (pos (point)) + (buffer-undo-list t)) + ;; Keep all markers untouched, this prevents `hippie-expand' and + ;; others from getting confused. Bug#19650. + (insert-before-markers + (python-shell-font-lock-with-font-lock-buffer + (delete-region (line-beginning-position) + (line-end-position)) + (insert input) + ;; Ensure buffer is fontified, keeping it + ;; compatible with Emacs < 24.4. + (if (fboundp 'font-lock-ensure) + (funcall 'font-lock-ensure) + (font-lock-default-fontify-buffer)) + ;; Replace FACE text properties with FONT-LOCK-FACE so + ;; they are not overwritten by comint buffer's font lock. + (python-util-text-properties-replace-name + 'face 'font-lock-face) + (buffer-substring (line-beginning-position) + (line-end-position)))) + ;; Remove non-fontified original text. + (delete-region pos (cdr (python-util-comint-last-prompt))) + ;; Point should be already at pos, this is for extra safety. + (goto-char pos)))) (defun python-shell-font-lock-turn-on (&optional msg) "Turn on shell font-lock. commit b480a6adda9cfd76c3f38970e257654de9eff4f2 Author: Fabián Ezequiel Gallina Date: Sat Feb 7 18:41:44 2015 -0300 Fix attribution in previous commit diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 34d4013..29fa965 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog @@ -3,7 +3,7 @@ python.el: Keep eldoc visible while typing args. (Bug#19637) * progmodes/python.el (python-eldoc--get-symbol-at-point): New - function. + function based on Carlos Pita patch. (python-eldoc--get-doc-at-point, python-eldoc-at-point): Use it. 2015-02-07 Fabián Ezequiel Gallina commit 2155973e5e35d11a50ce6773bb34d5df68beea57 Author: Fabián Ezequiel Gallina Date: Sat Feb 7 18:39:07 2015 -0300 python.el: Keep eldoc visible while typing args. Fixes: debbugs:19637 * lisp/progmodes/python.el (python-eldoc--get-symbol-at-point): New function. (python-eldoc--get-doc-at-point, python-eldoc-at-point): Use it. * test/automated/python-tests.el (python-eldoc--get-symbol-at-point-1) (python-eldoc--get-symbol-at-point-2) (python-eldoc--get-symbol-at-point-3) (python-eldoc--get-symbol-at-point-4): New tests. diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 655ae57..34d4013 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog @@ -1,5 +1,13 @@ 2015-02-07 Fabián Ezequiel Gallina + python.el: Keep eldoc visible while typing args. (Bug#19637) + + * progmodes/python.el (python-eldoc--get-symbol-at-point): New + function. + (python-eldoc--get-doc-at-point, python-eldoc-at-point): Use it. + +2015-02-07 Fabián Ezequiel Gallina + Fix hideshow integration. (Bug#19761) * progmodes/python.el diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el index 3399429..72a76a4 100644 --- a/lisp/progmodes/python.el +++ b/lisp/progmodes/python.el @@ -3921,15 +3921,29 @@ See `python-check-command' for the default." :type 'string :group 'python) +(defun python-eldoc--get-symbol-at-point () + "Get the current symbol for eldoc. +Returns the current symbol handling point within arguments." + (save-excursion + (let ((start (python-syntax-context 'paren))) + (when start + (goto-char start)) + (when (or start + (eobp) + (memq (char-syntax (char-after)) '(?\ ?-))) + ;; Try to adjust to closest symbol if not in one. + (python-util-forward-comment -1))) + (python-info-current-symbol t))) + (defun python-eldoc--get-doc-at-point (&optional force-input force-process) "Internal implementation to get documentation at point. -If not FORCE-INPUT is passed then what `python-info-current-symbol' +If not FORCE-INPUT is passed then what `python-eldoc--get-symbol-at-point' returns will be used. If not FORCE-PROCESS is passed what `python-shell-get-process' returns is used." (let ((process (or force-process (python-shell-get-process)))) (when process (let ((input (or force-input - (python-info-current-symbol t)))) + (python-eldoc--get-symbol-at-point)))) (and input ;; Prevent resizing the echo area when iPython is ;; enabled. Bug#18794. @@ -3949,7 +3963,7 @@ inferior Python process is updated properly." "Get help on SYMBOL using `help'. Interactively, prompt for symbol." (interactive - (let ((symbol (python-info-current-symbol t)) + (let ((symbol (python-eldoc--get-symbol-at-point)) (enable-recursive-minibuffers t)) (list (read-string (if symbol (format "Describe symbol (default %s): " symbol) diff --git a/test/ChangeLog b/test/ChangeLog index b1e2151..ff02bd6 100644 --- a/test/ChangeLog +++ b/test/ChangeLog @@ -1,6 +1,14 @@ 2015-02-07 Fabián Ezequiel Gallina * automated/python-tests.el + (python-eldoc--get-symbol-at-point-1) + (python-eldoc--get-symbol-at-point-2) + (python-eldoc--get-symbol-at-point-3) + (python-eldoc--get-symbol-at-point-4): New tests. + +2015-02-07 Fabián Ezequiel Gallina + + * automated/python-tests.el (python-tests-visible-string): New function. (python-parens-electric-indent-1) (python-triple-quote-pairing): Fix indentation, move require calls. diff --git a/test/automated/python-tests.el b/test/automated/python-tests.el index e5fcda9..47e2a6e 100644 --- a/test/automated/python-tests.el +++ b/test/automated/python-tests.el @@ -2943,6 +2943,63 @@ class Foo(models.Model): ;;; Eldoc +(ert-deftest python-eldoc--get-symbol-at-point-1 () + "Test paren handling." + (python-tests-with-temp-buffer + " +map(xx +map(codecs.open('somefile' +" + (python-tests-look-at "ap(xx") + (should (string= (python-eldoc--get-symbol-at-point) "map")) + (goto-char (line-end-position)) + (should (string= (python-eldoc--get-symbol-at-point) "map")) + (python-tests-look-at "('somefile'") + (should (string= (python-eldoc--get-symbol-at-point) "map")) + (goto-char (line-end-position)) + (should (string= (python-eldoc--get-symbol-at-point) "codecs.open")))) + +(ert-deftest python-eldoc--get-symbol-at-point-2 () + "Ensure self is replaced with the class name." + (python-tests-with-temp-buffer + " +class TheClass: + + def some_method(self, n): + return n + + def other(self): + return self.some_method(1234) + +" + (python-tests-look-at "self.some_method") + (should (string= (python-eldoc--get-symbol-at-point) + "TheClass.some_method")) + (python-tests-look-at "1234)") + (should (string= (python-eldoc--get-symbol-at-point) + "TheClass.some_method")))) + +(ert-deftest python-eldoc--get-symbol-at-point-3 () + "Ensure symbol is found when point is at end of buffer." + (python-tests-with-temp-buffer + " +some_symbol + +" + (goto-char (point-max)) + (should (string= (python-eldoc--get-symbol-at-point) + "some_symbol")))) + +(ert-deftest python-eldoc--get-symbol-at-point-4 () + "Ensure symbol is found when point is at whitespace." + (python-tests-with-temp-buffer + " +some_symbol some_other_symbol +" + (python-tests-look-at " some_other_symbol") + (should (string= (python-eldoc--get-symbol-at-point) + "some_symbol")))) + ;;; Imenu commit 2d467a0ff0cd446ec0d83044a0be819cbf874cdf Author: Fabián Ezequiel Gallina Date: Sat Feb 7 16:43:47 2015 -0300 Fix hideshow integration. Fixes: debbugs:19761 * lisp/progmodes/python.el (python-hideshow-forward-sexp-function): New function based on Carlos Pita patch. (python-mode): Make `hs-special-modes-alist` use it and initialize the end regexp with the empty string to avoid skipping parens. * test/automated/python-tests.el (python-tests-visible-string): New function. (python-parens-electric-indent-1) (python-triple-quote-pairing): Fix indentation, move require calls. (python-hideshow-hide-levels-1) (python-hideshow-hide-levels-2): New tests. diff --git a/lisp/ChangeLog b/lisp/ChangeLog index a02f964..655ae57 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog @@ -1,5 +1,15 @@ 2015-02-07 Fabián Ezequiel Gallina + Fix hideshow integration. (Bug#19761) + + * progmodes/python.el + (python-hideshow-forward-sexp-function): New function based on + Carlos Pita patch. + (python-mode): Make `hs-special-modes-alist` use it and initialize + the end regexp with the empty string to avoid skipping parens. + +2015-02-07 Fabián Ezequiel Gallina + * progmodes/python.el (python-check-custom-command): Do not use defvar-local for compat with Emacs<24.3. diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el index de25118..3399429 100644 --- a/lisp/progmodes/python.el +++ b/lisp/progmodes/python.el @@ -3958,6 +3958,17 @@ Interactively, prompt for symbol." (message (python-eldoc--get-doc-at-point symbol))) +;;; Hideshow + +(defun python-hideshow-forward-sexp-function (arg) + "Python specific `forward-sexp' function for `hs-minor-mode'. +Argument ARG is ignored." + arg ; Shut up, byte compiler. + (python-nav-end-of-defun) + (unless (python-info-current-line-empty-p) + (backward-char))) + + ;;; Imenu (defvar python-imenu-format-item-label-function @@ -4693,11 +4704,16 @@ Arguments START and END narrow the buffer region to work on." (add-function :before-until (local 'eldoc-documentation-function) #'python-eldoc-function)) - (add-to-list 'hs-special-modes-alist - `(python-mode "^\\s-*\\(?:def\\|class\\)\\>" nil "#" - ,(lambda (_arg) - (python-nav-end-of-defun)) - nil)) + (add-to-list + 'hs-special-modes-alist + `(python-mode + "\\s-*\\(?:def\\|class\\)\\>" + ;; Use the empty string as end regexp so it doesn't default to + ;; "\\s)". This way parens at end of defun are properly hidden. + "" + "#" + python-hideshow-forward-sexp-function + nil)) (set (make-local-variable 'outline-regexp) (python-rx (* space) block-start)) diff --git a/test/ChangeLog b/test/ChangeLog index e0d4eeb..b1e2151 100644 --- a/test/ChangeLog +++ b/test/ChangeLog @@ -1,3 +1,12 @@ +2015-02-07 Fabián Ezequiel Gallina + + * automated/python-tests.el + (python-tests-visible-string): New function. + (python-parens-electric-indent-1) + (python-triple-quote-pairing): Fix indentation, move require calls. + (python-hideshow-hide-levels-1) + (python-hideshow-hide-levels-2): New tests. + 2015-02-07 Dmitry Gutov * automated/vc-tests.el (vc-test--working-revision): Fix diff --git a/test/automated/python-tests.el b/test/automated/python-tests.el index 672b05c..e5fcda9 100644 --- a/test/automated/python-tests.el +++ b/test/automated/python-tests.el @@ -24,6 +24,11 @@ (require 'ert) (require 'python) +;; Dependencies for testing: +(require 'electric) +(require 'hideshow) + + (defmacro python-tests-with-temp-buffer (contents &rest body) "Create a `python-mode' enabled temp buffer with CONTENTS. BODY is code to be executed within the temp buffer. Point is @@ -104,6 +109,28 @@ STRING, it is skipped so the next STRING occurrence is selected." (call-interactively 'self-insert-command))) chars))) +(defun python-tests-visible-string (&optional min max) + "Return the buffer string excluding invisible overlays. +Argument MIN and MAX delimit the region to be returned and +default to `point-min' and `point-max' respectively." + (let* ((min (or min (point-min))) + (max (or max (point-max))) + (buffer (current-buffer)) + (buffer-contents (buffer-substring-no-properties min max)) + (overlays + (sort (overlays-in min max) + (lambda (a b) + (let ((overlay-end-a (overlay-end a)) + (overlay-end-b (overlay-end b))) + (> overlay-end-a overlay-end-b)))))) + (with-temp-buffer + (insert buffer-contents) + (dolist (overlay overlays) + (if (overlay-get overlay 'invisible) + (delete-region (overlay-start overlay) + (overlay-end overlay)))) + (buffer-substring-no-properties (point-min) (point-max))))) + ;;; Tests for your tests, so you can test while you test. @@ -4358,12 +4385,11 @@ def foo(a, b, c): ;;; Electricity (ert-deftest python-parens-electric-indent-1 () - (require 'electric) (let ((eim electric-indent-mode)) (unwind-protect (progn (python-tests-with-temp-buffer - " + " from django.conf.urls import patterns, include, url from django.contrib import admin @@ -4375,66 +4401,148 @@ urlpatterns = patterns('', url(r'^$', views.index ) " - (electric-indent-mode 1) - (python-tests-look-at "views.index") - (end-of-line) + (electric-indent-mode 1) + (python-tests-look-at "views.index") + (end-of-line) - ;; Inserting commas within the same line should leave - ;; indentation unchanged. - (python-tests-self-insert ",") - (should (= (current-indentation) 4)) + ;; Inserting commas within the same line should leave + ;; indentation unchanged. + (python-tests-self-insert ",") + (should (= (current-indentation) 4)) - ;; As well as any other input happening within the same - ;; set of parens. - (python-tests-self-insert " name='index')") - (should (= (current-indentation) 4)) + ;; As well as any other input happening within the same + ;; set of parens. + (python-tests-self-insert " name='index')") + (should (= (current-indentation) 4)) - ;; But a comma outside it, should trigger indentation. - (python-tests-self-insert ",") - (should (= (current-indentation) 23)) + ;; But a comma outside it, should trigger indentation. + (python-tests-self-insert ",") + (should (= (current-indentation) 23)) - ;; Newline indents to the first argument column - (python-tests-self-insert "\n") - (should (= (current-indentation) 23)) + ;; Newline indents to the first argument column + (python-tests-self-insert "\n") + (should (= (current-indentation) 23)) - ;; All this input must not change indentation - (indent-line-to 4) - (python-tests-self-insert "url(r'^/login$', views.login)") - (should (= (current-indentation) 4)) + ;; All this input must not change indentation + (indent-line-to 4) + (python-tests-self-insert "url(r'^/login$', views.login)") + (should (= (current-indentation) 4)) - ;; But this comma does - (python-tests-self-insert ",") - (should (= (current-indentation) 23)))) + ;; But this comma does + (python-tests-self-insert ",") + (should (= (current-indentation) 23)))) (or eim (electric-indent-mode -1))))) (ert-deftest python-triple-quote-pairing () - (require 'electric) (let ((epm electric-pair-mode)) (unwind-protect (progn (python-tests-with-temp-buffer - "\"\"\n" - (or epm (electric-pair-mode 1)) - (goto-char (1- (point-max))) - (python-tests-self-insert ?\") - (should (string= (buffer-string) - "\"\"\"\"\"\"\n")) - (should (= (point) 4))) + "\"\"\n" + (or epm (electric-pair-mode 1)) + (goto-char (1- (point-max))) + (python-tests-self-insert ?\") + (should (string= (buffer-string) + "\"\"\"\"\"\"\n")) + (should (= (point) 4))) (python-tests-with-temp-buffer - "\n" - (python-tests-self-insert (list ?\" ?\" ?\")) - (should (string= (buffer-string) - "\"\"\"\"\"\"\n")) - (should (= (point) 4))) + "\n" + (python-tests-self-insert (list ?\" ?\" ?\")) + (should (string= (buffer-string) + "\"\"\"\"\"\"\n")) + (should (= (point) 4))) (python-tests-with-temp-buffer - "\"\n\"\"\n" - (goto-char (1- (point-max))) - (python-tests-self-insert ?\") - (should (= (point) (1- (point-max)))) - (should (string= (buffer-string) - "\"\n\"\"\"\n")))) + "\"\n\"\"\n" + (goto-char (1- (point-max))) + (python-tests-self-insert ?\") + (should (= (point) (1- (point-max)))) + (should (string= (buffer-string) + "\"\n\"\"\"\n")))) (or epm (electric-pair-mode -1))))) + +;;; Hideshow support + +(ert-deftest python-hideshow-hide-levels-1 () + "Should hide all methods when called after class start." + (let ((enabled hs-minor-mode)) + (unwind-protect + (progn + (python-tests-with-temp-buffer + " +class SomeClass: + + def __init__(self, arg, kwarg=1): + self.arg = arg + self.kwarg = kwarg + + def filter(self, nums): + def fn(item): + return item in [self.arg, self.kwarg] + return filter(fn, nums) + + def __str__(self): + return '%s-%s' % (self.arg, self.kwarg) +" + (hs-minor-mode 1) + (python-tests-look-at "class SomeClass:") + (forward-line) + (hs-hide-level 1) + (should + (string= + (python-tests-visible-string) + " +class SomeClass: + + def __init__(self, arg, kwarg=1): + def filter(self, nums): + def __str__(self):")))) + (or enabled (hs-minor-mode -1))))) + +(ert-deftest python-hideshow-hide-levels-2 () + "Should hide nested methods and parens at end of defun." + (let ((enabled hs-minor-mode)) + (unwind-protect + (progn + (python-tests-with-temp-buffer + " +class SomeClass: + + def __init__(self, arg, kwarg=1): + self.arg = arg + self.kwarg = kwarg + + def filter(self, nums): + def fn(item): + return item in [self.arg, self.kwarg] + return filter(fn, nums) + + def __str__(self): + return '%s-%s' % (self.arg, self.kwarg) +" + (hs-minor-mode 1) + (python-tests-look-at "def fn(item):") + (hs-hide-block) + (should + (string= + (python-tests-visible-string) + " +class SomeClass: + + def __init__(self, arg, kwarg=1): + self.arg = arg + self.kwarg = kwarg + + def filter(self, nums): + def fn(item): + return filter(fn, nums) + + def __str__(self): + return '%s-%s' % (self.arg, self.kwarg) +")))) + (or enabled (hs-minor-mode -1))))) + + (provide 'python-tests) commit 86c50b9af1e68ca87bfc9e6d0cdb28ae2e53cc32 Author: Fabián Ezequiel Gallina Date: Sat Feb 7 14:25:47 2015 -0300 * lisp/progmodes/python.el (python-check-custom-command): Do not use defvar-local for compat with Emacs<24.3. diff --git a/lisp/ChangeLog b/lisp/ChangeLog index a3abb1a..a02f964 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog @@ -1,3 +1,8 @@ +2015-02-07 Fabián Ezequiel Gallina + + * progmodes/python.el (python-check-custom-command): Do not use + defvar-local for compat with Emacs<24.3. + 2015-02-07 Martin Rudalics * frame.el (frame-notice-user-settings): Update diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el index 6551536..de25118 100644 --- a/lisp/progmodes/python.el +++ b/lisp/progmodes/python.el @@ -3849,8 +3849,10 @@ The skeleton will be bound to python-skeleton-NAME." :type 'string :group 'python) -(defvar-local python-check-custom-command nil +(defvar python-check-custom-command nil "Internal use.") +;; XXX: Avoid `defvar-local' for compat with Emacs<24.3 +(make-variable-buffer-local 'python-check-custom-command) (defun python-check (command) "Check a Python file (default current buffer's file). commit d1655783194f7b84ccac7114a2c341f10bc438b0 Author: Martin Rudalics Date: Sat Feb 7 11:51:03 2015 +0100 Try to improve handling of fullwidth/-height frames. * frame.el (frame-notice-user-settings): Update `frame-size-history'. (make-frame): Update `frame-size-history'. Call `frame-after-make-frame'. * faces.el (face-set-after-frame-default): Remove call to frame-can-run-window-configuration-change-hook. * frame.c (frame_size_history_add): New function. (frame_inhibit_resize): Consider frame_inhibit_implied_resize only after frame's after_make_frame slot is true. Inhibit resizing fullwidth-/height frames in one direction only. Update frame_size_history. (adjust_frame_size): Call frame_size_history_add. (make_frame): Initalize after_make_frame slot. (Fmake_terminal_frame): Adjust adjust_frame_size call. (Fcan_run_window_configuration_change_hook): Rename to Fframe_after_make_frame. Set after_make_frame slot. Return second argument. (x_set_frame_parameters): Postpone handling fullscreen parameter until after width and height parameters have been set. Apply width and height changes only if can_x_set_window_size is true. Update frame_size_history. (Qadjust_frame_size_1, Qadjust_frame_size_2) (Qadjust_frame_size_3, QEmacsFrameResize, Qframe_inhibit_resize) (Qx_set_fullscreen, Qx_check_fullscreen, Qx_set_window_size_1) (Qxg_frame_resized, Qxg_frame_set_char_size_1) (Qxg_frame_set_char_size_2, Qxg_frame_set_char_size_3) (Qxg_change_toolbar_position, Qx_net_wm_state) (Qx_handle_net_wm_state, Qtb_size_cb, Qupdate_frame_tool_bar) (Qfree_frame_tool_bar): New symbol for updating frame_size_history. (Qtip_frame, Qterminal_frame): New symbols. (Vframe_adjust_size_history): Rename to frame_size_history. * frame.h (struct frame): Rename can_run_window_configuration_change_hook slot to after_make_frame. (frame_size_history_add): Extern. * gtkutil.c (xg_frame_resized): Call frame_size_history_add. Don't set FRAME_PIXEL_WIDTH and FRAME_PIXEL_HEIGHT here. (xg_frame_set_char_size): Try to preserve the status of fullwidth/-height frames. Call frame_size_history_add. (tb_size_cb, update_frame_tool_bar, free_frame_tool_bar) (xg_change_toolbar_position): Call frame_size_history_add. * w32fns.c (x_change_tool_bar_height): Handle frame's fullscreen status. (Fx_create_frame): Process fullscreen parameter after frame has been resized. (x_create_tip_frame): Pass Qtip_frame to adjust_frame_size. (Fx_frame_geometry): Don't pollute pure storage. * w32term.c (w32_read_socket): For WM_WINDOWPOSCHANGED, WM_ACTIVATE and WM_ACTIVATEAPP set frame's visibility before calling w32fullscreen_hook. For WM_DISPLAYCHANGE call w32fullscreen_hook immediately. (x_fullscreen_adjust, x_check_fullscreen): Remove. (w32fullscreen_hook): Call change_frame_size just as with a "normal" frame resize operation. Call do_pending_window_change. (x_set_window_size): Try to handle fullwidth and fullheight more accurately. Don't rely on w32_enable_frame_resize_hack. (w32_enable_frame_resize_hack): Remove variable. * widget.c (EmacsFrameResize): Remove dead code. Call frame_size_history_add * window.c (run_window_configuration_change_hook): Check f->after_make_frame instead of f->can_run_window_configuration_change_hook. * xfns.c (x_change_tool_bar_height): Handle frame's fullscreen status. (Fx_create_frame): Process fullscreen parameter after frame has been resized. (Fx_frame_geometry): Don't pollute pure storage. * xterm.c (x_net_wm_state, x_handle_net_wm_state): Call frame_size_history_add. (do_ewmh_fullscreen): Handle x_frame_normalize_before_maximize. (x_check_fullscreen): Count in menubar when calling XResizeWindow. Wait for ConfigureNotify event. Call frame_size_history_add. (x_set_window_size_1): Remove PIXELWISE argument. Try to handle changing a fullheight frame's width or a fullwidth frame's height. Call frame_size_history_add. (x_set_window_size): Simplify xg_frame_set_char_size and x_set_window_size_1 calls. (x_frame_normalize_before_maximize): New variable. diff --git a/lisp/ChangeLog b/lisp/ChangeLog index c67113f..a3abb1a 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog @@ -1,3 +1,12 @@ +2015-02-07 Martin Rudalics + + * frame.el (frame-notice-user-settings): Update + `frame-size-history'. + (make-frame): Update `frame-size-history'. Call + `frame-after-make-frame'. + * faces.el (face-set-after-frame-default): Remove call to + frame-can-run-window-configuration-change-hook. + 2015-02-06 Dmitry Gutov * vc/vc-cvs.el (vc-cvs-dir-status-files): Don't pass DIR to diff --git a/lisp/faces.el b/lisp/faces.el index 22bf262..ce74c72 100644 --- a/lisp/faces.el +++ b/lisp/faces.el @@ -2092,8 +2092,7 @@ frame parameters in PARAMETERS." (value (cdr (assq param-name parameters)))) (if value (set-face-attribute (nth 1 param) frame - (nth 2 param) value)))) - (frame-can-run-window-configuration-change-hook frame t))) + (nth 2 param) value)))))) (defun tty-handle-reverse-video (frame parameters) "Handle the reverse-video frame parameter for terminal frames." diff --git a/lisp/frame.el b/lisp/frame.el index 1d5bbf2..ecb433e 100644 --- a/lisp/frame.el +++ b/lisp/frame.el @@ -465,6 +465,16 @@ there (in decreasing order of priority)." (frame-set-background-mode frame-initial-frame)) (face-set-after-frame-default frame-initial-frame) (setq newparms (delq new-bg newparms))) + + (when (numberp (car frame-size-history)) + (setq frame-size-history + (cons (1- (car frame-size-history)) + (cons + (list frame-initial-frame + "frame-notice-user-settings" + nil newparms) + (cdr frame-size-history))))) + (modify-frame-parameters frame-initial-frame newparms))))) ;; Restore the original buffer. @@ -686,7 +696,7 @@ the new frame according to its own rules." ;; Now make the frame. (run-hooks 'before-make-frame-hook) -;; (setq frame-adjust-size-history '(t)) +;; (setq frame-size-history '(1000)) (setq frame (funcall (gui-method frame-creation-function w) params)) @@ -697,11 +707,14 @@ the new frame according to its own rules." (let ((val (frame-parameter oldframe param))) (when val (set-frame-parameter frame param val))))) - (when (eq (car frame-adjust-size-history) t) - (setq frame-adjust-size-history - (cons t (cons (list "Frame made") - (cdr frame-adjust-size-history))))) + (when (numberp (car frame-size-history)) + (setq frame-size-history + (cons (1- (car frame-size-history)) + (cons (list frame "make-frame") + (cdr frame-size-history))))) + ;; We can run `window-configuration-change-hook' for this frame now. + (frame-after-make-frame frame t) (run-hook-with-args 'after-make-frame-functions frame) frame)) diff --git a/src/ChangeLog b/src/ChangeLog index cd72f98..ec70cdb 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,79 @@ +2015-02-07 Martin Rudalics + + * frame.c (frame_size_history_add): New function. + (frame_inhibit_resize): Consider frame_inhibit_implied_resize + only after frame's after_make_frame slot is true. Inhibit + resizing fullwidth-/height frames in one direction only. Update + frame_size_history. + (adjust_frame_size): Call frame_size_history_add. + (make_frame): Initalize after_make_frame slot. + (Fmake_terminal_frame): Adjust adjust_frame_size call. + (Fcan_run_window_configuration_change_hook): Rename to + Fframe_after_make_frame. Set after_make_frame slot. Return + second argument. + (x_set_frame_parameters): Postpone handling fullscreen parameter + until after width and height parameters have been set. Apply + width and height changes only if can_x_set_window_size is true. + Update frame_size_history. + (Qadjust_frame_size_1, Qadjust_frame_size_2) + (Qadjust_frame_size_3, QEmacsFrameResize, Qframe_inhibit_resize) + (Qx_set_fullscreen, Qx_check_fullscreen, Qx_set_window_size_1) + (Qxg_frame_resized, Qxg_frame_set_char_size_1) + (Qxg_frame_set_char_size_2, Qxg_frame_set_char_size_3) + (Qxg_change_toolbar_position, Qx_net_wm_state) + (Qx_handle_net_wm_state, Qtb_size_cb, Qupdate_frame_tool_bar) + (Qfree_frame_tool_bar): New symbol for updating + frame_size_history. + (Qtip_frame, Qterminal_frame): New symbols. + (Vframe_adjust_size_history): Rename to frame_size_history. + * frame.h (struct frame): Rename + can_run_window_configuration_change_hook slot to + after_make_frame. + (frame_size_history_add): Extern. + * gtkutil.c (xg_frame_resized): Call frame_size_history_add. + Don't set FRAME_PIXEL_WIDTH and FRAME_PIXEL_HEIGHT here. + (xg_frame_set_char_size): Try to preserve the status of + fullwidth/-height frames. Call frame_size_history_add. + (tb_size_cb, update_frame_tool_bar, free_frame_tool_bar) + (xg_change_toolbar_position): Call frame_size_history_add. + * w32fns.c (x_change_tool_bar_height): Handle frame's fullscreen + status. + (Fx_create_frame): Process fullscreen parameter after frame has + been resized. + (x_create_tip_frame): Pass Qtip_frame to adjust_frame_size. + (Fx_frame_geometry): Don't pollute pure storage. + * w32term.c (w32_read_socket): For WM_WINDOWPOSCHANGED, + WM_ACTIVATE and WM_ACTIVATEAPP set frame's visibility before + calling w32fullscreen_hook. For WM_DISPLAYCHANGE call + w32fullscreen_hook immediately. + (x_fullscreen_adjust, x_check_fullscreen): Remove. + (w32fullscreen_hook): Call change_frame_size just as with a + "normal" frame resize operation. Call do_pending_window_change. + (x_set_window_size): Try to handle fullwidth and fullheight more + accurately. Don't rely on w32_enable_frame_resize_hack. + (w32_enable_frame_resize_hack): Remove variable. + * widget.c (EmacsFrameResize): Remove dead code. Call + frame_size_history_add + * window.c (run_window_configuration_change_hook): Check + f->after_make_frame instead of + f->can_run_window_configuration_change_hook. + * xfns.c (x_change_tool_bar_height): Handle frame's fullscreen status. + (Fx_create_frame): Process fullscreen parameter after frame has + been resized. + (Fx_frame_geometry): Don't pollute pure storage. + * xterm.c (x_net_wm_state, x_handle_net_wm_state): Call + frame_size_history_add. + (do_ewmh_fullscreen): Handle x_frame_normalize_before_maximize. + (x_check_fullscreen): Count in menubar when calling + XResizeWindow. Wait for ConfigureNotify event. Call + frame_size_history_add. + (x_set_window_size_1): Remove PIXELWISE argument. Try to handle + changing a fullheight frame's width or a fullwidth frame's + height. Call frame_size_history_add. + (x_set_window_size): Simplify xg_frame_set_char_size and + x_set_window_size_1 calls. + (x_frame_normalize_before_maximize): New variable. + 2015-02-07 Paul Eggert Remove no-longer-used cursor_in_echo_area code diff --git a/src/frame.c b/src/frame.c index 890e897..96fe377 100644 --- a/src/frame.c +++ b/src/frame.c @@ -149,6 +149,33 @@ get_frame_param (register struct frame *frame, Lisp_Object prop) return Fcdr (tem); } + +void +frame_size_history_add (struct frame *f, Lisp_Object fun_symbol, + int width, int height, Lisp_Object rest) +{ + Lisp_Object frame; + int number; + + XSETFRAME (frame, f); + if (CONSP (frame_size_history) + && NUMBERP (Fcar (frame_size_history)) + && ((number = XINT (Fcar (frame_size_history))) > 0)) + frame_size_history = + Fcons (make_number (number - 1), + Fcons (list4 + (frame, fun_symbol, + ((width > 0) + ? list4 (make_number (FRAME_TEXT_WIDTH (f)), + make_number (FRAME_TEXT_HEIGHT (f)), + make_number (width), + make_number (height)) + : Qnil), + rest), + Fcdr (frame_size_history))); +} + + /* Return 1 if `frame-inhibit-implied-resize' is non-nil or fullscreen state of frame F would be affected by a vertical (horizontal if HORIZONTAL is true) resize. PARAMETER is the symbol of the frame @@ -156,11 +183,27 @@ get_frame_param (register struct frame *frame, Lisp_Object prop) bool frame_inhibit_resize (struct frame *f, bool horizontal, Lisp_Object parameter) { - return (EQ (frame_inhibit_implied_resize, Qt) - || (CONSP (frame_inhibit_implied_resize) - && !NILP (Fmemq (parameter, frame_inhibit_implied_resize))) - || !NILP (get_frame_param (f, Qfullscreen)) - || FRAME_TERMCAP_P (f) || FRAME_MSDOS_P (f)); + Lisp_Object fullscreen = get_frame_param (f, Qfullscreen); + bool inhibit + = ((f->after_make_frame + && (EQ (frame_inhibit_implied_resize, Qt) + || (CONSP (frame_inhibit_implied_resize) + && !NILP (Fmemq (parameter, frame_inhibit_implied_resize))))) + || (horizontal + && !EQ (fullscreen, Qnil) && !EQ (fullscreen, Qfullheight)) + || (!horizontal + && !EQ (fullscreen, Qnil) && !EQ (fullscreen, Qfullwidth)) + || FRAME_TERMCAP_P (f) || FRAME_MSDOS_P (f)); + + if (inhibit && !FRAME_TERMCAP_P (f) && !FRAME_MSDOS_P (f)) + frame_size_history_add + (f, Qframe_inhibit_resize, 0, 0, + list5 (horizontal ? Qt : Qnil, parameter, + f->after_make_frame ? Qt : Qnil, + frame_inhibit_implied_resize, + fullscreen)); + + return inhibit; } static void @@ -369,18 +412,9 @@ adjust_frame_size (struct frame *f, int new_width, int new_height, int inhibit, XSETFRAME (frame, f); - /* `make-frame' initializes Vframe_adjust_size_history to (Qt) and - strips its car when exiting. Just in case make sure its size never - exceeds 100. */ - if (!NILP (Fconsp (Vframe_adjust_size_history)) - && EQ (Fcar (Vframe_adjust_size_history), Qt) - && XFASTINT (Fsafe_length (Vframe_adjust_size_history)) <= 100) - Vframe_adjust_size_history = - Fcons (Qt, Fcons (list5 (make_number (0), - make_number (new_text_width), - make_number (new_text_height), - make_number (inhibit), parameter), - Fcdr (Vframe_adjust_size_history))); + frame_size_history_add + (f, Qadjust_frame_size_1, new_text_width, new_text_height, + list2 (parameter, make_number (inhibit))); /* The following two values are calculated from the old window body sizes and any "new" settings for scroll bars, dividers, fringes and @@ -391,7 +425,7 @@ adjust_frame_size (struct frame *f, int new_width, int new_height, int inhibit, = frame_windows_min_size (frame, Qnil, (inhibit == 5) ? Qt : Qnil, Qt); if (inhibit >= 2 && inhibit <= 4) - /* If INHIBIT is in [2..4] inhibit if the "old" window sizes stay + /* When INHIBIT is in [2..4] inhibit if the "old" window sizes stay within the limits and either frame_inhibit_resize tells us to do so or INHIBIT equals 4. */ { @@ -449,16 +483,10 @@ adjust_frame_size (struct frame *f, int new_width, int new_height, int inhibit, else if (inhibit_vertical) new_text_height = old_text_height; - if (!NILP (Fconsp (Vframe_adjust_size_history)) - && EQ (Fcar (Vframe_adjust_size_history), Qt) - && XFASTINT (Fsafe_length (Vframe_adjust_size_history)) <= 100) - Vframe_adjust_size_history = - Fcons (Qt, Fcons (list5 (make_number (1), - make_number (new_text_width), - make_number (new_text_height), - make_number (new_cols), - make_number (new_lines)), - Fcdr (Vframe_adjust_size_history))); + frame_size_history_add + (f, Qadjust_frame_size_2, new_text_width, new_text_height, + list2 (inhibit_horizontal ? Qt : Qnil, + inhibit_vertical ? Qt : Qnil)); x_set_window_size (f, 0, new_text_width, new_text_height, 1); f->resized_p = true; @@ -525,6 +553,11 @@ adjust_frame_size (struct frame *f, int new_width, int new_height, int inhibit, FrameRows (FRAME_TTY (f)) = new_lines + FRAME_TOP_MARGIN (f); } + frame_size_history_add + (f, Qadjust_frame_size_3, new_text_width, new_text_height, + list4 (make_number (old_pixel_width), make_number (old_pixel_height), + make_number (new_pixel_width), make_number (new_pixel_height))); + /* Assign new sizes. */ FRAME_TEXT_WIDTH (f) = new_text_width; FRAME_TEXT_HEIGHT (f) = new_text_height; @@ -533,17 +566,6 @@ adjust_frame_size (struct frame *f, int new_width, int new_height, int inhibit, SET_FRAME_COLS (f, new_cols); SET_FRAME_LINES (f, new_lines); - if (!NILP (Fconsp (Vframe_adjust_size_history)) - && EQ (Fcar (Vframe_adjust_size_history), Qt) - && XFASTINT (Fsafe_length (Vframe_adjust_size_history)) <= 100) - Vframe_adjust_size_history = - Fcons (Qt, Fcons (list5 (make_number (2), - make_number (new_text_width), - make_number (new_text_height), - make_number (new_cols), - make_number (new_lines)), - Fcdr (Vframe_adjust_size_history))); - { struct window *w = XWINDOW (FRAME_SELECTED_WINDOW (f)); int text_area_x, text_area_y, text_area_width, text_area_height; @@ -608,7 +630,7 @@ make_frame (bool mini_p) f->redisplay = true; f->garbaged = true; f->can_x_set_window_size = false; - f->can_run_window_configuration_change_hook = false; + f->after_make_frame = false; f->tool_bar_redisplayed_once = false; f->column_width = 1; /* !FRAME_WINDOW_P value. */ f->line_height = 1; /* !FRAME_WINDOW_P value. */ @@ -1020,7 +1042,8 @@ affects all frames on the same terminal device. */) { int width, height; get_tty_size (fileno (FRAME_TTY (f)->input), &width, &height); - adjust_frame_size (f, width, height - FRAME_MENU_BAR_LINES (f), 5, 0, Qnil); + adjust_frame_size (f, width, height - FRAME_MENU_BAR_LINES (f), + 5, 0, Qterminal_frame); } adjust_frame_glyphs (f); @@ -2260,24 +2283,25 @@ If there is no window system support, this function does nothing. */) return Qnil; } -DEFUN ("frame-can-run-window-configuration-change-hook", - Fcan_run_window_configuration_change_hook, - Scan_run_window_configuration_change_hook, 2, 2, 0, - doc: /* Whether `window-configuration-change-hook' is run for frame FRAME. -FRAME nil means use the selected frame. Second argument ALLOW non-nil +DEFUN ("frame-after-make-frame", + Fframe_after_make_frame, + Sframe_after_make_frame, 2, 2, 0, + doc: /* Mark FRAME as made. +FRAME nil means use the selected frame. Second argument MADE non-nil means functions on `window-configuration-change-hook' are called -whenever the window configuration of FRAME changes. ALLOW nil means +whenever the window configuration of FRAME changes. MADE nil means these functions are not called. -This function is currently called by `face-set-after-frame-default' only -and should be otherwise used with utter care to avoid that running -functions on `window-configuration-change-hook' is impeded forever. */) - (Lisp_Object frame, Lisp_Object allow) +This function is currently called by `make-frame' only and should be +otherwise used with utter care to avoid that running functions on +`window-configuration-change-hook' is impeded forever. */) + (Lisp_Object frame, Lisp_Object made) { struct frame *f = decode_live_frame (frame); - f->can_run_window_configuration_change_hook = NILP (allow) ? false : true; - return Qnil; + f->after_make_frame = NILP (made) ? false : true; + + return made; } @@ -3037,7 +3061,7 @@ x_set_frame_parameters (struct frame *f, Lisp_Object alist) set them both at once. So we wait until we've looked at the entire list before we set them. */ int width IF_LINT (= 0), height IF_LINT (= 0); - bool width_change = 0, height_change = 0; + bool width_change = false, height_change = false; /* Same here. */ Lisp_Object left, top; @@ -3045,6 +3069,10 @@ x_set_frame_parameters (struct frame *f, Lisp_Object alist) /* Same with these. */ Lisp_Object icon_left, icon_top; + /* And with this. */ + Lisp_Object fullscreen; + bool fullscreen_change = false; + /* Record in these vectors all the parms specified. */ Lisp_Object *parms; Lisp_Object *values; @@ -3138,6 +3166,11 @@ x_set_frame_parameters (struct frame *f, Lisp_Object alist) icon_top = val; else if (EQ (prop, Qicon_left)) icon_left = val; + else if (EQ (prop, Qfullscreen)) + { + fullscreen = val; + fullscreen_change = true; + } else if (EQ (prop, Qforeground_color) || EQ (prop, Qbackground_color) || EQ (prop, Qfont)) @@ -3218,14 +3251,14 @@ x_set_frame_parameters (struct frame *f, Lisp_Object alist) that here since otherwise a size change implied by an intermittent font change may get lost as in Bug#17142. */ if (!width_change) - width = (f->new_width + width = ((f->can_x_set_window_size && f->new_width) ? (f->new_pixelwise ? f->new_width : (f->new_width * FRAME_COLUMN_WIDTH (f))) : FRAME_TEXT_WIDTH (f)); if (!height_change) - height = (f->new_height + height = ((f->can_x_set_window_size && f->new_height) ? (f->new_pixelwise ? f->new_height : (f->new_height * FRAME_LINE_HEIGHT (f))) @@ -3298,6 +3331,20 @@ x_set_frame_parameters (struct frame *f, Lisp_Object alist) /* Actually set that position, and convert to absolute. */ x_set_offset (f, leftpos, toppos, -1); } + + if (fullscreen_change) + { + Lisp_Object old_value = get_frame_param (f, Qfullscreen); + + frame_size_history_add + (f, Qx_set_fullscreen, 0, 0, list2 (old_value, fullscreen)); + + store_frame_param (f, Qfullscreen, fullscreen); + if (!EQ (fullscreen, old_value)) + x_set_fullscreen (f, fullscreen, old_value); + } + + #ifdef HAVE_X_WINDOWS if ((!NILP (icon_left) || !NILP (icon_top)) && ! (icon_left_no_change && icon_top_no_change)) @@ -4834,11 +4881,33 @@ syms_of_frame (void) DEFSYM (Qtool_bar_external, "tool-bar-external"); DEFSYM (Qtool_bar_size, "tool-bar-size"); DEFSYM (Qframe_inner_size, "frame-inner-size"); + /* The following are used for frame_size_history. */ + DEFSYM (Qadjust_frame_size_1, "adjust-frame-size-1"); + DEFSYM (Qadjust_frame_size_2, "adjust-frame-size-2"); + DEFSYM (Qadjust_frame_size_3, "adjust-frame-size-3"); + DEFSYM (QEmacsFrameResize, "EmacsFrameResize"); + DEFSYM (Qframe_inhibit_resize, "frame-inhibit-resize"); + DEFSYM (Qx_set_fullscreen, "x-set-fullscreen"); + DEFSYM (Qx_check_fullscreen, "x-check-fullscreen"); + DEFSYM (Qx_set_window_size_1, "x-set-window-size-1"); + DEFSYM (Qxg_frame_resized, "xg-frame-resized"); + DEFSYM (Qxg_frame_set_char_size_1, "xg-frame-set-char-size-1"); + DEFSYM (Qxg_frame_set_char_size_2, "xg-frame-set-char-size-2"); + DEFSYM (Qxg_frame_set_char_size_3, "xg-frame-set-char-size-3"); + DEFSYM (Qxg_change_toolbar_position, "xg-change-toolbar-position"); + DEFSYM (Qx_net_wm_state, "x-net-wm-state"); + DEFSYM (Qx_handle_net_wm_state, "x-handle-net-wm-state"); + DEFSYM (Qtb_size_cb, "tb-size-cb"); + DEFSYM (Qupdate_frame_tool_bar, "update-frame-tool-bar"); + DEFSYM (Qfree_frame_tool_bar, "free-frame-tool-bar"); + DEFSYM (Qchange_frame_size, "change-frame-size"); DEFSYM (Qxg_frame_set_char_size, "xg-frame-set-char-size"); DEFSYM (Qset_window_configuration, "set-window-configuration"); DEFSYM (Qx_create_frame_1, "x-create-frame-1"); DEFSYM (Qx_create_frame_2, "x-create-frame-2"); + DEFSYM (Qtip_frame, "tip-frame"); + DEFSYM (Qterminal_frame, "terminal-frame"); #ifdef HAVE_NS DEFSYM (Qns_parse_geometry, "ns-parse-geometry"); @@ -5106,9 +5175,22 @@ even if this option is non-nil. */); frame_inhibit_implied_resize = Qt; #endif - DEFVAR_LISP ("frame-adjust-size-history", Vframe_adjust_size_history, - doc: /* History of frame size adjustments. */); - Vframe_adjust_size_history = Qnil; + DEFVAR_LISP ("frame-size-history", frame_size_history, + doc: /* History of frame size adjustments. +If non-nil, list recording frame size adjustment. Adjustments are +recorded only if the first element of this list is a positive number. +Adding an adjustment decrements that number by one. + +The remaining elements are the adjustments. Each adjustment is a list +of four elements `frame', `function', `sizes' and `more'. `frame' is +the affected frame and `function' the invoking function. `sizes' is +usually a list of four elements `old-width', `old-height', `new-width' +and `new-height' representing the old and new sizes recorded/requested +by `function'. `more' is a list with additional information. + +The function `frame--size-history' displays the value of this variable +in a more readable form. */); + frame_size_history = Qnil; staticpro (&Vframe_list); @@ -5141,7 +5223,7 @@ even if this option is non-nil. */); defsubr (&Sraise_frame); defsubr (&Slower_frame); defsubr (&Sx_focus_frame); - defsubr (&Scan_run_window_configuration_change_hook); + defsubr (&Sframe_after_make_frame); defsubr (&Sredirect_frame_focus); defsubr (&Sframe_focus); defsubr (&Sframe_parameters); diff --git a/src/frame.h b/src/frame.h index 0c08d12..6f5de3f 100644 --- a/src/frame.h +++ b/src/frame.h @@ -332,9 +332,8 @@ struct frame frame. */ bool_bf can_x_set_window_size : 1; - /* True means run_window_configuration_change_hook can be processed - for this frame. */ - bool_bf can_run_window_configuration_change_hook : 1; + /* Set to true after this frame was made by `make-frame'. */ + bool_bf after_make_frame : 1; /* True means tool bar has been redisplayed at least once in current session. */ @@ -392,9 +391,9 @@ struct frame int left_pos, top_pos; /* Total width of this frame (including fringes, vertical scroll bar - and internal border widths) and total height (including menu bar, - tool bar, horizontal scroll bar and internal border widths) in - pixels. */ + and internal border widths) and total height (including internal + menu and tool bars, horizontal scroll bar and internal border + widths) in pixels. */ int pixel_width, pixel_height; /* These many pixels are the difference between the outer window (i.e. the @@ -1124,6 +1123,8 @@ extern void frame_make_pointer_visible (struct frame *); extern Lisp_Object delete_frame (Lisp_Object, Lisp_Object); extern bool frame_inhibit_resize (struct frame *, bool, Lisp_Object); extern void adjust_frame_size (struct frame *, int, int, int, bool, Lisp_Object); +extern void frame_size_history_add (struct frame *f, Lisp_Object fun_symbol, + int width, int height, Lisp_Object rest); extern Lisp_Object Vframe_list; diff --git a/src/gtkutil.c b/src/gtkutil.c index 21f3cb1..063e882 100644 --- a/src/gtkutil.c +++ b/src/gtkutil.c @@ -886,23 +886,25 @@ xg_frame_resized (struct frame *f, int pixelwidth, int pixelheight) if (pixelwidth == -1 && pixelheight == -1) { if (FRAME_GTK_WIDGET (f) && gtk_widget_get_mapped (FRAME_GTK_WIDGET (f))) - gdk_window_get_geometry (gtk_widget_get_window (FRAME_GTK_WIDGET (f)), - 0, 0, - &pixelwidth, &pixelheight); - else return; + gdk_window_get_geometry (gtk_widget_get_window (FRAME_GTK_WIDGET (f)), + 0, 0, &pixelwidth, &pixelheight); + else + return; } - width = FRAME_PIXEL_TO_TEXT_WIDTH (f, pixelwidth); height = FRAME_PIXEL_TO_TEXT_HEIGHT (f, pixelheight); + frame_size_history_add + (f, Qxg_frame_resized, width, height, Qnil); + if (width != FRAME_TEXT_WIDTH (f) || height != FRAME_TEXT_HEIGHT (f) || pixelwidth != FRAME_PIXEL_WIDTH (f) || pixelheight != FRAME_PIXEL_HEIGHT (f)) { - FRAME_PIXEL_WIDTH (f) = pixelwidth; - FRAME_PIXEL_HEIGHT (f) = pixelheight; +/** FRAME_PIXEL_WIDTH (f) = pixelwidth; **/ +/** FRAME_PIXEL_HEIGHT (f) = pixelheight; **/ xg_clear_under_internal_border (f); change_frame_size (f, width, height, 0, 1, 0, 1); @@ -921,24 +923,71 @@ xg_frame_set_char_size (struct frame *f, int width, int height) { int pixelwidth = FRAME_TEXT_TO_PIXEL_WIDTH (f, width); int pixelheight = FRAME_TEXT_TO_PIXEL_HEIGHT (f, height); + Lisp_Object fullscreen = get_frame_param (f, Qfullscreen); + gint gwidth, gheight; if (FRAME_PIXEL_HEIGHT (f) == 0) return; + gtk_window_get_size (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)), + &gwidth, &gheight); + /* Do this before resize, as we don't know yet if we will be resized. */ xg_clear_under_internal_border (f); - /* Must resize our top level widget. Font size may have changed, - but not rows/cols. */ - gtk_window_resize (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)), - pixelwidth + FRAME_TOOLBAR_WIDTH (f), - pixelheight + FRAME_TOOLBAR_HEIGHT (f) - + FRAME_MENUBAR_HEIGHT (f)); - x_wm_set_size_hint (f, 0, 0); + /* Resize the top level widget so rows and columns remain constant. + + When the frame is fullheight and we only want to change the width + or it is fullwidth and we only want to change the height we should + be able to preserve the fullscreen property. However, due to the + fact that we have to send a resize request anyway, the window + manager will abolish it. At least the respective size should + remain unchanged but giving the frame back its normal size will + be broken ... */ + if (EQ (fullscreen, Qfullwidth) && width == FRAME_TEXT_WIDTH (f)) + { + frame_size_history_add + (f, Qxg_frame_set_char_size_1, width, height, + list2 (make_number (gheight), + make_number (pixelheight + FRAME_TOOLBAR_HEIGHT (f) + + FRAME_MENUBAR_HEIGHT (f)))); + + gtk_window_resize (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)), + gwidth, + pixelheight + FRAME_TOOLBAR_HEIGHT (f) + + FRAME_MENUBAR_HEIGHT (f)); + } + else if (EQ (fullscreen, Qfullheight) && height == FRAME_TEXT_HEIGHT (f)) + { + frame_size_history_add + (f, Qxg_frame_set_char_size_2, width, height, + list2 (make_number (gwidth), + make_number (pixelwidth + FRAME_TOOLBAR_WIDTH (f)))); + + gtk_window_resize (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)), + pixelwidth + FRAME_TOOLBAR_WIDTH (f), + gheight); + } + + else + { + frame_size_history_add + (f, Qxg_frame_set_char_size_3, width, height, + list2 (make_number (pixelwidth + FRAME_TOOLBAR_WIDTH (f)), + make_number (pixelheight + FRAME_TOOLBAR_HEIGHT (f) + + FRAME_MENUBAR_HEIGHT (f)))); + + gtk_window_resize (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)), + pixelwidth + FRAME_TOOLBAR_WIDTH (f), + pixelheight + FRAME_TOOLBAR_HEIGHT (f) + + FRAME_MENUBAR_HEIGHT (f)); + fullscreen = Qnil; + } SET_FRAME_GARBAGED (f); cancel_mouse_face (f); + x_wm_set_size_hint (f, 0, 0); /* We can not call change_frame_size for a mapped frame, we can not set pixel width/height either. The window manager may override our resize request, XMonad does this all the time. @@ -952,9 +1001,17 @@ xg_frame_set_char_size (struct frame *f, int width, int height) (void)gtk_events_pending (); gdk_flush (); x_wait_for_event (f, ConfigureNotify); + + if (!NILP (fullscreen)) + /* Try to restore fullscreen state. */ + { + store_frame_param (f, Qfullscreen, fullscreen); + x_set_fullscreen (f, fullscreen, fullscreen); + } } else - adjust_frame_size (f, -1, -1, 5, 0, Qxg_frame_set_char_size); + adjust_frame_size (f, width, height, 5, 0, Qxg_frame_set_char_size); + } /* Handle height/width changes (i.e. add/remove/move menu/toolbar). @@ -4214,8 +4271,12 @@ tb_size_cb (GtkWidget *widget, allocated between widgets, it may get another. So we must update size hints if tool bar size changes. Seen on Fedora 18 at least. */ struct frame *f = user_data; + if (xg_update_tool_bar_sizes (f)) - adjust_frame_size (f, -1, -1, 2, 0, Qtool_bar_lines); + { + frame_size_history_add (f, Qtb_size_cb, 0, 0, Qnil); + adjust_frame_size (f, -1, -1, 5, 0, Qtool_bar_lines); + } } /* Create a tool bar for frame F. */ @@ -4489,10 +4550,11 @@ xg_update_tool_bar_sizes (struct frame *f) FRAME_TOOLBAR_RIGHT_WIDTH (f) = nr; FRAME_TOOLBAR_TOP_HEIGHT (f) = nt; FRAME_TOOLBAR_BOTTOM_HEIGHT (f) = nb; - return 1; - } - return 0; + return true; + } + else + return false; } static char * @@ -4815,7 +4877,10 @@ update_frame_tool_bar (struct frame *f) xg_pack_tool_bar (f, FRAME_TOOL_BAR_POSITION (f)); gtk_widget_show_all (x->toolbar_widget); if (xg_update_tool_bar_sizes (f)) - adjust_frame_size (f, -1, -1, 2, 0, Qtool_bar_lines); + { + frame_size_history_add (f, Qupdate_frame_tool_bar, 0, 0, Qnil); + adjust_frame_size (f, -1, -1, 2, 0, Qtool_bar_lines); + } } unblock_input (); @@ -4863,6 +4928,7 @@ free_frame_tool_bar (struct frame *f) NULL); } + frame_size_history_add (f, Qfree_frame_tool_bar, 0, 0, Qnil); adjust_frame_size (f, -1, -1, 2, 0, Qtool_bar_lines); unblock_input (); @@ -4892,8 +4958,13 @@ xg_change_toolbar_position (struct frame *f, Lisp_Object pos) xg_pack_tool_bar (f, pos); g_object_unref (top_widget); + if (xg_update_tool_bar_sizes (f)) - adjust_frame_size (f, -1, -1, 2, 0, Qtool_bar_lines); + { + frame_size_history_add (f, Qxg_change_toolbar_position, 0, 0, Qnil); + adjust_frame_size (f, -1, -1, 2, 0, Qtool_bar_lines); + } + unblock_input (); } diff --git a/src/w32fns.c b/src/w32fns.c index 8435270..08000d8 100644 --- a/src/w32fns.c +++ b/src/w32fns.c @@ -1722,6 +1722,7 @@ x_change_tool_bar_height (struct frame *f, int height) int old_height = FRAME_TOOL_BAR_HEIGHT (f); int lines = (height + unit - 1) / unit; int old_text_height = FRAME_TEXT_HEIGHT (f); + Lisp_Object fullscreen; /* Make sure we redisplay all windows in this frame. */ windows_or_buffers_changed = 23; @@ -1746,7 +1747,10 @@ x_change_tool_bar_height (struct frame *f, int height) f->n_tool_bar_rows = 0; adjust_frame_size (f, -1, -1, - (!f->tool_bar_redisplayed_once ? 1 + ((!f->tool_bar_redisplayed_once + && (NILP (fullscreen = + get_frame_param (f, Qfullscreen)) + || EQ (fullscreen, Qfullwidth))) ? 1 : (old_height == 0 || height == 0) ? 2 : 4), false, Qtool_bar_lines); @@ -4668,8 +4672,6 @@ This function is an internal primitive--use `make-frame' instead. */) "bufferPredicate", "BufferPredicate", RES_TYPE_SYMBOL); x_default_parameter (f, parameters, Qtitle, Qnil, "title", "Title", RES_TYPE_STRING); - x_default_parameter (f, parameters, Qfullscreen, Qnil, - "fullscreen", "Fullscreen", RES_TYPE_SYMBOL); f->output_data.w32->dwStyle = WS_OVERLAPPEDWINDOW; f->output_data.w32->parent_desc = FRAME_DISPLAY_INFO (f)->root_window; @@ -4728,6 +4730,12 @@ This function is an internal primitive--use `make-frame' instead. */) x_wm_set_size_hint (f, window_prompting, false); unblock_input (); + /* Process fullscreen parameter here in the hope that normalizing a + fullheight/fullwidth frame will produce the size set by the last + adjust_frame_size call. */ + x_default_parameter (f, parameters, Qfullscreen, Qnil, + "fullscreen", "Fullscreen", RES_TYPE_SYMBOL); + /* Make the window appear on the frame and enable display, unless the caller says not to. However, with explicit parent, Emacs cannot control visibility, so don't try. */ @@ -5832,7 +5840,7 @@ x_create_tip_frame (struct w32_display_info *dpyinfo, SET_FRAME_COLS (f, 0); SET_FRAME_LINES (f, 0); adjust_frame_size (f, width * FRAME_COLUMN_WIDTH (f), - height * FRAME_LINE_HEIGHT (f), 0, true, Qnil); + height * FRAME_LINE_HEIGHT (f), 0, true, Qtip_frame); /* Add `tooltip' frame parameter's default value. */ if (NILP (Fframe_parameter (frame, Qtooltip))) @@ -7558,7 +7566,7 @@ elements (all size values are in pixels). menu_bar_height = single_bar_height; return - listn (CONSTYPE_PURE, 10, + listn (CONSTYPE_HEAP, 10, Fcons (Qframe_position, Fcons (make_number (frame_outer_edges.left), make_number (frame_outer_edges.top))), diff --git a/src/w32term.c b/src/w32term.c index 251c46c..fb9d238 100644 --- a/src/w32term.c +++ b/src/w32term.c @@ -3344,8 +3344,6 @@ static void x_horizontal_scroll_bar_report_motion (struct frame **, Lisp_Object enum scroll_bar_part *, Lisp_Object *, Lisp_Object *, Time *); -static void x_check_fullscreen (struct frame *); - static void w32_define_cursor (Window window, Cursor cursor) { @@ -4989,8 +4987,12 @@ w32_read_socket (struct terminal *terminal, sets the WAIT flag. */ if ((msg.msg.message == WM_WINDOWPOSCHANGED || msg.msg.wParam) && (f->want_fullscreen & FULLSCREEN_WAIT)) - w32fullscreen_hook (f); - x_check_fullscreen (f); + { + /* Must set visibility right here since otherwise + w32fullscreen_hook returns immediately. */ + SET_FRAME_VISIBLE (f, 1); + w32fullscreen_hook (f); + } } check_visibility = 1; break; @@ -5269,11 +5271,18 @@ w32_read_socket (struct terminal *terminal, if (f) { + Lisp_Object fullscreen = get_frame_param (f, Qfullscreen); + dpyinfo->n_cbits = msg.msg.wParam; /* The new display could have a different resolution, in - which case we must reconsider what fullscreen - means. */ - x_check_fullscreen (f); + which case we must reconsider what fullscreen means. + The following code is untested yet. */ + if (!NILP (fullscreen)) + { + x_set_fullscreen (f, fullscreen, fullscreen); + w32fullscreen_hook (f); + } + DebPrint (("display change: %d %d\n", (short) LOWORD (msg.msg.lParam), (short) HIWORD (msg.msg.lParam))); @@ -5959,75 +5968,6 @@ x_set_offset (struct frame *f, register int xoff, register int yoff, unblock_input (); } -/* Calculate fullscreen size. Return in *TOP_POS and *LEFT_POS the - wanted positions of the WM window (not Emacs window). - Return in *WIDTH and *HEIGHT the wanted width and height of Emacs - window (FRAME_X_WINDOW). - */ - -static void -x_fullscreen_adjust (struct frame *f, int *width, int *height, int *top_pos, int *left_pos) -{ - int newwidth = FRAME_COLS (f); - int newheight = FRAME_LINES (f); - Display_Info *dpyinfo = FRAME_DISPLAY_INFO (f); - - *top_pos = f->top_pos; - *left_pos = f->left_pos; - - if (f->want_fullscreen & FULLSCREEN_HEIGHT) - { - int ph; - - ph = x_display_pixel_height (dpyinfo); - newheight = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, ph); - ph = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, newheight) - f->y_pixels_diff; - newheight = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, ph); - *top_pos = 0; - } - - if (f->want_fullscreen & FULLSCREEN_WIDTH) - { - int pw; - - pw = x_display_pixel_width (dpyinfo); - newwidth = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, pw); - pw = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, newwidth) - f->x_pixels_diff; - newwidth = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, pw); - *left_pos = 0; - } - - *width = newwidth; - *height = newheight; -} - -/* Check if we need to resize the frame due to a fullscreen request. - If so needed, resize the frame. */ -static void -x_check_fullscreen (struct frame *f) -{ - if (f->want_fullscreen & FULLSCREEN_BOTH) - { - int width, height, ign; - - x_real_positions (f, &f->left_pos, &f->top_pos); - - x_fullscreen_adjust (f, &width, &height, &ign, &ign); - - /* We do not need to move the window, it shall be taken care of - when setting WM manager hints. */ - if (FRAME_COLS (f) != width || FRAME_LINES (f) != height) - { - change_frame_size (f, width, height, 0, 1, 0, 0); - SET_FRAME_GARBAGED (f); - cancel_mouse_face (f); - - /* Wait for the change of frame size to occur. */ - f->want_fullscreen |= FULLSCREEN_WAIT; - } - } -} - static void w32fullscreen_hook (struct frame *f) { @@ -6074,6 +6014,10 @@ w32fullscreen_hook (struct frame *f) SetWindowPos (hwnd, HWND_TOP, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_NOOWNERZORDER | SWP_FRAMECHANGED); + change_frame_size + (f, FRAME_PIXEL_TO_TEXT_WIDTH (f, rect.right - rect.left), + FRAME_PIXEL_TO_TEXT_HEIGHT (f, rect.bottom - rect.top), + 0, 1, 0, 1); } else { @@ -6082,10 +6026,39 @@ w32fullscreen_hook (struct frame *f) FRAME_NORMAL_PLACEMENT (f).rcNormalPosition, &rect); SetWindowPos (hwnd, HWND_TOP, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, 0); + + if (f->want_fullscreen == FULLSCREEN_WIDTH) + { + int border_width = GetSystemMetrics (SM_CXFRAME); + + change_frame_size + (f, (FRAME_PIXEL_TO_TEXT_WIDTH + (f, rect.right - rect.left - 2 * border_width)), + 0, 0, 1, 0, 1); + } + else + { + int border_height = GetSystemMetrics (SM_CYFRAME); + /* Won't work for wrapped menu bar. */ + int menu_bar_height = GetSystemMetrics (SM_CYMENU); + int title_height = GetSystemMetrics (SM_CYCAPTION); + + change_frame_size + (f, 0, (FRAME_PIXEL_TO_TEXT_HEIGHT + (f, rect.bottom - rect.top - 2 * border_height + - title_height - menu_bar_height)), + 0, 1, 0, 1); + } } f->want_fullscreen = FULLSCREEN_NONE; unblock_input (); + + if (f->want_fullscreen == FULLSCREEN_BOTH + || f->want_fullscreen == FULLSCREEN_WIDTH + || f->want_fullscreen == FULLSCREEN_HEIGHT) + do_pending_window_change (0); + } else f->want_fullscreen |= FULLSCREEN_WAIT; @@ -6101,6 +6074,7 @@ x_set_window_size (struct frame *f, bool change_gravity, int width, int height, bool pixelwise) { int pixelwidth, pixelheight; + Lisp_Object fullscreen = get_frame_param (f, Qfullscreen); RECT rect; block_input (); @@ -6119,7 +6093,7 @@ x_set_window_size (struct frame *f, bool change_gravity, if (w32_add_wrapped_menu_bar_lines) { /* When the menu bar wraps sending a SetWindowPos shrinks the - height of the frame when the wrapped menu bar lines are not + height of the frame then the wrapped menu bar lines are not accounted for (Bug#15174 and Bug#18720). Here we add these extra lines to the frame height. */ MENUBARINFO info; @@ -6143,9 +6117,6 @@ x_set_window_size (struct frame *f, bool change_gravity, f->win_gravity = NorthWestGravity; x_wm_set_size_hint (f, (long) 0, false); - f->want_fullscreen = FULLSCREEN_NONE; - w32fullscreen_hook (f); - rect.left = rect.top = 0; rect.right = pixelwidth; rect.bottom = pixelheight; @@ -6153,45 +6124,45 @@ x_set_window_size (struct frame *f, bool change_gravity, AdjustWindowRect (&rect, f->output_data.w32->dwStyle, FRAME_EXTERNAL_MENU_BAR (f)); - my_set_window_pos (FRAME_W32_WINDOW (f), - NULL, - 0, 0, - rect.right - rect.left, - rect.bottom - rect.top, - SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE); - - /* If w32_enable_frame_resize_hack is non-nil, immediately apply the - new pixel sizes to the frame and its subwindows. - - Jason Rumney earlier refused to call change_frame_size right here - with the following argument: - - The following mirrors what is done in xterm.c. It appears to be for - informing lisp of the new size immediately, while the actual resize - will happen asynchronously. But on Windows, the menu bar - automatically wraps when the frame is too narrow to contain it, and - that causes any calculations made here to come out wrong. The end - is some nasty buggy behavior, including the potential loss of the - minibuffer. - - Disabling this code is either not sufficient to fix the problems - completely, or it causes fresh problems, but at least it removes - the most problematic symptom of the minibuffer becoming unusable. - - However, as the discussion about how to handle frame size - parameters on Windows (Bug#1348, Bug#16028) shows, that cure seems - worse than the disease. In particular, menu bar wrapping looks - like a non-issue - maybe so because Windows eventually gets back to - us with the correct client rectangle anyway. But we have to avoid - calling change_frame_size with a delta of less than one canoncial - character size when frame_resize_pixelwise is nil, as explained in - the comment above. */ - - if (w32_enable_frame_resize_hack) + if (!(f->after_make_frame) + && !(f->want_fullscreen & FULLSCREEN_WAIT) + && FRAME_VISIBLE_P (f)) + { + RECT window_rect; + + GetWindowRect (FRAME_W32_WINDOW (f), &window_rect); + if (EQ (fullscreen, Qmaximized) + || EQ (fullscreen, Qfullboth) + || EQ (fullscreen, Qfullwidth)) + { + rect.left = window_rect.left; + rect.right = window_rect.right; + pixelwidth = 0; + } + if (EQ (fullscreen, Qmaximized) + || EQ (fullscreen, Qfullboth) + || EQ (fullscreen, Qfullheight)) + { + rect.top = window_rect.top; + rect.bottom = window_rect.bottom; + pixelheight = 0; + } + } + + if (pixelwidth > 0 || pixelheight > 0) { - change_frame_size (f, FRAME_PIXEL_TO_TEXT_WIDTH (f, pixelwidth), - FRAME_PIXEL_TO_TEXT_HEIGHT (f, pixelheight), + my_set_window_pos (FRAME_W32_WINDOW (f), NULL, + 0, 0, + rect.right - rect.left, + rect.bottom - rect.top, + SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE); + + change_frame_size (f, + ((pixelwidth == 0) + ? 0 : FRAME_PIXEL_TO_TEXT_WIDTH (f, pixelwidth)), + ((pixelheight == 0) + ? 0 : FRAME_PIXEL_TO_TEXT_HEIGHT (f, pixelheight)), 0, 1, 0, 1); SET_FRAME_GARBAGED (f); @@ -7102,7 +7073,7 @@ Windows 8. It is set to nil on Windows 9X. */); w32_unicode_filenames = 0; - /* FIXME: The following two variables will be (hopefully) removed + /* FIXME: The following variable will be (hopefully) removed before Emacs 25.1 gets released. */ DEFVAR_BOOL ("w32-add-wrapped-menu-bar-lines", @@ -7116,16 +7087,6 @@ wrapped menu bar lines when sending frame resize requests to the Windows API. */); w32_add_wrapped_menu_bar_lines = 1; - DEFVAR_BOOL ("w32-enable-frame-resize-hack", - w32_enable_frame_resize_hack, - doc: /* Non-nil means enable hack for frame resizing on Windows. -A value of nil means to resize frames by sending a corresponding request -to the Windows API and changing the pixel sizes of the frame and its -windows after the latter calls back. If this is non-nil, Emacs changes -the pixel sizes of the frame and its windows at the time it sends the -resize request to the API. */); - w32_enable_frame_resize_hack = 1; - /* Tell Emacs about this window system. */ Fprovide (Qw32, Qnil); } diff --git a/src/widget.c b/src/widget.c index c4d6940..acf559f 100644 --- a/src/widget.c +++ b/src/widget.c @@ -460,7 +460,7 @@ update_wm_hints (EmacsFrame ew) base_width = (wmshell->core.width - ew->core.width + (rounded_width - (char_width * cw))); base_height = (wmshell->core.height - ew->core.height - + (rounded_height - (char_height * ch))); + + (rounded_height - (char_height * ch))); /* This is kind of sleazy, but I can't see how else to tell it to make it mark the WM_SIZE_HINTS size as user specified. @@ -573,39 +573,20 @@ EmacsFrameResize (Widget widget) { EmacsFrame ew = (EmacsFrame)widget; struct frame *f = ew->emacs_frame.frame; + int width, height; - /* Always process resize requests pixelwise. Frame maximizing - should work even when frame_resize_pixelwise is nil. */ - if (true || frame_resize_pixelwise) - { - int width, height; - - pixel_to_text_size (ew, ew->core.width, ew->core.height, &width, &height); - change_frame_size (f, width, height, 0, 1, 0, 1); + pixel_to_text_size (ew, ew->core.width, ew->core.height, &width, &height); - update_wm_hints (ew); - update_various_frame_slots (ew); + frame_size_history_add + (f, QEmacsFrameResize, width, height, + list2 (make_number (ew->core.width), make_number (ew->core.height))); - cancel_mouse_face (f); - } - else - { - struct x_output *x = f->output_data.x; - int columns, rows; + change_frame_size (f, width, height, 0, 1, 0, 1); - pixel_to_char_size (ew, ew->core.width, ew->core.height, &columns, &rows); - if (columns != FRAME_COLS (f) - || rows != FRAME_LINES (f) - || ew->core.width != FRAME_PIXEL_WIDTH (f) - || ew->core.height + x->menubar_height != FRAME_PIXEL_HEIGHT (f)) - { - change_frame_size (f, columns, rows, 0, 1, 0, 0); - update_wm_hints (ew); - update_various_frame_slots (ew); + update_wm_hints (ew); + update_various_frame_slots (ew); - cancel_mouse_face (f); - } - } + cancel_mouse_face (f); } static XtGeometryResult diff --git a/src/window.c b/src/window.c index 2f44bf7..2931400 100644 --- a/src/window.c +++ b/src/window.c @@ -3329,7 +3329,7 @@ run_window_configuration_change_hook (struct frame *f) if (NILP (Vrun_hooks) || !(f->can_x_set_window_size) - || !(f->can_run_window_configuration_change_hook)) + || !(f->after_make_frame)) return; /* Use the right buffer. Matters when running the local hooks. */ diff --git a/src/xfns.c b/src/xfns.c index 65eb6b4..e667e71 100644 --- a/src/xfns.c +++ b/src/xfns.c @@ -1095,6 +1095,7 @@ x_change_tool_bar_height (struct frame *f, int height) int unit = FRAME_LINE_HEIGHT (f); int old_height = FRAME_TOOL_BAR_HEIGHT (f); int lines = (height + unit - 1) / unit; + Lisp_Object fullscreen; /* Make sure we redisplay all windows in this frame. */ windows_or_buffers_changed = 60; @@ -1126,7 +1127,10 @@ x_change_tool_bar_height (struct frame *f, int height) f->n_tool_bar_rows = 0; adjust_frame_size (f, -1, -1, - (!f->tool_bar_redisplayed_once ? 1 + ((!f->tool_bar_redisplayed_once + && (NILP (fullscreen = + get_frame_param (f, Qfullscreen)) + || EQ (fullscreen, Qfullwidth))) ? 1 : (old_height == 0 || height == 0) ? 2 : 4), false, Qtool_bar_lines); @@ -3180,9 +3184,7 @@ This function is an internal primitive--use `make-frame' instead. */) "title", "Title", RES_TYPE_STRING); x_default_parameter (f, parms, Qwait_for_wm, Qt, "waitForWM", "WaitForWM", RES_TYPE_BOOLEAN); - x_default_parameter (f, parms, Qfullscreen, Qnil, - "fullscreen", "Fullscreen", RES_TYPE_SYMBOL); - x_default_parameter (f, parms, Qtool_bar_position, + x_default_parameter (f, parms, Qtool_bar_position, FRAME_TOOL_BAR_POSITION (f), 0, 0, RES_TYPE_SYMBOL); /* Compute the size of the X window. */ @@ -3259,6 +3261,12 @@ This function is an internal primitive--use `make-frame' instead. */) x_wm_set_size_hint (f, window_prompting, false); unblock_input (); + /* Process fullscreen parameter here in the hope that normalizing a + fullheight/fullwidth frame will produce the size set by the last + adjust_frame_size call. */ + x_default_parameter (f, parms, Qfullscreen, Qnil, + "fullscreen", "Fullscreen", RES_TYPE_SYMBOL); + /* Make the window appear on the frame and enable display, unless the caller says not to. However, with explicit parent, Emacs cannot control visibility, so don't try. */ @@ -4318,7 +4326,7 @@ elements (all size values are in pixels). inner_height -= tool_bar_height; return - listn (CONSTYPE_PURE, 10, + listn (CONSTYPE_HEAP, 10, Fcons (Qframe_position, Fcons (make_number (f->left_pos), make_number (f->top_pos))), Fcons (Qframe_outer_size, diff --git a/src/xterm.c b/src/xterm.c index 3955d02..6a63a45 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -212,7 +212,7 @@ enum xembed_message }; static bool x_alloc_nearest_color_1 (Display *, Colormap, XColor *); -static void x_set_window_size_1 (struct frame *, bool, int, int, bool); +static void x_set_window_size_1 (struct frame *, bool, int, int); static void x_raise_frame (struct frame *); static void x_lower_frame (struct frame *); static const XColor *x_color_cells (Display *, int *); @@ -6575,6 +6575,10 @@ x_net_wm_state (struct frame *f, Window window) break; } + frame_size_history_add + (f, Qx_net_wm_state, 0, 0, + list2 (get_frame_param (f, Qfullscreen), lval)); + store_frame_param (f, Qfullscreen, lval); /** store_frame_param (f, Qsticky, sticky ? Qt : Qnil); **/ } @@ -9227,30 +9231,78 @@ do_ewmh_fullscreen (struct frame *f) None); break; case FULLSCREEN_WIDTH: - if (cur == FULLSCREEN_BOTH || cur == FULLSCREEN_HEIGHT - || cur == FULLSCREEN_MAXIMIZED) - set_wm_state (frame, false, dpyinfo->Xatom_net_wm_state_fullscreen, - dpyinfo->Xatom_net_wm_state_maximized_vert); - if (cur != FULLSCREEN_MAXIMIZED) - set_wm_state (frame, true, - dpyinfo->Xatom_net_wm_state_maximized_horz, None); + if (x_frame_normalize_before_maximize && cur == FULLSCREEN_MAXIMIZED) + { + set_wm_state (frame, false, + dpyinfo->Xatom_net_wm_state_maximized_horz, + dpyinfo->Xatom_net_wm_state_maximized_vert); + set_wm_state (frame, true, + dpyinfo->Xatom_net_wm_state_maximized_horz, None); + } + else + { + if (cur == FULLSCREEN_BOTH || cur == FULLSCREEN_HEIGHT + || cur == FULLSCREEN_MAXIMIZED) + set_wm_state (frame, false, dpyinfo->Xatom_net_wm_state_fullscreen, + dpyinfo->Xatom_net_wm_state_maximized_vert); + if (cur != FULLSCREEN_MAXIMIZED || x_frame_normalize_before_maximize) + set_wm_state (frame, true, + dpyinfo->Xatom_net_wm_state_maximized_horz, None); + } break; case FULLSCREEN_HEIGHT: - if (cur == FULLSCREEN_BOTH || cur == FULLSCREEN_WIDTH - || cur == FULLSCREEN_MAXIMIZED) - set_wm_state (frame, false, dpyinfo->Xatom_net_wm_state_fullscreen, - dpyinfo->Xatom_net_wm_state_maximized_horz); - if (cur != FULLSCREEN_MAXIMIZED) - set_wm_state (frame, true, - dpyinfo->Xatom_net_wm_state_maximized_vert, None); + if (x_frame_normalize_before_maximize && cur == FULLSCREEN_MAXIMIZED) + { + set_wm_state (frame, false, + dpyinfo->Xatom_net_wm_state_maximized_horz, + dpyinfo->Xatom_net_wm_state_maximized_vert); + set_wm_state (frame, true, + dpyinfo->Xatom_net_wm_state_maximized_vert, None); + } + else + { + if (cur == FULLSCREEN_BOTH || cur == FULLSCREEN_WIDTH + || cur == FULLSCREEN_MAXIMIZED) + set_wm_state (frame, false, dpyinfo->Xatom_net_wm_state_fullscreen, + dpyinfo->Xatom_net_wm_state_maximized_horz); + if (cur != FULLSCREEN_MAXIMIZED || x_frame_normalize_before_maximize) + set_wm_state (frame, true, + dpyinfo->Xatom_net_wm_state_maximized_vert, None); + } break; case FULLSCREEN_MAXIMIZED: - if (cur == FULLSCREEN_BOTH) - set_wm_state (frame, false, dpyinfo->Xatom_net_wm_state_fullscreen, - None); - set_wm_state (frame, true, - dpyinfo->Xatom_net_wm_state_maximized_horz, - dpyinfo->Xatom_net_wm_state_maximized_vert); + if (x_frame_normalize_before_maximize && cur == FULLSCREEN_WIDTH) + { + set_wm_state (frame, false, + dpyinfo->Xatom_net_wm_state_maximized_horz, None); + set_wm_state (frame, true, + dpyinfo->Xatom_net_wm_state_maximized_horz, + dpyinfo->Xatom_net_wm_state_maximized_vert); + } + else if (x_frame_normalize_before_maximize && cur == FULLSCREEN_HEIGHT) + { + set_wm_state (frame, false, + dpyinfo->Xatom_net_wm_state_maximized_vert, None); + set_wm_state (frame, true, + dpyinfo->Xatom_net_wm_state_maximized_horz, + dpyinfo->Xatom_net_wm_state_maximized_vert); + } + else + { + if (cur == FULLSCREEN_BOTH) + set_wm_state (frame, false, dpyinfo->Xatom_net_wm_state_fullscreen, + None); + else if (cur == FULLSCREEN_HEIGHT) + set_wm_state (frame, true, + dpyinfo->Xatom_net_wm_state_maximized_horz, None); + else if (cur == FULLSCREEN_WIDTH) + set_wm_state (frame, true, None, + dpyinfo->Xatom_net_wm_state_maximized_vert); + else + set_wm_state (frame, true, + dpyinfo->Xatom_net_wm_state_maximized_horz, + dpyinfo->Xatom_net_wm_state_maximized_vert); + } break; case FULLSCREEN_NONE: if (cur == FULLSCREEN_BOTH) @@ -9307,6 +9359,10 @@ x_handle_net_wm_state (struct frame *f, const XPropertyEvent *event) break; } + frame_size_history_add + (f, Qx_handle_net_wm_state, 0, 0, + list2 (get_frame_param (f, Qfullscreen), lval)); + store_frame_param (f, Qfullscreen, lval); store_frame_param (f, Qsticky, sticky ? Qt : Qnil); @@ -9343,13 +9399,26 @@ x_check_fullscreen (struct frame *f) break; case FULLSCREEN_WIDTH: width = x_display_pixel_width (dpyinfo); - break; + height = height + FRAME_MENUBAR_HEIGHT (f); + break; case FULLSCREEN_HEIGHT: height = x_display_pixel_height (dpyinfo); } + frame_size_history_add + (f, Qx_check_fullscreen, width, height, Qnil); + XResizeWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f), - width, height); + width, height); + + if (FRAME_VISIBLE_P (f)) + x_wait_for_event (f, ConfigureNotify); + else + { + change_frame_size (f, width, height - FRAME_MENUBAR_HEIGHT (f), + false, true, false, true); + x_sync (f); + } } } @@ -9490,21 +9559,57 @@ x_wait_for_event (struct frame *f, int eventtype) static void x_set_window_size_1 (struct frame *f, bool change_gravity, - int width, int height, bool pixelwise) + int width, int height) { - int pixelwidth, pixelheight; - - pixelwidth = (pixelwise - ? FRAME_TEXT_TO_PIXEL_WIDTH (f, width) - : FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, width)); - pixelheight = ((pixelwise - ? FRAME_TEXT_TO_PIXEL_HEIGHT (f, height) - : FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, height))); + int pixelwidth = FRAME_TEXT_TO_PIXEL_WIDTH (f, width); + int pixelheight = FRAME_TEXT_TO_PIXEL_HEIGHT (f, height); + int old_width = FRAME_PIXEL_WIDTH (f); + int old_height = FRAME_PIXEL_HEIGHT (f); + Lisp_Object fullscreen = get_frame_param (f, Qfullscreen); if (change_gravity) f->win_gravity = NorthWestGravity; x_wm_set_size_hint (f, 0, false); - XResizeWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f), - pixelwidth, pixelheight + FRAME_MENUBAR_HEIGHT (f)); + + /* When the frame is fullheight and we only want to change the width + or it is fullwidth and we only want to change the height we should + be able to preserve the fullscreen property. However, due to the + fact that we have to send a resize request anyway, the window + manager will abolish it. At least the respective size should + remain unchanged but giving the frame back its normal size will + be broken ... */ + if (EQ (fullscreen, Qfullwidth) && width == FRAME_TEXT_WIDTH (f)) + { + frame_size_history_add + (f, Qxg_frame_set_char_size_1, width, height, + list2 (make_number (old_height), + make_number (pixelheight + FRAME_MENUBAR_HEIGHT (f)))); + + XResizeWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f), + old_width, pixelheight + FRAME_MENUBAR_HEIGHT (f)); + } + else if (EQ (fullscreen, Qfullheight) && height == FRAME_TEXT_HEIGHT (f)) + { + frame_size_history_add + (f, Qxg_frame_set_char_size_2, width, height, + list2 (make_number (old_width), make_number (pixelwidth))); + + XResizeWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f), + pixelwidth, old_height); + } + + else + { + frame_size_history_add + (f, Qxg_frame_set_char_size_3, width, height, + list2 (make_number (pixelwidth + FRAME_TOOLBAR_WIDTH (f)), + make_number (pixelheight + FRAME_TOOLBAR_HEIGHT (f) + + FRAME_MENUBAR_HEIGHT (f)))); + + XResizeWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f), + pixelwidth, pixelheight + FRAME_MENUBAR_HEIGHT (f)); + fullscreen = Qnil; + } + /* We've set {FRAME,PIXEL}_{WIDTH,HEIGHT} to the values we hope to @@ -9531,7 +9636,16 @@ x_set_window_size_1 (struct frame *f, bool change_gravity, not right if the frame is visible. Instead wait (with timeout) for the ConfigureNotify. */ if (FRAME_VISIBLE_P (f)) - x_wait_for_event (f, ConfigureNotify); + { + x_wait_for_event (f, ConfigureNotify); + + if (!NILP (fullscreen)) + /* Try to restore fullscreen state. */ + { + store_frame_param (f, Qfullscreen, fullscreen); + x_set_fullscreen (f, fullscreen, fullscreen); + } + } else { change_frame_size (f, width, height, false, true, false, true); @@ -9578,20 +9692,21 @@ x_set_window_size (struct frame *f, bool change_gravity, } #endif + /* Pixelize width and height, if necessary. */ + if (! pixelwise) + { + width = width * FRAME_COLUMN_WIDTH (f); + height = height * FRAME_LINE_HEIGHT (f); + } + #ifdef USE_GTK if (FRAME_GTK_WIDGET (f)) - if (! pixelwise) - xg_frame_set_char_size (f, width * FRAME_COLUMN_WIDTH (f), - height * FRAME_LINE_HEIGHT (f)); - else - xg_frame_set_char_size (f, width, height); + xg_frame_set_char_size (f, width, height); else - x_set_window_size_1 (f, change_gravity, width, height, pixelwise); + x_set_window_size_1 (f, change_gravity, width, height); #else /* not USE_GTK */ - - x_set_window_size_1 (f, change_gravity, width, height, pixelwise); + x_set_window_size_1 (f, change_gravity, width, height); x_clear_under_internal_border (f); - #endif /* not USE_GTK */ /* If cursor was outside the new size, mark it as off. */ @@ -11602,4 +11717,15 @@ default is nil, which is the same as `super'. */); make_float (DEFAULT_REHASH_SIZE), make_float (DEFAULT_REHASH_THRESHOLD), Qnil); + + DEFVAR_BOOL ("x-frame-normalize-before-maximize", + x_frame_normalize_before_maximize, + doc: /* Non-nil means normalize frame before maximizing. +If this variable is t, Emacs asks the window manager to give the frame +intermediately its normal size whenever changing from a full-height or +full-width state to the fully maximized one and vice versa. + +Set this variable only if your window manager cannot handle the +transition between the various maximization states. */); + x_frame_normalize_before_maximize = false; }