(defgroup frame-utils nil "Portable Emacs frame utility functions")
(defconst fru-emacs22p
(and (not (featurep 'xemacs)) (>= emacs-major-version 22)))
(defconst fru-winntp
(or (eq window-system 'w32)
(eq window-system 'win32)
(eq system-type 'windows-nt))
"Running under Windows NT?")
(defconst fru-xwmp
(memq window-system '(x mac macos darwin))
"Running under some X Window Manager?")
(cond
(fru-winntp (load "w32-fns")))
(defvar fru-restored-configuration ?f
"The positions, states and window configurations of ALL frames as the
\"restored\" state of Emacs. In this state the default frame is visible and
not maximized/iconified. What the register stores is the list returned by
`current-frame-configuration' plus the position of point.")
(defun fru-auto-display-window (&optional W)
"Select window W, then shrink its height to be as small as possible to
display its buffer, and shrink/grow its width to by `fill-column' of the
current buffer."
(save-excursion
(if W (select-window W))
(shrink-window-if-larger-than-buffer)
(while (> (window-width) fill-column) (enlarge-window-horizontally -1))
(while (< (window-width) fill-column) (enlarge-window-horizontally 1)))
)
(defun fru-auto-display-frame (&optional F)
"Maximize/restore/repair the frame F (default: selected).
Invoke this function multiple times until F is displayed as you like it."
(interactive)
(or F (setq F (selected-frame)))
(let* ((default-columns (+ 1 fill-column))
(move-frame current-prefix-arg)
(W (selected-window))
(maximized (frame-maximized-p F))
(restored (frame-restored-p F))
(special (or buffer-read-only (window-dedicated-p W))))
(if move-frame
(let* ((n (fru-number-of-horizontal-monitors))
(m (fru-number-of-vertical-monitors))
(h (fru-get-horizontal-monitor-of-frame F))
(v (fru-get-vertical-monitor-of-frame F)))
(fru-move-frame-to-monitor (if (>= h (- n 1)) 0 (+ h 1)) v F)
)
(cond
((not (frame-visible-p F))
(if (frame-iconified-p F)
(fru-restore-frame F)
(fru-raise-and-focus-frame F))
)
(special
(iconify-frame F) (fru-raise-and-focus-frame)
(message "Switched from dedicated frame to default frame.")
)
(t
(cond (maximized (fru-restore-frame))
(restored (fru-maximize-frame))
(t (error "Frame neither maximized nor restored?")))
(unless (one-window-p t)
(fru-auto-display-window))
)
)
)
)
)
(defun fru-echo-frame-parameters (&optional F what)
"Print some frame parameters in the echo area."
(interactive)
(or F (setq F (selected-frame)))
(message (concat " %s\n"
" Monitor: %dx%d_%dx%d Display: %s Max.cols/rows.: %dx%d Font: %s\n"
" Frame(%s): %d-%d_%s Cols/rows/fill: %dx%d_%d Border: %d,%d,%d,%d")
(or what "")
(fru-number-of-horizontal-monitors)
(fru-number-of-vertical-monitors)
(fru-display-pixel-width)
(fru-display-pixel-height)
(fru-concat-x-geometry (display-pixel-width) (display-pixel-height))
(fru-frame-columns F) (fru-frame-rows F)
(fru-concat-x-geometry (frame-char-width F) (frame-char-height F))
(if (frame-maximized-p F) "maximized"
(if (frame-restored-p F) "restored"
(if (frame-iconified-p F) "iconified" "?")))
(+ 1 (fru-get-horizontal-monitor-of-frame F))
(+ 1 (fru-get-vertical-monitor-of-frame F))
(fru-concat-x-geometry (frame-pixel-width F) (frame-pixel-height F)
(fru-frame-left-position F) (fru-frame-top-position F))
(frame-width F) (frame-height F) fill-column
(fru-frame-decoration-left)
(fru-frame-decoration-right)
(fru-frame-decoration-top)
(fru-frame-decoration-bottom)
)
)
(defun fru-restore-frame (&optional F)
"Restore frame F (default: selected frame)."
(interactive)
(or F (setq F (selected-frame)))
(let ((random-pos t)
(name (if (fru-is-default-frame F) "Default frame" "Frame")))
(cond
(fru-winntp
(w32-send-sys-command 61728 F))
(t
(when (and (fru-is-default-frame F) (get-register fru-restored-configuration))
(window-configuration-to-register ?t)
(jump-to-register fru-restored-configuration t)
(jump-to-register ?t)
(unless (setq random-pos (frame-maximized-p F))
(message "%s restored" name)))
(when random-pos
(let* ((maxcols (fru-frame-columns F))
(maxrows (fru-frame-rows F))
(dpw (fru-display-pixel-width))
(vmn 0)
(hmn (/ (+ (fru-frame-left-position F) (fru-frame-decoration-left F)) dpw)))
(random t)
(if (zerop (random 2))
(set-frame-position F (+ 200 (* hmn dpw)) 100))
(set-frame-size F (if (one-window-p t)
(+ fill-column 3)
(+ (truncate (/ maxcols 2)) 10))
(+ (truncate (/ maxrows 2)) 5))
(message "%s restored to some random position on monitor %d-%d" name vmn hmn))
)
)
)
(if (fru-is-default-frame F)
(frame-configuration-to-register fru-restored-configuration)))
)
(defun fru-set-frame-position (F x y)
(let ((w (frame-width F))
(h (frame-height F)))
(set-frame-size F 10 10)
(set-frame-position F x y)
(set-frame-size F (min w (fru-frame-columns F)) (min h (fru-frame-rows F)))
)
)
(defun fru-set-frame-pixel-size (F width height)
(set-frame-size F (fru-frame-columns F width) (fru-frame-rows F height)))
(defun fru-set-frame-icon (&optional iconfile F title)
(interactive)
(or F (setq F (selected-frame)))
(if iconfile
(if (--file-readable-p iconfile)
(modify-frame-parameters F (list (cons 'icon-type iconfile)))
(message "%s: icon-file not found" iconfile)))
(if title
(setq frame-title-format title)))
(defun fru-maximize-frame (&optional F)
"Maximize frame F (defaults to selected) to cover the whole display."
(interactive)
(or F (setq F (selected-frame)))
(when (and (fru-is-default-frame F)
(not (frame-maximized-p F)))
(frame-configuration-to-register fru-restored-configuration))
(cond
(fru-winntp
(w32-send-sys-command 61488 F)
(when (fru-is-default-frame F)
(message "Default frame maximized")))
(t
(let* ((maxcols (fru-frame-columns F))
(maxrows (fru-frame-rows F))
(dpw (fru-display-pixel-width))
(name (if (fru-is-default-frame F) "Default frame" "Frame"))
(vmn 0)
(hmn (floor (/ (fru-frame-left-position F) dpw))))
(fru-set-frame-position F (* hmn dpw) 0)
(set-frame-size F maxcols maxrows)
(message "%s maximized on monitor %d-%d" name (+ hmn 1) (+ vmn 1)))
)
)
)
(defun fru-move-frame-to-monitor (hmn vmn &optional F)
"HMN/VMN are zerobased monitor numbers. F defaults to the selected frame."
(interactive)
(or F (setq F (selected-frame)))
(let* ((dpw (fru-display-pixel-width))
(dph (fru-display-pixel-height))
(was-maximized (frame-maximized-p F))
(h (fru-get-horizontal-monitor-of-frame F))
(v (fru-get-vertical-monitor-of-frame F))
(xoffs (- (fru-frame-left-position F) (* h dpw)))
(yoffs (- (fru-frame-top-position F) (* v dph)))
(newx (max 0 (+ xoffs (* hmn dpw))))
(newy (max 0 (+ yoffs (* vmn dph)))))
(set-frame-position F newx newy)
(if was-maximized (fru-maximize-frame F))
(fru-echo-frame-parameters F "MOVED FRAME"))
)
(defsubst frame-available-p (F)
"Actually an alias for `frame-visible-p'."
(and (frame-live-p F) (eq t (frame-visible-p F))))
(unless (fboundp 'frame-totally-visible-p)
(defsubst frame-totally-visible-p (F)
"Returns t when a frame is not obscured by any other X window and not
iconified (see `frame-visible-p'). In this generic implementation, however, we
can only test if a frame is currently in use for display."
(frame-available-p F)))
(defsubst frame-iconified-p (F)
"Returns t when a frame is iconified."
(and (frame-available-p F) (eq 'icon (frame-visible-p F))))
(defsubst frame-restored-p (F)
"True when frame is not iconified and not maximized."
(and (frame-available-p F)
(not (or (frame-iconified-p F)
(frame-maximized-p F)))))
(defsubst frame-maximized-p (F)
"True when frame F covers at least 95% of the display width and height."
(if (frame-available-p F)
(let ((dpw (fru-display-pixel-width))
(dph (fru-display-pixel-height))
(fpw (frame-pixel-width F))
(fph (frame-pixel-height F)))
(and (>= fpw (* dpw 0.95))
(>= fph (* dph 0.95))))))
(defun fru-concat-x-geometry (width height &optional xoffset yoffset)
"Make X11 geometry string of the form
<width>x<height>{+-}<xoffset>{+-}<yoffset>
for specifying the size and placement location for an object. `width',
`height', `xoffset' and `yoffset' are numbers that measure pixels.
The `width' and `height' parts of the geometry specification are measured in
pixels. `xoffset' and `yoffset' specify the distance of the placement
coordinate. Both types of offsets are measured from the indicated edge of the
object to the corresponding edge of the related object (when this is the
screen, its top-left edge known as (0,0)).
+xoffset The left edge of the object is to be placed `xoffset' pixels in from the left edge.
-xoffset The left edge of the object is to be placed `xoffset' pixels out from the left edge
+yoffset The top edge of the object is to be `yoffset' pixels below the top edge.
-yoffset The top edge of the object is to be `yoffset' pixels above the top edge
Either `xoffset' or `yoffset' both must be present."
(concat (if width (format "%dx%d" width height))
(if xoffset (format (if (>= xoffset 0) "+%d" "%d") xoffset))
(if yoffset (format (if (>= yoffset 0) "+%d" "%d") yoffset)))
)
(defun fru-find-file-reuse-frames (filename &optional lineno)
"Reuse a visible frame already containing the file and go to LINENO."
(let ((buffer (find-file-noselect (file-truename filename)))
(pop-up-frames t)
(display-buffer-reuse-frames t))
(set-buffer buffer)
(select-window (display-buffer buffer nil t))
(fru-raise-and-focus-frame (window-frame (get-buffer-window buffer)))
(when lineno (goto-line lineno))))
(defun fru-get-frame-from-buffer (&optional buf)
"Return frame object for buffer BUF (default: current)."
(window-frame (get-buffer-window (or buf (current-buffer)))))
(defun fru-raise-and-focus-frame (&optional F)
"Raise frame F, make it visible and select it for subsequent edit commands.
F defaults to the default frame, i.e. `default-minibuffer-frame'."
(or F (setq F default-minibuffer-frame))
(when (frame-live-p F)
(redirect-frame-focus F)
(raise-frame F)
(make-frame-visible F)
(unless fru-emacs22p (focus-frame F))
(select-frame F)
(select-frame-set-input-focus F)
(cond ((and fru-xwmp (fboundp 'x-focus-frame))
(x-focus-frame F))
(fru-winntp (w32-focus-frame F)))
(when focus-follows-mouse
(set-mouse-position F (1- (frame-width F)) 0)))
)
(defvar fru-frame-pixel-width nil
"Use this variable to define the # of pels a single monitor can display
horizontally, or `nil' for the full `display-pixel-width'.
Note, however, that `display-pixel-width' relates to all monitors.")
(defvar fru-frame-pixel-height nil
"Use this variable to define the # of pels a single monitor can display
vertically, or `nil' for the full `display-pixel-height'.
Note, however, that `display-pixel-height' relates to all monitors.")
(defun fru-have-multiple-monitors ()
"Return t if more than one monitor is available.
Multiple monitors are defined indirectly by `fru-frame-pixel-width' and
`fru-frame-pixel-height'."
(or (> (fru-number-of-horizontal-monitors) 1)
(> (fru-number-of-vertical-monitors) 1)))
(defun fru-number-of-horizontal-monitors ()
"Get the one-based # monitor columns."
(max 1 (if fru-frame-pixel-width (/ (display-pixel-width) fru-frame-pixel-width) 0)))
(defun fru-number-of-vertical-monitors ()
"Get the one-based # monitor rows."
(max 1 (if fru-frame-pixel-height (/ (display-pixel-height) fru-frame-pixel-height) 0)))
(defun fru-get-vertical-monitor-of-frame (&optional F)
"Get zerobased row index of monitor displaying F."
(/ (+ (fru-frame-top-position F) (fru-frame-decoration-top F)) (fru-display-pixel-height)))
(defun fru-get-horizontal-monitor-of-frame (&optional F)
"Get zerobased column index of monitor displaying F."
(/ (+ (fru-frame-left-position F) (fru-frame-decoration-left F)) (fru-display-pixel-width)))
(defun fru-display-pixel-width ()
"`display-pixel-width' quotient for multiple monitors placed horizontally.
See `fru-display-pixel-height'."
(/ (display-pixel-width) (fru-number-of-horizontal-monitors)))
(defun fru-display-pixel-height ()
"`display-pixel-height' quotient for multiple monitors stacked vertically.
See `fru-display-pixel-width'."
(/ (display-pixel-height) (fru-number-of-vertical-monitors)))
(defun fru-frame-border-width (&optional F)
(+ (frame-parameter F 'border-width) (frame-parameter F 'internal-border-width)))
(defun fru-frame-decoration-top (&optional F)
(+ (fru-frame-border-width F)
(if fru-winntp 12 0)))
(defun fru-frame-decoration-bottom (&optional F)
(+ (fru-frame-border-width F)
(if fru-winntp 18 0)))
(defun fru-frame-decoration-left (&optional F)
(+ (fru-frame-border-width F)
(if fru-emacs22p (frame-parameter F 'left-fringe)
(if fru-winntp 8 18))))
(defun fru-frame-decoration-right (&optional F)
(+ (fru-frame-border-width F)
(if fru-emacs22p (frame-parameter F 'right-fringe)
(if fru-winntp 8 12))))
(defun fru-is-default-frame (&optional F)
"The default frame is the initial frame from which all others are spawned (`default-minibuffer-frame').
The value is set by `frame-initialize' (<frame.el>), called by <startup.el>
before loading the user's initialization file."
(eq (or F (selected-frame)) default-minibuffer-frame))
(defun fru-frame-top-position (F)
"Get vertical frame position (top edge) in pixels."
(eval (frame-parameter F 'top)))
(defun fru-frame-left-position (F)
"Get horizontal frame position (left edge) in pixels."
(eval (frame-parameter F 'left)))
(defun fru-frame-columns (&optional F width)
"Calculates the maximum number of columns that can fit in pixels specified by
WIDTH (default: `fru-display-pixel-width')."
(truncate (/ (- (or width (fru-display-pixel-width))
(fru-frame-decoration-left F)
(fru-frame-decoration-right F))
(frame-char-width F))))
(defun fru-frame-rows (&optional F height)
"Calculates the number of rows that can fit in pixels specified by
HEIGHT (default: `fru-display-pixel-height')."
(truncate (/ (- (or height (fru-display-pixel-height))
(fru-frame-decoration-top F)
(fru-frame-decoration-bottom F))
(frame-char-height F))))
(defun fru-frame-font-to-point()
"Under NT pop dialog and choose a font. Insert fon-string at point."
(interactive)
(cond
(fru-winntp (insert(prin1-to-string(x-select-font))))
(t (insert (frame-parameter nil 'font)))))
(defun fru-list-fonts()
"Show list of all available fonts"
(interactive)
(pop-to-buffer "*Fonts*")
(erase-buffer)
(insert-string (prin1-to-string (x-list-fonts "*")))
(goto-char (point-min)) (delete-char 2)
(while (re-search-forward "\" \"" nil t)
(replace-match "\n"))
(goto-char (point-max)) (delete-char -2)
(sort-lines nil (point-min) (point-max))
(goto-char (point-min))
(local-set-key "q" (quote delete-window)))
(defun fru-set-frame-font (&optional fontnum F)
"Enables font on frame F according to an abstract number FONTNUM:
0 user-selection...
1-4 monospaced tiny, small, normal, large
5-7 sans-serif small, normal, large
8-9 serif normal, large
F defaults to current frame. Interactively FONTNUM is the prefix-arg."
(interactive)
(let ((Forg (if F (selected-frame)))
(num (if current-prefix-arg current-prefix-arg fontnum))
(was-maximized (frame-maximized-p F)))
(if F (select-frame F))
(cond
(fru-winntp
(cond ((eq num 0) (set-frame-font (x-select-font nil t)))
((eq num 1) (set-frame-font "MS Dialog Light-6"))
((eq num 2) (set-frame-font "Lucida Console-9"))
((eq num 3) (set-frame-font "Courier-10"))
((eq num 4) (set-frame-font "Lucida Sans Typewriter-10"))
((eq num 5) (set-frame-font "-outline-Lucida Console-normal-r-normal-normal-16-157-96-96-c-*-iso10646-1"))
((eq num 6) (set-frame-font "-outline-Lucida Console-normal-r-normal-normal-18-157-96-96-c-*-iso10646-1"))
((eq num 7) (set-frame-font "-outline-Times New Roman-normal-r-normal-normal-17-142-96-96-p-*-iso10646-1"))
((eq num 8) (set-frame-font "-outline-Times New Roman-normal-r-normal-normal-19-142-96-96-p-*-iso10646-1"))
((eq num 9) (set-frame-font "-outline-Times New Roman-normal-r-normal-normal-24-180-96-96-p-*-iso10646-1"))
)
(fru-restore-frame)
(fru-maximize-frame)
)
(fru-xwmp
(cond ((eq num 0) (shell-command "xfontsel&"))
((eq num 1) (set-frame-font "-misc-*-medium-r-normal-*-13-*-*-*-*-*-iso8859-1"))
((eq num 2) (set-frame-font "-adobe-*-medium-r-*-*-14-*-*-*-*-*-iso8859-1"))
((eq num 3) (set-frame-font "9x15"))
((eq num 4) (set-frame-font "-*-fixed-medium-r-normal-*-20-*-ISO8859-1"))
((eq num 5) (set-frame-font "-adobe-helvetica-bold-r-*-*-14-*-*-*-*-*-iso8859-1"))
((eq num 6) (set-frame-font "-adobe-helvetica-medium-r-*-*-20-*-*-*-*-*-iso8859-1"))
((eq num 7) (set-frame-font "-b&h-*-medium-r-*-sans-18-*-*-*-*-*-iso8859-1"))
((eq num 8) (set-frame-font "-adobe-times-medium-r-*-*-20-*-*-*-*-*-iso8859-1"))
((eq num 9) (set-frame-font "-adobe-new century schoolbook-medium-r-*-*-24-*-*-*-*-*-iso8859-1"))))
)
(fru-echo-frame-parameters F "SET FONT")
(if was-maximized (fru-maximize-frame F))
(if Forg (select-frame Forg))
)
)
(provide 'frame-utils)