Avoid opening the same file in multiple Okular instances

1

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 ?

ysalmon

Posted 2019-02-22T09:42:47.817

Reputation: 143

Answers

2

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()

ysalmon

Posted 2019-02-22T09:42:47.817

Reputation: 143

Thanks, I'm using this to provide the same desired behaviour with Lyx, and it's perfect. – Autumn – 2019-10-04T21:37:59.920

Thanks, would it be possible with a similar python or bash function and .bashrc shortcut that internally finds whether an instance exists and should be used. Then you can call this function from terminal, without modifying okular in bin. Or isn't changing the okular in bin a problem (package manager, etc.)? Thanks anyway for sharing your useful code with this answer – Peruz – 2020-02-27T18:04:43.260

You might want to leave /usr/bin/okular untouched and create the script in /usr/local/bin/okular or even ~/bin/okular. It should take precedence but you may have to adapt the code slightly. – ysalmon – 2020-02-28T15:23:42.053

0

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.

Lutz Büch

Posted 2019-02-22T09:42:47.817

Reputation: 1

1The documentation about --unique is indeed very scarce. But it seems this switch makes Okular use a unique instance for all opened files : opening a different file causes the currently opened file to be replaced in the unique instance. I aim at having a unique instance for each different file, not a unique instance for all files. – ysalmon – 2019-07-20T11:08:25.333