zathura/utils.c
Abdo Roig-Maranges 030a8c65c1 add functions to compute page positions
The plan is to put in adjustment.c every piece of code that has to do
with document positioning, either computing it from data on the document
side, or talking to GTK.

We want to have at our disposal functions to compute sizes and positions
without having to ask for it to a GTK widget. The new functions are:

 - move page_calc_height_width to adjustment.c

 - add page_calc_position that rotates a position relative to a page
   according to the rotation settings.

 - add position_to_page_number that computes the number of a page
   sitting at a given position (given in document-relative coordinates)

 - add page_number_to_position that computes the position (in document
   relative coordinates) that will be placed at the center of the viewport.

 - add page_is_visible that checks whether the given page intersects the
   viewport.
2013-10-26 17:13:55 +02:00

374 lines
8.9 KiB
C

/* See LICENSE file for license and copyright information */
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <math.h>
#include <gtk/gtk.h>
#include <girara/session.h>
#include <girara/utils.h>
#include <girara/settings.h>
#include <glib/gi18n.h>
#include "links.h"
#include "utils.h"
#include "zathura.h"
#include "internal.h"
#include "document.h"
#include "page.h"
#include "plugin.h"
#include <girara/datastructures.h>
#define BLOCK_SIZE 64
const char*
file_get_extension(const char* path)
{
if (path == NULL) {
return NULL;
}
const char* res = strrchr(path, '.');
if (res == NULL) {
return NULL;
}
return res + 1;
}
bool
file_valid_extension(zathura_t* zathura, const char* path)
{
if (zathura == NULL || path == NULL || zathura->plugins.manager == NULL) {
return false;
}
const gchar* content_type = g_content_type_guess(path, NULL, 0, NULL);
if (content_type == NULL) {
return false;
}
zathura_plugin_t* plugin = zathura_plugin_manager_get_plugin(zathura->plugins.manager, content_type);
g_free((void*)content_type);
return (plugin == NULL) ? false : true;
}
bool
execute_command(char* const argv[], char** output)
{
if (!output) {
return false;
}
int p[2];
if (pipe(p)) {
return -1;
}
pid_t pid = fork();
if (pid == -1) { // failure
return false;
} else if (pid == 0) { // child
dup2(p[1], 1);
close(p[0]);
if (execvp(argv[0], argv) == -1) {
return false;
}
} else { // parent
dup2(p[0], 0);
close(p[1]);
/* read output */
unsigned int bc = BLOCK_SIZE;
unsigned int i = 0;
char* buffer = malloc(sizeof(char) * bc);
*output = NULL;
if (!buffer) {
close(p[0]);
return false;
}
char c;
while (1 == read(p[0], &c, 1)) {
buffer[i++] = c;
if (i == bc) {
bc += BLOCK_SIZE;
char* tmp = realloc(buffer, sizeof(char) * bc);
if (!tmp) {
free(buffer);
close(p[0]);
return false;
}
buffer = tmp;
}
}
char* tmp = realloc(buffer, sizeof(char) * (bc + 1));
if (!tmp) {
free(buffer);
close(p[0]);
return false;
}
buffer = tmp;
buffer[i] = '\0';
*output = buffer;
/* wait for child to terminate */
waitpid(pid, NULL, 0);
close(p[0]);
}
return true;
}
void
document_index_build(GtkTreeModel* model, GtkTreeIter* parent,
girara_tree_node_t* tree)
{
girara_list_t* list = girara_node_get_children(tree);
GIRARA_LIST_FOREACH(list, girara_tree_node_t*, iter, node)
zathura_index_element_t* index_element = (zathura_index_element_t*)girara_node_get_data(node);
zathura_link_type_t type = zathura_link_get_type(index_element->link);
zathura_link_target_t target = zathura_link_get_target(index_element->link);
gchar* description = NULL;
if (type == ZATHURA_LINK_GOTO_DEST) {
description = g_strdup_printf("Page %d", target.page_number + 1);
} else {
description = g_strdup(target.value);
}
GtkTreeIter tree_iter;
gtk_tree_store_append(GTK_TREE_STORE(model), &tree_iter, parent);
gtk_tree_store_set(GTK_TREE_STORE(model), &tree_iter, 0, index_element->title, 1, description, 2, index_element, -1);
g_object_weak_ref(G_OBJECT(model), (GWeakNotify) zathura_index_element_free, index_element);
g_free(description);
if (girara_node_get_num_children(node) > 0) {
document_index_build(model, &tree_iter, node);
}
GIRARA_LIST_FOREACH_END(list, gchar*, iter, name);
}
void
page_calculate_offset(zathura_t* zathura, zathura_page_t* page, page_offset_t* offset)
{
g_return_if_fail(page != NULL);
g_return_if_fail(offset != NULL);
GtkWidget* widget = zathura_page_get_widget(zathura, page);
g_return_if_fail(gtk_widget_translate_coordinates(widget,
zathura->ui.page_widget, 0, 0, &(offset->x), &(offset->y)) == true);
}
zathura_rectangle_t
rotate_rectangle(zathura_rectangle_t rectangle, unsigned int degree, double height, double width)
{
zathura_rectangle_t tmp;
switch (degree) {
case 90:
tmp.x1 = height - rectangle.y2;
tmp.x2 = height - rectangle.y1;
tmp.y1 = rectangle.x1;
tmp.y2 = rectangle.x2;
break;
case 180:
tmp.x1 = width - rectangle.x2;
tmp.x2 = width - rectangle.x1;
tmp.y1 = height - rectangle.y2;
tmp.y2 = height - rectangle.y1;
break;
case 270:
tmp.x1 = rectangle.y1;
tmp.x2 = rectangle.y2;
tmp.y1 = width - rectangle.x2;
tmp.y2 = width - rectangle.x1;
break;
default:
tmp.x1 = rectangle.x1;
tmp.x2 = rectangle.x2;
tmp.y1 = rectangle.y1;
tmp.y2 = rectangle.y2;
}
return tmp;
}
zathura_rectangle_t
recalc_rectangle(zathura_page_t* page, zathura_rectangle_t rectangle)
{
if (page == NULL) {
goto error_ret;
}
zathura_document_t* document = zathura_page_get_document(page);
if (document == NULL) {
goto error_ret;
}
double page_height = zathura_page_get_height(page);
double page_width = zathura_page_get_width(page);
double scale = zathura_document_get_scale(document);
zathura_rectangle_t tmp = rotate_rectangle(rectangle, zathura_document_get_rotation(document), page_height, page_width);
tmp.x1 *= scale;
tmp.x2 *= scale;
tmp.y1 *= scale;
tmp.y2 *= scale;
return tmp;
error_ret:
return rectangle;
}
GtkWidget*
zathura_page_get_widget(zathura_t* zathura, zathura_page_t* page)
{
if (zathura == NULL || page == NULL || zathura->pages == NULL) {
return NULL;
}
unsigned int page_number = zathura_page_get_index(page);
return zathura->pages[page_number];
}
void
document_draw_search_results(zathura_t* zathura, bool value)
{
if (zathura == NULL || zathura->document == NULL || zathura->pages == NULL) {
return;
}
unsigned int number_of_pages = zathura_document_get_number_of_pages(zathura->document);
for (unsigned int page_id = 0; page_id < number_of_pages; page_id++) {
g_object_set(zathura->pages[page_id], "draw-search-results", (value == true) ? TRUE : FALSE, NULL);
}
}
char*
zathura_get_version_string(zathura_t* zathura, bool markup)
{
if (zathura == NULL) {
return NULL;
}
GString* string = g_string_new(NULL);
/* zathura version */
char* zathura_version = g_strdup_printf("zathura %d.%d.%d", ZATHURA_VERSION_MAJOR, ZATHURA_VERSION_MINOR, ZATHURA_VERSION_REV);
g_string_append(string, zathura_version);
g_free(zathura_version);
char* format = (markup == true) ? "\n<i>(plugin)</i> %s (%d.%d.%d) <i>(%s)</i>" : "\n(plugin) %s (%d.%d.%d) (%s)";
/* plugin information */
girara_list_t* plugins = zathura_plugin_manager_get_plugins(zathura->plugins.manager);
if (plugins != NULL) {
GIRARA_LIST_FOREACH(plugins, zathura_plugin_t*, iter, plugin)
char* name = zathura_plugin_get_name(plugin);
zathura_plugin_version_t version = zathura_plugin_get_version(plugin);
char* text = g_strdup_printf(format,
(name == NULL) ? "-" : name,
version.major,
version.minor,
version.rev,
zathura_plugin_get_path(plugin)
);
g_string_append(string, text);
g_free(text);
GIRARA_LIST_FOREACH_END(plugins, zathura_plugin_t*, iter, plugin);
}
char* version = string->str;
g_string_free(string, FALSE);
return version;
}
char*
replace_substring(const char* string, const char* old, const char* new)
{
if (string == NULL || old == NULL || new == NULL) {
return NULL;
}
size_t old_len = strlen(old);
size_t new_len = strlen(new);
/* count occurences */
unsigned int count = 0;
unsigned int i = 0;
for (i = 0; string[i] != '\0'; i++) {
if (strstr(&string[i], old) == &string[i]) {
i += (old_len - 1);
count++;
}
}
if (count == 0) {
return NULL;
}
char* ret = g_malloc0(sizeof(char) * (i - count * old_len + count * new_len + 1));
i = 0;
/* replace */
while (*string != '\0') {
if (strstr(string, old) == string) {
strncpy(&ret[i], new, new_len);
i += new_len;
string += old_len;
} else {
ret[i++] = *string++;
}
}
return ret;
}
GdkAtom* get_selection(zathura_t* zathura)
{
g_return_val_if_fail(zathura != NULL, NULL);
char* value;
girara_setting_get(zathura->ui.session, "selection-clipboard", &value);
GdkAtom* selection = g_malloc(sizeof(GdkAtom));
if (strcmp(value, "primary") == 0) {
*selection = GDK_SELECTION_PRIMARY;
} else if (strcmp(value, "clipboard") == 0) {
*selection = GDK_SELECTION_CLIPBOARD;
} else {
girara_error("Invalid value for the selection-clipboard setting");
g_free(value);
g_free(selection);
return NULL;
}
g_free(value);
return selection;
}