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