Subject: bug#745: pop-to-buffer, frames, and input focus

From: Helmut Eller <[email-masked]>
Date: Sat, 23 Aug 2008 10:55:04 +0200

* martin rudalics [2008-08-22 18:39+0200] writes:

>>>> pop-to-buffer doesn't switch input focus with: Sawfish, kwin,
>>>> metacity, fluxbox, twm.
>>>> It does with icewm.
>>>>
>>>> display-buffer seems to switch focus with: Sawfish, kwin, fluxbox,
>>>> icewm, twm.
>>> You probably mean display-buffer does _not_ switch focus with these.
>>
>> I meant to say: display-buffer _does_ switch focus when creating a new
>> frame with those window managers: Sawfish, kwin, fluxbox, icewm, twm.
>
> I still don't understand.  Simplistically spoken, `pop-to-buffer' is
> `display-buffer' + `select-window'.  How can, using Sawfish say,
> `display-buffer' switch focus and `pop-to-buffer' not switch focus?

Sorry, that was indeed confusing.
The problematic cases are

  (let ((pop-up-frames t)) (display-buffer ...)) 

for display-buffer, if the buffer was not visible before.  In this case
a new frame appears, which (wrongly) has the input focus.  (If the
buffer is already visible in some frame, that frame is raised but the
focus is not moved to that frame.  This is IMO correct.)

For pop-to-buffer:

  (let ((display-buffer-reuse-frames t)) (pop-to-buffer ...))

if the buffer is already visible in a frame which has not the input
focus.  This should move input focus to that frame, but it currently
doesn't.  (If the frame has already the focus, pop-to-buffer works as it
should.)

Let's call the display-buffer case, situation A and the pop-to-buffer
case, situation B.

>
> We should fix it this time.  Please try again two things with the
> window-managers you listed above and `pop-up-frames' non-nil:
>
> - tell whether `display-buffer' does switch focus.
>
> - tell whether `pop-to-buffer' does switch focus.
>
> - try both, if possible, with click-to-focus and a focus-follows-mouse
>   settings (maybe you have to set the value of the Emacs variable
>   `focus-follows-mouse' appropriately).

OK, here is what I see:

A  B  WM         WM focus mode
--------------------------------------- 
Y  N  Sawfish    follow-mouse (enter-only + focus-window-when-mapped)
N  N  Sawfish    follow-mouse (enter-only + !focus-window-when-mapped)
Y  N  Sawfish    follow-mouse (enter-exit + focus-window-when-mapped)
N  N  Sawfish    follow-mouse (enter-exit + !focus-window-when-mapped)
Y  N  Sawfish    click-to-focus (click + focus-window-when-mapped)
N  N  Sawfish    click-to-focus (click + !focus-window-when-mapped)
Y  N  Sawfish    click-to-focus (click + focus-window-when-mapped + focus-click-through)
N  N  Sawfish    click-to-focus (click + !focus-window-when-mapped + focus-click-through)
?  N  Metacity   follow-mouse (mouse)
?  N  Metacity   follow-mouse (sloppy)
?  N  Metacity   click-to-focus (click)
Y  N  KWin       follow-mouse
Y  N  KWin       click-to-focus
Y  M  FluxBox    follow-mouse (Sloppy Focus)
Y  M  FluxBox    follow-mouse (Auto Raise)
Y  N  FluxBox    click-to-focus
Y  Y  IceWM      click-to-focus
Y  N  Twm        follow-mouse (new frames need mouse click for placement)

A and B are the scenarios described above.
Y means: Yes, does switch focus.
N means: No, doesn't switch focus.
? means: sometimes (probably depending on mouse and window positions)
M means: No, doesn't switch focus, except when raising the frame 
         also moves the mouse pointer into the frame.

I set Emacs' focus-follows-mouse according to the WM focus mode (except 
when I forgot it :-)

The Ys for Sawfish are apparently directly related to the
focus-window-when-mapped option.  So, it's probably not Emacs that
switches the focus in the A scenario, but the window managers.

>
> Here on Windos XP with a focus-follows-mouse policy, `display-buffer'
> and `pop-to-buffer' both switch focus.  IIRC, people reported troubles
> with the standard click-to-focus policy.  Honestly, I'm a bit reluctant
> to try out click-to-focus here, maybe someone else can try?
>
>> Maybe we could move the input focus to the selected frame in a lazy
>> fashion.  E.g. when Emacs waits for new events, we could compare the
>> currently focused frame with the selected frame, and if they differ we
>> could switch the focus to the selected frame.  This would make
>> select-frame more useful.
>
> I suppose we should introduce a customizable variable which allows to
> call `select-frame-set-input-focus' (or something similar) at least in
> `pop-to-buffer' but maybe also in `display-buffer'.  But we should also
> provide a doc-string recommending what setting this variable should have
> on which platform.

Yes, that would be good.  The docstring for select-window could perhaps
also state a bit more prominently that the "selected window" and the
"input focus" are different things or at least refer to
select-frame-set-input-focus.

BTW, below is a proof of concept implementation for the
update-focus-lazily idea.

Helmut.

--- keyboard.c.~1.969.~	2008-08-15 14:47:16.000000000 +0200
+++ keyboard.c	2008-08-23 10:23:12.000000000 +0200
@@ -1602,6 +1602,21 @@ (at your option) any later version.
 	  && !EQ (internal_last_event_frame, selected_frame))
 	Fselect_frame (internal_last_event_frame);
 #endif
+#if 1
+      {
+	if (!detect_input_pending()
+	    && NILP(internal_last_event_frame)) {
+	  Display *dpy = FRAME_X_DISPLAY (check_x_frame(selected_frame));
+	  Window focus;
+	  int revert_to;
+	  XGetInputFocus (dpy, &focus, &revert_to);
+	  if (focus != None
+	      && focus != FRAME_X_WINDOW (check_x_frame(selected_frame)))
+	    Fx_focus_frame (selected_frame);
+	}
+      }
+#endif
+
       /* If it has changed current-menubar from previous value,
 	 really recompute the menubar from the value.  */
       if (! NILP (Vlucid_menu_bar_dirty_flag)