mirror of
https://git.pwmt.org/pwmt/zathura.git
synced 2024-11-10 20:33:46 +01:00
Create a page view widget (Closes: #90).
Add a widget derived from GtkDrawingArea that handles the drawing. It automaticaly requests rerendering of the page if necessary (i.e on a scroll and rotate). This should solve all the rendering issues.
This commit is contained in:
parent
3df59895cd
commit
a1cdb48921
@ -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);
|
||||
|
11
document.c
11
document.c
@ -23,6 +23,7 @@
|
||||
#include "zathura.h"
|
||||
#include "render.h"
|
||||
#include "database.h"
|
||||
#include "page_view_widget.h"
|
||||
|
||||
#include <girara/datastructures.h>
|
||||
#include <girara/utils.h>
|
||||
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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 */
|
||||
};
|
||||
|
||||
/**
|
||||
|
212
page_view_widget.c
Normal file
212
page_view_widget.c
Normal file
@ -0,0 +1,212 @@
|
||||
/* See LICENSE file for license and copyright information */
|
||||
|
||||
#include "page_view_widget.h"
|
||||
#include "render.h"
|
||||
#include <girara/macros.h>
|
||||
#include <girara/utils.h>
|
||||
#include <girara/settings.h>
|
||||
|
||||
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);
|
||||
}
|
37
page_view_widget.h
Normal file
37
page_view_widget.h
Normal file
@ -0,0 +1,37 @@
|
||||
/* See LICENSE file for license and copyright information */
|
||||
|
||||
#ifndef PAGE_VIEW_WIDGET_H
|
||||
#define PAGE_VIEW_WIDGET_H
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#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
|
103
render.c
103
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;
|
||||
}
|
||||
|
2
utils.c
2
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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user