Problem :
When invoked on a file that is already opened, okular will simply start another instance. This leads to cluttering for example when compiling LaTeX documents and repeatedly starting the viewer, or simply when one has forgotten a file is opened and opens it again from the file manager.
Evince on the contrary will detect this and raise the existing window instead.
How to achieve this with okular ?
Solution :
Here is a quick and dirty trick : it is a Python script that just checks for an existing instance.
To use it, rename /usr/bin/okular
to /usr/bin/okular.real
and save this script as /usr/bin/okular
.
#! /usr/bin/env python3
import subprocess
import sys
import os
import getpass
OKULAR_FN = "okular.real"
def get_okular_instance(filename) :
try :
lproc = subprocess.check_output(["ps", "-C", OKULAR_FN, "-o", "pid,user,args", "--no-headers"], universal_newlines=True).splitlines()
except subprocess.CalledProcessError :
return []
result = []
me = getpass.getuser()
for proc in lproc :
pid, user, _, args = proc.split(maxsplit=3)
if user == me and args == filename :
result.append(pid)
return result
def get_window_id(pid) :
fenetres = subprocess.check_output(["wmctrl", "-ulp"], universal_newlines=True)
for f in fenetres.splitlines() :
donnees = f.split()
if len(donnees) < 3 :
continue
if donnees[2] == pid :
return donnees[0]
return None
def raise_window(wid) :
subprocess.call(["wmctrl", "-i", "-a", wid])
def runcmd(cmdl) :
subprocess.Popen(cmdl, stdin=None, stdout=None, stderr=None, close_fds=True)
def main() :
if len(sys.argv) < 2 :
runcmd([OKULAR_FN])
else :
filename = os.path.abspath(sys.argv[1])
pidl = get_okular_instance(filename)
if len(pidl) != 1 :
runcmd([OKULAR_FN, filename])
else :
wid = get_window_id(pidl[0])
if wid is None :
runcmd([OKULAR_FN, filename])
else :
raise_window(wid)
if __name__ == "__main__" :
main()
For me, the command line option --unique
works.
The documentation only indicates the term “unique instance control”, which sounds like it does the right thing, and for me it seems to.