[gnome-panel/wip/applets/clock: 9/18] clock: rewrite ClockLocationTile
- From: Alberts Muktupāvels <muktupavels src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-panel/wip/applets/clock: 9/18] clock: rewrite ClockLocationTile
- Date: Fri, 14 Nov 2014 16:40:53 +0000 (UTC)
commit 9a305f357b195c97b774c94b46352615167f56c9
Author: Alberts Muktupāvels <alberts muktupavels gmail com>
Date: Sun Nov 9 22:26:15 2014 +0200
clock: rewrite ClockLocationTile
applets/clock/clock-location-tile.c | 1025 +++++++++++++++++++++--------------
applets/clock/clock-location-tile.h | 83 ++-
applets/clock/clock.c | 39 +--
3 files changed, 669 insertions(+), 478 deletions(-)
---
diff --git a/applets/clock/clock-location-tile.c b/applets/clock/clock-location-tile.c
index 04900dc..6ad6a8d 100644
--- a/applets/clock/clock-location-tile.c
+++ b/applets/clock/clock-location-tile.c
@@ -1,399 +1,319 @@
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <string.h>
-#include <stdlib.h>
+/*
+ * Copyright (C) 2014 Alberts Muktupāvels
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Alberts Muktupāvels <alberts muktupavels gmail com>
+ * Carlos Garcia Campos <carlosgc gnome org>
+ * Federico Mena Quintero <federico novell com>
+ * Frank Solensky <frank src gnome org>
+ * Frédéric Crozat <fcrozat src gnome org>
+ * Giovanni Campagna <gcampagna src gnome org>
+ * Jens Granseuer <jensgr gmx net>
+ * Jeremy Bicha <jbicha ubuntu com>
+ * Matthias Clasen <mclasen redhat com>
+ * Milan Bouchet-Valat <nalimilan club fr>
+ * Vincent Untz <vuntz gnome org>
+ */
+#include <config.h>
#include <glib/gi18n.h>
-#include <gtk/gtk.h>
-#include <gdk/gdkx.h>
+#include <stdlib.h>
-#include "clock.h"
#include "clock-face.h"
-#include "clock-time.h"
#include "clock-location-tile.h"
-#include "clock-location.h"
-#include "clock-utils.h"
-#include "clock-marshallers.h"
+#include "clock-time.h"
#include "set-timezone.h"
-G_DEFINE_TYPE (ClockLocationTile, clock_location_tile, GTK_TYPE_BIN)
+struct _ClockLocationTilePrivate
+{
+ ClockLocation *location;
+ ClockTime *time;
+ GDesktopClockFormat clock_format;
+
+ gulong weather_updated_id;
-enum {
+ GtkWidget *time_label;
+
+ GtkWidget *button_label;
+ GtkWidget *button;
+ GtkWidget *marker;
+ GtkWidget *spacer;
+};
+
+G_DEFINE_TYPE_WITH_PRIVATE (ClockLocationTile,
+ clock_location_tile,
+ GTK_TYPE_EVENT_BOX)
+
+enum
+{
TILE_PRESSED,
- NEED_CLOCK_FORMAT,
LAST_SIGNAL
};
-static guint signals[LAST_SIGNAL];
+enum
+{
+ PROP_0,
+ PROP_LOCATION,
+ PROP_CLOCK_FORMAT,
+ N_PROPERTIES
+};
-typedef struct {
- ClockLocation *location;
+static guint object_signals[LAST_SIGNAL] = { 0, };
+static GParamSpec *object_properties[N_PROPERTIES] = { NULL, };
- GDateTime *last_refresh;
- long last_offset;
+static void
+make_current_cb (gpointer user_data,
+ GError *error)
+{
+ GtkWidget *dialog;
+ if (!error)
+ return;
- GtkWidget *box;
- GtkWidget *clock_face;
- GtkWidget *city_label;
- GtkWidget *time_label;
+ dialog = gtk_message_dialog_new (NULL,
+ 0,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_CLOSE,
+ _("Failed to set the system timezone"));
- GtkWidget *current_button;
- GtkWidget *current_label;
- GtkWidget *current_marker;
- GtkWidget *current_spacer;
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
+ "%s",
+ error->message);
+ g_error_free (error);
- GtkWidget *weather_icon;
+ g_signal_connect (dialog, "response",
+ G_CALLBACK (gtk_widget_destroy), NULL);
- gulong location_weather_updated_id;
-} ClockLocationTilePrivate;
+ gtk_window_present (GTK_WINDOW (dialog));
+}
-static void clock_location_tile_finalize (GObject *);
+static void
+make_current (GtkWidget *widget,
+ gpointer user_data)
+{
+ ClockLocationTile *tile;
-#define PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CLOCK_LOCATION_TILE_TYPE, ClockLocationTilePrivate))
+ tile = CLOCK_LOCATION_TILE (user_data);
-static void clock_location_tile_fill (ClockLocationTile *this);
-static void update_weather_icon (ClockLocation *loc, GWeatherInfo *info, gpointer data);
-static gboolean weather_tooltip (GtkWidget *widget,
- gint x, gint y,
- gboolean keyboard_mode,
- GtkTooltip *tooltip,
- gpointer data);
+ clock_location_make_current (tile->priv->location,
+ (GFunc) make_current_cb,
+ NULL,
+ NULL);
+}
-ClockLocationTile *
-clock_location_tile_new (ClockLocation *loc)
+static gboolean
+clock_location_tile_enter_or_leave (GtkWidget *widget,
+ GdkEventCrossing *event,
+ gpointer user_data)
{
- ClockLocationTile *this;
- ClockLocationTilePrivate *priv;
+ ClockLocationTile *tile;
- this = g_object_new (CLOCK_LOCATION_TILE_TYPE, NULL);
- priv = PRIVATE (this);
+ if (event->mode != GDK_CROSSING_NORMAL)
+ return TRUE;
- priv->location = g_object_ref (loc);
+ tile = CLOCK_LOCATION_TILE (user_data);
- clock_location_tile_fill (this);
+ if (clock_location_is_current (tile->priv->location)) {
+ gtk_widget_hide (tile->priv->button);
+ gtk_widget_show (tile->priv->marker);
+ gtk_widget_hide (tile->priv->spacer);
- update_weather_icon (loc, clock_location_get_weather_info (loc), this);
- gtk_widget_set_has_tooltip (priv->weather_icon, TRUE);
+ return TRUE;
+ }
- g_signal_connect (priv->weather_icon, "query-tooltip",
- G_CALLBACK (weather_tooltip), this);
- priv->location_weather_updated_id = g_signal_connect (G_OBJECT (loc), "weather-updated",
- G_CALLBACK (update_weather_icon), this);
+ if (event->type == GDK_ENTER_NOTIFY) {
+ gint can_set;
- return this;
-}
+ if (clock_location_is_current_timezone (tile->priv->location)) {
+ can_set = 2;
+ } else {
+ can_set = can_set_system_timezone ();
+ }
-static void
-clock_location_tile_class_init (ClockLocationTileClass *this_class)
-{
- GObjectClass *g_obj_class = G_OBJECT_CLASS (this_class);
-
- g_obj_class->finalize = clock_location_tile_finalize;
-
- g_type_class_add_private (this_class, sizeof (ClockLocationTilePrivate));
-
- signals[TILE_PRESSED] = g_signal_new ("tile-pressed",
- G_TYPE_FROM_CLASS (g_obj_class),
- G_SIGNAL_RUN_FIRST,
- G_STRUCT_OFFSET (ClockLocationTileClass, tile_pressed),
- NULL,
- NULL,
- g_cclosure_marshal_VOID__VOID,
- G_TYPE_NONE, 0);
- signals[NEED_CLOCK_FORMAT] = g_signal_new ("need-clock-format",
- G_TYPE_FROM_CLASS (g_obj_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ClockLocationTileClass,
need_clock_format),
- NULL,
- NULL,
- _clock_marshal_INT__VOID,
- G_TYPE_INT, 0);
+ if (can_set != 0) {
+ const gchar *markup;
+
+ if (can_set == 1) {
+ markup = _("<small>Set...</small>");
+ } else {
+ markup = _("<small>Set</small>");
+ }
+
+ gtk_label_set_markup (GTK_LABEL (tile->priv->button_label),
+ markup);
+
+ gtk_widget_show (tile->priv->button);
+ gtk_widget_hide (tile->priv->marker);
+ gtk_widget_hide (tile->priv->spacer);
+ } else {
+ gtk_widget_hide (tile->priv->button);
+ gtk_widget_hide (tile->priv->marker);
+ gtk_widget_show (tile->priv->spacer);
+ }
+ } else {
+ if (event->detail != GDK_NOTIFY_INFERIOR) {
+ gtk_widget_hide (tile->priv->button);
+ gtk_widget_hide (tile->priv->marker);
+ gtk_widget_show (tile->priv->spacer);
+ }
+ }
+
+ return TRUE;
}
-static void
-clock_location_tile_init (ClockLocationTile *this)
+/*
+ * Should match enum values in gdesktop-enums.h:
+ * https://git.gnome.org/browse/gsettings-desktop-schemas/tree/headers/gdesktop-enums.h
+ */
+static GType
+g_desktop_clock_format_get_type (void)
{
- ClockLocationTilePrivate *priv = PRIVATE (this);
-
- priv->location = NULL;
+ static GType etype = 0;
- priv->last_refresh = NULL;
- priv->last_offset = 0;
+ if (etype == 0) {
+ static const GEnumValue values[] = {
+ { G_DESKTOP_CLOCK_FORMAT_24H, "G_DESKTOP_CLOCK_FORMAT_24H", "24h" },
+ { G_DESKTOP_CLOCK_FORMAT_12H, "G_DESKTOP_CLOCK_FORMAT_12H", "12h" },
+ { 0, NULL, NULL }
+ };
+ etype = g_enum_register_static ("GDesktopClockFormat", values);
+ }
- priv->clock_face = NULL;
- priv->city_label = NULL;
- priv->time_label = NULL;
+ return etype;
}
-static void
-clock_location_tile_finalize (GObject *g_obj)
+static gboolean
+show_weather_tooltip (GtkWidget *widget,
+ gint x,
+ gint y,
+ gboolean keyboard_mode,
+ GtkTooltip *tooltip,
+ gpointer user_data)
{
- ClockLocationTilePrivate *priv = PRIVATE (g_obj);
+ ClockLocationTile *tile;
+ GWeatherInfo *info;
- if (priv->last_refresh) {
- g_date_time_unref (priv->last_refresh);
- priv->last_refresh = NULL;
- }
+ tile = CLOCK_LOCATION_TILE (user_data);
+ info = clock_location_get_weather_info (tile->priv->location);
- if (priv->location) {
- g_signal_handler_disconnect (priv->location, priv->location_weather_updated_id);
- priv->location_weather_updated_id = 0;
+ if (!info || !gweather_info_is_valid (info))
+ return FALSE;
- g_object_unref (priv->location);
- priv->location = NULL;
- }
+ weather_info_setup_tooltip (info,
+ tile->priv->location,
+ tooltip,
+ tile->priv->clock_format);
- G_OBJECT_CLASS (clock_location_tile_parent_class)->finalize (g_obj);
-}
-
-static gboolean
-press_on_tile (GtkWidget *widget,
- GdkEventButton *event,
- ClockLocationTile *tile)
-{
- g_signal_emit (tile, signals[TILE_PRESSED], 0);
-
- return TRUE;
+ return TRUE;
}
static void
-make_current_cb (gpointer data, GError *error)
+update_weather_icon (ClockLocation *location,
+ GWeatherInfo *info,
+ gpointer user_data)
{
- GtkWidget *dialog;
+ GtkWidget *icon;
+ const gchar *icon_name;
- if (error) {
- dialog = gtk_message_dialog_new (NULL,
- 0,
- GTK_MESSAGE_ERROR,
- GTK_BUTTONS_CLOSE,
- _("Failed to set the system timezone"));
- gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), "%s", error->message);
- g_signal_connect (dialog, "response",
- G_CALLBACK (gtk_widget_destroy), NULL);
- gtk_window_present (GTK_WINDOW (dialog));
-
- g_error_free (error);
- }
-}
+ icon = GTK_WIDGET (user_data);
-static void
-make_current (GtkWidget *widget, ClockLocationTile *tile)
-{
- ClockLocationTilePrivate *priv = PRIVATE (tile);
+ if (!info || !gweather_info_is_valid (info)) {
+ gtk_widget_hide (icon);
+ return;
+ }
- clock_location_make_current (priv->location,
- (GFunc)make_current_cb, tile, NULL);
+ icon_name = gweather_info_get_icon_name (info);
+ gtk_image_set_from_icon_name (GTK_IMAGE (icon),
+ icon_name,
+ GTK_ICON_SIZE_INVALID);
+ gtk_image_set_pixel_size (GTK_IMAGE (icon), 16);
+ gtk_widget_show (icon);
}
-static gboolean
-enter_or_leave_tile (GtkWidget *widget,
- GdkEventCrossing *event,
- ClockLocationTile *tile)
+static GtkWidget *
+clock_location_tile_get_weather_icon (ClockLocationTile *tile)
{
- ClockLocationTilePrivate *priv = PRIVATE (tile);
+ ClockLocation *location;
+ GtkWidget *icon;
- if (event->mode != GDK_CROSSING_NORMAL) {
- return TRUE;
- }
+ location = tile->priv->location;
+ icon = gtk_image_new ();
- if (clock_location_is_current (priv->location)) {
- gtk_widget_hide (priv->current_button);
- gtk_widget_hide (priv->current_spacer);
- gtk_widget_show (priv->current_marker);
+ gtk_widget_set_no_show_all (icon, TRUE);
+ gtk_widget_set_has_tooltip (icon, TRUE);
+ gtk_widget_set_valign (icon, GTK_ALIGN_START);
- return TRUE;
- }
+ g_signal_connect (icon, "query-tooltip",
+ G_CALLBACK (show_weather_tooltip), tile);
- if (event->type == GDK_ENTER_NOTIFY) {
- gint can_set;
+ tile->priv->weather_updated_id =
+ g_signal_connect (location, "weather-updated",
+ G_CALLBACK (update_weather_icon), icon);
- if (clock_location_is_current_timezone (priv->location))
- can_set = 2;
- else
- can_set = can_set_system_timezone ();
- if (can_set != 0) {
- gtk_label_set_markup (GTK_LABEL (priv->current_label),
- can_set == 1 ?
- _("<small>Set...</small>") :
- _("<small>Set</small>"));
- gtk_widget_hide (priv->current_spacer);
- gtk_widget_hide (priv->current_marker);
- gtk_widget_show (priv->current_button);
- }
- else {
- gtk_widget_hide (priv->current_marker);
- gtk_widget_hide (priv->current_button);
- gtk_widget_show (priv->current_spacer);
- }
- }
- else {
- if (event->detail != GDK_NOTIFY_INFERIOR) {
- gtk_widget_hide (priv->current_button);
- gtk_widget_hide (priv->current_marker);
- gtk_widget_show (priv->current_spacer);
- }
- }
+ update_weather_icon (location,
+ clock_location_get_weather_info (location),
+ icon);
- return TRUE;
+ return icon;
}
-static void
-clock_location_tile_fill (ClockLocationTile *this)
+static GtkWidget *
+clock_location_tile_get_title (ClockLocation *location)
{
- ClockLocationTilePrivate *priv = PRIVATE (this);
- GtkWidget *strut;
- GtkWidget *box;
- GtkWidget *tile;
- GtkWidget *head_section;
- GtkSizeGroup *current_group;
- GtkSizeGroup *button_group;
-
- priv->box = gtk_event_box_new ();
-
- gtk_widget_add_events (priv->box, GDK_BUTTON_PRESS_MASK | GDK_ENTER_NOTIFY_MASK |
GDK_LEAVE_NOTIFY_MASK);
- g_signal_connect (priv->box, "button-press-event",
- G_CALLBACK (press_on_tile), this);
- g_signal_connect (priv->box, "enter-notify-event",
- G_CALLBACK (enter_or_leave_tile), this);
- g_signal_connect (priv->box, "leave-notify-event",
- G_CALLBACK (enter_or_leave_tile), this);
-
- tile = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
- gtk_widget_set_margin_top (tile, 3);
- gtk_widget_set_margin_bottom (tile, 3);
- gtk_widget_set_margin_start (tile, 3);
-
- head_section = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
-
- priv->city_label = gtk_label_new (NULL);
- gtk_widget_set_margin_end (priv->city_label, 3);
- gtk_label_set_xalign (GTK_LABEL (priv->city_label), 0);
-
- gtk_box_pack_start (GTK_BOX (head_section), priv->city_label, FALSE, FALSE, 0);
-
- priv->time_label = gtk_label_new (NULL);
- gtk_widget_set_margin_end (priv->time_label, 3);
- gtk_label_set_yalign (GTK_LABEL (priv->time_label), 0);
-
- priv->weather_icon = gtk_image_new ();
- gtk_widget_set_valign (priv->weather_icon, GTK_ALIGN_START);
-
- box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
- gtk_box_pack_start (GTK_BOX (head_section), box, FALSE, FALSE, 0);
- gtk_box_pack_start (GTK_BOX (box), priv->weather_icon, FALSE, FALSE, 0);
- gtk_box_pack_start (GTK_BOX (box), priv->time_label, FALSE, FALSE, 0);
-
- priv->current_button = gtk_button_new ();
- /* The correct label is set on EnterNotify events */
- priv->current_label = gtk_label_new ("");
- gtk_widget_show (priv->current_label);
- gtk_widget_set_no_show_all (priv->current_button, TRUE);
- gtk_container_add (GTK_CONTAINER (priv->current_button), priv->current_label);
- gtk_widget_set_tooltip_text (priv->current_button,
- _("Set location as current location and use its timezone for this
computer"));
-
- priv->current_marker = gtk_image_new_from_icon_name ("go-home", GTK_ICON_SIZE_BUTTON);
- gtk_widget_set_no_show_all (priv->current_marker, TRUE);
-
- priv->current_spacer = gtk_event_box_new ();
- gtk_widget_set_no_show_all (priv->current_spacer, TRUE);
-
- strut = gtk_event_box_new ();
- gtk_box_pack_start (GTK_BOX (box), strut, TRUE, TRUE, 0);
- gtk_box_pack_start (GTK_BOX (box), priv->current_button, FALSE, FALSE, 0);
- gtk_box_pack_start (GTK_BOX (box), priv->current_marker, FALSE, FALSE, 0);
- gtk_box_pack_start (GTK_BOX (box), priv->current_spacer, FALSE, FALSE, 0);
-
- button_group = gtk_size_group_new (GTK_SIZE_GROUP_VERTICAL);
- gtk_size_group_set_ignore_hidden (button_group, FALSE);
- gtk_size_group_add_widget (button_group, strut);
- gtk_size_group_add_widget (button_group, priv->current_button);
- g_object_unref (button_group);
-
- /*
- * Avoid resizing the popup as the tiles display the current marker,
- * set button or nothing. For that purpose, replace 'nothing' with
- * an event box, and force the button, marker and spacer to have the
- * same size via a size group. The visibility of the three is managed
- * manually to ensure that only one of them is shown at any time.
- * (The all have to be shown initially to get the sizes worked out,
- * but they are never visible together).
- */
- current_group = gtk_size_group_new (GTK_SIZE_GROUP_BOTH);
- gtk_size_group_set_ignore_hidden (current_group, FALSE);
- gtk_size_group_add_widget (current_group, priv->current_button);
- gtk_size_group_add_widget (current_group, priv->current_marker);
- gtk_size_group_add_widget (current_group, priv->current_spacer);
- g_object_unref (current_group);
-
- gtk_widget_show (priv->current_button);
- gtk_widget_show (priv->current_marker);
- gtk_widget_show (priv->current_spacer);
-
- g_signal_connect (priv->current_button, "clicked",
- G_CALLBACK (make_current), this);
-
- ClockTime *time = clock_time_new (priv->location);
- priv->clock_face = clock_face_new (priv->location, time, FALSE);
- gtk_widget_set_size_request (priv->clock_face, 52, 52);
- g_object_unref (time);
-
- gtk_box_pack_start (GTK_BOX (tile), priv->clock_face, FALSE, FALSE, 0);
- gtk_box_pack_start (GTK_BOX (tile), head_section, TRUE, TRUE, 0);
-
- gtk_container_add (GTK_CONTAINER (priv->box), tile);
- gtk_container_add (GTK_CONTAINER (this), priv->box);
-}
+ GtkWidget *label;
+ gchar *markup;
-static gboolean
-clock_needs_label_refresh (ClockLocationTile *this)
-{
- ClockLocationTilePrivate *priv = PRIVATE (this);
- GDateTime *now;
- long offset;
- gboolean retval;
+ label = gtk_label_new (NULL);
+ markup = g_strdup_printf ("<big><b>%s</b></big>",
+ clock_location_get_name (location));
- if (!priv->last_refresh)
- return TRUE;
+ gtk_label_set_markup (GTK_LABEL (label), markup);
+ g_free (markup);
- now = clock_location_localtime (priv->location);
- offset = clock_location_get_offset (priv->location);
-
- retval = FALSE;
- if (g_date_time_get_year (now) > g_date_time_get_year (priv->last_refresh)
- || g_date_time_get_month (now) > g_date_time_get_month (priv->last_refresh)
- || g_date_time_get_day_of_month (now) > g_date_time_get_day_of_month (priv->last_refresh)
- || g_date_time_get_hour (now) > g_date_time_get_hour (priv->last_refresh)
- || g_date_time_get_minute (now) > g_date_time_get_minute (priv->last_refresh)
- || offset != priv->last_offset) {
- retval = TRUE;
- }
-
- g_date_time_unref (now);
- return retval;
+ gtk_label_set_xalign (GTK_LABEL (label), 0);
+
+ return label;
}
-static char *
-format_time (GDateTime *now,
- const char *tzname,
- GDesktopClockFormat clock_format,
- long offset)
+static gchar *
+format_time (ClockLocationTile *tile)
{
- const char *format;
- GDateTime *local_now;
- char *buf;
- char *tmp;
- long hours, minutes;
-
- local_now = g_date_time_new_now_local ();
-
- if (g_date_time_get_day_of_week (local_now) !=
- g_date_time_get_day_of_week (now)) {
- if (clock_format == G_DESKTOP_CLOCK_FORMAT_12H) {
+ GDateTime *time;
+ GDateTime *time_local;
+ const gchar *tzname;
+ glong offset;
+ gint day_of_week;
+ gint day_of_week_local;
+ const gchar *format;
+ gchar *buf;
+ glong hours;
+ glong minutes;
+ gchar *tmp;
+
+ time = clock_location_localtime (tile->priv->location);
+ time_local = g_date_time_new_now_local ();
+ tzname = clock_location_get_tzname (tile->priv->location);
+ offset = -clock_location_get_offset (tile->priv->location);
+
+ day_of_week = g_date_time_get_day_of_week (time);
+ day_of_week_local = g_date_time_get_day_of_week (time_local);
+
+ if (day_of_week != day_of_week_local) {
+ if (tile->priv->clock_format == G_DESKTOP_CLOCK_FORMAT_12H) {
/* Translators: This is a strftime format string.
* It is used to display the time in 12-hours format
* (eg, like in the US: 8:10 am), when the local
@@ -410,9 +330,8 @@ format_time (GDateTime *now,
* (the %A expands to the weekday). */
format = _("%H:%M <small>(%A)</small>");
}
- }
- else {
- if (clock_format == G_DESKTOP_CLOCK_FORMAT_12H) {
+ } else {
+ if (tile->priv->clock_format == G_DESKTOP_CLOCK_FORMAT_12H) {
/* Translators: This is a strftime format string.
* It is used to display the time in 12-hours format
* (eg, like in the US: 8:10 am). The %p expands to
@@ -427,135 +346,401 @@ format_time (GDateTime *now,
}
}
- g_date_time_unref (local_now);
+ g_date_time_unref (time_local);
+
+ buf = g_date_time_format (time, format);
+ g_date_time_unref (time);
- buf = g_date_time_format (now, format);
- hours = offset / 3600;
- minutes = labs (offset % 3600) / 60;
+ hours = offset / 3600;
+ minutes = labs (offset % 3600) / 60;
if (hours != 0 && minutes != 0) {
tmp = g_strdup_printf ("%s <small>%s %+ld:%ld</small>", buf, tzname, hours, minutes);
- }
- else if (hours != 0) {
+ } else if (hours != 0) {
tmp = g_strdup_printf ("%s <small>%s %+ld</small>", buf, tzname, hours);
- }
- else {
+ } else {
tmp = g_strdup_printf ("%s <small>%s</small>", buf, tzname);
}
g_free (buf);
+
return tmp;
}
-void
-clock_location_tile_refresh (ClockLocationTile *this, gboolean force_refresh)
+static GtkWidget *
+clock_location_tile_get_time (ClockLocationTile *tile)
{
- ClockLocationTilePrivate *priv = PRIVATE (this);
- gchar *tmp;
- const char *tzname;
- GDateTime *now;
- long offset;
- int format;
-
- g_return_if_fail (IS_CLOCK_LOCATION_TILE (this));
-
- if (clock_location_is_current (priv->location)) {
- gtk_widget_hide (priv->current_spacer);
- gtk_widget_hide (priv->current_button);
- gtk_widget_show (priv->current_marker);
- }
- else {
- if (gtk_widget_get_visible (priv->current_marker)) {
- gtk_widget_hide (priv->current_marker);
- gtk_widget_hide (priv->current_button);
- gtk_widget_show (priv->current_spacer);
- }
- }
+ GtkWidget *label;
+ gchar *markup;
- if (!force_refresh && !clock_needs_label_refresh (this)) {
- return;
- }
+ label = gtk_label_new (NULL);
+ markup = format_time (tile);
- now = clock_location_localtime (priv->location);
- tzname = clock_location_get_tzname (priv->location);
+ gtk_label_set_markup (GTK_LABEL (label), markup);
+ g_free (markup);
- if (priv->last_refresh)
- g_date_time_unref (priv->last_refresh);
- priv->last_refresh = g_date_time_ref (now);
- priv->last_offset = clock_location_get_offset (priv->location);
+ gtk_label_set_xalign (GTK_LABEL (label), 0);
+ gtk_label_set_yalign (GTK_LABEL (label), 0);
+
+ return label;
+}
+
+static void
+update_clock_face_size (GtkWidget *widget,
+ GtkAllocation *allocation,
+ gpointer user_data)
+{
+ GtkWidget *face;
+ guint size;
+
+ face = GTK_WIDGET (user_data);
+ size = allocation->height;
+
+ gtk_widget_set_size_request (face, size, size);
+}
+
+static GtkWidget *
+clock_location_tile_get_button (ClockLocationTile *tile)
+{
+ const gchar *tooltip;
+ GtkWidget *button;
+ GtkWidget *label;
- tmp = g_strdup_printf ("<big><b>%s</b></big>",
- clock_location_get_name (priv->location));
- gtk_label_set_markup (GTK_LABEL (priv->city_label), tmp);
- g_free (tmp);
+ button = gtk_button_new ();
+ gtk_widget_set_no_show_all (button, TRUE);
+ gtk_widget_hide (button);
- g_signal_emit (this, signals[NEED_CLOCK_FORMAT], 0, &format);
+ tooltip = _("Set location as current location and use its timezone for this computer");
+ gtk_widget_set_tooltip_text (button, tooltip);
- offset = - priv->last_offset;
+ label = gtk_label_new (NULL);
+ gtk_container_add (GTK_CONTAINER (button), label);
+ gtk_widget_show (label);
- tmp = format_time (now, tzname, format, offset);
+ g_signal_connect (button, "clicked",
+ G_CALLBACK (make_current), tile);
- gtk_label_set_markup (GTK_LABEL (priv->time_label), tmp);
+ tile->priv->button = button;
+ tile->priv->button_label = label;
- g_free (tmp);
+ return button;
}
-static gboolean
-weather_tooltip (GtkWidget *widget,
- gint x,
- gint y,
- gboolean keyboard_mode,
- GtkTooltip *tooltip,
- gpointer data)
+static GtkWidget *
+clock_location_tile_get_marker (ClockLocationTile *tile)
{
- ClockLocationTile *tile = data;
- ClockLocationTilePrivate *priv = PRIVATE (tile);
- GWeatherInfo *info;
- int clock_format;
+ GtkWidget *marker;
- info = clock_location_get_weather_info (priv->location);
+ marker = gtk_image_new_from_icon_name ("go-home",
+ GTK_ICON_SIZE_BUTTON);
+ gtk_widget_set_no_show_all (marker, TRUE);
+ if (clock_location_is_current (tile->priv->location))
+ gtk_widget_show (marker);
- if (!info || !gweather_info_is_valid (info))
- return FALSE;
+ tile->priv->marker = marker;
- g_signal_emit (tile, signals[NEED_CLOCK_FORMAT], 0, &clock_format);
+ return marker;
+}
+
+static void
+clock_location_tile_fill (ClockLocationTile *tile)
+{
+ GtkWidget *box1;
+ GtkWidget *face;
+ GtkWidget *info;
+ GtkWidget *city;
+ GtkWidget *box2;
+ GtkWidget *icon;
+ GtkWidget *time;
+ GtkWidget *button;
+ GtkWidget *marker;
+ GtkWidget *strut;
+ GtkSizeGroup *button_group;
+ GtkSizeGroup *group;
+
+ gtk_container_set_border_width (GTK_CONTAINER (tile), 3);
+
+ box1 = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
+ gtk_container_add (GTK_CONTAINER (tile), box1);
+
+ face = clock_face_new (tile->priv->location,
+ tile->priv->time,
+ FALSE);
+ gtk_box_pack_start (GTK_BOX (box1), face, FALSE, FALSE, 0);
+ gtk_widget_show (face);
+
+ g_signal_connect (box1, "size-allocate",
+ G_CALLBACK (update_clock_face_size), face);
+
+ info = gtk_box_new (GTK_ORIENTATION_VERTICAL, 4);
+ gtk_box_pack_start (GTK_BOX (box1), info, TRUE, TRUE, 0);
+ gtk_widget_show (info);
+
+ city = clock_location_tile_get_title (tile->priv->location);
+ gtk_box_pack_start (GTK_BOX (info), city, FALSE, FALSE, 0);
+ gtk_widget_show (city);
+
+ box2 = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
+ gtk_box_pack_start (GTK_BOX (info), box2, FALSE, FALSE, 0);
+ gtk_widget_show (box2);
+
+ icon = clock_location_tile_get_weather_icon (tile);
+ gtk_box_pack_start (GTK_BOX (box2), icon, FALSE, FALSE, 0);
+
+ time = clock_location_tile_get_time (tile);
+ gtk_box_pack_start (GTK_BOX (box2), time, FALSE, FALSE, 0);
+ gtk_widget_show (time);
+ tile->priv->time_label = time;
+
+ button = clock_location_tile_get_button (tile);
+ gtk_box_pack_end (GTK_BOX (box2), button, FALSE, FALSE, 0);
+ tile->priv->button = button;
+
+ marker = clock_location_tile_get_marker (tile);
+ gtk_box_pack_end (GTK_BOX (box2), marker, FALSE, FALSE, 0);
+ tile->priv->marker = marker;
+
+ tile->priv->spacer = gtk_event_box_new ();
+ gtk_widget_set_no_show_all (tile->priv->spacer, TRUE);
+ gtk_box_pack_start (GTK_BOX (box2), tile->priv->spacer, FALSE, FALSE, 0);
+
+ strut = gtk_event_box_new ();
+ gtk_box_pack_start (GTK_BOX (box2), strut, TRUE, TRUE, 0);
+
+ button_group = gtk_size_group_new (GTK_SIZE_GROUP_VERTICAL);
+ gtk_size_group_set_ignore_hidden (button_group, FALSE);
+ gtk_size_group_add_widget (button_group, strut);
+ gtk_size_group_add_widget (button_group, tile->priv->button);
+ g_object_unref (button_group);
+
+ group = gtk_size_group_new (GTK_SIZE_GROUP_BOTH);
+ gtk_size_group_set_ignore_hidden (group, FALSE);
+ gtk_size_group_add_widget (group, tile->priv->button);
+ gtk_size_group_add_widget (group, tile->priv->marker);
+ gtk_size_group_add_widget (group, tile->priv->spacer);
+ g_object_unref (group);
+}
+
+static gboolean
+clock_location_tile_button_press (GtkWidget *widget,
+ GdkEventButton *event,
+ gpointer user_data)
+{
+ ClockLocationTile *tile;
- weather_info_setup_tooltip (info, priv->location, tooltip, clock_format);
+ tile = CLOCK_LOCATION_TILE (user_data);
+
+ g_signal_emit (tile, object_signals[TILE_PRESSED], 0,
+ tile->priv->location);
return TRUE;
}
static void
-update_weather_icon (ClockLocation *loc, GWeatherInfo *info, gpointer data)
+update_time_label (ClockLocationTile *tile)
{
- ClockLocationTile *tile = data;
- ClockLocationTilePrivate *priv = PRIVATE (tile);
- GdkPixbuf *pixbuf = NULL;
- GtkIconTheme *theme = NULL;
- const gchar *icon_name;
-
- if (!info || !gweather_info_is_valid (info))
- return;
-
- icon_name = gweather_info_get_icon_name (info);
- theme = gtk_icon_theme_get_default ();
- pixbuf = gtk_icon_theme_load_icon (theme, icon_name, 16,
- GTK_ICON_LOOKUP_GENERIC_FALLBACK, NULL);
-
- if (pixbuf) {
- gtk_image_set_from_pixbuf (GTK_IMAGE (priv->weather_icon), pixbuf);
- gtk_widget_set_margin_end (priv->weather_icon, 6);
- }
+ gchar *markup;
+
+ markup = format_time (tile);
+
+ gtk_label_set_markup (GTK_LABEL (tile->priv->time_label),
+ markup);
+
+ g_free (markup);
}
-ClockLocation *
-clock_location_tile_get_location (ClockLocationTile *this)
+static void
+clock_location_tile_minute_changed (ClockTime *time,
+ gint hour,
+ gint minute,
+ gpointer user_data)
{
- ClockLocationTilePrivate *priv;
+ ClockLocationTile *tile;
- g_return_val_if_fail (IS_CLOCK_LOCATION_TILE (this), NULL);
+ tile = CLOCK_LOCATION_TILE (user_data);
+
+ update_time_label (tile);
+}
+
+static void
+clock_location_tile_set_location (ClockLocationTile *tile,
+ ClockLocation *location)
+{
+ if (tile->priv->location)
+ g_object_unref (tile->priv->location);
+
+ if (tile->priv->time)
+ g_object_unref (tile->priv->time);
+
+ tile->priv->location = g_object_ref (location);
+ tile->priv->time = clock_time_new (location);
+
+ g_signal_connect (tile->priv->time, "minute-changed",
+ G_CALLBACK (clock_location_tile_minute_changed), tile);
+}
+
+static GObject *
+clock_location_tile_constructor (GType gtype,
+ guint n_properties,
+ GObjectConstructParam *properties)
+{
+ GObject *object;
+ ClockLocationTile *tile;
+
+ object = G_OBJECT_CLASS (clock_location_tile_parent_class)->constructor (gtype,
+ n_properties,
+ properties);
+ tile = CLOCK_LOCATION_TILE (object);
+
+ gtk_widget_add_events (GTK_WIDGET (tile),
+ GDK_BUTTON_PRESS_MASK |
+ GDK_ENTER_NOTIFY_MASK |
+ GDK_LEAVE_NOTIFY_MASK);
+
+ g_signal_connect (tile, "button-press-event",
+ G_CALLBACK (clock_location_tile_button_press), tile);
+ g_signal_connect (tile, "enter-notify-event",
+ G_CALLBACK (clock_location_tile_enter_or_leave), tile);
+ g_signal_connect (tile, "leave-notify-event",
+ G_CALLBACK (clock_location_tile_enter_or_leave), tile);
+
+ clock_location_tile_fill (tile);
+
+ return object;
+}
+
+static void
+clock_location_tile_finalize (GObject *object)
+{
+ ClockLocationTile *tile;
+
+ tile = CLOCK_LOCATION_TILE (object);
+
+ if (tile->priv->weather_updated_id > 0) {
+ g_signal_handler_disconnect (tile->priv->location,
+ tile->priv->weather_updated_id);
+ tile->priv->weather_updated_id = 0;
+ }
+
+ g_clear_object (&tile->priv->time);
+ g_clear_object (&tile->priv->location);
+
+ G_OBJECT_CLASS (clock_location_tile_parent_class)->finalize (object);
+}
+
+static void
+clock_location_tile_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ ClockLocationTile *tile;
+
+ tile = CLOCK_LOCATION_TILE (object);
+
+ switch (property_id)
+ {
+ case PROP_LOCATION:
+ clock_location_tile_set_location (tile,
+ g_value_get_object (value));
+ break;
+ case PROP_CLOCK_FORMAT:
+ tile->priv->clock_format = g_value_get_enum (value);
+ update_time_label (tile);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object,
+ property_id,
+ pspec);
+ break;
+ }
+}
+
+static void
+clock_location_tile_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ ClockLocationTile *tile;
+
+ tile = CLOCK_LOCATION_TILE (object);
+
+ switch (property_id)
+ {
+ case PROP_LOCATION:
+ g_value_set_object (value, tile->priv->location);
+ break;
+ case PROP_CLOCK_FORMAT:
+ g_value_set_enum (value, tile->priv->clock_format);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object,
+ property_id,
+ pspec);
+ break;
+ }
+}
+
+static void
+clock_location_tile_class_init (ClockLocationTileClass *class)
+{
+ GObjectClass *object_class;
+
+ object_class = G_OBJECT_CLASS (class);
+
+ object_class->constructor = clock_location_tile_constructor;
+ object_class->finalize = clock_location_tile_finalize;
+ object_class->set_property = clock_location_tile_set_property;
+ object_class->get_property = clock_location_tile_get_property;
+
+ object_signals[TILE_PRESSED] =
+ g_signal_new ("tile-pressed",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (ClockLocationTileClass, tile_pressed),
+ NULL,
+ NULL,
+ NULL,
+ G_TYPE_NONE,
+ 1,
+ CLOCK_TYPE_LOCATION);
+
+ object_properties[PROP_LOCATION] =
+ g_param_spec_object ("location",
+ "location",
+ "location",
+ CLOCK_TYPE_LOCATION,
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_READWRITE);
+
+ object_properties[PROP_CLOCK_FORMAT] =
+ g_param_spec_enum ("clock-format",
+ "clock-format",
+ "clock-format",
+ g_desktop_clock_format_get_type (),
+ G_DESKTOP_CLOCK_FORMAT_24H,
+ G_PARAM_READWRITE);
+
+ g_object_class_install_properties (object_class,
+ N_PROPERTIES,
+ object_properties);
+}
+
+static void
+clock_location_tile_init (ClockLocationTile *tile)
+{
+ tile->priv = clock_location_tile_get_instance_private (tile);
+}
+
+GtkWidget *
+clock_location_tile_new (ClockLocation *location)
+{
+ GObject *object;
- priv = PRIVATE (this);
+ object = g_object_new (CLOCK_TYPE_LOCATION_TILE,
+ "location", location,
+ NULL);
- return g_object_ref (priv->location);
+ return GTK_WIDGET (object);
}
diff --git a/applets/clock/clock-location-tile.h b/applets/clock/clock-location-tile.h
index d165bb9..95896eb 100644
--- a/applets/clock/clock-location-tile.h
+++ b/applets/clock/clock-location-tile.h
@@ -1,42 +1,73 @@
-#ifndef __CLOCK_LOCATION_TILE_H__
-#define __CLOCK_LOCATION_TILE_H__
+/*
+ * Copyright (C) 2014 Alberts Muktupāvels
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Alberts Muktupāvels <alberts muktupavels gmail com>
+ * Federico Mena Quintero <federico novell com>
+ * Giovanni Campagna <gcampagna src gnome org>
+ * Matthias Clasen <mclasen redhat com>
+ * Vincent Untz <vuntz gnome org>
+ */
+
+#ifndef CLOCK_LOCATION_TILE_H
+#define CLOCK_LOCATION_TILE_H
#include <gtk/gtk.h>
-#include "clock.h"
-#include "clock-face.h"
#include "clock-location.h"
G_BEGIN_DECLS
-#define CLOCK_LOCATION_TILE_TYPE (clock_location_tile_get_type ())
-#define CLOCK_LOCATION_TILE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CLOCK_LOCATION_TILE_TYPE,
ClockLocationTile))
-#define CLOCK_LOCATION_TILE_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), CLOCK_LOCATION_TILE_TYPE,
ClockLocationTileClass))
-#define IS_CLOCK_LOCATION_TILE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CLOCK_LOCATION_TILE_TYPE))
-#define IS_CLOCK_LOCATION_TILE_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), CLOCK_LOCATION_TILE_TYPE))
-#define CLOCK_LOCATION_TILE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), CLOCK_LOCATION_TILE_TYPE,
ClockLocationTileClass))
+#define CLOCK_TYPE_LOCATION_TILE (clock_location_tile_get_type ())
+#define CLOCK_LOCATION_TILE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), \
+ CLOCK_TYPE_LOCATION_TILE, \
+ ClockLocationTile))
+#define CLOCK_LOCATION_TILE_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), \
+ CLOCK_TYPE_LOCATION_TILE, \
+ ClockLocationTileClass))
+#define CLOCK_IS_LOCATION_TILE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), \
+ CLOCK_TYPE_LOCATION_TILE))
+#define CLOCK_IS_LOCATION_TILE_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), \
+ CLOCK_TYPE_LOCATION_TILE))
+#define CLOCK_LOCATION_TILE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), \
+ CLOCK_TYPE_LOCATION_TILE, \
+ ClockLocationTileClass))
-typedef struct
-{
- GtkBin parent;
-} ClockLocationTile;
+typedef struct _ClockLocationTile ClockLocationTile;
+typedef struct _ClockLocationTileClass ClockLocationTileClass;
+typedef struct _ClockLocationTilePrivate ClockLocationTilePrivate;
-typedef struct
+struct _ClockLocationTile
{
- GtkBinClass parent_class;
-
- void (* tile_pressed) (ClockLocationTile *tile);
- int (* need_clock_format) (ClockLocationTile *tile);
-} ClockLocationTileClass;
+ GtkEventBox parent;
+ ClockLocationTilePrivate *priv;
+};
-GType clock_location_tile_get_type (void);
+struct _ClockLocationTileClass
+{
+ GtkEventBoxClass parent_class;
-ClockLocationTile *clock_location_tile_new (ClockLocation *loc);
+ void (* tile_pressed) (ClockLocationTile *tile,
+ ClockLocation *location);
+};
-ClockLocation *clock_location_tile_get_location (ClockLocationTile *this);
+GType clock_location_tile_get_type (void);
-void clock_location_tile_refresh (ClockLocationTile *this,
- gboolean force_refresh);
+GtkWidget *clock_location_tile_new (ClockLocation *location);
G_END_DECLS
-#endif /* __CLOCK_H__ */
+
+#endif
diff --git a/applets/clock/clock.c b/applets/clock/clock.c
index 265eb7d..23cd758 100644
--- a/applets/clock/clock.c
+++ b/applets/clock/clock.c
@@ -247,18 +247,6 @@ set_atk_name_description (GtkWidget *widget,
atk_object_set_name (obj, name);
}
-static void
-update_location_tiles (ClockData *cd)
-{
- GList *l;
-
- for (l = cd->location_tiles; l; l = l->next) {
- ClockLocationTile *tile;
-
- tile = CLOCK_LOCATION_TILE (l->data);
- clock_location_tile_refresh (tile, FALSE);
- }
-}
static void
update_clock (GnomeWallClock *wall_clock, GParamSpec *pspec, ClockData * cd)
@@ -272,7 +260,6 @@ update_clock (GnomeWallClock *wall_clock, GParamSpec *pspec, ClockData * cd)
gtk_widget_queue_resize (cd->panel_button);
update_tooltip (cd);
- update_location_tiles (cd);
if (cd->map_widget && cd->calendar_popup && gtk_widget_get_visible (cd->calendar_popup))
clock_map_update_time (CLOCK_MAP (cd->map_widget));
@@ -635,24 +622,13 @@ sort_locations_by_time (gconstpointer a, gconstpointer b)
}
static void
-location_tile_pressed_cb (ClockLocationTile *tile, gpointer data)
+location_tile_pressed_cb (ClockLocationTile *tile,
+ ClockLocation *loc,
+ gpointer data)
{
ClockData *cd = data;
- ClockLocation *loc;
-
- loc = clock_location_tile_get_location (tile);
clock_map_blink_location (CLOCK_MAP (cd->map_widget), loc);
-
- g_object_unref (loc);
-}
-
-static int
-location_tile_need_clock_format_cb(ClockLocationTile *tile, gpointer data)
-{
- ClockData *cd = data;
-
- return g_settings_get_enum (cd->clock_settings, "clock-format");
}
static void
@@ -692,8 +668,10 @@ create_cities_section (ClockData *cd)
city = clock_location_tile_new (loc);
g_signal_connect (city, "tile-pressed",
G_CALLBACK (location_tile_pressed_cb), cd);
- g_signal_connect (city, "need-clock-format",
- G_CALLBACK (location_tile_need_clock_format_cb), cd);
+
+ g_settings_bind (cd->clock_settings, "clock-format",
+ city, "clock-format",
+ G_SETTINGS_BIND_GET);
gtk_box_pack_start (GTK_BOX (cd->cities_section),
GTK_WIDGET (city),
@@ -701,8 +679,6 @@ create_cities_section (ClockData *cd)
cd->location_tiles = g_list_prepend (cd->location_tiles, city);
- clock_location_tile_refresh (city, TRUE);
-
node = g_list_next (node);
}
@@ -1212,7 +1188,6 @@ location_set_current_cb (ClockLocation *loc,
if (cd->map_widget)
clock_map_refresh (CLOCK_MAP (cd->map_widget));
- update_location_tiles (cd);
save_cities_store (cd);
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]