The problem#
Previously, I wrote a script for opening and
immediately focusing xfce4-appfinder
. But
xfce4-appfinder
will notice if it's already open and just assume
you want to use the existing window. Even if it's on a different
desktop. And therefore attempting to focus it will either do nothing or
switch to that desktop, neither of which is desirable.
The solution#
The actual solution I settled on is more of a workaround than a
solution: having xfce4-appfinder
on a different desktop doesn't
really make sense, so I just set it to be on all desktops (specified
as the non-existent desktop -1
), so it would never be on the wrong
desktop:
xdotool set_desktop_for_window "$winid" -1
To actually move the window to the current desktop, replace
xdotool windowactivate "$winid"
with
desktop="$(xdotool get_desktop)"
win_desktop="$(xdotool get_desktop_for_window "$winid")"
if [[ "$desktop" == "$win_desktop" ]]
then
xdotool windowactivate "$winid"
else
xdotool set_desktop_for_window "$winid" -1
xdotool set_desktop_for_window "$winid" "$desktop" \
windowactivate "$winid"
fi
Although this assumes that you know the $winid
of the window you want
to move. If you have just the title it works just as well to use
wmctrl -R "Application Finder"
The details#
Doing the right thing slowly#
This StackOverflow answer suggests using
wmctrl
, specifically, the -R
option which the man
page documents as
Move the window
to the current desktop, raise the window, and give it focus.
Sounds like exactly what we want. Unfortunately, it's slow1:
$ time wmctrl -R "Application Finder"
real 0m0.115s
user 0m0.009s
sys 0m0.004s
It does support an option -i
to take the window ID instead of the
title, but that doesn't make a significant speed difference:
time wmctrl -iR "$winid"
real 0m0.106s
user 0m0.004s
sys 0m0.000s
Note that it's only slow relative to operations on window IDs. Getting
the window ID from the window title takes about a tenth of second, so
if all you have is the window title, then wmctrl
is as fast as we
could hope for.
Doing the wrong thing quickly#
xdotool
has a set_desktop_for_window
subcommand that
almost does what we want and quickly:
$ desktop="$(time xdotool get_desktop)"
real 0m0.003s
user 0m0.002s
sys 0m0.000s
$ time xdotool set_desktop_for_window "$winid" "$desktop"\
windowactivate "$winid"
real 0m0.003s
user 0m0.003s
sys 0m0.000s
The window does indeed get moved to the current desktop. The catch is that it often, although not always, then changes the current desktop to the desktop the window was on. This still happens if the commands are separated:
$ xdotool set_desktop_for_window "$winid" "$desktop"
$ xdotool windowactivate "$winid"
Needless to say, this behavior is surprising and undesirable.
Note that just
$ xdotool windowactivate "$winid"
will switch desktops to whatever desktop the window is on, so what must be happening is that the commands get executed in the wrong order somehow.
Placing window on all desktops#
Experimenting, I noticed there was an exception to that rule: if
$desktop
is -1
, which is used to put a window on all desktops,
then the desktop change never happens. One thing we can do with this
information is what I suggested above of just leaving the window on all
desktops. But the other option is to place it on all desktops for a
split second while moving it to a different desktop:
xdotool set_desktop_for_window "$winid" -1
xdotool set_desktop_for_window "$winid" "$desktop" \
windowactivate "$winid"
Since it is on all desktops when the second command executes, focusing the window never involves changing desktops. But it still ends up on the desired (current) desktop after it finishes.
Putting it all together#
As alluded to above, this is only useful if we know the window ID. The
script in my previous post assumed the window of interest
was the most recently opened window. That makes sense if it really was
just opened by the script, but if it's an existing window on another
desktop, that may not be the case. So this version of the script has
a fallback on the final line of using wmctrl
and killing the
xprop
job if finds an existing window. Since wmctrl
is
called immediately after xfce4-appfinder
, it will almost always
execute before xfce4-appfinder
has a chance to create a window, so
it will only run in the case that the window was already open.
#!/usr/bin/bash
(xprop -spy -root _NET_CLIENT_LIST | stdbuf -oL head -2 |
while read -r l
do
winid="${l/#*, /}"
if [[ $(xdotool getwindowname "$winid") == \
"Application Finder" ]]
then
desktop="$(xdotool get_desktop)"
w_desktop="$(xdotool get_desktop_for_window "$winid")"
if [[ "$desktop" == "$w_desktop" ]]
then
xdotool windowactivate "$winid"
else
xdotool set_desktop_for_window "$winid" -1
xdotool set_desktop_for_window "$winid" "$desktop" \
windowactivate "$winid"
fi
ppid=$BASHPID
ppid=$(ps -o ppid:1= "$ppid")
pkill -9 -P "$ppid"
fi
done
) &
xfce4-appfinder &
wmctrl -R "Application Finder" && pkill -P "$(jobs -p %1)"
Comments
Have something to add? Post a comment by sending an email to comments@aweirdimagination.net. You may use Markdown for formatting.
There are no comments yet.