mirror of
https://git.pwmt.org/pwmt/zathura.git
synced 2024-12-28 21:55:59 +01:00
030a8c65c1
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.
374 lines
8.9 KiB
C
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;
|
|
}
|