Mercurial > pidgin.yaz
comparison src/savedstatuses.c @ 12724:10ef9171ca87
[gaim-migrate @ 15068]
Don't have a separate popular status list. That was stupid.
Instead, keep the saved_status GList sorted by popularity.
This should be faster for the few things that it affects, and
it fixes the bug where the docklet wouldn't show popular statuses
at startup
committer: Tailor Script <tailor@pidgin.im>
author | Mark Doliner <mark@kingant.net> |
---|---|
date | Thu, 05 Jan 2006 00:11:20 +0000 |
parents | d03afaccd41c |
children | d3232d64fafd |
comparison
equal
deleted
inserted
replaced
12723:20f5daedcccb | 12724:10ef9171ca87 |
---|---|
75 const GaimStatusType *type; | 75 const GaimStatusType *type; |
76 char *message; | 76 char *message; |
77 }; | 77 }; |
78 | 78 |
79 static GList *saved_statuses = NULL; | 79 static GList *saved_statuses = NULL; |
80 static GList *popular_statuses = NULL; | |
81 static guint save_timer = 0; | 80 static guint save_timer = 0; |
82 static gboolean statuses_loaded = FALSE; | 81 static gboolean statuses_loaded = FALSE; |
83 | 82 |
84 /* | 83 /* |
85 * This hash table keeps track of which timestamps we've | 84 * This hash table keeps track of which timestamps we've |
97 /********************************************************************* | 96 /********************************************************************* |
98 * Private utility functions * | 97 * Private utility functions * |
99 *********************************************************************/ | 98 *********************************************************************/ |
100 | 99 |
101 static void | 100 static void |
102 free_statussavedsub(GaimSavedStatusSub *substatus) | 101 free_saved_status_sub(GaimSavedStatusSub *substatus) |
103 { | 102 { |
104 g_return_if_fail(substatus != NULL); | 103 g_return_if_fail(substatus != NULL); |
105 | 104 |
106 g_free(substatus->message); | 105 g_free(substatus->message); |
107 g_free(substatus); | 106 g_free(substatus); |
108 } | 107 } |
109 | 108 |
110 static void | 109 static void |
111 free_statussaved(GaimSavedStatus *status) | 110 free_saved_status(GaimSavedStatus *status) |
112 { | 111 { |
113 g_return_if_fail(status != NULL); | 112 g_return_if_fail(status != NULL); |
114 | 113 |
115 g_free(status->title); | 114 g_free(status->title); |
116 g_free(status->message); | 115 g_free(status->message); |
117 | 116 |
118 while (status->substatuses != NULL) | 117 while (status->substatuses != NULL) |
119 { | 118 { |
120 GaimSavedStatusSub *substatus = status->substatuses->data; | 119 GaimSavedStatusSub *substatus = status->substatuses->data; |
121 status->substatuses = g_list_remove(status->substatuses, substatus); | 120 status->substatuses = g_list_remove(status->substatuses, substatus); |
122 free_statussavedsub(substatus); | 121 free_saved_status_sub(substatus); |
123 } | 122 } |
124 | 123 |
125 g_free(status); | 124 g_free(status); |
126 } | 125 } |
127 | 126 |
143 g_hash_table_insert(creation_times, | 142 g_hash_table_insert(creation_times, |
144 &status->creation_time, | 143 &status->creation_time, |
145 status); | 144 status); |
146 } | 145 } |
147 | 146 |
147 /** | |
148 * A magic number is calcuated for each status, and then the | |
149 * statuses are ordered by the magic number. The magic number | |
150 * is the date the status was last used offset by one day for | |
151 * each time the status has been used (but only by 10 days at | |
152 * the most). | |
153 * | |
154 * The goal is to have recently used statuses at the top of | |
155 * the list, but to also keep frequently used statuses near | |
156 * the top. | |
157 */ | |
148 static gint | 158 static gint |
149 compare_times(gconstpointer a, gconstpointer b) | 159 saved_statuses_sort_func(gconstpointer a, gconstpointer b) |
150 { | 160 { |
151 const time_t timea = *((time_t *)a); | 161 const GaimSavedStatus *saved_status_a = a; |
152 const time_t timeb = *((time_t *)b); | 162 const GaimSavedStatus *saved_status_b = b; |
153 if (timea > timeb) | 163 time_t time_a = saved_status_a->lastused + |
164 (MIN(saved_status_a->usage_count, 10) * 86400); | |
165 time_t time_b = saved_status_b->lastused + | |
166 (MIN(saved_status_b->usage_count, 10) * 86400); | |
167 if (time_a > time_b) | |
154 return -1; | 168 return -1; |
155 if (timea < timeb) | 169 if (time_a < time_b) |
156 return 1; | 170 return 1; |
157 return 0; | 171 return 0; |
158 } | 172 } |
159 | 173 |
160 /** | 174 /** |
164 * does the expiration. | 178 * does the expiration. |
165 */ | 179 */ |
166 static void | 180 static void |
167 remove_old_transient_statuses() | 181 remove_old_transient_statuses() |
168 { | 182 { |
169 GList *lastused; | |
170 time_t threshold; | |
171 time_t creation_time; | |
172 GList *l, *next; | 183 GList *l, *next; |
173 GaimSavedStatus *saved_status; | 184 GaimSavedStatus *saved_status; |
174 int i; | 185 int count; |
175 | 186 time_t creation_time; |
176 /* Construct a GList containing the lastused times from each transient status */ | 187 |
177 lastused = NULL; | 188 /* |
178 for (l = saved_statuses; l != NULL; l = l->next) | 189 * Iterate through the list of saved statuses. Delete all |
179 { | 190 * transient statuses except for the first MAX_TRANSIENTS |
191 * (remember, the saved statuses are already sorted by popularity). | |
192 */ | |
193 count = 0; | |
194 for (l = saved_statuses; l != NULL; l = next) | |
195 { | |
196 next = l->next; | |
180 saved_status = l->data; | 197 saved_status = l->data; |
181 if (gaim_savedstatus_is_transient(saved_status)) | 198 if (gaim_savedstatus_is_transient(saved_status)) |
182 lastused = g_list_insert_sorted(lastused, &saved_status->lastused, compare_times); | |
183 } | |
184 | |
185 /* Find the 5th most recently used transient status */ | |
186 l = lastused; | |
187 i = 0; | |
188 while ((l != NULL) && (i < MAX_TRANSIENTS)) | |
189 { | |
190 l = l->next; | |
191 i++; | |
192 } | |
193 if (l != NULL) | |
194 threshold = *((time_t *)l->data); | |
195 else | |
196 threshold = 0; | |
197 g_list_free(lastused); | |
198 | |
199 if (threshold == 0) | |
200 /* We have 5 or fewer transient statuses, so there is nothing to delete */ | |
201 return; | |
202 | |
203 /* Delete all transient statuses older than the threshold */ | |
204 for (l = saved_statuses; l != NULL; l = next) | |
205 { | |
206 next = l->next; | |
207 saved_status = l->data; | |
208 if (gaim_savedstatus_is_transient(saved_status) && (saved_status->lastused <= threshold)) | |
209 { | 199 { |
210 saved_statuses = g_list_remove(saved_statuses, saved_status); | 200 if (count == MAX_TRANSIENTS) |
211 creation_time = gaim_savedstatus_get_creation_time(saved_status); | 201 { |
212 g_hash_table_remove(creation_times, &creation_time); | 202 saved_statuses = g_list_remove(saved_statuses, saved_status); |
213 free_statussaved(saved_status); | 203 creation_time = gaim_savedstatus_get_creation_time(saved_status); |
204 g_hash_table_remove(creation_times, &creation_time); | |
205 free_saved_status(saved_status); | |
206 } | |
207 else | |
208 count++; | |
214 } | 209 } |
215 } | 210 } |
216 schedule_save(); | 211 |
212 if (count == MAX_TRANSIENTS) | |
213 schedule_save(); | |
217 } | 214 } |
218 | 215 |
219 /********************************************************************* | 216 /********************************************************************* |
220 * Writing to disk * | 217 * Writing to disk * |
221 *********************************************************************/ | 218 *********************************************************************/ |
519 { | 516 { |
520 GaimSavedStatus *new; | 517 GaimSavedStatus *new; |
521 new = parse_status(status); | 518 new = parse_status(status); |
522 saved_statuses = g_list_prepend(saved_statuses, new); | 519 saved_statuses = g_list_prepend(saved_statuses, new); |
523 } | 520 } |
521 saved_statuses = g_list_sort(saved_statuses, saved_statuses_sort_func); | |
524 | 522 |
525 xmlnode_free(statuses); | 523 xmlnode_free(statuses); |
526 } | 524 } |
527 | 525 |
528 | 526 |
541 status = g_new0(GaimSavedStatus, 1); | 539 status = g_new0(GaimSavedStatus, 1); |
542 status->title = g_strdup(title); | 540 status->title = g_strdup(title); |
543 status->type = type; | 541 status->type = type; |
544 set_creation_time(status, time(NULL)); | 542 set_creation_time(status, time(NULL)); |
545 | 543 |
546 saved_statuses = g_list_prepend(saved_statuses, status); | 544 saved_statuses = g_list_insert_sorted(saved_statuses, status, saved_statuses_sort_func); |
547 | 545 |
548 schedule_save(); | 546 schedule_save(); |
549 | 547 |
550 return status; | 548 return status; |
551 } | 549 } |
648 return FALSE; | 646 return FALSE; |
649 | 647 |
650 saved_statuses = g_list_remove(saved_statuses, status); | 648 saved_statuses = g_list_remove(saved_statuses, status); |
651 creation_time = gaim_savedstatus_get_creation_time(status); | 649 creation_time = gaim_savedstatus_get_creation_time(status); |
652 g_hash_table_remove(creation_times, &creation_time); | 650 g_hash_table_remove(creation_times, &creation_time); |
653 free_statussaved(status); | 651 free_saved_status(status); |
654 | 652 |
655 schedule_save(); | 653 schedule_save(); |
656 | 654 |
657 /* | 655 /* |
658 * If we just deleted our current status or our idleaway status, | 656 * If we just deleted our current status or our idleaway status, |
673 gaim_savedstatuses_get_all(void) | 671 gaim_savedstatuses_get_all(void) |
674 { | 672 { |
675 return saved_statuses; | 673 return saved_statuses; |
676 } | 674 } |
677 | 675 |
678 /** | |
679 * A magic number is calcuated for each status, and then the | |
680 * statuses are ordered by the magic number. The magic number | |
681 * is the date the status was last used offset by one day for | |
682 * each time the status has been used (but only by 10 days at | |
683 * the most). | |
684 * | |
685 * The goal is to have recently used statuses at the top of | |
686 * the list, but to also keep frequently used statuses near | |
687 * the top. | |
688 */ | |
689 static gint | |
690 popular_statuses_compare_func(gconstpointer a, gconstpointer b) | |
691 { | |
692 const GaimSavedStatus *saved_status_a = a; | |
693 const GaimSavedStatus *saved_status_b = b; | |
694 time_t time_a = saved_status_a->lastused + | |
695 (MIN(saved_status_a->usage_count, 10) * 86400); | |
696 time_t time_b = saved_status_b->lastused + | |
697 (MIN(saved_status_b->usage_count, 10) * 86400); | |
698 if (time_a > time_b) | |
699 return -1; | |
700 if (time_a < time_b) | |
701 return 1; | |
702 return 0; | |
703 } | |
704 | |
705 GList * | 676 GList * |
706 gaim_savedstatuses_get_popular(unsigned int how_many) | 677 gaim_savedstatuses_get_popular(unsigned int how_many) |
707 { | 678 { |
708 GList *truncated = NULL; | 679 GList *truncated = NULL; |
709 GList *cur; | 680 GList *cur; |
710 int i; | 681 int i; |
711 | 682 |
712 /* Copy 'how_many' elements to a new list */ | 683 /* Copy 'how_many' elements to a new list */ |
713 for (i = 0, cur = popular_statuses; (i < how_many) && (cur != NULL); i++) | 684 for (i = 0, cur = saved_statuses; (i < how_many) && (cur != NULL); i++) |
714 { | 685 { |
715 truncated = g_list_append(truncated, cur->data); | 686 truncated = g_list_append(truncated, cur->data); |
716 cur = cur->next; | 687 cur = cur->next; |
717 } | 688 } |
718 | 689 |
940 | 911 |
941 saved_status->lastused = time(NULL); | 912 saved_status->lastused = time(NULL); |
942 gaim_prefs_set_int("/core/savedstatus/current", | 913 gaim_prefs_set_int("/core/savedstatus/current", |
943 gaim_savedstatus_get_creation_time(saved_status)); | 914 gaim_savedstatus_get_creation_time(saved_status)); |
944 | 915 |
945 /* Update our list of popular statuses */ | 916 /* Make sure our list of saved statuses remains sorted */ |
946 saved_status->usage_count++; | 917 saved_status->usage_count++; |
947 g_list_free(popular_statuses); | 918 saved_statuses = g_list_remove(saved_statuses, saved_status); |
948 popular_statuses = g_list_copy(saved_statuses); | 919 saved_statuses = g_list_insert_sorted(saved_statuses, saved_status, saved_statuses_sort_func); |
949 popular_statuses = g_list_sort(popular_statuses, | |
950 popular_statuses_compare_func); | |
951 | 920 |
952 } | 921 } |
953 | 922 |
954 void | 923 void |
955 gaim_savedstatus_activate_for_account(const GaimSavedStatus *saved_status, | 924 gaim_savedstatus_activate_for_account(const GaimSavedStatus *saved_status, |
1029 } | 998 } |
1030 | 999 |
1031 while (saved_statuses != NULL) { | 1000 while (saved_statuses != NULL) { |
1032 GaimSavedStatus *saved_status = saved_statuses->data; | 1001 GaimSavedStatus *saved_status = saved_statuses->data; |
1033 saved_statuses = g_list_remove(saved_statuses, saved_status); | 1002 saved_statuses = g_list_remove(saved_statuses, saved_status); |
1034 free_statussaved(saved_status); | 1003 free_saved_status(saved_status); |
1035 } | 1004 } |
1036 | 1005 |
1037 g_hash_table_destroy(creation_times); | 1006 g_hash_table_destroy(creation_times); |
1038 } | 1007 } |
1039 | 1008 |