/*
 * GtkSocket callbacks
 */
static gboolean
on_plug_removed (AwnAppletProxy *proxy, gpointer user_data)
{
  AwnAppletProxyPrivate *priv;

  g_return_val_if_fail (AWN_IS_APPLET_PROXY (proxy), FALSE);
  priv = proxy->priv;

  /* reset our old position */
  priv->old_x = 0;
  priv->old_y = 0;
  priv->old_w = 0;
  priv->old_h = 0;

  /* indicate that the applet crashed and allow restart */
  priv->running = FALSE;
  priv->crashed = TRUE;
  awn_icon_set_tooltip_text (AWN_ICON (priv->throbber),
    _("Whoops! The applet crashed. Click to restart it."));
  awn_throbber_set_type (AWN_THROBBER (priv->throbber),
                         AWN_THROBBER_TYPE_SAD_FACE);
  awn_icon_set_hover_effects (AWN_ICON (priv->throbber), TRUE);

  g_signal_emit (proxy, _proxy_signals[APPLET_CRASHED], 0);

  return TRUE;
}
/*
 * GOBJECT CODE 
 */
static void
awn_applet_proxy_get_property (GObject    *object,
                               guint       prop_id,
                               GValue     *value,
                               GParamSpec *pspec)
{
  AwnAppletProxyPrivate *priv;

  g_return_if_fail (AWN_IS_APPLET_PROXY (object));
  priv = AWN_APPLET_PROXY (object)->priv;

  switch (prop_id)
  {
    case PROP_PATH:
      g_value_set_string (value, priv->path);
      break;
    case PROP_UID:
      g_value_set_string (value, priv->uid);
      break;
    case PROP_POSITION:
      g_value_set_int (value, priv->position);
      break;
    case PROP_OFFSET:
      g_value_set_int (value, priv->offset);
      break;
    case PROP_SIZE:
      g_value_set_int (value, priv->size);
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
  }
}
GtkWidget*
awn_applet_proxy_get_throbber(AwnAppletProxy *proxy)
{
  g_return_val_if_fail(AWN_IS_APPLET_PROXY(proxy), NULL);

  return proxy->priv->throbber;
}
static void
awn_applet_proxy_set_property (GObject      *object,
                               guint         prop_id,
                               const GValue *value,
                               GParamSpec   *pspec)
{
  AwnAppletProxyPrivate *priv;

  g_return_if_fail (AWN_IS_APPLET_PROXY (object));
  priv = AWN_APPLET_PROXY (object)->priv;

  switch (prop_id)
  {
    case PROP_PATH:
      priv->path = g_value_dup_string (value);
      break;
    case PROP_UID:
      priv->uid = g_value_dup_string (value);
      break;
    case PROP_POSITION:
      priv->position = g_value_get_int (value);
      awn_icon_set_pos_type (AWN_ICON (priv->throbber), priv->position);
      break;
    case PROP_OFFSET:
      priv->offset = g_value_get_int (value);
      awn_icon_set_offset (AWN_ICON (priv->throbber), priv->offset);
      break;
    case PROP_SIZE:
      priv->size = g_value_get_int (value);
      awn_throbber_set_size (AWN_THROBBER (priv->throbber), priv->size);
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
  }
}
static gboolean
awn_applet_proxy_idle_cb (gpointer data)
{
  g_return_val_if_fail (AWN_IS_APPLET_PROXY (data), FALSE);
  AwnAppletProxyPrivate *priv = AWN_APPLET_PROXY_GET_PRIVATE (data);

  awn_applet_proxy_execute (AWN_APPLET_PROXY (data));

  priv->idle_id = 0;

  return FALSE;
}
/* FIXME: should we schedule the event or not?
static gboolean
schedule_send_client_event (gpointer data)
{
  GdkEvent *event = (GdkEvent*) data;

  gdk_event_send_client_message (event, GDK_WINDOW_XID (event->client.window));

  gdk_event_free (event);

  return FALSE;
}
*/
static void on_size_alloc (AwnAppletProxy *proxy, GtkAllocation *alloc)
{
  AwnAppletProxyPrivate *priv;
  GtkWidget *parent;
  GtkAllocation parent_alloc;
  GdkWindow *plug_win;

  g_return_if_fail (AWN_IS_APPLET_PROXY (proxy));

  priv = proxy->priv;

  parent = gtk_widget_get_parent (GTK_WIDGET (proxy));
  gtk_widget_get_allocation (parent, &parent_alloc);

  gint pos_x = alloc->x;
  gint pos_y = alloc->y;
  gint rel_x = pos_x - parent_alloc.x;
  gint rel_y = pos_y - parent_alloc.y;
  gint parent_w = parent_alloc.width;
  gint parent_h = parent_alloc.height;

  if (pos_x == priv->old_x && pos_y == priv->old_y
      && parent_w == priv->old_w && parent_h == priv->old_h) return;

  priv->old_x = pos_x;
  priv->old_y = pos_y;
  priv->old_w = parent_w;
  priv->old_h = parent_h;

  /* Only directly access the struct member if we have to. */
  plug_win = gtk_socket_get_plug_window (GTK_SOCKET (proxy));
  if (plug_win)
  {
    GdkAtom msg_type = gdk_atom_intern("_AWN_APPLET_POS_CHANGE", FALSE);
    GdkEvent *event = gdk_event_new (GDK_CLIENT_EVENT);
    event->client.window = g_object_ref (plug_win);
    event->client.data_format = 32;
    event->client.message_type = msg_type;
    // first two longs are our relative [x, y]
    event->client.data.l[0] = rel_x;
    event->client.data.l[1] = rel_y;
    // other two longs are our parent's [w, h]
    event->client.data.l[2] = parent_w;
    event->client.data.l[3] = parent_h;

    gdk_event_send_client_message (event, GDK_WINDOW_XID (plug_win));

    gdk_event_free (event);
    /* g_idle_add (schedule_send_client_event, event); */
  }
}
static GtkWidget*
_create_applet (AwnAppletManager *manager, const gchar *path, const gchar *uid)
{
	AwnAppletManagerPrivate *priv;
        GtkWidget *applet = NULL;
        	
	g_return_val_if_fail (AWN_IS_APPLET_MANAGER (manager), NULL);
	priv = AWN_APPLET_MANAGER_GET_PRIVATE (manager);   
	
	if (g_strstr_len (path, strlen (path), "taskman")) {
		applet = _load_taskmanager (manager);
	} else {
		applet = awn_applet_proxy_new (path, uid);
	}
        
        g_object_set (G_OBJECT (applet), 
                      "orient", AWN_ORIENTATION_BOTTOM,
                      "height", priv->settings->bar_height,
                      NULL);
                
        gtk_widget_set_size_request (applet, -1,
                                     priv->settings->bar_height *2);
        gtk_box_pack_start (GTK_BOX (manager), applet, 
                            FALSE, FALSE, 0);
        gtk_widget_show_all (GTK_WIDGET (applet));
                
        g_object_set_qdata (G_OBJECT (applet), 
                            touch_quark, GINT_TO_POINTER (0));
                
        g_hash_table_insert (priv->applets, 
                             g_strdup (uid),
                             applet);
	
	if (AWN_IS_APPLET_PROXY (applet))
		awn_applet_proxy_exec (AWN_APPLET_PROXY (applet));

               
        if (g_strstr_len (path, strlen (path), "separator")) {
	        awn_bar_add_separator (AWN_BAR (priv->settings->bar), applet);
	}
                
        return applet;
}
static void
on_child_exit (GPid pid, gint status, gpointer user_data)
{
  if (AWN_IS_APPLET_PROXY (user_data))
  {
    AwnAppletProxyPrivate *priv = AWN_APPLET_PROXY_GET_PRIVATE (user_data);

    /* FIXME: we could do something with the status var... nice error messages?! */
    /*
    switch (status)
    {
      case ???:
        awn_throbber_set_text (AWN_THROBBER (priv->throbber), _("..."));
        break;
      default:
        awn_throbber_set_text (AWN_THROBBER (priv->throbber), _("..."));
        break;
    }
    */

    priv->running = FALSE;
    priv->crashed = TRUE;

    awn_throbber_set_type (AWN_THROBBER (priv->throbber),
                           AWN_THROBBER_TYPE_SAD_FACE);
    awn_icon_set_tooltip_text (AWN_ICON (priv->throbber),
      _("Whoops! The applet crashed. Click to restart it."));
    awn_icon_set_hover_effects (AWN_ICON (priv->throbber), TRUE);

    g_signal_emit (user_data, _proxy_signals[APPLET_CRASHED], 0);
    /* we won't call gtk_widget_show - on_plug_removed does that
     * and if the plug wasn't even added, the throbber widget is still visible
     */
  }

  g_spawn_close_pid(pid); /* doesn't do anything on UNIX, but let's have it */
}
void
awn_applet_manager_load_applets (AwnAppletManager *manager)
{
	AwnAppletManagerPrivate *priv;
	GError *err = NULL;
	GSList *keys = NULL, *k;
	GConfClient *client = gconf_client_get_default ();
	
	g_return_if_fail (AWN_IS_APPLET_MANAGER (manager));
	priv = AWN_APPLET_MANAGER_GET_PRIVATE (manager);     
	
	priv->applets = g_hash_table_new (g_str_hash, g_str_equal);
	
	keys = gconf_client_get_list (client,
                                      AWN_APPLETS_KEY,
                                      GCONF_VALUE_STRING,
                                      &err); 

        if (keys == NULL || err) {
                keys = g_slist_append (keys, 
                                       LIBDIR"/awn/applets/taskman.desktop::1");
                gconf_client_set_list (client, AWN_APPLETS_KEY,
                                       GCONF_VALUE_STRING, keys, NULL);
                if (err)
                        g_print ("%s\n", err->message);
                return;        
        }
        
        for (k = keys; k != NULL; k = k->next) {
                GtkWidget *applet = NULL;
               
                gchar **tokens = NULL;
                tokens = g_strsplit (k->data, "::", 2);
                
                if (tokens == NULL) {
                        g_warning ("Bad key: %s", (gchar*)k->data);
                        continue;
                }
                
		if (g_strstr_len (tokens[0], strlen (tokens[0]), "taskman")) {
			applet = _load_taskmanager (manager);
		} else {
			applet = awn_applet_proxy_new (tokens[0], tokens[1]);
                	g_object_set (G_OBJECT (applet), 
                              	      "orient", AWN_ORIENTATION_BOTTOM,
                               	      "height", priv->settings->bar_height,
                                      NULL);
		}

                
                gtk_widget_set_size_request (applet, -1, 
                                             (priv->settings->bar_height)*2 +priv->settings->icon_offset);
                
                gtk_box_pack_start (GTK_BOX (manager), applet, 
                                    FALSE, FALSE, 0);
                gtk_widget_show_all (GTK_WIDGET (applet));
                
                g_object_set_qdata (G_OBJECT (applet), 
                                    touch_quark, GINT_TO_POINTER (0));
                
                g_hash_table_insert (priv->applets, 
                                     g_strdup (tokens[1]),
                                     applet);
                
		if (AWN_IS_APPLET_PROXY (applet))
			awn_applet_proxy_exec (AWN_APPLET_PROXY (applet));
                
                if (g_strstr_len (tokens[0], strlen (tokens[0]), "separator")) {
                        awn_bar_add_separator (AWN_BAR (priv->settings->bar), applet);
                }
                g_print ("APPLET : %s\n", tokens[0]);
                g_strfreev (tokens);
        }
}