1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
3
* Copyright (C) 2009-2013 Richard Hughes <richard@hughsie.com>
5
* Most of this code was taken from Zif, libzif/zif-state.c
7
* Licensed under the GNU General Public License Version 2
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.
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.
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.
29
#if GLIB_CHECK_VERSION(2,29,19)
30
#include <glib-unix.h>
33
#include <rpm/rpmsq.h>
35
#include "hif-utils.h"
36
#include "hif-state.h"
38
#define HIF_STATE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), HIF_TYPE_STATE, HifStatePrivate))
40
struct _HifStatePrivate
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;
51
gdouble *step_profile;
52
gpointer error_handler_user_data;
53
gpointer lock_handler_user_data;
58
guint last_percentage;
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;
68
PkStatusEnum last_action;
69
PkStatusEnum child_action;
71
HifStateErrorHandlerCb error_handler_cb;
72
HifStateLockHandlerCb lock_handler_cb;
79
SIGNAL_PERCENTAGE_CHANGED,
80
SIGNAL_SUBPERCENTAGE_CHANGED,
81
SIGNAL_ALLOW_CANCEL_CHANGED,
82
SIGNAL_ACTION_CHANGED,
83
SIGNAL_PACKAGE_PROGRESS_CHANGED,
93
static guint signals [SIGNAL_LAST] = { 0 };
95
G_DEFINE_TYPE (HifState, hif_state, G_TYPE_OBJECT)
97
#define HIF_STATE_SPEED_SMOOTHING_ITEMS 5
100
* hif_state_set_report_progress:
103
hif_state_set_report_progress (HifState *state, gboolean report_progress)
105
g_return_if_fail (HIF_IS_STATE (state));
106
state->priv->report_progress = report_progress;
110
* hif_state_set_enable_profile:
113
hif_state_set_enable_profile (HifState *state, gboolean enable_profile)
115
g_return_if_fail (HIF_IS_STATE (state));
116
state->priv->enable_profile = enable_profile;
120
* hif_state_set_lock_handler:
123
hif_state_set_lock_handler (HifState *state,
124
HifStateLockHandlerCb lock_handler_cb,
127
state->priv->lock_handler_cb = lock_handler_cb;
128
state->priv->lock_handler_user_data = user_data;
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,
139
* hif_state_take_lock:
142
hif_state_take_lock (HifState *state,
143
HifLockType lock_type,
144
HifLockMode lock_mode,
150
/* no custom handler */
151
if (state->priv->lock_handler_cb == NULL) {
152
lock_id = hif_lock_take (state->priv->lock,
160
ret = state->priv->lock_handler_cb (state,
164
state->priv->lock_handler_user_data);
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));
178
* hif_state_discrete_to_percent:
181
hif_state_discrete_to_percent (guint discrete, guint steps)
183
/* check we are in range */
184
if (discrete > steps)
187
g_warning ("steps is 0!");
190
return ((gfloat) discrete * (100.0f / (gfloat) (steps)));
194
* hif_state_print_parent_chain:
197
hif_state_print_parent_chain (HifState *state, guint level)
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);
206
* hif_state_get_cancellable:
209
hif_state_get_cancellable (HifState *state)
211
g_return_val_if_fail (HIF_IS_STATE (state), NULL);
212
return state->priv->cancellable;
216
* hif_state_set_cancellable:
219
hif_state_set_cancellable (HifState *state, GCancellable *cancellable)
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);
227
* hif_state_get_allow_cancel:
230
hif_state_get_allow_cancel (HifState *state)
232
g_return_val_if_fail (HIF_IS_STATE (state), FALSE);
233
return state->priv->allow_cancel && state->priv->allow_cancel_child;
237
* hif_state_set_allow_cancel:
240
hif_state_set_allow_cancel (HifState *state, gboolean allow_cancel)
242
g_return_if_fail (HIF_IS_STATE (state));
244
state->priv->allow_cancel_changed_state = TRUE;
246
/* quick optimisation that saves lots of signals */
247
if (state->priv->allow_cancel == allow_cancel)
249
state->priv->allow_cancel = allow_cancel;
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);
257
* hif_state_get_speed:
260
hif_state_get_speed (HifState *state)
262
g_return_val_if_fail (HIF_IS_STATE (state), 0);
263
return state->priv->speed;
267
* hif_state_set_speed_internal:
270
hif_state_set_speed_internal (HifState *state, guint64 speed)
272
if (state->priv->speed == speed)
274
state->priv->speed = speed;
275
g_object_notify (G_OBJECT (state), "speed");
279
* hif_state_set_speed:
282
hif_state_set_speed (HifState *state, guint64 speed)
287
g_return_if_fail (HIF_IS_STATE (state));
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;
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];
304
g_debug ("speed = %" G_GUINT64_FORMAT " kb/sec", sum / 1024);
305
hif_state_set_speed_internal (state, sum);
309
* hif_state_release_locks:
312
hif_state_release_locks (HifState *state)
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,
328
g_ptr_array_set_size (state->priv->lock_ids, 0);
334
* hif_state_set_percentage:
337
hif_state_set_percentage (HifState *state, guint percentage)
339
gboolean ret = FALSE;
342
if (!state->priv->report_progress) {
348
if (percentage == state->priv->last_percentage)
352
if (percentage > 100) {
353
hif_state_print_parent_chain (state, 0);
354
g_warning ("percentage %i%% is invalid on %p!",
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);
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);
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);
382
/* speed no longer valid */
383
if (percentage == 100)
384
hif_state_set_speed_internal (state, 0);
387
if (percentage == 100) {
388
ret = hif_state_release_locks (state);
394
state->priv->last_percentage = percentage;
396
/* are we so low we don't care */
397
if (state->priv->global_share < 0.001)
401
g_signal_emit (state, signals [SIGNAL_PERCENTAGE_CHANGED], 0, percentage);
410
* hif_state_get_percentage:
413
hif_state_get_percentage (HifState *state)
415
return state->priv->last_percentage;
419
* hif_state_set_subpercentage:
422
hif_state_set_subpercentage (HifState *state, guint percentage)
424
/* are we so low we don't care */
425
if (state->priv->global_share < 0.01)
429
g_signal_emit (state, signals [SIGNAL_SUBPERCENTAGE_CHANGED], 0, percentage);
435
* hif_state_action_start:
438
hif_state_action_start (HifState *state, PkStatusEnum action, const gchar *action_hint)
440
g_return_val_if_fail (HIF_IS_STATE (state), FALSE);
443
if (action == PK_STATUS_ENUM_UNKNOWN) {
444
g_warning ("cannot set action PK_STATUS_ENUM_UNKNOWN");
449
if (state->priv->action == action &&
450
g_strcmp0 (action_hint, state->priv->action_hint) == 0) {
451
g_debug ("same action as before, ignoring");
455
/* remember for stop */
456
state->priv->last_action = state->priv->action;
459
g_free (state->priv->action_hint);
460
state->priv->action_hint = g_strdup (action_hint);
463
state->priv->action = action;
466
g_signal_emit (state, signals [SIGNAL_ACTION_CHANGED], 0, action, action_hint);
471
* hif_state_set_package_progress:
474
hif_state_set_package_progress (HifState *state,
475
const gchar *package_id,
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);
485
g_signal_emit (state, signals [SIGNAL_PACKAGE_PROGRESS_CHANGED], 0,
486
package_id, action, percentage);
490
* hif_state_action_stop:
493
hif_state_action_stop (HifState *state)
495
g_return_val_if_fail (HIF_IS_STATE (state), FALSE);
497
/* nothing ever set */
498
if (state->priv->action == PK_STATUS_ENUM_UNKNOWN) {
499
g_debug ("cannot unset action PK_STATUS_ENUM_UNKNOWN");
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;
512
g_signal_emit (state, signals [SIGNAL_ACTION_CHANGED], 0, state->priv->action, NULL);
517
* hif_state_get_action_hint:
520
hif_state_get_action_hint (HifState *state)
522
g_return_val_if_fail (HIF_IS_STATE (state), NULL);
523
return state->priv->action_hint;
527
* hif_state_get_action:
530
hif_state_get_action (HifState *state)
532
g_return_val_if_fail (HIF_IS_STATE (state), PK_STATUS_ENUM_UNKNOWN);
533
return state->priv->action;
537
* hif_state_child_percentage_changed_cb:
540
hif_state_child_percentage_changed_cb (HifState *child, guint percentage, HifState *state)
545
guint parent_percentage;
547
/* propagate up the stack if HifState has only one step */
548
if (state->priv->steps == 1) {
549
hif_state_set_percentage (state, percentage);
553
/* did we call done on a state that did not have a size set? */
554
if (state->priv->steps == 0)
557
/* always provide two levels of signals */
558
hif_state_set_subpercentage (state, percentage);
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);
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;
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;
580
offset = hif_state_discrete_to_percent (state->priv->current, state->priv->steps);
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;
585
g_warning ("range=%f (from %i to %i), should be impossible", range, state->priv->current+1, state->priv->steps);
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));
596
/* get the extra contributed by the child */
597
extra = ((gfloat) percentage / 100.0f) * range;
599
/* emit from the parent */
600
parent_percentage = (guint) (offset + extra);
602
hif_state_set_percentage (state, parent_percentage);
606
* hif_state_child_subpercentage_changed_cb:
609
hif_state_child_subpercentage_changed_cb (HifState *child, guint percentage, HifState *state)
611
/* discard this, unless the HifState has only one step */
612
if (state->priv->steps != 1)
615
/* propagate up the stack as if the parent didn't exist */
616
hif_state_set_subpercentage (state, percentage);
620
* hif_state_child_allow_cancel_changed_cb:
623
hif_state_child_allow_cancel_changed_cb (HifState *child, gboolean allow_cancel, HifState *state)
626
state->priv->allow_cancel_child = allow_cancel;
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);
634
* hif_state_child_action_changed_cb:
637
hif_state_child_action_changed_cb (HifState *child, PkStatusEnum action, const gchar *action_hint, HifState *state)
640
state->priv->action = action;
643
g_signal_emit (state, signals [SIGNAL_ACTION_CHANGED], 0, action, action_hint);
647
* hif_state_child_package_progress_changed_cb:
650
hif_state_child_package_progress_changed_cb (HifState *child,
651
const gchar *package_id,
657
g_signal_emit (state, signals [SIGNAL_PACKAGE_PROGRESS_CHANGED], 0,
658
package_id, action, progress);
665
hif_state_reset (HifState *state)
669
g_return_val_if_fail (HIF_IS_STATE (state), FALSE);
672
if (!state->priv->report_progress) {
678
state->priv->steps = 0;
679
state->priv->current = 0;
680
state->priv->last_percentage = 0;
682
/* only use the timer if profiling; it's expensive */
683
if (state->priv->enable_profile)
684
g_timer_start (state->priv->timer);
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;
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;
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;
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;
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;
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;
719
if (state->priv->child != NULL) {
720
g_object_unref (state->priv->child);
721
state->priv->child = NULL;
725
hif_state_release_locks (state);
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;
737
* hif_state_set_global_share:
740
hif_state_set_global_share (HifState *state, gdouble global_share)
742
state->priv->global_share = global_share;
746
* hif_state_child_notify_speed_cb:
749
hif_state_child_notify_speed_cb (HifState *child,
753
hif_state_set_speed_internal (state,
754
hif_state_get_speed (child));
758
* hif_state_get_child:
761
hif_state_get_child (HifState *state)
763
HifState *child = NULL;
765
g_return_val_if_fail (HIF_IS_STATE (state), NULL);
768
if (!state->priv->report_progress) {
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);
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),
798
state->priv->subpercentage_child_id =
799
g_signal_connect (child, "subpercentage-changed",
800
G_CALLBACK (hif_state_child_subpercentage_changed_cb),
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),
806
state->priv->action_child_id =
807
g_signal_connect (child, "action-changed",
808
G_CALLBACK (hif_state_child_action_changed_cb),
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),
814
state->priv->notify_speed_child_id =
815
g_signal_connect (child, "notify::speed",
816
G_CALLBACK (hif_state_child_notify_speed_cb),
820
child->priv->current = 0;
821
child->priv->last_percentage = 0;
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;
827
/* set the global share on the new child */
828
hif_state_set_global_share (child, state->priv->global_share);
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);
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);
842
/* set the profile state */
843
hif_state_set_enable_profile (child,
844
state->priv->enable_profile);
850
* hif_state_set_number_steps_real:
853
hif_state_set_number_steps_real (HifState *state, guint steps, const gchar *strloc)
855
gboolean ret = FALSE;
857
g_return_val_if_fail (state != NULL, FALSE);
859
/* nothing to do for 0 steps */
866
if (!state->priv->report_progress) {
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);
880
g_free (state->priv->id);
881
state->priv->id = g_strdup_printf ("%s", strloc);
883
/* only use the timer if profiling; it's expensive */
884
if (state->priv->enable_profile)
885
g_timer_start (state->priv->timer);
888
hif_state_reset (state);
891
state->priv->steps = steps;
893
/* global share just got smaller */
894
state->priv->global_share /= steps;
903
* hif_state_set_steps_real:
906
hif_state_set_steps_real (HifState *state, GError **error, const gchar *strloc, gint value, ...)
912
gboolean ret = FALSE;
914
g_return_val_if_fail (state != NULL, FALSE);
915
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
918
if (!state->priv->report_progress) {
923
/* we must set at least one thing */
926
/* process the valist */
927
va_start (args, value);
929
value_temp = va_arg (args, gint);
930
if (value_temp == -1)
932
total += (guint) value_temp;
936
/* does not sum to 100% */
940
PK_ERROR_ENUM_INTERNAL_ERROR,
941
"percentage not 100: %i",
946
/* set step number */
947
ret = hif_state_set_number_steps_real (state, i+1, strloc);
951
PK_ERROR_ENUM_INTERNAL_ERROR,
952
"failed to set number steps: %i",
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);
964
value_temp = va_arg (args, gint);
965
if (value_temp == -1)
968
/* we pre-add the data to make access simpler */
969
total += (guint) value_temp;
970
state->priv->step_data[i+1] = total;
981
* hif_state_show_profile:
984
hif_state_show_profile (HifState *state)
987
gdouble total_time = 0.0f;
990
guint uncumalitive = 0;
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]);
998
if (state->priv->steps > 0)
999
g_string_set_size (result, result->len - 2);
1000
g_string_append (result, " }\n");
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;
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];
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);
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);
1030
hif_state_check (HifState *state, GError **error)
1032
gboolean ret = TRUE;
1034
g_return_val_if_fail (state != NULL, FALSE);
1035
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1037
/* are we cancelled */
1038
if (g_cancellable_is_cancelled (state->priv->cancellable)) {
1039
g_set_error_literal (error,
1041
PK_ERROR_ENUM_TRANSACTION_CANCELLED,
1042
"cancelled by user action");
1051
* hif_state_done_real:
1054
hif_state_done_real (HifState *state, GError **error, const gchar *strloc)
1060
g_return_val_if_fail (state != NULL, FALSE);
1061
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1064
ret = hif_state_check (state, error);
1069
if (!state->priv->report_progress)
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]",
1077
hif_state_print_parent_chain (state, 0);
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);
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);
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);
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);
1115
/* do not abort, as we want to clean this up */
1119
/* we just checked for cancel, so it's not true to say we're blocking */
1120
hif_state_set_allow_cancel (state, TRUE);
1123
state->priv->current++;
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);
1130
/* this is cumalative, for speedy access */
1131
percentage = state->priv->step_data[state->priv->current - 1];
1133
hif_state_set_percentage (state, (guint) percentage);
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);
1142
/* reset child if it exists */
1143
if (state->priv->child != NULL)
1144
hif_state_reset (state->priv->child);
1150
* hif_state_finished_real:
1153
hif_state_finished_real (HifState *state, GError **error, const gchar *strloc)
1157
g_return_val_if_fail (state != NULL, FALSE);
1158
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1161
ret = hif_state_check (state, error);
1165
/* is already at 100%? */
1166
if (state->priv->current == state->priv->steps)
1170
state->priv->current = state->priv->steps;
1172
/* set new percentage */
1173
hif_state_set_percentage (state, 100);
1179
* hif_state_finalize:
1182
hif_state_finalize (GObject *object)
1186
g_return_if_fail (object != NULL);
1187
g_return_if_fail (HIF_IS_STATE (object));
1188
state = HIF_STATE (object);
1191
hif_state_release_locks (state);
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);
1205
G_OBJECT_CLASS (hif_state_parent_class)->finalize (object);
1209
* hif_state_get_property:
1212
hif_state_get_property (GObject *object,
1217
HifState *state = HIF_STATE (object);
1218
HifStatePrivate *priv = state->priv;
1222
g_value_set_uint64 (value, priv->speed);
1225
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1231
* hif_state_set_property:
1234
hif_state_set_property (GObject *object,
1236
const GValue *value,
1239
HifState *state = HIF_STATE (object);
1240
HifStatePrivate *priv = state->priv;
1244
priv->speed = g_value_get_uint64 (value);
1247
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1253
* hif_state_class_init:
1256
hif_state_class_init (HifStateClass *klass)
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;
1267
pspec = g_param_spec_uint64 ("speed", NULL, NULL,
1270
g_object_class_install_property (object_class, PROP_SPEED, pspec);
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);
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);
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);
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);
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);
1307
g_type_class_add_private (klass, sizeof (HifStatePrivate));
1314
hif_state_init (HifState *state)
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);
1333
hif_state_new (void)
1336
state = g_object_new (HIF_TYPE_STATE, NULL);
1337
return HIF_STATE (state);