X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/cbd447e1cdbbebcd2a04144194138bb7936dea9d..1650d7102ae8ea943e4197b7d91198640f0e0ff6:/lisp/frame.el diff --git a/lisp/frame.el b/lisp/frame.el index 0096ef9696..09738d1e2e 100644 --- a/lisp/frame.el +++ b/lisp/frame.el @@ -1,6 +1,6 @@ ;;; frame.el --- multi-frame management independent of window systems -*- lexical-binding:t -*- -;; Copyright (C) 1993-1994, 1996-1997, 2000-2015 Free Software +;; Copyright (C) 1993-1994, 1996-1997, 2000-2016 Free Software ;; Foundation, Inc. ;; Maintainer: emacs-devel@gnu.org @@ -27,35 +27,24 @@ ;;; Code: (eval-when-compile (require 'cl-lib)) -;; Dispatch tables for GUI methods. - -(defun gui-method--name (base) - (intern (format "%s-alist" base))) - -(defmacro gui-method (name &optional type) - (macroexp-let2 nil type (or type `window-system) - `(alist-get ,type ,(gui-method--name name) - (lambda (&rest _args) - (error "No method %S for %S frame" ',name ,type))))) - -(defmacro gui-method-define (name type fun) - `(setf (gui-method ,name ',type) ,fun)) - -(defmacro gui-method-declare (name &optional tty-fun doc) - (declare (doc-string 3) (indent 2)) - `(defvar ,(gui-method--name name) - ,(if tty-fun `(list (cons nil ,tty-fun))) ,doc)) - -(defmacro gui-call (name &rest args) - `(funcall (gui-method ,name) ,@args)) - -(gui-method-declare frame-creation-function - #'tty-create-frame-with-faces +(cl-defgeneric frame-creation-function (params) "Method for window-system dependent functions to create a new frame. The window system startup file should add its frame creation function to this method, which should take an alist of parameters as its argument.") +(cl-generic-define-context-rewriter window-system (value) + ;; If `value' is a `consp', it's probably an old-style specializer, + ;; so just use it, and anyway `eql' isn't very useful on cons cells. + `(window-system ,(if (consp value) value `(eql ,value)))) + +(cl-defmethod frame-creation-function (params &context (window-system nil)) + ;; It's tempting to get rid of tty-create-frame-with-faces and turn it into + ;; this method (i.e. move this method to faces.el), but faces.el is loaded + ;; much earlier from loadup.el (before cl-generic and even before + ;; cl-preloaded), so we'd first have to reorder that part. + (tty-create-frame-with-faces params)) + (defvar window-system-default-frame-alist nil "Window-system dependent default frame parameters. The value should be an alist of elements (WINDOW-SYSTEM . ALIST), @@ -79,7 +68,7 @@ handles the corresponding kind of display.") You can set this in your init file; for example, (setq initial-frame-alist - '((top . 1) (left . 1) (width . 80) (height . 55))) + \\='((top . 1) (left . 1) (width . 80) (height . 55))) Parameters specified here supersede the values given in `default-frame-alist'. @@ -114,7 +103,7 @@ initial minibuffer frame. You can set this in your init file; for example, (setq minibuffer-frame-alist - '((top . 1) (left . 1) (width . 80) (height . 2))) + \\='((top . 1) (left . 1) (width . 80) (height . 2))) It is not necessary to include (minibuffer . only); that is appended when the minibuffer frame is created." @@ -217,6 +206,7 @@ This function runs the hook `focus-out-hook'." "Non-nil means function `frame-notice-user-settings' wasn't run yet.") (declare-function tool-bar-mode "tool-bar" (&optional arg)) +(declare-function tool-bar-height "xdisp.c" (&optional frame pixelwise)) (defalias 'tool-bar-lines-needed 'tool-bar-height) @@ -259,6 +249,10 @@ there (in decreasing order of priority)." (let ((newparms (frame-parameters)) (frame (selected-frame))) (tty-handle-reverse-video frame newparms) + ;; tty-handle-reverse-video might change the frame's + ;; color parameters, and we need to use the updated + ;; value below. + (setq newparms (frame-parameters)) ;; If we changed the background color, we need to update ;; the background-mode parameter, and maybe some faces, ;; too. @@ -266,7 +260,7 @@ there (in decreasing order of priority)." (unless (or (assq 'background-mode initial-frame-alist) (assq 'background-mode default-frame-alist)) (frame-set-background-mode frame)) - (face-set-after-frame-default frame)))))) + (face-set-after-frame-default frame newparms)))))) ;; If the initial frame is still around, apply initial-frame-alist ;; and default-frame-alist to it. @@ -471,7 +465,7 @@ there (in decreasing order of priority)." (cons (1- (car frame-size-history)) (cons (list frame-initial-frame - "frame-notice-user-settings" + "FRAME-NOTICE-USER" nil newparms) (cdr frame-size-history))))) @@ -546,7 +540,8 @@ is not considered (see `next-frame')." Return nil if we don't know how to interpret DISPLAY." ;; MS-Windows doesn't know how to create a GUI frame in a -nw session. (if (and (eq system-type 'windows-nt) - (null (window-system))) + (null (window-system)) + (not (daemonp))) nil (cl-loop for descriptor in display-format-alist for pattern = (car descriptor) @@ -681,7 +676,8 @@ the new frame according to its own rules." frame) (unless (get w 'window-system-initialized) - (funcall (gui-method window-system-initialization w) display) + (let ((window-system w)) ;Hack attack! + (window-system-initialization display)) (setq x-display-name display) (put w 'window-system-initialized t)) @@ -698,8 +694,8 @@ the new frame according to its own rules." ;; (setq frame-size-history '(1000)) - (setq frame - (funcall (gui-method frame-creation-function w) params)) + (setq frame (let ((window-system w)) ;Hack attack! + (frame-creation-function params))) (normal-erase-is-backspace-setup-frame frame) ;; Inherit the original frame's parameters. (dolist (param frame-inherited-parameters) @@ -710,7 +706,7 @@ the new frame according to its own rules." (when (numberp (car frame-size-history)) (setq frame-size-history (cons (1- (car frame-size-history)) - (cons (list frame "make-frame") + (cons (list frame "MAKE-FRAME") (cdr frame-size-history))))) ;; We can run `window-configuration-change-hook' for this frame now. @@ -915,7 +911,7 @@ if you want Emacs to examine the brightness for you. If you change this without using customize, you should use `frame-set-background-mode' to update existing frames; -e.g. (mapc 'frame-set-background-mode (frame-list))." +e.g. (mapc \\='frame-set-background-mode (frame-list))." :group 'faces :set #'(lambda (var value) (set-default var value) @@ -1200,7 +1196,15 @@ To get the frame's current background color, use `frame-parameters'." (modify-frame-parameters (selected-frame) (list (cons 'background-color color-name))) (or window-system - (face-set-after-frame-default (selected-frame)))) + (face-set-after-frame-default (selected-frame) + (list + (cons 'background-color color-name) + ;; Pass the foreground-color as + ;; well, if defined, to avoid + ;; losing it when faces are reset + ;; to their defaults. + (assq 'foreground-color + (frame-parameters)))))) (defun set-foreground-color (color-name) "Set the foreground color of the selected frame to COLOR-NAME. @@ -1210,7 +1214,15 @@ To get the frame's current foreground color, use `frame-parameters'." (modify-frame-parameters (selected-frame) (list (cons 'foreground-color color-name))) (or window-system - (face-set-after-frame-default (selected-frame)))) + (face-set-after-frame-default (selected-frame) + (list + (cons 'foreground-color color-name) + ;; Pass the background-color as + ;; well, if defined, to avoid + ;; losing it when faces are reset + ;; to their defaults. + (assq 'background-color + (frame-parameters)))))) (defun set-cursor-color (color-name) "Set the text cursor color of the selected frame to COLOR-NAME. @@ -1304,6 +1316,157 @@ live frame and defaults to the selected one." (setq vertical default-frame-scroll-bars)) (cons vertical (and horizontal 'bottom)))) +(declare-function x-frame-geometry "xfns.c" (&optional frame)) +(declare-function w32-frame-geometry "w32fns.c" (&optional frame)) +(declare-function ns-frame-geometry "nsfns.m" (&optional frame)) + +(defun frame-geometry (&optional frame) + "Return geometric attributes of FRAME. +FRAME must be a live frame and defaults to the selected one. The return +value is an association list of the attributes listed below. All height +and width values are in pixels. + +`outer-position' is a cons of the outer left and top edges of FRAME + relative to the origin - the position (0, 0) - of FRAME's display. + +`outer-size' is a cons of the outer width and height of FRAME. The + outer size includes the title bar and the external borders as well as + any menu and/or tool bar of frame. + +`external-border-size' is a cons of the horizontal and vertical width of + FRAME's external borders as supplied by the window manager. + +`title-bar-size' is a cons of the width and height of the title bar of + FRAME as supplied by the window manager. If both of them are zero, + FRAME has no title bar. If only the width is zero, Emacs was not + able to retrieve the width information. + +`menu-bar-external', if non-nil, means the menu bar is external (never + included in the inner edges of FRAME). + +`menu-bar-size' is a cons of the width and height of the menu bar of + FRAME. + +`tool-bar-external', if non-nil, means the tool bar is external (never + included in the inner edges of FRAME). + +`tool-bar-position' tells on which side the tool bar on FRAME is and can + be one of `left', `top', `right' or `bottom'. If this is nil, FRAME + has no tool bar. + +`tool-bar-size' is a cons of the width and height of the tool bar of + FRAME. + +`internal-border-width' is the width of the internal border of + FRAME." + (let* ((frame (window-normalize-frame frame)) + (frame-type (framep-on-display frame))) + (cond + ((eq frame-type 'x) + (x-frame-geometry frame)) + ((eq frame-type 'w32) + (w32-frame-geometry frame)) + ((eq frame-type 'ns) + (ns-frame-geometry frame)) + (t + (list + '(outer-position 0 . 0) + (cons 'outer-size (cons (frame-width frame) (frame-height frame))) + '(external-border-size 0 . 0) + '(title-bar-size 0 . 0) + '(menu-bar-external . nil) + (let ((menu-bar-lines (frame-parameter frame 'menu-bar-lines))) + (cons 'menu-bar-size + (if menu-bar-lines + (cons (frame-width frame) 1) + 1 0))) + '(tool-bar-external . nil) + '(tool-bar-position . nil) + '(tool-bar-size 0 . 0) + (cons 'internal-border-width + (frame-parameter frame 'internal-border-width))))))) + +(defun frame--size-history (&optional frame) + "Print history of resize operations for FRAME. +Print prettified version of `frame-size-history' into a buffer +called *frame-size-history*. Optional argument FRAME denotes the +frame whose history will be printed. FRAME defaults to the +selected frame." + (let ((history (reverse frame-size-history)) + entry) + (setq frame (window-normalize-frame frame)) + (with-current-buffer (get-buffer-create "*frame-size-history*") + (erase-buffer) + (insert (format "Frame size history of %s\n" frame)) + (while (listp (setq entry (pop history))) + (when (eq (car entry) frame) + (pop entry) + (insert (format "%s" (pop entry))) + (move-to-column 24 t) + (while entry + (insert (format " %s" (pop entry)))) + (insert "\n")))))) + +(declare-function x-frame-edges "xfns.c" (&optional frame type)) +(declare-function w32-frame-edges "w32fns.c" (&optional frame type)) +(declare-function ns-frame-edges "nsfns.m" (&optional frame type)) + +(defun frame-edges (&optional frame type) + "Return coordinates of FRAME's edges. +FRAME must be a live frame and defaults to the selected one. The +list returned has the form (LEFT TOP RIGHT BOTTOM) where all +values are in pixels relative to the origin - the position (0, 0) +- of FRAME's display. For terminal frames all values are +relative to LEFT and TOP which are both zero. + +Optional argument TYPE specifies the type of the edges. TYPE +`outer-edges' means to return the outer edges of FRAME. TYPE +`native-edges' (or nil) means to return the native edges of +FRAME. TYPE `inner-edges' means to return the inner edges of +FRAME." + (let* ((frame (window-normalize-frame frame)) + (frame-type (framep-on-display frame))) + (cond + ((eq frame-type 'x) + (x-frame-edges frame type)) + ((eq frame-type 'w32) + (w32-frame-edges frame type)) + ((eq frame-type 'ns) + (ns-frame-edges frame type)) + (t + (list 0 0 (frame-width frame) (frame-height frame)))))) + +(declare-function w32-mouse-absolute-pixel-position "w32fns.c") +(declare-function x-mouse-absolute-pixel-position "xfns.c") + +(defun mouse-absolute-pixel-position () + "Return absolute position of mouse cursor in pixels. +The position is returned as a cons cell (X . Y) of the +coordinates of the mouse cursor position in pixels relative to a +position (0, 0) of the selected frame's terminal." + (let ((frame-type (framep-on-display))) + (cond + ((eq frame-type 'x) + (x-mouse-absolute-pixel-position)) + ((eq frame-type 'w32) + (w32-mouse-absolute-pixel-position)) + (t + (cons 0 0))))) + +(declare-function w32-set-mouse-absolute-pixel-position "w32fns.c" (x y)) +(declare-function x-set-mouse-absolute-pixel-position "xfns.c" (x y)) + +(defun set-mouse-absolute-pixel-position (x y) + "Move mouse pointer to absolute pixel position (X, Y). +The coordinates X and Y are interpreted in pixels relative to a +position (0, 0) of the selected frame's terminal." + (let ((frame-type (framep-on-display))) + (cond + ((eq frame-type 'x) + (x-set-mouse-absolute-pixel-position x y)) + ((eq frame-type 'w32) + (w32-set-mouse-absolute-pixel-position x y))))) + (defun frame-monitor-attributes (&optional frame) "Return the attributes of the physical monitor dominating FRAME. If FRAME is omitted or nil, describe the currently selected frame. @@ -1741,6 +1904,122 @@ left untouched. FRAME nil or omitted means use the selected frame." 'delete-frame-functions "22.1") +;;; Window dividers. +(defgroup window-divider nil + "Window dividers." + :version "25.1" + :group 'frames + :group 'windows) + +(defcustom window-divider-default-places 'right-only + "Default positions of window dividers. +Possible values are `bottom-only' (dividers on the bottom of each +window only), `right-only' (dividers on the right of each window +only), and t (dividers on the bottom and on the right of each +window). The default is `right-only'. + +The value takes effect if and only if dividers are enabled by +`window-divider-mode'. + +To position dividers on frames individually, use the frame +parameters `bottom-divider-width' and `right-divider-width'." + :type '(choice (const :tag "Bottom only" bottom-only) + (const :tag "Right only" right-only) + (const :tag "Bottom and right" t)) + :initialize 'custom-initialize-default + :set (lambda (symbol value) + (set-default symbol value) + (when window-divider-mode + (window-divider-mode-apply t))) + :version "25.1") + +(defun window-divider-width-valid-p (value) + "Return non-nil if VALUE is a positive number." + (and (numberp value) (> value 0))) + +(defcustom window-divider-default-bottom-width 6 + "Default width of dividers on bottom of windows. +The value must be a positive integer and takes effect when bottom +dividers are displayed by `window-divider-mode'. + +To adjust bottom dividers for frames individually, use the frame +parameter `bottom-divider-width'." + :type '(restricted-sexp + :tag "Default width of bottom dividers" + :match-alternatives (frame-window-divider-width-valid-p)) + :initialize 'custom-initialize-default + :set (lambda (symbol value) + (set-default symbol value) + (when window-divider-mode + (window-divider-mode-apply t))) + :version "25.1") + +(defcustom window-divider-default-right-width 6 + "Default width of dividers on the right of windows. +The value must be a positive integer and takes effect when right +dividers are displayed by `window-divider-mode'. + +To adjust right dividers for frames individually, use the frame +parameter `right-divider-width'." + :type '(restricted-sexp + :tag "Default width of right dividers" + :match-alternatives (frame-window-divider-width-valid-p)) + :initialize 'custom-initialize-default + :set (lambda (symbol value) + (set-default symbol value) + (when window-divider-mode + (window-divider-mode-apply t))) + :version "25.1") + +(defun window-divider-mode-apply (enable) + "Apply window divider places and widths to all frames. +If ENABLE is nil, apply default places and widths. Else reset +all divider widths to zero." + (let ((bottom (if (and enable + (memq window-divider-default-places + '(bottom-only t))) + window-divider-default-bottom-width + 0)) + (right (if (and enable + (memq window-divider-default-places + '(right-only t))) + window-divider-default-right-width + 0))) + (modify-all-frames-parameters + (list (cons 'bottom-divider-width bottom) + (cons 'right-divider-width right))) + (setq default-frame-alist + (assq-delete-all + 'bottom-divider-width default-frame-alist)) + (setq default-frame-alist + (assq-delete-all + 'right-divider-width default-frame-alist)) + (when (> bottom 0) + (setq default-frame-alist + (cons + (cons 'bottom-divider-width bottom) + default-frame-alist))) + (when (> right 0) + (setq default-frame-alist + (cons + (cons 'right-divider-width right) + default-frame-alist))))) + +(define-minor-mode window-divider-mode + "Display dividers between windows (Window Divider mode). +With a prefix argument ARG, enable Window Divider mode if ARG is +positive, and disable it otherwise. If called from Lisp, enable +the mode if ARG is omitted or nil. + +The option `window-divider-default-places' specifies on which +side of a window dividers are displayed. The options +`window-divider-default-bottom-width' and +`window-divider-default-right-width' specify their respective +widths." + :group 'window-divider + :global t + (window-divider-mode-apply window-divider-mode)) + ;; Blinking cursor (defgroup cursor nil @@ -1795,8 +2074,12 @@ command starts, by installing a pre-command hook." (defun blink-cursor-timer-function () "Timer function of timer `blink-cursor-timer'." (internal-show-cursor nil (not (internal-show-cursor-p))) + ;; Suspend counting blinks when the w32 menu-bar menu is displayed, + ;; since otherwise menu tooltips will behave erratically. + (or (and (fboundp 'w32--menu-bar-in-use) + (w32--menu-bar-in-use)) + (setq blink-cursor-blinks-done (1+ blink-cursor-blinks-done))) ;; Each blink is two calls to this function. - (setq blink-cursor-blinks-done (1+ blink-cursor-blinks-done)) (when (and (> blink-cursor-blinks 0) (<= (* 2 blink-cursor-blinks) blink-cursor-blinks-done)) (blink-cursor-suspend) @@ -1948,6 +2231,18 @@ See also `toggle-frame-maximized'." (make-obsolete-variable 'window-system-version "it does not give useful information." "24.3") +;; Variables which should trigger redisplay of the current buffer. +(setq redisplay--variables (make-hash-table :test 'eq :size 10)) +(mapc (lambda (var) + (puthash var 1 redisplay--variables)) + '(line-spacing + overline-margin + line-prefix + wrap-prefix + truncate-lines + bidi-paragraph-direction + bidi-display-reordering)) + (provide 'frame) ;;; frame.el ends here