# HG changeset patch # User Gary Kramlich # Date 1647912343 18000 # Node ID 8befd71928c289b533445a8c6df555f46e0d5ba5 # Parent 92438aae20670ec7026e930618ef06ec067a9cc2 Create a new status manager that's built in glade Behavorial Changes: * Confirmation dialog for remove has been removed. * Remove button is disabled if the currently selected status is the active status. Previously this scenario was silently ignored after confirmation. Errata: It is possible to open multiple modify windows for a status. Previously the editor was reaching into the manager and controlling this pointer. I was going to fix this, but the editor isn't a widget yet and I don't like doing duplicate work. Testing Done: Basically tried everything I could think of with editing and selecting and so on. Bugs closed: PIDGIN-17590 Reviewed at https://reviews.imfreedom.org/r/1322/ diff -r 92438aae2067 -r 8befd71928c2 pidgin/meson.build --- a/pidgin/meson.build Fri Mar 18 00:13:23 2022 -0500 +++ b/pidgin/meson.build Mon Mar 21 20:25:43 2022 -0500 @@ -53,6 +53,7 @@ 'pidginprotocolchooser.c', 'pidginprotocolstore.c', 'pidginscrollbook.c', + 'pidginstatusmanager.c', 'pidginstatusprimitivechooser.c', 'pidginstatusprimitivestore.c', 'pidginstylecontext.c', @@ -116,6 +117,7 @@ 'pidginprotocolchooser.h', 'pidginprotocolstore.h', 'pidginscrollbook.h', + 'pidginstatusmanager.h', 'pidginstatusprimitivechooser.h', 'pidginstatusprimitivestore.h', 'pidginstylecontext.h', diff -r 92438aae2067 -r 8befd71928c2 pidgin/pidginapplication.c --- a/pidgin/pidginapplication.c Fri Mar 18 00:13:23 2022 -0500 +++ b/pidgin/pidginapplication.c Mon Mar 21 20:25:43 2022 -0500 @@ -40,7 +40,6 @@ #include "gtkdialogs.h" #include "gtkprivacy.h" #include "gtkroomlist.h" -#include "gtksavedstatuses.h" #include "gtkxfer.h" #include "pidginabout.h" #include "pidginaccountsdisabledmenu.h" @@ -50,6 +49,7 @@ #include "pidgindebug.h" #include "pidginmooddialog.h" #include "pidgin/pidginpluginsdialog.h" +#include "pidgin/pidginstatusmanager.h" #include "pidginprefs.h" struct _PidginApplication { @@ -410,7 +410,14 @@ pidgin_application_show_status_manager(GSimpleAction *simple, GVariant *parameter, gpointer data) { - pidgin_status_window_show(); + static GtkWidget *manager = NULL; + + if(!GTK_IS_WIDGET(manager)) { + manager = pidgin_status_manager_new(); + g_object_add_weak_pointer(G_OBJECT(manager), (gpointer)&manager); + } + + gtk_widget_show_all(manager); } static GActionEntry app_entries[] = { diff -r 92438aae2067 -r 8befd71928c2 pidgin/pidginstatusmanager.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pidgin/pidginstatusmanager.c Mon Mar 21 20:25:43 2022 -0500 @@ -0,0 +1,307 @@ +/* + * Pidgin - Internet Messenger + * Copyright (C) Pidgin Developers + * + * 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, see . + */ + +#include "pidginstatusmanager.h" + +#include "gtksavedstatuses.h" +#include "pidginiconname.h" + +enum { + RESPONSE_USE, + RESPONSE_ADD, + RESPONSE_MODIFY, + RESPONSE_REMOVE +}; + +enum { + COLUMN_TITLE, + COLUMN_ICON_NAME, + COLUMN_TYPE, + COLUMN_MESSAGE, + COLUMN_STATUS +}; + +struct _PidginStatusManager { + GtkDialog parent; + + GtkListStore *model; + GtkTreeSelection *selection; + + GtkWidget *use_button; + GtkWidget *modify_button; + GtkWidget *remove_button; +}; + +G_DEFINE_TYPE(PidginStatusManager, pidgin_status_manager, GTK_TYPE_DIALOG) + +/****************************************************************************** + * Helpers + *****************************************************************************/ +static PurpleSavedStatus * +pidgin_status_manager_get_selected_status(PidginStatusManager *manager) { + PurpleSavedStatus *status = NULL; + GtkTreeIter iter; + + if(gtk_tree_selection_count_selected_rows(manager->selection) == 0) { + return NULL; + } + + gtk_tree_selection_get_selected(manager->selection, NULL, &iter); + gtk_tree_model_get(GTK_TREE_MODEL(manager->model), &iter, + COLUMN_STATUS, &status, + -1); + + return status; +} + +static void +pidgin_status_manager_add(PidginStatusManager *manager, + PurpleSavedStatus *status) +{ + PurpleStatusPrimitive primitive; + GtkTreeIter iter; + gchar *message = NULL; + const gchar *icon_name = NULL, *type = NULL; + + message = purple_markup_strip_html(purple_savedstatus_get_message(status)); + + primitive = purple_savedstatus_get_primitive_type(status); + icon_name = pidgin_icon_name_from_status_primitive(primitive, NULL); + type = purple_primitive_get_name_from_type(primitive); + + gtk_list_store_append(manager->model, &iter); + gtk_list_store_set(manager->model, &iter, + COLUMN_TITLE, purple_savedstatus_get_title(status), + COLUMN_ICON_NAME, icon_name, + COLUMN_TYPE, type, + COLUMN_MESSAGE, message, + COLUMN_STATUS, status, + -1); + + g_free(message); +} + +static void +pidgin_status_manager_populate_helper(gpointer data, gpointer user_data) { + PidginStatusManager *manager = user_data; + PurpleSavedStatus *status = data; + + if(!purple_savedstatus_is_transient(status)) { + pidgin_status_manager_add(manager, status); + } +} + +static void +pidgin_status_manager_refresh(PidginStatusManager *manager) { + GList *statuses = NULL; + + gtk_list_store_clear(manager->model); + + statuses = purple_savedstatuses_get_all(); + g_list_foreach(statuses, pidgin_status_manager_populate_helper, manager); +} + +/****************************************************************************** + * Callbacks + *****************************************************************************/ +static void +pidgin_status_manager_response_cb(GtkDialog *dialog, gint response_id, + gpointer data) +{ + PidginStatusManager *manager = data; + PurpleSavedStatus *status = NULL; + + switch(response_id) { + case RESPONSE_USE: + status = pidgin_status_manager_get_selected_status(manager); + + purple_savedstatus_activate(status); + + break; + case RESPONSE_ADD: + pidgin_status_editor_show(FALSE, NULL); + break; + case RESPONSE_MODIFY: + status = pidgin_status_manager_get_selected_status(manager); + + pidgin_status_editor_show(TRUE, status); + + break; + case RESPONSE_REMOVE: + status = pidgin_status_manager_get_selected_status(manager); + + purple_savedstatus_delete_by_status(status); + + break; + case GTK_RESPONSE_CLOSE: + gtk_widget_destroy(GTK_WIDGET(dialog)); + break; + } +} + +static void +pidgin_status_manager_row_activated_cb(G_GNUC_UNUSED GtkTreeView *tree_view, + GtkTreePath *path, + G_GNUC_UNUSED GtkTreeViewColumn *column, + gpointer data) +{ + PidginStatusManager *manager = data; + GtkTreeIter iter; + + if(gtk_tree_model_get_iter(GTK_TREE_MODEL(manager->model), &iter, path)) { + PurpleSavedStatus *status = NULL; + + gtk_tree_model_get(GTK_TREE_MODEL(manager->model), &iter, + COLUMN_STATUS, &status, + -1); + + pidgin_status_editor_show(TRUE, status); + } +} + +static void +pidgin_status_manager_selection_changed_cb(GtkTreeSelection *selection, + gpointer data) +{ + PidginStatusManager *manager = data; + gboolean sensitive = TRUE; + + if(gtk_tree_selection_count_selected_rows(selection) == 0) { + sensitive = FALSE; + } + + gtk_widget_set_sensitive(manager->use_button, sensitive); + gtk_widget_set_sensitive(manager->modify_button, sensitive); + + /* Only enable the remove button if the currently selected row is not the + * currently active status. + */ + if(sensitive) { + PurpleSavedStatus *status = NULL; + + status = pidgin_status_manager_get_selected_status(manager); + + sensitive = status != purple_savedstatus_get_current(); + } + + gtk_widget_set_sensitive(manager->remove_button, sensitive); +} + +static void +pidgin_status_manager_savedstatus_changed_cb(PurpleSavedStatus *new_status, + G_GNUC_UNUSED PurpleSavedStatus *old_status, + gpointer data) +{ + PidginStatusManager *manager = data; + PurpleSavedStatus *selected = NULL; + + /* Disable the remove button if the selected status is the currently active + * status. + */ + selected = pidgin_status_manager_get_selected_status(manager); + if(selected != NULL) { + gboolean sensitive = selected != new_status; + + gtk_widget_set_sensitive(manager->remove_button, sensitive); + } +} + +static void +pidgin_status_manager_savedstatus_updated_cb(G_GNUC_UNUSED PurpleSavedStatus *status, + gpointer data) +{ + PidginStatusManager *manager = data; + + pidgin_status_manager_refresh(manager); +} + +/****************************************************************************** + * GObject Implementation + *****************************************************************************/ +static void +pidgin_status_manager_finalize(GObject *obj) { + purple_signals_disconnect_by_handle(obj); + + G_OBJECT_CLASS(pidgin_status_manager_parent_class)->finalize(obj); +} + +static void +pidgin_status_manager_init(PidginStatusManager *manager) { + gpointer handle = NULL; + + gtk_widget_init_template(GTK_WIDGET(manager)); + + pidgin_status_manager_refresh(manager); + + handle = purple_savedstatuses_get_handle(); + purple_signal_connect(handle, "savedstatus-changed", manager, + PURPLE_CALLBACK(pidgin_status_manager_savedstatus_changed_cb), + manager); + purple_signal_connect(handle, "savedstatus-added", manager, + PURPLE_CALLBACK(pidgin_status_manager_savedstatus_updated_cb), + manager); + purple_signal_connect(handle, "savedstatus-deleted", manager, + PURPLE_CALLBACK(pidgin_status_manager_savedstatus_updated_cb), + manager); + purple_signal_connect(handle, "savedstatus-modified", manager, + PURPLE_CALLBACK(pidgin_status_manager_savedstatus_updated_cb), + manager); +} + +static void +pidgin_status_manager_class_init(PidginStatusManagerClass *klass) { + GObjectClass *obj_class = G_OBJECT_CLASS(klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass); + + obj_class->finalize = pidgin_status_manager_finalize; + + gtk_widget_class_set_template_from_resource( + widget_class, + "/im/pidgin/Pidgin3/Status/manager.ui" + ); + + gtk_widget_class_bind_template_child(widget_class, PidginStatusManager, + model); + gtk_widget_class_bind_template_child(widget_class, PidginStatusManager, + selection); + gtk_widget_class_bind_template_child(widget_class, PidginStatusManager, + use_button); + gtk_widget_class_bind_template_child(widget_class, PidginStatusManager, + modify_button); + gtk_widget_class_bind_template_child(widget_class, PidginStatusManager, + remove_button); + + gtk_widget_class_bind_template_callback(widget_class, + pidgin_status_manager_response_cb); + gtk_widget_class_bind_template_callback(widget_class, + pidgin_status_manager_row_activated_cb); + gtk_widget_class_bind_template_callback(widget_class, + pidgin_status_manager_selection_changed_cb); +} + +/****************************************************************************** + * Public API + *****************************************************************************/ +GtkWidget * +pidgin_status_manager_new(void) { + return g_object_new(PIDGIN_TYPE_STATUS_MANAGER, NULL); +} diff -r 92438aae2067 -r 8befd71928c2 pidgin/pidginstatusmanager.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pidgin/pidginstatusmanager.h Mon Mar 21 20:25:43 2022 -0500 @@ -0,0 +1,57 @@ +/* + * Pidgin - Internet Messenger + * Copyright (C) Pidgin Developers + * + * 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, see . + */ + +#if !defined(PIDGIN_GLOBAL_HEADER_INSIDE) && !defined(PIDGIN_COMPILATION) +# error "only may be included directly" +#endif + +#ifndef PIDGIN_STATUS_MANAGER_H +#define PIDGIN_STATUS_MANAGER_H + +#include + +#include + +G_BEGIN_DECLS + +/** + * PidginStatusManager: + * + * A dialog for managing statuses. + */ + +#define PIDGIN_TYPE_STATUS_MANAGER (pidgin_status_manager_get_type()) +G_DECLARE_FINAL_TYPE(PidginStatusManager, pidgin_status_manager, PIDGIN, + STATUS_MANAGER, GtkDialog) + +/** + * pidgin_status_manager_new: + * + * Creates a new instance of the dialog. + * + * Returns: (transfer full): The new #PidginStatusManager instance. + */ +GtkWidget *pidgin_status_manager_new(void); + +G_END_DECLS + +#endif /* PIDGIN_STATUS_MANAGER_H */ diff -r 92438aae2067 -r 8befd71928c2 pidgin/resources/Status/manager.ui --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pidgin/resources/Status/manager.ui Mon Mar 21 20:25:43 2022 -0500 @@ -0,0 +1,226 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff -r 92438aae2067 -r 8befd71928c2 pidgin/resources/pidgin.gresource.xml --- a/pidgin/resources/pidgin.gresource.xml Fri Mar 18 00:13:23 2022 -0500 +++ b/pidgin/resources/pidgin.gresource.xml Mon Mar 21 20:25:43 2022 -0500 @@ -30,6 +30,7 @@ Privacy/dialog.ui Protocols/chooser.ui Roomlist/roomlist.ui + Status/manager.ui Whiteboard/whiteboard.ui Xfer/xfer.ui closebutton.ui diff -r 92438aae2067 -r 8befd71928c2 po/POTFILES.in --- a/po/POTFILES.in Fri Mar 18 00:13:23 2022 -0500 +++ b/po/POTFILES.in Mon Mar 21 20:25:43 2022 -0500 @@ -412,6 +412,7 @@ pidgin/resources/Privacy/dialog.ui pidgin/resources/Protocols/chooser.ui pidgin/resources/Roomlist/roomlist.ui +pidgin/resources/Status/manager.ui pidgin/resources/Whiteboard/whiteboard.ui pidgin/resources/Xfer/xfer.ui pidgin/resources/gtk/menus.ui