diff --git a/libpurple/protocol.h b/libpurple/protocol.h
--- a/libpurple/protocol.h
+++ b/libpurple/protocol.h
@@ -132,6 +132,8 @@
  * PurpleProtocol:
  *
  * Represents an instance of a protocol registered with #PurpleProtocolManager.
+ *
+ * Since: 3.0.0
  */
 
 /**
@@ -185,6 +187,8 @@
  *
  * Returns: %TRUE if a protocol implements a function in an interface,
  *          %FALSE otherwise.
+ *
+ * Since: 3.0.0
  */
 #define PURPLE_PROTOCOL_IMPLEMENTS(protocol, IFACE, func) \
 	(PURPLE_IS_PROTOCOL_##IFACE(protocol) && \
@@ -343,6 +347,56 @@
  */
 const gchar *purple_protocol_get_list_icon(PurpleProtocol *protocol, PurpleAccount *account, PurpleBuddy *buddy);
 
+/**
+ * purple_protocol_get_icon_name:
+ * @protocol: The #PurpleProtocol instance.
+ *
+ * Gets the name of the icon that the protocol made available via either
+ * purple_protocol_get_icon_search_path() or
+ * purple_protocol_get_resource_path().
+ *
+ * Returns: The name of the icon for @protocol.
+ *
+ * Since: 3.0.0
+ */
+const gchar *purple_protocol_get_icon_name(PurpleProtocol *protocol);
+
+/**
+ * purple_protocol_get_icon_search_path:
+ * @protocol: The #PurpleProtocol instance.
+ *
+ * Gets the icon search path for @protocol. This is used to allow protocol
+ * plugins to install their icons in any XDG icon theme compliant directory.
+ * The returned value should be the path of where the icons are on disk. See
+ * gtk_icon_theme_add_search_path() for additional information.
+ *
+ * User interfaces will look for icons in this path named
+ * %chat-<protocol-name> where protocol-name is the name property of @protocol.
+ *
+ * Returns: The file system path where the icons can be found.
+ *
+ * Since: 3.0.0
+ */
+const gchar *purple_protocol_get_icon_search_path(PurpleProtocol *protocol);
+
+/**
+ * purple_protocol_get_icon_resource_path:
+ * @protocol: The #PurpleProtocol instance.
+ *
+ * Gets the icon resource path for @protocol. This is used to make icons that
+ * have been embedded into a plugin available to libpurple. The returned value
+ * should be the path of where the icons are in the resource. See
+ * gtk_icon_theme_add_resource_path() for additional information.
+ *
+ * User interfaces will look for icons in this path named
+ * %chat-<protocol-name> where protocol-name is the name property of @protocol.
+ *
+ * Returns: The gresource path where the icons can be found.
+ *
+ * Since: 3.0.0
+ */
+const gchar *purple_protocol_get_icon_resource_path(PurpleProtocol *protocol);
+
 G_END_DECLS
 
 #endif /* PURPLE_PROTOCOL_H */
# HG changeset patch
# Node ID 4e7a90c391af
# Parent  82a21ea342d8
diff --git a/libpurple/protocol.c b/libpurple/protocol.c
--- a/libpurple/protocol.c
+++ b/libpurple/protocol.c
@@ -29,6 +29,9 @@
 	PROP_ID,
 	PROP_NAME,
 	PROP_DESCRIPTION,
+	PROP_ICON_NAME,
+	PROP_ICON_SEARCH_PATH,
+	PROP_ICON_RESOURCE_PATH,
 	PROP_OPTIONS,
 	N_PROPERTIES,
 };
@@ -39,6 +42,10 @@
 	gchar *name;
 	gchar *description;
 
+	gchar *icon_name;
+	gchar *icon_search_path;
+	gchar *icon_resource_path;
+
 	PurpleProtocolOptions options;
 } PurpleProtocolPrivate;
 
@@ -82,6 +89,50 @@
 }
 
 static void
+purple_protocol_set_icon_name(PurpleProtocol *protocol,
+                              const gchar *icon_name)
+{
+	PurpleProtocolPrivate *priv = NULL;
+
+	priv = purple_protocol_get_instance_private(protocol);
+
+	g_free(priv->icon_name);
+	priv->icon_name = g_strdup(icon_name);
+
+	g_object_notify_by_pspec(G_OBJECT(protocol), properties[PROP_ICON_NAME]);
+}
+
+static void
+purple_protocol_set_icon_search_path(PurpleProtocol *protocol,
+                                     const gchar *path)
+{
+	PurpleProtocolPrivate *priv = NULL;
+
+	priv = purple_protocol_get_instance_private(protocol);
+
+	g_free(priv->icon_search_path);
+	priv->icon_search_path = g_strdup(path);
+
+	g_object_notify_by_pspec(G_OBJECT(protocol),
+	                         properties[PROP_ICON_SEARCH_PATH]);
+}
+
+static void
+purple_protocol_set_icon_resource_path(PurpleProtocol *protocol,
+                                       const gchar *path)
+{
+	PurpleProtocolPrivate *priv = NULL;
+
+	priv = purple_protocol_get_instance_private(protocol);
+
+	g_free(priv->icon_resource_path);
+	priv->icon_resource_path = g_strdup(path);
+
+	g_object_notify_by_pspec(G_OBJECT(protocol),
+	                         properties[PROP_ICON_RESOURCE_PATH]);
+}
+
+static void
 purple_protocol_set_options(PurpleProtocol *protocol,
                             PurpleProtocolOptions options)
 {
@@ -110,7 +161,19 @@
 			g_value_set_string(value, purple_protocol_get_name(protocol));
 			break;
 		case PROP_DESCRIPTION:
-			g_value_set_string(value, purple_protocol_get_description(protocol));
+			g_value_set_string(value,
+			                   purple_protocol_get_description(protocol));
+			break;
+		case PROP_ICON_NAME:
+			g_value_set_string(value, purple_protocol_get_icon_name(protocol));
+			break;
+		case PROP_ICON_SEARCH_PATH:
+			g_value_set_string(value,
+			                   purple_protocol_get_icon_search_path(protocol));
+			break;
+		case PROP_ICON_RESOURCE_PATH:
+			g_value_set_string(value,
+			                   purple_protocol_get_icon_resource_path(protocol));
 			break;
 		case PROP_OPTIONS:
 			g_value_set_flags(value, purple_protocol_get_options(protocol));
@@ -135,7 +198,19 @@
 			purple_protocol_set_name(protocol, g_value_get_string(value));
 			break;
 		case PROP_DESCRIPTION:
-			purple_protocol_set_description(protocol, g_value_get_string(value));
+			purple_protocol_set_description(protocol,
+			                                g_value_get_string(value));
+			break;
+		case PROP_ICON_NAME:
+			purple_protocol_set_icon_name(protocol, g_value_get_string(value));
+			break;
+		case PROP_ICON_SEARCH_PATH:
+			purple_protocol_set_icon_search_path(protocol,
+			                                     g_value_get_string(value));
+			break;
+		case PROP_ICON_RESOURCE_PATH:
+			purple_protocol_set_icon_resource_path(protocol,
+			                                       g_value_get_string(value));
 			break;
 		case PROP_OPTIONS:
 			purple_protocol_set_options(protocol, g_value_get_flags(value));
@@ -203,6 +278,8 @@
 	 * PurpleProtocol::id:
 	 *
 	 * The identifier for the protocol.
+	 *
+	 * Since: 3.0.0
 	 */
 	properties[PROP_ID] = g_param_spec_string(
 		"id", "id",
@@ -214,6 +291,8 @@
 	 * PurpleProtocol::name:
 	 *
 	 * The name to show in user interface for the protocol.
+	 *
+	 * Since: 3.0.0
 	 */
 	properties[PROP_NAME] = g_param_spec_string(
 		"name", "name",
@@ -225,6 +304,8 @@
 	 * PurpleProtocol::description:
 	 *
 	 * The description to show in user interface for the protocol.
+	 *
+	 * Since: 3.0.0
 	 */
 	properties[PROP_DESCRIPTION] = g_param_spec_string(
 		"description", "description",
@@ -233,9 +314,55 @@
 		G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
 
 	/**
+	 * PurpleProtocol::icon-name:
+	 *
+	 * The name of an icon that has been installed to either the path specified
+	 * via PurpleProtocol::icon-search-path or
+	 * PurpleProtocol::icon-resource-path.
+	 *
+	 * Since: 3.0.0
+	 */
+	properties[PROP_ICON_NAME] = g_param_spec_string(
+		"icon-name", "icon-name",
+		"The name of the XDG icon.",
+		NULL,
+		G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
+
+	/**
+	 * PurpleProtocol::icon-search-path:
+	 *
+	 * The path to an XDG Icon Theme directory which contains the icons for the
+	 * protocol. See purple_protocol_get_icon_search_path() for more
+	 * information.
+	 *
+	 * Since: 3.0.0
+	 */
+	properties[PROP_ICON_SEARCH_PATH] = g_param_spec_string(
+		"icon-search-path", "icon-search-path",
+		"The path to an XDG Icon Theme directory.",
+		NULL,
+		G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
+
+	/**
+	 * PurpleProtocol::icon-resource-path:
+	 *
+	 * A #GResource path which contains the icons for the protocol. See
+	 * purple_protocol_get_icon_resource_path() for more information.
+	 *
+	 * Since: 3.0.0
+	 */
+	properties[PROP_ICON_RESOURCE_PATH] = g_param_spec_string(
+		"icon-resource-path", "icon-resource-path",
+		"The GResource path to the icons.",
+		NULL,
+		G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
+
+	/**
 	 * PurpleProtocol::options:
 	 *
 	 * The #PurpleProtocolOptions for the protocol.
+	 *
+	 * Since: 3.0.0
 	 */
 	properties[PROP_OPTIONS] = g_param_spec_flags(
 		"options", "options",
@@ -283,6 +410,39 @@
 	return priv->description;
 }
 
+const gchar *
+purple_protocol_get_icon_name(PurpleProtocol *protocol) {
+	PurpleProtocolPrivate *priv = NULL;
+
+	g_return_val_if_fail(PURPLE_IS_PROTOCOL(protocol), NULL);
+
+	priv = purple_protocol_get_instance_private(protocol);
+
+	return priv->icon_name;
+}
+
+const gchar *
+purple_protocol_get_icon_search_path(PurpleProtocol *protocol) {
+	PurpleProtocolPrivate *priv = NULL;
+
+	g_return_val_if_fail(PURPLE_IS_PROTOCOL(protocol), NULL);
+
+	priv = purple_protocol_get_instance_private(protocol);
+
+	return priv->icon_search_path;
+}
+
+const gchar *
+purple_protocol_get_icon_resource_path(PurpleProtocol *protocol) {
+	PurpleProtocolPrivate *priv = NULL;
+
+	g_return_val_if_fail(PURPLE_IS_PROTOCOL(protocol), NULL);
+
+	priv = purple_protocol_get_instance_private(protocol);
+
+	return priv->icon_resource_path;
+}
+
 PurpleProtocolOptions
 purple_protocol_get_options(PurpleProtocol *protocol) {
 	PurpleProtocolPrivate *priv = NULL;
diff --git a/libpurple/protocols/irc/irc.c b/libpurple/protocols/irc/irc.c
--- a/libpurple/protocols/irc/irc.c
+++ b/libpurple/protocols/irc/irc.c
@@ -1164,8 +1164,10 @@
 		"id", "prpl-irc",
 		"name", "IRC",
 		"description", "Internet Relay Chat (IRC) is a text-based chat system",
+		"icon-name", "im-irc",
+		"icon-resource-path", "/im/pidgin/libpurple/irc/icons",
 		"options", OPT_PROTO_CHAT_TOPIC | OPT_PROTO_PASSWORD_OPTIONAL |
-	               OPT_PROTO_SLASH_COMMANDS_NATIVE,
+		           OPT_PROTO_SLASH_COMMANDS_NATIVE,
 		NULL));
 }
 
diff --git a/libpurple/protocols/irc/meson.build b/libpurple/protocols/irc/meson.build
--- a/libpurple/protocols/irc/meson.build
+++ b/libpurple/protocols/irc/meson.build
@@ -8,6 +8,12 @@
 ]
 
 if DYNAMIC_IRC
+	irc_resources = gnome.compile_resources('ircresource',
+		'resources/irc.gresource.xml',
+		source_dir : 'resources',
+		c_name : 'irc')
+	IRC_SOURCES += irc_resources
+
 	irc_prpl = shared_library('irc', IRC_SOURCES,
 	    dependencies : [sasl, libpurple_dep, glib, gio, ws2_32],
 	    install : true, install_dir : PURPLE_PLUGINDIR)
diff --git a/libpurple/protocols/irc/resources/irc.gresource.xml b/libpurple/protocols/irc/resources/irc.gresource.xml
new file mode 100644
--- /dev/null
+++ b/libpurple/protocols/irc/resources/irc.gresource.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<gresources>
+  <gresource prefix="/im/pidgin/libpurple/irc">
+    <file>icons/16x16/apps/im-irc.png</file>
+    <file>icons/16x16/apps/scalable/im-irc.svg</file>
+    <file>icons/22x22/apps/im-irc.png</file>
+    <file>icons/22x22/apps/scalable/im-irc.svg</file>
+    <file>icons/48x48/apps/im-irc.png</file>
+    <file>icons/scalable/apps/im-irc.svg</file>
+  </gresource>
+</gresources>
diff --git a/pidgin/data/icons/hicolor/16x16/apps/im-irc.png b/libpurple/protocols/irc/resources/icons/16x16/apps/im-irc.png
rename from pidgin/data/icons/hicolor/16x16/apps/im-irc.png
rename to libpurple/protocols/irc/resources/icons/16x16/apps/im-irc.png
diff --git a/pidgin/data/icons/hicolor/16x16/apps/scalable/im-irc.svg b/libpurple/protocols/irc/resources/icons/16x16/apps/scalable/im-irc.svg
rename from pidgin/data/icons/hicolor/16x16/apps/scalable/im-irc.svg
rename to libpurple/protocols/irc/resources/icons/16x16/apps/scalable/im-irc.svg
diff --git a/pidgin/data/icons/hicolor/22x22/apps/im-irc.png b/libpurple/protocols/irc/resources/icons/22x22/apps/im-irc.png
rename from pidgin/data/icons/hicolor/22x22/apps/im-irc.png
rename to libpurple/protocols/irc/resources/icons/22x22/apps/im-irc.png
diff --git a/pidgin/data/icons/hicolor/22x22/apps/scalable/im-irc.svg b/libpurple/protocols/irc/resources/icons/22x22/apps/scalable/im-irc.svg
rename from pidgin/data/icons/hicolor/22x22/apps/scalable/im-irc.svg
rename to libpurple/protocols/irc/resources/icons/22x22/apps/scalable/im-irc.svg
diff --git a/pidgin/data/icons/hicolor/48x48/apps/im-irc.png b/libpurple/protocols/irc/resources/icons/48x48/apps/im-irc.png
rename from pidgin/data/icons/hicolor/48x48/apps/im-irc.png
rename to libpurple/protocols/irc/resources/icons/48x48/apps/im-irc.png
diff --git a/pidgin/data/icons/hicolor/scalable/apps/im-irc.svg b/libpurple/protocols/irc/resources/icons/scalable/apps/im-irc.svg
rename from pidgin/data/icons/hicolor/scalable/apps/im-irc.svg
rename to libpurple/protocols/irc/resources/icons/scalable/apps/im-irc.svg
diff --git a/pidgin/gtkutils.c b/pidgin/gtkutils.c
--- a/pidgin/gtkutils.c
+++ b/pidgin/gtkutils.c
@@ -254,12 +254,39 @@
 }
 
 GdkPixbuf *
-pidgin_create_icon_from_protocol(PurpleProtocol *protocol, PidginProtocolIconSize size, PurpleAccount *account)
+pidgin_create_icon_from_protocol(PurpleProtocol *protocol,
+                                 PidginProtocolIconSize size,
+                                 PurpleAccount *account)
 {
+	GInputStream *stream = NULL;
+	GdkPixbuf *pixbuf;
 	const char *protoname = NULL;
+	const gchar *icon_name = NULL;
 	char *tmp;
 	char *filename = NULL;
-	GdkPixbuf *pixbuf;
+
+	/* If the protocol specified an icon-name try to load it from the icon
+	 * theme.
+	 */
+	icon_name = purple_protocol_get_icon_name(protocol);
+	if(icon_name != NULL) {
+		GtkIconTheme *theme = gtk_icon_theme_get_default();
+		gint dimensions = 48;
+
+		if(size == PIDGIN_PROTOCOL_ICON_SMALL) {
+			dimensions = 16;
+		} else if(size == PIDGIN_PROTOCOL_ICON_MEDIUM) {
+			dimensions = 22;
+		}
+
+		pixbuf = gtk_icon_theme_load_icon(theme, icon_name, dimensions,
+		                                  GTK_ICON_LOOKUP_FORCE_SIZE, NULL);
+
+		if(GDK_IS_PIXBUF(pixbuf)) {
+			return pixbuf;
+		}
+
+	}
 
 	protoname = purple_protocol_get_list_icon(protocol, account, NULL);
 	if (protoname == NULL)
diff --git a/pidgin/libpidgin.c b/pidgin/libpidgin.c
--- a/pidgin/libpidgin.c
+++ b/pidgin/libpidgin.c
@@ -155,6 +155,36 @@
 #endif /* !_WIN32 */
 
 static void
+purple_ui_add_protocol_theme_paths(PurpleProtocol *protocol) {
+	GtkIconTheme *theme = NULL;
+	const gchar *path = NULL;
+
+	theme = gtk_icon_theme_get_default();
+
+	path = purple_protocol_get_icon_search_path(protocol);
+	if(path != NULL) {
+		gtk_icon_theme_prepend_search_path(theme, path);
+	}
+
+	path = purple_protocol_get_icon_resource_path(protocol);
+	if(path != NULL) {
+		gtk_icon_theme_add_resource_path(theme, path);
+	}
+}
+
+static void
+purple_ui_protocol_foreach_theme_cb(PurpleProtocol *protocol, gpointer data) {
+	purple_ui_add_protocol_theme_paths(protocol);
+}
+
+static void
+purple_ui_protocol_registered_cb(PurpleProtocolManager *manager,
+                                 PurpleProtocol *protocol)
+{
+	purple_ui_add_protocol_theme_paths(protocol);
+}
+
+static void
 debug_init(void)
 {
 	PidginDebugUi *ui = pidgin_debug_ui_new();
@@ -164,6 +194,7 @@
 static void
 pidgin_ui_init(void)
 {
+	PurpleProtocolManager *protocol_manager = NULL;
 	GtkIconTheme *theme = NULL;
 	gchar *path;
 
@@ -173,6 +204,19 @@
 	gtk_icon_theme_prepend_search_path(theme, path);
 	g_free(path);
 
+	/* Add a callback for when a protocol is registered to add its icon paths
+	 * if it was found after initial startup.
+	 */
+	protocol_manager = purple_protocol_manager_get_default();
+	g_signal_connect(protocol_manager, "registered",
+	                 G_CALLBACK(purple_ui_protocol_registered_cb), NULL);
+
+	/* Add the icon paths for all the protocols that libpurple found at start
+	 * up.
+	 */
+	purple_protocol_manager_foreach(protocol_manager,
+	                                purple_ui_protocol_foreach_theme_cb, NULL);
+
 	pidgin_stock_init();
 
 	/* Set the UI operation structures. */
