📄 st-link.c
字号:
/* * Copyright (c) 2003, 2004 Jean-Yves Lefort * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of Jean-Yves Lefort nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */#include "config.h"#include <glib/gi18n.h>#include <gtk/gtk.h>#include "sgtk-util.h"#include "st-link.h"#include "st-action.h"#include "st-dialog-api.h"#include "st-stock.h"#include "st-util-api.h"/*** type definitions ********************************************************/enum { ACTIVATE, LAST_SIGNAL};struct _STLinkPrivate{ GtkWidget *label; GtkWidget *menu; char *text; char *uri; gboolean in_link;};/*** variable declarations ***************************************************/static GObjectClass *parent_class = NULL;static unsigned int link_signals[LAST_SIGNAL] = { 0 };/*** function declarations ***************************************************/static void st_link_class_init (STLinkClass *class);static void st_link_init (STLink *link);static void st_link_finalize (GObject *object);static void st_link_update_text (STLink *link);static void st_link_update_cursor (STLink *link);static void st_link_activate (STLink *link);static gboolean st_link_expose_event_h (GtkWidget *widget, GdkEventExpose *event, gpointer user_data);static gboolean st_link_enter_notify_event_h (STLink *link, GdkEventCrossing *event, gpointer user_data);static gboolean st_link_leave_notify_event_h (STLink *link, GdkEventCrossing *event, gpointer user_data);static void st_link_open_activate_h (GtkMenuItem *item, gpointer user_data);static void st_link_copy_address_activate_h (GtkMenuItem *item, gpointer user_data);static gboolean st_link_button_release_event_h (STLink *link, GdkEventButton *event, gpointer user_data);static void st_link_open (STLink *link);static void st_link_copy_address (STLink *link);/*** implementation **********************************************************/GTypest_link_get_type (void){ static GType link_type = 0; if (! link_type) { static const GTypeInfo link_info = { sizeof(STLinkClass), NULL, NULL, (GClassInitFunc) st_link_class_init, NULL, NULL, sizeof(STLink), 0, (GInstanceInitFunc) st_link_init, }; link_type = g_type_register_static(GTK_TYPE_EVENT_BOX, "STLink", &link_info, 0); } return link_type;}static voidst_link_class_init (STLinkClass *class){ GObjectClass *object_class = G_OBJECT_CLASS(class); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(class); parent_class = g_type_class_peek_parent(class); g_type_class_add_private(class, sizeof(STLinkPrivate)); object_class->finalize = st_link_finalize; link_signals[ACTIVATE] = g_signal_new ("activate", G_OBJECT_CLASS_TYPE(object_class), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, G_STRUCT_OFFSET(STLinkClass, activate), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); widget_class->activate_signal = link_signals[ACTIVATE]; class->activate = st_link_activate;}static voidst_link_init (STLink *link){ GtkWidget *item; link->priv = G_TYPE_INSTANCE_GET_PRIVATE(link, ST_TYPE_LINK, STLinkPrivate); gtk_event_box_set_visible_window(GTK_EVENT_BOX(link), FALSE); link->priv->menu = gtk_menu_new(); item = gtk_image_menu_item_new_from_stock(ST_STOCK_OPEN_LINK, NULL); gtk_widget_show(item); gtk_menu_shell_append(GTK_MENU_SHELL(link->priv->menu), item); g_signal_connect(item, "activate", G_CALLBACK(st_link_open_activate_h), link); item = gtk_image_menu_item_new_from_stock(ST_STOCK_COPY_LINK_ADDRESS, NULL); gtk_widget_show(item); gtk_menu_shell_append(GTK_MENU_SHELL(link->priv->menu), item); g_signal_connect(item, "activate", G_CALLBACK(st_link_copy_address_activate_h), link); link->priv->label = gtk_label_new(NULL); gtk_container_add(GTK_CONTAINER(link), link->priv->label); gtk_widget_show(link->priv->label); sgtk_widget_set_popup_menu(GTK_WIDGET(link), GTK_MENU(link->priv->menu)); g_object_connect(link, "signal::expose-event", st_link_expose_event_h, NULL, "signal::enter-notify-event", st_link_enter_notify_event_h, NULL, "signal::leave-notify-event", st_link_leave_notify_event_h, NULL, "signal::button-release-event", st_link_button_release_event_h, NULL, NULL);}static voidst_link_finalize (GObject *object){ STLink *link = ST_LINK(object); gtk_widget_destroy(link->priv->menu); g_free(link->priv->text); g_free(link->priv->uri); parent_class->finalize(object);}static voidst_link_update_text (STLink *link){ g_return_if_fail(ST_IS_LINK(link)); if (link->priv->text) { char *markup; if (link->priv->uri) markup = g_strdup_printf("<span underline=\"single\">%s</span>", link->priv->text); else markup = g_strdup(link->priv->text); gtk_label_set_markup(GTK_LABEL(link->priv->label), markup); g_free(markup); } else gtk_label_set_text(GTK_LABEL(link->priv->label), NULL); if (link->priv->uri) { char *tip; tip = g_strdup_printf(_("Visit %s"), link->priv->uri); st_set_tooltip(GTK_WIDGET(link), tip); g_free(tip); } else st_set_tooltip(GTK_WIDGET(link), NULL);}static voidst_link_update_cursor (STLink *link){ g_return_if_fail(ST_IS_LINK(link)); /* GtkWidget->window is only available if the widget is realized. */ if (GTK_WIDGET_REALIZED(GTK_WIDGET(link))) { if (link->priv->uri && link->priv->in_link) { GdkCursor *cursor; /* set the proper cursor */ cursor = gdk_cursor_new(GDK_HAND2); gdk_window_set_cursor(GTK_WIDGET(link)->window, cursor); gdk_cursor_unref(cursor); } else gdk_window_set_cursor(GTK_WIDGET(link)->window, NULL); }}static voidst_link_activate (STLink *link){ if (link->priv->uri) st_link_open(link);}static gbooleanst_link_expose_event_h (GtkWidget *widget, GdkEventExpose *event, gpointer user_data){ if (GTK_WIDGET_DRAWABLE(widget) && GTK_WIDGET_HAS_FOCUS(widget)) { int border_width = GTK_CONTAINER(widget)->border_width; gtk_paint_focus(widget->style, widget->window, GTK_WIDGET_STATE(widget), &event->area, widget, "link", widget->allocation.x + border_width, widget->allocation.y + border_width, widget->allocation.width - border_width * 2, widget->allocation.height - border_width * 2); } return FALSE; /* propagate event */}static gbooleanst_link_enter_notify_event_h (STLink *link, GdkEventCrossing *event, gpointer user_data){ GtkWidget *event_widget; event_widget = gtk_get_event_widget((GdkEvent *) event); if (event_widget == (GtkWidget *) link && event->detail != GDK_NOTIFY_INFERIOR) link->priv->in_link = TRUE; st_link_update_cursor(link); return FALSE;}static gbooleanst_link_leave_notify_event_h (STLink *link, GdkEventCrossing *event, gpointer user_data){ GtkWidget *event_widget; event_widget = gtk_get_event_widget((GdkEvent *) event); if (event_widget == (GtkWidget *) link && event->detail != GDK_NOTIFY_INFERIOR) link->priv->in_link = FALSE; st_link_update_cursor(link); return FALSE;}static voidst_link_open_activate_h (GtkMenuItem *item, gpointer user_data){ STLink *link = user_data; st_link_open(link);}static voidst_link_copy_address_activate_h (GtkMenuItem *item, gpointer user_data){ STLink *link = user_data; st_link_copy_address(link);}static gbooleanst_link_button_release_event_h (STLink *link, GdkEventButton *event, gpointer user_data){ if (event->button == 1 && link->priv->in_link && link->priv->uri) { st_link_open(link); return TRUE; } return FALSE;}static voidst_link_open (STLink *link){ GError *err = NULL; g_return_if_fail(ST_IS_LINK(link)); g_return_if_fail(link->priv->uri != NULL); if (! st_action_run("view-web", link->priv->uri, &err)) { char *normalized; normalized = st_dialog_normalize(err->message); st_error_dialog(_("Unable to visit the link"), "%s", normalized); g_free(normalized); g_error_free(err); }}static voidst_link_copy_address (STLink *link){ GtkClipboard *clipboard; g_return_if_fail(ST_IS_LINK(link)); g_return_if_fail(link->priv->uri != NULL); clipboard = gtk_clipboard_get(gdk_atom_intern("PRIMARY", TRUE)); gtk_clipboard_set_text(clipboard, link->priv->uri, -1);}GtkWidget *st_link_new (void){ return g_object_new(ST_TYPE_LINK, NULL);}/** * st_link_set_text: * @link: a link. * @text: the link label (can contain Pango markup). * * Sets the text label of @link. **/voidst_link_set_text (STLink *link, const char *text){ g_return_if_fail(ST_IS_LINK(link)); g_free(link->priv->text); link->priv->text = g_strdup(text); st_link_update_text(link);}voidst_link_set_uri (STLink *link, const char *uri){ g_return_if_fail(ST_IS_LINK(link)); g_free(link->priv->uri); link->priv->uri = g_strdup(uri); st_link_update_text(link); st_link_update_cursor(link); if (link->priv->uri) { GTK_WIDGET_SET_FLAGS(link, GTK_CAN_FOCUS); sgtk_widget_set_popup_menu(GTK_WIDGET(link), GTK_MENU(link->priv->menu)); } else { GTK_WIDGET_UNSET_FLAGS(link, GTK_CAN_FOCUS); sgtk_widget_set_popup_menu(GTK_WIDGET(link), NULL); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -