pidgin/gtkimhtml.c

branch
imhtml.customlinks
changeset 24698
f9dd7117ade0
parent 24675
9b6a40a095fb
child 25007
ef8bc1f4a6ba
equal deleted inserted replaced
24697:0e771f0ae1c5 24698:f9dd7117ade0
86 struct im_image_data { 86 struct im_image_data {
87 int id; 87 int id;
88 GtkTextMark *mark; 88 GtkTextMark *mark;
89 }; 89 };
90 90
91 struct _GtkIMHtmlLink
92 {
93 GtkIMHtml *imhtml;
94 gchar *url;
95 GtkTextTag *tag;
96 };
97
91 typedef struct _GtkIMHtmlProtocol 98 typedef struct _GtkIMHtmlProtocol
92 { 99 {
93 char *name; 100 char *name;
94 int length; 101 int length;
95 102
96 gboolean (*activate)(GtkIMHtml *imhtml, const char *text); 103 gboolean (*activate)(GtkIMHtml *imhtml, GtkIMHtmlLink *link);
97 gboolean (*context_menu)(GtkIMHtml *imhtml, const char *text, GtkWidget *menu); 104 gboolean (*context_menu)(GtkIMHtml *imhtml, GtkIMHtmlLink *link, GtkWidget *menu);
98 } GtkIMHtmlProtocol; 105 } GtkIMHtmlProtocol;
99 106
100 static gboolean 107 static gboolean
101 gtk_text_view_drag_motion (GtkWidget *widget, 108 gtk_text_view_drag_motion (GtkWidget *widget,
102 GdkDragContext *context, 109 GdkDragContext *context,
123 static void imhtml_toggle_underline(GtkIMHtml *imhtml); 130 static void imhtml_toggle_underline(GtkIMHtml *imhtml);
124 static void imhtml_font_grow(GtkIMHtml *imhtml); 131 static void imhtml_font_grow(GtkIMHtml *imhtml);
125 static void imhtml_font_shrink(GtkIMHtml *imhtml); 132 static void imhtml_font_shrink(GtkIMHtml *imhtml);
126 static void imhtml_clear_formatting(GtkIMHtml *imhtml); 133 static void imhtml_clear_formatting(GtkIMHtml *imhtml);
127 static int gtk_imhtml_is_protocol(const char *text); 134 static int gtk_imhtml_is_protocol(const char *text);
135 static void gtk_imhtml_activate_tag(GtkIMHtml *imhtml, GtkTextTag *tag);
136 static void gtk_imhtml_link_destroy(GtkIMHtmlLink *link);
128 137
129 /* POINT_SIZE converts from AIM font sizes to a point size scale factor. */ 138 /* POINT_SIZE converts from AIM font sizes to a point size scale factor. */
130 #define MAX_FONT_SIZE 7 139 #define MAX_FONT_SIZE 7
131 #define POINT_SIZE(x) (_point_sizes [MIN ((x > 0 ? x : 1), MAX_FONT_SIZE) - 1]) 140 #define POINT_SIZE(x) (_point_sizes [MIN ((x > 0 ? x : 1), MAX_FONT_SIZE) - 1])
132 static const gdouble _point_sizes [] = { .85, .95, 1, 1.2, 1.44, 1.728, 2.0736}; 141 static const gdouble _point_sizes [] = { .85, .95, 1, 1.2, 1.44, 1.728, 2.0736};
1420 1429
1421 static void 1430 static void
1422 imhtml_url_clicked(GtkIMHtml *imhtml, const char *url) 1431 imhtml_url_clicked(GtkIMHtml *imhtml, const char *url)
1423 { 1432 {
1424 GtkIMHtmlProtocol *proto = imhtml_find_protocol(url); 1433 GtkIMHtmlProtocol *proto = imhtml_find_protocol(url);
1434 GtkIMHtmlLink *link;
1425 if (!proto) 1435 if (!proto)
1426 return; 1436 return;
1427 proto->activate(imhtml, url); /* XXX: Do something with the return value? */ 1437 link = g_new0(GtkIMHtmlLink, 1);
1438 link->imhtml = g_object_ref(imhtml);
1439 link->url = g_strdup(url);
1440 proto->activate(imhtml, link); /* XXX: Do something with the return value? */
1441 gtk_imhtml_link_destroy(link);
1428 } 1442 }
1429 1443
1430 /* Boring GTK+ stuff */ 1444 /* Boring GTK+ stuff */
1431 static void gtk_imhtml_class_init (GtkIMHtmlClass *klass) 1445 static void gtk_imhtml_class_init (GtkIMHtmlClass *klass)
1432 { 1446 {
1723 } 1737 }
1724 1738
1725 return imhtml_type; 1739 return imhtml_type;
1726 } 1740 }
1727 1741
1728 struct url_data { 1742 static void gtk_imhtml_link_destroy(GtkIMHtmlLink *link)
1729 GObject *object; 1743 {
1730 gchar *url; 1744 if (link->imhtml)
1731 GtkTextTag *tag; 1745 g_object_unref(link->imhtml);
1732 }; 1746 if (link->tag)
1733 1747 g_object_unref(link->tag);
1734 static void url_data_destroy(gpointer mydata) 1748 g_free(link->url);
1735 { 1749 g_free(link);
1736 struct url_data *data = mydata;
1737 g_object_unref(data->object);
1738 g_object_unref(data->tag);
1739 g_free(data->url);
1740 g_free(data);
1741 }
1742
1743 static void url_open(GtkWidget *w, struct url_data *data)
1744 {
1745 if(!data) return;
1746 g_signal_emit(data->object, signals[URL_CLICKED], 0, data->url);
1747 g_object_set_data(G_OBJECT(data->tag), "visited", GINT_TO_POINTER(TRUE));
1748 gtk_imhtml_set_link_color(GTK_IMHTML(data->object), data->tag);
1749 }
1750
1751 static void url_copy(GtkWidget *w, gchar *url) {
1752 GtkClipboard *clipboard;
1753
1754 clipboard = gtk_widget_get_clipboard(w, GDK_SELECTION_PRIMARY);
1755 gtk_clipboard_set_text(clipboard, url, -1);
1756
1757 clipboard = gtk_widget_get_clipboard(w, GDK_SELECTION_CLIPBOARD);
1758 gtk_clipboard_set_text(clipboard, url, -1);
1759 } 1750 }
1760 1751
1761 /* The callback for an event on a link tag. */ 1752 /* The callback for an event on a link tag. */
1762 static gboolean tag_event(GtkTextTag *tag, GObject *imhtml, GdkEvent *event, GtkTextIter *arg2, gpointer unused) 1753 static gboolean tag_event(GtkTextTag *tag, GObject *imhtml, GdkEvent *event, GtkTextIter *arg2, gpointer unused)
1763 { 1754 {
1769 GtkTextIter start, end; 1760 GtkTextIter start, end;
1770 /* we shouldn't open a URL if the user has selected something: */ 1761 /* we shouldn't open a URL if the user has selected something: */
1771 if (gtk_text_buffer_get_selection_bounds( 1762 if (gtk_text_buffer_get_selection_bounds(
1772 gtk_text_iter_get_buffer(arg2), &start, &end)) 1763 gtk_text_iter_get_buffer(arg2), &start, &end))
1773 return FALSE; 1764 return FALSE;
1774 1765 gtk_imhtml_activate_tag(GTK_IMHTML(imhtml), tag);
1775 /* A link was clicked--we emit the "url_clicked" signal
1776 * with the URL as the argument */
1777 g_object_ref(G_OBJECT(tag));
1778 g_signal_emit(imhtml, signals[URL_CLICKED], 0, g_object_get_data(G_OBJECT(tag), "link_url"));
1779 g_object_unref(G_OBJECT(tag));
1780 g_object_set_data(G_OBJECT(tag), "visited", GINT_TO_POINTER(TRUE));
1781 gtk_imhtml_set_link_color(GTK_IMHTML(imhtml), tag);
1782 return FALSE; 1766 return FALSE;
1783 } else if(event_button->button == 3) { 1767 } else if(event_button->button == 3) {
1784 GtkWidget *img, *item, *menu; 1768 GList *children;
1769 GtkWidget *menu;
1785 GtkIMHtmlProtocol *proto; 1770 GtkIMHtmlProtocol *proto;
1786 struct url_data *tempdata = g_new(struct url_data, 1); 1771 GtkIMHtmlLink *link = g_new(GtkIMHtmlLink, 1);
1787 tempdata->object = g_object_ref(imhtml); 1772 link->imhtml = g_object_ref(imhtml);
1788 tempdata->url = g_strdup(g_object_get_data(G_OBJECT(tag), "link_url")); 1773 link->url = g_strdup(g_object_get_data(G_OBJECT(tag), "link_url"));
1789 tempdata->tag = g_object_ref(tag); 1774 link->tag = g_object_ref(tag);
1790 1775
1791 /* Don't want the tooltip around if user right-clicked on link */ 1776 /* Don't want the tooltip around if user right-clicked on link */
1792 if (GTK_IMHTML(imhtml)->tip_window) { 1777 if (GTK_IMHTML(imhtml)->tip_window) {
1793 gtk_widget_destroy(GTK_IMHTML(imhtml)->tip_window); 1778 gtk_widget_destroy(GTK_IMHTML(imhtml)->tip_window);
1794 GTK_IMHTML(imhtml)->tip_window = NULL; 1779 GTK_IMHTML(imhtml)->tip_window = NULL;
1800 if (GTK_IMHTML(imhtml)->editable) 1785 if (GTK_IMHTML(imhtml)->editable)
1801 gdk_window_set_cursor(event_button->window, GTK_IMHTML(imhtml)->text_cursor); 1786 gdk_window_set_cursor(event_button->window, GTK_IMHTML(imhtml)->text_cursor);
1802 else 1787 else
1803 gdk_window_set_cursor(event_button->window, GTK_IMHTML(imhtml)->arrow_cursor); 1788 gdk_window_set_cursor(event_button->window, GTK_IMHTML(imhtml)->arrow_cursor);
1804 menu = gtk_menu_new(); 1789 menu = gtk_menu_new();
1805 g_object_set_data_full(G_OBJECT(menu), "x-imhtml-url-data", tempdata, url_data_destroy); 1790 g_object_set_data_full(G_OBJECT(menu), "x-imhtml-url-data", link,
1806 1791 (GDestroyNotify)gtk_imhtml_link_destroy);
1807 proto = imhtml_find_protocol(tempdata->url); 1792
1808 1793 proto = imhtml_find_protocol(link->url);
1809 if (!strncmp(tempdata->url, "mailto:", 7)) 1794
1810 { 1795 if (proto && proto->context_menu) {
1811 /* Copy Email Address */ 1796 proto->context_menu(GTK_IMHTML(link->imhtml), link, menu);
1812 img = gtk_image_new_from_stock(GTK_STOCK_COPY, 1797 }
1813 GTK_ICON_SIZE_MENU); 1798
1814 item = gtk_image_menu_item_new_with_mnemonic( 1799 children = gtk_container_get_children(GTK_CONTAINER(menu));
1815 _("_Copy Email Address")); 1800 if (!children) {
1816 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), img); 1801 GtkWidget *item = gtk_menu_item_new_with_label(_("No actions available"));
1817 g_signal_connect(G_OBJECT(item), "activate", 1802 gtk_widget_show(item);
1818 G_CALLBACK(url_copy), tempdata->url + 7); 1803 gtk_widget_set_sensitive(item, FALSE);
1819 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); 1804 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
1820 } 1805 } else {
1821 else if (proto && proto->context_menu) 1806 g_list_free(children);
1822 {
1823 GList *children;
1824 proto->context_menu(GTK_IMHTML(tempdata->object), tempdata->url, menu);
1825 children = gtk_container_get_children(GTK_CONTAINER(menu));
1826 if (!children) {
1827 item = gtk_menu_item_new_with_label(_("No actions available"));
1828 gtk_widget_show(item);
1829 gtk_widget_set_sensitive(item, FALSE);
1830 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
1831 } else {
1832 g_list_free(children);
1833 }
1834 }
1835 else
1836 {
1837 /* Open Link in Browser */
1838 img = gtk_image_new_from_stock(GTK_STOCK_JUMP_TO,
1839 GTK_ICON_SIZE_MENU);
1840 item = gtk_image_menu_item_new_with_mnemonic(
1841 _("_Open Link"));
1842 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), img);
1843 g_signal_connect(G_OBJECT(item), "activate",
1844 G_CALLBACK(url_open), tempdata);
1845 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
1846
1847 /* Copy Link Location */
1848 img = gtk_image_new_from_stock(GTK_STOCK_COPY,
1849 GTK_ICON_SIZE_MENU);
1850 item = gtk_image_menu_item_new_with_mnemonic(
1851 _("_Copy Link Location"));
1852 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), img);
1853 g_signal_connect(G_OBJECT(item), "activate",
1854 G_CALLBACK(url_copy), tempdata->url);
1855 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
1856 } 1807 }
1857 1808
1858 1809
1859 gtk_widget_show_all(menu); 1810 gtk_widget_show_all(menu);
1860 gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, 1811 gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL,
5795 g_object_unref(smiley->loader); 5746 g_object_unref(smiley->loader);
5796 g_free(smiley); 5747 g_free(smiley);
5797 } 5748 }
5798 5749
5799 gboolean gtk_imhtml_class_register_protocol(const char *name, 5750 gboolean gtk_imhtml_class_register_protocol(const char *name,
5800 gboolean (*activate)(GtkIMHtml *imhtml, const char *text), 5751 gboolean (*activate)(GtkIMHtml *imhtml, GtkIMHtmlLink *link),
5801 gboolean (*context_menu)(GtkIMHtml *imhtml, const char *text, GtkWidget *menu)) 5752 gboolean (*context_menu)(GtkIMHtml *imhtml, GtkIMHtmlLink *link, GtkWidget *menu))
5802 { 5753 {
5803 GtkIMHtmlClass *klass; 5754 GtkIMHtmlClass *klass;
5804 GtkIMHtmlProtocol *proto; 5755 GtkIMHtmlProtocol *proto;
5805 5756
5806 g_return_val_if_fail(name, FALSE); 5757 g_return_val_if_fail(name, FALSE);
5826 klass->protocols = g_list_prepend(klass->protocols, proto); 5777 klass->protocols = g_list_prepend(klass->protocols, proto);
5827 5778
5828 return TRUE; 5779 return TRUE;
5829 } 5780 }
5830 5781
5782 static void
5783 gtk_imhtml_activate_tag(GtkIMHtml *imhtml, GtkTextTag *tag)
5784 {
5785 /* A link was clicked--we emit the "url_clicked" signal
5786 * with the URL as the argument */
5787 g_object_ref(G_OBJECT(tag));
5788 g_signal_emit(imhtml, signals[URL_CLICKED], 0, g_object_get_data(G_OBJECT(tag), "link_url"));
5789 g_object_unref(G_OBJECT(tag));
5790 g_object_set_data(G_OBJECT(tag), "visited", GINT_TO_POINTER(TRUE));
5791 gtk_imhtml_set_link_color(GTK_IMHTML(imhtml), tag);
5792 }
5793
5794 gboolean gtk_imhtml_link_activate(GtkIMHtmlLink *link)
5795 {
5796 g_return_val_if_fail(link, FALSE);
5797
5798 if (link->tag) {
5799 gtk_imhtml_activate_tag(link->imhtml, link->tag);
5800 } else if (link->url) {
5801 g_signal_emit(link->imhtml, signals[URL_CLICKED], 0, link->url);
5802 } else
5803 return FALSE;
5804 return TRUE;
5805 }
5806
5807 const char *gtk_imhtml_link_get_url(GtkIMHtmlLink *link)
5808 {
5809 return link->url;
5810 }
5811
5812 const GtkTextTag * gtk_imhtml_link_get_text_tag(GtkIMHtmlLink *link)
5813 {
5814 return link->tag;
5815 }
5816

mercurial