static gboolean
invalidate_canvas (ChamplainPathLayer *layer)
{
  ChamplainPathLayerPrivate *priv = layer->priv;
  gfloat view_width, view_height;
  gint map_width, map_height;
  gint viewport_x, viewport_y;
  gint anchor_x, anchor_y;
  gfloat right_actor_width, right_actor_height;
  gfloat left_actor_width, left_actor_height;

  right_actor_width = 256;
  right_actor_height = 256;
  left_actor_width = 0;
  left_actor_height = 0;
  map_width = 256;
  map_height = 256;

  if (priv->view != NULL)
    {
      get_map_size (priv->view, &map_width, &map_height);
      clutter_actor_get_size (CLUTTER_ACTOR (priv->view), &view_width, &view_height);
      champlain_view_get_viewport_origin (priv->view, &viewport_x, &viewport_y);
      champlain_view_get_viewport_anchor (priv->view, &anchor_x, &anchor_y);

      right_actor_width = MIN (map_width - (viewport_x + anchor_x), (gint)view_width);
      right_actor_height = MIN (map_height - (viewport_y + anchor_y), (gint)view_height);
      left_actor_width = MIN (view_width - right_actor_width, map_width - right_actor_width);
      left_actor_height = right_actor_height;

      /* Ensure sizes are positive  */
      right_actor_width = MAX (0, right_actor_width);
      right_actor_height = MAX (0, right_actor_height);
      left_actor_width = MAX (0, left_actor_width);
      left_actor_height = MAX (0, left_actor_height);
    }

  clutter_actor_set_size (priv->path_actor, map_width, map_height);

  clutter_actor_set_size (priv->right_actor, right_actor_width, right_actor_height);
  clutter_canvas_set_size (CLUTTER_CANVAS (priv->right_canvas), right_actor_width, right_actor_height);
  clutter_content_invalidate (priv->right_canvas);

  if (left_actor_width != 0)
    {
      clutter_actor_set_size (priv->left_actor, left_actor_width, left_actor_height);
      clutter_canvas_set_size (CLUTTER_CANVAS (priv->left_canvas), left_actor_width, left_actor_height);
      clutter_content_invalidate (priv->left_canvas);
    }

  priv->redraw_scheduled = FALSE;

  return FALSE;
}
예제 #2
0
ClutterActor *
ckd_slide_new_for_poppler_page (PopplerPage *page, gdouble scale)
{
        CkdSlide *self = g_object_new (CKD_TYPE_SLIDE, NULL);
        CkdSlidePriv *priv = CKD_SLIDE_GET_PRIVATE (self);
        ClutterContent *canvas;
        gdouble w, h;
        
        priv->content = clutter_actor_new ();
        canvas = clutter_canvas_new ();

        poppler_page_get_size (page, &w, &h);
        
        clutter_canvas_set_size (CLUTTER_CANVAS(canvas), w * scale, h * scale);
        clutter_actor_set_content (priv->content, canvas);
        clutter_actor_set_content_scaling_filters (priv->content,
                                                   CLUTTER_SCALING_FILTER_TRILINEAR,
                                                   CLUTTER_SCALING_FILTER_LINEAR);
        g_object_unref (canvas);

        clutter_actor_set_size (priv->content, w * scale, h * scale);
        clutter_actor_add_child (CLUTTER_ACTOR(self), priv->content);

        struct CkdDrawData data = {page, scale};
        g_signal_connect (canvas, "draw", G_CALLBACK (draw_page), &data);
        
        clutter_content_invalidate (canvas);

        
        return (ClutterActor *)self;
}
예제 #3
0
static void
clutter_canvas_paint_content (ClutterContent   *content,
                              ClutterActor     *actor,
                              ClutterPaintNode *root)
{
  ClutterCanvas *self = CLUTTER_CANVAS (content);
  ClutterCanvasPrivate *priv = self->priv;
  ClutterPaintNode *node;

  if (priv->buffer == NULL)
    return;

  if (priv->dirty)
    g_clear_pointer (&priv->texture, cogl_object_unref);

  if (priv->texture == NULL)
    priv->texture = cogl_texture_new_from_bitmap (priv->buffer,
                                                  COGL_TEXTURE_NO_SLICING,
                                                  CLUTTER_CAIRO_FORMAT_ARGB32);

  if (priv->texture == NULL)
    return;

  node = clutter_actor_create_texture_paint_node (actor, priv->texture);
  clutter_paint_node_set_name (node, "Canvas Content");
  clutter_paint_node_add_child (root, node);
  clutter_paint_node_unref (node);

  priv->dirty = FALSE;
}
예제 #4
0
static void
clutter_canvas_get_property (GObject    *gobject,
                             guint       prop_id,
                             GValue     *value,
                             GParamSpec *pspec)
{
  ClutterCanvasPrivate *priv = CLUTTER_CANVAS (gobject)->priv;

  switch (prop_id)
    {
    case PROP_WIDTH:
      g_value_set_int (value, priv->width);
      break;

    case PROP_HEIGHT:
      g_value_set_int (value, priv->height);
      break;

    case PROP_SCALE_FACTOR:
      if (priv->scale_factor_set)
        g_value_set_int (value, priv->scale_factor);
      else
        g_value_set_int (value, -1);
      break;

    case PROP_SCALE_FACTOR_SET:
      g_value_set_boolean (value, priv->scale_factor_set);
      break;

    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
      break;
    }
}
예제 #5
0
static void
clutter_canvas_set_property (GObject      *gobject,
                             guint         prop_id,
                             const GValue *value,
                             GParamSpec   *pspec)
{
  ClutterCanvasPrivate *priv = CLUTTER_CANVAS (gobject)->priv;

  switch (prop_id)
    {
    case PROP_WIDTH:
      {
        gint new_size = g_value_get_int (value);

        if (priv->width != new_size)
          {
            priv->width = new_size;

            clutter_content_invalidate (CLUTTER_CONTENT (gobject));
          }
      }
      break;

    case PROP_HEIGHT:
      {
        gint new_size = g_value_get_int (value);

        if (priv->height != new_size)
          {
            priv->height = new_size;

            clutter_content_invalidate (CLUTTER_CONTENT (gobject));
          }
      }
      break;

    case PROP_SCALE_FACTOR:
      clutter_canvas_set_scale_factor (CLUTTER_CANVAS (gobject),
                                       g_value_get_int (value));
      break;

    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
      break;
    }
}
static void
champlain_path_layer_init (ChamplainPathLayer *self)
{
  ChamplainPathLayerPrivate *priv;

  self->priv = GET_PRIVATE (self);
  priv = self->priv;
  priv->view = NULL;

  priv->visible = TRUE;
  priv->fill = FALSE;
  priv->stroke = TRUE;
  priv->stroke_width = 2.0;
  priv->nodes = NULL;
  priv->dash = NULL;
  priv->num_dashes = 0;
  priv->redraw_scheduled = FALSE;

  priv->fill_color = clutter_color_copy (&DEFAULT_FILL_COLOR);
  priv->stroke_color = clutter_color_copy (&DEFAULT_STROKE_COLOR);

  priv->right_canvas = clutter_canvas_new ();
  priv->left_canvas = clutter_canvas_new ();

  clutter_canvas_set_size (CLUTTER_CANVAS (priv->right_canvas), 255, 255);
  clutter_canvas_set_size (CLUTTER_CANVAS (priv->left_canvas), 0, 0);

  g_signal_connect (priv->right_canvas, "draw", G_CALLBACK (redraw_path), self);
  g_signal_connect (priv->left_canvas, "draw", G_CALLBACK (redraw_path), self);

  priv->path_actor = clutter_actor_new ();
  clutter_actor_add_child (CLUTTER_ACTOR (self), priv->path_actor);
  clutter_actor_set_size (priv->path_actor, 255, 255);

  priv->right_actor = clutter_actor_new ();
  clutter_actor_set_size (priv->right_actor, 255, 255);
  clutter_actor_set_content (priv->right_actor, priv->right_canvas);
  clutter_actor_add_child (priv->path_actor, priv->right_actor);

  priv->left_actor = clutter_actor_new ();
  clutter_actor_set_size (priv->left_actor, 255, 255);
  clutter_actor_set_content (priv->left_actor, priv->left_canvas);
  clutter_actor_add_child (priv->path_actor, priv->left_actor);
}
예제 #7
0
static void meta_switcher_present_list(MetaSwitcher* self)
{
    MetaSwitcherPrivate* priv = self->priv;
    MetaScreen* screen = meta_plugin_get_screen(priv->plugin);
    MetaDisplay* display = meta_screen_get_display(screen);

    // windows on all workspaces
    GList* ls = meta_display_get_tab_list(display, META_TAB_LIST_NORMAL, NULL);
    if (!ls) return;

    GList* ws_list = meta_screen_get_workspaces(screen);
    g_list_foreach(ws_list, (GFunc)hook_ws_event, self);

    if (!priv->apps) {
        priv->apps = g_ptr_array_new();
        GList* orig = ls;
        while (ls) {
            g_ptr_array_add(priv->apps, ls->data);
            ls = ls->next;
        }
        g_list_free(orig);
    }

    clutter_actor_set_height(priv->top, APP_ACTOR_HEIGHT + 20);

    gint x = 0, y = 0;
    for (int i = 0; i < priv->apps->len; i++) {
        _add_app(self, g_ptr_array_index(priv->apps, i), &x, &y);
    }

    clutter_actor_set_margin_left(g_hash_table_lookup(priv->icons, g_ptr_array_index(priv->apps, 0)), 10);
    clutter_actor_set_margin_right(g_hash_table_lookup(priv->icons, g_ptr_array_index(priv->apps, priv->apps->len-1)), 10);

    gint screen_width = 0, screen_height = 0;
    meta_screen_get_size(screen, &screen_width, &screen_height);
    /* TODO: @sonald set top width when bigger than screen width */
    if (clutter_actor_get_width(priv->top) > screen_width)
        clutter_actor_set_width(priv->top, screen_width);

    gfloat w = clutter_actor_get_width(priv->top), h = clutter_actor_get_height(priv->top),
           tx = (screen_width - w) / 2, ty = (screen_height - h) / 2;
#if DEBUG
    g_message("%s, line %d, %f %f", __func__, __LINE__, w, tx);
#endif
    clutter_actor_set_position(priv->top, tx, ty);

    ClutterContent* canvas = clutter_canvas_new();
    clutter_canvas_set_size(CLUTTER_CANVAS(canvas), w, h);
    clutter_actor_set_content(priv->top, canvas);
    g_object_unref(canvas);
    g_signal_connect(canvas, "draw", G_CALLBACK(on_switcher_background_draw), self);

    clutter_content_invalidate(canvas);

    priv->selected_id = 0;
}
예제 #8
0
static void
on_actor_resize (ClutterActor           *actor,
                 const ClutterActorBox  *allocation,
                 ClutterAllocationFlags  flags,
                 gpointer                user_data)
{
  float width, height;

  /* match the canvas size to the actor's */
  clutter_actor_get_size (actor, &width, &height);
  clutter_canvas_set_size (CLUTTER_CANVAS (clutter_actor_get_content (actor)),
                           ceilf (width),
                           ceilf (height));
}
/**
 * champlain_point_set_size:
 * @point: a #ChamplainPoint
 * @size: The size of the point.
 *
 * Set the size of the point.
 *
 * Since: 0.10
 */
void
champlain_point_set_size (ChamplainPoint *point,
    gdouble size)
{
  g_return_if_fail (CHAMPLAIN_IS_POINT (point));

  ChamplainPointPrivate *priv = point->priv;

  point->priv->size = size;
  clutter_canvas_set_size (CLUTTER_CANVAS (priv->canvas), size, size);
  clutter_actor_set_size (CLUTTER_ACTOR (point), priv->size, priv->size);
  clutter_actor_set_translation (CLUTTER_ACTOR (point), -priv->size/2, -priv->size/2, 0.0);
  g_object_notify (G_OBJECT (point), "size");
  clutter_content_invalidate (priv->canvas);
}
예제 #10
0
static void
clutter_canvas_finalize (GObject *gobject)
{
  ClutterCanvasPrivate *priv = CLUTTER_CANVAS (gobject)->priv;

  if (priv->buffer != NULL)
    {
      cogl_object_unref (priv->buffer);
      priv->buffer = NULL;
    }

  g_clear_pointer (&priv->texture, cogl_object_unref);

  G_OBJECT_CLASS (clutter_canvas_parent_class)->finalize (gobject);
}
예제 #11
0
static void
clutter_canvas_invalidate (ClutterContent *content)
{
  ClutterCanvas *self = CLUTTER_CANVAS (content);
  ClutterCanvasPrivate *priv = self->priv;

  if (priv->buffer != NULL)
    {
      cogl_object_unref (priv->buffer);
      priv->buffer = NULL;
    }

  if (priv->width <= 0 || priv->height <= 0)
    return;

  clutter_canvas_emit_draw (self);
}
예제 #12
0
static gboolean
clutter_canvas_get_preferred_size (ClutterContent *content,
                                   gfloat         *width,
                                   gfloat         *height)
{
  ClutterCanvasPrivate *priv = CLUTTER_CANVAS (content)->priv;

  if (priv->width < 0 || priv->height < 0)
    return FALSE;

  if (width != NULL)
    *width = priv->width;

  if (height != NULL)
    *height = priv->height;

  return TRUE;
}
static void
champlain_point_init (ChamplainPoint *point)
{
  ChamplainPointPrivate *priv = GET_PRIVATE (point);

  point->priv = priv;

  priv->color = clutter_color_copy (&DEFAULT_COLOR);
  priv->size = 12;
  priv->canvas = clutter_canvas_new ();
  g_signal_connect (priv->canvas, "draw", G_CALLBACK (draw), point);
  clutter_canvas_set_size (CLUTTER_CANVAS (priv->canvas), priv->size, priv->size);
  clutter_actor_set_size (CLUTTER_ACTOR (point), priv->size, priv->size);
  clutter_actor_set_content (CLUTTER_ACTOR (point), priv->canvas);
  clutter_actor_set_translation (CLUTTER_ACTOR (point), -priv->size/2, -priv->size/2, 0.0);
  clutter_content_invalidate (priv->canvas);

  g_signal_connect (point, "notify::selected", G_CALLBACK (notify_selected), NULL);
}
static void
test_window (void)
{
  GsdOsdDrawContext ctx;
  ClutterActor *stage, *actor;
  ClutterContent *canvas;
  GtkWidgetPath *widget_path;

  /* create a resizable stage */
  stage = clutter_stage_new ();
  clutter_stage_set_title (CLUTTER_STAGE (stage), "OSD Test");
  clutter_stage_set_user_resizable (CLUTTER_STAGE (stage), TRUE);
  clutter_actor_set_background_color (stage, CLUTTER_COLOR_Red);
  clutter_actor_set_size (stage, 300, 300);
  clutter_actor_show (stage);

  /* box canvas */
  canvas = clutter_canvas_new ();
  clutter_canvas_set_size (CLUTTER_CANVAS (canvas), 300, 300);

  actor = clutter_actor_new ();
  clutter_actor_add_constraint (actor, clutter_bind_constraint_new (stage, CLUTTER_BIND_SIZE, 0));
  clutter_actor_set_content (actor, canvas);
  g_object_unref (canvas);

  clutter_actor_add_child (stage, actor);

  memset (&ctx, 0, sizeof(ctx));

  widget_path = gtk_widget_path_new ();
  gtk_widget_path_append_type (widget_path, GTK_TYPE_WINDOW);
  ctx.style = gtk_style_context_new ();
  gtk_style_context_set_path (ctx.style, widget_path);

  ctx.direction = clutter_get_default_text_direction ();
  ctx.theme = gtk_icon_theme_get_default ();

  g_signal_connect (canvas, "draw", G_CALLBACK (draw_box), &ctx);
  clutter_content_invalidate (canvas);

  g_signal_connect (stage, "destroy", G_CALLBACK (gtk_main_quit), NULL);
}
예제 #15
0
//FIXME: ClutterClone seems to have problem rendering children, so badges are stay in grandpar
static void create_window_badge(MosesOverview* self, ClutterActor* parent, int order)
{
    ClutterActor* badge = clutter_actor_new();
    clutter_actor_insert_child_above(clutter_actor_get_parent(parent), badge, NULL);

    gfloat tw, th;
    clutter_actor_get_transformed_size(parent, &tw, &th);

    gfloat w = 60.0, h = 60.0,
            x = (tw - w) / 2.0 + clutter_actor_get_x(parent),
            y = (th - h) / 2.0 + clutter_actor_get_y(parent);
    clutter_actor_set_position(badge, x, y);
    clutter_actor_set_size(badge, w, h);

    g_object_set_qdata(G_OBJECT(badge), moses_overview_window_clone_order(), GINT_TO_POINTER(order));
    g_object_set_qdata(G_OBJECT(parent), moses_overview_window_clone_order(), GINT_TO_POINTER(order));

    ClutterContent* canvas = clutter_canvas_new();
    clutter_canvas_set_size(CLUTTER_CANVAS(canvas), w, h);
    clutter_actor_set_content(badge, canvas);
    g_object_unref(canvas);
    g_signal_connect(canvas, "draw", G_CALLBACK(on_badge_draw), badge);

    clutter_content_invalidate(canvas);

    clutter_actor_set_scale(badge, 0.0, 0.0);

    //do animated show
    clutter_actor_save_easing_state(badge);
    clutter_actor_set_easing_mode(badge, CLUTTER_EASE_OUT_BACK);
    clutter_actor_set_easing_duration(badge, 350);

    clutter_actor_set_pivot_point(badge, 0.5, 0.5);
    clutter_actor_set_scale(badge, 1.0, 1.0);
    clutter_actor_restore_easing_state(badge);

    g_ptr_array_add(self->priv->badges, badge);
}
예제 #16
0
static ClutterActor *
make_flower_actor (void)
{
    gint petal_size = PETAL_MIN + rand() % PETAL_VAR;
    gint size = petal_size * 8;
    ClutterActor *ctex;
    ClutterContent *canvas;

    canvas = clutter_canvas_new ();
    g_signal_connect (canvas, "draw",
                      G_CALLBACK (draw_flower), GINT_TO_POINTER (petal_size));

    clutter_canvas_set_size (CLUTTER_CANVAS (canvas), size, size);
    ctex = g_object_new (CLUTTER_TYPE_ACTOR,
                         "content", canvas,
                         "width", (gfloat) size,
                         "height", (gfloat) size,
                         NULL);

    g_object_unref (canvas);

    return ctex;
}
예제 #17
0
static void
bacon_video_osd_actor_init (BaconVideoOsdActor *osd)
{
	ClutterActor *self;
	GtkWidgetPath *widget_path;

	self = CLUTTER_ACTOR (osd);
        osd->priv = BACON_VIDEO_OSD_ACTOR_GET_PRIVATE (osd);

	osd->priv->canvas = CLUTTER_CANVAS (clutter_canvas_new ());
	g_object_bind_property (self, "width",
				osd->priv->canvas, "width",
				G_BINDING_DEFAULT);
	g_object_bind_property (self, "height",
				osd->priv->canvas, "height",
				G_BINDING_DEFAULT);
	clutter_actor_set_content (self, CLUTTER_CONTENT (osd->priv->canvas));
	g_object_unref (osd->priv->canvas);

	osd->priv->icon_name = NULL;
	osd->priv->message = NULL;

	osd->priv->ctx = g_new0 (GsdOsdDrawContext, 1);

	widget_path = gtk_widget_path_new ();
	gtk_widget_path_append_type (widget_path, GTK_TYPE_WINDOW);
	osd->priv->style = gtk_style_context_new ();
	gtk_style_context_set_path (osd->priv->style, widget_path);
	gtk_widget_path_free (widget_path);

	osd->priv->ctx->direction = clutter_get_default_text_direction ();
	osd->priv->ctx->theme = gtk_icon_theme_get_default ();
	osd->priv->ctx->style = osd->priv->style;

	g_signal_connect (osd->priv->canvas, "draw", G_CALLBACK (bacon_video_osd_actor_draw), osd);
        osd->priv->fade_out_alpha = 1.0;
}
예제 #18
0
int
main (int argc,
    char *argv[])
{
  ClutterActor *actor, *stage, *buttons, *button;
  ChamplainMarkerLayer *layer;
  ChamplainPathLayer *path;
  gfloat width, total_width = 0;

  if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS)
    return 1;

  stage = clutter_stage_new ();
  clutter_actor_set_size (stage, 800, 600);
  g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL);

  /* Create the map view */
  actor = champlain_view_new ();
  clutter_actor_set_size (CLUTTER_ACTOR (actor), 800, 600);
  clutter_actor_add_child (stage, actor);

  /* Create the buttons */
  buttons = clutter_actor_new ();
  clutter_actor_set_position (buttons, PADDING, PADDING);

  button = make_button ("Zoom in");
  clutter_actor_add_child (buttons, button);
  clutter_actor_set_reactive (button, TRUE);
  clutter_actor_get_size (button, &width, NULL);
  total_width += width + PADDING;
  g_signal_connect (button, "button-release-event",
      G_CALLBACK (zoom_in),
      actor);

  button = make_button ("Zoom out");
  clutter_actor_add_child (buttons, button);
  clutter_actor_set_reactive (button, TRUE);
  clutter_actor_set_position (button, total_width, 0);
  clutter_actor_get_size (button, &width, NULL);
  g_signal_connect (button, "button-release-event",
      G_CALLBACK (zoom_out),
      actor);

  clutter_actor_add_child (stage, buttons);

  ClutterContent *canvas;
  canvas = clutter_canvas_new ();
  clutter_canvas_set_size (CLUTTER_CANVAS (canvas), 512, 256);
  g_signal_connect (canvas, "draw", G_CALLBACK (draw_background_tile), NULL);
  clutter_content_invalidate (canvas);
  champlain_view_set_background_pattern (CHAMPLAIN_VIEW (actor), canvas);

  /* Create the markers and marker layer */
  layer = create_marker_layer (CHAMPLAIN_VIEW (actor), &path);
  champlain_view_add_layer (CHAMPLAIN_VIEW (actor), CHAMPLAIN_LAYER (layer));

  /* Connect to the click event */
  clutter_actor_set_reactive (actor, TRUE);
  g_signal_connect (actor, "button-release-event",
      G_CALLBACK (map_view_button_release_cb),
      actor);

  /* Finish initialising the map view */
  g_object_set (G_OBJECT (actor), "zoom-level", 12,
      "kinetic-mode", TRUE, NULL);
  champlain_view_center_on (CHAMPLAIN_VIEW (actor), 45.466, -73.75);

  clutter_actor_show (stage);
  clutter_main ();

  return 0;
}
static gboolean
redraw_path (ClutterCanvas *canvas,
    cairo_t *cr,
    int width,
    int height,
    ChamplainPathLayer *layer)
{
  ChamplainPathLayerPrivate *priv = layer->priv;
  GList *elem;
  ChamplainView *view = priv->view;
  gint  viewport_x, viewport_y;
  gint anchor_x, anchor_y;
  
  /* layer not yet added to the view */
  if (view == NULL)
    return FALSE;

  if (!priv->visible || width == 0.0 || height ==  0.0)
    return FALSE;

  champlain_view_get_viewport_origin (priv->view, &viewport_x, &viewport_y);
  champlain_view_get_viewport_anchor (priv->view, &anchor_x, &anchor_y);

  if (canvas == CLUTTER_CANVAS (priv->right_canvas))
      clutter_actor_set_position (priv->right_actor, viewport_x, viewport_y);
  else
      clutter_actor_set_position (priv->left_actor, -anchor_x, viewport_y);

  /* Clear the drawing area */
  cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
  cairo_paint (cr);
  cairo_set_operator (cr, CAIRO_OPERATOR_OVER);

  cairo_set_line_join (cr, CAIRO_LINE_JOIN_BEVEL);

  for (elem = priv->nodes; elem != NULL; elem = elem->next)
    {
      ChamplainLocation *location = CHAMPLAIN_LOCATION (elem->data);
      gfloat x, y;

      x = champlain_view_longitude_to_x (view, champlain_location_get_longitude (location));
      y = champlain_view_latitude_to_y (view, champlain_location_get_latitude (location));

      if (canvas == CLUTTER_CANVAS (priv->right_canvas))
        cairo_line_to (cr, x, y);
      else
        cairo_line_to (cr, x + (viewport_x + anchor_x), y);
    }

  if (priv->closed_path)
    cairo_close_path (cr);

  cairo_set_source_rgba (cr,
      priv->fill_color->red / 255.0,
      priv->fill_color->green / 255.0,
      priv->fill_color->blue / 255.0,
      priv->fill_color->alpha / 255.0);

  if (priv->fill)
    cairo_fill_preserve (cr);

  cairo_set_source_rgba (cr,
      priv->stroke_color->red / 255.0,
      priv->stroke_color->green / 255.0,
      priv->stroke_color->blue / 255.0,
      priv->stroke_color->alpha / 255.0);

  cairo_set_line_width (cr, priv->stroke_width);
  cairo_set_dash(cr, priv->dash, priv->num_dashes, 0);

  if (priv->stroke)
    cairo_stroke (cr);

  set_surface (CHAMPLAIN_EXPORTABLE (layer), cairo_get_target (cr));

  return FALSE;
}
예제 #20
0
static void
on_new_kinect_device (GObject      *obj,
                      GAsyncResult *res,
                      gpointer      user_data)
{
  ClutterActor *stage, *instructions;
  GError *error = NULL;
  gint width = 640;
  gint height = 480;

  kinect = gfreenect_device_new_finish (res, &error);
  if (kinect == NULL)
    {
      g_debug ("Failed to created kinect device: %s", error->message);
      g_error_free (error);
      clutter_main_quit ();
      return;
    }

  g_debug ("Kinect device created!");

  stage = clutter_stage_new ();
  clutter_stage_set_title (CLUTTER_STAGE (stage), "Kinect Test");
  clutter_actor_set_size (stage, width * 2, height + 250);
  clutter_stage_set_user_resizable (CLUTTER_STAGE (stage), TRUE);

  g_signal_connect (stage, "destroy", G_CALLBACK (on_destroy), kinect);
  g_signal_connect (stage,
                    "key-release-event",
                    G_CALLBACK (on_key_release),
                    kinect);

  depth_tex = clutter_actor_new ();
  depth_canvas = clutter_canvas_new ();
  clutter_actor_set_content (depth_tex, depth_canvas);
  clutter_canvas_set_size (CLUTTER_CANVAS (depth_canvas), width, height);
  clutter_actor_set_size (depth_tex, width, height);
  clutter_actor_add_child (stage, depth_tex);

  video_tex = clutter_actor_new ();
  clutter_actor_set_content (video_tex, clutter_image_new ());
  clutter_actor_set_size (video_tex, width, height);
  clutter_actor_set_position (video_tex, width, 0.0);
  clutter_actor_add_child (stage, video_tex);

  info_text = clutter_text_new ();
  clutter_actor_set_position (info_text, 50, height + 20);
  clutter_actor_add_child (stage, info_text);

  instructions = create_instructions ();
  clutter_actor_set_position (instructions, 50, height + 70);
  clutter_actor_add_child (stage, instructions);

  skeleton = skeltrack_skeleton_new ();
  g_object_get (skeleton, "smoothing-factor", &SMOOTHING_FACTOR, NULL);

  set_info_text ();

  g_signal_connect (kinect,
                    "depth-frame",
                    G_CALLBACK (on_depth_frame),
                    NULL);

  g_signal_connect (kinect,
                    "video-frame",
                    G_CALLBACK (on_video_frame),
                    NULL);

  g_signal_connect (depth_canvas,
                    "draw",
                    G_CALLBACK (on_skeleton_draw),
                    NULL);

  gfreenect_device_set_tilt_angle (kinect, 0, NULL, NULL, NULL);

  gfreenect_device_start_depth_stream (kinect,
                                       GFREENECT_DEPTH_FORMAT_MM,
                                       NULL);

  gfreenect_device_start_video_stream (kinect,
                                       GFREENECT_RESOLUTION_MEDIUM,
                                       GFREENECT_VIDEO_FORMAT_RGB, NULL);

  clutter_actor_show (stage);
}
예제 #21
0
int
main (int argc, char *argv[])
{
  ClutterActor *stage, *box, *bg, *icon, *emblem, *label;
  ClutterLayoutManager *layout;
  ClutterContent *canvas, *image;
  ClutterColor *color;
  ClutterAction *action;
  GdkPixbuf *pixbuf;

  if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS)
    return 1;

  /* prepare the stage */
  stage = clutter_stage_new ();
  clutter_stage_set_title (CLUTTER_STAGE (stage), "BinLayout");
  clutter_actor_set_background_color (stage, CLUTTER_COLOR_Aluminium2);
  clutter_actor_set_size (stage, 640, 480);
  clutter_actor_show (stage);
  g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL);

  /* this is our BinLayout, with its default alignments */
  layout = clutter_bin_layout_new (CLUTTER_BIN_ALIGNMENT_CENTER,
                                   CLUTTER_BIN_ALIGNMENT_CENTER);

  /* the main container; this actor will use the BinLayout to lay
   * out its children; we use the anchor point to keep it centered
   * on the same position even when we change its size
   */
  box = clutter_actor_new ();
  clutter_actor_set_layout_manager (box, layout);
  clutter_actor_add_constraint (box, clutter_align_constraint_new (stage, CLUTTER_ALIGN_BOTH, 0.5));
  clutter_actor_set_position (box, 320, 240);
  clutter_actor_set_reactive (box, TRUE);
  clutter_actor_set_name (box, "box");
  clutter_actor_add_child (stage, box);

  /* the background is drawn using a canvas content */
  canvas = clutter_canvas_new ();
  g_signal_connect (canvas, "draw", G_CALLBACK (on_canvas_draw), NULL);
  clutter_canvas_set_size (CLUTTER_CANVAS (canvas), 200, 200);

  /* this is the background actor; we want it to fill the whole
   * of the allocation given to it by its parent
   */
  bg = clutter_actor_new ();
  clutter_actor_set_name (bg, "background");
  clutter_actor_set_size (bg, 200, 200);
  clutter_actor_set_content (bg, canvas);
  clutter_actor_set_x_expand (bg, TRUE);
  clutter_actor_set_y_expand (bg, TRUE);
  clutter_actor_set_x_align (bg, CLUTTER_ACTOR_ALIGN_FILL);
  clutter_actor_set_y_align (bg, CLUTTER_ACTOR_ALIGN_FILL);
  clutter_actor_add_child (box, bg);
  /* we use the ::transitions-completed signal to get notification
   * of the end of the sizing animation; this allows us to redraw
   * the canvas only once the animation has stopped
   */
  g_signal_connect (box, "transitions-completed",
                    G_CALLBACK (redraw_canvas),
                    canvas);

  /* we use GdkPixbuf to load an image from our data directory */
  pixbuf = gdk_pixbuf_new_from_file (TESTS_DATADIR G_DIR_SEPARATOR_S "redhand.png", NULL);
  image = clutter_image_new ();
  clutter_image_set_data (CLUTTER_IMAGE (image),
                          gdk_pixbuf_get_pixels (pixbuf),
                          gdk_pixbuf_get_has_alpha (pixbuf)
                            ? COGL_PIXEL_FORMAT_RGBA_8888
                            : COGL_PIXEL_FORMAT_RGB_888,
                          gdk_pixbuf_get_width (pixbuf),
                          gdk_pixbuf_get_height (pixbuf),
                          gdk_pixbuf_get_rowstride (pixbuf),
                          NULL);
  g_object_unref (pixbuf);

  /* this is the icon; it's going to be centered inside the box actor.
   * we use the content gravity to keep the aspect ratio of the image,
   * and the scaling filters to get a better result when scaling the
   * image down.
   */
  icon = clutter_actor_new ();
  clutter_actor_set_name (icon, "icon");
  clutter_actor_set_size (icon, 196, 196);
  clutter_actor_set_x_expand (icon, TRUE);
  clutter_actor_set_y_expand (icon, TRUE);
  clutter_actor_set_x_align (icon, CLUTTER_ACTOR_ALIGN_CENTER);
  clutter_actor_set_y_align (icon, CLUTTER_ACTOR_ALIGN_CENTER);
  clutter_actor_set_content_gravity (icon, CLUTTER_CONTENT_GRAVITY_RESIZE_ASPECT);
  clutter_actor_set_content_scaling_filters (icon,
                                             CLUTTER_SCALING_FILTER_TRILINEAR,
                                             CLUTTER_SCALING_FILTER_LINEAR);
  clutter_actor_set_content (icon, image);
  clutter_actor_add_child (box, icon);

  color = clutter_color_new (g_random_int_range (0, 255),
                             g_random_int_range (0, 255),
                             g_random_int_range (0, 255),
                             224);

  /* this is the emblem: a small rectangle with a random color, that we
   * want to put in the bottom right corner
   */
  emblem = clutter_actor_new ();
  clutter_actor_set_name (emblem, "emblem");
  clutter_actor_set_size (emblem, 48, 48);
  clutter_actor_set_background_color (emblem, color);
  clutter_actor_set_x_expand (emblem, TRUE);
  clutter_actor_set_y_expand (emblem, TRUE);
  clutter_actor_set_x_align (emblem, CLUTTER_ACTOR_ALIGN_END);
  clutter_actor_set_y_align (emblem, CLUTTER_ACTOR_ALIGN_END);
  clutter_actor_set_reactive (emblem, TRUE);
  clutter_actor_set_opacity (emblem, 0);
  clutter_actor_add_child (box, emblem);
  clutter_color_free (color);

  /* when clicking on the emblem, we want to perform an action */
  action = clutter_click_action_new ();
  clutter_actor_add_action (emblem, action);
  g_signal_connect (action, "clicked", G_CALLBACK (on_emblem_clicked), box);
  g_signal_connect (action, "long-press", G_CALLBACK (on_emblem_long_press), box);

  /* whenever the pointer enters the box, we show the emblem; we hide
   * the emblem when the pointer leaves the box
   */
  g_signal_connect (box,
                    "enter-event", G_CALLBACK (on_box_enter),
                    emblem);
  g_signal_connect (box,
                    "leave-event", G_CALLBACK (on_box_leave),
                    emblem);

  /* a label, that we want to position at the top and center of the box */
  label = clutter_text_new ();
  clutter_actor_set_name (label, "text");
  clutter_text_set_text (CLUTTER_TEXT (label), "A simple test");
  clutter_actor_set_x_expand (label, TRUE);
  clutter_actor_set_x_align (label, CLUTTER_ACTOR_ALIGN_CENTER);
  clutter_actor_set_y_expand (label, TRUE);
  clutter_actor_set_y_align (label, CLUTTER_ACTOR_ALIGN_START);
  clutter_actor_add_child (box, label);

  clutter_main ();

  return EXIT_SUCCESS;
}
예제 #22
0
int
main (int argc, char *argv[])
{
	ClutterActor *stage, *box, *bg, *bg2, *inset, *labelContainer,
	             *contentContainer, *labelbg, *fixed, *upper, *lower, *lowerInner;
	ClutterLayoutManager *layout, *labelContainer_l, *layoutFixed;
	ClutterTimeline *timeline;
	ClutterContent *canvas, *canvas1;

	ClutterColor color_with_trans = {0,0,0,0};
	clutter_x11_set_use_argb_visual (TRUE);

	if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS)
	    return (1);

	/* prepare the stage */
	stage = clutter_stage_new ();
	clutter_stage_set_use_alpha (CLUTTER_STAGE (stage), TRUE);
	clutter_stage_set_color (CLUTTER_STAGE (stage), &color_with_trans);
	clutter_stage_set_title (CLUTTER_STAGE (stage), "IPLocation Database");
	clutter_actor_set_background_color (stage, CLUTTER_COLOR_WHITE);
	clutter_actor_set_size (stage, 648, 246);
	clutter_stage_set_user_resizable (CLUTTER_STAGE (stage), TRUE);
	clutter_actor_show (stage);
	g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL);

	layout = clutter_bin_layout_new (CLUTTER_BIN_ALIGNMENT_CENTER,
			CLUTTER_BIN_ALIGNMENT_CENTER);

	box = clutter_actor_new ();
	clutter_actor_add_constraint (box, clutter_bind_constraint_new (stage, CLUTTER_BIND_SIZE, 0.0));
	clutter_actor_set_background_color (box, CLUTTER_COLOR_WHITE);
	clutter_actor_set_layout_manager (box, layout);
	clutter_actor_add_constraint (box, clutter_align_constraint_new (stage, CLUTTER_ALIGN_X_AXIS, 1));
	clutter_actor_set_name (box, "box");
	clutter_actor_add_child (stage, box);


	bg = clutter_actor_new ();
	//clutter_actor_set_background_color (bg, clutter_color_new (50, 50, 50, 255));
	clutter_actor_set_name (bg, "background");
	clutter_actor_set_reactive (bg, TRUE);
	//clutter_actor_set_x_expand (bg, TRUE);
	//clutter_actor_set_y_expand (bg, TRUE);
	clutter_actor_set_x_align (bg, CLUTTER_ACTOR_ALIGN_END);
	clutter_actor_set_y_align (bg, CLUTTER_ACTOR_ALIGN_FILL);
	canvas1 = clutter_canvas_new ();
	clutter_canvas_set_size (CLUTTER_CANVAS (canvas1), 300, 300);
	clutter_actor_set_content (bg, canvas1);
	/*clutter_actor_set_content_scaling_filters (bg2,
		 CLUTTER_SCALING_FILTER_TRILINEAR,
		 CLUTTER_SCALING_FILTER_LINEAR);*/
	g_object_unref (canvas1);
	clutter_actor_add_child (box, bg);


	bg2 = clutter_actor_new ();
	//clutter_actor_set_background_color (bg2, clutter_color_new (0, 100, 100, 255*.5));
	clutter_actor_set_name (bg2, "background");
	clutter_actor_set_reactive (bg2, TRUE);
	clutter_actor_set_size (bg2, 0, 0);
	//clutter_actor_set_x_expand (bg2, TRUE);
	//clutter_actor_set_y_expand (bg2, TRUE);
	clutter_actor_set_x_align (bg2, CLUTTER_ACTOR_ALIGN_END);
	clutter_actor_set_y_align (bg2, CLUTTER_ACTOR_ALIGN_FILL);
	clutter_actor_set_clip_to_allocation(bg2, TRUE);
	clutter_actor_add_child (box, bg2);
	clutter_actor_set_layout_manager (bg2, clutter_box_layout_new ());
	canvas = clutter_canvas_new ();
	clutter_canvas_set_size (CLUTTER_CANVAS (canvas), 300, 300);
	clutter_actor_set_content (bg2, canvas);
	/*clutter_actor_set_content_scaling_filters (bg2,
		 CLUTTER_SCALING_FILTER_TRILINEAR,
		 CLUTTER_SCALING_FILTER_LINEAR);*/
	g_object_unref (canvas);


	inset = clutter_actor_new ();
	//clutter_actor_set_background_color (inset, clutter_color_new (255, 0, 0, 255));
	clutter_actor_set_name (inset, "inset");
	clutter_actor_set_reactive (inset, TRUE);


	clutter_actor_set_margin_top (inset, 18);
	clutter_actor_set_margin_right (inset, 18);
	clutter_actor_set_margin_bottom (inset, 18);
	clutter_actor_set_margin_left (inset, 48);
	//clutter_actor_set_x_expand (inset, TRUE);
	//clutter_actor_set_y_expand (inset, TRUE);
	clutter_actor_set_x_align (inset, CLUTTER_ACTOR_ALIGN_FILL);
	clutter_actor_set_y_align (inset, CLUTTER_ACTOR_ALIGN_FILL);
	clutter_actor_set_clip_to_allocation(inset, TRUE);
	clutter_actor_add_child (bg2, inset);


	layout = clutter_box_layout_new ();
	clutter_box_layout_set_vertical (CLUTTER_BOX_LAYOUT (layout),
	                                    TRUE);
	clutter_box_layout_set_spacing (CLUTTER_BOX_LAYOUT (layout), 5);
	clutter_actor_set_layout_manager (inset, layout);


	labelContainer = clutter_actor_new ();
	clutter_actor_set_size (labelContainer, 0, 35);
	//clutter_actor_set_background_color (labelContainer, clutter_color_new (34, 134, 158, 255));
	clutter_actor_set_name (labelContainer, "labelContainer");
	clutter_actor_set_reactive (labelContainer, TRUE);
	//clutter_actor_set_x_expand (labelContainer, TRUE);
	//clutter_actor_set_y_expand (labelContainer, TRUE);
	clutter_actor_add_child (inset, labelContainer);

	labelContainer_l = clutter_bin_layout_new (CLUTTER_BIN_ALIGNMENT_CENTER,
			CLUTTER_BIN_ALIGNMENT_CENTER);
	clutter_actor_set_layout_manager (labelContainer, labelContainer_l);


	labelbg = clutter_actor_new ();
	clutter_actor_set_background_color (labelbg, clutter_color_new (34, 134, 158, 255));
	clutter_actor_set_name (labelbg, "labelbg");
	//clutter_actor_set_x_expand (labelbg, TRUE);
	clutter_actor_set_size (labelbg, 0, 35);
	clutter_actor_set_x_align (labelbg, CLUTTER_ACTOR_ALIGN_START);
	clutter_actor_set_y_align (labelbg, CLUTTER_ACTOR_ALIGN_FILL);
	clutter_actor_add_child (labelContainer, labelbg);


	contentContainer = clutter_actor_new ();
	clutter_actor_set_size (contentContainer, 0, 0);

	clutter_actor_set_background_color (contentContainer, clutter_color_new (0.290196*255, 0.427451*255, 0.462745*255, 255));
	clutter_actor_set_name (contentContainer, "labelContainer");
	//clutter_actor_set_x_expand (contentContainer, TRUE);
	//clutter_actor_set_y_expand (contentContainer, TRUE);
	clutter_actor_set_layout_manager (contentContainer, clutter_fixed_layout_new ());
	clutter_actor_add_child (inset, contentContainer);

	fixed = clutter_actor_new ();
	clutter_actor_set_background_color (fixed, clutter_color_new (9, 53, 71, 255));
	clutter_actor_set_name (fixed, "fixed");
	clutter_actor_set_size (fixed, 582, 210-40);
	clutter_actor_set_position (fixed, 582, 0);
	layoutFixed = clutter_box_layout_new ();
	clutter_box_layout_set_vertical (CLUTTER_BOX_LAYOUT (layoutFixed),
		                                TRUE);
	clutter_box_layout_set_spacing (CLUTTER_BOX_LAYOUT (layoutFixed), 8);
	clutter_actor_set_layout_manager (fixed, layoutFixed);
	clutter_actor_add_child (contentContainer, fixed);


	//------------------------------------------------------------------------//

	lower = clutter_actor_new ();
	clutter_actor_set_size (lower, 0, 0);
	clutter_actor_set_name (lower, "lower");
	//clutter_actor_set_x_expand (lower, TRUE);
	//clutter_actor_set_y_expand (lower, TRUE);
	clutter_actor_set_margin_right (lower, 8);
	clutter_actor_set_margin_top (lower, 8);
	clutter_actor_set_margin_left (lower, 8);
	clutter_actor_set_layout_manager (lower, clutter_fixed_layout_new ());
	clutter_actor_set_clip_to_allocation(lower, TRUE);
	clutter_actor_add_child (fixed, lower);

	lowerInner = clutter_actor_new ();
	clutter_actor_set_background_color (lowerInner, clutter_color_new (255, 255, 255, 30));
	clutter_actor_set_name (lowerInner, "fixed");
	clutter_actor_set_size (lowerInner, 566, 113);
	clutter_actor_set_position (lowerInner, 566, 0);
	clutter_actor_add_child (lower, lowerInner);


	upper = clutter_actor_new ();
	clutter_actor_set_size (upper, 0, 33);
	clutter_actor_set_name (upper, "upper");
	clutter_actor_set_x_expand (upper, TRUE);
	//clutter_actor_set_y_expand (upper, TRUE);
	clutter_actor_set_margin_bottom (upper, 8);
	clutter_actor_set_margin_right (upper, 8);
	clutter_actor_set_margin_left (upper, 8);
	//clutter_actor_set_layout_manager (upper, clutter_fixed_layout_new ());
	clutter_actor_add_child (fixed, upper);


	timeline = clutter_timeline_new (57/24.*1000);
	clutter_timeline_add_marker_at_time(timeline, "first", (40-35)/24.*1000);
	clutter_timeline_add_marker_at_time(timeline, "second", (46-35)/24.*1000);
	clutter_timeline_add_marker_at_time(timeline, "third", (51-35)/24.*1000);
	clutter_timeline_add_marker_at_time(timeline, "fourth", (52-35)/24.*1000);
	clutter_timeline_add_marker_at_time(timeline, "fifth", (58-35)/24.*1000);

	g_signal_connect (timeline, "marker-reached::first", G_CALLBACK (plate1anim), bg);
	g_signal_connect (timeline, "marker-reached::second", G_CALLBACK (plate2anim), bg2);
	g_signal_connect (timeline, "marker-reached::third", G_CALLBACK (plate3anim), labelbg);
	g_signal_connect (timeline, "marker-reached::fourth", G_CALLBACK (plate4anim), fixed);
	g_signal_connect (timeline, "marker-reached::fifth", G_CALLBACK (plate5anim), lowerInner);
	g_signal_connect (canvas1, "draw", G_CALLBACK (draw_1), NULL);
	g_signal_connect (bg, "paint", G_CALLBACK (on_actor_resize), canvas);
	g_signal_connect (canvas, "draw", G_CALLBACK (draw), NULL);
	g_signal_connect (bg2, "paint", G_CALLBACK (on_actor_resize), canvas);


	clutter_content_invalidate (canvas);

	clutter_timeline_start (timeline);
	clutter_main ();

	return (EXIT_SUCCESS);
}
예제 #23
0
int
main (int argc, char *argv[])
{
  ClutterActor *stage, *actor;
  ClutterContent *canvas;
  ClutterTransition *transition;

  /* initialize Clutter */
  if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS)
    return EXIT_FAILURE;

  /* create a stage */
  stage = clutter_stage_new ();
  clutter_stage_set_title (CLUTTER_STAGE (stage), "Rectangle with rounded corners");
  clutter_actor_set_background_color (stage, CLUTTER_COLOR_Black);
  clutter_actor_set_size (stage, 500, 500);
  clutter_actor_show (stage);

  /* our 2D canvas, courtesy of Cairo */
  canvas = clutter_canvas_new ();
  clutter_canvas_set_size (CLUTTER_CANVAS (canvas), 300, 300);

  /* the actor that will display the contents of the canvas */
  actor = clutter_actor_new ();
  clutter_actor_set_content (actor, canvas);
  clutter_actor_set_content_gravity (actor, CLUTTER_CONTENT_GRAVITY_CENTER);
  clutter_actor_set_content_scaling_filters (actor,
                                             CLUTTER_SCALING_FILTER_TRILINEAR,
                                             CLUTTER_SCALING_FILTER_LINEAR);
  clutter_actor_set_pivot_point (actor, 0.5f, 0.5f);
  clutter_actor_add_constraint (actor, clutter_align_constraint_new (stage, CLUTTER_ALIGN_BOTH, 0.5));
  clutter_actor_set_request_mode (actor, CLUTTER_REQUEST_CONTENT_SIZE);
  clutter_actor_add_child (stage, actor);

  /* the actor now owns the canvas */
  g_object_unref (canvas);

  /* create the continuous animation of the actor spinning around its center */
  transition = clutter_property_transition_new ("rotation-angle-y");
  clutter_transition_set_from (transition, G_TYPE_DOUBLE, 0.0);
  clutter_transition_set_to (transition, G_TYPE_DOUBLE, 360.0);
  clutter_timeline_set_duration (CLUTTER_TIMELINE (transition), 2000);
  clutter_timeline_set_repeat_count (CLUTTER_TIMELINE (transition), -1);
  clutter_actor_add_transition (actor, "rotateActor", transition);

  /* the actor now owns the transition */
  g_object_unref (transition);

  /* quit on destroy */
  g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL);

  /* connect our drawing code */
  g_signal_connect (canvas, "draw", G_CALLBACK (draw_content), NULL);

  /* invalidate the canvas, so that we can draw before the main loop starts */
  clutter_content_invalidate (canvas);

  clutter_main ();

  return EXIT_SUCCESS;
}
예제 #24
0
static void _add_app(MetaSwitcher* self, MetaWindow* app, gint* x, gint* y)
{
    MetaSwitcherPrivate* priv = self->priv;

    if (!priv->icons)
        priv->icons = g_hash_table_new(NULL, NULL);

    // container
    ClutterActor* actor = clutter_actor_new();
    WindowPrivate* win_priv = get_window_private(actor);
    win_priv->window = app;
    win_priv->highlight = FALSE;
    g_hash_table_insert(priv->icons, app, actor);

    gint w = APP_ACTOR_WIDTH, h = APP_ACTOR_HEIGHT, screen_width, screen_height;
    /* TODO: @sonald scale app actor width */
    MetaScreen *screen = meta_plugin_get_screen(priv->plugin);
    meta_screen_get_size(screen, &screen_width, &screen_height);
    if (priv->apps->len)
        w = (screen_width - priv->apps->len * APP_ICON_PADDING) / priv->apps->len;

    if (w > APP_ACTOR_WIDTH)
        w = APP_ACTOR_WIDTH;

    // add children
    ClutterContent* canvas = clutter_canvas_new();
    g_signal_connect(canvas, "draw", G_CALLBACK(on_icon_background_draw), actor);
    clutter_canvas_set_size(CLUTTER_CANVAS(canvas), w, h);

    ClutterActor* bg = clutter_actor_new();
    clutter_actor_set_name(bg, "bg");
    clutter_actor_set_content(bg, canvas);
    g_object_unref(canvas);

    clutter_actor_set_size(bg, w, h);
    g_object_set(bg, "x-expand", TRUE, "y-expand", TRUE, "x-align", CLUTTER_ACTOR_ALIGN_FILL,
            "y-align", CLUTTER_ACTOR_ALIGN_FILL, NULL);
    clutter_actor_add_child(actor, bg);

    ClutterActor* icon = load_icon_for_window(self, app);
    if (icon) clutter_actor_add_child(actor, icon);

    ClutterActor* label = clutter_text_new();
    clutter_actor_add_child(actor, label);
    clutter_text_set_text(CLUTTER_TEXT(label), meta_window_get_title(app));
    clutter_text_set_font_name(CLUTTER_TEXT(label), "Sans 10");
    ClutterColor clr = {0xff, 0xff, 0xff, 0xff};
    clutter_text_set_color(CLUTTER_TEXT(label), &clr);
    clutter_text_set_ellipsize(CLUTTER_TEXT(label), PANGO_ELLIPSIZE_END);
    g_object_set(label, "x-align", CLUTTER_ACTOR_ALIGN_CENTER, "y-align", CLUTTER_ACTOR_ALIGN_CENTER, NULL);

    gfloat pref_width = clutter_actor_get_width(label);
    if (pref_width > w - 10) {
        pref_width = w - 10;
        clutter_actor_set_width(label, pref_width);
    }
    /* TODO: @sonald adjust app title position */
    clutter_actor_set_position(label, (w - pref_width) / 2, APP_ICON_SIZE + 2);

    g_debug("%s: size: %d, %d", __func__, w, h);
    clutter_actor_show(actor);

    clutter_actor_add_child(priv->top, actor);

    *x += w;
}