summaryrefslogtreecommitdiff
path: root/lisp/frame.el
diff options
context:
space:
mode:
Diffstat (limited to 'lisp/frame.el')
-rw-r--r--lisp/frame.el269
1 files changed, 237 insertions, 32 deletions
diff --git a/lisp/frame.el b/lisp/frame.el
index 69119b4c24f..27f99fb7d21 100644
--- a/lisp/frame.el
+++ b/lisp/frame.el
@@ -702,7 +702,9 @@ Return nil if we don't know how to interpret DISPLAY."
The optional argument PARAMETERS specifies additional frame parameters."
(interactive (if (fboundp 'x-display-list)
(list (completing-read "Make frame on display: "
- (x-display-list)))
+ (x-display-list) nil
+ nil (car (x-display-list))
+ nil (car (x-display-list))))
(user-error "This Emacs build does not support X displays")))
(make-frame (cons (cons 'display display) parameters)))
@@ -799,7 +801,7 @@ also select the new frame."
(window-state-get (frame-root-window frame))))
(default-frame-alist
(seq-remove (lambda (elem)
- (memq (car elem) '(name parent-id)))
+ (memq (car elem) frame-internal-parameters))
(frame-parameters frame)))
(new-frame (make-frame)))
(when windows
@@ -809,12 +811,16 @@ also select the new frame."
new-frame))
(defvar before-make-frame-hook nil
- "Functions to run before `make-frame' creates a new frame.")
+ "Functions to run before `make-frame' creates a new frame.
+Note that these functions are usually not run for the initial
+frame, unless you add them to the hook in your early-init file.")
(defvar after-make-frame-functions nil
"Functions to run after `make-frame' created a new frame.
The functions are run with one argument, the newly created
-frame.")
+frame.
+Note that these functions are usually not run for the initial
+frame, unless you add them to the hook in your early-init file.")
(defvar after-setting-font-hook nil
"Functions to run after a frame's font has been changed.")
@@ -879,7 +885,6 @@ the new frame according to its own rules."
(error "Don't know how to interpret display %S"
display)))
(t window-system)))
- (oldframe (selected-frame))
(params parameters)
frame child-frame)
@@ -897,8 +902,12 @@ the new frame according to its own rules."
(dolist (p default-frame-alist)
(unless (assq (car p) params)
(push p params)))
-
-;; (setq frame-size-history '(1000))
+ ;; Add parameters from `frame-inherited-parameters' unless they are
+ ;; overridden by explicit parameters.
+ (dolist (param frame-inherited-parameters)
+ (unless (assq param parameters)
+ (let ((val (frame-parameter nil param)))
+ (when val (push (cons param val) params)))))
(when (eq (cdr (or (assq 'minibuffer params) '(minibuffer . t)))
'child-frame)
@@ -931,12 +940,6 @@ the new frame according to its own rules."
frame 'minibuffer (frame-root-window child-frame))))
(normal-erase-is-backspace-setup-frame frame)
- ;; Inherit original frame's parameters unless they are overridden
- ;; by explicit parameters.
- (dolist (param frame-inherited-parameters)
- (unless (assq param parameters)
- (let ((val (frame-parameter oldframe param)))
- (when val (set-frame-parameter frame param val)))))
;; We can run `window-configuration-change-hook' for this frame now.
(frame-after-make-frame frame t)
@@ -1586,6 +1589,11 @@ acquires focus to be automatically raised.
Note that this minor mode controls Emacs's own auto-raise
feature. Window managers that switch focus on mouse movement
often have their own auto-raise feature."
+ ;; This isn't really a global minor mode; rather, it's local to the
+ ;; selected frame, but declaring it as global prevents a misleading
+ ;; "Auto-Raise mode enabled in current buffer" message from being
+ ;; displayed when it is turned on.
+ :global t
:variable (frame-parameter nil 'auto-raise)
(if (frame-parameter nil 'auto-raise)
(raise-frame)))
@@ -1634,6 +1642,8 @@ live frame and defaults to the selected one."
(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))
+(declare-function pgtk-frame-geometry "pgtkfns.c" (&optional frame))
+(declare-function haiku-frame-geometry "haikufns.c" (&optional frame))
(defun frame-geometry (&optional frame)
"Return geometric attributes of FRAME.
@@ -1683,6 +1693,10 @@ and width values are in pixels.
(w32-frame-geometry frame))
((eq frame-type 'ns)
(ns-frame-geometry frame))
+ ((eq frame-type 'pgtk)
+ (pgtk-frame-geometry frame))
+ ((eq frame-type 'haiku)
+ (haiku-frame-geometry frame))
(t
(list
'(outer-position 0 . 0)
@@ -1713,7 +1727,7 @@ to the selected frame.
Storing information about resize operations is off by default.
If you set the variable `frame-size-history' like this
-(setq frame-size-history '(100))
+(setq frame-size-history \\='(100))
then Emacs will save information about the next 100 significant
operations affecting any frame's size in that variable. This
@@ -1807,6 +1821,8 @@ of frames like calls to map a frame or change its visibility."
(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))
+(declare-function pgtk-frame-edges "pgtkfns.c" (&optional frame type))
+(declare-function haiku-frame-edges "haikufns.c" (&optional frame type))
(defun frame-edges (&optional frame type)
"Return coordinates of FRAME's edges.
@@ -1830,12 +1846,18 @@ FRAME."
(w32-frame-edges frame type))
((eq frame-type 'ns)
(ns-frame-edges frame type))
+ ((eq frame-type 'pgtk)
+ (pgtk-frame-edges frame type))
+ ((eq frame-type 'haiku)
+ (haiku-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")
(declare-function ns-mouse-absolute-pixel-position "nsfns.m")
+(declare-function pgtk-mouse-absolute-pixel-position "pgtkfns.c")
+(declare-function haiku-mouse-absolute-pixel-position "haikufns.c")
(defun mouse-absolute-pixel-position ()
"Return absolute position of mouse cursor in pixels.
@@ -1850,12 +1872,18 @@ position (0, 0) of the selected frame's terminal."
(w32-mouse-absolute-pixel-position))
((eq frame-type 'ns)
(ns-mouse-absolute-pixel-position))
+ ((eq frame-type 'pgtk)
+ (pgtk-mouse-absolute-pixel-position))
+ ((eq frame-type 'haiku)
+ (haiku-mouse-absolute-pixel-position))
(t
(cons 0 0)))))
+(declare-function pgtk-set-mouse-absolute-pixel-position "pgtkfns.c" (x y))
(declare-function ns-set-mouse-absolute-pixel-position "nsfns.m" (x y))
(declare-function w32-set-mouse-absolute-pixel-position "w32fns.c" (x y))
(declare-function x-set-mouse-absolute-pixel-position "xfns.c" (x y))
+(declare-function haiku-set-mouse-absolute-pixel-position "haikufns.c" (x y))
(defun set-mouse-absolute-pixel-position (x y)
"Move mouse pointer to absolute pixel position (X, Y).
@@ -1863,12 +1891,16 @@ 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 'pgtk)
+ (pgtk-set-mouse-absolute-pixel-position x y))
((eq frame-type 'ns)
(ns-set-mouse-absolute-pixel-position x y))
((eq frame-type 'x)
(x-set-mouse-absolute-pixel-position x y))
((eq frame-type 'w32)
- (w32-set-mouse-absolute-pixel-position x y)))))
+ (w32-set-mouse-absolute-pixel-position x y))
+ ((eq frame-type 'haiku)
+ (haiku-set-mouse-absolute-pixel-position x y)))))
(defun frame-monitor-attributes (&optional frame)
"Return the attributes of the physical monitor dominating FRAME.
@@ -1961,6 +1993,9 @@ workarea attribute."
(declare-function x-frame-list-z-order "xfns.c" (&optional display))
(declare-function w32-frame-list-z-order "w32fns.c" (&optional display))
(declare-function ns-frame-list-z-order "nsfns.m" (&optional display))
+;; TODO: implement this on PGTK.
+;; (declare-function pgtk-frame-list-z-order "pgtkfns.c" (&optional display))
+(declare-function haiku-frame-list-z-order "haikufns.c" (&optional display))
(defun frame-list-z-order (&optional display)
"Return list of Emacs' frames, in Z (stacking) order.
@@ -1980,11 +2015,19 @@ Return nil if DISPLAY contains no Emacs frame."
((eq frame-type 'w32)
(w32-frame-list-z-order display))
((eq frame-type 'ns)
- (ns-frame-list-z-order display)))))
+ (ns-frame-list-z-order display))
+ ((eq frame-type 'pgtk)
+ ;; This is currently not supported on PGTK.
+ ;; (pgtk-frame-list-z-order display)
+ nil)
+ ((eq frame-type 'haiku)
+ (haiku-frame-list-z-order display)))))
(declare-function x-frame-restack "xfns.c" (frame1 frame2 &optional above))
(declare-function w32-frame-restack "w32fns.c" (frame1 frame2 &optional above))
(declare-function ns-frame-restack "nsfns.m" (frame1 frame2 &optional above))
+(declare-function pgtk-frame-restack "pgtkfns.c" (frame1 frame2 &optional above))
+(declare-function haiku-frame-restack "haikufns.c" (frame1 frame2 &optional above))
(defun frame-restack (frame1 frame2 &optional above)
"Restack FRAME1 below FRAME2.
@@ -2014,7 +2057,11 @@ Some window managers may refuse to restack windows."
((eq frame-type 'w32)
(w32-frame-restack frame1 frame2 above))
((eq frame-type 'ns)
- (ns-frame-restack frame1 frame2 above))))
+ (ns-frame-restack frame1 frame2 above))
+ ((eq frame-type 'haiku)
+ (haiku-frame-restack frame1 frame2 above))
+ ((eq frame-type 'pgtk)
+ (pgtk-frame-restack frame1 frame2 above))))
(error "Cannot restack frames")))
(defun frame-size-changed-p (&optional frame)
@@ -2061,8 +2108,8 @@ frame's display)."
((eq frame-type 'w32)
(with-no-warnings
(> w32-num-mouse-buttons 0)))
- ((memq frame-type '(x ns))
- t) ;; We assume X and NeXTstep *always* have a pointing device
+ ((memq frame-type '(x ns haiku pgtk))
+ t) ;; We assume X, NeXTstep, GTK, and Haiku *always* have a pointing device
(t
(or (and (featurep 'xt-mouse)
xterm-mouse-mode)
@@ -2087,7 +2134,7 @@ frames and several different fonts at once. This is true for displays
that use a window system such as X, and false for text-only terminals.
DISPLAY can be a display name, a frame, or nil (meaning the selected
frame's display)."
- (not (null (memq (framep-on-display display) '(x w32 ns)))))
+ (not (null (memq (framep-on-display display) '(x w32 ns pgtk haiku)))))
(defun display-images-p (&optional display)
"Return non-nil if DISPLAY can display images.
@@ -2115,7 +2162,7 @@ frame's display)."
;; a Windows DOS Box.
(with-no-warnings
(not (null dos-windows-version))))
- ((memq frame-type '(x w32 ns))
+ ((memq frame-type '(x w32 ns pgtk))
t)
(t
nil))))
@@ -2125,7 +2172,7 @@ frame's display)."
This means that, for example, DISPLAY can differentiate between
the keybinding RET and [return]."
(let ((frame-type (framep-on-display display)))
- (or (memq frame-type '(x w32 ns pc))
+ (or (memq frame-type '(x w32 ns pc pgtk))
;; MS-DOS and MS-Windows terminals have built-in support for
;; function (symbol) keys
(memq system-type '(ms-dos windows-nt)))))
@@ -2138,7 +2185,7 @@ DISPLAY should be either a frame or a display name (a string).
If DISPLAY is omitted or nil, it defaults to the selected frame's display."
(let ((frame-type (framep-on-display display)))
(cond
- ((memq frame-type '(x w32 ns))
+ ((memq frame-type '(x w32 ns haiku pgtk))
(x-display-screens display))
(t
1))))
@@ -2158,7 +2205,7 @@ with DISPLAY. To get information for each physical monitor, use
`display-monitor-attributes-list'."
(let ((frame-type (framep-on-display display)))
(cond
- ((memq frame-type '(x w32 ns))
+ ((memq frame-type '(x w32 ns haiku pgtk))
(x-display-pixel-height display))
(t
(frame-height (if (framep display) display (selected-frame)))))))
@@ -2178,7 +2225,7 @@ with DISPLAY. To get information for each physical monitor, use
`display-monitor-attributes-list'."
(let ((frame-type (framep-on-display display)))
(cond
- ((memq frame-type '(x w32 ns))
+ ((memq frame-type '(x w32 ns haiku pgtk))
(x-display-pixel-width display))
(t
(frame-width (if (framep display) display (selected-frame)))))))
@@ -2216,7 +2263,7 @@ For graphical terminals, note that on \"multi-monitor\" setups this
refers to the height in millimeters for all physical monitors
associated with DISPLAY. To get information for each physical
monitor, use `display-monitor-attributes-list'."
- (and (memq (framep-on-display display) '(x w32 ns))
+ (and (memq (framep-on-display display) '(x w32 ns haiku pgtk))
(or (cddr (assoc (or display (frame-parameter nil 'display))
display-mm-dimensions-alist))
(cddr (assoc t display-mm-dimensions-alist))
@@ -2237,7 +2284,7 @@ For graphical terminals, note that on \"multi-monitor\" setups this
refers to the width in millimeters for all physical monitors
associated with DISPLAY. To get information for each physical
monitor, use `display-monitor-attributes-list'."
- (and (memq (framep-on-display display) '(x w32 ns))
+ (and (memq (framep-on-display display) '(x w32 ns haiku pgtk))
(or (cadr (assoc (or display (frame-parameter nil 'display))
display-mm-dimensions-alist))
(cadr (assoc t display-mm-dimensions-alist))
@@ -2255,7 +2302,7 @@ DISPLAY can be a display name or a frame.
If DISPLAY is omitted or nil, it defaults to the selected frame's display."
(let ((frame-type (framep-on-display display)))
(cond
- ((memq frame-type '(x w32 ns))
+ ((memq frame-type '(x w32 ns haiku pgtk))
(x-display-backing-store display))
(t
'not-useful))))
@@ -2268,7 +2315,7 @@ DISPLAY can be a display name or a frame.
If DISPLAY is omitted or nil, it defaults to the selected frame's display."
(let ((frame-type (framep-on-display display)))
(cond
- ((memq frame-type '(x w32 ns))
+ ((memq frame-type '(x w32 ns haiku pgtk))
(x-display-save-under display))
(t
'not-useful))))
@@ -2281,7 +2328,7 @@ DISPLAY can be a display name or a frame.
If DISPLAY is omitted or nil, it defaults to the selected frame's display."
(let ((frame-type (framep-on-display display)))
(cond
- ((memq frame-type '(x w32 ns))
+ ((memq frame-type '(x w32 ns haiku pgtk))
(x-display-planes display))
((eq frame-type 'pc)
4)
@@ -2296,7 +2343,7 @@ DISPLAY can be a display name or a frame.
If DISPLAY is omitted or nil, it defaults to the selected frame's display."
(let ((frame-type (framep-on-display display)))
(cond
- ((memq frame-type '(x w32 ns))
+ ((memq frame-type '(x w32 ns haiku pgtk))
(x-display-color-cells display))
((eq frame-type 'pc)
16)
@@ -2313,7 +2360,7 @@ DISPLAY can be a display name or a frame.
If DISPLAY is omitted or nil, it defaults to the selected frame's display."
(let ((frame-type (framep-on-display display)))
(cond
- ((memq frame-type '(x w32 ns))
+ ((memq frame-type '(x w32 ns haiku pgtk))
(x-display-visual-class display))
((and (memq frame-type '(pc t))
(tty-display-color-p display))
@@ -2327,6 +2374,10 @@ If DISPLAY is omitted or nil, it defaults to the selected frame's display."
(&optional display))
(declare-function ns-display-monitor-attributes-list "nsfns.m"
(&optional terminal))
+(declare-function pgtk-display-monitor-attributes-list "pgtkfns.c"
+ (&optional terminal))
+(declare-function haiku-display-monitor-attributes-list "haikufns.c"
+ (&optional terminal))
(defun display-monitor-attributes-list (&optional display)
"Return a list of physical monitor attributes on DISPLAY.
@@ -2344,6 +2395,7 @@ of attribute keys and values as follows:
mm-size -- Width and height in millimeters in the form of
(WIDTH HEIGHT)
frames -- List of frames dominated by the physical monitor
+ scale-factor (*) -- Scale factor (float)
name (*) -- Name of the physical monitor as a string
source (*) -- Source of multi-monitor information as a string
@@ -2375,6 +2427,10 @@ monitors."
(w32-display-monitor-attributes-list display))
((eq frame-type 'ns)
(ns-display-monitor-attributes-list display))
+ ((eq frame-type 'pgtk)
+ (pgtk-display-monitor-attributes-list display))
+ ((eq frame-type 'haiku)
+ (haiku-display-monitor-attributes-list display))
(t
(let ((geometry (list 0 0 (display-pixel-width display)
(display-pixel-height display))))
@@ -2384,6 +2440,70 @@ monitors."
,(display-mm-height display)))
(frames . ,(frames-on-display-list display)))))))))
+(declare-function x-device-class "term/x-win.el" (name))
+(declare-function pgtk-device-class "term/pgtk-win.el" (name))
+
+(defun device-class (frame name)
+ "Return the class of the device NAME for an event generated on FRAME.
+NAME is a string that can be the value of `last-event-device', or
+nil. FRAME is a window system frame, typically the value of
+`last-event-frame' when `last-event-device' was set. On some
+window systems, it can also be a display name or a terminal.
+
+The class of a device is one of the following symbols:
+
+ `core-keyboard' means the device is a keyboard-like device, but
+ any other characteristics are unknown.
+
+ `core-pointer' means the device is a pointing device, but any
+ other characteristics are unknown.
+
+ `mouse' means the device is a computer mouse.
+
+ `trackpoint' means the device is a joystick or trackpoint.
+
+ `eraser' means the device is an eraser, which is typically the
+ other end of a stylus on a graphics tablet.
+
+ `pen' means the device is a stylus or some other similar
+ device.
+
+ `puck' means the device is a device similar to a mouse, but
+ reports absolute coordinates.
+
+ `power-button' means the device is a power button, volume
+ button, or some similar control.
+
+ `keyboard' means the device is a keyboard.
+
+ `touchscreen' means the device is a touchscreen.
+
+ `pad' means the device is a collection of buttons and rings and
+ strips commonly found in drawing tablets.
+
+ `touchpad' means the device is an indirect touch device, such
+ as a touchpad.
+
+ `piano' means the device is a piano, or some other kind of
+ musical instrument.
+
+ `test' means the device is used by the XTEST extension to
+ report input.
+
+It can also be nil, which means the class of the device could not
+be determined. Individual window systems may also return other
+symbols."
+ (let ((frame-type (framep-on-display frame)))
+ (cond ((eq frame-type 'x)
+ (x-device-class name))
+ ((eq frame-type 'pgtk)
+ (pgtk-device-class name))
+ (t (cond
+ ((string= name "Virtual core pointer")
+ 'core-pointer)
+ ((string= name "Virtual core keyboard")
+ 'core-keyboard))))))
+
;;;; Frame geometry values
@@ -2485,6 +2605,77 @@ deleting them."
(if iconify (iconify-frame this) (delete-frame this)))
(setq this next))))
+(defvar undelete-frame--deleted-frames nil
+ "Internal variable used by `undelete-frame--save-deleted-frame'.")
+
+(defun undelete-frame--save-deleted-frame (frame)
+ "Save the configuration of frames deleted with `delete-frame'.
+Only the 16 most recently deleted frames are saved."
+ (when (and after-init-time (frame-live-p frame))
+ (setq undelete-frame--deleted-frames
+ (cons
+ (list
+ (display-graphic-p)
+ (seq-remove
+ (lambda (elem)
+ (or (memq (car elem) frame-internal-parameters)
+ ;; When the daemon is started from a graphical
+ ;; environment, TTY frames have a 'display' parameter set
+ ;; to the value of $DISPLAY (see the note in
+ ;; `server--on-display-p'). Do not store that parameter
+ ;; in the frame data, otherwise `undelete-frame' attempts
+ ;; to restore a graphical frame.
+ (and (eq (car elem) 'display) (not (display-graphic-p)))))
+ (frame-parameters frame))
+ (window-state-get (frame-root-window frame)))
+ undelete-frame--deleted-frames))
+ (if (> (length undelete-frame--deleted-frames) 16)
+ (setq undelete-frame--deleted-frames
+ (butlast undelete-frame--deleted-frames)))))
+
+(define-minor-mode undelete-frame-mode
+ "Enable the `undelete-frame' command."
+ :group 'frames
+ :global t
+ (if undelete-frame-mode
+ (add-hook 'delete-frame-functions
+ #'undelete-frame--save-deleted-frame -75)
+ (remove-hook 'delete-frame-functions
+ #'undelete-frame--save-deleted-frame)
+ (setq undelete-frame--deleted-frames nil)))
+
+(defun undelete-frame (&optional arg)
+ "Undelete a frame deleted with `delete-frame'.
+Without a prefix argument, undelete the most recently deleted
+frame.
+With a numerical prefix argument ARG between 1 and 16, where 1 is
+most recently deleted frame, undelete the ARGth deleted frame.
+When called from Lisp, returns the new frame."
+ (interactive "P")
+ (if (not undelete-frame-mode)
+ (user-error "Undelete-Frame mode is disabled")
+ (if (consp arg)
+ (user-error "Missing deleted frame number argument")
+ (let* ((number (pcase arg ('nil 1) ('- -1) (_ arg)))
+ (frame-data (nth (1- number) undelete-frame--deleted-frames))
+ (graphic (display-graphic-p)))
+ (if (not (<= 1 number 16))
+ (user-error "%d is not a valid deleted frame number argument"
+ number)
+ (if (not frame-data)
+ (user-error "No deleted frame with number %d" number)
+ (if (not (eq graphic (nth 0 frame-data)))
+ (user-error
+ "Cannot undelete a %s display frame on a %s display"
+ (if graphic "non-graphic" "graphic")
+ (if graphic "graphic" "non-graphic"))
+ (setq undelete-frame--deleted-frames
+ (delq frame-data undelete-frame--deleted-frames))
+ (let* ((default-frame-alist (nth 1 frame-data))
+ (frame (make-frame)))
+ (window-state-put (nth 2 frame-data) (frame-root-window frame) 'safe)
+ (select-frame-set-input-focus frame)
+ frame))))))))
;;; Window dividers.
(defgroup window-divider nil
@@ -2776,6 +2967,12 @@ If the frame is in fullscreen state, don't change its state, but
set the frame's `fullscreen-restore' parameter to `maximized', so
the frame will be maximized after disabling fullscreen state.
+If you wish to hide the title bar when the frame is maximized, you
+can add something like the following to your init file:
+
+ (add-hook \\='window-size-change-functions
+ #\\='frame-hide-title-bar-when-maximized)
+
Note that with some window managers you may have to set
`frame-resize-pixelwise' to non-nil in order to make a frame
appear truly maximized. In addition, you may have to set
@@ -2829,6 +3026,7 @@ See also `toggle-frame-maximized'."
(define-key ctl-x-5-map "o" #'other-frame)
(define-key ctl-x-5-map "5" #'other-frame-prefix)
(define-key ctl-x-5-map "c" #'clone-frame)
+(define-key ctl-x-5-map "u" #'undelete-frame)
(define-key global-map [f11] #'toggle-frame-fullscreen)
(define-key global-map [(meta f10)] #'toggle-frame-maximized)
(define-key esc-map [f10] #'toggle-frame-maximized)
@@ -2890,6 +3088,13 @@ Offer NUMBER as default value, if it is a natural number."
bidi-display-reordering
bidi-inhibit-bpa))
+(defun frame-hide-title-bar-when-maximized (frame)
+ "Hide the title bar if FRAME is maximized.
+If FRAME isn't maximized, show the title bar."
+ (set-frame-parameter
+ frame 'undecorated
+ (eq (alist-get 'fullscreen (frame-parameters frame)) 'maximized)))
+
(provide 'frame)
;;; frame.el ends here