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