--- a/libpurple/purplerequestfield.c Mon Mar 13 15:26:14 2023 -0500
+++ b/libpurple/purplerequestfield.c Tue Mar 14 00:42:47 2023 -0500
@@ -21,7 +21,6 @@
#include <glib/gi18n-lib.h>
-#include "request/purplerequestfieldstring.h"
#include "purpleprivate.h"
@@ -50,6 +49,7 @@
@@ -107,6 +107,10 @@
g_value_set_boolean(value,
purple_request_field_is_required(field));
+ g_value_set_boolean(value, + purple_request_field_is_filled(field)); case PROP_IS_VALIDATABLE:
g_value_set_boolean(value,
purple_request_field_is_validatable(field));
@@ -280,6 +284,19 @@
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+ * PurpleRequestField:filled: + * Whether the field has been filled. + properties[PROP_FILLED] = g_param_spec_boolean( + "Whether the field has been filled.", + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); * PurpleRequestField:is-validatable:
* Whether the field can be validated by the requestor.
@@ -473,14 +490,17 @@
purple_request_field_is_filled(PurpleRequestField *field) {
+ PurpleRequestFieldClass *klass = NULL; + gboolean filled = TRUE; g_return_val_if_fail(PURPLE_IS_REQUEST_FIELD(field), FALSE);
- if(PURPLE_IS_REQUEST_FIELD_STRING(field)) {
- PurpleRequestFieldString *sfield = PURPLE_REQUEST_FIELD_STRING(field);
- return !purple_strempty(purple_request_field_string_get_value(sfield));
+ klass = PURPLE_REQUEST_FIELD_GET_CLASS(field); + if(klass != NULL && klass->is_filled != NULL) { + filled = klass->is_filled(field);
--- a/libpurple/purplerequestfield.h Mon Mar 13 15:26:14 2023 -0500
+++ b/libpurple/purplerequestfield.h Tue Mar 14 00:42:47 2023 -0500
@@ -53,6 +53,7 @@
GObjectClass parent_class;
+ gboolean (*is_filled)(PurpleRequestField *field); @@ -193,7 +194,11 @@
* purple_request_field_is_filled:
- * Checks, if specified field has value.
+ * Returns whether the field is currently filled. + * Note: For subclassers, if this is not overridden, then the field is assumed + * to always be filled. If the filled status changes, then subclasses should + * notify on [property@RequestField:filled]. * Returns: TRUE if the field has value, or FALSE.
--- a/libpurple/request/purplerequestfieldstring.c Mon Mar 13 15:26:14 2023 -0500
+++ b/libpurple/request/purplerequestfieldstring.c Tue Mar 14 00:42:47 2023 -0500
@@ -57,6 +57,16 @@
/******************************************************************************
+ * PurpleRequestField Implementation + *****************************************************************************/ +purple_request_field_string_is_filled(PurpleRequestField *field) { + PurpleRequestFieldString *strfield = PURPLE_REQUEST_FIELD_STRING(field); + return !purple_strempty(strfield->value); +/****************************************************************************** *****************************************************************************/
G_DEFINE_TYPE(PurpleRequestFieldString, purple_request_field_string,
@@ -138,8 +148,11 @@
purple_request_field_string_class_init(PurpleRequestFieldStringClass *klass) {
+ PurpleRequestFieldClass *field_class = PURPLE_REQUEST_FIELD_CLASS(klass); GObjectClass *obj_class = G_OBJECT_CLASS(klass);
+ field_class->is_filled = purple_request_field_string_is_filled; obj_class->finalize = purple_request_field_string_finalize;
obj_class->get_property = purple_request_field_string_get_property;
obj_class->set_property = purple_request_field_string_set_property;
@@ -237,14 +250,25 @@
purple_request_field_string_set_value(PurpleRequestFieldString *field,
+ gboolean before, after; g_return_if_fail(PURPLE_IS_REQUEST_FIELD_STRING(field));
- if(!purple_strequal(field->value, value)) {
- field->value = g_strdup(value);
+ if(purple_strequal(field->value, value)) { - g_object_notify_by_pspec(G_OBJECT(field), properties[PROP_VALUE]);
+ before = purple_request_field_string_is_filled(PURPLE_REQUEST_FIELD(field)); + field->value = g_strdup(value); + after = purple_request_field_string_is_filled(PURPLE_REQUEST_FIELD(field)); + g_object_freeze_notify(G_OBJECT(field)); + g_object_notify_by_pspec(G_OBJECT(field), properties[PROP_VALUE]); + g_object_notify(G_OBJECT(field), "filled"); + g_object_thaw_notify(G_OBJECT(field)); --- a/libpurple/tests/meson.build Mon Mar 13 15:26:14 2023 -0500
+++ b/libpurple/tests/meson.build Tue Mar 14 00:42:47 2023 -0500
@@ -26,6 +26,7 @@
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/tests/test_request_field.c Tue Mar 14 00:42:47 2023 -0500
@@ -0,0 +1,129 @@
+ * 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/>. +/****************************************************************************** + *****************************************************************************/ +test_request_field_notify_filled_cb(G_GNUC_UNUSED GObject *obj, + G_GNUC_UNUSED GParamSpec *pspec, + gboolean *called = data; +test_request_field_filled_string(void) { + PurpleRequestField *field = NULL; + gboolean called = FALSE; + field = purple_request_field_string_new("test-string", "Test string", NULL, + g_signal_connect(field, "notify::filled", + G_CALLBACK(test_request_field_notify_filled_cb), &called); + g_assert_false(purple_request_field_is_filled(field)); + /* Passing same value should not trigger. */ + purple_request_field_string_set_value(PURPLE_REQUEST_FIELD_STRING(field), + g_assert_false(called); + g_assert_false(purple_request_field_is_filled(field)); + /* Passing an empty string should not trigger, as NULL and "" are + * considered the same. */ + purple_request_field_string_set_value(PURPLE_REQUEST_FIELD_STRING(field), + g_assert_false(called); + g_assert_false(purple_request_field_is_filled(field)); + /* Now that there's a change from empty to filled, notify should occur. */ + purple_request_field_string_set_value(PURPLE_REQUEST_FIELD_STRING(field), + g_assert_true(purple_request_field_is_filled(field)); + /* Passing same value should not trigger. */ + purple_request_field_string_set_value(PURPLE_REQUEST_FIELD_STRING(field), + g_assert_false(called); + g_assert_true(purple_request_field_is_filled(field)); + /* And then going back to empty should notify. */ + purple_request_field_string_set_value(PURPLE_REQUEST_FIELD_STRING(field), + g_assert_false(purple_request_field_is_filled(field)); +test_request_field_filled_nonstring(void) { + /* Anything that's not a string should always be considered filled and + PurpleRequestField *field = NULL; + gboolean called = FALSE; + field = purple_request_field_int_new("test-int", "Test int", 50, 0, 100); + g_signal_connect(field, "notify::filled", + G_CALLBACK(test_request_field_notify_filled_cb), &called); + g_assert_true(purple_request_field_is_filled(field)); + purple_request_field_int_set_value(PURPLE_REQUEST_FIELD_INT(field), 50); + g_assert_false(called); + g_assert_true(purple_request_field_is_filled(field)); + purple_request_field_int_set_value(PURPLE_REQUEST_FIELD_INT(field), 0); + g_assert_false(called); + g_assert_true(purple_request_field_is_filled(field)); + purple_request_field_int_set_value(PURPLE_REQUEST_FIELD_INT(field), 100); + g_assert_false(called); + g_assert_true(purple_request_field_is_filled(field)); +/****************************************************************************** + *****************************************************************************/ +main(gint argc, gchar *argv[]) { + g_test_init(&argc, &argv, NULL); + g_test_add_func("/request-field/filled-string", + test_request_field_filled_string); + g_test_add_func("/request-field/filled-nonstring", + test_request_field_filled_nonstring);