Branch data Line data Source code
1 : : /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
2 : : *
3 : : * Copyright © 2020 Endless Mobile, Inc.
4 : : *
5 : : * SPDX-License-Identifier: GPL-2.0-or-later
6 : : *
7 : : * This program is free software; you can redistribute it and/or modify
8 : : * it under the terms of the GNU General Public License as published by
9 : : * the Free Software Foundation; either version 2 of the License, or
10 : : * (at your option) any later version.
11 : : *
12 : : * This program 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
15 : : * GNU General Public License for more details.
16 : : *
17 : : * You should have received a copy of the GNU General Public License
18 : : * along with this program; if not, see <http://www.gnu.org/licenses/>.
19 : : *
20 : : * Authors:
21 : : * - Philip Withnall <withnall@endlessm.com>
22 : : */
23 : :
24 : : #include <gio/gio.h>
25 : : #include <glib.h>
26 : : #include <glib-object.h>
27 : : #include <glib/gi18n.h>
28 : : #include <gtk/gtk.h>
29 : : #include <libmalcontent/malcontent.h>
30 : :
31 : : #include "user-image.h"
32 : : #include "user-selector.h"
33 : :
34 : :
35 : : static gint sort_users (gconstpointer a,
36 : : gconstpointer b,
37 : : gpointer user_data);
38 : : static void reload_users (MctUserSelector *self);
39 : : static void notify_n_items_cb (GObject *obj,
40 : : GParamSpec *pspec,
41 : : gpointer user_data);
42 : : static void user_manager_notify_is_loaded_cb (GObject *object,
43 : : GParamSpec *pspec,
44 : : void *user_data);
45 : : static void user_added_cb (MctUserManager *user_manager,
46 : : MctUser *user,
47 : : gpointer user_data);
48 : : static void user_removed_cb (MctUserManager *user_manager,
49 : : MctUser *user,
50 : : void *user_data);
51 : : static void on_user_row_activated (MctUserSelector *self,
52 : : AdwActionRow *row);
53 : : static GtkWidget *create_user_row (gpointer item, gpointer user_data);
54 : :
55 : :
56 : : /**
57 : : * MctUserSelector:
58 : : *
59 : : * The user selector is a widget which lists available user accounts and allows
60 : : * the user to select one.
61 : : *
62 : : * Since: 0.5.0
63 : : */
64 : : struct _MctUserSelector
65 : : {
66 : : GtkBox parent_instance;
67 : :
68 : : GtkListBox *user_list;
69 : :
70 : : GListStore *model /* (owned) */;
71 : :
72 : : MctUserManager *user_manager; /* (owned) */
73 : : MctManager *policy_manager; /* (owned) */
74 : : MctUser *current_user; /* (owned) (nullable) */
75 : : MctUser *selected_user; /* (owned) (nullable) */
76 : : gboolean show_parents;
77 : : guint n_users;
78 : : GCancellable *cancellable; /* (owned) */
79 : : };
80 : :
81 [ # # # # : 0 : G_DEFINE_TYPE (MctUserSelector, mct_user_selector, GTK_TYPE_BOX)
# # ]
82 : :
83 : : typedef enum
84 : : {
85 : : PROP_SELECTED_USER = 1,
86 : : PROP_POLICY_MANAGER,
87 : : PROP_USER_MANAGER,
88 : : PROP_CURRENT_USER,
89 : : PROP_N_USERS,
90 : : PROP_SHOW_PARENTS,
91 : : } MctUserSelectorProperty;
92 : :
93 : : static GParamSpec *properties[PROP_SHOW_PARENTS + 1];
94 : :
95 : : static void
96 : 0 : mct_user_selector_constructed (GObject *obj)
97 : : {
98 : 0 : MctUserSelector *self = MCT_USER_SELECTOR (obj);
99 : :
100 : : /* Chain up. */
101 : 0 : G_OBJECT_CLASS (mct_user_selector_parent_class)->constructed (obj);
102 : :
103 : : /* The policy manager is mandatory and must have been loaded already. */
104 : 0 : g_assert (self->policy_manager != NULL);
105 : :
106 : : /* The user manager is mandatory and must have been loaded already. */
107 : 0 : g_assert (self->user_manager != NULL);
108 : :
109 : 0 : self->model = g_list_store_new (MCT_TYPE_USER);
110 : 0 : gtk_list_box_bind_model (self->user_list,
111 : 0 : G_LIST_MODEL (self->model),
112 : : (GtkListBoxCreateWidgetFunc)create_user_row,
113 : : self,
114 : : NULL);
115 : :
116 : 0 : g_signal_connect_object (self->model, "notify::n-items",
117 : : G_CALLBACK (notify_n_items_cb),
118 : : self, G_CONNECT_DEFAULT);
119 : 0 : g_signal_connect (self->user_manager, "notify::is-loaded",
120 : : G_CALLBACK (user_manager_notify_is_loaded_cb), self);
121 : 0 : g_signal_connect (self->user_manager, "user-added",
122 : : G_CALLBACK (user_added_cb), self);
123 : 0 : g_signal_connect (self->user_manager, "user-removed",
124 : : G_CALLBACK (user_removed_cb), self);
125 : 0 : }
126 : :
127 : : static void
128 : 0 : mct_user_selector_get_property (GObject *object,
129 : : guint prop_id,
130 : : GValue *value,
131 : : GParamSpec *pspec)
132 : : {
133 : 0 : MctUserSelector *self = MCT_USER_SELECTOR (object);
134 : :
135 [ # # # # : 0 : switch ((MctUserSelectorProperty) prop_id)
# # # ]
136 : : {
137 : 0 : case PROP_SELECTED_USER:
138 : 0 : g_value_set_object (value, self->selected_user);
139 : 0 : break;
140 : :
141 : 0 : case PROP_POLICY_MANAGER:
142 : 0 : g_value_set_object (value, self->policy_manager);
143 : 0 : break;
144 : :
145 : 0 : case PROP_USER_MANAGER:
146 : 0 : g_value_set_object (value, self->user_manager);
147 : 0 : break;
148 : :
149 : 0 : case PROP_CURRENT_USER:
150 : 0 : g_value_set_object (value, self->current_user);
151 : 0 : break;
152 : :
153 : 0 : case PROP_N_USERS:
154 : 0 : g_value_set_uint (value, mct_user_selector_get_n_users (self));
155 : 0 : break;
156 : :
157 : 0 : case PROP_SHOW_PARENTS:
158 : 0 : g_value_set_boolean (value, self->show_parents);
159 : 0 : break;
160 : :
161 : 0 : default:
162 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
163 : : }
164 : 0 : }
165 : :
166 : : static void
167 : 0 : mct_user_selector_set_property (GObject *object,
168 : : guint prop_id,
169 : : const GValue *value,
170 : : GParamSpec *pspec)
171 : : {
172 : 0 : MctUserSelector *self = MCT_USER_SELECTOR (object);
173 : :
174 [ # # # # : 0 : switch ((MctUserSelectorProperty) prop_id)
# # # ]
175 : : {
176 : 0 : case PROP_SELECTED_USER:
177 : : /* Currently read only */
178 : : g_assert_not_reached ();
179 : : break;
180 : :
181 : 0 : case PROP_POLICY_MANAGER:
182 : : /* Construct-only. May not be %NULL. */
183 : 0 : g_assert (self->policy_manager == NULL);
184 : 0 : self->policy_manager = g_value_dup_object (value);
185 : 0 : g_assert (self->policy_manager != NULL);
186 : 0 : break;
187 : :
188 : 0 : case PROP_USER_MANAGER:
189 : 0 : g_assert (self->user_manager == NULL);
190 : 0 : self->user_manager = g_value_dup_object (value);
191 : 0 : break;
192 : :
193 : 0 : case PROP_CURRENT_USER:
194 : 0 : mct_user_selector_set_current_user (self, g_value_get_object (value));
195 : 0 : break;
196 : :
197 : 0 : case PROP_N_USERS:
198 : : /* Currently read only */
199 : : g_assert_not_reached ();
200 : : break;
201 : :
202 : 0 : case PROP_SHOW_PARENTS:
203 : 0 : self->show_parents = g_value_get_boolean (value);
204 : 0 : reload_users (self);
205 : 0 : break;
206 : :
207 : 0 : default:
208 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
209 : : }
210 : 0 : }
211 : :
212 : : static void
213 : 0 : mct_user_selector_dispose (GObject *object)
214 : : {
215 : 0 : MctUserSelector *self = (MctUserSelector *)object;
216 : :
217 : 0 : g_cancellable_cancel (self->cancellable);
218 [ # # ]: 0 : g_clear_object (&self->cancellable);
219 : :
220 [ # # ]: 0 : g_clear_object (&self->model);
221 [ # # ]: 0 : g_clear_object (&self->selected_user);
222 : :
223 [ # # ]: 0 : if (self->user_manager != NULL)
224 : : {
225 : 0 : g_signal_handlers_disconnect_by_func (self->user_manager, user_removed_cb, self);
226 : 0 : g_signal_handlers_disconnect_by_func (self->user_manager, user_added_cb, self);
227 : 0 : g_signal_handlers_disconnect_by_func (self->user_manager, user_manager_notify_is_loaded_cb, self);
228 : :
229 [ # # ]: 0 : g_clear_object (&self->user_manager);
230 : : }
231 : :
232 [ # # ]: 0 : g_clear_object (&self->policy_manager);
233 : :
234 : 0 : G_OBJECT_CLASS (mct_user_selector_parent_class)->dispose (object);
235 : 0 : }
236 : :
237 : : static void
238 : 0 : mct_user_selector_class_init (MctUserSelectorClass *klass)
239 : : {
240 : 0 : GObjectClass *object_class = G_OBJECT_CLASS (klass);
241 : 0 : GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
242 : :
243 : 0 : object_class->constructed = mct_user_selector_constructed;
244 : 0 : object_class->get_property = mct_user_selector_get_property;
245 : 0 : object_class->set_property = mct_user_selector_set_property;
246 : 0 : object_class->dispose = mct_user_selector_dispose;
247 : :
248 : : /**
249 : : * MctUserSelector:selected-user: (nullable)
250 : : *
251 : : * The currently selected user account.
252 : : *
253 : : * This may be `NULL` if no user is selected.
254 : : *
255 : : * Currently read only but may become writable in future.
256 : : *
257 : : * Since: 0.14.0
258 : : */
259 : 0 : properties[PROP_SELECTED_USER] =
260 : 0 : g_param_spec_object ("selected-user", NULL, NULL,
261 : : MCT_TYPE_USER,
262 : : G_PARAM_READABLE |
263 : : G_PARAM_STATIC_STRINGS |
264 : : G_PARAM_EXPLICIT_NOTIFY);
265 : :
266 : : /**
267 : : * MctUserSelector:policy-manager: (not nullable)
268 : : *
269 : : * The policy manager providing the data for the widget.
270 : : *
271 : : * Since: 0.14.0
272 : : */
273 : 0 : properties[PROP_POLICY_MANAGER] =
274 : 0 : g_param_spec_object ("policy-manager", NULL, NULL,
275 : : MCT_TYPE_MANAGER,
276 : : G_PARAM_READWRITE |
277 : : G_PARAM_CONSTRUCT_ONLY |
278 : : G_PARAM_STATIC_STRINGS);
279 : :
280 : : /**
281 : : * MctUserSelector:user-manager: (not nullable)
282 : : *
283 : : * The user manager providing the data for the widget.
284 : : *
285 : : * This must have already been asynchronously loaded using
286 : : * [method@Malcontent.UserManager.load_async] before this widget is mapped.
287 : : * This widget has no ‘loading’ view.
288 : : *
289 : : * Since: 0.14.0
290 : : */
291 : 0 : properties[PROP_USER_MANAGER] =
292 : 0 : g_param_spec_object ("user-manager", NULL, NULL,
293 : : MCT_TYPE_USER_MANAGER,
294 : : G_PARAM_READWRITE |
295 : : G_PARAM_CONSTRUCT_ONLY |
296 : : G_PARAM_STATIC_STRINGS |
297 : : G_PARAM_EXPLICIT_NOTIFY);
298 : :
299 : : /**
300 : : * MctUserSelector:current-user: (nullable)
301 : : *
302 : : * The user currently using the widget.
303 : : *
304 : : * This is used to display the correct family group. Typically it is the
305 : : * result of calling:
306 : : * ```c
307 : : * mct_user_manager_get_user_by_uid (user_manager, getuid ())
308 : : * ```
309 : : *
310 : : * It may be `NULL` if the user’s data is not yet known, but it must be set
311 : : * before this widget is mapped. This widget has no ‘loading’ view.
312 : : *
313 : : * Since: 0.14.0
314 : : */
315 : 0 : properties[PROP_CURRENT_USER] =
316 : 0 : g_param_spec_object ("current-user", NULL, NULL,
317 : : MCT_TYPE_USER,
318 : : G_PARAM_READWRITE |
319 : : G_PARAM_STATIC_STRINGS |
320 : : G_PARAM_EXPLICIT_NOTIFY);
321 : :
322 : : /**
323 : : * MctUserSelector:show-parents:
324 : : *
325 : : * Whether to show parents in the list, or hide them.
326 : : *
327 : : * Since: 0.14.0
328 : : */
329 : 0 : properties[PROP_SHOW_PARENTS] =
330 : 0 : g_param_spec_boolean ("show-parents", NULL, NULL,
331 : : TRUE,
332 : : G_PARAM_READWRITE |
333 : : G_PARAM_STATIC_STRINGS);
334 : :
335 : : /**
336 : : * MctUserSelector:n-users:
337 : : *
338 : : * The number of users contained in this selector.
339 : : *
340 : : * Since: 0.14.0
341 : : */
342 : 0 : properties[PROP_N_USERS] =
343 : 0 : g_param_spec_uint ("n-users",
344 : : NULL,
345 : : NULL,
346 : : 0,
347 : : G_MAXUINT,
348 : : 0,
349 : : G_PARAM_READABLE |
350 : : G_PARAM_STATIC_STRINGS |
351 : : G_PARAM_EXPLICIT_NOTIFY);
352 : :
353 : 0 : g_object_class_install_properties (object_class, G_N_ELEMENTS (properties), properties);
354 : :
355 : 0 : gtk_widget_class_set_template_from_resource (widget_class, "/org/freedesktop/MalcontentControl/ui/user-selector.ui");
356 : :
357 : 0 : gtk_widget_class_bind_template_child (widget_class, MctUserSelector, user_list);
358 : :
359 : 0 : gtk_widget_class_bind_template_callback (widget_class, on_user_row_activated);
360 : 0 : }
361 : :
362 : : static void
363 : 0 : mct_user_selector_init (MctUserSelector *self)
364 : : {
365 : 0 : self->show_parents = TRUE;
366 : 0 : self->cancellable = g_cancellable_new ();
367 : :
368 : 0 : gtk_widget_init_template (GTK_WIDGET (self));
369 : 0 : }
370 : :
371 : : static void
372 : 0 : notify_n_items_cb (GObject *obj,
373 : : GParamSpec *pspec,
374 : : gpointer user_data)
375 : : {
376 : 0 : MctUserSelector *self = MCT_USER_SELECTOR (user_data);
377 : :
378 : 0 : g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_N_USERS]);
379 : 0 : }
380 : :
381 : : static void
382 : 0 : user_manager_notify_is_loaded_cb (GObject *object,
383 : : GParamSpec *pspec,
384 : : void *user_data)
385 : : {
386 : 0 : MctUserSelector *self = MCT_USER_SELECTOR (user_data);
387 : :
388 : 0 : reload_users (self);
389 : 0 : }
390 : :
391 : : static void
392 : 0 : on_user_row_activated (MctUserSelector *self,
393 : : AdwActionRow *row)
394 : : {
395 : : MctUser *user;
396 : :
397 [ # # ]: 0 : g_clear_object (&self->selected_user);
398 : :
399 : 0 : user = g_object_get_data (G_OBJECT (row), "user");
400 : :
401 [ # # ]: 0 : if (g_set_object (&self->selected_user, user))
402 : 0 : g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SELECTED_USER]);
403 : 0 : }
404 : :
405 : : static void
406 : 0 : user_notify_display_name_cb (GObject *object,
407 : : GParamSpec *pspec,
408 : : void *user_data)
409 : : {
410 : 0 : MctUser *user = MCT_USER (object);
411 : 0 : AdwPreferencesRow *row = ADW_PREFERENCES_ROW (user_data);
412 : : MctUserSelector *self;
413 : :
414 : 0 : adw_preferences_row_set_title (ADW_PREFERENCES_ROW (row),
415 : : mct_user_get_display_name (user));
416 : :
417 : : /* The new name might have changed the row’s position in the list, so re-sort
418 : : * the list. */
419 : 0 : self = MCT_USER_SELECTOR (gtk_widget_get_ancestor (GTK_WIDGET (row), MCT_TYPE_USER_SELECTOR));
420 [ # # ]: 0 : if (self != NULL)
421 : 0 : g_list_store_sort (self->model, sort_users, self);
422 : 0 : }
423 : :
424 : : static GtkWidget *
425 : 0 : create_user_row (gpointer item, gpointer user_data)
426 : : {
427 : : MctUser *user;
428 : : GtkWidget *row, *user_image;
429 : :
430 : 0 : row = adw_action_row_new ();
431 : 0 : gtk_list_box_row_set_activatable (GTK_LIST_BOX_ROW (row), TRUE);
432 : :
433 : 0 : user = item;
434 : :
435 : 0 : g_object_set_data_full (G_OBJECT (row), "user", g_object_ref (user), g_object_unref);
436 : :
437 : 0 : adw_preferences_row_set_title (ADW_PREFERENCES_ROW (row),
438 : : mct_user_get_display_name (user));
439 : 0 : g_signal_connect_object (user, "notify::display-name",
440 : : G_CALLBACK (user_notify_display_name_cb), row,
441 : : G_CONNECT_DEFAULT);
442 : :
443 : 0 : user_image = mct_user_image_new ();
444 : 0 : mct_user_image_set_user (MCT_USER_IMAGE (user_image), user);
445 : 0 : gtk_widget_set_margin_top (user_image, 12);
446 : 0 : gtk_widget_set_margin_bottom (user_image, 12);
447 : 0 : adw_action_row_add_prefix (ADW_ACTION_ROW (row), user_image);
448 : 0 : adw_action_row_activate (ADW_ACTION_ROW (row));
449 : :
450 : 0 : GtkWidget *arrow = gtk_image_new_from_icon_name ("go-next-symbolic");
451 : 0 : adw_action_row_add_suffix (ADW_ACTION_ROW (row), arrow);
452 : :
453 : 0 : return row;
454 : : }
455 : :
456 : : static gint
457 : 0 : sort_users (gconstpointer a, gconstpointer b, gpointer user_data)
458 : : {
459 : 0 : MctUserSelector *self = MCT_USER_SELECTOR (user_data);
460 : : MctUser *ua, *ub;
461 : : gint result;
462 : :
463 : 0 : ua = MCT_USER ((gpointer) a);
464 : 0 : ub = MCT_USER ((gpointer) b);
465 : :
466 : : /* Make sure the current user is shown first */
467 [ # # # # ]: 0 : if (self->current_user != NULL && mct_user_equal (ua, self->current_user))
468 : : {
469 : 0 : result = G_MININT32;
470 : : }
471 [ # # # # ]: 0 : else if (self->current_user != NULL && mct_user_equal (ub, self->current_user))
472 : : {
473 : 0 : result = G_MAXINT32;
474 : : }
475 : : else
476 : : {
477 : 0 : g_autofree gchar *name1 = NULL, *name2 = NULL;
478 : :
479 : 0 : name1 = g_utf8_collate_key (mct_user_get_display_name (ua), -1);
480 : 0 : name2 = g_utf8_collate_key (mct_user_get_display_name (ub), -1);
481 : :
482 : 0 : result = strcmp (name1, name2);
483 : : }
484 : :
485 : 0 : return result;
486 : : }
487 : :
488 : : static void reload_users_cb (GObject *object,
489 : : GAsyncResult *result,
490 : : void *user_data);
491 : :
492 : : static void
493 : 0 : reload_users (MctUserSelector *self)
494 : : {
495 [ # # ]: 0 : if (!mct_user_manager_get_is_loaded (self->user_manager) ||
496 [ # # ]: 0 : self->current_user == NULL)
497 : 0 : return;
498 : :
499 : 0 : mct_user_manager_get_family_members_for_user_async (self->user_manager,
500 : : self->current_user,
501 : : self->cancellable,
502 : : reload_users_cb,
503 : : self);
504 : : }
505 : :
506 : : static void
507 : 0 : reload_users_cb (GObject *object,
508 : : GAsyncResult *result,
509 : : void *user_data)
510 : : {
511 : 0 : MctUserManager *user_manager = MCT_USER_MANAGER (object);
512 : 0 : MctUserSelector *self = MCT_USER_SELECTOR (user_data);
513 : 0 : g_autoptr(MctUserArray) users = NULL;
514 : 0 : size_t n_users = 0;
515 : 0 : g_autoptr(GError) local_error = NULL;
516 : :
517 : 0 : users = mct_user_manager_get_family_members_for_user_finish (user_manager, result, &n_users, &local_error);
518 [ # # ]: 0 : if (local_error != NULL)
519 : 0 : g_debug ("Error getting users: %s", local_error->message);
520 : : else
521 : 0 : g_debug ("Got %zu users", n_users);
522 : :
523 : 0 : g_list_store_remove_all (self->model);
524 : :
525 [ # # ]: 0 : for (size_t i = 0; i < n_users; i++)
526 : : {
527 : 0 : MctUser *user = users[i];
528 : 0 : user_added_cb (self->user_manager, user, self);
529 : : }
530 : 0 : }
531 : :
532 : : static void
533 : 0 : user_added_cb (MctUserManager *user_manager,
534 : : MctUser *user,
535 : : void *user_data)
536 : : {
537 : 0 : MctUserSelector *self = MCT_USER_SELECTOR (user_data);
538 : :
539 [ # # # # ]: 0 : if (self->current_user != NULL &&
540 : 0 : !mct_user_is_in_same_family (user, self->current_user))
541 : : {
542 : 0 : g_debug ("Ignoring user %s not in the same family as current user %s",
543 : : mct_user_get_display_name (user), mct_user_get_display_name (self->current_user));
544 : 0 : return;
545 : : }
546 : :
547 [ # # ]: 0 : if (mct_user_get_user_type (user) == MCT_USER_TYPE_PARENT &&
548 [ # # ]: 0 : !self->show_parents)
549 : : {
550 : 0 : g_debug ("Ignoring parent %s", mct_user_get_display_name (user));
551 : 0 : return;
552 : : }
553 : :
554 : 0 : g_debug ("User added: %u %s", (guint) mct_user_get_uid (user), mct_user_get_display_name (user));
555 : :
556 : 0 : g_list_store_insert_sorted (self->model, user, sort_users, self);
557 : : }
558 : :
559 : : static void
560 : 0 : user_removed_cb (MctUserManager *user_manager,
561 : : MctUser *user,
562 : : void *user_data)
563 : : {
564 : 0 : MctUserSelector *self = MCT_USER_SELECTOR (user_data);
565 : :
566 : 0 : reload_users (self);
567 : 0 : }
568 : :
569 : : /**
570 : : * mct_user_selector_new:
571 : : * @policy_manager: (transfer none): a policy manager to provide the policy data
572 : : * @user_manager: (transfer none): a user manager to provide the user data
573 : : *
574 : : * Create a new #MctUserSelector widget.
575 : : *
576 : : * Returns: (transfer full): a new user selector
577 : : * Since: 0.14.0
578 : : */
579 : : MctUserSelector *
580 : 0 : mct_user_selector_new (MctManager *policy_manager,
581 : : MctUserManager *user_manager)
582 : : {
583 : 0 : g_return_val_if_fail (MCT_IS_MANAGER (policy_manager), NULL);
584 : 0 : g_return_val_if_fail (MCT_IS_USER_MANAGER (user_manager), NULL);
585 : :
586 : 0 : return g_object_new (MCT_TYPE_USER_SELECTOR,
587 : : "policy-manager", policy_manager,
588 : : "user-manager", user_manager,
589 : : NULL);
590 : : }
591 : :
592 : : /**
593 : : * mct_user_selector_get_selected_user:
594 : : * @self: an #MctUserSelector
595 : : *
596 : : * Get the value of [property@Malcontent.UserSelector:selected-user].
597 : : *
598 : : * Returns: (transfer none) (nullable): the currently selected user, or `NULL`
599 : : * if no user is selected.
600 : : * Since: 0.14.0
601 : : */
602 : : MctUser *
603 : 0 : mct_user_selector_get_selected_user (MctUserSelector *self)
604 : : {
605 : 0 : g_return_val_if_fail (MCT_IS_USER_SELECTOR (self), NULL);
606 : :
607 : 0 : return self->selected_user;
608 : : }
609 : :
610 : : /**
611 : : * mct_user_selector_get_current_user:
612 : : * @self: a user selector
613 : : *
614 : : * Get the value of [property@Malcontent.UserSelector:current-user].
615 : : *
616 : : * Returns: (transfer none) (nullable): the user currently using the widget, or
617 : : * `NULL` if not known
618 : : * Since: 0.14.0
619 : : */
620 : : MctUser *
621 : 0 : mct_user_selector_get_current_user (MctUserSelector *self)
622 : : {
623 : 0 : g_return_val_if_fail (MCT_IS_USER_SELECTOR (self), NULL);
624 : :
625 : 0 : return self->current_user;
626 : : }
627 : :
628 : : /**
629 : : * mct_user_selector_set_current_user:
630 : : * @self: a user selector
631 : : * @current_user: (transfer none) (nullable): the user currently using the
632 : : * widget, or `NULL` if not known
633 : : *
634 : : * Set the value of [property@Malcontent.UserSelector:current-user].
635 : : *
636 : : * Since: 0.14.0
637 : : */
638 : : void
639 : 0 : mct_user_selector_set_current_user (MctUserSelector *self,
640 : : MctUser *current_user)
641 : : {
642 : 0 : g_return_if_fail (MCT_IS_USER_SELECTOR (self));
643 : 0 : g_return_if_fail (current_user == NULL || MCT_IS_USER (current_user));
644 : :
645 [ # # ]: 0 : if (g_set_object (&self->current_user, current_user))
646 : : {
647 : 0 : reload_users (self);
648 : 0 : g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_CURRENT_USER]);
649 : : }
650 : : }
651 : :
652 : : /**
653 : : * mct_user_selector_select_user_by_username:
654 : : * @self: an #MctUserSelector
655 : : * @user: the user to select
656 : : *
657 : : * Selects the given @user in the widget. This might fail if @user isn’t
658 : : * a valid user, or if they aren’t listed in the selector due to being a
659 : : * parent (see #MctUserSelector:show-parents).
660 : : *
661 : : * Returns: %TRUE if the user was successfully selected, %FALSE otherwise
662 : : * Since: 0.14.0
663 : : */
664 : : gboolean
665 : 0 : mct_user_selector_select_user (MctUserSelector *self,
666 : : MctUser *user)
667 : : {
668 : 0 : g_return_val_if_fail (MCT_IS_USER_SELECTOR (self), FALSE);
669 : 0 : g_return_val_if_fail (MCT_IS_USER (user), FALSE);
670 : :
671 [ # # ]: 0 : if (!g_list_store_find_with_equal_func (self->model, user, (GEqualFunc) mct_user_equal, NULL))
672 : 0 : return FALSE;
673 : :
674 [ # # ]: 0 : if (g_set_object (&self->selected_user, user))
675 : 0 : g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SELECTED_USER]);
676 : :
677 : 0 : return TRUE;
678 : : }
679 : :
680 : : /**
681 : : * mct_user_selector_get_n_users:
682 : : * @self: an #MctUserSelector
683 : : *
684 : : * Gets the number of users in @self.
685 : : *
686 : : * Returns: the number of users in @self
687 : : * Since: 0.14.0
688 : : */
689 : : size_t
690 : 0 : mct_user_selector_get_n_users (MctUserSelector *self)
691 : : {
692 : 0 : g_return_val_if_fail (MCT_IS_USER_SELECTOR (self), 0);
693 : :
694 : 0 : return g_list_model_get_n_items (G_LIST_MODEL (self->model));
695 : : }
|