]> code.delx.au - gnu-emacs/blob - lisp/frame.el
* frame.el: Clean up initialization code.
[gnu-emacs] / lisp / frame.el
1 ;;; frame.el --- multi-frame management independent of window systems.
2
3 ;;;; Copyright (C) 1990, 1992, 1993 Free Software Foundation, Inc.
4
5 ;; Maintainer: FSF
6 ;; Keywords: internal
7
8 ;;; This file is part of GNU Emacs.
9 ;;;
10 ;;; GNU Emacs is free software; you can redistribute it and/or modify
11 ;;; it under the terms of the GNU General Public License as published by
12 ;;; the Free Software Foundation; either version 2, or (at your option)
13 ;;; any later version.
14 ;;;
15 ;;; GNU Emacs is distributed in the hope that it will be useful,
16 ;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 ;;; GNU General Public License for more details.
19 ;;;
20 ;;; You should have received a copy of the GNU General Public License
21 ;;; along with GNU Emacs; see the file COPYING. If not, write to
22 ;;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
23
24 ;;; Code:
25
26 (defvar frame-creation-function nil
27 "Window-system dependent function to call to create a new frame.
28 The window system startup file should set this to its frame creation
29 function, which should take an alist of parameters as its argument.")
30
31 ;;; The initial value given here for this must ask for a minibuffer.
32 ;;; There must always exist a frame with a minibuffer, and after we
33 ;;; delete the terminal frame, this will be the only frame.
34 (defvar initial-frame-alist '((minibuffer . t))
35 "Alist of values used when creating the initial emacs text frame.
36 These may be set in your init file, like this:
37 (setq initial-frame-alist '((top . 1) (left . 1) (width . 80) (height . 55)))
38 If this requests a frame without a minibuffer, and you do not create a
39 minibuffer frame on your own, one will be created, according to
40 `minibuffer-frame-alist'.
41 These supercede the values given in frame-default-alist.")
42
43 (defvar minibuffer-frame-alist '((width . 80) (height . 2))
44 "Alist of values to apply to a minibuffer frame.
45 These may be set in your init file, like this:
46 (setq minibuffer-frame-alist
47 '((top . 1) (left . 1) (width . 80) (height . 2)))
48 These supercede the values given in default-frame-alist.")
49
50 (defvar pop-up-frame-alist nil
51 "Alist of values used when creating pop-up frames.
52 Pop-up frames are used for completions, help, and the like.
53 This variable can be set in your init file, like this:
54 (setq pop-up-frame-alist '((width . 80) (height . 20)))
55 These supercede the values given in default-frame-alist.")
56
57 (setq pop-up-frame-function
58 (function (lambda ()
59 (new-frame pop-up-frame-alist))))
60
61 \f
62 ;;;; Arrangement of frames at startup
63
64 ;;; 1) Load the window system startup file from the lisp library and read the
65 ;;; high-priority arguments (-q and the like). The window system startup
66 ;;; file should create any frames specified in the window system defaults.
67 ;;;
68 ;;; 2) If no frames have been opened, we open an initial text frame.
69 ;;;
70 ;;; 3) Once the init file is done, we apply any newly set parameters
71 ;;; in initial-frame-alist to the frame.
72
73 (add-hook 'before-init-hook 'frame-initialize)
74 (add-hook 'window-setup-hook 'frame-notice-user-settings)
75
76 ;;; If we create the initial frame, this is it.
77 (defvar frame-initial-frame nil)
78
79 ;;; startup.el calls this function before loading the user's init
80 ;;; file - if there is no frame with a minibuffer open now, create
81 ;;; one to display messages while loading the init file.
82 (defun frame-initialize ()
83
84 ;; Are we actually running under a window system at all?
85 (if (and window-system (not noninteractive))
86 (progn
87 ;; If there is no frame with a minibuffer besides the terminal
88 ;; frame, then we need to create the opening frame. Make sure
89 ;; it has a minibuffer, but let initial-frame-alist omit the
90 ;; minibuffer spec.
91 (or (delq terminal-frame (minibuffer-frame-list))
92 (setq default-minibuffer-frame
93 (setq frame-initial-frame
94 (new-frame initial-frame-alist))))
95
96 ;; At this point, we know that we have a frame open, so we
97 ;; can delete the terminal frame.
98 (delete-frame terminal-frame)
99 (setq terminal-frame nil))
100
101 ;; No, we're not running a window system. Arrange to cause errors.
102 (setq frame-creation-function
103 (function
104 (lambda (parameters)
105 (error
106 "Can't create multiple frames without a window system."))))))
107
108 ;;; startup.el calls this function after loading the user's init
109 ;;; file. Now default-frame-alist and initial-frame-alist contain
110 ;;; information to which we must react; do what needs to be done.
111 (defun frame-notice-user-settings ()
112
113 ;; Creating and deleting frames may shift the selected frame around,
114 ;; and thus the current buffer. Protect against that. We don't
115 ;; want to use save-excursion here, because that may also try to set
116 ;; the buffer of the selected window, which fails when the selected
117 ;; window is the minibuffer.
118 (let ((old-buffer (current-buffer)))
119
120 ;; If the initial frame is still around, apply initial-frame-alist
121 ;; and default-frame-alist to it.
122 (if (frame-live-p frame-initial-frame)
123
124 ;; The initial frame we create above always has a minibuffer.
125 ;; If the user wants to remove it, or make it a minibuffer-only
126 ;; frame, then we'll have to delete the current frame and make a
127 ;; new one; you can't remove or add a root window to/from an
128 ;; existing frame.
129 ;;
130 ;; NOTE: default-frame-alist was nil when we created the
131 ;; existing frame. We need to explicitly include
132 ;; default-frame-alist in the parameters of the screen we
133 ;; create here, so that its new value, gleaned from the user's
134 ;; .emacs file, will be applied to the existing screen.
135 (if (not (eq (cdr (or (assq 'minibuffer initial-frame-alist)
136 (assq 'minibuffer default-frame-alist)
137 '(minibuffer . t)))
138 t))
139 ;; Create the new frame.
140 (let ((new
141 (new-frame
142 (append initial-frame-alist
143 default-frame-alist
144 (frame-parameters frame-initial-frame)))))
145
146 ;; The initial frame, which we are about to delete, may be
147 ;; the only frame with a minibuffer. If it is, create a
148 ;; new one.
149 (or (delq frame-initial-frame (minibuffer-frame-list))
150 (new-frame (append minibuffer-frame-alist
151 '((minibuffer . only)))))
152
153 ;; If the initial frame is serving as a surrogate
154 ;; minibuffer frame for any frames, we need to wean them
155 ;; onto a new frame. The default-minibuffer-frame
156 ;; variable must be handled similarly.
157 (let ((users-of-initial
158 (filtered-frame-list
159 (function (lambda (frame)
160 (and (not (eq frame frame-initial-frame))
161 (eq (window-frame
162 (minibuffer-window frame))
163 frame-initial-frame)))))))
164 (if (or users-of-initial
165 (eq default-minibuffer-frame frame-initial-frame))
166
167 ;; Choose an appropriate frame. Prefer frames which
168 ;; are only minibuffers.
169 (let* ((new-surrogate
170 (car
171 (or (filtered-frame-list
172 (function
173 (lambda (frame)
174 (eq (cdr (assq 'minibuffer
175 (frame-parameters frame)))
176 'only))))
177 (minibuffer-frame-list))))
178 (new-minibuffer (minibuffer-window new-surrogate)))
179
180 (if (eq default-minibuffer-frame frame-initial-frame)
181 (setq default-minibuffer-frame new-surrogate))
182
183 ;; Wean the frames using frame-initial-frame as
184 ;; their minibuffer frame.
185 (mapcar
186 (function
187 (lambda (frame)
188 (modify-frame-parameters
189 frame (list (cons 'minibuffer new-minibuffer)))))
190 users-of-initial))))
191
192 ;; Redirect events enqueued at this frame to the new frame.
193 ;; Is this a good idea?
194 (redirect-frame-focus frame-initial-frame new)
195
196 ;; Finally, get rid of the old frame.
197 (delete-frame frame-initial-frame))
198
199 ;; Otherwise, we don't need all that rigamarole; just apply
200 ;; the new parameters.
201 (modify-frame-parameters frame-initial-frame
202 (append initial-frame-alist
203 default-frame-alist))))
204
205 ;; Restore the original buffer.
206 (set-buffer old-buffer)
207
208 ;; Make sure the initial frame can be GC'd if it is ever deleted.
209 (makunbound 'frame-initial-frame)))
210
211 \f
212 ;;;; Creation of additional frames, and other frame miscellanea
213
214 ;;; Return some frame other than the current frame, creating one if
215 ;;; neccessary. Note that the minibuffer frame, if separate, is not
216 ;;; considered (see next-frame).
217 (defun get-other-frame ()
218 (let ((s (if (equal (next-frame (selected-frame)) (selected-frame))
219 (new-frame)
220 (next-frame (selected-frame)))))
221 s))
222
223 (defun next-multiframe-window ()
224 "Select the next window, regardless of which frame it is on."
225 (interactive)
226 (select-window (next-window (selected-window)
227 (> (minibuffer-depth) 0)
228 t)))
229
230 (defun previous-multiframe-window ()
231 "Select the previous window, regardless of which frame it is on."
232 (interactive)
233 (select-window (previous-window (selected-window)
234 (> (minibuffer-depth) 0)
235 t)))
236
237 (defun new-frame (&optional parameters)
238 "Create a new frame, displaying the current buffer.
239
240 Optional argument PARAMETERS is an alist of parameters for the new
241 frame. Specifically, PARAMETERS is a list of pairs, each having one
242 of the following forms:
243
244 (name . STRING) - The frame should be named STRING.
245
246 (height . NUMBER) - The frame should be NUMBER text lines high. If
247 this parameter is present, the width parameter must also be
248 given.
249
250 (width . NUMBER) - The frame should be NUMBER characters in width.
251 If this parameter is present, the height parameter must also
252 be given.
253
254 (minibuffer . t) - the frame should have a minibuffer
255 (minibuffer . none) - the frame should have no minibuffer
256 (minibuffer . only) - the frame should contain only a minibuffer
257 (minibuffer . WINDOW) - the frame should use WINDOW as its minibuffer window.
258
259 (NAME . VALUE), specifying the parameter and the value it should have.
260 NAME should be one of the following symbols:
261 name VALUE
262
263 The documentation for the function x-create-frame describes
264 additional frame parameters that Emacs will recognize when running
265 under the X Window System."
266 (interactive)
267 (funcall frame-creation-function parameters))
268
269 (defun filtered-frame-list (predicate)
270 "Return a list of all live frames which satisfy PREDICATE."
271 (let ((frames (frame-list))
272 good-frames)
273 (while (consp frames)
274 (if (funcall predicate (car frames))
275 (setq good-frames (cons (car frames) good-frames)))
276 (setq frames (cdr frames)))
277 good-frames))
278
279 (defun minibuffer-frame-list ()
280 "Return a list of all frames with their own minibuffers."
281 (filtered-frame-list
282 (function (lambda (frame)
283 (eq frame (window-frame (minibuffer-window frame)))))))
284
285 \f
286 ;;;; Frame configurations
287
288 (defun current-frame-configuration ()
289 "Return a list describing the positions and states of all frames.
290 Each element is a list of the form (FRAME ALIST WINDOW-CONFIG), where
291 FRAME is a frame object, ALIST is an association list specifying
292 some of FRAME's parameters, and WINDOW-CONFIG is a window
293 configuration object for FRAME."
294 (mapcar (function
295 (lambda (frame)
296 (list frame
297 (frame-parameters frame)
298 (current-window-configuration frame))))
299 (frame-list)))
300
301 (defun set-frame-configuration (configuration)
302 "Restore the frames to the state described by CONFIGURATION.
303 Each frame listed in CONFIGURATION has its position, size, window
304 configuration, and other parameters set as specified in CONFIGURATION."
305 (let (frames-to-delete)
306 (mapcar (function
307 (lambda (frame)
308 (let ((parameters (assq frame configuration)))
309 (if parameters
310 (progn
311 (modify-frame-parameters frame (nth 1 parameters))
312 (set-window-configuration (nth 2 parameters)))
313 (setq frames-to-delete (cons frame frames-to-delete))))))
314 (frame-list))
315 (mapcar 'delete-frame frames-to-delete)))
316
317 \f
318 ;;;; Convenience functions for accessing and interactively changing
319 ;;;; frame parameters.
320
321 (defun frame-height (&optional frame)
322 "Return number of lines available for display on FRAME.
323 If FRAME is omitted, describe the currently selected frame."
324 (cdr (assq 'height (frame-parameters frame))))
325
326 (defun frame-width (&optional frame)
327 "Return number of columns available for display on FRAME.
328 If FRAME is omitted, describe the currently selected frame."
329 (cdr (assq 'width (frame-parameters frame))))
330
331 (defun set-default-font (font-name)
332 "Set the font of the selected frame to FONT.
333 When called interactively, prompt for the name of the font to use."
334 (interactive "sFont name: ")
335 (modify-frame-parameters (selected-frame)
336 (list (cons 'font font-name))))
337
338 (defun set-frame-background (color-name)
339 "Set the background color of the selected frame to COLOR.
340 When called interactively, prompt for the name of the color to use."
341 (interactive "sColor: ")
342 (modify-frame-parameters (selected-frame)
343 (list (cons 'background-color color-name))))
344
345 (defun set-frame-foreground (color-name)
346 "Set the foreground color of the selected frame to COLOR.
347 When called interactively, prompt for the name of the color to use."
348 (interactive "sColor: ")
349 (modify-frame-parameters (selected-frame)
350 (list (cons 'foreground-color color-name))))
351
352 (defun set-cursor-color (color-name)
353 "Set the text cursor color of the selected frame to COLOR.
354 When called interactively, prompt for the name of the color to use."
355 (interactive "sColor: ")
356 (modify-frame-parameters (selected-frame)
357 (list (cons 'cursor-color color-name))))
358
359 (defun set-pointer-color (color-name)
360 "Set the color of the mouse pointer of the selected frame to COLOR.
361 When called interactively, prompt for the name of the color to use."
362 (interactive "sColor: ")
363 (modify-frame-parameters (selected-frame)
364 (list (cons 'mouse-color color-name))))
365
366 (defun set-auto-raise (arg)
367 "Toggle whether or not the selected frame should auto-raise.
368 With arg, turn auto-raise mode on if and only if arg is positive."
369 (interactive "P")
370 (if (null arg)
371 (setq arg
372 (if (cdr (assq 'auto-raise (frame-parameters (selected-frame))))
373 -1 1)))
374 (modify-frame-parameters (selected-frame)
375 (list (cons 'auto-raise (> arg 0)))))
376
377 (defun set-auto-lower (arg)
378 "Toggle whether or not the selected frame should auto-lower.
379 With arg, turn auto-lower mode on if and only if arg is positive."
380 (interactive "P")
381 (if (null arg)
382 (setq arg
383 (if (cdr (assq 'auto-lower (frame-parameters (selected-frame))))
384 -1 1)))
385 (modify-frame-parameters (selected-frame)
386 (list (cons 'auto-lower (> arg 0)))))
387
388 (defun set-vertical-bar (arg)
389 "Toggle whether or not the selected frame has vertical scrollbars.
390 With arg, turn vertical scrollbars on if and only if arg is positive."
391 (interactive "P")
392 (if (null arg)
393 (setq arg
394 (if (cdr (assq 'vertical-scrollbars
395 (frame-parameters (selected-frame))))
396 -1 1)))
397 (modify-frame-parameters (selected-frame)
398 (list (cons 'vertical-scrollbars (> arg 0)))))
399
400 (defun set-horizontal-bar (arg)
401 "Toggle whether or not the selected frame has horizontal scrollbars.
402 With arg, turn horizontal scrollbars on if and only if arg is positive.
403 Horizontal scrollbars aren't implemented yet."
404 (interactive "P")
405 (error "Horizontal scrollbars aren't implemented yet."))
406
407 \f
408 ;;;; Aliases for backward compatibility with Emacs 18.
409 (fset 'screen-height 'frame-height)
410 (fset 'screen-width 'frame-width)
411
412 (defun set-screen-width (cols &optional pretend)
413 "Obsolete function to change the size of the screen to COLS columns.\n\
414 Optional second arg non-nil means that redisplay should use COLS columns\n\
415 but that the idea of the actual width of the frame should not be changed.\n\
416 This function is provided only for compatibility with Emacs 18; new code\n\
417 should use `set-frame-width instead'."
418 (set-frame-width (selected-frame) cols pretend))
419
420 (defun set-screen-height (lines &optional pretend)
421 "Obsolete function to change the height of the screen to LINES lines.\n\
422 Optional second arg non-nil means that redisplay should use LINES lines\n\
423 but that the idea of the actual height of the screen should not be changed.\n\
424 This function is provided only for compatibility with Emacs 18; new code\n\
425 should use `set-frame-width' instead."
426 (set-frame-height (selected-frame) lines pretend))
427
428 (make-obsolete 'screen-height 'frame-height)
429 (make-obsolete 'screen-width 'frame-width)
430 (make-obsolete 'set-screen-width 'set-frame-width)
431 (make-obsolete 'set-screen-height 'set-frame-height)
432
433 \f
434 ;;;; Key bindings
435 (defvar ctl-x-5-map (make-sparse-keymap)
436 "Keymap for frame commands.")
437 (fset 'ctl-x-5-prefix ctl-x-5-map)
438 (define-key ctl-x-map "5" 'ctl-x-5-prefix)
439
440 (define-key ctl-x-5-map "2" 'new-frame)
441 (define-key ctl-x-5-map "0" 'delete-frame)
442
443 (provide 'frame)
444
445 ;;; frame.el ends here