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