pidgin/pidgin

4be2eda9548a
Parents f108e108784e
Children 53824f9c7cdc
Create PurpleWhiteboardManager for managing whiteboards

Testing Done:
Compiled only. Tried to create a silc account, but it dies deep in libsilc.

Reviewed at https://reviews.imfreedom.org/r/886/
--- a/doc/reference/libpurple/libpurple-docs.xml Thu Sep 02 21:22:55 2021 -0500
+++ b/doc/reference/libpurple/libpurple-docs.xml Thu Sep 02 21:28:40 2021 -0500
@@ -80,6 +80,7 @@
<xi:include href="xml/purpleplugininfo.xml" />
<xi:include href="xml/purplepresence.xml" />
<xi:include href="xml/purplewhiteboard.xml" />
+ <xi:include href="xml/purplewhiteboardmanager.xml" />
<xi:include href="xml/purplewhiteboardops.xml" />
<xi:include href="xml/purplewhiteboarduiops.xml" />
<xi:include href="xml/purpleuiinfo.xml" />
--- a/libpurple/core.c Thu Sep 02 21:22:55 2021 -0500
+++ b/libpurple/core.c Thu Sep 02 21:28:40 2021 -0500
@@ -170,6 +170,7 @@
purple_notify_init();
purple_conversations_init();
purple_conversation_manager_startup();
+ purple_whiteboard_manager_startup();
purple_blist_init();
purple_log_init();
purple_network_init();
@@ -219,6 +220,7 @@
/* Save .xml files, remove signals, etc. */
purple_idle_uninit();
+ purple_whiteboard_manager_shutdown();
purple_conversation_manager_shutdown();
purple_conversations_uninit();
purple_blist_uninit();
--- a/libpurple/meson.build Thu Sep 02 21:22:55 2021 -0500
+++ b/libpurple/meson.build Thu Sep 02 21:28:40 2021 -0500
@@ -73,6 +73,7 @@
'purpleprotocolserver.c',
'purpleuiinfo.c',
'purplewhiteboard.c',
+ 'purplewhiteboardmanager.c',
'purplewhiteboarduiops.c',
'queuedoutputstream.c',
'request.c',
@@ -164,6 +165,7 @@
'purpleprotocolserver.h',
'purpleuiinfo.h',
'purplewhiteboard.h',
+ 'purplewhiteboardmanager.h',
'purplewhiteboardops.h',
'purplewhiteboarduiops.h',
'queuedoutputstream.h',
--- a/libpurple/protocols/silc/wb.c Thu Sep 02 21:22:55 2021 -0500
+++ b/libpurple/protocols/silc/wb.c Thu Sep 02 21:28:40 2021 -0500
@@ -105,13 +105,24 @@
PurpleWhiteboard *silcpurple_wb_init(SilcPurple sg, SilcClientEntry client_entry)
{
PurpleWhiteboard *wb;
+ PurpleWhiteboardManager *manager;
SilcPurpleWb wbs;
+ gchar *id = NULL;
+
+ manager = purple_whiteboard_manager_get_default();
- wb = purple_whiteboard_get_session(sg->account, client_entry->nickname);
- if (!wb)
- wb = purple_whiteboard_new(sg->account, client_entry->nickname, 0);
- if (!wb)
+ id = g_strdup_printf("silc-client-%s", client_entry->nickname);
+ wb = purple_whiteboard_manager_find(manager, id);
+ if(!PURPLE_IS_WHITEBOARD(wb)) {
+ wb = purple_whiteboard_new(sg->account, id, 0);
+ purple_whiteboard_manager_register(manager, wb, NULL);
+ }
+
+ g_free(id);
+
+ if(!PURPLE_IS_WHITEBOARD(wb)) {
return NULL;
+ }
if (!purple_whiteboard_get_protocol_data(wb)) {
wbs = silc_calloc(1, sizeof(*wbs));
@@ -135,14 +146,24 @@
PurpleWhiteboard *silcpurple_wb_init_ch(SilcPurple sg, SilcChannelEntry channel)
{
+ PurpleWhiteboardManager *manager = NULL;
PurpleWhiteboard *wb;
SilcPurpleWb wbs;
+ gchar *id;
- wb = purple_whiteboard_get_session(sg->account, channel->channel_name);
- if (!wb)
- wb = purple_whiteboard_new(sg->account, channel->channel_name, 0);
- if (!wb)
+ manager = purple_whiteboard_manager_get_default();
+
+ id = g_strdup_printf("silc-channel-%s", channel->channel_name);
+ wb = purple_whiteboard_manager_find(manager, id);
+ if(!PURPLE_IS_WHITEBOARD(wb)) {
+ wb = purple_whiteboard_new(sg->account, id, 0);
+ }
+
+ g_free(id);
+
+ if(!PURPLE_IS_WHITEBOARD(wb)) {
return NULL;
+ }
if (!purple_whiteboard_get_protocol_data(wb)) {
wbs = silc_calloc(1, sizeof(*wbs));
@@ -315,18 +336,19 @@
SilcMessageFlags flags, const unsigned char *message,
SilcUInt32 message_len)
{
- SilcPurple sg;
- PurpleConnection *gc;
PurpleWhiteboard *wb;
+ PurpleWhiteboardManager *manager;
+ gchar *id = NULL;
+
+ manager = purple_whiteboard_manager_get_default();
- gc = client->application;
- sg = purple_connection_get_protocol_data(gc);
+ id = g_strdup_printf("silc-client-%s", sender->nickname);
+ wb = purple_whiteboard_manager_find(manager, id);
+ g_free(id);
- wb = purple_whiteboard_get_session(sg->account, sender->nickname);
- if (!wb) {
+ if(!PURPLE_IS_WHITEBOARD(wb)) {
/* Ask user if they want to open the whiteboard */
- silcpurple_wb_request(client, message, message_len,
- sender, NULL);
+ silcpurple_wb_request(client, message, message_len, sender, NULL);
return;
}
@@ -342,18 +364,20 @@
const unsigned char *message,
SilcUInt32 message_len)
{
- SilcPurple sg;
- PurpleConnection *gc;
PurpleWhiteboard *wb;
+ PurpleWhiteboardManager *manager;
+ gchar *id;
+
+ manager = purple_whiteboard_manager_get_default();
- gc = client->application;
- sg = purple_connection_get_protocol_data(gc);
+ id = g_strdup_printf("silc-channel-%s", channel->channel_name);
+ wb = purple_whiteboard_manager_find(manager, id);
+ g_free(id);
- wb = purple_whiteboard_get_session(sg->account, channel->channel_name);
- if (!wb) {
+ if(!PURPLE_IS_WHITEBOARD(wb)) {
/* Ask user if they want to open the whiteboard */
- silcpurple_wb_request(client, message, message_len,
- sender, channel);
+ silcpurple_wb_request(client, message, message_len, sender, channel);
+
return;
}
@@ -430,9 +454,14 @@
void silcpurple_wb_end(PurpleWhiteboard *wb)
{
SilcPurpleWb wbs = purple_whiteboard_get_protocol_data(wb);
+ PurpleWhiteboardManager *manager;
+
+ manager = purple_whiteboard_manager_get_default();
silc_free(wbs);
purple_whiteboard_set_protocol_data(wb, NULL);
+
+ purple_whiteboard_manager_unregister(manager, wb, NULL);
}
void silcpurple_wb_get_dimensions(const PurpleWhiteboard *wb, int *width, int *height)
--- a/libpurple/purpleprivate.h Thu Sep 02 21:22:55 2021 -0500
+++ b/libpurple/purpleprivate.h Thu Sep 02 21:28:40 2021 -0500
@@ -255,6 +255,25 @@
*/
void purple_credential_provider_deactivate(PurpleCredentialProvider *provider);
+/**
+ * purple_whiteboard_manager_startup:
+ *
+ * Starts up the whiteboard manager by creating the default instance.
+ *
+ * Since: 3.0.0
+ */
+void purple_whiteboard_manager_startup(void);
+
+/**
+ * purple_whiteboard_manager_shutdown:
+ *
+ * Shuts down the whiteboard manager by destroying the default instance.
+ *
+ * Since: 3.0.0
+ */
+void purple_whiteboard_manager_shutdown(void);
+
+
G_END_DECLS
#endif /* PURPLE_PRIVATE_H */
--- a/libpurple/purplewhiteboard.c Thu Sep 02 21:22:55 2021 -0500
+++ b/libpurple/purplewhiteboard.c Thu Sep 02 21:28:40 2021 -0500
@@ -27,12 +27,13 @@
#include "purpleprotocolfactory.h"
#include "purplewhiteboarduiops.h"
#include "protocol.h"
+#include "util.h"
typedef struct {
int state;
PurpleAccount *account;
- char *who;
+ gchar *id;
/* TODO Remove this and use protocol-specific subclasses. */
void *proto_data;
@@ -47,7 +48,7 @@
PROP_0,
PROP_STATE,
PROP_ACCOUNT,
- PROP_WHO,
+ PROP_ID,
PROP_DRAW_LIST,
N_PROPERTIES,
};
@@ -56,11 +57,6 @@
G_DEFINE_TYPE_WITH_PRIVATE(PurpleWhiteboard, purple_whiteboard, G_TYPE_OBJECT)
/******************************************************************************
- * Globals
- *****************************************************************************/
-static GList *wb_list = NULL;
-
-/******************************************************************************
* Helpers
*****************************************************************************/
static void
@@ -78,15 +74,15 @@
}
static void
-purple_whiteboard_set_who(PurpleWhiteboard *whiteboard, const gchar *who) {
+purple_whiteboard_set_id(PurpleWhiteboard *whiteboard, const gchar *id) {
PurpleWhiteboardPrivate *priv = NULL;
priv = purple_whiteboard_get_instance_private(whiteboard);
- g_clear_pointer(&priv->who, g_free);
- priv->who = g_strdup(who);
+ g_free(priv->id);
+ priv->id = g_strdup(id);
- g_object_notify_by_pspec(G_OBJECT(whiteboard), properties[PROP_WHO]);
+ g_object_notify_by_pspec(G_OBJECT(whiteboard), properties[PROP_ID]);
}
/******************************************************************************
@@ -106,8 +102,8 @@
purple_whiteboard_set_account(whiteboard,
g_value_get_object(value));
break;
- case PROP_WHO:
- purple_whiteboard_set_who(whiteboard, g_value_get_string(value));
+ case PROP_ID:
+ purple_whiteboard_set_id(whiteboard, g_value_get_string(value));
break;
case PROP_DRAW_LIST:
purple_whiteboard_set_draw_list(whiteboard,
@@ -133,9 +129,9 @@
g_value_set_object(value,
purple_whiteboard_get_account(whiteboard));
break;
- case PROP_WHO:
+ case PROP_ID:
g_value_set_string(value,
- purple_whiteboard_get_who(whiteboard));
+ purple_whiteboard_get_id(whiteboard));
break;
case PROP_DRAW_LIST:
g_value_set_pointer(value,
@@ -170,8 +166,6 @@
if(priv->protocol_ops != NULL && priv->protocol_ops->start != NULL) {
priv->protocol_ops->start(whiteboard);
}
-
- wb_list = g_list_append(wb_list, whiteboard);
}
static void
@@ -186,10 +180,8 @@
priv->protocol_ops->end(whiteboard);
}
- wb_list = g_list_remove(wb_list, whiteboard);
-
g_clear_object(&priv->account);
- g_clear_pointer(&priv->who, g_free);
+ g_clear_pointer(&priv->id, g_free);
/* TODO: figure out how we need to clean up the drawlist */
@@ -216,9 +208,9 @@
"The whiteboard's account.", PURPLE_TYPE_ACCOUNT,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
- properties[PROP_WHO] = g_param_spec_string(
- "who", "Who",
- "Who you're drawing with.", NULL,
+ properties[PROP_ID] = g_param_spec_string(
+ "id", "id",
+ "The ID of the whiteboard.", NULL,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
properties[PROP_DRAW_LIST] = g_param_spec_pointer(
@@ -257,14 +249,14 @@
}
const gchar *
-purple_whiteboard_get_who(PurpleWhiteboard *whiteboard) {
+purple_whiteboard_get_id(PurpleWhiteboard *whiteboard) {
PurpleWhiteboardPrivate *priv = NULL;
g_return_val_if_fail(PURPLE_IS_WHITEBOARD(whiteboard), NULL);
priv = purple_whiteboard_get_instance_private(whiteboard);
- return priv->who;
+ return priv->id;
}
void
@@ -296,24 +288,6 @@
purple_whiteboard_ui_ops_create(whiteboard);
}
-PurpleWhiteboard *
-purple_whiteboard_get_session(PurpleAccount *account, const gchar *who) {
- PurpleWhiteboard *whiteboard = NULL;
- PurpleWhiteboardPrivate *priv = NULL;
- GList *l = NULL;
-
- for(l = wb_list; l != NULL; l = l->next) {
- whiteboard = PURPLE_WHITEBOARD(l->data);
- priv = purple_whiteboard_get_instance_private(whiteboard);
-
- if(priv->account == account && purple_strequal(priv->who, who)) {
- return whiteboard;
- }
- }
-
- return NULL;
-}
-
void
purple_whiteboard_draw_list_destroy(GList *draw_list) {
g_list_free(draw_list);
@@ -491,12 +465,12 @@
}
PurpleWhiteboard *
-purple_whiteboard_new(PurpleAccount *account, const gchar *who, gint state) {
+purple_whiteboard_new(PurpleAccount *account, const gchar *id, gint state) {
PurpleWhiteboard *whiteboard = NULL;
PurpleProtocol *protocol = NULL;
g_return_val_if_fail(PURPLE_IS_ACCOUNT(account), NULL);
- g_return_val_if_fail(who != NULL, NULL);
+ g_return_val_if_fail(id != NULL, NULL);
protocol = purple_account_get_protocol(account);
@@ -504,12 +478,12 @@
if(PURPLE_IS_PROTOCOL_FACTORY(protocol)) {
whiteboard = purple_protocol_factory_whiteboard_new(
- PURPLE_PROTOCOL_FACTORY(protocol), account, who, state);
+ PURPLE_PROTOCOL_FACTORY(protocol), account, id, state);
} else {
whiteboard = g_object_new(PURPLE_TYPE_WHITEBOARD,
"account", account,
- "who", who,
- "state", state,
+ "id", id,
+ "state", state,
NULL
);
}
@@ -517,3 +491,20 @@
return whiteboard;
}
+gboolean
+purple_whiteboard_equal(PurpleWhiteboard *whiteboard1,
+ PurpleWhiteboard *whiteboard2)
+{
+ PurpleWhiteboardPrivate *priv1 = NULL, *priv2 = NULL;
+
+ if(whiteboard1 == NULL) {
+ return (whiteboard2 == NULL);
+ } else if(whiteboard2 == NULL) {
+ return FALSE;
+ }
+
+ priv1 = purple_whiteboard_get_instance_private(whiteboard1);
+ priv2 = purple_whiteboard_get_instance_private(whiteboard2);
+
+ return purple_strequal(priv1->id, priv2->id);
+}
--- a/libpurple/purplewhiteboard.h Thu Sep 02 21:22:55 2021 -0500
+++ b/libpurple/purplewhiteboard.h Thu Sep 02 21:28:40 2021 -0500
@@ -94,14 +94,14 @@
/**
* purple_whiteboard_new:
* @account: A #PurpleAccount instance.
- * @who: Who you're drawing with.
+ * @id: The identifier of the whiteboard.
* @state: The state.
*
* Creates a new whiteboard.
*
* Returns: (transfer full): The new #PurpleWhiteboard instance.
*/
-PurpleWhiteboard *purple_whiteboard_new(PurpleAccount *account, const gchar *who, gint state);
+PurpleWhiteboard *purple_whiteboard_new(PurpleAccount *account, const gchar *id, gint state);
/**
* purple_whiteboard_get_account:
@@ -114,14 +114,16 @@
PurpleAccount *purple_whiteboard_get_account(PurpleWhiteboard *whiteboard);
/**
- * purple_whiteboard_get_who:
+ * purple_whiteboard_get_id:
* @whiteboard: The #PurpleWhiteboard instance.
*
- * Gets the name of who you're drawing with.
+ * Gets the id of @whiteboard.
+ *
+ * Returns: The id of @whiteboard.
*
- * Returns: The name of who you're drawing with.
+ * Since: 3.0.0
*/
-const gchar *purple_whiteboard_get_who(PurpleWhiteboard *whiteboard);
+const gchar *purple_whiteboard_get_id(PurpleWhiteboard *whiteboard);
/**
* purple_whiteboard_set_state:
@@ -151,18 +153,6 @@
void purple_whiteboard_start(PurpleWhiteboard *whiteboard);
/**
- * purple_whiteboard_get_session:
- * @account: A #PurpleAccount instance.
- * @who: The name of the user you're drawing with.
- *
- * Finds a whiteboard from @account and @who.
- *
- * Returns: (transfer none): The #PurpleWhiteboard instance if found, otherwise
- * %NULL.
- */
-PurpleWhiteboard *purple_whiteboard_get_session(PurpleAccount *account, const gchar *who);
-
-/**
* purple_whiteboard_draw_list_destroy:
* @draw_list: (element-type gint): The drawing list.
*
@@ -313,6 +303,20 @@
*/
gpointer purple_whiteboard_get_protocol_data(PurpleWhiteboard *whiteboard);
+/**
+ * purple_whiteboard_equal:
+ * @whiteboard1: The first #PurpleWhiteboard instance to check.
+ * @whiteboard2: The second #PurpleWhiteboard instance to check.
+ *
+ * Checks the id's for @whiteboard1 and @whiteboard2 and return whether or not
+ * they are equal.
+ *
+ * Returns: %TRUE if the id's of @whiteboard1 and @whiteboard2 are equal.
+ *
+ * Since: 3.0.0
+ */
+gboolean purple_whiteboard_equal(PurpleWhiteboard *whiteboard1, PurpleWhiteboard *whiteboard2);
+
G_END_DECLS
#endif /* PURPLE_WHITEBOARD_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/purplewhiteboardmanager.c Thu Sep 02 21:28:40 2021 -0500
@@ -0,0 +1,269 @@
+/*
+ * 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 <glib/gi18n-lib.h>
+
+#include "purplewhiteboardmanager.h"
+#include "purpleprivate.h"
+
+enum {
+ SIG_REGISTERED,
+ SIG_UNREGISTERED,
+ N_SIGNALS,
+};
+static guint signals[N_SIGNALS] = {0, };
+
+typedef struct {
+ GListStore *store;
+} PurpleWhiteboardManagerPrivate;
+
+G_DEFINE_TYPE_WITH_PRIVATE(PurpleWhiteboardManager, purple_whiteboard_manager,
+ G_TYPE_OBJECT);
+
+static PurpleWhiteboardManager *default_manager = NULL;
+
+/******************************************************************************
+ * GObject Implementation
+ *****************************************************************************/
+static void
+purple_whiteboard_manager_finalize(GObject *obj) {
+ PurpleWhiteboardManager *manager = NULL;
+ PurpleWhiteboardManagerPrivate *priv = NULL;
+
+ manager = PURPLE_WHITEBOARD_MANAGER(obj);
+ priv = purple_whiteboard_manager_get_instance_private(manager);
+
+ g_clear_object(&priv->store);
+
+ G_OBJECT_CLASS(purple_whiteboard_manager_parent_class)->finalize(obj);
+}
+
+static void
+purple_whiteboard_manager_init(PurpleWhiteboardManager *manager) {
+ PurpleWhiteboardManagerPrivate *priv = NULL;
+
+ priv = purple_whiteboard_manager_get_instance_private(manager);
+
+ priv->store = g_list_store_new(PURPLE_TYPE_WHITEBOARD);
+}
+
+static void
+purple_whiteboard_manager_class_init(PurpleWhiteboardManagerClass *klass) {
+ GObjectClass *obj_class = G_OBJECT_CLASS(klass);
+
+ obj_class->finalize = purple_whiteboard_manager_finalize;
+
+ /**
+ * PurpleWhiteboardManager::registered:
+ * @manager: The #PurpleWhiteboardManager instance.
+ * @whiteboard: The #PurpleWhiteboard that was registered.
+ *
+ * Emitted after @whiteboard has been registered in @manager.
+ *
+ * Since: 3.0.0
+ */
+ signals[SIG_REGISTERED] = g_signal_new(
+ "registered",
+ G_OBJECT_CLASS_TYPE(klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET(PurpleWhiteboardManagerClass, registered),
+ NULL,
+ NULL,
+ NULL,
+ G_TYPE_NONE,
+ 1,
+ PURPLE_TYPE_WHITEBOARD);
+
+ /**
+ * PurpleWhiteboardManager::unregistered:
+ * @manager: The #PurpleWhiteboardManager instance.
+ * @whiteboard: The #PurpleWhiteboard that was unregistered.
+ *
+ * Emitted after @whiteboard has been unregistered from @manager.
+ *
+ * Since: 3.0.0
+ */
+ signals[SIG_UNREGISTERED] = g_signal_new(
+ "unregistered",
+ G_OBJECT_CLASS_TYPE(klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET(PurpleWhiteboardManagerClass, unregistered),
+ NULL,
+ NULL,
+ NULL,
+ G_TYPE_NONE,
+ 1,
+ PURPLE_TYPE_WHITEBOARD);
+}
+
+/******************************************************************************
+ * Private API
+ *****************************************************************************/
+void
+purple_whiteboard_manager_startup(void) {
+ if(default_manager == NULL) {
+ default_manager = g_object_new(PURPLE_TYPE_WHITEBOARD_MANAGER, NULL);
+ }
+}
+
+void
+purple_whiteboard_manager_shutdown(void) {
+ g_clear_object(&default_manager);
+}
+
+/******************************************************************************
+ * Public API
+ *****************************************************************************/
+PurpleWhiteboardManager *
+purple_whiteboard_manager_get_default(void) {
+ return default_manager;
+}
+
+gboolean
+purple_whiteboard_manager_register(PurpleWhiteboardManager *manager,
+ PurpleWhiteboard *whiteboard,
+ GError **error)
+{
+ PurpleWhiteboardManagerPrivate *priv = NULL;
+ gboolean found = FALSE;
+
+ g_return_val_if_fail(PURPLE_IS_WHITEBOARD_MANAGER(manager), FALSE);
+ g_return_val_if_fail(PURPLE_IS_WHITEBOARD(whiteboard), FALSE);
+
+ priv = purple_whiteboard_manager_get_instance_private(manager);
+
+ found = g_list_store_find_with_equal_func(priv->store, whiteboard,
+ (GEqualFunc)purple_whiteboard_equal,
+ NULL);
+
+ if(found) {
+ g_set_error(error, PURPLE_WHITEBOARD_MANAGER_DOMAIN, 0,
+ _("whiteboard %s is already registered"),
+ purple_whiteboard_get_id(whiteboard));
+
+ return FALSE;
+ }
+
+ g_list_store_insert(priv->store, 0, whiteboard);
+
+ g_signal_emit(G_OBJECT(manager), signals[SIG_REGISTERED], 0, whiteboard);
+
+ return TRUE;
+}
+
+gboolean
+purple_whiteboard_manager_unregister(PurpleWhiteboardManager *manager,
+ PurpleWhiteboard *whiteboard,
+ GError **error)
+{
+ PurpleWhiteboardManagerPrivate *priv = NULL;
+ guint position = 0;
+ gboolean found = FALSE;
+
+ g_return_val_if_fail(PURPLE_IS_WHITEBOARD_MANAGER(manager), FALSE);
+ g_return_val_if_fail(PURPLE_IS_WHITEBOARD(whiteboard), FALSE);
+
+ priv = purple_whiteboard_manager_get_instance_private(manager);
+
+ found = g_list_store_find_with_equal_func(priv->store, whiteboard,
+ (GEqualFunc)purple_whiteboard_equal,
+ &position);
+
+ if(!found) {
+ g_set_error(error, PURPLE_WHITEBOARD_MANAGER_DOMAIN, 0,
+ _("whiteboard %s is not registered"),
+ purple_whiteboard_get_id(whiteboard));
+
+ return FALSE;
+ }
+
+ /* Temporarily ref whiteboard so we can pass it along to the signal
+ * callbacks.
+ */
+ g_object_ref(G_OBJECT(whiteboard));
+
+ g_list_store_remove(priv->store, position);
+
+ g_signal_emit(G_OBJECT(manager), signals[SIG_UNREGISTERED], 0, whiteboard);
+
+ g_object_unref(G_OBJECT(whiteboard));
+
+ return TRUE;
+}
+
+PurpleWhiteboard *
+purple_whiteboard_manager_find(PurpleWhiteboardManager *manager,
+ const gchar *id)
+{
+ PurpleWhiteboardManagerPrivate *priv = NULL;
+ guint idx, n;
+
+ g_return_val_if_fail(PURPLE_IS_WHITEBOARD_MANAGER(manager), NULL);
+ g_return_val_if_fail(id != NULL, NULL);
+
+ priv = purple_whiteboard_manager_get_instance_private(manager);
+
+ n = g_list_model_get_n_items(G_LIST_MODEL(priv->store));
+ for(idx = 0; idx < n; idx++) {
+ GObject *obj = NULL;
+
+ obj = g_list_model_get_object(G_LIST_MODEL(priv->store), idx);
+ if(PURPLE_IS_WHITEBOARD(obj)) {
+ PurpleWhiteboard *whiteboard = PURPLE_WHITEBOARD(obj);
+
+ if(purple_strequal(id, purple_whiteboard_get_id(whiteboard))) {
+ return whiteboard;
+ }
+ }
+ g_clear_object(&obj);
+ }
+
+ return NULL;
+}
+
+void
+purple_whiteboard_manager_foreach(PurpleWhiteboardManager *manager,
+ PurpleWhiteboardManagerForeachFunc func,
+ gpointer data)
+{
+ PurpleWhiteboardManagerPrivate *priv = NULL;
+ guint idx, n;
+
+ g_return_if_fail(PURPLE_IS_WHITEBOARD_MANAGER(manager));
+ g_return_if_fail(func != NULL);
+
+ priv = purple_whiteboard_manager_get_instance_private(manager);
+
+ n = g_list_model_get_n_items(G_LIST_MODEL(priv->store));
+ for(idx = 0; idx < n; idx++) {
+ gpointer item = g_list_model_get_item(G_LIST_MODEL(priv->store), idx);
+ func(item, data);
+ g_object_unref(item);
+ }
+}
+
+GListModel *
+purple_whiteboard_manager_get_model(PurpleWhiteboardManager *manager) {
+ PurpleWhiteboardManagerPrivate *priv = NULL;
+
+ g_return_val_if_fail(PURPLE_IS_WHITEBOARD_MANAGER(manager), NULL);
+
+ priv = purple_whiteboard_manager_get_instance_private(manager);
+
+ return G_LIST_MODEL(priv->store);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/purplewhiteboardmanager.h Thu Sep 02 21:28:40 2021 -0500
@@ -0,0 +1,193 @@
+/*
+ * 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"
+#endif
+
+#ifndef PURPLE_WHITEBOARD_MANAGER_H
+#define PURPLE_WHITEBOARD_MANAGER_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include <libpurple/purplewhiteboard.h>
+
+G_BEGIN_DECLS
+
+/**
+ * SECTION:purplewhiteboardmanager
+ * @section_id: libpurple-purplewhiteboardmanager
+ * @title: Purple Whiteboard Manager
+ * @short_description: Management of whiteboards.
+ *
+ * #PurpleWhiteboardManager keeps track of all whiteboards and emits signals
+ * when whiteboards are registered and unregistered.
+ */
+
+/**
+ * PURPLE_WHITEBOARD_MANAGER_DOMAIN:
+ *
+ * A #GError domain for errors from #PurpleWhiteboardManager.
+ *
+ * Since: 3.0.0
+ */
+#define PURPLE_WHITEBOARD_MANAGER_DOMAIN (g_quark_from_static_string("purple-whiteboard-manager"))
+
+/**
+ * PURPLE_TYPE_WHITEBOARD_MANAGER:
+ *
+ * The standard _TYPE_ macro for #PurpleWhiteboardManager.
+ *
+ * Since: 3.0.0
+ */
+#define PURPLE_TYPE_WHITEBOARD_MANAGER (purple_whiteboard_manager_get_type())
+
+/**
+ * purple_whiteboard_manager_get_type:
+ *
+ * The standard _get_type macro for #PurpleWhiteboardManager.
+ *
+ * Since: 3.0.0
+ */
+
+/**
+ * PurpleWhiteboardManager:
+ *
+ * An opaque data structure that manages whiteboards.
+ *
+ * Since: 3.0.0
+ */
+G_DECLARE_DERIVABLE_TYPE(PurpleWhiteboardManager, purple_whiteboard_manager,
+ PURPLE, WHITEBOARD_MANAGER, GObject)
+
+/**
+ * PurpleWhiteboardManagerClass:
+ * @registered: The default signal handler for when a whiteboard is registered.
+ * @unregistered: The default signal handler for when a whiteboard is
+ * unregistered.
+ *
+ * The class structure for #PurpleWhiteboardManager.
+ *
+ * Since: 3.0.0
+ */
+struct _PurpleWhiteboardManagerClass {
+ /*< private >*/
+ GObjectClass parent;
+
+ /*< public >*/
+ void (*registered)(PurpleWhiteboardManager *manager, PurpleWhiteboard *whiteboard);
+ void (*unregistered)(PurpleWhiteboardManager *manager, PurpleWhiteboard *whiteboard);
+
+ /*< private >*/
+ gpointer reserved[4];
+};
+
+/**
+ * PurpleWhiteboardManagerForeachFunc:
+ * @whiteboard: The #PurpleWhiteboard instance.
+ * @data: User supplied data.
+ *
+ * A function to be used as a callback with purple_whiteboard_manager_foreach().
+ *
+ * Since: 3.0.0
+ */
+typedef void (*PurpleWhiteboardManagerForeachFunc)(PurpleWhiteboard *whiteboard, gpointer data);
+
+/**
+ * purple_whiteboard_manager_get_default:
+ *
+ * Gets the default #PurpleWhiteboardManager instance.
+ *
+ * Returns: (transfer none): The default #PurpleWhiteboardManager instance.
+ *
+ * Since: 3.0.0
+ */
+PurpleWhiteboardManager *purple_whiteboard_manager_get_default(void);
+
+/**
+ * purple_whiteboard_manager_register:
+ * @manager: The #PurpleWhiteboardManager instance.
+ * @whiteboard: The #PurpleWhiteboard to register.
+ * @error: (out) (optional) (nullable): A return address for a #GError.
+ *
+ * Registers @whiteboard with @manager.
+ *
+ * Returns: %TRUE if @whiteboard was successfully registered with @manager,
+ * %FALSE otherwise.
+ *
+ * Since: 3.0.0
+ */
+gboolean purple_whiteboard_manager_register(PurpleWhiteboardManager *manager, PurpleWhiteboard *whiteboard, GError **error);
+
+/**
+ * purple_whiteboard_manager_unregister:
+ * @manager: The #PurpleWhiteboardManager instance.
+ * @whiteboard: The #PurpleWhiteboard to unregister.
+ * @error: (out) (optional) (nullable): A return address for a #GError.
+ *
+ * Unregisters @whiteboard from @manager.
+ *
+ * Returns: %TRUE if @whiteboard was successfully unregistered from @manager,
+ * %FALSE otherwise.
+ *
+ * Since: 3.0.0
+ */
+gboolean purple_whiteboard_manager_unregister(PurpleWhiteboardManager *manager, PurpleWhiteboard *whiteboard, GError **error);
+
+/**
+ * purple_whiteboard_manager_find:
+ * @manager: The #PurpleWhiteboardManager instance.
+ * @id: The id of the #PurpleWhiteboard to find.
+ *
+ * Gets the #PurpleWhiteboard identified by @id if found, otherwise %NULL.
+ *
+ * Returns: (transfer full): The #PurpleWhiteboard identified by @id or %NULL.
+ *
+ * Since: 3.0.0
+ */
+PurpleWhiteboard *purple_whiteboard_manager_find(PurpleWhiteboardManager *manager, const gchar *id);
+
+/**
+ * purple_whiteboard_manager_foreach:
+ * @manager: The #PurpleWhiteboardManager instance.
+ * @func: (scope call): The #PurpleWhiteboardManagerForeachFunc to call.
+ * @data: User data to pass to @func.
+ *
+ * Calls @func for each #PurpleWhiteboard that @manager knows about.
+ *
+ * Since: 3.0.0
+ */
+void purple_whiteboard_manager_foreach(PurpleWhiteboardManager *manager, PurpleWhiteboardManagerForeachFunc func, gpointer data);
+
+/**
+ * purple_whiteboard_manager_get_model:
+ * @manager: The #PurpleWhiteboardManager instance.
+ *
+ * Gets the backing model of @manager as a #GListModel.
+ *
+ * Returns: (transfer none) (element-type PurpleWhiteboard): The #GListModel
+ * containing all of the #PurpleWhiteboards registered with @manager.
+ *
+ * Since: 3.0.0
+ */
+GListModel *purple_whiteboard_manager_get_model(PurpleWhiteboardManager *manager);
+
+G_END_DECLS
+
+#endif /* PURPLE_WHITEBOARD_MANAGER_H */
--- a/libpurple/tests/meson.build Thu Sep 02 21:22:55 2021 -0500
+++ b/libpurple/tests/meson.build Thu Sep 02 21:28:40 2021 -0500
@@ -13,7 +13,8 @@
'queued_output_stream',
'trie',
'util',
- 'xmlnode'
+ 'whiteboard_manager',
+ 'xmlnode',
]
test_ui = static_library(
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/tests/test_whiteboard_manager.c Thu Sep 02 21:28:40 2021 -0500
@@ -0,0 +1,54 @@
+/*
+ * Purple - Internet Messaging Library
+ * Copyright (C) Pidgin Developers <devel@pidgin.im>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <glib.h>
+
+#include <purple.h>
+
+#include "test_ui.h"
+
+/******************************************************************************
+ * Tests
+ *****************************************************************************/
+static void
+test_purple_whiteboard_manager_get_default(void) {
+ PurpleWhiteboardManager *manager1 = NULL, *manager2 = NULL;
+
+ manager1 = purple_whiteboard_manager_get_default();
+ g_assert_true(PURPLE_IS_WHITEBOARD_MANAGER(manager1));
+
+ manager2 = purple_whiteboard_manager_get_default();
+ g_assert_true(PURPLE_IS_WHITEBOARD_MANAGER(manager2));
+
+ g_assert_true(manager1 == manager2);
+}
+
+/******************************************************************************
+ * Main
+ *****************************************************************************/
+gint
+main(gint argc, gchar *argv[]) {
+ g_test_init(&argc, &argv, NULL);
+
+ test_ui_purple_init();
+
+ g_test_add_func("/whiteboard-manager/get-default",
+ test_purple_whiteboard_manager_get_default);
+
+ return g_test_run();
+}
--- a/meson.build Thu Sep 02 21:22:55 2021 -0500
+++ b/meson.build Thu Sep 02 21:28:40 2021 -0500
@@ -230,7 +230,7 @@
# #######################################################################
# # Check for GLib 2.44 (required)
# #######################################################################
-glib = dependency('glib-2.0', version : '>= 2.52.0')
+glib = dependency('glib-2.0', version : '>= 2.64.0')
gio = dependency('gio-2.0')
gobject = dependency('gobject-2.0')
gthread = dependency('gthread-2.0')
--- a/pidgin/gtkwhiteboard.c Thu Sep 02 21:22:55 2021 -0500
+++ b/pidgin/gtkwhiteboard.c Thu Sep 02 21:28:40 2021 -0500
@@ -588,13 +588,13 @@
* their username
*/
buddy = purple_blist_find_buddy(purple_whiteboard_get_account(wb),
- purple_whiteboard_get_who(wb));
+ purple_whiteboard_get_id(wb));
gtk_window_set_title(GTK_WINDOW(gtkwb),
buddy != NULL
? purple_buddy_get_contact_alias(buddy)
- : purple_whiteboard_get_who(wb));
- gtk_widget_set_name(GTK_WIDGET(gtkwb), purple_whiteboard_get_who(wb));
+ : purple_whiteboard_get_id(wb));
+ gtk_widget_set_name(GTK_WIDGET(gtkwb), purple_whiteboard_get_id(wb));
gtk_widget_set_size_request(GTK_WIDGET(gtkwb->drawing_area),
gtkwb->width, gtkwb->height);
--- a/po/POTFILES.in Thu Sep 02 21:22:55 2021 -0500
+++ b/po/POTFILES.in Thu Sep 02 21:28:40 2021 -0500
@@ -268,6 +268,7 @@
libpurple/purpleprotocolserver.c
libpurple/purpleuiinfo.c
libpurple/purplewhiteboard.c
+libpurple/purplewhiteboardmanager.c
libpurple/purplewhiteboarduiops.c
libpurple/queuedoutputstream.c
libpurple/request.c