6

When I have Emacs (24.4, Mac OS, NS build) in the foreground, I often have many windows open in one frame. I sometimes want to switch windows by clicking in an inactive window. By default, this calls mouse-set-point which (1) activates the window I clicked in, and (2) repositions the point to wherever I clicked. I want to change this behavior so clicking in an inactive window would only activate it, but not move the cursor. If I'm in an active window, I want it to reposition the cursor to wherever I clicked.

Is there any reasonable way built into Emacs to do this?

Edit 1: I just tried this:

(defadvice mouse-set-point (around cv/mouse-set-point (event) activate)
  (let ((event-target-window (caadr event)))
    (if (eql event-target-window (frame-selected-window))
        ad-do-it
      (set-frame-selected-window nil event-target-window))))

That doesn't work because mouse-set-point seems to fire in the new window to position itself.

Edit 2: Updated attempt:

(defadvice mouse-set-point (around cv/mouse-set-point (event) activate)
  (let ((event-name (car event))
        (event-target-window (caadr event)))
    (if (and (eql 'down-mouse-1 event-name)
             (eql event-target-window (frame-selected-window)))
        ad-do-it
      (set-frame-selected-window nil event-target-window))))

This does not work in a weird way. When I click above the cursor position in the inactive window, it does what I want. When I click below the cursor position the inactive window, it moves the cursor. Two events fire consistently: down-mouse-1 and then mouse-1. Both call mouse-set-point.

Edit 3: Replacing mouse-set-point does work, provided I also unset [down-mouse-1] (normally bound to mouse-drag-region):

(defun mouse-set-point-2 (event)
  (interactive "e")
  (mouse-minibuffer-check event)
  (let ((event-target-window (caadr event)))
    (if (eql event-target-window (frame-selected-window))
        (posn-set-point (event-end event))
      (set-frame-selected-window nil event-target-window))))

(global-set-key [mouse-1] 'mouse-set-point-2)

(global-unset-key [down-mouse-1])

Not good enough, I don't want to lose drag-selection with the mouse.

Edit 4: Adding advice to both mouse-set-point and mouse-drag-region seems to work.

7
  • 1
    I would suggest something that does both -- if current window, then set point -- if not current window, then select window only.
    – lawlist
    Jan 13, 2015 at 20:32
  • I posted an answer saying that binding [mouse-1] to mouse-select-window ought to do the trick, but when I try it, that doesn't work. Perhaps because event <down-mouse-1> invokes mouse-drag-region first? Besides @lawlist makes a good point. Jan 13, 2015 at 20:33
  • @Harald Hanche-Olsen -- the variable flyspell-mouse-map in flyspell has an example where mouse-2 is nil and down-mouse-2 is flyspell-correct-word -- perhaps a similar setup could be used. However, I imagine the final solution will be an advice before mouse-set-point that checks the current window and uses the function you suggested if its not the current window -- else, the default setting.
    – lawlist
    Jan 13, 2015 at 20:40
  • The underlying function is only about 4 lines of code -- why not just make a new function that tests for whether the current window is the proposed selected window and then either select window (if not current window) or set point (if current window)?
    – lawlist
    Jan 13, 2015 at 21:08
  • That works, as long as I unbind mouse-drag-region from [down-mouse-1], since that seems to do its own window switching. Unfortunately, that kills mouse drag-selection.
    – gcv
    Jan 13, 2015 at 21:45

2 Answers 2

5

The following advice achieves the behavior I want:

(defadvice mouse-set-point (around cv/mouse-set-point (event) activate)
  (let ((event-name (car event))
        (event-target-window (posn-window (event-start event))))
    (if (and (eql 'down-mouse-1 event-name)
             (eql event-target-window (selected-window)))
        ad-do-it
      (select-window event-target-window))))

(defadvice mouse-drag-region (around cv/mouse-drag-region (event) activate)
  (let ((event-target-window (posn-window (event-start event))))
    (if (eql event-target-window (selected-window))
        ad-do-it
      (select-window event-target-window))))
3
  • 1
    Why use advice (dangerous) when you can define your own command and bind it?
    – PythonNut
    Jan 14, 2015 at 17:53
  • Faaaaantastic! :D
    – Ole
    Jan 6, 2016 at 20:25
  • 1
    Thanks very much for the solution, but was getting "Symbol's function is void" from the caadr on Emacs 24.5. Fixed by adding (require 'cl) just before the defadvice stuff.
    – cel
    Dec 7, 2016 at 14:04
0

Here is another solution that works well for me:

(defadvice mouse-set-point (after wlh/mouse-set-point-advice (event &optional promote-to-region) activate)
  "Advice mouse click to remove multi cursors when present."
  (when (> (mc/num-cursors) 1)
    (mc/remove-fake-cursors)))

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.