Skip to content

Instantly share code, notes, and snippets.

@agzam
Last active May 6, 2024 03:48
Show Gist options
  • Star 22 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save agzam/76d761804330cc8c4600fccda952ed1c to your computer and use it in GitHub Desktop.
Save agzam/76d761804330cc8c4600fccda952ed1c to your computer and use it in GitHub Desktop.
Open pdf files with Zathura on Mac

Zathura on Mac

I want to open PDF files with Zathura on Mac. Problem is - Zathura does not have a proper App Bundle. So you cannot go in Finder to a pdf file, navigate to ‘Get Info’ and set pdf files to be opened with Zathura.

Luckily, you can create a custom App Bundle that wraps up a script that does that

But that is not as straightforward as you think it is, you can’t just execute a shell script. What if the file already opened with one of the instances of zathura process? Since Zathura is not a native OSX app, it will create a new process instance every time you open it.

The following script opens a file in Zathura, and if it was already opened, it would only activate the right window.

How to use it

  • Open Automator
  • Create new Application
  • Copy & paste this script
  • Save as ‘zathura-client.app’ (or whatever you like)
  • Associate .pdf files with that App - In Finder: Get Info -> Open with -> Change All
-- it's not even funny, I couldn't figure out the proper way of unqotting a
-- string in applescript with quoted form of POSIX path, so I did this instead

on replace_chars(this_text, search_string, replacement_string)
 set AppleScript's text item delimiters to the search_string
 set the item_list to every text item of this_text
 set AppleScript's text item delimiters to the replacement_string
 set this_text to the item_list as string
 set AppleScript's text item delimiters to ""
 return this_text
end replace_chars

on activate_open_instance(win_title, is_first_time)
  tell application "System Events"
    set zathuraProcList to a reference to (every process whose name is "zathura")
    repeat with proc in zathuraProcList
        set PID to proc's unix id 
        -- I needed to figure out if this is the instance of Zathura with the
        -- file on hand. And if it is, then focus on that window. Guess what?
        -- Apparently you cannot grab list of all windows for a process (through
        -- "System Events") if that process has fullscreen windows. It just not
        -- possible. You have to do something like:
        -- `tell application "zathura"`
        -- alas, Zathura is not a "Cocoa Application"
        -- so I had to run lsof for the process PID and strip down the output to contain only filenames 
        set myFiles to paragraphs of (do shell script "lsof -F -p " & PID & " | grep ^n/ | cut -c2-")
        set fName to my replace_chars(win_title,"'", "") -- have to unquote or comparison won't work
        if myFiles contains fName then
            tell proc 
              set frontmost to true
              if is_first_time then
                  set value of attribute "AXFullScreen" of window 1 to true -- set it to fullscreen the first time file opens
              end if
            end tell
            return true
        end if
    end repeat
  end tell
  
  return false
end activate_open_instance

on run {input, parameters}
  set filePath to quoted form of POSIX path of input
  -- first we try to find it (in case it's already opened)
  if not my activate_open_instance(filePath, false) then
    set zathura to "/usr/local/bin/zathura "
    do shell script zathura & filePath & " > /dev/null 2>&1 &"
    delay 0.3    -- delay is required so it can set the window to fullscreen, but until the window is created, you can't set its properties
    my activate_open_instance(filePath, true)
  end if
  return input
end run
@Enrico68
Copy link

Got this error

Cannot get POSIX path

@agzam
Copy link
Author

agzam commented Oct 22, 2021

@Enrico68 I guess you're attempting to run it in the Automator. Well, it won't work that way, because it's specifically made to work with a given file. One way to try it is to call the script from the command line, like so:

open -a /Applications/zathura-client.app ~/Books/some-book.pdf

@shaunlebron
Copy link

Thanks! Worked for me. I only had to change the path for homebrew:

/opt/homebrew/bin/zathura

@qwinters
Copy link

This script works for me, but on opening a PDF each time I get a small popup saying Connection is invalid so I think there might be some small tweaks to make. See image below:

Screen Shot 2022-07-11 at 10 11 25 AM

For reference I am on MacOS 12.5 Beta (updated today) with an M1 chip. Will try to dig into it myself and update if I find anything, but it's not high priority because overall the workflow works fine

@m-zheng
Copy link

m-zheng commented Aug 3, 2022

Thanks. It works like a charm. If someone does not want the full screen mode, you can remove the code below.

              if is_first_time then
                  set value of attribute "AXFullScreen" of window 1 to true -- set it to fullscreen the first time file opens
              end if

Meanwhile, add code below to the ~/.config/zathura/zathura so that the file is opened in the maximised window (but not full screen). Change 3000 if you have a larger screen.

set window-height 3000
set window-width 3000

@L1szt
Copy link

L1szt commented Nov 7, 2022

Thanks. It works like a charm. If someone does not want the full screen mode, you can remove the code below.

              if is_first_time then
                  set value of attribute "AXFullScreen" of window 1 to true -- set it to fullscreen the first time file opens
              end if

Meanwhile, add code below to the ~/.config/zathura/zathura so that the file is opened in the maximised window (but not full screen). Change 3000 if you have a larger screen.

set window-height 3000
set window-width 3000

Do you happen to know how to have tabs in zathura?

@m-zheng
Copy link

m-zheng commented Nov 7, 2022

Thanks. It works like a charm. If someone does not want the full screen mode, you can remove the code below.

              if is_first_time then
                  set value of attribute "AXFullScreen" of window 1 to true -- set it to fullscreen the first time file opens
              end if

Meanwhile, add code below to the ~/.config/zathura/zathura so that the file is opened in the maximised window (but not full screen). Change 3000 if you have a larger screen.

set window-height 3000
set window-width 3000

Do you happen to know how to have tabs in zathura?

I never use tabs in zathura. However, this link may be helpful.

@m-zheng
Copy link

m-zheng commented Dec 28, 2022

@agzam, I figure out the "proper way of unqotting a string in applescript with quoted form of POSIX path". It turned out you actually did not need to do it, just get it from the input. My script below now can stop opening multiple instances if the filename contains special characters, such as '. It can also open multiple files at the same time.

on activate_open_instance(quoted_win_title, unquoted_win_title, is_first_time)
  tell application "System Events"
    set zathuraProcList to a reference to (every process whose name is "zathura")
    repeat with proc in zathuraProcList
      set PID to proc's unix id
      -- I needed to figure out if this is the instance of Zathura with the
      -- file on hand. And if it is, then focus on that window. Guess what?
      -- Apparently you cannot grab list of all windows for a process (through
      -- "System Events") if that process has fullscreen windows. It just not
      -- possible. You have to do something like:
      -- `tell application "zathura"`
      -- alas, Zathura is not a "Cocoa Application"
      -- so I had to run lsof for the process PID and strip down the output to contain only filenames 
      set myFiles to paragraphs of (do shell script "lsof -F -p " & PID & " | grep ^n/ | cut -c2-")
      -- have to use unquoted win title or comparison won't work
      if myFiles contains unquoted_win_title then
        tell proc
          set frontmost to true
        end tell
        return true
      end if
    end repeat
  end tell
  
  return false
end activate_open_instance

on single_run {single_input}
  set quoted_filePath to quoted form of POSIX path of single_input
  set unquoted_filePath to POSIX path of single_input
  -- first we try to find it (in case it's already opened)
  if not my activate_open_instance(quoted_filePath, unquoted_filePath, false) then
    set zathura to "/usr/local/bin/zathura "
    do shell script zathura & quoted_filePath & " > /dev/null 2>&1 &"
    delay 0.8 -- delay is required so it can set the window to fullscreen, but until the window is created, you can't set its properties
    my activate_open_instance(quoted_filePath, unquoted_filePath, true)
  end if
end single_run

on run {input, parameters}
  set SelectedItems to input
  repeat with aFile in SelectedItems -- the loop through all selected items
      single_run(aFile)
  end repeat
end run

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment