libpurple/purpleidlemanager.c

Thu, 22 Feb 2024 06:03:16 -0600

author
Gary Kramlich <grim@reaperworld.com>
date
Thu, 22 Feb 2024 06:03:16 -0600
changeset 42596
b64b96f3b781
parent 42594
eddde70cedd8
child 42614
b75a5bbf6c35
permissions
-rw-r--r--

Add a favorite property to PurpleContactInfo

This will be used in the future for toggling whether or not contacts are
favorited or starred.

Testing Done:
Ran the unit tests under valgrind.

Reviewed at https://reviews.imfreedom.org/r/2965/

/*
 * Purple - Internet Messaging Library
 * Copyright (C) Pidgin Developers <devel@pidgin.im>
 *
 * Purple is the legal property of its developers, whose names are too numerous
 * to list here. Please refer to the COPYRIGHT file distributed with this
 * source distribution.
 *
 * This library 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 library 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 library; if not, see <https://www.gnu.org/licenses/>.
 */

#include "purpleidlemanager.h"
#include "purpleidlemanagerprivate.h"

#include "util.h"

enum {
	PROP_0,
	PROP_TIMESTAMP,
	N_PROPERTIES,
};
static GParamSpec *properties[N_PROPERTIES] = {NULL, };

struct _PurpleIdleManager {
	GObject parent;

	GHashTable *sources;
	char *active_source;
};

/******************************************************************************
 * GObject Implementation
 *****************************************************************************/
G_DEFINE_FINAL_TYPE(PurpleIdleManager, purple_idle_manager, G_TYPE_OBJECT)

static void
purple_idle_manager_finalize(GObject *obj) {
	PurpleIdleManager *manager = PURPLE_IDLE_MANAGER(obj);

	g_clear_pointer(&manager->sources, g_hash_table_destroy);
	g_clear_pointer(&manager->active_source, g_free);

	G_OBJECT_CLASS(purple_idle_manager_parent_class)->finalize(obj);
}

static void
purple_idle_manager_get_property(GObject *obj, guint param_id,
                                 GValue *value, GParamSpec *pspec)
{
	PurpleIdleManager *manager = PURPLE_IDLE_MANAGER(obj);

	switch(param_id) {
	case PROP_TIMESTAMP:
		g_value_set_boxed(value, purple_idle_manager_get_timestamp(manager));
		break;
	default:
		G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
		break;
	}
}

static void
purple_idle_manager_init(PurpleIdleManager *manager) {
	manager->sources = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
	                                         (GDestroyNotify)g_date_time_unref);
}

static void
purple_idle_manager_class_init(PurpleIdleManagerClass *klass) {
	GObjectClass *obj_class = G_OBJECT_CLASS(klass);

	obj_class->finalize = purple_idle_manager_finalize;
	obj_class->get_property = purple_idle_manager_get_property;

	/**
	 * PurpleIdleManager::timestamp:
	 *
	 * The aggregate of the oldest idle timestamp of all of the sources that
	 * are known.
	 *
	 * Since: 3.0.0
	 */
	properties[PROP_TIMESTAMP] = g_param_spec_boxed(
		"timestamp", "timestamp",
		"The aggregate of the oldest timestamp of all sources.",
		G_TYPE_DATE_TIME,
		G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);

	g_object_class_install_properties(obj_class, N_PROPERTIES, properties);
}

/******************************************************************************
 * Private API
 *****************************************************************************/
static PurpleIdleManager *default_manager = NULL;

void
purple_idle_manager_startup(void) {
	if(!PURPLE_IS_IDLE_MANAGER(default_manager)) {
		default_manager = g_object_new(PURPLE_TYPE_IDLE_MANAGER, NULL);
		g_object_add_weak_pointer(G_OBJECT(default_manager),
		                          (gpointer *)&default_manager);
	}
}

void
purple_idle_manager_shutdown(void) {
	g_clear_object(&default_manager);
}

/******************************************************************************
 * Public API
 *****************************************************************************/
PurpleIdleManager *
purple_idle_manager_get_default(void) {
	return default_manager;
}

gboolean
purple_idle_manager_set_source(PurpleIdleManager *manager,
                               const char *source,
                               GDateTime *timestamp)
{
	GHashTableIter iter;
	GDateTime *oldest = NULL;
	const char *new_source = NULL;
	gpointer key;
	gpointer value;

	g_return_val_if_fail(PURPLE_IS_IDLE_MANAGER(manager), FALSE);
	g_return_val_if_fail(!purple_strempty(source), FALSE);

	/* We're adding/updating a source. */
	if(timestamp != NULL) {
		g_hash_table_insert(manager->sources, g_strdup(source),
		                    g_date_time_ref(timestamp));
	} else {
		g_hash_table_remove(manager->sources, source);
	}

	g_hash_table_iter_init(&iter, manager->sources);
	while(g_hash_table_iter_next(&iter, &key, &value)) {
		/* If we don't have an oldest yet, use this value. */
		if(oldest == NULL || g_date_time_compare(value, oldest) < 0) {
			oldest = value;
			new_source = key;
		}
	}

	/* Finally check if new_source matches old source. */
	if(!purple_strequal(new_source, manager->active_source)) {
		/* We have to set the active source before emitting the property change
		 * otherwise purple_idle_manager_get_timestamp will look up the wrong
		 * value.
		 */
		g_free(manager->active_source);
		manager->active_source = g_strdup(new_source);

		g_object_notify_by_pspec(G_OBJECT(manager),
		                         properties[PROP_TIMESTAMP]);

		return TRUE;
	}

	return FALSE;
}

GDateTime *
purple_idle_manager_get_timestamp(PurpleIdleManager *manager) {
	g_return_val_if_fail(PURPLE_IS_IDLE_MANAGER(manager), NULL);

	if(manager->active_source == NULL) {
		return NULL;
	}

	return g_hash_table_lookup(manager->sources, manager->active_source);
}

mercurial