Merged in default (pull request #643)
Move the plugins dialog to glade using the gplugin-gtk widgets
Approved-by: Elliott Sales de Andrade
--- a/doc/reference/pidgin/pidgin-docs.xml Thu Nov 21 21:41:21 2019 -0600
+++ b/doc/reference/pidgin/pidgin-docs.xml Fri Nov 22 04:10:26 2019 +0000
@@ -35,7 +35,6 @@
<xi:include href="xml/gtkmedia.xml" />
<xi:include href="xml/gtknickcolors.xml" />
<xi:include href="xml/gtknotify.xml" />
- <xi:include href="xml/gtkplugin.xml" />
<xi:include href="xml/gtkpluginpref.xml" />
<xi:include href="xml/gtkpounce.xml" />
<xi:include href="xml/gtkprefs.xml" />
@@ -61,6 +60,8 @@
<xi:include href="xml/pidginlog.xml" />
<xi:include href="xml/pidginmenutray.xml" />
<xi:include href="xml/pidginmessage.xml" />
+ <xi:include href="xml/pidginplugininfo.xml" /> + <xi:include href="xml/pidginpluginsdialog.xml" /> <xi:include href="xml/pidginstock.xml" />
<xi:include href="xml/pidgintalkatu.xml" />
<xi:include href="xml/pidgintooltip.xml" />
--- a/meson.build Thu Nov 21 21:41:21 2019 -0600
+++ b/meson.build Fri Nov 22 04:10:26 2019 +0000
@@ -617,9 +617,9 @@
#######################################################################
-# Check for GPlugin 0.28.0
#######################################################################
-gplugin_dep = dependency('gplugin', version : '>= 0.28.0', required : false)
+gplugin_dep = dependency('gplugin', version : '>= 0.29.0', required : false) gplugin_gir = 'GPlugin-0.0'
@@ -629,19 +629,43 @@
gplugin_include_directories = []
+ gplugin_gtk_dep = dependency('gplugin-gtk', required : true) + if enable_introspection + gplugin_gtk_gir = 'GPluginGtk-0.0' + gplugin_gtk_include_directories = include_directories( + join_paths(gplugin_gtk_dep.get_pkgconfig_variable('prefix'), + gplugin_gtk_include_directories = [] gplugin_proj = subproject('gplugin',
'doc=' + get_option('doc').to_string(),
'gobject-introspection=' + enable_introspection.to_string(),
'nls=' + get_option('nls').to_string(),
+ 'gtk3=' + get_option('gtkui').to_string(), gplugin_dep = gplugin_proj.get_variable('gplugin_dep')
gplugin_gir = gplugin_proj.get_variable('gplugin_gir')[0]
gplugin_include_directories = []
+ gplugin_gtk_dep = gplugin_proj.get_variable('gplugin_gtk_dep') + if enable_introspection + gplugin_gtk_gir = gplugin_proj.get_variable('gplugin_gtk_gir')[0] + gplugin_gtk_include_directories = [] PLUGINS = get_option('plugins')
--- a/pidgin/gtkblist.c Thu Nov 21 21:41:21 2019 -0600
+++ b/pidgin/gtkblist.c Fri Nov 22 04:10:26 2019 +0000
@@ -45,7 +45,6 @@
@@ -63,6 +62,8 @@
#include "pidgin/pidgindebugplugininfo.h"
#include "pidgin/pidgingdkpixbuf.h"
#include "pidgin/pidginlog.h"
+#include "pidgin/pidginplugininfo.h" +#include "pidgin/pidginpluginsdialog.h" #include "pidgin/pidgintooltip.h"
#include "pidginmenutray.h"
@@ -3617,6 +3618,15 @@
***************************************************/
+pidgin_blist_plugins_dialog_cb(GtkAction *action, GtkWidget *window) { + GtkWidget *dialog = pidgin_plugins_dialog_new(); + gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(window)); + gtk_widget_show_all(dialog); _pidgin_about_cb(GtkAction *action, GtkWidget *window) {
GtkWidget *about = pidgin_about_dialog_new();
@@ -3650,7 +3660,7 @@
{ "ToolsMenu", NULL, N_("_Tools"), NULL, NULL, NULL },
{ "BuddyPounces", NULL, N_("Buddy _Pounces"), NULL, NULL, pidgin_pounces_manager_show },
{ "CustomSmileys", PIDGIN_STOCK_TOOLBAR_SMILEY, N_("Custom Smile_ys"), "<control>Y", NULL, pidgin_smiley_manager_show },
- { "Plugins", PIDGIN_STOCK_TOOLBAR_PLUGINS, N_("Plu_gins"), "<control>U", NULL, pidgin_plugin_dialog_show },
+ { "Plugins", PIDGIN_STOCK_TOOLBAR_PLUGINS, N_("Plu_gins"), "<control>U", NULL, pidgin_blist_plugins_dialog_cb }, { "Preferences", GTK_STOCK_PREFERENCES, N_("Pr_eferences"), "<control>P", NULL, pidgin_prefs_show },
{ "Privacy", NULL, N_("Pr_ivacy"), NULL, NULL, pidgin_privacy_dialog_show },
{ "SetMood", NULL, N_("Set _Mood"), "<control>D", NULL, set_mood_show },
--- a/pidgin/gtkplugin.c Thu Nov 21 21:41:21 2019 -0600
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,1074 +0,0 @@
- * 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
- * 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 "gtkpluginpref.h"
-#include "pidgintooltip.h"
-#define PIDGIN_RESPONSE_CONFIGURE 98121
- PidginPluginConfigFrameCb config_frame_cb;
-} PidginPluginInfoPrivate;
- PROP_GTK_CONFIG_FRAME_CB,
- PIDGIN_PLUGIN_UI_DATA_TYPE_FRAME,
- PIDGIN_PLUGIN_UI_DATA_TYPE_REQUEST
- PurplePluginPrefFrame *pref_frame;
- gpointer request_handle;
-G_DEFINE_TYPE_WITH_PRIVATE(PidginPluginInfo, pidgin_plugin_info,
- PURPLE_TYPE_PLUGIN_INFO);
-static void plugin_toggled_stage_two(PurplePlugin *plug, GtkTreeModel *model,
- GtkTreeIter *iter, GError *error, gboolean unload);
-static GtkWidget *expander = NULL;
-static GtkWidget *plugin_dialog = NULL;
-static GtkLabel *plugin_name = NULL;
-static GtkTextBuffer *plugin_desc = NULL;
-static GtkLabel *plugin_error = NULL;
-static GtkLabel *plugin_authors = NULL;
-static GtkLabel *plugin_website = NULL;
-static gchar *plugin_website_uri = NULL;
-static GtkLabel *plugin_filename = NULL;
-static GtkWidget *pref_button = NULL;
-/* Set method for GObject properties */
-pidgin_plugin_info_set_property(GObject *obj, guint param_id, const GValue *value,
- PidginPluginInfoPrivate *priv =
- pidgin_plugin_info_get_instance_private(
- PIDGIN_PLUGIN_INFO(obj));
- case PROP_GTK_CONFIG_FRAME_CB:
- priv->config_frame_cb = g_value_get_pointer(value);
- G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
-/* Get method for GObject properties */
-pidgin_plugin_info_get_property(GObject *obj, guint param_id, GValue *value,
- PidginPluginInfoPrivate *priv =
- pidgin_plugin_info_get_instance_private(
- PIDGIN_PLUGIN_INFO(obj));
- case PROP_GTK_CONFIG_FRAME_CB:
- g_value_set_pointer(value, priv->config_frame_cb);
- G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
-/* Class initializer function */
-static void pidgin_plugin_info_class_init(PidginPluginInfoClass *klass)
- GObjectClass *obj_class = G_OBJECT_CLASS(klass);
- obj_class->get_property = pidgin_plugin_info_get_property;
- obj_class->set_property = pidgin_plugin_info_set_property;
- g_object_class_install_property(obj_class, PROP_GTK_CONFIG_FRAME_CB,
- g_param_spec_pointer("gtk-config-frame-cb",
- "GTK configuration frame callback",
- "Callback that returns a GTK configuration frame",
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_STATIC_STRINGS));
-pidgin_plugin_info_init(PidginPluginInfo *info)
-pidgin_plugin_info_new(const char *first_property, ...)
- /* at least ID is required */
- va_start(var_args, first_property);
- info = g_object_new_valist(PIDGIN_TYPE_PLUGIN_INFO, first_property,
- g_object_set(info, "ui-requirement", PIDGIN_UI, NULL);
- return PIDGIN_PLUGIN_INFO(info);
-pidgin_plugin_has_prefs(PurplePlugin *plugin)
- PurplePluginInfo *info = purple_plugin_get_info(plugin);
- PidginPluginInfoPrivate *priv = NULL;
- g_return_val_if_fail(plugin != NULL, FALSE);
- if (!purple_plugin_is_loaded(plugin))
- if (PIDGIN_IS_PLUGIN_INFO(info))
- priv = pidgin_plugin_info_get_instance_private(
- PIDGIN_PLUGIN_INFO(info));
- ret = ((priv && priv->config_frame_cb) ||
- purple_plugin_info_get_pref_frame_cb(info) ||
- purple_plugin_info_get_pref_request_cb(info));
-pidgin_plugin_get_config_frame(PurplePlugin *plugin,
- PurplePluginPrefFrame **purple_pref_frame)
- GtkWidget *config = NULL;
- PurplePluginInfo *info;
- PurplePluginPrefFrameCb pref_frame_cb = NULL;
- g_return_val_if_fail(PURPLE_IS_PLUGIN(plugin), NULL);
- info = purple_plugin_get_info(plugin);
- if(!PURPLE_IS_PLUGIN_INFO(info))
- pref_frame_cb = purple_plugin_info_get_pref_frame_cb(info);
- PurplePluginPrefFrame *frame = pref_frame_cb(plugin);
- config = pidgin_plugin_pref_create_frame(frame);
- *purple_pref_frame = frame;
-pref_dialog_close(PurplePlugin *plugin)
- PurplePluginInfo *info;
- PidginPluginUiData *ui_data;
- g_return_if_fail(plugin != NULL);
- info = purple_plugin_get_info(plugin);
- ui_data = purple_plugin_info_get_ui_data(info);
- if (ui_data->type == PIDGIN_PLUGIN_UI_DATA_TYPE_REQUEST) {
- purple_request_close(PURPLE_REQUEST_FIELDS,
- ui_data->u.request_handle);
- 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);
- purple_plugin_info_set_ui_data(info, NULL);
-pref_dialog_response_cb(GtkWidget *dialog, int response, PurplePlugin *plugin)
- if (response == GTK_RESPONSE_CLOSE ||
- response == GTK_RESPONSE_DELETE_EVENT)
- pref_dialog_close(plugin);
-pidgin_plugin_open_config(PurplePlugin *plugin, GtkWindow *parent)
- PurplePluginInfo *info;
- PidginPluginInfoPrivate *priv = NULL;
- PidginPluginUiData *ui_data;
- PurplePluginPrefFrameCb pref_frame_cb;
- PurplePluginPrefRequestCb pref_request_cb;
- PidginPluginConfigFrameCb get_pidgin_frame = NULL;
- g_return_if_fail(plugin != NULL);
- info = purple_plugin_get_info(plugin);
- if (!pidgin_plugin_has_prefs(plugin)) {
- purple_debug_warning("gtkplugin", "Plugin has no prefs");
- if (purple_plugin_info_get_ui_data(info))
- if (PIDGIN_IS_PLUGIN_INFO(info))
- priv = pidgin_plugin_info_get_instance_private(
- PIDGIN_PLUGIN_INFO(info));
- pref_frame_cb = purple_plugin_info_get_pref_frame_cb(info);
- pref_request_cb = purple_plugin_info_get_pref_request_cb(info);
- get_pidgin_frame = priv->config_frame_cb;
- purple_debug_warning("gtkplugin",
- "Plugin %s contains more than one prefs "
- "callback, some will be ignored.",
- gplugin_plugin_info_get_name(
- GPLUGIN_PLUGIN_INFO(info)));
- g_return_if_fail(prefs_count > 0);
- ui_data = g_new0(PidginPluginUiData, 1);
- purple_plugin_info_set_ui_data(info, ui_data);
- /* Priority: pidgin frame > purple request > purple frame
- * Purple frame could be replaced with purple request some day.
- if (pref_request_cb && !get_pidgin_frame) {
- 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,
- GtkWidget *box, *dialog;
- ui_data->type = PIDGIN_PLUGIN_UI_DATA_TYPE_FRAME;
- box = pidgin_plugin_get_config_frame(plugin,
- &ui_data->u.frame.pref_frame);
- purple_debug_error("gtkplugin",
- "Failed to display prefs frame");
- purple_plugin_info_set_ui_data(info, NULL);
- gtk_widget_set_vexpand(box, TRUE);
- ui_data->u.frame.dialog = dialog = gtk_dialog_new_with_buttons(
- PIDGIN_ALERT_TITLE, parent,
- GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_CLOSE,
- GTK_RESPONSE_CLOSE, NULL);
- g_signal_connect(G_OBJECT(dialog), "response",
- G_CALLBACK(pref_dialog_response_cb), plugin);
- gtk_container_add(GTK_CONTAINER(
- gtk_dialog_get_content_area(GTK_DIALOG(dialog))),
- pidgin_make_scrollable(box, GTK_POLICY_NEVER,
- GTK_POLICY_AUTOMATIC, GTK_SHADOW_IN, 400, 400));
- gtk_window_set_role(GTK_WINDOW(dialog), "plugin_config");
- gtk_window_set_title(GTK_WINDOW(dialog),
- _(gplugin_plugin_info_get_name(
- GPLUGIN_PLUGIN_INFO(info))));
- gtk_widget_show_all(dialog);
-pidgin_plugins_save(void)
- purple_plugins_save_loaded(PIDGIN_PREFS_ROOT "/plugins/loaded");
-update_plugin_list(void *data)
- GtkListStore *ls = GTK_LIST_STORE(data);
- PurplePluginInfo *info;
- GPluginPluginInfo *ginfo;
- gtk_list_store_clear(ls);
- purple_plugins_refresh();
- plugins = purple_plugins_find_all();
- for (l = plugins; l != NULL; l = l->next)
- plug = PURPLE_PLUGIN(l->data);
- info = purple_plugin_get_info(plug);
- ginfo = GPLUGIN_PLUGIN_INFO(info);
- if (purple_plugin_is_internal(plug))
- gtk_list_store_append (ls, &iter);
- if (gplugin_plugin_info_get_name(ginfo)) {
- name = g_markup_escape_text(
- _(gplugin_plugin_info_get_name(ginfo)), -1);
- char *tmp = g_path_get_basename(
- gplugin_plugin_get_filename(plug));
- name = g_markup_escape_text(tmp, -1);
- version = g_markup_escape_text(
- gplugin_plugin_info_get_version(ginfo), -1);
- summary = g_markup_escape_text(
- gplugin_plugin_info_get_summary(ginfo), -1);
- desc = g_strdup_printf("<b>%s</b> %s\n%s", name,
- gtk_list_store_set(ls, &iter,
- 0, purple_plugin_is_loaded(plug),
- 3, purple_plugin_info_get_error(info),
-check_if_loaded(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
- gtk_tree_model_get(model, iter, 2, &plugin, -1);
- gtk_list_store_set(GTK_LIST_STORE(model), iter,
- 0, purple_plugin_is_loaded(plugin),
-update_loaded_plugins(GtkTreeModel *model)
- gtk_tree_model_foreach(model, check_if_loaded, NULL);
-static void plugin_loading_common(PurplePlugin *plugin, GtkTreeView *view, gboolean loaded)
- GtkTreeModel *model = gtk_tree_view_get_model(view);
- if (gtk_tree_model_get_iter_first(model, &iter)) {
- gtk_tree_model_get(model, &iter, 2, &plug, -1);
- gtk_list_store_set(GTK_LIST_STORE(model), &iter, 0, loaded, -1);
- /* If the loaded/unloaded plugin is the selected row,
- * update the pref_button. */
- sel = gtk_tree_view_get_selection(view);
- if (gtk_tree_selection_get_selected(sel, &model, &iter))
- gtk_tree_model_get(model, &iter, 2, &plug, -1);
- gtk_widget_set_sensitive(pref_button,
- pidgin_plugin_has_prefs(plug));
- } while (gtk_tree_model_iter_next(model, &iter));
-static void plugin_load_cb(PurplePlugin *plugin, gpointer data)
- GtkTreeView *view = (GtkTreeView *)data;
- plugin_loading_common(plugin, view, TRUE);
-static void plugin_unload_cb(PurplePlugin *plugin, gpointer data)
- GtkTreeView *view = (GtkTreeView *)data;
- plugin_loading_common(plugin, view, FALSE);
-static void plugin_unload_confirm_cb(gpointer *data)
- PurplePlugin *plugin = (PurplePlugin *)data[0];
- GtkTreeModel *model = (GtkTreeModel *)data[1];
- GtkTreeIter *iter = (GtkTreeIter *)data[2];
- plugin_toggled_stage_two(plugin, model, iter, NULL, TRUE);
-static void plugin_toggled(GtkCellRendererToggle *cell, gchar *pth, gpointer data)
- GtkTreeModel *model = (GtkTreeModel *)data;
- GtkTreeIter *iter = g_new(GtkTreeIter, 1);
- GtkTreePath *path = gtk_tree_path_new_from_string(pth);
- gtk_tree_model_get_iter(model, iter, path);
- gtk_tree_path_free(path);
- gtk_tree_model_get(model, iter, 2, &plug, -1);
- if (!purple_plugin_is_loaded(plug))
- pidgin_set_cursor(plugin_dialog, GDK_WATCH);
- purple_plugin_load(plug, &error);
- plugin_toggled_stage_two(plug, model, iter, error, FALSE);
- pidgin_clear_cursor(plugin_dialog);
- pref_dialog_close(plug);
- if (purple_plugin_get_dependent_plugins(plug) != NULL)
- GString *tmp = g_string_new(_("The following plugins will be unloaded."));
- for (l = purple_plugin_get_dependent_plugins(plug); l != NULL ; l = l->next)
- const char *dep_name = (const char *)l->data;
- PurplePlugin *dep_plugin = purple_plugins_find_plugin(dep_name);
- GPluginPluginInfo *dep_info;
- if (dep_plugin == NULL) {
- purple_debug_error("gtkplugin",
- "The %s plugin could not be found.",
- dep_info = GPLUGIN_PLUGIN_INFO(
- purple_plugin_get_info(dep_plugin));
- g_string_append_printf(
- gplugin_plugin_info_get_name(dep_info));
- cb_data = g_new(gpointer, 3);
- purple_request_action(plugin_dialog, NULL,
- _("Multiple plugins will be unloaded."),
- tmp->str, 0, NULL, cb_data, 2,
- G_CALLBACK(plugin_unload_confirm_cb),
- g_string_free(tmp, TRUE);
- plugin_toggled_stage_two(plug, model, iter, NULL, TRUE);
-static void plugin_toggled_stage_two(PurplePlugin *plug, GtkTreeModel *model, GtkTreeIter *iter, GError *error, gboolean unload)
- GPluginPluginInfo *info =
- GPLUGIN_PLUGIN_INFO(purple_plugin_get_info(plug));
- pidgin_set_cursor(plugin_dialog, GDK_WATCH);
- if (!purple_plugin_unload(plug, &error))
- const char *primary = _("Could not unload plugin");
- const char *reload = _("The plugin could not be unloaded now, but will be disabled at the next startup.");
- char *tmp = g_strdup_printf("%s\n\n%s", reload, error->message);
- purple_notify_warning(NULL, NULL, primary, tmp, NULL);
- purple_plugin_disable(plug);
- pidgin_clear_cursor(plugin_dialog);
- purple_notify_warning(NULL, NULL, _("Could not load plugin"), error->message, NULL);
- gtk_widget_set_sensitive(pref_button, pidgin_plugin_has_prefs(plug));
- gchar *name = g_markup_escape_text(
- gplugin_plugin_info_get_name(info), -1);
- gchar *disp_error = g_markup_escape_text(error->message, -1);
- text = g_strdup_printf("<b>%s</b> %s\n<span weight=\"bold\" "
- "color=\"red\">%s</span>",
- gplugin_plugin_info_get_name(info),
- gplugin_plugin_info_get_version(info),
- gtk_list_store_set(GTK_LIST_STORE (model), iter,
- text = g_strdup_printf(
- "<span weight=\"bold\" color=\"red\">%s</span>",
- gtk_label_set_markup(plugin_error, text);
- if ((unload && purple_plugin_get_dependent_plugins(plug)) ||
- (!unload && gplugin_plugin_info_get_dependencies(info))) {
- update_loaded_plugins(model);
- gtk_list_store_set(GTK_LIST_STORE (model), iter,
- 0, purple_plugin_is_loaded(plug),
-static gboolean ensure_plugin_visible(void *data)
- GtkTreeSelection *sel = GTK_TREE_SELECTION(data);
- GtkTreeView *tv = gtk_tree_selection_get_tree_view(sel);
- GtkTreeModel *model = gtk_tree_view_get_model(tv);
- if (!gtk_tree_selection_get_selected (sel, &model, &iter))
- path = gtk_tree_model_get_path(model, &iter);
- gtk_tree_view_scroll_to_cell(gtk_tree_selection_get_tree_view(sel), path, NULL, FALSE, 0, 0);
- gtk_tree_path_free(path);
-static void prefs_plugin_sel (GtkTreeSelection *sel, GtkTreeModel *model)
- gchar *buf, *tmp, *name, *version;
- const gchar * const *authorlist;
- PurplePluginInfo *info;
- GPluginPluginInfo *ginfo;
- if (!gtk_tree_selection_get_selected (sel, &model, &iter))
- gtk_widget_set_sensitive(pref_button, FALSE);
- /* Collapse and disable the expander widget */
- gtk_expander_set_expanded(GTK_EXPANDER(expander), FALSE);
- gtk_widget_set_sensitive(expander, FALSE);
- gtk_widget_set_sensitive(expander, TRUE);
- gtk_tree_model_get_value (model, &iter, 2, &val);
- plug = g_value_get_pointer(&val);
- info = purple_plugin_get_info(plug);
- ginfo = GPLUGIN_PLUGIN_INFO(info);
- name = g_markup_escape_text(gplugin_plugin_info_get_name(ginfo), -1);
- version = g_markup_escape_text(gplugin_plugin_info_get_version(ginfo),
- "<span size=\"larger\" weight=\"bold\">%s</span> "
- "<span size=\"smaller\">%s</span>",
- gtk_label_set_markup(plugin_name, buf);
- gtk_text_buffer_set_text(
- plugin_desc, gplugin_plugin_info_get_description(ginfo), -1);
- authorlist = gplugin_plugin_info_get_authors(ginfo);
- authors = g_strjoinv(",\n", (gchar **)authorlist);
- gtk_label_set_text(plugin_authors, authors);
- gtk_label_set_text(plugin_filename, gplugin_plugin_get_filename(plug));
- g_free(plugin_website_uri);
- plugin_website_uri = g_strdup(gplugin_plugin_info_get_website(ginfo));
- if (plugin_website_uri)
- tmp = g_markup_escape_text(plugin_website_uri, -1);
- buf = g_strdup_printf("<span underline=\"single\" "
- "foreground=\"blue\">%s</span>", tmp);
- gtk_label_set_markup(plugin_website, buf);
- gtk_label_set_text(plugin_website, NULL);
- if (purple_plugin_info_get_error(info) == NULL)
- gtk_label_set_text(plugin_error, NULL);
- tmp = g_markup_escape_text(purple_plugin_info_get_error(info), -1);
- _("<span foreground=\"red\" weight=\"bold\">"
- "Check the plugin website for an update."
- gtk_label_set_markup(plugin_error, buf);
- gtk_widget_set_sensitive(pref_button, pidgin_plugin_has_prefs(plug));
- /* Make sure the selected plugin is still visible */
- g_idle_add(ensure_plugin_visible, sel);
-static void plugin_dialog_response_cb(GtkWidget *d, int response, GtkTreeSelection *sel)
- g_return_if_fail(d != NULL);
- case GTK_RESPONSE_CLOSE:
- case GTK_RESPONSE_DELETE_EVENT:
- purple_request_close_with_handle(plugin_dialog);
- purple_signals_disconnect_by_handle(plugin_dialog);
- list = purple_plugins_find_all();
- g_list_free_full(list, (GDestroyNotify)pref_dialog_close);
- case PIDGIN_RESPONSE_CONFIGURE:
- if (! gtk_tree_selection_get_selected (sel, &model, &iter))
- gtk_tree_model_get_value(model, &iter, 2, &val);
- plugin = g_value_get_pointer(&val);
- pidgin_plugin_open_config(plugin, GTK_WINDOW(d));
-show_plugin_prefs_cb(GtkTreeView *view, GtkTreePath *path, GtkTreeViewColumn *column, GtkWidget *dialog)
- sel = gtk_tree_view_get_selection(view);
- if (!gtk_tree_selection_get_selected(sel, &model, &iter))
- gtk_tree_model_get(model, &iter, 2, &plugin, -1);
- if (!purple_plugin_is_loaded(plugin))
- /* Now show the pref-dialog for the plugin */
- plugin_dialog_response_cb(dialog, PIDGIN_RESPONSE_CONFIGURE, sel);
-pidgin_plugins_paint_tooltip(GtkWidget *tipwindow, cairo_t *cr, gpointer data)
- PangoLayout *layout = g_object_get_data(G_OBJECT(tipwindow), "tooltip-plugin");
- GtkStyleContext *context = gtk_widget_get_style_context(tipwindow);
- gtk_style_context_add_class(context, GTK_STYLE_CLASS_TOOLTIP);
- gtk_render_layout(context, cr, 6, 6, layout);
-pidgin_plugins_create_tooltip(GtkWidget *tipwindow, GtkTreePath *path,
- gpointer data, int *w, int *h)
- GtkTreeView *treeview = GTK_TREE_VIEW(data);
- PurplePlugin *plugin = NULL;
- GPluginPluginInfo *info;
- GtkTreeModel *model = gtk_tree_view_get_model(treeview);
- const char * const *authorlist;
- char *markup, *name, *desc;
- char *authors = NULL, *pauthors = NULL;
- if (!gtk_tree_model_get_iter(model, &iter, path))
- gtk_tree_model_get(model, &iter, 2, &plugin, -1);
- info = GPLUGIN_PLUGIN_INFO(purple_plugin_get_info(plugin));
- authorlist = gplugin_plugin_info_get_authors(info);
- authors = g_strjoinv(", ", (gchar **)authorlist);
- pauthors = g_markup_escape_text(authors, -1);
- markup = g_strdup_printf(
- "<span size='x-large' weight='bold'>%s</span>\n<b>%s:</b> "
- name = g_markup_escape_text(gplugin_plugin_info_get_name(info), -1),
- desc = g_markup_escape_text(
- gplugin_plugin_info_get_description(info), -1),
- (authorlist && g_strv_length((gchar **)authorlist) > 1
- layout = gtk_widget_create_pango_layout(tipwindow, NULL);
- pango_layout_set_markup(layout, markup, -1);
- pango_layout_set_wrap(layout, PANGO_WRAP_WORD);
- pango_layout_set_width(layout, 600000);
- pango_layout_get_size(layout, &width, &height);
- g_object_set_data_full(G_OBJECT(tipwindow), "tooltip-plugin", layout, g_object_unref);
- *w = PANGO_PIXELS(width) + 12;
- *h = PANGO_PIXELS(height) + 12;
-website_button_motion_cb(GtkWidget *button, GdkEventCrossing *event,
- if (plugin_website_uri) {
- pidgin_set_cursor(button, GDK_HAND2);
-website_button_clicked_cb(GtkButton *button, GdkEventButton *event,
- if (plugin_website_uri) {
- purple_notify_uri(NULL, plugin_website_uri);
- GtkBox *vbox = GTK_BOX(gtk_box_new(GTK_ORIENTATION_VERTICAL, 3));
- GtkSizeGroup *sg = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
- GtkWidget *label, *view, *website_button;
- plugin_name = GTK_LABEL(gtk_label_new(NULL));
- gtk_label_set_xalign(plugin_name, 0);
- gtk_label_set_yalign(plugin_name, 0);
- gtk_label_set_line_wrap(plugin_name, FALSE);
- gtk_label_set_selectable(plugin_name, TRUE);
- gtk_box_pack_start(vbox, GTK_WIDGET(plugin_name), FALSE, FALSE, 0);
- view = gtk_text_view_new();
- plugin_desc = gtk_text_view_get_buffer(GTK_TEXT_VIEW(view));
- g_object_set(view, "wrap-mode", GTK_WRAP_WORD,
- "left-margin", PIDGIN_HIG_CAT_SPACE,
- "right-margin", PIDGIN_HIG_CAT_SPACE,
- gtk_box_pack_start(vbox, view, TRUE, TRUE, 0);
- plugin_error = GTK_LABEL(gtk_label_new(NULL));
- gtk_label_set_xalign(plugin_error, 0);
- gtk_label_set_yalign(plugin_error, 0);
- gtk_label_set_line_wrap(plugin_error, FALSE);
- gtk_label_set_selectable(plugin_error, TRUE);
- gtk_box_pack_start(vbox, GTK_WIDGET(plugin_error), FALSE, FALSE, 0);
- plugin_authors = GTK_LABEL(gtk_label_new(NULL));
- gtk_label_set_line_wrap(plugin_authors, FALSE);
- gtk_label_set_xalign(plugin_authors, 0);
- gtk_label_set_yalign(plugin_authors, 0);
- gtk_label_set_selectable(plugin_authors, TRUE);
- pidgin_add_widget_to_vbox(vbox, "", sg,
- GTK_WIDGET(plugin_authors), TRUE, &label);
- gtk_label_set_markup(GTK_LABEL(label), _("<b>Written by:</b>"));
- gtk_label_set_xalign(GTK_LABEL(label), 0);
- gtk_label_set_yalign(GTK_LABEL(label), 0);
- website_button = gtk_event_box_new();
- gtk_event_box_set_visible_window(GTK_EVENT_BOX(website_button), FALSE);
- plugin_website = GTK_LABEL(gtk_label_new(NULL));
- g_object_set(G_OBJECT(plugin_website),
- "ellipsize", PANGO_ELLIPSIZE_MIDDLE, NULL);
- gtk_label_set_xalign(plugin_website, 0);
- gtk_label_set_yalign(plugin_website, 0);
- gtk_container_add(GTK_CONTAINER(website_button),
- GTK_WIDGET(plugin_website));
- g_signal_connect(website_button, "button-release-event",
- G_CALLBACK(website_button_clicked_cb), NULL);
- g_signal_connect(website_button, "enter-notify-event",
- G_CALLBACK(website_button_motion_cb), NULL);
- g_signal_connect(website_button, "leave-notify-event",
- G_CALLBACK(pidgin_clear_cursor), NULL);
- pidgin_add_widget_to_vbox(vbox, "", sg, website_button, TRUE, &label);
- gtk_label_set_markup(GTK_LABEL(label), _("<b>Web site:</b>"));
- gtk_label_set_xalign(GTK_LABEL(label), 0);
- plugin_filename = GTK_LABEL(gtk_label_new(NULL));
- gtk_label_set_line_wrap(plugin_filename, FALSE);
- gtk_label_set_xalign(plugin_filename, 0);
- gtk_label_set_yalign(plugin_filename, 0);
- gtk_label_set_selectable(plugin_filename, TRUE);
- pidgin_add_widget_to_vbox(vbox, "", sg,
- GTK_WIDGET(plugin_filename), TRUE, &label);
- gtk_label_set_markup(GTK_LABEL(label), _("<b>Filename:</b>"));
- gtk_label_set_xalign(GTK_LABEL(label), 0);
- gtk_label_set_yalign(GTK_LABEL(label), 0);
- return GTK_WIDGET(vbox);
-void pidgin_plugin_dialog_show()
- GtkCellRenderer *rend, *rendt;
- GtkTreeViewColumn *col;
- if (plugin_dialog != NULL) {
- gtk_window_present(GTK_WINDOW(plugin_dialog));
- plugin_dialog = gtk_dialog_new();
- gtk_window_set_title(GTK_WINDOW(plugin_dialog), _("Plugins"));
- pref_button = gtk_dialog_add_button(GTK_DIALOG(plugin_dialog),
- _("Configure Pl_ugin"), PIDGIN_RESPONSE_CONFIGURE);
- gtk_dialog_add_button(GTK_DIALOG(plugin_dialog),
- GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE);
- gtk_widget_set_sensitive(pref_button, FALSE);
- gtk_window_set_role(GTK_WINDOW(plugin_dialog), "plugins");
- ls = gtk_list_store_new(4, G_TYPE_BOOLEAN, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_BOOLEAN);
- gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(ls),
- 1, GTK_SORT_ASCENDING);
- update_plugin_list(ls);
- event_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(ls));
- g_signal_connect(G_OBJECT(event_view), "row-activated",
- G_CALLBACK(show_plugin_prefs_cb), plugin_dialog);
- purple_signal_connect(purple_plugins_get_handle(), "plugin-load", plugin_dialog,
- PURPLE_CALLBACK(plugin_load_cb), event_view);
- purple_signal_connect(purple_plugins_get_handle(), "plugin-unload", plugin_dialog,
- PURPLE_CALLBACK(plugin_unload_cb), event_view);
- rend = gtk_cell_renderer_toggle_new();
- sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (event_view));
- col = gtk_tree_view_column_new_with_attributes (_("Enabled"),
- gtk_tree_view_append_column (GTK_TREE_VIEW(event_view), col);
- gtk_tree_view_column_set_sort_column_id(col, 0);
- g_signal_connect(G_OBJECT(rend), "toggled",
- G_CALLBACK(plugin_toggled), ls);
- rendt = gtk_cell_renderer_text_new();
- "foreground", "#c0c0c0",
- col = gtk_tree_view_column_new_with_attributes (_("Name"),
- gtk_tree_view_column_set_expand (col, TRUE);
- g_object_set(rendt, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
- gtk_tree_view_append_column (GTK_TREE_VIEW(event_view), col);
- gtk_tree_view_column_set_sort_column_id(col, 1);
- g_object_unref(G_OBJECT(ls));
- gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(plugin_dialog))),
- pidgin_make_scrollable(event_view, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC, GTK_SHADOW_IN, -1, -1),
- gtk_tree_view_set_search_column(GTK_TREE_VIEW(event_view), 1);
- gtk_tree_view_set_search_equal_func(GTK_TREE_VIEW(event_view),
- pidgin_tree_view_search_equal_func, NULL, NULL);
- pidgin_tooltip_setup_for_treeview(event_view, event_view,
- pidgin_plugins_create_tooltip,
- pidgin_plugins_paint_tooltip);
- expander = gtk_expander_new(_("<b>Plugin Details</b>"));
- gtk_expander_set_use_markup(GTK_EXPANDER(expander), TRUE);
- gtk_widget_set_sensitive(expander, FALSE);
- gtk_container_add(GTK_CONTAINER(expander), create_details());
- gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(plugin_dialog))),
- expander, FALSE, FALSE, 0);
- g_signal_connect (G_OBJECT (sel), "changed", G_CALLBACK (prefs_plugin_sel), NULL);
- g_signal_connect(G_OBJECT(plugin_dialog), "response", G_CALLBACK(plugin_dialog_response_cb), sel);
- gtk_window_set_default_size(GTK_WINDOW(plugin_dialog), 430, 530);
- pidgin_auto_parent_window(plugin_dialog);
- gtk_widget_show_all(plugin_dialog);
--- a/pidgin/gtkplugin.h Thu Nov 21 21:41:21 2019 -0600
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,118 +0,0 @@
- * 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
- * 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
-#ifndef _PIDGINPLUGIN_H_
-#define _PIDGINPLUGIN_H_
- * @section_id: pidgin-gtkplugin
- * @short_description: <filename>gtkplugin.h</filename>
-#define PIDGIN_TYPE_PLUGIN_INFO (pidgin_plugin_info_get_type())
-#define PIDGIN_PLUGIN_INFO(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), PIDGIN_TYPE_PLUGIN_INFO, PidginPluginInfo))
-#define PIDGIN_PLUGIN_INFO_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), PIDGIN_TYPE_PLUGIN_INFO, PidginPluginInfoClass))
-#define PIDGIN_IS_PLUGIN_INFO(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), PIDGIN_TYPE_PLUGIN_INFO))
-#define PIDGIN_IS_PLUGIN_INFO_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), PIDGIN_TYPE_PLUGIN_INFO))
-#define PIDGIN_PLUGIN_INFO_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), PIDGIN_TYPE_PLUGIN_INFO, PidginPluginInfoClass))
-typedef struct _PidginPluginInfo PidginPluginInfo;
-typedef struct _PidginPluginInfoClass PidginPluginInfoClass;
-typedef GtkWidget *(*PidginPluginConfigFrameCb)(PurplePlugin *plugin);
- * Extends #PurplePluginInfo to hold UI information for pidgin.
-struct _PidginPluginInfo {
- PurplePluginInfo parent;
- * PidginPluginInfoClass:
- * The base class for all #PidginPluginInfo's.
-struct _PidginPluginInfoClass {
- PurplePluginInfoClass parent_class;
- void (*_pidgin_reserved1)(void);
- void (*_pidgin_reserved2)(void);
- void (*_pidgin_reserved3)(void);
- void (*_pidgin_reserved4)(void);
- * pidgin_plugin_info_get_type:
- * Returns: The #GType for the #PidginPluginInfo object.
-GType pidgin_plugin_info_get_type(void);
- * pidgin_plugin_info_new:
- * @first_property: The first property name
- * @...: The value of the first property, followed optionally by more
- * name/value pairs, followed by %NULL
- * Creates a new #PidginPluginInfo instance to be returned from
- * #plugin_query of a pidgin plugin, using the provided name/value
- * See purple_plugin_info_new() for a list of available property names.
- * Additionally, you can provide the property
- * <literal>"gtk-config-frame-cb"</literal>, which should be a callback that
- * returns a #GtkWidget for the plugin's configuration
- * (see #PidginPluginConfigFrameCb).
- * See purple_plugin_info_new().
- * Returns: A new #PidginPluginInfo instance.
-PidginPluginInfo *pidgin_plugin_info_new(const char *first_property, ...)
- G_GNUC_NULL_TERMINATED;
- * Saves all loaded plugins.
-void pidgin_plugins_save(void);
- * pidgin_plugin_dialog_show:
- * Shows the Plugins dialog
-void pidgin_plugin_dialog_show(void);
-#endif /* _PIDGINPLUGIN_H_ */
--- a/pidgin/libpidgin.c Thu Nov 21 21:41:21 2019 -0600
+++ b/pidgin/libpidgin.c Fri Nov 22 04:10:26 2019 +0000
@@ -52,7 +52,6 @@
@@ -62,10 +61,11 @@
#include "gtksmiley-theme.h"
-#include "pidginstock.h"
#include "gtkwhiteboard.h"
+#include "pidginplugininfo.h" +#include "pidginstock.h" --- a/pidgin/meson.build Thu Nov 21 21:41:21 2019 -0600
+++ b/pidgin/meson.build Fri Nov 22 04:10:26 2019 +0000
@@ -14,7 +14,6 @@
@@ -44,6 +43,8 @@
+ 'pidginpluginsdialog.c', @@ -65,7 +66,6 @@
@@ -96,6 +96,8 @@
+ 'pidginpluginsdialog.h', @@ -150,15 +152,16 @@
install_headers(libpidgin_headers, subdir : 'pidgin-3')
_libpidgin_dependencies = [
_libpidgin_dependencies += x11
@@ -195,7 +198,7 @@
- requires : ['gtk+-3.0', 'purple-3', 'talkatu'],
+ requires : ['gtk+-3.0', 'purple-3', 'talkatu', 'gplugin-gtk'], variables : ['plugindir=${libdir}/pidgin-@0@'.format(purple_major_version)])
@@ -224,20 +227,21 @@
introspection_sources = libpidgin_headers
gnome.generate_gir(libpidgin,
- sources : introspection_sources,
- includes : ['GObject-2.0', 'Gtk-3.0', libpurple_gir[0], talkatu_gir, gplugin_gir],
- symbol_prefix : 'pidgin',
- identifier_prefix : 'Pidgin',
- export_packages : 'pidgin-@0@'.format(purple_major_version),
- nsversion : '@0@.@1@'.format(purple_major_version,
- include_directories : [
- gplugin_include_directories,
- talkatu_include_directories,
- extra_args : ['--quiet'])
+ sources : introspection_sources, + includes : ['GObject-2.0', 'Gtk-3.0', libpurple_gir[0], talkatu_gir, gplugin_gir, gplugin_gtk_gir], + symbol_prefix : 'pidgin', + identifier_prefix : 'Pidgin', + export_packages : 'pidgin-@0@'.format(purple_major_version), + nsversion : '@0@.@1@'.format(purple_major_version, + include_directories : [ + gplugin_include_directories, + gplugin_gtk_include_directories, + talkatu_include_directories, + extra_args : ['--quiet']) --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/pidgin/pidginplugininfo.c Fri Nov 22 04:10:26 2019 +0000
@@ -0,0 +1,62 @@
+ * 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 + * 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 "pidginplugininfo.h" +struct _PidginPluginInfo { + PurplePluginInfo parent; +/****************************************************************************** + * GObject Implementation + *****************************************************************************/ +G_DEFINE_TYPE(PidginPluginInfo, pidgin_plugin_info, PURPLE_TYPE_PLUGIN_INFO); +pidgin_plugin_info_init(PidginPluginInfo *info) { +pidgin_plugin_info_class_init(PidginPluginInfoClass *klass) { +/****************************************************************************** + *****************************************************************************/ +pidgin_plugin_info_new(const char *first_property, ...) + /* at least ID is required */ + va_start(var_args, first_property); + info = g_object_new_valist(PIDGIN_TYPE_PLUGIN_INFO, first_property, + g_object_set(info, "ui-requirement", PIDGIN_UI, NULL); + return PIDGIN_PLUGIN_INFO(info); --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/pidgin/pidginplugininfo.h Fri Nov 22 04:10:26 2019 +0000
@@ -0,0 +1,62 @@
+ * 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 + * 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 +#ifndef PIDGIN_PLUGIN_INFO_H +#define PIDGIN_PLUGIN_INFO_H +#define PIDGIN_TYPE_PLUGIN_INFO (pidgin_plugin_info_get_type()) +G_DECLARE_FINAL_TYPE(PidginPluginInfo, pidgin_plugin_info, PIDGIN, PLUGIN_INFO, PurplePluginInfo) + * pidgin_plugin_info_new: + * @first_property: The first property name + * @...: The value of the first property, followed optionally by more + * name/value pairs, followed by %NULL + * Creates a new #PidginPluginInfo instance to be returned from + * #plugin_query of a pidgin plugin, using the provided name/value + * See purple_plugin_info_new() for a list of available property names. + * Additionally, you can provide the property + * <literal>"gtk-config-frame-cb"</literal>, which should be a callback that + * returns a #GtkWidget for the plugin's configuration + * (see #PidginPluginConfigFrameCb). + * See purple_plugin_info_new(). + * Returns: A new #PidginPluginInfo instance. +PidginPluginInfo *pidgin_plugin_info_new(const char *first_property, ...) + G_GNUC_NULL_TERMINATED; +#endif /* PIDGIN_PLUGIN_INFO_H */ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/pidgin/pidginpluginsdialog.c Fri Nov 22 04:10:26 2019 +0000
@@ -0,0 +1,345 @@
+ * 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 + * 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 <gplugin-gtk.h> +#include "gtkpluginpref.h" +struct _PidginPluginsDialog { + GtkWidget *configure_plugin_button; + GtkWidget *close_button; + GtkWidget *plugin_info; + GtkListStore *plugin_store; +/* this has a short life left to it... */ + PIDGIN_PLUGIN_UI_DATA_TYPE_FRAME, + PIDGIN_PLUGIN_UI_DATA_TYPE_REQUEST + PurplePluginPrefFrame *pref_frame; + gpointer request_handle; +/****************************************************************************** + *****************************************************************************/ +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 (purple_plugin_info_get_pref_frame_cb(info) || + purple_plugin_info_get_pref_request_cb(info)); +pidgin_plugins_dialog_get_selected(PidginPluginsDialog *dialog) { + GPluginPlugin *plugin = NULL; + GtkTreeSelection *selection = NULL; + GtkTreeModel *model = NULL; + 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) { + if(gtk_tree_selection_get_selected(selection, &model, &iter)) { + gtk_tree_model_get(model, &iter, + GPLUGIN_GTK_STORE_PLUGIN_COLUMN, &plugin, +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); + purple_debug_info("PidginPluginsDialog", "failed to find uidata\n"); + if (ui_data->type == PIDGIN_PLUGIN_UI_DATA_TYPE_REQUEST) { + purple_request_close(PURPLE_REQUEST_FIELDS, + ui_data->u.request_handle); + 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); + purple_plugin_info_set_ui_data(info, NULL); +/****************************************************************************** + *****************************************************************************/ +pidgin_plugins_dialog_close(GtkWidget *b, gpointer data) { + gtk_widget_destroy(GTK_WIDGET(data)); +pidgin_plugins_dialog_selection_cb(GtkTreeSelection *sel, gpointer data) { + PidginPluginsDialog *dialog = PIDGIN_PLUGINS_DIALOG(data); + GPluginPlugin *plugin = NULL; + GtkTreeModel *model = NULL; + if(gtk_tree_selection_get_selected(sel, &model, &iter)) { + gtk_tree_model_get(model, &iter, + GPLUGIN_GTK_STORE_PLUGIN_COLUMN, &plugin, + gplugin_gtk_plugin_info_set_plugin( + GPLUGIN_GTK_PLUGIN_INFO(dialog->plugin_info), + gtk_widget_set_sensitive( + GTK_WIDGET(dialog->configure_plugin_button), + pidgin_plugins_dialog_plugin_has_config(plugin) + g_object_unref(G_OBJECT(plugin)); +pidgin_plugins_dialog_pref_dialog_response_cb(GtkWidget *dialog, int response, + if (response == GTK_RESPONSE_CLOSE || + response == GTK_RESPONSE_DELETE_EVENT) + pidgin_plugins_dialog_pref_dialog_close(GPLUGIN_PLUGIN(data)); +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; + plugin = pidgin_plugins_dialog_get_selected(dialog); + if(!GPLUGIN_IS_PLUGIN(plugin)) { + 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)); + 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); + ui_data->u.frame.pref_frame = pref_frame_cb(plugin); + 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. + 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, + 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); + purple_debug_error("gtkplugin", + "Failed to display prefs frame"); + purple_plugin_info_set_ui_data(info, NULL); + g_object_unref(G_OBJECT(plugin)); + 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, + 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_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); +pidgin_plugins_dialog_class_init(PidginPluginsDialogClass *klass) { + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass); + gtk_widget_class_set_template_from_resource( + "/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); +pidgin_plugins_dialog_init(PidginPluginsDialog *dialog) { + gtk_widget_init_template(GTK_WIDGET(dialog)); + /* wire up the close button */ + G_CALLBACK(pidgin_plugins_dialog_close), + /* 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, +pidgin_plugins_dialog_new(void) { + PIDGIN_TYPE_PLUGINS_DIALOG, --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/pidgin/pidginpluginsdialog.h Fri Nov 22 04:10:26 2019 +0000
@@ -0,0 +1,55 @@
+ * 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 + * 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 +#ifndef PIDGIN_PLUGINS_DIALOG_H +#define PIDGIN_PLUGINS_DIALOG_H + * SECTION:pidginpluginsdialog + * @section_id: pidgin-plugins-dialog + * @short_description: A widget to display available plugins + * @title: Plugins Dialog +#define PIDGIN_TYPE_PLUGINS_DIALOG (pidgin_plugins_dialog_get_type()) +G_DECLARE_FINAL_TYPE(PidginPluginsDialog, pidgin_plugins_dialog, PIDGIN, + PLUGINS_DIALOG, GtkDialog) + * pidgin_plugins_dialog_new: + * Creates a new instance of #PidginPluginsDialog. + * Returns: (transfer full): The new #PidginPluginsDialog. +GtkWidget *pidgin_plugins_dialog_new(void); +#endif /* PIDGIN_PLUGINS_DIALOG_H */ --- a/pidgin/plugins/contact_priority.c Thu Nov 21 21:41:21 2019 -0600
+++ b/pidgin/plugins/contact_priority.c Fri Nov 22 04:10:26 2019 +0000
@@ -20,8 +20,8 @@
+#include "pidginplugininfo.h" --- a/pidgin/plugins/disco/xmppdisco.c Thu Nov 21 21:41:21 2019 -0600
+++ b/pidgin/plugins/disco/xmppdisco.c Fri Nov 22 04:10:26 2019 +0000
@@ -44,7 +44,7 @@
+#include "pidginplugininfo.h" --- a/pidgin/plugins/extplacement.c Thu Nov 21 21:41:21 2019 -0600
+++ b/pidgin/plugins/extplacement.c Fri Nov 22 04:10:26 2019 +0000
@@ -24,7 +24,7 @@
#include "conversation.h"
+#include "pidginplugininfo.h" --- a/pidgin/plugins/gtk-signals-test.c Thu Nov 21 21:41:21 2019 -0600
+++ b/pidgin/plugins/gtk-signals-test.c Fri Nov 22 04:10:26 2019 +0000
@@ -30,7 +30,7 @@
+#include "pidginplugininfo.h" /**************************************************************************
* Account subsystem signal callbacks
--- a/pidgin/plugins/gtkbuddynote.c Thu Nov 21 21:41:21 2019 -0600
+++ b/pidgin/plugins/gtkbuddynote.c Fri Nov 22 04:10:26 2019 +0000
@@ -19,7 +19,7 @@
+#include <pidginplugininfo.h> --- a/pidgin/plugins/iconaway.c Thu Nov 21 21:41:21 2019 -0600
+++ b/pidgin/plugins/iconaway.c Fri Nov 22 04:10:26 2019 +0000
@@ -26,7 +26,7 @@
+#include "pidginplugininfo.h" #define ICONAWAY_PLUGIN_ID "gtk-iconaway"
--- a/pidgin/plugins/relnot.c Thu Nov 21 21:41:21 2019 -0600
+++ b/pidgin/plugins/relnot.c Fri Nov 22 04:10:26 2019 +0000
@@ -32,10 +32,10 @@
+#include "pidginplugininfo.h" --- a/pidgin/plugins/ticker/ticker.c Thu Nov 21 21:41:21 2019 -0600
+++ b/pidgin/plugins/ticker/ticker.c Fri Nov 22 04:10:26 2019 +0000
@@ -35,8 +35,8 @@
+#include "pidginplugininfo.h" --- a/pidgin/plugins/xmppconsole/xmppconsole.c Thu Nov 21 21:41:21 2019 -0600
+++ b/pidgin/plugins/xmppconsole/xmppconsole.c Fri Nov 22 04:10:26 2019 +0000
@@ -22,7 +22,7 @@
+#include "pidginplugininfo.h" --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/pidgin/resources/Plugins/dialog.ui Fri Nov 22 04:10:26 2019 +0000
@@ -0,0 +1,112 @@
+<?xml version="1.0" encoding="UTF-8"?> +<!-- Generated with glade 3.22.1 --> + <requires lib="gtk+" version="3.20"/> + <requires lib="gplugin-gtk" version="0.28"/> + <object class="GPluginGtkStore" id="raw_plugin_store"/> + <object class="GtkTreeModelSort" id="plugin_store"> + <property name="model">raw_plugin_store</property> + <template class="PidginPluginsDialog" parent="GtkDialog"> + <property name="can_focus">False</property> + <property name="type_hint">dialog</property> + <child internal-child="vbox"> + <object class="GtkBox"> + <property name="can_focus">False</property> + <property name="orientation">vertical</property> + <property name="spacing">2</property> + <child internal-child="action_area"> + <object class="GtkButtonBox"> + <property name="can_focus">False</property> + <property name="layout_style">end</property> + <object class="GtkButton" id="configure_plugin_button"> + <property name="label" translatable="yes">Configure Plugin</property> + <property name="visible">True</property> + <property name="sensitive">False</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <signal name="clicked" handler="pidgin_plugins_dialog_config_plugin_cb" object="PidginPluginsDialog" swapped="no"/> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">0</property> + <object class="GtkButton" id="close_button"> + <property name="label" translatable="yes">Close</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">1</property> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">0</property> + <object class="GtkBox"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="homogeneous">True</property> + <object class="GtkScrolledWindow"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="shadow_type">in</property> + <object class="GPluginGtkView" id="tree_view"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="model">plugin_store</property> + <property name="headers_clickable">False</property> + <child internal-child="selection"> + <object class="GtkTreeSelection"> + <signal name="changed" handler="pidgin_plugins_dialog_selection_cb" object="PidginPluginsDialog" swapped="no"/> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + <object class="GPluginGtkPluginInfo" id="plugin_info"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="orientation">vertical</property> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">1</property> --- a/pidgin/resources/pidgin.gresource.xml Thu Nov 21 21:41:21 2019 -0600
+++ b/pidgin/resources/pidgin.gresource.xml Fri Nov 22 04:10:26 2019 +0000
@@ -10,6 +10,7 @@
<file compressed="true">Debug/debug.ui</file>
<file compressed="true">Debug/plugininfo.ui</file>
<file compressed="true">Log/log-viewer.ui</file>
+ <file compressed="true">Plugins/dialog.ui</file> <file compressed="true">Prefs/prefs.ui</file>
<file compressed="true">Prefs/vv.ui</file>
<file compressed="true">Whiteboard/whiteboard.ui</file>