1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2 /*
3  * Copyright (C) 2012 Red Hat
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License as
7  * published by the Free Software Foundation; either version 2 of the
8  * License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * 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; if not, see <http://www.gnu.org/licenses/>.
17  *
18  * Written by:
19  *     Jasper St. Pierre <jstpierre@mecheye.net>
20  */
21 
22 #include "config.h"
23 
24 #include "gnome-initial-setup.h"
25 
26 #include <errno.h>
27 #include <locale.h>
28 #include <stdlib.h>
29 #include <webkit2/webkit2.h>
30 
31 #include "cc-common-language.h"
32 #include "gis-assistant.h"
33 
34 #define GIS_TYPE_DRIVER_MODE (gis_driver_mode_get_type ())
35 
36 /* Statically include this for now. Maybe later
37  * we'll generate this from glib-mkenums. */
38 GType
gis_driver_mode_get_type(void)39 gis_driver_mode_get_type (void) {
40   static GType enum_type_id = 0;
41   if (G_UNLIKELY (!enum_type_id))
42     {
43       static const GEnumValue values[] = {
44         { GIS_DRIVER_MODE_NEW_USER, "GIS_DRIVER_MODE_NEW_USER", "new_user" },
45         { GIS_DRIVER_MODE_EXISTING_USER, "GIS_DRIVER_MODE_EXISTING_USER", "existing_user" },
46         { 0, NULL, NULL }
47       };
48       enum_type_id = g_enum_register_static("GisDriverMode", values);
49     }
50   return enum_type_id;
51 }
52 
53 enum {
54   REBUILD_PAGES,
55   LOCALE_CHANGED,
56   LAST_SIGNAL,
57 };
58 
59 static guint signals[LAST_SIGNAL];
60 
61 typedef enum {
62   PROP_MODE = 1,
63   PROP_USERNAME,
64   PROP_SMALL_SCREEN,
65   PROP_PARENTAL_CONTROLS_ENABLED,
66   PROP_FULL_NAME,
67   PROP_AVATAR,
68 } GisDriverProperty;
69 
70 static GParamSpec *obj_props[PROP_AVATAR + 1];
71 
72 struct _GisDriver {
73   GtkApplication  parent_instance;
74 
75   GtkWindow *main_window;
76   GisAssistant *assistant;
77 
78   GdmClient *client;
79   GdmGreeter *greeter;
80   GdmUserVerifier *user_verifier;
81 
82   ActUser *user_account;
83   gchar *user_password;
84 
85   ActUser *parent_account;  /* (owned) (nullable) */
86   gchar *parent_password;  /* (owned) (nullable) */
87 
88   gboolean parental_controls_enabled;
89 
90   gchar *lang_id;
91   gchar *username;
92   gchar *full_name;  /* (owned) (nullable) */
93 
94   GdkPixbuf *avatar;  /* (owned) (nullable) */
95 
96   GisDriverMode mode;
97   UmAccountMode account_mode;
98   gboolean small_screen;
99 
100   locale_t locale;
101 
102   const gchar *vendor_conf_file_path;
103   GKeyFile *vendor_conf_file;
104 };
105 
G_DEFINE_TYPE(GisDriver,gis_driver,GTK_TYPE_APPLICATION)106 G_DEFINE_TYPE (GisDriver, gis_driver, GTK_TYPE_APPLICATION)
107 
108 static void
109 gis_driver_dispose (GObject *object)
110 {
111   GisDriver *driver = GIS_DRIVER (object);
112 
113   g_clear_object (&driver->user_verifier);
114   g_clear_object (&driver->greeter);
115   g_clear_object (&driver->client);
116 
117   G_OBJECT_CLASS (gis_driver_parent_class)->dispose (object);
118 }
119 
120 static void
gis_driver_finalize(GObject * object)121 gis_driver_finalize (GObject *object)
122 {
123   GisDriver *driver = GIS_DRIVER (object);
124 
125   g_free (driver->lang_id);
126   g_free (driver->username);
127   g_free (driver->full_name);
128   g_free (driver->user_password);
129 
130   g_clear_object (&driver->avatar);
131 
132   g_clear_object (&driver->user_account);
133   g_clear_pointer (&driver->vendor_conf_file, g_key_file_free);
134 
135   g_clear_object (&driver->parent_account);
136   g_free (driver->parent_password);
137 
138   if (driver->locale != (locale_t) 0)
139     {
140       uselocale (LC_GLOBAL_LOCALE);
141       freelocale (driver->locale);
142     }
143 
144   G_OBJECT_CLASS (gis_driver_parent_class)->finalize (object);
145 }
146 
147 static void
assistant_page_changed(GtkScrolledWindow * sw)148 assistant_page_changed (GtkScrolledWindow *sw)
149 {
150   gtk_adjustment_set_value (gtk_scrolled_window_get_vadjustment (sw), 0);
151 }
152 
153 static void
prepare_main_window(GisDriver * driver)154 prepare_main_window (GisDriver *driver)
155 {
156   GtkWidget *child, *sw;
157 
158   child = g_object_ref (gtk_bin_get_child (GTK_BIN (driver->main_window)));
159   gtk_container_remove (GTK_CONTAINER (driver->main_window), child);
160   sw = gtk_scrolled_window_new (NULL, NULL);
161   gtk_widget_show (sw);
162   gtk_container_add (GTK_CONTAINER (driver->main_window), sw);
163   gtk_container_add (GTK_CONTAINER (sw), child);
164   g_object_unref (child);
165 
166   g_signal_connect_swapped (driver->assistant,
167                             "page-changed",
168                             G_CALLBACK (assistant_page_changed),
169                             sw);
170 
171   gtk_window_set_titlebar (driver->main_window,
172                            gis_assistant_get_titlebar (driver->assistant));
173 }
174 
175 static void
rebuild_pages(GisDriver * driver)176 rebuild_pages (GisDriver *driver)
177 {
178   g_signal_emit (G_OBJECT (driver), signals[REBUILD_PAGES], 0);
179 }
180 
181 GisAssistant *
gis_driver_get_assistant(GisDriver * driver)182 gis_driver_get_assistant (GisDriver *driver)
183 {
184   return driver->assistant;
185 }
186 
187 static void
gis_driver_locale_changed(GisDriver * driver)188 gis_driver_locale_changed (GisDriver *driver)
189 {
190   GtkTextDirection direction;
191 
192   direction = gtk_get_locale_direction ();
193   gtk_widget_set_default_direction (direction);
194 
195   rebuild_pages (driver);
196   gis_assistant_locale_changed (driver->assistant);
197 
198   g_signal_emit (G_OBJECT (driver), signals[LOCALE_CHANGED], 0);
199 }
200 
201 void
gis_driver_set_user_language(GisDriver * driver,const gchar * lang_id,gboolean update_locale)202 gis_driver_set_user_language (GisDriver *driver, const gchar *lang_id, gboolean update_locale)
203 {
204   g_free (driver->lang_id);
205   driver->lang_id = g_strdup (lang_id);
206 
207   cc_common_language_set_current_language (lang_id);
208 
209   if (update_locale)
210     {
211       locale_t locale = newlocale (LC_MESSAGES_MASK, lang_id, (locale_t) 0);
212       if (locale == (locale_t) 0)
213         {
214           g_warning ("Failed to create locale %s: %s", lang_id, g_strerror (errno));
215           return;
216         }
217 
218       uselocale (locale);
219 
220       if (driver->locale != (locale_t) 0 && driver->locale != LC_GLOBAL_LOCALE)
221         freelocale (driver->locale);
222       driver->locale = locale;
223 
224       gis_driver_locale_changed (driver);
225     }
226 }
227 
228 const gchar *
gis_driver_get_user_language(GisDriver * driver)229 gis_driver_get_user_language (GisDriver *driver)
230 {
231   return driver->lang_id;
232 }
233 
234 void
gis_driver_set_username(GisDriver * driver,const gchar * username)235 gis_driver_set_username (GisDriver *driver, const gchar *username)
236 {
237   g_free (driver->username);
238   driver->username = g_strdup (username);
239 
240   g_object_notify (G_OBJECT (driver), "username");
241 }
242 
243 const gchar *
gis_driver_get_username(GisDriver * driver)244 gis_driver_get_username (GisDriver *driver)
245 {
246   return driver->username;
247 }
248 
249 /**
250  * gis_driver_set_full_name:
251  * @driver: a #GisDriver
252  * @full_name: (nullable): full name of the main user, or %NULL if not known
253  *
254  * Set the #GisDriver:full-name property.
255  *
256  * Since: 3.36
257  */
258 void
gis_driver_set_full_name(GisDriver * driver,const gchar * full_name)259 gis_driver_set_full_name (GisDriver   *driver,
260                           const gchar *full_name)
261 {
262   g_return_if_fail (GIS_IS_DRIVER (driver));
263   g_return_if_fail (full_name == NULL ||
264                     g_utf8_validate (full_name, -1, NULL));
265 
266   if (g_strcmp0 (driver->full_name, full_name) == 0)
267     return;
268 
269   g_free (driver->full_name);
270   driver->full_name = g_strdup (full_name);
271 
272   g_object_notify_by_pspec (G_OBJECT (driver), obj_props[PROP_FULL_NAME]);
273 }
274 
275 /**
276  * gis_driver_get_full_name:
277  * @driver: a #GisDriver
278  *
279  * Get the #GisDriver:full-name property.
280  *
281  * Returns: (nullable): full name of the main user, or %NULL if not known
282  * Since: 3.36
283  */
284 const gchar *
gis_driver_get_full_name(GisDriver * driver)285 gis_driver_get_full_name (GisDriver *driver)
286 {
287   g_return_val_if_fail (GIS_IS_DRIVER (driver), NULL);
288 
289   return driver->full_name;
290 }
291 
292 /**
293  * gis_driver_set_avatar:
294  * @driver: a #GisDriver
295  * @avatar: (nullable) (transfer none): avatar of the main user, or %NULL if not known
296  *
297  * Set the #GisDriver:avatar property.
298  *
299  * Since: 3.36
300  */
301 void
gis_driver_set_avatar(GisDriver * driver,GdkPixbuf * avatar)302 gis_driver_set_avatar (GisDriver *driver,
303                        GdkPixbuf *avatar)
304 {
305   g_return_if_fail (GIS_IS_DRIVER (driver));
306   g_return_if_fail (avatar == NULL || GDK_IS_PIXBUF (avatar));
307 
308   if (g_set_object (&driver->avatar, avatar))
309     g_object_notify_by_pspec (G_OBJECT (driver), obj_props[PROP_AVATAR]);
310 }
311 
312 /**
313  * gis_driver_get_avatar:
314  * @driver: a #GisDriver
315  *
316  * Get the #GisDriver:avatar property.
317  *
318  * Returns: (nullable) (transfer none): avatar of the main user, or %NULL if not known
319  * Since: 3.36
320  */
321 GdkPixbuf *
gis_driver_get_avatar(GisDriver * driver)322 gis_driver_get_avatar (GisDriver *driver)
323 {
324   g_return_val_if_fail (GIS_IS_DRIVER (driver), NULL);
325 
326   return driver->avatar;
327 }
328 
329 void
gis_driver_set_user_permissions(GisDriver * driver,ActUser * user,const gchar * password)330 gis_driver_set_user_permissions (GisDriver   *driver,
331                                  ActUser     *user,
332                                  const gchar *password)
333 {
334   g_set_object (&driver->user_account, user);
335   g_free (driver->user_password);
336   driver->user_password = g_strdup (password);
337 }
338 
339 void
gis_driver_get_user_permissions(GisDriver * driver,ActUser ** user,const gchar ** password)340 gis_driver_get_user_permissions (GisDriver    *driver,
341                                  ActUser     **user,
342                                  const gchar **password)
343 {
344   if (user != NULL)
345     *user = driver->user_account;
346 
347   if (password != NULL)
348     *password = driver->user_password;
349 }
350 
351 /**
352  * gis_driver_set_parent_permissions:
353  * @driver: a #GisDriver
354  * @parent: (transfer none): user account for the parent
355  * @password: password for the parent
356  *
357  * Stores the parent account details for later use when saving the initial setup
358  * data.
359  *
360  * Since: 3.36
361  */
362 void
gis_driver_set_parent_permissions(GisDriver * driver,ActUser * parent,const gchar * password)363 gis_driver_set_parent_permissions (GisDriver   *driver,
364                                    ActUser     *parent,
365                                    const gchar *password)
366 {
367   g_set_object (&driver->parent_account, parent);
368   g_free (driver->parent_password);
369   driver->parent_password = g_strdup (password);
370 }
371 
372 /**
373  * gis_driver_get_parent_permissions:
374  * @driver: a #GisDriver
375  * @parent: (out) (transfer none) (optional) (nullable): return location for the
376  *    user account for the parent, which may be %NULL
377  * @password: (out) (transfer none) (optional) (nullable): return location for
378  *    the password for the parent
379  *
380  * Gets the parent account details saved from an earlier step in the initial
381  * setup process. They may be %NULL if not set yet.
382  *
383  * Since: 3.36
384  */
385 void
gis_driver_get_parent_permissions(GisDriver * driver,ActUser ** parent,const gchar ** password)386 gis_driver_get_parent_permissions (GisDriver    *driver,
387                                    ActUser     **parent,
388                                    const gchar **password)
389 {
390   if (parent != NULL)
391     *parent = driver->parent_account;
392   if (password != NULL)
393     *password = driver->parent_password;
394 }
395 
396 void
gis_driver_set_account_mode(GisDriver * driver,UmAccountMode mode)397 gis_driver_set_account_mode (GisDriver     *driver,
398                              UmAccountMode  mode)
399 {
400   driver->account_mode = mode;
401 }
402 
403 UmAccountMode
gis_driver_get_account_mode(GisDriver * driver)404 gis_driver_get_account_mode (GisDriver *driver)
405 {
406   return driver->account_mode;
407 }
408 
409 /**
410  * gis_driver_set_parental_controls_enabled:
411  * @driver: a #GisDriver
412  * @parental_controls_enabled: whether parental controls are enabled for the main user
413  *
414  * Set the #GisDriver:parental-controls-enabled property.
415  *
416  * Since: 3.36
417  */
418 void
gis_driver_set_parental_controls_enabled(GisDriver * driver,gboolean parental_controls_enabled)419 gis_driver_set_parental_controls_enabled (GisDriver *driver,
420                                           gboolean   parental_controls_enabled)
421 {
422   if (driver->parental_controls_enabled == parental_controls_enabled)
423     return;
424 
425   driver->parental_controls_enabled = parental_controls_enabled;
426   rebuild_pages (driver);
427 
428   g_object_notify_by_pspec (G_OBJECT (driver), obj_props[PROP_PARENTAL_CONTROLS_ENABLED]);
429 }
430 
431 /**
432  * gis_driver_get_parental_controls_enabled:
433  * @driver: a #GisDriver
434  *
435  * Get the #GisDriver:parental-controls-enabled property.
436  *
437  * Returns: whether parental controls are enabled for the main user
438  * Since: 3.36
439  */
440 gboolean
gis_driver_get_parental_controls_enabled(GisDriver * driver)441 gis_driver_get_parental_controls_enabled (GisDriver *driver)
442 {
443   return driver->parental_controls_enabled;
444 }
445 
446 gboolean
gis_driver_get_gdm_objects(GisDriver * driver,GdmGreeter ** greeter,GdmUserVerifier ** user_verifier)447 gis_driver_get_gdm_objects (GisDriver        *driver,
448                             GdmGreeter      **greeter,
449                             GdmUserVerifier **user_verifier)
450 {
451   if (driver->greeter == NULL || driver->user_verifier == NULL)
452     return FALSE;
453 
454   *greeter = driver->greeter;
455   *user_verifier = driver->user_verifier;
456 
457   return TRUE;
458 }
459 
460 void
gis_driver_add_page(GisDriver * driver,GisPage * page)461 gis_driver_add_page (GisDriver *driver,
462                      GisPage   *page)
463 {
464   gis_assistant_add_page (driver->assistant, page);
465 }
466 
467 void
gis_driver_hide_window(GisDriver * driver)468 gis_driver_hide_window (GisDriver *driver)
469 {
470   gtk_widget_hide (GTK_WIDGET (driver->main_window));
471 }
472 
473 static gboolean
load_vendor_conf_file_at_path(GisDriver * driver,const char * path)474 load_vendor_conf_file_at_path (GisDriver *driver,
475                                const char *path)
476 {
477   g_autoptr(GError) error = NULL;
478   g_autoptr(GKeyFile) vendor_conf_file = g_key_file_new ();
479 
480   if (!g_key_file_load_from_file (vendor_conf_file, path, G_KEY_FILE_NONE, &error))
481     {
482       if (!g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NOENT))
483         g_warning ("Could not read file %s: %s:", path, error->message);
484       return FALSE;
485     }
486 
487   driver->vendor_conf_file_path = path;
488   driver->vendor_conf_file = g_steal_pointer (&vendor_conf_file);
489   return TRUE;
490 }
491 
492 static void
load_vendor_conf_file(GisDriver * driver)493 load_vendor_conf_file (GisDriver *driver)
494 {
495 #ifdef VENDOR_CONF_FILE
496   load_vendor_conf_file_at_path (driver, VENDOR_CONF_FILE);
497 #else
498   /* If no path was passed at build time, then we have search path:
499    *
500    *  - First check $(sysconfdir)/gnome-initial-setup/vendor.conf
501    *  - Then check $(datadir)/gnome-initial-setup/vendor.conf
502    *
503    * This allows distributions to provide a default packaged config in a
504    * location that might be managed by ostree, and allows OEMs to
505    * override using an unmanaged location.
506    */
507   if (!load_vendor_conf_file_at_path (driver, PKGSYSCONFDIR "/vendor.conf"))
508     load_vendor_conf_file_at_path (driver, PKGDATADIR "/vendor.conf");
509 #endif
510 }
511 
512 static void
report_conf_error_if_needed(GisDriver * driver,const gchar * group,const gchar * key,const GError * error)513 report_conf_error_if_needed (GisDriver *driver,
514                              const gchar *group,
515                              const gchar *key,
516                              const GError *error)
517 {
518   if (!g_error_matches (error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_KEY_NOT_FOUND) &&
519       !g_error_matches (error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_GROUP_NOT_FOUND))
520     g_warning ("Error getting the value for key '%s' of group [%s] in %s: %s",
521                group, key, driver->vendor_conf_file_path, error->message);
522 }
523 
524 gboolean
gis_driver_conf_get_boolean(GisDriver * driver,const gchar * group,const gchar * key,gboolean default_value)525 gis_driver_conf_get_boolean (GisDriver *driver,
526                              const gchar *group,
527                              const gchar *key,
528                              gboolean default_value)
529 {
530   if (driver->vendor_conf_file) {
531     g_autoptr(GError) error = NULL;
532     gboolean new_value = g_key_file_get_boolean (driver->vendor_conf_file, group,
533                                                  key, &error);
534     if (error == NULL)
535       return new_value;
536 
537     report_conf_error_if_needed (driver, group, key, error);
538   }
539 
540   return default_value;
541 }
542 
543 GStrv
gis_driver_conf_get_string_list(GisDriver * driver,const gchar * group,const gchar * key,gsize * out_length)544 gis_driver_conf_get_string_list (GisDriver *driver,
545                                  const gchar *group,
546                                  const gchar *key,
547                                  gsize *out_length)
548 {
549   if (driver->vendor_conf_file) {
550     g_autoptr(GError) error = NULL;
551     GStrv new_value = g_key_file_get_string_list (driver->vendor_conf_file, group,
552                                                   key, out_length, &error);
553     if (error == NULL)
554       return new_value;
555 
556     report_conf_error_if_needed (driver, group, key, error);
557   }
558 
559   return NULL;
560 }
561 
562 gchar *
gis_driver_conf_get_string(GisDriver * driver,const gchar * group,const gchar * key)563 gis_driver_conf_get_string (GisDriver *driver,
564                             const gchar *group,
565                             const gchar *key)
566 {
567   if (driver->vendor_conf_file) {
568     g_autoptr(GError) error = NULL;
569     gchar *new_value = g_key_file_get_string (driver->vendor_conf_file, group,
570                                               key, &error);
571     if (error == NULL)
572       return new_value;
573 
574     report_conf_error_if_needed (driver, group, key, error);
575   }
576 
577   return NULL;
578 }
579 
580 GisDriverMode
gis_driver_get_mode(GisDriver * driver)581 gis_driver_get_mode (GisDriver *driver)
582 {
583   return driver->mode;
584 }
585 
586 gboolean
gis_driver_is_small_screen(GisDriver * driver)587 gis_driver_is_small_screen (GisDriver *driver)
588 {
589   return driver->small_screen;
590 }
591 
592 static gboolean
monitor_is_small(GdkMonitor * monitor)593 monitor_is_small (GdkMonitor *monitor)
594 {
595   GdkRectangle geom;
596 
597   if (g_getenv ("GIS_SMALL_SCREEN"))
598     return TRUE;
599 
600   gdk_monitor_get_geometry (monitor, &geom);
601   return geom.height < 800;
602 }
603 
604 static void
gis_driver_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)605 gis_driver_get_property (GObject      *object,
606                          guint         prop_id,
607                          GValue       *value,
608                          GParamSpec   *pspec)
609 {
610   GisDriver *driver = GIS_DRIVER (object);
611 
612   switch ((GisDriverProperty) prop_id)
613     {
614     case PROP_MODE:
615       g_value_set_enum (value, driver->mode);
616       break;
617     case PROP_USERNAME:
618       g_value_set_string (value, driver->username);
619       break;
620     case PROP_SMALL_SCREEN:
621       g_value_set_boolean (value, driver->small_screen);
622       break;
623     case PROP_PARENTAL_CONTROLS_ENABLED:
624       g_value_set_boolean (value, driver->parental_controls_enabled);
625       break;
626     case PROP_FULL_NAME:
627       g_value_set_string (value, driver->full_name);
628       break;
629     case PROP_AVATAR:
630       g_value_set_object (value, driver->avatar);
631       break;
632     default:
633       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
634       break;
635     }
636 }
637 
638 static void
gis_driver_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)639 gis_driver_set_property (GObject      *object,
640                          guint         prop_id,
641                          const GValue *value,
642                          GParamSpec   *pspec)
643 {
644   GisDriver *driver = GIS_DRIVER (object);
645 
646   switch ((GisDriverProperty) prop_id)
647     {
648     case PROP_MODE:
649       driver->mode = g_value_get_enum (value);
650       break;
651     case PROP_USERNAME:
652       g_free (driver->username);
653       driver->username = g_value_dup_string (value);
654       break;
655     case PROP_PARENTAL_CONTROLS_ENABLED:
656       gis_driver_set_parental_controls_enabled (driver, g_value_get_boolean (value));
657       break;
658     case PROP_FULL_NAME:
659       gis_driver_set_full_name (driver, g_value_get_string (value));
660       break;
661     case PROP_AVATAR:
662       gis_driver_set_avatar (driver, g_value_get_object (value));
663       break;
664     default:
665       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
666       break;
667     }
668 }
669 
670 static void
gis_driver_activate(GApplication * app)671 gis_driver_activate (GApplication *app)
672 {
673   GisDriver *driver = GIS_DRIVER (app);
674 
675   G_APPLICATION_CLASS (gis_driver_parent_class)->activate (app);
676 
677   gtk_window_present (GTK_WINDOW (driver->main_window));
678 }
679 
680 static void
set_small_screen_based_on_primary_monitor(GisDriver * driver)681 set_small_screen_based_on_primary_monitor (GisDriver *driver)
682 {
683   GdkDisplay *default_display;
684   GdkMonitor *primary_monitor;
685 
686   default_display = gdk_display_get_default ();
687   if (default_display == NULL)
688     return;
689 
690   primary_monitor = gdk_display_get_primary_monitor (default_display);
691   if (primary_monitor == NULL)
692     return;
693 
694   driver->small_screen = monitor_is_small (primary_monitor);
695 }
696 
697 /* Recompute driver->small_screen based on the monitor where the window is
698  * located, if the window is actually realized. If not, recompute it based on
699  * the primary monitor of the default display. */
700 static void
recompute_small_screen(GisDriver * driver)701 recompute_small_screen (GisDriver *driver) {
702   GdkWindow *window;
703   GdkDisplay *default_display = gdk_display_get_default ();
704   GdkMonitor *active_monitor;
705   gboolean old_value = driver->small_screen;
706 
707   if (!gtk_widget_get_realized (GTK_WIDGET (driver->main_window)))
708     {
709       set_small_screen_based_on_primary_monitor (driver);
710     }
711   else
712     {
713       window = gtk_widget_get_window (GTK_WIDGET (driver->main_window));
714       active_monitor = gdk_display_get_monitor_at_window (default_display, window);
715       driver->small_screen = monitor_is_small (active_monitor);
716     }
717 
718   if (driver->small_screen != old_value)
719     g_object_notify (G_OBJECT (driver), "small-screen");
720 }
721 
722 static void
update_screen_size(GisDriver * driver)723 update_screen_size (GisDriver *driver)
724 {
725   GdkWindow *window;
726   GdkGeometry size_hints;
727   GtkWidget *sw;
728 
729   recompute_small_screen (driver);
730 
731   if (!gtk_widget_get_realized (GTK_WIDGET (driver->main_window)))
732     return;
733 
734   sw = gtk_bin_get_child (GTK_BIN (driver->main_window));
735   window = gtk_widget_get_window (GTK_WIDGET (driver->main_window));
736 
737   if (driver->small_screen)
738     {
739       if (window)
740         gdk_window_set_functions (window,
741                                   GDK_FUNC_ALL | GDK_FUNC_MINIMIZE | GDK_FUNC_CLOSE);
742 
743       gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
744                                       GTK_POLICY_AUTOMATIC,
745                                       GTK_POLICY_AUTOMATIC);
746 
747       gtk_window_set_geometry_hints (driver->main_window, NULL, NULL, 0);
748       gtk_window_set_resizable (driver->main_window, TRUE);
749       gtk_window_set_position (driver->main_window, GTK_WIN_POS_NONE);
750 
751       gtk_window_maximize (driver->main_window);
752       gtk_window_present (driver->main_window);
753     }
754   else
755     {
756       if (window)
757         gdk_window_set_functions (window,
758                                   GDK_FUNC_ALL | GDK_FUNC_MINIMIZE | GDK_FUNC_CLOSE |
759                                   GDK_FUNC_RESIZE | GDK_FUNC_MOVE | GDK_FUNC_MAXIMIZE);
760 
761       gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
762                                       GTK_POLICY_NEVER,
763                                       GTK_POLICY_NEVER);
764 
765       size_hints.min_width = size_hints.max_width = 1024;
766       size_hints.min_height = size_hints.max_height = 768;
767       size_hints.win_gravity = GDK_GRAVITY_CENTER;
768 
769       gtk_window_set_geometry_hints (driver->main_window,
770                                      NULL,
771                                      &size_hints,
772                                      GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE | GDK_HINT_WIN_GRAVITY);
773       gtk_window_set_resizable (driver->main_window, FALSE);
774       gtk_window_set_position (driver->main_window, GTK_WIN_POS_CENTER_ALWAYS);
775 
776       gtk_window_unmaximize (driver->main_window);
777       gtk_window_present (driver->main_window);
778     }
779 }
780 
781 static void
screen_size_changed(GdkScreen * screen,GisDriver * driver)782 screen_size_changed (GdkScreen *screen, GisDriver *driver)
783 {
784   update_screen_size (driver);
785 }
786 
787 static void
window_realize_cb(GtkWidget * widget,gpointer user_data)788 window_realize_cb (GtkWidget *widget, gpointer user_data)
789 {
790   update_screen_size (GIS_DRIVER (user_data));
791 }
792 
793 static void
connect_to_gdm(GisDriver * driver)794 connect_to_gdm (GisDriver *driver)
795 {
796   g_autoptr(GError) error = NULL;
797 
798   driver->client = gdm_client_new ();
799 
800   driver->greeter = gdm_client_get_greeter_sync (driver->client, NULL, &error);
801   if (error == NULL)
802     driver->user_verifier = gdm_client_get_user_verifier_sync (driver->client, NULL, &error);
803 
804   if (error != NULL) {
805     g_warning ("Failed to open connection to GDM: %s", error->message);
806     g_clear_object (&driver->user_verifier);
807     g_clear_object (&driver->greeter);
808     g_clear_object (&driver->client);
809   }
810 }
811 
812 static void
gis_driver_startup(GApplication * app)813 gis_driver_startup (GApplication *app)
814 {
815   GisDriver *driver = GIS_DRIVER (app);
816   WebKitWebContext *context = webkit_web_context_get_default ();
817 
818   G_APPLICATION_CLASS (gis_driver_parent_class)->startup (app);
819 
820   webkit_web_context_set_sandbox_enabled (context, TRUE);
821 
822   if (driver->mode == GIS_DRIVER_MODE_NEW_USER)
823     connect_to_gdm (driver);
824 
825   driver->main_window = g_object_new (GTK_TYPE_APPLICATION_WINDOW,
826                                     "application", app,
827                                     "type", GTK_WINDOW_TOPLEVEL,
828                                     "icon-name", "preferences-system",
829                                     "deletable", FALSE,
830                                     NULL);
831 
832   g_signal_connect (driver->main_window,
833                     "realize",
834                     G_CALLBACK (window_realize_cb),
835                     (gpointer)app);
836 
837   driver->assistant = g_object_new (GIS_TYPE_ASSISTANT, NULL);
838   gtk_container_add (GTK_CONTAINER (driver->main_window), GTK_WIDGET (driver->assistant));
839 
840   gtk_widget_show (GTK_WIDGET (driver->assistant));
841 
842   gis_driver_set_user_language (driver, setlocale (LC_MESSAGES, NULL), FALSE);
843 
844   prepare_main_window (driver);
845   rebuild_pages (driver);
846 }
847 
848 static void
gis_driver_init(GisDriver * driver)849 gis_driver_init (GisDriver *driver)
850 {
851   GdkScreen *screen;
852 
853   screen = gdk_screen_get_default ();
854 
855   set_small_screen_based_on_primary_monitor (driver);
856 
857   load_vendor_conf_file (driver);
858 
859   if (screen != NULL)
860     g_signal_connect (screen, "size-changed",
861                       G_CALLBACK (screen_size_changed), driver);
862 }
863 
864 static void
gis_driver_class_init(GisDriverClass * klass)865 gis_driver_class_init (GisDriverClass *klass)
866 {
867   GApplicationClass *application_class = G_APPLICATION_CLASS (klass);
868   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
869 
870   gobject_class->get_property = gis_driver_get_property;
871   gobject_class->set_property = gis_driver_set_property;
872   gobject_class->dispose = gis_driver_dispose;
873   gobject_class->finalize = gis_driver_finalize;
874   application_class->startup = gis_driver_startup;
875   application_class->activate = gis_driver_activate;
876 
877   signals[REBUILD_PAGES] =
878     g_signal_new ("rebuild-pages",
879                   G_TYPE_FROM_CLASS (klass),
880                   G_SIGNAL_RUN_FIRST,
881                   0,
882                   NULL, NULL, NULL,
883                   G_TYPE_NONE, 0);
884 
885   signals[LOCALE_CHANGED] =
886     g_signal_new ("locale-changed",
887                   G_TYPE_FROM_CLASS (klass),
888                   G_SIGNAL_RUN_FIRST,
889                   0,
890                   NULL, NULL, NULL,
891                   G_TYPE_NONE, 0);
892 
893   obj_props[PROP_MODE] =
894     g_param_spec_enum ("mode", "", "",
895                        GIS_TYPE_DRIVER_MODE,
896                        GIS_DRIVER_MODE_EXISTING_USER,
897                        G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
898 
899   obj_props[PROP_USERNAME] =
900     g_param_spec_string ("username", "", "",
901                          NULL,
902                          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
903 
904   obj_props[PROP_SMALL_SCREEN] =
905     g_param_spec_boolean ("small-screen", "", "",
906                           FALSE,
907                           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
908 
909   /**
910    * GisDriver:parental-controls-enabled:
911    *
912    * Whether parental controls are enabled for the main user. If this is %TRUE,
913    * two user accounts will be created when this page is saved: one for the main
914    * user (a child) which will be a standard account; and one for the parent
915    * which will be an administrative account.
916    *
917    * Since: 3.36
918    */
919   obj_props[PROP_PARENTAL_CONTROLS_ENABLED] =
920     g_param_spec_boolean ("parental-controls-enabled",
921                           "Parental Controls Enabled",
922                           "Whether parental controls are enabled for the main user.",
923                           FALSE,
924                           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
925 
926   /**
927    * GisDriver:full-name: (nullable)
928    *
929    * Full name of the main user. May be %NULL if unknown or not set yet.
930    *
931    * Since: 3.36
932    */
933   obj_props[PROP_FULL_NAME] =
934     g_param_spec_string ("full-name",
935                          "Full Name",
936                          "Full name of the main user.",
937                          NULL,
938                          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
939 
940   /**
941    * GisDriver:avatar: (nullable)
942    *
943    * Avatar of the main user. May be %NULL if unknown or not set yet.
944    *
945    * Since: 3.36
946    */
947   obj_props[PROP_AVATAR] =
948     g_param_spec_object ("avatar",
949                          "Avatar",
950                          "Avatar of the main user.",
951                          GDK_TYPE_PIXBUF,
952                          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
953 
954   g_object_class_install_properties (gobject_class, G_N_ELEMENTS (obj_props), obj_props);
955 }
956 
957 gboolean
gis_driver_save_data(GisDriver * driver,GError ** error)958 gis_driver_save_data (GisDriver  *driver,
959                       GError    **error)
960 {
961   if (gis_get_mock_mode ())
962     {
963       g_message ("%s: Skipping saving data due to being in mock mode", G_STRFUNC);
964       return TRUE;
965     }
966 
967   return gis_assistant_save_data (driver->assistant, error);
968 }
969 
970 GisDriver *
gis_driver_new(GisDriverMode mode)971 gis_driver_new (GisDriverMode mode)
972 {
973   return g_object_new (GIS_TYPE_DRIVER,
974                        "application-id", "org.gnome.InitialSetup",
975                        "mode", mode,
976                        NULL);
977 }
978