1 ;;; ediff-wind.el --- window manipulation utilities
2 ;;; Copyright (C) 1994, 1995 Free Software Foundation, Inc.
4 ;; Author: Michael Kifer <kifer@cs.sunysb.edu>
6 ;; This file is part of GNU Emacs.
8 ;; GNU Emacs is free software; you can redistribute it and/or modify
9 ;; it under the terms of the GNU General Public License as published by
10 ;; the Free Software Foundation; either version 2, or (at your option)
13 ;; GNU Emacs is distributed in the hope that it will be useful,
14 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
15 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 ;; GNU General Public License for more details.
18 ;; You should have received a copy of the GNU General Public License
19 ;; along with GNU Emacs; see the file COPYING. If not, write to
20 ;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
26 (defvar ediff-window-setup-function
(if (ediff-window-display-p)
27 'ediff-setup-windows-multiframe
28 'ediff-setup-windows-plain
)
29 "*Function called to set up windows.
30 Ediff provides a choice of two functions: ediff-setup-windows-plain, for
31 doing everything in one frame, and ediff-setup-windows-multiframe,
32 which sets the control panel in a separate frame. Also, if the latter
33 function detects that one of the buffers A/B is seen in some other frame,
34 it will try to keep that buffer in that frame.
36 If you don't like the two functions provided---write your own one.
38 1. It should leave the control buffer current and the control window
40 2. It should set ediff-window-A, ediff-window-B, ediff-window-C,
41 and ediff-control-window to contain window objects that display
42 the corresponding buffers.
43 3. It should accept the following arguments:
44 buffer-A, buffer-B, buffer-C, control-buffer
45 Buffer C may not be used in jobs that compare only two buffers.
46 If you plan to do something fancy, take a close look at how the two
47 provided functions are written.")
49 ;; indicates if we are in a multiframe setup
50 (ediff-defvar-local ediff-multiframe nil
"")
52 ;; Share of the frame occupied by the merge window (buffer C)
53 (ediff-defvar-local ediff-merge-window-share
0.45 "")
55 ;; The control window.
56 (ediff-defvar-local ediff-control-window nil
"")
57 ;; Official window for buffer A
58 (ediff-defvar-local ediff-window-A nil
"")
59 ;; Official window for buffer B
60 (ediff-defvar-local ediff-window-B nil
"")
61 ;; Official window for buffer C
62 (ediff-defvar-local ediff-window-C nil
"")
63 ;; Ediff's window configuration.
64 ;; Used to minimize the need to rearrange windows.
65 (ediff-defvar-local ediff-window-config-saved
"" "")
68 (defvar ediff-split-window-function
'split-window-vertically
69 "*The function used to split the main window between buffer-A and buffer-B.
70 You can set it to a horizontal split instead of the default vertical split
71 by setting this variable to `split-window-horizontally'.
72 You can also have your own function to do fancy splits.
73 This variable has no effect when buffer-A/B are shown in different frames.
74 In this case, Ediff will use those frames to display these buffers.")
76 (defvar ediff-merge-split-window-function
'split-window-horizontally
77 "*The function used to split the main window between buffer-A and buffer-B.
78 You can set it to a vertical split instead of the default horizontal split
79 by setting this variable to `split-window-vertically'.
80 You can also have your own function to do fancy splits.
81 This variable has no effect when buffer-A/B/C are shown in different frames.
82 In this case, Ediff will use those frames to display these buffers.")
84 (defconst ediff-control-frame-parameters
85 (if (ediff-window-display-p)
90 '(user-position . t
) ; Emacs only
91 '(vertical-scroll-bars . nil
) ; Emacs only
92 '(scrollbar-width .
0) ; XEmacs only
93 '(menu-bar-lines .
0) ; Emacs only
94 '(visibility . nil
) ; doesn't work for XEmacs yet
95 ;; don't lower and auto-raise
98 ;; this blocks queries from window manager as to where to put
99 ;; ediff's control frame. we put the frame outside the display,
100 ;; so the initial frame won't jump all over the screen
101 (cons 'top
(if (fboundp 'ediff-display-pixel-height
)
102 (1+ (ediff-display-pixel-height))
104 (cons 'left
(if (fboundp 'ediff-display-pixel-width
)
105 (1+ (ediff-display-pixel-width))
108 "Frame parameters for displaying Ediff Control Panel.
109 Do not specify width and height here. These are computed automatically.")
111 ;; position of the mouse; used to decide whether to warp the mouse into ctl
113 (ediff-defvar-local ediff-mouse-pixel-position nil
"")
116 (defvar ediff-mouse-pixel-threshhold
30
117 "If the user moves mouse more than this many pixels, Ediff won't warp mouse into control window.")
119 (defvar ediff-grab-mouse t
120 "*If t, Ediff will always grab the mouse and put it in the control frame.
121 If 'maybe, Ediff will do it sometimes, but not after operations that require
122 relatively long time. If nil, the mouse will be entirely user's
125 (defvar ediff-control-frame-position-function
'ediff-make-frame-position
126 "Function to call to determine the desired location for the control panel.
127 Expects three parameters: the control buffer, the desired width and height
128 of the control frame. It returns an association list
129 of the form \(\(top . <position>\) \(left . <position>\)\)")
131 (defvar ediff-control-frame-upward-shift
(if ediff-xemacs-p
42 14)
132 "*The upward shift of control frame from the top of buffer A's frame.
134 This is used by the default control frame positioning function,
135 `ediff-make-frame-position'. This variable is provided for easy
136 customization of the default.")
138 (defvar ediff-narrow-control-frame-leftward-shift
(if ediff-xemacs-p
7 3)
139 "*The leftward shift of control frame from the right edge of buf A's frame.
140 Measured in characters.
141 This is used by the default control frame positioning function,
142 `ediff-make-frame-position' to adjust the position of the control frame
143 when it shows the short menu. This variable is provided for easy
144 customization of the default.")
146 (defvar ediff-wide-control-frame-rightward-shift
7
147 "*The rightward shift of control frame from the left edge of buf A's frame.
148 Measured in characters.
149 This is used by the default control frame positioning function,
150 `ediff-make-frame-position' to adjust the position of the control frame
151 when it shows the full menu. This variable is provided for easy
152 customization of the default.")
155 ;; Wide frame display
157 ;; t means Ediff is using wide display
158 (ediff-defvar-local ediff-wide-display-p nil
"")
159 ;; keeps frame config for toggling wide display
160 (ediff-defvar-local ediff-wide-display-orig-parameters nil
161 "Frame parameters to be restored when the user wants to toggle the wide
163 (ediff-defvar-local ediff-wide-display-frame nil
164 "Frame to be used for wide display.")
165 (ediff-defvar-local ediff-make-wide-display-function
'ediff-make-wide-display
166 "The value is a function that is called to create a wide display.
167 The function is called without arguments. It should resize the frame in
168 which buffers A, B, and C are to be displayed, and it should save the old
169 frame parameters in `ediff-wide-display-orig-parameters'.
170 The variable `ediff-wide-display-frame' should be set to contain
171 the frame used for the wide display.")
173 ;; Frame used for the control panel in a windowing system.
174 (ediff-defvar-local ediff-control-frame nil
"")
176 (defvar ediff-prefer-iconified-control-frame nil
177 "*If t, keep control panel iconified when help message is off.
178 This has effect only on a windowing system.
179 If t, hiting `?' to toggle control panel off iconifies it.
181 This is only useful in Emacs and only for certain kinds of window managers,
182 such as TWM and its derivatives, since the window manager must permit
183 keyboard input to go into icons. XEmacs completely ignores keyboard input
184 into icons, regardless of the window manager.")
188 (defun ediff-get-window-by-clicking (wind prev-wind wind-number
)
191 "Select windows by clicking. Please click on Window %d " wind-number
)
192 (while (not (ediff-mouse-event-p (setq event
(ediff-read-event))))
193 (if (sit-for 1) ; if sequence of events, wait till the final word
195 (message "Please click on Window %d " wind-number
))
196 (ediff-read-event) ; discard event
197 (setq wind
(if ediff-xemacs-p
199 (posn-window (event-start event
))))
203 ;; Select the lowest window on the frame.
204 (defun ediff-select-lowest-window ()
206 (select-window (frame-lowest-window))
207 (let* ((lowest-window (selected-window))
208 (bottom-edge (car (cdr (cdr (cdr (window-edges))))))
209 (last-window (save-excursion
210 (other-window -
1) (selected-window)))
213 (let* ((this-window (next-window))
215 (car (cdr (cdr (cdr (window-edges this-window
)))))))
216 (if (< bottom-edge next-bottom-edge
)
218 (setq bottom-edge next-bottom-edge
)
219 (setq lowest-window this-window
)))
221 (select-window this-window
)
222 (if (eq last-window this-window
)
224 (select-window lowest-window
)
225 (setq window-search nil
))))))))
228 ;;; Common window setup routines
230 ;; Set up the window configuration. If POS is given, set the points to
231 ;; the beginnings of the buffers.
232 ;; When 3way comparison is added, this will have to choose the appropriate
233 ;; setup function based on ediff-job-name
234 (defun ediff-setup-windows (buffer-A buffer-B buffer-C control-buffer
)
235 ;; Make sure we are not in the minibuffer window when we try to delete
236 ;; all other windows.
237 (run-hooks 'ediff-before-setup-windows-hook
)
238 (if (eq (selected-window) (minibuffer-window))
241 ;; in case user did a no-no on a tty
242 (or (ediff-window-display-p)
243 (setq ediff-window-setup-function
'ediff-setup-windows-plain
))
245 (or (ediff-keep-window-config control-buffer
)
247 (ediff-eval-in-buffer control-buffer ediff-window-setup-function
)
248 buffer-A buffer-B buffer-C control-buffer
))
249 (run-hooks 'ediff-after-setup-windows-hook
))
251 ;; Just set up 3 windows.
252 ;; Usually used without windowing systems
253 ;; With windowing, we want to use dedicated frames.
254 (defun ediff-setup-windows-plain (buffer-A buffer-B buffer-C control-buffer
)
255 (ediff-eval-in-buffer control-buffer
256 (setq ediff-multiframe nil
))
258 (ediff-setup-windows-plain-merge
259 buffer-A buffer-B buffer-C control-buffer
)
260 (ediff-setup-windows-plain-compare
261 buffer-A buffer-B buffer-C control-buffer
)))
263 (defun ediff-setup-windows-plain-merge (buf-A buf-B buf-C control-buffer
)
264 ;; skip dedicated and unsplittable frames
265 (ediff-destroy-control-frame control-buffer
)
266 (let ((window-min-height 2)
267 split-window-function
268 merge-window-share merge-window-lines
269 wind-A wind-B wind-C
)
270 (ediff-eval-in-buffer control-buffer
271 (setq merge-window-share ediff-merge-window-share
272 ;; this lets us have local versions of ediff-split-window-function
273 split-window-function ediff-split-window-function
))
274 (delete-other-windows)
275 (split-window-vertically)
276 (ediff-select-lowest-window)
277 (ediff-setup-control-buffer control-buffer
)
279 ;; go to the upper window and split it betw A, B, and possibly C
281 (setq merge-window-lines
282 (max 2 (round (* (window-height) merge-window-share
))))
283 (switch-to-buffer buf-A
)
284 (setq wind-A
(selected-window))
286 ;; XEmacs used to have a lot of trouble with display
287 ;; It did't set things right unless we tell it to sit still
289 ;;(if ediff-xemacs-p (sit-for 0))
291 (split-window-vertically (max 2 (- (window-height) merge-window-lines
)))
292 (if (eq (selected-window) wind-A
)
294 (setq wind-C
(selected-window))
295 (switch-to-buffer buf-C
)
297 (select-window wind-A
)
298 (funcall split-window-function
)
300 (if (eq (selected-window) wind-A
)
302 (switch-to-buffer buf-B
)
303 (setq wind-B
(selected-window))
305 (ediff-eval-in-buffer control-buffer
306 (setq ediff-window-A wind-A
307 ediff-window-B wind-B
308 ediff-window-C wind-C
))
310 (ediff-select-lowest-window)
311 (ediff-setup-control-buffer control-buffer
)
315 ;; This function handles all comparison jobs, including 3way jobs
316 (defun ediff-setup-windows-plain-compare (buf-A buf-B buf-C control-buffer
)
317 ;; skip dedicated and unsplittable frames
318 (ediff-destroy-control-frame control-buffer
)
319 (let ((window-min-height 2)
320 split-window-function wind-width-or-height
322 wind-A-start wind-B-start wind-A wind-B wind-C
)
323 (ediff-eval-in-buffer control-buffer
324 (setq wind-A-start
(ediff-overlay-start
325 (ediff-get-value-according-to-buffer-type
326 'A ediff-narrow-bounds
))
327 wind-B-start
(ediff-overlay-start
328 (ediff-get-value-according-to-buffer-type
329 'B ediff-narrow-bounds
))
330 ;; this lets us have local versions of ediff-split-window-function
331 split-window-function ediff-split-window-function
332 three-way-comparison ediff-3way-comparison-job
))
333 (delete-other-windows)
334 (split-window-vertically)
335 (ediff-select-lowest-window)
336 (ediff-setup-control-buffer control-buffer
)
338 ;; go to the upper window and split it betw A, B, and possibly C
340 (switch-to-buffer buf-A
)
341 (setq wind-A
(selected-window))
342 (if three-way-comparison
343 (setq wind-width-or-height
344 (/ (if (eq split-window-function
'split-window-vertically
)
345 (window-height wind-A
)
346 (window-width wind-A
))
349 ;; XEmacs used to have a lot of trouble with display
350 ;; It did't set things right unless we told it to sit still
352 ;;(if ediff-xemacs-p (sit-for 0))
354 (funcall split-window-function wind-width-or-height
)
356 (if (eq (selected-window) wind-A
)
358 (switch-to-buffer buf-B
)
359 (setq wind-B
(selected-window))
361 (if three-way-comparison
363 (funcall split-window-function
) ; equally
364 (if (eq (selected-window) wind-B
)
366 (switch-to-buffer buf-C
)
367 (setq wind-C
(selected-window))))
369 (ediff-eval-in-buffer control-buffer
370 (setq ediff-window-A wind-A
371 ediff-window-B wind-B
372 ediff-window-C wind-C
))
374 ;; It is unlikely that we will want to implement 3way window comparison.
375 ;; So, only buffers A and B are used here.
376 (if ediff-windows-job
378 (set-window-start wind-A wind-A-start
)
379 (set-window-start wind-B wind-B-start
)))
381 (ediff-select-lowest-window)
382 (ediff-setup-control-buffer control-buffer
)
386 ;; dispatch the appropriate window setup function
387 (defun ediff-setup-windows-multiframe (buf-A buf-B buf-C control-buf
)
388 (ediff-eval-in-buffer control-buf
389 (setq ediff-multiframe t
))
391 (ediff-setup-windows-multiframe-merge buf-A buf-B buf-C control-buf
)
392 (ediff-setup-windows-multiframe-compare buf-A buf-B buf-C control-buf
)))
394 (defun ediff-setup-windows-multiframe-merge (buf-A buf-B buf-C control-buf
)
396 ;;; If A and B are in the same frame but C's frame is different--- use one
397 ;;; frame for A and B and use a separate frame for C.
398 ;;; If C's frame is non-existent, then: if the first suitable
399 ;;; non-dedicated frame is different from A&B's, then use it for C.
400 ;;; Otherwise, put A,B, and C in one frame.
401 ;;; If buffers A, B, C are is separate frames, use them to display these
404 ;; Skip dedicated or iconified frames.
405 ;; Unsplittable frames are taken care of later.
406 (ediff-skip-unsuitable-frames 'ok-unsplittable
)
408 (let* ((window-min-height 2)
409 (wind-A (ediff-get-visible-buffer-window buf-A
))
410 (wind-B (ediff-get-visible-buffer-window buf-B
))
411 (wind-C (ediff-get-visible-buffer-window buf-C
))
412 (frame-A (if wind-A
(window-frame wind-A
)))
413 (frame-B (if wind-B
(window-frame wind-B
)))
414 (frame-C (if wind-C
(window-frame wind-C
)))
415 ;; on wide display, do things in one frame
417 (ediff-eval-in-buffer control-buf ediff-wide-display-p
))
418 ;; this lets us have local versions of ediff-split-window-function
419 (split-window-function
420 (ediff-eval-in-buffer control-buf ediff-split-window-function
))
421 (orig-wind (selected-window))
422 (orig-frame (selected-frame))
423 (use-same-frame (or force-one-frame
424 (eq frame-A
(or frame-C orig-frame
))
425 (eq frame-B
(or frame-C orig-frame
))
426 (not (frame-live-p frame-A
))
427 (not (frame-live-p frame-B
))
428 (and (eq frame-A frame-B
)
429 (not (frame-live-p frame-C
)))
431 (use-same-frame-for-AB (and (not use-same-frame
)
432 (eq frame-A frame-B
)))
433 (merge-window-share (ediff-eval-in-buffer control-buf
434 ediff-merge-window-share
))
436 designated-minibuffer-frame
437 done-A done-B done-C
)
440 (if (and (window-live-p wind-A
)
441 (null use-same-frame
)
442 (null use-same-frame-for-AB
))
444 (select-window wind-A
)
445 (delete-other-windows)
446 (switch-to-buffer buf-A
)
447 (setq wind-A
(selected-window))
451 (if (and (window-live-p wind-B
) (null use-same-frame
)) ; buf B on its own
453 (select-window wind-B
)
454 (delete-other-windows)
455 (switch-to-buffer buf-B
)
456 (setq wind-B
(selected-window))
460 (if (and (window-live-p wind-C
) (null use-same-frame
)) ; buf C on its own
462 (select-window wind-C
)
463 (delete-other-windows)
464 (switch-to-buffer buf-C
)
465 (setq wind-C
(selected-window))
468 (if use-same-frame-for-AB
470 (select-frame frame-A
)
471 (switch-to-buffer buf-A
)
472 (delete-other-windows)
473 (setq wind-A
(selected-window))
475 (funcall split-window-function
)
476 (if (eq (selected-window) wind-A
)
478 (switch-to-buffer buf-B
)
479 (setq wind-B
(selected-window))
485 (let ((curr-frame (selected-frame))
486 (window-min-height 2))
487 ;; avoid dedicated and non-splittable windows
488 (ediff-skip-unsuitable-frames)
489 (or (eq curr-frame
(selected-frame))
493 orig-wind
(selected-window)))
495 ;; set the right frame
496 (cond (wind-A (select-window wind-A
))
497 (wind-B (select-window wind-B
))
498 (wind-C (select-window wind-C
))
499 (t (select-window orig-wind
)))
500 (delete-other-windows)
501 (setq merge-window-lines
502 (max 2 (round (* (window-height) merge-window-share
))))
503 (switch-to-buffer buf-A
)
504 (setq wind-A
(selected-window))
506 ;; XEmacs used to have a lot of trouble with display
507 ;; It did't set things right unless we told it to catch breath
508 ;;(if ediff-xemacs-p (sit-for 0))
510 (split-window-vertically
511 (max 2 (- (window-height) merge-window-lines
)))
512 (if (eq (selected-window) wind-A
)
514 (setq wind-C
(selected-window))
515 (switch-to-buffer buf-C
)
517 (select-window wind-A
)
519 (funcall split-window-function
)
520 (if (eq (selected-window) wind-A
)
522 (switch-to-buffer buf-B
)
523 (setq wind-B
(selected-window))
530 (or done-A
; Buf A to be set in its own frame
531 (progn ; It was not set up yet as it wasn't visible
532 (select-window orig-wind
)
533 (delete-other-windows)
534 (switch-to-buffer buf-A
)
535 (setq wind-A
(selected-window))
537 (or done-B
; Buf B to be set in its own frame
538 (progn ; It was not set up yet as it wasn't visible
539 (select-window orig-wind
)
540 (delete-other-windows)
541 (switch-to-buffer buf-B
)
542 (setq wind-B
(selected-window))
545 (or done-C
; Buf C to be set in its own frame.
546 (progn ; It was not set up yet as it wasn't visible
547 (select-window orig-wind
)
548 (delete-other-windows)
549 (switch-to-buffer buf-C
)
550 (setq wind-C
(selected-window))
553 (ediff-eval-in-buffer control-buf
554 (setq ediff-window-A wind-A
555 ediff-window-B wind-B
556 ediff-window-C wind-C
)
557 (setq frame-A
(window-frame ediff-window-A
)
558 designated-minibuffer-frame
559 (window-frame (minibuffer-window frame-A
))))
561 (ediff-setup-control-frame control-buf designated-minibuffer-frame
)
565 ;; Window setup for all comparison jobs, including 3way comparisons
566 (defun ediff-setup-windows-multiframe-compare (buf-A buf-B buf-C control-buf
)
568 ;;; If a buffer is seen in a frame, use that frame for that buffer.
569 ;;; If it is not seen, use the current frame.
570 ;;; If both buffers are not seen, they share the current frame. If one
571 ;;; of the buffers is not seen, it is placed in the current frame (where
572 ;;; ediff started). If that frame is displaying the other buffer, it is
573 ;;; shared between the two buffers.
574 ;;; However, if we decide to put both buffers in one frame
575 ;;; and the selected frame isn't splittable, we create a new frame and
576 ;;; put both buffers there, event if one of this buffers is visible in
579 ;; Skip dedicated or iconified frames.
580 ;; Unsplittable frames are taken care of later.
581 (ediff-skip-unsuitable-frames 'ok-unsplittable
)
583 (let* ((window-min-height 2)
584 (wind-A (ediff-get-visible-buffer-window buf-A
))
585 (wind-B (ediff-get-visible-buffer-window buf-B
))
586 (wind-C (ediff-get-visible-buffer-window buf-C
))
587 (frame-A (if wind-A
(window-frame wind-A
)))
588 (frame-B (if wind-B
(window-frame wind-B
)))
589 (frame-C (if wind-C
(window-frame wind-C
)))
590 (ctl-frame-exists-p (ediff-eval-in-buffer control-buf
591 (frame-live-p ediff-control-frame
)))
592 ;; on wide display, do things in one frame
594 (ediff-eval-in-buffer control-buf ediff-wide-display-p
))
595 ;; this lets us have local versions of ediff-split-window-function
596 (split-window-function
597 (ediff-eval-in-buffer control-buf ediff-split-window-function
))
598 (three-way-comparison
599 (ediff-eval-in-buffer control-buf ediff-3way-comparison-job
))
600 (orig-wind (selected-window))
601 (use-same-frame (or force-one-frame
603 (if three-way-comparison
604 (or (eq frame-A frame-C
)
606 (not (frame-live-p frame-A
))
607 (not (frame-live-p frame-B
))
608 (not (frame-live-p frame-C
))))
609 (and (not (frame-live-p frame-B
))
610 (or ctl-frame-exists-p
611 (eq frame-A
(selected-frame))))
612 (and (not (frame-live-p frame-A
))
613 (or ctl-frame-exists-p
614 (eq frame-B
(selected-frame))))))
615 wind-A-start wind-B-start
616 designated-minibuffer-frame
617 done-A done-B done-C
)
619 (ediff-eval-in-buffer control-buf
620 (setq wind-A-start
(ediff-overlay-start
621 (ediff-get-value-according-to-buffer-type
622 'A ediff-narrow-bounds
))
623 wind-B-start
(ediff-overlay-start
624 (ediff-get-value-according-to-buffer-type
625 'B ediff-narrow-bounds
))))
627 (if (and (window-live-p wind-A
) (null use-same-frame
)) ; buf-A on its own
629 (select-window wind-A
)
630 (delete-other-windows)
631 (switch-to-buffer buf-A
)
632 (setq wind-A
(selected-window))
635 (if (and (window-live-p wind-B
) (null use-same-frame
)) ; buf B on its own
637 (select-window wind-B
)
638 (delete-other-windows)
639 (switch-to-buffer buf-B
)
640 (setq wind-B
(selected-window))
643 (if (and (window-live-p wind-C
) (null use-same-frame
)) ; buf C on its own
645 (select-window wind-C
)
646 (delete-other-windows)
647 (switch-to-buffer buf-C
)
648 (setq wind-C
(selected-window))
652 (let ((curr-frame (selected-frame))
653 ;; this affects 3way setups only
654 wind-width-or-height
)
655 ;; avoid dedicated and non-splittable windows
656 (ediff-skip-unsuitable-frames)
657 (or (eq curr-frame
(selected-frame))
661 orig-wind
(selected-window)))
663 ;; set the right frame
664 (cond (wind-A (select-window wind-A
))
665 (wind-B (select-window wind-B
))
666 (wind-C (select-window wind-C
))
667 (t (select-window orig-wind
)))
668 (delete-other-windows)
669 (switch-to-buffer buf-A
)
670 (setq wind-A
(selected-window))
672 ;; XEmacs used to have a lot of trouble with display
673 ;; It didn't set things right unless we told it to catch breath
674 ;;(if ediff-xemacs-p (sit-for 0))
676 (if three-way-comparison
677 (setq wind-width-or-height
679 (if (eq split-window-function
'split-window-vertically
)
680 (window-height wind-A
)
681 (window-width wind-A
))
684 (funcall split-window-function wind-width-or-height
)
685 (if (eq (selected-window) wind-A
)
687 (switch-to-buffer buf-B
)
688 (setq wind-B
(selected-window))
690 (if three-way-comparison
692 (funcall split-window-function
) ; equally
693 (if (memq (selected-window) (list wind-A wind-B
))
695 (switch-to-buffer buf-C
)
696 (setq wind-C
(selected-window))))
702 (or done-A
; Buf A to be set in its own frame
703 (progn ; It was not set up yet as it wasn't visible
704 (select-window orig-wind
)
705 (delete-other-windows)
706 (switch-to-buffer buf-A
)
707 (setq wind-A
(selected-window))
709 (or done-B
; Buf B to be set in its own frame
710 (progn ; It was not set up yet as it wasn't visible
711 (select-window orig-wind
)
712 (delete-other-windows)
713 (switch-to-buffer buf-B
)
714 (setq wind-B
(selected-window))
717 (if three-way-comparison
718 (or done-C
; Buf C to be set in its own frame
719 (progn ; It was not set up yet as it wasn't visible
720 (select-window orig-wind
)
721 (delete-other-windows)
722 (switch-to-buffer buf-C
)
723 (setq wind-C
(selected-window))
726 (ediff-eval-in-buffer control-buf
727 (setq ediff-window-A wind-A
728 ediff-window-B wind-B
729 ediff-window-C wind-C
)
731 (setq frame-A
(window-frame ediff-window-A
)
732 designated-minibuffer-frame
733 (window-frame (minibuffer-window frame-A
))))
735 ;; It is unlikely that we'll implement ediff-windows that would compare
736 ;; 3 windows at once. So, we don't use buffer C here.
737 (if ediff-windows-job
739 (set-window-start wind-A wind-A-start
)
740 (set-window-start wind-B wind-B-start
)))
742 (ediff-setup-control-frame control-buf designated-minibuffer-frame
)
745 ;; skip unsplittable and dedicated windows
746 ;; create a new splittable frame if none is found
747 (defun ediff-skip-unsuitable-frames (&optional ok-unsplittable
)
748 (if (ediff-window-display-p)
750 (while (and (not (eq (selected-window) last-window
))
752 (window-dedicated-p (selected-window))
753 (ediff-frame-iconified-p (selected-frame))
756 (ediff-frame-unsplittable-p (selected-frame)))))
757 ;; remember where started
758 (or last-window
(setq last-window
(selected-window)))
761 (if (eq (selected-window) last-window
)
762 ;; fed up, no appropriate frame
765 (select-frame (make-frame '((unsplittable)))))))))
767 ;; Prepare or refresh control frame
768 (defun ediff-setup-control-frame (ctl-buffer designated-minibuffer-frame
)
769 (let ((window-min-height 2)
770 ctl-frame-iconified-p dont-iconify-ctl-frame deiconify-ctl-frame
771 ctl-frame old-ctl-frame lines user-grabbed-mouse
772 fheight fwidth adjusted-parameters
)
774 (ediff-eval-in-buffer ctl-buffer
775 (if ediff-xemacs-p
(set-buffer-menubar nil
))
776 ;;(setq user-grabbed-mouse (ediff-user-grabbed-mouse))
777 (run-hooks 'ediff-before-setup-control-frame-hook
))
779 (setq old-ctl-frame
(ediff-eval-in-buffer ctl-buffer ediff-control-frame
))
780 ;; Delete the old ctl frame and get a new ctl frame.
781 ;; The old ctl frame is deleted to let emacs reset default minibuffer
782 ;; frame or when the ctl frame needs to be moved.
783 ;; The old frame isn't reused, since ediff-setup-control-frame is called
784 ;; very rarely, so the overhead is minimal.
785 (if (frame-live-p old-ctl-frame
) (delete-frame old-ctl-frame
))
787 ;; new ctl frame should be created while ctl-buff is current, so that
788 ;; the local default-minibuffer-frame will be consulted and
789 ;; that ediff-control-frame-parameters will have the right value.
790 (ediff-eval-in-buffer ctl-buffer
791 (let ((default-minibuffer-frame designated-minibuffer-frame
))
792 (setq ctl-frame
(make-frame ediff-control-frame-parameters
)
793 ediff-control-frame ctl-frame
)))
795 (setq ctl-frame-iconified-p
(ediff-frame-iconified-p ctl-frame
))
796 (select-frame ctl-frame
)
797 (if (window-dedicated-p (selected-window))
799 (delete-other-windows)
800 (switch-to-buffer ctl-buffer
))
802 ;; must be before ediff-setup-control-buffer
803 ;; just a precaution--we should be in ctl-buffer already
804 (ediff-eval-in-buffer ctl-buffer
805 (make-local-variable 'frame-title-format
)
806 (make-local-variable 'frame-icon-title-format
) ; XEmacs
807 (make-local-variable 'icon-title-format
)) ; Emacs
809 (ediff-setup-control-buffer ctl-buffer
)
810 (setq dont-iconify-ctl-frame
811 (not (string= ediff-help-message ediff-brief-help-message
)))
812 (setq deiconify-ctl-frame
813 (and (eq this-command
'ediff-toggle-help
)
814 dont-iconify-ctl-frame
))
816 ;; 1 more line for the modeline
817 (setq lines
(if ediff-xemacs-p
818 (+ 2 (count-lines (point-min) (point-max)))
819 (1+ (count-lines (point-min) (point-max))))
821 fwidth
(+ (ediff-help-message-line-length) 2)
822 adjusted-parameters
(append (list
825 (cons 'height fheight
))
827 ediff-control-frame-position-function
828 ctl-buffer fwidth fheight
)))
829 (if ediff-prefer-long-help-message
830 (setq adjusted-parameters
831 (cons '(auto-raise . nil
) adjusted-parameters
)))
833 ;; In XEmacs, buffer menubar needs to be killed before frame parameters
837 (set-specifier top-toolbar-height
(list ctl-frame
0))
838 (set-specifier bottom-toolbar-height
(list ctl-frame
0))
839 (set-specifier left-toolbar-width
(list ctl-frame
0))
840 (set-specifier right-toolbar-width
(list ctl-frame
0))
841 ;; XEmacs needed a redisplay, as it had trouble setting
842 ;; height correctly otherwise.
846 ;; Under OS/2 (emx) we have to call modify frame parameters twice, in
847 ;; order to make sure that at least once we do it for non-iconified
848 ;; frame. If appears that in the OS/2 port of Emacs, one can't modify
849 ;; frame parameters of iconified frames.
850 (if (eq system-type
'emx
)
851 (modify-frame-parameters ctl-frame adjusted-parameters
))
853 (goto-char (point-min))
855 (modify-frame-parameters ctl-frame adjusted-parameters
)
857 ;; This works around a bug in 19.25 and earlier. There, if frame gets
858 ;; iconified, the current buffer changes to that of the frame that
859 ;; becomes exposed as a result of this iconification.
860 ;; So, we make sure the current buffer doesn't change.
861 (select-frame ctl-frame
)
862 (ediff-refresh-control-frame)
864 (cond ((and ediff-prefer-iconified-control-frame
865 (not ctl-frame-iconified-p
) (not dont-iconify-ctl-frame
))
866 (iconify-frame ctl-frame
))
867 ((or deiconify-ctl-frame
(not ctl-frame-iconified-p
))
868 (raise-frame ctl-frame
)))
871 (set-window-buffer-dedicated (selected-window) ctl-buffer
)
872 (set-window-dedicated-p (selected-window) t
))
874 ;; resynch so the cursor will move to control frame
875 ;; per RMS suggestion
878 (while (and (not (frame-visible-p ctl-frame
)) (> count
0))
879 (setq count
(1- count
))
882 (or (ediff-frame-iconified-p ctl-frame
)
883 ;; don't warp the mouse, unless ediff-grab-mouse = t
884 (ediff-reset-mouse ctl-frame
(not (eq ediff-grab-mouse t
))))
887 (ediff-eval-in-buffer ctl-buffer
888 (make-local-variable 'select-frame-hook
)
889 (add-hook 'select-frame-hook
'ediff-xemacs-select-frame-hook
)
892 (ediff-eval-in-buffer ctl-buffer
893 (run-hooks 'ediff-after-setup-control-frame-hook
))
896 (defun ediff-destroy-control-frame (ctl-buffer)
897 (ediff-eval-in-buffer ctl-buffer
898 (if (and (ediff-window-display-p) (frame-live-p ediff-control-frame
))
899 (let ((ctl-frame ediff-control-frame
))
901 (set-buffer-menubar default-menubar
))
902 (setq ediff-control-frame nil
)
903 (delete-frame ctl-frame
)
905 (ediff-skip-unsuitable-frames)
906 ;;(ediff-reset-mouse nil)
910 ;; finds a good place to clip control frame
911 (defun ediff-make-frame-position (ctl-buffer ctl-frame-width ctl-frame-height
)
912 (ediff-eval-in-buffer ctl-buffer
913 (let* ((frame-A (window-frame ediff-window-A
))
914 (frame-A-parameters (frame-parameters frame-A
))
915 (frame-A-top (eval (cdr (assoc 'top frame-A-parameters
))))
916 (frame-A-left (eval (cdr (assoc 'left frame-A-parameters
))))
917 (frame-A-width (frame-width frame-A
))
918 (ctl-frame ediff-control-frame
)
919 horizontal-adjustment upward-adjustment
920 ctl-frame-top ctl-frame-left
)
922 ;; Multiple control frames are clipped based on the value of
923 ;; ediff-control-buffer-number. This is done in order not to obscure
924 ;; other active control panels.
925 (setq horizontal-adjustment
(* 2 ediff-control-buffer-number
)
926 upward-adjustment
(* -
14 ediff-control-buffer-number
))
929 (- frame-A-top upward-adjustment ediff-control-frame-upward-shift
)
932 (if ediff-prefer-long-help-message
933 (* (ediff-frame-char-width ctl-frame
)
934 (+ ediff-wide-control-frame-rightward-shift
935 horizontal-adjustment
))
936 (- (* frame-A-width
(ediff-frame-char-width frame-A
))
937 (* (ediff-frame-char-width ctl-frame
)
939 ediff-narrow-control-frame-leftward-shift
940 horizontal-adjustment
))))))
941 ;; keep ctl frame within the visible bounds
942 (setq ctl-frame-top
(max ctl-frame-top
1)
943 ctl-frame-left
(max ctl-frame-left
1))
946 (- (ediff-display-pixel-height)
947 (* 2 ctl-frame-height
948 (ediff-frame-char-height ctl-frame
))))
951 (- (ediff-display-pixel-width)
952 (* ctl-frame-width
(ediff-frame-char-width ctl-frame
)))))
954 (list (cons 'top ctl-frame-top
)
955 (cons 'left ctl-frame-left
))
958 (defun ediff-xemacs-select-frame-hook ()
959 (if (and (equal (selected-frame) ediff-control-frame
)
960 (not ediff-prefer-long-help-message
))
961 (raise-frame ediff-control-frame
)))
963 (defun ediff-make-wide-display ()
964 "Construct an alist of parameters for the wide display.
965 Saves the old frame parameters in `ediff-wide-display-orig-parameters'.
966 The frame to be resized is kept in `ediff-wide-display-frame'.
967 This function modifies only the left margin and the width of the display.
968 It assumes that it is called from within the control buffer."
969 (if (not (fboundp 'ediff-display-pixel-width
))
970 (error "Can't determine display width."))
971 (let* ((frame-A (window-frame ediff-window-A
))
972 (frame-A-params (frame-parameters frame-A
))
973 (cw (ediff-frame-char-width frame-A
))
974 (wd (- (/ (ediff-display-pixel-width) cw
) 5)))
975 (setq ediff-wide-display-orig-parameters
976 (list (cons 'left
(max 0 (eval (cdr (assoc 'left frame-A-params
)))))
977 (cons 'width
(cdr (assoc 'width frame-A-params
))))
978 ediff-wide-display-frame frame-A
)
979 (modify-frame-parameters frame-A
(list (cons 'left cw
)
984 ;; Revise the mode line to display which difference we have selected
985 ;; Also resets modelines of buffers A/B, since they may be clobbered by
986 ;; anothe invocations of Ediff.
987 (defun ediff-refresh-mode-lines ()
988 (let (buf-A-state-diff buf-B-state-diff buf-C-state-diff buf-C-state-merge
)
990 (if (ediff-valid-difference-p)
992 buf-C-state-diff
(ediff-get-state-of-diff ediff-current-difference
'C
)
993 buf-C-state-merge
(ediff-get-state-of-merge ediff-current-difference
)
994 buf-A-state-diff
(ediff-get-state-of-diff ediff-current-difference
'A
)
995 buf-B-state-diff
(ediff-get-state-of-diff ediff-current-difference
'B
)
996 buf-A-state-diff
(if buf-A-state-diff
997 (format "[%s] " buf-A-state-diff
)
999 buf-B-state-diff
(if buf-B-state-diff
1000 (format "[%s] " buf-B-state-diff
)
1002 buf-C-state-diff
(if (and (ediff-buffer-live-p ediff-buffer-C
)
1003 (or buf-C-state-diff buf-C-state-merge
))
1005 (or buf-C-state-diff
"")
1006 (if buf-C-state-merge
1007 (concat " " buf-C-state-merge
)
1009 (if (ediff-get-state-of-ancestor
1010 ediff-current-difference
)
1015 (setq buf-A-state-diff
""
1017 buf-C-state-diff
""))
1019 ;; control buffer format
1020 (setq mode-line-format
1021 (list (if (ediff-narrow-control-frame-p) " " "-- ")
1022 mode-line-buffer-identification
1024 ;; control buffer id
1025 (setq mode-line-buffer-identification
1026 (if (ediff-narrow-control-frame-p)
1027 (ediff-make-narrow-control-buffer-id 'skip-name
)
1028 (ediff-make-wide-control-buffer-id)))
1029 ;; Force mode-line redisplay
1030 (force-mode-line-update)
1032 (if (and (ediff-window-display-p) (frame-live-p ediff-control-frame
))
1033 (ediff-refresh-control-frame))
1035 (ediff-eval-in-buffer ediff-buffer-A
1036 (setq ediff-diff-status buf-A-state-diff
)
1037 (ediff-strip-mode-line-format)
1038 (setq mode-line-format
1039 (list " A: " 'ediff-diff-status mode-line-format
))
1040 (force-mode-line-update))
1041 (ediff-eval-in-buffer ediff-buffer-B
1042 (setq ediff-diff-status buf-B-state-diff
)
1043 (ediff-strip-mode-line-format)
1044 (setq mode-line-format
1045 (list " B: " 'ediff-diff-status mode-line-format
))
1046 (force-mode-line-update))
1048 (ediff-eval-in-buffer ediff-buffer-C
1049 (setq ediff-diff-status buf-C-state-diff
)
1050 (ediff-strip-mode-line-format)
1051 (setq mode-line-format
1052 (list " C: " 'ediff-diff-status mode-line-format
))
1053 (force-mode-line-update)))
1054 (if (ediff-buffer-live-p ediff-ancestor-buffer
)
1055 (ediff-eval-in-buffer ediff-ancestor-buffer
1056 (ediff-strip-mode-line-format)
1057 ;; we keep the second dummy string in the mode line format of the
1058 ;; ancestor, since for other buffers Ediff prepends 2 strings and
1059 ;; ediff-strip-mode-line-format expects that.
1060 (setq mode-line-format
1062 (cond ((not (stringp buf-C-state-merge
))
1064 ((string-match "prefer-A" buf-C-state-merge
)
1066 ((string-match "prefer-B" buf-C-state-merge
)
1069 mode-line-format
))))
1073 (defun ediff-refresh-control-frame ()
1074 (setq frame-title-format
(ediff-make-narrow-control-buffer-id)
1075 frame-icon-title-format
(ediff-make-narrow-control-buffer-id) ; XEmacs
1076 icon-title-format
(ediff-make-narrow-control-buffer-id)) ; Emacs
1077 ;; the emacs part will be modified once the 'name and 'title
1078 ;; frame parameters are separated
1080 (modify-frame-parameters
1082 (list (cons 'name
(ediff-make-narrow-control-buffer-id))))
1083 ;; force an update of the frame title
1084 (modify-frame-parameters ediff-control-frame
'(()))))
1087 (defun ediff-make-narrow-control-buffer-id (&optional skip-name
)
1092 (cdr (assoc 'name ediff-control-frame-parameters
))
1093 ediff-control-buffer-suffix
))
1094 (cond ((< ediff-current-difference
0)
1095 (format " _/%d" ediff-number-of-differences
))
1096 ((>= ediff-current-difference ediff-number-of-differences
)
1097 (format " $/%d" ediff-number-of-differences
))
1100 (1+ ediff-current-difference
)
1101 ediff-number-of-differences
)))))
1103 (defun ediff-make-wide-control-buffer-id ()
1104 (cond ((< ediff-current-difference
0)
1105 (list (format "%%b At start of %d diffs"
1106 ediff-number-of-differences
)))
1107 ((>= ediff-current-difference ediff-number-of-differences
)
1108 (list (format "%%b At end of %d diffs"
1109 ediff-number-of-differences
)))
1111 (list (format "%%b diff %d of %d"
1112 (1+ ediff-current-difference
)
1113 ediff-number-of-differences
)))))
1117 ;; If buff is not live, return nil
1118 (defun ediff-get-visible-buffer-window (buff)
1119 (if (ediff-buffer-live-p buff
)
1121 (get-buffer-window buff t
)
1122 (get-buffer-window buff
'visible
))))
1124 ;;; Functions to decide when to redraw windows
1127 (defun ediff-keep-window-config (control-buf)
1128 (and (eq control-buf
(current-buffer))
1129 (/= (buffer-size) 0)
1130 (ediff-eval-in-buffer control-buf
1131 (let ((ctl-wind ediff-control-window
)
1132 (A-wind ediff-window-A
)
1133 (B-wind ediff-window-B
)
1134 (C-wind ediff-window-C
))
1137 (ediff-window-visible-p A-wind
)
1138 (ediff-window-visible-p B-wind
)
1139 ;; if buffer C is defined then take it into account
1140 (or (not ediff-3way-job
)
1141 (ediff-window-visible-p C-wind
))
1142 (eq (window-buffer A-wind
) ediff-buffer-A
)
1143 (eq (window-buffer B-wind
) ediff-buffer-B
)
1144 (or (not ediff-3way-job
)
1145 (eq (window-buffer C-wind
) ediff-buffer-C
))
1146 (string= ediff-window-config-saved
1147 (format "%S%S%S%S%S%S%S"
1148 ctl-wind A-wind B-wind C-wind
1149 ediff-split-window-function
1150 (ediff-multiframe-setup-p)
1151 ediff-wide-display-p
)))))))
1154 (provide 'ediff-wind
)
1157 ;;; ediff-wind.el ends here