[gnome-panel/wip/applets/clock: 5/18] clock: rewrite ClockFace



commit 6a1afea5c3676a6a713855cf2d133a5ff92ec63e
Author: Alberts Muktupāvels <alberts muktupavels gmail com>
Date:   Sat Nov 8 21:02:23 2014 +0200

    clock: rewrite ClockFace

 applets/clock/clock-face.c          |  782 ++++++++++++++++++-----------------
 applets/clock/clock-face.h          |   77 ++--
 applets/clock/clock-location-tile.c |   47 +--
 applets/clock/clock-location-tile.h |    3 +-
 applets/clock/clock.c               |    2 +-
 5 files changed, 449 insertions(+), 462 deletions(-)
---
diff --git a/applets/clock/clock-face.c b/applets/clock/clock-face.c
index 2e95b11..e636f07 100644
--- a/applets/clock/clock-face.c
+++ b/applets/clock/clock-face.c
@@ -1,466 +1,482 @@
-/**
- * clock.c
+/*
+ * Copyright (C) 2007      Peter Teichman
+ * Copyright (C) 2005-2006 Davyd Madeley
+ * Copyright (C) 2014      Alberts Muktupāvels
  *
- * A GTK+ widget that implements a clock face
+ * 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.
  *
- * (c) 2007, Peter Teichman
- * (c) 2005-2006, Davyd Madeley
+ * 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:
- *   Davyd Madeley  <davyd madeley id au>
- *   Peter Teichman <peter novell com>
+ *    Alberts Muktupāvels <alberts muktupavels gmail com>
+ *    Davyd Madeley  <davyd madeley id au>
+ *    Peter Teichman <peter novell com>
  */
 
+#include <config.h>
 #include <gtk/gtk.h>
 #include <math.h>
-#include <time.h>
 
 #include "clock.h"
 #include "clock-face.h"
-#include "clock-location.h"
-#include "clock-utils.h"
-
-static GHashTable *pixbuf_cache = NULL;
-
-G_DEFINE_TYPE (ClockFace, clock_face, GTK_TYPE_WIDGET)
-
-static void     clock_face_finalize             (GObject *);
-static gboolean clock_face_draw                 (GtkWidget     *clock,
-                                                 cairo_t       *cr);
-static void     clock_face_get_preferred_width  (GtkWidget     *this,
-                                                 gint          *minimal_width,
-                                                 gint          *natural_width);
-static void     clock_face_get_preferred_height (GtkWidget     *this,
-                                                 gint          *minimal_height,
-                                                 gint          *natural_height);
-static void     clock_face_size_allocate        (GtkWidget     *clock,
-                                                GtkAllocation *allocation);
-
-static void update_time_and_face (ClockFace *this,
-                                  gboolean   force_face_loading);
-static void clock_face_load_face (ClockFace *this,
-                                 gint width, gint height);
-
-typedef enum {
-       CLOCK_FACE_MORNING,
-       CLOCK_FACE_DAY,
-       CLOCK_FACE_EVENING,
-       CLOCK_FACE_NIGHT,
-       CLOCK_FACE_INVALID
-} ClockFaceTimeOfDay;
+
+typedef enum _ClockFaceType ClockFaceType;
 
 struct _ClockFacePrivate
 {
-       GDateTime *time; /* the time on the clock face */
-        int minute_offset; /* the offset of the minutes hand */
-
-        ClockFaceSize size;
-       ClockFaceTimeOfDay timeofday;
-        ClockLocation *location;
-        GdkPixbuf *face_pixbuf;
-        GtkWidget *size_widget;
+       ClockLocation *location;
+       ClockTime     *time;
+       gboolean       show_seconds;
+
+       gint           hour;
+       gint           minute;
+       gint           second;
 };
 
-static void
-clock_face_class_init (ClockFaceClass *class)
+G_DEFINE_TYPE_WITH_PRIVATE (ClockFace,
+                            clock_face,
+                            GTK_TYPE_IMAGE)
+
+enum
 {
-        GObjectClass *obj_class;
-        GtkWidgetClass *widget_class;
+       PROP_0,
+       PROP_LOCATION,
+       PROP_TIME,
+       PROP_SHOW_SECONDS,
+       N_PROPERTIES
+};
 
-        obj_class = G_OBJECT_CLASS (class);
-        widget_class = GTK_WIDGET_CLASS (class);
+static GParamSpec *object_properties[N_PROPERTIES] = { NULL, };
 
-        /* GtkWidget signals */
-        widget_class->draw = clock_face_draw;
-        widget_class->get_preferred_width  = clock_face_get_preferred_width;
-        widget_class->get_preferred_height = clock_face_get_preferred_height;
-        widget_class->size_allocate = clock_face_size_allocate;
+enum _ClockFaceType
+{
+       CLOCK_FACE_TYPE_MORNING,
+       CLOCK_FACE_TYPE_DAY,
+       CLOCK_FACE_TYPE_EVENING,
+       CLOCK_FACE_TYPE_NIGHT
+};
 
-        /* GObject signals */
-        obj_class->finalize = clock_face_finalize;
+static gboolean
+clock_face_draw (GtkWidget *widget,
+                 cairo_t   *cr)
+{
+       ClockFace *face;
+       gdouble    hour_length;
+       gdouble    minute_length;
+       gdouble    second_length;
+       gdouble    x;
+       gdouble    y;
+       gdouble    radius;
+       gdouble    width;
+       gdouble    height;
+
+       face = CLOCK_FACE (widget);
+
+       if (GTK_WIDGET_CLASS (clock_face_parent_class)->draw)
+               GTK_WIDGET_CLASS (clock_face_parent_class)->draw (widget, cr);
+
+       x = gtk_widget_get_allocated_width (widget) / 2;
+       y = gtk_widget_get_allocated_height (widget) / 2;
+       radius = MIN (x, y) - 5;
+
+       if (x * 2 >= 50) {
+               hour_length = 0.45;
+               minute_length = 0.6;
+               second_length = 0.65;
+       } else {
+               hour_length = 0.5;
+               minute_length = 0.7;
+               second_length = 0.8;
+       }
+
+       cairo_set_line_width (cr, 1);
+
+       /* hour hand:
+        * the hour hand is rotated 30 degrees (pi/6 r) per hour +
+        * 1/2 a degree (pi/360 r) per minute
+        */
+       width = x + radius * hour_length * sin (M_PI / 6 * face->priv->hour +
+                                               M_PI / 360 * face->priv->minute);
+       height = y + radius * hour_length * -cos (M_PI / 6 * face->priv->hour +
+                                                 M_PI / 360 * face->priv->minute);
+
+       cairo_save (cr);
+       cairo_move_to (cr, x, y);
+       cairo_line_to (cr, width, height);
+       cairo_stroke (cr);
+       cairo_restore (cr);
+
+       /* minute hand:
+        * the minute hand is rotated 6 degrees (pi/30 r) per minute
+        */
+       width = x + radius * minute_length * sin (M_PI / 30 * face->priv->minute);
+       height = y + radius * minute_length * -cos (M_PI / 30 * face->priv->minute);
+
+       cairo_save (cr);
+       cairo_move_to (cr, x, y);
+       cairo_line_to (cr, width, height);
+       cairo_stroke (cr);
+       cairo_restore (cr);
+
+       /* second hand:
+        * operates identically to the minute hand
+        */
+       if (face->priv->show_seconds) {
+               width = x + radius * second_length * sin (M_PI / 30 * face->priv->second);
+               height = y + radius * second_length * -cos (M_PI / 30 * face->priv->second);
+
+               cairo_save (cr);
+               cairo_set_source_rgb (cr, 0.937, 0.161, 0.161); /* tango red */
+               cairo_move_to (cr, x, y);
+               cairo_line_to (cr, width, height);
+               cairo_stroke (cr);
+               cairo_restore (cr);
+       }
 
-        g_type_class_add_private (obj_class, sizeof (ClockFacePrivate));
+       return FALSE;
 }
 
-static void
-clock_face_init (ClockFace *this)
+/*
+ * FIXME: this should be a gsettings setting,
+ * currently hardcoded values:
+ * 1. morning : 7 - 9
+ * 2. day     : 9 - 17
+ * 3. evening : 17 - 22
+ * 4. night   : 22 - 7
+ */
+static ClockFaceType
+clock_face_get_type_from_hour (gint hour)
 {
-        ClockFacePrivate *priv;
-
-        priv = this->priv = G_TYPE_INSTANCE_GET_PRIVATE (this, INTL_TYPE_CLOCK_FACE, ClockFacePrivate);
+       ClockFaceType type;
 
-        priv->size = CLOCK_FACE_SMALL;
-        priv->timeofday = CLOCK_FACE_INVALID;
-        priv->location = NULL;
-        priv->size_widget = NULL;
+       if (hour < 7)
+               type = CLOCK_FACE_TYPE_NIGHT;
+       else if (hour < 9)
+               type = CLOCK_FACE_TYPE_MORNING;
+       else if (hour < 17)
+               type = CLOCK_FACE_TYPE_DAY;
+       else if (hour < 22)
+               type = CLOCK_FACE_TYPE_EVENING;
+       else
+               type = CLOCK_FACE_TYPE_NIGHT;
 
-        gtk_widget_set_has_window (GTK_WIDGET (this), FALSE);
+       return type;
 }
 
-static gboolean
-clock_face_draw (GtkWidget *this, cairo_t *cr)
+static gchar *
+clock_face_image_from_type (ClockFaceType type)
 {
-        ClockFacePrivate *priv = CLOCK_FACE (this)->priv;
-        int width, height;
-        double x, y;
-        double radius;
-        int hours, minutes, seconds;
-        /* Hand lengths as a multiple of the clock radius */
-        double hour_length, min_length, sec_length;
-
-        if (GTK_WIDGET_CLASS (clock_face_parent_class)->draw)
-                GTK_WIDGET_CLASS (clock_face_parent_class)->draw (this, cr);
-
-        if (priv->size == CLOCK_FACE_LARGE) {
-                hour_length = 0.45;
-                min_length = 0.6;
-                sec_length = 0.65;
-        } else {
-                hour_length = 0.5;
-                min_length = 0.7;
-                sec_length = 0.8;   /* not drawn currently */
-        }
-
-        width = gtk_widget_get_allocated_width (this);
-        height = gtk_widget_get_allocated_width (this);
-
-        x = width / 2;
-        y = height / 2;
-        radius = MIN (width / 2, height / 2) - 5;
-
-        /* clock back */
-        if (priv->face_pixbuf) {
-                cairo_save (cr);
-                gdk_cairo_set_source_pixbuf (cr, priv->face_pixbuf, 0, 0);
-                cairo_paint (cr);
-                cairo_restore (cr);
-        }
-
-        /* clock hands */
-        hours = g_date_time_get_hour (priv->time);
-        minutes = g_date_time_get_minute (priv->time) + priv->minute_offset;
-        seconds = g_date_time_get_seconds (priv->time);
-
-        cairo_set_line_width (cr, 1);
-
-        /* hour hand:
-         * the hour hand is rotated 30 degrees (pi/6 r) per hour +
-         * 1/2 a degree (pi/360 r) per minute
-         */
-        cairo_save (cr);
-        cairo_move_to (cr, x, y);
-        cairo_line_to (cr, x + radius * hour_length * sin (M_PI / 6 * hours +
-                                                           M_PI / 360 * minutes),
-                           y + radius * hour_length * -cos (M_PI / 6 * hours +
-                                                            M_PI / 360 * minutes));
-        cairo_stroke (cr);
-        cairo_restore (cr);
-        /* minute hand:
-         * the minute hand is rotated 6 degrees (pi/30 r) per minute
-         */
-        cairo_move_to (cr, x, y);
-        cairo_line_to (cr, x + radius * min_length * sin (M_PI / 30 * minutes),
-                           y + radius * min_length * -cos (M_PI / 30 * minutes));
-        cairo_stroke (cr);
-
-        /* seconds hand:
-         * operates identically to the minute hand
-         */
-        if (priv->size == CLOCK_FACE_LARGE) {
-                cairo_save (cr);
-                cairo_set_source_rgb (cr, 0.937, 0.161, 0.161); /* tango red */
-                cairo_move_to (cr, x, y);
-                cairo_line_to (cr, x + radius * sec_length * sin (M_PI / 30 * seconds),
-                               y + radius * sec_length * -cos (M_PI / 30 * seconds));
-                cairo_stroke (cr);
-                cairo_restore (cr);
-        }
-
-        return FALSE;
+       const gchar *faces[4] = {
+               "morning",
+               "day",
+               "evening",
+               "night"
+       };
+
+       return g_strconcat (CLOCK_RESOURCE_PATH "icons/",
+                           "clock-face-",
+                           faces[(gint) type],
+                           ".svg",
+                           NULL);
 }
 
-static void
-clock_face_redraw_canvas (ClockFace *this)
+static GdkPixbuf *
+clock_face_get_pixbuf (ClockFace *face)
 {
-        gtk_widget_queue_draw (GTK_WIDGET (this));
+       ClockFaceType  type;
+       gchar         *image;
+       gint           width;
+       gint           height;
+       gint           size;
+       GError        *error;
+       GdkPixbuf     *pixbuf;
+
+       type = clock_face_get_type_from_hour (face->priv->hour);
+       image = clock_face_image_from_type (type);
+
+       width = gtk_widget_get_allocated_width (GTK_WIDGET (face));
+       height = gtk_widget_get_allocated_height (GTK_WIDGET (face));
+
+       size = MIN (width, height);
+
+       error = NULL;
+       pixbuf = gdk_pixbuf_new_from_resource_at_scale (image,
+                                                       size,
+                                                       size,
+                                                       TRUE,
+                                                       &error);
+       g_free (image);
+
+       if (error) {
+               g_warning ("Failed to load clock face: %s", error->message);
+               g_error_free (error);
+       }
+
+       return pixbuf;
 }
 
 static void
-clock_face_get_preferred_width (GtkWidget *this,
-                                gint      *minimal_width,
-                                gint      *natural_width)
+clock_face_hour_changed (ClockTime *time,
+                         gint       hour,
+                         gpointer   user_data)
 {
-        ClockFacePrivate *priv = CLOCK_FACE (this)->priv;
-
-        if (priv->size_widget != NULL) {
-               int child_minimal_height;
-               int child_natural_height;
-
-                /* Tie our size to the height of the size_widget */
-                gtk_widget_get_preferred_height (GTK_WIDGET (priv->size_widget),
-                                                 &child_minimal_height,
-                                                 &child_natural_height);
-
-                /* Pad out our height by a little bit - this improves
-                   the balance */
-                *minimal_width = child_minimal_height + child_minimal_height / 8;
-                *natural_width = child_natural_height + child_natural_height / 8;
-        } else if (priv->face_pixbuf != NULL) {
-                /* Use the size of the current pixbuf */
-                *minimal_width = *natural_width = gdk_pixbuf_get_width (GDK_PIXBUF (priv->face_pixbuf));
-        } else {
-                /* we don't know anything, so use known dimensions for the svg
-                 * files */
-                if (priv->size == CLOCK_FACE_LARGE)
-                        *minimal_width = *natural_width = 50;
-                else
-                        *minimal_width = *natural_width = 36;
-        }
+       ClockFace *face;
+       GdkPixbuf *pixbuf;
+
+       face = CLOCK_FACE (user_data);
+
+       face->priv->hour = hour;
+
+       pixbuf = clock_face_get_pixbuf (face);
+       gtk_image_set_from_pixbuf (GTK_IMAGE (face), pixbuf);
+       g_object_unref (pixbuf);
 }
 
 static void
-clock_face_get_preferred_height (GtkWidget *this,
-                                 gint      *minimal_height,
-                                 gint      *natural_height)
+clock_face_minute_changed (ClockTime *time,
+                           gint       hour,
+                           gint       minute,
+                           gpointer   user_data)
 {
-        ClockFacePrivate *priv = CLOCK_FACE (this)->priv;
-
-        if (priv->size_widget != NULL) {
-               int child_minimal_height;
-               int child_natural_height;
-
-                /* Tie our size to the height of the size_widget */
-                gtk_widget_get_preferred_height (GTK_WIDGET (priv->size_widget),
-                                                 &child_minimal_height,
-                                                 &child_natural_height);
-
-                /* Pad out our height by a little bit - this improves
-                   the balance */
-                *minimal_height = child_minimal_height + child_minimal_height / 8;
-                *natural_height = child_natural_height + child_natural_height / 8;
-        } else if (priv->face_pixbuf != NULL) {
-                /* Use the size of the current pixbuf */
-                *minimal_height = *natural_height = gdk_pixbuf_get_height (GDK_PIXBUF (priv->face_pixbuf));
-        } else {
-                /* we don't know anything, so use known dimensions for the svg
-                 * files */
-                if (priv->size == CLOCK_FACE_LARGE)
-                        *minimal_height = *natural_height = 50;
-                else
-                        *minimal_height = *natural_height = 36;
-        }
+       ClockFace *face;
+
+       face = CLOCK_FACE (user_data);
+
+       if (face->priv->show_seconds)
+               return;
+
+       face->priv->hour = hour;
+       face->priv->minute = minute;
+
+       gtk_widget_queue_draw (GTK_WIDGET (face));
 }
 
 static void
-clock_face_size_allocate (GtkWidget     *this,
-                          GtkAllocation *allocation)
+clock_face_second_changed (ClockTime *time,
+                           gint       hour,
+                           gint       minute,
+                           gint       second,
+                           gpointer   user_data)
 {
-        GtkAllocation this_allocation;
-        GtkAllocation old_allocation;
-
-        gtk_widget_get_allocation (this, &this_allocation);
+       ClockFace *face;
 
-        old_allocation.width = this_allocation.width;
-        old_allocation.height = this_allocation.height;
+       face = CLOCK_FACE (user_data);
 
-        if (GTK_WIDGET_CLASS (clock_face_parent_class)->size_allocate)
-                GTK_WIDGET_CLASS (clock_face_parent_class)->size_allocate (this, allocation);
+       if (!face->priv->show_seconds)
+               return;
 
-        if (old_allocation.width  == allocation->width &&
-            old_allocation.height == allocation->height)
-                return;
+       face->priv->hour = hour;
+       face->priv->minute = minute;
+       face->priv->second = second;
 
-        /* Reload the face for the new size */
-        update_time_and_face (CLOCK_FACE (this), TRUE);
+       gtk_widget_queue_draw (GTK_WIDGET (face));
 }
 
 static void
-update_time_and_face (ClockFace *this,
-                      gboolean   force_face_loading)
+clock_face_size_allocate (GtkWidget     *widget,
+                          GtkAllocation *allocation)
 {
-        ClockFacePrivate *priv;
-       ClockFaceTimeOfDay timeofday;
-       int hour;
-
-        priv = this->priv;
+       ClockFace     *face;
+       GtkAllocation  old_allocation;
+       GdkPixbuf     *pixbuf;
 
-       if (priv->time)
-               g_date_time_unref (priv->time);
-        /* update the time */
-        if (priv->location)
-                priv->time = clock_location_localtime (priv->location);
-       else
-               priv->time = g_date_time_new_now_local ();
-
-       /* FIXME  this should be a gconf setting
-         * Or we could use some code from clock-sun.c?
-         * currently we hardcode
-         * morning 7-9
-         * day 9-17
-         * evening 17-22
-         * night 22-7
-         */
-       hour = g_date_time_get_hour (priv->time);
-       if (hour < 7)
-               timeofday = CLOCK_FACE_NIGHT;
-       else if (hour < 9)
-               timeofday = CLOCK_FACE_MORNING;
-       else if (hour < 17)
-               timeofday = CLOCK_FACE_DAY;
-       else if (hour < 22)
-               timeofday = CLOCK_FACE_EVENING;
-       else
-               timeofday = CLOCK_FACE_NIGHT;
+       gtk_widget_get_allocation (widget, &old_allocation);
 
-       if (priv->timeofday != timeofday || force_face_loading) {
-                GtkAllocation allocation;
-               gint width, height;
+       GTK_WIDGET_CLASS (clock_face_parent_class)->size_allocate (widget,
+                                                                  allocation);
 
-               priv->timeofday = timeofday;
+       if (old_allocation.width == allocation->width &&
+           old_allocation.height == allocation->height)
+               return;
 
-                gtk_widget_get_allocation (GTK_WIDGET (this), &allocation);
+       face = CLOCK_FACE (widget);
 
-               width = allocation.width;
-               height = allocation.height;
+       if (face->priv->hour == -1)
+               return;
 
-                /* Only load the pixbuf if we have some space allocated.
-                 * Note that 1x1 is not really some space... */
-               if (width > 1 && height > 1)
-                        clock_face_load_face (this, width, height);
-       }
+       pixbuf = clock_face_get_pixbuf (CLOCK_FACE (widget));
+       gtk_image_set_from_pixbuf (GTK_IMAGE (widget), pixbuf);
+       g_object_unref (pixbuf);
 }
 
-gboolean
-clock_face_refresh (ClockFace *this)
+static void
+clock_face_finalize (GObject *object)
 {
-       update_time_and_face (this, FALSE);
-        clock_face_redraw_canvas (this);
+       ClockFace *face;
 
-        return TRUE; /* keep running this event */
+       face = CLOCK_FACE (object);
+
+       g_clear_object (&face->priv->time);
+       g_clear_object (&face->priv->location);
+
+       G_OBJECT_CLASS (clock_face_parent_class)->finalize (object);
 }
 
-GtkWidget *
-clock_face_new (ClockFaceSize size)
+static void
+clock_face_set_location (ClockFace     *face,
+                         ClockLocation *location)
 {
-        GObject *obj = g_object_new (INTL_TYPE_CLOCK_FACE, NULL);
-        ClockFacePrivate *priv = CLOCK_FACE (obj)->priv;
+       if (face->priv->location)
+               g_object_unref (face->priv->location);
 
-        priv->size = size;
-
-        return GTK_WIDGET (obj);
+       face->priv->location = g_object_ref (location);
 }
 
-GtkWidget *
-clock_face_new_with_location (ClockFaceSize size,
-                             ClockLocation *loc,
-                             GtkWidget *size_widget)
+static void
+clock_face_set_time (ClockFace *face,
+                     ClockTime *time)
 {
-        GObject *obj = g_object_new (INTL_TYPE_CLOCK_FACE, NULL);
-        ClockFacePrivate *priv = CLOCK_FACE (obj)->priv;
-
-        priv->size = size;
-        priv->location = g_object_ref (loc);
-        priv->size_widget = g_object_ref (size_widget);
+       if (face->priv->time)
+               g_object_unref (face->priv->time);
+
+       face->priv->time = g_object_ref (time);
+
+       g_signal_connect (face->priv->time,
+                         "hour-changed",
+                         G_CALLBACK (clock_face_hour_changed),
+                         face);
+       g_signal_connect (face->priv->time,
+                         "minute-changed",
+                         G_CALLBACK (clock_face_minute_changed),
+                         face);
+       g_signal_connect (face->priv->time,
+                         "second-changed",
+                         G_CALLBACK (clock_face_second_changed),
+                         face);
+}
 
-        return GTK_WIDGET (obj);
+static void
+clock_face_set_property (GObject      *object,
+                         guint         property_id,
+                         const GValue *value,
+                         GParamSpec   *pspec)
+{
+       ClockFace *face;
+
+       face = CLOCK_FACE (object);
+
+       switch (property_id)
+       {
+               case PROP_LOCATION:
+                       clock_face_set_location (face,
+                                                g_value_get_object (value));
+                       break;
+               case PROP_TIME:
+                       clock_face_set_time (face,
+                                            g_value_get_object (value));
+                       break;
+               case PROP_SHOW_SECONDS:
+                       face->priv->show_seconds = g_value_get_boolean (value);
+                       break;
+               default:
+                       G_OBJECT_WARN_INVALID_PROPERTY_ID (object,
+                                                          property_id,
+                                                          pspec);
+                       break;
+       }
 }
 
 static void
-clock_face_finalize (GObject *obj)
+clock_face_get_property (GObject    *object,
+                         guint       property_id,
+                         GValue     *value,
+                         GParamSpec *pspec)
 {
-        ClockFace *face = CLOCK_FACE (obj);
-        ClockFacePrivate *priv = face->priv;
-
-        if (priv->location) {
-                g_object_unref (priv->location);
-                priv->location = NULL;
-        }
-
-        if (priv->face_pixbuf) {
-                g_object_unref (priv->face_pixbuf);
-                priv->face_pixbuf = NULL;
-        }
-
-        if (priv->size_widget) {
-                g_object_unref (priv->size_widget);
-                priv->size_widget = NULL;
-        }
-
-        G_OBJECT_CLASS (clock_face_parent_class)->finalize (obj);
-
-        if (pixbuf_cache && g_hash_table_size (pixbuf_cache) == 0) {
-                g_hash_table_destroy (pixbuf_cache);
-                pixbuf_cache = NULL;
-        }
+       ClockFace *face;
+
+       face = CLOCK_FACE (object);
+
+       switch (property_id)
+       {
+               case PROP_LOCATION:
+                       g_value_set_object (value, face->priv->location);
+                       break;
+               case PROP_TIME:
+                       g_value_set_object (value, face->priv->time);
+                       break;
+               case PROP_SHOW_SECONDS:
+                       g_value_set_boolean (value, face->priv->show_seconds);
+                       break;
+               default:
+                       G_OBJECT_WARN_INVALID_PROPERTY_ID (object,
+                                                          property_id,
+                                                          pspec);
+                       break;
+       }
 }
 
-/* The pixbuf is being disposed, so remove it from the cache */
 static void
-remove_pixbuf_from_cache (const char *key,
-                          GObject    *pixbuf)
+clock_face_class_init (ClockFaceClass *class)
 {
-        g_hash_table_remove (pixbuf_cache, key);
+       GObjectClass   *object_class;
+       GtkWidgetClass *widget_class;
+
+       object_class = G_OBJECT_CLASS (class);
+       widget_class = GTK_WIDGET_CLASS (class);
+
+       object_class->finalize = clock_face_finalize;
+       object_class->set_property = clock_face_set_property;
+       object_class->get_property = clock_face_get_property;
+
+       widget_class->draw = clock_face_draw;
+       widget_class->size_allocate = clock_face_size_allocate;
+
+       object_properties[PROP_LOCATION] =
+               g_param_spec_object ("location",
+                                    "location",
+                                    "location",
+                                    CLOCK_TYPE_LOCATION,
+                                    G_PARAM_CONSTRUCT_ONLY |
+                                    G_PARAM_READWRITE);
+
+       object_properties[PROP_TIME] =
+               g_param_spec_object ("time",
+                                    "time",
+                                    "time",
+                                    CLOCK_TYPE_TIME,
+                                    G_PARAM_CONSTRUCT_ONLY |
+                                    G_PARAM_READWRITE);
+
+       object_properties[PROP_SHOW_SECONDS] =
+               g_param_spec_boolean ("show-seconds",
+                                     "show-seconds",
+                                     "show-seconds",
+                                     FALSE,
+                                     G_PARAM_READWRITE);
+
+       g_object_class_install_properties (object_class,
+                                          N_PROPERTIES,
+                                          object_properties);
 }
 
 static void
-clock_face_load_face (ClockFace *this, gint width, gint height)
+clock_face_init (ClockFace *face)
+{
+       face->priv = clock_face_get_instance_private (face);
+       face->priv->hour = -1;
+}
+
+GtkWidget *
+clock_face_new (ClockLocation *location,
+                ClockTime     *time,
+                gboolean       show_seconds)
 {
-        ClockFacePrivate *priv = this->priv;
-       const gchar *size_string[2] = { "small", "large" };
-        const gchar *daytime_string[4] = { "morning", "day", "evening", "night" };
-       gchar *cache_name;
-       gchar *name;
-
-        if (!pixbuf_cache)
-                pixbuf_cache = g_hash_table_new_full (g_str_hash, g_str_equal,
-                                                      g_free, NULL);
-
-        if (priv->face_pixbuf != NULL) {
-                /* This might empty the cache, but it's useless to destroy
-                 * it since this object is still alive and might add another
-                 * pixbuf in the cache later (eg, a few lines below) */
-                g_object_unref (priv->face_pixbuf);
-                priv->face_pixbuf = NULL;
-        }
-
-        /* Look for the pixbuf in the process-wide cache first */
-        cache_name = g_strdup_printf ("%d-%d-%d-%d",
-                                      priv->size, priv->timeofday,
-                                      width, height);
-
-        priv->face_pixbuf = g_hash_table_lookup (pixbuf_cache, cache_name);
-        if (priv->face_pixbuf) {
-                g_object_ref (priv->face_pixbuf);
-                return;
-        }
-
-        /* The pixbuf is not cached, let's load it */
-       name = g_strconcat (CLOCK_RESOURCE_PATH "icons/",
-                           "clock-face-", size_string[priv->size],
-                            "-", daytime_string[priv->timeofday], ".svg",
-                            NULL);
-       priv->face_pixbuf = clock_utils_pixbuf_from_svg_resource_at_size (name,
-                                                                         width, height);
-       g_free (name);
-
-       if (!priv->face_pixbuf) {
-               name = g_strconcat (CLOCK_RESOURCE_PATH "icons/",
-                                   "clock-face-", size_string[priv->size], ".svg",
-                                   NULL);
-               priv->face_pixbuf = clock_utils_pixbuf_from_svg_resource_at_size (name,
-                                                                                 width, height);
-                g_free (name);
-        }
-
-        /* Save the found pixbuf in the cache */
-        if (priv->face_pixbuf) {
-                g_hash_table_replace (pixbuf_cache,
-                                      cache_name, priv->face_pixbuf);
-                /* This will handle automatic removal from the cache when
-                 * the pixbuf isn't needed anymore */
-                g_object_weak_ref (G_OBJECT (priv->face_pixbuf),
-                                   (GWeakNotify) remove_pixbuf_from_cache,
-                                   cache_name);
-        } else
-                g_free (cache_name);
+       GObject *object;
+
+       object = g_object_new (CLOCK_TYPE_FACE,
+                              "location", location,
+                              "time", time,
+                              "show-seconds", show_seconds,
+                              NULL);
+
+       return GTK_WIDGET (object);
 }
diff --git a/applets/clock/clock-face.h b/applets/clock/clock-face.h
index cd620a6..3748e54 100644
--- a/applets/clock/clock-face.h
+++ b/applets/clock/clock-face.h
@@ -1,61 +1,68 @@
-/**
- * clock.h
+/*
+ * Copyright (C) 2014 Alberts Muktupāvels
  *
- * A GTK+ widget that implements a clock face
+ * 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.
  *
- * (c) 2007, Peter Teichman
- * (c) 2005-2006, Davyd Madeley
+ * 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:
- *   Davyd Madeley  <davyd madeley id au>
- *   Peter Teichman <peter novell com>
+ *    Alberts Muktupāvels <alberts muktupavels gmail com>
  */
 
-#ifndef __INTL_CLOCK_FACE_H__
-#define __INTL_CLOCK_FACE_H__
+#ifndef CLOCK_FACE_H
+#define CLOCK_FACE_H
 
 #include <gtk/gtk.h>
+
 #include "clock-location.h"
+#include "clock-time.h"
 
 G_BEGIN_DECLS
 
-#define INTL_TYPE_CLOCK_FACE          (clock_face_get_type ())
-#define CLOCK_FACE(obj)               (G_TYPE_CHECK_INSTANCE_CAST ((obj), INTL_TYPE_CLOCK_FACE, ClockFace))
-#define CLOCK_FACE_CLASS(obj)         (G_TYPE_CHECK_CLASS_CAST ((obj), INTL_CLOCK_FACE, ClockFaceClass))
-#define INTL_IS_CLOCK_FACE(obj)       (G_TYPE_CHECK_INSTANCE_TYPE ((obj), INTL_TYPE_CLOCK_FACE))
-#define INTL_IS_CLOCK_FACE_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE ((obj), INTL_TYPE_CLOCK_FACE))
-#define CLOCK_FACE_GET_CLASS          (G_TYPE_INSTANCE_GET_CLASS ((obj), INTL_TYPE_CLOCK_FACE, 
ClockFaceClass))
+#define CLOCK_TYPE_FACE         (clock_face_get_type ())
+#define CLOCK_FACE(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), \
+                                 CLOCK_TYPE_FACE,                 \
+                                 ClockFace))
+#define CLOCK_FACE_CLASS(c)     (G_TYPE_CHECK_CLASS_CAST ((c),    \
+                                 CLOCK_TYPE_FACE,                 \
+                                 ClockFaceClass))
+#define CLOCK_IS_FACE(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), \
+                                 CLOCK_TYPE_FACE))
+#define CLOCK_IS_FACE_CLASS(c)  (G_TYPE_CHECK_CLASS_TYPE ((c),    \
+                                 CLOCK_TYPE_FACE))
+#define CLOCK_FACE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS((o),   \
+                                 CLOCK_TYPE_FACE,                 \
+                                 ClockFaceClass))
 
-typedef struct _ClockFace           ClockFace;
-typedef struct _ClockFacePrivate    ClockFacePrivate;
-typedef struct _ClockFaceClass      ClockFaceClass;
+typedef struct _ClockFace        ClockFace;
+typedef struct _ClockFaceClass   ClockFaceClass;
+typedef struct _ClockFacePrivate ClockFacePrivate;
 
 struct _ClockFace
 {
-        GtkWidget parent;
-
-        /* < private > */
-        ClockFacePrivate *priv;
+       GtkImage          parent;
+       ClockFacePrivate *priv;
 };
 
 struct _ClockFaceClass
 {
-        GtkWidgetClass parent_class;
+       GtkImageClass parent_class;
 };
 
-typedef enum {
-        CLOCK_FACE_SMALL,
-        CLOCK_FACE_LARGE
-} ClockFaceSize;
-
-GType clock_face_get_type (void);
-
-GtkWidget *clock_face_new (ClockFaceSize size);
-GtkWidget *clock_face_new_with_location (ClockFaceSize size,
-                                        ClockLocation *loc,
-                                        GtkWidget *size_widget);
-gboolean clock_face_refresh (ClockFace *this);
+GType      clock_face_get_type (void);
 
+GtkWidget *clock_face_new      (ClockLocation *location,
+                                ClockTime     *time,
+                                gboolean       show_seconds);
 
 G_END_DECLS
 
diff --git a/applets/clock/clock-location-tile.c b/applets/clock/clock-location-tile.c
index e0a426c..fae4be3 100644
--- a/applets/clock/clock-location-tile.c
+++ b/applets/clock/clock-location-tile.c
@@ -11,6 +11,7 @@
 
 #include "clock.h"
 #include "clock-face.h"
+#include "clock-time.h"
 #include "clock-location-tile.h"
 #include "clock-location.h"
 #include "clock-utils.h"
@@ -33,7 +34,6 @@ typedef struct {
         GDateTime *last_refresh;
        long last_offset;
 
-        ClockFaceSize size;
 
        GtkWidget *box;
         GtkWidget *clock_face;
@@ -63,8 +63,7 @@ static gboolean weather_tooltip (GtkWidget *widget,
                                 gpointer    data);
 
 ClockLocationTile *
-clock_location_tile_new (ClockLocation *loc,
-                        ClockFaceSize size)
+clock_location_tile_new (ClockLocation *loc)
 {
         ClockLocationTile *this;
         ClockLocationTilePrivate *priv;
@@ -73,7 +72,6 @@ clock_location_tile_new (ClockLocation *loc,
         priv = PRIVATE (this);
 
         priv->location = g_object_ref (loc);
-        priv->size = size;
 
         clock_location_tile_fill (this);
 
@@ -125,7 +123,6 @@ clock_location_tile_init (ClockLocationTile *this)
        priv->last_refresh = NULL;
        priv->last_offset = 0;
 
-        priv->size = CLOCK_FACE_SMALL;
 
         priv->clock_face = NULL;
         priv->city_label = NULL;
@@ -340,8 +337,10 @@ clock_location_tile_fill (ClockLocationTile *this)
         g_signal_connect (priv->current_button, "clicked",
                           G_CALLBACK (make_current), this);
 
-        priv->clock_face = clock_face_new_with_location (
-                priv->size, priv->location, head_section);
+        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);
@@ -351,36 +350,6 @@ clock_location_tile_fill (ClockLocationTile *this)
 }
 
 static gboolean
-clock_needs_face_refresh (ClockLocationTile *this)
-{
-        ClockLocationTilePrivate *priv = PRIVATE (this);
-        GDateTime *now;
-       gboolean retval;
-
-       if (!priv->last_refresh)
-               return TRUE;
-
-        now = clock_location_localtime (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)) {
-               retval = TRUE;
-        }
-
-        if ((priv->size == CLOCK_FACE_LARGE)
-            && g_date_time_get_second (now) > g_date_time_get_second (priv->last_refresh)) {
-                retval = TRUE;
-        }
-
-       g_date_time_unref (now);
-       return retval;
-}
-
-static gboolean
 clock_needs_label_refresh (ClockLocationTile *this)
 {
         ClockLocationTilePrivate *priv = PRIVATE (this);
@@ -540,10 +509,6 @@ clock_location_tile_refresh (ClockLocationTile *this, gboolean force_refresh)
                }
        }
 
-        if (clock_needs_face_refresh (this)) {
-                clock_face_refresh (CLOCK_FACE (priv->clock_face));
-        }
-
         if (!force_refresh && !clock_needs_label_refresh (this)) {
                 return;
         }
diff --git a/applets/clock/clock-location-tile.h b/applets/clock/clock-location-tile.h
index c9c0497..8eae703 100644
--- a/applets/clock/clock-location-tile.h
+++ b/applets/clock/clock-location-tile.h
@@ -32,8 +32,7 @@ typedef struct
 
 GType clock_location_tile_get_type (void);
 
-ClockLocationTile *clock_location_tile_new (ClockLocation *loc,
-                                           ClockFaceSize size);
+ClockLocationTile *clock_location_tile_new (ClockLocation *loc);
 
 ClockLocation *clock_location_tile_get_location (ClockLocationTile *this);
 
diff --git a/applets/clock/clock.c b/applets/clock/clock.c
index 9ff21fe..747280c 100644
--- a/applets/clock/clock.c
+++ b/applets/clock/clock.c
@@ -689,7 +689,7 @@ create_cities_section (ClockData *cd)
         while (node) {
                 ClockLocation *loc = node->data;
 
-                city = clock_location_tile_new (loc, CLOCK_FACE_SMALL);
+                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",


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