2008-06-10 Emmanuele Bassi <ebassi@openedhand.com>

Bug #815 - Split up request, allocation, and paint box

	* clutter/clutter-actor.[ch]: Rework the size allocation,
	request and paint area. Now ::request_coords() is called
	::allocate(), and ::query_coords() has been split into
	::get_preferred_width() and ::get_preferred_height(). See
	the documentation and the layout test on how to implement
	a container and layout manager with the new API. (#915,
	based on a patch by Havoc Pennington, Lucas Rocha and Johan
	Bilien)

	* clutter/clutter-clone-texture.c: Port CloneTexture to
	the new size negotiation API; it just means forwarding
	the requests to the parent texture.

	* clutter/clutter-deprecated.h: Add deprecated and replaced
	API.

	* clutter/clutter-entry.c: Port Entry to the new size
	negotiation API.

	* clutter/clutter-group.c: Port Group to the new size
	negotiation API; the semantics of the Group actor do not
	change.

	* clutter/clutter-label.c: Port Label to the new size
	negotiation API, and vastly simplify the code.

	* clutter/clutter-main.[ch]: Add API for executing a
	relayout when needed.

	* clutter/clutter-private.h: Add new Stage private API.

	* clutter/clutter-rectangle.c: Update the get_abs_opacity()
	call to get_paint_opacity().

	* clutter/clutter-stage.c:
	(clutter_stage_get_preferred_width),
	(clutter_stage_get_preferred_height),
	(clutter_stage_allocate),
	(clutter_stage_class_init): Port Stage to the new size
	negotiation API.

	* clutter/clutter-texture.c: Port Texture to the new size
	negotiation API.

	* clutter/clutter-types.h: Add ClutterRequestMode enumeration.

	* clutter/x11/clutter-stage-x11.c: Port the X11 stage
	implementation to the new size negotiation API.

	* tests/Makefile.am: Add the layout manager test case.

	* tests/test-opacity.c: Update.

	* tests/test-project.c: Update.

	* tests/test-layout.c: Test case for a layout manager implemented
	using the new size negotiation API; the layout manager handles
	both transformed and untransformed children.
This commit is contained in:
Emmanuele Bassi 2008-06-10 17:07:52 +00:00
parent fb613411c8
commit 473d0e9fc3
19 changed files with 3976 additions and 1420 deletions

View File

@ -1,3 +1,66 @@
2008-06-10 Emmanuele Bassi <ebassi@openedhand.com>
Bug #815 - Split up request, allocation, and paint box
* clutter/clutter-actor.[ch]: Rework the size allocation,
request and paint area. Now ::request_coords() is called
::allocate(), and ::query_coords() has been split into
::get_preferred_width() and ::get_preferred_height(). See
the documentation and the layout test on how to implement
a container and layout manager with the new API. (#915,
based on a patch by Havoc Pennington, Lucas Rocha and Johan
Bilien)
* clutter/clutter-clone-texture.c: Port CloneTexture to
the new size negotiation API; it just means forwarding
the requests to the parent texture.
* clutter/clutter-deprecated.h: Add deprecated and replaced
API.
* clutter/clutter-entry.c: Port Entry to the new size
negotiation API.
* clutter/clutter-group.c: Port Group to the new size
negotiation API; the semantics of the Group actor do not
change.
* clutter/clutter-label.c: Port Label to the new size
negotiation API, and vastly simplify the code.
* clutter/clutter-main.[ch]: Add API for executing a
relayout when needed.
* clutter/clutter-private.h: Add new Stage private API.
* clutter/clutter-rectangle.c: Update the get_abs_opacity()
call to get_paint_opacity().
* clutter/clutter-stage.c:
(clutter_stage_get_preferred_width),
(clutter_stage_get_preferred_height),
(clutter_stage_allocate),
(clutter_stage_class_init): Port Stage to the new size
negotiation API.
* clutter/clutter-texture.c: Port Texture to the new size
negotiation API.
* clutter/clutter-types.h: Add ClutterRequestMode enumeration.
* clutter/x11/clutter-stage-x11.c: Port the X11 stage
implementation to the new size negotiation API.
* tests/Makefile.am: Add the layout manager test case.
* tests/test-opacity.c: Update.
* tests/test-project.c: Update.
* tests/test-layout.c: Test case for a layout manager implemented
using the new size negotiation API; the layout manager handles
both transformed and untransformed children.
2008-06-10 Emmanuele Bassi <ebassi@openedhand.com>
* Makefile.am: Add the po/ directory to the build.

File diff suppressed because it is too large Load Diff

View File

@ -157,13 +157,13 @@ struct _ClutterActor
/**
* ClutterActorClass:
* @show: signal class handler for ClutterActor::show; it must chain
* @show: signal class handler for #ClutterActor::show; it must chain
* up to the parent's implementation
* @show_all: virtual function for containers and composite actors, to
* determine which children should be shown when calling
* clutter_actor_show_all() on the actor. Defaults to calling
* clutter_actor_show().
* @hide: signal class handler for ClutterActor::hide; it must chain
* @hide: signal class handler for #ClutterActor::hide; it must chain
* up to the parent's implementation
* @hide_all: virtual function for containers and composite actors, to
* determine which children should be shown when calling
@ -172,31 +172,36 @@ struct _ClutterActor
* @realize: virtual function, used to allocate resources for the actor;
* it should chain up to the parent's implementation
* @unrealize: virtual function, used to deallocate resources allocated
* in ::realized; it should chain up to the parent's implementation
* in ::realize; it should chain up to the parent's implementation
* @paint: virtual function, used to paint the actor
* @request_coords: virtual function, used when setting the coordinates
* of an actor
* @query_coords: virtual function, used when querying the actor for
* its coordinates; it must chain up to the parent's implementation
* @parent_set: signal class closure for the ClutterActor::parent-set
* @destroy: signal class closure for ClutterActor::destroy
* @get_preferred_width: virtual function, used when querying the minimum and
* natural widths of an actor
* @get_preferred_height: virtual function, used when querying the minimum and
* natural heights of an actor
* @allocate: virtual function, used when settings the coordinates of an
* actor
* @get_paint_area: virtual function, used when querying the untrasformed
* bounding box of an actor; it's used internally by
* clutter_actor_get_stage_area()
* @parent_set: signal class closure for the #ClutterActor::parent-set
* @destroy: signal class closure for #ClutterActor::destroy
* @pick: virtual function, used to draw an outline of the actor with
* the given colour
* @event: signal class closure for ClutterActor::event
* the given color
* @event: signal class closure for #ClutterActor::event
* @button_press_event: signal class closure for
* ClutterActor::button-press-event
* #ClutterActor::button-press-event
* @button_release_event: signal class closure for
* ClutterActor::button-release-event
* @scroll_event: signal class closure for ClutterActor::scroll-event
* @key_press_event: signal class closure for ClutterActor::key-press-event
* #ClutterActor::button-release-event
* @scroll_event: signal class closure for #ClutterActor::scroll-event
* @key_press_event: signal class closure for #ClutterActor::key-press-event
* @key_release_event: signal class closure for
* ClutterActor::key-release-event
* @motion_event: signal class closure for ClutterActor::motion-event
* @enter_event: signal class closure for ClutterActor::enter-event
* @leave_event: signal class closure for ClutterActor::leave-event
* @captured_event: signal class closure for ClutterActor::captured-event
* @focus_in: signal class closure for ClutterActor::focus-in
* @focus_out: signal class closure for ClutterActor::focus-out
* #ClutterActor::key-release-event
* @motion_event: signal class closure for #ClutterActor::motion-event
* @enter_event: signal class closure for #ClutterActor::enter-event
* @leave_event: signal class closure for #ClutterActor::leave-event
* @captured_event: signal class closure for #ClutterActor::captured-event
* @focus_in: signal class closure for #ClutterActor::focus-in
* @focus_out: signal class closure for #ClutterActor::focus-out
*
* Base class for actors.
*/
@ -206,23 +211,34 @@ struct _ClutterActorClass
GInitiallyUnownedClass parent_class;
/*< public >*/
void (* show) (ClutterActor *actor);
void (* show_all) (ClutterActor *actor);
void (* hide) (ClutterActor *actor);
void (* hide_all) (ClutterActor *actor);
void (* realize) (ClutterActor *actor);
void (* unrealize) (ClutterActor *actor);
void (* paint) (ClutterActor *actor);
void (* request_coords) (ClutterActor *actor,
ClutterActorBox *box);
void (* query_coords) (ClutterActor *actor,
ClutterActorBox *box);
void (* parent_set) (ClutterActor *actor,
ClutterActor *old_parent);
void (* show) (ClutterActor *actor);
void (* show_all) (ClutterActor *actor);
void (* hide) (ClutterActor *actor);
void (* hide_all) (ClutterActor *actor);
void (* realize) (ClutterActor *actor);
void (* unrealize) (ClutterActor *actor);
void (* paint) (ClutterActor *actor);
void (* parent_set) (ClutterActor *actor,
ClutterActor *old_parent);
void (* destroy) (ClutterActor *actor);
void (* pick) (ClutterActor *actor,
const ClutterColor *color);
void (* destroy) (ClutterActor *actor);
void (* pick) (ClutterActor *actor,
const ClutterColor *color);
/* size negotiation */
void (* get_preferred_width) (ClutterActor *actor,
ClutterUnit for_height,
ClutterUnit *min_width_p,
ClutterUnit *natural_width_p);
void (* get_preferred_height) (ClutterActor *actor,
ClutterUnit for_width,
ClutterUnit *min_height_p,
ClutterUnit *natural_height_p);
void (* allocate) (ClutterActor *actor,
const ClutterActorBox *box,
gboolean absolute_origin_changed);
void (* get_paint_area) (ClutterActor *actor,
ClutterActorBox *box);
/* event signals */
gboolean (* event) (ClutterActor *actor,
@ -253,216 +269,246 @@ struct _ClutterActorClass
gpointer _padding_dummy[32];
};
GType clutter_actor_get_type (void) G_GNUC_CONST;
GType clutter_actor_get_type (void) G_GNUC_CONST;
void clutter_actor_show (ClutterActor *self);
void clutter_actor_show_all (ClutterActor *self);
void clutter_actor_hide (ClutterActor *self);
void clutter_actor_hide_all (ClutterActor *self);
void clutter_actor_realize (ClutterActor *self);
void clutter_actor_unrealize (ClutterActor *self);
void clutter_actor_paint (ClutterActor *self);
void clutter_actor_pick (ClutterActor *self,
const ClutterColor *color);
void clutter_actor_queue_redraw (ClutterActor *self);
void clutter_actor_destroy (ClutterActor *self);
void clutter_actor_show (ClutterActor *self);
void clutter_actor_show_all (ClutterActor *self);
void clutter_actor_hide (ClutterActor *self);
void clutter_actor_hide_all (ClutterActor *self);
void clutter_actor_realize (ClutterActor *self);
void clutter_actor_unrealize (ClutterActor *self);
void clutter_actor_paint (ClutterActor *self);
void clutter_actor_pick (ClutterActor *self,
const ClutterColor *color);
void clutter_actor_queue_redraw (ClutterActor *self);
void clutter_actor_queue_relayout (ClutterActor *self);
void clutter_actor_destroy (ClutterActor *self);
void clutter_actor_request_coords (ClutterActor *self,
ClutterActorBox *box);
void clutter_actor_query_coords (ClutterActor *self,
ClutterActorBox *box);
void clutter_actor_set_geometry (ClutterActor *self,
const ClutterGeometry *geometry);
void clutter_actor_get_geometry (ClutterActor *self,
ClutterGeometry *geometry);
void clutter_actor_get_coords (ClutterActor *self,
gint *x_1,
gint *y_1,
gint *x_2,
gint *y_2);
void clutter_actor_set_size (ClutterActor *self,
gint width,
gint height);
void clutter_actor_set_sizeu (ClutterActor *self,
ClutterUnit width,
ClutterUnit height);
void clutter_actor_get_size (ClutterActor *self,
guint *width,
guint *height);
void clutter_actor_get_sizeu (ClutterActor *self,
ClutterUnit *width,
ClutterUnit *height);
void clutter_actor_get_abs_size (ClutterActor *self,
guint *width,
guint *height);
void clutter_actor_set_position (ClutterActor *self,
gint x,
gint y);
void clutter_actor_set_positionu (ClutterActor *self,
ClutterUnit x,
ClutterUnit y);
void clutter_actor_get_position (ClutterActor *self,
gint *x,
gint *y);
void clutter_actor_get_positionu (ClutterActor *self,
ClutterUnit *x,
ClutterUnit *y);
void clutter_actor_get_abs_position (ClutterActor *self,
gint *x,
gint *y);
guint clutter_actor_get_width (ClutterActor *self);
ClutterUnit clutter_actor_get_widthu (ClutterActor *self);
guint clutter_actor_get_height (ClutterActor *self);
ClutterUnit clutter_actor_get_heightu (ClutterActor *self);
void clutter_actor_set_width (ClutterActor *self,
guint width);
void clutter_actor_set_widthu (ClutterActor *self,
ClutterUnit width);
void clutter_actor_set_height (ClutterActor *self,
guint height);
void clutter_actor_set_heightu (ClutterActor *self,
ClutterUnit height);
gint clutter_actor_get_x (ClutterActor *self);
ClutterUnit clutter_actor_get_xu (ClutterActor *self);
gint clutter_actor_get_y (ClutterActor *self);
ClutterUnit clutter_actor_get_yu (ClutterActor *self);
void clutter_actor_set_x (ClutterActor *self,
gint x);
void clutter_actor_set_xu (ClutterActor *self,
ClutterUnit x);
void clutter_actor_set_y (ClutterActor *self,
gint y);
void clutter_actor_set_yu (ClutterActor *self,
ClutterUnit y);
void clutter_actor_set_rotation (ClutterActor *self,
ClutterRotateAxis axis,
gdouble angle,
gint x,
gint y,
gint z);
void clutter_actor_set_rotationx (ClutterActor *self,
ClutterRotateAxis axis,
ClutterFixed angle,
gint x,
gint y,
gint z);
void clutter_actor_set_rotationu (ClutterActor *self,
ClutterRotateAxis axis,
gdouble angle,
ClutterUnit x,
ClutterUnit y,
ClutterUnit z);
gdouble clutter_actor_get_rotation (ClutterActor *self,
ClutterRotateAxis axis,
gint *x,
gint *y,
gint *z);
ClutterFixed clutter_actor_get_rotationx (ClutterActor *self,
ClutterRotateAxis axis,
gint *x,
gint *y,
gint *z);
gdouble clutter_actor_get_rotationu (ClutterActor *self,
ClutterRotateAxis axis,
ClutterUnit *x,
ClutterUnit *y,
ClutterUnit *z);
/* size negotiation */
void clutter_actor_get_preferred_width (ClutterActor *self,
ClutterUnit for_height,
ClutterUnit *min_width_p,
ClutterUnit *natural_width_p);
void clutter_actor_get_preferred_height (ClutterActor *self,
ClutterUnit for_width,
ClutterUnit *min_height_p,
ClutterUnit *natural_height_p);
void clutter_actor_get_preferred_size (ClutterActor *self,
ClutterUnit *min_width_p,
ClutterUnit *min_height_p,
ClutterUnit *natural_width_p,
ClutterUnit *natural_height_p);
void clutter_actor_allocate (ClutterActor *self,
const ClutterActorBox *box,
gboolean absolute_origin_changed);
void clutter_actor_get_allocation_coords (ClutterActor *self,
gint *x1,
gint *y1,
gint *x2,
gint *y2);
void clutter_actor_get_allocation_box (ClutterActor *self,
ClutterActorBox *box);
void clutter_actor_get_allocation_geometry (ClutterActor *self,
ClutterGeometry *geom);
void clutter_actor_get_allocation_vertices (ClutterActor *self,
ClutterActor *ancestor,
ClutterVertex verts[4]);
void clutter_actor_get_paint_area (ClutterActor *self,
ClutterActorBox *box);
void clutter_actor_set_opacity (ClutterActor *self,
guint8 opacity);
guint8 clutter_actor_get_opacity (ClutterActor *self);
guint8 clutter_actor_get_abs_opacity (ClutterActor *self);
void clutter_actor_set_name (ClutterActor *self,
const gchar *name);
G_CONST_RETURN gchar *clutter_actor_get_name (ClutterActor *self);
guint32 clutter_actor_get_gid (ClutterActor *self);
void clutter_actor_set_clip (ClutterActor *self,
gint xoff,
gint yoff,
gint width,
gint height);
void clutter_actor_set_clipu (ClutterActor *self,
ClutterUnit xoff,
ClutterUnit yoff,
ClutterUnit width,
ClutterUnit height);
void clutter_actor_remove_clip (ClutterActor *self);
gboolean clutter_actor_has_clip (ClutterActor *self);
void clutter_actor_get_clip (ClutterActor *self,
gint *xoff,
gint *yoff,
gint *width,
gint *height);
void clutter_actor_get_clipu (ClutterActor *self,
ClutterUnit *xoff,
ClutterUnit *yoff,
ClutterUnit *width,
ClutterUnit *height);
void clutter_actor_set_parent (ClutterActor *self,
ClutterActor *parent);
ClutterActor * clutter_actor_get_parent (ClutterActor *self);
void clutter_actor_reparent (ClutterActor *self,
ClutterActor *new_parent);
void clutter_actor_unparent (ClutterActor *self);
void clutter_actor_raise (ClutterActor *self,
ClutterActor *below);
void clutter_actor_lower (ClutterActor *self,
ClutterActor *above);
void clutter_actor_raise_top (ClutterActor *self);
void clutter_actor_lower_bottom (ClutterActor *self);
void clutter_actor_set_depth (ClutterActor *self,
gint depth);
gint clutter_actor_get_depth (ClutterActor *self);
void clutter_actor_set_depthu (ClutterActor *self,
ClutterUnit depth);
ClutterUnit clutter_actor_get_depthu (ClutterActor *self);
void clutter_actor_set_reactive (ClutterActor *actor,
gboolean reactive);
gboolean clutter_actor_get_reactive (ClutterActor *actor);
void clutter_actor_set_scalex (ClutterActor *self,
ClutterFixed scale_x,
ClutterFixed scale_y);
void clutter_actor_set_scale (ClutterActor *self,
gdouble scale_x,
gdouble scale_y);
void clutter_actor_get_scalex (ClutterActor *self,
ClutterFixed *scale_x,
ClutterFixed *scale_y);
void clutter_actor_get_scale (ClutterActor *self,
gdouble *scale_x,
gdouble *scale_y);
void clutter_actor_set_geometry (ClutterActor *self,
const ClutterGeometry *geometry);
void clutter_actor_get_geometry (ClutterActor *self,
ClutterGeometry *geometry);
void clutter_actor_set_size (ClutterActor *self,
gint width,
gint height);
void clutter_actor_set_sizeu (ClutterActor *self,
ClutterUnit width,
ClutterUnit height);
void clutter_actor_get_size (ClutterActor *self,
guint *width,
guint *height);
void clutter_actor_get_sizeu (ClutterActor *self,
ClutterUnit *width,
ClutterUnit *height);
void clutter_actor_get_transformed_size (ClutterActor *self,
guint *width,
guint *height);
void clutter_actor_get_transformed_sizeu (ClutterActor *self,
ClutterUnit *width,
ClutterUnit *height);
void clutter_actor_set_position (ClutterActor *self,
gint x,
gint y);
void clutter_actor_set_positionu (ClutterActor *self,
ClutterUnit x,
ClutterUnit y);
void clutter_actor_get_position (ClutterActor *self,
gint *x,
gint *y);
void clutter_actor_get_positionu (ClutterActor *self,
ClutterUnit *x,
ClutterUnit *y);
void clutter_actor_get_transformed_position (ClutterActor *self,
gint *x,
gint *y);
void clutter_actor_get_transformed_positionu (ClutterActor *self,
ClutterUnit *x,
ClutterUnit *y);
void clutter_actor_move_by (ClutterActor *self,
gint dx,
gint dy);
void clutter_actor_move_byu (ClutterActor *self,
ClutterUnit dx,
ClutterUnit dy);
void clutter_actor_get_vertices (ClutterActor *self,
ClutterVertex verts[4]);
void clutter_actor_get_relative_vertices (ClutterActor *self,
ClutterActor *ancestor,
ClutterVertex verts[4]);
void clutter_actor_apply_transform_to_point (ClutterActor *self,
ClutterVertex *point,
ClutterVertex *vertex);
void clutter_actor_apply_relative_transform_to_point (ClutterActor *self,
ClutterActor *ancestor,
ClutterVertex *point,
ClutterVertex *vertex);
gboolean clutter_actor_event (ClutterActor *actor,
ClutterEvent *event,
gboolean capture);
ClutterActor * clutter_get_actor_by_gid (guint32 id);
gboolean clutter_actor_get_fixed_position_set (ClutterActor *self);
void clutter_actor_set_fixed_position_set (ClutterActor *self,
gboolean is_set);
gboolean clutter_actor_should_pick_paint (ClutterActor *self);
guint clutter_actor_get_width (ClutterActor *self);
ClutterUnit clutter_actor_get_widthu (ClutterActor *self);
guint clutter_actor_get_height (ClutterActor *self);
ClutterUnit clutter_actor_get_heightu (ClutterActor *self);
void clutter_actor_set_width (ClutterActor *self,
guint width);
void clutter_actor_set_widthu (ClutterActor *self,
ClutterUnit width);
void clutter_actor_set_height (ClutterActor *self,
guint height);
void clutter_actor_set_heightu (ClutterActor *self,
ClutterUnit height);
gint clutter_actor_get_x (ClutterActor *self);
ClutterUnit clutter_actor_get_xu (ClutterActor *self);
gint clutter_actor_get_y (ClutterActor *self);
ClutterUnit clutter_actor_get_yu (ClutterActor *self);
void clutter_actor_set_x (ClutterActor *self,
gint x);
void clutter_actor_set_xu (ClutterActor *self,
ClutterUnit x);
void clutter_actor_set_y (ClutterActor *self,
gint y);
void clutter_actor_set_yu (ClutterActor *self,
ClutterUnit y);
void clutter_actor_set_rotation (ClutterActor *self,
ClutterRotateAxis axis,
gdouble angle,
gint x,
gint y,
gint z);
void clutter_actor_set_rotationx (ClutterActor *self,
ClutterRotateAxis axis,
ClutterFixed angle,
gint x,
gint y,
gint z);
void clutter_actor_set_rotationu (ClutterActor *self,
ClutterRotateAxis axis,
gdouble angle,
ClutterUnit x,
ClutterUnit y,
ClutterUnit z);
gdouble clutter_actor_get_rotation (ClutterActor *self,
ClutterRotateAxis axis,
gint *x,
gint *y,
gint *z);
ClutterFixed clutter_actor_get_rotationx (ClutterActor *self,
ClutterRotateAxis axis,
gint *x,
gint *y,
gint *z);
gdouble clutter_actor_get_rotationu (ClutterActor *self,
ClutterRotateAxis axis,
ClutterUnit *x,
ClutterUnit *y,
ClutterUnit *z);
gboolean clutter_actor_set_shader (ClutterActor *self,
ClutterShader *shader);
ClutterShader * clutter_actor_get_shader (ClutterActor *self);
void clutter_actor_set_shader_param (ClutterActor *self,
const gchar *param,
gfloat value);
void clutter_actor_set_opacity (ClutterActor *self,
guint8 opacity);
guint8 clutter_actor_get_opacity (ClutterActor *self);
guint8 clutter_actor_get_paint_opacity (ClutterActor *self);
void clutter_actor_set_name (ClutterActor *self,
const gchar *name);
G_CONST_RETURN gchar *clutter_actor_get_name (ClutterActor *self);
guint32 clutter_actor_get_gid (ClutterActor *self);
void clutter_actor_set_clip (ClutterActor *self,
gint xoff,
gint yoff,
gint width,
gint height);
void clutter_actor_set_clipu (ClutterActor *self,
ClutterUnit xoff,
ClutterUnit yoff,
ClutterUnit width,
ClutterUnit height);
void clutter_actor_remove_clip (ClutterActor *self);
gboolean clutter_actor_has_clip (ClutterActor *self);
void clutter_actor_get_clip (ClutterActor *self,
gint *xoff,
gint *yoff,
gint *width,
gint *height);
void clutter_actor_get_clipu (ClutterActor *self,
ClutterUnit *xoff,
ClutterUnit *yoff,
ClutterUnit *width,
ClutterUnit *height);
void clutter_actor_set_parent (ClutterActor *self,
ClutterActor *parent);
ClutterActor * clutter_actor_get_parent (ClutterActor *self);
void clutter_actor_reparent (ClutterActor *self,
ClutterActor *new_parent);
void clutter_actor_unparent (ClutterActor *self);
ClutterActor* clutter_actor_get_stage (ClutterActor *actor);
void clutter_actor_raise (ClutterActor *self,
ClutterActor *below);
void clutter_actor_lower (ClutterActor *self,
ClutterActor *above);
void clutter_actor_raise_top (ClutterActor *self);
void clutter_actor_lower_bottom (ClutterActor *self);
void clutter_actor_set_depth (ClutterActor *self,
gint depth);
gint clutter_actor_get_depth (ClutterActor *self);
void clutter_actor_set_depthu (ClutterActor *self,
ClutterUnit depth);
ClutterUnit clutter_actor_get_depthu (ClutterActor *self);
void clutter_actor_set_scalex (ClutterActor *self,
ClutterFixed scale_x,
ClutterFixed scale_y);
void clutter_actor_set_scale (ClutterActor *self,
gdouble scale_x,
gdouble scale_y);
void clutter_actor_get_scalex (ClutterActor *self,
ClutterFixed *scale_x,
ClutterFixed *scale_y);
void clutter_actor_get_scale (ClutterActor *self,
gdouble *scale_x,
gdouble *scale_y);
void clutter_actor_move_by (ClutterActor *self,
gint dx,
gint dy);
void clutter_actor_move_byu (ClutterActor *self,
ClutterUnit dx,
ClutterUnit dy);
void clutter_actor_set_reactive (ClutterActor *actor,
gboolean reactive);
gboolean clutter_actor_get_reactive (ClutterActor *actor);
gboolean clutter_actor_event (ClutterActor *actor,
ClutterEvent *event,
gboolean capture);
ClutterActor * clutter_get_actor_by_gid (guint32 id);
gboolean clutter_actor_set_shader (ClutterActor *self,
ClutterShader *shader);
ClutterShader * clutter_actor_get_shader (ClutterActor *self);
void clutter_actor_set_shader_param (ClutterActor *self,
const gchar *param,
gfloat value);
void clutter_actor_set_anchor_point (ClutterActor *self,
gint anchor_x,
@ -484,9 +530,9 @@ void clutter_actor_get_anchor_pointu (ClutterActor *self,
ClutterUnit *anchor_y);
void clutter_actor_set_anchor_point_from_gravity (ClutterActor *self,
ClutterGravity gravity);
void clutter_actor_move_anchor_point_from_gravity (ClutterActor *self,
ClutterGravity gravity);
gboolean clutter_actor_transform_stage_point (ClutterActor *self,
ClutterUnit x,
ClutterUnit y,
@ -494,12 +540,21 @@ gboolean clutter_actor_transform_stage_point (ClutterActor *self,
ClutterUnit *y_out);
gboolean clutter_actor_is_rotated (ClutterActor *self);
gboolean clutter_actor_is_scaled (ClutterActor *self);
gboolean clutter_actor_should_pick_paint (ClutterActor *self);
void clutter_actor_box_get_from_vertices (ClutterVertex vtx[4],
ClutterActorBox *box);
ClutterActor* clutter_actor_get_stage (ClutterActor *actor);
void clutter_actor_get_abs_allocation_vertices (ClutterActor *self,
ClutterVertex verts[4]);
void clutter_actor_apply_transform_to_point (ClutterActor *self,
ClutterVertex *point,
ClutterVertex *vertex);
void clutter_actor_apply_relative_transform_to_point (ClutterActor *self,
ClutterActor *ancestor,
ClutterVertex *point,
ClutterVertex *vertex);
G_END_DECLS
#endif /* _HAVE_CLUTTER_ACTOR_H */

View File

@ -68,6 +68,74 @@ struct _ClutterCloneTexturePrivate
guint repeat_y : 1;
};
static void
clutter_clone_texture_get_preferred_width (ClutterActor *self,
ClutterUnit for_height,
ClutterUnit *min_width_p,
ClutterUnit *natural_width_p)
{
ClutterCloneTexturePrivate *priv = CLUTTER_CLONE_TEXTURE (self)->priv;
ClutterActor *parent_texture;
ClutterActorClass *parent_texture_class;
/* Note that by calling the get_width_request virtual method directly
* and skipping the clutter_actor_get_preferred_width() wrapper, we
* are ignoring any size request override set on the parent texture
* and just getting the normal size of the parent texture.
*/
parent_texture = CLUTTER_ACTOR (priv->parent_texture);
if (!parent_texture)
{
if (min_width_p)
*min_width_p = 0;
if (natural_width_p)
*natural_width_p = 0;
return;
}
parent_texture_class = CLUTTER_ACTOR_GET_CLASS (parent_texture);
parent_texture_class->get_preferred_width (parent_texture,
for_height,
min_width_p,
natural_width_p);
}
static void
clutter_clone_texture_get_preferred_height (ClutterActor *self,
ClutterUnit for_width,
ClutterUnit *min_height_p,
ClutterUnit *natural_height_p)
{
ClutterCloneTexturePrivate *priv = CLUTTER_CLONE_TEXTURE (self)->priv;
ClutterActor *parent_texture;
ClutterActorClass *parent_texture_class;
/* Note that by calling the get_height_request virtual method directly
* and skipping the clutter_actor_get_preferred_height() wrapper, we
* are ignoring any size request override set on the parent texture and
* just getting the normal size of the parent texture.
*/
parent_texture = CLUTTER_ACTOR (priv->parent_texture);
if (!parent_texture)
{
if (min_height_p)
*min_height_p = 0;
if (natural_height_p)
*natural_height_p = 0;
return;
}
parent_texture_class = CLUTTER_ACTOR_GET_CLASS (parent_texture);
parent_texture_class->get_preferred_height (parent_texture,
for_width,
min_height_p,
natural_height_p);
}
static void
clutter_clone_texture_paint (ClutterActor *self)
{
@ -99,10 +167,10 @@ clutter_clone_texture_paint (ClutterActor *self)
cogl_push_matrix ();
col.alpha = clutter_actor_get_abs_opacity (self);
col.alpha = clutter_actor_get_paint_opacity (self);
cogl_color (&col);
clutter_actor_get_coords (self, &x_1, &y_1, &x_2, &y_2);
clutter_actor_get_allocation_coords (self, &x_1, &y_1, &x_2, &y_2);
CLUTTER_NOTE (PAINT, "paint to x1: %i, y1: %i x2: %i, y2: %i "
"opacity: %i",
@ -156,14 +224,8 @@ set_parent_texture (ClutterCloneTexture *ctexture,
if (texture)
{
gint width, height;
priv->parent_texture = g_object_ref (texture);
/* Sync up the size to parent texture base pixbuf size. */
clutter_texture_get_base_size (texture, &width, &height);
clutter_actor_set_size (actor, width, height);
/* queue a redraw if the cloned texture is already visible */
if (CLUTTER_ACTOR_IS_VISIBLE (priv->parent_texture) &&
was_visible)
@ -171,6 +233,8 @@ set_parent_texture (ClutterCloneTexture *ctexture,
clutter_actor_show (actor);
clutter_actor_queue_redraw (actor);
}
clutter_actor_queue_relayout (actor);
}
}
@ -265,7 +329,12 @@ clutter_clone_texture_class_init (ClutterCloneTextureClass *klass)
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
actor_class->paint = clutter_clone_texture_paint;
actor_class->paint =
clutter_clone_texture_paint;
actor_class->get_preferred_width =
clutter_clone_texture_get_preferred_width;
actor_class->get_preferred_height =
clutter_clone_texture_get_preferred_height;
gobject_class->finalize = clutter_clone_texture_finalize;
gobject_class->dispose = clutter_clone_texture_dispose;

View File

@ -45,4 +45,11 @@
#define clutter_texture_new_from_pixbuf clutter_texture_new_from_pixbuf_DEPRECATED_BY_clutter_texture_new_from_file_OR_clutter_texture_new_AND_clutter_texture_set_from_rgb_data
#define clutter_texture_set_pixbuf clutter_texture_set_pixbuf+DEPRECATED_BY_clutter_texture_set_from_rgb_data
#define clutter_actor_query_coords clutter_actor_query_coords_REPLACED_BY_clutter_actor_get_width_request_AND_clutter_actor_get_height_request
#define clutter_actor_request_coords clutter_actor_request_coords_REPLACED_BY_clutter_actor_allocate
#define clutter_actor_get_abs_position clutter_actor_get_abs_position_REPLACED_BY_clutter_actor_get_transformed_position
#define clutter_actor_get_abs_size clutter_actor_get_abs_size_REPLACED_BY_clutter_actor_get_transformed_size
#define clutter_actor_get_abs_opacity clutter_actor_get_abs_opacity_REPLACED_BY_clutter_actor_get_paint_opacity
#endif /* CLUTTER_DEPRECATED_H */

View File

@ -473,7 +473,7 @@ clutter_entry_paint (ClutterActor *self)
}
memcpy (&color, &priv->fgcol, sizeof (ClutterColor));
color.alpha = clutter_actor_get_abs_opacity (self);
color.alpha = clutter_actor_get_paint_opacity (self);
pango_clutter_render_layout (priv->layout,
priv->text_x + priv->entry_padding, 0,
@ -484,8 +484,9 @@ clutter_entry_paint (ClutterActor *self)
}
static void
clutter_entry_request_coords (ClutterActor *self,
ClutterActorBox *box)
clutter_entry_allocate (ClutterActor *self,
const ClutterActorBox *box,
gboolean absolute_origin_changed)
{
ClutterEntry *entry = CLUTTER_ENTRY (self);
ClutterEntryPrivate *priv = entry->priv;
@ -501,7 +502,7 @@ clutter_entry_request_coords (ClutterActor *self,
priv->width = width;
}
CLUTTER_ACTOR_CLASS (clutter_entry_parent_class)->request_coords (self, box);
CLUTTER_ACTOR_CLASS (clutter_entry_parent_class)->allocate (self, box, absolute_origin_changed);
}
static inline void
@ -633,13 +634,13 @@ clutter_entry_finalize (GObject *object)
static void
clutter_entry_class_init (ClutterEntryClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
klass->paint_cursor = clutter_entry_paint_cursor;
actor_class->paint = clutter_entry_paint;
actor_class->request_coords = clutter_entry_request_coords;
actor_class->allocate = clutter_entry_allocate;
actor_class->key_press_event = clutter_entry_key_press;
gobject_class->finalize = clutter_entry_finalize;

View File

@ -33,7 +33,7 @@
* rotating and clipping of the group will apply to the child actors.
*
* A #ClutterGroup's size is defined by the size and position of its children.
* Resize requests via parent #ClutterActor API will be ignored.
* Resize requests via the #ClutterActor API will be ignored.
*/
#ifdef HAVE_CONFIG_H
@ -83,14 +83,14 @@ struct _ClutterGroupPrivate
static void
clutter_group_paint (ClutterActor *actor)
{
ClutterGroup *self = CLUTTER_GROUP(actor);
GList *child_item;
ClutterGroupPrivate *priv = CLUTTER_GROUP (actor)->priv;
GList *child_item;
CLUTTER_NOTE (PAINT, "ClutterGroup paint enter");
cogl_push_matrix();
cogl_push_matrix ();
for (child_item = self->priv->children;
for (child_item = priv->children;
child_item != NULL;
child_item = child_item->next)
{
@ -102,7 +102,7 @@ clutter_group_paint (ClutterActor *actor)
clutter_actor_paint (child);
}
cogl_pop_matrix();
cogl_pop_matrix ();
CLUTTER_NOTE (PAINT, "ClutterGroup paint leave");
}
@ -137,91 +137,286 @@ clutter_group_pick (ClutterActor *actor,
clutter_group_paint (actor);
}
static void
clutter_group_request_coords (ClutterActor *self,
ClutterActorBox *box)
clutter_fixed_layout_get_preferred_width (GList *children,
ClutterUnit *min_width_p,
ClutterUnit *natural_width_p)
{
ClutterActorBox cbox;
GList *l;
ClutterUnit min_left, min_right;
ClutterUnit natural_left, natural_right;
clutter_actor_query_coords (self, &cbox);
min_left = 0;
min_right = 0;
natural_left = 0;
natural_right = 0;
/* Only positioning works.
* Sizing requests fail, use scale() instead
*/
box->x2 = box->x1 + (cbox.x2 - cbox.x1);
box->y2 = box->y1 + (cbox.y2 - cbox.y1);
for (l = children; l != NULL; l = l->next)
{
ClutterActor *child = l->data;
ClutterUnit child_x, child_min, child_natural;
CLUTTER_ACTOR_CLASS (clutter_group_parent_class)->request_coords (self, box);
child_x = clutter_actor_get_xu (child);
clutter_actor_get_preferred_size (child,
&child_min, NULL,
&child_natural, NULL);
if (l == children)
{
/* First child */
min_left = child_x;
natural_left = child_x;
min_right = min_left + child_min;
natural_right = natural_left + child_natural;
}
else
{
/* Union of extents with previous children */
if (child_x < min_left)
min_left = child_x;
if (child_x < natural_left)
natural_left = child_x;
if (child_x + child_min > min_right)
min_right = child_x + child_min;
if (child_x + child_natural > natural_right)
natural_right = child_x + child_natural;
}
}
/* The preferred size is defined as the width and height we want starting
* from our origin, since our allocation will set the origin; so we now
* need to remove any part of the request that is to the left of the origin.
*/
if (min_left < 0)
min_left = 0;
if (natural_left < 0)
natural_left = 0;
if (min_right < 0)
min_right = 0;
if (natural_right < 0)
natural_right = 0;
g_assert (min_right >= min_left);
g_assert (natural_right >= natural_left);
if (min_width_p)
*min_width_p = min_right - min_left;
if (natural_width_p)
*natural_width_p = natural_right - min_left;
}
static void
clutter_group_query_coords (ClutterActor *self,
ClutterActorBox *box)
clutter_fixed_layout_get_preferred_height (GList *children,
ClutterUnit *min_height_p,
ClutterUnit *natural_height_p)
{
ClutterGroupPrivate *priv;
GList *child_item;
GList *l;
ClutterUnit min_top, min_bottom;
ClutterUnit natural_top, natural_bottom;
priv = CLUTTER_GROUP(self)->priv;
min_top = 0;
min_bottom = 0;
natural_top = 0;
natural_bottom = 0;
child_item = priv->children;
/* FIXME: Cache these values */
box->x2 = box->x1;
box->y2 = box->y1;
if (child_item)
for (l = children; l != NULL; l = l->next)
{
do
{
ClutterActor *child = CLUTTER_ACTOR(child_item->data);
ClutterActorBox cbox;
ClutterActor *child = l->data;
ClutterUnit child_y, child_min, child_natural;
#if 0 /* XXX - Leave this post 0.6 ??? */
if (clutter_actor_is_scaled (child) ||
clutter_actor_is_rotated (child))
{
ClutterVertex vtx[4];
child_y = clutter_actor_get_yu (child);
clutter_actor_get_relative_vertices (child, self, vtx);
clutter_actor_box_get_from_vertices (vtx, &cbox);
}
else
#endif
{
gint anchor_x;
gint anchor_y;
clutter_actor_get_preferred_size (child,
NULL, &child_min,
NULL, &child_natural);
clutter_actor_query_coords (child, &cbox);
if (l == children)
{
/* First child */
min_top = child_y;
natural_top = child_y;
min_bottom = min_top + child_min;
natural_bottom = natural_top + child_natural;
}
else
{
/* Union of extents with previous children */
if (child_y < min_top)
min_top = child_y;
/*
* Must adjust these by the anchor point, as we need the box
* to be relative to the top-left corner of the parent
*/
clutter_actor_get_anchor_pointu (child, &anchor_x, &anchor_y);
if (child_y < natural_top)
natural_top = child_y;
cbox.x1 -= anchor_x;
cbox.x2 -= anchor_x;
cbox.y1 -= anchor_y;
cbox.y2 -= anchor_y;
}
if (child_y + child_min > min_bottom)
min_bottom = child_y + child_min;
/* FIXME: now that we go into the trouble of working out the
* projected sizes, we should do better than this (probably resize
* the box in all direction as required).
*
* Ignore any children with offscreen ( negaive )
* positions.
*
* Also x1 and x2 will be set by parent caller.
*/
if (box->x2 - box->x1 < cbox.x2)
box->x2 = cbox.x2 + box->x1;
if (child_y + child_natural > natural_bottom)
natural_bottom = child_y + child_natural;
}
}
if (box->y2 - box->y1 < cbox.y2)
box->y2 = cbox.y2 + box->y1;
}
while ((child_item = g_list_next(child_item)) != NULL);
/* The preferred size is defined as the width and height we want starting
* from our origin, since our allocation will set the origin; so we now
* need to remove any part of the request that is above the origin.
*/
if (min_top < 0)
min_top = 0;
if (natural_top < 0)
natural_top = 0;
if (min_bottom < 0)
min_bottom = 0;
if (natural_bottom < 0)
natural_bottom = 0;
g_assert (min_bottom >= min_top);
g_assert (natural_bottom >= natural_top);
if (min_height_p)
*min_height_p = min_bottom - min_top;
if (natural_height_p)
*natural_height_p = natural_bottom - min_top;
}
static void
clutter_fixed_layout_allocate (GList *children,
gboolean absolute_origin_changed)
{
GList *l;
for (l = children; l != NULL; l = l->next)
{
ClutterActor *child = l->data;
ClutterUnit child_x, child_y;
ClutterUnit natural_width, natural_height;
ClutterActorBox child_box;
child_x = clutter_actor_get_xu (child);
child_y = clutter_actor_get_yu (child);
/* All children get their position and natural size (the
* container's allocation is flat-out ignored).
*/
clutter_actor_get_preferred_size (child,
NULL, NULL,
&natural_width,
&natural_height);
child_box.x1 = child_x;
child_box.y1 = child_y;
child_box.x2 = child_box.x1 + natural_width;
child_box.y2 = child_box.y1 + natural_height;
clutter_actor_allocate (child, &child_box, absolute_origin_changed);
}
}
static void
clutter_group_get_preferred_width (ClutterActor *self,
ClutterUnit for_height,
ClutterUnit *min_width_p,
ClutterUnit *natural_width_p)
{
ClutterGroupPrivate *priv = CLUTTER_GROUP (self)->priv;
/* for_height is irrelevant to the fixed layout, so it's not used */
clutter_fixed_layout_get_preferred_width (priv->children,
min_width_p,
natural_width_p);
}
static void
clutter_group_get_preferred_height (ClutterActor *self,
ClutterUnit for_width,
ClutterUnit *min_height_p,
ClutterUnit *natural_height_p)
{
ClutterGroupPrivate *priv = CLUTTER_GROUP (self)->priv;
/* for_width is irrelevant to the fixed layout, so it's not used */
clutter_fixed_layout_get_preferred_height (priv->children,
min_height_p,
natural_height_p);
}
static void
clutter_group_allocate (ClutterActor *self,
const ClutterActorBox *box,
gboolean origin_changed)
{
ClutterGroupPrivate *priv = CLUTTER_GROUP (self)->priv;
/* chain up to set actor->allocation */
CLUTTER_ACTOR_CLASS (clutter_group_parent_class)->allocate (self, box,
origin_changed);
/* Note that fixed-layout allocation of children does not care what
* allocation the container received, so "box" is not passed in
* here. We do not require that children's allocations are completely
* contained by our own.
*/
clutter_fixed_layout_allocate (priv->children, origin_changed);
}
static void
clutter_group_get_paint_area (ClutterActor *self,
ClutterActorBox *box)
{
ClutterGroupPrivate *priv = CLUTTER_GROUP (self)->priv;
/* Our area is the union of all child boxes. */
if (!priv->children)
{
/* Only get our allocation if no children;
* if we do have children, we don't want this
* because the allocation is based on the children's
* untransformed layout, and we want the union of
* their transformed boxes (their paint boxes).
*/
clutter_actor_get_allocation_box (self, box);
}
else
{
ClutterActorBox all_box = { 0, }; /* initialize to silence gcc */
GList *l;
for (l = priv->children; l != NULL; l = l->next)
{
ClutterActor *child = l->data;
ClutterActorBox child_box = { 0, };
clutter_actor_get_paint_area (child, &child_box);
if (l == priv->children)
all_box = child_box;
else
{
if (child_box.x1 < all_box.x1)
all_box.x1 = child_box.x1;
if (child_box.y1 < all_box.y1)
all_box.y1 = child_box.y1;
if (child_box.x2 > all_box.x2)
all_box.x2 = child_box.x2;
if (child_box.y2 > all_box.y2)
all_box.y2 = child_box.y2;
}
}
*box = all_box;
}
}
@ -234,6 +429,8 @@ clutter_group_dispose (GObject *object)
if (priv->children)
{
g_list_foreach (priv->children, (GFunc) clutter_actor_destroy, NULL);
g_list_free (priv->children);
priv->children = NULL;
}
@ -277,6 +474,11 @@ clutter_group_real_add (ClutterContainer *container,
priv->children = g_list_append (priv->children, actor);
clutter_actor_set_parent (actor, CLUTTER_ACTOR (group));
/* queue a relayout, to get the correct positioning inside
* the ::actor-added signal handlers
*/
clutter_actor_queue_relayout (CLUTTER_ACTOR (group));
g_signal_emit_by_name (container, "actor-added", actor);
clutter_group_sort_depth_order (group);
@ -303,6 +505,11 @@ clutter_group_real_remove (ClutterContainer *container,
priv->children = g_list_remove (priv->children, actor);
clutter_actor_unparent (actor);
/* queue a relayout, to get the correct positioning inside
* the ::actor-removed signal handlers
*/
clutter_actor_queue_relayout (CLUTTER_ACTOR (group));
/* at this point, the actor passed to the "actor-removed" signal
* handlers is not parented anymore to the container but since we
* are holding a reference on it, it's still valid
@ -459,11 +666,14 @@ clutter_group_class_init (ClutterGroupClass *klass)
actor_class->pick = clutter_group_pick;
actor_class->show_all = clutter_group_real_show_all;
actor_class->hide_all = clutter_group_real_hide_all;
actor_class->request_coords = clutter_group_request_coords;
actor_class->query_coords = clutter_group_query_coords;
actor_class->realize = clutter_group_realize;
actor_class->unrealize = clutter_group_unrealize;
actor_class->get_preferred_width = clutter_group_get_preferred_width;
actor_class->get_preferred_height = clutter_group_get_preferred_height;
actor_class->allocate = clutter_group_allocate;
actor_class->get_paint_area = clutter_group_get_paint_area;
/**
* ClutterGroup::add:
* @group: the #ClutterGroup that received the signal

View File

@ -48,7 +48,7 @@
G_DEFINE_TYPE (ClutterLabel, clutter_label, CLUTTER_TYPE_ACTOR)
/* Probably move into main */
static PangoContext *_context = NULL;
static PangoContext *_context = NULL;
enum
{
@ -75,8 +75,6 @@ struct _ClutterLabelPrivate
ClutterColor fgcol;
ClutterActorBox allocation;
gchar *text;
gchar *font_name;
@ -95,194 +93,83 @@ struct _ClutterLabelPrivate
PangoAttrList *attrs;
PangoAttrList *effective_attrs;
PangoLayout *layout;
gint width_chars;
gint wrap_width;
};
static gint
get_label_char_width (ClutterLabel *label)
/*
* clutter_label_create_layout:
* @label: a #ClutterLabel
* @allocation_width: the width of the layout, or -1
*
* Creates a new #PangoLayout for the given @allocation_width, using
* the layout properties of the @label.
*/
static PangoLayout *
clutter_label_create_layout (ClutterLabel *label,
ClutterUnit allocation_width)
{
ClutterLabelPrivate *priv = label->priv;
PangoContext *context;
PangoFontMetrics *metrics;
gint char_width, digit_width, char_pixels, w;
context = pango_layout_get_context (priv->layout);
metrics = pango_context_get_metrics (context, priv->font_desc,
pango_context_get_language (context));
char_width = pango_font_metrics_get_approximate_char_width (metrics);
digit_width = pango_font_metrics_get_approximate_digit_width (metrics);
char_pixels = MAX (char_width, digit_width);
pango_font_metrics_unref (metrics);
PangoLayout *layout;
if (priv->width_chars < 0)
layout = pango_layout_new (_context);
if (priv->effective_attrs)
pango_layout_set_attributes (layout, priv->effective_attrs);
pango_layout_set_alignment (layout, priv->alignment);
pango_layout_set_single_paragraph_mode (layout, priv->single_line_mode);
pango_layout_set_font_description (layout, priv->font_desc);
pango_layout_set_justify (layout, priv->justify);
if (priv->text)
{
PangoRectangle rect;
pango_layout_set_width (priv->layout, -1);
pango_layout_get_extents (priv->layout, NULL, &rect);
w = char_pixels * 5;
w = MIN (rect.width, w);
}
else
{
/* enforce minimum width for ellipsized labels at ~5 chars */
w = char_pixels * MAX (priv->width_chars, 5);
}
return w;
}
static gint
get_label_wrap_width (ClutterLabel *label)
{
ClutterLabelPrivate *priv = label->priv;
if (priv->wrap_width < 0)
{
if (priv->width_chars > 0)
priv->wrap_width = get_label_char_width (label);
if (!priv->use_markup)
pango_layout_set_text (layout, priv->text, -1);
else
{
PangoLayout *tmp;
tmp = pango_layout_new (_context);
pango_layout_set_font_description (tmp, priv->font_desc);
pango_layout_set_text (tmp, "This is a very long string, which "
"should be enough for a wrap width.",
-1);
pango_layout_get_size (tmp, &priv->wrap_width, NULL);
g_object_unref (tmp);
}
pango_layout_set_markup (layout, priv->text, -1);
}
return priv->wrap_width;
}
static void
clutter_label_ensure_layout (ClutterLabel *label)
{
ClutterLabelPrivate *priv;
ClutterUnit raw_width;
gint width;
priv = label->priv;
/* use the last size requested, if any */
raw_width = priv->allocation.x2 - priv->allocation.x1;
width = CLUTTER_UNITS_TO_DEVICE (raw_width);
if (!priv->layout)
if (allocation_width > 0)
{
priv->layout = pango_layout_new (_context);
int layout_width, layout_height;
if (priv->effective_attrs)
pango_layout_set_attributes (priv->layout, priv->effective_attrs);
pango_layout_set_alignment (priv->layout, priv->alignment);
pango_layout_set_ellipsize (priv->layout, priv->ellipsize);
pango_layout_set_single_paragraph_mode (priv->layout,
priv->single_line_mode);
pango_layout_set_font_description (priv->layout, priv->font_desc);
pango_layout_set_justify (priv->layout, priv->justify);
if (priv->text)
{
if (!priv->use_markup)
pango_layout_set_text (priv->layout, priv->text, -1);
else
pango_layout_set_markup (priv->layout, priv->text, -1);
}
if (priv->ellipsize != PANGO_ELLIPSIZE_NONE)
pango_layout_set_width (priv->layout, raw_width > 0 ? CLUTTER_UNITS_TO_PANGO_UNIT (raw_width)
: -1);
else if (priv->wrap)
pango_layout_get_size (layout, &layout_width, &layout_height);
/* No need to set ellipsize or wrap if we already have enough
* space, since we don't want to make the layout wider than it
* would be otherwise.
*/
if (CLUTTER_UNITS_FROM_PANGO_UNIT (layout_width) > allocation_width)
{
pango_layout_set_wrap (priv->layout, priv->wrap_mode);
if (width > 0)
pango_layout_set_width (priv->layout, CLUTTER_UNITS_TO_PANGO_UNIT (raw_width));
else
if (priv->ellipsize != PANGO_ELLIPSIZE_NONE)
{
/* this was adapted from the GtkLabel code */
ClutterActor *stage = clutter_stage_get_default ();
gint stage_width = clutter_actor_get_width (stage);
gint longest_paragraph, height, wrap_width;
PangoRectangle logical_rect;
gint width;
pango_layout_set_width (priv->layout, -1);
pango_layout_get_extents (priv->layout, NULL, &logical_rect);
width = allocation_width > 0
? CLUTTER_UNITS_TO_PANGO_UNIT (allocation_width)
: -1;
width = logical_rect.width;
longest_paragraph = width;
wrap_width = get_label_wrap_width (label);
width = MAX (width, wrap_width);
width = MIN (width, PANGO_SCALE * (stage_width + 1) / 2);
pango_layout_set_width (priv->layout, width);
pango_layout_get_extents (priv->layout, NULL, &logical_rect);
width = logical_rect.width;
height = logical_rect.height;
if (longest_paragraph > 0)
{
gint n_lines, perfect_width;
n_lines = pango_layout_get_line_count (priv->layout);
perfect_width = (longest_paragraph + n_lines - 1) / n_lines;
if (perfect_width < width)
{
pango_layout_set_width (priv->layout, perfect_width);
pango_layout_get_extents (priv->layout, NULL,
&logical_rect);
if (logical_rect.height <= height)
width = logical_rect.width = width;
else
{
gint mid_width = (perfect_width + width) / 2;
if (mid_width > perfect_width)
{
pango_layout_set_width (priv->layout, mid_width);
pango_layout_get_extents (priv->layout, NULL,
&logical_rect);
if (logical_rect.height <= height);
width = logical_rect.width;
}
}
}
}
pango_layout_set_width (priv->layout, width);
pango_layout_set_ellipsize (layout, priv->ellipsize);
pango_layout_set_width (layout, width);
}
}
else
pango_layout_set_width (priv->layout, raw_width > 0 ? CLUTTER_UNITS_TO_PANGO_UNIT (raw_width)
: -1);
else if (priv->wrap)
{
gint width;
/* Prime the glyph cache */
pango_clutter_ensure_glyph_cache_for_layout (priv->layout);
width = allocation_width > 0
? CLUTTER_UNITS_TO_PANGO_UNIT (allocation_width)
: -1;
pango_layout_set_wrap (layout, priv->wrap_mode);
pango_layout_set_width (layout, width);
}
}
}
CLUTTER_NOTE (ACTOR, "Label width set to %d pixels", width);
}
pango_clutter_ensure_glyph_cache_for_layout (layout);
static void
clutter_label_clear_layout (ClutterLabel *label)
{
if (label->priv->layout)
{
g_object_unref (label->priv->layout);
label->priv->layout = NULL;
}
return layout;
}
static void
@ -294,8 +181,7 @@ clutter_label_paint (ClutterActor *self)
if (priv->font_desc == NULL || priv->text == NULL)
{
CLUTTER_NOTE (ACTOR, "layout: %p, desc: %p, text %p",
priv->layout,
CLUTTER_NOTE (ACTOR, "desc: %p, text %p",
priv->font_desc ? priv->font_desc : 0x0,
priv->text ? priv->text : 0x0);
return;
@ -303,85 +189,115 @@ clutter_label_paint (ClutterActor *self)
CLUTTER_NOTE (PAINT, "painting label (text:`%s')", priv->text);
clutter_label_ensure_layout (label);
/* XXX - this should never happen, as the layout is always
* recreated when the label allocation changes
*/
if (G_UNLIKELY (!priv->layout))
{
ClutterActorBox alloc = { 0, };
clutter_actor_get_allocation_box (self, &alloc);
priv->layout = clutter_label_create_layout (label, alloc.x2 - alloc.x1);
}
memcpy (&color, &priv->fgcol, sizeof (ClutterColor));
color.alpha = clutter_actor_get_abs_opacity (self);
color.alpha = clutter_actor_get_paint_opacity (self);
pango_clutter_render_layout (priv->layout, 0, 0, &color, 0);
}
static void
clutter_label_query_coords (ClutterActor *self,
ClutterActorBox *box)
{
ClutterLabel *label = CLUTTER_LABEL(self);
ClutterLabelPrivate *priv;
ClutterActorBox layout_box = { 0, };
PangoRectangle logical_rect;
clutter_label_get_preferred_width (ClutterActor *self,
ClutterUnit for_height,
ClutterUnit *min_width_p,
ClutterUnit *natural_width_p)
{
ClutterLabel *label = CLUTTER_LABEL (self);
ClutterLabelPrivate *priv = label->priv;
PangoRectangle logical_rect = { 0, };
PangoLayout *layout;
priv = label->priv;
/* we create a layout to compute the width request; we ignore the
* passed height because ClutterLabel is a height-for-width actor
*/
layout = clutter_label_create_layout (label, -1);
if (priv->wrap)
clutter_label_clear_layout (label);
pango_layout_get_extents (layout, NULL, &logical_rect);
clutter_label_ensure_layout (label);
pango_layout_get_extents (priv->layout, NULL, &logical_rect);
layout_box.x1 = box->x1;
layout_box.x2 = box->x1 + CLUTTER_UNITS_FROM_PANGO_UNIT (logical_rect.width);
layout_box.y1 = box->y1;
layout_box.y2 = box->y1 + CLUTTER_UNITS_FROM_PANGO_UNIT (logical_rect.height);
if ((priv->allocation.x2 - priv->allocation.x1) > 0)
if (min_width_p)
{
ClutterUnit alloc_width, alloc_height;
alloc_width = priv->allocation.x2 - priv->allocation.x1;
alloc_height = priv->allocation.y2 - priv->allocation.y1;
if ((alloc_width >= (layout_box.x2 - layout_box.x1)) &&
(alloc_height >= (layout_box.y2 - layout_box.y1)))
*box = priv->allocation;
if (priv->wrap || priv->ellipsize)
*min_width_p = 1;
else
*box = layout_box;
return;
*min_width_p = CLUTTER_UNITS_FROM_PANGO_UNIT (logical_rect.width);
}
else
*box = layout_box;
if (natural_width_p)
*natural_width_p = CLUTTER_UNITS_FROM_PANGO_UNIT (logical_rect.width);
g_object_unref (layout);
}
static void
clutter_label_request_coords (ClutterActor *self,
ClutterActorBox *box)
clutter_label_get_preferred_height (ClutterActor *self,
ClutterUnit for_width,
ClutterUnit *min_height_p,
ClutterUnit *natural_height_p)
{
ClutterLabel *label = CLUTTER_LABEL (self);
if (for_width == 0)
{
if (min_height_p)
*min_height_p = 0;
if (natural_height_p)
*natural_height_p = 0;
}
else
{
PangoLayout *layout;
PangoRectangle logical_rect = { 0, };
ClutterUnit height;
/* we create a new layout to compute the height for the
* given width and then discard it
*/
layout = clutter_label_create_layout (label, for_width);
pango_layout_get_extents (layout, NULL, &logical_rect);
height = CLUTTER_UNITS_FROM_PANGO_UNIT (logical_rect.height);
if (min_height_p)
*min_height_p = height;
if (natural_height_p)
*natural_height_p = height;
g_object_unref (layout);
}
}
static void
clutter_label_allocate (ClutterActor *self,
const ClutterActorBox *box,
gboolean origin_changed)
{
ClutterLabel *label = CLUTTER_LABEL (self);
ClutterLabelPrivate *priv = label->priv;
ClutterActorClass *parent_class;
if (priv->ellipsize)
/* the allocation was changed, so we must recreate the layout */
if (priv->layout)
{
if (priv->layout)
{
gint width;
PangoRectangle logical;
width = CLUTTER_UNITS_TO_PANGO_UNIT (box->x2 - box->x1);
pango_layout_set_width (priv->layout, -1);
pango_layout_get_extents (priv->layout, NULL, &logical);
if (logical.width > width)
pango_layout_set_width (priv->layout, width);
}
g_object_unref (priv->layout);
priv->layout = NULL;
}
else
clutter_label_clear_layout (label);
priv->allocation = *box;
priv->layout = clutter_label_create_layout (label, box->x2 - box->x1);
CLUTTER_ACTOR_CLASS (clutter_label_parent_class)->request_coords (self, box);
parent_class = CLUTTER_ACTOR_CLASS (clutter_label_parent_class);
parent_class->allocate (self, box, origin_changed);
}
static void
@ -532,9 +448,10 @@ clutter_label_class_init (ClutterLabelClass *klass)
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
actor_class->paint = clutter_label_paint;
actor_class->request_coords = clutter_label_request_coords;
actor_class->query_coords = clutter_label_query_coords;
actor_class->paint = clutter_label_paint;
actor_class->get_preferred_width = clutter_label_get_preferred_width;
actor_class->get_preferred_height = clutter_label_get_preferred_height;
actor_class->allocate = clutter_label_allocate;
gobject_class->finalize = clutter_label_finalize;
gobject_class->dispose = clutter_label_dispose;
@ -667,9 +584,6 @@ clutter_label_init (ClutterLabel *self)
priv->text = NULL;
priv->attrs = NULL;
priv->width_chars = -1;
priv->wrap_width = -1;
priv->fgcol.red = 0;
priv->fgcol.green = 0;
priv->fgcol.blue = 0;
@ -768,21 +682,12 @@ clutter_label_set_text (ClutterLabel *label,
priv = label->priv;
g_object_ref (label);
g_free (priv->text);
priv->text = g_strdup (text);
clutter_label_clear_layout (label);
/* Recreate the layout now so that the glyph cache will be primed
outside of the paint run */
clutter_label_ensure_layout (label);
if (CLUTTER_ACTOR_IS_VISIBLE (CLUTTER_ACTOR(label)))
clutter_actor_queue_redraw (CLUTTER_ACTOR(label));
clutter_actor_queue_relayout (CLUTTER_ACTOR (label));
g_object_notify (G_OBJECT (label), "text");
g_object_unref (label);
}
/**
@ -841,8 +746,6 @@ clutter_label_set_font_name (ClutterLabel *label,
return;
}
g_object_ref (label);
g_free (priv->font_name);
priv->font_name = g_strdup (font_name);
@ -850,21 +753,11 @@ clutter_label_set_font_name (ClutterLabel *label,
pango_font_description_free (priv->font_desc);
priv->font_desc = desc;
priv->wrap_width = -1;
if (label->priv->text && label->priv->text[0] != '\0')
{
clutter_label_clear_layout (label);
/* Recreate the layout now so that the glyph cache will be
primed outside of the paint run */
clutter_label_ensure_layout (label);
if (CLUTTER_ACTOR_IS_VISIBLE (label))
clutter_actor_queue_redraw (CLUTTER_ACTOR (label));
}
clutter_actor_queue_relayout (CLUTTER_ACTOR (label));
g_object_notify (G_OBJECT (label), "font-name");
g_object_unref (label);
}
@ -953,20 +846,11 @@ clutter_label_set_ellipsize (ClutterLabel *label,
if ((PangoEllipsizeMode) priv->ellipsize != mode)
{
g_object_ref (label);
priv->ellipsize = mode;
clutter_label_clear_layout (label);
/* Recreate the layout now so that the glyph cache will be
primed outside of the paint run */
clutter_label_ensure_layout (label);
if (CLUTTER_ACTOR_IS_VISIBLE (CLUTTER_ACTOR(label)))
clutter_actor_queue_redraw (CLUTTER_ACTOR(label));
clutter_actor_queue_relayout (CLUTTER_ACTOR (label));
g_object_notify (G_OBJECT (label), "ellipsize");
g_object_unref (label);
}
}
@ -1015,17 +899,11 @@ clutter_label_set_line_wrap (ClutterLabel *label,
if (priv->wrap != wrap)
{
g_object_ref (label);
priv->wrap = wrap;
clutter_label_clear_layout (label);
if (CLUTTER_ACTOR_IS_VISIBLE (CLUTTER_ACTOR (label)))
clutter_actor_queue_redraw (CLUTTER_ACTOR (label));
clutter_actor_queue_relayout (CLUTTER_ACTOR (label));
g_object_notify (G_OBJECT (label), "wrap");
g_object_unref (label);
}
}
@ -1071,17 +949,11 @@ clutter_label_set_line_wrap_mode (ClutterLabel *label,
if (priv->wrap_mode != wrap_mode)
{
g_object_ref (label);
priv->wrap_mode = wrap_mode;
clutter_label_clear_layout (label);
if (CLUTTER_ACTOR_IS_VISIBLE (CLUTTER_ACTOR (label)))
clutter_actor_queue_redraw (CLUTTER_ACTOR (label));
clutter_actor_queue_relayout (CLUTTER_ACTOR (label));
g_object_notify (G_OBJECT (label), "wrap-mode");
g_object_unref (label);
}
}
@ -1118,13 +990,11 @@ clutter_label_get_line_wrap_mode (ClutterLabel *label)
*
* Since: 0.2
**/
PangoLayout*
PangoLayout *
clutter_label_get_layout (ClutterLabel *label)
{
g_return_val_if_fail (CLUTTER_IS_LABEL (label), NULL);
clutter_label_ensure_layout (label);
return label->priv->layout;
}
@ -1136,8 +1006,6 @@ clutter_label_set_attributes_internal (ClutterLabel *label,
priv = label->priv;
g_object_ref (label);
if (attrs)
pango_attr_list_ref (attrs);
@ -1148,6 +1016,7 @@ clutter_label_set_attributes_internal (ClutterLabel *label,
{
if (attrs)
pango_attr_list_ref (attrs);
if (priv->effective_attrs)
pango_attr_list_unref (priv->effective_attrs);
priv->effective_attrs = attrs;
@ -1155,7 +1024,6 @@ clutter_label_set_attributes_internal (ClutterLabel *label,
label->priv->attrs = attrs;
g_object_notify (G_OBJECT (label), "attributes");
g_object_unref (label);
}
/**
@ -1178,10 +1046,7 @@ clutter_label_set_attributes (ClutterLabel *label,
clutter_label_set_attributes_internal (label, attrs);
clutter_label_clear_layout (label);
if (CLUTTER_ACTOR_IS_VISIBLE (CLUTTER_ACTOR(label)))
clutter_actor_queue_redraw (CLUTTER_ACTOR(label));
clutter_actor_queue_relayout (CLUTTER_ACTOR (label));
}
/**
@ -1224,19 +1089,11 @@ clutter_label_set_use_markup (ClutterLabel *label,
if (priv->use_markup != setting)
{
g_object_ref (label);
priv->use_markup = setting;
clutter_label_clear_layout (label);
/* Recreate the layout now so that the glyph cache will be
primed outside of the paint run */
clutter_label_ensure_layout (label);
if (CLUTTER_ACTOR_IS_VISIBLE (CLUTTER_ACTOR (label)))
clutter_actor_queue_redraw (CLUTTER_ACTOR (label));
clutter_actor_queue_relayout (CLUTTER_ACTOR (label));
g_object_notify (G_OBJECT (label), "use-markup");
g_object_unref (label);
}
}
@ -1277,16 +1134,11 @@ clutter_label_set_alignment (ClutterLabel *label,
if (priv->alignment != alignment)
{
g_object_ref (label);
priv->alignment = alignment;
clutter_label_clear_layout (label);
if (CLUTTER_ACTOR_IS_VISIBLE (CLUTTER_ACTOR (label)))
clutter_actor_queue_redraw (CLUTTER_ACTOR (label));
clutter_actor_queue_relayout (CLUTTER_ACTOR (label));
g_object_notify (G_OBJECT (label), "alignment");
g_object_unref (label);
}
}
@ -1333,10 +1185,7 @@ clutter_label_set_justify (ClutterLabel *label,
{
priv->justify = justify;
clutter_label_clear_layout (label);
if (CLUTTER_ACTOR_IS_VISIBLE (label))
clutter_actor_queue_redraw (CLUTTER_ACTOR (label));
clutter_actor_queue_relayout (CLUTTER_ACTOR (label));
g_object_notify (G_OBJECT (label), "justify");
}

View File

@ -106,8 +106,41 @@ clutter_get_show_fps (void)
return clutter_show_fps;
}
static inline void
clutter_maybe_setup_viewport (ClutterStage *stage)
void
_clutter_stage_maybe_relayout (ClutterActor *stage)
{
ClutterUnit natural_width, natural_height;
ClutterActorBox box = { 0, };
/* avoid reentrancy */
if (!(CLUTTER_PRIVATE_FLAGS (stage) & CLUTTER_ACTOR_IN_RELAYOUT))
{
CLUTTER_NOTE (ACTOR, "Recomputing layout");
CLUTTER_SET_PRIVATE_FLAGS (stage, CLUTTER_ACTOR_IN_RELAYOUT);
natural_width = natural_height = 0;
clutter_actor_get_preferred_size (stage,
NULL, NULL,
&natural_width, &natural_height);
box.x1 = 0;
box.y1 = 0;
box.x2 = natural_width;
box.y2 = natural_height;
CLUTTER_NOTE (ACTOR, "Allocating (0, 0 - %d, %d) for the stage",
CLUTTER_UNITS_TO_DEVICE (natural_width),
CLUTTER_UNITS_TO_DEVICE (natural_height));
clutter_actor_allocate (stage, &box, FALSE);
CLUTTER_UNSET_PRIVATE_FLAGS (stage, CLUTTER_ACTOR_IN_RELAYOUT);
}
}
void
_clutter_stage_maybe_setup_viewport (ClutterStage *stage)
{
if (CLUTTER_PRIVATE_FLAGS (stage) & CLUTTER_ACTOR_SYNC_MATRICES)
{
@ -148,6 +181,9 @@ clutter_redraw (ClutterStage *stage)
CLUTTER_NOTE (PAINT, " Redraw enter for stage:%p", stage);
CLUTTER_NOTE (MULTISTAGE, "Redraw called for stage:%p", stage);
/* Before we can paint, we have to be sure we have the latest layout */
_clutter_stage_maybe_relayout (CLUTTER_ACTOR (stage));
_clutter_backend_ensure_context (ctx->backend, stage);
/* Setup FPS count - not currently across *all* stages rather than per */
@ -160,7 +196,7 @@ clutter_redraw (ClutterStage *stage)
/* The code below can't go in stage paint as base actor_paint
* will get called before it (and break picking, etc)
*/
clutter_maybe_setup_viewport (stage);
_clutter_stage_maybe_setup_viewport (stage);
/* Call through to the actual backend to do the painting down from
* the stage. It will likely need to swap buffers, vblank sync etc
@ -322,7 +358,7 @@ _clutter_do_pick (ClutterStage *stage,
_clutter_backend_ensure_context (context->backend, stage);
/* needed for when a context switch happens */
clutter_maybe_setup_viewport (stage);
_clutter_stage_maybe_setup_viewport (stage);
cogl_paint_init (&white);
@ -2118,3 +2154,27 @@ clutter_set_use_mipmapped_text (gboolean value)
pango_clutter_font_map_set_use_mipmapping (CLUTTER_CONTEXT ()->font_map,
value);
}
/**
* clutter_get_use_mipmapped_text:
*
* Gets whether mipmapped textures are used in text operations.
* See clutter_set_use_mipmapped_text().
*
* Return value: %TRUE if text operations should use mipmapped
* textures
*
* Since: 0.8
*/
gboolean
clutter_get_use_mipmapped_text (void)
{
PangoClutterFontMap *font_map = NULL;
font_map = CLUTTER_CONTEXT ()->font_map;
if (font_map)
return pango_clutter_font_map_get_use_mipmapping (font_map);
return FALSE;
}

View File

@ -129,6 +129,7 @@ ClutterActor * clutter_get_keyboard_grab (void);
void clutter_clear_glyph_cache (void);
void clutter_set_use_mipmapped_text (gboolean value);
gboolean clutter_get_use_mipmapped_text (void);
G_END_DECLS

View File

@ -59,7 +59,8 @@ typedef enum {
* viewport / perspective etc
* needs (re)setting.
*/
CLUTTER_ACTOR_IN_PAINT = 1 << 4 /* Used to avoid recursion */
CLUTTER_ACTOR_IN_PAINT = 1 << 4, /* Used to avoid recursion */
CLUTTER_ACTOR_IN_RELAYOUT = 1 << 5 /* Used to avoid recursion */
} ClutterPrivateFlags;
typedef enum {
@ -142,10 +143,12 @@ void _clutter_stage_manager_remove_stage (ClutterStageManager *stage_manager,
/* stage */
void _clutter_stage_set_window (ClutterStage *stage,
ClutterStageWindow *stage_window);
ClutterStageWindow *_clutter_stage_get_window (ClutterStage *stage);
ClutterStageWindow *_clutter_stage_get_default_window (void);
void _clutter_stage_set_window (ClutterStage *stage,
ClutterStageWindow *stage_window);
ClutterStageWindow *_clutter_stage_get_window (ClutterStage *stage);
ClutterStageWindow *_clutter_stage_get_default_window (void);
void _clutter_stage_maybe_setup_viewport (ClutterStage *stage);
void _clutter_stage_maybe_relayout (ClutterActor *stage);
/* vfuncs implemented by backend */
GType _clutter_backend_impl_get_type (void);

View File

@ -84,7 +84,7 @@ clutter_rectangle_paint (ClutterActor *self)
: "unknown");
cogl_push_matrix();
clutter_actor_get_geometry (self, &geom);
clutter_actor_get_allocation_geometry (self, &geom);
/* parent paint call will have translated us into position so
* paint from 0, 0
@ -94,8 +94,9 @@ clutter_rectangle_paint (ClutterActor *self)
tmp_col.red = priv->border_color.red;
tmp_col.green = priv->border_color.green;
tmp_col.blue = priv->border_color.blue;
tmp_col.alpha = (clutter_actor_get_abs_opacity (self) *
priv->border_color.alpha) / 0xff;
tmp_col.alpha = clutter_actor_get_paint_opacity (self)
* priv->border_color.alpha
/ 255;
cogl_color (&tmp_col);
@ -120,13 +121,13 @@ clutter_rectangle_paint (ClutterActor *self)
tmp_col.red = priv->color.red;
tmp_col.green = priv->color.green;
tmp_col.blue = priv->color.blue;
tmp_col.alpha = (clutter_actor_get_abs_opacity (self) *
priv->color.alpha) / 0xff;
tmp_col.alpha = clutter_actor_get_paint_opacity (self)
* priv->color.alpha
/ 255;
cogl_color (&tmp_col);
cogl_rectangle (priv->border_width,
priv->border_width,
cogl_rectangle (priv->border_width, priv->border_width,
geom.width - priv->border_width * 2,
geom.height - priv->border_width * 2);
}
@ -135,8 +136,9 @@ clutter_rectangle_paint (ClutterActor *self)
tmp_col.red = priv->color.red;
tmp_col.green = priv->color.green;
tmp_col.blue = priv->color.blue;
tmp_col.alpha = (clutter_actor_get_abs_opacity (self) *
priv->color.alpha) / 0xff;
tmp_col.alpha = clutter_actor_get_paint_opacity (self)
* priv->color.alpha
/ 255;
cogl_color (&tmp_col);

View File

@ -121,25 +121,52 @@ enum
static guint stage_signals[LAST_SIGNAL] = { 0, };
static void
clutter_stage_request_coords (ClutterActor *self,
ClutterActorBox *box)
clutter_stage_get_preferred_width (ClutterActor *self,
ClutterUnit for_height,
ClutterUnit *min_width_p,
ClutterUnit *natural_width_p)
{
ClutterStagePrivate *priv = CLUTTER_STAGE (self)->priv;
g_assert (priv->impl != NULL);
CLUTTER_ACTOR_GET_CLASS (priv->impl)->request_coords (priv->impl, box);
CLUTTER_ACTOR_CLASS (clutter_stage_parent_class)->request_coords (self, box);
CLUTTER_ACTOR_GET_CLASS (priv->impl)->get_preferred_width (priv->impl,
for_height,
min_width_p,
natural_width_p);
}
static void
clutter_stage_query_coords (ClutterActor *self,
ClutterActorBox *box)
clutter_stage_get_preferred_height (ClutterActor *self,
ClutterUnit for_width,
ClutterUnit *min_height_p,
ClutterUnit *natural_height_p)
{
ClutterStagePrivate *priv = CLUTTER_STAGE (self)->priv;
g_assert (priv->impl != NULL);
CLUTTER_ACTOR_GET_CLASS (priv->impl)->query_coords (priv->impl, box);
CLUTTER_ACTOR_GET_CLASS (priv->impl)->get_preferred_height (priv->impl,
for_width,
min_height_p,
natural_height_p);
}
static void
clutter_stage_allocate (ClutterActor *self,
const ClutterActorBox *box,
gboolean origin_changed)
{
ClutterStagePrivate *priv = CLUTTER_STAGE (self)->priv;
g_assert (priv->impl != NULL);
CLUTTER_ACTOR_GET_CLASS (priv->impl)->allocate (priv->impl,
box,
origin_changed);
CLUTTER_ACTOR_CLASS (clutter_stage_parent_class)->allocate (self,
box,
origin_changed);
}
static void
@ -242,6 +269,32 @@ clutter_stage_hide (ClutterActor *self)
CLUTTER_ACTOR_CLASS (clutter_stage_parent_class)->hide (self);
}
static void
clutter_stage_real_fullscreen (ClutterStage *stage)
{
ClutterStagePrivate *priv = stage->priv;
ClutterUnit natural_width, natural_height;
ClutterActorBox box;
/* we need to force an allocation here because the size
* of the stage might have been changed by the backend
*
* this is a really bad solution to the issues caused by
* the fact that fullscreening the stage on the X11 backends
* is really an asynchronous operation
*/
clutter_actor_get_preferred_size (CLUTTER_ACTOR (priv->impl),
NULL, NULL,
&natural_width, &natural_height);
box.x1 = 0;
box.y1 = 0;
box.x2 = natural_width;
box.y2 = natural_height;
clutter_actor_allocate (CLUTTER_ACTOR (stage), &box, FALSE);
}
static void
clutter_stage_set_property (GObject *object,
guint prop_id,
@ -404,8 +457,9 @@ clutter_stage_class_init (ClutterStageClass *klass)
gobject_class->dispose = clutter_stage_dispose;
gobject_class->finalize = clutter_stage_finalize;
actor_class->request_coords = clutter_stage_request_coords;
actor_class->query_coords = clutter_stage_query_coords;
actor_class->allocate = clutter_stage_allocate;
actor_class->get_preferred_width = clutter_stage_get_preferred_width;
actor_class->get_preferred_height = clutter_stage_get_preferred_height;
actor_class->paint = clutter_stage_paint;
actor_class->pick = clutter_stage_pick;
actor_class->realize = clutter_stage_realize;
@ -518,7 +572,7 @@ clutter_stage_class_init (ClutterStageClass *klass)
stage_signals[FULLSCREEN] =
g_signal_new ("fullscreen",
G_TYPE_FROM_CLASS (gobject_class),
G_SIGNAL_RUN_LAST,
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (ClutterStageClass, fullscreen),
NULL, NULL,
clutter_marshal_VOID__VOID,
@ -575,6 +629,8 @@ clutter_stage_class_init (ClutterStageClass *klass)
clutter_marshal_VOID__VOID,
G_TYPE_NONE, 0);
klass->fullscreen = clutter_stage_real_fullscreen;
g_type_class_add_private (gobject_class, sizeof (ClutterStagePrivate));
}

View File

@ -40,10 +40,10 @@
* This process allows basic management of commonly limited available texture
* memory.
*
* Note: a ClutterTexture will scale its contents to fit the bounding box
* requested using clutter_actor_request_coords() and its wrappers. To
* display an area of a texture without scaling, you should set the clip
* area using clutter_actor_set_clip().
* Note: a ClutterTexture will scale its contents to fit the bounding
* box requested using clutter_actor_set_size(). To display an area of
* a texture without scaling, you should set the clip area using
* clutter_actor_set_clip().
*/
#ifdef HAVE_CONFIG_H
@ -318,6 +318,64 @@ clutter_texture_realize (ClutterActor *actor)
CLUTTER_NOTE (TEXTURE, "Texture realized");
}
static void
clutter_texture_get_preferred_width (ClutterActor *self,
ClutterUnit for_height,
ClutterUnit *min_width_p,
ClutterUnit *natural_width_p)
{
ClutterTexture *texture = CLUTTER_TEXTURE (self);
ClutterTexturePrivate *priv = texture->priv;
/* FIXME If we wanted to be clever here, we could set the natural
* width to preserve aspect ratio considering for_height
*/
/* Min request is always 0 since we can scale down or clip */
if (min_width_p)
*min_width_p = 0;
if (priv->sync_actor_size)
{
if (natural_width_p)
*natural_width_p = CLUTTER_UNITS_FROM_DEVICE (priv->width);
}
else
{
if (natural_width_p)
*natural_width_p = 0;
}
}
static void
clutter_texture_get_preferred_height (ClutterActor *self,
ClutterUnit for_width,
ClutterUnit *min_height_p,
ClutterUnit *natural_height_p)
{
ClutterTexture *texture = CLUTTER_TEXTURE (self);
ClutterTexturePrivate *priv = texture->priv;
/* FIXME If we wanted to be clever here, we could set the natural
* height to preserve aspect ratio considering for_width
*/
/* Min request is always 0 since we can scale down or clip */
if (min_height_p)
*min_height_p = 0;
if (priv->sync_actor_size)
{
if (natural_height_p)
*natural_height_p = CLUTTER_UNITS_FROM_DEVICE (priv->height);
}
else
{
if (natural_height_p)
*natural_height_p = 0;
}
}
static void
clutter_texture_paint (ClutterActor *self)
{
@ -370,10 +428,10 @@ clutter_texture_paint (ClutterActor *self)
: "unknown");
cogl_push_matrix ();
col.alpha = clutter_actor_get_abs_opacity (self);
col.alpha = clutter_actor_get_paint_opacity (self);
cogl_color (&col);
clutter_actor_get_coords (self, &x_1, &y_1, &x_2, &y_2);
clutter_actor_get_allocation_coords (self, &x_1, &y_1, &x_2, &y_2);
CLUTTER_NOTE (PAINT, "paint to x1: %i, y1: %i x2: %i, y2: %i "
"opacity: %i",
@ -400,23 +458,6 @@ clutter_texture_paint (ClutterActor *self)
cogl_pop_matrix ();
}
static void
clutter_texture_request_coords (ClutterActor *self,
ClutterActorBox *box)
{
ClutterTexture *texture = CLUTTER_TEXTURE (self);
ClutterActorBox old_request;
clutter_actor_query_coords (self, &old_request);
if (((box->x2 - box->x1) != (old_request.x2 - old_request.x1)) ||
((box->y2 - box->y1) != (old_request.y2 - old_request.y1)))
texture->priv->sync_actor_size = FALSE;
CLUTTER_ACTOR_CLASS (clutter_texture_parent_class)
->request_coords (self, box);
}
static void
clutter_texture_dispose (GObject *object)
{
@ -457,6 +498,7 @@ clutter_texture_set_property (GObject *object,
break;
case PROP_SYNC_SIZE:
priv->sync_actor_size = g_value_get_boolean (value);
clutter_actor_queue_relayout (CLUTTER_ACTOR (texture));
break;
case PROP_REPEAT_X:
if (priv->repeat_x != g_value_get_boolean (value))
@ -557,7 +599,9 @@ clutter_texture_class_init (ClutterTextureClass *klass)
actor_class->paint = clutter_texture_paint;
actor_class->realize = clutter_texture_realize;
actor_class->unrealize = clutter_texture_unrealize;
actor_class->request_coords = clutter_texture_request_coords;
actor_class->get_preferred_width = clutter_texture_get_preferred_width;
actor_class->get_preferred_height = clutter_texture_get_preferred_height;
gobject_class->dispose = clutter_texture_dispose;
gobject_class->set_property = clutter_texture_set_property;
@ -920,18 +964,11 @@ clutter_texture_set_cogl_texture (ClutterTexture *texture,
if (size_change)
{
g_signal_emit (texture, texture_signals[SIZE_CHANGE],
0, priv->width, priv->height);
g_signal_emit (texture, texture_signals[SIZE_CHANGE], 0,
priv->width,
priv->height);
if (priv->sync_actor_size)
{
clutter_actor_set_size (CLUTTER_ACTOR(texture),
priv->width,
priv->height);
/* The above call will clear sync_actor_size because the
size has changed so we need to put it back */
priv->sync_actor_size = TRUE;
}
clutter_actor_queue_relayout (CLUTTER_ACTOR (texture));
}
/* rename signal */
@ -1493,7 +1530,7 @@ on_fbo_source_size_change (GObject *object,
ClutterTexturePrivate *priv = texture->priv;
guint w, h;
clutter_actor_get_abs_size (priv->fbo_source, &w, &h);
clutter_actor_get_transformed_size (priv->fbo_source, &w, &h);
if (w != priv->width || h != priv->height)
{
@ -1616,7 +1653,7 @@ clutter_texture_new_from_actor (ClutterActor *actor)
return NULL;
}
clutter_actor_get_abs_size (actor, &w, &h);
clutter_actor_get_transformed_size (actor, &w, &h);
if (w == 0 || h == 0)
return NULL;

View File

@ -94,16 +94,26 @@ clutter_stage_x11_fix_window_size (ClutterStageX11 *stage_x11)
if (stage_x11->xwin != None && stage_x11->is_foreign_xwin == FALSE)
{
XSizeHints *size_hints;
ClutterUnit min_width, min_height;
size_hints = XAllocSizeHints();
clutter_actor_get_preferred_width (CLUTTER_ACTOR (stage_x11),
-1,
&min_width, NULL);
clutter_actor_get_preferred_height (CLUTTER_ACTOR (stage_x11),
min_width,
&min_height, NULL);
size_hints->min_width = CLUTTER_UNITS_TO_DEVICE (min_width);
size_hints->min_height = CLUTTER_UNITS_TO_DEVICE (min_height);
size_hints->flags = PMinSize;
if (!resize)
{
size_hints->max_width = size_hints->min_width =
stage_x11->xwin_width;
size_hints->max_height = size_hints->min_height =
stage_x11->xwin_height;
size_hints->flags = PMinSize|PMaxSize;
size_hints->max_width = size_hints->min_width;
size_hints->max_height = size_hints->min_height;
size_hints->flags |= PMaxSize;
}
XSetWMNormalHints (stage_x11->xdpy, stage_x11->xwin, size_hints);
@ -117,18 +127,18 @@ clutter_stage_x11_show (ClutterActor *actor)
{
ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (actor);
CLUTTER_ACTOR_CLASS (clutter_stage_x11_parent_class)->show (actor);
if (stage_x11->xwin)
{
/* Fire off a redraw to avoid flicker on first map.
* Appears not to work perfectly on intel drivers at least.
*/
*/
clutter_redraw (stage_x11->wrapper);
XSync (stage_x11->xdpy, FALSE);
XMapWindow (stage_x11->xdpy, stage_x11->xwin);
}
CLUTTER_ACTOR_SET_FLAGS (actor, CLUTTER_ACTOR_MAPPED);
}
static void
@ -136,8 +146,6 @@ clutter_stage_x11_hide (ClutterActor *actor)
{
ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (actor);
CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_MAPPED);
if (stage_x11->xwin)
XUnmapWindow (stage_x11->xdpy, stage_x11->xwin);
}
@ -156,41 +164,108 @@ clutter_stage_x11_set_wm_protocols (ClutterStageX11 *stage_x11)
}
static void
clutter_stage_x11_query_coords (ClutterActor *self,
ClutterActorBox *box)
clutter_stage_x11_get_preferred_width (ClutterActor *self,
ClutterUnit for_height,
ClutterUnit *min_width_p,
ClutterUnit *natural_width_p)
{
ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (self);
gboolean resize;
box->x1 = box->y1 = 0;
box->x2 = box->x1 + CLUTTER_UNITS_FROM_INT (stage_x11->xwin_width);
box->y2 = box->y1 + CLUTTER_UNITS_FROM_INT (stage_x11->xwin_height);
if (stage_x11->fullscreen_on_map)
{
int width;
width = DisplayWidth (stage_x11->xdpy, stage_x11->xscreen);
if (min_width_p)
*min_width_p = CLUTTER_UNITS_FROM_DEVICE (width);
if (natural_width_p)
*natural_width_p = CLUTTER_UNITS_FROM_DEVICE (width);
return;
}
resize = clutter_stage_get_user_resizable (stage_x11->wrapper);
if (min_width_p)
{
/* FIXME need API to set this */
if (resize)
*min_width_p = CLUTTER_UNITS_FROM_DEVICE (1);
else
*min_width_p = CLUTTER_UNITS_FROM_DEVICE (stage_x11->xwin_width);
}
if (natural_width_p)
*natural_width_p = CLUTTER_UNITS_FROM_DEVICE (stage_x11->xwin_width);
}
static void
clutter_stage_x11_request_coords (ClutterActor *self,
ClutterActorBox *box)
clutter_stage_x11_get_preferred_height (ClutterActor *self,
ClutterUnit for_width,
ClutterUnit *min_height_p,
ClutterUnit *natural_height_p)
{
ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (self);
gboolean resize;
if (stage_x11->fullscreen_on_map)
{
int height;
height = DisplayHeight (stage_x11->xdpy, stage_x11->xscreen);
if (min_height_p)
*min_height_p = CLUTTER_UNITS_FROM_DEVICE (height);
if (natural_height_p)
*natural_height_p = CLUTTER_UNITS_FROM_DEVICE (height);
return;
}
resize = clutter_stage_get_user_resizable (stage_x11->wrapper);
if (min_height_p)
{
if (resize)
*min_height_p = CLUTTER_UNITS_FROM_DEVICE (1); /* FIXME need API
* to set this
*/
else
*min_height_p = CLUTTER_UNITS_FROM_DEVICE (stage_x11->xwin_height);
}
if (natural_height_p)
*natural_height_p = CLUTTER_UNITS_FROM_DEVICE (stage_x11->xwin_height);
}
static void
clutter_stage_x11_allocate (ClutterActor *self,
const ClutterActorBox *box,
gboolean origin_changed)
{
ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (self);
ClutterActorClass *parent_class;
gint new_width, new_height;
new_width = ABS (CLUTTER_UNITS_TO_INT (box->x2 - box->x1));
new_height = ABS (CLUTTER_UNITS_TO_INT (box->y2 - box->y1));
new_height = ABS (CLUTTER_UNITS_TO_INT (box->y2 - box->y1));
/* X cant resize to 0 dimentions */
if (new_height == 0)
if (new_width == 0 || new_height == 0)
{
box->y2 = box->y1 + 1;
/* Should not happen, if this turns up we need to debug it and
* determine the cleanest way to fix.
*/
g_warning ("X11 stage not allowed to have 0 width or height");
new_width = 1;
new_height = 1;
}
if (new_width == 0)
{
box->x2 = box->x1 + 1;
new_width = 1;
}
if (new_width != stage_x11->xwin_width
|| new_height != stage_x11->xwin_height)
if (new_width != stage_x11->xwin_width ||
new_height != stage_x11->xwin_height)
{
stage_x11->xwin_width = new_width;
stage_x11->xwin_height = new_height;
@ -210,13 +285,13 @@ clutter_stage_x11_request_coords (ClutterActor *self,
if (stage_x11->xwin != None
&& !stage_x11->is_foreign_xwin
&& !stage_x11->handling_configure)
XResizeWindow (stage_x11->xdpy,
XResizeWindow (stage_x11->xdpy,
stage_x11->xwin,
stage_x11->xwin_width,
stage_x11->xwin_height);
clutter_stage_x11_fix_window_size (stage_x11);
if (stage_x11->xpixmap != None)
{
/* Need to recreate to resize */
@ -228,16 +303,9 @@ clutter_stage_x11_request_coords (ClutterActor *self,
CLUTTER_ACTOR_SYNC_MATRICES);
}
if (stage_x11->xwin != None
&& !stage_x11->is_foreign_xwin
&& !stage_x11->handling_configure) /* Do we want to bother ? */
XMoveWindow (stage_x11->xdpy,
stage_x11->xwin,
CLUTTER_UNITS_TO_INT (box->x1),
CLUTTER_UNITS_TO_INT (box->y1));
CLUTTER_ACTOR_CLASS (clutter_stage_x11_parent_class)->request_coords (self,
box);
/* chain up to fill in actor->priv->allocation */
parent_class = CLUTTER_ACTOR_CLASS (clutter_stage_x11_parent_class);
parent_class->allocate (self, box, origin_changed);
}
static inline void
@ -331,8 +399,26 @@ clutter_stage_x11_set_fullscreen (ClutterStageWindow *stage_window,
if (is_fullscreen)
{
int width, height;
width = DisplayWidth (stage_x11->xdpy, stage_x11->xscreen);
height = DisplayHeight (stage_x11->xdpy, stage_x11->xscreen);
/* we force the stage to the screen size here, in order to
* get the fullscreen stage size right after the call to
* clutter_stage_fullscreen(). XXX this might break in case
* the stage is not fullscreened, but if that does not happen
* we are massively screwed anyway
*/
stage_x11->xwin_width = width;
stage_x11->xwin_height = height;
clutter_actor_set_size (CLUTTER_ACTOR (stage), width, height);
if (stage_x11->xwin != None)
{
stage_x11->fullscreen_on_map = TRUE;
/* if the actor is not mapped we resize the stage window to match
* the size of the screen; this is useful for e.g. EGLX to avoid
* a resize when calling clutter_stage_fullscreen() before showing
@ -340,14 +426,6 @@ clutter_stage_x11_set_fullscreen (ClutterStageWindow *stage_window,
*/
if (!CLUTTER_ACTOR_IS_MAPPED (stage_x11))
{
gint width, height;
width = DisplayWidth (stage_x11->xdpy, stage_x11->xscreen);
height = DisplayHeight (stage_x11->xdpy, stage_x11->xscreen);
clutter_actor_set_size (CLUTTER_ACTOR (stage_x11),
width, height);
/* FIXME: This wont work if we support more states */
XChangeProperty (stage_x11->xdpy,
stage_x11->xwin,
@ -365,12 +443,10 @@ clutter_stage_x11_set_fullscreen (ClutterStageWindow *stage_window,
else
clutter_stage_set_user_resizable (stage, TRUE);
send_wmspec_change_state(backend_x11, stage_x11->xwin,
backend_x11->atom_NET_WM_STATE_FULLSCREEN,
TRUE);
send_wmspec_change_state (backend_x11, stage_x11->xwin,
backend_x11->atom_NET_WM_STATE_FULLSCREEN,
TRUE);
}
stage_x11->fullscreen_on_map = TRUE;
}
}
else
@ -388,10 +464,10 @@ clutter_stage_x11_set_fullscreen (ClutterStageWindow *stage_window,
{
clutter_stage_set_user_resizable (stage, TRUE);
send_wmspec_change_state(backend_x11,
stage_x11->xwin,
backend_x11->atom_NET_WM_STATE_FULLSCREEN,
FALSE);
send_wmspec_change_state (backend_x11,
stage_x11->xwin,
backend_x11->atom_NET_WM_STATE_FULLSCREEN,
FALSE);
/* reset the windows state - this isn't fun - see above */
if (!was_resizeable)
@ -414,7 +490,6 @@ clutter_stage_x11_set_cursor_visible (ClutterStageWindow *stage_window,
ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window);
stage_x11->is_cursor_visible = (cursor_visible == TRUE);
set_cursor_visible (stage_x11);
}
@ -426,7 +501,6 @@ clutter_stage_x11_set_title (ClutterStageWindow *stage_window,
g_free (stage_x11->title);
stage_x11->title = g_strdup (title);
set_wm_title (stage_x11);
}
@ -478,8 +552,10 @@ clutter_stage_x11_class_init (ClutterStageX11Class *klass)
actor_class->realize = clutter_stage_x11_realize;
actor_class->show = clutter_stage_x11_show;
actor_class->hide = clutter_stage_x11_hide;
actor_class->request_coords = clutter_stage_x11_request_coords;
actor_class->query_coords = clutter_stage_x11_query_coords;
actor_class->get_preferred_width = clutter_stage_x11_get_preferred_width;
actor_class->get_preferred_height = clutter_stage_x11_get_preferred_height;
actor_class->allocate = clutter_stage_x11_allocate;
}
static void
@ -681,7 +757,7 @@ clutter_stage_x11_map (ClutterStageX11 *stage_x11)
else
clutter_stage_unfullscreen (CLUTTER_STAGE (stage_x11->wrapper));
clutter_actor_queue_redraw (CLUTTER_ACTOR (stage_x11->wrapper));
clutter_actor_queue_relayout (CLUTTER_ACTOR (stage_x11->wrapper));
}
void

View File

@ -13,7 +13,7 @@ noinst_PROGRAMS = test-textures test-events test-offscreen test-scale \
test-cogl-tex-getset test-cogl-offscreen \
test-cogl-tex-polygon test-stage-read-pixels \
test-random-text test-clip test-paint-wrapper \
test-texture-quality test-entry-auto
test-texture-quality test-entry-auto test-layout
if X11_TESTS
noinst_PROGRAMS += test-pixmap
@ -24,22 +24,22 @@ LDADD = $(top_builddir)/clutter/libclutter-@CLUTTER_FLAVOUR@-@CLUTTER_MAJORMINOR
AM_CFLAGS = $(CLUTTER_CFLAGS)
AM_LDFLAGS = $(CLUTTER_LIBS)
test_textures_SOURCES = test-textures.c
test_events_SOURCES = test-events.c
test_offscreen_SOURCES = test-offscreen.c
test_scale_SOURCES = test-scale.c
test_actors_SOURCES = test-actors.c
test_grab_SOURCES = test-grab.c
test_behave_SOURCES = test-behave.c
test_text_SOURCES = test-text.c
test_entry_SOURCES = test-entry.c
test_project_SOURCES = test-project.c
test_unproject_SOURCES = test-unproject.c
test_perspective_SOURCES = test-perspective.c
test_rotate_SOURCES = test-rotate.c
test_depth_SOURCES = test-depth.c
test_threads_SOURCES = test-threads.c
test_timeline_SOURCES = test-timeline.c
test_textures_SOURCES = test-textures.c
test_events_SOURCES = test-events.c
test_offscreen_SOURCES = test-offscreen.c
test_scale_SOURCES = test-scale.c
test_actors_SOURCES = test-actors.c
test_grab_SOURCES = test-grab.c
test_behave_SOURCES = test-behave.c
test_text_SOURCES = test-text.c
test_entry_SOURCES = test-entry.c
test_project_SOURCES = test-project.c
test_unproject_SOURCES = test-unproject.c
test_perspective_SOURCES = test-perspective.c
test_rotate_SOURCES = test-rotate.c
test_depth_SOURCES = test-depth.c
test_threads_SOURCES = test-threads.c
test_timeline_SOURCES = test-timeline.c
test_timeline_dup_frames_SOURCES = test-timeline-dup-frames.c
test_timeline_interpolate_SOURCES = test-timeline-interpolate.c
test_timeline_rewind_SOURCES = test-timeline-rewind.c
@ -67,5 +67,6 @@ test_random_text_SOURCES = test-random-text.c
test_paint_wrapper_SOURCES = test-paint-wrapper.c
test_texture_quality_SOURCES = test-texture-quality.c
test_entry_auto_SOURCES = test-entry-auto.c
test_layout_SOURCES = test-layout.c
EXTRA_DIST = redhand.png test-script.json

785
tests/test-layout.c Normal file
View File

@ -0,0 +1,785 @@
#include <stdio.h>
#include <stdlib.h>
#include <cogl/cogl.h>
#include <clutter/clutter.h>
/* layout actor, by Lucas Rocha */
#define MY_TYPE_THING (my_thing_get_type ())
#define MY_THING(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MY_TYPE_THING, MyThing))
#define MY_IS_THING(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MY_TYPE_THING))
#define MY_THING_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MY_TYPE_THING, MyThingClass))
#define MY_IS_THING_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MY_TYPE_THING))
#define MY_THING_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MY_TYPE_THING, MyThingClass))
typedef struct _MyThing MyThing;
typedef struct _MyThingPrivate MyThingPrivate;
typedef struct _MyThingClass MyThingClass;
struct _MyThing
{
ClutterActor parent_instance;
MyThingPrivate *priv;
};
struct _MyThingClass
{
ClutterActorClass parent_class;
};
enum
{
PROP_0,
PROP_SPACING,
PROP_PADDING,
PROP_USE_TRANSFORMED_BOX
};
static void clutter_container_iface_init (ClutterContainerIface *iface);
G_DEFINE_TYPE_WITH_CODE (MyThing,
my_thing,
CLUTTER_TYPE_ACTOR,
G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTAINER,
clutter_container_iface_init));
#define MY_THING_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), MY_TYPE_THING, MyThingPrivate))
struct _MyThingPrivate
{
GList *children;
ClutterUnit spacing;
ClutterUnit padding;
guint use_transformed_box : 1;
};
/* Add, remove, foreach, copied from ClutterGroup code. */
static void
my_thing_real_add (ClutterContainer *container,
ClutterActor *actor)
{
MyThing *group = MY_THING (container);
MyThingPrivate *priv = group->priv;
g_object_ref (actor);
priv->children = g_list_append (priv->children, actor);
clutter_actor_set_parent (actor, CLUTTER_ACTOR (group));
g_signal_emit_by_name (container, "actor-added", actor);
/* queue relayout to allocate new item */
clutter_actor_queue_relayout (CLUTTER_ACTOR (group));
g_object_unref (actor);
}
static void
my_thing_real_remove (ClutterContainer *container,
ClutterActor *actor)
{
MyThing *group = MY_THING (container);
MyThingPrivate *priv = group->priv;
g_object_ref (actor);
priv->children = g_list_remove (priv->children, actor);
clutter_actor_unparent (actor);
/* At this point, the actor passed to the "actor-removed" signal
* handlers is not parented anymore to the container but since we
* are holding a reference on it, it's still valid
*/
g_signal_emit_by_name (container, "actor-removed", actor);
/* queue relayout to re-allocate children without the
removed item */
clutter_actor_queue_relayout (CLUTTER_ACTOR (group));
g_object_unref (actor);
}
static void
my_thing_real_foreach (ClutterContainer *container,
ClutterCallback callback,
gpointer user_data)
{
MyThingPrivate *priv = MY_THING (container)->priv;
GList *l;
for (l = priv->children; l; l = l->next)
(* callback) (CLUTTER_ACTOR (l->data), user_data);
}
static void
clutter_container_iface_init (ClutterContainerIface *iface)
{
iface->add = my_thing_real_add;
iface->remove = my_thing_real_remove;
iface->foreach = my_thing_real_foreach;
}
static void
my_thing_set_property (GObject *gobject,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
MyThingPrivate *priv = MY_THING (gobject)->priv;
gboolean needs_relayout = TRUE;
switch (prop_id)
{
case PROP_SPACING:
priv->spacing = clutter_value_get_unit (value);
break;
case PROP_PADDING:
priv->padding = clutter_value_get_unit (value);
break;
case PROP_USE_TRANSFORMED_BOX:
priv->use_transformed_box = g_value_get_boolean (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
needs_relayout = FALSE;
break;
}
/* setting spacing or padding queues a relayout
because they are supposed to change the internal
allocation of children */
if (needs_relayout)
clutter_actor_queue_relayout (CLUTTER_ACTOR (gobject));
}
static void
my_thing_get_property (GObject *gobject,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
MyThingPrivate *priv = MY_THING (gobject)->priv;
switch (prop_id)
{
case PROP_SPACING:
clutter_value_set_unit (value, priv->spacing);
break;
case PROP_PADDING:
clutter_value_set_unit (value, priv->padding);
break;
case PROP_USE_TRANSFORMED_BOX:
g_value_set_boolean (value, priv->use_transformed_box);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
}
}
static void
my_thing_finalize (GObject *gobject)
{
G_OBJECT_CLASS (my_thing_parent_class)->finalize (gobject);
}
static void
my_thing_dispose (GObject *gobject)
{
MyThing *self = MY_THING (gobject);
MyThingPrivate *priv = self->priv;
if (priv->children)
{
g_list_foreach (priv->children, (GFunc) clutter_actor_destroy, NULL);
priv->children = NULL;
}
G_OBJECT_CLASS (my_thing_parent_class)->dispose (gobject);
}
static void
my_thing_get_preferred_width (ClutterActor *self,
ClutterUnit for_height,
ClutterUnit *min_width_p,
ClutterUnit *natural_width_p)
{
MyThingPrivate *priv;
GList *l;
ClutterUnit min_left, min_right;
ClutterUnit natural_left, natural_right;
priv = MY_THING (self)->priv;
min_left = 0;
min_right = 0;
natural_left = 0;
natural_right = 0;
for (l = priv->children; l != NULL; l = l->next)
{
ClutterActor *child;
ClutterUnit child_x, child_min, child_natural;
child = l->data;
child_x = clutter_actor_get_xu (child);
clutter_actor_get_preferred_size (child,
&child_min, NULL,
&child_natural, NULL);
if (l == priv->children)
{
/* First child */
min_left = child_x;
natural_left = child_x;
min_right = min_left + child_min;
natural_right = natural_left + child_natural;
}
else
{
/* Union of extents with previous children */
if (child_x < min_left)
min_left = child_x;
if (child_x < natural_left)
natural_left = child_x;
if (child_x + child_min > min_right)
min_right = child_x + child_min;
if (child_x + child_natural > natural_right)
natural_right = child_x + child_natural;
}
}
if (min_left < 0)
min_left = 0;
if (natural_left < 0)
natural_left = 0;
if (min_right < 0)
min_right = 0;
if (natural_right < 0)
natural_right = 0;
g_assert (min_right >= min_left);
g_assert (natural_right >= natural_left);
if (min_width_p)
*min_width_p = min_right - min_left;
if (natural_width_p)
*natural_width_p = natural_right - min_left;
}
static void
my_thing_get_preferred_height (ClutterActor *self,
ClutterUnit for_width,
ClutterUnit *min_height_p,
ClutterUnit *natural_height_p)
{
MyThingPrivate *priv;
GList *l;
ClutterUnit min_top, min_bottom;
ClutterUnit natural_top, natural_bottom;
priv = MY_THING (self)->priv;
min_top = 0;
min_bottom = 0;
natural_top = 0;
natural_bottom = 0;
for (l = priv->children; l != NULL; l = l->next)
{
ClutterActor *child;
ClutterUnit child_y, child_min, child_natural;
child = l->data;
child_y = clutter_actor_get_yu (child);
clutter_actor_get_preferred_size (child,
NULL, &child_min,
NULL, &child_natural);
if (l == priv->children)
{
/* First child */
min_top = child_y;
natural_top = child_y;
min_bottom = min_top + child_min;
natural_bottom = natural_top + child_natural;
}
else
{
/* Union of extents with previous children */
if (child_y < min_top)
min_top = child_y;
if (child_y < natural_top)
natural_top = child_y;
if (child_y + child_min > min_bottom)
min_bottom = child_y + child_min;
if (child_y + child_natural > natural_bottom)
natural_bottom = child_y + child_natural;
}
}
if (min_top < 0)
min_top = 0;
if (natural_top < 0)
natural_top = 0;
if (min_bottom < 0)
min_bottom = 0;
if (natural_bottom < 0)
natural_bottom = 0;
g_assert (min_bottom >= min_top);
g_assert (natural_bottom >= natural_top);
if (min_height_p)
*min_height_p = min_bottom - min_top;
if (natural_height_p)
*natural_height_p = natural_bottom - min_top;
}
static void
my_thing_allocate (ClutterActor *self,
const ClutterActorBox *box,
gboolean absolute_origin_changed)
{
MyThingPrivate *priv;
ClutterUnit current_x, current_y, max_row_height;
GList *l;
/* chain up to set actor->allocation */
CLUTTER_ACTOR_CLASS (my_thing_parent_class)->allocate (self, box,
absolute_origin_changed);
priv = MY_THING (self)->priv;
current_x = priv->padding;
current_y = priv->padding;
max_row_height = 0;
/* The allocation logic here is to horizontally place children
* side-by-side and reflow into a new row when we run out of
* space
*/
for (l = priv->children; l != NULL; l = l->next)
{
ClutterActor *child;
ClutterUnit natural_width, natural_height;
ClutterActorBox child_box;
child = l->data;
clutter_actor_get_preferred_size (child,
NULL, NULL,
&natural_width, &natural_height);
/* if it fits in the current row, keep it there; otherwise
* reflow into another row
*/
if (current_x + natural_width > box->x2 - box->x1 - priv->padding)
{
current_x = priv->padding;
current_y += max_row_height + priv->spacing;
max_row_height = 0;
}
child_box.x1 = current_x;
child_box.y1 = current_y;
child_box.x2 = child_box.x1 + natural_width;
child_box.y2 = child_box.y1 + natural_height;
clutter_actor_allocate (child, &child_box, absolute_origin_changed);
/* if we take into account the transformation of the children
* then we first check if it's transformed; then we get the
* onscreen coordinates of the two points of the bounding box
* of the actor (origin(x, y) and (origin + size)(x,y)) and
* we update the coordinates and area given to the next child
*/
if (priv->use_transformed_box)
{
if (clutter_actor_is_scaled (child) ||
clutter_actor_is_rotated (child))
{
ClutterVertex v1 = { 0, }, v2 = { 0, };
ClutterActorBox box = { 0, };
/* origin */
v1.x = 0;
v1.y = 0;
clutter_actor_apply_transform_to_point (child, &v1, &v2);
box.x1 = v2.x;
box.y1 = v2.y;
/* size */
v1.x = natural_width;
v1.y = natural_height;
clutter_actor_apply_transform_to_point (child, &v1, &v2);
box.x2 = v2.x;
box.y2 = v2.y;
natural_width = box.x2 - box.x1;
natural_height = box.y2 - box.y1;
}
}
/* Record the maximum child height on current row to know
* what's the increment that should be used for the next
* row
*/
if (natural_height > max_row_height)
max_row_height = natural_height;
current_x += natural_width + priv->spacing;
}
}
static void
my_thing_paint (ClutterActor *actor)
{
MyThing *self = MY_THING (actor);
GList *c;
cogl_push_matrix();
/* paint all visible children */
for (c = self->priv->children;
c != NULL;
c = c->next)
{
ClutterActor *child = c->data;
g_assert (child != NULL);
if (CLUTTER_ACTOR_IS_VISIBLE (child))
clutter_actor_paint (child);
}
cogl_pop_matrix();
}
#define MIN_SIZE 24
#define MAX_SIZE 64
static void
my_thing_class_init (MyThingClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
gobject_class->set_property = my_thing_set_property;
gobject_class->get_property = my_thing_get_property;
gobject_class->dispose = my_thing_dispose;
gobject_class->finalize = my_thing_finalize;
actor_class->get_preferred_width = my_thing_get_preferred_width;
actor_class->get_preferred_height = my_thing_get_preferred_height;
actor_class->allocate = my_thing_allocate;
actor_class->paint = my_thing_paint;
g_object_class_install_property (gobject_class,
PROP_SPACING,
clutter_param_spec_unit ("spacing",
"Spacing",
"Spacing of the thing",
0, CLUTTER_MAXUNIT,
0,
G_PARAM_READWRITE));
g_object_class_install_property (gobject_class,
PROP_PADDING,
clutter_param_spec_unit ("padding",
"Padding",
"Padding around the thing",
0, CLUTTER_MAXUNIT,
0,
G_PARAM_READWRITE));
g_object_class_install_property (gobject_class,
PROP_USE_TRANSFORMED_BOX,
g_param_spec_boolean ("use-transformed-box",
"Use Transformed Box",
"Use transformed box when allocating",
FALSE,
G_PARAM_READWRITE));
g_type_class_add_private (klass, sizeof (MyThingPrivate));
}
static void
my_thing_init (MyThing *thing)
{
thing->priv = MY_THING_GET_PRIVATE (thing);
}
ClutterActor *
my_thing_new (gint padding,
gint spacing)
{
return g_object_new (MY_TYPE_THING,
"padding", CLUTTER_UNITS_FROM_DEVICE (padding),
"spacing", CLUTTER_UNITS_FROM_DEVICE (spacing),
NULL);
}
/* test code */
static ClutterActor *stage = NULL;
static ClutterActor *box = NULL;
static ClutterActor *icon = NULL;
static ClutterTimeline *timeline = NULL;
static ClutterBehaviour *behaviour = NULL;
static ClutterColor bg_color;
static void
toggle_property_value (ClutterActor *actor,
const gchar *property_name)
{
gboolean value;
g_object_get (G_OBJECT (actor),
property_name, &value,
NULL);
value = !value;
g_object_set (G_OBJECT (box),
property_name, value,
NULL);
}
static void
increase_property_value (ClutterActor *actor,
const char *property_name)
{
ClutterUnit value;
g_object_get (G_OBJECT (actor),
property_name, &value,
NULL);
value = value + CLUTTER_UNITS_FROM_DEVICE (10);
g_object_set (G_OBJECT (box),
property_name, value,
NULL);
}
static void
decrease_property_value (ClutterActor *actor,
const char *property_name)
{
ClutterUnit value;
g_object_get (G_OBJECT (actor),
property_name, &value,
NULL);
value = MAX (0, value - CLUTTER_UNITS_FROM_DEVICE (10));
g_object_set (G_OBJECT (box),
property_name, value,
NULL);
}
static ClutterActor *
create_item()
{
ClutterActor *clone =
clutter_clone_texture_new (CLUTTER_TEXTURE (icon));
gint32 size = g_random_int_range (MIN_SIZE, MAX_SIZE);
clutter_actor_set_size (clone, size, size);
clutter_behaviour_apply (behaviour, clone);
return clone;
}
static gboolean
keypress_cb (ClutterStage *stage,
ClutterKeyEvent *event,
gpointer data)
{
switch (clutter_key_event_symbol (event))
{
case CLUTTER_q:
{
clutter_main_quit ();
}
case CLUTTER_a:
{
if (icon != NULL)
{
ClutterActor *clone = create_item ();
/* Add one item to container */
clutter_container_add_actor (CLUTTER_CONTAINER (box), clone);
}
break;
}
case CLUTTER_d:
{
GList *children =
clutter_container_get_children (CLUTTER_CONTAINER (box));
if (children)
{
GList *last = g_list_last (children);
/* Remove last item on container */
clutter_container_remove_actor (CLUTTER_CONTAINER (box),
CLUTTER_ACTOR (last->data));
}
break;
}
case CLUTTER_w:
{
decrease_property_value (box, "padding");
break;
}
case CLUTTER_e:
{
increase_property_value (box, "padding");
break;
}
case CLUTTER_r:
{
decrease_property_value (box, "spacing");
break;
}
case CLUTTER_s:
{
toggle_property_value (box, "use-transformed-box");
break;
}
case CLUTTER_t:
{
increase_property_value (box, "spacing");
break;
}
case CLUTTER_z:
{
if (clutter_timeline_is_playing (timeline))
clutter_timeline_pause (timeline);
else
clutter_timeline_start (timeline);
break;
}
default:
break;
}
}
int
main (int argc,
char *argv[])
{
ClutterActor *instructions;
gint i;
GError *error = NULL;
clutter_init (&argc, &argv);
stage = clutter_stage_get_default ();
clutter_actor_set_size (stage, 800, 600);
clutter_color_parse ("Red", &bg_color);
timeline = clutter_timeline_new_for_duration (2000);
clutter_timeline_set_loop (timeline, TRUE);
behaviour = clutter_behaviour_scale_new (clutter_alpha_new_full (timeline,
CLUTTER_ALPHA_SINE,
NULL, NULL),
1.0, 1.0, 2.0, 2.0);
box = my_thing_new (10, 10);
clutter_actor_set_position (box, 20, 20);
clutter_actor_set_size (box, 400, -1);
icon = clutter_texture_new_from_file ("redhand.png", &error);
if (error)
g_error ("Unable to load 'redhand.png': %s", error->message);
for (i = 0; i < 33; i++)
{
ClutterActor *clone = create_item ();
clutter_container_add_actor (CLUTTER_CONTAINER (box), clone);
}
clutter_container_add_actor (CLUTTER_CONTAINER (stage), box);
instructions = clutter_label_new_with_text ("Sans 14",
"<b>Instructions:</b>\n"
"a - add a new item\n"
"d - remove last item\n"
"z - start/pause behaviour\n"
"w - decrease padding\n"
"e - increase padding\n"
"r - decrease spacing\n"
"t - increase spacing\n"
"s - use transformed box\n"
"q - quit");
clutter_label_set_use_markup (CLUTTER_LABEL (instructions), TRUE);
clutter_actor_set_position (instructions, 450, 10);
clutter_container_add_actor (CLUTTER_CONTAINER (stage), instructions);
g_signal_connect (stage, "key-release-event",
G_CALLBACK (keypress_cb),
NULL);
clutter_actor_show (stage);
clutter_main ();
g_object_unref (timeline);
g_object_unref (behaviour);
return EXIT_SUCCESS;
}

View File

@ -31,9 +31,9 @@ main (int argc, char *argv[])
clutter_label_get_color (CLUTTER_LABEL (label), &color_check);
g_assert (color_check.alpha == label_color.alpha);
g_print ("label 50%%.get_abs_opacity() = %d\n",
clutter_actor_get_abs_opacity (label));
g_assert (clutter_actor_get_abs_opacity (label) == 128);
g_print ("label 50%%.get_paint_opacity() = %d\n",
clutter_actor_get_paint_opacity (label));
g_assert (clutter_actor_get_paint_opacity (label) == 128);
clutter_actor_show (label);
@ -57,9 +57,9 @@ main (int argc, char *argv[])
clutter_label_get_color (CLUTTER_LABEL (label), &color_check);
g_assert (color_check.alpha == label_color.alpha);
g_print ("label 50%% + group 50%%.get_abs_opacity() = %d\n",
clutter_actor_get_abs_opacity (label));
g_assert (clutter_actor_get_abs_opacity (label) == 64);
g_print ("label 50%% + group 50%%.get_paint_opacity() = %d\n",
clutter_actor_get_paint_opacity (label));
g_assert (clutter_actor_get_paint_opacity (label) == 64);
clutter_actor_show (label);
@ -81,9 +81,9 @@ main (int argc, char *argv[])
clutter_rectangle_get_color (CLUTTER_RECTANGLE (rect), &color_check);
g_assert (color_check.alpha == rect_color.alpha);
g_print ("rect 100%%.get_abs_opacity() = %d\n",
clutter_actor_get_abs_opacity (rect));
g_assert (clutter_actor_get_abs_opacity (rect) == 128);
g_print ("rect 100%%.get_paint_opacity() = %d\n",
clutter_actor_get_paint_opacity (rect));
g_assert (clutter_actor_get_paint_opacity (rect) == 128);
clutter_actor_show (rect);
@ -101,9 +101,9 @@ main (int argc, char *argv[])
clutter_rectangle_get_color (CLUTTER_RECTANGLE (rect), &color_check);
g_assert (color_check.alpha == rect_color.alpha);
g_print ("rect 100%%.get_abs_opacity() = %d\n",
clutter_actor_get_abs_opacity (rect));
g_assert (clutter_actor_get_abs_opacity (rect) == 255);
g_print ("rect 100%%.get_paint_opacity() = %d\n",
clutter_actor_get_paint_opacity (rect));
g_assert (clutter_actor_get_paint_opacity (rect) == 255);
clutter_actor_show (rect);

View File

@ -12,7 +12,7 @@ init_handles ()
ClutterVertex v1, v2;
ClutterColor blue = { 0, 0, 0xff, 0xff };
clutter_actor_get_vertices (rect, v);
clutter_actor_get_abs_allocation_vertices (rect, v);
for (i = 0; i < 4; ++i)
{
p[i] = clutter_rectangle_new_with_color (&blue);
@ -58,7 +58,7 @@ place_handles ()
ClutterVertex v[4];
ClutterVertex v1, v2;
clutter_actor_get_vertices (rect, v);
clutter_actor_get_abs_allocation_vertices (rect, v);
for (i = 0; i < 4; ++i)
{
clutter_actor_set_position (p[i],
@ -136,8 +136,8 @@ on_event (ClutterStage *stage,
clutter_event_get_coords (event, &x, &y);
clutter_actor_query_coords (dragging, &box1);
clutter_actor_query_coords (rect, &box2);
clutter_actor_get_allocation_box (dragging, &box1);
clutter_actor_get_allocation_box (rect, &box2);
xp = CLUTTER_INT_TO_FIXED (x-3) - box1.x1;
yp = CLUTTER_INT_TO_FIXED (y-3) - box1.y1;
@ -178,7 +178,10 @@ on_event (ClutterStage *stage,
break;
}
clutter_actor_request_coords (rect, &box2);
/* FIXME this is just plain wrong, to allocate directly
* like this
*/
clutter_actor_allocate (rect, &box2, TRUE);
}
place_handles ();