Sat, 14 Nov 2020 03:39:06 -0600
Create PidginPresenceIcon that displays the correct icon for its bound PurplePresence
Testing Done:
Tested all presence changes except invisible as I don't have an account that supports it.
Reviewed at https://reviews.imfreedom.org/r/213/
/* * 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 "pidgin/pidginpresenceicon.h" struct _PidginPresenceIcon { GtkImage parent; PurplePresence *presence; gchar *fallback; GtkIconSize icon_size; }; enum { PROP_0, PROP_PRESENCE, PROP_FALLBACK, PROP_ICON_SIZE, N_PROPERTIES }; static GParamSpec *properties[N_PROPERTIES] = { NULL, }; G_DEFINE_TYPE(PidginPresenceIcon, pidgin_presence_icon, GTK_TYPE_IMAGE) /****************************************************************************** * Implementation *****************************************************************************/ static void pidgin_presence_icon_update(PidginPresenceIcon *icon) { const gchar *icon_name = icon->fallback; /* Sorry for the pyramid of doom, couldn't come up with a better way to do * this... */ if(PURPLE_IS_PRESENCE(icon->presence)) { PurpleStatus *status = NULL; status = purple_presence_get_active_status(icon->presence); if(PURPLE_IS_STATUS(status)) { PurpleStatusType *type = purple_status_get_status_type(status); if(type != NULL) { switch(purple_status_type_get_primitive(type)) { case PURPLE_STATUS_OFFLINE: icon_name = "pidgin-user-offline"; break; case PURPLE_STATUS_AVAILABLE: icon_name = "pidgin-user-available"; break; case PURPLE_STATUS_UNAVAILABLE: icon_name = "pidgin-user-unavailable"; break; case PURPLE_STATUS_AWAY: icon_name = "pidgin-user-away"; break; case PURPLE_STATUS_INVISIBLE: icon_name = "pidgin-user-invisible"; break; case PURPLE_STATUS_EXTENDED_AWAY: icon_name = "pidgin-user-extended-away"; break; case PURPLE_STATUS_MOBILE: case PURPLE_STATUS_TUNE: case PURPLE_STATUS_MOOD: case PURPLE_STATUS_UNSET: default: /* Use the fallback which was set above. */ break; } } } } gtk_image_set_from_icon_name(GTK_IMAGE(icon), icon_name, icon->icon_size); } static void pidgin_presence_icon_active_status_changed_cb(GObject *obj, GParamSpec *pspec, gpointer data) { pidgin_presence_icon_update(PIDGIN_PRESENCE_ICON(data)); } /****************************************************************************** * GObject Implementation *****************************************************************************/ static void pidgin_presence_icon_get_property(GObject *obj, guint param_id, GValue *value, GParamSpec *pspec) { PidginPresenceIcon *icon = PIDGIN_PRESENCE_ICON(obj); switch(param_id) { case PROP_PRESENCE: g_value_set_object(value, pidgin_presence_icon_get_presence(icon)); break; case PROP_FALLBACK: g_value_set_string(value, pidgin_presence_icon_get_fallback(icon)); break; case PROP_ICON_SIZE: g_value_set_enum(value, pidgin_presence_icon_get_icon_size(icon)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec); break; } } static void pidgin_presence_icon_set_property(GObject *obj, guint param_id, const GValue *value, GParamSpec *pspec) { PidginPresenceIcon *icon = PIDGIN_PRESENCE_ICON(obj); switch(param_id) { case PROP_PRESENCE: pidgin_presence_icon_set_presence(icon, g_value_get_object(value)); break; case PROP_FALLBACK: pidgin_presence_icon_set_fallback(icon, g_value_get_string(value)); break; case PROP_ICON_SIZE: pidgin_presence_icon_set_icon_size(icon, g_value_get_enum(value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec); break; } } static void pidgin_presence_icon_finalize(GObject *obj) { PidginPresenceIcon *icon = PIDGIN_PRESENCE_ICON(obj); g_clear_object(&icon->presence); g_clear_pointer(&icon->fallback, g_free); G_OBJECT_CLASS(pidgin_presence_icon_parent_class)->finalize(obj); } static void pidgin_presence_icon_init(PidginPresenceIcon *presenceicon) { /* Use the icon name fallback that we're expecting. */ g_object_set(G_OBJECT(presenceicon), "use-fallback", TRUE, NULL); } static void pidgin_presence_icon_class_init(PidginPresenceIconClass *klass) { GObjectClass *obj_class = G_OBJECT_CLASS(klass); obj_class->finalize = pidgin_presence_icon_finalize; obj_class->get_property = pidgin_presence_icon_get_property; obj_class->set_property = pidgin_presence_icon_set_property; /** * PidginPresenceIcon::presence: * * The #PurplePresence that this icon will be representing. */ properties[PROP_PRESENCE] = g_param_spec_object( "presence", "presence", "The presence that this icon is representing", PURPLE_TYPE_PRESENCE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS); /** * PidginPresenceIcon::fallback: * * The name of the icon to use as a fallback when no presence is set. */ properties[PROP_FALLBACK] = g_param_spec_string( "fallback", "fallback", "The name of the icon to use as a fallback", "user-invisible", G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS); /** * PidginPresenceIcon::icon-size: * * The #GtkIconSize that should be used. */ properties[PROP_ICON_SIZE] = g_param_spec_enum( "icon-size", "icon-size", "The GtkIconSize to use", GTK_TYPE_ICON_SIZE, GTK_ICON_SIZE_MENU, G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS); g_object_class_install_properties(obj_class, N_PROPERTIES, properties); } /****************************************************************************** * Public API *****************************************************************************/ GtkWidget * pidgin_presence_icon_new(PurplePresence *presence, const gchar *fallback, GtkIconSize icon_size) { return g_object_new( PIDGIN_TYPE_PRESENCE_ICON, "presence", presence, "fallback", fallback, "icon_size", icon_size, NULL); } PurplePresence * pidgin_presence_icon_get_presence(PidginPresenceIcon *icon) { g_return_val_if_fail(PIDGIN_IS_PRESENCE_ICON(icon), NULL); return icon->presence; } void pidgin_presence_icon_set_presence(PidginPresenceIcon *icon, PurplePresence *presence) { PurplePresence *old = NULL; g_return_if_fail(PIDGIN_IS_PRESENCE_ICON(icon)); /* We only want to disconnect signal handlers if the presence was changed, * but to do that, we need to keep a reference to the old presence. */ if(PURPLE_IS_PRESENCE(icon->presence)) { old = g_object_ref(G_OBJECT(icon->presence)); } if(g_set_object(&icon->presence, presence)) { if(G_IS_OBJECT(old)) { /* If we previously had a presence, disconnect our signal handlers. */ g_signal_handlers_disconnect_by_data(old, icon); } if(PURPLE_IS_PRESENCE(icon->presence)) { g_signal_connect(icon->presence, "notify::active-status", G_CALLBACK(pidgin_presence_icon_active_status_changed_cb), icon); } g_object_freeze_notify(G_OBJECT(icon)); pidgin_presence_icon_update(icon); g_object_notify_by_pspec(G_OBJECT(icon), properties[PROP_PRESENCE]); g_object_thaw_notify(G_OBJECT(icon)); } g_clear_object(&old); } const gchar * pidgin_presence_icon_get_fallback(PidginPresenceIcon *icon) { g_return_val_if_fail(PIDGIN_IS_PRESENCE_ICON(icon), NULL); return icon->fallback; } void pidgin_presence_icon_set_fallback(PidginPresenceIcon *icon, const gchar *fallback) { g_return_if_fail(PIDGIN_IS_PRESENCE_ICON(icon)); g_return_if_fail(fallback != NULL); g_free(icon->fallback); icon->fallback = g_strdup(fallback); g_object_freeze_notify(G_OBJECT(icon)); pidgin_presence_icon_update(icon); g_object_notify_by_pspec(G_OBJECT(icon), properties[PROP_FALLBACK]); g_object_thaw_notify(G_OBJECT(icon)); } GtkIconSize pidgin_presence_icon_get_icon_size(PidginPresenceIcon *icon) { g_return_val_if_fail(PIDGIN_IS_PRESENCE_ICON(icon), GTK_ICON_SIZE_INVALID); return icon->icon_size; } void pidgin_presence_icon_set_icon_size(PidginPresenceIcon *icon, GtkIconSize icon_size) { g_return_if_fail(PIDGIN_IS_PRESENCE_ICON(icon)); icon->icon_size = icon_size; g_object_freeze_notify(G_OBJECT(icon)); pidgin_presence_icon_update(icon); g_object_notify_by_pspec(G_OBJECT(icon), properties[PROP_ICON_SIZE]); g_object_thaw_notify(G_OBJECT(icon)); }