1 /*
2 category.c
3
4
5
6 2003 Plus Huang
7 */
8
9 #include <stdlib.h>
10 #include "category.h"
11 #include "category_store.h"
12 #include "download_thread.h"
13
category_new()14 Category* category_new ()
15 {
16 Category* cate = g_malloc (sizeof (Category));
17
18 // initial base class category_setting
19 category_setting_init (&cate->setting);
20
21 g_static_rec_mutex_init (&cate->mutex);
22
23 download_store_init (&cate->waiting_store);
24 download_store_init (&cate->completed_store);
25 download_store_init (&cate->recycled_store);
26
27 download_store_set_historical (&cate->completed_store, TRUE);
28 download_store_set_historical (&cate->recycled_store, TRUE);
29
30 download_list_view_init (&cate->waiting_view, &cate->waiting_store);
31 download_list_view_init (&cate->completed_view, &cate->completed_store);
32 download_list_view_init (&cate->recycled_view, &cate->recycled_store);
33 download_list_view_hide_runtime_state (&cate->completed_view);
34 download_list_view_hide_runtime_state (&cate->recycled_view);
35
36 cate->valid = FALSE;
37 cate->reference_count = 1;
38 cate->thread_list = NULL;
39 cate->n_thread = 0;
40
41 category_apply_setting (cate);
42
43 return cate;
44 }
45
category_new_from_setting(CategorySetting * cd)46 Category* category_new_from_setting (CategorySetting* cd)
47 {
48 Category* cate = category_new ();
49
50 category_setting_assign (&cate->setting, cd);
51 category_apply_setting (cate);
52
53 return cate;
54 }
55
category_ref(Category * ca)56 void category_ref (Category* ca)
57 {
58 category_lock (ca);
59 ca->reference_count++;
60 category_unlock (ca);
61 }
62
category_unref(Category * ca)63 void category_unref (Category* ca)
64 {
65 int count;
66
67 category_lock (ca);
68 count = --ca->reference_count;
69 category_unlock (ca);
70
71 if (count > 0)
72 return;
73
74 g_static_rec_mutex_free (&ca->mutex);
75
76 category_setting_clear (&ca->setting);
77
78 download_list_view_clear (&ca->waiting_view);
79 download_list_view_clear (&ca->completed_view);
80 download_list_view_clear (&ca->recycled_view);
81
82 download_store_clear (&ca->waiting_store);
83 download_store_clear (&ca->completed_store);
84 download_store_clear (&ca->recycled_store);
85
86 g_free (ca);
87 }
88
category_apply_setting(Category * ca)89 void category_apply_setting (Category* ca)
90 {
91 CategorySetting* setting = CATEGORY_SETTING (ca);
92 DownloadListView* dlv = &ca->waiting_view;
93
94 gtk_tree_view_column_set_visible (dlv->col_completed,
95 setting->col_completed);
96 gtk_tree_view_column_set_visible (dlv->col_total,
97 setting->col_total);
98 gtk_tree_view_column_set_visible (dlv->col_speed,
99 setting->col_speed);
100 gtk_tree_view_column_set_visible (dlv->col_retry,
101 setting->col_retry);
102 gtk_tree_view_column_set_visible (dlv->col_url,
103 setting->col_url);
104
105 gtk_tree_view_column_set_visible (ca->completed_view.col_url,
106 setting->col_url);
107 gtk_tree_view_column_set_visible (ca->recycled_view.col_url,
108 setting->col_url);
109
110 ca->completed_store.capacity_limit = setting->completed_capacity;
111 ca->recycled_store.capacity_limit = setting->recycled_capacity;
112 }
113
category_changed_with_children(Category * ca,gint flag_child)114 void category_changed_with_children (Category* ca, gint flag_child)
115 {
116 GtkTreePath* path;
117 GtkTreeIter iter;
118 CategoryStore* category_store = (CategoryStore*)ca->category_store;
119
120 if (ca->valid==FALSE)
121 return;
122
123 // list store
124 path = gtk_tree_model_get_path ((GtkTreeModel*)category_store->list_store,
125 &ca->iter_list_store);
126 gtk_tree_model_row_changed ((GtkTreeModel*)category_store->list_store,
127 path, &ca->iter_list_store);
128 gtk_tree_path_free (path);
129
130 // tree store
131 path = gtk_tree_model_get_path ((GtkTreeModel*)category_store->tree_store,
132 &ca->iter_tree_store);
133 gtk_tree_model_row_changed ((GtkTreeModel*)category_store->tree_store,
134 path, &ca->iter_tree_store);
135 gtk_tree_path_free (path);
136
137 if (flag_child) {
138 gtk_tree_model_iter_children ((GtkTreeModel*)category_store->tree_store,
139 &iter, &ca->iter_tree_store);
140 if (flag_child & CATEGORY_COMPLETED) {
141 path = gtk_tree_model_get_path ((GtkTreeModel*)category_store->tree_store,
142 &iter);
143 gtk_tree_model_row_changed ((GtkTreeModel*)category_store->tree_store,
144 path, &iter);
145 gtk_tree_path_free (path);
146 }
147 if (flag_child & CATEGORY_RECYCLED) {
148 gtk_tree_model_iter_next ((GtkTreeModel*)category_store->tree_store,
149 &iter);
150 path = gtk_tree_model_get_path ((GtkTreeModel*)category_store->tree_store,
151 &iter);
152 gtk_tree_model_row_changed ((GtkTreeModel*)category_store->tree_store,
153 path, &iter);
154 gtk_tree_path_free (path);
155 }
156 }
157 }
158
category_thread_count_request(Category * ca)159 gint category_thread_count_request (Category* ca)
160 {
161 return CATEGORY_SETTING(ca)->n_active_download - ca->n_thread;
162 }
163
category_thread_destroy(Category * ca)164 void category_thread_destroy (Category* ca)
165 {
166 DownloadThread* dt;
167
168 category_lock (ca);
169
170 for (dt=ca->thread_list; dt; dt=dt->next)
171 download_thread_destroy (dt);
172
173 category_unlock (ca);
174 }
175
category_thread_activate(Category * ca)176 gboolean category_thread_activate (Category* ca)
177 {
178 GtkTreeIter iter;
179 DownloadThread* thread;
180 gboolean found;
181 gboolean activated = FALSE;
182
183 do {
184 if (category_thread_count_request (ca) <= 0 )
185 break;
186
187 download_store_lock (&ca->waiting_store);
188
189 if (found=download_store_find_waiting (&ca->waiting_store, &iter)) {
190 thread = download_thread_new (ca, &iter);
191 download_store_unlock (&ca->waiting_store);
192 download_thread_activate (thread);
193 }
194 else
195 download_store_unlock (&ca->waiting_store);
196 activated = TRUE;
197 } while (found);
198
199 return activated;
200 }
201
category_thread_stop(Category * ca)202 void category_thread_stop (Category* ca)
203 {
204 DownloadThread* dt;
205
206 category_lock (ca);
207
208 for (dt=ca->thread_list; dt; dt=dt->next)
209 download_thread_stop (dt);
210
211 category_unlock (ca);
212 }
213
category_thread_remove(Category * category,gpointer th)214 void category_thread_remove (Category* category,
215 gpointer th)
216 {
217 DownloadThread* thread = th;
218 gboolean activated = TRUE;
219
220 category_lock (category);
221
222 if (category->thread_list == thread) {
223 category->thread_list = thread->next;
224 }
225 if (thread->next)
226 thread->next->prev = thread->prev;
227 if (thread->prev)
228 thread->prev->next = thread->next;
229
230 category->n_thread--;
231 if (category->n_thread==0) {
232 CATEGORY_SETTING (category)->state = CATEGORY_STATE_WAITING;
233 category_changed (category);
234 activated = FALSE;
235 }
236
237 category_unlock (category);
238
239 // avoid dead lock
240 if (activated == FALSE) {
241 category_store_thread_unref ((CategoryStore*)category->category_store);
242 category_store_thread_activate_next ((CategoryStore*)category->category_store,
243 category);
244 }
245 }
246
category_thread_add(Category * category,gpointer thread)247 void category_thread_add (Category* category,
248 gpointer thread)
249 {
250 gboolean activated = FALSE;
251
252 category_lock (category);
253
254 if (category->n_thread==0) {
255 CATEGORY_SETTING (category)->state = CATEGORY_STATE_EXECUTING;
256 category_changed (category);
257 activated = TRUE;
258 }
259 category->n_thread++;
260
261 if (category->thread_list) {
262 ((DownloadThread*)category->thread_list)->prev = thread;
263 ((DownloadThread*)thread)->next = category->thread_list;
264 }
265 category->thread_list = thread;
266
267 category_unlock (category);
268
269 // avoid dead lock
270 if (activated)
271 category_store_thread_ref ((CategoryStore*)category->category_store);
272 }
273
274