1 /* GObject - GLib Type, Object, Parameter and Signal Library
2 * Copyright (C) 2001, 2003 Red Hat, Inc.
3 *
4 * SPDX-License-Identifier: LGPL-2.1-or-later
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General
17 * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include <glib-object.h>
21
22 #include "marshalers.h"
23 #include "testcommon.h"
24
25 /* What this test tests is the behavior of signal accumulators
26 * Two accumulators are tested:
27 *
28 * 1: A custom accumulator that appends the returned strings
29 * 2: The standard g_signal_accumulator_true_handled that stops
30 * emission on TRUE returns.
31 */
32
33 /* TestObject, a parent class for TestObject */
34 #define TEST_TYPE_OBJECT (test_object_get_type ())
35 typedef struct _TestObject TestObject;
36 typedef struct _TestObjectClass TestObjectClass;
37
38 struct _TestObject
39 {
40 GObject parent_instance;
41 };
42 struct _TestObjectClass
43 {
44 GObjectClass parent_class;
45
46 gchar* (*test_signal1) (TestObject *tobject,
47 gint param);
48 gboolean (*test_signal2) (TestObject *tobject,
49 gint param);
50 GVariant* (*test_signal3) (TestObject *tobject,
51 gboolean *weak_ptr);
52 };
53
54 static GType test_object_get_type (void);
55
56 static gboolean
57 test_signal1_accumulator (GSignalInvocationHint *ihint,
58 GValue *return_accu,
59 const GValue *handler_return,
60 gpointer data)
61 {
62 const gchar *accu_string = g_value_get_string (return_accu);
63 const gchar *new_string = g_value_get_string (handler_return);
64 gchar *result_string;
65
66 if (accu_string)
67 result_string = g_strconcat (accu_string, new_string, NULL);
68 else if (new_string)
69 result_string = g_strdup (new_string);
70 else
71 result_string = NULL;
72
73 g_value_take_string (return_accu, result_string);
74
75 return TRUE;
76 }
77
78 static gchar *
79 test_object_signal1_callback_before (TestObject *tobject,
80 gint param,
81 gpointer data)
82 {
83 return g_strdup ("<before>");
84 }
85
86 static gchar *
87 test_object_real_signal1 (TestObject *tobject,
88 gint param)
89 {
90 return g_strdup ("<default>");
91 }
92
93 static gchar *
94 test_object_signal1_callback_after (TestObject *tobject,
95 gint param,
96 gpointer data)
97 {
98 return g_strdup ("<after>");
99 }
100
101 static gboolean
102 test_object_signal2_callback_before (TestObject *tobject,
103 gint param)
104 {
105 switch (param)
106 {
107 case 1: return TRUE;
108 case 2: return FALSE;
109 case 3: return FALSE;
110 case 4: return FALSE;
111 }
112
113 g_assert_not_reached ();
114 return FALSE;
115 }
116
117 static gboolean
118 test_object_real_signal2 (TestObject *tobject,
119 gint param)
120 {
121 switch (param)
122 {
123 case 1: g_assert_not_reached (); return FALSE;
124 case 2: return TRUE;
125 case 3: return FALSE;
126 case 4: return FALSE;
127 }
128
129 g_assert_not_reached ();
130 return FALSE;
131 }
132
133 static gboolean
134 test_object_signal2_callback_after (TestObject *tobject,
135 gint param)
136 {
137 switch (param)
138 {
139 case 1: g_assert_not_reached (); return FALSE;
140 case 2: g_assert_not_reached (); return FALSE;
141 case 3: return TRUE;
142 case 4: return FALSE;
143 }
144
145 g_assert_not_reached ();
146 return FALSE;
147 }
148
149 static gboolean
150 test_signal3_accumulator (GSignalInvocationHint *ihint,
151 GValue *return_accu,
152 const GValue *handler_return,
153 gpointer data)
154 {
155 GVariant *variant;
156
157 variant = g_value_get_variant (handler_return);
158 g_assert_false (g_variant_is_floating (variant));
159
160 g_value_set_variant (return_accu, variant);
161
162 return variant == NULL;
163 }
164
165 /* To be notified when the variant is finalised, we construct
166 * it from data with a custom GDestroyNotify.
167 */
168
169 typedef struct {
170 char *mem;
171 gsize n;
172 gboolean *weak_ptr;
173 } VariantData;
174
175 static void
176 free_data (VariantData *data)
177 {
178 *(data->weak_ptr) = TRUE;
179 g_free (data->mem);
180 g_slice_free (VariantData, data);
181 }
182
183 static GVariant *
184 test_object_real_signal3 (TestObject *tobject,
185 gboolean *weak_ptr)
186 {
187 GVariant *variant;
188 VariantData *data;
189
190 variant = g_variant_ref_sink (g_variant_new_uint32 (42));
191 data = g_slice_new (VariantData);
192 data->weak_ptr = weak_ptr;
193 data->n = g_variant_get_size (variant);
194 data->mem = g_malloc (data->n);
195 g_variant_store (variant, data->mem);
196 g_variant_unref (variant);
197
198 variant = g_variant_new_from_data (G_VARIANT_TYPE ("u"),
199 data->mem,
200 data->n,
201 TRUE,
202 (GDestroyNotify) free_data,
203 data);
204 return g_variant_ref_sink (variant);
205 }
206
207 static void
208 test_object_class_init (TestObjectClass *class)
209 {
210 class->test_signal1 = test_object_real_signal1;
211 class->test_signal2 = test_object_real_signal2;
212 class->test_signal3 = test_object_real_signal3;
213
214 g_signal_new ("test-signal1",
215 G_OBJECT_CLASS_TYPE (class),
216 G_SIGNAL_RUN_LAST,
217 G_STRUCT_OFFSET (TestObjectClass, test_signal1),
218 test_signal1_accumulator, NULL,
219 test_STRING__INT,
220 G_TYPE_STRING, 1, G_TYPE_INT);
221 g_signal_new ("test-signal2",
222 G_OBJECT_CLASS_TYPE (class),
223 G_SIGNAL_RUN_LAST,
224 G_STRUCT_OFFSET (TestObjectClass, test_signal2),
225 g_signal_accumulator_true_handled, NULL,
226 test_BOOLEAN__INT,
227 G_TYPE_BOOLEAN, 1, G_TYPE_INT);
228 g_signal_new ("test-signal3",
229 G_OBJECT_CLASS_TYPE (class),
230 G_SIGNAL_RUN_LAST,
231 G_STRUCT_OFFSET (TestObjectClass, test_signal3),
232 test_signal3_accumulator, NULL,
233 test_VARIANT__POINTER,
234 G_TYPE_VARIANT, 1, G_TYPE_POINTER);
235 }
236
237 static DEFINE_TYPE(TestObject, test_object,
238 test_object_class_init, NULL, NULL,
239 G_TYPE_OBJECT);
240
241 static void
242 test_accumulator (void)
243 {
244 TestObject *object;
245 gchar *string_result;
246 gboolean bool_result;
247 gboolean variant_finalised;
248 GVariant *variant_result;
249
250 object = g_object_new (TEST_TYPE_OBJECT, NULL);
251
252 g_signal_connect (object, "test-signal1",
253 G_CALLBACK (test_object_signal1_callback_before), NULL);
254 g_signal_connect_after (object, "test-signal1",
255 G_CALLBACK (test_object_signal1_callback_after), NULL);
256
257 g_signal_emit_by_name (object, "test-signal1", 0, &string_result);
258 g_assert_cmpstr (string_result, ==, "<before><default><after>");
259 g_free (string_result);
260
261 g_signal_connect (object, "test-signal2",
262 G_CALLBACK (test_object_signal2_callback_before), NULL);
263 g_signal_connect_after (object, "test-signal2",
264 G_CALLBACK (test_object_signal2_callback_after), NULL);
265
266 bool_result = FALSE;
267 g_signal_emit_by_name (object, "test-signal2", 1, &bool_result);
268 g_assert_true (bool_result);
269 bool_result = FALSE;
270 g_signal_emit_by_name (object, "test-signal2", 2, &bool_result);
271 g_assert_true (bool_result);
272 bool_result = FALSE;
273 g_signal_emit_by_name (object, "test-signal2", 3, &bool_result);
274 g_assert_true (bool_result);
275 bool_result = TRUE;
276 g_signal_emit_by_name (object, "test-signal2", 4, &bool_result);
277 g_assert_false (bool_result);
278
279 variant_finalised = FALSE;
280 variant_result = NULL;
281 g_signal_emit_by_name (object, "test-signal3", &variant_finalised, &variant_result);
282 g_assert_nonnull (variant_result);
283 g_assert_false (g_variant_is_floating (variant_result));
284
285 /* Test that variant_result had refcount 1 */
286 g_assert_false (variant_finalised);
287 g_variant_unref (variant_result);
288 g_assert_true (variant_finalised);
289
290 g_object_unref (object);
291 }
292
293 int
294 main (int argc,
295 char *argv[])
296 {
297 g_log_set_always_fatal (g_log_set_always_fatal (G_LOG_FATAL_MASK) |
298 G_LOG_LEVEL_WARNING |
299 G_LOG_LEVEL_CRITICAL);
300
301 g_test_init (&argc, &argv, NULL);
302
303 g_test_add_func ("/gobject/accumulator", test_accumulator);
304
305 return g_test_run ();
306 }