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