~ubuntu-branches/ubuntu/trusty/packagekit/trusty

« back to all changes in this revision

Viewing changes to backends/hawkey/hif-state.c

  • Committer: Package Import Robot
  • Author(s): Sebastian Heinlein
  • Date: 2013-08-27 23:45:23 UTC
  • mfrom: (56.1.26 sid)
  • Revision ID: package-import@ubuntu.com-20130827234523-hm4d57mvdf5x17cg
Tags: 0.8.10-2ubuntu1
* Merge from Debian unstable. Remaining changes:
  + Client tools alternatively depend on or recommend aptdaemon's
    compatibility layer
  + packagekit provides the virtual packagekit-system-interface
  + Add break on packagekit-plugin-click <= 0.3
  + Fix default url in vendor-ubuntu.diff

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
 
2
 *
 
3
 * Copyright (C) 2009-2013 Richard Hughes <richard@hughsie.com>
 
4
 *
 
5
 * Most of this code was taken from Zif, libzif/zif-state.c
 
6
 *
 
7
 * Licensed under the GNU General Public License Version 2
 
8
 *
 
9
 * This program is free software; you can redistribute it and/or modify
 
10
 * it under the terms of the GNU General Public License as published by
 
11
 * the Free Software Foundation; either version 2 of the License, or
 
12
 * (at your option) any later version.
 
13
 *
 
14
 * This program is distributed in the hope that it will be useful,
 
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
17
 * GNU General Public License for more details.
 
18
 *
 
19
 * You should have received a copy of the GNU General Public License
 
20
 * along with this program; if not, write to the Free Software
 
21
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 
22
 */
 
23
 
 
24
#ifdef HAVE_CONFIG_H
 
25
#  include <config.h>
 
26
#endif
 
27
 
 
28
#include <glib.h>
 
29
#if GLIB_CHECK_VERSION(2,29,19)
 
30
#include <glib-unix.h>
 
31
#endif
 
32
#include <signal.h>
 
33
#include <rpm/rpmsq.h>
 
34
 
 
35
#include "hif-utils.h"
 
36
#include "hif-state.h"
 
37
 
 
38
#define HIF_STATE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), HIF_TYPE_STATE, HifStatePrivate))
 
39
 
 
40
struct _HifStatePrivate
 
41
{
 
42
        gboolean                 allow_cancel;
 
43
        gboolean                 allow_cancel_changed_state;
 
44
        gboolean                 allow_cancel_child;
 
45
        gboolean                 enable_profile;
 
46
        gboolean                 report_progress;
 
47
        GCancellable            *cancellable;
 
48
        gchar                   *action_hint;
 
49
        gchar                   *id;
 
50
        gdouble                  global_share;
 
51
        gdouble                 *step_profile;
 
52
        gpointer                 error_handler_user_data;
 
53
        gpointer                 lock_handler_user_data;
 
54
        GTimer                  *timer;
 
55
        guint64                  speed;
 
56
        guint64                 *speed_data;
 
57
        guint                    current;
 
58
        guint                    last_percentage;
 
59
        guint                   *step_data;
 
60
        guint                    steps;
 
61
        gulong                   action_child_id;
 
62
        gulong                   package_progress_child_id;
 
63
        gulong                   notify_speed_child_id;
 
64
        gulong                   allow_cancel_child_id;
 
65
        gulong                   percentage_child_id;
 
66
        gulong                   subpercentage_child_id;
 
67
        PkStatusEnum             action;
 
68
        PkStatusEnum             last_action;
 
69
        PkStatusEnum             child_action;
 
70
        HifState                *child;
 
71
        HifStateErrorHandlerCb   error_handler_cb;
 
72
        HifStateLockHandlerCb    lock_handler_cb;
 
73
        HifState                *parent;
 
74
        GPtrArray               *lock_ids;
 
75
        HifLock                 *lock;
 
76
};
 
77
 
 
78
enum {
 
79
        SIGNAL_PERCENTAGE_CHANGED,
 
80
        SIGNAL_SUBPERCENTAGE_CHANGED,
 
81
        SIGNAL_ALLOW_CANCEL_CHANGED,
 
82
        SIGNAL_ACTION_CHANGED,
 
83
        SIGNAL_PACKAGE_PROGRESS_CHANGED,
 
84
        SIGNAL_LAST
 
85
};
 
86
 
 
87
enum {
 
88
        PROP_0,
 
89
        PROP_SPEED,
 
90
        PROP_LAST
 
91
};
 
92
 
 
93
static guint signals [SIGNAL_LAST] = { 0 };
 
94
 
 
95
G_DEFINE_TYPE (HifState, hif_state, G_TYPE_OBJECT)
 
96
 
 
97
#define HIF_STATE_SPEED_SMOOTHING_ITEMS         5
 
98
 
 
99
/**
 
100
 * hif_state_set_report_progress:
 
101
 **/
 
102
void
 
103
hif_state_set_report_progress (HifState *state, gboolean report_progress)
 
104
{
 
105
        g_return_if_fail (HIF_IS_STATE (state));
 
106
        state->priv->report_progress = report_progress;
 
107
}
 
108
 
 
109
/**
 
110
 * hif_state_set_enable_profile:
 
111
 **/
 
112
void
 
113
hif_state_set_enable_profile (HifState *state, gboolean enable_profile)
 
114
{
 
115
        g_return_if_fail (HIF_IS_STATE (state));
 
116
        state->priv->enable_profile = enable_profile;
 
117
}
 
118
 
 
119
/**
 
120
 * hif_state_set_lock_handler:
 
121
 **/
 
122
void
 
123
hif_state_set_lock_handler (HifState *state,
 
124
                            HifStateLockHandlerCb lock_handler_cb,
 
125
                            gpointer user_data)
 
126
{
 
127
        state->priv->lock_handler_cb = lock_handler_cb;
 
128
        state->priv->lock_handler_user_data = user_data;
 
129
 
 
130
        /* if there is an existing child, set the handler on this too */
 
131
        if (state->priv->child != NULL) {
 
132
                hif_state_set_lock_handler (state->priv->child,
 
133
                                            lock_handler_cb,
 
134
                                            user_data);
 
135
        }
 
136
}
 
137
 
 
138
/**
 
139
 * hif_state_take_lock:
 
140
 **/
 
141
gboolean
 
142
hif_state_take_lock (HifState *state,
 
143
                     HifLockType lock_type,
 
144
                     HifLockMode lock_mode,
 
145
                     GError **error)
 
146
{
 
147
        gboolean ret = TRUE;
 
148
        guint lock_id = 0;
 
149
 
 
150
        /* no custom handler */
 
151
        if (state->priv->lock_handler_cb == NULL) {
 
152
                lock_id = hif_lock_take (state->priv->lock,
 
153
                                         lock_type,
 
154
                                         lock_mode,
 
155
                                         error);
 
156
                if (lock_id == 0)
 
157
                        ret = FALSE;
 
158
        } else {
 
159
                lock_id = G_MAXUINT;
 
160
                ret = state->priv->lock_handler_cb (state,
 
161
                                                    state->priv->lock,
 
162
                                                    lock_type,
 
163
                                                    error,
 
164
                                                    state->priv->lock_handler_user_data);
 
165
        }
 
166
        if (!ret)
 
167
                goto out;
 
168
 
 
169
        /* add the lock to an array so we can release on completion */
 
170
        g_debug ("adding lock %i", lock_id);
 
171
        g_ptr_array_add (state->priv->lock_ids,
 
172
                         GUINT_TO_POINTER (lock_id));
 
173
out:
 
174
        return ret;
 
175
}
 
176
 
 
177
/**
 
178
 * hif_state_discrete_to_percent:
 
179
 **/
 
180
static gfloat
 
181
hif_state_discrete_to_percent (guint discrete, guint steps)
 
182
{
 
183
        /* check we are in range */
 
184
        if (discrete > steps)
 
185
                return 100;
 
186
        if (steps == 0) {
 
187
                g_warning ("steps is 0!");
 
188
                return 0;
 
189
        }
 
190
        return ((gfloat) discrete * (100.0f / (gfloat) (steps)));
 
191
}
 
192
 
 
193
/**
 
194
 * hif_state_print_parent_chain:
 
195
 **/
 
196
static void
 
197
hif_state_print_parent_chain (HifState *state, guint level)
 
198
{
 
199
        if (state->priv->parent != NULL)
 
200
                hif_state_print_parent_chain (state->priv->parent, level + 1);
 
201
        g_print ("%i) %s (%i/%i)\n",
 
202
                 level, state->priv->id, state->priv->current, state->priv->steps);
 
203
}
 
204
 
 
205
/**
 
206
 * hif_state_get_cancellable:
 
207
 **/
 
208
GCancellable *
 
209
hif_state_get_cancellable (HifState *state)
 
210
{
 
211
        g_return_val_if_fail (HIF_IS_STATE (state), NULL);
 
212
        return state->priv->cancellable;
 
213
}
 
214
 
 
215
/**
 
216
 * hif_state_set_cancellable:
 
217
 **/
 
218
void
 
219
hif_state_set_cancellable (HifState *state, GCancellable *cancellable)
 
220
{
 
221
        g_return_if_fail (HIF_IS_STATE (state));
 
222
        g_return_if_fail (state->priv->cancellable == NULL);
 
223
        state->priv->cancellable = g_object_ref (cancellable);
 
224
}
 
225
 
 
226
/**
 
227
 * hif_state_get_allow_cancel:
 
228
 **/
 
229
gboolean
 
230
hif_state_get_allow_cancel (HifState *state)
 
231
{
 
232
        g_return_val_if_fail (HIF_IS_STATE (state), FALSE);
 
233
        return state->priv->allow_cancel && state->priv->allow_cancel_child;
 
234
}
 
235
 
 
236
/**
 
237
 * hif_state_set_allow_cancel:
 
238
 **/
 
239
void
 
240
hif_state_set_allow_cancel (HifState *state, gboolean allow_cancel)
 
241
{
 
242
        g_return_if_fail (HIF_IS_STATE (state));
 
243
 
 
244
        state->priv->allow_cancel_changed_state = TRUE;
 
245
 
 
246
        /* quick optimisation that saves lots of signals */
 
247
        if (state->priv->allow_cancel == allow_cancel)
 
248
                return;
 
249
        state->priv->allow_cancel = allow_cancel;
 
250
 
 
251
        /* just emit if both this and child is okay */
 
252
        g_signal_emit (state, signals [SIGNAL_ALLOW_CANCEL_CHANGED], 0,
 
253
                       state->priv->allow_cancel && state->priv->allow_cancel_child);
 
254
}
 
255
 
 
256
/**
 
257
 * hif_state_get_speed:
 
258
 **/
 
259
guint64
 
260
hif_state_get_speed (HifState *state)
 
261
{
 
262
        g_return_val_if_fail (HIF_IS_STATE (state), 0);
 
263
        return state->priv->speed;
 
264
}
 
265
 
 
266
/**
 
267
 * hif_state_set_speed_internal:
 
268
 **/
 
269
static void
 
270
hif_state_set_speed_internal (HifState *state, guint64 speed)
 
271
{
 
272
        if (state->priv->speed == speed)
 
273
                return;
 
274
        state->priv->speed = speed;
 
275
        g_object_notify (G_OBJECT (state), "speed");
 
276
}
 
277
 
 
278
/**
 
279
 * hif_state_set_speed:
 
280
 **/
 
281
void
 
282
hif_state_set_speed (HifState *state, guint64 speed)
 
283
{
 
284
        guint i;
 
285
        guint64 sum = 0;
 
286
        guint sum_cnt = 0;
 
287
        g_return_if_fail (HIF_IS_STATE (state));
 
288
 
 
289
        /* move the data down one entry */
 
290
        for (i=HIF_STATE_SPEED_SMOOTHING_ITEMS-1; i > 0; i--)
 
291
                state->priv->speed_data[i] = state->priv->speed_data[i-1];
 
292
        state->priv->speed_data[0] = speed;
 
293
 
 
294
        /* get the average */
 
295
        for (i = 0; i < HIF_STATE_SPEED_SMOOTHING_ITEMS; i++) {
 
296
                if (state->priv->speed_data[i] > 0) {
 
297
                        sum += state->priv->speed_data[i];
 
298
                        sum_cnt++;
 
299
                }
 
300
        }
 
301
        if (sum_cnt > 0)
 
302
                sum /= sum_cnt;
 
303
 
 
304
        g_debug ("speed = %" G_GUINT64_FORMAT " kb/sec", sum / 1024);
 
305
        hif_state_set_speed_internal (state, sum);
 
306
}
 
307
 
 
308
/**
 
309
 * hif_state_release_locks:
 
310
 **/
 
311
static gboolean
 
312
hif_state_release_locks (HifState *state)
 
313
{
 
314
        gboolean ret = TRUE;
 
315
        guint i;
 
316
        guint lock_id;
 
317
 
 
318
        /* release each one */
 
319
        for (i = 0; i < state->priv->lock_ids->len; i++) {
 
320
                lock_id = GPOINTER_TO_UINT (g_ptr_array_index (state->priv->lock_ids, i));
 
321
                g_debug ("releasing lock %i", lock_id);
 
322
                ret = hif_lock_release (state->priv->lock,
 
323
                                        lock_id,
 
324
                                        NULL);
 
325
                if (!ret)
 
326
                        goto out;
 
327
        }
 
328
        g_ptr_array_set_size (state->priv->lock_ids, 0);
 
329
out:
 
330
        return ret;
 
331
}
 
332
 
 
333
/**
 
334
 * hif_state_set_percentage:
 
335
 **/
 
336
gboolean
 
337
hif_state_set_percentage (HifState *state, guint percentage)
 
338
{
 
339
        gboolean ret = FALSE;
 
340
 
 
341
        /* do we care */
 
342
        if (!state->priv->report_progress) {
 
343
                ret = TRUE;
 
344
                goto out;
 
345
        }
 
346
 
 
347
        /* is it the same */
 
348
        if (percentage == state->priv->last_percentage)
 
349
                goto out;
 
350
 
 
351
        /* is it invalid */
 
352
        if (percentage > 100) {
 
353
                hif_state_print_parent_chain (state, 0);
 
354
                g_warning ("percentage %i%% is invalid on %p!",
 
355
                           percentage, state);
 
356
                goto out;
 
357
        }
 
358
 
 
359
        /* is it less */
 
360
        if (percentage < state->priv->last_percentage) {
 
361
                if (state->priv->enable_profile) {
 
362
                        hif_state_print_parent_chain (state, 0);
 
363
                        g_warning ("percentage should not go down from %i to %i on %p!",
 
364
                                   state->priv->last_percentage, percentage, state);
 
365
                }
 
366
                goto out;
 
367
        }
 
368
 
 
369
        /* we're done, so we're not preventing cancellation anymore */
 
370
        if (percentage == 100 && !state->priv->allow_cancel) {
 
371
                g_debug ("done, so allow cancel 1 for %p", state);
 
372
                hif_state_set_allow_cancel (state, TRUE);
 
373
        }
 
374
 
 
375
        /* automatically cancel any action */
 
376
        if (percentage == 100 && state->priv->action != PK_STATUS_ENUM_UNKNOWN) {
 
377
                g_debug ("done, so cancelling action %s",
 
378
                         pk_status_enum_to_string (state->priv->action));
 
379
                hif_state_action_stop (state);
 
380
        }
 
381
 
 
382
        /* speed no longer valid */
 
383
        if (percentage == 100)
 
384
                hif_state_set_speed_internal (state, 0);
 
385
 
 
386
        /* release locks? */
 
387
        if (percentage == 100) {
 
388
                ret = hif_state_release_locks (state);
 
389
                if (!ret)
 
390
                        goto out;
 
391
        }
 
392
 
 
393
        /* save */
 
394
        state->priv->last_percentage = percentage;
 
395
 
 
396
        /* are we so low we don't care */
 
397
        if (state->priv->global_share < 0.001)
 
398
                goto out;
 
399
 
 
400
        /* emit */
 
401
        g_signal_emit (state, signals [SIGNAL_PERCENTAGE_CHANGED], 0, percentage);
 
402
 
 
403
        /* success */
 
404
        ret = TRUE;
 
405
out:
 
406
        return ret;
 
407
}
 
408
 
 
409
/**
 
410
 * hif_state_get_percentage:
 
411
 **/
 
412
guint
 
413
hif_state_get_percentage (HifState *state)
 
414
{
 
415
        return state->priv->last_percentage;
 
416
}
 
417
 
 
418
/**
 
419
 * hif_state_set_subpercentage:
 
420
 **/
 
421
static gboolean
 
422
hif_state_set_subpercentage (HifState *state, guint percentage)
 
423
{
 
424
        /* are we so low we don't care */
 
425
        if (state->priv->global_share < 0.01)
 
426
                goto out;
 
427
 
 
428
        /* just emit */
 
429
        g_signal_emit (state, signals [SIGNAL_SUBPERCENTAGE_CHANGED], 0, percentage);
 
430
out:
 
431
        return TRUE;
 
432
}
 
433
 
 
434
/**
 
435
 * hif_state_action_start:
 
436
 **/
 
437
gboolean
 
438
hif_state_action_start (HifState *state, PkStatusEnum action, const gchar *action_hint)
 
439
{
 
440
        g_return_val_if_fail (HIF_IS_STATE (state), FALSE);
 
441
 
 
442
        /* ignore this */
 
443
        if (action == PK_STATUS_ENUM_UNKNOWN) {
 
444
                g_warning ("cannot set action PK_STATUS_ENUM_UNKNOWN");
 
445
                return FALSE;
 
446
        }
 
447
 
 
448
        /* is different? */
 
449
        if (state->priv->action == action &&
 
450
            g_strcmp0 (action_hint, state->priv->action_hint) == 0) {
 
451
                g_debug ("same action as before, ignoring");
 
452
                return FALSE;
 
453
        }
 
454
 
 
455
        /* remember for stop */
 
456
        state->priv->last_action = state->priv->action;
 
457
 
 
458
        /* save hint */
 
459
        g_free (state->priv->action_hint);
 
460
        state->priv->action_hint = g_strdup (action_hint);
 
461
 
 
462
        /* save */
 
463
        state->priv->action = action;
 
464
 
 
465
        /* just emit */
 
466
        g_signal_emit (state, signals [SIGNAL_ACTION_CHANGED], 0, action, action_hint);
 
467
        return TRUE;
 
468
}
 
469
 
 
470
/**
 
471
 * hif_state_set_package_progress:
 
472
 **/
 
473
void
 
474
hif_state_set_package_progress (HifState *state,
 
475
                                const gchar *package_id,
 
476
                                PkStatusEnum action,
 
477
                                guint percentage)
 
478
{
 
479
        g_return_if_fail (HIF_IS_STATE (state));
 
480
        g_return_if_fail (package_id != NULL);
 
481
        g_return_if_fail (action != PK_STATUS_ENUM_UNKNOWN);
 
482
        g_return_if_fail (percentage <= 100);
 
483
 
 
484
        /* just emit */
 
485
        g_signal_emit (state, signals [SIGNAL_PACKAGE_PROGRESS_CHANGED], 0,
 
486
                       package_id, action, percentage);
 
487
}
 
488
 
 
489
/**
 
490
 * hif_state_action_stop:
 
491
 **/
 
492
gboolean
 
493
hif_state_action_stop (HifState *state)
 
494
{
 
495
        g_return_val_if_fail (HIF_IS_STATE (state), FALSE);
 
496
 
 
497
        /* nothing ever set */
 
498
        if (state->priv->action == PK_STATUS_ENUM_UNKNOWN) {
 
499
                g_debug ("cannot unset action PK_STATUS_ENUM_UNKNOWN");
 
500
                return FALSE;
 
501
        }
 
502
 
 
503
        /* pop and reset */
 
504
        state->priv->action = state->priv->last_action;
 
505
        state->priv->last_action = PK_STATUS_ENUM_UNKNOWN;
 
506
        if (state->priv->action_hint != NULL) {
 
507
                g_free (state->priv->action_hint);
 
508
                state->priv->action_hint = NULL;
 
509
        }
 
510
 
 
511
        /* just emit */
 
512
        g_signal_emit (state, signals [SIGNAL_ACTION_CHANGED], 0, state->priv->action, NULL);
 
513
        return TRUE;
 
514
}
 
515
 
 
516
/**
 
517
 * hif_state_get_action_hint:
 
518
 **/
 
519
const gchar *
 
520
hif_state_get_action_hint (HifState *state)
 
521
{
 
522
        g_return_val_if_fail (HIF_IS_STATE (state), NULL);
 
523
        return state->priv->action_hint;
 
524
}
 
525
 
 
526
/**
 
527
 * hif_state_get_action:
 
528
 **/
 
529
PkStatusEnum
 
530
hif_state_get_action (HifState *state)
 
531
{
 
532
        g_return_val_if_fail (HIF_IS_STATE (state), PK_STATUS_ENUM_UNKNOWN);
 
533
        return state->priv->action;
 
534
}
 
535
 
 
536
/**
 
537
 * hif_state_child_percentage_changed_cb:
 
538
 **/
 
539
static void
 
540
hif_state_child_percentage_changed_cb (HifState *child, guint percentage, HifState *state)
 
541
{
 
542
        gfloat offset;
 
543
        gfloat range;
 
544
        gfloat extra;
 
545
        guint parent_percentage;
 
546
 
 
547
        /* propagate up the stack if HifState has only one step */
 
548
        if (state->priv->steps == 1) {
 
549
                hif_state_set_percentage (state, percentage);
 
550
                return;
 
551
        }
 
552
 
 
553
        /* did we call done on a state that did not have a size set? */
 
554
        if (state->priv->steps == 0)
 
555
                return;
 
556
 
 
557
        /* always provide two levels of signals */
 
558
        hif_state_set_subpercentage (state, percentage);
 
559
 
 
560
        /* already at >= 100% */
 
561
        if (state->priv->current >= state->priv->steps) {
 
562
                g_warning ("already at %i/%i steps on %p", state->priv->current, state->priv->steps, state);
 
563
                return;
 
564
        }
 
565
 
 
566
        /* we have to deal with non-linear steps */
 
567
        if (state->priv->step_data != NULL) {
 
568
                /* we don't store zero */
 
569
                if (state->priv->current == 0) {
 
570
                        parent_percentage = percentage * state->priv->step_data[state->priv->current] / 100;
 
571
                } else {
 
572
                        /* bilinearly interpolate for speed */
 
573
                        parent_percentage = (((100 - percentage) * state->priv->step_data[state->priv->current-1]) +
 
574
                                             (percentage * state->priv->step_data[state->priv->current])) / 100;
 
575
                }
 
576
                goto out;
 
577
        }
 
578
 
 
579
        /* get the offset */
 
580
        offset = hif_state_discrete_to_percent (state->priv->current, state->priv->steps);
 
581
 
 
582
        /* get the range between the parent step and the next parent step */
 
583
        range = hif_state_discrete_to_percent (state->priv->current+1, state->priv->steps) - offset;
 
584
        if (range < 0.01) {
 
585
                g_warning ("range=%f (from %i to %i), should be impossible", range, state->priv->current+1, state->priv->steps);
 
586
                return;
 
587
        }
 
588
 
 
589
        /* restore the pre-child action */
 
590
        if (percentage == 100) {
 
591
                state->priv->last_action = state->priv->child_action;
 
592
                g_debug ("restoring last action %s",
 
593
                         pk_status_enum_to_string (state->priv->child_action));
 
594
        }
 
595
 
 
596
        /* get the extra contributed by the child */
 
597
        extra = ((gfloat) percentage / 100.0f) * range;
 
598
 
 
599
        /* emit from the parent */
 
600
        parent_percentage = (guint) (offset + extra);
 
601
out:
 
602
        hif_state_set_percentage (state, parent_percentage);
 
603
}
 
604
 
 
605
/**
 
606
 * hif_state_child_subpercentage_changed_cb:
 
607
 **/
 
608
static void
 
609
hif_state_child_subpercentage_changed_cb (HifState *child, guint percentage, HifState *state)
 
610
{
 
611
        /* discard this, unless the HifState has only one step */
 
612
        if (state->priv->steps != 1)
 
613
                return;
 
614
 
 
615
        /* propagate up the stack as if the parent didn't exist */
 
616
        hif_state_set_subpercentage (state, percentage);
 
617
}
 
618
 
 
619
/**
 
620
 * hif_state_child_allow_cancel_changed_cb:
 
621
 **/
 
622
static void
 
623
hif_state_child_allow_cancel_changed_cb (HifState *child, gboolean allow_cancel, HifState *state)
 
624
{
 
625
        /* save */
 
626
        state->priv->allow_cancel_child = allow_cancel;
 
627
 
 
628
        /* just emit if both this and child is okay */
 
629
        g_signal_emit (state, signals [SIGNAL_ALLOW_CANCEL_CHANGED], 0,
 
630
                       state->priv->allow_cancel && state->priv->allow_cancel_child);
 
631
}
 
632
 
 
633
/**
 
634
 * hif_state_child_action_changed_cb:
 
635
 **/
 
636
static void
 
637
hif_state_child_action_changed_cb (HifState *child, PkStatusEnum action, const gchar *action_hint, HifState *state)
 
638
{
 
639
        /* save */
 
640
        state->priv->action = action;
 
641
 
 
642
        /* just emit */
 
643
        g_signal_emit (state, signals [SIGNAL_ACTION_CHANGED], 0, action, action_hint);
 
644
}
 
645
 
 
646
/**
 
647
 * hif_state_child_package_progress_changed_cb:
 
648
 **/
 
649
static void
 
650
hif_state_child_package_progress_changed_cb (HifState *child,
 
651
                                             const gchar *package_id,
 
652
                                             PkStatusEnum action,
 
653
                                             guint progress,
 
654
                                             HifState *state)
 
655
{
 
656
        /* just emit */
 
657
        g_signal_emit (state, signals [SIGNAL_PACKAGE_PROGRESS_CHANGED], 0,
 
658
                       package_id, action, progress);
 
659
}
 
660
 
 
661
/**
 
662
 * hif_state_reset:
 
663
 **/
 
664
gboolean
 
665
hif_state_reset (HifState *state)
 
666
{
 
667
        gboolean ret = TRUE;
 
668
 
 
669
        g_return_val_if_fail (HIF_IS_STATE (state), FALSE);
 
670
 
 
671
        /* do we care */
 
672
        if (!state->priv->report_progress) {
 
673
                ret = TRUE;
 
674
                goto out;
 
675
        }
 
676
 
 
677
        /* reset values */
 
678
        state->priv->steps = 0;
 
679
        state->priv->current = 0;
 
680
        state->priv->last_percentage = 0;
 
681
 
 
682
        /* only use the timer if profiling; it's expensive */
 
683
        if (state->priv->enable_profile)
 
684
                g_timer_start (state->priv->timer);
 
685
 
 
686
        /* disconnect client */
 
687
        if (state->priv->percentage_child_id != 0) {
 
688
                g_signal_handler_disconnect (state->priv->child,
 
689
                                             state->priv->percentage_child_id);
 
690
                state->priv->percentage_child_id = 0;
 
691
        }
 
692
        if (state->priv->subpercentage_child_id != 0) {
 
693
                g_signal_handler_disconnect (state->priv->child,
 
694
                                             state->priv->subpercentage_child_id);
 
695
                state->priv->subpercentage_child_id = 0;
 
696
        }
 
697
        if (state->priv->allow_cancel_child_id != 0) {
 
698
                g_signal_handler_disconnect (state->priv->child,
 
699
                                             state->priv->allow_cancel_child_id);
 
700
                state->priv->allow_cancel_child_id = 0;
 
701
        }
 
702
        if (state->priv->action_child_id != 0) {
 
703
                g_signal_handler_disconnect (state->priv->child,
 
704
                                             state->priv->action_child_id);
 
705
                state->priv->action_child_id = 0;
 
706
        }
 
707
        if (state->priv->package_progress_child_id != 0) {
 
708
                g_signal_handler_disconnect (state->priv->child,
 
709
                                             state->priv->package_progress_child_id);
 
710
                state->priv->package_progress_child_id = 0;
 
711
        }
 
712
        if (state->priv->notify_speed_child_id != 0) {
 
713
                g_signal_handler_disconnect (state->priv->child,
 
714
                                             state->priv->notify_speed_child_id);
 
715
                state->priv->notify_speed_child_id = 0;
 
716
        }
 
717
 
 
718
        /* unref child */
 
719
        if (state->priv->child != NULL) {
 
720
                g_object_unref (state->priv->child);
 
721
                state->priv->child = NULL;
 
722
        }
 
723
 
 
724
        /* no more locks */
 
725
        hif_state_release_locks (state);
 
726
 
 
727
        /* no more step data */
 
728
        g_free (state->priv->step_data);
 
729
        g_free (state->priv->step_profile);
 
730
        state->priv->step_data = NULL;
 
731
        state->priv->step_profile = NULL;
 
732
out:
 
733
        return ret;
 
734
}
 
735
 
 
736
/**
 
737
 * hif_state_set_global_share:
 
738
 **/
 
739
static void
 
740
hif_state_set_global_share (HifState *state, gdouble global_share)
 
741
{
 
742
        state->priv->global_share = global_share;
 
743
}
 
744
 
 
745
/**
 
746
 * hif_state_child_notify_speed_cb:
 
747
 **/
 
748
static void
 
749
hif_state_child_notify_speed_cb (HifState *child,
 
750
                                 GParamSpec *pspec,
 
751
                                 HifState *state)
 
752
{
 
753
        hif_state_set_speed_internal (state,
 
754
                                      hif_state_get_speed (child));
 
755
}
 
756
 
 
757
/**
 
758
 * hif_state_get_child:
 
759
 **/
 
760
HifState *
 
761
hif_state_get_child (HifState *state)
 
762
{
 
763
        HifState *child = NULL;
 
764
 
 
765
        g_return_val_if_fail (HIF_IS_STATE (state), NULL);
 
766
 
 
767
        /* do we care */
 
768
        if (!state->priv->report_progress) {
 
769
                child = state;
 
770
                goto out;
 
771
        }
 
772
 
 
773
        /* already set child */
 
774
        if (state->priv->child != NULL) {
 
775
                g_signal_handler_disconnect (state->priv->child,
 
776
                                             state->priv->percentage_child_id);
 
777
                g_signal_handler_disconnect (state->priv->child,
 
778
                                             state->priv->subpercentage_child_id);
 
779
                g_signal_handler_disconnect (state->priv->child,
 
780
                                             state->priv->allow_cancel_child_id);
 
781
                g_signal_handler_disconnect (state->priv->child,
 
782
                                             state->priv->action_child_id);
 
783
                g_signal_handler_disconnect (state->priv->child,
 
784
                                             state->priv->package_progress_child_id);
 
785
                g_signal_handler_disconnect (state->priv->child,
 
786
                                             state->priv->notify_speed_child_id);
 
787
                g_object_unref (state->priv->child);
 
788
        }
 
789
 
 
790
        /* connect up signals */
 
791
        child = hif_state_new ();
 
792
        child->priv->parent = state; /* do not ref! */
 
793
        state->priv->child = child;
 
794
        state->priv->percentage_child_id =
 
795
                g_signal_connect (child, "percentage-changed",
 
796
                                  G_CALLBACK (hif_state_child_percentage_changed_cb),
 
797
                                  state);
 
798
        state->priv->subpercentage_child_id =
 
799
                g_signal_connect (child, "subpercentage-changed",
 
800
                                  G_CALLBACK (hif_state_child_subpercentage_changed_cb),
 
801
                                  state);
 
802
        state->priv->allow_cancel_child_id =
 
803
                g_signal_connect (child, "allow-cancel-changed",
 
804
                                  G_CALLBACK (hif_state_child_allow_cancel_changed_cb),
 
805
                                  state);
 
806
        state->priv->action_child_id =
 
807
                g_signal_connect (child, "action-changed",
 
808
                                  G_CALLBACK (hif_state_child_action_changed_cb),
 
809
                                  state);
 
810
        state->priv->package_progress_child_id =
 
811
                g_signal_connect (child, "package-progress-changed",
 
812
                                  G_CALLBACK (hif_state_child_package_progress_changed_cb),
 
813
                                  state);
 
814
        state->priv->notify_speed_child_id =
 
815
                g_signal_connect (child, "notify::speed",
 
816
                                  G_CALLBACK (hif_state_child_notify_speed_cb),
 
817
                                  state);
 
818
 
 
819
        /* reset child */
 
820
        child->priv->current = 0;
 
821
        child->priv->last_percentage = 0;
 
822
 
 
823
        /* save so we can recover after child has done */
 
824
        child->priv->action = state->priv->action;
 
825
        state->priv->child_action = state->priv->action;
 
826
 
 
827
        /* set the global share on the new child */
 
828
        hif_state_set_global_share (child, state->priv->global_share);
 
829
 
 
830
        /* set cancellable, creating if required */
 
831
        if (state->priv->cancellable == NULL)
 
832
                state->priv->cancellable = g_cancellable_new ();
 
833
        hif_state_set_cancellable (child, state->priv->cancellable);
 
834
 
 
835
        /* set the lock handler if one exists on the child */
 
836
        if (state->priv->lock_handler_cb != NULL) {
 
837
                hif_state_set_lock_handler (child,
 
838
                                            state->priv->lock_handler_cb,
 
839
                                            state->priv->lock_handler_user_data);
 
840
        }
 
841
 
 
842
        /* set the profile state */
 
843
        hif_state_set_enable_profile (child,
 
844
                                      state->priv->enable_profile);
 
845
out:
 
846
        return child;
 
847
}
 
848
 
 
849
/**
 
850
 * hif_state_set_number_steps_real:
 
851
 **/
 
852
gboolean
 
853
hif_state_set_number_steps_real (HifState *state, guint steps, const gchar *strloc)
 
854
{
 
855
        gboolean ret = FALSE;
 
856
 
 
857
        g_return_val_if_fail (state != NULL, FALSE);
 
858
 
 
859
        /* nothing to do for 0 steps */
 
860
        if (steps == 0) {
 
861
                ret = TRUE;
 
862
                goto out;
 
863
        }
 
864
 
 
865
        /* do we care */
 
866
        if (!state->priv->report_progress) {
 
867
                ret = TRUE;
 
868
                goto out;
 
869
        }
 
870
 
 
871
        /* did we call done on a state that did not have a size set? */
 
872
        if (state->priv->steps != 0) {
 
873
                g_warning ("steps already set to %i, can't set %i! [%s]",
 
874
                             state->priv->steps, steps, strloc);
 
875
                hif_state_print_parent_chain (state, 0);
 
876
                goto out;
 
877
        }
 
878
 
 
879
        /* set id */
 
880
        g_free (state->priv->id);
 
881
        state->priv->id = g_strdup_printf ("%s", strloc);
 
882
 
 
883
        /* only use the timer if profiling; it's expensive */
 
884
        if (state->priv->enable_profile)
 
885
                g_timer_start (state->priv->timer);
 
886
 
 
887
        /* imply reset */
 
888
        hif_state_reset (state);
 
889
 
 
890
        /* set steps */
 
891
        state->priv->steps = steps;
 
892
 
 
893
        /* global share just got smaller */
 
894
        state->priv->global_share /= steps;
 
895
 
 
896
        /* success */
 
897
        ret = TRUE;
 
898
out:
 
899
        return ret;
 
900
}
 
901
 
 
902
/**
 
903
 * hif_state_set_steps_real:
 
904
 **/
 
905
gboolean
 
906
hif_state_set_steps_real (HifState *state, GError **error, const gchar *strloc, gint value, ...)
 
907
{
 
908
        va_list args;
 
909
        guint i;
 
910
        gint value_temp;
 
911
        guint total;
 
912
        gboolean ret = FALSE;
 
913
 
 
914
        g_return_val_if_fail (state != NULL, FALSE);
 
915
        g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
916
 
 
917
        /* do we care */
 
918
        if (!state->priv->report_progress) {
 
919
                ret = TRUE;
 
920
                goto out;
 
921
        }
 
922
 
 
923
        /* we must set at least one thing */
 
924
        total = value;
 
925
 
 
926
        /* process the valist */
 
927
        va_start (args, value);
 
928
        for (i = 0;; i++) {
 
929
                value_temp = va_arg (args, gint);
 
930
                if (value_temp == -1)
 
931
                        break;
 
932
                total += (guint) value_temp;
 
933
        }
 
934
        va_end (args);
 
935
 
 
936
        /* does not sum to 100% */
 
937
        if (total != 100) {
 
938
                g_set_error (error,
 
939
                             HIF_ERROR,
 
940
                             PK_ERROR_ENUM_INTERNAL_ERROR,
 
941
                             "percentage not 100: %i",
 
942
                             total);
 
943
                goto out;
 
944
        }
 
945
 
 
946
        /* set step number */
 
947
        ret = hif_state_set_number_steps_real (state, i+1, strloc);
 
948
        if (!ret) {
 
949
                g_set_error (error,
 
950
                             HIF_ERROR,
 
951
                             PK_ERROR_ENUM_INTERNAL_ERROR,
 
952
                             "failed to set number steps: %i",
 
953
                             i+1);
 
954
                goto out;
 
955
        }
 
956
 
 
957
        /* save this data */
 
958
        total = value;
 
959
        state->priv->step_data = g_new0 (guint, i+2);
 
960
        state->priv->step_profile = g_new0 (gdouble, i+2);
 
961
        state->priv->step_data[0] = total;
 
962
        va_start (args, value);
 
963
        for (i = 0;; i++) {
 
964
                value_temp = va_arg (args, gint);
 
965
                if (value_temp == -1)
 
966
                        break;
 
967
 
 
968
                /* we pre-add the data to make access simpler */
 
969
                total += (guint) value_temp;
 
970
                state->priv->step_data[i+1] = total;
 
971
        }
 
972
        va_end (args);
 
973
 
 
974
        /* success */
 
975
        ret = TRUE;
 
976
out:
 
977
        return ret;
 
978
}
 
979
 
 
980
/**
 
981
 * hif_state_show_profile:
 
982
 **/
 
983
static void
 
984
hif_state_show_profile (HifState *state)
 
985
{
 
986
        gdouble division;
 
987
        gdouble total_time = 0.0f;
 
988
        GString *result;
 
989
        guint i;
 
990
        guint uncumalitive = 0;
 
991
 
 
992
        /* get the total time so we can work out the divisor */
 
993
        result = g_string_new ("Raw timing data was { ");
 
994
        for (i = 0; i < state->priv->steps; i++) {
 
995
                g_string_append_printf (result, "%.3f, ",
 
996
                                        state->priv->step_profile[i]);
 
997
        }
 
998
        if (state->priv->steps > 0)
 
999
                g_string_set_size (result, result->len - 2);
 
1000
        g_string_append (result, " }\n");
 
1001
 
 
1002
        /* get the total time so we can work out the divisor */
 
1003
        for (i = 0; i < state->priv->steps; i++)
 
1004
                total_time += state->priv->step_profile[i];
 
1005
        division = total_time / 100.0f;
 
1006
 
 
1007
        /* what we set */
 
1008
        g_string_append (result, "steps were set as [ ");
 
1009
        for (i = 0; i < state->priv->steps; i++) {
 
1010
                g_string_append_printf (result, "%i, ",
 
1011
                                        state->priv->step_data[i] - uncumalitive);
 
1012
                uncumalitive = state->priv->step_data[i];
 
1013
        }
 
1014
 
 
1015
        /* what we _should_ have set */
 
1016
        g_string_append_printf (result, "-1 ] but should have been: [ ");
 
1017
        for (i = 0; i < state->priv->steps; i++) {
 
1018
                g_string_append_printf (result, "%.0f, ",
 
1019
                                        state->priv->step_profile[i] / division);
 
1020
        }
 
1021
        g_string_append (result, "-1 ]");
 
1022
        g_printerr ("\n\n%s at %s\n\n", result->str, state->priv->id);
 
1023
        g_string_free (result, TRUE);
 
1024
}
 
1025
 
 
1026
/**
 
1027
 * hif_state_check:
 
1028
 **/
 
1029
gboolean
 
1030
hif_state_check (HifState *state, GError **error)
 
1031
{
 
1032
        gboolean ret = TRUE;
 
1033
 
 
1034
        g_return_val_if_fail (state != NULL, FALSE);
 
1035
        g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
1036
 
 
1037
        /* are we cancelled */
 
1038
        if (g_cancellable_is_cancelled (state->priv->cancellable)) {
 
1039
                g_set_error_literal (error,
 
1040
                                     HIF_ERROR,
 
1041
                                     PK_ERROR_ENUM_TRANSACTION_CANCELLED,
 
1042
                                     "cancelled by user action");
 
1043
                ret = FALSE;
 
1044
                goto out;
 
1045
        }
 
1046
out:
 
1047
        return ret;
 
1048
}
 
1049
 
 
1050
/**
 
1051
 * hif_state_done_real:
 
1052
 **/
 
1053
gboolean
 
1054
hif_state_done_real (HifState *state, GError **error, const gchar *strloc)
 
1055
{
 
1056
        gboolean ret;
 
1057
        gdouble elapsed;
 
1058
        gfloat percentage;
 
1059
 
 
1060
        g_return_val_if_fail (state != NULL, FALSE);
 
1061
        g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
1062
 
 
1063
        /* check */
 
1064
        ret = hif_state_check (state, error);
 
1065
        if (!ret)
 
1066
                goto out;
 
1067
 
 
1068
        /* do we care */
 
1069
        if (!state->priv->report_progress)
 
1070
                goto out;
 
1071
 
 
1072
        /* did we call done on a state that did not have a size set? */
 
1073
        if (state->priv->steps == 0) {
 
1074
                g_set_error (error, HIF_ERROR, PK_ERROR_ENUM_INTERNAL_ERROR,
 
1075
                             "done on a state %p that did not have a size set! [%s]",
 
1076
                             state, strloc);
 
1077
                hif_state_print_parent_chain (state, 0);
 
1078
                ret = FALSE;
 
1079
                goto out;
 
1080
        }
 
1081
 
 
1082
        /* check the interval was too big in allow_cancel false mode */
 
1083
        if (state->priv->enable_profile) {
 
1084
                elapsed = g_timer_elapsed (state->priv->timer, NULL);
 
1085
                if (!state->priv->allow_cancel_changed_state && state->priv->current > 0) {
 
1086
                        if (elapsed > 0.1f) {
 
1087
                                g_warning ("%.1fms between hif_state_done() and no hif_state_set_allow_cancel()", elapsed * 1000);
 
1088
                                hif_state_print_parent_chain (state, 0);
 
1089
                        }
 
1090
                }
 
1091
 
 
1092
                /* save the duration in the array */
 
1093
                if (state->priv->step_profile != NULL)
 
1094
                        state->priv->step_profile[state->priv->current] = elapsed;
 
1095
                g_timer_start (state->priv->timer);
 
1096
        }
 
1097
 
 
1098
        /* is already at 100%? */
 
1099
        if (state->priv->current >= state->priv->steps) {
 
1100
                g_set_error (error, HIF_ERROR, PK_ERROR_ENUM_INTERNAL_ERROR,
 
1101
                             "already at 100%% state [%s]", strloc);
 
1102
                hif_state_print_parent_chain (state, 0);
 
1103
                ret = FALSE;
 
1104
                goto out;
 
1105
        }
 
1106
 
 
1107
        /* is child not at 100%? */
 
1108
        if (state->priv->child != NULL) {
 
1109
                HifStatePrivate *child_priv = state->priv->child->priv;
 
1110
                if (child_priv->current != child_priv->steps) {
 
1111
                        g_print ("child is at %i/%i steps and parent done [%s]\n",
 
1112
                                 child_priv->current, child_priv->steps, strloc);
 
1113
                        hif_state_print_parent_chain (state->priv->child, 0);
 
1114
                        ret = TRUE;
 
1115
                        /* do not abort, as we want to clean this up */
 
1116
                }
 
1117
        }
 
1118
 
 
1119
        /* we just checked for cancel, so it's not true to say we're blocking */
 
1120
        hif_state_set_allow_cancel (state, TRUE);
 
1121
 
 
1122
        /* another */
 
1123
        state->priv->current++;
 
1124
 
 
1125
        /* find new percentage */
 
1126
        if (state->priv->step_data == NULL) {
 
1127
                percentage = hif_state_discrete_to_percent (state->priv->current,
 
1128
                                                            state->priv->steps);
 
1129
        } else {
 
1130
                /* this is cumalative, for speedy access */
 
1131
                percentage = state->priv->step_data[state->priv->current - 1];
 
1132
        }
 
1133
        hif_state_set_percentage (state, (guint) percentage);
 
1134
 
 
1135
        /* show any profiling stats */
 
1136
        if (state->priv->enable_profile &&
 
1137
            state->priv->current == state->priv->steps &&
 
1138
            state->priv->step_profile != NULL) {
 
1139
                hif_state_show_profile (state);
 
1140
        }
 
1141
 
 
1142
        /* reset child if it exists */
 
1143
        if (state->priv->child != NULL)
 
1144
                hif_state_reset (state->priv->child);
 
1145
out:
 
1146
        return ret;
 
1147
}
 
1148
 
 
1149
/**
 
1150
 * hif_state_finished_real:
 
1151
 **/
 
1152
gboolean
 
1153
hif_state_finished_real (HifState *state, GError **error, const gchar *strloc)
 
1154
{
 
1155
        gboolean ret;
 
1156
 
 
1157
        g_return_val_if_fail (state != NULL, FALSE);
 
1158
        g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
1159
 
 
1160
        /* check */
 
1161
        ret = hif_state_check (state, error);
 
1162
        if (!ret)
 
1163
                goto out;
 
1164
 
 
1165
        /* is already at 100%? */
 
1166
        if (state->priv->current == state->priv->steps)
 
1167
                goto out;
 
1168
 
 
1169
        /* all done */
 
1170
        state->priv->current = state->priv->steps;
 
1171
 
 
1172
        /* set new percentage */
 
1173
        hif_state_set_percentage (state, 100);
 
1174
out:
 
1175
        return ret;
 
1176
}
 
1177
 
 
1178
/**
 
1179
 * hif_state_finalize:
 
1180
 **/
 
1181
static void
 
1182
hif_state_finalize (GObject *object)
 
1183
{
 
1184
        HifState *state;
 
1185
 
 
1186
        g_return_if_fail (object != NULL);
 
1187
        g_return_if_fail (HIF_IS_STATE (object));
 
1188
        state = HIF_STATE (object);
 
1189
 
 
1190
        /* no more locks */
 
1191
        hif_state_release_locks (state);
 
1192
 
 
1193
        hif_state_reset (state);
 
1194
        g_free (state->priv->id);
 
1195
        g_free (state->priv->action_hint);
 
1196
        g_free (state->priv->step_data);
 
1197
        g_free (state->priv->step_profile);
 
1198
        if (state->priv->cancellable != NULL)
 
1199
                g_object_unref (state->priv->cancellable);
 
1200
        g_timer_destroy (state->priv->timer);
 
1201
        g_free (state->priv->speed_data);
 
1202
        g_ptr_array_unref (state->priv->lock_ids);
 
1203
        g_object_unref (state->priv->lock);
 
1204
 
 
1205
        G_OBJECT_CLASS (hif_state_parent_class)->finalize (object);
 
1206
}
 
1207
 
 
1208
/**
 
1209
 * hif_state_get_property:
 
1210
 **/
 
1211
static void
 
1212
hif_state_get_property (GObject *object,
 
1213
                        guint prop_id,
 
1214
                        GValue *value,
 
1215
                        GParamSpec *pspec)
 
1216
{
 
1217
        HifState *state = HIF_STATE (object);
 
1218
        HifStatePrivate *priv = state->priv;
 
1219
 
 
1220
        switch (prop_id) {
 
1221
        case PROP_SPEED:
 
1222
                g_value_set_uint64 (value, priv->speed);
 
1223
                break;
 
1224
        default:
 
1225
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 
1226
                break;
 
1227
        }
 
1228
}
 
1229
 
 
1230
/**
 
1231
 * hif_state_set_property:
 
1232
 **/
 
1233
static void
 
1234
hif_state_set_property (GObject *object,
 
1235
                        guint prop_id,
 
1236
                        const GValue *value,
 
1237
                        GParamSpec *pspec)
 
1238
{
 
1239
        HifState *state = HIF_STATE (object);
 
1240
        HifStatePrivate *priv = state->priv;
 
1241
 
 
1242
        switch (prop_id) {
 
1243
        case PROP_SPEED:
 
1244
                priv->speed = g_value_get_uint64 (value);
 
1245
                break;
 
1246
        default:
 
1247
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 
1248
                break;
 
1249
        }
 
1250
}
 
1251
 
 
1252
/**
 
1253
 * hif_state_class_init:
 
1254
 **/
 
1255
static void
 
1256
hif_state_class_init (HifStateClass *klass)
 
1257
{
 
1258
        GParamSpec *pspec;
 
1259
        GObjectClass *object_class = G_OBJECT_CLASS (klass);
 
1260
        object_class->finalize = hif_state_finalize;
 
1261
        object_class->get_property = hif_state_get_property;
 
1262
        object_class->set_property = hif_state_set_property;
 
1263
 
 
1264
        /**
 
1265
         * HifState:speed:
 
1266
         */
 
1267
        pspec = g_param_spec_uint64 ("speed", NULL, NULL,
 
1268
                                     0, G_MAXUINT64, 0,
 
1269
                                     G_PARAM_READABLE);
 
1270
        g_object_class_install_property (object_class, PROP_SPEED, pspec);
 
1271
 
 
1272
        signals [SIGNAL_PERCENTAGE_CHANGED] =
 
1273
                g_signal_new ("percentage-changed",
 
1274
                              G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
 
1275
                              G_STRUCT_OFFSET (HifStateClass, percentage_changed),
 
1276
                              NULL, NULL, g_cclosure_marshal_VOID__UINT,
 
1277
                              G_TYPE_NONE, 1, G_TYPE_UINT);
 
1278
 
 
1279
        signals [SIGNAL_SUBPERCENTAGE_CHANGED] =
 
1280
                g_signal_new ("subpercentage-changed",
 
1281
                              G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
 
1282
                              G_STRUCT_OFFSET (HifStateClass, subpercentage_changed),
 
1283
                              NULL, NULL, g_cclosure_marshal_VOID__UINT,
 
1284
                              G_TYPE_NONE, 1, G_TYPE_UINT);
 
1285
 
 
1286
        signals [SIGNAL_ALLOW_CANCEL_CHANGED] =
 
1287
                g_signal_new ("allow-cancel-changed",
 
1288
                              G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
 
1289
                              G_STRUCT_OFFSET (HifStateClass, allow_cancel_changed),
 
1290
                              NULL, NULL, g_cclosure_marshal_VOID__BOOLEAN,
 
1291
                              G_TYPE_NONE, 1, G_TYPE_BOOLEAN);
 
1292
 
 
1293
        signals [SIGNAL_ACTION_CHANGED] =
 
1294
                g_signal_new ("action-changed",
 
1295
                              G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
 
1296
                              G_STRUCT_OFFSET (HifStateClass, action_changed),
 
1297
                              NULL, NULL, g_cclosure_marshal_generic,
 
1298
                              G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_STRING);
 
1299
 
 
1300
        signals [SIGNAL_PACKAGE_PROGRESS_CHANGED] =
 
1301
                g_signal_new ("package-progress-changed",
 
1302
                              G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
 
1303
                              G_STRUCT_OFFSET (HifStateClass, package_progress_changed),
 
1304
                              NULL, NULL, g_cclosure_marshal_generic,
 
1305
                              G_TYPE_NONE, 3, G_TYPE_STRING, G_TYPE_UINT, G_TYPE_UINT);
 
1306
 
 
1307
        g_type_class_add_private (klass, sizeof (HifStatePrivate));
 
1308
}
 
1309
 
 
1310
/**
 
1311
 * hif_state_init:
 
1312
 **/
 
1313
static void
 
1314
hif_state_init (HifState *state)
 
1315
{
 
1316
        state->priv = HIF_STATE_GET_PRIVATE (state);
 
1317
        state->priv->allow_cancel = TRUE;
 
1318
        state->priv->allow_cancel_child = TRUE;
 
1319
        state->priv->global_share = 1.0f;
 
1320
        state->priv->action = PK_STATUS_ENUM_UNKNOWN;
 
1321
        state->priv->last_action = PK_STATUS_ENUM_UNKNOWN;
 
1322
        state->priv->timer = g_timer_new ();
 
1323
        state->priv->lock_ids = g_ptr_array_new ();
 
1324
        state->priv->report_progress = TRUE;
 
1325
        state->priv->lock = hif_lock_new ();
 
1326
        state->priv->speed_data = g_new0 (guint64, HIF_STATE_SPEED_SMOOTHING_ITEMS);
 
1327
}
 
1328
 
 
1329
/**
 
1330
 * hif_state_new:
 
1331
 **/
 
1332
HifState *
 
1333
hif_state_new (void)
 
1334
{
 
1335
        HifState *state;
 
1336
        state = g_object_new (HIF_TYPE_STATE, NULL);
 
1337
        return HIF_STATE (state);
 
1338
}
 
1339