Fri, 06 Dec 2024 15:18:29 -0600
Add Pidgin.Badges to Pidgin.Message
Also switch to the normal icon size instead of large.
Testing Done:
Joined an irc server with /r/3694 and sent some messages.
Reviewed at https://reviews.imfreedom.org/r/3695/
/* * Purple - Internet Messaging Library * Copyright (C) Pidgin Developers <devel@pidgin.im> * * Purple 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 library 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 library 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 library; if not, see <https://www.gnu.org/licenses/>. */ #include <birb.h> #include "purplecommand.h" #include "util.h" struct _PurpleCommand { GObject parent; char *icon_name; GDateTime *last_used; char *name; int priority; char *source; char *summary; PurpleTags *tags; guint use_count; }; enum { PROP_0, PROP_ICON_NAME, PROP_LAST_USED, PROP_NAME, PROP_PRIORITY, PROP_SOURCE, PROP_SUMMARY, PROP_TAGS, PROP_USE_COUNT, N_PROPERTIES, }; static GParamSpec *properties[N_PROPERTIES] = {NULL, }; enum { SIG_EXECUTED, N_SIGNALS, }; static guint signals[N_SIGNALS] = {0, }; /****************************************************************************** * Helpers *****************************************************************************/ static void purple_command_set_name(PurpleCommand *command, const char *name) { g_return_if_fail(PURPLE_IS_COMMAND(command)); g_return_if_fail(!purple_strempty(name)); if(g_set_str(&command->name, name)) { g_object_notify_by_pspec(G_OBJECT(command), properties[PROP_NAME]); } } static void purple_command_set_source(PurpleCommand *command, const char *source) { g_return_if_fail(PURPLE_IS_COMMAND(command)); g_return_if_fail(!purple_strempty(source)); if(g_set_str(&command->source, source)) { g_object_notify_by_pspec(G_OBJECT(command), properties[PROP_SOURCE]); } } static void purple_command_set_priority(PurpleCommand *command, int priority) { g_return_if_fail(PURPLE_IS_COMMAND(command)); if(command->priority != priority) { command->priority = priority; g_object_notify_by_pspec(G_OBJECT(command), properties[PROP_PRIORITY]); } } /****************************************************************************** * Default Handlers *****************************************************************************/ static void purple_command_default_executed_handler(PurpleCommand *command, G_GNUC_UNUSED PurpleConversation *conversation, G_GNUC_UNUSED GStrv params) { GDateTime *now = NULL; GObject *obj = G_OBJECT(command); /* We're going to set multiple properties, so we need to freeze property * notifications. */ g_object_freeze_notify(obj); /* We use local time as this should be user specific. */ now = g_date_time_new_now_local(); purple_command_set_last_used(command, now); birb_date_time_clear(&now); if(command->use_count < G_MAXUINT32) { purple_command_set_use_count(command, command->use_count + 1); } g_object_thaw_notify(obj); } /****************************************************************************** * GObject Implementation *****************************************************************************/ G_DEFINE_FINAL_TYPE(PurpleCommand, purple_command, G_TYPE_OBJECT) static void purple_command_finalize(GObject *obj) { PurpleCommand *command = PURPLE_COMMAND(obj); g_clear_pointer(&command->icon_name, g_free); birb_date_time_clear(&command->last_used); g_clear_pointer(&command->name, g_free); g_clear_pointer(&command->source, g_free); g_clear_pointer(&command->summary, g_free); g_clear_object(&command->tags); G_OBJECT_CLASS(purple_command_parent_class)->finalize(obj); } static void purple_command_get_property(GObject *obj, guint param_id, GValue *value, GParamSpec *pspec) { PurpleCommand *command = PURPLE_COMMAND(obj); switch(param_id) { case PROP_ICON_NAME: g_value_set_string(value, purple_command_get_icon_name(command)); break; case PROP_LAST_USED: g_value_set_boxed(value, purple_command_get_last_used(command)); break; case PROP_NAME: g_value_set_string(value, purple_command_get_name(command)); break; case PROP_PRIORITY: g_value_set_int(value, purple_command_get_priority(command)); break; case PROP_SOURCE: g_value_set_string(value, purple_command_get_source(command)); break; case PROP_SUMMARY: g_value_set_string(value, purple_command_get_summary(command)); break; case PROP_TAGS: g_value_set_object(value, purple_command_get_tags(command)); break; case PROP_USE_COUNT: g_value_set_uint(value, purple_command_get_use_count(command)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec); break; } } static void purple_command_set_property(GObject *obj, guint param_id, const GValue *value, GParamSpec *pspec) { PurpleCommand *command = PURPLE_COMMAND(obj); switch(param_id) { case PROP_ICON_NAME: purple_command_set_icon_name(command, g_value_get_string(value)); break; case PROP_LAST_USED: purple_command_set_last_used(command, g_value_get_boxed(value)); break; case PROP_NAME: purple_command_set_name(command, g_value_get_string(value)); break; case PROP_PRIORITY: purple_command_set_priority(command, g_value_get_int(value)); break; case PROP_SOURCE: purple_command_set_source(command, g_value_get_string(value)); break; case PROP_SUMMARY: purple_command_set_summary(command, g_value_get_string(value)); break; case PROP_USE_COUNT: purple_command_set_use_count(command, g_value_get_uint(value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec); break; } } static void purple_command_init(PurpleCommand *command) { command->tags = purple_tags_new(); } static void purple_command_class_init(PurpleCommandClass *klass) { GObjectClass *obj_class = G_OBJECT_CLASS(klass); obj_class->finalize = purple_command_finalize; obj_class->get_property = purple_command_get_property; obj_class->set_property = purple_command_set_property; /** * PurpleCommand:icon-name: * * The icon name for the command. * * Since: 3.0 */ properties[PROP_ICON_NAME] = g_param_spec_string( "icon-name", NULL, NULL, NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); /** * PurpleCommand:last-used: * * The date time of when the command was last used. * * Since: 3.0 */ properties[PROP_LAST_USED] = g_param_spec_boxed( "last-used", NULL, NULL, G_TYPE_DATE_TIME, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); /** * PurpleCommand:name: * * The name of the command. * * This is what the user would type after the prefix that the user * interface is using. If the user interface is using `/`, then this would * be `me` for the `/me` command. * * Since: 3.0 */ properties[PROP_NAME] = g_param_spec_string( "name", NULL, NULL, NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); /** * PurpleCommand:priority: * * The priority for the command. * * If multiple commands have the same name, this will be used to determine * which one to return or sort first. Higher values will have higher * priority. * * Since: 3.0 */ properties[PROP_PRIORITY] = g_param_spec_int( "priority", NULL, NULL, G_MININT32, G_MAXINT32, 0, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); /** * PurpleCommand:source: * * The source of the command. * * This is a user visible string that user interfaces can display to help * users determine what this command is from. For example, this could be * `IRC`, `XMPP`, `my cool plugin`, etc. * * Since: 3.0 */ properties[PROP_SOURCE] = g_param_spec_string( "source", NULL, NULL, NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); /** * PurpleCommand:summary: * * A summary of the command. * * This is a user visible string that user interfaces can display to help * users determine what this command will do. * * Since: 3.0 */ properties[PROP_SUMMARY] = g_param_spec_string( "summary", NULL, NULL, NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); /** * PurpleCommand:tags: * * The [class@Tags] for the command. * * These tags will be used with [property@Conversation:tags] in a call to * [method@Tags.contains] to determine if the command is valid for a * conversation. Likewise, if this doesn't contain any tags, it will match * all conversations. * * Since: 3.0 */ properties[PROP_TAGS] = g_param_spec_object( "tags", NULL, NULL, PURPLE_TYPE_TAGS, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); /** * PurpleCommand:use-count: * * The count of how many times the command has been used. * * Since: 3.0 */ properties[PROP_USE_COUNT] = g_param_spec_uint( "use-count", NULL, NULL, 0, G_MAXUINT32, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_properties(obj_class, N_PROPERTIES, properties); /** * PurpleCommand::executed: * @command: The instance. * @conversation: (nullable): The conversation this command was run from. * @params: (nullable): The parameters passed to the command. * * Emitted when [method@Command.execute] is called. * * Since: 3.0 */ signals[SIG_EXECUTED] = g_signal_new_class_handler( "executed", G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_LAST, G_CALLBACK(purple_command_default_executed_handler), NULL, NULL, NULL, G_TYPE_NONE, 2, PURPLE_TYPE_CONVERSATION, G_TYPE_STRV); } /****************************************************************************** * Public API *****************************************************************************/ void purple_command_execute(PurpleCommand *command, PurpleConversation *conversation, const char *params) { GStrv paramsv = NULL; g_return_if_fail(PURPLE_IS_COMMAND(command)); if(params != NULL) { paramsv = g_strsplit(params, " ", -1); } purple_command_executev(command, conversation, paramsv); g_clear_pointer(¶msv, g_strfreev); } void purple_command_executev(PurpleCommand *command, PurpleConversation *conversation, GStrv params) { g_return_if_fail(PURPLE_IS_COMMAND(command)); g_signal_emit(G_OBJECT(command), signals[SIG_EXECUTED], 0, conversation, params); } const char * purple_command_get_icon_name(PurpleCommand *command) { g_return_val_if_fail(PURPLE_IS_COMMAND(command), NULL); return command->icon_name; } GDateTime * purple_command_get_last_used(PurpleCommand *command) { g_return_val_if_fail(PURPLE_IS_COMMAND(command), NULL); return command->last_used; } const char * purple_command_get_name(PurpleCommand *command) { g_return_val_if_fail(PURPLE_IS_COMMAND(command), NULL); return command->name; } int purple_command_get_priority(PurpleCommand *command) { g_return_val_if_fail(PURPLE_IS_COMMAND(command), 0); return command->priority; } const char * purple_command_get_source(PurpleCommand *command) { g_return_val_if_fail(PURPLE_IS_COMMAND(command), NULL); return command->source; } const char * purple_command_get_summary(PurpleCommand *command) { g_return_val_if_fail(PURPLE_IS_COMMAND(command), NULL); return command->summary; } PurpleTags * purple_command_get_tags(PurpleCommand *command) { g_return_val_if_fail(PURPLE_IS_COMMAND(command), NULL); return command->tags; } guint purple_command_get_use_count(PurpleCommand *command) { g_return_val_if_fail(PURPLE_IS_COMMAND(command), 0); return command->use_count; } PurpleCommand * purple_command_new(const char *name, const char *source, int priority) { g_return_val_if_fail(!purple_strempty(name), NULL); g_return_val_if_fail(!purple_strempty(source), NULL); return g_object_new( PURPLE_TYPE_COMMAND, "name", name, "source", source, "priority", priority, NULL); } void purple_command_set_icon_name(PurpleCommand *command, const char *icon_name) { g_return_if_fail(PURPLE_IS_COMMAND(command)); if(g_set_str(&command->icon_name, icon_name)) { g_object_notify_by_pspec(G_OBJECT(command), properties[PROP_ICON_NAME]); } } void purple_command_set_last_used(PurpleCommand *command, GDateTime *last_used) { g_return_if_fail(PURPLE_IS_COMMAND(command)); if(birb_date_time_set(&command->last_used, last_used)) { g_object_notify_by_pspec(G_OBJECT(command), properties[PROP_LAST_USED]); } } void purple_command_set_summary(PurpleCommand *command, const char *summary) { g_return_if_fail(PURPLE_IS_COMMAND(command)); if(g_set_str(&command->summary, summary)) { g_object_notify_by_pspec(G_OBJECT(command), properties[PROP_SUMMARY]); } } void purple_command_set_use_count(PurpleCommand *command, guint use_count) { g_return_if_fail(PURPLE_IS_COMMAND(command)); if(command->use_count != use_count) { command->use_count = use_count; g_object_notify_by_pspec(G_OBJECT(command), properties[PROP_USE_COUNT]); } }