diff options
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); -} -  | 
