Sat, 09 Aug 2025 18:12:31 +0800
Add builtin library dependency for introspection
Without specifying, gir defaults to the system pidgin/purple libraries by default,
which fails the build when new symbols were added and gir failed to link for them.
/* * Pidgin - Internet Messenger * Copyright (C) Pidgin Developers <devel@pidgin.im> * * 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 <https://www.gnu.org/licenses/>. */ #include <glib/gi18n.h> #include <purple.h> #include "pidginaccountmanager.h" #include "pidgincore.h" #include "pidginaccounteditor.h" #include "pidginaccountmanagerrow.h" struct _PidginAccountManager { AdwWindow parent; AdwNavigationView *view; struct { GtkListBox *list_box; GtkActionBar *action_bar; } overview; struct { PidginAccountEditor *editor; GtkButton *add; GtkWidget *remove; } editor; /* This is used to not go back to the manager when an account was edited * directly, via the `accounts->(account)->edit` menu or the * `connection error` notification. */ gboolean edit_only; }; G_DEFINE_FINAL_TYPE(PidginAccountManager, pidgin_account_manager, ADW_TYPE_WINDOW) /****************************************************************************** * Helpers *****************************************************************************/ static GtkWidget * pidgin_account_manager_create_widget(gpointer item, G_GNUC_UNUSED gpointer data) { if(!PURPLE_IS_ACCOUNT(item)) { return NULL; } return pidgin_account_manager_row_new(PURPLE_ACCOUNT(item)); } static void pidgin_account_manager_real_edit_account(PidginAccountManager *manager, PurpleAccount *account, gboolean edit_only) { g_return_if_fail(PIDGIN_IS_ACCOUNT_MANAGER(manager)); manager->edit_only = edit_only; pidgin_account_editor_set_account(manager->editor.editor, account); /* Scroll the editor back to the top of the scrolled window. */ adw_preferences_page_scroll_to_top(ADW_PREFERENCES_PAGE(manager->editor.editor)); if(PURPLE_IS_ACCOUNT(account)) { gtk_button_set_label(manager->editor.add, _("_Save")); gtk_widget_set_visible(manager->editor.remove, TRUE); } else { gtk_button_set_label(manager->editor.add, _("_Add")); gtk_widget_set_visible(manager->editor.remove, FALSE); } adw_navigation_view_push_by_tag(manager->view, "editor"); } /****************************************************************************** * Callbacks *****************************************************************************/ /* This is used by the add button on the placeholder page. */ static void pidgin_account_manager_create_account(G_GNUC_UNUSED GtkButton *self, gpointer data) { PidginAccountManager *manager = data; pidgin_account_manager_real_edit_account(manager, NULL, FALSE); } static void pidgin_account_manager_refresh_add_cb(GListModel *list, G_GNUC_UNUSED guint position, G_GNUC_UNUSED guint removed, G_GNUC_UNUSED guint added, gpointer data) { PidginAccountManager *manager = data; /* If there are no accounts, the placeholder is shown, which includes an * Add button. So hide the button box if that's the case. */ gtk_action_bar_set_revealed(manager->overview.action_bar, g_list_model_get_n_items(list) != 0); } static void pidgin_account_manager_row_activated_cb(G_GNUC_UNUSED GtkListBox *box, GtkListBoxRow *row, gpointer data) { PurpleAccount *account = NULL; PidginAccountManager *manager = data; PidginAccountManagerRow *manager_row = NULL; manager_row = PIDGIN_ACCOUNT_MANAGER_ROW(row); account = pidgin_account_manager_row_get_account(manager_row); pidgin_account_manager_real_edit_account(manager, account, FALSE); } static void pidgin_account_manager_remove_account_cb(G_GNUC_UNUSED AdwMessageDialog *self, char *response, gpointer data) { PidginAccountManager *account_manager = data; PurpleAccount *account = NULL; PurpleNotificationManager *notification_manager = NULL; if(!purple_strequal(response, "remove")) { return; } account = pidgin_account_editor_get_account(account_manager->editor.editor); /* Remove all notifications including connection errors for the account. */ notification_manager = purple_notification_manager_get_default(); purple_notification_manager_remove_with_account(notification_manager, account, TRUE); /* Delete the account. */ purple_accounts_delete(account); pidgin_account_manager_show_overview(account_manager); } static void pidgin_account_manager_remove_clicked_cb(G_GNUC_UNUSED GtkButton *self, gpointer data) { PidginAccountManager *manager = data; PurpleAccount *account = NULL; PurpleProtocol *protocol = NULL; AdwAlertDialog *dialog = NULL; const char *name = NULL; const char *protocol_name = _("Unknown"); account = pidgin_account_editor_get_account(manager->editor.editor); name = purple_account_get_username(account); protocol = purple_account_get_protocol(account); if(PURPLE_IS_PROTOCOL(protocol)) { protocol_name = purple_protocol_get_name(protocol); } dialog = ADW_ALERT_DIALOG(adw_alert_dialog_new(_("Remove account?"), NULL)); adw_alert_dialog_format_body( dialog, _("Do you want to remove the %s (%s) account from Pidgin?"), name, protocol_name); adw_alert_dialog_add_responses(dialog, "cancel", _("Cancel"), "remove", _("Remove"), NULL); adw_alert_dialog_set_response_appearance(dialog, "remove", ADW_RESPONSE_DESTRUCTIVE); adw_alert_dialog_set_default_response(dialog, "cancel"); adw_alert_dialog_set_close_response(dialog, "cancel"); g_signal_connect(dialog, "response", G_CALLBACK(pidgin_account_manager_remove_account_cb), manager); adw_dialog_present(ADW_DIALOG(dialog), GTK_WIDGET(manager)); } static void pidgin_account_manager_save_clicked_cb(G_GNUC_UNUSED GtkButton *self, gpointer data) { PidginAccountManager *manager = data; pidgin_account_editor_save(manager->editor.editor); if(manager->edit_only) { gtk_window_destroy(GTK_WINDOW(manager)); } else { pidgin_account_manager_show_overview(manager); } } /****************************************************************************** * GObject Implementation *****************************************************************************/ static void pidgin_account_manager_init(PidginAccountManager *manager) { GListModel *purple_manager = NULL; gtk_widget_init_template(GTK_WIDGET(manager)); purple_manager = purple_account_manager_get_default_as_model(); gtk_list_box_bind_model(manager->overview.list_box, purple_manager, pidgin_account_manager_create_widget, NULL, NULL); g_signal_connect_object(purple_manager, "items-changed", G_CALLBACK(pidgin_account_manager_refresh_add_cb), manager, 0); pidgin_account_manager_refresh_add_cb(purple_manager, 0, 0, 0, manager); } static void pidgin_account_manager_class_init(PidginAccountManagerClass *klass) { GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass); gtk_widget_class_set_template_from_resource( widget_class, "/im/pidgin/Pidgin3/Accounts/manager.ui" ); gtk_widget_class_bind_template_child(widget_class, PidginAccountManager, view); gtk_widget_class_bind_template_child(widget_class, PidginAccountManager, overview.list_box); gtk_widget_class_bind_template_child(widget_class, PidginAccountManager, overview.action_bar); gtk_widget_class_bind_template_child(widget_class, PidginAccountManager, editor.editor); gtk_widget_class_bind_template_child(widget_class, PidginAccountManager, editor.add); gtk_widget_class_bind_template_child(widget_class, PidginAccountManager, editor.remove); gtk_widget_class_bind_template_callback(widget_class, pidgin_account_manager_row_activated_cb); gtk_widget_class_bind_template_callback(widget_class, pidgin_account_manager_create_account); gtk_widget_class_bind_template_callback(widget_class, pidgin_account_manager_remove_clicked_cb); gtk_widget_class_bind_template_callback(widget_class, pidgin_account_manager_save_clicked_cb); } /****************************************************************************** * Public API *****************************************************************************/ GtkWidget * pidgin_account_manager_new(GtkApplication *application) { return g_object_new( PIDGIN_TYPE_ACCOUNT_MANAGER, "application", application, NULL); } void pidgin_account_manager_show_overview(PidginAccountManager *manager) { g_return_if_fail(PIDGIN_IS_ACCOUNT_MANAGER(manager)); adw_navigation_view_pop_to_tag(manager->view, "overview"); pidgin_account_editor_set_account(manager->editor.editor, NULL); } void pidgin_account_manager_edit_account(PidginAccountManager *manager, PurpleAccount *account) { g_return_if_fail(PIDGIN_IS_ACCOUNT_MANAGER(manager)); g_return_if_fail(PURPLE_IS_ACCOUNT(account)); pidgin_account_manager_real_edit_account(manager, account, TRUE); }