Create PurpleUi that merges PurpleCoreUiOps and PurpleUiInfo
This created a lot more refactoring that I imagined, but it's mostly just moving stuff around.
I skipped the unit tests for now because we already have a `test_ui.[ch]` in the tests directory which we can/should move to a separate library or something, so it's available outside of the `libpurple/tests/` directory.
Testing Done:
Ran the unit tests, launched pidgin3, and launched finch3 with out issue.
Bugs closed: PIDGIN-17697
Reviewed at https://reviews.imfreedom.org/r/1925/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/finch/finchui.c Mon Oct 31 04:02:09 2022 -0500
@@ -0,0 +1,246 @@
+ * Finch - Universal Text Chat Client + * Copyright (C) Pidgin Developers <devel@pidgin.im> + * Finch 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, see <https://www.gnu.org/licenses/>. +#define G_SETTINGS_ENABLE_BACKEND +#include <gio/gsettingsbackend.h> +#include "finchnotifications.h" +#include "gntroomlist.h" +G_DEFINE_TYPE(FinchUi, finch_ui, PURPLE_TYPE_UI) +/****************************************************************************** + *****************************************************************************/ +finch_history_init(GError **error) { + PurpleHistoryManager *manager = NULL; + PurpleHistoryAdapter *adapter = NULL; + gchar *filename = NULL; + const gchar *id = NULL; + manager = purple_history_manager_get_default(); + /* Attempt to create the config directory. */ + g_mkdir_with_parents(purple_config_dir(), 0700); + filename = g_build_filename(purple_config_dir(), "history.db", NULL); + adapter = purple_sqlite_history_adapter_new(filename); + id = purple_history_adapter_get_id(adapter); + if(!purple_history_manager_register(manager, adapter, error)) { + g_clear_object(&adapter); + /* The manager adds a ref to the adapter on registration, so we can remove + g_clear_object(&adapter); + return purple_history_manager_set_active(manager, id, error); +/****************************************************************************** + * PurpleUi Implementation + *****************************************************************************/ +finch_ui_prefs_init(G_GNUC_UNUSED PurpleUi *ui) { +finch_ui_start(G_GNUC_UNUSED PurpleUi *ui) { +#ifdef _WIN32 /* TODO: don't change it when using FHS under win32 */ + gnt_set_config_dir(purple_config_dir()); + if(!finch_history_init(&error)) { + g_critical("failed to initialize the history api: %s", + error != NULL ? error->message : "unknown"); + purple_prefs_add_none("/purple/gnt"); + finch_connections_init(); + purple_connections_set_ui_ops(finch_connections_get_ui_ops()); + /* Initialize the buddy list */ + purple_blist_set_ui(FINCH_TYPE_BUDDY_LIST); + /* Now the conversations */ + finch_conversation_init(); + purple_conversations_set_ui_ops(finch_conv_get_ui_ops()); + purple_notify_set_ui_ops(finch_notify_get_ui_ops()); + purple_request_set_ui_ops(finch_request_get_ui_ops()); + purple_xfers_set_ui_ops(finch_xfers_get_ui_ops()); + purple_roomlist_set_ui_ops(finch_roomlist_get_ui_ops()); + finch_media_manager_init(); + gnt_register_action(_("Accounts"), finch_accounts_show_all); + gnt_register_action(_("Buddy List"), finch_blist_show); + gnt_register_action(_("Notifications"), finch_notifications_window_show); + gnt_register_action(_("Debug Window"), finch_debug_window_show); + gnt_register_action(_("File Transfers"), finch_xfer_dialog_show); + gnt_register_action(_("Plugins"), finch_plugins_show_all); + gnt_register_action(_("Room List"), finch_roomlist_show_all); + gnt_register_action(_("Preferences"), finch_prefs_show_all); + gnt_register_action(_("Statuses"), finch_savedstatus_show_all); +finch_ui_stop(G_GNUC_UNUSED PurpleUi *ui) { + purple_accounts_set_ui_ops(NULL); + finch_accounts_uninit(); + purple_connections_set_ui_ops(NULL); + finch_connections_uninit(); + purple_blist_set_ui(G_TYPE_INVALID); + purple_conversations_set_ui_ops(NULL); + finch_conversation_uninit(); + purple_notify_set_ui_ops(NULL); + purple_request_set_ui_ops(NULL); + finch_request_uninit(); + purple_xfers_set_ui_ops(NULL); + finch_roomlist_uninit(); + purple_roomlist_set_ui_ops(NULL); + finch_media_manager_uninit(); + gnt_set_config_dir(NULL); +finch_ui_get_settings_backend(G_GNUC_UNUSED PurpleUi *ui) { + GSettingsBackend *backend = NULL; + config = g_build_filename(purple_config_dir(), "finch3.ini", NULL); + backend = g_keyfile_settings_backend_new(config, "/", NULL); +/****************************************************************************** + * GObject Implementation + *****************************************************************************/ +finch_ui_init(G_GNUC_UNUSED FinchUi *ui) { +finch_ui_class_init(FinchUiClass *klass) { + PurpleUiClass *ui_class = PURPLE_UI_CLASS(klass); + ui_class->prefs_init = finch_ui_prefs_init; + ui_class->start = finch_ui_start; + ui_class->stop = finch_ui_stop; + ui_class->get_settings_backend = finch_ui_get_settings_backend; +/****************************************************************************** + *****************************************************************************/ + "website", "https://pidgin.im", + "support-website", "https://pidgin.im/contact/", + "client-type", "console", --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/finch/finchui.h Mon Oct 31 04:02:09 2022 -0500
@@ -0,0 +1,51 @@
+ * Finch - Universal Text Chat Client + * Copyright (C) Pidgin Developers <devel@pidgin.im> + * Finch 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, see <https://www.gnu.org/licenses/>. +#if !defined(FINCH_GLOBAL_HEADER_INSIDE) && !defined(FINCH_COMPILATION) +# error "only <finch.h> may be included directly" +#define FINCH_TYPE_UI (finch_ui_get_type()) +G_DECLARE_FINAL_TYPE(FinchUi, finch_ui, FINCH, UI, PurpleUi) + * Creates the [class@Purple.Ui] for finch. + * Note: This isn't really useful outside of Finch itself. +PurpleUi *finch_ui_new(void); --- a/finch/gntui.c Mon Oct 31 03:06:44 2022 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,184 +0,0 @@
- * Finch 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 <glib/gi18n-lib.h>
-#include "finchnotifications.h"
-#include "gntroomlist.h"
-finch_history_init(GError **error) {
- PurpleHistoryManager *manager = NULL;
- PurpleHistoryAdapter *adapter = NULL;
- gchar *filename = NULL;
- const gchar *id = NULL;
- manager = purple_history_manager_get_default();
- /* Attempt to create the config directory. */
- g_mkdir_with_parents(purple_config_dir(), 0700);
- filename = g_build_filename(purple_config_dir(), "history.db", NULL);
- adapter = purple_sqlite_history_adapter_new(filename);
- id = purple_history_adapter_get_id(adapter);
- if(!purple_history_manager_register(manager, adapter, error)) {
- g_clear_object(&adapter);
- /* The manager adds a ref to the adapter on registration, so we can remove
- g_clear_object(&adapter);
- return purple_history_manager_set_active(manager, id, error);
-#ifdef _WIN32 /* TODO: don't change it when using FHS under win32 */
- gnt_set_config_dir(purple_config_dir());
- if(!finch_history_init(&error)) {
- g_critical("failed to initialize the history api: %s",
- error != NULL ? error->message : "unknown");
- purple_prefs_add_none("/purple/gnt");
- finch_connections_init();
- purple_connections_set_ui_ops(finch_connections_get_ui_ops());
- /* Initialize the buddy list */
- purple_blist_set_ui(FINCH_TYPE_BUDDY_LIST);
- /* Now the conversations */
- finch_conversation_init();
- purple_conversations_set_ui_ops(finch_conv_get_ui_ops());
- purple_notify_set_ui_ops(finch_notify_get_ui_ops());
- purple_request_set_ui_ops(finch_request_get_ui_ops());
- purple_xfers_set_ui_ops(finch_xfers_get_ui_ops());
- purple_roomlist_set_ui_ops(finch_roomlist_get_ui_ops());
- finch_media_manager_init();
- gnt_register_action(_("Accounts"), finch_accounts_show_all);
- gnt_register_action(_("Buddy List"), finch_blist_show);
- gnt_register_action(_("Notifications"), finch_notifications_window_show);
- gnt_register_action(_("Debug Window"), finch_debug_window_show);
- gnt_register_action(_("File Transfers"), finch_xfer_dialog_show);
- gnt_register_action(_("Plugins"), finch_plugins_show_all);
- gnt_register_action(_("Room List"), finch_roomlist_show_all);
- gnt_register_action(_("Preferences"), finch_prefs_show_all);
- gnt_register_action(_("Statuses"), finch_savedstatus_show_all);
- purple_accounts_set_ui_ops(NULL);
- finch_accounts_uninit();
- purple_connections_set_ui_ops(NULL);
- finch_connections_uninit();
- purple_blist_set_ui(G_TYPE_INVALID);
- purple_conversations_set_ui_ops(NULL);
- finch_conversation_uninit();
- purple_notify_set_ui_ops(NULL);
- purple_request_set_ui_ops(NULL);
- finch_request_uninit();
- purple_xfers_set_ui_ops(NULL);
- finch_roomlist_uninit();
- purple_roomlist_set_ui_ops(NULL);
- finch_media_manager_uninit();
- gnt_set_config_dir(NULL);
--- a/finch/gntui.h Mon Oct 31 03:06:44 2022 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,36 +0,0 @@
- * Finch 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
-#if !defined(FINCH_GLOBAL_HEADER_INSIDE) && !defined(FINCH_COMPILATION)
-# error "only <finch.h> may be included directly"
-void finch_ui_init(void);
-void finch_ui_uninit(void);
--- a/finch/libfinch.c Mon Oct 31 03:06:44 2022 -0500
+++ b/finch/libfinch.c Mon Oct 31 04:02:09 2022 -0500
@@ -26,54 +26,19 @@
#include <glib/gi18n-lib.h>
-#define G_SETTINGS_ENABLE_BACKEND
-#include <gio/gsettingsbackend.h>
#include "package_revision.h"
-finch_get_settings_backend(void) {
- GSettingsBackend *backend = NULL;
- config = g_build_filename(purple_config_dir(), "finch3.ini", NULL);
- backend = g_keyfile_settings_backend_new(config, "/", NULL);
-static PurpleCoreUiOps core_ops = {
- .ui_prefs_init = finch_prefs_init,
- .ui_init = finch_ui_init,
- .get_settings_backend = finch_get_settings_backend,
-static PurpleCoreUiOps *
-gnt_core_get_ui_ops(void)
start_with_debugwin(gpointer null)
@@ -106,7 +71,6 @@
init_libpurple(int argc, char **argv)
- PurpleUiInfo *ui_info = NULL;
gboolean opt_nologin = FALSE;
gboolean opt_version = FALSE;
gboolean opt_debug = FALSE;
@@ -196,14 +160,9 @@
g_timeout_add(0, start_with_debugwin, NULL);
- purple_core_set_ui_ops(gnt_core_get_ui_ops());
purple_idle_set_ui(finch_idle_new());
- ui_info = purple_ui_info_new("finch3", _("Finch"), VERSION,
- "https://developer.pidgin.im", "console");
- if (!purple_core_init(ui_info))
+ if (!purple_core_init(finch_ui_new())) "Initialization of the Purple core failed. Dumping core.\n"
--- a/finch/meson.build Mon Oct 31 03:06:44 2022 -0500
+++ b/finch/meson.build Mon Oct 31 04:02:09 2022 -0500
@@ -79,6 +79,7 @@
@@ -93,7 +94,6 @@
@@ -101,6 +101,7 @@
@@ -115,7 +116,6 @@
--- a/libpurple/core.c Mon Oct 31 03:06:44 2022 -0500
+++ b/libpurple/core.c Mon Oct 31 04:02:09 2022 -0500
@@ -54,26 +54,25 @@
-static PurpleCoreUiOps *_ops = NULL;
static PurpleCore *_core = NULL;
static GSettingsBackend *settings_backend = NULL;
purple_core_print_version(void)
- PurpleUiInfo *ui_info = purple_core_get_ui_info();
+ PurpleUi *ui = purple_core_get_ui(); const gchar *ui_name = NULL;
const gchar *ui_version = NULL;
gchar *ui_full_name = NULL;
- if(PURPLE_IS_UI_INFO(ui_info)) {
- ui_name = purple_ui_info_get_name(ui_info);
- ui_version = purple_ui_info_get_version(ui_info);
+ ui_name = purple_ui_get_name(ui); + ui_version = purple_ui_get_version(ui); @@ -93,11 +92,10 @@
-purple_core_init(PurpleUiInfo *ui_info) {
+purple_core_init(PurpleUi *ui) { - g_return_val_if_fail(PURPLE_IS_UI_INFO(ui_info), FALSE);
+ g_return_val_if_fail(PURPLE_IS_UI(ui), FALSE); g_return_val_if_fail(purple_get_core() == NULL, FALSE);
bindtextdomain(PACKAGE, PURPLE_LOCALEDIR);
@@ -107,11 +105,9 @@
_core = core = g_new0(PurpleCore, 1);
- core->ui_info = ui_info;
- ops = purple_core_get_ui_ops();
/* This monster is to work around a bug that was fixed in glib 2.73.3. Once
* we require glib 2.74.0 this should be removed.
@@ -143,15 +139,12 @@
/* The prefs subsystem needs to be initialized before static protocols
* for protocol prefs to work. */
- settings_backend = ops->get_settings_backend();
+ settings_backend = purple_ui_get_settings_backend(core->ui);
- if (ops->ui_prefs_init != NULL) {
+ purple_ui_prefs_init(core->ui); purple_notification_manager_startup();
@@ -197,8 +190,7 @@
purple_network_discover_my_ip();
- if (ops != NULL && ops->ui_init != NULL)
+ purple_ui_start(core->ui); /* Load the buddy list after UI init */
@@ -211,7 +203,6 @@
PurpleCore *core = purple_get_core();
PurpleCredentialManager *credential_manager = NULL;
PurpleHistoryManager *history_manager = NULL;
@@ -249,9 +240,7 @@
_purple_image_store_uninit();
- ops = purple_core_get_ui_ops();
- if (ops != NULL && ops->quit != NULL)
+ purple_ui_stop(core->ui); /* Everything after prefs_uninit must not try to read any prefs */
g_clear_object(&settings_backend);
@@ -275,7 +264,7 @@
- g_clear_object(&core->ui_info);
+ g_clear_object(&core->ui); @@ -310,19 +299,7 @@
-purple_core_set_ui_ops(PurpleCoreUiOps *ops)
+purple_core_get_ui(void) {
-purple_core_get_ui_ops(void)
-purple_core_get_ui_info(void) {
--- a/libpurple/core.h Mon Oct 31 03:06:44 2022 -0500
+++ b/libpurple/core.h Mon Oct 31 04:02:09 2022 -0500
@@ -29,7 +29,7 @@
-#include <libpurple/purplecoreuiops.h>
+#include <libpurple/purpleui.h> typedef struct PurpleCore PurpleCore;
@@ -37,7 +37,7 @@
- * @ui_info: (transfer full): The [class@UiInfo] of the UI using the core.
+ * @ui: (transfer full): The [class@Purple.Ui] of the UI using the core. * Initializes the core of purple.
@@ -45,7 +45,7 @@
* Returns: %TRUE if successful, or %FALSE otherwise.
-gboolean purple_core_init(PurpleUiInfo *ui_info);
+gboolean purple_core_init(PurpleUi *ui); @@ -112,30 +112,13 @@
gpointer purple_core_get_settings_backend(void);
- * purple_core_set_ui_ops:
- * @ops: A UI ops structure for the core.
- * Sets the UI ops for the core.
-void purple_core_set_ui_ops(PurpleCoreUiOps *ops);
- * purple_core_get_ui_ops:
- * Returns the UI ops for the core.
+ * Gets the [class@Purple.Ui] that is running. - * Returns: The core's UI ops structure.
+ * Returns: (transfer none): The ui. -PurpleCoreUiOps *purple_core_get_ui_ops(void);
- * purple_core_get_ui_info:
- * Returns a #PurpleUiInfo that contains information about the user interface.
- * Returns: (transfer none): A #PurpleUiInfo instance.
-PurpleUiInfo *purple_core_get_ui_info(void);
+PurpleUi *purple_core_get_ui(void); --- a/libpurple/meson.build Mon Oct 31 03:06:44 2022 -0500
+++ b/libpurple/meson.build Mon Oct 31 04:02:09 2022 -0500
@@ -50,7 +50,6 @@
'purpleconversationmanager.c',
'purpleconversationuiops.c',
'purplecredentialmanager.c',
'purplecredentialprovider.c',
@@ -88,7 +87,7 @@
'purplesqlitehistoryadapter.c',
'purplewhiteboardmanager.c',
'purplewhiteboarduiops.c',
@@ -155,7 +154,6 @@
'purpleconversationmanager.h',
'purpleconversationuiops.h',
'purplecredentialmanager.h',
'purplecredentialprovider.h',
@@ -194,7 +192,7 @@
'purplesqlitehistoryadapter.h',
'purplewhiteboardmanager.h',
--- a/libpurple/plugins/kwallet/purplekwallet.cpp Mon Oct 31 03:06:44 2022 -0500
+++ b/libpurple/plugins/kwallet/purplekwallet.cpp Mon Oct 31 04:02:09 2022 -0500
@@ -53,12 +53,12 @@
*****************************************************************************/
purple_kwallet_get_ui_name(void) {
- PurpleUiInfo *ui_info = NULL;
- ui_info = purple_core_get_ui_info();
- if(PURPLE_IS_UI_INFO(ui_info)) {
- ui_name = purple_ui_info_get_name(ui_info);
+ ui = purple_core_get_ui(); + ui_name = purple_ui_get_name(ui); --- a/libpurple/protocols/jabber/bosh.c Mon Oct 31 03:06:44 2022 -0500
+++ b/libpurple/protocols/jabber/bosh.c Mon Oct 31 04:02:09 2022 -0500
@@ -65,13 +65,13 @@
- PurpleUiInfo *ui_info = purple_core_get_ui_info();
+ PurpleUi *ui = purple_core_get_ui(); const gchar *ui_name = NULL;
const gchar *ui_version = NULL;
- if(PURPLE_IS_UI_INFO(ui_info)) {
- ui_name = purple_ui_info_get_name(ui_info);
- ui_version = purple_ui_info_get_version(ui_info);
+ ui_name = purple_ui_get_name(ui); + ui_version = purple_ui_get_version(ui); --- a/libpurple/protocols/jabber/iq.c Mon Oct 31 03:06:44 2022 -0500
+++ b/libpurple/protocols/jabber/iq.c Mon Oct 31 04:02:09 2022 -0500
@@ -224,7 +224,7 @@
if(type == JABBER_IQ_GET) {
const char *ui_name = NULL, *ui_version = NULL;
iq = jabber_iq_new_query(js, JABBER_IQ_RESULT, "jabber:iq:version");
@@ -234,11 +234,11 @@
query = purple_xmlnode_get_child(iq->node, "query");
- ui_info = purple_core_get_ui_info();
+ ui = purple_core_get_ui(); - if(PURPLE_IS_UI_INFO(ui_info)) {
- ui_name = purple_ui_info_get_name(ui_info);
- ui_version = purple_ui_info_get_version(ui_info);
+ ui_name = purple_ui_get_name(ui); + ui_version = purple_ui_get_version(ui); if(NULL != ui_name && NULL != ui_version) {
--- a/libpurple/protocols/jabber/jabber.c Mon Oct 31 03:06:44 2022 -0500
+++ b/libpurple/protocols/jabber/jabber.c Mon Oct 31 04:02:09 2022 -0500
@@ -3679,7 +3679,7 @@
- PurpleUiInfo *ui_info = purple_core_get_ui_info();
+ PurpleUi *ui = purple_core_get_ui(); const gchar *type = "pc"; /* default client type, if unknown or
@@ -3713,7 +3713,7 @@
jabber_cmds = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, cmds_free_func);
- ui_type = ui_info ? purple_ui_info_get_client_type(ui_info) : NULL;
+ ui_type = ui ? purple_ui_get_client_type(ui) : NULL; if (purple_strequal(ui_type, "pc") ||
purple_strequal(ui_type, "console") ||
@@ -3725,8 +3725,8 @@
- ui_name = purple_ui_info_get_name(ui_info);
+ ui_name = purple_ui_get_name(ui); --- a/libpurple/purplecoreuiops.c Mon Oct 31 03:06:44 2022 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,48 +0,0 @@
- * Purple - Internet Messaging Library
- * Copyright (C) Pidgin Developers <devel@pidgin.im>
- * 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 "purplecoreuiops.h"
-static PurpleCoreUiOps *
-purple_core_ui_ops_copy(PurpleCoreUiOps *ops)
- PurpleCoreUiOps *ops_new;
- g_return_val_if_fail(ops != NULL, NULL);
- ops_new = g_new(PurpleCoreUiOps, 1);
-purple_core_ui_ops_get_type(void)
- type = g_boxed_type_register_static("PurpleCoreUiOps",
- (GBoxedCopyFunc)purple_core_ui_ops_copy,
- (GBoxedFreeFunc)g_free);
--- a/libpurple/purplecoreuiops.h Mon Oct 31 03:06:44 2022 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,75 +0,0 @@
- * Purple - Internet Messaging Library
- * Copyright (C) Pidgin Developers <devel@pidgin.im>
- * 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/>.
-#if !defined(PURPLE_GLOBAL_HEADER_INSIDE) && !defined(PURPLE_COMPILATION)
-# error "only <purple.h> may be included directly"
-#ifndef PURPLE_CORE_UIOPS_H
-#define PURPLE_CORE_UIOPS_H
-#include <glib-object.h>
-#include <libpurple/purpleuiinfo.h>
-#define PURPLE_TYPE_CORE_UI_OPS (purple_core_ui_ops_get_type())
-typedef struct _PurpleCoreUiOps PurpleCoreUiOps;
- * @ui_prefs_init: Called just after the preferences subsystem is initialized;
- * the UI could use this callback to add some preferences it
- * needs to be in place when other subsystems are initialized.
- * @ui_init: Called after all of libpurple has been initialized. The UI
- * should use this hook to set all other necessary
- * <link linkend="chapter-ui-ops"><literal>UiOps structures</literal></link>.
- * @quit: Called after most of libpurple has been uninitialized.
- * @get_settings_backend: Called to get the [class@Gio.SettingsBackend] that
- * Callbacks that fire at different points of the initialization and teardown
- * of libpurple, along with a hook to return descriptive information about the
-struct _PurpleCoreUiOps {
- void (*ui_prefs_init)(void);
- gpointer (*get_settings_backend)(void);
- * purple_core_ui_ops_get_type:
- * Returns: The #GType for the #PurpleCoreUiOps boxed structure.
-GType purple_core_ui_ops_get_type(void);
-#endif /* PURPLE_CORE_UIOPS_H */
--- a/libpurple/purplepath.c Mon Oct 31 03:06:44 2022 -0500
+++ b/libpurple/purplepath.c Mon Oct 31 04:02:09 2022 -0500
@@ -19,7 +19,7 @@
#include <libpurple/purplepath.h>
#include <libpurple/core.h>
-#include <libpurple/purpleuiinfo.h>
+#include <libpurple/purpleui.h> # include "win32/win32dep.h"
@@ -43,10 +43,10 @@
- PurpleUiInfo *info = purple_core_get_ui_info();
+ PurpleUi *ui = purple_core_get_ui(); - id = purple_ui_info_get_id(info);
+ id = purple_ui_get_id(ui); --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/purpleui.c Mon Oct 31 04:02:09 2022 -0500
@@ -0,0 +1,425 @@
+ * Purple - Internet Messaging Library + * Copyright (C) Pidgin Developers <devel@pidgin.im> + * 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/>. +static GParamSpec *properties[N_PROPERTIES] = {NULL,}; +G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE(PurpleUi, purple_ui, G_TYPE_OBJECT) +/****************************************************************************** + *****************************************************************************/ +purple_ui_set_id(PurpleUi *ui, const char *id) { + PurpleUiPrivate *priv = NULL; + g_return_if_fail(PURPLE_IS_UI(ui)); + priv = purple_ui_get_instance_private(ui); + priv->id = g_strdup(id); + g_object_notify_by_pspec(G_OBJECT(ui), properties[PROP_ID]); +purple_ui_set_name(PurpleUi *ui, const char *name) { + PurpleUiPrivate *priv = NULL; + g_return_if_fail(PURPLE_IS_UI(ui)); + priv = purple_ui_get_instance_private(ui); + priv->name = g_strdup(name); + g_object_notify_by_pspec(G_OBJECT(ui), properties[PROP_NAME]); +purple_ui_set_version(PurpleUi *ui, const char *version) { + PurpleUiPrivate *priv = NULL; + g_return_if_fail(PURPLE_IS_UI(ui)); + priv = purple_ui_get_instance_private(ui); + priv->version = g_strdup(version); + g_object_notify_by_pspec(G_OBJECT(ui), properties[PROP_VERSION]); +purple_ui_set_website(PurpleUi *ui, const char *website) { + PurpleUiPrivate *priv = NULL; + g_return_if_fail(PURPLE_IS_UI(ui)); + priv = purple_ui_get_instance_private(ui); + priv->website = g_strdup(website); + g_object_notify_by_pspec(G_OBJECT(ui), properties[PROP_WEBSITE]); +purple_ui_set_support_website(PurpleUi *ui, const char *support_website) { + PurpleUiPrivate *priv = NULL; + g_return_if_fail(PURPLE_IS_UI(ui)); + priv = purple_ui_get_instance_private(ui); + g_free(priv->support_website); + priv->support_website = g_strdup(support_website); + g_object_notify_by_pspec(G_OBJECT(ui), properties[PROP_SUPPORT_WEBSITE]); +purple_ui_set_client_type(PurpleUi *ui, const char *client_type) { + PurpleUiPrivate *priv = NULL; + g_return_if_fail(PURPLE_IS_UI(ui)); + priv = purple_ui_get_instance_private(ui); + g_free(priv->client_type); + priv->client_type = g_strdup(client_type); + g_object_notify_by_pspec(G_OBJECT(ui), properties[PROP_CLIENT_TYPE]); +/****************************************************************************** + * GObject Implementation + *****************************************************************************/ +purple_ui_get_property(GObject *obj, guint param_id, GValue *value, + PurpleUi *ui = PURPLE_UI(obj); + g_value_set_string(value, purple_ui_get_id(ui)); + g_value_set_string(value, purple_ui_get_name(ui)); + g_value_set_string(value, purple_ui_get_version(ui)); + g_value_set_string(value, purple_ui_get_website(ui)); + case PROP_SUPPORT_WEBSITE: + g_value_set_string(value, purple_ui_get_support_website(ui)); + g_value_set_string(value, purple_ui_get_client_type(ui)); + G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec); +purple_ui_set_property(GObject *obj, guint param_id, const GValue *value, + PurpleUi *ui = PURPLE_UI(obj); + purple_ui_set_id(ui, g_value_get_string(value)); + purple_ui_set_name(ui, g_value_get_string(value)); + purple_ui_set_version(ui, g_value_get_string(value)); + purple_ui_set_website(ui, g_value_get_string(value)); + case PROP_SUPPORT_WEBSITE: + purple_ui_set_support_website(ui, g_value_get_string(value)); + purple_ui_set_client_type(ui, g_value_get_string(value)); + G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec); +purple_ui_finalize(GObject *obj) { + PurpleUiPrivate *priv = purple_ui_get_instance_private(PURPLE_UI(obj)); + g_clear_pointer(&priv->id, g_free); + g_clear_pointer(&priv->name, g_free); + g_clear_pointer(&priv->version, g_free); + g_clear_pointer(&priv->website, g_free); + g_clear_pointer(&priv->support_website, g_free); + g_clear_pointer(&priv->client_type, g_free); + G_OBJECT_CLASS(purple_ui_parent_class)->finalize(obj); +purple_ui_init(G_GNUC_UNUSED PurpleUi *ui) { +purple_ui_class_init(PurpleUiClass *klass) { + GObjectClass *obj_class = G_OBJECT_CLASS(klass); + obj_class->get_property = purple_ui_get_property; + obj_class->set_property = purple_ui_set_property; + obj_class->finalize = purple_ui_finalize; + * The identifier of the user interface. This is used in places where a + * constant string is need to represent the user interface. + properties[PROP_ID] = g_param_spec_string( + "The identifier of the user interface", + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); + * The name of the user interface. This is used in places where it will be + * displayed to users, so it should be translated. + properties[PROP_NAME] = g_param_spec_string( + "The name of the user interface", + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); + * The version number of the user interface. + properties[PROP_VERSION] = g_param_spec_string( + "The version of the user interface", + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); + * The website of the user interface. This should be the main website. + properties[PROP_WEBSITE] = g_param_spec_string( + "The website of the user interface", + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); + * PurpleUi:support-website: + * The support website of the user interface. This should link to a page + * that specifically directs users how to get support for your user + properties[PROP_SUPPORT_WEBSITE] = g_param_spec_string( + "support-website", "support-website", + "The support website of the user interface", + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); + * PurpleUi:client-type: + * The client type of the user interface. Common values include `bot`, + * `console`, `mobile`, `pc`, `web`, etc. + properties[PROP_CLIENT_TYPE] = g_param_spec_string( + "client-type", "client-type", + "The client type of the user interface", + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); + g_object_class_install_properties(obj_class, N_PROPERTIES, properties); +/****************************************************************************** + *****************************************************************************/ +purple_ui_get_id(PurpleUi *ui) { + PurpleUiPrivate *priv = NULL; + g_return_val_if_fail(PURPLE_IS_UI(ui), NULL); + priv = purple_ui_get_instance_private(ui); +purple_ui_get_name(PurpleUi *ui) { + PurpleUiPrivate *priv = NULL; + g_return_val_if_fail(PURPLE_IS_UI(ui), NULL); + priv = purple_ui_get_instance_private(ui); +purple_ui_get_version(PurpleUi *ui) { + PurpleUiPrivate *priv = NULL; + g_return_val_if_fail(PURPLE_IS_UI(ui), NULL); + priv = purple_ui_get_instance_private(ui); +purple_ui_get_website(PurpleUi *ui) { + PurpleUiPrivate *priv = NULL; + g_return_val_if_fail(PURPLE_IS_UI(ui), NULL); + priv = purple_ui_get_instance_private(ui); +purple_ui_get_support_website(PurpleUi *ui) { + PurpleUiPrivate *priv = NULL; + g_return_val_if_fail(PURPLE_IS_UI(ui), NULL); + priv = purple_ui_get_instance_private(ui); + return priv->support_website; +purple_ui_get_client_type(PurpleUi *ui) { + PurpleUiPrivate *priv = NULL; + g_return_val_if_fail(PURPLE_IS_UI(ui), NULL); + priv = purple_ui_get_instance_private(ui); + return priv->client_type; +purple_ui_prefs_init(PurpleUi *ui) { + PurpleUiClass *klass = NULL; + g_return_if_fail(PURPLE_IS_UI(ui)); + klass = PURPLE_UI_GET_CLASS(ui); + if(klass != NULL && klass->prefs_init != NULL) { +purple_ui_start(PurpleUi *ui) { + PurpleUiClass *klass = NULL; + g_return_if_fail(PURPLE_IS_UI(ui)); + klass = PURPLE_UI_GET_CLASS(ui); + if(klass != NULL && klass->start != NULL) { +purple_ui_stop(PurpleUi *ui) { + PurpleUiClass *klass = NULL; + g_return_if_fail(PURPLE_IS_UI(ui)); + klass = PURPLE_UI_GET_CLASS(ui); + if(klass != NULL && klass->stop != NULL) { +purple_ui_get_settings_backend(PurpleUi *ui) { + PurpleUiClass *klass = NULL; + g_return_val_if_fail(PURPLE_IS_UI(ui), NULL); + klass = PURPLE_UI_GET_CLASS(ui); + if(klass != NULL && klass->get_settings_backend != NULL) { + return klass->get_settings_backend(ui); --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/purpleui.h Mon Oct 31 04:02:09 2022 -0500
@@ -0,0 +1,201 @@
+ * Purple - Internet Messaging Library + * Copyright (C) Pidgin Developers <devel@pidgin.im> + * 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/>. +#if !defined(PURPLE_GLOBAL_HEADER_INSIDE) && !defined(PURPLE_COMPILATION) +# error "only <pidgin.h> may be included directly" +#include <glib-object.h> +#define PURPLE_TYPE_UI (purple_ui_get_type()) +G_DECLARE_DERIVABLE_TYPE(PurpleUi, purple_ui, PURPLE, UI, GObject) + * An abstract class representing a user interface. All user interfaces must + * create a subclass of this and pass it to [func@Purple.Core.init]. + * @prefs_init: This function is called to initialize the ui's preferences. + * This is slowly being phased out for @get_settings_backend, but + * @start: Called when libpurple is done with its initialization when the user + * interface should start telling libpurple about the rest of the user + * interface's interfaces. + * @stop: Called after most of libpurple has been uninitialized. + * @get_settings_backend: Called to get the [class@Gio.SettingsBackend] that + * The base class for all user interfaces which is used to identify themselves + * to libpurple when calling [func@Purple.core_init]. + void (*prefs_init)(PurpleUi *ui); + void (*start)(PurpleUi *ui); + void (*stop)(PurpleUi *ui); + gpointer (*get_settings_backend)(PurpleUi *ui); + * Gets the id for the user interface. + * Returns: id of the user interface. +const char *purple_ui_get_id(PurpleUi *ui); + * Gets the name of @ui. This should be translated. + * Returns: The name of the user interface. +const char *purple_ui_get_name(PurpleUi *ui); + * purple_ui_get_version: + * Gets the version of @ui. + * Returns: The version of the user interface. +const char *purple_ui_get_version(PurpleUi *ui); + * purple_ui_get_website: + * Gets the website from @ui. + * Returns: (nullable): The website URI of the user interface or %NULL. +const char *purple_ui_get_website(PurpleUi *ui); + * purple_ui_get_support_website: + * Gets the support website from @ui. + * Returns: (nullable): The support website URI of the user interface or %NULL. +const char *purple_ui_get_support_website(PurpleUi *ui); + * purple_ui_get_client_type: + * Gets the client type from @ui. + * Returns: (transfer none): The client type of the user interface. +const char *purple_ui_get_client_type(PurpleUi *ui); + * purple_ui_prefs_init: + * Tells @ui that it should be initializing its preferences. + * Note: This should only be called by libpurple. +void purple_ui_prefs_init(PurpleUi *ui); + * Tells @ui that libpurple is done initializing and that @ui should continue + * Note: This should only be called by libpurple. +void purple_ui_start(PurpleUi *ui); + * Tells @ui that libpurple is done shutting down. + * Note: This should only be called by libpurple. +void purple_ui_stop(PurpleUi *ui); + * purple_ui_get_settings_backend: + * Get the [class@Gio.SettingsBackend] that @ui is using for its settings. + * Note: This should only be called by libpurple. + * Returns: (transfer full): The settings that @ui is using. +gpointer purple_ui_get_settings_backend(PurpleUi *ui); +#endif /* PURPLE_UI_H */ --- a/libpurple/purpleuiinfo.c Mon Oct 31 03:06:44 2022 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,326 +0,0 @@
- * Purple 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 "purpleuiinfo.h"
- gchar *support_website;
-static GParamSpec *properties[N_PROPERTIES] = { NULL, };
-/******************************************************************************
- *****************************************************************************/
-purple_ui_info_set_id(PurpleUiInfo *info, const gchar *id) {
- info->id = g_strdup(id);
-purple_ui_info_set_name(PurpleUiInfo *info, const gchar *name) {
- info->name = g_strdup(name);
-purple_ui_info_set_version(PurpleUiInfo *info, const gchar *version) {
- info->version = g_strdup(version);
-purple_ui_info_set_website(PurpleUiInfo *info, const gchar *website) {
- info->website = g_strdup(website);
-purple_ui_info_set_support_website(PurpleUiInfo *info,
- const gchar *support_website)
- g_free(info->support_website);
- info->support_website = g_strdup(support_website);
-purple_ui_info_set_client_type(PurpleUiInfo *info, const gchar *client_type) {
- g_free(info->client_type);
- info->client_type = g_strdup(client_type);
-/******************************************************************************
- * GObject Implementation
- *****************************************************************************/
-G_DEFINE_TYPE(PurpleUiInfo, purple_ui_info, G_TYPE_OBJECT);
-purple_ui_info_get_property(GObject *obj, guint param_id, GValue *value,
- PurpleUiInfo *info = PURPLE_UI_INFO(obj);
- g_value_set_string(value, purple_ui_info_get_id(info));
- g_value_set_string(value, purple_ui_info_get_name(info));
- g_value_set_string(value, purple_ui_info_get_version(info));
- g_value_set_string(value, purple_ui_info_get_website(info));
- case PROP_SUPPORT_WEBSITE:
- g_value_set_string(value, purple_ui_info_get_support_website(info));
- g_value_set_string(value, purple_ui_info_get_client_type(info));
- G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
-purple_ui_info_set_property(GObject *obj, guint param_id, const GValue *value,
- PurpleUiInfo *info = PURPLE_UI_INFO(obj);
- purple_ui_info_set_id(info, g_value_get_string(value));
- purple_ui_info_set_name(info, g_value_get_string(value));
- purple_ui_info_set_version(info, g_value_get_string(value));
- purple_ui_info_set_website(info, g_value_get_string(value));
- case PROP_SUPPORT_WEBSITE:
- purple_ui_info_set_support_website(info,
- g_value_get_string(value));
- purple_ui_info_set_client_type(info, g_value_get_string(value));
- G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
-purple_ui_info_init(PurpleUiInfo *info) {
-purple_ui_info_finalize(GObject *obj) {
- PurpleUiInfo *info = PURPLE_UI_INFO(obj);
- g_clear_pointer(&info->id, g_free);
- g_clear_pointer(&info->name, g_free);
- g_clear_pointer(&info->version, g_free);
- g_clear_pointer(&info->website, g_free);
- g_clear_pointer(&info->support_website, g_free);
- g_clear_pointer(&info->client_type, g_free);
- G_OBJECT_CLASS(purple_ui_info_parent_class)->finalize(obj);
-purple_ui_info_class_init(PurpleUiInfoClass *klass) {
- GObjectClass *obj_class = G_OBJECT_CLASS(klass);
- obj_class->get_property = purple_ui_info_get_property;
- obj_class->set_property = purple_ui_info_set_property;
- obj_class->finalize = purple_ui_info_finalize;
- * The identifier of the user interface.
- g_param_spec_string("id", "id", "The identifier of the user interface",
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_STATIC_STRINGS);
- * The name of the user interface.
- properties[PROP_NAME] =
- g_param_spec_string("name", "name", "The name of the user interface",
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_STATIC_STRINGS);
- * PurpleUiInfo:version:
- * The version of the user interface.
- properties[PROP_VERSION] =
- g_param_spec_string("version", "version",
- "The version of the user interface",
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_STATIC_STRINGS);
- * PurpleUiInfo:website:
- * The website of the user interface.
- properties[PROP_WEBSITE] =
- g_param_spec_string("website", "website",
- "The website of the user interface",
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_STATIC_STRINGS);
- * PurpleUiInfo:support-website:
- * The support website of the user interface.
- properties[PROP_SUPPORT_WEBSITE] =
- g_param_spec_string("support-website", "support-website",
- "The support website of the user interface",
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_STATIC_STRINGS);
- * PurpleUiInfo:client-type:
- * The client type of the user interface.
- properties[PROP_CLIENT_TYPE] =
- g_param_spec_string("client-type", "client-type",
- "The client type of the user interface",
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_STATIC_STRINGS);
- g_object_class_install_properties(obj_class, N_PROPERTIES, properties);
-/******************************************************************************
- *****************************************************************************/
-purple_ui_info_new(const gchar *id, const gchar *name,
- const gchar *version, const gchar *website,
- const gchar *support_website, const gchar *client_type)
- return g_object_new(PURPLE_TYPE_UI_INFO,
- "support-website", support_website,
- "client-type", client_type,
-purple_ui_info_get_id(PurpleUiInfo *info) {
- g_return_val_if_fail(PURPLE_IS_UI_INFO(info), NULL);
-purple_ui_info_get_name(PurpleUiInfo *info) {
- g_return_val_if_fail(PURPLE_IS_UI_INFO(info), NULL);
-purple_ui_info_get_version(PurpleUiInfo *info) {
- g_return_val_if_fail(PURPLE_IS_UI_INFO(info), NULL);
-purple_ui_info_get_website(PurpleUiInfo *info) {
- g_return_val_if_fail(PURPLE_IS_UI_INFO(info), NULL);
-purple_ui_info_get_support_website(PurpleUiInfo *info) {
- g_return_val_if_fail(PURPLE_IS_UI_INFO(info), NULL);
- return info->support_website;
-purple_ui_info_get_client_type(PurpleUiInfo *info) {
- g_return_val_if_fail(PURPLE_IS_UI_INFO(info), NULL);
- return info->client_type;
--- a/libpurple/purpleuiinfo.h Mon Oct 31 03:06:44 2022 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,143 +0,0 @@
- * Purple - Internet Messaging Library
- * Copyright (C) Pidgin Developers <devel@pidgin.im>
- * Purple 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, see <https://www.gnu.org/licenses/>.
-#if !defined(PURPLE_GLOBAL_HEADER_INSIDE) && !defined(PURPLE_COMPILATION)
-# error "only <purple.h> may be included directly"
-#ifndef PURPLE_UI_INFO_H
-#define PURPLE_UI_INFO_H
-#include <glib-object.h>
-#define PURPLE_TYPE_UI_INFO (purple_ui_info_get_type())
- * #PurpleUiInfo keeps track of basic information about the user interface.
-G_DECLARE_FINAL_TYPE(PurpleUiInfo, purple_ui_info, PURPLE, UI_INFO, GObject)
- * @name: The name, which will be displayed.
- * @version: The version.
- * @website: The website.
- * @support_website: The support website.
- * @client_type: The client type.
- * Creates a new #PurpleUiInfo with the given values. If you only want to set
- * a few of these, you should use g_object_new() directly.
- * Returns: (transfer full): The newly created #PurpleUiInfo instance.
-PurpleUiInfo *purple_ui_info_new(const gchar *id,
- const gchar *support_website,
- const gchar *client_type);
- * purple_ui_info_get_id:
- * Gets the identifier from @info.
- * Returns: The identifier from @info.
-const gchar *purple_ui_info_get_id(PurpleUiInfo *info);
- * purple_ui_info_get_name:
- * @info: The #PurpleUiInfo instance.
- * Gets the name from @info.
- * Returns: The name from @info.
-const gchar *purple_ui_info_get_name(PurpleUiInfo *info);
- * purple_ui_info_get_version:
- * @info: The #PurpleUiInfo instance.
- * Gets the version from @info.
- * Returns: The version from @info.
-const gchar *purple_ui_info_get_version(PurpleUiInfo *info);
- * purple_ui_info_get_website:
- * @info: The #PurpleUiInfo instance.
- * Gets the website from @info.
- * Returns: The website for @info.
-const gchar *purple_ui_info_get_website(PurpleUiInfo *info);
- * purple_ui_info_get_support_website:
- * @info: The #PurpleUiInfo instance.
- * Gets the support website from @info.
- * Returns: The support website from @info.
-const gchar *purple_ui_info_get_support_website(PurpleUiInfo *info);
- * purple_ui_info_get_client_type:
- * @info: The #PurpleUiInfo instance.
- * Gets the client type from @info. For example: 'bot', 'console', 'mobile',
- * Returns: The client type of @info.
-const gchar *purple_ui_info_get_client_type(PurpleUiInfo *info);
-#endif /* PURPLE_UI_INFO_H */
--- a/libpurple/tests/test_ui.c Mon Oct 31 03:06:44 2022 -0500
+++ b/libpurple/tests/test_ui.c Mon Oct 31 04:02:09 2022 -0500
@@ -58,21 +58,51 @@
.write_conv = test_write_conv
+/****************************************************************************** + * PurpleUi Implementation + *****************************************************************************/ +G_DECLARE_FINAL_TYPE(TestPurpleUi, test_purple_ui, TEST_PURPLE, UI, PurpleUi) +G_DEFINE_TYPE(TestPurpleUi, test_purple_ui, PURPLE_TYPE_UI)
+test_purple_ui_start(G_GNUC_UNUSED PurpleUi *ui) { purple_conversations_set_ui_ops(&test_conv_uiops);
-test_ui_get_settings_backend(void) {
+test_purple_ui_get_settings_backend(G_GNUC_UNUSED PurpleUi *ui) { return g_memory_settings_backend_new();
-static PurpleCoreUiOps test_core_uiops = {
- .ui_init = test_ui_init,
- .get_settings_backend = test_ui_get_settings_backend,
+test_purple_ui_init(G_GNUC_UNUSED TestPurpleUi *ui) { +test_purple_ui_class_init(TestPurpleUiClass *klass) { + PurpleUiClass *ui_class = PURPLE_UI_CLASS(klass); + ui_class->start = test_purple_ui_start; + ui_class->get_settings_backend = test_purple_ui_get_settings_backend; +test_purple_ui_new(void) { + test_purple_ui_get_type(), + "website", PURPLE_WEBSITE, + "support-website", PURPLE_WEBSITE, test_ui_init_history(GError **error) {
@@ -101,7 +131,7 @@
test_ui_purple_init(void) {
- PurpleUiInfo *ui_info = NULL;
@@ -116,21 +146,12 @@
/* set the magic PURPLE_PLUGINS_SKIP environment variable */
g_setenv("PURPLE_PLUGINS_SKIP", "1", TRUE);
- /* Set the core-uiops, which is used to
- * - initialize the ui specific preferences.
- * - initialize the debug ui.
- * - initialize the ui components for all the modules.
- * - uninitialize the ui components for all the modules when the core terminates.
- purple_core_set_ui_ops(&test_core_uiops);
- ui_info = purple_ui_info_new("test", "Test-UI", VERSION, PURPLE_WEBSITE,
- PURPLE_WEBSITE, "test");
+ ui = test_purple_ui_new(); /* Now that all the essential stuff has been set, let's try to init the core. It's
* necessary to provide a non-NULL name for the current ui to the core. This name
* is used by stuff that depends on this ui, for example the ui-specific plugins. */
- if (!purple_core_init(ui_info)) {
+ if (!purple_core_init(ui)) { /* Initializing the core failed. Terminate. */
"libpurple initialization failed. Dumping core.\n"
--- a/pidgin/gtkconv.h Mon Oct 31 03:06:44 2022 -0500
+++ b/pidgin/gtkconv.h Mon Oct 31 04:02:09 2022 -0500
@@ -26,6 +26,8 @@
#ifndef _PIDGIN_CONVERSATION_H_
#define _PIDGIN_CONVERSATION_H_
typedef struct _PidginConversation PidginConversation;
--- a/pidgin/libpidgin.c Mon Oct 31 03:06:44 2022 -0500
+++ b/pidgin/libpidgin.c Mon Oct 31 04:02:09 2022 -0500
@@ -30,31 +30,12 @@
#include <glib/gi18n-lib.h>
-#define G_SETTINGS_ENABLE_BACKEND
-#include <gio/gsettingsbackend.h>
-#include "gtkroomlist.h"
-#include "gtkwhiteboard.h"
#include "pidginapplication.h"
-#include "pidgindebug.h"
-#include "pidginplugininfo.h"
-#include "pidginprefs.h"
-#include "pidginprivate.h"
@@ -154,181 +135,6 @@
-purple_ui_add_protocol_theme_paths(PurpleProtocol *protocol) {
- GdkDisplay *display = NULL;
- GtkIconTheme *theme = NULL;
- const gchar *path = NULL;
- display = gdk_display_get_default();
- theme = gtk_icon_theme_get_for_display(display);
- path = purple_protocol_get_icon_search_path(protocol);
- gtk_icon_theme_add_search_path(theme, path);
- path = purple_protocol_get_icon_resource_path(protocol);
- gtk_icon_theme_add_resource_path(theme, path);
-purple_ui_protocol_foreach_theme_cb(PurpleProtocol *protocol, gpointer data) {
- purple_ui_add_protocol_theme_paths(protocol);
-purple_ui_protocol_registered_cb(PurpleProtocolManager *manager,
- PurpleProtocol *protocol)
- purple_ui_add_protocol_theme_paths(protocol);
-pidgin_history_init(GError **error) {
- PurpleHistoryManager *manager = NULL;
- PurpleHistoryAdapter *adapter = NULL;
- gchar *filename = NULL;
- const gchar *id = NULL;
- manager = purple_history_manager_get_default();
- /* Attempt to create the config_dir. We don't care about the result as the
- * logging adapter will fail with a better error than us failing to create
- g_mkdir_with_parents(purple_config_dir(), 0700);
- filename = g_build_filename(purple_config_dir(), "history.db", NULL);
- adapter = purple_sqlite_history_adapter_new(filename);
- id = purple_history_adapter_get_id(adapter);
- if(!purple_history_manager_register(manager, adapter, error)) {
- g_clear_object(&adapter);
- /* The manager adds a ref to the adapter on registration, so we can remove
- g_clear_object(&adapter);
- return purple_history_manager_set_active(manager, id, error);
- PurpleProtocolManager *protocol_manager = NULL;
- GdkDisplay *display = NULL;
- GtkIconTheme *theme = NULL;
- display = gdk_display_get_default();
- theme = gtk_icon_theme_get_for_display(display);
- path = g_build_filename(PURPLE_DATADIR, "pidgin", "icons", NULL);
- gtk_icon_theme_add_search_path(theme, path);
- /* Add a callback for when a protocol is registered to add its icon paths
- * if it was found after initial startup.
- protocol_manager = purple_protocol_manager_get_default();
- g_signal_connect(protocol_manager, "registered",
- G_CALLBACK(purple_ui_protocol_registered_cb), NULL);
- /* Add the icon paths for all the protocols that libpurple found at start
- purple_protocol_manager_foreach(protocol_manager,
- purple_ui_protocol_foreach_theme_cb, NULL);
- if(!pidgin_history_init(&error)) {
- g_critical("failed to initialize the history api: %s",
- error != NULL ? error->message : "unknown");
- /* Set the UI operation structures. */
- purple_xfers_set_ui_ops(pidgin_xfers_get_ui_ops());
- purple_blist_set_ui(PIDGIN_TYPE_BUDDY_LIST);
- purple_notify_set_ui_ops(pidgin_notify_get_ui_ops());
- purple_request_set_ui_ops(pidgin_request_get_ui_ops());
- purple_connections_set_ui_ops(pidgin_connections_get_ui_ops());
- purple_whiteboard_set_ui_ops(pidgin_whiteboard_get_ui_ops());
- purple_idle_set_ui(pidgin_idle_new());
- pidgin_accounts_init();
- pidgin_connection_init();
- pidgin_conversations_init();
- pidgin_commands_init();
- pidgin_roomlist_init();
- /* Be sure to close all windows that are not attached to anything
- * (e.g., the debug window), or they may access things after they are
- pidgin_notify_uninit();
- pidgin_commands_uninit();
- pidgin_conversations_uninit();
- pidgin_request_uninit();
- pidgin_connection_uninit();
- pidgin_accounts_uninit();
- pidgin_debug_window_hide();
- /* and end it all... */
- g_application_quit(g_application_get_default());
-pidgin_get_settings_backend(void) {
- GSettingsBackend *backend = NULL;
- config = g_build_filename(purple_config_dir(), "pidgin3.ini", NULL);
- backend = g_keyfile_settings_backend_new(config, "/", NULL);
-static PurpleCoreUiOps core_ops = {
- .ui_prefs_init = pidgin_prefs_init,
- .ui_init = pidgin_ui_init,
- .get_settings_backend = pidgin_get_settings_backend,
-pidgin_core_get_ui_ops(void)
pidgin_setup_error_handler(void)
--- a/pidgin/meson.build Mon Oct 31 03:06:44 2022 -0500
+++ b/pidgin/meson.build Mon Oct 31 04:02:09 2022 -0500
@@ -61,6 +61,7 @@
'pidginstatusprimitivechooser.c',
'pidginstatusprimitivestore.c',
'prefs/pidginawayprefs.c',
'prefs/pidginconversationprefs.c',
@@ -129,6 +130,7 @@
'pidginstatusprimitivechooser.h',
'pidginstatusprimitivestore.h',
libpidgin_prefs_headers = [
--- a/pidgin/pidginapplication.c Mon Oct 31 03:06:44 2022 -0500
+++ b/pidgin/pidginapplication.c Mon Oct 31 04:02:09 2022 -0500
@@ -52,9 +52,10 @@
#include "pidginmooddialog.h"
#include "pidginpluginsdialog.h"
#include "pidginpluginsmenu.h"
+#include "pidginprefs.h" #include "pidginstatuseditor.h"
#include "pidginstatusmanager.h"
-#include "pidginprefs.h"
struct _PidginApplication {
@@ -745,7 +746,6 @@
pidgin_application_startup(GApplication *application) {
PurpleAccountManager *manager = NULL;
- PurpleUiInfo *ui_info = NULL;
GList *active_accounts = NULL;
@@ -780,13 +780,7 @@
- purple_core_set_ui_ops(pidgin_core_get_ui_ops());
- ui_info = purple_ui_info_new("pidgin3", PIDGIN_NAME, VERSION,
- "https://developer.pidgin.im", "pc");
- if(!purple_core_init(ui_info)) {
+ if(!purple_core_init(pidgin_ui_new())) { _("Initialization of the libpurple core failed. Aborting!\n"
"Please report this!\n"));
--- a/pidgin/pidgincore.h Mon Oct 31 03:06:44 2022 -0500
+++ b/pidgin/pidgincore.h Mon Oct 31 04:02:09 2022 -0500
@@ -61,17 +61,5 @@
int pidgin_start(int argc, char *argv[]);
- * pidgin_core_get_ui_ops:
- * Gets the #PurpleCoreUiOps that Pidgin sets up. You probably don't want to
- * Returns: The #PurpleCoreUiOps for Pidgin.
-PurpleCoreUiOps *pidgin_core_get_ui_ops(void);
#endif /* PIDGIN_CORE_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/pidgin/pidginui.c Mon Oct 31 04:02:09 2022 -0500
@@ -0,0 +1,263 @@
+ * 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 + * 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/>. +#define G_SETTINGS_ENABLE_BACKEND +#include <gio/gsettingsbackend.h> +#include "gtkroomlist.h" +#include "gtkwhiteboard.h" +#include "pidgindebug.h" +#include "pidginprefs.h" +#include "pidginprivate.h" +G_DEFINE_TYPE(PidginUi, pidgin_ui, PURPLE_TYPE_UI) +/****************************************************************************** + *****************************************************************************/ +pidgin_history_init(GError **error) { + PurpleHistoryManager *manager = NULL; + PurpleHistoryAdapter *adapter = NULL; + gchar *filename = NULL; + const gchar *id = NULL; + manager = purple_history_manager_get_default(); + /* Attempt to create the config_dir. We don't care about the result as the + * logging adapter will fail with a better error than us failing to create + g_mkdir_with_parents(purple_config_dir(), 0700); + filename = g_build_filename(purple_config_dir(), "history.db", NULL); + adapter = purple_sqlite_history_adapter_new(filename); + id = purple_history_adapter_get_id(adapter); + if(!purple_history_manager_register(manager, adapter, error)) { + g_clear_object(&adapter); + /* The manager adds a ref to the adapter on registration, so we can remove + g_clear_object(&adapter); + return purple_history_manager_set_active(manager, id, error); +pidgin_ui_add_protocol_theme_paths(PurpleProtocol *protocol) { + GdkDisplay *display = NULL; + GtkIconTheme *theme = NULL; + const gchar *path = NULL; + display = gdk_display_get_default(); + theme = gtk_icon_theme_get_for_display(display); + path = purple_protocol_get_icon_search_path(protocol); + gtk_icon_theme_add_search_path(theme, path); + path = purple_protocol_get_icon_resource_path(protocol); + gtk_icon_theme_add_resource_path(theme, path); +/****************************************************************************** + *****************************************************************************/ +pidgin_ui_protocol_foreach_theme_cb(PurpleProtocol *protocol, + G_GNUC_UNUSED gpointer data) + pidgin_ui_add_protocol_theme_paths(protocol); +pidgin_ui_protocol_registered_cb(G_GNUC_UNUSED PurpleProtocolManager *manager, + PurpleProtocol *protocol) + pidgin_ui_add_protocol_theme_paths(protocol); +/****************************************************************************** + * PurpleUi Implementation + *****************************************************************************/ +pidgin_ui_prefs_init(G_GNUC_UNUSED PurpleUi *ui) { +pidgin_ui_start(G_GNUC_UNUSED PurpleUi *ui) { + PurpleProtocolManager *protocol_manager = NULL; + GdkDisplay *display = NULL; + GtkIconTheme *theme = NULL; + display = gdk_display_get_default(); + theme = gtk_icon_theme_get_for_display(display); + path = g_build_filename(PURPLE_DATADIR, "pidgin", "icons", NULL); + gtk_icon_theme_add_search_path(theme, path); + /* Add a callback for when a protocol is registered to add its icon paths + * if it was found after initial startup. + protocol_manager = purple_protocol_manager_get_default(); + g_signal_connect(protocol_manager, "registered", + G_CALLBACK(pidgin_ui_protocol_registered_cb), NULL); + /* Add the icon paths for all the protocols that libpurple found at start + purple_protocol_manager_foreach(protocol_manager, + pidgin_ui_protocol_foreach_theme_cb, NULL); + if(!pidgin_history_init(&error)) { + g_critical("failed to initialize the history api: %s", + error != NULL ? error->message : "unknown"); + /* Set the UI operation structures. */ + purple_xfers_set_ui_ops(pidgin_xfers_get_ui_ops()); + purple_blist_set_ui(PIDGIN_TYPE_BUDDY_LIST); + purple_notify_set_ui_ops(pidgin_notify_get_ui_ops()); + purple_request_set_ui_ops(pidgin_request_get_ui_ops()); + purple_connections_set_ui_ops(pidgin_connections_get_ui_ops()); + purple_whiteboard_set_ui_ops(pidgin_whiteboard_get_ui_ops()); + purple_idle_set_ui(pidgin_idle_new()); + pidgin_accounts_init(); + pidgin_connection_init(); + pidgin_conversations_init(); + pidgin_commands_init(); + pidgin_roomlist_init(); +pidgin_ui_stop(G_GNUC_UNUSED PurpleUi *ui) { + /* Be sure to close all windows that are not attached to anything + * (e.g., the debug window), or they may access things after they are + pidgin_notify_uninit(); + pidgin_commands_uninit(); + pidgin_conversations_uninit(); + pidgin_request_uninit(); + pidgin_connection_uninit(); + pidgin_accounts_uninit(); + pidgin_debug_window_hide(); + /* and end it all... */ + g_application_quit(g_application_get_default()); +pidgin_ui_get_settings_backend(G_GNUC_UNUSED PurpleUi *ui) { + GSettingsBackend *backend = NULL; + config = g_build_filename(purple_config_dir(), "pidgin3.ini", NULL); + backend = g_keyfile_settings_backend_new(config, "/", NULL); +/****************************************************************************** + * GObject Implementation + *****************************************************************************/ +pidgin_ui_init(G_GNUC_UNUSED PidginUi *ui) { +pidgin_ui_class_init(PidginUiClass *klass) { + PurpleUiClass *ui_class = PURPLE_UI_CLASS(klass); + ui_class->prefs_init = pidgin_ui_prefs_init; + ui_class->start = pidgin_ui_start; + ui_class->stop = pidgin_ui_stop; + ui_class->get_settings_backend = pidgin_ui_get_settings_backend; +/****************************************************************************** + *****************************************************************************/ + "website", "https://pidgin.im", + "support-website", "https://pidgin.im/contact/", --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/pidgin/pidginui.h Mon Oct 31 04:02:09 2022 -0500
@@ -0,0 +1,60 @@
+ * 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 + * 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/>. +#if !defined(PIDGIN_GLOBAL_HEADER_INSIDE) && !defined(PIDGIN_COMPILATION) +# error "only <pidgin.h> may be included directly" + * Is a subclass of [class@Purple.Ui] that identifies Pidgin to libpurple. +#define PIDGIN_TYPE_UI (pidgin_ui_get_type()) +G_DECLARE_FINAL_TYPE(PidginUi, pidgin_ui, PIDGIN, UI, PurpleUi) + * Creates the new [class@Pidgin.Ui] instance. + * Note: there's not much use for this outside of Pidgin's internal code. + * Returns: (transfer full): The new instance. +PurpleUi *pidgin_ui_new(void); +#endif /* PIDGIN_UI_H */ --- a/po/POTFILES.in Mon Oct 31 03:06:44 2022 -0500
+++ b/po/POTFILES.in Mon Oct 31 04:02:09 2022 -0500
@@ -188,7 +188,6 @@
libpurple/purpleconversation.c
libpurple/purpleconversationmanager.c
libpurple/purpleconversationuiops.c
-libpurple/purplecoreuiops.c
libpurple/purplecredentialmanager.c
libpurple/purplecredentialprovider.c
libpurple/purpledebugui.c
@@ -219,7 +218,7 @@
libpurple/purpleprotocolserver.c
libpurple/purpleprotocolwhiteboard.c
libpurple/purplesqlitehistoryadapter.c
-libpurple/purpleuiinfo.c
libpurple/purplewhiteboard.c
libpurple/purplewhiteboardmanager.c
libpurple/purplewhiteboarduiops.c