swisspig.net - To hell with the pig... I'm going to Switzerland.

Mozilla Bug on Linux (Tuesday, August 23, 2005)

I discovered a bug in Firefox on Linux today. For a while, there had been complaints that Firefox would randomly steal focus, which was really annoying. For example, you open a link in a new window, then you go back to reading the old window while the new page loads in the background. Then, when the new page was done loading, suddenly, it would pop up to the front. Clearly that's annoying. Similarly, if a notification dialog (like your page timed out) was generated, it would focus Firefox.

So the "solution", was to make new Firefox windows focus only when Firefox itself was in focus. The problem with this, is that if you have a toolbar shortcut or keyboard shortcut to Firefox, and you use it when Firefox is running, but not the current focus (i.e. Thunderbird is in focus, or an xterm), the new browser window comes up behind the active window.

The excuse is that it's the window manager's responsibility to make sure this new window is active. And it would, if the new window were a new application. But it isn't — when you execute that shortcut, it actually sends a signal to the existing Firefox process, which then spawns a new window. The window manager (metacity, for example) sees the existing process spawning a new window, and does not bring it to the front — it doesn't know the difference between a new browser window and a dialog box, and it should not.

Firefox should be smart enough to know that when it receives the signal to open a new browser window, that it should also raise that window, so that the requester can actually use it.

In any event, since it is unlikely that this will ever be fixed, I have found a work-around. Ideally, you could use devilspie, however it has an action for bringing the window to the front, but not making it active. Duh. And I don't feel like hacking the code to make it work. Besides, why run yet another daemon?

Well, the most obvious reason to run another daemon, is because you want to be able to capture window creation events, rather than having to deduce which window needs to be raised. But since devilspie can't quite do it (and by the way, no hard feelings to devilspie — it's pretty cool for a 0.10 release), I had to find another way.

Enter wmctrl. It uses the EWMH specification (whatever that is) to communicate with various window managers, including metacity. You can use it to send instructions to windows, such as resizing them, moving them around, and of course raising them.

So now the trick is to write a script that will open a new Firefox window, then use wmctrl to raise and activate that new window. This is easy for a new empty window, but can be more tricky if you have a new window with a URL (i.e. from clicking on a link in gaim or Thunderbird). In that case, you have to guess which browser is most recent. Turns out, it's usually the last one on the list of open windows. So, after all is said and done, here's the script that seems to work:

#!/bin/bash

# how many windows are open?
WINCOUNT=`wmctrl -l | wc -l`

# launch firefox
firefox $@

# don't try to raise the window until we know it's open
while [ "`wmctrl -l | wc -l`" = "$WINCOUNT" ]; do
   sleep 0.1
done

# raise the new empty window...  or raise the most 
# recently opened window (the extra complexity makes
# it marginally faster for empty windows)
wmctrl -F -a "^Mozilla Firefox$" || \
   wmctrl -i -a `wmctrl -l | grep "Mozilla Firefox" | \
   tail -1 | sed -e "s/ .*//"`

Exciting stuff, huh? Also useful in my current efforts has been Thunderbird: Guide for the Perplexed, which outlines some interesting customizations for the bird.

—Brian (8/23/2005 1:35 PM)
(1 comments)

Comments

I have since updated the code:

#!/bin/bash

# how many windows are open?
WINCOUNT=`wmctrl -l | wc -l`

ARGS="$@"

if [ "$ARGS" == "" ]; then
    echo foo
    ARGS=about:blank
fi

# launch firefox
firefox -new-tab $ARGS

# don't try to raise the window until we know it's open
#while [ "`wmctrl -l | wc -l`" = "$WINCOUNT" ]; do
#   sleep 0.1
#done

# raise the new empty window...  or raise the most 
# recently opened window (the extra complexity makes
# it marginally faster for empty windows)
wmctrl -F -a "^Firefox$" || \
    wmctrl -i -a `wmctrl -l | grep "Firefox" | \
    tail -1 | sed -e "s/ .*//"`

-- Brian (5/28/2008 8:24 AM)

Name
URL
Comment
(no html)
 

Disclaimer: Opinions on this site are those of Brian Ziman and do not necessarily
reflect the views of any other organizations or businesses mentioned.