4

I am coming fro MacOS system, and in that system I am addicted to one specific function: while working with (almost) any file, in (almost) any application, I can click in the title bar of the window showing the file, and open the parent folder of that file in the filesystem.

In the MacOS this is a functionality that works for almost any application, and it is based on an interplay between the Operating System and (most of) the applications written for that OS.

right-clicking the title I can access the parent folder of the document

wit a second click I am presented with the window of the folder containing the file, with the file itself highlighted

I would like to have something similar on a Linux system (I am using Mint, with Cinnamon Desktop Environment).

I am aware that maybe I need to write some script, and maybe part of the solution is described here in this U&L question/answer. What is still missing is a way to get the path to the file.

So, the minimal functionality I need is to (quickly) get the filepath to the document I am visualizing, while I am in a GUI application with a document window open.

Thanks for any insight.

1
  • 1
    I don't think this is possible in a general way, but I would like to know if there is a solution.
    – Bodo
    Sep 24, 2021 at 11:40

2 Answers 2

3

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.

1
  • 1
    Thanks a lot @ahmad-ismail ! this seems a really big progress! Please give me some time to digest and test your code, I think I will accept this answer! :)
    – Fabio
    May 11 at 13:55
2

This would be functionality of the application, possibly provided via the GUI toolkit that the application uses, and not functionality of the operating system or the desktop environment. Since you're using Mint with Cinnamon, you're probably mostly using Gnome applications.

In most Gnome applications, with Gnome ≤3.36 (tested on Ubuntu 20.04), the following key sequence will work: Ctrl+O Alt+Up Shift+F10 Return

  1. Ctrl+O is the usual Gnome keyboard shortcut for the “open” command. It opens to the Gtk file open dialog. Everything that follows works in any application that uses this file open dialog. The dialog opens on the directory containing the current file.
  2. Alt+Up goes up to the current directory's parent directory. The previous directory, which is the directory you're interested in, is selected.
  3. Shift+F10 brings up the context menu.
  4. Return selects the first entry on the context menu, which is “Open With File Manager”.

With the mouse, that would be:

  1. Select the “open file” command. (“Save as” would also work.)
  2. The path to the current directory is displayed at the top, with each directory in a separate box. Click on the second box from the right, i.e. the parent of the current directory.
  3. Right-click on the selected entry (which is the directory you're interested in) to bring up the context menu.
  4. Choose “Open With File Manager” in the context menu.

I'm not a Gnome expert. Maybe there's a more convenient way.

With Gnome ≥3.38, this has unfortunately become a lot more cumbersome, because the file open dialog shows the “Recent” list by default. To see the directory containing the current file, you need to navigate to it in the left tab (with the keyboard: F6 Down Down…). Then you can use Alt+Up or the top bar to navigate to the parent directory.

With Kate (tested with 19.12.3), right-click on the file name in the tab header and choose “Open Containing Folder”.

2
  • Thanks a lot @Gilles, this already helps! However, I can't get the contextual help that you mention, neither with the shift-f10 stroke, nor with the right-click. Here is an image of my "open" dialog window: imgur.com/a/PhQFdij And here is an image of what happens if I left-click (not right-click) on the path: imgur.com/a/im0y2u5 . I wasn't able to copy the path, if you know how to copy the path that would be useful...! :)
    – Fabio
    Sep 24, 2021 at 12:28
  • @Fabio Ah, you're using Kate, which is a KDE application. KDE applications actually use the Gtk file open dialog if they detect your environment is Gnome, I don't know why it isn't doing that for you. But anyway there's a much easier Kate-specific way which is very much like the Mac way you describe: right-click on the tab header. Sep 24, 2021 at 12:48

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .