static void cc_timezone_map_dispose (GObject *object) { CcTimezoneMapPrivate *priv = CC_TIMEZONE_MAP (object)->priv; if (priv->orig_background) { g_object_unref (priv->orig_background); priv->orig_background = NULL; } if (priv->orig_color_map) { g_object_unref (priv->orig_color_map); priv->orig_color_map = NULL; } if (priv->background) { g_object_unref (priv->background); priv->background = NULL; } if (priv->color_map) { g_object_unref (priv->color_map); priv->color_map = NULL; priv->visible_map_pixels = NULL; priv->visible_map_rowstride = 0; } G_OBJECT_CLASS (cc_timezone_map_parent_class)->dispose (object); }
static void cc_timezone_map_size_allocate (GtkWidget *widget, GtkAllocation *allocation) { CcTimezoneMapPrivate *priv = CC_TIMEZONE_MAP (widget)->priv; if (priv->background) g_object_unref (priv->background); priv->background = gdk_pixbuf_scale_simple (priv->orig_background, allocation->width, allocation->height, GDK_INTERP_BILINEAR); if (priv->color_map) g_object_unref (priv->color_map); priv->color_map = gdk_pixbuf_scale_simple (priv->orig_color_map, allocation->width, allocation->height, GDK_INTERP_BILINEAR); priv->visible_map_pixels = gdk_pixbuf_get_pixels (priv->color_map); priv->visible_map_rowstride = gdk_pixbuf_get_rowstride (priv->color_map); GTK_WIDGET_CLASS (cc_timezone_map_parent_class)->size_allocate (widget, allocation); }
static void city_changed_cb (GtkComboBox *box, CcDateTimePanel *self) { static gboolean inside = FALSE; GtkTreeIter iter; gchar *zone; /* prevent re-entry from location changed callback */ if (inside) return; inside = TRUE; if (gtk_combo_box_get_active_iter (box, &iter)) { gtk_tree_model_get (gtk_combo_box_get_model (box), &iter, CITY_COL_ZONE, &zone, -1); cc_timezone_map_set_timezone (CC_TIMEZONE_MAP (self->priv->map), zone); g_free (zone); } inside = FALSE; }
static void get_initial_timezone (CcDateTimePanel *self) { const gchar *timezone; timezone = timedate1_get_timezone (self->priv->dtm); if (timezone == NULL || !cc_timezone_map_set_timezone (CC_TIMEZONE_MAP (self->priv->map), timezone)) { g_warning ("Timezone '%s' is unhandled, setting %s as default", timezone ? timezone : "(null)", DEFAULT_TZ); cc_timezone_map_set_timezone (CC_TIMEZONE_MAP (self->priv->map), DEFAULT_TZ); } self->priv->current_location = cc_timezone_map_get_location (CC_TIMEZONE_MAP (self->priv->map)); update_timezone (self); }
static void get_timezone_cb (GObject *source, GAsyncResult *res, gpointer user_data) { CcDateTimePanel *self = user_data; GtkWidget *widget; gchar *timezone; GError *error; error = NULL; if (!date_time_mechanism_call_get_timezone_finish (self->priv->dtm, &timezone, res, &error)) { g_warning ("Could not get current timezone: %s", error->message); g_error_free (error); } else { if (!cc_timezone_map_set_timezone (CC_TIMEZONE_MAP (self->priv->map), timezone)) { g_warning ("Timezone '%s' is unhandled, setting %s as default", timezone, DEFAULT_TZ); cc_timezone_map_set_timezone (CC_TIMEZONE_MAP (self->priv->map), DEFAULT_TZ); } self->priv->current_location = cc_timezone_map_get_location (CC_TIMEZONE_MAP (self->priv->map)); update_timezone (self); } /* now that the initial state is loaded set connect the signals */ widget = (GtkWidget*) gtk_builder_get_object (self->priv->builder, "region_combobox"); g_signal_connect (widget, "changed", G_CALLBACK (region_changed_cb), self); widget = (GtkWidget*) gtk_builder_get_object (self->priv->builder, "city_combobox"); g_signal_connect (widget, "changed", G_CALLBACK (city_changed_cb), self); g_signal_connect (self->priv->map, "location-changed", G_CALLBACK (location_changed_cb), self); g_free (timezone); }
static void cc_timezone_map_finalize (GObject *object) { CcTimezoneMapPrivate *priv = CC_TIMEZONE_MAP (object)->priv; if (priv->tzdb) { tz_db_free (priv->tzdb); priv->tzdb = NULL; } G_OBJECT_CLASS (cc_timezone_map_parent_class)->finalize (object); }
static void cc_timezone_map_get_preferred_height (GtkWidget *widget, gint *minimum, gint *natural) { CcTimezoneMapPrivate *priv = CC_TIMEZONE_MAP (widget)->priv; gint size; size = gdk_pixbuf_get_height (priv->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) { CcTimezoneMapPrivate *priv = CC_TIMEZONE_MAP (widget)->priv; gint size; /* The + 20 here is a slight tweak to make the map fill the * panel better without causing horizontal growing */ size = 300 * gdk_pixbuf_get_height (priv->orig_background) / gdk_pixbuf_get_width (priv->orig_background) + 20; if (minimum != NULL) *minimum = size; if (natural != NULL) *natural = size; }
static gboolean city_changed_cb (GtkEntryCompletion *entry_completion, GtkTreeModel *model, GtkTreeIter *iter, CcDateTimePanel *self) { GtkWidget *entry; gchar *zone; gtk_tree_model_get (model, iter, CITY_COL_ZONE, &zone, -1); cc_timezone_map_set_timezone (CC_TIMEZONE_MAP (self->priv->map), zone); g_free (zone); entry = gtk_entry_completion_get_entry (GTK_ENTRY_COMPLETION (entry_completion)); gtk_entry_set_text (GTK_ENTRY (entry), ""); return TRUE; }
static void cc_timezone_map_dispose (GObject *object) { CcTimezoneMapPrivate *priv = CC_TIMEZONE_MAP (object)->priv; g_clear_object (&priv->orig_background); g_clear_object (&priv->orig_background_dim); g_clear_object (&priv->orig_color_map); g_clear_object (&priv->background); g_clear_object (&priv->pin); g_clear_pointer (&priv->bubble_text, g_free); if (priv->color_map) { g_clear_object (&priv->color_map); priv->visible_map_pixels = NULL; priv->visible_map_rowstride = 0; } G_OBJECT_CLASS (cc_timezone_map_parent_class)->dispose (object); }
static gboolean button_press_event (GtkWidget *widget, GdkEventButton *event) { CcTimezoneMapPrivate *priv = CC_TIMEZONE_MAP (widget)->priv; gint x, y; guchar r, g, b, a; guchar *pixels; gint rowstride; gsize i; const GPtrArray *array; gint width, height; GList *distances = NULL; GtkAllocation alloc; x = event->x; y = event->y; rowstride = priv->visible_map_rowstride; pixels = priv->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) { priv->selected_offset = color_codes[i].offset; } } gtk_widget_queue_draw (widget); /* work out the co-ordinates */ array = tz_get_locations (priv->tzdb); gtk_widget_get_allocation (widget, &alloc); width = alloc.width; height = alloc.height; for (i = 0; i < array->len; i++) { gdouble pointx, pointy, dx, dy; TzLocation *loc = array->pdata[i]; pointx = convert_longtitude_to_x (loc->longitude, width); pointy = convert_latitude_to_y (loc->latitude, height); dx = pointx - x; dy = pointy - y; loc->dist = dx * dx + dy * dy; distances = g_list_prepend (distances, loc); } distances = g_list_sort (distances, (GCompareFunc) sort_locations); set_location (CC_TIMEZONE_MAP (widget), (TzLocation*) distances->data); g_list_free (distances); return TRUE; }
static gboolean cc_timezone_map_draw (GtkWidget *widget, cairo_t *cr) { CcTimezoneMapPrivate *priv = CC_TIMEZONE_MAP (widget)->priv; GdkPixbuf *hilight, *orig_hilight, *pin; GtkAllocation alloc; gchar *file; GError *err = NULL; gdouble pointx, pointy; char buf[16]; gtk_widget_get_allocation (widget, &alloc); /* paint background */ gdk_cairo_set_source_pixbuf (cr, priv->background, 0, 0); cairo_paint (cr); /* paint hilight */ file = g_strdup_printf (DATADIR "/timezone_%s.png", g_ascii_formatd (buf, sizeof (buf), "%g", priv->selected_offset)); orig_hilight = gdk_pixbuf_new_from_file (file, &err); g_free (file); file = NULL; if (!orig_hilight) { g_warning ("Could not load hilight: %s", (err) ? err->message : "Unknown Error"); if (err) g_clear_error (&err); } else { 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); g_object_unref (hilight); g_object_unref (orig_hilight); } /* load pin icon */ pin = gdk_pixbuf_new_from_file (DATADIR "/pin.png", &err); if (err) { g_warning ("Could not load pin icon: %s", err->message); g_clear_error (&err); } if (priv->location) { pointx = convert_longtitude_to_x (priv->location->longitude, alloc.width); pointy = convert_latitude_to_y (priv->location->latitude, alloc.height); if (pointy > alloc.height) pointy = alloc.height; if (pin) { gdk_cairo_set_source_pixbuf (cr, pin, pointx - 8, pointy - 14); cairo_paint (cr); } } if (pin) { g_object_unref (pin); } return TRUE; }
static gboolean cc_timezone_map_draw (GtkWidget *widget, cairo_t *cr) { CcTimezoneMapPrivate *priv = CC_TIMEZONE_MAP (widget)->priv; GdkPixbuf *hilight, *orig_hilight; GtkAllocation alloc; gchar *file; GError *err = NULL; gdouble pointx, pointy; char buf[16]; const char *fmt; gtk_widget_get_allocation (widget, &alloc); /* paint background */ gdk_cairo_set_source_pixbuf (cr, priv->background, 0, 0); cairo_paint (cr); /* paint hilight */ if (gtk_widget_is_sensitive (widget)) fmt = DATETIME_RESOURCE_PATH "/timezone_%s.png"; else fmt = DATETIME_RESOURCE_PATH "/timezone_%s_dim.png"; file = g_strdup_printf (fmt, g_ascii_formatd (buf, sizeof (buf), "%g", priv->selected_offset)); orig_hilight = gdk_pixbuf_new_from_resource (file, &err); g_free (file); file = NULL; if (!orig_hilight) { g_warning ("Could not load hilight: %s", (err) ? err->message : "Unknown Error"); if (err) g_clear_error (&err); } else { 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); g_object_unref (hilight); g_object_unref (orig_hilight); } if (priv->location) { pointx = convert_longitude_to_x (priv->location->longitude, alloc.width); pointy = convert_latitude_to_y (priv->location->latitude, alloc.height); pointx = CLAMP (floor (pointx), 0, alloc.width); pointy = CLAMP (floor (pointy), 0, alloc.height); draw_text_bubble (cr, widget, pointx, pointy); if (priv->pin) { gdk_cairo_set_source_pixbuf (cr, priv->pin, pointx - PIN_HOT_POINT_X, pointy - PIN_HOT_POINT_Y); cairo_paint (cr); } } return TRUE; }
static void draw_text_bubble (cairo_t *cr, GtkWidget *widget, gdouble pointx, gdouble pointy) { static const double corner_radius = 9.0; static const double margin_top = 12.0; static const double margin_bottom = 12.0; static const double margin_left = 24.0; static const double margin_right = 24.0; CcTimezoneMapPrivate *priv = CC_TIMEZONE_MAP (widget)->priv; GtkAllocation alloc; PangoLayout *layout; PangoRectangle text_rect; double x; double y; double width; double height; if (!priv->bubble_text) return; gtk_widget_get_allocation (widget, &alloc); layout = gtk_widget_create_pango_layout (widget, NULL); /* Layout the text */ pango_layout_set_alignment (layout, PANGO_ALIGN_CENTER); pango_layout_set_spacing (layout, 3); pango_layout_set_markup (layout, priv->bubble_text, -1); 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; if (pointx < alloc.width / 2) x = pointx + 25; else x = pointx - width - 25; y = pointy - 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); g_object_unref (layout); cairo_restore (cr); }
static void update_timezone (CcDateTimePanel *self) { CcDateTimePanelPrivate *priv = self->priv; char *bubble_text; char *city_country; char *label; char *time_label; char *utc_label; char *tz_desc; gboolean use_ampm; if (priv->clock_format == G_DESKTOP_CLOCK_FORMAT_12H) use_ampm = TRUE; else use_ampm = FALSE; city_country = translated_city_name (priv->current_location); /* Update the timezone on the listbow row */ /* Translators: "timezone (details)" */ label = g_strdup_printf (C_("timezone desc", "%s (%s)"), g_date_time_get_timezone_abbreviation (self->priv->date), city_country); gtk_label_set_text (GTK_LABEL (W ("timezone_label")), label); g_free (label); /* Translators: UTC here means the Coordinated Universal Time. * %:::z will be replaced by the offset from UTC e.g. UTC+02 */ utc_label = g_date_time_format (priv->date, _("UTC%:::z")); if (use_ampm) { /* Translators: This is the time format used in 12-hour mode. */ time_label = g_date_time_format (priv->date, _("%l:%M %p")); } else { /* Translators: This is the time format used in 24-hour mode. */ time_label = g_date_time_format (priv->date, _("%R")); } /* Update the text bubble in the timezone map */ /* Translators: "timezone (utc shift)" */ tz_desc = g_strdup_printf (C_("timezone map", "%s (%s)"), g_date_time_get_timezone_abbreviation (self->priv->date), utc_label); bubble_text = g_strdup_printf ("<b>%s</b>\n" "<small>%s</small>\n" "<b>%s</b>", tz_desc, city_country, time_label); cc_timezone_map_set_bubble_text (CC_TIMEZONE_MAP (priv->map), bubble_text); g_free (tz_desc); g_free (bubble_text); g_free (city_country); g_free (time_label); g_free (utc_label); }