Esempio n. 1
0
static void
mex_column_pick (ClutterActor *actor, const ClutterColor *color)
{
  GList *c;
  gdouble value;
  MxPadding padding;
  ClutterActorBox box;

  MexColumn *self = MEX_COLUMN (actor);
  MexColumnPrivate *priv = self->priv;

  CLUTTER_ACTOR_CLASS (mex_column_parent_class)->pick (actor, color);

  /* Don't pick children when we don't have focus */
  if (!priv->has_focus)
    return;

  mx_widget_get_padding (MX_WIDGET (actor), &padding);
  clutter_actor_get_allocation_box (actor, &box);
  if (priv->adjustment)
    value = priv->adjustment_value;
  else
    value = 0;

  cogl_clip_push_rectangle (padding.left,
                            padding.top + value,
                            box.x2 - box.x1 - padding.right,
                            box.y2 - box.y1 - padding.bottom + value);

  for (c = priv->children; c; c = c->next)
    clutter_actor_paint (c->data);

  cogl_clip_pop ();
}
static void
mx_stack_paint_children (ClutterActor *actor)
{
  MxStackPrivate *priv = MX_STACK (actor)->priv;

  GList *c;

  for (c = priv->children; c; c = c->next)
    {
      ClutterActor *child = c->data;
      gboolean crop;

      if (!CLUTTER_ACTOR_IS_VISIBLE (child))
        continue;

      clutter_container_child_get (CLUTTER_CONTAINER (actor),
                                   child,
                                   "crop", &crop,
                                   NULL);

      if (crop)
        {
          /* clip */
          cogl_clip_push_rectangle (priv->allocation.x1,
                                    priv->allocation.y1,
                                    priv->allocation.x2,
                                    priv->allocation.y2);
          clutter_actor_paint (c->data);
          cogl_clip_pop ();
        }
      else
        clutter_actor_paint (c->data);
    }
}
Esempio n. 3
0
static void
mex_content_box_paint (ClutterActor *actor)
{
  MexContentBoxPrivate *priv = MEX_CONTENT_BOX (actor)->priv;
  gboolean clipped = FALSE;

  CLUTTER_ACTOR_CLASS (mex_content_box_parent_class)->paint (actor);

  if (G_UNLIKELY (priv->clip_to_allocation))
    {
      ClutterActorBox box;
      clutter_actor_get_allocation_box (actor, &box);
      cogl_clip_push_rectangle (0, 0, box.x2 - box.x1, box.y2 - box.y1);
      clipped = TRUE;
    }

  clutter_actor_paint (priv->tile);

  if (G_UNLIKELY (priv->extras_visible))
    {
      ClutterActorBox box;

      clutter_actor_paint (priv->action_list);
      clutter_actor_paint (priv->info_panel);

      /* separator */
      cogl_set_source_color4ub (255, 255, 255, 51);
      clutter_actor_get_allocation_box (priv->info_panel, &box);
      cogl_path_line (box.x1, box.y1, box.x2, box.y1);
      cogl_path_stroke ();
    }

  if (G_UNLIKELY (clipped))
    cogl_clip_pop ();
}
Esempio n. 4
0
static void
mex_column_paint (ClutterActor *actor)
{
  GList *c;
  MxPadding padding;
  ClutterActorBox box;

  MexColumn *self = MEX_COLUMN (actor);
  MexColumnPrivate *priv = self->priv;

  CLUTTER_ACTOR_CLASS (mex_column_parent_class)->paint (actor);

  mx_widget_get_padding (MX_WIDGET (actor), &padding);
  clutter_actor_get_allocation_box (actor, &box);

  cogl_clip_push_rectangle (padding.left,
                            padding.top + priv->adjustment_value,
                            box.x2 - box.x1 - padding.right,
                            box.y2 - box.y1 - padding.bottom +
                            priv->adjustment_value);

  for (c = priv->children; c; c = c->next)
    {
      /* skip the current focus and paint it last*/
      if (priv->current_focus != c->data)
        clutter_actor_paint (c->data);
    }

  /* paint the current focused actor last to ensure any shadow is drawn
   * on top of other items */
  if (priv->current_focus)
    clutter_actor_paint (priv->current_focus);

  cogl_clip_pop ();
}
Esempio n. 5
0
static void
st_box_layout_paint (ClutterActor *actor)
{
  StBoxLayout *self = ST_BOX_LAYOUT (actor);
  StBoxLayoutPrivate *priv = self->priv;
  StThemeNode *theme_node = st_widget_get_theme_node (ST_WIDGET (actor));
  GList *l, *children;
  gdouble x, y;
  ClutterActorBox allocation_box;
  ClutterActorBox content_box;

  get_border_paint_offsets (self, &x, &y);
  if (x != 0 || y != 0)
    {
      cogl_push_matrix ();
      cogl_translate ((int)x, (int)y, 0);
    }

  CLUTTER_ACTOR_CLASS (st_box_layout_parent_class)->paint (actor);

  if (x != 0 || y != 0)
    {
      cogl_pop_matrix ();
    }

  children = st_container_get_children_list (ST_CONTAINER (actor));

  if (children == NULL)
    return;

  clutter_actor_get_allocation_box (actor, &allocation_box);
  st_theme_node_get_content_box (theme_node, &allocation_box, &content_box);

  content_box.x1 += x;
  content_box.y1 += y;
  content_box.x2 += x;
  content_box.y2 += y;

  /* The content area forms the viewport into the scrolled contents, while
   * the borders and background stay in place; after drawing the borders and
   * background, we clip to the content area */
  if (priv->hadjustment || priv->vadjustment)
    cogl_clip_push_rectangle ((int)content_box.x1,
                              (int)content_box.y1,
                              (int)content_box.x2,
                              (int)content_box.y2);

  for (l = children; l; l = g_list_next (l))
    {
      ClutterActor *child = (ClutterActor*) l->data;

      if (CLUTTER_ACTOR_IS_VISIBLE (child))
        clutter_actor_paint (child);
    }

  if (priv->hadjustment || priv->vadjustment)
    cogl_clip_pop ();
}
Esempio n. 6
0
/* XXX: Deprecated API */
void
cogl_clip_push (float x_offset,
                float y_offset,
                float width,
                float height)
{
  cogl_clip_push_rectangle (x_offset,
                            y_offset,
                            x_offset + width,
                            y_offset + height);
}
Esempio n. 7
0
static void
st_box_layout_paint (ClutterActor *actor)
{
  StBoxLayout *self = ST_BOX_LAYOUT (actor);
  StBoxLayoutPrivate *priv = self->priv;
  StThemeNode *theme_node = st_widget_get_theme_node (ST_WIDGET (actor));
  gdouble x, y;
  ClutterActorBox allocation_box;
  ClutterActorBox content_box;
  ClutterActor *child;

  get_border_paint_offsets (self, &x, &y);
  if (x != 0 || y != 0)
    {
      cogl_push_matrix ();
      cogl_translate ((int)x, (int)y, 0);
    }

  st_widget_paint_background (ST_WIDGET (actor));

  if (x != 0 || y != 0)
    {
      cogl_pop_matrix ();
    }

  if (clutter_actor_get_n_children (actor) == 0)
    return;

  clutter_actor_get_allocation_box (actor, &allocation_box);
  st_theme_node_get_content_box (theme_node, &allocation_box, &content_box);

  content_box.x1 += x;
  content_box.y1 += y;
  content_box.x2 += x;
  content_box.y2 += y;

  /* The content area forms the viewport into the scrolled contents, while
   * the borders and background stay in place; after drawing the borders and
   * background, we clip to the content area */
  if (priv->hadjustment || priv->vadjustment)
    cogl_clip_push_rectangle ((int)content_box.x1,
                              (int)content_box.y1,
                              (int)content_box.x2,
                              (int)content_box.y2);

  for (child = clutter_actor_get_first_child (actor);
       child != NULL;
       child = clutter_actor_get_next_sibling (child))
    clutter_actor_paint (child);

  if (priv->hadjustment || priv->vadjustment)
    cogl_clip_pop ();
}
Esempio n. 8
0
static void
st_box_layout_pick (ClutterActor       *actor,
                    const ClutterColor *color)
{
  StBoxLayout *self = ST_BOX_LAYOUT (actor);
  StBoxLayoutPrivate *priv = self->priv;
  StThemeNode *theme_node = st_widget_get_theme_node (ST_WIDGET (actor));
  gdouble x, y;
  ClutterActorBox allocation_box;
  ClutterActorBox content_box;
  ClutterActor *child;

  get_border_paint_offsets (self, &x, &y);
  if (x != 0 || y != 0)
    {
      cogl_push_matrix ();
      cogl_translate ((int)x, (int)y, 0);
    }

  CLUTTER_ACTOR_CLASS (st_box_layout_parent_class)->pick (actor, color);

  if (x != 0 || y != 0)
    {
      cogl_pop_matrix ();
    }

  if (clutter_actor_get_n_children (actor) == 0)
    return;

  clutter_actor_get_allocation_box (actor, &allocation_box);
  st_theme_node_get_content_box (theme_node, &allocation_box, &content_box);

  content_box.x1 += x;
  content_box.y1 += y;
  content_box.x2 += x;
  content_box.y2 += y;

  if (priv->hadjustment || priv->vadjustment)
    cogl_clip_push_rectangle ((int)content_box.x1,
                              (int)content_box.y1,
                              (int)content_box.x2,
                              (int)content_box.y2);

  for (child = clutter_actor_get_first_child (actor);
       child != NULL;
       child = clutter_actor_get_next_sibling (child))
    clutter_actor_paint (child);

  if (priv->hadjustment || priv->vadjustment)
    cogl_clip_pop ();
}
Esempio n. 9
0
static void
mex_grid_view_paint (ClutterActor *actor)
{
  MexGridViewPrivate *priv = MEX_GRID_VIEW (actor)->priv;
  ClutterActorBox gbox, mbox;

  CLUTTER_ACTOR_CLASS (mex_grid_view_parent_class)->paint (actor);

  clutter_actor_get_allocation_box (priv->menu_layout, &mbox);
  clutter_actor_get_allocation_box (priv->grid_layout, &gbox);

  cogl_clip_push_rectangle (mbox.x2, mbox.y1, gbox.x2, gbox.y2);

  clutter_actor_paint (priv->grid_layout);

  cogl_clip_pop ();

  clutter_actor_paint (priv->menu_layout);
}
static void
shell_slicer_paint_child (ShellSlicer *self)
{
  ClutterActor *child;
  ClutterActorBox self_box;
  ClutterActorBox child_box;
  float width, height, child_width, child_height;
  StAlign x_align, y_align;
  double x_align_factor, y_align_factor;

  child = st_bin_get_child (ST_BIN (self));

  if (!child)
    return;

  st_bin_get_alignment (ST_BIN (self), &x_align, &y_align);
  _st_get_align_factors (x_align, y_align,
                         &x_align_factor, &y_align_factor);

  clutter_actor_get_allocation_box (CLUTTER_ACTOR (self), &self_box);
  clutter_actor_get_allocation_box (child, &child_box);

  width = self_box.x2 - self_box.x1;
  height = self_box.y2 - self_box.y1;
  child_width = child_box.x2 - child_box.x1;
  child_height = child_box.y2 - child_box.y1;

  cogl_push_matrix ();

  cogl_clip_push_rectangle (0, 0, width, height);
  cogl_translate ((int)(0.5 + x_align_factor * (width - child_width)),
                  (int)(0.5 + y_align_factor * (height - child_height)),
                  0);

  clutter_actor_paint (child);

  cogl_clip_pop ();

  cogl_pop_matrix ();
}
Esempio n. 11
0
static void
on_paint (ClutterActor *actor, CallbackData *data)
{
  int i;
  ClutterGeometry stage_size;
  gint hand_width, hand_height;
  GSList *node;

  clutter_actor_get_allocation_geometry (data->stage, &stage_size);

  hand_width = cogl_texture_get_width (data->hand);
  hand_height = cogl_texture_get_height (data->hand);

  /* Setup the clipping */
  for (node = data->clips; node; node = node->next)
    {
      Clip *clip = (Clip *) node->data;

      if (clip->type == CLIP_RECTANGLE)
        cogl_clip_push_rectangle (clip->x1,
                                  clip->y1,
                                  clip->x2,
                                  clip->y2);
      else if (clip->type == CLIP_ROTATED_RECTANGLE)
        {
          float size = MIN (ABS (clip->x2 - clip->x1),
                            ABS (clip->y2 - clip->y1));
          int cx = (clip->x1 + clip->x2) / 2;
          int cy = (clip->y1 + clip->y2) / 2;

          size = sqrtf ((size / 2) * (size / 2) * 2);

          cogl_push_matrix ();

          /* Rotate 45° about the centre point */
          cogl_translate (cx, cy, 0.0f);
          cogl_rotate (45.0f, 0.0f, 0.0f, 1.0f);
          cogl_clip_push_rectangle (-size / 2, -size / 2, size / 2, size / 2);

          cogl_pop_matrix ();
        }
      else
        {
          make_clip_path (clip);
          cogl_clip_push_from_path ();
        }
    }

  /* Draw a rectangle filling the entire stage */
  cogl_set_source_color4ub (0x80, 0x80, 0xff, 0xff);
  cogl_rectangle (0, 0, stage_size.width, stage_size.height);

  draw_shapes (10, 10);

  /* Draw the hand at different rotations */
  for (i = -2; i <= 2; i++)
    {
      cogl_push_matrix ();

      cogl_translate (stage_size.width / 2 + stage_size.width / 6 * i,
                      stage_size.height / 2, 0);

      cogl_rotate (i * 40, 0, 1, 0);

      cogl_set_source_color4ub (0xff, 0xff, 0xff, 0xff);

      cogl_set_source_texture (data->hand);
      cogl_rectangle_with_texture_coords ((-hand_width / 2),
                                          (-hand_height / 2),
                                          (hand_width / 2),
                                          (hand_height / 2),
                                          0, 0, 1, 1);

      cogl_pop_matrix ();
    }

  draw_shapes (stage_size.width - 310, stage_size.height - 110);

  /* Remove all of the clipping */
  g_slist_foreach (data->clips, (GFunc) cogl_clip_pop, NULL);

  /* Draw the bounding box for each of the clips */
  for (node = data->clips; node; node = node->next)
    {
      Clip *clip = (Clip *) node->data;

      make_clip_path (clip);
      cogl_set_source_color4ub (0x00, 0x00, 0xff, 0xff);
      cogl_path_stroke ();
    }

  /* Draw the bounding box for the pending new clip */
  if (data->current_clip.type != CLIP_NONE)
    {
      make_clip_path (&data->current_clip);
      cogl_set_source_color4ub (0xff, 0x00, 0x00, 0xff);
      cogl_path_stroke ();
    }
}
Esempio n. 12
0
static void
on_paint (ClutterActor *actor, void *state)
{
  float saved_viewport[4];
  CoglMatrix saved_projection;
  CoglMatrix projection;
  CoglMatrix modelview;
  guchar *data;
  CoglHandle tex;
  CoglHandle offscreen;
  CoglColor black;
  float x0;
  float y0;
  float width;
  float height;

  /* for clearing the offscreen framebuffer to black... */
  cogl_color_init_from_4ub (&black, 0x00, 0x00, 0x00, 0xff);

  cogl_get_viewport (saved_viewport);
  cogl_get_projection_matrix (&saved_projection);
  cogl_push_matrix ();

  cogl_matrix_init_identity (&projection);
  cogl_matrix_init_identity (&modelview);

  cogl_set_projection_matrix (&projection);
  cogl_set_modelview_matrix (&modelview);

  /* - Create a 100x200 viewport (i.e. smaller than the onscreen framebuffer)
   *   and position it a (20, 10) inside the framebuffer.
   * - Fill the whole viewport with a purple rectangle
   * - Verify that the framebuffer is black with a 100x200 purple rectangle at
   *   (20, 10)
   */
  cogl_set_viewport (20, /* x */
                     10, /* y */
                     100, /* width */
                     200); /* height */
  /* clear everything... */
  cogl_clear (&black, COGL_BUFFER_BIT_COLOR);
  /* fill the viewport with purple.. */
  cogl_set_source_color4ub (0xff, 0x00, 0xff, 0xff);
  cogl_rectangle (-1, 1, 1, -1);
  assert_rectangle_color_and_black_border (20, 10, 100, 200,
                                           0xff, 0x00, 0xff);


  /* - Create a viewport twice the size of the onscreen framebuffer with
   *   a negative offset positioning it at (-20, -10) relative to the
   *   buffer itself.
   * - Draw a 100x200 green rectangle at (40, 20) within the viewport (which
   *   is (20, 10) within the framebuffer)
   * - Verify that the framebuffer is black with a 100x200 green rectangle at
   *   (20, 10)
   */
  cogl_set_viewport (-20, /* x */
                     -10, /* y */
                     FRAMEBUFFER_WIDTH * 2, /* width */
                     FRAMEBUFFER_HEIGHT * 2); /* height */
  /* clear everything... */
  cogl_clear (&black, COGL_BUFFER_BIT_COLOR);
  /* draw a 100x200 green rectangle offset into the viewport such that its
   * top left corner should be found at (20, 10) in the offscreen buffer */
  /* (offset 40 pixels right from the left of the viewport) */
  x0 = -1.0f + (1.0f / FRAMEBUFFER_WIDTH) * 40.f;
  /* (offset 20 pixels down from the top of the viewport) */
  y0 = 1.0f - (1.0f / FRAMEBUFFER_HEIGHT) * 20.0f;
  width = (1.0f / FRAMEBUFFER_WIDTH) * 100;
  height = (1.0f / FRAMEBUFFER_HEIGHT) * 200;
  cogl_set_source_color4ub (0x00, 0xff, 0x00, 0xff);
  cogl_rectangle (x0, y0, x0 + width, y0 - height);
  assert_rectangle_color_and_black_border (20, 10, 100, 200,
                                           0x00, 0xff, 0x00);


  /* - Create a 200x400 viewport and position it a (20, 10) inside the draw
   *   buffer.
   * - Push a 100x200 window space clip rectangle at (20, 10)
   * - Fill the whole viewport with a blue rectangle
   * - Verify that the framebuffer is black with a 100x200 blue rectangle at
   *   (20, 10)
   */
  cogl_set_viewport (20, /* x */
                     10, /* y */
                     200, /* width */
                     400); /* height */
  /* clear everything... */
  cogl_clear (&black, COGL_BUFFER_BIT_COLOR);
  cogl_clip_push_window_rectangle (20, 10, 100, 200);
  /* fill the viewport with blue.. */
  cogl_set_source_color4ub (0x00, 0x00, 0xff, 0xff);
  cogl_rectangle (-1, 1, 1, -1);
  cogl_clip_pop ();
  assert_rectangle_color_and_black_border (20, 10, 100, 200,
                                           0x00, 0x00, 0xff);


  /* - Create a 200x400 viewport and position it a (20, 10) inside the draw
   *   buffer.
   * - Push a 100x200 model space clip rectangle at (20, 10) in the viewport
   *   (i.e. (40, 20) inside the framebuffer)
   * - Fill the whole viewport with a green rectangle
   * - Verify that the framebuffer is black with a 100x200 green rectangle at
   *   (40, 20)
   */
  cogl_set_viewport (20, /* x */
                     10, /* y */
                     200, /* width */
                     400); /* height */
  /* clear everything... */
  cogl_clear (&black, COGL_BUFFER_BIT_COLOR);
  /* figure out where to position our clip rectangle in model space
   * coordinates... */
  /* (offset 40 pixels right from the left of the viewport) */
  x0 = -1.0f + (2.0f / 200) * 20.f;
  /* (offset 20 pixels down from the top of the viewport) */
  y0 = 1.0f - (2.0f / 400) * 10.0f;
  width = (2.0f / 200) * 100;
  height = (2.0f / 400) * 200;
  /* add the clip rectangle... */
  cogl_push_matrix ();
  cogl_translate (x0 + (width/2.0), y0 - (height/2.0), 0);
  /* XXX: Rotate just enough to stop Cogl from converting our model space
   * rectangle into a window space rectangle.. */
  cogl_rotate (0.1, 0, 0, 1);
  cogl_clip_push_rectangle (-(width/2.0), -(height/2.0),
                            width/2.0, height/2.0);
  cogl_pop_matrix ();
  /* fill the viewport with green.. */
  cogl_set_source_color4ub (0x00, 0xff, 0x00, 0xff);
  cogl_rectangle (-1, 1, 1, -1);
  cogl_clip_pop ();
  assert_rectangle_color_and_black_border (40, 20, 100, 200,
                                           0x00, 0xff, 0x00);


  /* Set the viewport to something specific so we can verify that it gets
   * restored after we are done testing with an offscreen framebuffer... */
  cogl_set_viewport (20, 10, 100, 200);

  /*
   * Next test offscreen drawing...
   */
  data = g_malloc (FRAMEBUFFER_WIDTH * 4 * FRAMEBUFFER_HEIGHT);
  tex = cogl_texture_new_from_data (FRAMEBUFFER_WIDTH, FRAMEBUFFER_HEIGHT,
                                    COGL_TEXTURE_NO_SLICING,
                                    COGL_PIXEL_FORMAT_RGBA_8888, /* data fmt */
                                    COGL_PIXEL_FORMAT_ANY, /* internal fmt */
                                    FRAMEBUFFER_WIDTH * 4, /* rowstride */
                                    data);
  g_free (data);
  offscreen = cogl_offscreen_new_to_texture (tex);

  cogl_push_framebuffer (offscreen);


  /* - Create a 100x200 viewport (i.e. smaller than the offscreen framebuffer)
   *   and position it a (20, 10) inside the framebuffer.
   * - Fill the whole viewport with a blue rectangle
   * - Verify that the framebuffer is black with a 100x200 blue rectangle at
   *   (20, 10)
   */
  cogl_set_viewport (20, /* x */
                     10, /* y */
                     100, /* width */
                     200); /* height */
  /* clear everything... */
  cogl_clear (&black, COGL_BUFFER_BIT_COLOR);
  /* fill the viewport with blue.. */
  cogl_set_source_color4ub (0x00, 0x00, 0xff, 0xff);
  cogl_rectangle (-1, 1, 1, -1);
  assert_rectangle_color_and_black_border (20, 10, 100, 200,
                                           0x00, 0x00, 0xff);


  /* - Create a viewport twice the size of the offscreen framebuffer with
   *   a negative offset positioning it at (-20, -10) relative to the
   *   buffer itself.
   * - Draw a 100x200 red rectangle at (40, 20) within the viewport (which
   *   is (20, 10) within the framebuffer)
   * - Verify that the framebuffer is black with a 100x200 red rectangle at
   *   (20, 10)
   */
  cogl_set_viewport (-20, /* x */
                     -10, /* y */
                     FRAMEBUFFER_WIDTH * 2, /* width */
                     FRAMEBUFFER_HEIGHT * 2); /* height */
  /* clear everything... */
  cogl_clear (&black, COGL_BUFFER_BIT_COLOR);
  /* draw a 100x200 red rectangle offset into the viewport such that its
   * top left corner should be found at (20, 10) in the offscreen buffer */
  /* (offset 40 pixels right from the left of the viewport) */
  x0 = -1.0f + (1.0f / FRAMEBUFFER_WIDTH) * 40.f;
  /* (offset 20 pixels down from the top of the viewport) */
  y0 = 1.0f - (1.0f / FRAMEBUFFER_HEIGHT) * 20.0f;
  width = (1.0f / FRAMEBUFFER_WIDTH) * 100;
  height = (1.0f / FRAMEBUFFER_HEIGHT) * 200;
  cogl_set_source_color4ub (0xff, 0x00, 0x00, 0xff);
  cogl_rectangle (x0, y0, x0 + width, y0 - height);
  assert_rectangle_color_and_black_border (20, 10, 100, 200,
                                           0xff, 0x00, 0x00);


  /* - Create a 200x400 viewport and position it a (20, 10) inside the draw
   *   buffer.
   * - Push a 100x200 window space clip rectangle at (20, 10)
   * - Fill the whole viewport with a blue rectangle
   * - Verify that the framebuffer is black with a 100x200 blue rectangle at
   *   (20, 10)
   */
  cogl_set_viewport (20, /* x */
                     10, /* y */
                     200, /* width */
                     400); /* height */
  /* clear everything... */
  cogl_clear (&black, COGL_BUFFER_BIT_COLOR);
  cogl_clip_push_window_rectangle (20, 10, 100, 200);
  /* fill the viewport with blue.. */
  cogl_set_source_color4ub (0x00, 0x00, 0xff, 0xff);
  cogl_rectangle (-1, 1, 1, -1);
  cogl_clip_pop ();
  assert_rectangle_color_and_black_border (20, 10, 100, 200,
                                           0x00, 0x00, 0xff);


  /* - Create a 200x400 viewport and position it a (20, 10) inside the draw
   *   buffer.
   * - Push a 100x200 model space clip rectangle at (20, 10) in the viewport
   *   (i.e. (40, 20) inside the framebuffer)
   * - Fill the whole viewport with a green rectangle
   * - Verify that the framebuffer is black with a 100x200 green rectangle at
   *   (40, 20)
   */
  cogl_set_viewport (20, /* x */
                     10, /* y */
                     200, /* width */
                     400); /* height */
  /* clear everything... */
  cogl_clear (&black, COGL_BUFFER_BIT_COLOR);
  /* figure out where to position our clip rectangle in model space
   * coordinates... */
  /* (offset 40 pixels right from the left of the viewport) */
  x0 = -1.0f + (2.0f / 200) * 20.f;
  /* (offset 20 pixels down from the top of the viewport) */
  y0 = 1.0f - (2.0f / 400) * 10.0f;
  width = (2.0f / 200) * 100;
  height = (2.0f / 400) * 200;
  /* add the clip rectangle... */
  cogl_push_matrix ();
  cogl_translate (x0 + (width/2.0), y0 - (height/2.0), 0);
  /* XXX: Rotate just enough to stop Cogl from converting our model space
   * rectangle into a window space rectangle.. */
  cogl_rotate (0.1, 0, 0, 1);
  cogl_clip_push_rectangle (-(width/2.0), -(height/2.0),
                            width/2, height/2);
  cogl_pop_matrix ();
  /* fill the viewport with green.. */
  cogl_set_source_color4ub (0x00, 0xff, 0x00, 0xff);
  cogl_rectangle (-1, 1, 1, -1);
  cogl_clip_pop ();
  assert_rectangle_color_and_black_border (40, 20, 100, 200,
                                           0x00, 0xff, 0x00);


  /* Set the viewport to something obscure to verify that it gets
   * replace when we switch back to the onscreen framebuffer... */
  cogl_set_viewport (0, 0, 10, 10);

  cogl_pop_framebuffer ();
  cogl_handle_unref (offscreen);

  /*
   * Verify that the previous onscreen framebuffer's viewport was restored
   * by drawing a white rectangle across the whole viewport. This should
   * draw a 100x200 rectangle at (20,10) relative to the onscreen draw
   * buffer...
   */
  cogl_clear (&black, COGL_BUFFER_BIT_COLOR);
  cogl_set_source_color4ub (0xff, 0xff, 0xff, 0xff);
  cogl_rectangle (-1, 1, 1, -1);
  assert_rectangle_color_and_black_border (20, 10, 100, 200,
                                           0xff, 0xff, 0xff);


  /* Uncomment to display the last contents of the offscreen framebuffer */
#if 1
  cogl_matrix_init_identity (&projection);
  cogl_matrix_init_identity (&modelview);
  cogl_set_viewport (0, 0, FRAMEBUFFER_WIDTH, FRAMEBUFFER_HEIGHT);
  cogl_set_projection_matrix (&projection);
  cogl_set_modelview_matrix (&modelview);
  cogl_set_source_texture (tex);
  cogl_rectangle (-1, 1, 1, -1);
#endif

  cogl_handle_unref (tex);

  /* Finally restore the stage's original state... */
  cogl_pop_matrix ();
  cogl_set_projection_matrix (&saved_projection);
  cogl_set_viewport (saved_viewport[0], saved_viewport[1],
                     saved_viewport[2], saved_viewport[3]);


  /* Comment this out if you want visual feedback of what this test
   * paints.
   */
  clutter_main_quit ();
}