view pkui-backend.c @ 56:63347002d746

Simplify PkuiBackend Make the "check-interval" property construct-only since it is never changed at runtime and schedule the first check for updates in the "constructed" method. Remove unused property get methods. Destroy PkClient and remove periodic check in the "dispose" method.
author Guido Berhoerster <guido+pk-update-icon@berhoerster.name>
date Sun, 01 Jul 2018 22:38:11 +0200
parents 7de92a24e86c
children
line wrap: on
line source

/*
 * (C) 2011 Guido Berhoerster <guido+pk-update-icon@berhoerster.name>
 *
 * 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);
	case PROP_CHECK_INTERVAL:
		self->priv->check_interval = g_value_get_uint(value);
		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_constructed(GObject *gobject)
{
	PkuiBackend	*self = PKUI_BACKEND(gobject);

	self->priv->periodic_check_id =
	    g_timeout_add_seconds(self->priv->startup_delay,
	    (GSourceFunc)periodic_check, self);
}

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

	if (self->priv->pk_client != NULL) {
		g_clear_object(&self->priv->pk_client);
	}

	if (self->priv->periodic_check_id != 0) {
		g_source_remove(self->priv->periodic_check_id);
		self->priv->periodic_check_id = 0;
	}

	G_OBJECT_CLASS(pkui_backend_parent_class)->dispose(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->constructed = pkui_backend_constructed;
	gobject_class->dispose = pkui_backend_dispose;

	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_ONLY);
	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();
}

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);
}

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);
}