From 5af4d27ccf1d24d696d40e76ce33a0a393fdf9f6 Mon Sep 17 00:00:00 2001 From: Tristan Chabredier Date: Sun, 6 Nov 2005 10:24:50 +0000 Subject: [PATCH] 2005-11-06 [wwp] 1.9.99cvs12 * src/textview.c * src/gtk/about.c * src/gtk/gtkutils.c * src/gtk/gtkutils.h fix a compilation warning, make links sensitive in the about dialog --- ChangeLog | 9 ++ PATCHSETS | 1 + configure.ac | 2 +- src/gtk/about.c | 281 +++++++++++++++++++++++++++++++++++++++++++-- src/gtk/gtkutils.c | 25 ++++ src/gtk/gtkutils.h | 4 + src/textview.c | 19 +-- 7 files changed, 315 insertions(+), 26 deletions(-) diff --git a/ChangeLog b/ChangeLog index 2815778d4..463a45cfe 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2005-11-06 [wwp] 1.9.99cvs12 + + * src/textview.c + * src/gtk/about.c + * src/gtk/gtkutils.c + * src/gtk/gtkutils.h + fix a compilation warning, + make links sensitive in the about dialog + 2005-11-04 [wwp] 1.9.99cvs11 * src/gtk/about.c diff --git a/PATCHSETS b/PATCHSETS index b8c940c8d..e877b78ed 100644 --- a/PATCHSETS +++ b/PATCHSETS @@ -978,3 +978,4 @@ ( cvs diff -u -r 1.9.2.9 -r 1.9.2.10 src/common/ssl.c; ) > 1.9.99cvs9.patchset ( cvs diff -u -r 1.4.2.22 -r 1.4.2.23 src/gtk/about.c; ) > 1.9.99cvs10.patchset ( cvs diff -u -r 1.4.2.23 -r 1.4.2.24 src/gtk/about.c; ) > 1.9.99cvs11.patchset +( cvs diff -u -r 1.96.2.82 -r 1.96.2.83 src/textview.c; cvs diff -u -r 1.4.2.24 -r 1.4.2.25 src/gtk/about.c; cvs diff -u -r 1.5.2.16 -r 1.5.2.17 src/gtk/gtkutils.c; cvs diff -u -r 1.4.2.14 -r 1.4.2.15 src/gtk/gtkutils.h; ) > 1.9.99cvs12.patchset diff --git a/configure.ac b/configure.ac index 064ef5ea1..1dabf7744 100644 --- a/configure.ac +++ b/configure.ac @@ -11,7 +11,7 @@ MINOR_VERSION=9 MICRO_VERSION=99 INTERFACE_AGE=0 BINARY_AGE=0 -EXTRA_VERSION=11 +EXTRA_VERSION=12 EXTRA_RELEASE= EXTRA_GTK2_VERSION= diff --git a/src/gtk/about.c b/src/gtk/about.c index b59d91b4a..48d0d7462 100644 --- a/src/gtk/about.c +++ b/src/gtk/about.c @@ -48,12 +48,43 @@ #include "version.h" #include "authors.h" #include "codeconv.h" +#include "menu.h" +#include "textview.h" static GtkWidget *window; +static gchar* uri_hover = NULL; +static GtkTextIter uri_hover_start_iter; +static GtkTextIter uri_hover_end_iter; +static GdkCursor *hand_cursor = NULL; +static GdkCursor *text_cursor = NULL; static void about_create(void); static gboolean key_pressed(GtkWidget *widget, GdkEventKey *event); static void about_uri_clicked(GtkButton *button, gpointer data); +static gboolean about_textview_uri_clicked(GtkTextTag *tag, GObject *obj, + GdkEvent *event, GtkTextIter *iter, + GtkWidget *textview); +static void about_open_link_cb(GtkWidget *widget, guint action, void *data); +static void about_copy_link_cb(GtkWidget *widget, guint action, void *data); +static gboolean about_textview_motion_notify(GtkWidget *widget, + GdkEventMotion *event, + GtkWidget *textview); +static gboolean about_textview_leave_notify(GtkWidget *widget, + GdkEventCrossing *event, + GtkWidget *textview); +static gboolean about_textview_visibility_notify(GtkWidget *widget, + GdkEventVisibility *event, + GtkWidget *textview); +static void about_textview_uri_update(GtkWidget *textview, gint x, gint y); + +static GtkItemFactoryEntry textview_link_popup_entries[] = +{ + {N_("/_Open with Web browser"), NULL, about_open_link_cb, 0, NULL}, + {N_("/Copy this _link"), NULL, about_copy_link_cb, 0, NULL}, +}; + +static GtkWidget *link_popupmenu; + void about_show(void) { @@ -83,7 +114,8 @@ static void about_create(void) GtkWidget *confirm_area; GtkWidget *close_button; GtkTextBuffer *buffer; - GtkTextIter iter, start_iter; + GtkTextIter iter; + GtkTextTag *tag; #if HAVE_SYS_UTSNAME_H struct utsname utsbuf; @@ -248,17 +280,22 @@ static void about_create(void) gtk_text_view_set_right_margin(GTK_TEXT_VIEW(text), 6); gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(text), FALSE); gtk_container_add(GTK_CONTAINER(scrolledwin), text); + gtk_widget_add_events(text, GDK_LEAVE_NOTIFY_MASK); buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text)); gtk_text_buffer_get_iter_at_offset(buffer, &iter, 0); /* textview link style (based upon main prefs) */ gtkut_convert_int_to_gdk_color(prefs_common.uri_col, - (GdkColor*)&uri_color); - gtk_text_buffer_create_tag(buffer, "link", + (GdkColor*)&uri_color); + tag = gtk_text_buffer_create_tag(buffer, "link", "foreground-gdk", &uri_color, "wrap-mode", GTK_WRAP_NONE, NULL); + gtk_text_buffer_create_tag(buffer, "link-hover", + "foreground-gdk", &uri_color, + "underline", PANGO_UNDERLINE_SINGLE, + NULL); gtk_text_buffer_insert(buffer, &iter, _( "Sylpheed-Claws is a lightweight, fast and " @@ -276,6 +313,13 @@ static void about_create(void) "link", NULL); gtk_text_buffer_insert(buffer, &iter, _("\n"), -1); + g_signal_connect(G_OBJECT(tag), "event", + G_CALLBACK(about_textview_uri_clicked), text); + g_signal_connect(G_OBJECT(text), "motion-notify-event", + G_CALLBACK(about_textview_motion_notify), text); + g_signal_connect(G_OBJECT(text), "leave-notify-event", + G_CALLBACK(about_textview_leave_notify), text); + gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolledwin, gtk_label_new(_("Info"))); @@ -293,6 +337,7 @@ static void about_create(void) gtk_text_view_set_right_margin(GTK_TEXT_VIEW(text), 6); gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(text), FALSE); gtk_container_add(GTK_CONTAINER(scrolledwin), text); + gtk_widget_add_events(text, GDK_LEAVE_NOTIFY_MASK); buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text)); gtk_text_buffer_get_iter_at_offset(buffer, &iter, 0); @@ -463,16 +508,27 @@ static void about_create(void) "Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, " "MA 02110-1301, USA.\n\n"), -1); #ifdef USE_OPENSSL - gtk_text_buffer_create_tag(buffer, "link", - "foreground-gdk", &uri_color, - NULL); + tag = gtk_text_buffer_create_tag(buffer, "link", + "foreground-gdk", &uri_color, + NULL); + gtk_text_buffer_create_tag(buffer, "link-hover", + "foreground-gdk", &uri_color, + "underline", PANGO_UNDERLINE_SINGLE, + NULL); gtk_text_buffer_insert(buffer, &iter, _("This product includes software developed by the OpenSSL Project " "for use in the OpenSSL Toolkit ("), -1); gtk_text_buffer_insert_with_tags_by_name(buffer, &iter, "http://www.openssl.org/", -1, - "link", NULL); + "link", NULL); gtk_text_buffer_insert(buffer, &iter, _(").\n"), -1); + + g_signal_connect(G_OBJECT(tag), "event", + G_CALLBACK(about_textview_uri_clicked), text); + g_signal_connect(G_OBJECT(text), "motion-notify-event", + G_CALLBACK(about_textview_motion_notify), text); + g_signal_connect(G_OBJECT(text), "leave-notify-event", + G_CALLBACK(about_textview_leave_notify), text); #endif gtk_notebook_append_page(GTK_NOTEBOOK(notebook), @@ -505,3 +561,214 @@ static void about_uri_clicked(GtkButton *button, gpointer data) { open_uri(HOMEPAGE_URI, prefs_common.uri_cmd); } + +static gboolean about_textview_uri_clicked(GtkTextTag *tag, GObject *obj, + GdkEvent *event, GtkTextIter *iter, + GtkWidget *textview) +{ + GtkTextIter start_iter, end_iter; + GdkEventButton *bevent; + gchar *link = NULL; + + if (!event || !tag) { + return FALSE; + } + + if (event->type != GDK_BUTTON_PRESS && event->type != GDK_2BUTTON_PRESS + && event->type != GDK_BUTTON_RELEASE) { + return FALSE; + } + + /* get link text from tag */ + if (get_tag_range(iter, tag, &start_iter, + &end_iter) == FALSE) { + return FALSE; + } + link = gtk_text_iter_get_text(&start_iter, &end_iter); + if (link == NULL) { + return FALSE; + } + + bevent = (GdkEventButton *) event; + if (bevent->button == 1 && event->type == GDK_BUTTON_RELEASE) { + GtkTextBuffer *buffer; + + /* we shouldn't follow a link if the user has selected something */ + buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textview)); + gtk_text_buffer_get_selection_bounds(buffer, &start_iter, &end_iter); + if (gtk_text_iter_get_offset(&start_iter) != gtk_text_iter_get_offset(&end_iter)) { + return FALSE; + } + /* open link and do *not* return TRUE so that + further gtk processing of the signal is done */ + open_uri(link, prefs_common.uri_cmd); + + } else { + if (bevent->button == 3 && event->type == GDK_BUTTON_PRESS) { + GtkItemFactory *link_popupfactory; + gint n_entries; + + n_entries = sizeof(textview_link_popup_entries) / + sizeof(textview_link_popup_entries[0]); + link_popupmenu = menu_create_items( + textview_link_popup_entries, n_entries, + "", &link_popupfactory, + textview); + + g_object_set_data( + G_OBJECT(link_popupmenu), + "menu_button", link); + gtk_menu_popup(GTK_MENU(link_popupmenu), + NULL, NULL, NULL, NULL, + bevent->button, bevent->time); + + return TRUE; + } + } + return FALSE; +} + +static void about_open_link_cb(GtkWidget *widget, guint action, void *data) +{ + gchar *link = g_object_get_data(G_OBJECT(link_popupmenu), + "menu_button"); + + if (link == NULL) { + return; + } + + open_uri(link, prefs_common.uri_cmd); + g_object_set_data(G_OBJECT(link_popupmenu), "menu_button", + NULL); +} + +static void about_copy_link_cb(GtkWidget *widget, guint action, void *data) +{ + gchar *link = g_object_get_data(G_OBJECT(link_popupmenu), + "menu_button"); + + if (link == NULL) { + return; + } + + gtk_clipboard_set_text(gtk_clipboard_get(GDK_SELECTION_PRIMARY), link, -1); + gtk_clipboard_set_text(gtk_clipboard_get(GDK_SELECTION_CLIPBOARD), link, -1); + g_object_set_data(G_OBJECT(link_popupmenu), "menu_button", NULL); +} + +static gboolean about_textview_motion_notify(GtkWidget *widget, + GdkEventMotion *event, + GtkWidget *textview) +{ + about_textview_uri_update(textview, event->x, event->y); + gdk_window_get_pointer(widget->window, NULL, NULL, NULL); + + return FALSE; +} + +static gboolean about_textview_leave_notify(GtkWidget *widget, + GdkEventCrossing *event, + GtkWidget *textview) +{ + about_textview_uri_update(textview, -1, -1); + + return FALSE; +} + +static gboolean about_textview_visibility_notify(GtkWidget *widget, + GdkEventVisibility *event, + GtkWidget *textview) +{ + gint wx, wy; + GdkWindow *window; + + window = gtk_text_view_get_window(GTK_TEXT_VIEW(widget), + GTK_TEXT_WINDOW_TEXT); + + /* check if occurred for the text window part */ + if (window != event->window) { + return FALSE; + } + + gdk_window_get_pointer(widget->window, &wx, &wy, NULL); + about_textview_uri_update(textview, wx, wy); + + return FALSE; +} + +static void about_textview_uri_update(GtkWidget *textview, gint x, gint y) +{ + GtkTextBuffer *buffer; + GtkTextIter start_iter, end_iter; + gchar *uri = NULL; + gboolean same; + + buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textview)); + + if (x != -1 && y != -1) { + gint bx, by; + GtkTextIter iter; + GSList *tags; + GSList *cur; + + gtk_text_view_window_to_buffer_coords(GTK_TEXT_VIEW(textview), + GTK_TEXT_WINDOW_WIDGET, + x, y, &bx, &by); + gtk_text_view_get_iter_at_location(GTK_TEXT_VIEW(textview), + &iter, bx, by); + + tags = gtk_text_iter_get_tags(&iter); + for (cur = tags; cur != NULL; cur = cur->next) { + GtkTextTag *tag = cur->data; + char *name; + + g_object_get(G_OBJECT(tag), "name", &name, NULL); + if (strcmp(name, "link") == 0 + && get_tag_range(&iter, tag, &start_iter, &end_iter)) { + uri = gtk_text_iter_get_text(&start_iter, &end_iter); + } + g_free(name); + + if (uri) { + break; + } + } + g_slist_free(tags); + } + + /* compare previous hovered link and this one + (here links must be unique in text buffer otherwise RemoteURI structures should be + used as in textview.c) */ + same = (uri != NULL && uri_hover != NULL + && strcmp((char*)uri, (char*)uri_hover) == 0); + + if (same == FALSE) { + GdkWindow *window; + + if (uri_hover) { + gtk_text_buffer_remove_tag_by_name(buffer, + "link-hover", + &uri_hover_start_iter, + &uri_hover_end_iter); + } + + uri_hover = uri; + if (uri) { + uri_hover_start_iter = start_iter; + uri_hover_end_iter = end_iter; + + gtk_text_buffer_apply_tag_by_name(buffer, + "link-hover", + &start_iter, + &end_iter); + } + + window = gtk_text_view_get_window(GTK_TEXT_VIEW(textview), + GTK_TEXT_WINDOW_TEXT); + if (!hand_cursor) + hand_cursor = gdk_cursor_new(GDK_HAND2); + if (!text_cursor) + text_cursor = gdk_cursor_new(GDK_XTERM); + gdk_window_set_cursor(window, uri ? hand_cursor : text_cursor); + } +} diff --git a/src/gtk/gtkutils.c b/src/gtk/gtkutils.c index 92e3dc7df..6c3e57aca 100644 --- a/src/gtk/gtkutils.c +++ b/src/gtk/gtkutils.c @@ -958,3 +958,28 @@ gint create_xpm_from_xface(gchar *xpm[], const gchar *xface) return 0; } #endif + +gboolean get_tag_range(GtkTextIter *iter, + GtkTextTag *tag, + GtkTextIter *start_iter, + GtkTextIter *end_iter) +{ + GtkTextIter _start_iter, _end_iter; + + _end_iter = *iter; + if (!gtk_text_iter_forward_to_tag_toggle(&_end_iter, tag)) { + debug_print("Can't find end"); + return FALSE; + } + + _start_iter = _end_iter; + if (!gtk_text_iter_backward_to_tag_toggle(&_start_iter, tag)) { + debug_print("Can't find start."); + return FALSE; + } + + *start_iter = _start_iter; + *end_iter = _end_iter; + + return TRUE; +} diff --git a/src/gtk/gtkutils.h b/src/gtk/gtkutils.h index ca979ded5..417a13ffb 100644 --- a/src/gtk/gtkutils.h +++ b/src/gtk/gtkutils.h @@ -187,4 +187,8 @@ GtkWidget *gtkut_get_browse_directory_btn(const gchar *label); #if HAVE_LIBCOMPFACE gint create_xpm_from_xface(gchar *xpm[], const gchar *xface); #endif +gboolean get_tag_range(GtkTextIter *iter, + GtkTextTag *tag, + GtkTextIter *start_iter, + GtkTextIter *end_iter); #endif /* __GTKUTILS_H__ */ diff --git a/src/textview.c b/src/textview.c index 538094327..0ed29a8ee 100644 --- a/src/textview.c +++ b/src/textview.c @@ -1845,24 +1845,7 @@ static gboolean textview_get_uri_range(TextView *textview, GtkTextIter *start_iter, GtkTextIter *end_iter) { - GtkTextIter _start_iter, _end_iter; - - _end_iter = *iter; - if (!gtk_text_iter_forward_to_tag_toggle(&_end_iter, tag)) { - debug_print("Can't find end"); - return FALSE; - } - - _start_iter = _end_iter; - if (!gtk_text_iter_backward_to_tag_toggle(&_start_iter, tag)) { - debug_print("Can't find start."); - return FALSE; - } - - *start_iter = _start_iter; - *end_iter = _end_iter; - - return TRUE; + return get_tag_range(iter, tag, start_iter, end_iter); } static RemoteURI *textview_get_uri_from_range(TextView *textview, -- 2.25.1