ClutterBox2DJoint *
clutter_box2d_add_mouse_joint (ClutterBox2D        *box2d,
                               ClutterActor        *actor,
                               const ClutterVertex *target)
{
    ClutterBox2DPrivate *priv;
    b2MouseJointDef md;

    g_return_val_if_fail (CLUTTER_IS_BOX2D (box2d), NULL);
    g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL);
    g_return_val_if_fail (target != NULL, NULL);

    priv = box2d->priv;

    clutter_box2d_joint_ensure_body (box2d, actor);

    md.bodyA = priv->ground_body;
    md.bodyB = clutter_box2d_get_child (box2d, actor)->priv->body;

    if (!md.bodyB)
        return NULL;

    md.target = b2Vec2( (target->x) * priv->scale_factor,
                        (target->y) * priv->scale_factor);
    md.bodyA->SetAwake (false);
    md.maxForce = 5100.0f * md.bodyB->GetMass ();

    return joint_new (box2d, priv->world->CreateJoint(&md), CLUTTER_BOX2D_JOINT_MOUSE);
}
ClutterBox2DJoint *
clutter_box2d_add_weld_joint (ClutterBox2D        *box2d,
                              ClutterActor        *actor1,
                              ClutterActor        *actor2,
                              const ClutterVertex *anchor1,
                              const ClutterVertex *anchor2)
{
    ClutterBox2DPrivate *priv;
    b2WeldJointDef jd;

    g_return_val_if_fail (CLUTTER_IS_BOX2D (box2d), NULL);
    g_return_val_if_fail (CLUTTER_IS_ACTOR (actor1), NULL);
    g_return_val_if_fail (CLUTTER_IS_ACTOR (actor2), NULL);
    g_return_val_if_fail (anchor1 != NULL, NULL);
    g_return_val_if_fail (anchor2 != NULL, NULL);

    priv = box2d->priv;

    clutter_box2d_joint_ensure_bodies (box2d, actor1, actor2);

    jd.collideConnected = false;
    jd.bodyA = clutter_box2d_get_child (box2d, actor1)->priv->body;
    jd.bodyB = clutter_box2d_get_child (box2d, actor2)->priv->body;

    if (!jd.bodyA || !jd.bodyB)
        return NULL;

    jd.localAnchorA = b2Vec2 (anchor1->x * priv->scale_factor,
                              anchor1->y * priv->scale_factor);
    jd.localAnchorB = b2Vec2 (anchor2->x * priv->scale_factor,
                              anchor2->y * priv->scale_factor);
    jd.referenceAngle = jd.bodyB->GetAngle() - jd.bodyA->GetAngle();

    return joint_new (box2d, priv->world->CreateJoint (&jd), CLUTTER_BOX2D_JOINT_WELD);
}
ClutterBox2DJoint *
clutter_box2d_add_weld_joint2 (ClutterBox2D        *box2d,
                               ClutterActor        *actor1,
                               ClutterActor        *actor2,
                               const ClutterVertex *anchor)
{
    ClutterBox2DPrivate *priv;
    b2Body *bodyA, *bodyB;
    b2WeldJointDef jd;

    g_return_val_if_fail (CLUTTER_IS_BOX2D (box2d), NULL);
    g_return_val_if_fail (CLUTTER_IS_ACTOR (actor1), NULL);
    g_return_val_if_fail (CLUTTER_IS_ACTOR (actor2), NULL);
    g_return_val_if_fail (anchor != NULL, NULL);

    priv = box2d->priv;

    clutter_box2d_joint_ensure_bodies (box2d, actor1, actor2);

    jd.collideConnected = false;

    bodyA = clutter_box2d_get_child (box2d, actor1)->priv->body;
    bodyB = clutter_box2d_get_child (box2d, actor2)->priv->body;
    if (!bodyA || !bodyB)
        return NULL;

    jd.Initialize (bodyA, bodyB,
                   b2Vec2 (anchor->x * priv->scale_factor,
                           anchor->y * priv->scale_factor));

    return joint_new (box2d, priv->world->CreateJoint (&jd), CLUTTER_BOX2D_JOINT_WELD);
}
ClutterBox2DJoint *
clutter_box2d_add_pulley_joint (ClutterBox2D        *box2d,
                                ClutterActor        *actor1,
                                ClutterActor        *actor2,
                                const ClutterVertex *anchor1,
                                const ClutterVertex *anchor2,
                                const ClutterVertex *ground_anchor1,
                                const ClutterVertex *ground_anchor2,
                                gdouble              length1,
                                gdouble              length2,
                                gdouble              max_length1,
                                gdouble              max_length2,
                                gdouble              ratio)
{
    ClutterBox2DPrivate *priv;
    b2PulleyJointDef jd;

    g_return_val_if_fail (CLUTTER_IS_BOX2D (box2d), NULL);
    g_return_val_if_fail (CLUTTER_IS_ACTOR (actor1), NULL);
    g_return_val_if_fail (CLUTTER_IS_ACTOR (actor2), NULL);
    g_return_val_if_fail (anchor1 != NULL, NULL);
    g_return_val_if_fail (anchor2 != NULL, NULL);
    g_return_val_if_fail (ground_anchor1 != NULL, NULL);
    g_return_val_if_fail (ground_anchor2 != NULL, NULL);

    priv = box2d->priv;

    clutter_box2d_joint_ensure_bodies (box2d, actor1, actor2);

    jd.collideConnected = false;
    jd.bodyA = clutter_box2d_get_child (box2d, actor1)->priv->body;
    jd.bodyB = clutter_box2d_get_child (box2d, actor2)->priv->body;

    if (!jd.bodyA || !jd.bodyB)
        return NULL;

    jd.groundAnchorA = b2Vec2 (ground_anchor1->x * priv->scale_factor,
                               ground_anchor1->y * priv->scale_factor);
    jd.groundAnchorB = b2Vec2 (ground_anchor2->x * priv->scale_factor,
                               ground_anchor2->y * priv->scale_factor);
    jd.localAnchorA = b2Vec2 (anchor1->x * priv->scale_factor,
                              anchor1->y * priv->scale_factor);
    jd.localAnchorB = b2Vec2 (anchor2->x * priv->scale_factor,
                              anchor2->y * priv->scale_factor);
    jd.ratio = ratio;
    jd.lengthA = length1 * priv->scale_factor;
    jd.lengthB = length2 * priv->scale_factor;
    jd.maxLengthA = max_length1 * priv->scale_factor;
    jd.maxLengthB = max_length2 * priv->scale_factor;

    return joint_new (box2d, priv->world->CreateJoint (&jd), CLUTTER_BOX2D_JOINT_PULLEY);
}
ClutterBox2DJoint *
clutter_box2d_add_pulley_joint2 (ClutterBox2D        *box2d,
                                 ClutterActor        *actor1,
                                 ClutterActor        *actor2,
                                 const ClutterVertex *anchor1,
                                 const ClutterVertex *anchor2,
                                 const ClutterVertex *ground_anchor1,
                                 const ClutterVertex *ground_anchor2,
                                 gdouble              max_length1,
                                 gdouble              max_length2,
                                 gdouble              ratio)
{
    ClutterBox2DPrivate *priv;
    b2Body *bodyA, *bodyB;
    b2PulleyJointDef jd;

    g_return_val_if_fail (CLUTTER_IS_BOX2D (box2d), NULL);
    g_return_val_if_fail (CLUTTER_IS_ACTOR (actor1), NULL);
    g_return_val_if_fail (CLUTTER_IS_ACTOR (actor2), NULL);
    g_return_val_if_fail (anchor1 != NULL, NULL);
    g_return_val_if_fail (anchor2 != NULL, NULL);
    g_return_val_if_fail (ground_anchor1 != NULL, NULL);
    g_return_val_if_fail (ground_anchor2 != NULL, NULL);

    priv = box2d->priv;

    clutter_box2d_joint_ensure_bodies (box2d, actor1, actor2);

    jd.collideConnected = false;

    bodyA = clutter_box2d_get_child (box2d, actor1)->priv->body;
    bodyB = clutter_box2d_get_child (box2d, actor2)->priv->body;
    if (!bodyA || !bodyB)
        return NULL;

    jd.Initialize (bodyA, bodyB,
                   b2Vec2 (ground_anchor1->x * priv->scale_factor,
                           ground_anchor1->y * priv->scale_factor),
                   b2Vec2 (ground_anchor2->x * priv->scale_factor,
                           ground_anchor2->y * priv->scale_factor),
                   b2Vec2 (anchor1->x * priv->scale_factor,
                           anchor1->y * priv->scale_factor),
                   b2Vec2 (anchor2->x * priv->scale_factor,
                           anchor2->y * priv->scale_factor),
                   ratio);

    return joint_new (box2d, priv->world->CreateJoint (&jd), CLUTTER_BOX2D_JOINT_PULLEY);
}
ClutterBox2DJoint *
clutter_box2d_add_prismatic_joint (ClutterBox2D        *box2d,
                                   ClutterActor        *actor1,
                                   ClutterActor        *actor2,
                                   const ClutterVertex *anchor1,
                                   const ClutterVertex *anchor2,
                                   gdouble              min_length,
                                   gdouble              max_length,
                                   const ClutterVertex *axis)
{
    ClutterBox2DPrivate *priv;
    b2PrismaticJointDef jd;

    g_return_val_if_fail (CLUTTER_IS_BOX2D (box2d), NULL);
    g_return_val_if_fail (CLUTTER_IS_ACTOR (actor1), NULL);
    g_return_val_if_fail (CLUTTER_IS_ACTOR (actor2), NULL);
    g_return_val_if_fail (anchor1 != NULL, NULL);
    g_return_val_if_fail (anchor2 != NULL, NULL);
    g_return_val_if_fail (axis != NULL, NULL);

    priv = box2d->priv;

    clutter_box2d_joint_ensure_bodies (box2d, actor1, actor2);

    jd.collideConnected = false;
    jd.bodyA = clutter_box2d_get_child (box2d, actor1)->priv->body;
    jd.bodyB = clutter_box2d_get_child (box2d, actor2)->priv->body;

    if (!jd.bodyA || !jd.bodyB)
        return NULL;

    jd.localAnchorA = b2Vec2( (anchor1->x) * priv->scale_factor,
                              (anchor1->y) * priv->scale_factor);
    jd.localAnchorB = b2Vec2( (anchor2->x) * priv->scale_factor,
                              (anchor2->y) * priv->scale_factor);
    jd.lowerTranslation = min_length * priv->scale_factor;
    jd.upperTranslation = max_length * priv->scale_factor;
    jd.enableLimit = true;
    jd.localAxis1 = b2Vec2( (axis->x),
                            (axis->y));
    jd.referenceAngle = jd.bodyB->GetAngle() - jd.bodyA->GetAngle();

    return joint_new (box2d, priv->world->CreateJoint (&jd), CLUTTER_BOX2D_JOINT_PRISMATIC);
}
ClutterBox2DJoint *
clutter_box2d_add_line_joint2 (ClutterBox2D        *box2d,
                               ClutterActor        *actor1,
                               ClutterActor        *actor2,
                               const ClutterVertex *anchor,
                               gdouble              min_length,
                               gdouble              max_length,
                               const ClutterVertex *axis)
{
    ClutterBox2DPrivate *priv;
    b2Body *bodyA, *bodyB;
    b2LineJointDef jd;

    g_return_val_if_fail (CLUTTER_IS_BOX2D (box2d), NULL);
    g_return_val_if_fail (CLUTTER_IS_ACTOR (actor1), NULL);
    g_return_val_if_fail (CLUTTER_IS_ACTOR (actor2), NULL);
    g_return_val_if_fail (anchor != NULL, NULL);
    g_return_val_if_fail (axis != NULL, NULL);

    priv = box2d->priv;

    clutter_box2d_joint_ensure_bodies (box2d, actor1, actor2);

    jd.collideConnected = false;

    bodyA = clutter_box2d_get_child (box2d, actor1)->priv->body;
    bodyB = clutter_box2d_get_child (box2d, actor2)->priv->body;
    if (!bodyA || !bodyB)
        return NULL;

    jd.Initialize (bodyA, bodyB,
                   b2Vec2(anchor->x * priv->scale_factor,
                          anchor->y * priv->scale_factor),
                   b2Vec2(axis->x,
                          axis->y));
    jd.lowerTranslation = min_length * priv->scale_factor;
    jd.upperTranslation = max_length * priv->scale_factor;
    jd.enableLimit = true;

    return joint_new (box2d, priv->world->CreateJoint (&jd), CLUTTER_BOX2D_JOINT_LINE);
}
ClutterBox2DJoint *
clutter_box2d_add_distance_joint2 (ClutterBox2D        *box2d,
                                   ClutterActor        *actor1,
                                   ClutterActor        *actor2,
                                   const ClutterVertex *anchor1,
                                   const ClutterVertex *anchor2,
                                   gdouble              frequency,
                                   gdouble              damping_ratio)
{
    ClutterBox2DPrivate *priv;
    b2DistanceJointDef jd;
    b2Body *bodyA, *bodyB;

    g_return_val_if_fail (CLUTTER_IS_BOX2D (box2d), NULL);
    g_return_val_if_fail (CLUTTER_IS_ACTOR (actor1), NULL);
    g_return_val_if_fail (CLUTTER_IS_ACTOR (actor2), NULL);
    g_return_val_if_fail (anchor1 != NULL, NULL);
    g_return_val_if_fail (anchor2 != NULL, NULL);

    priv = box2d->priv;

    clutter_box2d_joint_ensure_bodies (box2d, actor1, actor2);

    jd.collideConnected = false;

    bodyA = clutter_box2d_get_child (box2d, actor1)->priv->body;
    bodyB = clutter_box2d_get_child (box2d, actor2)->priv->body;
    if (!bodyA || !bodyB)
        return NULL;

    jd.Initialize (bodyA, bodyB,
                   b2Vec2(anchor1->x * priv->scale_factor,
                          anchor1->y * priv->scale_factor),
                   b2Vec2(anchor2->x * priv->scale_factor,
                          anchor2->y * priv->scale_factor));
    jd.frequencyHz = frequency;
    jd.dampingRatio = damping_ratio;

    return joint_new (box2d, priv->world->CreateJoint (&jd), CLUTTER_BOX2D_JOINT_DISTANCE);
}
static gboolean
actor_manipulator_press (ClutterActor *stage,
                         ClutterEvent *event,
                         gpointer      data)
{
  ClutterActor *actor;

  actor = clutter_stage_get_actor_at_pos (CLUTTER_STAGE (stage),
                                          CLUTTER_PICK_ALL,
                                          event->button.x,
                                          event->button.y);


  if (actor == stage ||
      CLUTTER_IS_GROUP (actor))
    {
      if (event->button.button == 3)
        {
          popup_nuke (stage, event->button.x, event->button.y);
          popup_add ("+rectangle", "bar", G_CALLBACK (
                       action_add_rectangle), scene_get_group ());
          popup_add ("+circle", "bar", G_CALLBACK (
                       action_add_circle), scene_get_group ());
          popup_add ("+triangle", "bar", G_CALLBACK (
                       action_add_triangle), scene_get_group ());
          popup_add ("+text", "bar", G_CALLBACK (
                       action_add_text), scene_get_group ());
          popup_add ("+image", "bar", G_CALLBACK (
                       action_add_image), scene_get_group ());
#if 0
          popup_add ("+block-tree", "bar", G_CALLBACK (
                       action_add_block_tree), scene_get_group ());
#endif
          popup_add ("zero gravity", "bar", G_CALLBACK (
                       action_zero_gravity), scene_get_group ());
        }
      return TRUE;
    }

  if (actor == NULL)
    {
      return FALSE;
    }

  if (event->button.button == 3)
    {
      popup_nuke (stage, event->button.x, event->button.y);
      popup_add ("remove", "bar", G_CALLBACK (action_remove), actor);
      popup_add ("set linear velocity", "bar", G_CALLBACK (action_set_linear_velocity), actor);
      popup_add ("set dynamic", "bar", G_CALLBACK (action_set_dynamic), actor);
      popup_add ("set static", "bar", G_CALLBACK (action_set_static), actor);
      popup_add_slider ("opacity", "hm", 0.0, 255.0,
                        clutter_actor_get_opacity (actor) * 1.0,
                        G_CALLBACK (set_opacity), actor);

      popup_add_slider ("rotation", "hm", 0.0, 360.0,
                        clutter_actor_get_rotation (actor, CLUTTER_Z_AXIS, NULL,
                                                    NULL, NULL),
                        G_CALLBACK (set_rotation), actor);

      popup_add ("ok", "bar", NULL, NULL);
      return TRUE;
    }

  if (!should_be_manipulated (actor))
    return FALSE;

  manipulated_actor = actor;

  clutter_actor_get_position (actor, &orig_x, &orig_y);
  orig_rotation = clutter_actor_get_rotation (actor, CLUTTER_Z_AXIS, NULL,
                                               NULL,
                                               NULL);

  start_x =  (event->button.x);
  start_y =  (event->button.y);

  clutter_actor_transform_stage_point (
    clutter_actor_get_parent (manipulated_actor),
    start_x, start_y,
    &start_x, &start_y);


  mode = Direct;


#ifdef BOX2D_MANIPULATION
  /* Use Box2D manipulation if the actor is dynamic, and the physics
   * engine is running
   */
  if (CLUTTER_IS_BOX2D (scene_get_group ()) &&
      clutter_box2d_get_simulating (CLUTTER_BOX2D (scene_get_group ())))
    {
      ClutterBox2D *box2d  = CLUTTER_BOX2D (scene_get_group ());
      /*ClutterVertex target = { start_x, start_y };*/
      gint type;
      
      clutter_container_child_get (CLUTTER_CONTAINER (box2d),
                                   manipulated_actor, "mode", &type, NULL);
      	  
      if (type == CLUTTER_BOX2D_DYNAMIC)
        {
#if 0
            mouse_joint = clutter_box2d_add_mouse_joint (CLUTTER_BOX2D (
                                                           scene_get_group ()),
                                                         manipulated_actor,
                                                         &target);
#endif
            mode = None; /*Box2D;*/
            manipulated_actor = NULL;
            return FALSE;
        }
    }
#endif
  clutter_set_motion_events_enabled (FALSE);

  return TRUE;
}