4

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 ?

3 Answers 3

2

The only option for such a case that is provided with Okular is when files are opened in new tabs. When this is enabled, the option to "switch to the tab if the file is already open" can then be used to have the desired effect. The relevant option is highlighted in the screenshot below:

okular_settings_switch_to_existing_tab

2

Here is a quick and dirty trick : it is a Python script that just checks for an existing instance.

Save this script as /usr/local/bin/okular and make it executable. Since usually, $PATH is set up so that files in /usr/local/bin take precedence over those in /usr/bin, your script will run instead of the standard okular.

#! /usr/bin/env python3

import subprocess
import sys
import os
import getpass

OKULAR_FN = "okular"
OKULAR_FULLPATH="/usr/bin/okular"

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_FULLPATH])
    else :
        filename = os.path.abspath(sys.argv[1])
        pidl = get_okular_instance(filename)
        if len(pidl) != 1 :
            runcmd([OKULAR_FULLPATH, filename])
        else :
            wid = get_window_id(pidl[0])
            if wid is None :
                runcmd([OKULAR_FULLPATH, filename])
            else :
                raise_window(wid)

if __name__ == "__main__" :
    main()
3
  • Thanks, I'm using this to provide the same desired behaviour with Lyx, and it's perfect.
    – Autumn
    Commented Oct 4, 2019 at 21:37
  • 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
    Commented Feb 27, 2020 at 18:04
  • 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
    Commented Feb 28, 2020 at 15:23
1

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.

1
  • 1
    The 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
    Commented Jul 20, 2019 at 11:08

You must log in to answer this question.

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