[gnome-initial-setup/wip/port-to-gtk4: 5/17] timezone: Port to GTK4




commit d5177013ba5873d47b03db30b570d1725779117f
Author: Georges Basile Stavracas Neto <georges stavracas gmail com>
Date:   Thu Jul 7 09:06:38 2022 -0300

    timezone: Port to GTK4
    
    This port required quite a substantial rework. The new timezone map
    code is copied verbatim from Settings, as well as the new flatter
    map itself.

 gnome-initial-setup/gnome-initial-setup.c          |   4 +-
 gnome-initial-setup/meson.build                    |   6 +-
 gnome-initial-setup/pages/meson.build              |   2 +-
 .../pages/timezone/cc-timezone-map.c               | 431 +++++++--------------
 gnome-initial-setup/pages/timezone/data/bg.png     | Bin 213448 -> 85309 bytes
 gnome-initial-setup/pages/timezone/data/bg_dim.png | Bin 95862 -> 62521 bytes
 gnome-initial-setup/pages/timezone/data/cc.png     | Bin 51482 -> 0 bytes
 gnome-initial-setup/pages/timezone/data/pin.png    | Bin 666 -> 447 bytes
 .../pages/timezone/data/timezone_-1.png            | Bin 8012 -> 0 bytes
 .../pages/timezone/data/timezone_-10.png           | Bin 7783 -> 0 bytes
 .../pages/timezone/data/timezone_-10_dim.png       | Bin 5139 -> 0 bytes
 .../pages/timezone/data/timezone_-11.png           | Bin 8347 -> 0 bytes
 .../pages/timezone/data/timezone_-11_dim.png       | Bin 4815 -> 0 bytes
 .../pages/timezone/data/timezone_-1_dim.png        | Bin 4953 -> 0 bytes
 .../pages/timezone/data/timezone_-2.png            | Bin 4333 -> 0 bytes
 .../pages/timezone/data/timezone_-2_dim.png        | Bin 2670 -> 0 bytes
 .../pages/timezone/data/timezone_-3.5.png          | Bin 740 -> 0 bytes
 .../pages/timezone/data/timezone_-3.5_dim.png      | Bin 995 -> 0 bytes
 .../pages/timezone/data/timezone_-3.png            | Bin 13615 -> 0 bytes
 .../pages/timezone/data/timezone_-3_dim.png        | Bin 8773 -> 0 bytes
 .../pages/timezone/data/timezone_-4.png            | Bin 16851 -> 0 bytes
 .../pages/timezone/data/timezone_-4_dim.png        | Bin 9785 -> 0 bytes
 .../pages/timezone/data/timezone_-5.5.png          | Bin 437 -> 0 bytes
 .../pages/timezone/data/timezone_-5.5_dim.png      | Bin 859 -> 0 bytes
 .../pages/timezone/data/timezone_-5.png            | Bin 19166 -> 0 bytes
 .../pages/timezone/data/timezone_-5_dim.png        | Bin 12224 -> 0 bytes
 .../pages/timezone/data/timezone_-6.png            | Bin 13764 -> 0 bytes
 .../pages/timezone/data/timezone_-6_dim.png        | Bin 8833 -> 0 bytes
 .../pages/timezone/data/timezone_-7.png            | Bin 11977 -> 0 bytes
 .../pages/timezone/data/timezone_-7_dim.png        | Bin 7868 -> 0 bytes
 .../pages/timezone/data/timezone_-8.png            | Bin 6801 -> 0 bytes
 .../pages/timezone/data/timezone_-8_dim.png        | Bin 4261 -> 0 bytes
 .../pages/timezone/data/timezone_-9.5.png          | Bin 437 -> 0 bytes
 .../pages/timezone/data/timezone_-9.5_dim.png      | Bin 859 -> 0 bytes
 .../pages/timezone/data/timezone_-9.png            | Bin 7908 -> 0 bytes
 .../pages/timezone/data/timezone_-9_dim.png        | Bin 4972 -> 0 bytes
 .../pages/timezone/data/timezone_0.png             | Bin 11074 -> 0 bytes
 .../pages/timezone/data/timezone_0_dim.png         | Bin 7074 -> 0 bytes
 .../pages/timezone/data/timezone_1.png             | Bin 15458 -> 0 bytes
 .../pages/timezone/data/timezone_10.5.png          | Bin 421 -> 0 bytes
 .../pages/timezone/data/timezone_10.5_dim.png      | Bin 844 -> 0 bytes
 .../pages/timezone/data/timezone_10.png            | Bin 12829 -> 0 bytes
 .../pages/timezone/data/timezone_10_dim.png        | Bin 8395 -> 0 bytes
 .../pages/timezone/data/timezone_11.5.png          | Bin 446 -> 0 bytes
 .../pages/timezone/data/timezone_11.5_dim.png      | Bin 868 -> 0 bytes
 .../pages/timezone/data/timezone_11.png            | Bin 12113 -> 0 bytes
 .../pages/timezone/data/timezone_11_dim.png        | Bin 6744 -> 0 bytes
 .../pages/timezone/data/timezone_12.75.png         | Bin 409 -> 0 bytes
 .../pages/timezone/data/timezone_12.75_dim.png     | Bin 846 -> 0 bytes
 .../pages/timezone/data/timezone_12.png            | Bin 7130 -> 0 bytes
 .../pages/timezone/data/timezone_12_dim.png        | Bin 3935 -> 0 bytes
 .../pages/timezone/data/timezone_13.png            | Bin 621 -> 0 bytes
 .../pages/timezone/data/timezone_13_dim.png        | Bin 876 -> 0 bytes
 .../pages/timezone/data/timezone_14.png            | Bin 7722 -> 0 bytes
 .../pages/timezone/data/timezone_14_dim.png        | Bin 4150 -> 0 bytes
 .../pages/timezone/data/timezone_1_dim.png         | Bin 10187 -> 0 bytes
 .../pages/timezone/data/timezone_2.png             | Bin 12854 -> 0 bytes
 .../pages/timezone/data/timezone_2_dim.png         | Bin 8709 -> 0 bytes
 .../pages/timezone/data/timezone_3.5.png           | Bin 2142 -> 0 bytes
 .../pages/timezone/data/timezone_3.5_dim.png       | Bin 1781 -> 0 bytes
 .../pages/timezone/data/timezone_3.png             | Bin 17475 -> 0 bytes
 .../pages/timezone/data/timezone_3_dim.png         | Bin 9877 -> 0 bytes
 .../pages/timezone/data/timezone_4.5.png           | Bin 1773 -> 0 bytes
 .../pages/timezone/data/timezone_4.5_dim.png       | Bin 1385 -> 0 bytes
 .../pages/timezone/data/timezone_4.png             | Bin 4954 -> 0 bytes
 .../pages/timezone/data/timezone_4_dim.png         | Bin 2754 -> 0 bytes
 .../pages/timezone/data/timezone_5.5.png           | Bin 5692 -> 0 bytes
 .../pages/timezone/data/timezone_5.5_dim.png       | Bin 3471 -> 0 bytes
 .../pages/timezone/data/timezone_5.75.png          | Bin 2885 -> 0 bytes
 .../pages/timezone/data/timezone_5.75_dim.png      | Bin 1596 -> 0 bytes
 .../pages/timezone/data/timezone_5.png             | Bin 14539 -> 0 bytes
 .../pages/timezone/data/timezone_5_dim.png         | Bin 8117 -> 0 bytes
 .../pages/timezone/data/timezone_6.5.png           | Bin 1609 -> 0 bytes
 .../pages/timezone/data/timezone_6.5_dim.png       | Bin 1675 -> 0 bytes
 .../pages/timezone/data/timezone_6.png             | Bin 7654 -> 0 bytes
 .../pages/timezone/data/timezone_6_dim.png         | Bin 4584 -> 0 bytes
 .../pages/timezone/data/timezone_7.png             | Bin 14412 -> 0 bytes
 .../pages/timezone/data/timezone_7_dim.png         | Bin 7972 -> 0 bytes
 .../pages/timezone/data/timezone_8.75.png          | Bin 13993 -> 0 bytes
 .../pages/timezone/data/timezone_8.75_dim.png      | Bin 7064 -> 0 bytes
 .../pages/timezone/data/timezone_8.png             | Bin 16050 -> 0 bytes
 .../pages/timezone/data/timezone_8_dim.png         | Bin 9378 -> 0 bytes
 .../pages/timezone/data/timezone_9.5.png           | Bin 1959 -> 0 bytes
 .../pages/timezone/data/timezone_9.5_dim.png       | Bin 1611 -> 0 bytes
 .../pages/timezone/data/timezone_9.png             | Bin 14366 -> 0 bytes
 .../pages/timezone/data/timezone_9_dim.png         | Bin 8362 -> 0 bytes
 .../pages/timezone/datetime.gresource.xml          |  79 ----
 .../pages/timezone/gis-bubble-widget.c             |  23 +-
 .../pages/timezone/gis-bubble-widget.css           |   2 +-
 .../pages/timezone/gis-bubble-widget.h             |   6 +-
 .../pages/timezone/gis-bubble-widget.ui            |   8 +-
 .../pages/timezone/gis-location-entry.c            |  78 +++-
 .../pages/timezone/gis-location-entry.h            |   6 +-
 .../pages/timezone/gis-timezone-page.c             |  29 +-
 .../pages/timezone/gis-timezone-page.ui            |  15 -
 gnome-initial-setup/pages/timezone/tz.c            |  52 ++-
 gnome-initial-setup/pages/timezone/tz.h            |   8 +-
 97 files changed, 275 insertions(+), 474 deletions(-)
---
diff --git a/gnome-initial-setup/gnome-initial-setup.c b/gnome-initial-setup/gnome-initial-setup.c
index 82963e21..5321c8a6 100644
--- a/gnome-initial-setup/gnome-initial-setup.c
+++ b/gnome-initial-setup/gnome-initial-setup.c
@@ -33,7 +33,7 @@
 #include "pages/language/gis-language-page.h"
 #include "pages/keyboard/gis-keyboard-page.h"
 #include "pages/network/gis-network-page.h"
-//#include "pages/timezone/gis-timezone-page.h"
+#include "pages/timezone/gis-timezone-page.h"
 #include "pages/privacy/gis-privacy-page.h"
 //#include "pages/software/gis-software-page.h"
 //#include "pages/goa/gis-goa-page.h"
@@ -67,7 +67,7 @@ static PageData page_table[] = {
   PAGE (keyboard, FALSE),
   PAGE (network,  FALSE),
   PAGE (privacy,  FALSE),
-  //PAGE (timezone, TRUE),
+  PAGE (timezone, TRUE),
   //PAGE (software, TRUE),
   //PAGE (goa,      FALSE),
   //PAGE (account,  TRUE),
diff --git a/gnome-initial-setup/meson.build b/gnome-initial-setup/meson.build
index 6197b9ef..85f67c97 100644
--- a/gnome-initial-setup/meson.build
+++ b/gnome-initial-setup/meson.build
@@ -50,7 +50,7 @@ dependencies = [
     dependency ('libnma-gtk4', version: '>= 1.0'),
     dependency ('polkit-gobject-1', version: '>= 0.103'),
     dependency ('accountsservice'),
-    #geocode_glib_2_dep,
+    geocode_glib_2_dep,
     dependency ('gnome-desktop-4'),
     dependency ('gsettings-desktop-schemas', version: '>= 3.37.1'),
     dependency ('fontconfig'),
@@ -60,8 +60,8 @@ dependencies = [
     dependency ('glib-2.0', version: '>= 2.63.1'),
     dependency ('gio-unix-2.0', version: '>= 2.53.0'),
     dependency ('gdm', version: '>= 3.8.3'),
-    #dependency ('gweather4'),
-    #dependency ('libgeoclue-2.0', version: '>= 2.3.1'),
+    dependency ('gweather4'),
+    dependency ('libgeoclue-2.0', version: '>= 2.3.1'),
     cc.find_library('m', required: false),
     dependency ('pango', version: '>= 1.32.5'),
     #dependency ('json-glib-1.0'),
diff --git a/gnome-initial-setup/pages/meson.build b/gnome-initial-setup/pages/meson.build
index 208b775f..aff33f2c 100644
--- a/gnome-initial-setup/pages/meson.build
+++ b/gnome-initial-setup/pages/meson.build
@@ -3,7 +3,7 @@ pages = [
    'language',
    'keyboard',
    'network',
-   #'timezone',
+   'timezone',
    'privacy',
    #'goa',
    #'password',
diff --git a/gnome-initial-setup/pages/timezone/cc-timezone-map.c 
b/gnome-initial-setup/pages/timezone/cc-timezone-map.c
index 3c813a68..863b4c9e 100644
--- a/gnome-initial-setup/pages/timezone/cc-timezone-map.c
+++ b/gnome-initial-setup/pages/timezone/cc-timezone-map.c
@@ -44,18 +44,11 @@ struct _CcTimezoneMap
 {
   GtkWidget parent_instance;
 
-  GdkPixbuf *orig_background;
-  GdkPixbuf *orig_background_dim;
-  GdkPixbuf *orig_color_map;
+  GdkTexture *orig_background;
+  GdkTexture *orig_background_dim;
 
-  GdkPixbuf *background;
-  GdkPixbuf *color_map;
-  GdkPixbuf *pin;
-
-  guchar *visible_map_pixels;
-  gint visible_map_rowstride;
-
-  gdouble selected_offset;
+  GdkTexture *background;
+  GdkTexture *pin;
 
   TzDB *tzdb;
   TzLocation *location;
@@ -73,50 +66,16 @@ enum
 
 static guint signals[LAST_SIGNAL];
 
-
-static CcTimezoneMapOffset color_codes[] =
+static GdkTexture *
+texture_from_resource (const gchar  *resource_path,
+                       GError      **error)
 {
-    {-11.0, 43, 0, 0, 255 },
-    {-10.0, 85, 0, 0, 255 },
-    {-9.5, 102, 255, 0, 255 },
-    {-9.0, 128, 0, 0, 255 },
-    {-8.0, 170, 0, 0, 255 },
-    {-7.0, 212, 0, 0, 255 },
-    {-6.0, 255, 0, 1, 255 }, // north
-    {-6.0, 255, 0, 0, 255 }, // south
-    {-5.0, 255, 42, 42, 255 },
-    {-4.5, 192, 255, 0, 255 },
-    {-4.0, 255, 85, 85, 255 },
-    {-3.5, 0, 255, 0, 255 },
-    {-3.0, 255, 128, 128, 255 },
-    {-2.0, 255, 170, 170, 255 },
-    {-1.0, 255, 213, 213, 255 },
-    {0.0, 43, 17, 0, 255 },
-    {1.0, 85, 34, 0, 255 },
-    {2.0, 128, 51, 0, 255 },
-    {3.0, 170, 68, 0, 255 },
-    {3.5, 0, 255, 102, 255 },
-    {4.0, 212, 85, 0, 255 },
-    {4.5, 0, 204, 255, 255 },
-    {5.0, 255, 102, 0, 255 },
-    {5.5, 0, 102, 255, 255 },
-    {5.75, 0, 238, 207, 247 },
-    {6.0, 255, 127, 42, 255 },
-    {6.5, 204, 0, 254, 254 },
-    {7.0, 255, 153, 85, 255 },
-    {8.0, 255, 179, 128, 255 },
-    {9.0, 255, 204, 170, 255 },
-    {9.5, 170, 0, 68, 250 },
-    {10.0, 255, 230, 213, 255 },
-    {10.5, 212, 124, 21, 250 },
-    {11.0, 212, 170, 0, 255 },
-    {11.5, 249, 25, 87, 253 },
-    {12.0, 255, 204, 0, 255 },
-    {12.75, 254, 74, 100, 248 },
-    {13.0, 255, 85, 153, 250 },
-    {-100, 0, 0, 0, 0 }
-};
+  g_autofree gchar *full_path = g_strdup_printf ("resource://%s", resource_path);
+  g_autoptr(GFile) file = g_file_new_for_uri (full_path);
+  g_autoptr(GdkTexture) texture = gdk_texture_new_from_file (file, error);
 
+  return g_steal_pointer (&texture);
+}
 
 static void
 cc_timezone_map_dispose (GObject *object)
@@ -125,19 +84,10 @@ cc_timezone_map_dispose (GObject *object)
 
   g_clear_object (&self->orig_background);
   g_clear_object (&self->orig_background_dim);
-  g_clear_object (&self->orig_color_map);
   g_clear_object (&self->background);
   g_clear_object (&self->pin);
   g_clear_pointer (&self->bubble_text, g_free);
 
-  if (self->color_map)
-    {
-      g_clear_object (&self->color_map);
-
-      self->visible_map_pixels = NULL;
-      self->visible_map_rowstride = 0;
-    }
-
   G_OBJECT_CLASS (cc_timezone_map_parent_class)->dispose (object);
 }
 
@@ -153,30 +103,27 @@ cc_timezone_map_finalize (GObject *object)
 
 /* GtkWidget functions */
 static void
-cc_timezone_map_get_preferred_width (GtkWidget *widget,
-                                     gint      *minimum,
-                                     gint      *natural)
+cc_timezone_map_measure (GtkWidget      *widget,
+                         GtkOrientation  orientation,
+                         gint            for_size,
+                         gint           *minimum,
+                         gint           *natural,
+                         gint           *minimum_baseline,
+                         gint           *natural_baseline)
 {
   CcTimezoneMap *map = CC_TIMEZONE_MAP (widget);
   gint size;
 
-  size = gdk_pixbuf_get_width (map->orig_background);
-
-  if (minimum != NULL)
-    *minimum = size;
-  if (natural != NULL)
-    *natural = size;
-}
-
-static void
-cc_timezone_map_get_preferred_height (GtkWidget *widget,
-                                      gint      *minimum,
-                                      gint      *natural)
-{
-  CcTimezoneMap *map = CC_TIMEZONE_MAP (widget);
-  gint size;
+  switch (orientation)
+    {
+    case GTK_ORIENTATION_HORIZONTAL:
+      size = gdk_texture_get_width (map->orig_background);
+      break;
 
-  size = gdk_pixbuf_get_height (map->orig_background);
+    case GTK_ORIENTATION_VERTICAL:
+      size = gdk_texture_get_height (map->orig_background);
+      break;
+    }
 
   if (minimum != NULL)
     *minimum = size;
@@ -185,68 +132,28 @@ cc_timezone_map_get_preferred_height (GtkWidget *widget,
 }
 
 static void
-cc_timezone_map_size_allocate (GtkWidget     *widget,
-                               GtkAllocation *allocation)
+cc_timezone_map_size_allocate (GtkWidget *widget,
+                               gint       width,
+                               gint       height,
+                               gint       baseline)
 {
   CcTimezoneMap *map = CC_TIMEZONE_MAP (widget);
-  GdkPixbuf *pixbuf;
-
-  if (map->background)
-    g_object_unref (map->background);
+  GdkTexture *texture;
 
   if (!gtk_widget_is_sensitive (widget))
-    pixbuf = map->orig_background_dim;
+    texture = map->orig_background_dim;
   else
-    pixbuf = map->orig_background;
+    texture = map->orig_background;
 
-  map->background = gdk_pixbuf_scale_simple (pixbuf,
-                                             allocation->width,
-                                             allocation->height,
-                                             GDK_INTERP_BILINEAR);
-
-  if (map->color_map)
-    g_object_unref (map->color_map);
-
-  map->color_map = gdk_pixbuf_scale_simple (map->orig_color_map,
-                                            allocation->width,
-                                            allocation->height,
-                                            GDK_INTERP_BILINEAR);
-
-  map->visible_map_pixels = gdk_pixbuf_get_pixels (map->color_map);
-  map->visible_map_rowstride = gdk_pixbuf_get_rowstride (map->color_map);
+  g_clear_object (&map->background);
+  map->background = g_object_ref (texture);
 
   GTK_WIDGET_CLASS (cc_timezone_map_parent_class)->size_allocate (widget,
-                                                                  allocation);
-}
-
-static void
-cc_timezone_map_realize (GtkWidget *widget)
-{
-  GdkWindowAttr attr = { 0, };
-  GtkAllocation allocation;
-  GdkWindow *window;
-
-  gtk_widget_get_allocation (widget, &allocation);
-
-  gtk_widget_set_realized (widget, TRUE);
-
-  attr.window_type = GDK_WINDOW_CHILD;
-  attr.wclass = GDK_INPUT_OUTPUT;
-  attr.width = allocation.width;
-  attr.height = allocation.height;
-  attr.x = allocation.x;
-  attr.y = allocation.y;
-  attr.event_mask = gtk_widget_get_events (widget)
-                                 | GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK;
-
-  window = gdk_window_new (gtk_widget_get_parent_window (widget), &attr,
-                           GDK_WA_X | GDK_WA_Y);
-
-  gdk_window_set_user_data (window, widget);
-  gtk_widget_set_window (widget, window);
+                                                                  width,
+                                                                  height,
+                                                                  baseline);
 }
 
-
 static gdouble
 convert_longitude_to_x (gdouble longitude, gint map_width)
 {
@@ -284,10 +191,12 @@ convert_latitude_to_y (gdouble latitude, gdouble map_height)
 }
 
 static void
-draw_text_bubble (cairo_t *cr,
-                  GtkWidget *widget,
-                  gdouble pointx,
-                  gdouble pointy)
+draw_text_bubble (CcTimezoneMap *map,
+                  GtkSnapshot   *snapshot,
+                  gint           width,
+                  gint           height,
+                  gdouble        pointx,
+                  gdouble        pointy)
 {
   static const double corner_radius = 9.0;
   static const double margin_top = 12.0;
@@ -295,20 +204,19 @@ draw_text_bubble (cairo_t *cr,
   static const double margin_left = 24.0;
   static const double margin_right = 24.0;
 
-  CcTimezoneMap *map = CC_TIMEZONE_MAP (widget);
-  GtkAllocation alloc;
-  PangoLayout *layout;
+  GskRoundedRect rounded_rect;
   PangoRectangle text_rect;
+  PangoLayout *layout;
+  GdkRGBA rgba;
   double x;
   double y;
-  double width;
-  double height;
+  double bubble_width;
+  double bubble_height;
 
   if (!map->bubble_text)
     return;
 
-  gtk_widget_get_allocation (widget, &alloc);
-  layout = gtk_widget_create_pango_layout (widget, NULL);
+  layout = gtk_widget_create_pango_layout (GTK_WIDGET (map), NULL);
 
   /* Layout the text */
   pango_layout_set_alignment (layout, PANGO_ALIGN_CENTER);
@@ -318,134 +226,107 @@ draw_text_bubble (cairo_t *cr,
   pango_layout_get_pixel_extents (layout, NULL, &text_rect);
 
   /* Calculate the bubble size based on the text layout size */
-  width = text_rect.width + margin_left + margin_right;
-  height = text_rect.height + margin_top + margin_bottom;
+  bubble_width = text_rect.width + margin_left + margin_right;
+  bubble_height = text_rect.height + margin_top + margin_bottom;
 
-  if (pointx < alloc.width / 2)
+  if (pointx < width / 2)
     x = pointx + 25;
   else
-    x = pointx - width - 25;
+    x = pointx - bubble_width - 25;
 
-  y = pointy - height / 2;
+  y = pointy - bubble_height / 2;
 
   /* Make sure it fits in the visible area */
-  x = CLAMP (x, 0, alloc.width - width);
-  y = CLAMP (y, 0, alloc.height - height);
-
-  cairo_save (cr);
-  cairo_translate (cr, x, y);
-
-  /* Draw the bubble */
-  cairo_new_sub_path (cr);
-  cairo_arc (cr, width - corner_radius, corner_radius, corner_radius, radians (-90), radians (0));
-  cairo_arc (cr, width - corner_radius, height - corner_radius, corner_radius, radians (0), radians (90));
-  cairo_arc (cr, corner_radius, height - corner_radius, corner_radius, radians (90), radians (180));
-  cairo_arc (cr, corner_radius, corner_radius, corner_radius, radians (180), radians (270));
-  cairo_close_path (cr);
-
-  cairo_set_source_rgba (cr, 0.2, 0.2, 0.2, 0.7);
-  cairo_fill (cr);
-
-  /* And finally draw the text */
-  cairo_set_source_rgb (cr, 1, 1, 1);
-  cairo_move_to (cr, margin_left, margin_top);
-  pango_cairo_show_layout (cr, layout);
+  x = CLAMP (x, 0, width - bubble_width);
+  y = CLAMP (y, 0, height - bubble_height);
+
+  gtk_snapshot_save (snapshot);
+
+  gsk_rounded_rect_init (&rounded_rect,
+                         &GRAPHENE_RECT_INIT (x, y, bubble_width, bubble_height),
+                         &GRAPHENE_SIZE_INIT (corner_radius, corner_radius),
+                         &GRAPHENE_SIZE_INIT (corner_radius, corner_radius),
+                         &GRAPHENE_SIZE_INIT (corner_radius, corner_radius),
+                         &GRAPHENE_SIZE_INIT (corner_radius, corner_radius));
+
+  gtk_snapshot_push_rounded_clip (snapshot, &rounded_rect);
+
+  rgba = (GdkRGBA) {
+    .red = 0.2,
+    .green = 0.2,
+    .blue = 0.2,
+    .alpha = 0.7,
+  };
+  gtk_snapshot_append_color (snapshot,
+                             &rgba,
+                             &GRAPHENE_RECT_INIT (x, y, bubble_width, bubble_height));
+
+
+  rgba = (GdkRGBA) {
+    .red = 1.0,
+    .green = 1.0,
+    .blue = 1.0,
+    .alpha = 1.0,
+  };
+  gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT (x + margin_left, y + margin_top));
+  gtk_snapshot_append_layout (snapshot, layout, &rgba);
+
+  gtk_snapshot_pop (snapshot);
+  gtk_snapshot_restore (snapshot);
 
   g_object_unref (layout);
-  cairo_restore (cr);
 }
 
-static gboolean
-cc_timezone_map_draw (GtkWidget *widget,
-                      cairo_t   *cr)
+static void
+cc_timezone_map_snapshot (GtkWidget   *widget,
+                          GtkSnapshot *snapshot)
 {
   CcTimezoneMap *map = CC_TIMEZONE_MAP (widget);
-  g_autoptr(GdkPixbuf) orig_hilight = NULL;
-  GtkAllocation alloc;
-  g_autofree gchar *file = NULL;
-  g_autoptr(GError) err = NULL;
   gdouble pointx, pointy;
-  char buf[16];
+  gint width, height;
 
-  gtk_widget_get_allocation (widget, &alloc);
+  width = gtk_widget_get_width (widget);
+  height = gtk_widget_get_height (widget);
 
   /* paint background */
-  gdk_cairo_set_source_pixbuf (cr, map->background, 0, 0);
-  cairo_paint (cr);
-
-  /* paint hilight */
-  if (gtk_widget_is_sensitive (widget))
-    {
-      file = g_strdup_printf (DATETIME_RESOURCE_PATH "/timezone_%s.png",
-                              g_ascii_formatd (buf, sizeof (buf),
-                                               "%g", map->selected_offset));
-    }
-  else
-    {
-      file = g_strdup_printf (DATETIME_RESOURCE_PATH "/timezone_%s_dim.png",
-                              g_ascii_formatd (buf, sizeof (buf),
-                                               "%g", map->selected_offset));
-
-    }
-
-  orig_hilight = gdk_pixbuf_new_from_resource (file, &err);
-
-  if (!orig_hilight)
-    {
-      g_warning ("Could not load hilight: %s",
-                 (err) ? err->message : "Unknown Error");
-    }
-  else
-    {
-      g_autoptr(GdkPixbuf) hilight = NULL;
-
-      hilight = gdk_pixbuf_scale_simple (orig_hilight, alloc.width,
-                                         alloc.height, GDK_INTERP_BILINEAR);
-      gdk_cairo_set_source_pixbuf (cr, hilight, 0, 0);
-
-      cairo_paint (cr);
-    }
+  gtk_snapshot_append_texture (snapshot,
+                               map->background,
+                               &GRAPHENE_RECT_INIT (0, 0, width, height));
 
   if (map->location)
     {
-      pointx = convert_longitude_to_x (map->location->longitude, alloc.width);
-      pointy = convert_latitude_to_y (map->location->latitude, alloc.height);
+      pointx = convert_longitude_to_x (map->location->longitude, width);
+      pointy = convert_latitude_to_y (map->location->latitude, height);
 
-      pointx = CLAMP (floor (pointx), 0, alloc.width);
-      pointy = CLAMP (floor (pointy), 0, alloc.height);
+      pointx = CLAMP (floor (pointx), 0, width);
+      pointy = CLAMP (floor (pointy), 0, height);
 
-      draw_text_bubble (cr, widget, pointx, pointy);
+      draw_text_bubble (map, snapshot, width, height, pointx, pointy);
 
       if (map->pin)
         {
-          gdk_cairo_set_source_pixbuf (cr, map->pin,
-                                       pointx - PIN_HOT_POINT_X,
-                                       pointy - PIN_HOT_POINT_Y);
-          cairo_paint (cr);
+          gtk_snapshot_append_texture (snapshot,
+                                       map->pin,
+                                       &GRAPHENE_RECT_INIT (pointx - PIN_HOT_POINT_X,
+                                                            pointy - PIN_HOT_POINT_Y,
+                                                            gdk_texture_get_width (map->pin),
+                                                            gdk_texture_get_height (map->pin)));
         }
     }
-
-  return TRUE;
 }
 
 static void
 update_cursor (GtkWidget *widget)
 {
-  GdkWindow *window;
-  g_autoptr(GdkCursor) cursor = NULL;
+  const gchar *cursor_name = NULL;
 
   if (!gtk_widget_get_realized (widget))
     return;
 
   if (gtk_widget_is_sensitive (widget))
-    {
-      GdkDisplay *display;
-      display = gtk_widget_get_display (widget);
-      cursor = gdk_cursor_new_for_display (display, GDK_HAND2);
-    }
+    cursor_name = "pointer";
 
-  window = gtk_widget_get_window (widget);
-  gdk_window_set_cursor (window, cursor);
+  gtk_widget_set_cursor_from_name (widget, cursor_name);
 }
 
 static void
@@ -468,11 +349,9 @@ cc_timezone_map_class_init (CcTimezoneMapClass *klass)
   object_class->dispose = cc_timezone_map_dispose;
   object_class->finalize = cc_timezone_map_finalize;
 
-  widget_class->get_preferred_width = cc_timezone_map_get_preferred_width;
-  widget_class->get_preferred_height = cc_timezone_map_get_preferred_height;
+  widget_class->measure = cc_timezone_map_measure;
   widget_class->size_allocate = cc_timezone_map_size_allocate;
-  widget_class->realize = cc_timezone_map_realize;
-  widget_class->draw = cc_timezone_map_draw;
+  widget_class->snapshot = cc_timezone_map_snapshot;
   widget_class->state_flags_changed = cc_timezone_map_state_flags_changed;
 
   signals[LOCATION_CHANGED] = g_signal_new ("location-changed",
@@ -510,58 +389,29 @@ set_location (CcTimezoneMap *map,
 
   info = tz_info_from_location (map->location);
 
-  map->selected_offset = tz_location_get_utc_offset (map->location)
-    / (60.0*60.0) + ((info->daylight) ? -1.0 : 0.0);
+  gtk_widget_queue_draw (GTK_WIDGET (map));
 
   g_signal_emit (map, signals[LOCATION_CHANGED], 0, map->location);
 }
 
 static gboolean
-button_press_event (CcTimezoneMap  *map,
-                    GdkEventButton *event)
+map_clicked_cb (GtkGestureClick *self,
+                gint             n_press,
+                gdouble          x,
+                gdouble          y,
+                CcTimezoneMap   *map)
 {
-  gint x, y;
-  guchar r, g, b, a;
-  guchar *pixels;
-  gint rowstride;
-  gint i;
-
   const GPtrArray *array;
   gint width, height;
   GList *distances = NULL;
-  GtkAllocation alloc;
-
-  x = event->x;
-  y = event->y;
-
-
-  rowstride = map->visible_map_rowstride;
-  pixels = map->visible_map_pixels;
-
-  r = pixels[(rowstride * y + x * 4)];
-  g = pixels[(rowstride * y + x * 4) + 1];
-  b = pixels[(rowstride * y + x * 4) + 2];
-  a = pixels[(rowstride * y + x * 4) + 3];
-
-
-  for (i = 0; color_codes[i].offset != -100; i++)
-    {
-       if (color_codes[i].red == r && color_codes[i].green == g
-           && color_codes[i].blue == b && color_codes[i].alpha == a)
-         {
-           map->selected_offset = color_codes[i].offset;
-         }
-    }
-
-  gtk_widget_queue_draw (GTK_WIDGET (map));
+  gint i;
 
-  /* work out the co-ordinates */
+  /* work out the coordinates */
 
   array = tz_get_locations (map->tzdb);
 
-  gtk_widget_get_allocation (GTK_WIDGET (map), &alloc);
-  width = alloc.width;
-  height = alloc.height;
+  width = gtk_widget_get_width (GTK_WIDGET (map));
+  height = gtk_widget_get_height (GTK_WIDGET (map));
 
   for (i = 0; i < array->len; i++)
     {
@@ -591,11 +441,10 @@ button_press_event (CcTimezoneMap  *map,
 static void
 cc_timezone_map_init (CcTimezoneMap *map)
 {
+  GtkGesture *click_gesture;
   GError *err = NULL;
 
-  map->orig_background = gdk_pixbuf_new_from_resource (DATETIME_RESOURCE_PATH "/bg.png",
-                                                       &err);
-
+  map->orig_background = texture_from_resource (DATETIME_RESOURCE_PATH "/bg.png", &err);
   if (!map->orig_background)
     {
       g_warning ("Could not load background image: %s",
@@ -603,9 +452,7 @@ cc_timezone_map_init (CcTimezoneMap *map)
       g_clear_error (&err);
     }
 
-  map->orig_background_dim = gdk_pixbuf_new_from_resource (DATETIME_RESOURCE_PATH "/bg_dim.png",
-                                                           &err);
-
+  map->orig_background_dim = texture_from_resource (DATETIME_RESOURCE_PATH "/bg_dim.png", &err);
   if (!map->orig_background_dim)
     {
       g_warning ("Could not load background image: %s",
@@ -613,17 +460,7 @@ cc_timezone_map_init (CcTimezoneMap *map)
       g_clear_error (&err);
     }
 
-  map->orig_color_map = gdk_pixbuf_new_from_resource (DATETIME_RESOURCE_PATH "/cc.png",
-                                                      &err);
-  if (!map->orig_color_map)
-    {
-      g_warning ("Could not load background image: %s",
-                 (err) ? err->message : "Unknown error");
-      g_clear_error (&err);
-    }
-
-  map->pin = gdk_pixbuf_new_from_resource (DATETIME_RESOURCE_PATH "/pin.png",
-                                           &err);
+  map->pin = texture_from_resource (DATETIME_RESOURCE_PATH "/pin.png", &err);
   if (!map->pin)
     {
       g_warning ("Could not load pin icon: %s",
@@ -633,7 +470,9 @@ cc_timezone_map_init (CcTimezoneMap *map)
 
   map->tzdb = tz_load_db ();
 
-  g_signal_connect_object (map, "button-press-event", G_CALLBACK (button_press_event), map, 
G_CONNECT_SWAPPED);
+  click_gesture = gtk_gesture_click_new ();
+  g_signal_connect (click_gesture, "pressed", G_CALLBACK (map_clicked_cb), map);
+  gtk_widget_add_controller (GTK_WIDGET (map), GTK_EVENT_CONTROLLER (click_gesture));
 }
 
 CcTimezoneMap *
diff --git a/gnome-initial-setup/pages/timezone/data/bg.png b/gnome-initial-setup/pages/timezone/data/bg.png
index 4180ee87..43e4016d 100644
Binary files a/gnome-initial-setup/pages/timezone/data/bg.png and 
b/gnome-initial-setup/pages/timezone/data/bg.png differ
diff --git a/gnome-initial-setup/pages/timezone/data/bg_dim.png 
b/gnome-initial-setup/pages/timezone/data/bg_dim.png
index 3d34b944..8db7a197 100644
Binary files a/gnome-initial-setup/pages/timezone/data/bg_dim.png and 
b/gnome-initial-setup/pages/timezone/data/bg_dim.png differ
diff --git a/gnome-initial-setup/pages/timezone/data/pin.png b/gnome-initial-setup/pages/timezone/data/pin.png
index 40dd4eaf..c347a9e2 100644
Binary files a/gnome-initial-setup/pages/timezone/data/pin.png and 
b/gnome-initial-setup/pages/timezone/data/pin.png differ
diff --git a/gnome-initial-setup/pages/timezone/datetime.gresource.xml 
b/gnome-initial-setup/pages/timezone/datetime.gresource.xml
index 6445cce6..5a3dbb3e 100644
--- a/gnome-initial-setup/pages/timezone/datetime.gresource.xml
+++ b/gnome-initial-setup/pages/timezone/datetime.gresource.xml
@@ -4,85 +4,6 @@
     <file>backward</file>
     <file alias="bg.png">data/bg.png</file>
     <file alias="bg_dim.png">data/bg_dim.png</file>
-    <file alias="cc.png">data/cc.png</file>
     <file alias="pin.png">data/pin.png</file>
-    <file alias="timezone_0.png">data/timezone_0.png</file>
-    <file alias="timezone_0_dim.png">data/timezone_0_dim.png</file>
-    <file alias="timezone_-10.png">data/timezone_-10.png</file>
-    <file alias="timezone_-10_dim.png">data/timezone_-10_dim.png</file>
-    <file alias="timezone_10.png">data/timezone_10.png</file>
-    <file alias="timezone_10_dim.png">data/timezone_10_dim.png</file>
-    <file alias="timezone_10.5.png">data/timezone_10.5.png</file>
-    <file alias="timezone_10.5_dim.png">data/timezone_10.5_dim.png</file>
-    <file alias="timezone_-1.png">data/timezone_-1.png</file>
-    <file alias="timezone_-1_dim.png">data/timezone_-1_dim.png</file>
-    <file alias="timezone_1.png">data/timezone_1.png</file>
-    <file alias="timezone_1_dim.png">data/timezone_1_dim.png</file>
-    <file alias="timezone_-11.png">data/timezone_-11.png</file>
-    <file alias="timezone_-11_dim.png">data/timezone_-11_dim.png</file>
-    <file alias="timezone_11.png">data/timezone_11.png</file>
-    <file alias="timezone_11_dim.png">data/timezone_11_dim.png</file>
-    <file alias="timezone_11.5.png">data/timezone_11.5.png</file>
-    <file alias="timezone_11.5_dim.png">data/timezone_11.5_dim.png</file>
-    <file alias="timezone_12.png">data/timezone_12.png</file>
-    <file alias="timezone_12_dim.png">data/timezone_12_dim.png</file>
-    <file alias="timezone_12.75.png">data/timezone_12.75.png</file>
-    <file alias="timezone_12.75_dim.png">data/timezone_12.75_dim.png</file>
-    <file alias="timezone_13.png">data/timezone_13.png</file>
-    <file alias="timezone_13_dim.png">data/timezone_13_dim.png</file>
-    <file alias="timezone_14.png">data/timezone_14.png</file>
-    <file alias="timezone_14_dim.png">data/timezone_14_dim.png</file>
-    <file alias="timezone_-2.png">data/timezone_-2.png</file>
-    <file alias="timezone_-2_dim.png">data/timezone_-2_dim.png</file>
-    <file alias="timezone_2.png">data/timezone_2.png</file>
-    <file alias="timezone_2_dim.png">data/timezone_2_dim.png</file>
-    <file alias="timezone_-3.png">data/timezone_-3.png</file>
-    <file alias="timezone_-3_dim.png">data/timezone_-3_dim.png</file>
-    <file alias="timezone_3.png">data/timezone_3.png</file>
-    <file alias="timezone_3_dim.png">data/timezone_3_dim.png</file>
-    <file alias="timezone_-3.5.png">data/timezone_-3.5.png</file>
-    <file alias="timezone_-3.5_dim.png">data/timezone_-3.5_dim.png</file>
-    <file alias="timezone_3.5.png">data/timezone_3.5.png</file>
-    <file alias="timezone_3.5_dim.png">data/timezone_3.5_dim.png</file>
-    <file alias="timezone_-4.png">data/timezone_-4.png</file>
-    <file alias="timezone_-4_dim.png">data/timezone_-4_dim.png</file>
-    <file alias="timezone_4.png">data/timezone_4.png</file>
-    <file alias="timezone_4_dim.png">data/timezone_4_dim.png</file>
-    <file alias="timezone_4.5.png">data/timezone_4.5.png</file>
-    <file alias="timezone_4.5_dim.png">data/timezone_4.5_dim.png</file>
-    <file alias="timezone_-5.png">data/timezone_-5.png</file>
-    <file alias="timezone_-5_dim.png">data/timezone_-5_dim.png</file>
-    <file alias="timezone_5.png">data/timezone_5.png</file>
-    <file alias="timezone_5_dim.png">data/timezone_5_dim.png</file>
-    <file alias="timezone_-5.5.png">data/timezone_-5.5.png</file>
-    <file alias="timezone_-5.5_dim.png">data/timezone_-5.5_dim.png</file>
-    <file alias="timezone_5.5.png">data/timezone_5.5.png</file>
-    <file alias="timezone_5.5_dim.png">data/timezone_5.5_dim.png</file>
-    <file alias="timezone_5.75.png">data/timezone_5.75.png</file>
-    <file alias="timezone_5.75_dim.png">data/timezone_5.75_dim.png</file>
-    <file alias="timezone_-6.png">data/timezone_-6.png</file>
-    <file alias="timezone_-6_dim.png">data/timezone_-6_dim.png</file>
-    <file alias="timezone_6.png">data/timezone_6.png</file>
-    <file alias="timezone_6_dim.png">data/timezone_6_dim.png</file>
-    <file alias="timezone_6.5.png">data/timezone_6.5.png</file>
-    <file alias="timezone_6.5_dim.png">data/timezone_6.5_dim.png</file>
-    <file alias="timezone_-7.png">data/timezone_-7.png</file>
-    <file alias="timezone_-7_dim.png">data/timezone_-7_dim.png</file>
-    <file alias="timezone_7.png">data/timezone_7.png</file>
-    <file alias="timezone_7_dim.png">data/timezone_7_dim.png</file>
-    <file alias="timezone_-8.png">data/timezone_-8.png</file>
-    <file alias="timezone_-8_dim.png">data/timezone_-8_dim.png</file>
-    <file alias="timezone_8.png">data/timezone_8.png</file>
-    <file alias="timezone_8_dim.png">data/timezone_8_dim.png</file>
-    <file alias="timezone_8.75.png">data/timezone_8.75.png</file>
-    <file alias="timezone_8.75_dim.png">data/timezone_8.75_dim.png</file>
-    <file alias="timezone_-9.png">data/timezone_-9.png</file>
-    <file alias="timezone_-9_dim.png">data/timezone_-9_dim.png</file>
-    <file alias="timezone_9.png">data/timezone_9.png</file>
-    <file alias="timezone_9_dim.png">data/timezone_9_dim.png</file>
-    <file alias="timezone_-9.5.png">data/timezone_-9.5.png</file>
-    <file alias="timezone_-9.5_dim.png">data/timezone_-9.5_dim.png</file>
-    <file alias="timezone_9.5.png">data/timezone_9.5.png</file>
-    <file alias="timezone_9.5_dim.png">data/timezone_9.5_dim.png</file>
   </gresource>
 </gresources>
diff --git a/gnome-initial-setup/pages/timezone/gis-bubble-widget.c 
b/gnome-initial-setup/pages/timezone/gis-bubble-widget.c
index 982cce7a..a6e8ab71 100644
--- a/gnome-initial-setup/pages/timezone/gis-bubble-widget.c
+++ b/gnome-initial-setup/pages/timezone/gis-bubble-widget.c
@@ -30,7 +30,7 @@ struct _GisBubbleWidgetPrivate
 };
 typedef struct _GisBubbleWidgetPrivate GisBubbleWidgetPrivate;
 
-G_DEFINE_TYPE_WITH_PRIVATE (GisBubbleWidget, gis_bubble_widget, GTK_TYPE_BIN);
+G_DEFINE_TYPE_WITH_PRIVATE (GisBubbleWidget, gis_bubble_widget, ADW_TYPE_BIN);
 
 enum {
   PROP_0,
@@ -56,12 +56,8 @@ gis_bubble_widget_get_property (GObject    *object,
       g_value_set_string (value, gtk_label_get_label (GTK_LABEL (priv->label)));
       break;
     case PROP_ICON_NAME:
-      {
-        const char *icon_name;
-        gtk_image_get_icon_name (GTK_IMAGE (priv->icon), &icon_name, NULL);
-        g_value_set_string (value, icon_name);
-        break;
-      }
+      g_value_set_string (value, gtk_image_get_icon_name (GTK_IMAGE (priv->icon)));
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -105,15 +101,12 @@ add_style_from_resource (const char *resource)
   uri = g_strconcat ("resource://", resource, NULL);
   file = g_file_new_for_uri (uri);
 
-  if (!gtk_css_provider_load_from_file (provider, file, NULL))
-    goto out;
+  gtk_css_provider_load_from_file (provider, file);
 
-  gtk_style_context_add_provider_for_screen (gdk_screen_get_default (),
-                                             GTK_STYLE_PROVIDER (provider),
-                                             GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
+  gtk_style_context_add_provider_for_display (gdk_display_get_default (),
+                                              GTK_STYLE_PROVIDER (provider),
+                                              GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
   g_object_unref (provider);
-
- out:
   g_object_unref (file);
   g_free (uri);
 }
@@ -128,6 +121,8 @@ gis_bubble_widget_class_init (GisBubbleWidgetClass *klass)
   gtk_widget_class_bind_template_child_private (GTK_WIDGET_CLASS (klass), GisBubbleWidget, icon);
   gtk_widget_class_bind_template_child_private (GTK_WIDGET_CLASS (klass), GisBubbleWidget, label);
 
+  gtk_widget_class_set_css_name (GTK_WIDGET_CLASS (klass), "bubble");
+
   object_class->set_property = gis_bubble_widget_set_property;
   object_class->get_property = gis_bubble_widget_get_property;
 
diff --git a/gnome-initial-setup/pages/timezone/gis-bubble-widget.css 
b/gnome-initial-setup/pages/timezone/gis-bubble-widget.css
index 85de5772..768e69cc 100644
--- a/gnome-initial-setup/pages/timezone/gis-bubble-widget.css
+++ b/gnome-initial-setup/pages/timezone/gis-bubble-widget.css
@@ -1,5 +1,5 @@
 
-.gis-bubble-widget {
+bubble {
     border-radius: 20px;
     background-color: rgba(0, 0, 0, 0.6);
     color: white;
diff --git a/gnome-initial-setup/pages/timezone/gis-bubble-widget.h 
b/gnome-initial-setup/pages/timezone/gis-bubble-widget.h
index 41e56905..60291669 100644
--- a/gnome-initial-setup/pages/timezone/gis-bubble-widget.h
+++ b/gnome-initial-setup/pages/timezone/gis-bubble-widget.h
@@ -22,7 +22,7 @@
 #ifndef __GIS_BUBBLE_WIDGET_H__
 #define __GIS_BUBBLE_WIDGET_H__
 
-#include <gtk/gtk.h>
+#include <adwaita.h>
 
 G_BEGIN_DECLS
 
@@ -38,12 +38,12 @@ typedef struct _GisBubbleWidgetClass   GisBubbleWidgetClass;
 
 struct _GisBubbleWidget
 {
-    GtkBin parent;
+    AdwBin parent;
 };
 
 struct _GisBubbleWidgetClass
 {
-    GtkBinClass parent_class;
+    AdwBinClass parent_class;
 };
 
 GType gis_bubble_widget_get_type (void);
diff --git a/gnome-initial-setup/pages/timezone/gis-bubble-widget.ui 
b/gnome-initial-setup/pages/timezone/gis-bubble-widget.ui
index 1c255ce3..89dd1216 100644
--- a/gnome-initial-setup/pages/timezone/gis-bubble-widget.ui
+++ b/gnome-initial-setup/pages/timezone/gis-bubble-widget.ui
@@ -1,16 +1,11 @@
 <?xml version="1.0"?>
 <interface>
-  <requires lib="gtk+" version="3.0"/>
-  <template class="GisBubbleWidget" parent="GtkBin">
+  <template class="GisBubbleWidget" parent="AdwBin">
     <child>
       <object class="GtkAspectFrame" id="aspect_frame">
         <property name="visible">True</property>
-        <style>
-          <class name="gis-bubble-widget" />
-        </style>
         <child>
           <object class="GtkBox" id="box">
-            <property name="visible">True</property>
             <property name="orientation">vertical</property>
             <property name="width-request">128</property>
             <property name="height-request">128</property>
@@ -18,7 +13,6 @@
             <property name="valign">center</property>
             <child>
               <object class="GtkImage" id="icon">
-                <property name="visible">True</property>
                 <property name="vexpand">True</property>
                 <property name="pixel-size">64</property>
               </object>
diff --git a/gnome-initial-setup/pages/timezone/gis-location-entry.c 
b/gnome-initial-setup/pages/timezone/gis-location-entry.c
index 37b72a5e..60b38bdd 100644
--- a/gnome-initial-setup/pages/timezone/gis-location-entry.c
+++ b/gnome-initial-setup/pages/timezone/gis-location-entry.c
@@ -22,6 +22,7 @@
  */
 
 struct _GisLocationEntryPrivate {
+    GtkWidget        *entry;
     GWeatherLocation *location;
     GWeatherLocation *top;
     gboolean          show_named_timezones;
@@ -30,7 +31,11 @@ struct _GisLocationEntryPrivate {
     GtkTreeModel     *model;
 };
 
-G_DEFINE_TYPE_WITH_PRIVATE (GisLocationEntry, gis_location_entry, GTK_TYPE_SEARCH_ENTRY)
+static void editable_iface_init (GtkEditableInterface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (GisLocationEntry, gis_location_entry, GTK_TYPE_WIDGET,
+                         G_ADD_PRIVATE (GisLocationEntry)
+                         G_IMPLEMENT_INTERFACE (GTK_TYPE_EDITABLE, editable_iface_init));
 
 enum {
     PROP_0,
@@ -86,6 +91,21 @@ static gboolean match_selected (GtkEntryCompletion *completion,
 static void     entry_changed (GisLocationEntry *entry);
 static void _no_matches (GtkEntryCompletion *completion, GisLocationEntry *entry);
 
+static GtkEditable*
+gis_location_entry_get_delegate (GtkEditable *editable)
+{
+    GisLocationEntry *entry = GIS_LOCATION_ENTRY (editable);
+    GisLocationEntryPrivate *priv = gis_location_entry_get_instance_private (entry);
+
+    return GTK_EDITABLE (priv->entry);
+}
+
+static void
+editable_iface_init (GtkEditableInterface *iface)
+{
+    iface->get_delegate = gis_location_entry_get_delegate;
+}
+
 static void
 gis_location_entry_init (GisLocationEntry *entry)
 {
@@ -94,6 +114,10 @@ gis_location_entry_init (GisLocationEntry *entry)
 
     priv = entry->priv = gis_location_entry_get_instance_private (entry);
 
+    priv->entry = gtk_entry_new ();
+    gtk_widget_set_parent (priv->entry, GTK_WIDGET (entry));
+    gtk_editable_init_delegate (GTK_EDITABLE (entry));
+
     completion = gtk_entry_completion_new ();
 
     gtk_entry_completion_set_popup_set_width (completion, FALSE);
@@ -107,7 +131,7 @@ gis_location_entry_init (GisLocationEntry *entry)
     g_signal_connect (completion, "no-matches",
                       G_CALLBACK (_no_matches), entry);
 
-    gtk_entry_set_completion (GTK_ENTRY (entry), completion);
+    gtk_entry_set_completion (GTK_ENTRY (entry->priv->entry), completion);
     g_object_unref (completion);
 
     priv->custom_text = FALSE;
@@ -146,6 +170,9 @@ dispose (GObject *object)
         priv->cancellable = NULL;
     }
 
+    gtk_editable_finish_delegate (GTK_EDITABLE (entry));
+    g_clear_pointer (&priv->entry, gtk_widget_unparent);
+
     G_OBJECT_CLASS (gis_location_entry_parent_class)->dispose (object);
 }
 
@@ -186,7 +213,7 @@ constructed (GObject *object)
     fill_location_entry_model (store, entry->priv->top, NULL, NULL, NULL, NULL, 
entry->priv->show_named_timezones);
 
     entry->priv->model = GTK_TREE_MODEL (store);
-    completion = gtk_entry_get_completion (GTK_ENTRY (entry));
+    completion = gtk_entry_get_completion (GTK_ENTRY (entry->priv->entry));
     gtk_entry_completion_set_match_func (completion, matcher, NULL, NULL);
     gtk_entry_completion_set_model (completion, GTK_TREE_MODEL (store));
 
@@ -197,6 +224,7 @@ static void
 gis_location_entry_class_init (GisLocationEntryClass *location_entry_class)
 {
     GObjectClass *object_class = G_OBJECT_CLASS (location_entry_class);
+    GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (location_entry_class);
 
     object_class->constructed = constructed;
     object_class->finalize = finalize;
@@ -226,6 +254,10 @@ gis_location_entry_class_init (GisLocationEntryClass *location_entry_class)
                              "The selected GWeatherLocation",
                              GWEATHER_TYPE_LOCATION,
                              G_PARAM_READWRITE));
+
+    gtk_editable_install_properties (object_class, LAST_PROP);
+
+    gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BIN_LAYOUT);
 }
 
 static void
@@ -234,6 +266,9 @@ set_property (GObject *object, guint prop_id,
 {
     GisLocationEntry *entry = GIS_LOCATION_ENTRY (object);
 
+    if (gtk_editable_delegate_set_property (object, prop_id, value, pspec))
+      return;
+
     switch (prop_id) {
     case PROP_TOP:
         entry->priv->top = g_value_dup_object (value);
@@ -257,6 +292,9 @@ get_property (GObject *object, guint prop_id,
 {
     GisLocationEntry *entry = GIS_LOCATION_ENTRY (object);
 
+    if (gtk_editable_delegate_get_property (object, prop_id, value, pspec))
+      return;
+
     switch (prop_id) {
     case PROP_SHOW_NAMED_TIMEZONES:
         g_value_set_boolean (value, entry->priv->show_named_timezones);
@@ -276,19 +314,18 @@ entry_changed (GisLocationEntry *entry)
     GtkEntryCompletion *completion;
     const gchar *text;
 
-    completion = gtk_entry_get_completion (GTK_ENTRY (entry));
+    completion = gtk_entry_get_completion (GTK_ENTRY (entry->priv->entry));
 
     if (entry->priv->cancellable) {
         g_cancellable_cancel (entry->priv->cancellable);
         g_object_unref (entry->priv->cancellable);
         entry->priv->cancellable = NULL;
-        gtk_entry_completion_delete_action (completion, 0);
     }
 
-    gtk_entry_completion_set_match_func (gtk_entry_get_completion (GTK_ENTRY (entry)), matcher, NULL, NULL);
-    gtk_entry_completion_set_model (gtk_entry_get_completion (GTK_ENTRY (entry)), entry->priv->model);
+    gtk_entry_completion_set_match_func (completion, matcher, NULL, NULL);
+    gtk_entry_completion_set_model (completion, entry->priv->model);
 
-    text = gtk_entry_get_text (GTK_ENTRY (entry));
+    text = gtk_editable_get_text (GTK_EDITABLE (entry));
 
     if (text && *text)
         entry->priv->custom_text = TRUE;
@@ -296,6 +333,16 @@ entry_changed (GisLocationEntry *entry)
         set_location_internal (entry, NULL, NULL, NULL);
 }
 
+static void
+set_entry_text (GisLocationEntry *entry,
+                const char       *text)
+{
+    GisLocationEntryPrivate *priv = entry->priv;
+
+    if (g_strcmp0 (gtk_editable_get_text (GTK_EDITABLE (priv->entry)), text) != 0)
+        gtk_editable_set_text (GTK_EDITABLE (priv->entry), text);
+}
+
 static void
 set_location_internal (GisLocationEntry *entry,
                        GtkTreeModel     *model,
@@ -316,16 +363,16 @@ set_location_internal (GisLocationEntry *entry,
                             LOC_GIS_LOCATION_ENTRY_COL_DISPLAY_NAME, &name,
                             LOC_GIS_LOCATION_ENTRY_COL_LOCATION, &priv->location,
                             -1);
-        gtk_entry_set_text (GTK_ENTRY (entry), name);
+        set_entry_text (entry, name);
         priv->custom_text = FALSE;
         g_free (name);
     } else if (loc) {
         priv->location = g_object_ref (loc);
-        gtk_entry_set_text (GTK_ENTRY (entry), gweather_location_get_name (loc));
+        set_entry_text (entry, gweather_location_get_name (loc));
         priv->custom_text = FALSE;
     } else {
         priv->location = NULL;
-        gtk_entry_set_text (GTK_ENTRY (entry), "");
+        set_entry_text (entry, "");
         priv->custom_text = TRUE;
     }
 
@@ -355,7 +402,7 @@ gis_location_entry_set_location (GisLocationEntry *entry,
 
     g_return_if_fail (GIS_IS_LOCATION_ENTRY (entry));
 
-    completion = gtk_entry_get_completion (GTK_ENTRY (entry));
+    completion = gtk_entry_get_completion (GTK_ENTRY (entry->priv->entry));
     model = gtk_entry_completion_get_model (completion);
 
     if (loc == NULL) {
@@ -446,7 +493,7 @@ gis_location_entry_set_city (GisLocationEntry *entry,
     g_return_val_if_fail (GIS_IS_LOCATION_ENTRY (entry), FALSE);
     g_return_val_if_fail (code != NULL, FALSE);
 
-    completion = gtk_entry_get_completion (GTK_ENTRY (entry));
+    completion = gtk_entry_get_completion (GTK_ENTRY (entry->priv->entry));
     model = gtk_entry_completion_get_model (completion);
 
     gtk_tree_model_get_iter_first (model, &iter);
@@ -805,21 +852,18 @@ _got_places (GObject      *source_object,
     g_object_unref (store);
 
  out:
-    gtk_entry_completion_delete_action (completion, 0);
     g_clear_object (&self->priv->cancellable);
 }
 
 static void
 _no_matches (GtkEntryCompletion *completion, GisLocationEntry *entry) {
-    const gchar *key = gtk_entry_get_text(GTK_ENTRY (entry));
+    const gchar *key = gtk_editable_get_text (GTK_EDITABLE (entry->priv->entry));
     GeocodeForward *forward;
 
     if (entry->priv->cancellable) {
         g_cancellable_cancel (entry->priv->cancellable);
         g_object_unref (entry->priv->cancellable);
         entry->priv->cancellable = NULL;
-    } else {
-        gtk_entry_completion_insert_action_text (completion, 0, _("Loading…"));
     }
 
     entry->priv->cancellable = g_cancellable_new ();
diff --git a/gnome-initial-setup/pages/timezone/gis-location-entry.h 
b/gnome-initial-setup/pages/timezone/gis-location-entry.h
index 30c19dbb..98a76127 100644
--- a/gnome-initial-setup/pages/timezone/gis-location-entry.h
+++ b/gnome-initial-setup/pages/timezone/gis-location-entry.h
@@ -6,7 +6,7 @@
 
 #pragma once
 
-#include <gtk/gtk.h>
+#include <adwaita.h>
 #include <libgweather/gweather.h>
 
 G_BEGIN_DECLS
@@ -23,14 +23,14 @@ typedef struct _GisLocationEntryPrivate GisLocationEntryPrivate;
 #define GIS_LOCATION_ENTRY_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), GIS_TYPE_LOCATION_ENTRY, 
GisLocationEntryClass))
 
 struct _GisLocationEntry {
-    GtkSearchEntry parent;
+    AdwBin parent;
 
     /*< private >*/
     GisLocationEntryPrivate *priv;
 };
 
 struct _GisLocationEntryClass {
-    GtkSearchEntryClass parent_class;
+    AdwBinClass parent_class;
 };
 
 GType                   gis_location_entry_get_type        (void);
diff --git a/gnome-initial-setup/pages/timezone/gis-timezone-page.c 
b/gnome-initial-setup/pages/timezone/gis-timezone-page.c
index 5db54133..2ca34d08 100644
--- a/gnome-initial-setup/pages/timezone/gis-timezone-page.c
+++ b/gnome-initial-setup/pages/timezone/gis-timezone-page.c
@@ -346,7 +346,7 @@ map_location_changed (CcTimezoneMap   *map,
   gis_page_set_complete (GIS_PAGE (page), (location != NULL));
 
   if (!priv->in_search)
-    gtk_entry_set_text (GTK_ENTRY (priv->search_entry), "");
+    gtk_editable_set_text (GTK_EDITABLE (priv->search_entry), "");
 
   update_timezone (page, location);
   queue_set_timezone (page, location->zone);
@@ -398,15 +398,18 @@ stop_geolocation (GisTimezonePage *page)
 }
 
 static void
-page_added (GisTimezonePage *page)
+gis_timezone_page_root (GtkWidget *widget)
 {
+  GisTimezonePage *page = GIS_TIMEZONE_PAGE (widget);
   GisTimezonePagePrivate *priv = gis_timezone_page_get_instance_private (page);
 
-   if (priv->geoclue_cancellable == NULL)
-     {
-       priv->geoclue_cancellable = g_cancellable_new ();
-       get_location_from_geoclue_async (page);
-     }
+  GTK_WIDGET_CLASS (gis_timezone_page_parent_class)->root (widget);
+
+ if (priv->geoclue_cancellable == NULL)
+   {
+     priv->geoclue_cancellable = g_cancellable_new ();
+     get_location_from_geoclue_async (page);
+   }
 }
 
 static void
@@ -451,8 +454,6 @@ gis_timezone_page_constructed (GObject *object)
                     G_CALLBACK (entry_mapped), page);
   g_signal_connect (priv->map, "location-changed",
                     G_CALLBACK (map_location_changed), page);
-  g_signal_connect (GTK_WIDGET (page), "parent-set",
-                    G_CALLBACK (page_added), NULL);
 
   gtk_widget_show (GTK_WIDGET (page));
 }
@@ -500,18 +501,20 @@ gis_timezone_page_class_init (GisTimezonePageClass *klass)
 {
   GisPageClass *page_class = GIS_PAGE_CLASS (klass);
   GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
 
-  gtk_widget_class_set_template_from_resource (GTK_WIDGET_CLASS (klass), 
"/org/gnome/initial-setup/gis-timezone-page.ui");
+  gtk_widget_class_set_template_from_resource (widget_class, 
"/org/gnome/initial-setup/gis-timezone-page.ui");
 
-  gtk_widget_class_bind_template_child_private (GTK_WIDGET_CLASS (klass), GisTimezonePage, map);
-  gtk_widget_class_bind_template_child_private (GTK_WIDGET_CLASS (klass), GisTimezonePage, search_entry);
-  gtk_widget_class_bind_template_child_private (GTK_WIDGET_CLASS (klass), GisTimezonePage, search_overlay);
+  gtk_widget_class_bind_template_child_private (widget_class, GisTimezonePage, map);
+  gtk_widget_class_bind_template_child_private (widget_class, GisTimezonePage, search_entry);
+  gtk_widget_class_bind_template_child_private (widget_class, GisTimezonePage, search_overlay);
 
   page_class->page_id = PAGE_ID;
   page_class->locale_changed = gis_timezone_page_locale_changed;
   page_class->apply = gis_timezone_page_apply;
   object_class->constructed = gis_timezone_page_constructed;
   object_class->dispose = gis_timezone_page_dispose;
+  widget_class->root = gis_timezone_page_root;
 }
 
 static void
diff --git a/gnome-initial-setup/pages/timezone/gis-timezone-page.ui 
b/gnome-initial-setup/pages/timezone/gis-timezone-page.ui
index 588ec412..a48b53e6 100644
--- a/gnome-initial-setup/pages/timezone/gis-timezone-page.ui
+++ b/gnome-initial-setup/pages/timezone/gis-timezone-page.ui
@@ -1,18 +1,13 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<!-- Generated with glade 3.16.0 on Tue Oct 22 19:34:41 2013 -->
 <interface>
-  <!-- interface-requires gtk+ 3.0 -->
   <template class="GisTimezonePage" parent="GisPage">
     <child>
       <object class="GtkBox" id="box">
-        <property name="visible">True</property>
-        <property name="can_focus">False</property>
         <property name="orientation">vertical</property>
         <property name="halign">center</property>
         <property name="valign">fill</property>
         <child>
           <object class="GisPageHeader" id="header">
-            <property name="visible">True</property>
             <property name="margin_top">24</property>
             <property name="title" translatable="yes">Time Zone</property>
             <property name="subtitle" translatable="yes">The time zone will be set automatically if your 
location can be found. You can also search for a city to set it yourself.</property>
@@ -22,45 +17,35 @@
         </child>
         <child>
           <object class="GtkBox" id="page_box">
-            <property name="visible">True</property>
             <property name="margin_top">18</property>
             <property name="valign">center</property>
             <property name="orientation">vertical</property>
             <property name="spacing">14</property>
             <child>
               <object class="GisLocationEntry" id="search_entry">
-                <property name="visible">True</property>
                 <property name="halign">center</property>
                 <property name="max-width-chars">55</property>
               </object>
             </child>
             <child>
               <object class="GtkFrame" id="map_frame">
-                <property name="visible">True</property>
-                <property name="can_focus">False</property>
                 <property name="margin_bottom">18</property>
                 <property name="hexpand">True</property>
                 <property name="label_xalign">0</property>
                 <child>
                   <object class="GtkOverlay" id="map_overlay">
-                    <property name="visible">True</property>
                     <child>
                       <object class="CcTimezoneMap" id="map">
-                        <property name="visible">True</property>
                         <property name="hexpand">True</property>
                       </object>
                     </child>
                     <child type="overlay">
                       <object class="GisBubbleWidget" id="search_overlay">
-                        <property name="visible">True</property>
                         <property name="label" translatable="yes">Please search for a nearby city</property>
                         <property name="icon-name">edit-find-symbolic</property>
                         <property name="halign">center</property>
                         <property name="valign">center</property>
                       </object>
-                      <packing>
-                        <property name="pass-through">True</property>
-                      </packing>
                     </child>
                   </object>
                 </child>
diff --git a/gnome-initial-setup/pages/timezone/tz.c b/gnome-initial-setup/pages/timezone/tz.c
index 6e96dd45..4fe2305b 100644
--- a/gnome-initial-setup/pages/timezone/tz.c
+++ b/gnome-initial-setup/pages/timezone/tz.c
@@ -181,14 +181,46 @@ tz_location_get_position (TzLocation *loc, double *longitude, double *latitude)
        *latitude = loc->latitude;
 }
 
+/* For timezone map display purposes, we try to highlight regions of the
+ * world that keep the same time.  There is no reasonable API to discover
+ * this; at the moment we just group timezones by their non-daylight-savings
+ * UTC offset and hope that's good enough.  However, in some cases that
+ * produces confusing results.  For example, Irish Standard Time is legally
+ * defined as the country's summer time, with a negative DST offset in
+ * winter; but this results in the same observed clock times as countries
+ * that observe Western European (Summer) Time, not those that observe
+ * Central European (Summer) Time, so we should group Ireland with the
+ * former, matching the grouping implied by data/timezone_*.png.
+ *
+ * This is something of a hack, and there remain other problems with
+ * timezone grouping: for example, grouping timezones north and south of the
+ * equator together where DST is observed at different times of the year is
+ * dubious.
+ */
+struct {
+       const char *zone;
+       gint offset;
+} base_offset_overrides[] = {
+       { "Europe/Dublin",  0 },
+};
+
 glong
-tz_location_get_utc_offset (TzLocation *loc)
+tz_location_get_base_utc_offset (TzLocation *loc)
 {
        g_autoptr(TzInfo) tz_info = NULL;
        glong offset;
+       guint i;
 
        tz_info = tz_info_from_location (loc);
-       offset = tz_info->utc_offset;
+       offset = tz_info->utc_offset + (tz_info->daylight ? -3600 : 0);
+
+       for (i = 0; i < G_N_ELEMENTS (base_offset_overrides); i++) {
+               if (g_str_equal (loc->zone, base_offset_overrides[i].zone)) {
+                       offset = base_offset_overrides[i].offset;
+                       break;
+               }
+       }
+
        return offset;
 }
 
@@ -215,19 +247,10 @@ tz_info_from_location (TzLocation *loc)
        curzone = localtime (&curtime);
 
 #ifndef __sun
-       /* Currently this solution doesnt seem to work - I get that */
-       /* America/Phoenix uses daylight savings, which is wrong    */
-       tzinfo->tzname_normal = g_strdup (curzone->tm_zone);
-       if (curzone->tm_isdst) 
-               tzinfo->tzname_daylight =
-                       g_strdup (&curzone->tm_zone[curzone->tm_isdst]);
-       else
-               tzinfo->tzname_daylight = NULL;
-
+       tzinfo->tzname = g_strdup (curzone->tm_zone);
        tzinfo->utc_offset = curzone->tm_gmtoff;
 #else
-       tzinfo->tzname_normal = NULL;
-       tzinfo->tzname_daylight = NULL;
+       tzinfo->tzname = NULL;
        tzinfo->utc_offset = 0;
 #endif
 
@@ -247,8 +270,7 @@ tz_info_free (TzInfo *tzinfo)
 {
        g_return_if_fail (tzinfo != NULL);
        
-       if (tzinfo->tzname_normal) g_free (tzinfo->tzname_normal);
-       if (tzinfo->tzname_daylight) g_free (tzinfo->tzname_daylight);
+       if (tzinfo->tzname) g_free (tzinfo->tzname);
        g_free (tzinfo);
 }
 
diff --git a/gnome-initial-setup/pages/timezone/tz.h b/gnome-initial-setup/pages/timezone/tz.h
index a2376f8a..feef1658 100644
--- a/gnome-initial-setup/pages/timezone/tz.h
+++ b/gnome-initial-setup/pages/timezone/tz.h
@@ -56,15 +56,13 @@ struct _TzLocation
 };
 
 /* see the glibc info page information on time zone information */
-/*  tzname_normal    is the default name for the timezone */
-/*  tzname_daylight  is the name of the zone when in daylight savings */
+/*  tzname           is the default name for the timezone */
 /*  utc_offset       is offset in seconds from utc */
 /*  daylight         if non-zero then location obeys daylight savings */
 
 struct _TzInfo
 {
-       gchar *tzname_normal;
-       gchar *tzname_daylight;
+       gchar *tzname;
        glong utc_offset;
        gint daylight;
 };
@@ -80,7 +78,7 @@ void       tz_location_get_position   (TzLocation *loc,
 char      *tz_location_get_country    (TzLocation *loc);
 gchar     *tz_location_get_zone       (TzLocation *loc);
 gchar     *tz_location_get_comment    (TzLocation *loc);
-glong      tz_location_get_utc_offset (TzLocation *loc);
+glong      tz_location_get_base_utc_offset (TzLocation *loc);
 gint       tz_location_set_locally    (TzLocation *loc);
 TzInfo    *tz_info_from_location      (TzLocation *loc);
 void       tz_info_free               (TzInfo *tz_info);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]