pidgin/gtksavedstatuses.c

Mon, 23 May 2022 22:05:35 -0500

author
Gary Kramlich <grim@reaperworld.com>
date
Mon, 23 May 2022 22:05:35 -0500
branch
gtk4
changeset 41547
a6a75a9d8a09
parent 41416
253e831b0a1e
child 41947
7b3312d0760c
permissions
-rw-r--r--

Update the GTK request implementation for GTK4

I had to `#if 0` a fair amount of code as it needs rewriting and there's no point in doing that now when we can't test the rewrite.

Testing Done:
Compiled

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

/* pidgin
 *
 * Pidgin 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 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  02111-1301  USA
 */

#include <glib/gi18n-lib.h>

#include <gtk/gtk.h>

#include <purple.h>

#include "gtksavedstatuses.h"
#include "pidginiconname.h"

enum {
	SS_MENU_ENTRY_TYPE_PRIMITIVE,
	SS_MENU_ENTRY_TYPE_SAVEDSTATUS
};

enum {
	/* _SSMenuEntryType */
	SS_MENU_TYPE_COLUMN,

	/*
	 * This is a GdkPixbuf (the other columns are strings).
	 * This column is visible.
	 */
	SS_MENU_ICON_COLUMN,

	/* The text displayed on the status box.  This column is visible. */
	SS_MENU_TEXT_COLUMN,

	/*
	 * This value depends on SS_MENU_TYPE_COLUMN.  For _SAVEDSTATUS types,
	 * this is the creation time.  For _PRIMITIVE types,
	 * this is the PurpleStatusPrimitive.
	 */
	SS_MENU_DATA_COLUMN,

	/*
	 * This is the emblem to use for this status
	 */
	SS_MENU_EMBLEM_COLUMN,

	/*
	 * And whether or not that emblem is visible
	 */
	SS_MENU_EMBLEM_VISIBLE_COLUMN,

	SS_MENU_NUM_COLUMNS
};

static void
status_menu_cb(GtkComboBox *widget, void(*callback)(PurpleSavedStatus*))
{
	GtkTreeIter iter;
	int type;
	gpointer data;
	PurpleSavedStatus *status = NULL;

	if (!gtk_combo_box_get_active_iter(widget, &iter))
		return;

	gtk_tree_model_get(gtk_combo_box_get_model(widget), &iter,
			   SS_MENU_TYPE_COLUMN, &type,
			   SS_MENU_DATA_COLUMN, &data,
			   -1);

	if (type == SS_MENU_ENTRY_TYPE_PRIMITIVE)
	{
		PurpleStatusPrimitive primitive = GPOINTER_TO_INT(data);
		status = purple_savedstatus_find_transient_by_type_and_message(primitive, NULL);
		if (status == NULL)
			status = purple_savedstatus_new(NULL, primitive);
	}
	else if (type == SS_MENU_ENTRY_TYPE_SAVEDSTATUS)
		status = purple_savedstatus_find_by_creation_time(GPOINTER_TO_INT(data));

	callback(status);
}

static gint
saved_status_sort_alphabetically_func(gconstpointer a, gconstpointer b)
{
	const PurpleSavedStatus *saved_status_a = a;
	const PurpleSavedStatus *saved_status_b = b;
	return g_utf8_collate(purple_savedstatus_get_title(saved_status_a),
				  purple_savedstatus_get_title(saved_status_b));
}

static gboolean pidgin_status_menu_add_primitive(GtkListStore *model, GtkWidget *w, PurpleStatusPrimitive primitive,
	PurpleSavedStatus *current_status)
{
	GtkTreeIter iter;
	gboolean currently_selected = FALSE;

	gtk_list_store_append(model, &iter);
	gtk_list_store_set(model, &iter,
			   SS_MENU_TYPE_COLUMN, SS_MENU_ENTRY_TYPE_PRIMITIVE,
			   SS_MENU_ICON_COLUMN, pidgin_icon_name_from_status_primitive(primitive, NULL),
			   SS_MENU_TEXT_COLUMN, purple_primitive_get_name_from_type(primitive),
			   SS_MENU_DATA_COLUMN, GINT_TO_POINTER(primitive),
			   SS_MENU_EMBLEM_VISIBLE_COLUMN, FALSE,
			   -1);

	if (purple_savedstatus_is_transient(current_status)
			&& !purple_savedstatus_has_substatuses(current_status)
			&& purple_savedstatus_get_primitive_type(current_status) == primitive)
		currently_selected = TRUE;

	return currently_selected;
}

static void
pidgin_status_menu_update_iter(GtkWidget *combobox, GtkListStore *store, GtkTreeIter *iter,
		PurpleSavedStatus *status)
{
	PurpleStatusPrimitive primitive;

	if (store == NULL)
		store = GTK_LIST_STORE(gtk_combo_box_get_model(GTK_COMBO_BOX(combobox)));

	primitive = purple_savedstatus_get_primitive_type(status);
	gtk_list_store_set(store, iter,
			SS_MENU_TYPE_COLUMN, SS_MENU_ENTRY_TYPE_SAVEDSTATUS,
			SS_MENU_ICON_COLUMN, pidgin_icon_name_from_status_primitive(primitive, NULL),
			SS_MENU_TEXT_COLUMN, purple_savedstatus_get_title(status),
			SS_MENU_DATA_COLUMN, GINT_TO_POINTER(purple_savedstatus_get_creation_time(status)),
			SS_MENU_EMBLEM_COLUMN, "document-save",
			SS_MENU_EMBLEM_VISIBLE_COLUMN, TRUE,
			-1);
}

static gboolean
pidgin_status_menu_find_iter(GtkListStore *store, GtkTreeIter *iter, PurpleSavedStatus *find)
{
	int type;
	gpointer data;
	time_t creation_time = purple_savedstatus_get_creation_time(find);
	GtkTreeModel *model = GTK_TREE_MODEL(store);

	if (!gtk_tree_model_get_iter_first(model, iter))
		return FALSE;

	do {
		gtk_tree_model_get(model, iter,
				SS_MENU_TYPE_COLUMN, &type,
				SS_MENU_DATA_COLUMN, &data,
				-1);
		if (type == SS_MENU_ENTRY_TYPE_PRIMITIVE)
			continue;
		if (GPOINTER_TO_INT(data) == creation_time)
			return TRUE;
	} while (gtk_tree_model_iter_next(model, iter));

	return FALSE;
}

static void
savedstatus_added_cb(PurpleSavedStatus *status, GtkWidget *combobox)
{
	GtkListStore *store;
	GtkTreeIter iter;

	if (purple_savedstatus_is_transient(status))
		return;

	store = GTK_LIST_STORE(gtk_combo_box_get_model(GTK_COMBO_BOX(combobox)));
	gtk_list_store_append(store, &iter);
	pidgin_status_menu_update_iter(combobox, store, &iter, status);
}

static void
savedstatus_deleted_cb(PurpleSavedStatus *status, GtkWidget *combobox)
{
	GtkListStore *store;
	GtkTreeIter iter;

	if (purple_savedstatus_is_transient(status))
		return;

	store = GTK_LIST_STORE(gtk_combo_box_get_model(GTK_COMBO_BOX(combobox)));
	if (pidgin_status_menu_find_iter(store, &iter, status))
		gtk_list_store_remove(store, &iter);
}

static void
savedstatus_modified_cb(PurpleSavedStatus *status, GtkWidget *combobox)
{
	GtkListStore *store;
	GtkTreeIter iter;

	if (purple_savedstatus_is_transient(status))
		return;

	store = GTK_LIST_STORE(gtk_combo_box_get_model(GTK_COMBO_BOX(combobox)));
	if (pidgin_status_menu_find_iter(store, &iter, status))
		pidgin_status_menu_update_iter(combobox, store, &iter, status);
}

GtkWidget *pidgin_status_menu(PurpleSavedStatus *current_status, GCallback callback)
{
	GtkWidget *combobox;
	GtkListStore *model;
	GList *sorted, *cur;
	int i = 0;
	int index = -1;
	GtkTreeIter iter;
	GtkCellRenderer *text_rend;
	GtkCellRenderer *icon_rend;
	GtkCellRenderer *emblem_rend;

	model = gtk_list_store_new(SS_MENU_NUM_COLUMNS, G_TYPE_INT, G_TYPE_STRING,
				   G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_STRING, G_TYPE_BOOLEAN);

	combobox = gtk_combo_box_new();

	if (pidgin_status_menu_add_primitive(model, combobox, PURPLE_STATUS_AVAILABLE, current_status))
		index = i;
	i++;

	if (pidgin_status_menu_add_primitive(model, combobox, PURPLE_STATUS_AWAY, current_status))
		index = i;
	i++;

	if (pidgin_status_menu_add_primitive(model, combobox, PURPLE_STATUS_INVISIBLE, current_status))
		index = i;
	i++;

	if (pidgin_status_menu_add_primitive(model, combobox, PURPLE_STATUS_OFFLINE, current_status))
		index = i;
	i++;

	sorted = g_list_copy((GList *)purple_savedstatuses_get_all());
	sorted = g_list_sort(sorted, saved_status_sort_alphabetically_func);
	for (cur = sorted; cur; cur = cur->next)
	{
		PurpleSavedStatus *status = (PurpleSavedStatus *) cur->data;
		if (!purple_savedstatus_is_transient(status))
		{
			gtk_list_store_append(model, &iter);

			pidgin_status_menu_update_iter(combobox, model, &iter, status);

			if (status == current_status)
				index = i;
			i++;
		}
	}
	g_list_free(sorted);

	gtk_combo_box_set_model(GTK_COMBO_BOX(combobox), GTK_TREE_MODEL(model));

	text_rend = gtk_cell_renderer_text_new();
	icon_rend = gtk_cell_renderer_pixbuf_new();
	emblem_rend = gtk_cell_renderer_pixbuf_new();
	gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combobox), icon_rend, FALSE);
	gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combobox), text_rend, TRUE);
	gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combobox), emblem_rend, FALSE);
	gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(combobox), icon_rend, "icon-name", SS_MENU_ICON_COLUMN, NULL);
	gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(combobox), text_rend, "markup", SS_MENU_TEXT_COLUMN, NULL);
	gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(combobox), emblem_rend,
					"icon-name", SS_MENU_EMBLEM_COLUMN, "visible", SS_MENU_EMBLEM_VISIBLE_COLUMN, NULL);
	g_object_set(text_rend, "ellipsize", PANGO_ELLIPSIZE_END, NULL);

	gtk_combo_box_set_active(GTK_COMBO_BOX(combobox), index);
	g_signal_connect(G_OBJECT(combobox), "changed", G_CALLBACK(status_menu_cb), callback);

	/* Make sure the list is updated dynamically when a substatus is changed/deleted
	 * or a new one is added. */
	purple_signal_connect(purple_savedstatuses_get_handle(), "savedstatus-added",
			combobox, G_CALLBACK(savedstatus_added_cb), combobox);
	purple_signal_connect(purple_savedstatuses_get_handle(), "savedstatus-deleted",
			combobox, G_CALLBACK(savedstatus_deleted_cb), combobox);
	purple_signal_connect(purple_savedstatuses_get_handle(), "savedstatus-modified",
			combobox, G_CALLBACK(savedstatus_modified_cb), combobox);
	g_signal_connect(G_OBJECT(combobox), "destroy",
			G_CALLBACK(purple_signals_disconnect_by_handle), NULL);

	return combobox;
}

mercurial