/* diversity-world.c - 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 #include "diversity-marshal.h" #include "world-tree.h" enum { STATE_CHANGED, OBJECT_ADDED, OBJECT_REMOVED, VIEWPORT_ADDED, VIEWPORT_REMOVED, TUNNELED_CHANGED, LAST_SIGNAL }; enum { PROP_0, PROP_TUNNEL, }; #define DIVERSITY_WORLD_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), DIVERSITY_TYPE_WORLD, DiversityWorldPrivate)) typedef struct _DiversityWorldPrivate DiversityWorldPrivate; struct _DiversityWorldPrivate { DiversityBard *self; DiversityNetwork *network; gchar *tunnel; gboolean tunneled; WorldTree *tree; GHashTable *tables[NUM_DIVERSITY_OBJECT_TYPES]; }; static guint world_signals[LAST_SIGNAL] = { 0 }; G_DEFINE_TYPE(DiversityWorld, diversity_world, G_TYPE_OBJECT); static void diversity_world_dispose(GObject *obj) { DiversityWorld *world = (DiversityWorld *) obj; DiversityWorldPrivate *priv = DIVERSITY_WORLD_GET_PRIVATE(world); g_object_unref(priv->self); world_tree_free(priv->tree); priv->tree = NULL; ((GObjectClass *) diversity_world_parent_class)->dispose(obj); } static void diversity_world_finalize(GObject *obj) { DiversityWorldPrivate *priv = DIVERSITY_WORLD_GET_PRIVATE(obj); gint i; for (i = 0; i < NUM_DIVERSITY_OBJECT_TYPES; i++) if (priv->tables[i]) g_hash_table_destroy(priv->tables[i]); g_free(priv->network); ((GObjectClass *) diversity_world_parent_class)->finalize(obj); } static void diversity_world_set_property(GObject *obj, guint prop_id, const GValue *value, GParamSpec *pspec) { DiversityWorld *world = DIVERSITY_WORLD(obj); switch (prop_id) { case PROP_TUNNEL: diversity_world_set_tunnel(world, g_value_get_string(value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, prop_id, pspec); break; } } static void diversity_world_get_property(GObject *obj, guint prop_id, GValue *value, GParamSpec *pspec) { DiversityWorld *world = DIVERSITY_WORLD(obj); DiversityWorldPrivate *priv = DIVERSITY_WORLD_GET_PRIVATE(world); switch (prop_id) { case PROP_TUNNEL: g_value_set_string(value, priv->tunnel); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, prop_id, pspec); break; } } static void diversity_world_class_init(DiversityWorldClass *klass) { GObjectClass *o_class = (GObjectClass *) klass; o_class->set_property = diversity_world_set_property; o_class->get_property = diversity_world_get_property; o_class->dispose = diversity_world_dispose; o_class->finalize = diversity_world_finalize; g_type_class_add_private(klass, sizeof(DiversityWorldPrivate)); g_object_class_install_property(o_class, PROP_TUNNEL, g_param_spec_string("tunnel", "Tunnel", "Tunnel to the server", "", G_PARAM_READWRITE)); world_signals[STATE_CHANGED] = g_signal_new("state-changed", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET(DiversityWorldClass, state_changed), NULL, NULL, g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT); world_signals[OBJECT_ADDED] = g_signal_new("object-added", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET(DiversityWorldClass, object_added), NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, G_TYPE_OBJECT); world_signals[OBJECT_REMOVED] = g_signal_new("object-removed", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET(DiversityWorldClass, object_removed), NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, G_TYPE_OBJECT); world_signals[VIEWPORT_ADDED] = g_signal_new("viewport-added", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET(DiversityWorldClass, viewport_added), NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, G_TYPE_OBJECT); world_signals[VIEWPORT_REMOVED] = g_signal_new("viewport-removed", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET(DiversityWorldClass, viewport_removed), NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, G_TYPE_OBJECT); world_signals[TUNNELED_CHANGED] = g_signal_new("tunneled-changed", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET(DiversityWorldClass, tunneled_changed), NULL, NULL, g_cclosure_marshal_VOID__BOOLEAN, G_TYPE_NONE, 1, G_TYPE_BOOLEAN); } static void diversity_world_init(DiversityWorld *world) { DiversityWorldPrivate *priv = DIVERSITY_WORLD_GET_PRIVATE(world); gint i; priv->self = diversity_bard_new(); priv->tree = world_tree_new(20, 16); priv->network = g_malloc0(sizeof(DiversityNetwork)); for (i = 0; i < NUM_DIVERSITY_OBJECT_TYPES; i++) priv->tables[i] = NULL; priv->tunnel = NULL; priv->tunneled = FALSE; } void diversity_world_add_object(DiversityWorld *world, DiversityObject *obj) { DiversityWorldPrivate *priv = DIVERSITY_WORLD_GET_PRIVATE(world); if (!world_tree_add(priv->tree, obj)) return; if (obj->id) { if (!priv->tables[obj->type]) priv->tables[obj->type] = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL); g_hash_table_insert(priv->tables[obj->type], g_strdup(obj->id), obj); } g_signal_emit(world, world_signals[OBJECT_ADDED], 0, obj); } void diversity_world_remove_object(DiversityWorld *world, DiversityObject *obj) { DiversityWorldPrivate *priv = DIVERSITY_WORLD_GET_PRIVATE(world); if (!world_tree_remove(priv->tree, obj)) return; if (obj->id) g_hash_table_remove(priv->tables[obj->type], obj->id); g_signal_emit(world, world_signals[OBJECT_REMOVED], 0, obj); } DiversityObject *diversity_world_lookup_object(DiversityWorld *world, DiversityObjectType type, const gchar *id) { DiversityWorldPrivate *priv = DIVERSITY_WORLD_GET_PRIVATE(world); DiversityObject *obj = NULL; if (priv->tables[type]) obj = g_hash_table_lookup(priv->tables[type], id); return obj; } void diversity_world_add_viewport(DiversityWorld *world, DiversityViewport *view) { DiversityWorldPrivate *priv = DIVERSITY_WORLD_GET_PRIVATE(world); if (world_tree_add_viewport(priv->tree, view)) g_signal_emit(world, world_signals[VIEWPORT_ADDED], 0, view); } void diversity_world_remove_viewport(DiversityWorld *world, DiversityViewport *view) { DiversityWorldPrivate *priv = DIVERSITY_WORLD_GET_PRIVATE(world); if (world_tree_remove_viewport(priv->tree, view)) g_signal_emit(world, world_signals[VIEWPORT_REMOVED], 0, view); } DiversityBard *diversity_world_get_self(DiversityWorld *world) { DiversityWorldPrivate *priv = DIVERSITY_WORLD_GET_PRIVATE(world); return priv->self; } void diversity_world_get_position(DiversityWorld *world, gdouble *lon, gdouble *lat) { DiversityWorldPrivate *priv = DIVERSITY_WORLD_GET_PRIVATE(world); diversity_object_geometry_get(DIVERSITY_OBJECT(priv->self), lon, lat, NULL, NULL); } void diversity_world_set_tunnel(DiversityWorld *world, const gchar *tunnel) { DiversityWorldPrivate *priv = DIVERSITY_WORLD_GET_PRIVATE(world); if (priv->tunnel != tunnel) { g_free(priv->tunnel); priv->tunnel = g_strdup(tunnel); g_object_notify(G_OBJECT(world), "tunnel"); diversity_world_set_tunneled(world, FALSE); } } const gchar *diversity_world_get_tunnel(DiversityWorld *world) { DiversityWorldPrivate *priv = DIVERSITY_WORLD_GET_PRIVATE(world); return priv->tunnel; } void diversity_world_set_tunneled(DiversityWorld *world, gboolean tunneled) { DiversityWorldPrivate *priv = DIVERSITY_WORLD_GET_PRIVATE(world); if (priv->tunneled != tunneled) { priv->tunneled = tunneled; g_signal_emit(world, world_signals[TUNNELED_CHANGED], 0, priv->tunneled); } } gboolean diversity_world_get_tunneled(DiversityWorld *world) { DiversityWorldPrivate *priv = DIVERSITY_WORLD_GET_PRIVATE(world); return priv->tunneled; } void diversity_world_connect_ap(DiversityWorld *world, DiversityAp *ap) { DiversityWorldPrivate *priv = DIVERSITY_WORLD_GET_PRIVATE(world); DiversityNetwork *network = priv->network; if (network->connect_ap) network->connect_ap(network, ap); } void diversity_world_connect_wired(DiversityWorld *world) { DiversityWorldPrivate *priv = DIVERSITY_WORLD_GET_PRIVATE(world); DiversityNetwork *network = priv->network; if (network->connect_wired) network->connect_wired(network); } void diversity_world_sleep(DiversityWorld *world, gboolean sleep) { DiversityWorldPrivate *priv = DIVERSITY_WORLD_GET_PRIVATE(world); DiversityNetwork *network = priv->network; if (network->sleep) network->sleep(network, sleep); } const DiversityNetwork *diversity_world_network_get(DiversityWorld *world) { DiversityWorldPrivate *priv = DIVERSITY_WORLD_GET_PRIVATE(world); return priv->network; } void diversity_world_network_set_capabilities(DiversityWorld *world, gboolean has_wired, gboolean has_wireless) { DiversityWorldPrivate *priv = DIVERSITY_WORLD_GET_PRIVATE(world); priv->network->has_wired = has_wired; priv->network->has_wireless = has_wireless; } void diversity_world_network_set_state(DiversityWorld *world, DiversityNetworkState state) { DiversityWorldPrivate *priv = DIVERSITY_WORLD_GET_PRIVATE(world); if (priv->network->state != state) { priv->network->state = state; g_signal_emit(world, world_signals[STATE_CHANGED], 0, state); } } void diversity_world_network_set_detail(DiversityWorld *world, DiversityNetworkDetail detail) { DiversityWorldPrivate *priv = DIVERSITY_WORLD_GET_PRIVATE(world); priv->network->detail = detail; } void diversity_world_network_set_ap(DiversityWorld *world, DiversityAp *ap) { DiversityWorldPrivate *priv = DIVERSITY_WORLD_GET_PRIVATE(world); priv->network->ap = ap; } void diversity_world_network_set_interface(DiversityWorld *world, gpointer connect_ap, gpointer connect_wired, gpointer sleep, gpointer data) { DiversityWorldPrivate *priv = DIVERSITY_WORLD_GET_PRIVATE(world); priv->network->connect_ap = connect_ap; priv->network->connect_wired = connect_wired; priv->network->sleep = sleep; priv->network->data = data; }