view pkui-backend.c @ 51:f119075975e8 version-2

Release version 2
author Guido Berhoerster <gber@opensuse.org>
date Fri, 19 Jun 2015 13:08:33 +0200
parents a29fbf0a7f6c
children 7de92a24e86c
line wrap: on
line source

/*
 * (C) 2011 Guido Berhoerster <gber@opensuse.org>
 *
 * Licensed under the GNU General Public License Version 2
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include <packagekit-glib2/packagekit.h>
#include "pkui-backend.h"

G_DEFINE_TYPE(PkuiBackend, pkui_backend, G_TYPE_OBJECT)

#define	PKUI_BACKEND_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), \
	PKUI_TYPE_BACKEND, PkuiBackendPrivate))

struct _PkuiBackendPrivate
{
	PkuiBackend	*backend;
	PkClient	*pk_client;
	guint		periodic_check_id;
	guint		updates_normal;
	guint		updates_important;
	guint		previous_updates_normal;
	guint		previous_updates_important;
	guint		startup_delay;
	guint		check_interval;
	gint64		last_check;
	gboolean	inhibit_check;
};

enum
{
	PROP_0,

	PROP_UPDATES_NORMAL,
	PROP_UPDATES_IMPORTANT,
	PROP_STARTUP_DELAY,
	PROP_CHECK_INTERVAL,
	PROP_INHIBIT_CHECK
};

enum
{
	STATE_CHANGED_SIGNAL,

	LAST_SIGNAL
};

static guint	pkui_backend_signals[LAST_SIGNAL] = { 0 };

static gboolean	periodic_check(gpointer data);

static void
pkui_backend_set_property(GObject *object, guint property_id,
    const GValue *value, GParamSpec *pspec)
{
	PkuiBackend	*self = PKUI_BACKEND(object);
	gboolean	inhibit_check;
	gint64		time_to_check;

	switch (property_id) {
	case PROP_STARTUP_DELAY:
		self->priv->startup_delay = g_value_get_uint(value);

		if (self->priv->periodic_check_id != 0) {
			g_source_remove(self->priv->periodic_check_id);
		}
		self->priv->periodic_check_id =
		    g_timeout_add_seconds(self->priv->startup_delay,
		    (GSourceFunc)periodic_check, self);
		break;
	case PROP_CHECK_INTERVAL:
		self->priv->check_interval = g_value_get_uint(value);

		/*
		 * reschedule only if the first run has been completed and
		 * checks are currently not inibited, otherwise the new
		 * interval will be picked up anyway
		 */
		if (!self->priv->inhibit_check && self->priv->last_check > 0) {
			time_to_check = g_get_real_time() -
			    self->priv->last_check;
			if (time_to_check <= 0)
				pkui_backend_check_now(self);
			else {
				if (self->priv->periodic_check_id != 0) {
					g_source_remove(self->priv->periodic_check_id);
				}
				self->priv->periodic_check_id =
				    g_timeout_add_seconds(time_to_check,
				    periodic_check, self);
			}
		}
		break;
	case PROP_INHIBIT_CHECK:
		inhibit_check = g_value_get_boolean(value);

		/*
		 * when changing self->priv->inhibit_check from FALSE to TRUE
		 * and the first run has been completed remove the periodic
		 * check, when changing from TRUE to FALSE either trigger a run
		 * immediately when more time than self->priv->check_interval
		 * has passed or just reschedule the next check
		 */
		if (!self->priv->inhibit_check && inhibit_check &&
		    self->priv->periodic_check_id != 0) {
			g_source_remove(self->priv->periodic_check_id);
			self->priv->periodic_check_id = 0;
		} else if (self->priv->inhibit_check && !inhibit_check) {
			self->priv->periodic_check_id =
			    g_timeout_add_seconds(self->priv->check_interval,
			    (GSourceFunc)periodic_check, self);
		}
		self->priv->inhibit_check = inhibit_check;
		break;
	default:
		G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
		break;
	}
}

static void
pkui_backend_get_property(GObject *object, guint property_id, GValue *value,
    GParamSpec *pspec)
{
	PkuiBackend	*self = PKUI_BACKEND(object);

	switch (property_id) {
	case PROP_UPDATES_NORMAL:
		g_value_set_uint(value, self->priv->updates_normal);
		break;
	case PROP_UPDATES_IMPORTANT:
		g_value_set_uint(value, self->priv->updates_important);
		break;
	case PROP_STARTUP_DELAY:
		g_value_set_uint(value, self->priv->startup_delay);
		break;
	case PROP_CHECK_INTERVAL:
		g_value_set_uint(value, self->priv->check_interval);
		break;
	case PROP_INHIBIT_CHECK:
		g_value_set_boolean(value, self->priv->inhibit_check);
		break;
	default:
		G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
		break;
	}
}

static void
pkui_backend_finalize(GObject *gobject)
{
	PkuiBackend	*self = PKUI_BACKEND(gobject);

	if (self->priv->pk_client != NULL)
		g_object_unref(self->priv->pk_client);

	G_OBJECT_CLASS(pkui_backend_parent_class)->finalize(gobject);
}

static void
pkui_backend_class_init(PkuiBackendClass *klass)
{
	GObjectClass	*gobject_class = G_OBJECT_CLASS(klass);
	GParamSpec	*pspec;

	gobject_class->set_property = pkui_backend_set_property;
	gobject_class->get_property = pkui_backend_get_property;
	gobject_class->finalize = pkui_backend_finalize;

	pspec = g_param_spec_uint("updates-normal", "Normal updates",
	    "Number of normal package updates", 0, G_MAXUINT, 0,
	    G_PARAM_READABLE);
	g_object_class_install_property(gobject_class, PROP_UPDATES_NORMAL,
	    pspec);

	pspec = g_param_spec_uint("updates-important", "Important updates",
	    "Number of important package updates", 0, G_MAXUINT, 0,
	    G_PARAM_READABLE);
	g_object_class_install_property(gobject_class, PROP_UPDATES_IMPORTANT,
	    pspec);

	pspec = g_param_spec_uint("startup-delay", "Startup delay",
	    "Initial delay in seconds before the first check for new package "
	    "updates", 0, G_MAXUINT, 300,
	    G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
	g_object_class_install_property(gobject_class, PROP_STARTUP_DELAY,
	    pspec);

	pspec = g_param_spec_uint("check-interval", "Check interval",
	    "Interval in seconds for checking for new package updates", 1,
	    G_MAXUINT, 86400, G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
	g_object_class_install_property(gobject_class, PROP_CHECK_INTERVAL,
	    pspec);

	pspec = g_param_spec_boolean("inhibit-check", "Inhibit check",
	    "Whether to inhibit checks for new package updates", FALSE,
	    G_PARAM_READWRITE);
	g_object_class_install_property(gobject_class, PROP_INHIBIT_CHECK,
	    pspec);

	pkui_backend_signals[STATE_CHANGED_SIGNAL] =
	    g_signal_newv("state-changed", G_TYPE_FROM_CLASS(gobject_class),
	    G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, NULL,
	    NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, NULL);

	g_type_class_add_private(klass, sizeof (PkuiBackendPrivate));
}

static void
pkui_backend_init(PkuiBackend *self)
{
	self->priv = PKUI_BACKEND_GET_PRIVATE(self);

	self->priv->pk_client = pk_client_new();
	self->priv->updates_normal = 0;
	self->priv->updates_important = 0;
	self->priv->periodic_check_id =
	    g_timeout_add_seconds(self->priv->startup_delay,
	    (GSourceFunc)periodic_check, self);
	self->priv->last_check = 0;
}

static gboolean
periodic_check(gpointer data)
{
	PkuiBackend	*self = PKUI_BACKEND(data);

	pkui_backend_check_now(self);

	/* rescheduling happens after results are available */
	self->priv->periodic_check_id = 0;
	return (FALSE);
}

static void
process_pk_package_info(PkPackage *pkg, gpointer *user_data)
{
	PkuiBackend	*self = PKUI_BACKEND(user_data);
	PkInfoEnum	type_info = pk_package_get_info(pkg);

	switch (type_info) {
	case PK_INFO_ENUM_LOW:
	case PK_INFO_ENUM_ENHANCEMENT:
	case PK_INFO_ENUM_NORMAL:
		self->priv->updates_normal++;
		break;
	case PK_INFO_ENUM_BUGFIX:
	case PK_INFO_ENUM_IMPORTANT:
	case PK_INFO_ENUM_SECURITY:
		self->priv->updates_important++;
		break;
	default:
		break;
	}
}

static void
get_updates_finished(GObject *object, GAsyncResult *res, gpointer user_data)
{
	PkClient	*client = PK_CLIENT(object);
	PkuiBackend	*self = PKUI_BACKEND(user_data);
	PkResults	*results = NULL;
	GError		*error = NULL;
	GPtrArray	*list = NULL;

	g_debug("PackageKit finished checking for updates");

	results = pk_client_generic_finish(PK_CLIENT(client), res, &error);
	if (results == NULL) {
		g_warning("error: %s\n", error->message);
		g_error_free(error);
		goto out;
	}

	list = pk_results_get_package_array(results);
	if (list == NULL)
		goto out;
	self->priv->previous_updates_normal = self->priv->updates_normal;
	self->priv->previous_updates_important = self->priv->updates_important;
	self->priv->updates_normal = 0;
	self->priv->updates_important = 0;
	g_ptr_array_foreach(list, (GFunc)process_pk_package_info, self);

	if (self->priv->updates_normal != self->priv->previous_updates_normal ||
	    self->priv->updates_important !=
	    self->priv->previous_updates_important) {
		g_debug("normal updates: %d, important updates: %d",
		    self->priv->updates_normal, self->priv->updates_important);
		g_debug("emit state-changed");

		g_signal_emit(self, pkui_backend_signals[STATE_CHANGED_SIGNAL],
		    0);
	}

out:
	if (results != NULL)
		g_object_unref(results);
	if (list != NULL)
		g_ptr_array_unref(list);

	self->priv->last_check = g_get_real_time();

	if (!self->priv->inhibit_check) {
		if (self->priv->periodic_check_id != 0) {
			g_source_remove(self->priv->periodic_check_id);
		}
		self->priv->periodic_check_id =
			g_timeout_add_seconds(self->priv->check_interval,
			    (GSourceFunc)periodic_check, self);
	}
}

PkuiBackend *
pkui_backend_new(guint startup_delay, guint check_interval)
{
	g_return_val_if_fail(check_interval > 0, NULL);

	return (g_object_new(PKUI_TYPE_BACKEND, "startup-delay", startup_delay,
	    "check-interval", check_interval, NULL));
}

guint
pkui_backend_get_updates_normal(PkuiBackend *self)
{
	guint	updates_normal;

	g_return_val_if_fail(PKUI_IS_BACKEND(self), 0);

	g_object_get(G_OBJECT(self), "updates-normal", &updates_normal, NULL);

	return (updates_normal);
}

guint
pkui_backend_get_updates_important(PkuiBackend *self)
{
	guint	updates_important;

	g_return_val_if_fail(PKUI_IS_BACKEND(self), 0);

	g_object_get(G_OBJECT(self), "updates-important", &updates_important,
	    NULL);

	return (updates_important);
}

void
pkui_backend_set_inhibit_check(PkuiBackend *self, gboolean inhibit_check)
{
	g_return_if_fail(PKUI_IS_BACKEND(self));

	g_object_set(G_OBJECT(self), "inhibit-check", inhibit_check, NULL);
}

gboolean
pkui_backend_get_inhibit_check(PkuiBackend *self)
{
	gboolean	inhibit_check;

	g_return_val_if_fail(PKUI_IS_BACKEND(self), FALSE);

	g_object_get(G_OBJECT(self), "inhibit-check", &inhibit_check, NULL);

	return (inhibit_check);
}

guint
pkui_backend_get_startup_interval(PkuiBackend *self)
{
	guint	startup_interval;

	g_return_val_if_fail(PKUI_IS_BACKEND(self), 0);

	g_object_get(G_OBJECT(self), "startup-interval", &startup_interval,
	    NULL);

	return (startup_interval);
}

void
pkui_backend_set_check_interval(PkuiBackend *self, guint check_interval)
{
	g_return_if_fail(PKUI_IS_BACKEND(self));

	g_object_set(G_OBJECT(self), "check-interval", check_interval, NULL);
}

guint
pkui_backend_get_check_interval(PkuiBackend *self)
{
	guint	check_interval;

	g_return_val_if_fail(PKUI_IS_BACKEND(self), 0);

	g_object_get(G_OBJECT(self), "check-interval", &check_interval, NULL);

	return (check_interval);
}

void
pkui_backend_check_now(PkuiBackend *self)
{
	g_return_if_fail(PKUI_IS_BACKEND(self));

	g_debug("querying PackageKit for updates");

	pk_client_get_updates_async(self->priv->pk_client,
	    pk_bitfield_value(PK_FILTER_ENUM_NONE), NULL, NULL, NULL,
	    get_updates_finished, self);
}