pidgin/pidgin

Add some new methods to purple tags
default tip
12 minutes ago, Gary Kramlich
b45add2a840c
Add some new methods to purple tags

* purple_tags_exists is a simplier version of purple_tags_lookup.
* purple_tags_contains makes it easier to find multiple matching tags.

Testing Done:
Ran the unit tests under valgrind and had the turtles check in on things too.

Reviewed at https://reviews.imfreedom.org/r/3143/
/*
* Pidgin - Internet Messenger
* Copyright (C) Pidgin Developers <devel@pidgin.im>
*
* Pidgin is the legal property of its developers, whose names are too numerous
* to list here. Please refer to the COPYRIGHT file distributed with this
* source distribution.
*
* 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, see <https://www.gnu.org/licenses/>.
*/
#include "pidginpluginsmenu.h"
#include "pidginapplication.h"
#include <gplugin.h>
#include <purple.h>
struct _PidginPluginsMenu {
GMenuModel parent;
GQueue *plugins;
};
G_DEFINE_FINAL_TYPE(PidginPluginsMenu, pidgin_plugins_menu, G_TYPE_MENU_MODEL)
/******************************************************************************
* Helpers
*****************************************************************************/
static void
pidgin_plugins_menu_add_item(gpointer data, gpointer user_data) {
PidginPluginsMenu *menu = user_data;
GPluginPlugin *plugin = data;
GPluginPluginInfo *info = NULL;
info = gplugin_plugin_get_info(plugin);
if(PURPLE_IS_PLUGIN_INFO(info)) {
GActionGroup *group = NULL;
group = purple_plugin_info_get_action_group(PURPLE_PLUGIN_INFO(info));
if(G_IS_ACTION_GROUP(group)) {
GApplication *application = g_application_get_default();
const gchar *prefix;
prefix = gplugin_plugin_info_get_id(info);
pidgin_application_add_action_group(PIDGIN_APPLICATION(application),
prefix, group);
g_queue_push_tail(menu->plugins, g_object_ref(plugin));
}
}
g_clear_object(&info);
}
static void
pidgin_plugins_menu_refresh(PidginPluginsMenu *menu) {
GPluginManager *manager = NULL;
GSList *loaded = NULL;
gint removed = 0, added = 0;
removed = g_queue_get_length(menu->plugins);
g_queue_clear_full(menu->plugins, g_object_unref);
manager = gplugin_manager_get_default();
loaded = gplugin_manager_find_plugins_with_state(manager,
GPLUGIN_PLUGIN_STATE_LOADED);
g_slist_foreach(loaded, pidgin_plugins_menu_add_item, menu);
g_slist_free_full(loaded, g_object_unref);
added = g_queue_get_length(menu->plugins);
/* Tell our listeners that our menu has changed. */
g_menu_model_items_changed(G_MENU_MODEL(menu), 0, removed, added);
}
/******************************************************************************
* Callbacks
*****************************************************************************/
static void
pidgin_plugins_menu_plugin_loaded_cb(G_GNUC_UNUSED GObject *manager,
G_GNUC_UNUSED GPluginPlugin *plugin,
gpointer data)
{
pidgin_plugins_menu_refresh(PIDGIN_PLUGINS_MENU(data));
}
static void
pidgin_plugins_menu_plugin_unloaded_cb(G_GNUC_UNUSED GObject *manager,
GPluginPlugin *plugin,
gpointer data)
{
GApplication *application = NULL;
GPluginPluginInfo *info = NULL;
const gchar *prefix;
/* Remove the action group that the plugin added. */
info = gplugin_plugin_get_info(plugin);
if(GPLUGIN_IS_PLUGIN_INFO(info)) {
prefix = gplugin_plugin_info_get_id(info);
if(prefix != NULL) {
application = g_application_get_default();
pidgin_application_add_action_group(PIDGIN_APPLICATION(application),
prefix, NULL);
}
}
/* Refresh the list */
pidgin_plugins_menu_refresh(PIDGIN_PLUGINS_MENU(data));
}
/******************************************************************************
* GMenuModel Implementation
*****************************************************************************/
static gboolean
pidgin_plugins_menu_is_mutable(G_GNUC_UNUSED GMenuModel *model) {
return TRUE;
}
static gint
pidgin_plugins_menu_get_n_items(GMenuModel *model) {
PidginPluginsMenu *menu = PIDGIN_PLUGINS_MENU(model);
return g_queue_get_length(menu->plugins);
}
static void
pidgin_plugins_menu_get_item_attributes(GMenuModel *model, gint index,
GHashTable **attributes)
{
PidginPluginsMenu *menu = PIDGIN_PLUGINS_MENU(model);
GPluginPlugin *plugin = NULL;
GPluginPluginInfo *info = NULL;
GVariant *value = NULL;
/* Create our hash table of attributes to return. */
*attributes = g_hash_table_new_full(g_str_hash, g_str_equal, NULL,
(GDestroyNotify)g_variant_unref);
/* Get the plugin the caller is interested in. */
plugin = g_queue_peek_nth(menu->plugins, index);
if(plugin == NULL) {
return;
}
/* Grab the plugin info and set the label attribute to the name of the
* plugin and set the action name space to the plugin's id.
*/
info = gplugin_plugin_get_info(plugin);
value = g_variant_new_string(gplugin_plugin_info_get_name(info));
g_hash_table_insert(*attributes, G_MENU_ATTRIBUTE_LABEL,
g_variant_ref_sink(value));
g_object_unref(info);
}
static void
pidgin_plugins_menu_get_item_links(GMenuModel *model, gint index,
GHashTable **links)
{
PidginPluginsMenu *menu = PIDGIN_PLUGINS_MENU(model);
PurplePluginInfo *purple_info = NULL;
GPluginPlugin *plugin = NULL;
GPluginPluginInfo *info = NULL;
GMenuModel *actions_model = NULL;
*links = g_hash_table_new_full(g_str_hash, g_str_equal, NULL,
g_object_unref);
plugin = g_queue_peek_nth(menu->plugins, index);
if(!GPLUGIN_IS_PLUGIN(plugin)) {
return;
}
info = gplugin_plugin_get_info(plugin);
purple_info = PURPLE_PLUGIN_INFO(info);
/* We need to use a section for the ACTION_NAMESPACE attribute to work, so
* create a menu, and add a new section item to it with the menu from the
* plugin, then set the ACTION_NAMESPACE attribute. Finally return the menu
* as the submenu.
*/
actions_model = purple_plugin_info_get_action_menu(purple_info);
if(G_IS_MENU_MODEL(actions_model)) {
GMenu *menu = NULL;
GMenuItem *section = NULL;
menu = g_menu_new();
section = g_menu_item_new_section(NULL, actions_model);
g_menu_item_set_attribute(section, G_MENU_ATTRIBUTE_ACTION_NAMESPACE,
"s", gplugin_plugin_info_get_id(info));
g_menu_append_item(menu, section);
g_object_unref(section);
g_hash_table_insert(*links, G_MENU_LINK_SUBMENU, menu);
}
g_object_unref(info);
}
/******************************************************************************
* GObject Implementation
*****************************************************************************/
static void
pidgin_plugins_menu_finalize(GObject *obj) {
PidginPluginsMenu *menu = PIDGIN_PLUGINS_MENU(obj);
g_queue_free_full(menu->plugins, g_object_unref);
G_OBJECT_CLASS(pidgin_plugins_menu_parent_class)->finalize(obj);
}
static void
pidgin_plugins_menu_constructed(GObject *obj) {
G_OBJECT_CLASS(pidgin_plugins_menu_parent_class)->constructed(obj);
pidgin_plugins_menu_refresh(PIDGIN_PLUGINS_MENU(obj));
}
static void
pidgin_plugins_menu_init(PidginPluginsMenu *menu) {
GPluginManager *manager = NULL;
menu->plugins = g_queue_new();
/* Connect to the plugin manager's signals so we can stay up to date. */
manager = gplugin_manager_get_default();
g_signal_connect_object(manager, "loaded-plugin",
G_CALLBACK(pidgin_plugins_menu_plugin_loaded_cb),
menu, 0);
g_signal_connect_object(manager, "unloaded-plugin",
G_CALLBACK(pidgin_plugins_menu_plugin_unloaded_cb),
menu, 0);
};
static void
pidgin_plugins_menu_class_init(PidginPluginsMenuClass *klass) {
GObjectClass *obj_class = G_OBJECT_CLASS(klass);
GMenuModelClass *model_class = G_MENU_MODEL_CLASS(klass);
obj_class->finalize = pidgin_plugins_menu_finalize;
obj_class->constructed = pidgin_plugins_menu_constructed;
model_class->is_mutable = pidgin_plugins_menu_is_mutable;
model_class->get_n_items = pidgin_plugins_menu_get_n_items;
model_class->get_item_attributes = pidgin_plugins_menu_get_item_attributes;
model_class->get_item_links = pidgin_plugins_menu_get_item_links;
}
/******************************************************************************
* Public API
*****************************************************************************/
GMenuModel *
pidgin_plugins_menu_new(void) {
return g_object_new(PIDGIN_TYPE_PLUGINS_MENU, NULL);
}