diff --git a/callbacks.c b/callbacks.c index 526a687..5b29da3 100644 --- a/callbacks.c +++ b/callbacks.c @@ -69,13 +69,8 @@ cb_view_vadjustment_value_changed(GtkAdjustment *adjustment, gpointer data) || ( (begin >= lower) && (end >= upper) && (begin <= upper) ) /* [> begin of the page is in viewport <] */ ) { page->visible = true; - if (page->surface == NULL) { - render_page(zathura->sync.render_thread, page); - } } else { page->visible = false; - cairo_surface_destroy(page->surface); - page->surface = NULL; } free(offset); diff --git a/document.c b/document.c index e2b5572..fb96f4d 100644 --- a/document.c +++ b/document.c @@ -23,6 +23,7 @@ #include "zathura.h" #include "render.h" #include "database.h" +#include "page_view_widget.h" #include #include @@ -432,16 +433,10 @@ zathura_page_get(zathura_document_t* document, unsigned int page_id) if (page != NULL) { page->number = page_id; page->visible = false; - page->event_box = gtk_event_box_new(); - page->drawing_area = gtk_drawing_area_new(); - page->surface = NULL; + page->drawing_area = zathura_page_view_new(page); page->document = document; - g_signal_connect(page->drawing_area, "expose-event", G_CALLBACK(page_expose_event), page); gtk_widget_set_size_request(page->drawing_area, page->width * document->scale, page->height * document->scale); - gtk_container_add(GTK_CONTAINER(page->event_box), page->drawing_area); - - g_static_mutex_init(&(page->lock)); } return page; @@ -459,8 +454,6 @@ zathura_page_free(zathura_page_t* page) return false; } - g_static_mutex_free(&(page->lock)); - return page->document->functions.page_free(page); } diff --git a/document.h b/document.h index 64e205d..00dcc14 100644 --- a/document.h +++ b/document.h @@ -162,10 +162,7 @@ struct zathura_page_s zathura_document_t* document; /**< Document */ void* data; /**< Custom data */ bool visible; /**< Page is visible */ - GtkWidget* event_box; /**< Widget wrapper for mouse events */ GtkWidget* drawing_area; /**< Drawing area */ - GStaticMutex lock; /**< Lock */ - cairo_surface_t* surface; /** Cairo surface */ }; /** diff --git a/page_view_widget.c b/page_view_widget.c new file mode 100644 index 0000000..f72de5a --- /dev/null +++ b/page_view_widget.c @@ -0,0 +1,212 @@ +/* See LICENSE file for license and copyright information */ + +#include "page_view_widget.h" +#include "render.h" +#include +#include +#include + +G_DEFINE_TYPE(ZathuraPageView, zathura_page_view, GTK_TYPE_DRAWING_AREA) + +typedef struct zathura_page_view_private_s { + zathura_page_t* page; + zathura_t* zathura; + cairo_surface_t* surface; /** Cairo surface */ + GStaticMutex lock; /**< Lock */ +} zathura_page_view_private_t; + +#define ZATHURA_PAGE_VIEW_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((obj), ZATHURA_TYPE_PAGE_VIEW, zathura_page_view_private_t)) + +static gboolean zathura_page_view_expose(GtkWidget* widget, GdkEventExpose* event); +static void zathura_page_view_finalize(GObject* object); +static void zathura_page_view_set_property(GObject* object, guint prop_id, const GValue* value, GParamSpec* pspec); +static void zathura_page_view_size_allocate(GtkWidget* widget, GdkRectangle* allocation); + +enum properties_e +{ + PROP_0, + PROP_PAGE +}; + +static void +zathura_page_view_class_init(ZathuraPageViewClass* class) +{ + /* add private members */ + g_type_class_add_private(class, sizeof(zathura_page_view_private_t)); + + /* overwrite methods */ + GtkWidgetClass* widget_class = GTK_WIDGET_CLASS(class); + widget_class->expose_event = zathura_page_view_expose; + widget_class->size_allocate = zathura_page_view_size_allocate; + + GObjectClass* object_class = G_OBJECT_CLASS(class); + object_class->finalize = zathura_page_view_finalize; + object_class->set_property = zathura_page_view_set_property; + + /* add properties */ + g_object_class_install_property(object_class, PROP_PAGE, + g_param_spec_pointer("page", "page", "the page to draw", G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)); +} + +static void +zathura_page_view_init(ZathuraPageView* widget) +{ + zathura_page_view_private_t* priv = ZATHURA_PAGE_VIEW_GET_PRIVATE(widget); + priv->page = NULL; + priv->surface = NULL; + g_static_mutex_init(&(priv->lock)); + + /* we want mouse events */ + gtk_widget_add_events(GTK_WIDGET(widget), + GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK); +} + +GtkWidget* +zathura_page_view_new(zathura_page_t* page) +{ + g_return_val_if_fail(page != NULL, NULL); + + return g_object_new(ZATHURA_TYPE_PAGE_VIEW, "page", page); +} + +static void +zathura_page_view_finalize(GObject* object) +{ + ZathuraPageView* widget = ZATHURA_PAGE_VIEW(object); + zathura_page_view_private_t* priv = ZATHURA_PAGE_VIEW_GET_PRIVATE(widget); + if (priv->surface) { + cairo_surface_destroy(priv->surface); + } + g_static_mutex_free(&(priv->lock)); + + G_OBJECT_CLASS(zathura_page_view_parent_class)->finalize(object); +} + +static void +zathura_page_view_set_property(GObject* object, guint prop_id, const GValue* value, GParamSpec* pspec) +{ + ZathuraPageView* pageview = ZATHURA_PAGE_VIEW(object); + zathura_page_view_private_t* priv = ZATHURA_PAGE_VIEW_GET_PRIVATE(pageview); + + switch (prop_id) { + case PROP_PAGE: + priv->page = g_value_get_pointer(value); + priv->zathura = priv->page->document->zathura; + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + } +} + +static gboolean +zathura_page_view_expose(GtkWidget* widget, GdkEventExpose* event) +{ + cairo_t* cairo = gdk_cairo_create(widget->window); + if (cairo == NULL) { + girara_error("Could not retreive cairo object"); + return FALSE; + } + + /* set clip region */ + cairo_rectangle(cairo, event->area.x, event->area.y, event->area.width, event->area.height); + cairo_clip(cairo); + + zathura_page_view_private_t* priv = ZATHURA_PAGE_VIEW_GET_PRIVATE(widget); + g_static_mutex_lock(&(priv->lock)); + if (priv->surface != NULL) { + cairo_save(cairo); + + unsigned int page_height = widget->allocation.height; + unsigned int page_width = widget->allocation.width; + if (priv->page->document->rotate % 180) { + page_height = widget->allocation.width; + page_width = widget->allocation.height; + } + + girara_info("h %d, w %d", page_height, page_width); + + switch (priv->page->document->rotate) { + case 90: + cairo_translate(cairo, page_width, 0); + break; + case 180: + cairo_translate(cairo, page_width, page_height); + break; + case 270: + cairo_translate(cairo, 0, page_height); + break; + } + + if (priv->page->document->rotate != 0) { + cairo_rotate(cairo, priv->page->document->rotate * G_PI / 180.0); + } + + cairo_set_source_surface(cairo, priv->surface, 0, 0); + cairo_paint(cairo); + + cairo_restore(cairo); + } else { + /* set background color */ + cairo_set_source_rgb(cairo, 255, 255, 255); + cairo_rectangle(cairo, 0, 0, widget->allocation.width, widget->allocation.height); + cairo_fill(cairo); + + bool render_loading = true; + girara_setting_get(priv->zathura->ui.session, "render-loading", &render_loading); + + /* write text */ + if (render_loading == true) { + cairo_set_source_rgb(cairo, 0, 0, 0); + const char* text = "Loading..."; + cairo_select_font_face(cairo, "Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); + cairo_set_font_size(cairo, 16.0); + cairo_text_extents_t extents; + cairo_text_extents(cairo, text, &extents); + double x = widget->allocation.width * 0.5 - (extents.width * 0.5 + extents.x_bearing); + double y = widget->allocation.height * 0.5 - (extents.height * 0.5 + extents.y_bearing); + cairo_move_to(cairo, x, y); + cairo_show_text(cairo, text); + } + + /* render real page */ + render_page(priv->zathura->sync.render_thread, priv->page); + } + cairo_destroy(cairo); + + g_static_mutex_unlock(&(priv->lock)); + return FALSE; +} + +static void +zathura_page_view_redraw_canvas(ZathuraPageView* pageview) +{ + GtkWidget* widget = GTK_WIDGET(pageview); + /* redraw the cairo canvas completely by exposing it */ + /* GdkRegion* region = gdk_drawable_get_clip_region(widget->window); + gdk_window_invalidate_region(widget->window, region, TRUE); + gdk_window_process_updates(widget->window, TRUE); + gdk_region_destroy(region); */ + gtk_widget_queue_draw(widget); +} + +void +zathura_page_view_update_surface(ZathuraPageView* widget, cairo_surface_t* surface) +{ + zathura_page_view_private_t* priv = ZATHURA_PAGE_VIEW_GET_PRIVATE(widget); + g_static_mutex_lock(&(priv->lock)); + if (priv->surface) { + cairo_surface_destroy(priv->surface); + } + priv->surface = surface; + g_static_mutex_unlock(&(priv->lock)); + /* force a redraw here */ + zathura_page_view_redraw_canvas(widget); +} + +static void +zathura_page_view_size_allocate(GtkWidget* widget, GdkRectangle* allocation) +{ + GTK_WIDGET_CLASS(zathura_page_view_parent_class)->size_allocate(widget, allocation); + zathura_page_view_update_surface(ZATHURA_PAGE_VIEW(widget), NULL); +} diff --git a/page_view_widget.h b/page_view_widget.h new file mode 100644 index 0000000..2b1316f --- /dev/null +++ b/page_view_widget.h @@ -0,0 +1,37 @@ +/* See LICENSE file for license and copyright information */ + +#ifndef PAGE_VIEW_WIDGET_H +#define PAGE_VIEW_WIDGET_H + +#include +#include "document.h" + +typedef struct zathura_page_view_s ZathuraPageView; +typedef struct zathura_page_view_class_s ZathuraPageViewClass; + +struct zathura_page_view_s { + GtkDrawingArea parent; +}; + +struct zathura_page_view_class_s { + GtkDrawingAreaClass parent_class; +}; + +#define ZATHURA_TYPE_PAGE_VIEW \ + (zathura_page_view_get_type ()) +#define ZATHURA_PAGE_VIEW(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), ZATHURA_TYPE_PAGE_VIEW, ZathuraPageView)) +#define ZATHURA_PAGE_VIEW_CLASS(obj) \ + (G_TYPE_CHECK_CLASS_CAST ((obj), ZATHURA_PAGE_VIEW, ZathuraPageViewClass)) +#define ZATHURA_IS_PAGE_VIEW(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), ZATHURA_PAGE_VIEW)) +#define ZATHURA_IS_PAGE_VIEW_WDIGET_CLASS(obj) \ + (G_TYPE_CHECK_CLASS_TYPE ((obj), ZATHURA_TYPE_PAGE_VIEW)) +#define ZATHURA_PAGE_VIEW_GET_CLASS \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), ZATHURA_TYPE_PAGE_VIEW, ZathuraPageViewclass)) + +GType zathura_page_view_get_type(void); +GtkWidget* zathura_page_view_new(zathura_page_t* page); +void zathura_page_view_update_surface(ZathuraPageView* widget, cairo_surface_t* surface); + +#endif diff --git a/render.c b/render.c index 7bb88f9..9dc926b 100644 --- a/render.c +++ b/render.c @@ -9,6 +9,7 @@ #include "render.h" #include "zathura.h" #include "document.h" +#include "page_view_widget.h" void* render_job(void* data); bool render(zathura_t* zathura, zathura_page_t* page); @@ -139,7 +140,7 @@ render_free(render_thread_t* render_thread) bool render_page(render_thread_t* render_thread, zathura_page_t* page) { - if (!render_thread || !page || !render_thread->list || page->surface) { + if (!render_thread || !page || !render_thread->list) { return false; } @@ -160,8 +161,8 @@ render(zathura_t* zathura, zathura_page_t* page) return false; } + girara_info("rendering: %d", page->number); gdk_threads_enter(); - g_static_mutex_lock(&(page->lock)); /* create cairo surface */ unsigned int page_width = 0; @@ -171,7 +172,6 @@ render(zathura_t* zathura, zathura_page_t* page) cairo_surface_t* surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24, page_width, page_height); if (surface == NULL) { - g_static_mutex_unlock(&(page->lock)); gdk_threads_leave(); return false; } @@ -180,7 +180,6 @@ render(zathura_t* zathura, zathura_page_t* page) if (cairo == NULL) { cairo_surface_destroy(surface); - g_static_mutex_unlock(&(page->lock)); gdk_threads_leave(); return false; } @@ -199,7 +198,6 @@ render(zathura_t* zathura, zathura_page_t* page) if (zathura_page_render(page, cairo) == false) { cairo_destroy(cairo); cairo_surface_destroy(surface); - g_static_mutex_unlock(&(page->lock)); gdk_threads_leave(); return false; } @@ -243,11 +241,9 @@ render(zathura_t* zathura, zathura_page_t* page) } } - /* draw to gtk widget */ - page->surface = surface; - gtk_widget_queue_draw(page->drawing_area); + /* update the widget */ + zathura_page_view_update_surface(ZATHURA_PAGE_VIEW(page->drawing_area), surface); - g_static_mutex_unlock(&(page->lock)); gdk_threads_leave(); return true; @@ -263,9 +259,6 @@ render_all(zathura_t* zathura) /* unmark all pages */ for (unsigned int page_id = 0; page_id < zathura->document->number_of_pages; page_id++) { zathura_page_t* page = zathura->document->pages[page_id]; - cairo_surface_destroy(page->surface); - page->surface = NULL; - unsigned int page_height = 0, page_width = 0; page_calc_height_width(page, &page_height, &page_width, true); @@ -273,89 +266,3 @@ render_all(zathura_t* zathura) gtk_widget_queue_resize(page->drawing_area); } } - -gboolean -page_expose_event(GtkWidget* UNUSED(widget), GdkEventExpose* UNUSED(event), - gpointer data) -{ - zathura_page_t* page = data; - if (page == NULL) { - return FALSE; - } - - g_static_mutex_lock(&(page->lock)); - - cairo_t* cairo = gdk_cairo_create(page->drawing_area->window); - - if (cairo == NULL) { - girara_error("Could not retreive cairo object"); - g_static_mutex_unlock(&(page->lock)); - return FALSE; - } - - unsigned int page_height = 0, page_width = 0; - page_calc_height_width(page, &page_height, &page_width, true); - - if (page->surface != NULL) { - cairo_save(cairo); - - switch (page->document->rotate) { - case 90: - cairo_translate(cairo, page_width, 0); - break; - case 180: - cairo_translate(cairo, page_width, page_height); - break; - case 270: - cairo_translate(cairo, 0, page_height); - break; - } - - if (page->document->rotate != 0) { - cairo_rotate(cairo, page->document->rotate * G_PI / 180.0); - } - - cairo_set_source_surface(cairo, page->surface, 0, 0); - cairo_paint(cairo); - - cairo_restore(cairo); - } else { - /* set background color */ - cairo_set_source_rgb(cairo, 255, 255, 255); - cairo_rectangle(cairo, 0, 0, page_width, page->height * page->height); - cairo_fill(cairo); - - bool render_loading = true; - if (page->document != NULL && page->document->zathura != NULL && - page->document->zathura->ui.session != NULL) { - girara_setting_get(page->document->zathura->ui.session, "render-loading", &render_loading); - } - - /* write text */ - if (render_loading == true) { - cairo_set_source_rgb(cairo, 0, 0, 0); - const char* text = "Loading..."; - cairo_select_font_face(cairo, "Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); - cairo_set_font_size(cairo, 16.0); - cairo_text_extents_t extents; - cairo_text_extents(cairo, text, &extents); - double x = page_width * 0.5 - (extents.width * 0.5 + extents.x_bearing); - double y = page_height * 0.5 - (extents.height * 0.5 + extents.y_bearing); - cairo_move_to(cairo, x, y); - cairo_show_text(cairo, text); - } - - /* render real page */ - render_page(page->document->zathura->sync.render_thread, page); - - /* update statusbar */ - } - cairo_destroy(cairo); - - page->document->current_page_number = page->number; - statusbar_page_number_update(page->document->zathura); - - g_static_mutex_unlock(&(page->lock)); - - return TRUE; -} diff --git a/utils.c b/utils.c index 01406e9..cdd9909 100644 --- a/utils.c +++ b/utils.c @@ -194,7 +194,7 @@ page_calculate_offset(zathura_page_t* page) zathura_document_t* document = page->document; zathura_t* zathura = document->zathura; - if (gtk_widget_translate_coordinates(page->event_box, zathura->ui.page_view, 0, 0, &(offset->x), &(offset->y)) == false) { + if (gtk_widget_translate_coordinates(page->drawing_area, zathura->ui.page_view, 0, 0, &(offset->x), &(offset->y)) == false) { free(offset); return NULL; } diff --git a/zathura.c b/zathura.c index f681658..08765cd 100644 --- a/zathura.c +++ b/zathura.c @@ -438,7 +438,7 @@ document_open(zathura_t* zathura, const char* path, const char* password) /* create blank pages */ for (unsigned int page_id = 0; page_id < document->number_of_pages; page_id++) { zathura_page_t* page = document->pages[page_id]; - gtk_widget_realize(page->event_box); + gtk_widget_realize(page->drawing_area); } /* bookmarks */ @@ -624,7 +624,7 @@ page_view_set_mode(zathura_t* zathura, unsigned int pages_per_row) { int x = i % pages_per_row; int y = i / pages_per_row; - gtk_table_attach(GTK_TABLE(zathura->ui.page_view), zathura->document->pages[i]->event_box, x, x + 1, y, y + 1, GTK_SHRINK, GTK_SHRINK, 0, 0); + gtk_table_attach(GTK_TABLE(zathura->ui.page_view), zathura->document->pages[i]->drawing_area, x, x + 1, y, y + 1, GTK_SHRINK, GTK_SHRINK, 0, 0); } gtk_widget_show_all(zathura->ui.page_view);