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