]> code.delx.au - gnu-emacs/blob - lisp/vc/ediff-wind.el
Merge from trunk
[gnu-emacs] / lisp / vc / ediff-wind.el
1 ;;; ediff-wind.el --- window manipulation utilities
2
3 ;; Copyright (C) 1994-1997, 2000-2012 Free Software Foundation, Inc.
4
5 ;; Author: Michael Kifer <kifer@cs.stonybrook.edu>
6 ;; Package: ediff
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 3 of the License, or
13 ;; (at your option) 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. If not, see <http://www.gnu.org/licenses/>.
22
23 ;;; Commentary:
24
25 ;;; Code:
26
27
28 ;; Compiler pacifier
29 (defvar icon-title-format)
30 (defvar top-toolbar-height)
31 (defvar bottom-toolbar-height)
32 (defvar left-toolbar-height)
33 (defvar right-toolbar-height)
34 (defvar left-toolbar-width)
35 (defvar right-toolbar-width)
36 (defvar default-menubar)
37 (defvar top-gutter)
38 (defvar frame-icon-title-format)
39 (defvar ediff-diff-status)
40
41 ;; declare-function does not exist in XEmacs
42 (eval-and-compile
43 (unless (fboundp 'declare-function) (defmacro declare-function (&rest r))))
44
45 (eval-when-compile
46 (require 'ediff-util)
47 (require 'ediff-help))
48 ;; end pacifier
49
50 (require 'ediff-init)
51
52 ;; be careful with ediff-tbar
53 (if (featurep 'xemacs)
54 (require 'ediff-tbar)
55 (defun ediff-compute-toolbar-width () 0))
56
57 (defgroup ediff-window nil
58 "Ediff window manipulation."
59 :prefix "ediff-"
60 :group 'ediff
61 :group 'frames)
62
63
64 ;; Determine which window setup function to use based on current window system.
65 (defun ediff-choose-window-setup-function-automatically ()
66 (declare (obsolete ediff-setup-windows-default "24.3"))
67 (if (ediff-window-display-p)
68 'ediff-setup-windows-multiframe
69 'ediff-setup-windows-plain))
70
71 (defcustom ediff-window-setup-function 'ediff-setup-windows-default
72 "Function called to set up windows.
73 Ediff provides a choice of three functions:
74 (1) `ediff-setup-windows-multiframe', which sets the control panel
75 in a separate frame.
76 (2) `ediff-setup-windows-plain', which does everything in one frame
77 (3) `ediff-setup-windows-default' (the default), which does (1)
78 on a graphical display and (2) on a text terminal.
79
80 The command \\[ediff-toggle-multiframe] can be used to toggle
81 between the multiframe display and the single frame display. If
82 the multiframe function detects that one of the buffers A/B is
83 seen in some other frame, it will try to keep that buffer in that
84 frame.
85
86 If you don't like any of the two provided functions, write your own one.
87 The basic guidelines:
88 1. It should leave the control buffer current and the control window
89 selected.
90 2. It should set `ediff-window-A', `ediff-window-B', `ediff-window-C',
91 and `ediff-control-window' to contain window objects that display
92 the corresponding buffers.
93 3. It should accept the following arguments:
94 buffer-A, buffer-B, buffer-C, control-buffer
95 Buffer C may not be used in jobs that compare only two buffers.
96 If you plan to do something fancy, take a close look at how the two
97 provided functions are written."
98 :type '(choice (const :tag "Choose Automatically" ediff-setup-windows-default)
99 (const :tag "Multi Frame" ediff-setup-windows-multiframe)
100 (const :tag "Single Frame" ediff-setup-windows-plain)
101 (function :tag "Other function"))
102 :group 'ediff-window
103 :version "24.3")
104
105 ;; indicates if we are in a multiframe setup
106 (ediff-defvar-local ediff-multiframe nil "")
107
108 ;; Share of the frame occupied by the merge window (buffer C)
109 (ediff-defvar-local ediff-merge-window-share 0.45 "")
110
111 ;; The control window.
112 (ediff-defvar-local ediff-control-window nil "")
113 ;; Official window for buffer A
114 (ediff-defvar-local ediff-window-A nil "")
115 ;; Official window for buffer B
116 (ediff-defvar-local ediff-window-B nil "")
117 ;; Official window for buffer C
118 (ediff-defvar-local ediff-window-C nil "")
119 ;; Ediff's window configuration.
120 ;; Used to minimize the need to rearrange windows.
121 (ediff-defvar-local ediff-window-config-saved "" "")
122
123 ;; Association between buff-type and ediff-window-*
124 (defconst ediff-window-alist
125 '((A . ediff-window-A)
126 (?A . ediff-window-A)
127 (B . ediff-window-B)
128 (?B . ediff-window-B)
129 (C . ediff-window-C)
130 (?C . ediff-window-C)))
131
132
133 (defcustom ediff-split-window-function 'split-window-vertically
134 "The function used to split the main window between buffer-A and buffer-B.
135 You can set it to a horizontal split instead of the default vertical split
136 by setting this variable to `split-window-horizontally'.
137 You can also have your own function to do fancy splits.
138 This variable has no effect when buffer-A/B are shown in different frames.
139 In this case, Ediff will use those frames to display these buffers."
140 :type '(choice
141 (const :tag "Split vertically" split-window-vertically)
142 (const :tag "Split horizontally" split-window-horizontally)
143 function)
144 :group 'ediff-window)
145
146 (defcustom ediff-merge-split-window-function 'split-window-horizontally
147 "The function used to split the main window between buffer-A and buffer-B.
148 You can set it to a vertical split instead of the default horizontal split
149 by setting this variable to `split-window-vertically'.
150 You can also have your own function to do fancy splits.
151 This variable has no effect when buffer-A/B/C are shown in different frames.
152 In this case, Ediff will use those frames to display these buffers."
153 :type '(choice
154 (const :tag "Split vertically" split-window-vertically)
155 (const :tag "Split horizontally" split-window-horizontally)
156 function)
157 :group 'ediff-window)
158
159 ;; Definitions hidden from the compiler by compat wrappers.
160 (declare-function ediff-display-pixel-width "ediff-init")
161 (declare-function ediff-display-pixel-height "ediff-init")
162
163 (defconst ediff-control-frame-parameters
164 (list
165 '(name . "Ediff")
166 ;;'(unsplittable . t)
167 '(minibuffer . nil)
168 '(user-position . t) ; Emacs only
169 '(vertical-scroll-bars . nil) ; Emacs only
170 '(scrollbar-width . 0) ; XEmacs only
171 '(scrollbar-height . 0) ; XEmacs only
172 '(menu-bar-lines . 0) ; Emacs only
173 '(tool-bar-lines . 0) ; Emacs 21+ only
174 '(left-fringe . 0)
175 '(right-fringe . 0)
176 ;; don't lower but auto-raise
177 '(auto-lower . nil)
178 '(auto-raise . t)
179 '(visibility . nil)
180 ;; make initial frame small to avoid distraction
181 '(width . 1) '(height . 1)
182 ;; this blocks queries from window manager as to where to put
183 ;; ediff's control frame. we put the frame outside the display,
184 ;; so the initial frame won't jump all over the screen
185 (cons 'top (if (fboundp 'ediff-display-pixel-height)
186 (1+ (ediff-display-pixel-height))
187 3000))
188 (cons 'left (if (fboundp 'ediff-display-pixel-width)
189 (1+ (ediff-display-pixel-width))
190 3000))
191 )
192 "Frame parameters for displaying Ediff Control Panel.
193 Used internally---not a user option.")
194
195 ;; position of the mouse; used to decide whether to warp the mouse into ctl
196 ;; frame
197 (ediff-defvar-local ediff-mouse-pixel-position nil "")
198
199 ;; not used for now
200 (defvar ediff-mouse-pixel-threshold 30
201 "If the user moves mouse more than this many pixels, Ediff won't warp mouse into control window.")
202
203 (defcustom ediff-grab-mouse t
204 "If t, Ediff will always grab the mouse and put it in the control frame.
205 If 'maybe, Ediff will do it sometimes, but not after operations that require
206 relatively long time. If nil, the mouse will be entirely user's
207 responsibility."
208 :type 'boolean
209 :group 'ediff-window)
210
211 (defcustom ediff-control-frame-position-function 'ediff-make-frame-position
212 "Function to call to determine the desired location for the control panel.
213 Expects three parameters: the control buffer, the desired width and height
214 of the control frame. It returns an association list
215 of the form \(\(top . <position>\) \(left . <position>\)\)"
216 :type 'function
217 :group 'ediff-window)
218
219 (defcustom ediff-control-frame-upward-shift 42
220 "The upward shift of control frame from the top of buffer A's frame.
221 Measured in pixels.
222 This is used by the default control frame positioning function,
223 `ediff-make-frame-position'. This variable is provided for easy
224 customization of the default control frame positioning."
225 :type 'integer
226 :group 'ediff-window)
227
228 (defcustom ediff-narrow-control-frame-leftward-shift (if (featurep 'xemacs) 7 3)
229 "The leftward shift of control frame from the right edge of buf A's frame.
230 Measured in characters.
231 This is used by the default control frame positioning function,
232 `ediff-make-frame-position' to adjust the position of the control frame
233 when it shows the short menu. This variable is provided for easy
234 customization of the default."
235 :type 'integer
236 :group 'ediff-window)
237
238 (defcustom ediff-wide-control-frame-rightward-shift 7
239 "The rightward shift of control frame from the left edge of buf A's frame.
240 Measured in characters.
241 This is used by the default control frame positioning function,
242 `ediff-make-frame-position' to adjust the position of the control frame
243 when it shows the full menu. This variable is provided for easy
244 customization of the default."
245 :type 'integer
246 :group 'ediff-window)
247
248
249 ;; Wide frame display
250
251 ;; t means Ediff is using wide display
252 (ediff-defvar-local ediff-wide-display-p nil "")
253 ;; keeps frame config for toggling wide display
254 (ediff-defvar-local ediff-wide-display-orig-parameters nil
255 "Frame parameters to be restored when the user wants to toggle the wide
256 display off.")
257 (ediff-defvar-local ediff-wide-display-frame nil
258 "Frame to be used for wide display.")
259 (ediff-defvar-local ediff-make-wide-display-function 'ediff-make-wide-display
260 "The value is a function that is called to create a wide display.
261 The function is called without arguments. It should resize the frame in
262 which buffers A, B, and C are to be displayed, and it should save the old
263 frame parameters in `ediff-wide-display-orig-parameters'.
264 The variable `ediff-wide-display-frame' should be set to contain
265 the frame used for the wide display.")
266
267 ;; Frame used for the control panel in a windowing system.
268 (ediff-defvar-local ediff-control-frame nil "")
269
270 (defcustom ediff-prefer-iconified-control-frame nil
271 "If t, keep control panel iconified when help message is off.
272 This has effect only on a windowing system.
273 If t, hitting `?' to toggle control panel off iconifies it.
274
275 This is only useful in Emacs and only for certain kinds of window managers,
276 such as TWM and its derivatives, since the window manager must permit
277 keyboard input to go into icons. XEmacs completely ignores keyboard input
278 into icons, regardless of the window manager."
279 :type 'boolean
280 :group 'ediff-window)
281
282 ;;; Functions
283
284 (defun ediff-get-window-by-clicking (wind prev-wind wind-number)
285 (let (event)
286 (message
287 "Select windows by clicking. Please click on Window %d " wind-number)
288 (while (not (ediff-mouse-event-p (setq event (ediff-read-event))))
289 (if (sit-for 1) ; if sequence of events, wait till the final word
290 (beep 1))
291 (message "Please click on Window %d " wind-number))
292 (ediff-read-event) ; discard event
293 (setq wind (if (featurep 'xemacs)
294 (event-window event)
295 (posn-window (event-start event))))))
296
297
298 ;; Select the lowest window on the frame.
299 (defun ediff-select-lowest-window ()
300 (if (featurep 'xemacs)
301 (select-window (frame-lowest-window))
302 (let* ((lowest-window (selected-window))
303 (bottom-edge (car (cdr (cdr (cdr (window-edges))))))
304 (last-window (save-excursion
305 (other-window -1) (selected-window)))
306 (window-search t))
307 (while window-search
308 (let* ((this-window (next-window))
309 (next-bottom-edge
310 (car (cdr (cdr (cdr (window-edges this-window)))))))
311 (if (< bottom-edge next-bottom-edge)
312 (setq bottom-edge next-bottom-edge
313 lowest-window this-window))
314 (select-window this-window)
315 (when (eq last-window this-window)
316 (select-window lowest-window)
317 (setq window-search nil)))))))
318
319
320 ;;; Common window setup routines
321
322 ;; Set up the window configuration. If POS is given, set the points to
323 ;; the beginnings of the buffers.
324 ;; When 3way comparison is added, this will have to choose the appropriate
325 ;; setup function based on ediff-job-name
326 (defun ediff-setup-windows (buffer-A buffer-B buffer-C control-buffer)
327 ;; Make sure we are not in the minibuffer window when we try to delete
328 ;; all other windows.
329 (run-hooks 'ediff-before-setup-windows-hook)
330 (if (eq (selected-window) (minibuffer-window))
331 (other-window 1))
332
333 ;; in case user did a no-no on a tty
334 (or (ediff-window-display-p)
335 (setq ediff-window-setup-function 'ediff-setup-windows-plain))
336
337 (or (ediff-keep-window-config control-buffer)
338 (funcall
339 (ediff-with-current-buffer control-buffer ediff-window-setup-function)
340 buffer-A buffer-B buffer-C control-buffer))
341 (run-hooks 'ediff-after-setup-windows-hook))
342
343 (defun ediff-setup-windows-default (buffer-A buffer-B buffer-C control-buffer)
344 (funcall (if (display-graphic-p)
345 'ediff-setup-windows-multiframe
346 'ediff-setup-windows-plain)
347 buffer-A buffer-B buffer-C control-buffer))
348
349 ;; Just set up 3 windows.
350 ;; Usually used without windowing systems
351 ;; With windowing, we want to use dedicated frames.
352 (defun ediff-setup-windows-plain (buffer-A buffer-B buffer-C control-buffer)
353 (ediff-with-current-buffer control-buffer
354 (setq ediff-multiframe nil))
355 (if ediff-merge-job
356 (ediff-setup-windows-plain-merge
357 buffer-A buffer-B buffer-C control-buffer)
358 (ediff-setup-windows-plain-compare
359 buffer-A buffer-B buffer-C control-buffer)))
360
361 (defun ediff-setup-windows-plain-merge (buf-A buf-B buf-C control-buffer)
362 ;; skip dedicated and unsplittable frames
363 (ediff-destroy-control-frame control-buffer)
364 (let ((window-min-height 1)
365 split-window-function
366 merge-window-share merge-window-lines
367 wind-A wind-B wind-C)
368 (ediff-with-current-buffer control-buffer
369 (setq merge-window-share ediff-merge-window-share
370 ;; this lets us have local versions of ediff-split-window-function
371 split-window-function ediff-split-window-function))
372 (delete-other-windows)
373 (set-window-dedicated-p (selected-window) nil)
374 (split-window-vertically)
375 (ediff-select-lowest-window)
376 (ediff-setup-control-buffer control-buffer)
377
378 ;; go to the upper window and split it betw A, B, and possibly C
379 (other-window 1)
380 (setq merge-window-lines
381 (max 2 (round (* (window-height) merge-window-share))))
382 (switch-to-buffer buf-A)
383 (setq wind-A (selected-window))
384
385 ;; XEmacs used to have a lot of trouble with display
386 ;; It did't set things right unless we tell it to sit still
387 ;; 19.12 seems ok.
388 ;;(if (featurep 'xemacs) (sit-for 0))
389
390 (split-window-vertically (max 2 (- (window-height) merge-window-lines)))
391 (if (eq (selected-window) wind-A)
392 (other-window 1))
393 (setq wind-C (selected-window))
394 (switch-to-buffer buf-C)
395
396 (select-window wind-A)
397 (funcall split-window-function)
398
399 (if (eq (selected-window) wind-A)
400 (other-window 1))
401 (switch-to-buffer buf-B)
402 (setq wind-B (selected-window))
403
404 (ediff-with-current-buffer control-buffer
405 (setq ediff-window-A wind-A
406 ediff-window-B wind-B
407 ediff-window-C wind-C))
408
409 (ediff-select-lowest-window)
410 (ediff-setup-control-buffer control-buffer)
411 ))
412
413
414 ;; This function handles all comparison jobs, including 3way jobs
415 (defun ediff-setup-windows-plain-compare (buf-A buf-B buf-C control-buffer)
416 ;; skip dedicated and unsplittable frames
417 (ediff-destroy-control-frame control-buffer)
418 (let ((window-min-height 1)
419 split-window-function wind-width-or-height
420 three-way-comparison
421 wind-A-start wind-B-start wind-A wind-B wind-C)
422 (ediff-with-current-buffer control-buffer
423 (setq wind-A-start (ediff-overlay-start
424 (ediff-get-value-according-to-buffer-type
425 'A ediff-narrow-bounds))
426 wind-B-start (ediff-overlay-start
427 (ediff-get-value-according-to-buffer-type
428 'B ediff-narrow-bounds))
429 ;; this lets us have local versions of ediff-split-window-function
430 split-window-function ediff-split-window-function
431 three-way-comparison ediff-3way-comparison-job))
432 ;; if in minibuffer go somewhere else
433 (if (save-match-data
434 (string-match "\*Minibuf-" (buffer-name (window-buffer))))
435 (select-window (next-window nil 'ignore-minibuf)))
436 (delete-other-windows)
437 (set-window-dedicated-p (selected-window) nil)
438 (split-window-vertically)
439 (ediff-select-lowest-window)
440 (ediff-setup-control-buffer control-buffer)
441
442 ;; go to the upper window and split it betw A, B, and possibly C
443 (other-window 1)
444 (switch-to-buffer buf-A)
445 (setq wind-A (selected-window))
446 (if three-way-comparison
447 (setq wind-width-or-height
448 (/ (if (eq split-window-function 'split-window-vertically)
449 (window-height wind-A)
450 (window-width wind-A))
451 3)))
452
453 ;; XEmacs used to have a lot of trouble with display
454 ;; It did't set things right unless we told it to sit still
455 ;; 19.12 seems ok.
456 ;;(if (featurep 'xemacs) (sit-for 0))
457
458 (funcall split-window-function wind-width-or-height)
459
460 (if (eq (selected-window) wind-A)
461 (other-window 1))
462 (switch-to-buffer buf-B)
463 (setq wind-B (selected-window))
464
465 (if three-way-comparison
466 (progn
467 (funcall split-window-function) ; equally
468 (if (eq (selected-window) wind-B)
469 (other-window 1))
470 (switch-to-buffer buf-C)
471 (setq wind-C (selected-window))))
472
473 (ediff-with-current-buffer control-buffer
474 (setq ediff-window-A wind-A
475 ediff-window-B wind-B
476 ediff-window-C wind-C))
477
478 ;; It is unlikely that we will want to implement 3way window comparison.
479 ;; So, only buffers A and B are used here.
480 (if ediff-windows-job
481 (progn
482 (set-window-start wind-A wind-A-start)
483 (set-window-start wind-B wind-B-start)))
484
485 (ediff-select-lowest-window)
486 (ediff-setup-control-buffer control-buffer)
487 ))
488
489
490 ;; dispatch an appropriate window setup function
491 (defun ediff-setup-windows-multiframe (buf-A buf-B buf-C control-buf)
492 (ediff-with-current-buffer control-buf
493 (setq ediff-multiframe t))
494 (if ediff-merge-job
495 (ediff-setup-windows-multiframe-merge buf-A buf-B buf-C control-buf)
496 (ediff-setup-windows-multiframe-compare buf-A buf-B buf-C control-buf)))
497
498 (defun ediff-setup-windows-multiframe-merge (buf-A buf-B buf-C control-buf)
499 ;;; Algorithm:
500 ;;; 1. Never use frames that have dedicated windows in them---it is bad to
501 ;;; destroy dedicated windows.
502 ;;; 2. If A and B are in the same frame but C's frame is different--- use one
503 ;;; frame for A and B and use a separate frame for C.
504 ;;; 3. If C's frame is non-existent, then: if the first suitable
505 ;;; non-dedicated frame is different from A&B's, then use it for C.
506 ;;; Otherwise, put A,B, and C in one frame.
507 ;;; 4. If buffers A, B, C are is separate frames, use them to display these
508 ;;; buffers.
509
510 ;; Skip dedicated or iconified frames.
511 ;; Unsplittable frames are taken care of later.
512 (ediff-skip-unsuitable-frames 'ok-unsplittable)
513
514 (let* ((window-min-height 1)
515 (wind-A (ediff-get-visible-buffer-window buf-A))
516 (wind-B (ediff-get-visible-buffer-window buf-B))
517 (wind-C (ediff-get-visible-buffer-window buf-C))
518 (frame-A (if wind-A (window-frame wind-A)))
519 (frame-B (if wind-B (window-frame wind-B)))
520 (frame-C (if wind-C (window-frame wind-C)))
521 ;; on wide display, do things in one frame
522 (force-one-frame
523 (ediff-with-current-buffer control-buf ediff-wide-display-p))
524 ;; this lets us have local versions of ediff-split-window-function
525 (split-window-function
526 (ediff-with-current-buffer control-buf ediff-split-window-function))
527 (orig-wind (selected-window))
528 (orig-frame (selected-frame))
529 (use-same-frame (or force-one-frame
530 ;; A and C must be in one frame
531 (eq frame-A (or frame-C orig-frame))
532 ;; B and C must be in one frame
533 (eq frame-B (or frame-C orig-frame))
534 ;; A or B is not visible
535 (not (frame-live-p frame-A))
536 (not (frame-live-p frame-B))
537 ;; A or B is not suitable for display
538 (not (ediff-window-ok-for-display wind-A))
539 (not (ediff-window-ok-for-display wind-B))
540 ;; A and B in the same frame, and no good frame
541 ;; for C
542 (and (eq frame-A frame-B)
543 (not (frame-live-p frame-C)))
544 ))
545 ;; use-same-frame-for-AB implies wind A and B are ok for display
546 (use-same-frame-for-AB (and (not use-same-frame)
547 (eq frame-A frame-B)))
548 (merge-window-share (ediff-with-current-buffer control-buf
549 ediff-merge-window-share))
550 merge-window-lines
551 designated-minibuffer-frame
552 done-A done-B done-C)
553
554 ;; buf-A on its own
555 (if (and (window-live-p wind-A)
556 (null use-same-frame) ; implies wind-A is suitable
557 (null use-same-frame-for-AB))
558 (progn ; bug A on its own
559 ;; buffer buf-A is seen in live wind-A
560 (select-window wind-A)
561 (delete-other-windows)
562 (setq wind-A (selected-window))
563 (setq done-A t)))
564
565 ;; buf-B on its own
566 (if (and (window-live-p wind-B)
567 (null use-same-frame) ; implies wind-B is suitable
568 (null use-same-frame-for-AB))
569 (progn ; buf B on its own
570 ;; buffer buf-B is seen in live wind-B
571 (select-window wind-B)
572 (delete-other-windows)
573 (setq wind-B (selected-window))
574 (setq done-B t)))
575
576 ;; buf-C on its own
577 (if (and (window-live-p wind-C)
578 (ediff-window-ok-for-display wind-C)
579 (null use-same-frame)) ; buf C on its own
580 (progn
581 ;; buffer buf-C is seen in live wind-C
582 (select-window wind-C)
583 (delete-other-windows)
584 (setq wind-C (selected-window))
585 (setq done-C t)))
586
587 (if (and use-same-frame-for-AB ; implies wind A and B are suitable
588 (window-live-p wind-A))
589 (progn
590 ;; wind-A must already be displaying buf-A
591 (select-window wind-A)
592 (delete-other-windows)
593 (setq wind-A (selected-window))
594
595 (funcall split-window-function)
596 (if (eq (selected-window) wind-A)
597 (other-window 1))
598 (switch-to-buffer buf-B)
599 (setq wind-B (selected-window))
600
601 (setq done-A t
602 done-B t)))
603
604 (if use-same-frame
605 (let ((window-min-height 1))
606 (if (and (eq frame-A frame-B)
607 (eq frame-B frame-C)
608 (frame-live-p frame-A))
609 (select-frame frame-A)
610 ;; avoid dedicated and non-splittable windows
611 (ediff-skip-unsuitable-frames))
612 (delete-other-windows)
613 (setq merge-window-lines
614 (max 2 (round (* (window-height) merge-window-share))))
615 (switch-to-buffer buf-A)
616 (setq wind-A (selected-window))
617
618 (split-window-vertically
619 (max 2 (- (window-height) merge-window-lines)))
620 (if (eq (selected-window) wind-A)
621 (other-window 1))
622 (setq wind-C (selected-window))
623 (switch-to-buffer buf-C)
624
625 (select-window wind-A)
626
627 (funcall split-window-function)
628 (if (eq (selected-window) wind-A)
629 (other-window 1))
630 (switch-to-buffer buf-B)
631 (setq wind-B (selected-window))
632
633 (setq done-A t
634 done-B t
635 done-C t)
636 ))
637
638 (or done-A ; Buf A to be set in its own frame,
639 ;;; or it was set before because use-same-frame = 1
640 (progn
641 ;; Buf-A was not set up yet as it wasn't visible,
642 ;; and use-same-frame = nil, use-same-frame-for-AB = nil
643 (select-window orig-wind)
644 (delete-other-windows)
645 (switch-to-buffer buf-A)
646 (setq wind-A (selected-window))
647 ))
648 (or done-B ; Buf B to be set in its own frame,
649 ;;; or it was set before because use-same-frame = 1
650 (progn
651 ;; Buf-B was not set up yet as it wasn't visible
652 ;; and use-same-frame = nil, use-same-frame-for-AB = nil
653 (select-window orig-wind)
654 (delete-other-windows)
655 (switch-to-buffer buf-B)
656 (setq wind-B (selected-window))
657 ))
658
659 (or done-C ; Buf C to be set in its own frame,
660 ;;; or it was set before because use-same-frame = 1
661 (progn
662 ;; Buf-C was not set up yet as it wasn't visible
663 ;; and use-same-frame = nil
664 (select-window orig-wind)
665 (delete-other-windows)
666 (switch-to-buffer buf-C)
667 (setq wind-C (selected-window))
668 ))
669
670 (ediff-with-current-buffer control-buf
671 (setq ediff-window-A wind-A
672 ediff-window-B wind-B
673 ediff-window-C wind-C)
674 (setq frame-A (window-frame ediff-window-A)
675 designated-minibuffer-frame
676 (window-frame (minibuffer-window frame-A))))
677
678 (ediff-setup-control-frame control-buf designated-minibuffer-frame)
679 ))
680
681
682 ;; Window setup for all comparison jobs, including 3way comparisons
683 (defun ediff-setup-windows-multiframe-compare (buf-A buf-B buf-C control-buf)
684 ;;; Algorithm:
685 ;;; If a buffer is seen in a frame, use that frame for that buffer.
686 ;;; If it is not seen, use the current frame.
687 ;;; If both buffers are not seen, they share the current frame. If one
688 ;;; of the buffers is not seen, it is placed in the current frame (where
689 ;;; ediff started). If that frame is displaying the other buffer, it is
690 ;;; shared between the two buffers.
691 ;;; However, if we decide to put both buffers in one frame
692 ;;; and the selected frame isn't splittable, we create a new frame and
693 ;;; put both buffers there, event if one of this buffers is visible in
694 ;;; another frame.
695
696 ;; Skip dedicated or iconified frames.
697 ;; Unsplittable frames are taken care of later.
698 (ediff-skip-unsuitable-frames 'ok-unsplittable)
699
700 (let* ((window-min-height 1)
701 (wind-A (ediff-get-visible-buffer-window buf-A))
702 (wind-B (ediff-get-visible-buffer-window buf-B))
703 (wind-C (ediff-get-visible-buffer-window buf-C))
704 (frame-A (if wind-A (window-frame wind-A)))
705 (frame-B (if wind-B (window-frame wind-B)))
706 (frame-C (if wind-C (window-frame wind-C)))
707 (ctl-frame-exists-p (ediff-with-current-buffer control-buf
708 (frame-live-p ediff-control-frame)))
709 ;; on wide display, do things in one frame
710 (force-one-frame
711 (ediff-with-current-buffer control-buf ediff-wide-display-p))
712 ;; this lets us have local versions of ediff-split-window-function
713 (split-window-function
714 (ediff-with-current-buffer control-buf ediff-split-window-function))
715 (three-way-comparison
716 (ediff-with-current-buffer control-buf ediff-3way-comparison-job))
717 (orig-wind (selected-window))
718 (use-same-frame (or force-one-frame
719 (eq frame-A frame-B)
720 (not (ediff-window-ok-for-display wind-A))
721 (not (ediff-window-ok-for-display wind-B))
722 (if three-way-comparison
723 (or (eq frame-A frame-C)
724 (eq frame-B frame-C)
725 (not (ediff-window-ok-for-display wind-C))
726 (not (frame-live-p frame-A))
727 (not (frame-live-p frame-B))
728 (not (frame-live-p frame-C))))
729 (and (not (frame-live-p frame-B))
730 (or ctl-frame-exists-p
731 (eq frame-A (selected-frame))))
732 (and (not (frame-live-p frame-A))
733 (or ctl-frame-exists-p
734 (eq frame-B (selected-frame))))))
735 wind-A-start wind-B-start
736 designated-minibuffer-frame
737 done-A done-B done-C)
738
739 (ediff-with-current-buffer control-buf
740 (setq wind-A-start (ediff-overlay-start
741 (ediff-get-value-according-to-buffer-type
742 'A ediff-narrow-bounds))
743 wind-B-start (ediff-overlay-start
744 (ediff-get-value-according-to-buffer-type
745 'B ediff-narrow-bounds))))
746
747 (if (and (window-live-p wind-A) (null use-same-frame)) ; buf-A on its own
748 (progn
749 ;; buffer buf-A is seen in live wind-A
750 (select-window wind-A) ; must be displaying buf-A
751 (delete-other-windows)
752 (setq wind-A (selected-window))
753 (setq done-A t)))
754
755 (if (and (window-live-p wind-B) (null use-same-frame)) ; buf B on its own
756 (progn
757 ;; buffer buf-B is seen in live wind-B
758 (select-window wind-B) ; must be displaying buf-B
759 (delete-other-windows)
760 (setq wind-B (selected-window))
761 (setq done-B t)))
762
763 (if (and (window-live-p wind-C) (null use-same-frame)) ; buf C on its own
764 (progn
765 ;; buffer buf-C is seen in live wind-C
766 (select-window wind-C) ; must be displaying buf-C
767 (delete-other-windows)
768 (setq wind-C (selected-window))
769 (setq done-C t)))
770
771 (if use-same-frame
772 (let (wind-width-or-height) ; this affects 3way setups only
773 (if (and (eq frame-A frame-B) (frame-live-p frame-A))
774 (select-frame frame-A)
775 ;; avoid dedicated and non-splittable windows
776 (ediff-skip-unsuitable-frames))
777 (delete-other-windows)
778 (switch-to-buffer buf-A)
779 (setq wind-A (selected-window))
780
781 (if three-way-comparison
782 (setq wind-width-or-height
783 (/
784 (if (eq split-window-function 'split-window-vertically)
785 (window-height wind-A)
786 (window-width wind-A))
787 3)))
788
789 (funcall split-window-function wind-width-or-height)
790 (if (eq (selected-window) wind-A)
791 (other-window 1))
792 (switch-to-buffer buf-B)
793 (setq wind-B (selected-window))
794
795 (if three-way-comparison
796 (progn
797 (funcall split-window-function) ; equally
798 (if (memq (selected-window) (list wind-A wind-B))
799 (other-window 1))
800 (switch-to-buffer buf-C)
801 (setq wind-C (selected-window))))
802 (setq done-A t
803 done-B t
804 done-C t)
805 ))
806
807 (or done-A ; Buf A to be set in its own frame
808 ;;; or it was set before because use-same-frame = 1
809 (progn
810 ;; Buf-A was not set up yet as it wasn't visible,
811 ;; and use-same-frame = nil
812 (select-window orig-wind)
813 (delete-other-windows)
814 (switch-to-buffer buf-A)
815 (setq wind-A (selected-window))
816 ))
817 (or done-B ; Buf B to be set in its own frame
818 ;;; or it was set before because use-same-frame = 1
819 (progn
820 ;; Buf-B was not set up yet as it wasn't visible,
821 ;; and use-same-frame = nil
822 (select-window orig-wind)
823 (delete-other-windows)
824 (switch-to-buffer buf-B)
825 (setq wind-B (selected-window))
826 ))
827
828 (if three-way-comparison
829 (or done-C ; Buf C to be set in its own frame
830 ;;; or it was set before because use-same-frame = 1
831 (progn
832 ;; Buf-C was not set up yet as it wasn't visible,
833 ;; and use-same-frame = nil
834 (select-window orig-wind)
835 (delete-other-windows)
836 (switch-to-buffer buf-C)
837 (setq wind-C (selected-window))
838 )))
839
840 (ediff-with-current-buffer control-buf
841 (setq ediff-window-A wind-A
842 ediff-window-B wind-B
843 ediff-window-C wind-C)
844
845 (setq frame-A (window-frame ediff-window-A)
846 designated-minibuffer-frame
847 (window-frame (minibuffer-window frame-A))))
848
849 ;; It is unlikely that we'll implement a version of ediff-windows that
850 ;; would compare 3 windows at once. So, we don't use buffer C here.
851 (if ediff-windows-job
852 (progn
853 (set-window-start wind-A wind-A-start)
854 (set-window-start wind-B wind-B-start)))
855
856 (ediff-setup-control-frame control-buf designated-minibuffer-frame)
857 ))
858
859 ;; skip unsplittable frames and frames that have dedicated windows.
860 ;; create a new splittable frame if none is found
861 (defun ediff-skip-unsuitable-frames (&optional ok-unsplittable)
862 (if (ediff-window-display-p)
863 (let ((wind-frame (window-frame (selected-window)))
864 seen-windows)
865 (while (and (not (memq (selected-window) seen-windows))
866 (or
867 (ediff-frame-has-dedicated-windows wind-frame)
868 (ediff-frame-iconified-p wind-frame)
869 ;; skip small windows
870 (< (frame-height wind-frame)
871 (* 3 window-min-height))
872 (if ok-unsplittable
873 nil
874 (ediff-frame-unsplittable-p wind-frame))))
875 ;; remember history
876 (setq seen-windows (cons (selected-window) seen-windows))
877 ;; try new window
878 (other-window 1 t)
879 (setq wind-frame (window-frame (selected-window)))
880 )
881 (if (memq (selected-window) seen-windows)
882 ;; fed up, no appropriate frames
883 (setq wind-frame (make-frame '((unsplittable)))))
884
885 (select-frame wind-frame)
886 )))
887
888 (defun ediff-frame-has-dedicated-windows (frame)
889 (let (ans)
890 (walk-windows
891 (lambda (wind) (if (window-dedicated-p wind)
892 (setq ans t)))
893 'ignore-minibuffer
894 frame)
895 ans))
896
897 ;; window is ok, if it is only one window on the frame, not counting the
898 ;; minibuffer, or none of the frame's windows is dedicated.
899 ;; The idea is that it is bad to destroy dedicated windows while creating an
900 ;; ediff window setup
901 (defun ediff-window-ok-for-display (wind)
902 (and
903 (window-live-p wind)
904 (or
905 ;; only one window
906 (eq wind (next-window wind 'ignore-minibuffer (window-frame wind)))
907 ;; none is dedicated (in multiframe setup)
908 (not (ediff-frame-has-dedicated-windows (window-frame wind)))
909 )))
910
911 ;; Prepare or refresh control frame
912 (defun ediff-setup-control-frame (ctl-buffer designated-minibuffer-frame)
913 (let ((window-min-height 1)
914 ctl-frame-iconified-p dont-iconify-ctl-frame deiconify-ctl-frame
915 ctl-frame old-ctl-frame lines
916 ;; user-grabbed-mouse
917 fheight fwidth adjusted-parameters)
918
919 (ediff-with-current-buffer ctl-buffer
920 (if (and (featurep 'xemacs) (featurep 'menubar))
921 (set-buffer-menubar nil))
922 ;;(setq user-grabbed-mouse (ediff-user-grabbed-mouse))
923 (run-hooks 'ediff-before-setup-control-frame-hook))
924
925 (setq old-ctl-frame (ediff-with-current-buffer ctl-buffer ediff-control-frame))
926 (ediff-with-current-buffer ctl-buffer
927 (setq ctl-frame (if (frame-live-p old-ctl-frame)
928 old-ctl-frame
929 (make-frame ediff-control-frame-parameters))
930 ediff-control-frame ctl-frame)
931 ;; protect against undefined face-attribute
932 (condition-case nil
933 (if (and (featurep 'emacs) (face-attribute 'mode-line :box))
934 (set-face-attribute 'mode-line ctl-frame :box nil))
935 (error)))
936
937 (setq ctl-frame-iconified-p (ediff-frame-iconified-p ctl-frame))
938 (select-frame ctl-frame)
939 (if (window-dedicated-p (selected-window))
940 ()
941 (delete-other-windows)
942 (switch-to-buffer ctl-buffer))
943
944 ;; must be before ediff-setup-control-buffer
945 ;; just a precaution--we should be in ctl-buffer already
946 (ediff-with-current-buffer ctl-buffer
947 (make-local-variable 'frame-title-format)
948 (make-local-variable 'frame-icon-title-format) ; XEmacs
949 (make-local-variable 'icon-title-format)) ; Emacs
950
951 (ediff-setup-control-buffer ctl-buffer)
952 (setq dont-iconify-ctl-frame
953 (not (string= ediff-help-message ediff-brief-help-message)))
954 (setq deiconify-ctl-frame
955 (and (eq this-command 'ediff-toggle-help)
956 dont-iconify-ctl-frame))
957
958 ;; 1 more line for the mode line
959 (setq lines (1+ (count-lines (point-min) (point-max)))
960 fheight lines
961 fwidth (max (+ (ediff-help-message-line-length) 2)
962 (ediff-compute-toolbar-width))
963 adjusted-parameters
964 (list
965 ;; possibly change surrogate minibuffer
966 (cons 'minibuffer
967 (minibuffer-window
968 designated-minibuffer-frame))
969 (cons 'width fwidth)
970 (cons 'height fheight)
971 (cons 'user-position t)
972 ))
973
974 ;; adjust autoraise
975 (setq adjusted-parameters
976 (cons (if ediff-use-long-help-message
977 '(auto-raise . nil)
978 '(auto-raise . t))
979 adjusted-parameters))
980
981 ;; In XEmacs, buffer menubar needs to be killed before frame parameters
982 ;; are changed.
983 (if (ediff-has-toolbar-support-p)
984 (when (featurep 'xemacs)
985 (if (ediff-has-gutter-support-p)
986 (set-specifier top-gutter (list ctl-frame nil)))
987 (sit-for 0)
988 (set-specifier top-toolbar-height (list ctl-frame 0))
989 ;;(set-specifier bottom-toolbar-height (list ctl-frame 0))
990 (set-specifier left-toolbar-width (list ctl-frame 0))
991 (set-specifier right-toolbar-width (list ctl-frame 0))))
992
993 ;; As a precaution, we call modify frame parameters twice, in
994 ;; order to make sure that at least once we do it for
995 ;; a non-iconified frame. (It appears that in the Windows port of
996 ;; Emacs, one can't modify frame parameters of iconified frames.)
997 (if (eq system-type 'windows-nt)
998 (modify-frame-parameters ctl-frame adjusted-parameters))
999
1000 ;; make or zap toolbar (if not requested)
1001 (ediff-make-bottom-toolbar ctl-frame)
1002
1003 (goto-char (point-min))
1004
1005 (modify-frame-parameters ctl-frame adjusted-parameters)
1006 (make-frame-visible ctl-frame)
1007
1008 ;; This works around a bug in 19.25 and earlier. There, if frame gets
1009 ;; iconified, the current buffer changes to that of the frame that
1010 ;; becomes exposed as a result of this iconification.
1011 ;; So, we make sure the current buffer doesn't change.
1012 (select-frame ctl-frame)
1013 (ediff-refresh-control-frame)
1014
1015 (cond ((and ediff-prefer-iconified-control-frame
1016 (not ctl-frame-iconified-p) (not dont-iconify-ctl-frame))
1017 (iconify-frame ctl-frame))
1018 ((or deiconify-ctl-frame (not ctl-frame-iconified-p))
1019 (raise-frame ctl-frame)))
1020
1021 (set-window-dedicated-p (selected-window) t)
1022
1023 ;; Now move the frame. We must do it separately due to an obscure bug in
1024 ;; XEmacs
1025 (modify-frame-parameters
1026 ctl-frame
1027 (funcall ediff-control-frame-position-function ctl-buffer fwidth fheight))
1028
1029 ;; synchronize so the cursor will move to control frame
1030 ;; per RMS suggestion
1031 (if (ediff-window-display-p)
1032 (let ((count 7))
1033 (sit-for .1)
1034 (while (and (not (frame-visible-p ctl-frame)) (> count 0))
1035 (setq count (1- count))
1036 (sit-for .3))))
1037
1038 (or (ediff-frame-iconified-p ctl-frame)
1039 ;; don't warp the mouse, unless ediff-grab-mouse = t
1040 (ediff-reset-mouse ctl-frame
1041 (or (eq this-command 'ediff-quit)
1042 (not (eq ediff-grab-mouse t)))))
1043
1044 (when (featurep 'xemacs)
1045 (ediff-with-current-buffer ctl-buffer
1046 (make-local-hook 'select-frame-hook)
1047 (add-hook 'select-frame-hook
1048 'ediff-xemacs-select-frame-hook nil 'local)))
1049
1050 (ediff-with-current-buffer ctl-buffer
1051 (run-hooks 'ediff-after-setup-control-frame-hook))))
1052
1053
1054 (defun ediff-destroy-control-frame (ctl-buffer)
1055 (ediff-with-current-buffer ctl-buffer
1056 (if (and (ediff-window-display-p) (frame-live-p ediff-control-frame))
1057 (let ((ctl-frame ediff-control-frame))
1058 (if (and (featurep 'xemacs) (featurep 'menubar))
1059 (set-buffer-menubar default-menubar))
1060 (setq ediff-control-frame nil)
1061 (delete-frame ctl-frame))))
1062 (if ediff-multiframe
1063 (ediff-skip-unsuitable-frames))
1064 ;;(ediff-reset-mouse nil)
1065 )
1066
1067
1068 ;; finds a good place to clip control frame
1069 (defun ediff-make-frame-position (ctl-buffer ctl-frame-width ctl-frame-height)
1070 (ediff-with-current-buffer ctl-buffer
1071 (let* ((frame-A (window-frame ediff-window-A))
1072 (frame-A-parameters (frame-parameters frame-A))
1073 (frame-A-top (eval (cdr (assoc 'top frame-A-parameters))))
1074 (frame-A-left (eval (cdr (assoc 'left frame-A-parameters))))
1075 (frame-A-width (frame-width frame-A))
1076 (ctl-frame ediff-control-frame)
1077 horizontal-adjustment upward-adjustment
1078 ctl-frame-top ctl-frame-left)
1079
1080 ;; Multiple control frames are clipped based on the value of
1081 ;; ediff-control-buffer-number. This is done in order not to obscure
1082 ;; other active control panels.
1083 (setq horizontal-adjustment (* 2 ediff-control-buffer-number)
1084 upward-adjustment (* -14 ediff-control-buffer-number))
1085
1086 (setq ctl-frame-top
1087 (- frame-A-top upward-adjustment ediff-control-frame-upward-shift)
1088 ctl-frame-left
1089 (+ frame-A-left
1090 (if ediff-use-long-help-message
1091 (* (ediff-frame-char-width ctl-frame)
1092 (+ ediff-wide-control-frame-rightward-shift
1093 horizontal-adjustment))
1094 (- (* frame-A-width (ediff-frame-char-width frame-A))
1095 (* (ediff-frame-char-width ctl-frame)
1096 (+ ctl-frame-width
1097 ediff-narrow-control-frame-leftward-shift
1098 horizontal-adjustment))))))
1099 (setq ctl-frame-top
1100 (min ctl-frame-top
1101 (- (ediff-display-pixel-height)
1102 (* 2 ctl-frame-height
1103 (ediff-frame-char-height ctl-frame))))
1104 ctl-frame-left
1105 (min ctl-frame-left
1106 (- (ediff-display-pixel-width)
1107 (* ctl-frame-width (ediff-frame-char-width ctl-frame)))))
1108 ;; keep ctl frame within the visible bounds
1109 (setq ctl-frame-top (max ctl-frame-top 1)
1110 ctl-frame-left (max ctl-frame-left 1))
1111
1112 (list (cons 'top ctl-frame-top)
1113 (cons 'left ctl-frame-left))
1114 )))
1115
1116 (defun ediff-xemacs-select-frame-hook ()
1117 (if (and (equal (selected-frame) ediff-control-frame)
1118 (not ediff-use-long-help-message))
1119 (raise-frame ediff-control-frame)))
1120
1121 (defun ediff-make-wide-display ()
1122 "Construct an alist of parameters for the wide display.
1123 Saves the old frame parameters in `ediff-wide-display-orig-parameters'.
1124 The frame to be resized is kept in `ediff-wide-display-frame'.
1125 This function modifies only the left margin and the width of the display.
1126 It assumes that it is called from within the control buffer."
1127 (if (not (fboundp 'ediff-display-pixel-width))
1128 (error "Can't determine display width"))
1129 (let* ((frame-A (window-frame ediff-window-A))
1130 (frame-A-params (frame-parameters frame-A))
1131 (cw (ediff-frame-char-width frame-A))
1132 (wd (- (/ (ediff-display-pixel-width) cw) 5)))
1133 (setq ediff-wide-display-orig-parameters
1134 (list (cons 'left (max 0 (eval (cdr (assoc 'left frame-A-params)))))
1135 (cons 'width (cdr (assoc 'width frame-A-params))))
1136 ediff-wide-display-frame frame-A)
1137 (modify-frame-parameters
1138 frame-A `((left . ,cw) (width . ,wd) (user-position . t)))))
1139
1140
1141 ;; Revise the mode line to display which difference we have selected
1142 ;; Also resets mode lines of buffers A/B, since they may be clobbered by
1143 ;; other invocations of Ediff.
1144 (defun ediff-refresh-mode-lines ()
1145 (let (buf-A-state-diff buf-B-state-diff buf-C-state-diff buf-C-state-merge)
1146
1147 (if (ediff-valid-difference-p)
1148 (setq
1149 buf-C-state-diff (ediff-get-state-of-diff ediff-current-difference 'C)
1150 buf-C-state-merge (ediff-get-state-of-merge ediff-current-difference)
1151 buf-A-state-diff (ediff-get-state-of-diff ediff-current-difference 'A)
1152 buf-B-state-diff (ediff-get-state-of-diff ediff-current-difference 'B)
1153 buf-A-state-diff (if buf-A-state-diff
1154 (format "[%s] " buf-A-state-diff)
1155 "")
1156 buf-B-state-diff (if buf-B-state-diff
1157 (format "[%s] " buf-B-state-diff)
1158 "")
1159 buf-C-state-diff (if (and (ediff-buffer-live-p ediff-buffer-C)
1160 (or buf-C-state-diff buf-C-state-merge))
1161 (format "[%s%s%s] "
1162 (or buf-C-state-diff "")
1163 (if buf-C-state-merge
1164 (concat " " buf-C-state-merge)
1165 "")
1166 (if (ediff-get-state-of-ancestor
1167 ediff-current-difference)
1168 " AncestorEmpty"
1169 "")
1170 )
1171 ""))
1172 (setq buf-A-state-diff ""
1173 buf-B-state-diff ""
1174 buf-C-state-diff ""))
1175
1176 ;; control buffer format
1177 (setq mode-line-format
1178 (if (ediff-narrow-control-frame-p)
1179 (list " " mode-line-buffer-identification)
1180 (list "-- " mode-line-buffer-identification " Quick Help")))
1181 ;; control buffer id
1182 (setq mode-line-buffer-identification
1183 (if (ediff-narrow-control-frame-p)
1184 (ediff-make-narrow-control-buffer-id 'skip-name)
1185 (ediff-make-wide-control-buffer-id)))
1186 ;; Force mode-line redisplay
1187 (force-mode-line-update)
1188
1189 (if (and (ediff-window-display-p) (frame-live-p ediff-control-frame))
1190 (ediff-refresh-control-frame))
1191
1192 (ediff-with-current-buffer ediff-buffer-A
1193 (setq ediff-diff-status buf-A-state-diff)
1194 (ediff-strip-mode-line-format)
1195 (setq mode-line-format
1196 (list " A: " 'ediff-diff-status mode-line-format))
1197 (force-mode-line-update))
1198 (ediff-with-current-buffer ediff-buffer-B
1199 (setq ediff-diff-status buf-B-state-diff)
1200 (ediff-strip-mode-line-format)
1201 (setq mode-line-format
1202 (list " B: " 'ediff-diff-status mode-line-format))
1203 (force-mode-line-update))
1204 (if ediff-3way-job
1205 (ediff-with-current-buffer ediff-buffer-C
1206 (setq ediff-diff-status buf-C-state-diff)
1207 (ediff-strip-mode-line-format)
1208 (setq mode-line-format
1209 (list " C: " 'ediff-diff-status mode-line-format))
1210 (force-mode-line-update)))
1211 (if (ediff-buffer-live-p ediff-ancestor-buffer)
1212 (ediff-with-current-buffer ediff-ancestor-buffer
1213 (ediff-strip-mode-line-format)
1214 ;; we keep the second dummy string in the mode line format of the
1215 ;; ancestor, since for other buffers Ediff prepends 2 strings and
1216 ;; ediff-strip-mode-line-format expects that.
1217 (setq mode-line-format
1218 (list " Ancestor: "
1219 (cond ((not (stringp buf-C-state-merge))
1220 "")
1221 ((string-match "prefer-A" buf-C-state-merge)
1222 "[=diff(B)] ")
1223 ((string-match "prefer-B" buf-C-state-merge)
1224 "[=diff(A)] ")
1225 (t ""))
1226 mode-line-format))))
1227 ))
1228
1229
1230 (defun ediff-refresh-control-frame ()
1231 (if (featurep 'emacs)
1232 ;; set frame/icon titles for Emacs
1233 (modify-frame-parameters
1234 ediff-control-frame
1235 (list (cons 'title (ediff-make-base-title))
1236 (cons 'icon-name (ediff-make-narrow-control-buffer-id))
1237 ))
1238 ;; set frame/icon titles for XEmacs
1239 (setq frame-title-format (ediff-make-base-title)
1240 frame-icon-title-format (ediff-make-narrow-control-buffer-id))
1241 ;; force an update of the frame title
1242 (modify-frame-parameters ediff-control-frame '(()))))
1243
1244
1245 (defun ediff-make-narrow-control-buffer-id (&optional skip-name)
1246 (concat
1247 (if skip-name
1248 " "
1249 (ediff-make-base-title))
1250 (cond ((< ediff-current-difference 0)
1251 (format " _/%d" ediff-number-of-differences))
1252 ((>= ediff-current-difference ediff-number-of-differences)
1253 (format " $/%d" ediff-number-of-differences))
1254 (t
1255 (format " %d/%d"
1256 (1+ ediff-current-difference)
1257 ediff-number-of-differences)))))
1258
1259 (defun ediff-make-base-title ()
1260 (concat
1261 (cdr (assoc 'name ediff-control-frame-parameters))
1262 ediff-control-buffer-suffix))
1263
1264 (defun ediff-make-wide-control-buffer-id ()
1265 (cond ((< ediff-current-difference 0)
1266 (list (format "%%b At start of %d diffs"
1267 ediff-number-of-differences)))
1268 ((>= ediff-current-difference ediff-number-of-differences)
1269 (list (format "%%b At end of %d diffs"
1270 ediff-number-of-differences)))
1271 (t
1272 (list (format "%%b diff %d of %d"
1273 (1+ ediff-current-difference)
1274 ediff-number-of-differences)))))
1275
1276
1277
1278 ;; If buff is not live, return nil
1279 (defun ediff-get-visible-buffer-window (buff)
1280 (if (ediff-buffer-live-p buff)
1281 (if (featurep 'xemacs)
1282 (get-buffer-window buff t)
1283 (get-buffer-window buff 'visible))))
1284
1285
1286 ;;; Functions to decide when to redraw windows
1287
1288 (defun ediff-keep-window-config (control-buf)
1289 (and (eq control-buf (current-buffer))
1290 (/= (buffer-size) 0)
1291 (ediff-with-current-buffer control-buf
1292 (let ((ctl-wind ediff-control-window)
1293 (A-wind ediff-window-A)
1294 (B-wind ediff-window-B)
1295 (C-wind ediff-window-C))
1296
1297 (and
1298 (ediff-window-visible-p A-wind)
1299 (ediff-window-visible-p B-wind)
1300 ;; if buffer C is defined then take it into account
1301 (or (not ediff-3way-job)
1302 (ediff-window-visible-p C-wind))
1303 (eq (window-buffer A-wind) ediff-buffer-A)
1304 (eq (window-buffer B-wind) ediff-buffer-B)
1305 (or (not ediff-3way-job)
1306 (eq (window-buffer C-wind) ediff-buffer-C))
1307 (string= ediff-window-config-saved
1308 (format "%S%S%S%S%S%S%S"
1309 ctl-wind A-wind B-wind C-wind
1310 ediff-split-window-function
1311 (ediff-multiframe-setup-p)
1312 ediff-wide-display-p)))))))
1313
1314
1315 (provide 'ediff-wind)
1316
1317
1318 ;; Local Variables:
1319 ;; eval: (put 'ediff-defvar-local 'lisp-indent-hook 'defun)
1320 ;; eval: (put 'ediff-with-current-buffer 'lisp-indent-hook 1)
1321 ;; eval: (put 'ediff-with-current-buffer 'edebug-form-spec '(form body))
1322 ;; End:
1323
1324 ;;; ediff-wind.el ends here