pidgin/pidginpluginsdialog.c

Sun, 07 Jun 2020 02:39:43 -0500

author
Gary Kramlich <grim@reaperworld.com>
date
Sun, 07 Jun 2020 02:39:43 -0500
branch
Ball--Gy-rgy/update-screenshot-url-in-appdata-file-1591293245974
changeset 40438
708c6622acc6
parent 40225
b6f1592a07ec
child 40496
6941fece679b
permissions
-rw-r--r--

closing merged branch

/*
 * 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 "pidginpluginsdialog.h"

#include <glib/gi18n.h>

#include <gplugin.h>
#include <gplugin-gtk.h>

#include <purple.h>

#include "gtkpluginpref.h"

struct _PidginPluginsDialog {
	GtkDialog parent;

	GtkWidget *tree_view;
	GtkWidget *configure_plugin_button;
	GtkWidget *close_button;
	GtkWidget *plugin_info;

	GtkListStore *plugin_store;
};

/* this has a short life left to it... */
typedef struct
{
	enum
	{
		PIDGIN_PLUGIN_UI_DATA_TYPE_FRAME,
		PIDGIN_PLUGIN_UI_DATA_TYPE_REQUEST
	} type;

	union
	{
		struct
		{
			GtkWidget *dialog;
			PurplePluginPrefFrame *pref_frame;
		} frame;

		gpointer request_handle;
	} u;
} PidginPluginUiData;

/******************************************************************************
 * Helpers
 *****************************************************************************/
static gboolean
pidgin_plugins_dialog_plugin_has_config(GPluginPlugin *plugin) {
	GPluginPluginInfo *ginfo = gplugin_plugin_get_info(plugin);
	PurplePluginInfo *info = PURPLE_PLUGIN_INFO(ginfo);
	GPluginPluginState state;

	g_return_val_if_fail(GPLUGIN_IS_PLUGIN(plugin), FALSE);

	state = gplugin_plugin_get_state(plugin);

	if (state != GPLUGIN_PLUGIN_STATE_LOADED) {
		return FALSE;
	}

	return (purple_plugin_info_get_pref_frame_cb(info) ||
	       purple_plugin_info_get_pref_request_cb(info));
}

static GPluginPlugin *
pidgin_plugins_dialog_get_selected(PidginPluginsDialog *dialog) {
	GPluginPlugin *plugin = NULL;
	GtkTreeSelection *selection = NULL;
	GtkTreeModel *model = NULL;
	GtkTreeIter iter;

	g_return_val_if_fail(PIDGIN_IS_PLUGINS_DIALOG(dialog), NULL);

	selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dialog->tree_view));
	/* not sure if this is necessary, but playing defense. - grim 20191112 */
	if(selection == NULL) {
		return NULL;
	}

	if(gtk_tree_selection_get_selected(selection, &model, &iter)) {
		gtk_tree_model_get(model, &iter,
		                   GPLUGIN_GTK_STORE_PLUGIN_COLUMN, &plugin,
		                   -1);
	}

	return plugin;
}

static void
pidgin_plugins_dialog_pref_dialog_close(GPluginPlugin *plugin) {
	GPluginPluginInfo *ginfo = gplugin_plugin_get_info(plugin);
	PurplePluginInfo *info = PURPLE_PLUGIN_INFO(ginfo);
	PidginPluginUiData *ui_data;

	ui_data = purple_plugin_info_get_ui_data(info);
	if (ui_data == NULL) {
		purple_debug_info("PidginPluginsDialog", "failed to find uidata\n");
		return;
	}

	if (ui_data->type == PIDGIN_PLUGIN_UI_DATA_TYPE_REQUEST) {
		purple_request_close(PURPLE_REQUEST_FIELDS,
			ui_data->u.request_handle);
		return;
	}

	g_return_if_fail(ui_data->type == PIDGIN_PLUGIN_UI_DATA_TYPE_FRAME);

	gtk_widget_destroy(ui_data->u.frame.dialog);

	if (ui_data->u.frame.pref_frame) {
		purple_plugin_pref_frame_destroy(ui_data->u.frame.pref_frame);
	}

	g_free(ui_data);
	purple_plugin_info_set_ui_data(info, NULL);
}

/******************************************************************************
 * Callbacks
 *****************************************************************************/
static void
pidgin_plugins_dialog_close(GtkWidget *b, gpointer data) {
	gtk_widget_destroy(GTK_WIDGET(data));
}

static void
pidgin_plugins_dialog_selection_cb(GtkTreeSelection *sel, gpointer data) {
	PidginPluginsDialog *dialog = PIDGIN_PLUGINS_DIALOG(data);
	GPluginPlugin *plugin = NULL;
	GtkTreeModel *model = NULL;
	GtkTreeIter iter;

	if(gtk_tree_selection_get_selected(sel, &model, &iter)) {
		gtk_tree_model_get(model, &iter,
		                   GPLUGIN_GTK_STORE_PLUGIN_COLUMN, &plugin,
		                   -1);
	}

	gplugin_gtk_plugin_info_set_plugin(
		GPLUGIN_GTK_PLUGIN_INFO(dialog->plugin_info),
		plugin
	);

	gtk_widget_set_sensitive(
		GTK_WIDGET(dialog->configure_plugin_button),
		pidgin_plugins_dialog_plugin_has_config(plugin)
	);

	g_object_unref(G_OBJECT(plugin));
}

static void
pidgin_plugins_dialog_pref_dialog_response_cb(GtkWidget *dialog, int response,
                                              gpointer data)
{
	if (response == GTK_RESPONSE_CLOSE ||
		response == GTK_RESPONSE_DELETE_EVENT)
	{
		pidgin_plugins_dialog_pref_dialog_close(GPLUGIN_PLUGIN(data));
	}
}

static void
pidgin_plugins_dialog_config_plugin_cb(GtkWidget *button, gpointer data) {
	PidginPluginsDialog *dialog = PIDGIN_PLUGINS_DIALOG(data);
	PidginPluginUiData *ui_data;
	PurplePluginInfo *info;
	PurplePluginPrefFrameCb pref_frame_cb;
	PurplePluginPrefRequestCb pref_request_cb;
	GPluginPlugin *plugin = NULL;
	GPluginPluginInfo *ginfo = NULL;
	gint prefs_count;

	plugin = pidgin_plugins_dialog_get_selected(dialog);
	if(!GPLUGIN_IS_PLUGIN(plugin)) {
		return;
	}

	ginfo = gplugin_plugin_get_info(plugin);
	info = PURPLE_PLUGIN_INFO(ginfo);

	if(purple_plugin_info_get_ui_data(info)) {
		g_object_unref(G_OBJECT(plugin));
		return;
	}

	pref_frame_cb = purple_plugin_info_get_pref_frame_cb(info);
	pref_request_cb = purple_plugin_info_get_pref_request_cb(info);

	ui_data = g_new0(PidginPluginUiData, 1);
	purple_plugin_info_set_ui_data(info, ui_data);

	prefs_count = 0;
	if (pref_frame_cb) {
		prefs_count++;

		ui_data->u.frame.pref_frame = pref_frame_cb(plugin);
	}

	if (pref_request_cb) {
		prefs_count++;
	}

	if (prefs_count > 1) {
		purple_debug_warning("gtkplugin",
		                     "Plugin %s contains more than one prefs "
		                     "callback, some will be ignored.",
		                     gplugin_plugin_info_get_name(ginfo));
	}
	g_return_if_fail(prefs_count > 0);


	/* Priority: pidgin frame > purple request > purple frame
	 * Purple frame could be replaced with purple request some day.
	 */
	if (pref_request_cb) {
		ui_data->type = PIDGIN_PLUGIN_UI_DATA_TYPE_REQUEST;
		ui_data->u.request_handle = pref_request_cb(plugin);
		purple_request_add_close_notify(ui_data->u.request_handle,
			purple_callback_set_zero, &info->ui_data);
		purple_request_add_close_notify(ui_data->u.request_handle,
			g_free, ui_data);
	} else {
		GtkWidget *box, *pdialog, *content, *sw;

		ui_data->type = PIDGIN_PLUGIN_UI_DATA_TYPE_FRAME;

		box = pidgin_plugin_pref_create_frame(ui_data->u.frame.pref_frame);
		if (box == NULL) {
			purple_debug_error("gtkplugin",
				"Failed to display prefs frame");
			g_free(ui_data);
			purple_plugin_info_set_ui_data(info, NULL);
			g_object_unref(G_OBJECT(plugin));
			return;
		}
		gtk_widget_set_vexpand(box, TRUE);

		ui_data->u.frame.dialog = pdialog = gtk_dialog_new_with_buttons(
			PIDGIN_ALERT_TITLE, GTK_WINDOW(dialog),
			GTK_DIALOG_DESTROY_WITH_PARENT,
			_("Close"), GTK_RESPONSE_CLOSE,
			NULL);

		g_signal_connect(G_OBJECT(pdialog), "response",
			G_CALLBACK(pidgin_plugins_dialog_pref_dialog_response_cb), plugin);

		content = gtk_dialog_get_content_area(GTK_DIALOG(pdialog));

		sw = gtk_scrolled_window_new(NULL, NULL);
		gtk_container_add(GTK_CONTAINER(content), sw);
		gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
		                               GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
		gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw),
		                                    GTK_SHADOW_IN);
		gtk_widget_set_size_request(sw, 400, 400);

		gtk_container_add(GTK_CONTAINER(sw), box);

		gtk_window_set_role(GTK_WINDOW(pdialog), "plugin_config");
		gtk_window_set_title(GTK_WINDOW(pdialog),
		                     _(gplugin_plugin_info_get_name(
		                             GPLUGIN_PLUGIN_INFO(info))));
		gtk_widget_show_all(pdialog);
	}
	g_object_unref(G_OBJECT(plugin));
}

/******************************************************************************
 * GObject Implementation
 *****************************************************************************/
G_DEFINE_TYPE(PidginPluginsDialog, pidgin_plugins_dialog, GTK_TYPE_DIALOG);

static void
pidgin_plugins_dialog_class_init(PidginPluginsDialogClass *klass) {
	GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass);

	gtk_widget_class_set_template_from_resource(
		widget_class,
		"/im/pidgin/Pidgin/Plugins/dialog.ui"
	);

	gtk_widget_class_bind_template_child(widget_class, PidginPluginsDialog, tree_view);
	gtk_widget_class_bind_template_child(widget_class, PidginPluginsDialog, configure_plugin_button);
	gtk_widget_class_bind_template_child(widget_class, PidginPluginsDialog, close_button);
	gtk_widget_class_bind_template_child(widget_class, PidginPluginsDialog, plugin_info);
	gtk_widget_class_bind_template_child(widget_class, PidginPluginsDialog, plugin_store);

	gtk_widget_class_bind_template_callback(widget_class, pidgin_plugins_dialog_selection_cb);
	gtk_widget_class_bind_template_callback(widget_class, pidgin_plugins_dialog_config_plugin_cb);
}

static void
pidgin_plugins_dialog_init(PidginPluginsDialog *dialog) {
	gtk_widget_init_template(GTK_WIDGET(dialog));

	/* wire up the close button */
	g_signal_connect(
		dialog->close_button,
		"clicked",
		G_CALLBACK(pidgin_plugins_dialog_close),
		dialog
	);

	/* set the sort column for the plugin_store */
	gtk_tree_sortable_set_sort_column_id(
		GTK_TREE_SORTABLE(dialog->plugin_store),
		GPLUGIN_GTK_STORE_MARKUP_COLUMN,
		GTK_SORT_ASCENDING
	);
}

GtkWidget *
pidgin_plugins_dialog_new(void) {
	return g_object_new(
		PIDGIN_TYPE_PLUGINS_DIALOG,
		"title", _("Plugins"),
		NULL
	);
}

mercurial