我一直很困惑为什么Linux中的文件管理器不能阻止应用程序同时打开同一个文件两次?
具体来说,我想阻止 PDF 文件阅读器 OkularA.pdf
在我已经打开该文件时再次打开该文件。我需要收到警告或只显示文件的打开副本A.pdf
。
更一般地说,我希望任何应用程序都发生这种情况,而不仅仅是 Okular。我想让 Linux 中的文档管理行为与 Windows 中相同。
答案1
文件管理器负责调用应用程序来打开文件。它无法控制应用程序对文件执行的操作,特别是如果您打开同一个文件两次,应用程序是否会打开一个新窗口。
在多个窗口中打开同一文件可能很有用,例如当您想要查看同一文档的不同部分时。因此,系统地拒绝在同一文档上打开多个窗口是很糟糕的。哪种行为是默认行为主要取决于品味。某些应用程序默认打开一个新窗口,其他应用程序默认聚焦于现有窗口。
Okular 默认打开一个新窗口。如果您使用 启动所有实例okular --unique
,那么第二次运行该命令时,它不会打开新窗口(尽管它不会聚焦现有窗口,至少在您没有运行 KDE 的情况下)。请注意,第一个实例--unique
和第二个实例必须已启动。
Evince,Gnome PDF 查看器,默认为您想要的行为:如果您第二次打开同一文档,它将聚焦于现有窗口。它没有用于打开单独窗口的命令行选项,您必须通过 GUI 来执行此操作(菜单“文件”→“打开副本”或Ctrl+ N)。
答案2
我编写了以下脚本来完成 Okular 的 flatpak 版本的所需行为(我使用的是 LMDE 5)。该脚本基于通过更改窗口标题wmctrl
。
由于新的欢迎屏幕,获得所需的行为很棘手,但我想我做到了(我不是专家程序员,所以我很欣赏任何改进代码的建议。)
在运行脚本之前,请确保取消选中“在标题栏中显示文档标题(如果可用)”选项,并将选项“不显示文档标题时”设置为“显示完整文件路径”(脚本会更改它,但它需要另外,取消选中“在选项卡中打开新文件”选项。
#!/usr/bin/env bash
# Set expectedwindowtitle whether there is an argument or not, to handle the
# welcome screen:
if [ -z "$1" ]
then
expectedwindowtitle="Welcome"
else
pdfbasename=$(basename "$1")
pdffullpath=$(dirname "$(realpath "$1")")
pdfpath=${pdffullpath/#$HOME/\~}
expectedwindowtitle="$pdfbasename ($pdfpath)"
fi
# Search for a window with the substring "— Okular" in the title (with em-dash,
# U+2014, that is, untouched), and get its ID and filename:
originaltitle=`wmctrl -l | grep -v "okularjump" | grep -v "grep" | grep -m 1 "— Okular" | awk 'BEGIN{RS=" — Okular"; FS="'$HOSTNAME' "}NF>1{print $NF}'`
originalwindowID=`wmctrl -l | grep -v "okularjump" | grep -v "grep" | grep -m 1 "— Okular" | awk '{ print $1; }'`
# If there is an existent window with the substring "— Okular" (with em-dash)
# and a filename in the title, then rename it to a new format, as follows:
# [basemane (short path) – Okular
# Note that the separator in the new format is an en-dash (U+2013)
if [ ! -z "$originaltitle" ]
then
originalfullpath=$(dirname "$originaltitle")
originalbasename=$(basename "$originaltitle")
originalpath=${originalfullpath/#$HOME/\~}
newwindowname="$originalbasename ($originalpath) – Okular" # With en-dash
wmctrl -r $originaltitle -N "$newwindowname"
fi
# Search for an already modified window title that matches the expected window
# title and extract the basename and the path
existentwindowtitle=`wmctrl -l | grep -v "okularjump" | grep -v "grep" | grep "– Okular" | grep -m 1 "$expectedwindowtitle" | awk 'BEGIN{RS=" – Okular"; FS="'$HOSTNAME' "}NF>1{print $NF}'` # With en-dashes
# If expected and existent windows are the same, then switch to the existent
# window
if [[ "$expectedwindowtitle" == "$existentwindowtitle" ]]
then
wmctrl -a "$existentwindowtitle"
else
# There is an argument and nothing to switch to. Then, open the argument with
# the new format in the title
if [ ! -z "$1" ]
then
/usr/bin/flatpak run --branch=stable --arch=x86_64 --command=okular --file-forwarding org.kde.okular @@ "$1" @@ &>/dev/null &
while ! test -n "$argoriginalwindowID"; do
sleep 0.01
argoriginalwindowID=`wmctrl -l | grep -v "okularjump" | grep -v "grep" | grep "— Okular" | grep -i -m 1 "$(basename "$1")" | awk '{ print $1; }'`
done
pdffullpath=$(dirname "$(realpath "$1")")
pdfpath=${pdffullpath/#$HOME/\~}
argWname="$(basename "$1") ($pdfpath) – Okular"
wmctrl -ir $argoriginalwindowID -N "$argWname"
else
# There is no argument and nothing to switch to. Open a welcome screen
# with the word Welcome in the title (to make possible to find it later)
/usr/bin/flatpak run --branch=stable --arch=x86_64 --command=okular --file-forwarding org.kde.okular --title "Welcome" &>/dev/null &
while ! test -n "$welcomeWname"; do
sleep 0.01
welcomeWname=`wmctrl -l | grep -v "okularjump" | grep -v "grep" | grep -m 1 "— Okular" | grep -m 1 "Welcome"`
done
originalwindowID=`wmctrl -l | grep -v "okularjump" | grep -v "grep" | grep -m 1 "— Okular" | grep -m 1 "Welcome" | awk '{ print $1; }'`
newwindowname="Welcome – Okular"
wmctrl -ir $originalwindowID -N "$newwindowname"
fi
fi
为了在系统中默认使用该脚本,我将代码保存为 ~/okularjump,使其可执行并将其复制到/usr/bin
.然后,我将默认的 .desktop 文件复制到用户文件夹两次:一次是为了运行脚本,另一次是为了隐藏默认的 flatpak 启动器:
chmod +x okularjump
sudo cp okularjump /usr/bin/
cp /var/lib/flatpak/app/org.kde.okular/current/active/export/share/applications/org.kde.okular.desktop ~/.local/share/applications/
cp /var/lib/flatpak/app/org.kde.okular/current/active/export/share/applications/org.kde.okular.desktop ~/.local/share/applications/okular.desktop
echo "Hidden=true" >> ~/.local/share/applications/org.kde.okular.desktop
然后,我将 ~/.local/share/applications/okular.desktop 中的 Exec 行更改为Exec=okularjump %U
最后,我在系统设置中将 Okular 设置为默认 PDF 管理器。
关于打开同一文件的多个实例,仍然可以通过打开对话框从 Okular 打开文件来完成。该脚本将在下次运行时调整窗口标题。
我从 Jumpapp 中获得灵感https://github.com/mkropat/jumpapp(这应该适用于非 Flatpak 版本,但我不确定)和 Flatjumphttps://github.com/ceranco/flatjump(这对我不起作用,但我邀请尝试)。