Saturday, February 20, 2010

Emacs Tip #35: framemove

Ever wanted to easily navigate between frames? Perhaps using arrow keys? Surprisingly, this didn't exist before (AFAIK).

I wrote the package framemove to have the same usage as Emacs' built in windmove package. And, even better, it can integrate with windmove so that when you run out of windows to move between, you'll jump to the next frame in that direction.

To install framemove on its own:

(require 'framemove)
(framemove-default-keybindings) ;; default prefix is Meta

But you might want to use this in conjunction with windmove, in which case this is the integration code to add to your .emacs:

(require 'framemove)
(setq framemove-hook-into-windmove t)

With the integration with windmove, you just do SHIFT-right to move focus to the window to the right of the current, and when there are no more, focus will shift to the frame to the right.

Switching frames is a little more challenging than switching windows - mostly because windows are simply rectangular divisions of a window - it is easy to tell what window (if any) is to the right of the point. For frames, the answer is ambiguous because the placements of frames is free-form, and frames can overlap. I think this initial implementation does a reasonable job of choosing which frame to select. It first tries the frame directly in line with the point, and if one doesn't exist, it then uses the distance between the point (projected onto the edge of the current frame) and the frames in the given direction, and after that it just tries any frame that extends beyond the current frame in that direction.

Check it out.

Currently, when focus shifts to a new frame - the point does not change inside the frame.


DiG said...

I've been dreaming about this for sometime. I had to use s-` to switch frames on Mac OS X and s-left, s-right, etc. to move to the window. My fingers never got used to it. Now with framemove emacs frame/window switching on two monitors is awesome.

(when (require 'framemove nil :noerror)
(setq framemove-hook-into-windmove t))
(windmove-default-keybindings 'super)

Thank you!

redshodan said...

This is very very cool. I use a dual monitor setup 90% of the time and Switching frames has been annoying since the order of windows is dependent on the X window manager. Sometimes (but only sometimes) I wish for full app switching like OS/X where super/alt-tab switches between entire apps and not just windows. Really I just want to switch to a particular window with a well known key sequence. This does that very well.

I've used windmove for a good while and its just natural to extend windmove like this. Thank you!

Unknown said...

(require cl) is missing

ustunozgur said...
This comment has been removed by the author.
ustunozgur said...
This comment has been removed by the author.
ustunozgur said...
This comment has been removed by the author.
ustunozgur said...

I usually have two frames, left and right so I use this:

Duncan MacGregor said...

You aren't the first to do this, but you are the first to distribute it. The problem I hit, and your code has as well), is that when 2 frames (A and B) have the same geometry and another (C) is to one side then I may be able to navigate from A to C, but then end up navigating back to B and have no way to get back to A again. Since my normal setup is two monitors, each with a couple of maximized frames, this issues rears its head rather quickly.

I don't know of a way to query the z-order of frames from elisp, so it's hard to make sensible navigation decisions based on what the user sees.

Maybe it's time to ditch mulitple frames and have another crack at writing something like elscreen that can display a single tab bar across the top of the frame, and not start going wrong after a split-window-horizontally. Problem with that is the only way I can see to do a tab bar like that is as a separate window, and half the window functions are down in the C so I can't wrap advice round them.

Anonymous said...
This comment has been removed by a blog administrator.
Geek said...

Nice. I'd like to mention that I initially had (setq windmove-wrap-around t) for wind move, which just wrapped around. I couldn't see how to jump to another frame then (does not work). So you might add a comment in frame move that this wind move setting should not be used.