]> git.lyx.org Git - lyx.git/blob - development/Win32/pdfview/pdfview.nsi
7798dbaa9647a4654230c6d1a10e03f05f88273a
[lyx.git] / development / Win32 / pdfview / pdfview.nsi
1 /*
2
3 Windows PDF view helper
4 Author: Joost Verburg and Uwe Stöhr
5
6 This will be installed as pdfview.exe.
7
8 The application will launch the default PDF viewer to display the PDF file,
9 but works around the file locking problems of Adobe Reader and Acrobat.
10
11 The files pdfopen/pdfclose are part of this archive:
12 http://www.tex.ac.uk/tex-archive/systems/win32/w32tex/pdftex-w32.tar.xz
13
14 */
15
16 !include LogicLib.nsh
17 !include FileFunc.nsh
18
19 #--------------------------------
20 # Settings
21
22 Caption "PDF Viewer"
23 OutFile pdfview.exe
24 Icon "..\packaging\icons\lyx.ico"
25 SilentInstall silent
26
27 #--------------------------------
28 # Windows Vista (and later) settings
29
30 RequestExecutionLevel user
31
32 #--------------------------------
33 # Constants
34
35 !define FALSE 0
36 !define TRUE 1
37
38 # http://msdn.microsoft.com/en-us/library/windows/desktop/aa364417%28v=vs.85%29.aspx
39 !define FILE_NOTIFY_CHANGE_LAST_WRITE 0x00000010
40 # http://msdn.microsoft.com/en-us/library/windows/desktop/ms687032%28v=vs.85%29.aspx
41 !define WAIT_TIMEOUT 0x00000102
42
43 #--------------------------------
44 # Variables
45
46 Var Character
47 Var RunAppReturn
48
49 Var OriginalFile
50 Var OriginalFileName
51 Var OriginalDir
52
53 Var PDFFile
54 Var ViewerFileName
55 Var Viewer
56
57 Var ChangeNotification
58 Var WaitReturn
59 Var LockedFile
60
61 Var TimeDiff
62
63 #--------------------------------
64 # Macros
65
66 !macro SystemCall STACK
67
68   # Call a Windows API function
69
70   Push `${STACK}`
71   CallInstDLL "$EXEDIR\System.dll" Call
72
73 !macroend
74
75 !macro HideConsole COMMAND_LINE
76
77   # Run an application and hide console output
78
79   Push `${COMMAND_LINE}`
80   CallInstDLL "$EXEDIR\Console.dll" Exec
81   Pop $RunAppReturn
82   
83   ${If} $RunAppReturn == "error"
84     MessageBox MB_OK|MB_ICONSTOP "Error opening PDF file $PDFFile."
85   ${EndIf}
86
87 !macroend
88
89 # all following macros and functions are from
90 # http://nsis.sourceforge.net/FileTimeDiff
91 !define GetFileTimeS "!insertmacro _GetFileTimeS"
92
93 !macro _GetFileTimeS _Time_ _File_
94
95    Push "${_File_}"
96    Call GetFileTimeS
97    Pop ${_Time_}
98    
99 !macroend
100
101 Function GetFileTimeS
102         
103    Exch $0  ;; File / hi
104    Push $1  ;; lo
105  
106    ClearErrors
107    GetFileTime "$0" $0 $1
108    IfErrors err
109    System::Call '*(i r1, i r0) i .r0'
110    System::Call '*$0(l .r0)'
111    System::Int64Op $0 / 10000000  ;; Conversion From '100 ns' to '1 sec' unit
112    Goto end
113  
114    err:
115       Push ""
116       SetErrors
117       Goto +3
118    end:
119    System::Free $0
120    Exch 2
121    Pop $0
122    Pop $1
123    
124 FunctionEnd
125
126 !define FileTimeDiff "!insertmacro _FileTimeDiff"
127
128 !macro _FileTimeDiff _RetVal_ _FileA_ _FileB_
129
130    Push "${_FileB_}"
131    Push "${_FileA_}"
132    Call FileTimeDiff
133    Pop ${_RetVal_}
134    
135 !macroend
136
137 Function FileTimeDiff 
138    Exch $0  ;; FileA
139    Exch 
140    Exch $1  ;; FileB
141  
142    ${GetFileTimeS} $0 "$0"
143    IfErrors err
144    ${GetFileTimeS} $1 "$1"
145    IfErrors err
146    System::Int64Op $0 - $1
147    Goto end
148  
149    err:
150       Push ""
151       SetErrors
152    end:
153    Exch 2
154    Pop $0
155    Pop $1
156    
157 FunctionEnd
158
159 #--------------------------------
160 # PDF viewing
161
162 Section "View PDF file"
163
164   InitPluginsDir # Temporary directory for PDF file
165
166   # Command line parameters
167   ${GetParameters} $OriginalFile
168
169   # Trim quotes
170   StrCpy $Character $OriginalFile 1
171   ${If} $Character == '"'
172     StrCpy $OriginalFile $OriginalFile "" 1
173   ${EndIf}
174   StrCpy $Character $OriginalFile 1 -1
175   ${If} $Character == '"'
176     StrCpy $OriginalFile $OriginalFile -1
177   ${EndIf}
178
179   GetFullPathName $OriginalFile $OriginalFile
180   ${GetFileName} $OriginalFile $OriginalFileName
181   ${GetParent} $OriginalFile $OriginalDir # tmpbuf
182   ${GetParent} $OriginalDir $OriginalDir # tmpdir
183
184   SetOutPath $TEMP # The LyX tmpbuf should not be locked
185
186   StrCpy $PDFFile $PLUGINSDIR\$OriginalFileName
187
188   # Check whether the file will be opened with Adobe Reader or Adobe Acrobat
189   !insertmacro SystemCall "shell32::FindExecutable(t '$OriginalFile', t '', t .s)"
190   Pop $ViewerFileName
191   ${GetFileName} $ViewerFileName $Viewer
192
193   ${If} $Viewer == ""
194     MessageBox MB_OK|MB_ICONEXCLAMATION "No PDF viewer is installed. \
195         Please install a PDF viewer such as Adobe Reader."
196     Quit        
197   ${EndIf}
198
199   ${If} $Viewer == "AcroRd32.exe"
200   ${OrIf} $Viewer == "Acrobat.exe"
201     
202     # Close existing view
203     ${If} ${FileExists} $PDFFile
204       !insertmacro HideConsole '"$EXEDIR\pdfclose.exe" --file "$PDFFile"'
205     ${EndIf}
206     
207     # Copy PDF to temporary file to allow LyX to overwrite the original
208     CopyFiles /SILENT $OriginalFile $PDFFile
209     
210     # Open a new view
211     !insertmacro HideConsole '"$EXEDIR\pdfopen.exe" --file "$PDFFile"'
212         
213     # check if a file in LyX's temp folder has been changed
214     !insertmacro SystemCall "kernel32::FindFirstChangeNotification(t '$OriginalDir', \
215       i 1, i ${FILE_NOTIFY_CHANGE_LAST_WRITE}) i.s"
216     Pop $ChangeNotification
217     
218     ${Do}
219     
220       # wait until the folder is not changed anymore, if so a "0" is returned
221       # otherwise a "258" (0x00000102) is returned
222       !insertmacro SystemCall "kernel32::WaitForSingleObject(i $ChangeNotification, i 10000) i.s"
223       Pop $WaitReturn
224       
225       # Check whether the lock of the PDF file is still active (if not, Adobe Reader is closed)
226       FileOpen $LockedFile $PDFFile a
227       ${If} $LockedFile != ""
228         # Quit this application
229         FileClose $LockedFile
230         Delete $PDFFile
231         !insertmacro SystemCall "kernel32::FindCloseChangeNotification(i $ChangeNotification)"
232         Quit
233       ${EndIf}
234       
235       # if the folder is (for now) not changed anymore
236       ${IfNot} $WaitReturn = ${WAIT_TIMEOUT}
237       
238         # check if the PDF-file in our temp directory is older than the one
239         # in LyX's temp folder because then it has been changed by LaTeX
240         ${FileTimeDiff} $TimeDiff "$PDFFile" "$OriginalFile"
241         
242         # if the file is older than 1 second
243         ${If} $TimeDiff < -1
244           # close the PDF
245           !insertmacro HideConsole '"$EXEDIR\pdfclose.exe" --file "$PDFFile"'
246           
247           # The problem is now that LaTeX might need several runs and therefore the PDF can
248           # also be rewritten consecutively several times.
249           # If we would directly open the file we will get in troubles as the PDF can be
250           # unreadable. We also don't know the time of a LaTeX run.
251           # (As example take UserGuide.lyx, view it, then remove a letter in a section heading
252           # and finally update the view.)
253           # We therefore loop until the PDF is no longer changed and wait some time in each loop.
254           ${Do}
255            CopyFiles /SILENT $OriginalFile $PDFFile
256            # wait 1.666 seconds (is empirically enough time that the PDF can be changed)
257            Sleep 1666
258            ${FileTimeDiff} $TimeDiff "$PDFFile" "$OriginalFile"
259           ${LoopUntil} $TimeDiff = 0
260           
261           # open the new file
262           !insertmacro HideConsole '"$EXEDIR\pdfopen.exe" --file "$PDFFile"'
263         ${EndIf}
264         
265         #Monitor again
266         !insertmacro SystemCall "kernel32::FindNextChangeNotification(i $ChangeNotification)"
267         
268       ${EndIf} # end ifnot
269     
270     ${Loop}
271     
272   ${Else}
273   
274     # Another PDF viewer like GSView is used
275     # No need for special actions, just forward to ShellExecute
276     ExecShell open $OriginalFile
277     
278   ${EndIf}
279     
280 SectionEnd