mirror of
https://git.pwmt.org/pwmt/zathura.git
synced 2025-01-27 17:17:52 +01:00
Highlight search results, Clickable links, ...
Added following functionality: * Highlight search results * Markup possibility for notification * Show PDF information * Show links on page * Click and open link in browser In progress and todo: * Search function in a own thread * Export command: Export images, attachments Fixes and other changes: * Set default background to drawing area and removed border * Set default window width and height
This commit is contained in:
parent
1789541e78
commit
01e613adc0
2 changed files with 251 additions and 41 deletions
30
config.h
30
config.h
|
@ -1,28 +1,34 @@
|
|||
/* settings */
|
||||
static const int SHOW_NOTIFICATION = 5;
|
||||
static const float ZOOM_STEP = 0.1;
|
||||
static const float SCROLL_STEP = 40;
|
||||
static const float HL_TRANSPARENCY = 0.4;
|
||||
static const int SHOW_NOTIFICATION = 5;
|
||||
static const int DEFAULT_WIDTH = 800;
|
||||
static const int DEFAULT_HEIGHT = 600;
|
||||
static const char BROWSER[] = "firefox %s";
|
||||
|
||||
/* look */
|
||||
static const char font[] = "monospace normal 9";
|
||||
static const char default_bgcolor[] = "#141414";
|
||||
static const char default_fgcolor[] = "#CCCCCC";
|
||||
static const char default_bgcolor[] = "#000000";
|
||||
static const char default_fgcolor[] = "#DDDDDD";
|
||||
|
||||
static const char notification_fgcolor[] = "#0F0F0F";
|
||||
static const char notification_bgcolor[] = "#F9F9F9";
|
||||
static const char notification_warning_fgcolor[] = "2222222";
|
||||
static const char notification_warning_bgcolor[] = "#E8E62E";
|
||||
static const char notification_error_fgcolor[] = "#CCCCCC";
|
||||
static const char notification_error_bgcolor[] = "#B82121";
|
||||
static const char notification_warning_fgcolor[] = "DDDDDDC";
|
||||
static const char notification_warning_bgcolor[] = "#D0C54D";
|
||||
static const char notification_error_fgcolor[] = "#FFFFFF";
|
||||
static const char notification_error_bgcolor[] = "#BC2800";
|
||||
|
||||
static const char inputbar_bgcolor[] = "#141414";
|
||||
static const char inputbar_fgcolor[] = "#9FBC00";
|
||||
|
||||
static const char completion_fgcolor[] = "#CCCCCC";
|
||||
static const char completion_fgcolor[] = "#DDDDDD";
|
||||
static const char completion_bgcolor[] = "#232323";
|
||||
static const char completion_hl_fgcolor[] = "#232323";
|
||||
static const char completion_hl_bgcolor[] = "#9FBC00";
|
||||
|
||||
static const char search_highlight[] = "#9FBC00";
|
||||
|
||||
/* shortcuts */
|
||||
Shortcut shortcuts[] = {
|
||||
// mask, key, function, argument
|
||||
|
@ -56,14 +62,12 @@ Shortcut shortcuts[] = {
|
|||
/* commands */
|
||||
Command commands[] = {
|
||||
// command, function
|
||||
{"g", cmd_goto},
|
||||
{"export", cmd_export},
|
||||
{"goto", cmd_goto},
|
||||
{"o", cmd_open},
|
||||
{"info", cmd_info},
|
||||
{"links", cmd_links},
|
||||
{"open", cmd_open},
|
||||
{"r", cmd_rotate},
|
||||
{"rotate", cmd_rotate},
|
||||
{"q", cmd_quit},
|
||||
{"quit", cmd_quit},
|
||||
{"z", cmd_zoom},
|
||||
{"zoom", cmd_zoom},
|
||||
};
|
||||
|
|
256
zathura.c
256
zathura.c
|
@ -41,6 +41,7 @@ struct
|
|||
GdkColor completion_bg;
|
||||
GdkColor completion_hl_fg;
|
||||
GdkColor completion_hl_bg;
|
||||
GdkColor search_highlight;
|
||||
PangoFontDescription *font;
|
||||
} Settings;
|
||||
|
||||
|
@ -84,11 +85,14 @@ void update_title();
|
|||
void update_status();
|
||||
void set_page(int);
|
||||
void draw();
|
||||
void hilight_result(PopplerRectangle*);
|
||||
void highlight_result(PopplerRectangle*);
|
||||
void open_link(char*);
|
||||
|
||||
gboolean complete(Argument*);
|
||||
gboolean delete_widget(gpointer);
|
||||
GtkLabel* notify(int, char*);
|
||||
|
||||
GtkWidget* notify(int, char*);
|
||||
GtkWidget* update_notification(GtkWidget*, int, char*);
|
||||
|
||||
/* shortcut declarations */
|
||||
void sc_focus_inputbar(Argument*);
|
||||
|
@ -102,7 +106,10 @@ void sc_print(Argument*);
|
|||
void sc_quit(Argument*);
|
||||
|
||||
/* command declarations */
|
||||
void cmd_export(int, char**);
|
||||
void cmd_goto(int, char**);
|
||||
void cmd_info(int, char**);
|
||||
void cmd_links(int, char**);
|
||||
void cmd_open(int, char**);
|
||||
void cmd_rotate(int, char**);
|
||||
void cmd_quit(int, char**);
|
||||
|
@ -113,7 +120,9 @@ void cb_draw(GtkWidget*, gpointer);
|
|||
void cb_destroy(GtkWidget*, gpointer);
|
||||
void cb_inputbar_activate(GtkEntry*, gpointer);
|
||||
void cb_inputbar_button_pressed(GtkWidget*, GdkEventButton*, gpointer);
|
||||
void cb_drawing_area_button_pressed(GtkWidget*, GdkEventButton*, gpointer);
|
||||
|
||||
gboolean cb_label_open_link(GtkLabel*, gchar*, gpointer);
|
||||
gboolean cb_inputbar_key_pressed(GtkEntry*, GdkEventKey*, gpointer);
|
||||
gboolean cb_inputbar_key_released(GtkEntry*, GdkEventKey*, gpointer);
|
||||
gboolean cb_view_key_pressed(GtkWidget*, GdkEventKey*, gpointer);
|
||||
|
@ -140,6 +149,7 @@ init()
|
|||
gdk_color_parse(completion_bgcolor, &(Zathura.Settings.completion_bg));
|
||||
gdk_color_parse(completion_hl_fgcolor, &(Zathura.Settings.completion_hl_fg));
|
||||
gdk_color_parse(completion_hl_bgcolor, &(Zathura.Settings.completion_hl_bg));
|
||||
gdk_color_parse(search_highlight, &(Zathura.Settings.search_highlight));
|
||||
Zathura.Settings.font = pango_font_description_from_string(font);
|
||||
|
||||
/* variables */
|
||||
|
@ -154,7 +164,7 @@ init()
|
|||
|
||||
/* window */
|
||||
gtk_window_set_title(Zathura.window, "zathura");
|
||||
gtk_window_set_default_size(Zathura.window, 800, 600);
|
||||
gtk_window_set_default_size(Zathura.window, DEFAULT_WIDTH, DEFAULT_HEIGHT);
|
||||
g_signal_connect(G_OBJECT(Zathura.window), "destroy", G_CALLBACK(cb_destroy), NULL);
|
||||
|
||||
/* box */
|
||||
|
@ -162,7 +172,9 @@ init()
|
|||
gtk_container_add(GTK_CONTAINER(Zathura.window), GTK_WIDGET(Zathura.box));
|
||||
|
||||
/* view */
|
||||
gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(Zathura.view), Zathura.drawing_area);
|
||||
gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(Zathura.view),
|
||||
Zathura.drawing_area);
|
||||
gtk_viewport_set_shadow_type((GtkViewport*) gtk_bin_get_child(GTK_BIN(Zathura.view)), GTK_SHADOW_NONE);
|
||||
g_signal_connect(G_OBJECT(Zathura.view), "key-press-event", G_CALLBACK(cb_view_key_pressed), NULL);
|
||||
|
||||
#ifdef SHOW_SCROLLBARS
|
||||
|
@ -173,6 +185,10 @@ init()
|
|||
|
||||
/* drawing area */
|
||||
g_signal_connect(G_OBJECT(Zathura.drawing_area), "expose-event", G_CALLBACK(cb_draw), NULL);
|
||||
g_signal_connect(G_OBJECT(Zathura.drawing_area), "button-press-event", G_CALLBACK(cb_drawing_area_button_pressed), NULL);
|
||||
gtk_widget_set_events(Zathura.drawing_area, GDK_BUTTON_PRESS_MASK);
|
||||
gtk_widget_modify_bg(GTK_WIDGET(Zathura.drawing_area), GTK_STATE_NORMAL, &(Zathura.Settings.default_bg));
|
||||
|
||||
|
||||
/* inputbar */
|
||||
gtk_entry_set_inner_border(Zathura.inputbar, NULL);
|
||||
|
@ -203,12 +219,28 @@ update_title()
|
|||
gtk_window_set_title(GTK_WINDOW(Zathura.window), "zathura");
|
||||
}
|
||||
|
||||
GtkLabel*
|
||||
GtkWidget*
|
||||
notify(int level, char* text)
|
||||
{
|
||||
GtkLabel *message = GTK_LABEL(gtk_label_new(text));
|
||||
GtkEventBox *view = GTK_EVENT_BOX(gtk_event_box_new());
|
||||
|
||||
update_notification(GTK_WIDGET(view), level, text);
|
||||
|
||||
gtk_container_add(GTK_CONTAINER(Zathura.notification), GTK_WIDGET(view));
|
||||
|
||||
gtk_widget_show_all(GTK_WIDGET(Zathura.window));
|
||||
g_timeout_add_seconds(SHOW_NOTIFICATION, delete_widget, GTK_WIDGET(GTK_WIDGET(view)));
|
||||
|
||||
return GTK_WIDGET(view);
|
||||
}
|
||||
|
||||
GtkWidget*
|
||||
update_notification(GtkWidget* view, int level, char* text)
|
||||
{
|
||||
GtkLabel *message = GTK_LABEL(gtk_label_new(""));
|
||||
gtk_label_set_markup(message, text);
|
||||
g_signal_connect(G_OBJECT(message), "activate-link", G_CALLBACK(cb_label_open_link), NULL);
|
||||
|
||||
gtk_misc_set_alignment(GTK_MISC(message), 0, 0);
|
||||
gtk_widget_modify_font(GTK_WIDGET(message), Zathura.Settings.font);
|
||||
|
||||
|
@ -229,13 +261,12 @@ notify(int level, char* text)
|
|||
|
||||
}
|
||||
|
||||
if(gtk_bin_get_child(GTK_BIN(view)))
|
||||
gtk_container_remove(GTK_CONTAINER(view), gtk_bin_get_child(GTK_BIN(view)));
|
||||
|
||||
gtk_container_add(GTK_CONTAINER(view), GTK_WIDGET(message));
|
||||
gtk_container_add(GTK_CONTAINER(Zathura.notification), GTK_WIDGET(view));
|
||||
|
||||
gtk_widget_show_all(GTK_WIDGET(Zathura.window));
|
||||
g_timeout_add_seconds(SHOW_NOTIFICATION, delete_widget, GTK_WIDGET(GTK_WIDGET(view)));
|
||||
|
||||
return message;
|
||||
return GTK_WIDGET(view);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -244,11 +275,7 @@ update_status()
|
|||
char* text = "";
|
||||
|
||||
if(Zathura.PDF.document && Zathura.PDF.page)
|
||||
{
|
||||
char* show_page = g_strdup_printf("[%i/%i]", Zathura.PDF.page_number + 1,
|
||||
Zathura.PDF.number_of_pages);
|
||||
text = g_strdup_printf("%s %s", show_page, Zathura.PDF.file);
|
||||
}
|
||||
text = g_strdup_printf("[%i/%i] %s", Zathura.PDF.page_number + 1, Zathura.PDF.number_of_pages, Zathura.PDF.file);
|
||||
|
||||
gtk_entry_set_text(Zathura.inputbar, text);
|
||||
}
|
||||
|
@ -332,9 +359,44 @@ draw()
|
|||
}
|
||||
|
||||
void
|
||||
hilight_result(PopplerRectangle* rectangle)
|
||||
highlight_result(PopplerRectangle* rectangle)
|
||||
{
|
||||
double page_height, page_width;
|
||||
double width, height;
|
||||
double scale;
|
||||
|
||||
poppler_page_get_size(Zathura.PDF.page, &page_width, &page_height);
|
||||
scale = Zathura.PDF.scale;
|
||||
width = (rectangle->x2 - rectangle->x1) * scale;
|
||||
height = (rectangle->y2 - rectangle->y1) * scale;
|
||||
|
||||
cairo_t *cairo = cairo_create(Zathura.PDF.surface);
|
||||
cairo_set_source_rgba(cairo, Zathura.Settings.search_highlight.red, Zathura.Settings.search_highlight.green,
|
||||
Zathura.Settings.search_highlight.blue, HL_TRANSPARENCY);
|
||||
|
||||
switch(Zathura.PDF.rotate)
|
||||
{
|
||||
case 90:
|
||||
cairo_rectangle(cairo, scale * rectangle->y1, scale * rectangle->x1, height, width);
|
||||
break;
|
||||
case 180:
|
||||
cairo_rectangle(cairo, scale * (page_width - rectangle->x1) - width, scale * rectangle->y1, width, height);
|
||||
break;
|
||||
case 270:
|
||||
cairo_rectangle(cairo, scale * (page_height - rectangle->y1) - height, scale * (page_width - rectangle->x1) - width, height, width);
|
||||
break;
|
||||
default:
|
||||
cairo_rectangle(cairo, scale * rectangle->x1, scale * (page_height - rectangle->y1) - height, width, height);
|
||||
}
|
||||
|
||||
cairo_fill(cairo);
|
||||
}
|
||||
|
||||
void
|
||||
open_link(char* link)
|
||||
{
|
||||
char* start_browser = g_strdup_printf(BROWSER, link);
|
||||
system(start_browser);
|
||||
}
|
||||
|
||||
gboolean
|
||||
|
@ -573,6 +635,7 @@ sc_search(Argument *argument)
|
|||
GList* results;
|
||||
GList* list;
|
||||
|
||||
|
||||
if(argument->data)
|
||||
search_item = (char*) argument->data;
|
||||
|
||||
|
@ -580,7 +643,8 @@ sc_search(Argument *argument)
|
|||
return;
|
||||
|
||||
/* search document */
|
||||
GtkLabel* search_status = notify(DEFAULT, "Searching...");
|
||||
GtkWidget* search_status = notify(DEFAULT, "Searching...");
|
||||
|
||||
if(argument->n)
|
||||
direction = (argument->n == BACKWARD) ? -1 : 1;
|
||||
|
||||
|
@ -599,17 +663,16 @@ sc_search(Argument *argument)
|
|||
{
|
||||
draw();
|
||||
|
||||
gtk_label_set_text(search_status, g_strdup_printf("%s found on page %i for %i time(s)",
|
||||
update_notification(GTK_WIDGET(search_status), DEFAULT, g_strdup_printf("%s found on page %i for %i time(s)",
|
||||
search_item, Zathura.PDF.page_number, g_list_length(results)));
|
||||
|
||||
for(list = results; list && list->data; list = g_list_next(list))
|
||||
{
|
||||
hilight_result((PopplerRectangle*) list->data);
|
||||
highlight_result((PopplerRectangle*) list->data);
|
||||
}
|
||||
}
|
||||
else
|
||||
gtk_label_set_text(search_status, g_strdup_printf("No match for %s", search_item));
|
||||
|
||||
update_notification(search_status, DEFAULT, g_strdup_printf("No match for %s", search_item));
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -653,14 +716,35 @@ cmd_open(int argc, char** argv)
|
|||
|
||||
Zathura.PDF.number_of_pages = poppler_document_get_n_pages(Zathura.PDF.document);
|
||||
Zathura.PDF.file = file + strlen("file://");
|
||||
set_page(0);
|
||||
|
||||
set_page(0);
|
||||
draw();
|
||||
|
||||
update_status();
|
||||
update_title();
|
||||
}
|
||||
|
||||
void
|
||||
cmd_export(int argc, char** argv)
|
||||
{
|
||||
if(argc == 0)
|
||||
return;
|
||||
|
||||
if(strcmp(argv[0], "image") == 0)
|
||||
{
|
||||
|
||||
}
|
||||
else if(strcmp(argv[0], "links") == 0)
|
||||
{
|
||||
|
||||
}
|
||||
else if(strcmp(argv[0], "attachments") == 0)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
cmd_goto(int argc, char** argv)
|
||||
{
|
||||
|
@ -679,6 +763,79 @@ cmd_goto(int argc, char** argv)
|
|||
update_status();
|
||||
}
|
||||
|
||||
void
|
||||
cmd_info(int argc, char** argv)
|
||||
{
|
||||
if(!Zathura.PDF.document)
|
||||
return;
|
||||
|
||||
gchar *info;
|
||||
gchar *title, *author;
|
||||
gchar *subject, *keywords;
|
||||
gchar *creator, *producer;
|
||||
GTime creation_date, modification_date;
|
||||
|
||||
g_object_get(Zathura.PDF.document,
|
||||
"title", &title,
|
||||
"author", &author,
|
||||
"subject", &subject,
|
||||
"keywords", &keywords,
|
||||
"creator", &creator,
|
||||
"producer", &producer,
|
||||
"creation-date", &creation_date,
|
||||
"mod-date", &modification_date,
|
||||
NULL);
|
||||
|
||||
info = g_strconcat(
|
||||
"<b>Title:</b> ", title ? title : "", "\n",
|
||||
"<b>Author:</b> ", author ? author : "", "\n",
|
||||
"<b>Subject:</b> ", subject ? subject : "", "\n",
|
||||
"<b>Keywords:</b> ", keywords ? keywords : "", "\n",
|
||||
"<b>Creator:</b> ", creator ? creator : "", "\n",
|
||||
"<b>Producer:</b> ", producer ? producer : "",
|
||||
NULL);
|
||||
|
||||
notify(DEFAULT, info);
|
||||
}
|
||||
|
||||
void
|
||||
cmd_links(int argc, char** argv)
|
||||
{
|
||||
if(!Zathura.PDF.document && !Zathura.PDF.page)
|
||||
return;
|
||||
|
||||
GList *link_list;
|
||||
GList *links;
|
||||
int number_of_links;
|
||||
|
||||
link_list = poppler_page_get_link_mapping(Zathura.PDF.page);
|
||||
number_of_links = g_list_length(link_list);
|
||||
|
||||
if(number_of_links > 0)
|
||||
notify(DEFAULT, g_strdup_printf("%d links found", number_of_links));
|
||||
else
|
||||
notify(WARNING, "No links found");
|
||||
|
||||
for(links = link_list; links; links = g_list_next(links))
|
||||
{
|
||||
PopplerLinkMapping *link_mapping;
|
||||
PopplerAction *action;
|
||||
|
||||
link_mapping = (PopplerLinkMapping*) links->data;
|
||||
action = poppler_action_copy(link_mapping->action);
|
||||
|
||||
if(action->type == POPPLER_ACTION_URI)
|
||||
{
|
||||
char* link_name = poppler_page_get_text(Zathura.PDF.page, POPPLER_SELECTION_WORD, &link_mapping->area);
|
||||
link_name = g_strdup_printf("<a href=\"%s\">%s</a>", action->uri.uri, link_name);
|
||||
|
||||
notify(DEFAULT, g_strdup_printf("<b>%s:</b> %s", link_name, action->uri.uri));
|
||||
}
|
||||
}
|
||||
|
||||
poppler_page_free_link_mapping(link_list);
|
||||
}
|
||||
|
||||
void
|
||||
cmd_rotate(int argc, char** argv)
|
||||
{
|
||||
|
@ -772,7 +929,6 @@ cb_inputbar_activate(GtkEntry* entry, gpointer data)
|
|||
{
|
||||
Argument argument;
|
||||
argument.data = (char*) gtk_entry_get_text(entry) + 1;
|
||||
argument.n = -1;
|
||||
sc_search(&argument);
|
||||
g_strfreev(tokens);
|
||||
update_status();
|
||||
|
@ -812,6 +968,56 @@ cb_inputbar_button_pressed(GtkWidget* widget, GdkEventButton* event, gpointer da
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
cb_drawing_area_button_pressed(GtkWidget* widget, GdkEventButton* event, gpointer data)
|
||||
{
|
||||
if(!Zathura.PDF.document && !Zathura.PDF.page)
|
||||
return;
|
||||
|
||||
// left click
|
||||
if(event->button == 1)
|
||||
{
|
||||
// check for links
|
||||
GList *link_list = poppler_page_get_link_mapping(Zathura.PDF.page);
|
||||
GList *links;
|
||||
int number_of_links = g_list_length(link_list);
|
||||
|
||||
if(number_of_links <= 0)
|
||||
return;
|
||||
|
||||
for(links = link_list; links; links = g_list_next(links))
|
||||
{
|
||||
PopplerLinkMapping *link_mapping = (PopplerLinkMapping*) links->data;
|
||||
PopplerAction *action = poppler_action_copy(link_mapping->action);
|
||||
|
||||
if(action->type == POPPLER_ACTION_URI)
|
||||
{
|
||||
double page_width, page_height;
|
||||
poppler_page_get_size(Zathura.PDF.page, &page_width, &page_height);
|
||||
|
||||
// check if click is in url area
|
||||
if( (link_mapping->area.x1 <= event->x)
|
||||
&& (link_mapping->area.x2 >= event->x)
|
||||
&& (link_mapping->area.y1 <= (page_height - event->y))
|
||||
&& (link_mapping->area.y2 >= (page_height - event->y))
|
||||
)
|
||||
{
|
||||
open_link(action->uri.uri);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
poppler_page_free_link_mapping(link_list);
|
||||
}
|
||||
}
|
||||
|
||||
gboolean
|
||||
cb_label_open_link(GtkLabel* label, gchar* link, gpointer data)
|
||||
{
|
||||
open_link(link);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
cb_inputbar_key_pressed(GtkEntry* entry, GdkEventKey *event, gpointer data)
|
||||
{
|
||||
|
@ -821,6 +1027,7 @@ cb_inputbar_key_pressed(GtkEntry* entry, GdkEventKey *event, gpointer data)
|
|||
{
|
||||
case GDK_Escape:
|
||||
gtk_widget_grab_focus(GTK_WIDGET(Zathura.view));
|
||||
update_status();
|
||||
argument.n = HIDE;
|
||||
return complete(&argument);
|
||||
case GDK_Tab:
|
||||
|
@ -850,7 +1057,6 @@ cb_inputbar_key_released(GtkEntry *entry, GdkEventKey *event, gpointer data)
|
|||
{
|
||||
Argument argument;
|
||||
argument.data = (char*) text + 1;
|
||||
argument.n = -1;
|
||||
sc_search(&argument);
|
||||
gtk_widget_grab_focus(GTK_WIDGET(Zathura.inputbar));
|
||||
gtk_editable_set_position(GTK_EDITABLE(Zathura.inputbar), -1);
|
||||
|
|
Loading…
Reference in a new issue