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