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