]> www.fi.muni.cz Git - evince.git/blob - shell/ev-job-queue.c
Cleanup mime type detection on document load. Fix for the bug #336448.
[evince.git] / shell / ev-job-queue.c
1 #include "ev-job-queue.h"
2
3 /* Like glib calling convention, all functions with _locked in their name assume
4  * that we've already locked the doc mutex and can freely and safely access
5  * data.
6  */
7 GCond *render_cond = NULL;
8 GMutex *ev_queue_mutex = NULL;
9
10 static GQueue *links_queue = NULL;
11 static GQueue *render_queue_high = NULL;
12 static GQueue *render_queue_low = NULL;
13 static GQueue *thumbnail_queue_high = NULL;
14 static GQueue *thumbnail_queue_low = NULL;
15 static GQueue *xfer_queue = NULL;
16 static GQueue *fonts_queue = NULL;
17
18 /* Queues used for backends supporting EvAsyncRender interface,
19    they are executed on the main thread */
20 static GQueue *async_render_queue_high = NULL;
21 static GQueue *async_render_queue_low = NULL;
22 static gboolean async_rendering = FALSE;
23
24 static void ev_job_queue_run_next (void);
25
26 static gboolean
27 remove_job_from_queue_locked (GQueue *queue, EvJob *job)
28 {
29         GList *list;
30
31         list = g_queue_find (queue, job);
32         if (list) {
33                 g_object_unref (G_OBJECT (job));
34                 g_queue_delete_link (queue, list);
35
36                 return TRUE;
37         }
38         return FALSE;
39 }
40
41 static gboolean
42 remove_job_from_async_queue (GQueue *queue, EvJob *job)
43 {
44         return remove_job_from_queue_locked (queue, job);
45 }
46
47 static void
48 add_job_to_async_queue (GQueue *queue, EvJob *job)
49 {
50         g_object_ref (job);
51         g_queue_push_tail (queue, job);
52 }
53
54 static void
55 add_job_to_queue_locked (GQueue *queue,
56                          EvJob  *job)
57 {
58         g_object_ref (job);
59         g_queue_push_tail (queue, job);
60         g_cond_broadcast (render_cond);
61 }
62
63 static gboolean
64 notify_finished (GObject *job)
65 {
66         ev_job_finished (EV_JOB (job));
67
68         return FALSE;
69 }
70
71 static void
72 job_finished_cb (EvJob *job)
73 {
74         g_object_unref (job);
75         async_rendering = FALSE;
76         ev_job_queue_run_next ();
77 }
78
79 static void
80 handle_job (EvJob *job)
81 {
82         g_object_ref (G_OBJECT (job));
83
84         if (EV_JOB (job)->async) {
85                 async_rendering = TRUE;
86                 if (EV_IS_JOB_RENDER (job)) {
87                         g_signal_connect (job, "finished",
88                                           G_CALLBACK (job_finished_cb), NULL);
89                 } else {
90                         g_assert_not_reached ();
91                 }
92         }
93
94         if (EV_IS_JOB_THUMBNAIL (job))
95                 ev_job_thumbnail_run (EV_JOB_THUMBNAIL (job));
96         else if (EV_IS_JOB_LINKS (job))
97                 ev_job_links_run (EV_JOB_LINKS (job));
98         else if (EV_IS_JOB_XFER (job))
99                 ev_job_xfer_run (EV_JOB_XFER (job));
100         else if (EV_IS_JOB_RENDER (job))
101                 ev_job_render_run (EV_JOB_RENDER (job));
102         else if (EV_IS_JOB_FONTS (job))
103                 ev_job_fonts_run (EV_JOB_FONTS (job));
104
105         if (!EV_JOB (job)->async) {
106                 /* We let the idle own a ref, as we (the queue) are done with the job. */
107                 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
108                                  (GSourceFunc) notify_finished,
109                                  job,
110                                  g_object_unref);
111         }
112 }
113
114 static EvJob *
115 search_for_jobs_unlocked (void)
116 {
117         EvJob *job;
118
119         job = (EvJob *) g_queue_pop_head (render_queue_high);
120         if (job)
121                 return job;
122
123         job = (EvJob *) g_queue_pop_head (thumbnail_queue_high);
124         if (job)
125                 return job;
126
127         job = (EvJob *) g_queue_pop_head (render_queue_low);
128         if (job)
129                 return job;
130
131         job = (EvJob *) g_queue_pop_head (links_queue);
132         if (job)
133                 return job;
134
135         job = (EvJob *) g_queue_pop_head (xfer_queue);
136         if (job)
137                 return job;
138
139         job = (EvJob *) g_queue_pop_head (thumbnail_queue_low);
140         if (job)
141                 return job;
142
143         job = (EvJob *) g_queue_pop_head (fonts_queue);
144         if (job)
145                 return job;
146
147         return NULL;
148 }
149
150 static gboolean
151 no_jobs_available_unlocked (void)
152 {
153         return g_queue_is_empty (render_queue_high)
154                 && g_queue_is_empty (render_queue_low)
155                 && g_queue_is_empty (links_queue)
156                 && g_queue_is_empty (xfer_queue)
157                 && g_queue_is_empty (thumbnail_queue_high)
158                 && g_queue_is_empty (thumbnail_queue_low)
159                 && g_queue_is_empty (fonts_queue);
160 }
161
162 /* the thread mainloop function */
163 static gpointer
164 ev_render_thread (gpointer data)
165 {
166         while (TRUE) {
167                 EvJob *job;
168
169                 g_mutex_lock (ev_queue_mutex);
170                 if (no_jobs_available_unlocked ()) {
171                         g_cond_wait (render_cond, ev_queue_mutex);
172                 }
173
174                 job = search_for_jobs_unlocked ();
175                 g_mutex_unlock (ev_queue_mutex);
176
177                 /* Now that we have our job, we handle it */
178                 if (job) {
179                         handle_job (job);
180                         g_object_unref (G_OBJECT (job));
181                 }
182         }
183         return NULL;
184
185 }
186
187 static void
188 ev_job_queue_run_next (void)
189 {
190         EvJob *job;
191
192         job = (EvJob *) g_queue_pop_head (async_render_queue_high);
193
194         if (job == NULL) {
195                 job = (EvJob *) g_queue_pop_head (async_render_queue_low);
196         }
197
198         /* Now that we have our job, we handle it */
199         if (job) {
200                 handle_job (job);
201                 g_object_unref (G_OBJECT (job));
202         }
203 }
204
205 /* Public Functions */
206 void
207 ev_job_queue_init (void)
208 {
209         if (!g_thread_supported ()) g_thread_init (NULL);
210
211         render_cond = g_cond_new ();
212         ev_queue_mutex = g_mutex_new ();
213
214         links_queue = g_queue_new ();
215         xfer_queue = g_queue_new ();
216         render_queue_high = g_queue_new ();
217         render_queue_low = g_queue_new ();
218         async_render_queue_high = g_queue_new ();
219         async_render_queue_low = g_queue_new ();
220         thumbnail_queue_high = g_queue_new ();
221         thumbnail_queue_low = g_queue_new ();
222         fonts_queue = g_queue_new ();
223
224         g_thread_create (ev_render_thread, NULL, FALSE, NULL);
225
226 }
227
228 static GQueue *
229 find_queue (EvJob         *job,
230             EvJobPriority  priority)
231 {
232         if (EV_JOB (job)->async) {
233                 if (EV_IS_JOB_RENDER (job)) {
234                         if (priority == EV_JOB_PRIORITY_HIGH)
235                                 return async_render_queue_high;
236                         else
237                                 return async_render_queue_low;
238                 }
239         } else {
240                 if (EV_IS_JOB_RENDER (job)) {
241                         if (priority == EV_JOB_PRIORITY_HIGH)
242                                 return render_queue_high;
243                         else
244                                 return render_queue_low;
245                 } else if (EV_IS_JOB_THUMBNAIL (job)) {
246                         if (priority == EV_JOB_PRIORITY_HIGH)
247                                 return thumbnail_queue_high;
248                         else
249                                 return thumbnail_queue_low;
250                 } else if (EV_IS_JOB_XFER (job)) {
251                         /* the priority doesn't effect xfer */
252                         return xfer_queue;
253                 } else if (EV_IS_JOB_LINKS (job)) {
254                         /* the priority doesn't effect links */
255                         return links_queue;
256                 } else if (EV_IS_JOB_FONTS (job)) {
257                         /* the priority doesn't effect fonts */
258                         return fonts_queue;
259                 }
260         }
261
262         g_assert_not_reached ();
263         return NULL;
264 }
265
266 void
267 ev_job_queue_add_job (EvJob         *job,
268                       EvJobPriority  priority)
269 {
270         GQueue *queue;
271
272         g_return_if_fail (EV_IS_JOB (job));
273
274         queue = find_queue (job, priority);
275
276         if (!EV_JOB (job)->async) {
277                 g_mutex_lock (ev_queue_mutex);
278                 add_job_to_queue_locked (queue, job);
279                 g_mutex_unlock (ev_queue_mutex);
280         } else {
281                 add_job_to_async_queue (queue, job);
282                 if (!async_rendering) {
283                         ev_job_queue_run_next ();
284                 }
285         }
286 }
287
288 static gboolean
289 move_job_async (EvJob *job, GQueue *old_queue, GQueue *new_queue)
290 {
291         gboolean retval = FALSE;
292
293         g_object_ref (job);
294
295         if (remove_job_from_queue_locked (old_queue, job)) {
296                 add_job_to_async_queue (new_queue, job);
297                 retval = TRUE;
298         }
299
300         g_object_unref (job);
301
302         return retval;
303 }
304
305 static gboolean
306 move_job (EvJob *job, GQueue *old_queue, GQueue *new_queue)
307 {
308         gboolean retval = FALSE;
309
310         g_mutex_lock (ev_queue_mutex);
311         g_object_ref (job);
312
313         if (remove_job_from_queue_locked (old_queue, job)) {
314                 add_job_to_queue_locked (new_queue, job);
315                 retval = TRUE;
316         }
317
318         g_object_unref (job);
319         g_mutex_unlock (ev_queue_mutex);
320
321         return retval;
322 }
323
324 gboolean
325 ev_job_queue_update_job (EvJob         *job,
326                          EvJobPriority  new_priority)
327 {
328         gboolean retval = FALSE;
329         
330         g_return_val_if_fail (EV_IS_JOB (job), FALSE);
331
332         if (EV_JOB (job)->async) {
333                 if (EV_IS_JOB_RENDER (job)) {
334                         if (new_priority == EV_JOB_PRIORITY_LOW) {
335                                 retval = move_job_async (job, async_render_queue_high,
336                                                          async_render_queue_low);
337                         } else if (new_priority == EV_JOB_PRIORITY_HIGH) {
338                                 retval = move_job_async (job, async_render_queue_low,
339                                                          async_render_queue_high);
340                         }
341                 } else {
342                         g_assert_not_reached ();
343                 }
344         } else {
345                 if (EV_IS_JOB_THUMBNAIL (job)) {
346                         if (new_priority == EV_JOB_PRIORITY_LOW) {
347                                 retval = move_job (job, thumbnail_queue_high,
348                                                    thumbnail_queue_low);
349                         } else if (new_priority == EV_JOB_PRIORITY_HIGH) {
350                                 retval = move_job (job, thumbnail_queue_low,
351                                                    thumbnail_queue_high);
352                         }
353                 } else if (EV_IS_JOB_RENDER (job)) {
354                         if (new_priority == EV_JOB_PRIORITY_LOW) {
355                                 retval = move_job (job, render_queue_high,
356                                                    render_queue_low);
357                         } else if (new_priority == EV_JOB_PRIORITY_HIGH) {
358                                 retval = move_job (job, render_queue_low,
359                                                    render_queue_high);
360                         }
361                 } else {
362                         g_assert_not_reached ();
363                 }
364         }       
365
366         return retval;
367 }
368
369 gboolean
370 ev_job_queue_remove_job (EvJob *job)
371 {
372         gboolean retval = FALSE;
373
374         g_return_val_if_fail (EV_IS_JOB (job), FALSE);
375
376         if (EV_JOB (job)->async) {
377                 if (EV_IS_JOB_RENDER (job)) {
378                         retval = remove_job_from_async_queue (async_render_queue_high, job);
379                         retval = retval || remove_job_from_async_queue (async_render_queue_low, job);
380                 } else {
381                         g_assert_not_reached ();
382                 }
383         } else {
384                 g_mutex_lock (ev_queue_mutex);
385
386                 if (EV_IS_JOB_THUMBNAIL (job)) {
387                         retval = remove_job_from_queue_locked (thumbnail_queue_high, job);
388                         retval = retval || remove_job_from_queue_locked (thumbnail_queue_low, job);
389                 } else if (EV_IS_JOB_RENDER (job)) {
390                         retval = remove_job_from_queue_locked (render_queue_high, job);
391                         retval = retval || remove_job_from_queue_locked (render_queue_low, job);
392                 } else if (EV_IS_JOB_LINKS (job)) {
393                         retval = remove_job_from_queue_locked (links_queue, job);
394                 } else if (EV_IS_JOB_XFER (job)) {
395                         retval = remove_job_from_queue_locked (xfer_queue, job);
396                 } else if (EV_IS_JOB_FONTS (job)) {
397                         retval = remove_job_from_queue_locked (fonts_queue, job);
398                 } else {
399                         g_assert_not_reached ();
400                 }
401
402                 g_mutex_unlock (ev_queue_mutex);
403         }
404         
405         return retval;
406 }
407
408