Fix "focus follows mouse" matlab focus bug

From Applied Optics Wiki
Revision as of 20:55, 25 July 2013 by Matt (talk | contribs)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

If you use a focus policy such as focus follows mouse or focus under mouse and use matlab you will quickly find matlab becomes unusable.

In the olden days the destination for any graphics operation (eg plot()) was determined by the figure(); command. A few years ago matlab decided this confused windows users and decided as a matter of policy that the focus selected by figure() would be overridden by whatever figure window had been last focussed by the user (normally clicking in the window).

This was a daft idea - it may have saved a few newbies from being confused but the great power of matlab is that it is script driven and following the user focus takes control away from the script.

As a side effect, it made matlab very hard to use if you use a window manager focus policy that does not follow windows conventions, in particular "focus follows mouse", "focus under mouse" or variations on these schemes. These are very common outside of windows and mac environments and extremely useful. Once you have gotten used to them you'll never go back. The problem is that when you use these schemes you cannot help but focus the figure windows as you move the mouse around. This results in your matlab scripts plotting in random figure windows which completely screws up your scripts and figures.

Anyway help is at hand -- here are a few lines of code that will undo this daft design decision and return matlab to a state where figure() determines which window is plotted to - not that last figure the mouse happened to brush over:


Put these functions in your matlab path:

(1) figure.m:

 %% fix the annoying focus follows mouse bug 
 %% (c) GPL Matt Clark 2013 
 function h=figure(varargin);
 global hasfocus;
       if(nargin<2)
               if(nargin<1)
                       n=1;
               else
                       n=varargin{:};
                       end
               h=builtin('figure',n);
               jFig = get(h,'JavaFrame');
               jAxis = jFig.getAxisComponent;
               set(jAxis,'FocusGainedCallback',{@setfocus,h});
               hasfocus=h;
       else
               h=builtin('figure',varargin{:});
       end;

(2) axes.m

 %% fix the annoying focus follows mouse bug
 %% (c) GPL Mtt Clark 2013 v1.0
 function h=axes(varargin);
 global hasfocus;
       if(nargin~=1)
               %% in this circumstance we'll either create an axes in the current figure
               %% or create a new axes both of which are handled here and we return the axes
               %% handle
               h=builtin('axes',varargin{:});
               hasfocus=get(h,'Parent');
               return;
               end
       if(nargin==1)
               %% under this circumstance axes does not return a handle
               %% if it is successful we should make this figure current
               %% since this axes will be current, but if not we'll throw
               %% an error and keep the same focus
               if(nargout>0)
                       %% try to maintain compatibility with builtin('axes')
                       %% by throwing this error if a return is asked for here
                       error('MATLAB:maxlhs','Too many output arguments.')
                       end;
               try
                       builtin('axes',varargin{1});
                       %% since there was no error we set the focus appropriately
                       hasfocus=get(varargin{1},'Parent');
               catch
                       %% we caught the error
                       rethrow(lasterror)
                       disp('some error in case it wasnt printed');
                       end
               return;
               end;


(3) setfocus.m

 %% fix the annoying focus follows mouse bug 
 %% (c) GPL Matt Clark 2013 
 function setfocus(jAxis, jEventData, hFig)
 global hasfocus;
       %% deal with the case when the focussed window has been lost
       %% I can't remember what the correct behaviour should be so
       %% I'll resort to doing nothing / focusing the current window
       %% and setting the focus to the current window - nasty
       t=get(0,'Children');
       t=find(t==hasfocus);
       if(isempty(t))
               %printf('Trying to focus a dead window doing nothing',hFig);
               hasfocus=hFig;
               return
               end;
       set(0,'currentfigure',hasfocus)
       end

(4) If you are bothered by warning messages spamming up your console put this line in your matlab start up files:

 warning off MATLAB:dispatcher:nameConflict

Works for me on matlab 2007something

It works by storing the last figure set by figure(); and then every time a figure is focussed it resets the 'currentfigure' to the stored value;