Please check Open File Explorer on a File that is open by another Application. I am the OP of that question. menu's answer is the accepted one. Here is the complete solution. However, to understand how it works, you have go through the referred post thoroughly.
Create the following script (give it proper permissions) and bind it to a keyboard shortcut (I have bound it to Super key + O), let's say the script name is open-file-path.sh
. Now when you use the keyboard shortcut on gui applications like evince (which has single process for single window and the path of the file can be found via ps
command) that has some file open, the file will most probably open in File Explorer.
#!/bin/bash
WINDOW_ID=$(xdotool getactivewindow)
PID_OF_ACTIVE_WINDOW=$(xdotool getwindowpid $WINDOW_ID)
CLASS_NAME=$(xprop -id $WINDOW_ID | rg WM_CLASS | cut -d '"' -f2)
if [ "$CLASS_NAME" = "com.github.johnfactotum.Foliate" ]; then
log=$HOME/.myfoliate.log
# nemo "$(awk -v var="$WINDOW_ID" '$1 == var {print}' $log | cut -d" " -f3-)"
nemo "$(grep -oP "$WINDOW_ID $PID_OF_ACTIVE_WINDOW \K.*" $log)"
exit 1
fi
if [ "$CLASS_NAME" = "libreoffice" ]; then
log=$HOME/.mylibreoffice.log
# nemo "$(awk -v var="$WINDOW_ID" '$1 == var {print}' $log | cut -d" " -f3-)"
nemo "$(grep -oP "$WINDOW_ID $PID_OF_ACTIVE_WINDOW \K.*" $log)"
exit 1
fi
if [[ "$CLASS_NAME" == @(gl) ]] ; then
nemo "$(echo '{ "command": ["get_property", "path"] }' | socat - /tmp/mpv-socket | jq -r ".data")"
exit 1
fi
MY_COMMAND_PATH=$(ps -p $PID_OF_ACTIVE_WINDOW -o command)
# https://stackoverflow.com/q/76028252/1772898
if printf -- '%s\n' "$MY_COMMAND_PATH" | grep -qoP '(file://)?(?<!\w)/(?!usr/).*?\.\w{3,4}+'; then
nemo "$(printf -- '%s\n' "$MY_COMMAND_PATH" | grep -oP '(file://)?(?<!\w)/(?!usr/).*?\.\w{3,4}+')"
fi
Just to be clear the criteria are:
- a single process correspondents to a single window
- the path of the file can be found via
ps
command
For other applications which do not meet the criteria (like libreoffice, foliate etc), there are some extra steps. Even after following the extra steps they will have some issues. It will not work if you use the File > Open option withing the application. You will have to use double click to open the file. This issue can be solved if these applications expose some internal api to give the file path (for example, in case of mpv, we are using internal api).
Let us discuss mpv first. By default it will just work. It meets the criteria.
- a single process correspondents to a single window
- the path of the file can be found via
ps
command
you just have to remove
if [[ "$CLASS_NAME" == @(gl) ]] ; then
nemo "$(echo '{ "command": ["get_property", "path"] }' | socat - /tmp/mpv-socket | jq -r ".data")"
exit 1
fi
from open-file-path.sh
.
But in my case I have made some changes so that there is always a single window that is why I needed this workaround.
in my situation regarding mpv you have to create a socket. Add input-ipc-server=/tmp/mpv-socket
in $HOME/.config/mpv/mpv.conf
. Then we have to create a wrapper for the mpv executable. In case of desktop applications we use the .desktop
file. For mpv, it is /usr/share/applications/mpv.desktop
. As we have to edit it, i like to place a copy of it in $HOME/.local/share/applications/mpv.desktop
and then edit the copy. $HOME/.local/share/applications
has precedence over /usr/share/applications
.
cp /usr/share/applications/mpv.desktop $HOME/.local/share/applications/mpv.desktop
Then change the following lines in $HOME/.local/share/applications/mpv.desktop
TryExec=mpv
Exec=mpv --player-operation-mode=pseudo-gui -- %U
with
TryExec=/home/ismail/.dotfiles/.resources/bash-scripts/mpv.sh
Exec=/home/ismail/.dotfiles/.resources/bash-scripts/mpv.sh %U
The /home/ismail/.dotfiles/.resources/bash-scripts/mpv.sh
file looks like:
#!/bin/bash
socat_to_mpv() {
socat - "/tmp/mpv-socket"
}
if pgrep -x mpv >/dev/null ; then
wmctrl -x -R gl.mpv
echo "{ \"command\": [\"loadfile\", \"$1\", \"replace\"] }" | socat_to_mpv
else
mpv "$1"
fi
It is wrapper code. We are running some code before and/or after starting mpv.
In case of Foliate, in the file $HOME/.local/share/applications/com.github.johnfactotum.Foliate.desktop
(which I have copied from /usr/share/applications/
, like mpv) Replace Exec
with:
Exec=/home/ismail/.dotfiles/.resources/bash-scripts/foliate.sh %U
The foliate.sh
file looks like:
#!/bin/bash
log=$HOME/.myfoliate.log
file=$1
com.github.johnfactotum.Foliate "$1" &
sleep 2
for id in $(xdotool search --onlyvisible --class 'com.github.johnfactotum.Foliate')
do
winpid=$(xdotool getwindowpid $id)
winname=$(xdotool getwindowname $id)
grep -q "^$id $winpid .*" $log || echo "$id $winpid $file" >> $log
done
pid_of_foliate=$(xdotool search --name 'com.github.johnfactotum.Foliate' getwindowpid)
if [ -n "$pid_of_foliate" ]
then
awk -i inplace -v var="$pid_of_foliate" '$2 == var {print}' $log
fi
In case of libreoffice, in the following files (which I have copied from /usr/share/applications/
, like mpv):
$HOME/.local/share/applications/libreoffice-calc.desktop
$HOME/.local/share/applications/libreoffice-draw.desktop
$HOME/.local/share/applications/libreoffice-impress.desktop
$HOME/.local/share/applications/libreoffice-writer.desktop
Replace Exec
with:
Exec=/home/ismail/.dotfiles/.resources/bash-scripts/libreoffice.sh --calc %U
Exec=/home/ismail/.dotfiles/.resources/bash-scripts/libreoffice.sh --draw %U
Exec=/home/ismail/.dotfiles/.resources/bash-scripts/libreoffice.sh --impress %U
Exec=/home/ismail/.dotfiles/.resources/bash-scripts/libreoffice.sh --writer %U
respectively.
The libreoffice.sh
file will look like:
#!/bin/bash
log=$HOME/.mylibreoffice.log
file=$2
libreoffice "$1" "$2" &
sleep 2
for id in $(xdotool search --onlyvisible --class 'libreoffice')
do
winpid=$(xdotool getwindowpid $id)
winname=$(xdotool getwindowname $id)
grep -q "^$id $winpid .*" $log || echo "$id $winpid $file" >> $log
done
pid_of_libreoffice=$(xdotool search --class 'libreoffice' getwindowpid)
if [ -n "$pid_of_libreoffice" ]
then
awk -i inplace -v var="$pid_of_libreoffice" '$2 == var {print}' $log
fi
The idea is we do not use many applications. For the applications we use, there are ways we can get at least close to our expected behavior.
NOTE: Install the dependencies of the scripts if they are not there. Specially you might have to install xdotool
.
NOTE: I use nemo
to open files but if you use other file explorer then you might have to change the script accordingly. Just replacing nemo
with nautilus
or something like that will most probably work.
Area of Improvement:
This solution does not work on some apps like vscode. However, they have their Right Click > Open Containing Folder options.
Update 1:
I have been working on a gnome extension to make the experience much better. I faced few issues while working on the problem. If gnome kindly exposed one data (the windowID), and corrected one data (the PID) then it would have been a much better solution. At this moment, it would be a hack.
The issues I faced in linked bellow.
https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/6705
https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/6708
https://gitlab.gnome.org/GNOME/glib/-/issues/3016
If these two issues are resolved then hopefully we can get an gnome extension which we can use to "while working with (almost) any file, in (almost) any application, use a keyboard shortcut, and open the parent folder of that file (while the file is selected) in the filesystem."
Currently I am not feeling like to work on a hacky solution, and most of my problem is addressed with the current solution I have mentioned above.
So, if those problems are addressed then please let me know and hopefully I will finish the job.