Implement rendering of signature information

This commit is contained in:
Sebastian Ramacher 2023-12-08 17:47:20 +01:00
parent 946e865cc6
commit 8d0b292027
4 changed files with 342 additions and 196 deletions

View file

@ -194,9 +194,22 @@ cb_window_statbusbar_changed(girara_session_t* session, const char* name,
}
}
void
config_load_default(zathura_t* zathura)
{
static void cb_show_signature_info(girara_session_t* session, const char* UNUSED(name),
girara_setting_type_t UNUSED(type), const void* value, void* UNUSED(data)) {
g_return_if_fail(value != NULL);
g_return_if_fail(session != NULL);
g_return_if_fail(session->global.data != NULL);
zathura_t* zathura = session->global.data;
if (zathura->document == NULL) {
return;
}
zathura_show_signature_information(zathura, *(const bool*)value);
update_visible_pages(zathura);
}
void config_load_default(zathura_t* zathura) {
if (zathura == NULL || zathura->ui.session == NULL) {
return;
}
@ -363,6 +376,10 @@ config_load_default(zathura_t* zathura)
/* default to no sandbox when running in WSL */
const char* string_value = running_under_wsl() ? "none" : "normal";
girara_setting_add(gsession, "sandbox", string_value, STRING, true, _("Sandbox level"), cb_sandbox_changed, NULL);
bool_value = false;
girara_setting_add(gsession, "show-signature-information", &bool_value, BOOLEAN, false,
_("Disable additional information for signatures embedded in the document."),
cb_show_signature_info, NULL);
#define DEFAULT_SHORTCUTS(mode) \
girara_shortcut_add(gsession, 0, GDK_KEY_a, NULL, sc_adjust_window, (mode), ZATHURA_ADJUST_BESTFIT, NULL); \
@ -459,17 +476,21 @@ config_load_default(zathura_t* zathura)
girara_mouse_event_add(gsession, 0, 0, sc_mouse_scroll, (mode), GIRARA_EVENT_SCROLL_DOWN, DOWN, NULL); \
girara_mouse_event_add(gsession, 0, 0, sc_mouse_scroll, (mode), GIRARA_EVENT_SCROLL_LEFT, LEFT, NULL); \
girara_mouse_event_add(gsession, 0, 0, sc_mouse_scroll, (mode), GIRARA_EVENT_SCROLL_RIGHT, RIGHT, NULL); \
girara_mouse_event_add(gsession, 0, 0, sc_mouse_scroll, (mode), GIRARA_EVENT_SCROLL_BIDIRECTIONAL, BIDIRECTIONAL, NULL); \
girara_mouse_event_add(gsession, 0, 0, sc_mouse_scroll, (mode), GIRARA_EVENT_SCROLL_BIDIRECTIONAL, BIDIRECTIONAL, \
NULL); \
\
girara_mouse_event_add(gsession, GDK_SHIFT_MASK, 0, sc_mouse_scroll, (mode), GIRARA_EVENT_SCROLL_UP, LEFT, NULL); \
girara_mouse_event_add(gsession, GDK_SHIFT_MASK, 0, sc_mouse_scroll, (mode), GIRARA_EVENT_SCROLL_DOWN, RIGHT, NULL); \
\
girara_mouse_event_add(gsession, GDK_CONTROL_MASK, 0, sc_mouse_zoom, (mode), GIRARA_EVENT_SCROLL_UP, UP, NULL); \
girara_mouse_event_add(gsession, GDK_CONTROL_MASK, 0, sc_mouse_zoom, (mode), GIRARA_EVENT_SCROLL_DOWN, DOWN, NULL); \
girara_mouse_event_add(gsession, GDK_CONTROL_MASK, 0, sc_mouse_zoom, (mode), GIRARA_EVENT_SCROLL_BIDIRECTIONAL, BIDIRECTIONAL, NULL); \
girara_mouse_event_add(gsession, 0, GIRARA_MOUSE_BUTTON2, sc_mouse_scroll, (mode), GIRARA_EVENT_BUTTON_PRESS, 0, NULL); \
girara_mouse_event_add(gsession, GDK_BUTTON2_MASK, GIRARA_MOUSE_BUTTON2, sc_mouse_scroll, (mode), GIRARA_EVENT_BUTTON_RELEASE, 0, NULL); \
girara_mouse_event_add(gsession, GDK_BUTTON2_MASK, 0, sc_mouse_scroll, (mode), GIRARA_EVENT_MOTION_NOTIFY, 0, NULL); \
girara_mouse_event_add(gsession, GDK_CONTROL_MASK, 0, sc_mouse_zoom, (mode), GIRARA_EVENT_SCROLL_BIDIRECTIONAL, \
BIDIRECTIONAL, NULL); \
girara_mouse_event_add(gsession, 0, GIRARA_MOUSE_BUTTON2, sc_mouse_scroll, (mode), GIRARA_EVENT_BUTTON_PRESS, 0, \
NULL); \
girara_mouse_event_add(gsession, GDK_BUTTON2_MASK, GIRARA_MOUSE_BUTTON2, sc_mouse_scroll, (mode), \
GIRARA_EVENT_BUTTON_RELEASE, 0, NULL); \
girara_mouse_event_add(gsession, GDK_BUTTON2_MASK, 0, sc_mouse_scroll, (mode), GIRARA_EVENT_MOTION_NOTIFY, 0, NULL);
/* Define mode-less shortcuts
* girara adds them only for normal mode, so passing 0 as mode is currently

View file

@ -58,6 +58,12 @@ typedef struct zathura_page_widget_private_s {
zathura_rectangle_t bounds; /**< Highlight bounds */
gboolean draw; /**< Draw highlighted region */
} highlighter;
struct {
girara_list_t* list; /**< List of signatures on the page */
gboolean retrieved; /**< True if we already tried to retrieve the list of signatures */
gboolean draw; /**< True if links should be drawn */
} signatures;
} ZathuraPagePrivate;
G_DEFINE_TYPE_WITH_CODE(ZathuraPage, zathura_page_widget, GTK_TYPE_DRAWING_AREA, G_ADD_PRIVATE(ZathuraPage))
@ -97,6 +103,7 @@ enum properties_e {
PROP_SEARCH_RESULTS_CURRENT,
PROP_DRAW_SEARCH_RESULTS,
PROP_LAST_VIEW,
PROP_DRAW_SIGNATURES,
};
enum {
@ -148,6 +155,10 @@ zathura_page_widget_class_init(ZathuraPageClass* class)
g_param_spec_int("search-length", "search-length", "The number of search results", -1, INT_MAX, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property(object_class, PROP_DRAW_SEARCH_RESULTS,
g_param_spec_boolean("draw-search-results", "draw-search-results", "Set to true if search results should be drawn", FALSE, G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property(object_class, PROP_DRAW_SIGNATURES,
g_param_spec_boolean("draw-signatures", "draw-signatures",
"Set to true if signatures should be drawn", FALSE,
G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
/* add signals */
signals[TEXT_SELECTED] = g_signal_new("text-selected",
@ -244,8 +255,12 @@ zathura_page_widget_init(ZathuraPage* widget)
priv->highlighter.bounds.y2 = -1;
priv->highlighter.draw = false;
const unsigned int event_mask = GDK_BUTTON_PRESS_MASK |
GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK | GDK_LEAVE_NOTIFY_MASK;
priv->signatures.list = NULL;
priv->signatures.retrieved = false;
priv->signatures.draw = false;
const unsigned int event_mask =
GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK | GDK_LEAVE_NOTIFY_MASK;
gtk_widget_add_events(GTK_WIDGET(widget), event_mask);
}
@ -384,9 +399,7 @@ get_text_extents(const char* string, zathura_t* zathura, cairo_font_weight_t wei
return text;
}
static void
zathura_page_widget_set_property(GObject* object, guint prop_id, const GValue* value, GParamSpec* pspec)
{
static void zathura_page_widget_set_property(GObject* object, guint prop_id, const GValue* value, GParamSpec* pspec) {
ZathuraPage* pageview = ZATHURA_PAGE(object);
ZathuraPagePrivate* priv = zathura_page_widget_get_instance_private(pageview);
@ -412,7 +425,8 @@ zathura_page_widget_set_property(GObject* object, guint prop_id, const GValue* v
/* get size of text that should be large enough for every link hint */
text = get_text_extents("888", priv->zathura, CAIRO_FONT_WEIGHT_BOLD);
GIRARA_LIST_FOREACH_BODY(priv->links.list, zathura_link_t*, link,
for (size_t idx = 0; idx != girara_list_size(priv->links.list); ++idx) {
zathura_link_t* link = girara_list_nth(priv->links.list, idx);
if (link != NULL) {
/* redraw link area */
zathura_rectangle_t rectangle = recalc_rectangle(priv->page, zathura_link_get_position(link));
@ -423,7 +437,7 @@ zathura_page_widget_set_property(GObject* object, guint prop_id, const GValue* v
rectangle.y1 = rectangle.y2 - text.height;
redraw_rect(pageview, &rectangle);
}
);
}
}
break;
case PROP_LINKS_OFFSET:
@ -475,6 +489,26 @@ zathura_page_widget_set_property(GObject* object, guint prop_id, const GValue* v
gtk_widget_queue_draw(GTK_WIDGET(object));
}
break;
case PROP_DRAW_SIGNATURES:
priv->signatures.draw = g_value_get_boolean(value);
/* get links */
if (priv->signatures.draw == TRUE && priv->signatures.retrieved == FALSE) {
priv->signatures.list = zathura_page_get_signatures(priv->page, NULL);
priv->signatures.retrieved = TRUE;
}
if (priv->signatures.retrieved == TRUE && priv->signatures.list != NULL) {
for (size_t idx = 0; idx != girara_list_size(priv->signatures.list); ++idx) {
zathura_signature_info_t* signature = girara_list_nth(priv->signatures.list, idx);
if (signature == NULL) {
continue;
}
/* redraw signature area */
zathura_rectangle_t rectangle = recalc_rectangle(priv->page, signature->position);
redraw_rect(pageview, &rectangle);
}
}
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
}
@ -523,9 +557,7 @@ get_safe_device_factors(cairo_surface_t* surface)
return factors;
}
static gboolean
zathura_page_widget_draw(GtkWidget* widget, cairo_t* cairo)
{
static gboolean zathura_page_widget_draw(GtkWidget* widget, cairo_t* cairo) {
ZathuraPage* page = ZATHURA_PAGE(widget);
ZathuraPagePrivate* priv = zathura_page_widget_get_instance_private(page);
zathura_t* zathura = priv->zathura;
@ -637,6 +669,70 @@ zathura_page_widget_draw(GtkWidget* widget, cairo_t* cairo)
}
}
/* draw signatures */
if (priv->signatures.draw == true && priv->signatures.list != NULL) {
for (size_t idx = 0; idx != girara_list_size(priv->signatures.list); ++idx) {
zathura_signature_info_t* signature = girara_list_nth(priv->signatures.list, idx);
if (signature == NULL) {
continue;
}
GdkRGBA color;
char* text = NULL;
bool free_text = false;
switch (signature->state) {
case ZATHURA_SIGNATURE_VALID: {
color = zathura->ui.colors.signature_success;
char* sig_time = g_date_time_format(signature->time, "%F %T");
text = g_strdup_printf(_("Signature is valid.\nThis document is signed by\n %s\non %s."), signature->signer,
sig_time);
free_text = true;
g_free(sig_time);
break;
}
case ZATHURA_SIGNATURE_CERTIFICATE_EXPIRED:
color = zathura->ui.colors.signature_warning;
text = _("Signature certificate is expired.");
break;
case ZATHURA_SIGNATURE_CERTIFICATE_REVOKED:
color = zathura->ui.colors.signature_error;
text = _("Signature certificate is revoked.");
break;
case ZATHURA_SIGNATURE_CERTIFICATE_UNTRUSTED:
color = zathura->ui.colors.signature_error;
text = _("Signature certificate is not trusted.");
break;
case ZATHURA_SIGNATURE_CERTIFICATE_INVALID:
color = zathura->ui.colors.signature_error;
text = _("Signature certificate is invalid.");
break;
default:
color = zathura->ui.colors.signature_error;
text = _("Signature is invalid.");
}
/* draw position */
zathura_rectangle_t rectangle = recalc_rectangle(priv->page, signature->position);
cairo_set_source_rgba(cairo, color.red, color.green, color.blue, color.alpha);
cairo_rectangle(cairo, rectangle.x1, rectangle.y1, (rectangle.x2 - rectangle.x1),
(rectangle.y2 - rectangle.y1));
cairo_fill(cairo);
/* draw text */
const GdkRGBA color_fg = zathura->ui.colors.highlight_color_fg;
cairo_set_source_rgba(cairo, color_fg.red, color_fg.green, color_fg.blue, transparency);
cairo_text_extents_t extents;
cairo_text_extents(cairo, text, &extents);
cairo_move_to(cairo, rectangle.x1 + 1, rectangle.y1 + extents.height + 1);
cairo_show_text(cairo, text);
if (free_text == true) {
g_free(text);
}
}
}
/* draw search results */
if (priv->search.list != NULL && priv->search.draw == true) {
int idx = 0;

View file

@ -1349,6 +1349,9 @@ document_open(zathura_t* zathura, const char* path, const char* uri, const char*
position_set(zathura, file_info.position_x, file_info.position_y);
}
bool show_signature_information = false;
girara_setting_get(zathura->ui.session, "show-signature-information", &show_signature_information);
zathura_show_signature_information(zathura, show_signature_information);
update_visible_pages(zathura);
return true;
@ -1896,3 +1899,21 @@ zathura_signal_sigterm(gpointer data)
return TRUE;
}
#endif
void zathura_show_signature_information(zathura_t* zathura, bool show) {
if (zathura->document == NULL) {
return;
}
GValue show_sig_info_value = {0};
g_value_init(&show_sig_info_value, G_TYPE_BOOLEAN);
g_value_set_boolean(&show_sig_info_value, show);
const unsigned int number_of_pages = zathura_document_get_number_of_pages(zathura->document);
for (unsigned int page = 0; page != number_of_pages; ++page) {
// draw signature info
g_object_set_property(G_OBJECT(zathura->pages[page]), "draw-signatures", &show_sig_info_value);
}
g_value_unset(&show_sig_info_value);
}

View file

@ -455,4 +455,12 @@ void statusbar_page_number_update(zathura_t* zathura);
*/
char* get_formatted_filename(zathura_t* zathura, bool statusbar);
/**
* Show additional signature information
*
* @param zathura The zathura session
* @param show Whether to show the signature information
*/
void zathura_show_signature_information(zathura_t* zathura, bool show);
#endif // ZATHURA_H