~ubuntu-branches/ubuntu/vivid/rawstudio/vivid

« back to all changes in this revision

Viewing changes to librawstudio/rs-job-queue.c

  • Committer: Bazaar Package Importer
  • Author(s): Bernd Zeimetz
  • Date: 2011-07-28 17:36:32 UTC
  • mfrom: (2.1.11 upstream)
  • Revision ID: james.westby@ubuntu.com-20110728173632-5czluz9ye3c83zc5
Tags: 2.0-1
* [3750b2cf] Merge commit 'upstream/2.0'
* [63637468] Removing Patch, not necessary anymore.
* [2fb580dc] Add new build-dependencies.
* [c57d953b] Run dh_autoreconf due to patches in configure.in
* [13febe39] Add patch to remove the libssl requirement.
* [5ae773fe] Replace libjpeg62-dev by libjpeg8-dev :)
* [1969d755] Don't build static libraries.
* [7cfe0a2e] Add a patch to fix the plugin directory path.
  As plugins are shared libraries, they need to go into /usr/lib,
  not into /usr/share.
  Thanks to Andrew McMillan
* [c1d0d9dd] Don't install .la files for all plugins and libraries.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * * Copyright (C) 2006-2011 Anders Brander <anders@brander.dk>, 
 
3
 * * Anders Kvist <akv@lnxbx.dk> and Klaus Post <klauspost@gmail.com>
 
4
 *
 
5
 * This program is free software; you can redistribute it and/or
 
6
 * modify it under the terms of the GNU General Public License
 
7
 * as published by the Free Software Foundation; either version 2
 
8
 * of the License, or (at your option) any later version.
 
9
 *
 
10
 * This program is distributed in the hope that it will be useful,
 
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
 * GNU General Public License for more details.
 
14
 *
 
15
 * You should have received a copy of the GNU General Public License
 
16
 * along with this program; if not, write to the Free Software
 
17
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 
18
 */
 
19
#include <rawstudio.h>
 
20
#include "rs-job-queue.h"
 
21
 
 
22
struct _RSJobQueueSlot {
 
23
        GtkWidget *container;
 
24
        GtkWidget *label;
 
25
        GtkWidget *progress;
 
26
};
 
27
 
 
28
struct _RSJob {
 
29
        RSJobFunc func;
 
30
        RSJobQueue *job_queue;
 
31
        RSJobQueueSlot *slot;
 
32
        gpointer data;
 
33
        gpointer result;
 
34
        gboolean done;
 
35
        GCond *done_cond;
 
36
        GMutex *done_mutex;
 
37
};
 
38
 
 
39
struct _RSJobQueue {
 
40
        GObject parent;
 
41
        gboolean dispose_has_run;
 
42
 
 
43
        GMutex *lock;
 
44
        GThreadPool *pool;
 
45
        gint n_slots;
 
46
        GtkWidget *window;
 
47
        GtkWidget *box;
 
48
};
 
49
 
 
50
G_DEFINE_TYPE (RSJobQueue, rs_job_queue, G_TYPE_OBJECT)
 
51
 
 
52
static void job_consumer(gpointer data, gpointer unused);
 
53
 
 
54
static void
 
55
rs_job_queue_dispose (GObject *object)
 
56
{
 
57
        RSJobQueue *job_queue = RS_JOB_QUEUE(object);
 
58
 
 
59
        if (!job_queue->dispose_has_run)
 
60
        {
 
61
                job_queue->dispose_has_run = TRUE;
 
62
 
 
63
                g_mutex_free(job_queue->lock);
 
64
        }
 
65
 
 
66
        /* Chain up */
 
67
        G_OBJECT_CLASS(rs_job_queue_parent_class)->dispose(object);
 
68
}
 
69
 
 
70
static void
 
71
rs_job_queue_class_init (RSJobQueueClass *klass)
 
72
{
 
73
        GObjectClass *object_class = G_OBJECT_CLASS (klass);
 
74
 
 
75
        object_class->dispose = rs_job_queue_dispose;
 
76
}
 
77
 
 
78
static void
 
79
rs_job_queue_init(RSJobQueue *job_queue)
 
80
{
 
81
        job_queue->dispose_has_run = FALSE;
 
82
        job_queue->lock = g_mutex_new();
 
83
        job_queue->pool = g_thread_pool_new(((GFunc) job_consumer), NULL, rs_get_number_of_processor_cores(), TRUE, NULL);
 
84
        job_queue->n_slots = 0;
 
85
        job_queue->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
 
86
        job_queue->box = gtk_vbox_new(TRUE, 1);
 
87
 
 
88
        gtk_container_add(GTK_CONTAINER(job_queue->window), job_queue->box);
 
89
 
 
90
        gtk_window_set_accept_focus(GTK_WINDOW(job_queue->window), FALSE);
 
91
        gtk_window_set_keep_above(GTK_WINDOW(job_queue->window), TRUE);
 
92
        gtk_window_set_skip_pager_hint(GTK_WINDOW(job_queue->window), TRUE);
 
93
        gtk_window_set_skip_taskbar_hint(GTK_WINDOW(job_queue->window), TRUE);
 
94
        gtk_window_set_title(GTK_WINDOW(job_queue->window), "");
 
95
        gtk_window_set_type_hint(GTK_WINDOW(job_queue->window), GDK_WINDOW_TYPE_HINT_NOTIFICATION);
 
96
 
 
97
        /* Let's spice it up a notch! :) */
 
98
#if GTK_CHECK_VERSION(2,12,0)
 
99
        gtk_window_set_opacity(GTK_WINDOW(job_queue->window), 0.75);
 
100
#endif
 
101
 
 
102
#if GTK_CHECK_VERSION(2,10,0)
 
103
        gtk_window_set_deletable(GTK_WINDOW(job_queue->window), FALSE);
 
104
#endif
 
105
 
 
106
        /* Set the gravity, so that resizes will still result in a window
 
107
         * positioned in the lower left */
 
108
        gtk_window_set_gravity(GTK_WINDOW(job_queue->window), GDK_GRAVITY_SOUTH_EAST);
 
109
 
 
110
        /* Place the window in lower left corner of screen */
 
111
        gtk_window_move(GTK_WINDOW(job_queue->window), 0, gdk_screen_get_height(gdk_display_get_default_screen(gdk_display_get_default()))-50);
 
112
}
 
113
 
 
114
/**
 
115
 * Get a new RSJobQueue
 
116
 * @return A new RSJobQueue
 
117
 */
 
118
static RSJobQueue *
 
119
rs_job_queue_new(void)
 
120
{
 
121
        return g_object_new (RS_TYPE_JOB_QUEUE, NULL);
 
122
}
 
123
 
 
124
/**
 
125
 * Return the RSJobQueue singleton
 
126
 * @note THis function should be thread safe
 
127
 * @return A RSJobQueue singleton
 
128
 */
 
129
static RSJobQueue *
 
130
rs_job_queue_get_singleton(void)
 
131
{
 
132
        static RSJobQueue *singleton = NULL;
 
133
        static GStaticMutex lock = G_STATIC_MUTEX_INIT;
 
134
 
 
135
        g_static_mutex_lock(&lock);
 
136
        if (!singleton)
 
137
                singleton = rs_job_queue_new();
 
138
        g_static_mutex_unlock(&lock);
 
139
 
 
140
        g_assert(RS_IS_JOB_QUEUE(singleton));
 
141
 
 
142
        return singleton;
 
143
}
 
144
 
 
145
/**
 
146
 * Add a new processing slot to a RSJobQueue window
 
147
 * @param job_queue A RSJobQueue
 
148
 * @return A new RSJobQueueSlot
 
149
 */
 
150
static RSJobQueueSlot *
 
151
rs_job_queue_add_slot(RSJobQueue *job_queue)
 
152
{
 
153
        RSJobQueueSlot *slot = g_new0(RSJobQueueSlot, 1);
 
154
 
 
155
        g_mutex_lock(job_queue->lock);
 
156
        gdk_threads_enter();
 
157
 
 
158
        slot->container = gtk_vbox_new(FALSE, 0);
 
159
        slot->progress = gtk_progress_bar_new();
 
160
        gtk_progress_bar_set_text(GTK_PROGRESS_BAR(slot->progress), "Hello...");
 
161
        gtk_box_pack_start(GTK_BOX(slot->container), slot->progress, FALSE, TRUE, 1);
 
162
 
 
163
        gtk_box_pack_start(GTK_BOX(job_queue->box), slot->container, FALSE, TRUE, 1);
 
164
 
 
165
        /* If we previously got 0 slots open, position the window again */
 
166
        if (job_queue->n_slots == 0)
 
167
                gtk_window_move(GTK_WINDOW(job_queue->window), 0, gdk_screen_get_height(gdk_display_get_default_screen(gdk_display_get_default()))-50);
 
168
 
 
169
        /* For some reason this must be called everytime to trigger correct placement?! */
 
170
        gtk_widget_show_all(job_queue->window);
 
171
 
 
172
        job_queue->n_slots++;
 
173
 
 
174
        gdk_threads_leave();
 
175
        g_mutex_unlock(job_queue->lock);
 
176
 
 
177
        return slot;
 
178
}
 
179
 
 
180
/**
 
181
 * Remove and frees a RSJobQueueSlot from a RSJobQueue window
 
182
 * @param job_queue A RSJobQueue
 
183
 * @param slot The slot to remove and free
 
184
 */
 
185
static void
 
186
rs_job_queue_remove_slot(RSJobQueue *job_queue, RSJobQueueSlot *slot)
 
187
{
 
188
        g_mutex_lock(job_queue->lock);
 
189
        gdk_threads_enter();
 
190
 
 
191
        gtk_container_remove(GTK_CONTAINER(job_queue->box), slot->container);
 
192
        job_queue->n_slots--;
 
193
 
 
194
        /* If we got less than 1 slot left, we hide the window, no reason to
 
195
         * show an empty window */
 
196
        if (job_queue->n_slots < 1)
 
197
                gtk_widget_hide_all(job_queue->window);
 
198
 
 
199
        /* We resize the window to 1,1 to make it as small as _possible_ to
 
200
         * avoid blank space after removing a slot */
 
201
        gtk_window_resize(GTK_WINDOW(job_queue->window), 1, 1);
 
202
 
 
203
        gdk_threads_leave();
 
204
        g_mutex_unlock(job_queue->lock);
 
205
}
 
206
 
 
207
/**
 
208
 * A function to consume jobs, this should run in its own thread
 
209
 * @note Will never return
 
210
 */
 
211
static void
 
212
job_consumer(gpointer data, gpointer unused)
 
213
{
 
214
        RSJob *job = (RSJob *) data;
 
215
        RSJobQueueSlot *slot = rs_job_queue_add_slot(job->job_queue);
 
216
        
 
217
        /* Call the job */
 
218
        if (!job->done)
 
219
                job->result = job->func(slot, job->data);
 
220
 
 
221
        rs_job_queue_remove_slot(job->job_queue, slot);
 
222
        g_object_unref(job->job_queue);
 
223
 
 
224
        if (job->done_cond)
 
225
        {
 
226
                /* If we take this path, we shouldn't free the job, rs_job_queue_wait()
 
227
                 * must take care of that */
 
228
                g_mutex_lock(job->done_mutex);
 
229
                job->done = TRUE;
 
230
                g_cond_signal(job->done_cond);
 
231
                g_mutex_unlock(job->done_mutex);
 
232
        }
 
233
        else
 
234
                g_free(job);
 
235
}
 
236
 
 
237
/**
 
238
 * Add a new job to the job queue
 
239
 * @note When func is called, it WILL be from another thread, it may be
 
240
 *       required to acquire the GDK lock if any GTK+ stuff is done in the
 
241
 *       callback!
 
242
 * @param func A function to call for performing the job
 
243
 * @param data Data to pass to func
 
244
 * @param waitable If TRUE, rs_job_queue_wait() will wait until completion
 
245
 */
 
246
RSJob *
 
247
rs_job_queue_add_job(RSJobFunc func, gpointer data, gboolean waitable)
 
248
{
 
249
        RSJobQueue *job_queue = rs_job_queue_get_singleton();
 
250
 
 
251
    g_assert(func != NULL);
 
252
 
 
253
        g_mutex_lock(job_queue->lock);
 
254
 
 
255
        RSJob *job = g_new0(RSJob, 1);
 
256
    job->func = func;
 
257
        job->job_queue = g_object_ref(job_queue);
 
258
    job->data = data;
 
259
    job->done = FALSE;
 
260
 
 
261
        if (waitable)
 
262
    {
 
263
        job->done_cond = g_cond_new();
 
264
        job->done_mutex = g_mutex_new();
 
265
    }
 
266
    else
 
267
    {
 
268
        job->done_cond = NULL;
 
269
        job->done_mutex = NULL;
 
270
    }
 
271
 
 
272
    g_thread_pool_push(job_queue->pool, job, NULL);
 
273
        g_mutex_unlock(job_queue->lock);
 
274
 
 
275
        return job;
 
276
}
 
277
 
 
278
/**
 
279
 * Wait (hang) until a job is finished and then free the memory allocated to job
 
280
 * @param job The RSJob to wait for
 
281
 * @return The value returned by the func given to rs_job_queue_add()
 
282
 */
 
283
gpointer
 
284
rs_job_queue_wait(RSJob *job)
 
285
{
 
286
        gpointer result = NULL;
 
287
 
 
288
        g_assert(job != NULL);
 
289
        g_assert(job->done_cond != NULL);
 
290
        g_assert(job->done_mutex != NULL);
 
291
 
 
292
        /* Wait for it */
 
293
        g_mutex_lock(job->done_mutex);
 
294
        while(!job->done)
 
295
                g_cond_wait(job->done_cond, job->done_mutex);
 
296
        g_mutex_unlock(job->done_mutex);
 
297
 
 
298
        /* Free everything */
 
299
        g_cond_free(job->done_cond);
 
300
        g_mutex_free(job->done_mutex);
 
301
        g_free(job);
 
302
 
 
303
        result = job->result;
 
304
 
 
305
        return result;
 
306
}
 
307
 
 
308
/**
 
309
 * Update the job description
 
310
 * @note You should NOT have aquired the GDK thread lock when calling this
 
311
 *       function.
 
312
 * @param slot A job_slot as recieved in the job callback function
 
313
 * @param description The new description or NULL to show nothing
 
314
 */
 
315
void
 
316
rs_job_update_description(RSJobQueueSlot *slot, const gchar *description)
 
317
{
 
318
        gdk_threads_enter();
 
319
 
 
320
        if (description)
 
321
                gtk_progress_bar_set_text(GTK_PROGRESS_BAR(slot->progress), description);
 
322
        else
 
323
                gtk_progress_bar_set_text(GTK_PROGRESS_BAR(slot->progress), "");
 
324
 
 
325
        gdk_threads_leave();
 
326
}
 
327
 
 
328
/**
 
329
 * Update the job progress bar
 
330
 * @note You should NOT have aquired the GDK thread lock when calling this
 
331
 *       function.
 
332
 * @param slot A job_slot as recieved in the job callback function
 
333
 * @param fraction A value between 0.0 and 1.0 to set the progress bar at
 
334
 *                 the specific fraction or -1.0 to pulse the progress bar.
 
335
 */
 
336
void
 
337
rs_job_update_progress(RSJobQueueSlot *slot, const gdouble fraction)
 
338
{
 
339
        gdk_threads_enter();
 
340
 
 
341
        if (fraction < 0.0)
 
342
                gtk_progress_bar_pulse(GTK_PROGRESS_BAR(slot->progress));
 
343
        else
 
344
                gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(slot->progress), fraction);
 
345
 
 
346
        gdk_threads_leave();
 
347
}