diff --git a/src/Makefile.am b/src/Makefile.am index 44f9da7c4..d39f6cfde 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -58,6 +58,8 @@ libgnome_shell_la_SOURCES = \ shell-app-system.h \ shell-arrow.c \ shell-arrow.h \ + shell-drawing-area.c \ + shell-drawing-area.h \ shell-embedded-window.c \ shell-embedded-window.h \ shell-embedded-window-private.h \ @@ -73,6 +75,8 @@ libgnome_shell_la_SOURCES = \ shell-global.h \ shell-status-menu.c \ shell-status-menu.h \ + shell-stack.c \ + shell-stack.h \ shell-tray-manager.c \ shell-tray-manager.h \ shell-texture-cache.c \ diff --git a/src/shell-drawing-area.c b/src/shell-drawing-area.c new file mode 100644 index 000000000..78a7e94e8 --- /dev/null +++ b/src/shell-drawing-area.c @@ -0,0 +1,92 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/** + * SECTION:shell-drawing-area + * @short_description: A dynamically-sized Cairo drawing area + * + * #ShellDrawingArea is similar to #ClutterCairoTexture in that + * it allows drawing via Cairo; the primary difference is that + * it is dynamically sized. To use, connect to the @redraw + * signal, and inside the signal handler, call + * clutter_cairo_texture_create() to begin drawing. + */ + +#include "shell-drawing-area.h" + +#include +#include +#include + +G_DEFINE_TYPE(ShellDrawingArea, shell_drawing_area, CLUTTER_TYPE_GROUP); + +struct _ShellDrawingAreaPrivate { + ClutterCairoTexture *texture; +}; + +/* Signals */ +enum +{ + REDRAW, + LAST_SIGNAL +}; + +static guint shell_drawing_area_signals [LAST_SIGNAL] = { 0 }; + +static void +shell_drawing_area_allocate (ClutterActor *self, + const ClutterActorBox *box, + ClutterAllocationFlags flags) +{ + ShellDrawingArea *area = SHELL_DRAWING_AREA (self); + int width = box->x2 - box->x1; + int height = box->y2 - box->y1; + + clutter_actor_allocate (CLUTTER_ACTOR (area->priv->texture), box, flags); + if (width > 0 && height > 0) + { + clutter_cairo_texture_set_surface_size (area->priv->texture, + width, height); + g_signal_emit (G_OBJECT (self), shell_drawing_area_signals[REDRAW], 0, + area->priv->texture); + } +} + +static void +shell_drawing_area_class_init (ShellDrawingAreaClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass); + + actor_class->allocate = shell_drawing_area_allocate; + + shell_drawing_area_signals[REDRAW] = + g_signal_new ("redraw", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (ShellDrawingAreaClass, redraw), + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, G_TYPE_OBJECT); + + g_type_class_add_private (gobject_class, sizeof (ShellDrawingAreaPrivate)); +} + +static void +shell_drawing_area_init (ShellDrawingArea *area) +{ + area->priv = G_TYPE_INSTANCE_GET_PRIVATE (area, SHELL_TYPE_DRAWING_AREA, + ShellDrawingAreaPrivate); + area->priv->texture = CLUTTER_CAIRO_TEXTURE (clutter_cairo_texture_new (1, 1)); + clutter_container_add_actor (CLUTTER_CONTAINER (area), CLUTTER_ACTOR (area->priv->texture)); +} + +/** + * shell_drawing_area_get_texture: + * + * Return Value: (transfer none): + */ +ClutterCairoTexture * +shell_drawing_area_get_texture (ShellDrawingArea *area) +{ + return area->priv->texture; +} diff --git a/src/shell-drawing-area.h b/src/shell-drawing-area.h new file mode 100644 index 000000000..7a4eef918 --- /dev/null +++ b/src/shell-drawing-area.h @@ -0,0 +1,37 @@ +#ifndef __SHELL_DRAWING_AREA_H__ +#define __SHELL_DRAWING_AREA_H__ + +#include +#include + +#define SHELL_TYPE_DRAWING_AREA (shell_drawing_area_get_type ()) +#define SHELL_DRAWING_AREA(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SHELL_TYPE_DRAWING_AREA, ShellDrawingArea)) +#define SHELL_DRAWING_AREA_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SHELL_TYPE_DRAWING_AREA, ShellDrawingAreaClass)) +#define SHELL_IS_DRAWING_AREA(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SHELL_TYPE_DRAWING_AREA)) +#define SHELL_IS_DRAWING_AREA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SHELL_TYPE_DRAWING_AREA)) +#define SHELL_DRAWING_AREA_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SHELL_TYPE_DRAWING_AREA, ShellDrawingAreaClass)) + +typedef struct _ShellDrawingArea ShellDrawingArea; +typedef struct _ShellDrawingAreaClass ShellDrawingAreaClass; + +typedef struct _ShellDrawingAreaPrivate ShellDrawingAreaPrivate; + +struct _ShellDrawingArea +{ + ClutterGroup parent; + + ShellDrawingAreaPrivate *priv; +}; + +struct _ShellDrawingAreaClass +{ + ClutterGroupClass parent_class; + + void (*redraw) (ShellDrawingArea *area, ClutterCairoTexture *texture); +}; + +GType shell_drawing_area_get_type (void) G_GNUC_CONST; + +ClutterCairoTexture *shell_drawing_area_get_texture (ShellDrawingArea *area); + +#endif /* __SHELL_DRAWING_AREA_H__ */ diff --git a/src/shell-stack.c b/src/shell-stack.c new file mode 100644 index 000000000..dedd9b298 --- /dev/null +++ b/src/shell-stack.c @@ -0,0 +1,152 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/** + * SECTION:shell-stack + * @short_description: Pure "Z-axis" container class + * + * A #ShellStack draws its children on top of each other, + * aligned to the top left. It will be sized in width/height + * according to the largest such dimension of its children, and + * all children will be allocated that size. This differs + * from #ClutterGroup which allocates its children their natural + * size, even if that would overflow the size allocated to the stack. + */ + +#include "shell-stack.h" + +G_DEFINE_TYPE (ShellStack, + shell_stack, + CLUTTER_TYPE_GROUP); + +static void +shell_stack_allocate (ClutterActor *self, + const ClutterActorBox *box, + ClutterAllocationFlags flags) +{ + ClutterGroupPrivate *priv = CLUTTER_GROUP (self)->priv; + GList *children, *iter; + + /* chain up to set actor->allocation */ + (CLUTTER_ACTOR_CLASS (g_type_class_peek (clutter_actor_get_type ())))->allocate (self, box, flags); + + children = clutter_container_get_children (CLUTTER_CONTAINER (self)); + for (iter = children; iter; iter = iter->next) + { + ClutterActor *actor = CLUTTER_ACTOR (iter->data); + clutter_actor_allocate (actor, box, flags); + } + g_list_free (children); +} + +static void +shell_stack_get_preferred_height (ClutterActor *actor, + gfloat for_width, + gfloat *min_height_p, + gfloat *natural_height_p) +{ + ShellStack *stack = SHELL_STACK (actor); + gboolean first = TRUE; + float min = 0, natural = 0; + GList *children; + GList *iter; + + children = clutter_container_get_children (CLUTTER_CONTAINER (stack)); + + for (iter = children; iter; iter = iter->next) + { + ClutterActor *child = iter->data; + float child_min, child_natural; + + clutter_actor_get_preferred_height (child, + for_width, + &child_min, + &child_natural); + + if (first) + { + first = FALSE; + min = child_min; + natural = child_natural; + } + else + { + if (child_min > min) + min = child_min; + + if (child_natural > natural) + natural = child_natural; + } + } + + if (min_height_p) + *min_height_p = min; + + if (natural_height_p) + *natural_height_p = natural; + + g_list_free (children); +} + +static void +shell_stack_get_preferred_width (ClutterActor *actor, + gfloat for_height, + gfloat *min_width_p, + gfloat *natural_width_p) +{ + ShellStack *stack = SHELL_STACK (actor); + gboolean first = TRUE; + float min = 0, natural = 0; + GList *iter; + GList *children; + + children = clutter_container_get_children (CLUTTER_CONTAINER (stack)); + + for (iter = children; iter; iter = iter->next) + { + ClutterActor *child = iter->data; + float child_min, child_natural; + + clutter_actor_get_preferred_width (child, + for_height, + &child_min, + &child_natural); + + if (first) + { + first = FALSE; + min = child_min; + natural = child_natural; + } + else + { + if (child_min > min) + min = child_min; + + if (child_natural > natural) + natural = child_natural; + } + } + + if (min_width_p) + *min_width_p = min; + + if (natural_width_p) + *natural_width_p = natural; + g_list_free (children); +} + +static void +shell_stack_class_init (ShellStackClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass); + + actor_class->get_preferred_width = shell_stack_get_preferred_width; + actor_class->get_preferred_height = shell_stack_get_preferred_height; + actor_class->allocate = shell_stack_allocate; +} + +static void +shell_stack_init (ShellStack *actor) +{ +} diff --git a/src/shell-stack.h b/src/shell-stack.h new file mode 100644 index 000000000..ade255cbc --- /dev/null +++ b/src/shell-stack.h @@ -0,0 +1,33 @@ +#ifndef __SHELL_STACK_H__ +#define __SHELL_STACK_H__ + +#include +#include + +#define SHELL_TYPE_STACK (shell_stack_get_type ()) +#define SHELL_STACK(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SHELL_TYPE_STACK, ShellStack)) +#define SHELL_STACK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SHELL_TYPE_STACK, ShellStackClass)) +#define SHELL_IS_STACK(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SHELL_TYPE_STACK)) +#define SHELL_IS_STACK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SHELL_TYPE_STACK)) +#define SHELL_STACK_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SHELL_TYPE_STACK, ShellStackClass)) + +typedef struct _ShellStack ShellStack; +typedef struct _ShellStackClass ShellStackClass; + +typedef struct _ShellStackPrivate ShellStackPrivate; + +struct _ShellStack +{ + ClutterGroup parent; + + ShellStackPrivate *priv; +}; + +struct _ShellStackClass +{ + ClutterGroupClass parent_class; +}; + +GType shell_stack_get_type (void) G_GNUC_CONST; + +#endif /* __SHELL_STACK_H__ */