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