Switch to recommended form of GPLv3 permissions notice.
[bpt/emacs.git] / lisp / ediff-wind.el
CommitLineData
475f9031 1;;; ediff-wind.el --- window manipulation utilities
b578f267 2
0d30b337 3;; Copyright (C) 1994, 1995, 1996, 1997, 2000, 2001, 2002, 2003,
409cc4a3 4;; 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
475f9031 5
50a07e18 6;; Author: Michael Kifer <kifer@cs.stonybrook.edu>
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)
475f9031 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
475f9031
KH
127 "*The function used to split the main window between buffer-A and buffer-B.
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
475f9031
KH
140 "*The function used to split the main window between buffer-A and buffer-B.
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
6853a937
MK
197 "*If t, Ediff will always grab the mouse and put it in the control frame.
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
475f9031
KH
213 "*The upward shift of control frame from the top of buffer A's frame.
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)
475f9031
KH
222 "*The leftward shift of control frame from the right edge of buf A's frame.
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
475f9031
KH
232 "*The rightward shift of control frame from the left edge of buf A's frame.
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
475f9031
KH
264 "*If t, keep control panel iconified when help message is off.
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))
419 (delete-other-windows)
2d84cc27 420 (set-window-dedicated-p (selected-window) nil)
475f9031
KH
421 (split-window-vertically)
422 (ediff-select-lowest-window)
423 (ediff-setup-control-buffer control-buffer)
71296446 424
475f9031 425 ;; go to the upper window and split it betw A, B, and possibly C
6628e7f8 426 (other-window 1)
475f9031
KH
427 (switch-to-buffer buf-A)
428 (setq wind-A (selected-window))
429 (if three-way-comparison
430 (setq wind-width-or-height
431 (/ (if (eq split-window-function 'split-window-vertically)
432 (window-height wind-A)
433 (window-width wind-A))
434 3)))
71296446 435
6853a937
MK
436 ;; XEmacs used to have a lot of trouble with display
437 ;; It did't set things right unless we told it to sit still
438 ;; 19.12 seems ok.
e83d1fe8 439 ;;(if (featurep 'xemacs) (sit-for 0))
71296446 440
475f9031 441 (funcall split-window-function wind-width-or-height)
71296446 442
475f9031
KH
443 (if (eq (selected-window) wind-A)
444 (other-window 1))
445 (switch-to-buffer buf-B)
446 (setq wind-B (selected-window))
71296446 447
475f9031
KH
448 (if three-way-comparison
449 (progn
450 (funcall split-window-function) ; equally
451 (if (eq (selected-window) wind-B)
452 (other-window 1))
453 (switch-to-buffer buf-C)
454 (setq wind-C (selected-window))))
71296446 455
e756eb9f 456 (ediff-with-current-buffer control-buffer
475f9031
KH
457 (setq ediff-window-A wind-A
458 ediff-window-B wind-B
459 ediff-window-C wind-C))
71296446 460
475f9031
KH
461 ;; It is unlikely that we will want to implement 3way window comparison.
462 ;; So, only buffers A and B are used here.
18b5607f 463 (if ediff-windows-job
475f9031
KH
464 (progn
465 (set-window-start wind-A wind-A-start)
466 (set-window-start wind-B wind-B-start)))
71296446 467
475f9031
KH
468 (ediff-select-lowest-window)
469 (ediff-setup-control-buffer control-buffer)
470 ))
471
71296446 472
4ae69eac 473;; dispatch an appropriate window setup function
475f9031 474(defun ediff-setup-windows-multiframe (buf-A buf-B buf-C control-buf)
e756eb9f 475 (ediff-with-current-buffer control-buf
475f9031
KH
476 (setq ediff-multiframe t))
477 (if ediff-merge-job
478 (ediff-setup-windows-multiframe-merge buf-A buf-B buf-C control-buf)
479 (ediff-setup-windows-multiframe-compare buf-A buf-B buf-C control-buf)))
71296446 480
475f9031
KH
481(defun ediff-setup-windows-multiframe-merge (buf-A buf-B buf-C control-buf)
482;;; Algorithm:
bbe6126c
MK
483;;; 1. Never use frames that have dedicated windows in them---it is bad to
484;;; destroy dedicated windows.
485;;; 2. If A and B are in the same frame but C's frame is different--- use one
6628e7f8 486;;; frame for A and B and use a separate frame for C.
bbe6126c
MK
487;;; 3. If C's frame is non-existent, then: if the first suitable
488;;; non-dedicated frame is different from A&B's, then use it for C.
489;;; Otherwise, put A,B, and C in one frame.
490;;; 4. If buffers A, B, C are is separate frames, use them to display these
491;;; buffers.
475f9031 492
6628e7f8 493 ;; Skip dedicated or iconified frames.
18b5607f 494 ;; Unsplittable frames are taken care of later.
475f9031 495 (ediff-skip-unsuitable-frames 'ok-unsplittable)
71296446 496
4ae69eac 497 (let* ((window-min-height 1)
475f9031
KH
498 (wind-A (ediff-get-visible-buffer-window buf-A))
499 (wind-B (ediff-get-visible-buffer-window buf-B))
500 (wind-C (ediff-get-visible-buffer-window buf-C))
18b5607f
KH
501 (frame-A (if wind-A (window-frame wind-A)))
502 (frame-B (if wind-B (window-frame wind-B)))
503 (frame-C (if wind-C (window-frame wind-C)))
475f9031 504 ;; on wide display, do things in one frame
6628e7f8 505 (force-one-frame
e756eb9f 506 (ediff-with-current-buffer control-buf ediff-wide-display-p))
475f9031 507 ;; this lets us have local versions of ediff-split-window-function
6628e7f8 508 (split-window-function
e756eb9f 509 (ediff-with-current-buffer control-buf ediff-split-window-function))
475f9031 510 (orig-wind (selected-window))
18b5607f 511 (orig-frame (selected-frame))
475f9031 512 (use-same-frame (or force-one-frame
bbe6126c 513 ;; A and C must be in one frame
475f9031 514 (eq frame-A (or frame-C orig-frame))
bbe6126c 515 ;; B and C must be in one frame
475f9031 516 (eq frame-B (or frame-C orig-frame))
bbe6126c 517 ;; A or B is not visible
18b5607f
KH
518 (not (frame-live-p frame-A))
519 (not (frame-live-p frame-B))
bbe6126c
MK
520 ;; A or B is not suitable for display
521 (not (ediff-window-ok-for-display wind-A))
522 (not (ediff-window-ok-for-display wind-B))
523 ;; A and B in the same frame, and no good frame
524 ;; for C
18b5607f
KH
525 (and (eq frame-A frame-B)
526 (not (frame-live-p frame-C)))
475f9031 527 ))
bbe6126c 528 ;; use-same-frame-for-AB implies wind A and B are ok for display
475f9031
KH
529 (use-same-frame-for-AB (and (not use-same-frame)
530 (eq frame-A frame-B)))
e756eb9f 531 (merge-window-share (ediff-with-current-buffer control-buf
475f9031
KH
532 ediff-merge-window-share))
533 merge-window-lines
534 designated-minibuffer-frame
535 done-A done-B done-C)
71296446 536
475f9031
KH
537 ;; buf-A on its own
538 (if (and (window-live-p wind-A)
bbe6126c 539 (null use-same-frame) ; implies wind-A is suitable
475f9031 540 (null use-same-frame-for-AB))
bbe6126c
MK
541 (progn ; bug A on its own
542 ;; buffer buf-A is seen in live wind-A
475f9031
KH
543 (select-window wind-A)
544 (delete-other-windows)
475f9031
KH
545 (setq wind-A (selected-window))
546 (setq done-A t)))
71296446 547
475f9031 548 ;; buf-B on its own
bbe6126c
MK
549 (if (and (window-live-p wind-B)
550 (null use-same-frame) ; implies wind-B is suitable
551 (null use-same-frame-for-AB))
552 (progn ; buf B on its own
553 ;; buffer buf-B is seen in live wind-B
475f9031
KH
554 (select-window wind-B)
555 (delete-other-windows)
475f9031
KH
556 (setq wind-B (selected-window))
557 (setq done-B t)))
71296446 558
475f9031 559 ;; buf-C on its own
bbe6126c
MK
560 (if (and (window-live-p wind-C)
561 (ediff-window-ok-for-display wind-C)
562 (null use-same-frame)) ; buf C on its own
475f9031 563 (progn
bbe6126c 564 ;; buffer buf-C is seen in live wind-C
475f9031
KH
565 (select-window wind-C)
566 (delete-other-windows)
475f9031
KH
567 (setq wind-C (selected-window))
568 (setq done-C t)))
71296446 569
bbe6126c
MK
570 (if (and use-same-frame-for-AB ; implies wind A and B are suitable
571 (window-live-p wind-A))
6628e7f8 572 (progn
bbe6126c
MK
573 ;; wind-A must already be displaying buf-A
574 (select-window wind-A)
475f9031
KH
575 (delete-other-windows)
576 (setq wind-A (selected-window))
71296446 577
475f9031 578 (funcall split-window-function)
6628e7f8 579 (if (eq (selected-window) wind-A)
475f9031
KH
580 (other-window 1))
581 (switch-to-buffer buf-B)
582 (setq wind-B (selected-window))
71296446 583
475f9031
KH
584 (setq done-A t
585 done-B t)))
71296446 586
475f9031 587 (if use-same-frame
bbe6126c 588 (let ((window-min-height 1))
ddc90f39
MK
589 (if (and (eq frame-A frame-B)
590 (eq frame-B frame-C)
591 (frame-live-p frame-A))
592 (select-frame frame-A)
593 ;; avoid dedicated and non-splittable windows
594 (ediff-skip-unsuitable-frames))
475f9031
KH
595 (delete-other-windows)
596 (setq merge-window-lines
597 (max 2 (round (* (window-height) merge-window-share))))
598 (switch-to-buffer buf-A)
599 (setq wind-A (selected-window))
71296446 600
475f9031
KH
601 (split-window-vertically
602 (max 2 (- (window-height) merge-window-lines)))
6628e7f8 603 (if (eq (selected-window) wind-A)
475f9031
KH
604 (other-window 1))
605 (setq wind-C (selected-window))
606 (switch-to-buffer buf-C)
71296446 607
475f9031 608 (select-window wind-A)
71296446 609
475f9031 610 (funcall split-window-function)
6628e7f8 611 (if (eq (selected-window) wind-A)
475f9031
KH
612 (other-window 1))
613 (switch-to-buffer buf-B)
614 (setq wind-B (selected-window))
71296446 615
475f9031
KH
616 (setq done-A t
617 done-B t
618 done-C t)
619 ))
71296446 620
bbe6126c
MK
621 (or done-A ; Buf A to be set in its own frame,
622 ;;; or it was set before because use-same-frame = 1
623 (progn
624 ;; Buf-A was not set up yet as it wasn't visible,
625 ;; and use-same-frame = nil, use-same-frame-for-AB = nil
475f9031
KH
626 (select-window orig-wind)
627 (delete-other-windows)
628 (switch-to-buffer buf-A)
629 (setq wind-A (selected-window))
630 ))
bbe6126c
MK
631 (or done-B ; Buf B to be set in its own frame,
632 ;;; or it was set before because use-same-frame = 1
633 (progn
634 ;; Buf-B was not set up yet as it wasn't visible
635 ;; and use-same-frame = nil, use-same-frame-for-AB = nil
475f9031
KH
636 (select-window orig-wind)
637 (delete-other-windows)
638 (switch-to-buffer buf-B)
639 (setq wind-B (selected-window))
640 ))
71296446 641
bbe6126c
MK
642 (or done-C ; Buf C to be set in its own frame,
643 ;;; or it was set before because use-same-frame = 1
644 (progn
645 ;; Buf-C was not set up yet as it wasn't visible
646 ;; and use-same-frame = nil
475f9031
KH
647 (select-window orig-wind)
648 (delete-other-windows)
649 (switch-to-buffer buf-C)
650 (setq wind-C (selected-window))
651 ))
71296446 652
e756eb9f 653 (ediff-with-current-buffer control-buf
475f9031
KH
654 (setq ediff-window-A wind-A
655 ediff-window-B wind-B
656 ediff-window-C wind-C)
18b5607f
KH
657 (setq frame-A (window-frame ediff-window-A)
658 designated-minibuffer-frame
659 (window-frame (minibuffer-window frame-A))))
71296446 660
18b5607f 661 (ediff-setup-control-frame control-buf designated-minibuffer-frame)
475f9031
KH
662 ))
663
71296446 664
475f9031
KH
665;; Window setup for all comparison jobs, including 3way comparisons
666(defun ediff-setup-windows-multiframe-compare (buf-A buf-B buf-C control-buf)
667;;; Algorithm:
6628e7f8 668;;; If a buffer is seen in a frame, use that frame for that buffer.
475f9031
KH
669;;; If it is not seen, use the current frame.
670;;; If both buffers are not seen, they share the current frame. If one
671;;; of the buffers is not seen, it is placed in the current frame (where
3af0304a 672;;; ediff started). If that frame is displaying the other buffer, it is
475f9031
KH
673;;; shared between the two buffers.
674;;; However, if we decide to put both buffers in one frame
675;;; and the selected frame isn't splittable, we create a new frame and
676;;; put both buffers there, event if one of this buffers is visible in
677;;; another frame.
71296446 678
475f9031
KH
679 ;; Skip dedicated or iconified frames.
680 ;; Unsplittable frames are taken care of later.
681 (ediff-skip-unsuitable-frames 'ok-unsplittable)
71296446 682
4ae69eac 683 (let* ((window-min-height 1)
475f9031
KH
684 (wind-A (ediff-get-visible-buffer-window buf-A))
685 (wind-B (ediff-get-visible-buffer-window buf-B))
686 (wind-C (ediff-get-visible-buffer-window buf-C))
18b5607f
KH
687 (frame-A (if wind-A (window-frame wind-A)))
688 (frame-B (if wind-B (window-frame wind-B)))
689 (frame-C (if wind-C (window-frame wind-C)))
e756eb9f 690 (ctl-frame-exists-p (ediff-with-current-buffer control-buf
18b5607f 691 (frame-live-p ediff-control-frame)))
475f9031 692 ;; on wide display, do things in one frame
6628e7f8 693 (force-one-frame
e756eb9f 694 (ediff-with-current-buffer control-buf ediff-wide-display-p))
475f9031 695 ;; this lets us have local versions of ediff-split-window-function
6628e7f8 696 (split-window-function
e756eb9f 697 (ediff-with-current-buffer control-buf ediff-split-window-function))
475f9031 698 (three-way-comparison
e756eb9f 699 (ediff-with-current-buffer control-buf ediff-3way-comparison-job))
475f9031
KH
700 (orig-wind (selected-window))
701 (use-same-frame (or force-one-frame
702 (eq frame-A frame-B)
bbe6126c
MK
703 (not (ediff-window-ok-for-display wind-A))
704 (not (ediff-window-ok-for-display wind-B))
475f9031
KH
705 (if three-way-comparison
706 (or (eq frame-A frame-C)
707 (eq frame-B frame-C)
bbe6126c 708 (not (ediff-window-ok-for-display wind-C))
18b5607f
KH
709 (not (frame-live-p frame-A))
710 (not (frame-live-p frame-B))
711 (not (frame-live-p frame-C))))
712 (and (not (frame-live-p frame-B))
475f9031 713 (or ctl-frame-exists-p
18b5607f
KH
714 (eq frame-A (selected-frame))))
715 (and (not (frame-live-p frame-A))
475f9031 716 (or ctl-frame-exists-p
18b5607f 717 (eq frame-B (selected-frame))))))
6628e7f8 718 wind-A-start wind-B-start
475f9031
KH
719 designated-minibuffer-frame
720 done-A done-B done-C)
71296446 721
e756eb9f 722 (ediff-with-current-buffer control-buf
475f9031
KH
723 (setq wind-A-start (ediff-overlay-start
724 (ediff-get-value-according-to-buffer-type
725 'A ediff-narrow-bounds))
726 wind-B-start (ediff-overlay-start
727 (ediff-get-value-according-to-buffer-type
18b5607f 728 'B ediff-narrow-bounds))))
71296446 729
475f9031
KH
730 (if (and (window-live-p wind-A) (null use-same-frame)) ; buf-A on its own
731 (progn
bbe6126c
MK
732 ;; buffer buf-A is seen in live wind-A
733 (select-window wind-A) ; must be displaying buf-A
475f9031 734 (delete-other-windows)
475f9031
KH
735 (setq wind-A (selected-window))
736 (setq done-A t)))
71296446 737
475f9031
KH
738 (if (and (window-live-p wind-B) (null use-same-frame)) ; buf B on its own
739 (progn
bbe6126c
MK
740 ;; buffer buf-B is seen in live wind-B
741 (select-window wind-B) ; must be displaying buf-B
475f9031 742 (delete-other-windows)
475f9031
KH
743 (setq wind-B (selected-window))
744 (setq done-B t)))
71296446 745
475f9031
KH
746 (if (and (window-live-p wind-C) (null use-same-frame)) ; buf C on its own
747 (progn
bbe6126c
MK
748 ;; buffer buf-C is seen in live wind-C
749 (select-window wind-C) ; must be displaying buf-C
475f9031 750 (delete-other-windows)
475f9031
KH
751 (setq wind-C (selected-window))
752 (setq done-C t)))
71296446 753
475f9031 754 (if use-same-frame
bbe6126c 755 (let (wind-width-or-height) ; this affects 3way setups only
ddc90f39
MK
756 (if (and (eq frame-A frame-B) (frame-live-p frame-A))
757 (select-frame frame-A)
758 ;; avoid dedicated and non-splittable windows
759 (ediff-skip-unsuitable-frames))
475f9031
KH
760 (delete-other-windows)
761 (switch-to-buffer buf-A)
762 (setq wind-A (selected-window))
71296446 763
475f9031
KH
764 (if three-way-comparison
765 (setq wind-width-or-height
766 (/
767 (if (eq split-window-function 'split-window-vertically)
768 (window-height wind-A)
769 (window-width wind-A))
770 3)))
71296446 771
475f9031 772 (funcall split-window-function wind-width-or-height)
6628e7f8 773 (if (eq (selected-window) wind-A)
475f9031
KH
774 (other-window 1))
775 (switch-to-buffer buf-B)
776 (setq wind-B (selected-window))
71296446 777
475f9031
KH
778 (if three-way-comparison
779 (progn
780 (funcall split-window-function) ; equally
781 (if (memq (selected-window) (list wind-A wind-B))
782 (other-window 1))
783 (switch-to-buffer buf-C)
784 (setq wind-C (selected-window))))
785 (setq done-A t
786 done-B t
787 done-C t)
788 ))
71296446 789
475f9031 790 (or done-A ; Buf A to be set in its own frame
bbe6126c 791 ;;; or it was set before because use-same-frame = 1
6628e7f8 792 (progn
bbe6126c
MK
793 ;; Buf-A was not set up yet as it wasn't visible,
794 ;; and use-same-frame = nil
475f9031
KH
795 (select-window orig-wind)
796 (delete-other-windows)
797 (switch-to-buffer buf-A)
798 (setq wind-A (selected-window))
799 ))
800 (or done-B ; Buf B to be set in its own frame
bbe6126c 801 ;;; or it was set before because use-same-frame = 1
6628e7f8 802 (progn
bbe6126c
MK
803 ;; Buf-B was not set up yet as it wasn't visible,
804 ;; and use-same-frame = nil
475f9031
KH
805 (select-window orig-wind)
806 (delete-other-windows)
807 (switch-to-buffer buf-B)
808 (setq wind-B (selected-window))
809 ))
71296446 810
475f9031
KH
811 (if three-way-comparison
812 (or done-C ; Buf C to be set in its own frame
bbe6126c 813 ;;; or it was set before because use-same-frame = 1
6628e7f8 814 (progn
bbe6126c
MK
815 ;; Buf-C was not set up yet as it wasn't visible,
816 ;; and use-same-frame = nil
475f9031
KH
817 (select-window orig-wind)
818 (delete-other-windows)
819 (switch-to-buffer buf-C)
820 (setq wind-C (selected-window))
821 )))
71296446 822
e756eb9f 823 (ediff-with-current-buffer control-buf
475f9031
KH
824 (setq ediff-window-A wind-A
825 ediff-window-B wind-B
826 ediff-window-C wind-C)
2e955a8b 827
18b5607f
KH
828 (setq frame-A (window-frame ediff-window-A)
829 designated-minibuffer-frame
830 (window-frame (minibuffer-window frame-A))))
71296446 831
bbe6126c 832 ;; It is unlikely that we'll implement a version of ediff-windows that
3af0304a 833 ;; would compare 3 windows at once. So, we don't use buffer C here.
18b5607f 834 (if ediff-windows-job
475f9031
KH
835 (progn
836 (set-window-start wind-A wind-A-start)
837 (set-window-start wind-B wind-B-start)))
71296446 838
18b5607f 839 (ediff-setup-control-frame control-buf designated-minibuffer-frame)
475f9031
KH
840 ))
841
bbe6126c 842;; skip unsplittable frames and frames that have dedicated windows.
475f9031
KH
843;; create a new splittable frame if none is found
844(defun ediff-skip-unsuitable-frames (&optional ok-unsplittable)
18b5607f 845 (if (ediff-window-display-p)
2e955a8b
MK
846 (let ((wind-frame (window-frame (selected-window)))
847 seen-windows)
657f9cb8 848 (while (and (not (memq (selected-window) seen-windows))
475f9031 849 (or
2e955a8b
MK
850 (ediff-frame-has-dedicated-windows wind-frame)
851 (ediff-frame-iconified-p wind-frame)
3af0304a 852 ;; skip small windows
2e955a8b 853 (< (frame-height wind-frame)
3af0304a 854 (* 3 window-min-height))
475f9031
KH
855 (if ok-unsplittable
856 nil
2e955a8b
MK
857 (ediff-frame-unsplittable-p wind-frame))))
858 ;; remember history
657f9cb8 859 (setq seen-windows (cons (selected-window) seen-windows))
475f9031 860 ;; try new window
2e955a8b
MK
861 (other-window 1 t)
862 (setq wind-frame (window-frame (selected-window)))
863 )
657f9cb8 864 (if (memq (selected-window) seen-windows)
2e955a8b
MK
865 ;; fed up, no appropriate frames
866 (setq wind-frame (make-frame '((unsplittable)))))
867
868 (select-frame wind-frame)
869 )))
475f9031 870
bbe6126c 871(defun ediff-frame-has-dedicated-windows (frame)
2e955a8b 872 (let (ans)
71296446 873 (walk-windows
3af0304a
MK
874 (lambda (wind) (if (window-dedicated-p wind)
875 (setq ans t)))
bbe6126c
MK
876 'ignore-minibuffer
877 frame)
bbe6126c
MK
878 ans))
879
880;; window is ok, if it is only one window on the frame, not counting the
881;; minibuffer, or none of the frame's windows is dedicated.
882;; The idea is that it is bad to destroy dedicated windows while creating an
883;; ediff window setup
884(defun ediff-window-ok-for-display (wind)
885 (and
886 (window-live-p wind)
6628e7f8 887 (or
bbe6126c
MK
888 ;; only one window
889 (eq wind (next-window wind 'ignore-minibuffer (window-frame wind)))
2d84cc27 890 ;; none is dedicated (in multiframe setup)
bbe6126c
MK
891 (not (ediff-frame-has-dedicated-windows (window-frame wind)))
892 )))
893
475f9031 894;; Prepare or refresh control frame
18b5607f 895(defun ediff-setup-control-frame (ctl-buffer designated-minibuffer-frame)
4ae69eac 896 (let ((window-min-height 1)
475f9031 897 ctl-frame-iconified-p dont-iconify-ctl-frame deiconify-ctl-frame
6628e7f8 898 ctl-frame old-ctl-frame lines
bbe6126c 899 ;; user-grabbed-mouse
6628e7f8 900 fheight fwidth adjusted-parameters)
71296446 901
e756eb9f 902 (ediff-with-current-buffer ctl-buffer
2d84cc27
MK
903 (if (and (featurep 'xemacs) (featurep 'menubar))
904 (set-buffer-menubar nil))
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
2d84cc27
MK
916 (if (and (featurep 'emacs) (face-attribute 'mode-line :box))
917 (set-face-attribute 'mode-line ctl-frame :box nil))
f6d49b2f 918 (error)))
71296446 919
475f9031 920 (setq ctl-frame-iconified-p (ediff-frame-iconified-p ctl-frame))
18b5607f 921 (select-frame ctl-frame)
475f9031
KH
922 (if (window-dedicated-p (selected-window))
923 ()
924 (delete-other-windows)
925 (switch-to-buffer ctl-buffer))
71296446 926
475f9031 927 ;; must be before ediff-setup-control-buffer
6853a937 928 ;; just a precaution--we should be in ctl-buffer already
e756eb9f 929 (ediff-with-current-buffer ctl-buffer
6853a937
MK
930 (make-local-variable 'frame-title-format)
931 (make-local-variable 'frame-icon-title-format) ; XEmacs
932 (make-local-variable 'icon-title-format)) ; Emacs
71296446 933
475f9031
KH
934 (ediff-setup-control-buffer ctl-buffer)
935 (setq dont-iconify-ctl-frame
936 (not (string= ediff-help-message ediff-brief-help-message)))
6628e7f8 937 (setq deiconify-ctl-frame
475f9031
KH
938 (and (eq this-command 'ediff-toggle-help)
939 dont-iconify-ctl-frame))
71296446 940
475f9031 941 ;; 1 more line for the modeline
4ae69eac 942 (setq lines (1+ (count-lines (point-min) (point-max)))
475f9031 943 fheight lines
bf5d92c5
MK
944 fwidth (max (+ (ediff-help-message-line-length) 2)
945 (ediff-compute-toolbar-width))
ddc90f39
MK
946 adjusted-parameters
947 (list
948 ;; possibly change surrogate minibuffer
949 (cons 'minibuffer
950 (minibuffer-window
951 designated-minibuffer-frame))
952 (cons 'width fwidth)
59f1b058
MK
953 (cons 'height fheight)
954 (cons 'user-position t)
955 ))
2e955a8b
MK
956
957 ;; adjust autoraise
958 (setq adjusted-parameters
959 (cons (if ediff-use-long-help-message
960 '(auto-raise . nil)
961 '(auto-raise . t))
962 adjusted-parameters))
71296446 963
475f9031 964 ;; In XEmacs, buffer menubar needs to be killed before frame parameters
6628e7f8 965 ;; are changed.
2eb4bdca 966 (if (ediff-has-toolbar-support-p)
f6d49b2f
GM
967 (when (featurep 'xemacs)
968 (if (ediff-has-gutter-support-p)
969 (set-specifier top-gutter (list ctl-frame nil)))
970 (sit-for 0)
971 (set-specifier top-toolbar-height (list ctl-frame 0))
972 ;;(set-specifier bottom-toolbar-height (list ctl-frame 0))
973 (set-specifier left-toolbar-width (list ctl-frame 0))
974 (set-specifier right-toolbar-width (list ctl-frame 0))))
71296446 975
4ae69eac 976 ;; Under OS/2 (emx) we have to call modify frame parameters twice, in order
3af0304a 977 ;; to make sure that at least once we do it for non-iconified frame. If
4ae69eac 978 ;; appears that in the OS/2 port of Emacs, one can't modify frame
3af0304a 979 ;; parameters of iconified frames. As a precaution, we do likewise for
4ae69eac
MK
980 ;; windows-nt.
981 (if (memq system-type '(emx windows-nt windows-95))
18b5607f 982 (modify-frame-parameters ctl-frame adjusted-parameters))
71296446 983
ddc90f39
MK
984 ;; make or zap toolbar (if not requested)
985 (ediff-make-bottom-toolbar ctl-frame)
71296446 986
ddc90f39
MK
987 (goto-char (point-min))
988
6853a937 989 (modify-frame-parameters ctl-frame adjusted-parameters)
bbe6126c 990 (make-frame-visible ctl-frame)
71296446 991
3af0304a 992 ;; This works around a bug in 19.25 and earlier. There, if frame gets
475f9031
KH
993 ;; iconified, the current buffer changes to that of the frame that
994 ;; becomes exposed as a result of this iconification.
995 ;; So, we make sure the current buffer doesn't change.
18b5607f 996 (select-frame ctl-frame)
475f9031 997 (ediff-refresh-control-frame)
71296446 998
6853a937
MK
999 (cond ((and ediff-prefer-iconified-control-frame
1000 (not ctl-frame-iconified-p) (not dont-iconify-ctl-frame))
1001 (iconify-frame ctl-frame))
1002 ((or deiconify-ctl-frame (not ctl-frame-iconified-p))
1003 (raise-frame ctl-frame)))
71296446 1004
bbe6126c 1005 (set-window-dedicated-p (selected-window) t)
ddc90f39 1006
3af0304a 1007 ;; Now move the frame. We must do it separately due to an obscure bug in
ddc90f39
MK
1008 ;; XEmacs
1009 (modify-frame-parameters
1010 ctl-frame
1011 (funcall ediff-control-frame-position-function ctl-buffer fwidth fheight))
71296446 1012
bbe6126c 1013 ;; synchronize so the cursor will move to control frame
6853a937 1014 ;; per RMS suggestion
4ae69eac
MK
1015 (if (ediff-window-display-p)
1016 (let ((count 7))
1017 (sit-for .1)
1018 (while (and (not (frame-visible-p ctl-frame)) (> count 0))
1019 (setq count (1- count))
1020 (sit-for .3))))
6853a937 1021
475f9031 1022 (or (ediff-frame-iconified-p ctl-frame)
6853a937 1023 ;; don't warp the mouse, unless ediff-grab-mouse = t
4ae69eac
MK
1024 (ediff-reset-mouse ctl-frame
1025 (or (eq this-command 'ediff-quit)
1026 (not (eq ediff-grab-mouse t)))))
71296446 1027
f6d49b2f
GM
1028 (when (featurep 'xemacs)
1029 (ediff-with-current-buffer ctl-buffer
1030 (make-local-hook 'select-frame-hook)
1031 (add-hook 'select-frame-hook
1032 'ediff-xemacs-select-frame-hook nil 'local)))
71296446 1033
e756eb9f 1034 (ediff-with-current-buffer ctl-buffer
f6d49b2f 1035 (run-hooks 'ediff-after-setup-control-frame-hook))))
ddc90f39 1036
71296446 1037
18b5607f 1038(defun ediff-destroy-control-frame (ctl-buffer)
e756eb9f 1039 (ediff-with-current-buffer ctl-buffer
18b5607f
KH
1040 (if (and (ediff-window-display-p) (frame-live-p ediff-control-frame))
1041 (let ((ctl-frame ediff-control-frame))
2d84cc27
MK
1042 (if (and (featurep 'xemacs) (featurep 'menubar))
1043 (set-buffer-menubar default-menubar))
18b5607f 1044 (setq ediff-control-frame nil)
f6d49b2f 1045 (delete-frame ctl-frame))))
2d84cc27
MK
1046 (if ediff-multiframe
1047 (ediff-skip-unsuitable-frames))
6853a937
MK
1048 ;;(ediff-reset-mouse nil)
1049 )
71296446 1050
475f9031
KH
1051
1052;; finds a good place to clip control frame
1053(defun ediff-make-frame-position (ctl-buffer ctl-frame-width ctl-frame-height)
e756eb9f 1054 (ediff-with-current-buffer ctl-buffer
18b5607f
KH
1055 (let* ((frame-A (window-frame ediff-window-A))
1056 (frame-A-parameters (frame-parameters frame-A))
6853a937
MK
1057 (frame-A-top (eval (cdr (assoc 'top frame-A-parameters))))
1058 (frame-A-left (eval (cdr (assoc 'left frame-A-parameters))))
18b5607f 1059 (frame-A-width (frame-width frame-A))
475f9031
KH
1060 (ctl-frame ediff-control-frame)
1061 horizontal-adjustment upward-adjustment
6628e7f8 1062 ctl-frame-top ctl-frame-left)
71296446 1063
475f9031 1064 ;; Multiple control frames are clipped based on the value of
3af0304a 1065 ;; ediff-control-buffer-number. This is done in order not to obscure
475f9031
KH
1066 ;; other active control panels.
1067 (setq horizontal-adjustment (* 2 ediff-control-buffer-number)
1068 upward-adjustment (* -14 ediff-control-buffer-number))
1069
6853a937
MK
1070 (setq ctl-frame-top
1071 (- frame-A-top upward-adjustment ediff-control-frame-upward-shift)
1072 ctl-frame-left
1073 (+ frame-A-left
4ae69eac 1074 (if ediff-use-long-help-message
6853a937
MK
1075 (* (ediff-frame-char-width ctl-frame)
1076 (+ ediff-wide-control-frame-rightward-shift
1077 horizontal-adjustment))
1078 (- (* frame-A-width (ediff-frame-char-width frame-A))
1079 (* (ediff-frame-char-width ctl-frame)
1080 (+ ctl-frame-width
1081 ediff-narrow-control-frame-leftward-shift
1082 horizontal-adjustment))))))
6853a937
MK
1083 (setq ctl-frame-top
1084 (min ctl-frame-top
1085 (- (ediff-display-pixel-height)
1086 (* 2 ctl-frame-height
1087 (ediff-frame-char-height ctl-frame))))
1088 ctl-frame-left
1089 (min ctl-frame-left
1090 (- (ediff-display-pixel-width)
1091 (* ctl-frame-width (ediff-frame-char-width ctl-frame)))))
4ae69eac
MK
1092 ;; keep ctl frame within the visible bounds
1093 (setq ctl-frame-top (max ctl-frame-top 1)
1094 ctl-frame-left (max ctl-frame-left 1))
71296446 1095
6853a937
MK
1096 (list (cons 'top ctl-frame-top)
1097 (cons 'left ctl-frame-left))
1098 )))
71296446 1099
18b5607f 1100(defun ediff-xemacs-select-frame-hook ()
6853a937 1101 (if (and (equal (selected-frame) ediff-control-frame)
4ae69eac 1102 (not ediff-use-long-help-message))
18b5607f 1103 (raise-frame ediff-control-frame)))
71296446 1104
475f9031
KH
1105(defun ediff-make-wide-display ()
1106 "Construct an alist of parameters for the wide display.
1107Saves the old frame parameters in `ediff-wide-display-orig-parameters'.
1108The frame to be resized is kept in `ediff-wide-display-frame'.
1109This function modifies only the left margin and the width of the display.
1110It assumes that it is called from within the control buffer."
18b5607f 1111 (if (not (fboundp 'ediff-display-pixel-width))
6628e7f8 1112 (error "Can't determine display width"))
18b5607f
KH
1113 (let* ((frame-A (window-frame ediff-window-A))
1114 (frame-A-params (frame-parameters frame-A))
475f9031 1115 (cw (ediff-frame-char-width frame-A))
18b5607f 1116 (wd (- (/ (ediff-display-pixel-width) cw) 5)))
6628e7f8 1117 (setq ediff-wide-display-orig-parameters
6853a937 1118 (list (cons 'left (max 0 (eval (cdr (assoc 'left frame-A-params)))))
475f9031
KH
1119 (cons 'width (cdr (assoc 'width frame-A-params))))
1120 ediff-wide-display-frame frame-A)
59f1b058
MK
1121 (modify-frame-parameters
1122 frame-A `((left . ,cw) (width . ,wd) (user-position t)))))
71296446 1123
475f9031
KH
1124
1125;; Revise the mode line to display which difference we have selected
1126;; Also resets modelines of buffers A/B, since they may be clobbered by
1127;; anothe invocations of Ediff.
1128(defun ediff-refresh-mode-lines ()
1129 (let (buf-A-state-diff buf-B-state-diff buf-C-state-diff buf-C-state-merge)
71296446 1130
475f9031
KH
1131 (if (ediff-valid-difference-p)
1132 (setq
1133 buf-C-state-diff (ediff-get-state-of-diff ediff-current-difference 'C)
1134 buf-C-state-merge (ediff-get-state-of-merge ediff-current-difference)
1135 buf-A-state-diff (ediff-get-state-of-diff ediff-current-difference 'A)
1136 buf-B-state-diff (ediff-get-state-of-diff ediff-current-difference 'B)
1137 buf-A-state-diff (if buf-A-state-diff
1138 (format "[%s] " buf-A-state-diff)
1139 "")
1140 buf-B-state-diff (if buf-B-state-diff
1141 (format "[%s] " buf-B-state-diff)
1142 "")
1143 buf-C-state-diff (if (and (ediff-buffer-live-p ediff-buffer-C)
1144 (or buf-C-state-diff buf-C-state-merge))
6853a937 1145 (format "[%s%s%s] "
475f9031
KH
1146 (or buf-C-state-diff "")
1147 (if buf-C-state-merge
1148 (concat " " buf-C-state-merge)
6853a937 1149 "")
6628e7f8 1150 (if (ediff-get-state-of-ancestor
6853a937
MK
1151 ediff-current-difference)
1152 " AncestorEmpty"
1153 "")
1154 )
475f9031
KH
1155 ""))
1156 (setq buf-A-state-diff ""
1157 buf-B-state-diff ""
1158 buf-C-state-diff ""))
71296446 1159
475f9031
KH
1160 ;; control buffer format
1161 (setq mode-line-format
ddc90f39
MK
1162 (if (ediff-narrow-control-frame-p)
1163 (list " " mode-line-buffer-identification)
1164 (list "-- " mode-line-buffer-identification " Quick Help")))
475f9031 1165 ;; control buffer id
6628e7f8 1166 (setq mode-line-buffer-identification
475f9031
KH
1167 (if (ediff-narrow-control-frame-p)
1168 (ediff-make-narrow-control-buffer-id 'skip-name)
1169 (ediff-make-wide-control-buffer-id)))
1170 ;; Force mode-line redisplay
1171 (force-mode-line-update)
71296446 1172
18b5607f 1173 (if (and (ediff-window-display-p) (frame-live-p ediff-control-frame))
475f9031 1174 (ediff-refresh-control-frame))
71296446 1175
e756eb9f 1176 (ediff-with-current-buffer ediff-buffer-A
475f9031
KH
1177 (setq ediff-diff-status buf-A-state-diff)
1178 (ediff-strip-mode-line-format)
1179 (setq mode-line-format
1180 (list " A: " 'ediff-diff-status mode-line-format))
1181 (force-mode-line-update))
e756eb9f 1182 (ediff-with-current-buffer ediff-buffer-B
475f9031
KH
1183 (setq ediff-diff-status buf-B-state-diff)
1184 (ediff-strip-mode-line-format)
1185 (setq mode-line-format
1186 (list " B: " 'ediff-diff-status mode-line-format))
1187 (force-mode-line-update))
1188 (if ediff-3way-job
e756eb9f 1189 (ediff-with-current-buffer ediff-buffer-C
475f9031
KH
1190 (setq ediff-diff-status buf-C-state-diff)
1191 (ediff-strip-mode-line-format)
1192 (setq mode-line-format
1193 (list " C: " 'ediff-diff-status mode-line-format))
1194 (force-mode-line-update)))
6853a937 1195 (if (ediff-buffer-live-p ediff-ancestor-buffer)
e756eb9f 1196 (ediff-with-current-buffer ediff-ancestor-buffer
6853a937
MK
1197 (ediff-strip-mode-line-format)
1198 ;; we keep the second dummy string in the mode line format of the
1199 ;; ancestor, since for other buffers Ediff prepends 2 strings and
1200 ;; ediff-strip-mode-line-format expects that.
1201 (setq mode-line-format
1202 (list " Ancestor: "
1203 (cond ((not (stringp buf-C-state-merge))
1204 "")
1205 ((string-match "prefer-A" buf-C-state-merge)
1206 "[=diff(B)] ")
1207 ((string-match "prefer-B" buf-C-state-merge)
1208 "[=diff(A)] ")
1209 (t ""))
1210 mode-line-format))))
475f9031 1211 ))
71296446
JB
1212
1213
475f9031 1214(defun ediff-refresh-control-frame ()
e83d1fe8 1215 (if (featurep 'emacs)
bbe6126c 1216 ;; set frame/icon titles for Emacs
6853a937
MK
1217 (modify-frame-parameters
1218 ediff-control-frame
bbe6126c
MK
1219 (list (cons 'title (ediff-make-base-title))
1220 (cons 'icon-name (ediff-make-narrow-control-buffer-id))
1221 ))
1222 ;; set frame/icon titles for XEmacs
1223 (setq frame-title-format (ediff-make-base-title)
1224 frame-icon-title-format (ediff-make-narrow-control-buffer-id))
6853a937
MK
1225 ;; force an update of the frame title
1226 (modify-frame-parameters ediff-control-frame '(()))))
71296446
JB
1227
1228
475f9031
KH
1229(defun ediff-make-narrow-control-buffer-id (&optional skip-name)
1230 (concat
1231 (if skip-name
1232 " "
bbe6126c 1233 (ediff-make-base-title))
6628e7f8 1234 (cond ((< ediff-current-difference 0)
475f9031
KH
1235 (format " _/%d" ediff-number-of-differences))
1236 ((>= ediff-current-difference ediff-number-of-differences)
1237 (format " $/%d" ediff-number-of-differences))
1238 (t
1239 (format " %d/%d"
1240 (1+ ediff-current-difference)
1241 ediff-number-of-differences)))))
bbe6126c
MK
1242
1243(defun ediff-make-base-title ()
1244 (concat
1245 (cdr (assoc 'name ediff-control-frame-parameters))
1246 ediff-control-buffer-suffix))
71296446 1247
475f9031
KH
1248(defun ediff-make-wide-control-buffer-id ()
1249 (cond ((< ediff-current-difference 0)
1250 (list (format "%%b At start of %d diffs"
1251 ediff-number-of-differences)))
1252 ((>= ediff-current-difference ediff-number-of-differences)
1253 (list (format "%%b At end of %d diffs"
1254 ediff-number-of-differences)))
1255 (t
1256 (list (format "%%b diff %d of %d"
1257 (1+ ediff-current-difference)
1258 ediff-number-of-differences)))))
1259
1260
1261
1262;; If buff is not live, return nil
1263(defun ediff-get-visible-buffer-window (buff)
1264 (if (ediff-buffer-live-p buff)
e83d1fe8 1265 (if (featurep 'xemacs)
475f9031
KH
1266 (get-buffer-window buff t)
1267 (get-buffer-window buff 'visible))))
71296446 1268
475f9031 1269
bbe6126c 1270;;; Functions to decide when to redraw windows
71296446 1271
475f9031
KH
1272(defun ediff-keep-window-config (control-buf)
1273 (and (eq control-buf (current-buffer))
1274 (/= (buffer-size) 0)
e756eb9f 1275 (ediff-with-current-buffer control-buf
475f9031
KH
1276 (let ((ctl-wind ediff-control-window)
1277 (A-wind ediff-window-A)
1278 (B-wind ediff-window-B)
1279 (C-wind ediff-window-C))
71296446 1280
475f9031
KH
1281 (and
1282 (ediff-window-visible-p A-wind)
1283 (ediff-window-visible-p B-wind)
1284 ;; if buffer C is defined then take it into account
1285 (or (not ediff-3way-job)
1286 (ediff-window-visible-p C-wind))
1287 (eq (window-buffer A-wind) ediff-buffer-A)
1288 (eq (window-buffer B-wind) ediff-buffer-B)
1289 (or (not ediff-3way-job)
1290 (eq (window-buffer C-wind) ediff-buffer-C))
1291 (string= ediff-window-config-saved
18b5607f 1292 (format "%S%S%S%S%S%S%S"
475f9031 1293 ctl-wind A-wind B-wind C-wind
18b5607f
KH
1294 ediff-split-window-function
1295 (ediff-multiframe-setup-p)
1296 ediff-wide-display-p)))))))
475f9031
KH
1297
1298
b6178721
MK
1299(provide 'ediff-wind)
1300
1301
bbe6126c
MK
1302;;; Local Variables:
1303;;; eval: (put 'ediff-defvar-local 'lisp-indent-hook 'defun)
e756eb9f
MK
1304;;; eval: (put 'ediff-with-current-buffer 'lisp-indent-hook 1)
1305;;; eval: (put 'ediff-with-current-buffer 'edebug-form-spec '(form body))
bbe6126c
MK
1306;;; End:
1307
cbee283d 1308;; arch-tag: 73d9a5d7-eed7-4d9c-8b4b-21d5d78eb597
475f9031 1309;;; ediff-wind.el ends here