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