From b5d0b28bb9a061740edd9640d9f8f87163b20b44 Mon Sep 17 00:00:00 2001 From: Jeremie Knuesel Date: Mon, 22 Jan 2018 22:51:36 +0100 Subject: [PATCH] Implement support for HiDPI displays --- zathura/callbacks.c | 22 ++++++++++++++++++++++ zathura/callbacks.h | 15 +++++++++++++++ zathura/document.c | 24 ++++++++++++++++++++++++ zathura/document.h | 19 +++++++++++++++++++ zathura/render.c | 16 ++++++++++++++++ zathura/zathura.c | 3 +++ 6 files changed, 99 insertions(+) diff --git a/zathura/callbacks.c b/zathura/callbacks.c index 7db22f8..c768195 100644 --- a/zathura/callbacks.c +++ b/zathura/callbacks.c @@ -216,6 +216,28 @@ cb_refresh_view(GtkWidget* GIRARA_UNUSED(view), gpointer data) statusbar_page_number_update(zathura); } +gboolean +cb_window_configure(GtkWidget* widget, GdkEventConfigure* UNUSED(configure), zathura_t* zathura) +{ + if (widget == NULL || zathura == NULL || zathura->document == NULL) { + return false; + } + + int new_factor = gtk_widget_get_scale_factor(widget); + + double current_x; + double current_y; + zathura_document_get_device_scale(zathura->document, ¤t_x, ¤t_y); + + if (new_factor != current_x || new_factor != current_y) { + zathura_document_set_device_scale(zathura->document, new_factor, new_factor); + girara_debug("New device scale: %d", new_factor); + render_all(zathura); + } + + return false; +} + void cb_page_layout_value_changed(girara_session_t* session, const char* name, girara_setting_type_t UNUSED(type), void* value, void* UNUSED(data)) { diff --git a/zathura/callbacks.h b/zathura/callbacks.h index 15e4ba1..8ef65b8 100644 --- a/zathura/callbacks.h +++ b/zathura/callbacks.h @@ -79,6 +79,21 @@ void cb_view_vadjustment_changed(GtkAdjustment *adjustment, gpointer data); */ void cb_refresh_view(GtkWidget* view, gpointer data); +/** + * This function gets called when the main window is reconfigured, i.e. when + * its size, position or stacking order has changed, or when the device scale + * factor has changed (e.g. when moving from a regular to a HiDPI screen). + * + * It checks if the device scale factor has changed and if yes, records the new + * value and triggers a re-rendering of the document. + * + * @param widget The main window GtkWidget + * @param configure The GDK configure event + * @param zathura The zathura instance + */ +gboolean cb_window_configure(GtkWidget* widget, GdkEventConfigure* configure, + zathura_t* zathura); + /** * This function gets called when the value of the "pages-per-row" * variable changes diff --git a/zathura/document.c b/zathura/document.c index cddb00d..055a4d6 100644 --- a/zathura/document.c +++ b/zathura/document.c @@ -36,6 +36,8 @@ struct zathura_document_s { double cell_height; /**< height of a page cell in the document (not ransformed by scale and rotation) */ unsigned int view_width; /**< width of current viewport */ unsigned int view_height; /**< height of current viewport */ + double device_scale_x; /**< x scale factor (for e.g. HiDPI) */ + double device_scale_y; /**< y scale factor (for e.g. HiDPI) */ unsigned int pages_per_row; /**< number of pages in a row */ unsigned int first_page_column; /**< column of the first page */ unsigned int page_padding; /**< padding between pages */ @@ -132,6 +134,8 @@ zathura_document_open(zathura_t* zathura, const char* path, const char* uri, document->cell_height = 0.0; document->view_height = 0; document->view_width = 0; + document->device_scale_x = 0.0; + document->device_scale_y = 0.0; document->position_x = 0.0; document->position_y = 0.0; @@ -500,6 +504,26 @@ zathura_document_get_viewport_size(zathura_document_t* document, *width = document->view_width; } +void +zathura_document_set_device_scale(zathura_document_t* document, + double x_factor, double y_factor) +{ + if (document == NULL) { + return; + } + document->device_scale_x = x_factor; + document->device_scale_y = y_factor; +} + +void +zathura_document_get_device_scale(zathura_document_t* document, + double *x_factor, double* y_factor) +{ + g_return_if_fail(document != NULL && x_factor != NULL && y_factor != NULL); + *x_factor = document->device_scale_x; + *y_factor = document->device_scale_y; +} + void zathura_document_get_cell_size(zathura_document_t* document, unsigned int* height, unsigned int* width) diff --git a/zathura/document.h b/zathura/document.h index 3118f30..b49e865 100644 --- a/zathura/document.h +++ b/zathura/document.h @@ -249,6 +249,25 @@ void zathura_document_get_viewport_size(zathura_document_t* document, unsigned int *height, unsigned int* width); +/** + * Set the device scale factors (e.g. for HiDPI). These are generally integers + * and equal for x and y. These scaling factors are only used when rendering to + * the screen. + * + * @param[in] x_factor,yfactor The x and y scale factors + */ +void +zathura_document_set_device_scale(zathura_document_t* document, + double x_factor, double y_factor); +/** + * Return the current device scale factors. + * + * @param[out] x_factor,yfactor The x and y scale factors + */ +void +zathura_document_get_device_scale(zathura_document_t* document, + double *x_factor, double* y_factor); + /** * Return the size of a cell from the document's layout table in pixels. Assumes * that the table is homogeneous (i.e. every cell has the same dimensions). It diff --git a/zathura/render.c b/zathura/render.c index 51967a8..727d357 100644 --- a/zathura/render.c +++ b/zathura/render.c @@ -740,6 +740,14 @@ render(render_job_t* job, ZathuraRenderRequest* request, ZathuraRenderer* render &page_height, &page_width, false); + double device_scale_x; + double device_scale_y; + zathura_document_get_device_scale(document, &device_scale_x, &device_scale_y); + + if (device_scale_x != 0.0 && device_scale_y != 0.0) { + page_width *= device_scale_x; + page_height *= device_scale_y; + } cairo_surface_t* surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24, page_width, page_height); @@ -751,6 +759,14 @@ render(render_job_t* job, ZathuraRenderRequest* request, ZathuraRenderer* render return false; } + if (device_scale_x != 0.0 && device_scale_y != 0.0) { + cairo_surface_set_device_scale(surface, device_scale_x, device_scale_y); + if (cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS) { + cairo_surface_destroy(surface); + return false; + } + } + cairo_t* cairo = cairo_create(surface); if (cairo == NULL) { cairo_surface_destroy(surface); diff --git a/zathura/zathura.c b/zathura/zathura.c index 938aed3..250dcaa 100644 --- a/zathura/zathura.c +++ b/zathura/zathura.c @@ -153,6 +153,9 @@ init_ui(zathura_t* zathura) g_signal_connect(G_OBJECT(zathura->ui.session->gtk.view), "refresh-view", G_CALLBACK(cb_refresh_view), zathura); + g_signal_connect(G_OBJECT(zathura->ui.session->gtk.window), "configure-event", + G_CALLBACK(cb_window_configure), zathura); + /* page view */ zathura->ui.page_widget = gtk_grid_new(); gtk_grid_set_row_homogeneous(GTK_GRID(zathura->ui.page_widget), TRUE);