1 | /* gtkaccessibleattributeset.c: Accessible attribute content |
2 | * |
3 | * Copyright 2020 GNOME Foundation |
4 | * |
5 | * SPDX-License-Identifier: LGPL-2.1-or-later |
6 | * |
7 | * This library is free software; you can redistribute it and/or |
8 | * modify it under the terms of the GNU Lesser General Public |
9 | * License as published by the Free Software Foundation; either |
10 | * version 2.1 of the License, or (at your option) any later version. |
11 | * |
12 | * This library is distributed in the hope that it will be useful, |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
15 | * Lesser General Public License for more details. |
16 | * |
17 | * You should have received a copy of the GNU Lesser General Public |
18 | * License along with this library; if not, see <http://www.gnu.org/licenses/>. |
19 | */ |
20 | |
21 | #include "config.h" |
22 | |
23 | #include "gtkaccessibleattributesetprivate.h" |
24 | |
25 | #include "gtkbitmaskprivate.h" |
26 | #include "gtkenums.h" |
27 | |
28 | struct _GtkAccessibleAttributeSet |
29 | { |
30 | gsize n_attributes; |
31 | |
32 | GtkAccessibleAttributeNameFunc name_func; |
33 | GtkAccessibleAttributeDefaultFunc default_func; |
34 | |
35 | GtkBitmask *attributes_set; |
36 | |
37 | GtkAccessibleValue **attribute_values; |
38 | }; |
39 | |
40 | static GtkAccessibleAttributeSet * |
41 | gtk_accessible_attribute_set_init (GtkAccessibleAttributeSet *self, |
42 | gsize n_attributes, |
43 | GtkAccessibleAttributeNameFunc name_func, |
44 | GtkAccessibleAttributeDefaultFunc default_func) |
45 | { |
46 | self->n_attributes = n_attributes; |
47 | self->name_func = name_func; |
48 | self->default_func = default_func; |
49 | self->attribute_values = g_new (GtkAccessibleValue *, n_attributes); |
50 | self->attributes_set = _gtk_bitmask_new (); |
51 | |
52 | /* Initialize all attribute values, so we can always get the full attribute */ |
53 | for (int i = 0; i < self->n_attributes; i++) |
54 | self->attribute_values[i] = (* self->default_func) (i); |
55 | |
56 | return self; |
57 | } |
58 | |
59 | GtkAccessibleAttributeSet * |
60 | gtk_accessible_attribute_set_new (gsize n_attributes, |
61 | GtkAccessibleAttributeNameFunc name_func, |
62 | GtkAccessibleAttributeDefaultFunc default_func) |
63 | { |
64 | GtkAccessibleAttributeSet *set = g_rc_box_new0 (GtkAccessibleAttributeSet); |
65 | |
66 | return gtk_accessible_attribute_set_init (self: set, n_attributes, name_func, default_func); |
67 | } |
68 | |
69 | GtkAccessibleAttributeSet * |
70 | gtk_accessible_attribute_set_ref (GtkAccessibleAttributeSet *self) |
71 | { |
72 | g_return_val_if_fail (self != NULL, NULL); |
73 | |
74 | return g_rc_box_acquire (self); |
75 | } |
76 | |
77 | static void |
78 | gtk_accessible_attribute_set_free (gpointer data) |
79 | { |
80 | GtkAccessibleAttributeSet *self = data; |
81 | |
82 | for (int i = 0; i < self->n_attributes; i++) |
83 | { |
84 | if (self->attribute_values[i] != NULL) |
85 | gtk_accessible_value_unref (self: self->attribute_values[i]); |
86 | } |
87 | |
88 | g_free (mem: self->attribute_values); |
89 | |
90 | _gtk_bitmask_free (mask: self->attributes_set); |
91 | } |
92 | |
93 | void |
94 | gtk_accessible_attribute_set_unref (GtkAccessibleAttributeSet *self) |
95 | { |
96 | g_rc_box_release_full (mem_block: self, clear_func: gtk_accessible_attribute_set_free); |
97 | } |
98 | |
99 | /*< private > |
100 | * gtk_accessible_attribute_set_add: |
101 | * @self: a `GtkAccessibleAttributeSet` |
102 | * @attribute: the attribute to set |
103 | * @value: (nullable): a `GtkAccessibleValue` |
104 | * |
105 | * Adds @attribute to the attributes set, and sets its value. |
106 | * |
107 | * If @value is %NULL, the @attribute is reset to its default value. |
108 | * |
109 | * If you want to remove @attribute from the set, use gtk_accessible_attribute_set_remove() |
110 | * instead. |
111 | * |
112 | * Returns: %TRUE if the set was modified, and %FALSE otherwise |
113 | */ |
114 | gboolean |
115 | gtk_accessible_attribute_set_add (GtkAccessibleAttributeSet *self, |
116 | int attribute, |
117 | GtkAccessibleValue *value) |
118 | { |
119 | g_return_val_if_fail (attribute >= 0 && attribute < self->n_attributes, FALSE); |
120 | |
121 | if (value != NULL) |
122 | { |
123 | if (gtk_accessible_value_equal (value_a: value, value_b: self->attribute_values[attribute])) |
124 | return FALSE; |
125 | } |
126 | else |
127 | { |
128 | if (!_gtk_bitmask_get (mask: self->attributes_set, index_: attribute)) |
129 | return FALSE; |
130 | } |
131 | |
132 | g_clear_pointer (&(self->attribute_values[attribute]), gtk_accessible_value_unref); |
133 | |
134 | if (value != NULL) |
135 | self->attribute_values[attribute] = gtk_accessible_value_ref (self: value); |
136 | else |
137 | self->attribute_values[attribute] = (* self->default_func) (attribute); |
138 | |
139 | self->attributes_set = _gtk_bitmask_set (mask: self->attributes_set, index_: attribute, TRUE); |
140 | |
141 | return TRUE; |
142 | } |
143 | |
144 | /*< private > |
145 | * gtk_accessible_attribute_set_remove: |
146 | * @self: a `GtkAccessibleAttributeSet` |
147 | * @attribute: the attribute to be removed |
148 | * |
149 | * Resets the @attribute in the given `GtkAccessibleAttributeSet` |
150 | * to its default value. |
151 | * |
152 | * Returns: %TRUE if the set was modified, and %FALSE otherwise |
153 | */ |
154 | gboolean |
155 | gtk_accessible_attribute_set_remove (GtkAccessibleAttributeSet *self, |
156 | int attribute) |
157 | { |
158 | g_return_val_if_fail (attribute >= 0 && attribute < self->n_attributes, FALSE); |
159 | |
160 | if (!_gtk_bitmask_get (mask: self->attributes_set, index_: attribute)) |
161 | return FALSE; |
162 | |
163 | g_clear_pointer (&(self->attribute_values[attribute]), gtk_accessible_value_unref); |
164 | |
165 | self->attribute_values[attribute] = (* self->default_func) (attribute); |
166 | self->attributes_set = _gtk_bitmask_set (mask: self->attributes_set, index_: attribute, FALSE); |
167 | |
168 | return TRUE; |
169 | } |
170 | |
171 | gboolean |
172 | gtk_accessible_attribute_set_contains (GtkAccessibleAttributeSet *self, |
173 | int attribute) |
174 | { |
175 | g_return_val_if_fail (attribute >= 0 && attribute < self->n_attributes, FALSE); |
176 | |
177 | return _gtk_bitmask_get (mask: self->attributes_set, index_: attribute); |
178 | } |
179 | |
180 | /*< private > |
181 | * gtk_accessible_attribute_set_get_value: |
182 | * @self: a `GtkAccessibleAttributeSet` |
183 | * @attribute: the attribute to retrieve |
184 | * |
185 | * Retrieves the value of the given @attribute in the set. |
186 | * |
187 | * Returns: (transfer none): the value for the attribute |
188 | */ |
189 | GtkAccessibleValue * |
190 | gtk_accessible_attribute_set_get_value (GtkAccessibleAttributeSet *self, |
191 | int attribute) |
192 | { |
193 | g_return_val_if_fail (attribute >= 0 && attribute < self->n_attributes, NULL); |
194 | |
195 | return self->attribute_values[attribute]; |
196 | } |
197 | |
198 | gsize |
199 | gtk_accessible_attribute_set_get_length (GtkAccessibleAttributeSet *self) |
200 | { |
201 | return self->n_attributes; |
202 | } |
203 | |
204 | guint |
205 | gtk_accessible_attribute_set_get_changed (GtkAccessibleAttributeSet *self) |
206 | { |
207 | guint changed = 0; |
208 | |
209 | for (gsize i = 0; i < self->n_attributes; i++) |
210 | { |
211 | if (gtk_accessible_attribute_set_contains (self, attribute: i)) |
212 | changed |= (1 << i); |
213 | } |
214 | |
215 | return changed; |
216 | } |
217 | |
218 | /*< private > |
219 | * gtk_accessible_attribute_set_print: |
220 | * @self: a `GtkAccessibleAttributeSet` |
221 | * @only_set: %TRUE if only the set attributes should be printed |
222 | * @buffer: a `GString` |
223 | * |
224 | * Prints the contents of the `GtkAccessibleAttributeSet` into @buffer. |
225 | */ |
226 | void |
227 | gtk_accessible_attribute_set_print (GtkAccessibleAttributeSet *self, |
228 | gboolean only_set, |
229 | GString *buffer) |
230 | { |
231 | if (only_set && _gtk_bitmask_is_empty (mask: self->attributes_set)) |
232 | { |
233 | g_string_append (string: buffer, val: "{}" ); |
234 | return; |
235 | } |
236 | |
237 | g_string_append (string: buffer, val: "{\n" ); |
238 | |
239 | for (gsize i = 0; i < self->n_attributes; i++) |
240 | { |
241 | if (only_set && !_gtk_bitmask_get (mask: self->attributes_set, index_: i)) |
242 | continue; |
243 | |
244 | g_string_append (string: buffer, val: " " ); |
245 | g_string_append (string: buffer, val: self->name_func (i)); |
246 | g_string_append (string: buffer, val: ": " ); |
247 | |
248 | gtk_accessible_value_print (self: self->attribute_values[i], buffer); |
249 | |
250 | g_string_append (string: buffer, val: ",\n" ); |
251 | } |
252 | |
253 | g_string_append (string: buffer, val: "}" ); |
254 | } |
255 | |
256 | /*< private > |
257 | * gtk_accessible_attribute_set_to_string: |
258 | * @self: a `GtkAccessibleAttributeSet` |
259 | * |
260 | * Prints the contents of a `GtkAccessibleAttributeSet` into a string. |
261 | * |
262 | * Returns: (transfer full): a newly allocated string with the contents |
263 | * of the `GtkAccessibleAttributeSet` |
264 | */ |
265 | char * |
266 | gtk_accessible_attribute_set_to_string (GtkAccessibleAttributeSet *self) |
267 | { |
268 | GString *buf = g_string_new (NULL); |
269 | |
270 | gtk_accessible_attribute_set_print (self, TRUE, buffer: buf); |
271 | |
272 | return g_string_free (string: buf, FALSE); |
273 | } |
274 | |