Code

gtk-tpdfv: Auto-reload the PDF on expose if the file has changed.
[tpdfview.git] / src / gtk-tpdfv.c
index 771dff99871ebd2f2490207790760175caa684e9..cba2e1f2a1c13697e384cb8d1eeab7e62c0547e8 100644 (file)
@@ -43,6 +43,8 @@
 #include <stdlib.h>
 #include <string.h>
 
+#include <sys/stat.h>
+
 #define TPDFV_MIN(a, b) ((a) <= (b) ? (a) : (b))
 #define TPDFV_MAX(a, b) ((a) >= (b) ? (a) : (b))
 
@@ -56,6 +58,8 @@ typedef enum {
 typedef struct {
        char *filename;
 
+       time_t mtime;
+
        PopplerDocument *doc;
        PopplerPage     *current_page;
 
@@ -79,11 +83,52 @@ G_DEFINE_TYPE(GtkTPDFV, gtk_tpdfv, GTK_TYPE_DRAWING_AREA);
  * Private helper functions.
  */
 
-static gboolean
-tpdfv_init(gtk_tpdfv_t *pdf, const char *filename)
+static void
+tpdfv_open(gtk_tpdfv_t *pdf)
 {
        GError *err = NULL;
 
+       struct stat statbuf;
+
+       if ((! pdf) || (! pdf->filename))
+               return;
+
+       memset(&statbuf, 0, sizeof(statbuf));
+       if (stat(pdf->filename + strlen("file://"), &statbuf) != 0) {
+               char errbuf[1024];
+               strerror_r(errno, errbuf, sizeof(errbuf));
+               fprintf(stderr, "Failed to access PDF: %s.\n", errbuf);
+               return;
+       }
+
+       pdf->mtime = statbuf.st_mtime;
+
+       pdf->doc = poppler_document_new_from_file(pdf->filename,
+                       /* password = */ NULL, &err);
+       if (! pdf->doc) {
+               fprintf(stderr, "Failed to open PDF: %s.\n", err->message);
+               return;
+       }
+
+       pdf->total_pages = poppler_document_get_n_pages(pdf->doc);
+       if (pdf->current_page_no >= pdf->total_pages)
+               pdf->current_page_no = pdf->total_pages - 1;
+} /* tpdfv_open */
+
+static void
+tpdfv_close(gtk_tpdfv_t *pdf)
+{
+       if (! pdf)
+               return;
+
+       g_object_unref(pdf->doc);
+       pdf->doc = NULL;
+       pdf->current_page = NULL;
+} /* tpdfv_close */
+
+static gboolean
+tpdfv_init(gtk_tpdfv_t *pdf, const char *filename)
+{
        if (strstr(filename, "://"))
                pdf->filename = strdup(filename);
        else {
@@ -105,12 +150,8 @@ tpdfv_init(gtk_tpdfv_t *pdf, const char *filename)
                return FALSE;
        }
 
-       pdf->doc = poppler_document_new_from_file(pdf->filename,
-                       /* password = */ NULL, &err);
-       if (! pdf->doc) {
-               fprintf(stderr, "Failed to open PDF: %s.\n", err->message);
-               return FALSE;
-       }
+       pdf->doc = NULL;
+       tpdfv_open(pdf);
 
        pdf->current_page_no = 0;
        pdf->current_page = poppler_document_get_page(pdf->doc,
@@ -120,8 +161,6 @@ tpdfv_init(gtk_tpdfv_t *pdf, const char *filename)
                return FALSE;
        }
 
-       pdf->total_pages = poppler_document_get_n_pages(pdf->doc);
-
        pdf->zoom_mode   = TPDFV_ZOOM_CUSTOM;
        pdf->zoom_factor = 1.0;
        pdf->delta_x = pdf->delta_y = 0.0;
@@ -134,8 +173,7 @@ tpdfv_clean(gtk_tpdfv_t *pdf)
        if (! pdf)
                return;
 
-       g_object_unref(pdf->doc);
-       pdf->doc          = NULL;
+       tpdfv_close(pdf);
        pdf->current_page = NULL;
        free(pdf->filename);
        pdf->filename = NULL;
@@ -150,8 +188,8 @@ do_redraw(GtkWidget *widget)
 
        pdf = GTK_TPDFV_GET_PRIVATE(widget);
 
-       if (poppler_page_get_index(pdf->current_page)
-                       != pdf->current_page_no) {
+       if ((! pdf->current_page) || (poppler_page_get_index(pdf->current_page)
+                       != pdf->current_page_no)) {
                pdf->current_page = poppler_document_get_page(pdf->doc,
                pdf->current_page_no);
 
@@ -179,6 +217,8 @@ gtk_tpdfv_expose(GtkWidget *tpdfv, GdkEventExpose *event)
        gtk_tpdfv_t *pdf;
        cairo_t *cr;
 
+       struct stat statbuf;
+
        gdouble width, height;
 
        gdouble page_width  = 0.0;
@@ -192,6 +232,17 @@ gtk_tpdfv_expose(GtkWidget *tpdfv, GdkEventExpose *event)
        if (! pdf)
                return FALSE;
 
+       memset(&statbuf, 0, sizeof(statbuf));
+       if (stat(pdf->filename + strlen("file://"), &statbuf)) {
+               char errbuf[1024];
+               strerror_r(errno, errbuf, sizeof(errbuf));
+               fprintf(stderr, "Failed to access PDF: %s.\n", errbuf);
+               return FALSE;
+       }
+
+       if (statbuf.st_mtime > pdf->mtime)
+               gtk_tpdfv_reload(tpdfv);
+
        cr = gdk_cairo_create(tpdfv->window);
        cairo_rectangle(cr, event->area.x, event->area.y,
                        event->area.width, event->area.height);
@@ -287,6 +338,17 @@ gtk_tpdfv_new(const char *filename)
        return GTK_WIDGET(tpdfv);
 } /* gtk_tpdfv_new */
 
+void
+gtk_tpdfv_reload(GtkWidget *widget)
+{
+       gtk_tpdfv_t *pdf;
+
+       pdf = GTK_TPDFV_GET_PRIVATE(widget);
+       tpdfv_close(pdf);
+       tpdfv_open(pdf);
+       do_redraw(widget);
+} /* gtk_tpdfv_reload */
+
 void
 gtk_tpdfv_page_up(GtkWidget *widget)
 {