Sat, 09 Aug 2025 17:37:27 +0800
Fix the birb header path
The birb header referred would only work with birb provided by wrap casuing
build to fail because of system-installed birb dependency. The commit points
it to the correct path <birb.h>.
See: https://keep.imfreedom.org/birb/birb/file/5bf00c7d7f80/birb/meson.build#l77
| 42918 | 1 | /* |
| 2 | * Purple - Internet Messaging Library | |
| 3 | * Copyright (C) Pidgin Developers <devel@pidgin.im> | |
| 4 | * | |
| 5 | * Purple is the legal property of its developers, whose names are too numerous | |
| 6 | * to list here. Please refer to the COPYRIGHT file distributed with this | |
| 7 | * source distribution. | |
| 8 | * | |
| 9 | * This library is free software; you can redistribute it and/or modify it | |
| 10 | * under the terms of the GNU General Public License as published by the Free | |
| 11 | * Software Foundation; either version 2 of the License, or (at your option) | |
| 12 | * any later version. | |
| 13 | * | |
| 14 | * This library is distributed in the hope that it will be useful, but WITHOUT | |
| 15 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 16 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
| 17 | * more details. | |
| 18 | * | |
| 19 | * You should have received a copy of the GNU General Public License along with | |
| 20 | * this library; if not, see <https://www.gnu.org/licenses/>. | |
| 21 | */ | |
| 22 | ||
| 23 | #include <gio/gio.h> | |
| 24 | ||
| 25 | #include "purplebadges.h" | |
| 26 | ||
| 27 | #include "util.h" | |
| 28 | ||
| 29 | struct _PurpleBadges { | |
| 30 | GObject parent; | |
| 31 | ||
| 32 | GPtrArray *badges; | |
| 33 | }; | |
| 34 | ||
| 35 | enum { | |
| 36 | PROP_0, | |
| 37 | PROP_ITEM_TYPE, | |
| 38 | PROP_N_ITEMS, | |
| 39 | N_PROPERTIES, | |
| 40 | }; | |
| 41 | static GParamSpec *properties[N_PROPERTIES] = {NULL, }; | |
| 42 | ||
| 43 | /****************************************************************************** | |
| 44 | * GListModel Implementation | |
| 45 | *****************************************************************************/ | |
| 46 | static GType | |
| 47 | purple_badges_get_item_type(G_GNUC_UNUSED GListModel *model) { | |
| 48 | return PURPLE_TYPE_BADGE; | |
| 49 | } | |
| 50 | ||
| 51 | static guint | |
| 52 | purple_badges_get_n_items(GListModel *model) { | |
| 53 | PurpleBadges *badges = PURPLE_BADGES(model); | |
| 54 | ||
| 55 | return badges->badges->len; | |
| 56 | } | |
| 57 | ||
| 58 | static gpointer | |
| 59 | purple_badges_get_item(GListModel *model, guint position) { | |
| 60 | PurpleBadges *badges = PURPLE_BADGES(model); | |
| 61 | PurpleBadge *badge = NULL; | |
| 62 | ||
| 63 | if(position < badges->badges->len) { | |
| 64 | badge = g_ptr_array_index(badges->badges, position); | |
| 65 | ||
| 66 | if(PURPLE_IS_BADGE(badge)) { | |
| 67 | g_object_ref(badge); | |
| 68 | } | |
| 69 | } | |
| 70 | ||
| 71 | return badge; | |
| 72 | } | |
| 73 | ||
| 74 | static void | |
| 75 | purple_badges_list_model_init(GListModelInterface *iface) { | |
| 76 | iface->get_item_type = purple_badges_get_item_type; | |
| 77 | iface->get_n_items = purple_badges_get_n_items; | |
| 78 | iface->get_item = purple_badges_get_item; | |
| 79 | } | |
| 80 | ||
| 81 | /****************************************************************************** | |
| 82 | * GObject Implementation | |
| 83 | *****************************************************************************/ | |
| 84 | G_DEFINE_FINAL_TYPE_WITH_CODE(PurpleBadges, purple_badges, G_TYPE_OBJECT, | |
| 85 | G_IMPLEMENT_INTERFACE(G_TYPE_LIST_MODEL, | |
| 86 | purple_badges_list_model_init)) | |
| 87 | ||
| 88 | static void | |
| 89 | purple_badges_finalize(GObject *obj) { | |
| 90 | PurpleBadges *badges = PURPLE_BADGES(obj); | |
| 91 | ||
| 92 | g_clear_pointer(&badges->badges, g_ptr_array_unref); | |
| 93 | ||
| 94 | G_OBJECT_CLASS(purple_badges_parent_class)->finalize(obj); | |
| 95 | } | |
| 96 | ||
| 97 | static void | |
| 98 | purple_badges_get_property(GObject *obj, guint param_id, GValue *value, | |
| 99 | GParamSpec *pspec) | |
| 100 | { | |
| 101 | GListModel *model = G_LIST_MODEL(obj); | |
| 102 | ||
| 103 | switch(param_id) { | |
| 104 | case PROP_ITEM_TYPE: | |
| 105 | g_value_set_gtype(value, g_list_model_get_item_type(model)); | |
| 106 | break; | |
| 107 | case PROP_N_ITEMS: | |
| 108 | g_value_set_uint(value, g_list_model_get_n_items(model)); | |
| 109 | break; | |
| 110 | default: | |
| 111 | G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec); | |
| 112 | break; | |
| 113 | } | |
| 114 | } | |
| 115 | ||
| 116 | static void | |
| 117 | purple_badges_init(PurpleBadges *badges) { | |
| 118 | badges->badges = g_ptr_array_new_full(0, g_object_unref); | |
| 119 | } | |
| 120 | ||
| 121 | static void | |
| 122 | purple_badges_class_init(PurpleBadgesClass *klass) { | |
| 123 | GObjectClass *obj_class = G_OBJECT_CLASS(klass); | |
| 124 | ||
| 125 | obj_class->finalize = purple_badges_finalize; | |
| 126 | obj_class->get_property = purple_badges_get_property; | |
| 127 | ||
| 128 | /** | |
| 129 | * PurpleBadges:item-type: | |
| 130 | * | |
|
42984
818220289e67
Update the gi-docgen subproject and fix some new issues it found
Gary Kramlich <grim@reaperworld.com>
parents:
42918
diff
changeset
|
131 | * The type of items. See [vfunc@Gio.ListModel.get_item_type]. |
| 42918 | 132 | * |
| 133 | * Since: 3.0 | |
| 134 | */ | |
| 135 | properties[PROP_ITEM_TYPE] = g_param_spec_gtype( | |
| 136 | "item-type", NULL, NULL, | |
| 137 | PURPLE_TYPE_BADGE, | |
| 138 | G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); | |
| 139 | ||
| 140 | /** | |
| 141 | * PurpleBadges:n-items: | |
| 142 | * | |
|
42984
818220289e67
Update the gi-docgen subproject and fix some new issues it found
Gary Kramlich <grim@reaperworld.com>
parents:
42918
diff
changeset
|
143 | * The number of items. See [vfunc@Gio.ListModel.get_n_items]. |
| 42918 | 144 | * |
| 145 | * Since: 3.0 | |
| 146 | */ | |
| 147 | properties[PROP_N_ITEMS] = g_param_spec_uint( | |
| 148 | "n-items", NULL, NULL, | |
| 149 | 0, G_MAXUINT, 0, | |
| 150 | G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); | |
| 151 | ||
| 152 | g_object_class_install_properties(obj_class, N_PROPERTIES, properties); | |
| 153 | } | |
| 154 | ||
| 155 | /****************************************************************************** | |
| 156 | * Public API | |
| 157 | *****************************************************************************/ | |
| 158 | gboolean | |
| 159 | purple_badges_add_badge(PurpleBadges *badges, PurpleBadge *badge) { | |
| 160 | gboolean found = FALSE; | |
| 161 | guint len = 0; | |
| 162 | ||
| 163 | g_return_val_if_fail(PURPLE_IS_BADGES(badges), FALSE); | |
| 164 | g_return_val_if_fail(PURPLE_IS_BADGE(badge), FALSE); | |
| 165 | ||
| 166 | found = g_ptr_array_find_with_equal_func(badges->badges, badge, | |
|
43202
1c2e548285f3
Add a badges-changed signal to Purple.ConversationMember and fix the items changed emissions
Gary Kramlich <grim@reaperworld.com>
parents:
43180
diff
changeset
|
167 | (GEqualFunc)purple_badge_equal, |
|
1c2e548285f3
Add a badges-changed signal to Purple.ConversationMember and fix the items changed emissions
Gary Kramlich <grim@reaperworld.com>
parents:
43180
diff
changeset
|
168 | NULL); |
| 42918 | 169 | |
| 170 | if(found) { | |
| 171 | return FALSE; | |
| 172 | } | |
| 173 | ||
| 174 | /* Store length before adding to make the math easier to understand. */ | |
| 175 | len = badges->badges->len; | |
| 176 | ||
| 177 | g_ptr_array_add(badges->badges, g_object_ref(badge)); | |
|
43202
1c2e548285f3
Add a badges-changed signal to Purple.ConversationMember and fix the items changed emissions
Gary Kramlich <grim@reaperworld.com>
parents:
43180
diff
changeset
|
178 | g_ptr_array_sort_values(badges->badges, (GCompareFunc)purple_badge_compare); |
| 42918 | 179 | |
| 180 | g_list_model_items_changed(G_LIST_MODEL(badges), 0, len, len + 1); | |
|
43128
1ce3ad90614c
Make sure we notify on the n-items property for all objects that have it
Gary Kramlich <grim@reaperworld.com>
parents:
42984
diff
changeset
|
181 | g_object_notify_by_pspec(G_OBJECT(badges), properties[PROP_N_ITEMS]); |
| 42918 | 182 | |
| 183 | return TRUE; | |
| 184 | } | |
| 185 | ||
|
43180
cafab5224c86
Implement Purple.Badges.compare
Gary Kramlich <grim@reaperworld.com>
parents:
43128
diff
changeset
|
186 | int |
|
cafab5224c86
Implement Purple.Badges.compare
Gary Kramlich <grim@reaperworld.com>
parents:
43128
diff
changeset
|
187 | purple_badges_compare(PurpleBadges *badges1, PurpleBadges *badges2) { |
|
cafab5224c86
Implement Purple.Badges.compare
Gary Kramlich <grim@reaperworld.com>
parents:
43128
diff
changeset
|
188 | guint n_badges1 = 0; |
|
cafab5224c86
Implement Purple.Badges.compare
Gary Kramlich <grim@reaperworld.com>
parents:
43128
diff
changeset
|
189 | guint n_badges2 = 0; |
|
cafab5224c86
Implement Purple.Badges.compare
Gary Kramlich <grim@reaperworld.com>
parents:
43128
diff
changeset
|
190 | guint n_badges = 0; |
|
cafab5224c86
Implement Purple.Badges.compare
Gary Kramlich <grim@reaperworld.com>
parents:
43128
diff
changeset
|
191 | |
|
cafab5224c86
Implement Purple.Badges.compare
Gary Kramlich <grim@reaperworld.com>
parents:
43128
diff
changeset
|
192 | /* NULL checks. */ |
|
cafab5224c86
Implement Purple.Badges.compare
Gary Kramlich <grim@reaperworld.com>
parents:
43128
diff
changeset
|
193 | if(badges1 == badges2) { |
|
cafab5224c86
Implement Purple.Badges.compare
Gary Kramlich <grim@reaperworld.com>
parents:
43128
diff
changeset
|
194 | return 0; |
|
cafab5224c86
Implement Purple.Badges.compare
Gary Kramlich <grim@reaperworld.com>
parents:
43128
diff
changeset
|
195 | } |
|
cafab5224c86
Implement Purple.Badges.compare
Gary Kramlich <grim@reaperworld.com>
parents:
43128
diff
changeset
|
196 | |
|
cafab5224c86
Implement Purple.Badges.compare
Gary Kramlich <grim@reaperworld.com>
parents:
43128
diff
changeset
|
197 | if(PURPLE_IS_BADGES(badges1) && !PURPLE_IS_BADGES(badges2)) { |
|
cafab5224c86
Implement Purple.Badges.compare
Gary Kramlich <grim@reaperworld.com>
parents:
43128
diff
changeset
|
198 | return -1; |
|
cafab5224c86
Implement Purple.Badges.compare
Gary Kramlich <grim@reaperworld.com>
parents:
43128
diff
changeset
|
199 | } |
|
cafab5224c86
Implement Purple.Badges.compare
Gary Kramlich <grim@reaperworld.com>
parents:
43128
diff
changeset
|
200 | |
|
cafab5224c86
Implement Purple.Badges.compare
Gary Kramlich <grim@reaperworld.com>
parents:
43128
diff
changeset
|
201 | if(PURPLE_IS_BADGES(badges2) && !PURPLE_IS_BADGES(badges1)) { |
|
cafab5224c86
Implement Purple.Badges.compare
Gary Kramlich <grim@reaperworld.com>
parents:
43128
diff
changeset
|
202 | return 1; |
|
cafab5224c86
Implement Purple.Badges.compare
Gary Kramlich <grim@reaperworld.com>
parents:
43128
diff
changeset
|
203 | } |
|
cafab5224c86
Implement Purple.Badges.compare
Gary Kramlich <grim@reaperworld.com>
parents:
43128
diff
changeset
|
204 | |
|
cafab5224c86
Implement Purple.Badges.compare
Gary Kramlich <grim@reaperworld.com>
parents:
43128
diff
changeset
|
205 | n_badges1 = badges1->badges->len; |
|
cafab5224c86
Implement Purple.Badges.compare
Gary Kramlich <grim@reaperworld.com>
parents:
43128
diff
changeset
|
206 | n_badges2 = badges2->badges->len; |
|
cafab5224c86
Implement Purple.Badges.compare
Gary Kramlich <grim@reaperworld.com>
parents:
43128
diff
changeset
|
207 | |
|
cafab5224c86
Implement Purple.Badges.compare
Gary Kramlich <grim@reaperworld.com>
parents:
43128
diff
changeset
|
208 | /* Empty checks. */ |
|
cafab5224c86
Implement Purple.Badges.compare
Gary Kramlich <grim@reaperworld.com>
parents:
43128
diff
changeset
|
209 | if(n_badges1 > 0 && n_badges2 == 0) { |
|
cafab5224c86
Implement Purple.Badges.compare
Gary Kramlich <grim@reaperworld.com>
parents:
43128
diff
changeset
|
210 | return -1; |
|
cafab5224c86
Implement Purple.Badges.compare
Gary Kramlich <grim@reaperworld.com>
parents:
43128
diff
changeset
|
211 | } |
|
cafab5224c86
Implement Purple.Badges.compare
Gary Kramlich <grim@reaperworld.com>
parents:
43128
diff
changeset
|
212 | |
|
cafab5224c86
Implement Purple.Badges.compare
Gary Kramlich <grim@reaperworld.com>
parents:
43128
diff
changeset
|
213 | if(n_badges1 == 0 && n_badges2 > 0) { |
|
cafab5224c86
Implement Purple.Badges.compare
Gary Kramlich <grim@reaperworld.com>
parents:
43128
diff
changeset
|
214 | return 1; |
|
cafab5224c86
Implement Purple.Badges.compare
Gary Kramlich <grim@reaperworld.com>
parents:
43128
diff
changeset
|
215 | } |
|
cafab5224c86
Implement Purple.Badges.compare
Gary Kramlich <grim@reaperworld.com>
parents:
43128
diff
changeset
|
216 | |
|
cafab5224c86
Implement Purple.Badges.compare
Gary Kramlich <grim@reaperworld.com>
parents:
43128
diff
changeset
|
217 | /* We now have to walk through and compare badges. */ |
|
cafab5224c86
Implement Purple.Badges.compare
Gary Kramlich <grim@reaperworld.com>
parents:
43128
diff
changeset
|
218 | n_badges = MIN(n_badges1, n_badges2); |
|
cafab5224c86
Implement Purple.Badges.compare
Gary Kramlich <grim@reaperworld.com>
parents:
43128
diff
changeset
|
219 | for(guint i = 0; i < n_badges; i++) { |
|
cafab5224c86
Implement Purple.Badges.compare
Gary Kramlich <grim@reaperworld.com>
parents:
43128
diff
changeset
|
220 | PurpleBadge *badge1 = g_ptr_array_index(badges1->badges, i); |
|
cafab5224c86
Implement Purple.Badges.compare
Gary Kramlich <grim@reaperworld.com>
parents:
43128
diff
changeset
|
221 | PurpleBadge *badge2 = g_ptr_array_index(badges2->badges, i); |
|
cafab5224c86
Implement Purple.Badges.compare
Gary Kramlich <grim@reaperworld.com>
parents:
43128
diff
changeset
|
222 | guint result = 0; |
|
cafab5224c86
Implement Purple.Badges.compare
Gary Kramlich <grim@reaperworld.com>
parents:
43128
diff
changeset
|
223 | |
|
cafab5224c86
Implement Purple.Badges.compare
Gary Kramlich <grim@reaperworld.com>
parents:
43128
diff
changeset
|
224 | result = purple_badge_compare(badge1, badge2); |
|
cafab5224c86
Implement Purple.Badges.compare
Gary Kramlich <grim@reaperworld.com>
parents:
43128
diff
changeset
|
225 | if(result != 0) { |
|
cafab5224c86
Implement Purple.Badges.compare
Gary Kramlich <grim@reaperworld.com>
parents:
43128
diff
changeset
|
226 | return result; |
|
cafab5224c86
Implement Purple.Badges.compare
Gary Kramlich <grim@reaperworld.com>
parents:
43128
diff
changeset
|
227 | } |
|
cafab5224c86
Implement Purple.Badges.compare
Gary Kramlich <grim@reaperworld.com>
parents:
43128
diff
changeset
|
228 | } |
|
cafab5224c86
Implement Purple.Badges.compare
Gary Kramlich <grim@reaperworld.com>
parents:
43128
diff
changeset
|
229 | |
|
cafab5224c86
Implement Purple.Badges.compare
Gary Kramlich <grim@reaperworld.com>
parents:
43128
diff
changeset
|
230 | /* All badges were equal so fall back to which one has the most badges. */ |
|
cafab5224c86
Implement Purple.Badges.compare
Gary Kramlich <grim@reaperworld.com>
parents:
43128
diff
changeset
|
231 | return n_badges2 - n_badges1; |
|
cafab5224c86
Implement Purple.Badges.compare
Gary Kramlich <grim@reaperworld.com>
parents:
43128
diff
changeset
|
232 | } |
|
cafab5224c86
Implement Purple.Badges.compare
Gary Kramlich <grim@reaperworld.com>
parents:
43128
diff
changeset
|
233 | |
|
cafab5224c86
Implement Purple.Badges.compare
Gary Kramlich <grim@reaperworld.com>
parents:
43128
diff
changeset
|
234 | PurpleBadges * |
|
cafab5224c86
Implement Purple.Badges.compare
Gary Kramlich <grim@reaperworld.com>
parents:
43128
diff
changeset
|
235 | purple_badges_new(void) { |
|
cafab5224c86
Implement Purple.Badges.compare
Gary Kramlich <grim@reaperworld.com>
parents:
43128
diff
changeset
|
236 | return g_object_new(PURPLE_TYPE_BADGES, NULL); |
|
cafab5224c86
Implement Purple.Badges.compare
Gary Kramlich <grim@reaperworld.com>
parents:
43128
diff
changeset
|
237 | } |
|
cafab5224c86
Implement Purple.Badges.compare
Gary Kramlich <grim@reaperworld.com>
parents:
43128
diff
changeset
|
238 | |
| 42918 | 239 | gboolean |
| 240 | purple_badges_remove_badge(PurpleBadges *badges, const char *id) { | |
| 241 | PurpleBadge *needle = NULL; | |
| 242 | gboolean found = FALSE; | |
| 243 | guint index = 0; | |
| 244 | ||
| 245 | g_return_val_if_fail(PURPLE_IS_BADGES(badges), FALSE); | |
| 246 | g_return_val_if_fail(!purple_strempty(id), FALSE); | |
| 247 | ||
| 248 | /* We only need the id, but the other values can't be null. */ | |
| 249 | needle = purple_badge_new(id, 0, "folder-saved-search-symbolic", "🔍"); | |
| 250 | ||
| 251 | found = g_ptr_array_find_with_equal_func(badges->badges, needle, | |
|
43202
1c2e548285f3
Add a badges-changed signal to Purple.ConversationMember and fix the items changed emissions
Gary Kramlich <grim@reaperworld.com>
parents:
43180
diff
changeset
|
252 | (GEqualFunc)purple_badge_equal, |
|
1c2e548285f3
Add a badges-changed signal to Purple.ConversationMember and fix the items changed emissions
Gary Kramlich <grim@reaperworld.com>
parents:
43180
diff
changeset
|
253 | &index); |
| 42918 | 254 | g_clear_object(&needle); |
| 255 | ||
| 256 | if(!found) { | |
| 257 | return FALSE; | |
| 258 | } | |
| 259 | ||
| 260 | g_ptr_array_remove_index(badges->badges, index); | |
| 261 | ||
| 262 | g_list_model_items_changed(G_LIST_MODEL(badges), index, 1, 0); | |
|
43128
1ce3ad90614c
Make sure we notify on the n-items property for all objects that have it
Gary Kramlich <grim@reaperworld.com>
parents:
42984
diff
changeset
|
263 | g_object_notify_by_pspec(G_OBJECT(badges), properties[PROP_N_ITEMS]); |
| 42918 | 264 | |
| 265 | return TRUE; | |
| 266 | } |