4

I use the following script (it is bound to a keyboard shortcut) to open selected file (clicking on a window after using the shortcut) in nemo. What is does is from window id (after clicking on the window), it get the process id, then using that get the file path that belong to the pid. After acquiring the file path, it opens that file with nemo.

#!/bin/bash

WINDOW_ID=$(xdotool getactivewindow)
PID_OF_ACTIVE_WINDOW=$(xdotool getwindowpid $WINDOW_ID)
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

But the problem is with Foliate. It use the same process for multiple windows. If I open multiple .epub files, it has multiple windows. But all the windows have one pid.

% xdotool getwindowpid 59418676
15977
% xdotool getwindowpid 59422435
15977
% ps -aux | grep 15977
ismail     15977  0.1  0.7 95405880 128992 ?     Sl   May05  10:23 /usr/bin/gjs /usr/bin/com.github.johnfactotum.Foliate /media/ismail/SSDWorking/book-collection/_Books/self-development-anxiety-self-talk/child/Freeing Your Child from Anxiety Powerful, Practical Solutions to Overcome Your Childs Fears, Worries, and Phobias (Tamar Chansky Ph.D.).epub
% readlink -f /proc/15977/exe
/usr/bin/gjs-console

I am using Zorin OS 16.2, which use Gnome 3.

I checked the sub-processes to see if I can get the path of other files, but did not help much.

% pgrep -P 15977
15995
15998
16011
139458
139662
% ps -p 15995 -o command
COMMAND
/usr/lib/x86_64-linux-gnu/webkit2gtk-4.0/WebKitNetworkProcess 7 16
% ps -p 15998 -o command
COMMAND
/usr/lib/x86_64-linux-gnu/webkit2gtk-4.0/WebKitNetworkProcess 8 19
% ps -p 16011 -o command
COMMAND
/usr/bin/bwrap --args 29 -- /usr/bin/xdg-dbus-proxy --args=26
% ps -p 139458 -o command
COMMAND
/usr/bin/bwrap --args 58 -- /usr/lib/x86_64-linux-gnu/webkit2gtk-4.0/WebKitWebProcess 59 54
% ps -p 139662 -o command
COMMAND
/usr/bin/bwrap --args 62 -- /usr/lib/x86_64-linux-gnu/webkit2gtk-4.0/WebKitWebProcess 73 58

How can I get the exact file path from window ID, when file is opened in Foliate?

Update 1

I have done some research. The following command works.

% dbus-send --session --print-reply --dest=com.github.johnfactotum.Foliate /com/github/johnfactotum/Foliate org.freedesktop.DBus.Introspectable.Introspect

I have also checked with d-feet that d-bus also show the windows.

Foliate D-Feet

Now if I could somehow get the file path and window id from here then it would solve my problem.

Ahmad Ismail
  • 2,478
  • 1
  • 22
  • 47

2 Answers2

3

What you might do to identify what file is shown in a window when using Foliate, is to look at the window name propery, which seems to hold the document title. You can get this interactively from xdotool selectwindow getwindowname or xprop WM_NAME.

You can then wrap Foliate inside a shell script so that when you run, say, myFoliate myfile.epub it can add to a log file the filename $PWD/$1 (or $1 if it begins /) and the equivalent title. When you later select a window, you can get the name which is the title, and look up this in the log to find the filename.

Getting the title for an epub file is feasible: the format is a zipped archive, with the <title> in xml in toc.ncx.

Instead, you can run something like

xdotool search --class 'Foliate' |
xargs -i xdotool getwindowname {}

at the start of the script to get the list of current names/titles, then again a few seconds after starting Foliate in the background. The new entry will be the new title.

This will not be able to distinguish between two versions of the same document with the same title. Instead, you can note in the log the window-id of the newly created window (using just xdotool search --class Foliate which outputs the list of window-ids), together with the filename. Then when you select the window, you lookup this number, rather than the title.

Obviously, the last match in the log should be used, if there are many out-of-date entries.


Here is a possible implementation as a script, myfoliate, which is called with either a filename, or -q to select a window and retrieve a filename. It is a bit overcomplicated as I added a locking mechanism to avoid getting the wrong id if two new Foliate windows are opened at once. The declare -A makes the variable windows an associative array, with the window ids as keys so we can easily find a new missing entry. The sleep 2 may need to be increased if Foliate is slow to start. The log file should probably be emptied at the start if it can be determined that there is no current Foliate running.

#!/bin/bash
log=$HOME/.myfoliate.log
if [ $# -ne 1 ]
then    echo "$0: usage: <filename>  or -q"
        exit 1
fi
if [ '-q' = "$1" ]
then    id=$(xdotool selectwindow)
        gawk <$log -v id="$id" '
        $1==id { $1 = ""; file=$0; }
        END{ print file; exit(file==""); }'
        exit
fi
if [[ "$1" =~ ^/ ]]
then    file=$1
else    file=$PWD/$1
fi
listwindows(){
        xdotool search --class 'Foliate'
}
( flock -n 9 || exit 2
declare -A windows
for id in $(listwindows)
do      windows[$id]=1
done
Foliate "$1" 9>&- &
sleep 2
for id in $(listwindows)
do      if [ "${windows[$id]}" == "" ]
        then    newwin=$id
        fi
done
if [ -z "$newwin" ]
then    echo "$0: failed"
        exit 3
fi
echo "$newwin $file" >&9
) 9>>$log
meuh
  • 49,672
  • 2
  • 52
  • 114
  • This is the correct answer. Can you please give us some code. It will be very helpful for people who later come to find a solution for this problem. – Ahmad Ismail May 09 '23 at 18:26
  • 1
    I've added a possible shell script. – meuh May 09 '23 at 20:31
  • 1
    You might have to replace `Foliate` with `com.github.johnfactotum.Foliate`. In my machine to check version of Foliate, i have to run `com.github.johnfactotum.Foliate -v`. In `/home/ismail/.local/share/applications/com.github.johnfactotum.Foliate.desktop` i have replaced `Exec=com.github.johnfactotum.Foliate %U` with `Exec=/home/ismail/.dotfiles/.resources/bash-scripts/foliate.sh %U`. Now it works like a charm. – Ahmad Ismail May 10 '23 at 06:40
  • Just to be clear, I have copied `/usr/share/applications/com.github.johnfactotum.Foliate.desktop` to `/home/ismail/.local/share/applications/com.github.johnfactotum.Foliate.desktop` and then edited it. – Ahmad Ismail May 10 '23 at 06:42
  • I have answered a question based on your answer. https://unix.stackexchange.com/a/745519/206574 Please review the answer (and suggest improvement, specially my coding skill is amateur at best, also i am not a native english speaker) and give us a feedback. It would be better if you could give an answer to that question based on our work (improve the code and logic, and also make it more generic). That way this problem of "opening a file on file explorer that is open on a gui app" will have better solution and help other linux users. – Ahmad Ismail May 11 '23 at 08:59
  • at the end of the answer i have mentioned some issues with the current solution. Also some thinks are hard coded. It is not generic enough, if someone want to use that solution, he has to know a lot and also have to edit the code. It would be better if the solution was simpler. – Ahmad Ismail May 11 '23 at 09:04
2

Yeah, that isn't really solvable: The assumption that each window belongs to a process of its own is simply wrong.

You will have to check whether Foliate offers some API with which you can map windows to the file shown in that window – it probably doesn't, there's quite a few levels of abstractions in between.

So, in short, with your current approach, it's impossible to achieve what you want.

You can possibly implement something that asks Foliate specifically to convert a WID to the document opened in that window, but it might take serious development effort within the Foliate code base.

Marcus Müller
  • 21,602
  • 2
  • 39
  • 54