Reload modified PDF document

This commits add the functionality that when the PDF file has been
rewritten in the background (e.g.: from another program), zathura
reloads the document to refresh the page.
This commit is contained in:
Moritz Lipp 2010-03-08 20:08:59 +01:00
parent e250cbc5d5
commit 7b1bc17b1e

View file

@ -9,6 +9,7 @@
#include <unistd.h> #include <unistd.h>
#include <libgen.h> #include <libgen.h>
#include <pthread.h> #include <pthread.h>
#include <sys/inotify.h>
#include <poppler/glib/poppler.h> #include <poppler/glib/poppler.h>
#include <cairo.h> #include <cairo.h>
@ -193,12 +194,14 @@ struct
pthread_mutex_t rotate_lock; pthread_mutex_t rotate_lock;
pthread_mutex_t search_lock; pthread_mutex_t search_lock;
pthread_mutex_t viewport_lock; pthread_mutex_t viewport_lock;
pthread_mutex_t document_lock;
} Lock; } Lock;
struct struct
{ {
pthread_t search_thread; pthread_t search_thread;
gboolean search_thread_running; gboolean search_thread_running;
pthread_t inotify_thread;
} Thread; } Thread;
struct struct
@ -215,6 +218,12 @@ struct
int last; int last;
} Marker; } Marker;
struct
{
int wd;
int fd;
} Inotify;
struct struct
{ {
GKeyFile *data; GKeyFile *data;
@ -258,6 +267,7 @@ GtkEventBox* createCompletionRow(GtkBox*, char*, char*, gboolean);
/* thread declaration */ /* thread declaration */
void* search(void*); void* search(void*);
void* watch_file(void*);
/* shortcut declarations */ /* shortcut declarations */
void sc_abort(Argument*); void sc_abort(Argument*);
@ -361,6 +371,7 @@ init_zathura()
pthread_mutex_init(&(Zathura.Lock.rotate_lock), NULL); pthread_mutex_init(&(Zathura.Lock.rotate_lock), NULL);
pthread_mutex_init(&(Zathura.Lock.search_lock), NULL); pthread_mutex_init(&(Zathura.Lock.search_lock), NULL);
pthread_mutex_init(&(Zathura.Lock.viewport_lock), NULL); pthread_mutex_init(&(Zathura.Lock.viewport_lock), NULL);
pthread_mutex_init(&(Zathura.Lock.document_lock), NULL);
/* look */ /* look */
gdk_color_parse(default_fgcolor, &(Zathura.Style.default_fg)); gdk_color_parse(default_fgcolor, &(Zathura.Style.default_fg));
@ -395,6 +406,8 @@ init_zathura()
Zathura.Marker.number_of_markers = 0; Zathura.Marker.number_of_markers = 0;
Zathura.Marker.last = -1; Zathura.Marker.last = -1;
Zathura.Inotify.fd = inotify_init();
/* UI */ /* UI */
Zathura.UI.window = GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL)); Zathura.UI.window = GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL));
Zathura.UI.box = GTK_BOX(gtk_vbox_new(FALSE, 0)); Zathura.UI.box = GTK_BOX(gtk_vbox_new(FALSE, 0));
@ -752,8 +765,10 @@ open_file(char* path, char* password)
/* open file */ /* open file */
GError* error = NULL; GError* error = NULL;
pthread_mutex_lock(&(Zathura.Lock.document_lock));
Zathura.PDF.document = poppler_document_new_from_file(g_strdup_printf("file://%s", file), Zathura.PDF.document = poppler_document_new_from_file(g_strdup_printf("file://%s", file),
password ? password : NULL, &error); password ? password : NULL, &error);
pthread_mutex_unlock(&(Zathura.Lock.document_lock));
if(!Zathura.PDF.document) if(!Zathura.PDF.document)
{ {
@ -765,7 +780,16 @@ open_file(char* path, char* password)
return FALSE; return FALSE;
} }
/* inotify */
if(Zathura.Inotify.fd != -1)
{
if((Zathura.Inotify.wd = inotify_add_watch(Zathura.Inotify.fd, file, IN_CLOSE_WRITE)) != -1)
pthread_create(&(Zathura.Thread.inotify_thread), NULL, watch_file, NULL);
}
pthread_mutex_lock(&(Zathura.Lock.document_lock));
Zathura.PDF.number_of_pages = poppler_document_get_n_pages(Zathura.PDF.document); Zathura.PDF.number_of_pages = poppler_document_get_n_pages(Zathura.PDF.document);
pthread_mutex_unlock(&(Zathura.Lock.document_lock));
Zathura.PDF.file = file; Zathura.PDF.file = file;
pthread_mutex_lock(&(Zathura.Lock.scale_lock)); pthread_mutex_lock(&(Zathura.Lock.scale_lock));
Zathura.PDF.scale = 100; Zathura.PDF.scale = 100;
@ -781,7 +805,9 @@ open_file(char* path, char* password)
for(i = 0; i < Zathura.PDF.number_of_pages; i++) for(i = 0; i < Zathura.PDF.number_of_pages; i++)
{ {
Zathura.PDF.pages[i] = malloc(sizeof(Page)); Zathura.PDF.pages[i] = malloc(sizeof(Page));
pthread_mutex_lock(&(Zathura.Lock.document_lock));
Zathura.PDF.pages[i]->page = poppler_document_get_page(Zathura.PDF.document, i); Zathura.PDF.pages[i]->page = poppler_document_get_page(Zathura.PDF.document, i);
pthread_mutex_unlock(&(Zathura.Lock.document_lock));
pthread_mutex_init(&(Zathura.PDF.pages[i]->lock), NULL); pthread_mutex_init(&(Zathura.PDF.pages[i]->lock), NULL);
} }
@ -1035,7 +1061,9 @@ search(void* parameter)
next_page = (Zathura.PDF.number_of_pages + Zathura.PDF.page_number + next_page = (Zathura.PDF.number_of_pages + Zathura.PDF.page_number +
page_counter * direction) % Zathura.PDF.number_of_pages; page_counter * direction) % Zathura.PDF.number_of_pages;
pthread_mutex_lock(&(Zathura.Lock.document_lock));
PopplerPage* page = poppler_document_get_page(Zathura.PDF.document, next_page); PopplerPage* page = poppler_document_get_page(Zathura.PDF.document, next_page);
pthread_mutex_unlock(&(Zathura.Lock.document_lock));
if(!page) if(!page)
pthread_exit(NULL); pthread_exit(NULL);
results = poppler_page_find_text(page, search_item); results = poppler_page_find_text(page, search_item);
@ -1061,6 +1089,43 @@ search(void* parameter)
pthread_exit(NULL); pthread_exit(NULL);
} }
void*
watch_file(void* parameter)
{
int blen = sizeof(struct inotify_event);
while(1)
{
/* wait for event */
char buf[blen];
if(read(Zathura.Inotify.fd, buf, blen) < 0)
continue;
/* process event */
struct inotify_event *event = (struct inotify_event*) buf;
if(event->mask & IN_CLOSE_WRITE)
{
/* save old information */
char* path = Zathura.PDF.file ? strdup(Zathura.PDF.file) : NULL;
char* password = Zathura.PDF.password ? strdup(Zathura.PDF.password) : NULL;
int scale = Zathura.PDF.scale;
int page = Zathura.PDF.page_number;
/* reopen and restore settings */
cmd_close(0, NULL);
open_file(path, password);
Zathura.PDF.scale = scale;
draw(page);
gtk_widget_queue_draw(Zathura.UI.drawing_area);
break;
}
}
pthread_exit(NULL);
}
/* shortcut implementation */ /* shortcut implementation */
void void
sc_abort(Argument* argument) sc_abort(Argument* argument)
@ -1260,7 +1325,9 @@ sc_toggle_index(Argument* argument)
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(Zathura.UI.index), gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(Zathura.UI.index),
GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
pthread_mutex_lock(&(Zathura.Lock.document_lock));
index_iter = poppler_index_iter_new(Zathura.PDF.document); index_iter = poppler_index_iter_new(Zathura.PDF.document);
pthread_mutex_unlock(&(Zathura.Lock.document_lock));
if(index_iter) if(index_iter)
{ {
@ -1756,12 +1823,20 @@ cmd_close(int argc, char** argv)
g_free(bookmarks); g_free(bookmarks);
} }
/* inotify */
if(Zathura.Inotify.fd != -1 && Zathura.Inotify.wd != -1)
inotify_rm_watch(Zathura.Inotify.fd, Zathura.Inotify.wd);
Zathura.Inotify.wd = -1;
/*pthread_cancel(Zathura.Thread.inotify_thread);*/
/* reset values */ /* reset values */
free(Zathura.PDF.pages); free(Zathura.PDF.pages);
g_object_unref(Zathura.PDF.document); g_object_unref(Zathura.PDF.document);
Zathura.State.pages = ""; Zathura.State.pages = "";
Zathura.State.filename = (char*) DEFAULT_TEXT; Zathura.State.filename = (char*) DEFAULT_TEXT;
Zathura.PDF.document = NULL; Zathura.PDF.document = NULL;
Zathura.PDF.file = ""; Zathura.PDF.file = "";
Zathura.PDF.password = ""; Zathura.PDF.password = "";
@ -2506,10 +2581,15 @@ cb_destroy(GtkWidget* widget, gpointer data)
pthread_mutex_destroy(&(Zathura.Lock.rotate_lock)); pthread_mutex_destroy(&(Zathura.Lock.rotate_lock));
pthread_mutex_destroy(&(Zathura.Lock.search_lock)); pthread_mutex_destroy(&(Zathura.Lock.search_lock));
pthread_mutex_destroy(&(Zathura.Lock.viewport_lock)); pthread_mutex_destroy(&(Zathura.Lock.viewport_lock));
pthread_mutex_destroy(&(Zathura.Lock.document_lock));
/* clean up other variables */ /* clean up other variables */
g_free(Zathura.Bookmarks.file); g_free(Zathura.Bookmarks.file);
/* inotify */
if(Zathura.Inotify.fd != -1)
close(Zathura.Inotify.fd);
gtk_main_quit(); gtk_main_quit();
return TRUE; return TRUE;
@ -2517,8 +2597,7 @@ cb_destroy(GtkWidget* widget, gpointer data)
gboolean cb_draw(GtkWidget* widget, GdkEventExpose* expose, gpointer data) gboolean cb_draw(GtkWidget* widget, GdkEventExpose* expose, gpointer data)
{ {
/*intptr_t t = (intptr_t) data;*/ int page_id = Zathura.PDF.page_number;
int page_id = Zathura.PDF.page_number; /* (int) t; */
if(page_id < 0 || page_id > Zathura.PDF.number_of_pages) if(page_id < 0 || page_id > Zathura.PDF.number_of_pages)
return FALSE; return FALSE;