Skip to content

Instantly share code, notes, and snippets.

@agzam
Last active March 10, 2025 11:13
Show Gist options
  • 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
@shivangp76
Copy link

Improved on @m-zheng by modifying the path of zathura to be dynamically determined from $(which zathura). This adds support for zathura installed from Homebrew.

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 (do shell script "which 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