1 /* font-manager-font-model.c
2 *
3 * Copyright (C) 2009 - 2021 Jerry Casiano
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program.
17 *
18 * If not, see <http://www.gnu.org/licenses/gpl-3.0.txt>.
19 */
20
21 #include "font-manager-font-model.h"
22
23 /**
24 * SECTION: font-manager-font-model
25 * @short_description: Font data model
26 * @title: Font Model
27 * @include: font-manager-font-model.h
28 * @see_also: #FontManagerFamily #FontManagerFont
29 *
30 * Minimal implementation which wraps the #JsonArray returned by #font_manager_sort_json_font_listing().
31 *
32 * This model provides read-only access to available #FontManagerFamily objects.
33 */
34
35 struct _FontManagerFontModel
36 {
37 GObject parent_instance;
38
39 gint stamp;
40 JsonArray *available_fonts;
41 };
42
43 static void g_list_model_interface_init (GListModelInterface *iface);
44 static void gtk_tree_model_interface_init (GtkTreeModelIface *iface);
45 static void gtk_tree_drag_source_interface_init (GtkTreeDragSourceIface *iface);
46 static void gtk_tree_drag_dest_interface_init (GtkTreeDragDestIface *iface);
47
48 G_DEFINE_TYPE_WITH_CODE(FontManagerFontModel, font_manager_font_model, G_TYPE_OBJECT,
49 G_IMPLEMENT_INTERFACE(G_TYPE_LIST_MODEL, g_list_model_interface_init)
50 G_IMPLEMENT_INTERFACE(GTK_TYPE_TREE_MODEL, gtk_tree_model_interface_init)
51 G_IMPLEMENT_INTERFACE(GTK_TYPE_TREE_DRAG_SOURCE, gtk_tree_drag_source_interface_init)
52 G_IMPLEMENT_INTERFACE(GTK_TYPE_TREE_DRAG_DEST, gtk_tree_drag_dest_interface_init))
53
54 enum
55 {
56 PROP_RESERVED,
57 PROP_SOURCE,
58 N_PROPERTIES
59 };
60
61 GType COLUMN_TYPES [FONT_MANAGER_FONT_MODEL_N_COLUMNS] = {
62 G_TYPE_OBJECT,
63 G_TYPE_STRING,
64 G_TYPE_STRING,
65 G_TYPE_INT
66 };
67
68 GType
font_manager_font_model_column_get_type(void)69 font_manager_font_model_column_get_type (void)
70 {
71 static volatile gsize g_define_type_id__volatile = 0;
72
73 if (g_once_init_enter (&g_define_type_id__volatile))
74 {
75 static const GEnumValue values[] = {
76 { FONT_MANAGER_FONT_MODEL_OBJECT, "FONT_MANAGER_FONT_MODEL_OBJECT", "object" },
77 { FONT_MANAGER_FONT_MODEL_NAME, "FONT_MANAGER_FONT_MODEL_NAME", "name" },
78 { FONT_MANAGER_FONT_MODEL_DESCRIPTION, "FONT_MANAGER_FONT_MODEL_DESCRIPTION", "description" },
79 { FONT_MANAGER_FONT_MODEL_COUNT, "FONT_MANAGER_FONT_MODEL_COUNT", "count" },
80 { FONT_MANAGER_FONT_MODEL_N_COLUMNS, "FONT_MANAGER_FONT_MODEL_N_COLUMNS", "n-columns" },
81 { 0, NULL, NULL }
82 };
83 GType g_define_type_id =
84 g_enum_register_static (g_intern_static_string ("FontManagerFontModelColumn"), values);
85 g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
86 }
87
88 return g_define_type_id__volatile;
89 }
90
91 #define SOURCE "source-array"
92
93 gint
get_n_variations(FontManagerFontModel * self,gint index)94 get_n_variations (FontManagerFontModel *self, gint index)
95 {
96 JsonObject *family = json_array_get_object_element(self->available_fonts, index);
97 return (gint) json_object_get_int_member(family, "n_variations");
98 }
99
100 gboolean
invalid_iter(GtkTreeIter * iter)101 invalid_iter (GtkTreeIter *iter) {
102 iter->stamp = 0;
103 return FALSE;
104 }
105
106 /* GtkTreeModelIface */
107
108 static GtkTreeModelFlags
font_manager_font_model_get_flags(G_GNUC_UNUSED GtkTreeModel * tree_model)109 font_manager_font_model_get_flags (G_GNUC_UNUSED GtkTreeModel *tree_model)
110 {
111 return GTK_TREE_MODEL_ITERS_PERSIST;
112 }
113
114 static gint
font_manager_font_model_get_n_columns(G_GNUC_UNUSED GtkTreeModel * tree_model)115 font_manager_font_model_get_n_columns (G_GNUC_UNUSED GtkTreeModel *tree_model)
116 {
117 return FONT_MANAGER_FONT_MODEL_N_COLUMNS;
118 }
119
120 static GType
font_manager_font_model_get_column_type(G_GNUC_UNUSED GtkTreeModel * tree_model,gint index)121 font_manager_font_model_get_column_type (G_GNUC_UNUSED GtkTreeModel *tree_model, gint index)
122 {
123 g_return_val_if_fail(index < FONT_MANAGER_FONT_MODEL_N_COLUMNS, G_TYPE_INVALID);
124 return COLUMN_TYPES[index];
125 }
126
127 static gboolean
font_manager_font_model_get_iter(GtkTreeModel * tree_model,GtkTreeIter * iter,GtkTreePath * path)128 font_manager_font_model_get_iter (GtkTreeModel *tree_model,
129 GtkTreeIter *iter,
130 GtkTreePath *path)
131 {
132 FontManagerFontModel *self = FONT_MANAGER_FONT_MODEL(tree_model);
133 g_return_val_if_fail(self != NULL, FALSE);
134 g_return_val_if_fail(path != NULL, FALSE);
135 gint depth = gtk_tree_path_get_depth(path);
136 gint *indices = gtk_tree_path_get_indices(path);
137 if (!self->available_fonts || indices[0] >= ((int) json_array_get_length(self->available_fonts)))
138 return invalid_iter(iter);
139 iter->stamp = self->stamp;
140 iter->user_data = GINT_TO_POINTER(indices[0]);
141 iter->user_data2 = GINT_TO_POINTER(-1);
142 if (depth > 1) {
143 gint n_variations = get_n_variations(self, indices[0]);
144 if (indices[1] >= n_variations)
145 return invalid_iter(iter);
146 iter->user_data2 = GINT_TO_POINTER(indices[1]);
147 }
148 return TRUE;
149 }
150
151 static GtkTreePath *
font_manager_font_model_get_path(GtkTreeModel * tree_model,GtkTreeIter * iter)152 font_manager_font_model_get_path (GtkTreeModel *tree_model, GtkTreeIter *iter)
153 {
154 FontManagerFontModel *self = FONT_MANAGER_FONT_MODEL(tree_model);
155 g_return_val_if_fail(self != NULL, NULL);
156 g_return_val_if_fail(iter->stamp == self->stamp, NULL);
157 GtkTreePath *path = gtk_tree_path_new();
158 gtk_tree_path_append_index(path, GPOINTER_TO_INT(iter->user_data));
159 if (GPOINTER_TO_INT(iter->user_data2) != -1)
160 gtk_tree_path_append_index(path, GPOINTER_TO_INT(iter->user_data2));
161 return path;
162 }
163
164 static void
font_manager_font_model_get_value(GtkTreeModel * tree_model,GtkTreeIter * iter,gint column,GValue * value)165 font_manager_font_model_get_value (GtkTreeModel *tree_model,
166 GtkTreeIter *iter,
167 gint column,
168 GValue *value)
169 {
170 FontManagerFontModel *self = FONT_MANAGER_FONT_MODEL(tree_model);
171 g_return_if_fail(self != NULL);
172 g_return_if_fail(self->available_fonts != NULL);
173 g_return_if_fail(json_array_get_length(self->available_fonts) > 0);
174 g_return_if_fail(iter != NULL);
175 g_return_if_fail(iter->stamp == self->stamp);
176 g_value_init(value, COLUMN_TYPES[column]);
177 JsonObject *root = NULL, *child = NULL;
178 root = json_array_get_object_element(self->available_fonts, GPOINTER_TO_INT(iter->user_data));
179 gboolean root_node = (GPOINTER_TO_INT(iter->user_data2) == -1);
180 if (!root_node) {
181 JsonArray *children = json_object_get_array_member(root, "variations");
182 child = json_array_get_object_element(children, GPOINTER_TO_INT(iter->user_data2));
183 }
184 JsonObject *obj = root_node ? root : child;
185 const gchar *member = root_node ? "family" : "style";
186 switch (column) {
187 case FONT_MANAGER_FONT_MODEL_NAME:
188 g_value_set_string(value, json_object_get_string_member(obj, member));
189 break;
190 case FONT_MANAGER_FONT_MODEL_DESCRIPTION:
191 g_value_set_string(value, json_object_get_string_member(obj, "description"));
192 break;
193 case FONT_MANAGER_FONT_MODEL_COUNT:
194 if (root_node)
195 g_value_set_int(value, get_n_variations(self, GPOINTER_TO_INT(iter->user_data)));
196 else
197 g_value_set_int(value, -1);
198 break;
199 case FONT_MANAGER_FONT_MODEL_OBJECT:
200 if (root_node) {
201 g_autoptr(FontManagerFamily) family = font_manager_family_new();
202 g_object_set(family, "source-object", obj, NULL);
203 g_value_set_object(value, family);
204 } else {
205 g_autoptr(FontManagerFont) font = font_manager_font_new();
206 g_object_set(font, "source-object", obj, NULL);
207 g_value_set_object(value, font);
208 }
209 break;
210 default:
211 g_critical(G_STRLOC ": Invalid column index : %i", column);
212 }
213 return;
214 }
215
216 static gboolean
font_manager_font_model_iter_next(GtkTreeModel * tree_model,GtkTreeIter * iter)217 font_manager_font_model_iter_next (GtkTreeModel *tree_model, GtkTreeIter *iter)
218 {
219 FontManagerFontModel *self = FONT_MANAGER_FONT_MODEL(tree_model);
220 g_return_val_if_fail(self != NULL, FALSE);
221 g_return_val_if_fail(iter != NULL, FALSE);
222 g_return_val_if_fail(iter->stamp == self->stamp, FALSE);
223 if (!self->available_fonts || json_array_get_length(self->available_fonts) < 1)
224 return invalid_iter(iter);
225 gint index = GPOINTER_TO_INT(iter->user_data);
226 if (GPOINTER_TO_INT(iter->user_data2) == -1) {
227 gint n_root_nodes = (gint) json_array_get_length(self->available_fonts);
228 if (!(index < n_root_nodes - 1))
229 return invalid_iter(iter);
230 iter->user_data = GINT_TO_POINTER(index + 1);
231 } else {
232 gint n_children = get_n_variations(self, index);
233 index = GPOINTER_TO_INT(iter->user_data2);
234 if (!(index < n_children - 1))
235 return invalid_iter(iter);
236 iter->user_data2 = GINT_TO_POINTER(index + 1);
237 }
238 return TRUE;
239 }
240
241 static gboolean
font_manager_font_model_iter_previous(GtkTreeModel * tree_model,GtkTreeIter * iter)242 font_manager_font_model_iter_previous (GtkTreeModel *tree_model, GtkTreeIter *iter)
243 {
244 FontManagerFontModel *self = FONT_MANAGER_FONT_MODEL(tree_model);
245 g_return_val_if_fail(self != NULL, FALSE);
246 g_return_val_if_fail(iter != NULL, FALSE);
247 g_return_val_if_fail(iter->stamp == self->stamp, FALSE);
248 if (!self->available_fonts || json_array_get_length(self->available_fonts) < 1)
249 return invalid_iter(iter);
250 gint index = GPOINTER_TO_INT(iter->user_data);
251 if (GPOINTER_TO_INT(iter->user_data2) == -1) {
252 if (index < 1)
253 return invalid_iter(iter);
254 iter->user_data = GINT_TO_POINTER(index - 1);
255 } else {
256 index = GPOINTER_TO_INT(iter->user_data2);
257 if (index < 1)
258 return invalid_iter(iter);
259 iter->user_data2 = GINT_TO_POINTER(index - 1);
260 }
261 return TRUE;
262 }
263
264 static gboolean
font_manager_font_model_iter_children(GtkTreeModel * tree_model,GtkTreeIter * iter,GtkTreeIter * parent)265 font_manager_font_model_iter_children (GtkTreeModel *tree_model,
266 GtkTreeIter *iter,
267 GtkTreeIter *parent)
268 {
269 FontManagerFontModel *self = FONT_MANAGER_FONT_MODEL(tree_model);
270 g_return_val_if_fail(self != NULL, FALSE);
271 iter->stamp = self->stamp;
272 if (!self->available_fonts || json_array_get_length(self->available_fonts) < 1)
273 return invalid_iter(iter);
274 /* Special case - if parent equals %NULL this function should return the first node */
275 if (parent == NULL) {
276 iter->user_data = GINT_TO_POINTER(0);
277 iter->user_data2 = GINT_TO_POINTER(-1);
278 } else if (GPOINTER_TO_INT(parent->user_data2) != -1) {
279 /* Maximum depth of this model is 2 */
280 return invalid_iter(iter);
281 } else {
282 iter->user_data = parent->user_data;
283 iter->user_data2 = GINT_TO_POINTER(0);
284 }
285 return TRUE;
286 }
287
288 static gboolean
font_manager_font_model_iter_has_child(GtkTreeModel * tree_model,GtkTreeIter * iter)289 font_manager_font_model_iter_has_child (GtkTreeModel *tree_model, GtkTreeIter *iter)
290 {
291 FontManagerFontModel *self = FONT_MANAGER_FONT_MODEL(tree_model);
292 g_return_val_if_fail(self != NULL, FALSE);
293 g_return_val_if_fail(iter != NULL, FALSE);
294 g_return_val_if_fail(iter->stamp == self->stamp, FALSE);
295 if (!self->available_fonts || json_array_get_length(self->available_fonts) < 1)
296 return FALSE;
297 return (GPOINTER_TO_INT(iter->user_data2) == -1);
298 }
299
300 static gint
font_manager_font_model_iter_n_children(GtkTreeModel * tree_model,GtkTreeIter * iter)301 font_manager_font_model_iter_n_children (GtkTreeModel *tree_model, GtkTreeIter *iter)
302 {
303 FontManagerFontModel *self = FONT_MANAGER_FONT_MODEL(tree_model);
304 g_return_val_if_fail(self != NULL, 0);
305 g_return_val_if_fail(self->available_fonts != NULL, 0);
306 /* Special case - if iter is %NULL this function should return the number of toplevel nodes */
307 if (iter == NULL)
308 return ((gint) json_array_get_length(self->available_fonts));
309 return get_n_variations(self, GPOINTER_TO_INT(iter->user_data));
310 }
311
312 static gboolean
font_manager_font_model_iter_nth_child(GtkTreeModel * tree_model,GtkTreeIter * iter,GtkTreeIter * parent,gint n)313 font_manager_font_model_iter_nth_child (GtkTreeModel *tree_model,
314 GtkTreeIter *iter,
315 GtkTreeIter *parent,
316 gint n)
317 {
318 FontManagerFontModel *self = FONT_MANAGER_FONT_MODEL(tree_model);
319 g_return_val_if_fail(self != NULL, FALSE);
320 g_return_val_if_fail(n >= 0, FALSE);
321 if (!self->available_fonts || json_array_get_length(self->available_fonts) < 1)
322 return FALSE;
323 iter->stamp = self->stamp;
324 /* Special case - if parent is %NULL this function should set iter to toplevel node n */
325 if (parent == NULL) {
326 gint n_root_nodes = (gint) json_array_get_length(self->available_fonts);
327 if (n < n_root_nodes) {
328 iter->user_data = GINT_TO_POINTER(n);
329 iter->user_data2 = GINT_TO_POINTER(-1);
330 return TRUE;
331 } else {
332 return invalid_iter(iter);
333 }
334 }
335
336 g_return_val_if_fail(parent->stamp == self->stamp, FALSE);
337 gint n_children = get_n_variations(self, GPOINTER_TO_INT(parent->user_data));
338
339 if (n > n_children -1) {
340 return invalid_iter(iter);
341 } else {
342 iter->user_data = parent->user_data;
343 iter->user_data2 = GINT_TO_POINTER(n);
344 return TRUE;
345 }
346
347 }
348
349 static gboolean
font_manager_font_model_iter_parent(GtkTreeModel * tree_model,GtkTreeIter * iter,GtkTreeIter * child)350 font_manager_font_model_iter_parent (GtkTreeModel *tree_model,
351 GtkTreeIter *iter,
352 GtkTreeIter *child)
353 {
354 FontManagerFontModel *self = FONT_MANAGER_FONT_MODEL(tree_model);
355 g_return_val_if_fail(self != NULL, FALSE);
356 g_return_val_if_fail(child->stamp == self->stamp, FALSE);
357 g_return_val_if_fail(child->user_data != NULL, FALSE);
358 g_return_val_if_fail(child->user_data2 != NULL, FALSE);
359 iter->stamp = self->stamp;
360 iter->user_data = child->user_data;
361 iter->user_data2 = GINT_TO_POINTER(-1);
362 return TRUE;
363 }
364
365 /* GListModelInterface */
366
367 static GType
font_manager_font_model_get_item_type(G_GNUC_UNUSED GListModel * self)368 font_manager_font_model_get_item_type (G_GNUC_UNUSED GListModel *self)
369 {
370 return FONT_MANAGER_TYPE_FAMILY;
371 }
372
373 static guint
font_manager_font_model_get_n_items(GListModel * self)374 font_manager_font_model_get_n_items (GListModel *self)
375 {
376 g_return_val_if_fail(self != NULL, 0);
377 FontManagerFontModel *model = FONT_MANAGER_FONT_MODEL(self);
378 return json_array_get_length(model->available_fonts);
379 }
380
381 static gpointer
font_manager_font_model_get_item(GListModel * self,guint position)382 font_manager_font_model_get_item (GListModel *self, guint position)
383 {
384 g_return_val_if_fail(self != NULL, NULL);
385 if (position >= font_manager_font_model_get_n_items(self))
386 return NULL;
387 FontManagerFontModel *model = FONT_MANAGER_FONT_MODEL(self);
388 JsonObject *obj = json_array_get_object_element(model->available_fonts, position);
389 FontManagerFamily *family = font_manager_family_new();
390 g_object_set(G_OBJECT(family), "source-object", obj, NULL);
391 return family;
392 }
393
394 static void
g_list_model_interface_init(GListModelInterface * iface)395 g_list_model_interface_init (GListModelInterface *iface)
396 {
397 iface->get_item_type = font_manager_font_model_get_item_type;
398 iface->get_n_items = font_manager_font_model_get_n_items;
399 iface->get_item = font_manager_font_model_get_item;
400 return;
401 }
402
403 /* GtkTreeModelIface */
404
405 static void
gtk_tree_model_interface_init(GtkTreeModelIface * iface)406 gtk_tree_model_interface_init (GtkTreeModelIface *iface)
407 {
408 iface->get_flags = font_manager_font_model_get_flags;
409 iface->get_n_columns = font_manager_font_model_get_n_columns;
410 iface->get_column_type = font_manager_font_model_get_column_type;
411 iface->get_iter = font_manager_font_model_get_iter;
412 iface->get_path = font_manager_font_model_get_path;
413 iface->get_value = font_manager_font_model_get_value;
414 iface->iter_next = font_manager_font_model_iter_next;
415 iface->iter_previous = font_manager_font_model_iter_previous;
416 iface->iter_children = font_manager_font_model_iter_children;
417 iface->iter_has_child = font_manager_font_model_iter_has_child;
418 iface->iter_n_children = font_manager_font_model_iter_n_children;
419 iface->iter_nth_child = font_manager_font_model_iter_nth_child;
420 iface->iter_parent = font_manager_font_model_iter_parent;
421 return;
422 }
423
424 /* GtkTreeDragSourceIface */
425
426 static gboolean
font_manager_font_model_row_draggable(G_GNUC_UNUSED GtkTreeDragSource * source,G_GNUC_UNUSED GtkTreePath * path)427 font_manager_font_model_row_draggable (G_GNUC_UNUSED GtkTreeDragSource *source,
428 G_GNUC_UNUSED GtkTreePath *path)
429 {
430 return TRUE;
431 }
432
433 static gboolean
font_manager_font_model_drag_data_get(GtkTreeDragSource * source,GtkTreePath * path,GtkSelectionData * selection_data)434 font_manager_font_model_drag_data_get (GtkTreeDragSource *source,
435 GtkTreePath *path,
436 GtkSelectionData *selection_data)
437 {
438 if (gtk_tree_set_row_drag_data(selection_data, GTK_TREE_MODEL(source), path))
439 return TRUE;
440 return FALSE;
441 }
442
443 static gboolean
font_manager_font_model_drag_data_delete(G_GNUC_UNUSED GtkTreeDragSource * drag_source,G_GNUC_UNUSED GtkTreePath * path)444 font_manager_font_model_drag_data_delete (G_GNUC_UNUSED GtkTreeDragSource *drag_source,
445 G_GNUC_UNUSED GtkTreePath *path)
446 {
447 /* This model is read-only */
448 return FALSE;
449 }
450
451 static void
gtk_tree_drag_source_interface_init(GtkTreeDragSourceIface * iface)452 gtk_tree_drag_source_interface_init (GtkTreeDragSourceIface *iface)
453 {
454 iface->row_draggable = font_manager_font_model_row_draggable;
455 iface->drag_data_get = font_manager_font_model_drag_data_get;
456 iface->drag_data_delete = font_manager_font_model_drag_data_delete;
457 return;
458 }
459
460 /* GtkTreeDragDestIface */
461
462 static gboolean
font_manager_font_model_drag_data_received(G_GNUC_UNUSED GtkTreeDragDest * drag_dest,G_GNUC_UNUSED GtkTreePath * dest,G_GNUC_UNUSED GtkSelectionData * selection_data)463 font_manager_font_model_drag_data_received (G_GNUC_UNUSED GtkTreeDragDest *drag_dest,
464 G_GNUC_UNUSED GtkTreePath *dest,
465 G_GNUC_UNUSED GtkSelectionData *selection_data)
466 {
467 return FALSE;
468 }
469
470 static gboolean
font_manager_font_model_row_drop_possible(G_GNUC_UNUSED GtkTreeDragDest * drag_dest,G_GNUC_UNUSED GtkTreePath * dest,G_GNUC_UNUSED GtkSelectionData * selection_data)471 font_manager_font_model_row_drop_possible (G_GNUC_UNUSED GtkTreeDragDest *drag_dest,
472 G_GNUC_UNUSED GtkTreePath *dest,
473 G_GNUC_UNUSED GtkSelectionData *selection_data)
474 {
475 /* This model is read-only */
476 return FALSE;
477 }
478
479 static void
gtk_tree_drag_dest_interface_init(GtkTreeDragDestIface * iface)480 gtk_tree_drag_dest_interface_init (GtkTreeDragDestIface *iface)
481 {
482 iface->drag_data_received = font_manager_font_model_drag_data_received;
483 iface->row_drop_possible = font_manager_font_model_row_drop_possible;
484 return;
485 }
486
487 /* FontManagerFontModel */
488
489 static void
font_manager_font_model_init(FontManagerFontModel * self)490 font_manager_font_model_init (FontManagerFontModel *self)
491 {
492 do { self->stamp = g_random_int(); } while (self->stamp == 0);
493 self->available_fonts = json_array_new();
494 return;
495 }
496
497 static void
font_manager_font_model_dispose(GObject * gobject)498 font_manager_font_model_dispose (GObject *gobject)
499 {
500 g_return_if_fail(gobject != NULL);
501 FontManagerFontModel *self = FONT_MANAGER_FONT_MODEL(gobject);
502 g_clear_pointer(&self->available_fonts, json_array_unref);
503 G_OBJECT_CLASS(font_manager_font_model_parent_class)->dispose(gobject);
504 return;
505 }
506
507 static void
font_manager_font_model_get_property(GObject * gobject,guint property_id,GValue * value,GParamSpec * pspec)508 font_manager_font_model_get_property (GObject *gobject,
509 guint property_id,
510 GValue *value,
511 GParamSpec *pspec)
512 {
513 g_return_if_fail(gobject != NULL);
514 FontManagerFontModel *self = FONT_MANAGER_FONT_MODEL(gobject);
515 g_return_if_fail(self->available_fonts != NULL);
516
517 switch (property_id) {
518 case PROP_SOURCE:
519 g_value_set_boxed(value, self->available_fonts);
520 break;
521 default:
522 G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, property_id, pspec);
523 break;
524 }
525
526 return;
527 }
528
529 static void
set_source(FontManagerFontModel * self,JsonArray * value)530 set_source (FontManagerFontModel *self, JsonArray *value)
531 {
532 g_return_if_fail(self != NULL);
533 if (self->available_fonts == value)
534 return;
535 if (self->available_fonts != NULL)
536 json_array_unref(self->available_fonts);
537 self->available_fonts = value ? json_array_ref(value) : NULL;
538 g_object_notify(G_OBJECT(self), SOURCE);
539 return;
540 }
541
542 static void
font_manager_font_model_set_property(GObject * gobject,guint property_id,const GValue * value,GParamSpec * pspec)543 font_manager_font_model_set_property (GObject *gobject,
544 guint property_id,
545 const GValue *value,
546 GParamSpec *pspec)
547 {
548 g_return_if_fail(gobject != NULL);
549 FontManagerFontModel *self = FONT_MANAGER_FONT_MODEL(gobject);
550
551 switch (property_id) {
552 case PROP_SOURCE:
553 set_source(self, g_value_get_boxed(value));
554 break;
555 default:
556 G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, property_id, pspec);
557 break;
558 }
559
560 return;
561 }
562
563 static void
font_manager_font_model_class_init(FontManagerFontModelClass * klass)564 font_manager_font_model_class_init (FontManagerFontModelClass *klass)
565 {
566 GObjectClass *object_class = G_OBJECT_CLASS(klass);
567 object_class->get_property = font_manager_font_model_get_property;
568 object_class->set_property = font_manager_font_model_set_property;
569 object_class->dispose = font_manager_font_model_dispose;
570
571 /**
572 * FontManagerFontModel:source-array:
573 *
574 * #JsonArray source.
575 */
576 g_object_class_install_property(object_class,
577 PROP_SOURCE,
578 g_param_spec_boxed(SOURCE,
579 NULL,
580 "#JsonArray backing this model",
581 JSON_TYPE_ARRAY,
582 G_PARAM_STATIC_STRINGS |
583 G_PARAM_READWRITE));
584 return;
585 }
586
587 /**
588 * font_manager_font_model_new:
589 *
590 * Returns : (transfer full) : A newly created #FontManagerFontModel.
591 * Free the returned object using #g_object_unref().
592 */
593 FontManagerFontModel *
font_manager_font_model_new(void)594 font_manager_font_model_new (void)
595 {
596 return g_object_new(FONT_MANAGER_TYPE_FONT_MODEL, NULL);
597 }
598