diff options
author | Leandro A. F. Pereira <leandro@hardinfo.org> | 2010-05-03 09:27:26 -0300 |
---|---|---|
committer | Leandro A. F. Pereira <leandro@hardinfo.org> | 2010-05-03 21:08:06 -0300 |
commit | 9273c075a2f993c5154614b70233d8f74515c851 (patch) | |
tree | eb72a8c58e6bc8f4ca3b739d28fbecc269c0052d /hardinfo2/help-viewer/markdown-text-view.c | |
parent | 9a50155ec3e27aa6cedf3f118196f1947c769a29 (diff) |
Move files from hardinfo2 to root.
Diffstat (limited to 'hardinfo2/help-viewer/markdown-text-view.c')
-rw-r--r-- | hardinfo2/help-viewer/markdown-text-view.c | 637 |
1 files changed, 0 insertions, 637 deletions
diff --git a/hardinfo2/help-viewer/markdown-text-view.c b/hardinfo2/help-viewer/markdown-text-view.c deleted file mode 100644 index 6bfcc131..00000000 --- a/hardinfo2/help-viewer/markdown-text-view.c +++ /dev/null @@ -1,637 +0,0 @@ -/* - * Markdown Text View - * GtkTextView subclass that supports Markdown syntax - * - * Copyright (C) 2009 Leandro Pereira <leandro@hardinfo.org> - * Portions Copyright (C) 2007-2008 Richard Hughes <richard@hughsie.com> - * Portions Copyright (C) GTK+ Team (based on hypertext textview demo) - * - * Licensed under the GNU General Public License Version 2 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#include <stdlib.h> -#include <gdk/gdkkeysyms.h> - -#include "markdown-text-view.h" -#include "config.h" - -static GdkCursor *hand_cursor = NULL; - -G_DEFINE_TYPE(MarkdownTextView, markdown_textview, GTK_TYPE_TEXT_VIEW); - -enum { - LINK_CLICKED, - HOVERING_OVER_LINK, - HOVERING_OVER_TEXT, - FILE_LOAD_COMPLETE, - LAST_SIGNAL -}; - -static guint markdown_textview_signals[LAST_SIGNAL] = { 0 }; - -GtkWidget *markdown_textview_new() -{ - return g_object_new(TYPE_MARKDOWN_TEXTVIEW, NULL); -} - -static void markdown_textview_class_init(MarkdownTextViewClass * klass) -{ - GObjectClass *object_class; - - if (!hand_cursor) { - hand_cursor = gdk_cursor_new(GDK_HAND2); - } - - object_class = G_OBJECT_CLASS(klass); - - markdown_textview_signals[LINK_CLICKED] = g_signal_new( - "link-clicked", - G_OBJECT_CLASS_TYPE(object_class), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET(MarkdownTextViewClass, link_clicked), - NULL, NULL, - g_cclosure_marshal_VOID__STRING, - G_TYPE_NONE, - 1, - G_TYPE_STRING); - - markdown_textview_signals[HOVERING_OVER_LINK] = g_signal_new( - "hovering-over-link", - G_OBJECT_CLASS_TYPE(object_class), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET(MarkdownTextViewClass, hovering_over_link), - NULL, NULL, - g_cclosure_marshal_VOID__STRING, - G_TYPE_NONE, - 1, - G_TYPE_STRING); - - markdown_textview_signals[HOVERING_OVER_TEXT] = g_signal_new( - "hovering-over-text", - G_OBJECT_CLASS_TYPE(object_class), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET(MarkdownTextViewClass, hovering_over_text), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, - 0); - - markdown_textview_signals[FILE_LOAD_COMPLETE] = g_signal_new( - "file-load-complete", - G_OBJECT_CLASS_TYPE(object_class), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET(MarkdownTextViewClass, file_load_complete), - NULL, NULL, - g_cclosure_marshal_VOID__STRING, - G_TYPE_NONE, - 1, - G_TYPE_STRING); -} - -static void -gtk_text_buffer_insert_markup(GtkTextBuffer * buffer, GtkTextIter * iter, - const gchar * markup) -{ - PangoAttrIterator *paiter; - PangoAttrList *attrlist; - GtkTextMark *mark; - GError *error = NULL; - gchar *text; - - g_return_if_fail(GTK_IS_TEXT_BUFFER(buffer)); - g_return_if_fail(markup != NULL); - - if (*markup == '\000') - return; - - /* invalid */ - if (!pango_parse_markup(markup, -1, 0, &attrlist, &text, NULL, &error)) { - g_warning("Invalid markup string: %s", error->message); - g_error_free(error); - return; - } - - /* trivial, no markup */ - if (attrlist == NULL) { - gtk_text_buffer_insert(buffer, iter, text, -1); - g_free(text); - return; - } - - /* create mark with right gravity */ - mark = gtk_text_buffer_create_mark(buffer, NULL, iter, FALSE); - paiter = pango_attr_list_get_iterator(attrlist); - - do { - PangoAttribute *attr; - GtkTextTag *tag; - GtkTextTag *tag_para; - gint start, end; - - pango_attr_iterator_range(paiter, &start, &end); - - if (end == G_MAXINT) /* last chunk */ - end = start - 1; /* resulting in -1 to be passed to _insert */ - - tag = gtk_text_tag_new(NULL); - - if ((attr = pango_attr_iterator_get(paiter, PANGO_ATTR_LANGUAGE))) - g_object_set(tag, "language", - pango_language_to_string(((PangoAttrLanguage *) - attr)->value), NULL); - - if ((attr = pango_attr_iterator_get(paiter, PANGO_ATTR_FAMILY))) - g_object_set(tag, "family", ((PangoAttrString *) attr)->value, - NULL); - - if ((attr = pango_attr_iterator_get(paiter, PANGO_ATTR_STYLE))) - g_object_set(tag, "style", ((PangoAttrInt *) attr)->value, - NULL); - - if ((attr = pango_attr_iterator_get(paiter, PANGO_ATTR_WEIGHT))) - g_object_set(tag, "weight", ((PangoAttrInt *) attr)->value, - NULL); - - if ((attr = pango_attr_iterator_get(paiter, PANGO_ATTR_VARIANT))) - g_object_set(tag, "variant", ((PangoAttrInt *) attr)->value, - NULL); - - if ((attr = pango_attr_iterator_get(paiter, PANGO_ATTR_STRETCH))) - g_object_set(tag, "stretch", ((PangoAttrInt *) attr)->value, - NULL); - - if ((attr = pango_attr_iterator_get(paiter, PANGO_ATTR_SIZE))) - g_object_set(tag, "size", ((PangoAttrInt *) attr)->value, - NULL); - - if ((attr = pango_attr_iterator_get(paiter, PANGO_ATTR_FONT_DESC))) - g_object_set(tag, "font-desc", - ((PangoAttrFontDesc *) attr)->desc, NULL); - - if ((attr = - pango_attr_iterator_get(paiter, PANGO_ATTR_FOREGROUND))) { - GdkColor col = { 0, - ((PangoAttrColor *) attr)->color.red, - ((PangoAttrColor *) attr)->color.green, - ((PangoAttrColor *) attr)->color.blue - }; - - g_object_set(tag, "foreground-gdk", &col, NULL); - } - - if ((attr = - pango_attr_iterator_get(paiter, PANGO_ATTR_BACKGROUND))) { - GdkColor col = { 0, - ((PangoAttrColor *) attr)->color.red, - ((PangoAttrColor *) attr)->color.green, - ((PangoAttrColor *) attr)->color.blue - }; - - g_object_set(tag, "background-gdk", &col, NULL); - } - - if ((attr = pango_attr_iterator_get(paiter, PANGO_ATTR_UNDERLINE))) - g_object_set(tag, "underline", ((PangoAttrInt *) attr)->value, - NULL); - - if ((attr = - pango_attr_iterator_get(paiter, PANGO_ATTR_STRIKETHROUGH))) - g_object_set(tag, "strikethrough", - (gboolean) (((PangoAttrInt *) attr)->value != 0), - NULL); - - if ((attr = pango_attr_iterator_get(paiter, PANGO_ATTR_RISE))) - g_object_set(tag, "rise", ((PangoAttrInt *) attr)->value, - NULL); - - if ((attr = pango_attr_iterator_get(paiter, PANGO_ATTR_SCALE))) - g_object_set(tag, "scale", ((PangoAttrFloat *) attr)->value, - NULL); - - gtk_text_tag_table_add(gtk_text_buffer_get_tag_table(buffer), tag); - - tag_para = - gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table - (buffer), "para"); - gtk_text_buffer_insert_with_tags(buffer, iter, text + start, - end - start, tag, tag_para, NULL); - - /* mark had right gravity, so it should be - * at the end of the inserted text now */ - gtk_text_buffer_get_iter_at_mark(buffer, iter, mark); - } while (pango_attr_iterator_next(paiter)); - - gtk_text_buffer_delete_mark(buffer, mark); - pango_attr_iterator_destroy(paiter); - pango_attr_list_unref(attrlist); - g_free(text); -} - - -static void -set_cursor_if_appropriate(MarkdownTextView * self, gint x, gint y) -{ - GSList *tags = NULL, *tagp = NULL; - GtkTextIter iter; - gboolean hovering = FALSE; - gchar *link_uri = NULL; - - gtk_text_view_get_iter_at_location(GTK_TEXT_VIEW(self), &iter, x, - y); - - tags = gtk_text_iter_get_tags(&iter); - for (tagp = tags; tagp != NULL; tagp = tagp->next) { - GtkTextTag *tag = tagp->data; - gint is_underline = 0; - gchar *lang = NULL; - - g_object_get(G_OBJECT(tag), - "underline", &is_underline, - "language", &lang, - NULL); - - if (is_underline == 1 && lang) { - link_uri = egg_markdown_get_link_uri(self->markdown, atoi(lang)); - g_free(lang); - hovering = TRUE; - break; - } - - g_free(lang); - } - - if (hovering != self->hovering_over_link) { - self->hovering_over_link = hovering; - - if (self->hovering_over_link) { - g_signal_emit(self, markdown_textview_signals[HOVERING_OVER_LINK], - 0, link_uri); - gdk_window_set_cursor(gtk_text_view_get_window - (GTK_TEXT_VIEW(self), - GTK_TEXT_WINDOW_TEXT), hand_cursor); - } else { - g_signal_emit(self, markdown_textview_signals[HOVERING_OVER_TEXT], 0); - gdk_window_set_cursor(gtk_text_view_get_window - (GTK_TEXT_VIEW(self), - GTK_TEXT_WINDOW_TEXT), NULL); - } - } - - if (link_uri) - g_free(link_uri); - - if (tags) - g_slist_free(tags); -} - -/* Update the cursor image if the pointer moved. - */ -static gboolean -motion_notify_event(GtkWidget * self, GdkEventMotion * event) -{ - gint x, y; - - gtk_text_view_window_to_buffer_coords(GTK_TEXT_VIEW(self), - GTK_TEXT_WINDOW_WIDGET, - event->x, event->y, &x, &y); - - set_cursor_if_appropriate(MARKDOWN_TEXTVIEW(self), x, y); - - gdk_window_get_pointer(self->window, NULL, NULL, NULL); - return FALSE; -} - -/* Also update the cursor image if the window becomes visible - * (e.g. when a window covering it got iconified). - */ -static gboolean -visibility_notify_event(GtkWidget * self, GdkEventVisibility * event) -{ - gint wx, wy, bx, by; - - gdk_window_get_pointer(self->window, &wx, &wy, NULL); - - gtk_text_view_window_to_buffer_coords(GTK_TEXT_VIEW(self), - GTK_TEXT_WINDOW_WIDGET, - wx, wy, &bx, &by); - - set_cursor_if_appropriate(MARKDOWN_TEXTVIEW(self), bx, by); - - return FALSE; -} - -static void -follow_if_link(GtkWidget * widget, GtkTextIter * iter) -{ - GSList *tags = NULL, *tagp = NULL; - MarkdownTextView *self = MARKDOWN_TEXTVIEW(widget); - - tags = gtk_text_iter_get_tags(iter); - for (tagp = tags; tagp != NULL; tagp = tagp->next) { - GtkTextTag *tag = tagp->data; - gint is_underline = 0; - gchar *lang = NULL; - - g_object_get(G_OBJECT(tag), - "underline", &is_underline, - "language", &lang, - NULL); - - if (is_underline == 1 && lang) { - gchar *link = egg_markdown_get_link_uri(self->markdown, atoi(lang)); - if (link) { - g_signal_emit(self, markdown_textview_signals[LINK_CLICKED], - 0, link); - g_free(link); - } - g_free(lang); - break; - } - - g_free(lang); - } - - if (tags) - g_slist_free(tags); -} - -static gboolean -key_press_event(GtkWidget * self, - GdkEventKey * event) -{ - GtkTextIter iter; - GtkTextBuffer *buffer; - - switch (event->keyval) { - case GDK_Return: - case GDK_KP_Enter: - buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(self)); - gtk_text_buffer_get_iter_at_mark(buffer, &iter, - gtk_text_buffer_get_insert - (buffer)); - follow_if_link(self, &iter); - break; - - default: - break; - } - - return FALSE; -} - -static gboolean -event_after(GtkWidget * self, GdkEvent * ev) -{ - GtkTextIter start, end, iter; - GtkTextBuffer *buffer; - GdkEventButton *event; - gint x, y; - - if (ev->type != GDK_BUTTON_RELEASE) - return FALSE; - - event = (GdkEventButton *) ev; - - if (event->button != 1) - return FALSE; - - buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(self)); - - /* we shouldn't follow a link if the user has selected something */ - gtk_text_buffer_get_selection_bounds(buffer, &start, &end); - if (gtk_text_iter_get_offset(&start) != gtk_text_iter_get_offset(&end)) - return FALSE; - - gtk_text_view_window_to_buffer_coords(GTK_TEXT_VIEW(self), - GTK_TEXT_WINDOW_WIDGET, - event->x, event->y, &x, &y); - - gtk_text_view_get_iter_at_location(GTK_TEXT_VIEW(self), &iter, x, - y); - - follow_if_link(self, &iter); - - return FALSE; -} - -void -markdown_textview_clear(MarkdownTextView * self) -{ - GtkTextBuffer *text_buffer; - - g_return_if_fail(IS_MARKDOWN_TEXTVIEW(self)); - - egg_markdown_clear(self->markdown); - - text_buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(self)); - gtk_text_buffer_set_text(text_buffer, "\n", 1); -} - -static void -load_images(MarkdownTextView * self) -{ - GtkTextBuffer *buffer; - GtkTextIter iter; - GSList *tags, *tagp; - gchar *image_path; - - buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(self)); - gtk_text_buffer_get_start_iter(buffer, &iter); - - do { - tags = gtk_text_iter_get_tags(&iter); - for (tagp = tags; tagp != NULL; tagp = tagp->next) { - GtkTextTag *tag = tagp->data; - gint is_underline = 0; - gchar *lang = NULL; - - g_object_get(G_OBJECT(tag), - "underline", &is_underline, - "language", &lang, - NULL); - - if (is_underline == 2 && lang) { - GdkPixbuf *pixbuf; - gchar *path; - - image_path = egg_markdown_get_link_uri(self->markdown, atoi(lang)); - path = g_build_filename(self->image_directory, image_path, NULL); - pixbuf = gdk_pixbuf_new_from_file(path, NULL); - if (pixbuf) { - GtkTextMark *mark; - GtkTextIter start; - - mark = gtk_text_buffer_create_mark(buffer, NULL, &iter, FALSE); - - gtk_text_buffer_get_iter_at_mark(buffer, &start, mark); - gtk_text_iter_forward_to_tag_toggle(&iter, tag); - gtk_text_buffer_delete(buffer, &start, &iter); - - gtk_text_buffer_insert_pixbuf(buffer, &iter, pixbuf); - - g_object_unref(pixbuf); - gtk_text_buffer_delete_mark(buffer, mark); - } - - g_free(image_path); - g_free(lang); - g_free(path); - break; - } - - g_free(lang); - } - - if (tags) - g_slist_free(tags); - } while (gtk_text_iter_forward_to_tag_toggle(&iter, NULL)); -} - -static gboolean -append_text(MarkdownTextView * self, - const gchar * text) -{ - GtkTextIter iter; - GtkTextBuffer *text_buffer; - gchar *line; - - g_return_val_if_fail(IS_MARKDOWN_TEXTVIEW(self), FALSE); - - text_buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(self)); - gtk_text_buffer_get_end_iter(text_buffer, &iter); - - line = egg_markdown_parse(self->markdown, text); - if (line && *line) { - gtk_text_buffer_insert_markup(text_buffer, &iter, line); - gtk_text_buffer_insert(text_buffer, &iter, "\n", 1); - g_free(line); - - return TRUE; - } - - return FALSE; -} - -gboolean -markdown_textview_set_text(MarkdownTextView * self, - const gchar * text) -{ - gboolean result = TRUE; - gchar **lines; - gint line; - - g_return_val_if_fail(IS_MARKDOWN_TEXTVIEW(self), FALSE); - - markdown_textview_clear(self); - - lines = g_strsplit(text, "\n", 0); - for (line = 0; result && lines[line]; line++) { - result = append_text(self, (const gchar *)lines[line]); - } - g_strfreev(lines); - - load_images(self); - - return result; -} - -gboolean -markdown_textview_load_file(MarkdownTextView * self, - const gchar * file_name) -{ - FILE *text_file; - gchar *path; - - g_return_val_if_fail(IS_MARKDOWN_TEXTVIEW(self), FALSE); - - path = g_build_filename(self->image_directory, file_name, NULL); - - /* we do assume UTF-8 encoding */ - if ((text_file = fopen(path, "rb"))) { - GtkTextBuffer *text_buffer; - GtkTextIter iter; - gchar *line; - gchar buffer[EGG_MARKDOWN_MAX_LINE_LENGTH]; - - text_buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(self)); - - gtk_text_buffer_set_text(text_buffer, "\n", 1); - gtk_text_buffer_get_start_iter(text_buffer, &iter); - - egg_markdown_clear(self->markdown); - - while (fgets(buffer, EGG_MARKDOWN_MAX_LINE_LENGTH, text_file)) { - line = egg_markdown_parse(self->markdown, buffer); - - if (line && *line) { - gtk_text_buffer_insert_markup(text_buffer, &iter, line); - gtk_text_buffer_insert(text_buffer, &iter, "\n", 1); - } - - g_free(line); - } - fclose(text_file); - - load_images(self); - - g_signal_emit(self, markdown_textview_signals[FILE_LOAD_COMPLETE], 0, file_name); - - g_free(path); - - return TRUE; - } - - g_free(path); - - return FALSE; -} - -void -markdown_textview_set_image_directory(MarkdownTextView * self, const gchar *directory) -{ - g_return_if_fail(IS_MARKDOWN_TEXTVIEW(self)); - - g_free(self->image_directory); - self->image_directory = g_strdup(directory); -} - -static void markdown_textview_init(MarkdownTextView * self) -{ - self->markdown = egg_markdown_new(); - self->image_directory = g_strdup("."); - - egg_markdown_set_output(self->markdown, EGG_MARKDOWN_OUTPUT_PANGO); - egg_markdown_set_escape(self->markdown, TRUE); - egg_markdown_set_autocode(self->markdown, TRUE); - egg_markdown_set_smart_quoting(self->markdown, TRUE); - - gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(self), GTK_WRAP_WORD); - gtk_text_view_set_editable(GTK_TEXT_VIEW(self), FALSE); - gtk_text_view_set_left_margin(GTK_TEXT_VIEW(self), 10); - gtk_text_view_set_right_margin(GTK_TEXT_VIEW(self), 10); - gtk_text_view_set_pixels_above_lines(GTK_TEXT_VIEW(self), 3); - gtk_text_view_set_pixels_below_lines(GTK_TEXT_VIEW(self), 3); - - g_signal_connect(self, "event-after", - G_CALLBACK(event_after), NULL); - g_signal_connect(self, "key-press-event", - G_CALLBACK(key_press_event), NULL); - g_signal_connect(self, "motion-notify-event", - G_CALLBACK(motion_notify_event), NULL); - g_signal_connect(self, "visibility-notify-event", - G_CALLBACK(visibility_notify_event), NULL); -} - |