aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Rudalics2011-10-21 11:15:32 +0200
committerMartin Rudalics2011-10-21 11:15:32 +0200
commite07b9a6d33fedd63f424c0e7627cbf680cbf3b6f (patch)
tree307557ece9c75b55af524cdf42d9f92bcba8dfcc
parent7e1361d995cba156dd4b14ac4ba236bf90908d46 (diff)
downloademacs-e07b9a6d33fedd63f424c0e7627cbf680cbf3b6f.tar.gz
emacs-e07b9a6d33fedd63f424c0e7627cbf680cbf3b6f.zip
Fix and improve mouse-dragging of horizontal/vertical lines.
* mouse.el (mouse-drag-window-above) (mouse-drag-move-window-bottom, mouse-drag-move-window-top) (mouse-drag-mode-line-1, mouse-drag-header-line) (mouse-drag-vertical-line-rightward-window): Remove. (mouse-drag-line): New function. (mouse-drag-mode-line, mouse-drag-header-line) (mouse-drag-vertical-line): Call mouse-drag-line. * window.el (window-at-side-p, windows-at-side): New functions.
-rw-r--r--lisp/ChangeLog11
-rw-r--r--lisp/mouse.el418
-rw-r--r--lisp/window.el29
3 files changed, 181 insertions, 277 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog
index 7f3e324a6e8..150ffd629e5 100644
--- a/lisp/ChangeLog
+++ b/lisp/ChangeLog
@@ -1,3 +1,14 @@
12011-10-21 Martin Rudalics <rudalics@gmx.at>
2
3 * mouse.el (mouse-drag-window-above)
4 (mouse-drag-move-window-bottom, mouse-drag-move-window-top)
5 (mouse-drag-mode-line-1, mouse-drag-header-line)
6 (mouse-drag-vertical-line-rightward-window): Remove.
7 (mouse-drag-line): New function.
8 (mouse-drag-mode-line, mouse-drag-header-line)
9 (mouse-drag-vertical-line): Call mouse-drag-line.
10 * window.el (window-at-side-p, windows-at-side): New functions.
11
12011-10-21 Ulrich Mueller <ulm@gentoo.org> 122011-10-21 Ulrich Mueller <ulm@gentoo.org>
2 13
3 * tar-mode.el (tar-grind-file-mode): 14 * tar-mode.el (tar-grind-file-mode):
diff --git a/lisp/mouse.el b/lisp/mouse.el
index ff175288445..ffa3db738ac 100644
--- a/lisp/mouse.el
+++ b/lisp/mouse.el
@@ -372,300 +372,164 @@ This command must be bound to a mouse click."
372 (split-window-horizontally 372 (split-window-horizontally
373 (min (max new-width first-col) last-col)))))) 373 (min (max new-width first-col) last-col))))))
374 374
375(defun mouse-drag-window-above (window) 375;; `mouse-drag-line' is now the common routine for handling all line
376 "Return the (or a) window directly above WINDOW. 376;; dragging events combining the earlier `mouse-drag-mode-line-1' and
377That means one whose bottom edge is at the same height as WINDOW's top edge." 377;; `mouse-drag-vertical-line'. It should improve the behavior of line
378 (let ((start-top (nth 1 (window-edges window))) 378;; dragging wrt Emacs 23 as follows:
379 (start-left (nth 0 (window-edges window))) 379
380 (start-right (nth 2 (window-edges window))) 380;; (1) Gratuitous error messages and restrictions have been (hopefully)
381 (start-window window) 381;; removed. (The help-echo that dragging the mode-line can resize a
382 above-window) 382;; one-window-frame's window will still show through via bindings.el.)
383 (setq window (previous-window window 0)) 383
384 (while (and (not above-window) (not (eq window start-window))) 384;; (2) No gratuitous selection of other windows should happen. (This
385 (let ((left (nth 0 (window-edges window))) 385;; has not been completely fixed for mouse-autoselected windows yet.)
386 (right (nth 2 (window-edges window)))) 386
387 (when (and (= (+ (window-height window) (nth 1 (window-edges window))) 387;; (3) Mouse clicks below a scroll-bar should pass through via unread
388 start-top) 388;; command events.
389 (or (and (<= left start-left) (<= start-right right)) 389
390 (and (<= start-left left) (<= left start-right)) 390;; Note that `window-in-direction' replaces `mouse-drag-window-above'
391 (and (<= start-left right) (<= right start-right)))) 391;; and `mouse-drag-vertical-line-rightward-window' with Emacs 24.1.
392 (setq above-window window))) 392(defun mouse-drag-line (start-event line)
393 (setq window (previous-window window))) 393 "Drag some line with the mouse.
394 above-window)) 394START-EVENT is the starting mouse-event of the drag action. LINE
395 395must be one of the symbols header, mode, or vertical."
396(defun mouse-drag-move-window-bottom (window growth)
397 "Move the bottom of WINDOW up or down by GROWTH lines.
398Move it down if GROWTH is positive, or up if GROWTH is negative.
399If this would make WINDOW too short,
400shrink the window or windows above it to make room."
401 (condition-case nil
402 (adjust-window-trailing-edge window growth nil)
403 (error nil)))
404
405(defsubst mouse-drag-move-window-top (window growth)
406 "Move the top of WINDOW up or down by GROWTH lines.
407Move it down if GROWTH is positive, or up if GROWTH is negative.
408If this would make WINDOW too short, shrink the window or windows
409above it to make room."
410 ;; Moving the top of WINDOW is actually moving the bottom of the
411 ;; window above.
412 (let ((window-above (mouse-drag-window-above window)))
413 (and window-above
414 (mouse-drag-move-window-bottom window-above (- growth)))))
415
416(defun mouse-drag-mode-line-1 (start-event mode-line-p)
417 "Change the height of a window by dragging on the mode or header line.
418START-EVENT is the starting mouse-event of the drag action.
419MODE-LINE-P non-nil means dragging a mode line; nil means a header line."
420 ;; Give temporary modes such as isearch a chance to turn off. 396 ;; Give temporary modes such as isearch a chance to turn off.
421 (run-hooks 'mouse-leave-buffer-hook) 397 (run-hooks 'mouse-leave-buffer-hook)
422 (let* ((done nil) 398 (let* ((echo-keystrokes 0)
423 (echo-keystrokes 0)
424 (start (event-start start-event)) 399 (start (event-start start-event))
425 (start-event-window (posn-window start)) 400 (window (posn-window start))
426 (start-event-frame (window-frame start-event-window)) 401 (frame (window-frame window))
427 (start-nwindows (count-windows t)) 402 (minibuffer-window (minibuffer-window frame))
428 (on-link (and mouse-1-click-follows-link 403 (on-link (and mouse-1-click-follows-link
429 (or mouse-1-click-in-non-selected-windows 404 (or mouse-1-click-in-non-selected-windows
430 (eq (posn-window start) (selected-window))) 405 (eq window (selected-window)))
431 (mouse-on-link-p start))) 406 (mouse-on-link-p start)))
432 (minibuffer (frame-parameter nil 'minibuffer)) 407 (enlarge-minibuffer
433 should-enlarge-minibuffer event mouse y top bot edges wconfig growth) 408 (and (eq line 'mode)
409 (eq (window-frame minibuffer-window) frame)
410 (not (one-window-p t frame))
411 (= (nth 1 (window-edges minibuffer-window))
412 (nth 3 (window-edges window)))))
413 (which-side
414 (and (eq line 'vertical)
415 (or (cdr (assq 'vertical-scroll-bars (frame-parameters frame)))
416 'right)))
417 done event mouse growth dragged)
418 (cond
419 ((eq line 'header)
420 ;; Check whether header-line can be dragged at all.
421 (when (window-at-side-p window 'top)
422 (setq done t)))
423 ((eq line 'mode)
424 ;; Check whether mode-line can be dragged at all.
425 (when (window-at-side-p window 'bottom)
426 (setq done t)))
427 ((eq line 'vertical)
428 ;; Get the window to adjust for the vertical case.
429 (setq window
430 (if (eq which-side 'right)
431 ;; If the scroll bar is on the window's right or there's
432 ;; no scroll bar at all, adjust the window where the
433 ;; start-event occurred.
434 window
435 ;; If the scroll bar is on the start-event window's left,
436 ;; adjust the window on the left of it.
437 (window-in-direction 'left window)))))
438
439 ;; Start tracking.
434 (track-mouse 440 (track-mouse
435 (progn 441 ;; Loop reading events and sampling the position of the mouse.
436 ;; if this is the bottommost ordinary window, then to 442 (while (not done)
437 ;; move its modeline the minibuffer must be enlarged. 443 (setq event (read-event))
438 (setq should-enlarge-minibuffer 444 (setq mouse (mouse-position))
439 (and minibuffer 445 ;; Do nothing if
440 mode-line-p 446 ;; - there is a switch-frame event.
441 (not (one-window-p t)) 447 ;; - the mouse isn't in the frame that we started in
442 (= (nth 1 (window-edges minibuffer)) 448 ;; - the mouse isn't in any Emacs frame
443 (nth 3 (window-edges start-event-window))))) 449 ;; Drag if
444 450 ;; - there is a mouse-movement event
445 ;; loop reading events and sampling the position of 451 ;; - there is a scroll-bar-movement event (??)
446 ;; the mouse. 452 ;; (same as mouse movement for our purposes)
447 (while (not done) 453 ;; Quit if
448 (setq event (read-event) 454 ;; - there is a keyboard event or some other unknown event.
449 mouse (mouse-position)) 455 (cond
450 456 ((not (consp event))
451 ;; do nothing if 457 (setq done t))
452 ;; - there is a switch-frame event. 458 ((memq (car event) '(switch-frame select-window))
453 ;; - the mouse isn't in the frame that we started in 459 nil)
454 ;; - the mouse isn't in any Emacs frame 460 ((not (memq (car event) '(mouse-movement scroll-bar-movement)))
455 ;; drag if 461 (when (consp event)
456 ;; - there is a mouse-movement event 462 ;; Do not unread a drag-mouse-1 event to avoid selecting
457 ;; - there is a scroll-bar-movement event 463 ;; some other window. For vertical line dragging do not
458 ;; (same as mouse movement for our purposes) 464 ;; unread mouse-1 events either (but only if we dragged at
459 ;; quit if 465 ;; least once to allow mouse-1 clicks get through.
460 ;; - there is a keyboard event or some other unknown event. 466 (unless (and dragged
461 (cond ((not (consp event)) 467 (if (eq line 'vertical)
462 (setq done t)) 468 (memq (car event) '(drag-mouse-1 mouse-1))
463 469 (eq (car event) 'drag-mouse-1)))
464 ((memq (car event) '(switch-frame select-window)) 470 (push event unread-command-events)))
465 nil) 471 (setq done t))
466 472 ((or (not (eq (car mouse) frame)) (null (car (cdr mouse))))
467 ((not (memq (car event) '(mouse-movement scroll-bar-movement))) 473 nil)
468 (when (consp event) 474 ((eq line 'vertical)
469 ;; Do not unread a drag-mouse-1 event since it will cause the 475 ;; Drag vertical divider (the calculations below are those
470 ;; selection of the window above when dragging the modeline 476 ;; from Emacs 23).
471 ;; above the selected window. 477 (setq growth
472 (unless (eq (car event) 'drag-mouse-1) 478 (- (- (cadr mouse)
473 (push event unread-command-events))) 479 (if (eq which-side 'right) 0 2))
474 (setq done t)) 480 (nth 2 (window-edges window))
475 481 -1))
476 ((not (eq (car mouse) start-event-frame)) 482 (unless (zerop growth)
477 nil) 483 ;; Remember that we dragged.
478 484 (setq dragged t))
479 ((null (car (cdr mouse))) 485 (adjust-window-trailing-edge window growth t))
480 nil) 486 (t
481 487 ;; Drag horizontal divider (the calculations below are those
482 (t 488 ;; from Emacs 23).
483 (setq y (cdr (cdr mouse)) 489 (setq growth
484 edges (window-edges start-event-window) 490 (if (eq line 'mode)
485 top (nth 1 edges) 491 (- (cddr mouse) (nth 3 (window-edges window)) -1)
486 bot (nth 3 edges)) 492 ;; The window's top includes the header line!
487 493 (- (nth 3 (window-edges window)) (cddr mouse))))
488 ;; compute size change needed 494
489 (cond (mode-line-p 495 (unless (zerop growth)
490 (setq growth (- y bot -1))) 496 ;; Remember that we dragged.
491 (t ; header line 497 (setq dragged t))
492 (when (< (- bot y) window-min-height) 498
493 (setq y (- bot window-min-height))) 499 (cond
494 ;; The window's top includes the header line! 500 (enlarge-minibuffer
495 (setq growth (- top y)))) 501 (adjust-window-trailing-edge window growth))
496 (setq wconfig (current-window-configuration)) 502 ((eq line 'mode)
497 503 (adjust-window-trailing-edge window growth))
498 ;; Check for an error case. 504 (t
499 (when (and (/= growth 0) 505 (adjust-window-trailing-edge window (- growth)))))))
500 (not minibuffer) 506
501 (one-window-p t)) 507 ;; Presumably, if this was just a click, the last event should be
502 (error "Attempt to resize sole window")) 508 ;; `mouse-1', whereas if this did move the mouse, it should be a
503 509 ;; `drag-mouse-1'. `dragged' nil tells us that we never dragged
504 ;; If we ever move, make sure we don't mistakenly treat 510 ;; and `on-link' tells us that there is a link to follow.
505 ;; some unexpected `mouse-1' final event as a sign that 511 (when (and on-link (not dragged)
506 ;; this whole drag was nothing more than a click. 512 (eq 'mouse-1 (car-safe (car unread-command-events))))
507 (if (/= growth 0) (setq on-link nil)) 513 ;; If mouse-2 has never been done by the user, it doesn't
508 514 ;; have the necessary property to be interpreted correctly.
509 ;; grow/shrink minibuffer? 515 (put 'mouse-2 'event-kind 'mouse-click)
510 (if should-enlarge-minibuffer 516 (setcar unread-command-events
511 (unless resize-mini-windows 517 (cons 'mouse-2 (cdar unread-command-events)))))))
512 (mouse-drag-move-window-bottom start-event-window growth))
513 ;; no. grow/shrink the selected window
514 ;(message "growth = %d" growth)
515 (if mode-line-p
516 (mouse-drag-move-window-bottom start-event-window growth)
517 (mouse-drag-move-window-top start-event-window growth)))
518
519 ;; if this window's growth caused another
520 ;; window to be deleted because it was too
521 ;; short, rescind the change.
522 ;;
523 ;; if size change caused space to be stolen
524 ;; from a window above this one, rescind the
525 ;; change, but only if we didn't grow/shrink
526 ;; the minibuffer. minibuffer size changes
527 ;; can cause all windows to shrink... no way
528 ;; around it.
529 (when (or (/= start-nwindows (count-windows t))
530 (and (not should-enlarge-minibuffer)
531 (> growth 0)
532 mode-line-p
533 (/= top
534 (nth 1 (window-edges
535 ;; Choose right window.
536 start-event-window)))))
537 (set-window-configuration wconfig)))))
538
539 ;; Presumably if this was just a click, the last event should
540 ;; be `mouse-1', whereas if this did move the mouse, it should be
541 ;; a `drag-mouse-1'. In any case `on-link' would have been nulled
542 ;; above if there had been any significant mouse movement.
543 (when (and on-link
544 (eq 'mouse-1 (car-safe (car unread-command-events))))
545 ;; If mouse-2 has never been done by the user, it doesn't
546 ;; have the necessary property to be interpreted correctly.
547 (put 'mouse-2 'event-kind 'mouse-click)
548 (setcar unread-command-events
549 (cons 'mouse-2 (cdar unread-command-events))))))))
550 518
551(defun mouse-drag-mode-line (start-event) 519(defun mouse-drag-mode-line (start-event)
552 "Change the height of a window by dragging on the mode line." 520 "Change the height of a window by dragging on the mode line."
553 (interactive "e") 521 (interactive "e")
554 (mouse-drag-mode-line-1 start-event t)) 522 (mouse-drag-line start-event 'mode))
555 523
556(defun mouse-drag-header-line (start-event) 524(defun mouse-drag-header-line (start-event)
557 "Change the height of a window by dragging on the header line. 525 "Change the height of a window by dragging on the header line."
558Windows whose header-lines are at the top of the frame cannot be
559resized by dragging their header-line."
560 (interactive "e") 526 (interactive "e")
561 ;; Changing the window's size by dragging its header-line when the 527 (mouse-drag-line start-event 'header))
562 ;; header-line is at the top of the frame is somewhat strange,
563 ;; because the header-line doesn't move, so don't do it.
564 (let* ((start (event-start start-event))
565 (window (posn-window start))
566 (frame (window-frame window))
567 (first-window (frame-first-window frame)))
568 (unless (or (eq window first-window)
569 (= (nth 1 (window-edges window))
570 (nth 1 (window-edges first-window))))
571 (mouse-drag-mode-line-1 start-event nil))))
572
573
574(defun mouse-drag-vertical-line-rightward-window (window)
575 "Return a window that is immediately to the right of WINDOW, or nil."
576 (let ((bottom (nth 3 (window-inside-edges window)))
577 (left (nth 0 (window-inside-edges window)))
578 best best-right
579 (try (previous-window window)))
580 (while (not (eq try window))
581 (let ((try-top (nth 1 (window-inside-edges try)))
582 (try-bottom (nth 3 (window-inside-edges try)))
583 (try-right (nth 2 (window-inside-edges try))))
584 (if (and (< try-top bottom)
585 (>= try-bottom bottom)
586 (< try-right left)
587 (or (null best-right) (> try-right best-right)))
588 (setq best-right try-right best try)))
589 (setq try (previous-window try)))
590 best))
591 528
592(defun mouse-drag-vertical-line (start-event) 529(defun mouse-drag-vertical-line (start-event)
593 "Change the width of a window by dragging on the vertical line." 530 "Change the width of a window by dragging on the vertical line."
594 (interactive "e") 531 (interactive "e")
595 ;; Give temporary modes such as isearch a chance to turn off. 532 (mouse-drag-line start-event 'vertical))
596 (run-hooks 'mouse-leave-buffer-hook)
597 (let* ((done nil)
598 (echo-keystrokes 0)
599 (start-event-frame (window-frame (car (car (cdr start-event)))))
600 (start-event-window (car (car (cdr start-event))))
601 event mouse x left right edges growth
602 (which-side
603 (or (cdr (assq 'vertical-scroll-bars (frame-parameters start-event-frame)))
604 'right)))
605 (cond
606 ((one-window-p t)
607 (error "Attempt to resize sole ordinary window"))
608 ((and (eq which-side 'right)
609 (>= (nth 2 (window-inside-edges start-event-window))
610 (frame-width start-event-frame)))
611 (error "Attempt to drag rightmost scrollbar"))
612 ((and (eq which-side 'left)
613 (= (nth 0 (window-inside-edges start-event-window)) 0))
614 (error "Attempt to drag leftmost scrollbar")))
615 (track-mouse
616 (progn
617 ;; loop reading events and sampling the position of
618 ;; the mouse.
619 (while (not done)
620 (setq event (read-event)
621 mouse (mouse-position))
622 ;; do nothing if
623 ;; - there is a switch-frame event.
624 ;; - the mouse isn't in the frame that we started in
625 ;; - the mouse isn't in any Emacs frame
626 ;; drag if
627 ;; - there is a mouse-movement event
628 ;; - there is a scroll-bar-movement event
629 ;; (same as mouse movement for our purposes)
630 ;; quit if
631 ;; - there is a keyboard event or some other unknown event
632 ;; unknown event.
633 (cond ((integerp event)
634 (setq done t))
635 ((memq (car event) '(switch-frame select-window))
636 nil)
637 ((not (memq (car event)
638 '(mouse-movement scroll-bar-movement)))
639 (if (consp event)
640 (setq unread-command-events
641 (cons event unread-command-events)))
642 (setq done t))
643 ((not (eq (car mouse) start-event-frame))
644 nil)
645 ((null (car (cdr mouse)))
646 nil)
647 (t
648 (let ((window
649 ;; If the scroll bar is on the window's left,
650 ;; adjust the window on the left.
651 (if (eq which-side 'right)
652 start-event-window
653 (mouse-drag-vertical-line-rightward-window
654 start-event-window))))
655 (setq x (- (car (cdr mouse))
656 (if (eq which-side 'right) 0 2))
657 edges (window-edges window)
658 left (nth 0 edges)
659 right (nth 2 edges))
660 ;; scale back a move that would make the
661 ;; window too thin.
662 (if (< (- x left -1) window-min-width)
663 (setq x (+ left window-min-width -1)))
664 ;; compute size change needed
665 (setq growth (- x right -1))
666 (condition-case nil
667 (adjust-window-trailing-edge window growth t)
668 (error nil))))))))))
669 533
670(defun mouse-set-point (event) 534(defun mouse-set-point (event)
671 "Move point to the position clicked on with the mouse. 535 "Move point to the position clicked on with the mouse.
diff --git a/lisp/window.el b/lisp/window.el
index 4d8b3c92b95..968f47f4f31 100644
--- a/lisp/window.el
+++ b/lisp/window.el
@@ -1084,6 +1084,35 @@ regardless of whether that buffer is current or not."
1084 (goto-char pos)) 1084 (goto-char pos))
1085 (set-window-point window pos))) 1085 (set-window-point window pos)))
1086 1086
1087(defun window-at-side-p (&optional window side)
1088 "Return t if WINDOW is at SIDE of its containing frame.
1089WINDOW can be any window and defaults to the selected one. SIDE
1090can be any of the symbols `left', `top', `right' or `bottom'.
1091The default value nil is handled like `bottom'."
1092 (setq window (window-normalize-any-window window))
1093 (let ((edge
1094 (cond
1095 ((eq side 'left) 0)
1096 ((eq side 'top) 1)
1097 ((eq side 'right) 2)
1098 ((memq side '(bottom nil)) 3))))
1099 (= (nth edge (window-edges window))
1100 (nth edge (window-edges (frame-root-window window))))))
1101
1102(defun windows-at-side (&optional frame side)
1103 "Return list of all windows on SIDE of FRAME.
1104FRAME must be a live frame and defaults to the selected frame.
1105SIDE can be any of the symbols `left', `top', `right' or
1106`bottom'. The default value nil is handled like `bottom'."
1107 (setq frame (window-normalize-frame frame))
1108 (let (windows)
1109 (walk-window-tree
1110 (lambda (window)
1111 (when (window-at-side-p window side)
1112 (setq windows (cons window windows))))
1113 frame)
1114 (nreverse windows)))
1115
1087(defun window-in-direction-2 (window posn &optional horizontal) 1116(defun window-in-direction-2 (window posn &optional horizontal)
1088 "Support function for `window-in-direction'." 1117 "Support function for `window-in-direction'."
1089 (if horizontal 1118 (if horizontal