/* diversity-object.c - DiversityObject, lovely resident in DiversityWorld * * Copyright 2007-2008 OpenMoko, Inc. * Authored by Chia-I Wu * * 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, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include #include "diversity-marshal.h" enum { PROPERTY_CHANGED, GEOMETRY_CHANGED, CONNECT, DISCONNECT, LAST_SIGNAL }; enum { PROP_0, PROP_ACCURACY, PROP_FLAGS, }; #define DIVERSITY_OBJECT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), DIVERSITY_TYPE_OBJECT, DiversityObjectPrivate)) typedef struct _DiversityObjectPrivate DiversityObjectPrivate; struct _DiversityObjectPrivate { DiversityRectangle rect; DiversityObjectAccuracy accuracy; time_t timestamp; guint flags; GSList *connections; }; static guint object_signals[LAST_SIGNAL] = { 0 }; G_DEFINE_TYPE(DiversityObject, diversity_object, G_TYPE_INITIALLY_UNOWNED); static void on_connection_finalized(gpointer data, GObject *target); static void diversity_object_finalize(GObject *g_obj) { DiversityObject *obj = DIVERSITY_OBJECT(g_obj); DiversityObjectPrivate *priv = DIVERSITY_OBJECT_GET_PRIVATE(obj); GSList *tmp_list; g_free(obj->id); tmp_list = priv->connections; while (tmp_list) { g_object_weak_unref(G_OBJECT(tmp_list->data), on_connection_finalized, obj); tmp_list = tmp_list->next; } g_slist_free(priv->connections); ((GObjectClass *) diversity_object_parent_class)->finalize(g_obj); } static void diversity_object_set_property(GObject *g_obj, guint prop_id, const GValue *value, GParamSpec *pspec) { DiversityObject *obj = DIVERSITY_OBJECT(g_obj); switch (prop_id) { case PROP_ACCURACY: diversity_object_set_accuracy(obj, g_value_get_int(value)); break; case PROP_FLAGS: diversity_object_set_flags(obj, g_value_get_uint(value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(g_obj, prop_id, pspec); break; } } static void diversity_object_get_property(GObject *g_obj, guint prop_id, GValue *value, GParamSpec *pspec) { DiversityObject *obj = DIVERSITY_OBJECT(g_obj); DiversityObjectPrivate *priv = DIVERSITY_OBJECT_GET_PRIVATE(obj); switch (prop_id) { case PROP_ACCURACY: g_value_set_int(value, priv->accuracy); break; case PROP_FLAGS: g_value_set_uint(value, priv->flags); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(g_obj, prop_id, pspec); break; } } inline static gchar *camelize(const gchar *name) { gchar *camel, *src, *dst; gboolean up = TRUE; camel = g_strdup(name); src = dst = camel; while (*src) { if (*src == '_' || *src == '-') { up = TRUE; src++; continue; } if (up) { *dst = g_ascii_toupper(*src); up = FALSE; } else { *dst = g_ascii_tolower(*src); } src++; dst++; } *dst = '\0'; return camel; } static void diversity_object_notify(GObject *g_obj, GParamSpec *pspec) { DiversityObject *obj = DIVERSITY_OBJECT(g_obj); GValue value = { 0 }; gchar *name; name = camelize(pspec->name); g_value_init(&value, pspec->value_type); g_object_get_property(g_obj, pspec->name, &value); g_signal_emit(obj, object_signals[PROPERTY_CHANGED], 0, name, &value); g_value_unset(&value); g_free(name); } static void diversity_object_class_init(DiversityObjectClass *klass) { GObjectClass *o_class = (GObjectClass *) klass; o_class->finalize = diversity_object_finalize; o_class->set_property = diversity_object_set_property; o_class->get_property = diversity_object_get_property; o_class->notify = diversity_object_notify; g_type_class_add_private(klass, sizeof(DiversityObjectPrivate)); klass->serial_number = 0; g_object_class_install_property(o_class, PROP_ACCURACY, g_param_spec_int("accuracy", "Accuracy", "Geometry accuracy", DIVERSITY_OBJECT_ACCURACY_NONE, DIVERSITY_OBJECT_ACCURACY_EXACT, DIVERSITY_OBJECT_ACCURACY_NONE, G_PARAM_READWRITE)); g_object_class_install_property(o_class, PROP_FLAGS, g_param_spec_uint("flags", "Flags", "Flags", 0, G_MAXUINT32, 0, G_PARAM_READWRITE)); object_signals[PROPERTY_CHANGED] = g_signal_new("property-changed", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET(DiversityObjectClass, property_changed), NULL, NULL, _diversity_marshal_VOID__STRING_BOXED, G_TYPE_NONE, 2, G_TYPE_STRING | G_SIGNAL_TYPE_STATIC_SCOPE, G_TYPE_VALUE | G_SIGNAL_TYPE_STATIC_SCOPE); object_signals[GEOMETRY_CHANGED] = g_signal_new("geometry-changed", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET(DiversityObjectClass, geometry_changed), NULL, NULL, _diversity_marshal_VOID__DOUBLE_DOUBLE_DOUBLE_DOUBLE, G_TYPE_NONE, 4, G_TYPE_DOUBLE, G_TYPE_DOUBLE, G_TYPE_DOUBLE, G_TYPE_DOUBLE); object_signals[CONNECT] = g_signal_new("connect", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET(DiversityObjectClass, connect), NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, G_TYPE_OBJECT); object_signals[DISCONNECT] = g_signal_new("disconnect", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET(DiversityObjectClass, disconnect), NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, G_TYPE_OBJECT); } static void diversity_object_init(DiversityObject *obj) { DiversityObjectClass *klass = DIVERSITY_OBJECT_GET_CLASS(obj); DiversityObjectPrivate *priv = DIVERSITY_OBJECT_GET_PRIVATE(obj); obj->serial_number = klass->serial_number++; obj->type = DIVERSITY_OBJECT_TYPE_OBJECT; obj->ubiquitous = FALSE; priv->rect.x = priv->rect.y = 0.0; priv->rect.width = priv->rect.height = 0.0; priv->accuracy = DIVERSITY_OBJECT_ACCURACY_NONE; priv->timestamp = 0; priv->flags = 0; priv->connections = NULL; } DiversityObject *diversity_object_new(const char *id) { DiversityObject *obj; obj = g_object_new(DIVERSITY_TYPE_OBJECT, NULL); obj->id = g_strdup(id); return obj; } void diversity_object_geometry_set(DiversityObject *obj, gdouble lon, gdouble lat, gdouble width, gdouble height) { DiversityObjectPrivate *priv = DIVERSITY_OBJECT_GET_PRIVATE(obj); if (width < 0.0) width = 0.0; if (height < 0.0) height = 0.0; if (lon < -180.0 || lon + width > 180.0 || lat < -90.0 || lat + height > 90.0) lon = lat = width = height = 0.0; if (lon == -180.0 && lat == -90.0 && width == 360.0 && height == 180.0) obj->ubiquitous = TRUE; priv->rect.x = lon; priv->rect.y = lat; priv->rect.width = width; priv->rect.height = height; g_signal_emit(obj, object_signals[GEOMETRY_CHANGED], 0, lon, lat, width, height); } void diversity_object_geometry_get(DiversityObject *obj, gdouble *lon, gdouble *lat, gdouble *width, gdouble *height) { DiversityObjectPrivate *priv = DIVERSITY_OBJECT_GET_PRIVATE(obj); if (lon) *lon = priv->rect.x; if (lat) *lat = priv->rect.y; if (width) *width = priv->rect.width; if (height) *height = priv->rect.height; } void diversity_object_set_flags(DiversityObject *obj, guint flags) { DiversityObjectPrivate *priv = DIVERSITY_OBJECT_GET_PRIVATE(obj); priv->flags = flags; g_object_notify(G_OBJECT(obj), "flags"); } guint diversity_object_get_flags(DiversityObject *obj) { DiversityObjectPrivate *priv = DIVERSITY_OBJECT_GET_PRIVATE(obj); return priv->flags; } inline static void set_flags(DiversityObject *obj, gint val, gboolean set) { DiversityObjectPrivate *priv = DIVERSITY_OBJECT_GET_PRIVATE(obj); guint flags = priv->flags; if (set) flags |= val; else flags &= ~val; diversity_object_set_flags(obj, flags); } void diversity_object_set_accuracy(DiversityObject *obj, DiversityObjectAccuracy accuracy) { DiversityObjectPrivate *priv = DIVERSITY_OBJECT_GET_PRIVATE(obj); priv->accuracy = accuracy; g_object_notify(G_OBJECT(obj), "accuracy"); } DiversityObjectAccuracy diversity_object_get_accuracy(DiversityObject *obj) { DiversityObjectPrivate *priv = DIVERSITY_OBJECT_GET_PRIVATE(obj); return priv->accuracy; } void diversity_object_set_persistent(DiversityObject *obj, gboolean persist) { set_flags(obj, DIVERSITY_OBJECT_FLAG_PERSISTENT, persist); } gboolean diversity_object_get_persistent(DiversityObject *obj) { DiversityObjectPrivate *priv = DIVERSITY_OBJECT_GET_PRIVATE(obj); return (priv->flags & DIVERSITY_OBJECT_FLAG_PERSISTENT); } void diversity_object_set_public(DiversityObject *obj, gboolean pub) { set_flags(obj, DIVERSITY_OBJECT_FLAG_PUBLIC, pub); } gboolean diversity_object_get_public(DiversityObject *obj) { DiversityObjectPrivate *priv = DIVERSITY_OBJECT_GET_PRIVATE(obj); return (priv->flags & DIVERSITY_OBJECT_FLAG_PUBLIC); } void diversity_object_set_pushed(DiversityObject *obj, gboolean pushed) { set_flags(obj, DIVERSITY_OBJECT_FLAG_PUSHED, pushed); } gboolean diversity_object_get_pushed(DiversityObject *obj) { DiversityObjectPrivate *priv = DIVERSITY_OBJECT_GET_PRIVATE(obj); return (priv->flags & DIVERSITY_OBJECT_FLAG_PUSHED); } void diversity_object_touch(DiversityObject *obj) { DiversityObjectPrivate *priv = DIVERSITY_OBJECT_GET_PRIVATE(obj); priv->timestamp = time(NULL); } GTime diversity_object_get_timestamp(DiversityObject *obj) { DiversityObjectPrivate *priv = DIVERSITY_OBJECT_GET_PRIVATE(obj); return (GTime) priv->timestamp; } static void on_connection_finalized(gpointer data, GObject *target) { DiversityObjectPrivate *priv = DIVERSITY_OBJECT_GET_PRIVATE(data); priv->connections = g_slist_remove(priv->connections, target); } void diversity_object_connect(DiversityObject *obj, DiversityObject *target) { DiversityObjectPrivate *priv = DIVERSITY_OBJECT_GET_PRIVATE(obj); GSList *tmp_list; if (G_UNLIKELY(obj == target)) return; tmp_list = priv->connections; while (tmp_list) { if (tmp_list->data == target) return; tmp_list = tmp_list->next; } g_object_weak_ref(G_OBJECT(target), on_connection_finalized, obj); priv->connections = g_slist_prepend(priv->connections, target); g_signal_emit(obj, object_signals[CONNECT], 0, target); } void diversity_object_disconnect(DiversityObject *obj, DiversityObject *target) { DiversityObjectPrivate *priv = DIVERSITY_OBJECT_GET_PRIVATE(obj); GSList *tmp_list; tmp_list = priv->connections; while (tmp_list) { if (tmp_list->data == target) break; tmp_list = tmp_list->next; } if (!tmp_list) return; priv->connections = g_slist_delete_link(priv->connections, tmp_list); g_object_weak_unref(G_OBJECT(target), on_connection_finalized, obj); g_signal_emit(obj, object_signals[DISCONNECT], 0, target); } const GSList *diversity_object_get_connections(DiversityObject *obj) { DiversityObjectPrivate *priv = DIVERSITY_OBJECT_GET_PRIVATE(obj); return priv->connections; } gboolean diversity_object_contain(DiversityObject *obj1, DiversityObject *obj2) { DiversityObjectPrivate *priv1 = DIVERSITY_OBJECT_GET_PRIVATE(obj1); DiversityObjectPrivate *priv2 = DIVERSITY_OBJECT_GET_PRIVATE(obj2); return DIVERSITY_RECTANGLE_CONTAIN(&priv1->rect, &priv2->rect); } gboolean diversity_object_intersect(DiversityObject *obj1, DiversityObject *obj2) { DiversityObjectPrivate *priv1 = DIVERSITY_OBJECT_GET_PRIVATE(obj1); DiversityObjectPrivate *priv2 = DIVERSITY_OBJECT_GET_PRIVATE(obj2); return DIVERSITY_RECTANGLE_INTERSECT(&priv1->rect, &priv2->rect); }