Code

gtk-tpdfv: Support relative pathnames as well.
[tpdfview.git] / src / gtk-tpdfv.c
index 771dff99871ebd2f2490207790760175caa684e9..e17a4eb22073f252910f0ee96afe48e2b941b9fa 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))
 
@@ -54,7 +56,9 @@ typedef enum {
 } tpdfv_zoommode_t;
 
 typedef struct {
-       char *filename;
+       gchar *filename;
+
+       time_t mtime;
 
        PopplerDocument *doc;
        PopplerPage     *current_page;
@@ -79,39 +83,84 @@ 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;
 
-       if (strstr(filename, "://"))
-               pdf->filename = strdup(filename);
-       else {
-               size_t len = strlen("file://") + strlen(filename);
-               pdf->filename = (char *)malloc(len + 1);
-               if (pdf->filename) {
-                       *pdf->filename = '\0';
-                       strncat(pdf->filename, "file://", len);
-                       strncat(pdf->filename, filename, len - strlen("file://"));
-               }
-       }
+       struct stat statbuf;
 
-       /* XXX: error reporting mechanism */
+       if ((! pdf) || (! pdf->filename))
+               return;
 
-       if (! pdf->filename) {
+       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 allocate string: %s.\n", errbuf);
-               return FALSE;
+               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)
+{
+       GError *err = NULL;
+
+       char *scheme;
+
+       if ((! pdf) || (! filename))
+               return FALSE;
+
+       scheme = g_uri_parse_scheme(filename);
+       if (scheme)
+               filename += strlen(scheme);
+
+       if (g_path_is_absolute(filename)) {
+               pdf->filename = g_filename_to_uri(filename,
+                               /* hostname = */ NULL, &err);
+       }
+       else {
+               gchar *tmp = g_build_filename(g_get_current_dir(), filename, NULL);
+               pdf->filename = g_filename_to_uri(tmp, /* hostname = */ NULL, &err);
+               g_free(tmp);
+       }
+
+       /* XXX: error reporting mechanism */
+
+       if (! pdf->filename) {
+               if (err)
+                       fprintf(stderr, "Failed to allocate string: %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,
                        pdf->current_page_no);
@@ -120,8 +169,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,10 +181,9 @@ 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);
+       g_free(pdf->filename);
        pdf->filename = NULL;
        return;
 } /* tpdfv_clean */
@@ -150,8 +196,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 +225,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 +240,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);
@@ -228,6 +287,15 @@ gtk_tpdfv_expose(GtkWidget *tpdfv, GdkEventExpose *event)
 
        cairo_translate(cr, x + pdf->delta_x, y + pdf->delta_y);
 
+       /* draw empty white page */
+       cairo_save(cr);
+
+       cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 1.0);
+       cairo_rectangle(cr, 0.0, 0.0, page_width, page_height);
+       cairo_fill(cr);
+
+       cairo_restore(cr);
+
        poppler_page_render(pdf->current_page, cr);
 
        cairo_destroy(cr);
@@ -287,6 +355,41 @@ 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 */
+
+int
+gtk_tpdfv_get_n_pages(GtkWidget *widget)
+{
+       gtk_tpdfv_t *pdf;
+
+       if (! widget)
+               return -1;
+
+       pdf = GTK_TPDFV_GET_PRIVATE(widget);
+       return pdf->total_pages;
+} /* gtk_tpdfv_get_n_pages */
+
+int
+gtk_tpdfv_get_current_page(GtkWidget *widget)
+{
+       gtk_tpdfv_t *pdf;
+
+       if (! widget)
+               return -1;
+
+       pdf = GTK_TPDFV_GET_PRIVATE(widget);
+       return pdf->current_page_no;
+} /* gtk_tpdfv_get_current_page */
+
 void
 gtk_tpdfv_page_up(GtkWidget *widget)
 {
@@ -331,6 +434,20 @@ gtk_tpdfv_last_page(GtkWidget *widget)
        do_redraw(widget);
 } /* gtk_tpdfv_last_page */
 
+void
+gtk_tpdfv_goto_page(GtkWidget *widget, int page)
+{
+       gtk_tpdfv_t *pdf;
+
+       pdf = GTK_TPDFV_GET_PRIVATE(widget);
+
+       if ((page < 0) || (page >= pdf->total_pages))
+               return;
+
+       pdf->current_page_no = page;
+       do_redraw(widget);
+} /* gtk_tpdfv_goto_page */
+
 void
 gtk_tpdfv_zoom_in(GtkWidget *widget)
 {