diff --git a/configure.in b/configure.in index bb2e11545..db1b72ed1 100644 --- a/configure.in +++ b/configure.in @@ -302,7 +302,7 @@ if test x$have_xrender = xyes; then AC_DEFINE(HAVE_RENDER, , [Building with Render extension support]) fi -CLUTTER_PACKAGE=clutter-0.8 +CLUTTER_PACKAGE=clutter-0.9 AC_SUBST(CLUTTER_PACKAGE) if test x$have_clutter = xyes; then METACITY_PC_MODULES="$METACITY_PC_MODULES $CLUTTER_PACKAGE " diff --git a/src/compositor/mutter/compositor-mutter.c b/src/compositor/mutter/compositor-mutter.c index 695e19586..f9006d677 100644 --- a/src/compositor/mutter/compositor-mutter.c +++ b/src/compositor/mutter/compositor-mutter.c @@ -34,11 +34,7 @@ #include #include -#include #include -#ifdef HAVE_GLX_TEXTURE_PIXMAP -#include -#endif /* HAVE_GLX_TEXTURE_PIXMAP */ #include #define SHADOW_RADIUS 8 @@ -1707,7 +1703,8 @@ clutter_cmp_manage_screen (MetaCompositor *compositor, PointerMotionMask | PropertyChangeMask | ButtonPressMask | ButtonReleaseMask | - KeyPressMask | KeyReleaseMask; + KeyPressMask | KeyReleaseMask | + StructureNotifyMask; if (XGetWindowAttributes (xdisplay, xwin, &attr)) { @@ -1872,6 +1869,11 @@ clutter_cmp_process_event (MetaCompositor *compositor, meta_error_trap_pop (xrc->display, FALSE); + /* Clutter needs to know about MapNotify events otherwise it will + think the stage is invisible */ + if (event->type == MapNotify) + clutter_x11_handle_event (event); + /* The above handling is basically just "observing" the events, so we return * FALSE to indicate that the event should not be filtered out; if we have * GTK+ windows in the same process, GTK+ needs the ConfigureNotify event, for example. diff --git a/src/compositor/mutter/mutter-shaped-texture.c b/src/compositor/mutter/mutter-shaped-texture.c index 1ced5dbad..1c91c44bb 100755 --- a/src/compositor/mutter/mutter-shaped-texture.c +++ b/src/compositor/mutter/mutter-shaped-texture.c @@ -25,15 +25,12 @@ #include -#include -#include -#ifdef HAVE_GLX_TEXTURE_PIXMAP -#include -#endif /* HAVE_GLX_TEXTURE_PIXMAP */ +#include "mutter-shaped-texture.h" + +#include #include #include -#include "mutter-shaped-texture.h" static void mutter_shaped_texture_dispose (GObject *object); static void mutter_shaped_texture_finalize (GObject *object); @@ -56,29 +53,15 @@ G_DEFINE_TYPE (MutterShapedTexture, mutter_shaped_texture, (G_TYPE_INSTANCE_GET_PRIVATE ((obj), MUTTER_TYPE_SHAPED_TEXTURE, \ MutterShapedTexturePrivate)) -enum TstMultiTexSupport - { - TST_MULTI_TEX_SUPPORT_UNKNOWN = 0, - TST_MULTI_TEX_SUPPORT_YES, - TST_MULTI_TEX_SUPPORT_NO - }; - -static enum TstMultiTexSupport -tst_multi_tex_support = TST_MULTI_TEX_SUPPORT_UNKNOWN; - -typedef void (* TstActiveTextureFunc) (GLenum texture); -typedef void (* TstClientActiveTextureFunc) (GLenum texture); - -static TstActiveTextureFunc tst_active_texture; -static TstClientActiveTextureFunc tst_client_active_texture; - struct _MutterShapedTexturePrivate { CoglHandle mask_texture; + CoglHandle material; +#if 1 /* see workaround comment in mutter_shaped_texture_paint */ + CoglHandle material_workaround; +#endif guint mask_width, mask_height; - guint mask_gl_width, mask_gl_height; - GLfloat mask_tex_coords[8]; GArray *rectangles; }; @@ -114,9 +97,23 @@ static void mutter_shaped_texture_dispose (GObject *object) { MutterShapedTexture *self = (MutterShapedTexture *) object; + MutterShapedTexturePrivate *priv = self->priv; mutter_shaped_texture_dirty_mask (self); + if (priv->material != COGL_INVALID_HANDLE) + { + cogl_material_unref (priv->material); + priv->material = COGL_INVALID_HANDLE; + } +#if 1 /* see comment in mutter_shaped_texture_paint */ + if (priv->material_workaround != COGL_INVALID_HANDLE) + { + cogl_material_unref (priv->material_workaround); + priv->material_workaround = COGL_INVALID_HANDLE; + } +#endif + G_OBJECT_CLASS (mutter_shaped_texture_parent_class)->dispose (object); } @@ -152,97 +149,12 @@ mutter_shaped_texture_dirty_mask (MutterShapedTexture *stex) } } -static gboolean -mutter_shaped_texture_is_multi_tex_supported (void) -{ - const gchar *extensions; - GLint max_tex_units = 0; - - if (tst_multi_tex_support != TST_MULTI_TEX_SUPPORT_UNKNOWN) - return tst_multi_tex_support == TST_MULTI_TEX_SUPPORT_YES; - - extensions = (const gchar *) glGetString (GL_EXTENSIONS); - - tst_active_texture = (TstActiveTextureFunc) - cogl_get_proc_address ("glActiveTextureARB"); - tst_client_active_texture = (TstClientActiveTextureFunc) - cogl_get_proc_address ("glClientActiveTextureARB"); - - glGetIntegerv (GL_MAX_TEXTURE_UNITS, &max_tex_units); - - if (extensions - && cogl_check_extension ("GL_ARB_multitexture", extensions) - && tst_active_texture - && tst_client_active_texture - && max_tex_units > 1) - { - tst_multi_tex_support = TST_MULTI_TEX_SUPPORT_YES; - return TRUE; - } - else - { - g_warning ("multi texturing not supported"); - tst_multi_tex_support = TST_MULTI_TEX_SUPPORT_NO; - return FALSE; - } -} - -static void -mutter_shaped_texture_set_coord_array (GLfloat x1, GLfloat y1, - GLfloat x2, GLfloat y2, - GLfloat *coords) -{ - coords[0] = x1; - coords[1] = y2; - coords[2] = x2; - coords[3] = y2; - coords[4] = x1; - coords[5] = y1; - coords[6] = x2; - coords[7] = y1; -} - -static void -mutter_shaped_texture_get_gl_size (CoglHandle tex, - guint *width, - guint *height) -{ - /* glGetTexLevelParameteriv isn't supported on GL ES so we need to - calculate the size that Cogl has used */ - - /* If NPOTs textures are supported then assume the GL texture is - exactly the right size */ - if ((cogl_get_features () & COGL_FEATURE_TEXTURE_NPOT)) - { - *width = cogl_texture_get_width (tex); - *height = cogl_texture_get_height (tex); - } - /* Otherwise assume that Cogl has used the next power of two */ - else - { - guint tex_width = cogl_texture_get_width (tex); - guint tex_height = cogl_texture_get_height (tex); - guint real_width = 1; - guint real_height = 1; - - while (real_width < tex_width) - real_width <<= 1; - while (real_height < tex_height) - real_height <<= 1; - - *width = real_width; - *height = real_height; - } -} - static void mutter_shaped_texture_ensure_mask (MutterShapedTexture *stex) { MutterShapedTexturePrivate *priv = stex->priv; CoglHandle paint_tex; guint tex_width, tex_height; - GLuint mask_gl_tex; - GLenum mask_target; paint_tex = clutter_texture_get_cogl_texture (CLUTTER_TEXTURE (stex)); @@ -325,27 +237,6 @@ mutter_shaped_texture_ensure_mask (MutterShapedTexture *stex) priv->mask_width = tex_width; priv->mask_height = tex_height; - - cogl_texture_get_gl_texture (priv->mask_texture, &mask_gl_tex, &mask_target); - - mutter_shaped_texture_get_gl_size (priv->mask_texture, - &priv->mask_gl_width, - &priv->mask_gl_height); - - if (mask_target == GL_TEXTURE_RECTANGLE_ARB) - mutter_shaped_texture_set_coord_array (0.0f, 0.0f, tex_width, tex_height, - priv->mask_tex_coords); - else if ((guint) priv->mask_gl_width == tex_width - && (guint) priv->mask_gl_height == tex_height) - mutter_shaped_texture_set_coord_array (0.0f, 0.0f, 1.0f, 1.0f, - priv->mask_tex_coords); - else - mutter_shaped_texture_set_coord_array (0.0f, 0.0f, - tex_width - / (GLfloat) priv->mask_gl_width, - tex_height - / (GLfloat) priv->mask_gl_height, - priv->mask_tex_coords); } } @@ -356,23 +247,10 @@ mutter_shaped_texture_paint (ClutterActor *actor) MutterShapedTexturePrivate *priv = stex->priv; CoglHandle paint_tex; guint tex_width, tex_height; - GLboolean texture_was_enabled, blend_was_enabled; - GLboolean vertex_array_was_enabled, tex_coord_array_was_enabled; - GLboolean color_array_was_enabled; - GLuint paint_gl_tex, mask_gl_tex; - GLenum paint_target, mask_target; - guint paint_gl_width, paint_gl_height; - GLfloat vertex_coords[8], paint_tex_coords[8]; ClutterActorBox alloc; - static const ClutterColor white = { 0xff, 0xff, 0xff, 0xff }; + CoglHandle material; #if 1 /* please see comment below about workaround */ guint depth; - GLint orig_gl_tex_env_mode; - GLint orig_gl_combine_alpha; - GLint orig_gl_src0_alpha; - GLfloat orig_gl_tex_env_color[4]; - gboolean need_to_restore_tex_env = FALSE; - const GLfloat const_alpha[4] = { 0.0, 0.0, 0.0, 1.0 }; #endif if (!CLUTTER_ACTOR_IS_REALIZED (CLUTTER_ACTOR (stex))) @@ -386,10 +264,9 @@ mutter_shaped_texture_paint (ClutterActor *actor) if (tex_width == 0 || tex_width == 0) /* no contents yet */ return; - /* If there are no rectangles or multi-texturing isn't supported, - fallback to the regular paint method */ - if (priv->rectangles->len < 1 - || !mutter_shaped_texture_is_multi_tex_supported ()) + /* If there are no rectangles fallback to the regular paint + method */ + if (priv->rectangles->len < 1) { CLUTTER_ACTOR_CLASS (mutter_shaped_texture_parent_class) ->paint (actor); @@ -399,174 +276,101 @@ mutter_shaped_texture_paint (ClutterActor *actor) if (paint_tex == COGL_INVALID_HANDLE) return; - /* If the texture is sliced then the multitexturing won't work */ - if (cogl_texture_is_sliced (paint_tex)) - { - CLUTTER_ACTOR_CLASS (mutter_shaped_texture_parent_class) - ->paint (actor); - return; - } - mutter_shaped_texture_ensure_mask (stex); - cogl_texture_get_gl_texture (paint_tex, &paint_gl_tex, &paint_target); - cogl_texture_get_gl_texture (priv->mask_texture, &mask_gl_tex, &mask_target); + if (priv->material == COGL_INVALID_HANDLE) + { + priv->material = cogl_material_new (); - /* We need to keep track of the some of the old state so that we - don't confuse Cogl */ - texture_was_enabled = glIsEnabled (paint_target); - blend_was_enabled = glIsEnabled (GL_BLEND); - vertex_array_was_enabled = glIsEnabled (GL_VERTEX_ARRAY); - tex_coord_array_was_enabled = glIsEnabled (GL_TEXTURE_COORD_ARRAY); - color_array_was_enabled = glIsEnabled (GL_COLOR_ARRAY); + /* Replace the RGB from layer 1 with the RGB from layer 0 */ + cogl_material_set_layer_combine_function + (priv->material, 1, + COGL_MATERIAL_LAYER_COMBINE_CHANNELS_RGB, + COGL_MATERIAL_LAYER_COMBINE_FUNC_REPLACE); + cogl_material_set_layer_combine_arg_src + (priv->material, 1, 0, + COGL_MATERIAL_LAYER_COMBINE_CHANNELS_RGB, + COGL_MATERIAL_LAYER_COMBINE_SRC_PREVIOUS); - glEnable (paint_target); - glEnable (GL_BLEND); - glEnableClientState (GL_VERTEX_ARRAY); - glEnableClientState (GL_TEXTURE_COORD_ARRAY); - glDisableClientState (GL_COLOR_ARRAY); - glVertexPointer (2, GL_FLOAT, 0, vertex_coords); - glTexCoordPointer (2, GL_FLOAT, 0, paint_tex_coords); - cogl_color (&white); - - /* Put the main painting texture in the first texture unit */ - glBindTexture (paint_target, paint_gl_tex); - - /* We need the actual size of the texture so that we can calculate - the right texture coordinates if NPOTs textures are not supported - and Cogl has oversized the texture */ - mutter_shaped_texture_get_gl_size (paint_tex, - &paint_gl_width, - &paint_gl_height); + /* Modulate the alpha in layer 1 with the alpha from the + previous layer */ + cogl_material_set_layer_combine_function + (priv->material, 1, + COGL_MATERIAL_LAYER_COMBINE_CHANNELS_ALPHA, + COGL_MATERIAL_LAYER_COMBINE_FUNC_MODULATE); + cogl_material_set_layer_combine_arg_src + (priv->material, 1, 0, + COGL_MATERIAL_LAYER_COMBINE_CHANNELS_ALPHA, + COGL_MATERIAL_LAYER_COMBINE_SRC_PREVIOUS); + cogl_material_set_layer_combine_arg_src + (priv->material, 1, 1, + COGL_MATERIAL_LAYER_COMBINE_CHANNELS_ALPHA, + COGL_MATERIAL_LAYER_COMBINE_SRC_TEXTURE); + } + material = priv->material; #if 1 - /* This was added as a workaround. It seems that with the intel drivers when - * multi-texturing using an RGB TFP texture, the texture is actually - * setup internally as an RGBA texture, where the alpha channel is mostly - * 0.0 so you only see a shimmer of the window. This workaround forcibly - * defines the alpha channel as 1.0. Maybe there is some clutter/cogl state - * that is interacting with this that is being overlooked, but for now this - * seems to work. */ - g_object_get (G_OBJECT (stex), "pixmap-depth", &depth, NULL); + /* This was added as a workaround. It seems that with the intel + * drivers when multi-texturing using an RGB TFP texture, the + * texture is actually setup internally as an RGBA texture, where + * the alpha channel is mostly 0.0 so you only see a shimmer of the + * window. This workaround forcibly defines the alpha channel as + * 1.0. Maybe there is some clutter/cogl state that is interacting + * with this that is being overlooked, but for now this seems to + * work. */ + g_object_get (stex, "pixmap-depth", &depth, NULL); if (depth == 24) { - glGetTexEnviv (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, - &orig_gl_tex_env_mode); - glGetTexEnviv (GL_TEXTURE_ENV, GL_COMBINE_ALPHA, &orig_gl_combine_alpha); - glGetTexEnviv (GL_TEXTURE_ENV, GL_SRC0_ALPHA, &orig_gl_src0_alpha); - glGetTexEnvfv (GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, - orig_gl_tex_env_color); - need_to_restore_tex_env = TRUE; + if (priv->material_workaround == COGL_INVALID_HANDLE) + { + material = priv->material_workaround = cogl_material_new (); - glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE); - glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_CONSTANT); - glTexEnvfv (GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, const_alpha); + /* Replace the RGB from layer 1 with the RGB from layer 0 */ + cogl_material_set_layer_combine_function + (material, 1, + COGL_MATERIAL_LAYER_COMBINE_CHANNELS_RGB, + COGL_MATERIAL_LAYER_COMBINE_FUNC_REPLACE); + cogl_material_set_layer_combine_arg_src + (material, 1, 0, + COGL_MATERIAL_LAYER_COMBINE_CHANNELS_RGB, + COGL_MATERIAL_LAYER_COMBINE_SRC_PREVIOUS); - /* Replace the RGB in the second texture with that of the first - texture */ - glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_REPLACE); - glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PREVIOUS); + /* Use the alpha from layer 1 modulated with the alpha from + the primary color */ + cogl_material_set_layer_combine_function + (material, 1, + COGL_MATERIAL_LAYER_COMBINE_CHANNELS_ALPHA, + COGL_MATERIAL_LAYER_COMBINE_FUNC_MODULATE); + cogl_material_set_layer_combine_arg_src + (material, 1, 0, + COGL_MATERIAL_LAYER_COMBINE_CHANNELS_ALPHA, + COGL_MATERIAL_LAYER_COMBINE_SRC_PRIMARY_COLOR); + cogl_material_set_layer_combine_arg_src + (material, 1, 1, + COGL_MATERIAL_LAYER_COMBINE_CHANNELS_ALPHA, + COGL_MATERIAL_LAYER_COMBINE_SRC_TEXTURE); + } + + material = priv->material_workaround; } #endif - /* Put the mask texture in the second texture unit */ - tst_active_texture (GL_TEXTURE1); - tst_client_active_texture (GL_TEXTURE1); - glBindTexture (mask_target, mask_gl_tex); + cogl_material_set_layer (material, 0, paint_tex); + cogl_material_set_layer (material, 1, priv->mask_texture); - glEnable (mask_target); + { + CoglColor color; + cogl_color_set_from_4ub (&color, 255, 255, 255, + clutter_actor_get_paint_opacity (actor)); + cogl_material_set_color (material, &color); + } - glEnableClientState (GL_TEXTURE_COORD_ARRAY); - glTexCoordPointer (2, GL_FLOAT, 0, priv->mask_tex_coords); - - glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); - -#if 1 /* see workaround notes above */ - if (depth == 24) - { - /* NOTE: This should be redundant, since we already explicitly forced an - * an alhpa value of 1.0 for texture unit 0, but this workaround only - * seems to help if we explicitly force the alpha values for both texture - * units. */ - /* XXX - we should also save/restore the values for this texture unit too - */ - glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE); - glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_TEXTURE); - glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_CONSTANT); - glTexEnvfv (GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, const_alpha); - } - else - { -#endif - - /* Multiply the alpha by the alpha in the second texture */ - glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE); - glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_TEXTURE); - glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_PREVIOUS); - -#if 1 /* see workaround notes above */ - } -#endif - - /* Replace the RGB in the second texture with that of the first - texture */ - glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_REPLACE); - glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PREVIOUS); + cogl_set_source (material); clutter_actor_get_allocation_box (actor, &alloc); - - mutter_shaped_texture_set_coord_array (0, 0, - CLUTTER_UNITS_TO_FLOAT (alloc.x2 - - alloc.x1), - CLUTTER_UNITS_TO_FLOAT (alloc.y2 - - alloc.y1), - vertex_coords); - - if (paint_target == GL_TEXTURE_RECTANGLE_ARB) - mutter_shaped_texture_set_coord_array (0.0f, 0.0f, tex_width, tex_height, - paint_tex_coords); - else if ((guint) paint_gl_width == tex_width - && (guint) paint_gl_height == tex_height) - mutter_shaped_texture_set_coord_array (0.0f, 0.0f, 1.0f, 1.0f, - paint_tex_coords); - else - mutter_shaped_texture_set_coord_array (0.0f, 0.0f, - tex_width - / (GLfloat) paint_gl_width, - tex_height - / (GLfloat) paint_gl_height, - paint_tex_coords); - - glDrawArrays (GL_TRIANGLE_STRIP, 0, 4); - - /* Disable the second texture unit and coord array */ - glDisable (mask_target); - glDisableClientState (GL_TEXTURE_COORD_ARRAY); - - /* Go back to operating on the first texture unit */ - tst_active_texture (GL_TEXTURE0); - tst_client_active_texture (GL_TEXTURE0); - - /* Restore the old state */ - if (!texture_was_enabled) - glDisable (paint_target); - if (!blend_was_enabled) - glDisable (GL_BLEND); - if (!vertex_array_was_enabled) - glDisableClientState (GL_VERTEX_ARRAY); - if (!tex_coord_array_was_enabled) - glDisableClientState (GL_TEXTURE_COORD_ARRAY); - if (color_array_was_enabled) - glEnableClientState (GL_COLOR_ARRAY); -#if 1 /* see note about workaround above */ - if (need_to_restore_tex_env) - { - glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, orig_gl_tex_env_mode); - glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA, orig_gl_combine_alpha); - glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA, orig_gl_src0_alpha); - glTexEnvfv (GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, orig_gl_tex_env_color); - } -#endif + cogl_rectangle (0, 0, + CLUTTER_UNITS_TO_FLOAT (alloc.x2 - alloc.x1), + CLUTTER_UNITS_TO_FLOAT (alloc.y2 - alloc.y1)); } static void @@ -577,8 +381,7 @@ mutter_shaped_texture_pick (ClutterActor *actor, MutterShapedTexturePrivate *priv = stex->priv; /* If there are no rectangles then use the regular pick */ - if (priv->rectangles->len < 1 - || !mutter_shaped_texture_is_multi_tex_supported ()) + if (priv->rectangles->len < 1) CLUTTER_ACTOR_CLASS (mutter_shaped_texture_parent_class) ->pick (actor, color); else if (clutter_actor_should_pick_paint (actor)) @@ -600,16 +403,17 @@ mutter_shaped_texture_pick (ClutterActor *actor, mutter_shaped_texture_ensure_mask (stex); - cogl_color (color); + cogl_set_source_color4ub (color->red, color->green, color->blue, + color->alpha); clutter_actor_get_allocation_box (actor, &alloc); /* Paint the mask rectangle in the given color */ - cogl_texture_rectangle (priv->mask_texture, - 0, 0, - CLUTTER_UNITS_TO_FIXED (alloc.x2 - alloc.x1), - CLUTTER_UNITS_TO_FIXED (alloc.y2 - alloc.y1), - 0, 0, CFX_ONE, CFX_ONE); + cogl_set_source_texture (priv->mask_texture); + cogl_rectangle_with_texture_coords (0, 0, + CLUTTER_UNITS_TO_FIXED (alloc.x2 - alloc.x1), + CLUTTER_UNITS_TO_FIXED (alloc.y2 - alloc.y1), + 0, 0, CFX_ONE, CFX_ONE); } } diff --git a/src/compositor/mutter/mutter-shaped-texture.h b/src/compositor/mutter/mutter-shaped-texture.h index 1cac287e6..7e553098d 100644 --- a/src/compositor/mutter/mutter-shaped-texture.h +++ b/src/compositor/mutter/mutter-shaped-texture.h @@ -26,8 +26,7 @@ #ifndef __MUTTER_SHAPED_TEXTURE_H__ #define __MUTTER_SHAPED_TEXTURE_H__ -#include -#include +#include #ifdef HAVE_GLX_TEXTURE_PIXMAP #include #endif /* HAVE_GLX_TEXTURE_PIXMAP */ diff --git a/src/compositor/mutter/plugins/default.c b/src/compositor/mutter/plugins/default.c index fd7fc291a..d7f664d34 100644 --- a/src/compositor/mutter/plugins/default.c +++ b/src/compositor/mutter/plugins/default.c @@ -96,12 +96,6 @@ MUTTER_PLUGIN_DECLARE(MutterDefaultPlugin, mutter_default_plugin); */ struct _MutterDefaultPluginPrivate { - ClutterEffectTemplate *destroy_effect; - ClutterEffectTemplate *minimize_effect; - ClutterEffectTemplate *maximize_effect; - ClutterEffectTemplate *map_effect; - ClutterEffectTemplate *switch_workspace_effect; - /* Valid only when switch_workspace effect is in progress */ ClutterTimeline *tml_switch_workspace1; ClutterTimeline *tml_switch_workspace2; @@ -114,16 +108,35 @@ struct _MutterDefaultPluginPrivate gboolean debug_mode : 1; }; +/* + * Per actor private data we attach to each actor. + */ +typedef struct _ActorPrivate +{ + ClutterActor *orig_parent; + + ClutterTimeline *tml_minimize; + ClutterTimeline *tml_maximize; + ClutterTimeline *tml_destroy; + ClutterTimeline *tml_map; + + gboolean is_minimized : 1; + gboolean is_maximized : 1; +} ActorPrivate; + +/* callback data for when animations complete */ +typedef struct +{ + ClutterActor *actor; + MutterPlugin *plugin; +} EffectCompleteData; + + static void mutter_default_plugin_dispose (GObject *object) { - MutterDefaultPluginPrivate *priv = MUTTER_DEFAULT_PLUGIN (object)->priv; - - g_object_unref (priv->destroy_effect); - g_object_unref (priv->minimize_effect); - g_object_unref (priv->maximize_effect); - g_object_unref (priv->switch_workspace_effect); - + /* MutterDefaultPluginPrivate *priv = MUTTER_DEFAULT_PLUGIN (object)->priv; + */ G_OBJECT_CLASS (mutter_default_plugin_parent_class)->dispose (object); } @@ -189,31 +202,6 @@ mutter_default_plugin_constructed (GObject *object) switch_timeout *= 2; } - priv->destroy_effect - = clutter_effect_template_new (clutter_timeline_new_for_duration ( - destroy_timeout), - CLUTTER_ALPHA_SINE_INC); - - - priv->minimize_effect - = clutter_effect_template_new (clutter_timeline_new_for_duration ( - minimize_timeout), - CLUTTER_ALPHA_SINE_INC); - - priv->maximize_effect - = clutter_effect_template_new (clutter_timeline_new_for_duration ( - maximize_timeout), - CLUTTER_ALPHA_SINE_INC); - - priv->map_effect - = clutter_effect_template_new (clutter_timeline_new_for_duration ( - map_timeout), - CLUTTER_ALPHA_SINE_INC); - - priv->switch_workspace_effect - = clutter_effect_template_new (clutter_timeline_new_for_duration ( - switch_timeout), - CLUTTER_ALPHA_SINE_INC); } static void @@ -254,23 +242,6 @@ mutter_default_plugin_init (MutterDefaultPlugin *self) priv->info.description = "This is an example of a plugin implementation."; } - -/* - * Per actor private data we attach to each actor. - */ -typedef struct _ActorPrivate -{ - ClutterActor *orig_parent; - - ClutterTimeline *tml_minimize; - ClutterTimeline *tml_maximize; - ClutterTimeline *tml_destroy; - ClutterTimeline *tml_map; - - gboolean is_minimized : 1; - gboolean is_maximized : 1; -} ActorPrivate; - /* * Actor private data accessor */ @@ -308,7 +279,7 @@ typedef struct SwitchWorkspaceData } SwitchWorkspaceData; static void -on_switch_workspace_effect_complete (ClutterActor *group, gpointer data) +on_switch_workspace_effect_complete (ClutterTimeline *timeline, gpointer data) { SwitchWorkspaceData *sw_data = data; MutterPlugin *plugin = sw_data->plugin; @@ -360,6 +331,7 @@ switch_workspace (MutterPlugin *plugin, int screen_width, screen_height; MetaScreen *screen = mutter_plugin_get_screen (plugin); SwitchWorkspaceData *sw_data = g_new (SwitchWorkspaceData, 1); + ClutterAnimation *animation; sw_data->plugin = plugin; sw_data->actors = actors; @@ -435,16 +407,23 @@ switch_workspace (MutterPlugin *plugin, priv->desktop1 = workspace0; priv->desktop2 = workspace1; - priv->tml_switch_workspace2 = - clutter_effect_scale (priv->switch_workspace_effect, - workspace1, 1.0, 1.0, - on_switch_workspace_effect_complete, - (gpointer)sw_data); + animation = clutter_actor_animate (workspace0, CLUTTER_EASE_IN_SINE, + SWITCH_TIMEOUT, + "scale-x", 1.0, + "scale-y", 1.0, + NULL); + priv->tml_switch_workspace1 = clutter_animation_get_timeline (animation); + g_signal_connect (priv->tml_switch_workspace1, + "completed", + G_CALLBACK (on_switch_workspace_effect_complete), + sw_data); - priv->tml_switch_workspace1 = - clutter_effect_scale (priv->switch_workspace_effect, - workspace0, 0.0, 0.0, - NULL, NULL); + animation = clutter_actor_animate (workspace1, CLUTTER_EASE_IN_SINE, + SWITCH_TIMEOUT, + "scale-x", 0.0, + "scale-y", 0.0, + NULL); + priv->tml_switch_workspace2 = clutter_animation_get_timeline (animation); } @@ -453,30 +432,32 @@ switch_workspace (MutterPlugin *plugin, * calls the manager callback function. */ static void -on_minimize_effect_complete (ClutterActor *actor, gpointer data) +on_minimize_effect_complete (ClutterTimeline *timeline, EffectCompleteData *data) { /* * Must reverse the effect of the effect; must hide it first to ensure * that the restoration will not be visible. */ - MutterPlugin *plugin = data; + MutterPlugin *plugin = data->plugin; ActorPrivate *apriv; - MutterWindow *mc_window = MUTTER_WINDOW (actor); + MutterWindow *mc_window = MUTTER_WINDOW (data->actor); - apriv = get_actor_private (MUTTER_WINDOW (actor)); + apriv = get_actor_private (MUTTER_WINDOW (data->actor)); apriv->tml_minimize = NULL; - clutter_actor_hide (actor); + clutter_actor_hide (data->actor); /* FIXME - we shouldn't assume the original scale, it should be saved * at the start of the effect */ - clutter_actor_set_scale (actor, 1.0, 1.0); - clutter_actor_move_anchor_point_from_gravity (actor, + clutter_actor_set_scale (data->actor, 1.0, 1.0); + clutter_actor_move_anchor_point_from_gravity (data->actor, CLUTTER_GRAVITY_NORTH_WEST); /* Now notify the manager that we are done with this effect */ mutter_plugin_effect_completed (plugin, mc_window, MUTTER_PLUGIN_MINIMIZE); + + g_free (data); } /* @@ -486,7 +467,6 @@ on_minimize_effect_complete (ClutterActor *actor, gpointer data) static void minimize (MutterPlugin *plugin, MutterWindow *mc_window) { - MutterDefaultPluginPrivate *priv = MUTTER_DEFAULT_PLUGIN (plugin)->priv; MetaCompWindowType type; ClutterActor *actor = CLUTTER_ACTOR (mc_window); @@ -494,6 +474,8 @@ minimize (MutterPlugin *plugin, MutterWindow *mc_window) if (type == META_COMP_WINDOW_NORMAL) { + ClutterAnimation *animation; + EffectCompleteData *data = g_new0 (EffectCompleteData, 1); ActorPrivate *apriv = get_actor_private (mc_window); apriv->is_minimized = TRUE; @@ -501,13 +483,19 @@ minimize (MutterPlugin *plugin, MutterWindow *mc_window) clutter_actor_move_anchor_point_from_gravity (actor, CLUTTER_GRAVITY_CENTER); - apriv->tml_minimize = clutter_effect_scale (priv->minimize_effect, - actor, - 0.0, - 0.0, - (ClutterEffectCompleteFunc) - on_minimize_effect_complete, - plugin); + animation = clutter_actor_animate (actor, + CLUTTER_EASE_IN_SINE, + MINIMIZE_TIMEOUT, + "scale-x", 0.0, + "scale-y", 0.0, + NULL); + apriv->tml_minimize = clutter_animation_get_timeline (animation); + data->plugin = plugin; + data->actor = actor; + g_signal_connect (apriv->tml_minimize, "completed", + G_CALLBACK (on_minimize_effect_complete), + data); + } else mutter_plugin_effect_completed (plugin, mc_window, @@ -519,25 +507,27 @@ minimize (MutterPlugin *plugin, MutterWindow *mc_window) * calls the manager callback function. */ static void -on_maximize_effect_complete (ClutterActor *actor, gpointer data) +on_maximize_effect_complete (ClutterTimeline *timeline, EffectCompleteData *data) { /* * Must reverse the effect of the effect. */ - MutterPlugin * plugin = data; - MutterWindow *mc_window = MUTTER_WINDOW (actor); + MutterPlugin * plugin = data->plugin; + MutterWindow *mc_window = MUTTER_WINDOW (data->actor); ActorPrivate *apriv = get_actor_private (mc_window); apriv->tml_maximize = NULL; /* FIXME - don't assume the original scale was 1.0 */ - clutter_actor_set_scale (actor, 1.0, 1.0); - clutter_actor_move_anchor_point_from_gravity (actor, + clutter_actor_set_scale (data->actor, 1.0, 1.0); + clutter_actor_move_anchor_point_from_gravity (data->actor, CLUTTER_GRAVITY_NORTH_WEST); /* Now notify the manager that we are done with this effect */ mutter_plugin_effect_completed (plugin, mc_window, MUTTER_PLUGIN_MAXIMIZE); + + g_free (data); } /* @@ -553,7 +543,6 @@ maximize (MutterPlugin *plugin, MutterWindow *mc_window, gint end_x, gint end_y, gint end_width, gint end_height) { - MutterDefaultPluginPrivate *priv = MUTTER_DEFAULT_PLUGIN (plugin)->priv; MetaCompWindowType type; ClutterActor *actor = CLUTTER_ACTOR (mc_window); @@ -566,6 +555,8 @@ maximize (MutterPlugin *plugin, if (type == META_COMP_WINDOW_NORMAL) { + ClutterAnimation *animation; + EffectCompleteData *data = g_new0 (EffectCompleteData, 1); ActorPrivate *apriv = get_actor_private (mc_window); guint width, height; gint x, y; @@ -589,15 +580,18 @@ maximize (MutterPlugin *plugin, clutter_actor_move_anchor_point (actor, anchor_x, anchor_y); - apriv->tml_maximize = - clutter_effect_scale (priv->maximize_effect, - actor, - scale_x, - scale_y, - (ClutterEffectCompleteFunc) - on_maximize_effect_complete, - plugin); - + animation = clutter_actor_animate (actor, + CLUTTER_EASE_IN_SINE, + MAXIMIZE_TIMEOUT, + "scale-x", scale_x, + "scale-y", scale_y, + NULL); + apriv->tml_maximize = clutter_animation_get_timeline (animation); + data->plugin = plugin; + data->actor = actor; + g_signal_connect (apriv->tml_maximize, "completed", + G_CALLBACK (on_maximize_effect_complete), + data); return; } @@ -630,22 +624,24 @@ unmaximize (MutterPlugin *plugin, } static void -on_map_effect_complete (ClutterActor *actor, gpointer data) +on_map_effect_complete (ClutterTimeline *timeline, EffectCompleteData *data) { /* * Must reverse the effect of the effect. */ - MutterPlugin *plugin = data; - MutterWindow *mc_window = MUTTER_WINDOW (actor); + MutterPlugin *plugin = data->plugin; + MutterWindow *mc_window = MUTTER_WINDOW (data->actor); ActorPrivate *apriv = get_actor_private (mc_window); apriv->tml_map = NULL; - clutter_actor_move_anchor_point_from_gravity (actor, + clutter_actor_move_anchor_point_from_gravity (data->actor, CLUTTER_GRAVITY_NORTH_WEST); /* Now notify the manager that we are done with this effect */ mutter_plugin_effect_completed (plugin, mc_window, MUTTER_PLUGIN_MAP); + + g_free (data); } /* @@ -655,7 +651,6 @@ on_map_effect_complete (ClutterActor *actor, gpointer data) static void map (MutterPlugin *plugin, MutterWindow *mc_window) { - MutterDefaultPluginPrivate *priv = MUTTER_DEFAULT_PLUGIN (plugin)->priv; MetaCompWindowType type; ClutterActor *actor = CLUTTER_ACTOR (mc_window); @@ -663,6 +658,8 @@ map (MutterPlugin *plugin, MutterWindow *mc_window) if (type == META_COMP_WINDOW_NORMAL) { + ClutterAnimation *animation; + EffectCompleteData *data = g_new0 (EffectCompleteData, 1); ActorPrivate *apriv = get_actor_private (mc_window); clutter_actor_move_anchor_point_from_gravity (actor, @@ -671,13 +668,18 @@ map (MutterPlugin *plugin, MutterWindow *mc_window) clutter_actor_set_scale (actor, 0.0, 0.0); clutter_actor_show (actor); - apriv->tml_map = clutter_effect_scale (priv->map_effect, - actor, - 1.0, - 1.0, - (ClutterEffectCompleteFunc) - on_map_effect_complete, - plugin); + animation = clutter_actor_animate (actor, + CLUTTER_EASE_IN_SINE, + MAP_TIMEOUT, + "scale-x", 1.0, + "scale-y", 1.0, + NULL); + apriv->tml_map = clutter_animation_get_timeline (animation); + data->actor = actor; + data->plugin = plugin; + g_signal_connect (apriv->tml_map, "completed", + G_CALLBACK (on_map_effect_complete), + data); apriv->is_minimized = FALSE; @@ -692,10 +694,10 @@ map (MutterPlugin *plugin, MutterWindow *mc_window) * further action than notifying the manager that the effect is completed. */ static void -on_destroy_effect_complete (ClutterActor *actor, gpointer data) +on_destroy_effect_complete (ClutterTimeline *timeline, EffectCompleteData *data) { - MutterPlugin *plugin = data; - MutterWindow *mc_window = MUTTER_WINDOW (actor); + MutterPlugin *plugin = data->plugin; + MutterWindow *mc_window = MUTTER_WINDOW (data->actor); ActorPrivate *apriv = get_actor_private (mc_window); apriv->tml_destroy = NULL; @@ -710,7 +712,6 @@ on_destroy_effect_complete (ClutterActor *actor, gpointer data) static void destroy (MutterPlugin *plugin, MutterWindow *mc_window) { - MutterDefaultPluginPrivate *priv = MUTTER_DEFAULT_PLUGIN (plugin)->priv; MetaCompWindowType type; ClutterActor *actor = CLUTTER_ACTOR (mc_window); @@ -718,18 +719,25 @@ destroy (MutterPlugin *plugin, MutterWindow *mc_window) if (type == META_COMP_WINDOW_NORMAL) { + ClutterAnimation *animation; + EffectCompleteData *data = g_new0 (EffectCompleteData, 1); ActorPrivate *apriv = get_actor_private (mc_window); clutter_actor_move_anchor_point_from_gravity (actor, CLUTTER_GRAVITY_CENTER); - apriv->tml_destroy = clutter_effect_scale (priv->destroy_effect, - actor, - 1.0, - 0.0, - (ClutterEffectCompleteFunc) - on_destroy_effect_complete, - plugin); + animation = clutter_actor_animate (actor, + CLUTTER_EASE_IN_SINE, + DESTROY_TIMEOUT, + "scale-x", 0.0, + "scale-y", 1.0, + NULL); + apriv->tml_destroy = clutter_animation_get_timeline (animation); + data->plugin = plugin; + data->actor = actor; + g_signal_connect (apriv->tml_destroy, "completed", + G_CALLBACK (on_destroy_effect_complete), + data); } else mutter_plugin_effect_completed (plugin, mc_window, @@ -740,7 +748,6 @@ static void kill_effect (MutterPlugin *plugin, MutterWindow *mc_window, gulong event) { ActorPrivate *apriv; - ClutterActor *actor = CLUTTER_ACTOR (mc_window); if (event & MUTTER_PLUGIN_SWITCH_WORKSPACE) { @@ -750,7 +757,7 @@ kill_effect (MutterPlugin *plugin, MutterWindow *mc_window, gulong event) { clutter_timeline_stop (priv->tml_switch_workspace1); clutter_timeline_stop (priv->tml_switch_workspace2); - on_switch_workspace_effect_complete (priv->desktop1, priv->actors); + g_signal_emit_by_name (priv->tml_switch_workspace1, "completed", NULL); } if (!(event & ~MUTTER_PLUGIN_SWITCH_WORKSPACE)) @@ -765,25 +772,25 @@ kill_effect (MutterPlugin *plugin, MutterWindow *mc_window, gulong event) if ((event & MUTTER_PLUGIN_MINIMIZE) && apriv->tml_minimize) { clutter_timeline_stop (apriv->tml_minimize); - on_minimize_effect_complete (actor, NULL); + g_signal_emit_by_name (apriv->tml_minimize, "completed", NULL); } if ((event & MUTTER_PLUGIN_MAXIMIZE) && apriv->tml_maximize) { clutter_timeline_stop (apriv->tml_maximize); - on_maximize_effect_complete (actor, NULL); + g_signal_emit_by_name (apriv->tml_maximize, "completed", NULL); } if ((event & MUTTER_PLUGIN_MAP) && apriv->tml_map) { clutter_timeline_stop (apriv->tml_map); - on_map_effect_complete (actor, NULL); + g_signal_emit_by_name (apriv->tml_map, "completed", NULL); } if ((event & MUTTER_PLUGIN_DESTROY) && apriv->tml_destroy) { clutter_timeline_stop (apriv->tml_destroy); - on_destroy_effect_complete (actor, NULL); + g_signal_emit_by_name (apriv->tml_destroy, "completed", NULL); } } diff --git a/src/compositor/mutter/tidy/tidy-texture-frame.c b/src/compositor/mutter/tidy/tidy-texture-frame.c index 2b613a7b6..e4485aafd 100644 --- a/src/compositor/mutter/tidy/tidy-texture-frame.c +++ b/src/compositor/mutter/tidy/tidy-texture-frame.c @@ -41,68 +41,161 @@ enum { PROP_0, + + PROP_PARENT_TEXTURE, + PROP_LEFT, PROP_TOP, PROP_RIGHT, PROP_BOTTOM }; -G_DEFINE_TYPE (TidyTextureFrame, - tidy_texture_frame, - CLUTTER_TYPE_CLONE_TEXTURE); +G_DEFINE_TYPE (TidyTextureFrame, tidy_texture_frame, CLUTTER_TYPE_ACTOR); -#define TIDY_TEXTURE_FRAME_GET_PRIVATE(obj) \ -(G_TYPE_INSTANCE_GET_PRIVATE ((obj), TIDY_TYPE_TEXTURE_FRAME, TidyTextureFramePrivate)) +#define TIDY_TEXTURE_FRAME_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), TIDY_TYPE_TEXTURE_FRAME, TidyTextureFramePrivate)) struct _TidyTextureFramePrivate { - gint left, top, right, bottom; + ClutterTexture *parent_texture; + + gfloat left; + gfloat top; + gfloat right; + gfloat bottom; + + CoglHandle material; }; +static void +tidy_texture_frame_get_preferred_width (ClutterActor *self, + ClutterUnit for_height, + ClutterUnit *min_width_p, + ClutterUnit *natural_width_p) +{ + TidyTextureFramePrivate *priv = TIDY_TEXTURE_FRAME (self)->priv; + + if (G_UNLIKELY (priv->parent_texture == NULL)) + { + if (min_width_p) + *min_width_p = 0; + + if (natural_width_p) + *natural_width_p = 0; + } + else + { + ClutterActorClass *klass; + + /* by directly querying the parent texture's class implementation + * we are going around any override mechanism the parent texture + * might have in place, and we ask directly for the original + * preferred width + */ + klass = CLUTTER_ACTOR_GET_CLASS (priv->parent_texture); + klass->get_preferred_width (CLUTTER_ACTOR (priv->parent_texture), + for_height, + min_width_p, + natural_width_p); + } +} + +static void +tidy_texture_frame_get_preferred_height (ClutterActor *self, + ClutterUnit for_width, + ClutterUnit *min_height_p, + ClutterUnit *natural_height_p) +{ + TidyTextureFramePrivate *priv = TIDY_TEXTURE_FRAME (self)->priv; + + if (G_UNLIKELY (priv->parent_texture == NULL)) + { + if (min_height_p) + *min_height_p = 0; + + if (natural_height_p) + *natural_height_p = 0; + } + else + { + ClutterActorClass *klass; + + /* by directly querying the parent texture's class implementation + * we are going around any override mechanism the parent texture + * might have in place, and we ask directly for the original + * preferred height + */ + klass = CLUTTER_ACTOR_GET_CLASS (priv->parent_texture); + klass->get_preferred_height (CLUTTER_ACTOR (priv->parent_texture), + for_width, + min_height_p, + natural_height_p); + } +} + +static void +tidy_texture_frame_realize (ClutterActor *self) +{ + TidyTextureFramePrivate *priv = TIDY_TEXTURE_FRAME (self)->priv; + + if (priv->material != COGL_INVALID_HANDLE) + return; + + priv->material = cogl_material_new (); + + CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_REALIZED); +} + +static void +tidy_texture_frame_unrealize (ClutterActor *self) +{ + TidyTextureFramePrivate *priv = TIDY_TEXTURE_FRAME (self)->priv; + + if (priv->material == COGL_INVALID_HANDLE) + return; + + cogl_material_unref (priv->material); + priv->material = COGL_INVALID_HANDLE; + + CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED); +} + static void tidy_texture_frame_paint (ClutterActor *self) { TidyTextureFramePrivate *priv = TIDY_TEXTURE_FRAME (self)->priv; - ClutterCloneTexture *clone_texture = CLUTTER_CLONE_TEXTURE (self); - ClutterTexture *parent_texture; - guint width, height; - guint tex_width, tex_height; - guint ex, ey; - ClutterFixed tx1, ty1, tx2, ty2; - ClutterColor col = { 0xff, 0xff, 0xff, 0xff }; - CoglHandle cogl_texture; - - priv = TIDY_TEXTURE_FRAME (self)->priv; + CoglHandle cogl_texture = COGL_INVALID_HANDLE; + ClutterActorBox box = { 0, }; + gfloat width, height; + gfloat tex_width, tex_height; + gfloat ex, ey; + gfloat tx1, ty1, tx2, ty2; + guint8 opacity; /* no need to paint stuff if we don't have a texture */ - parent_texture = clutter_clone_texture_get_parent_texture (clone_texture); - if (!parent_texture) + if (G_UNLIKELY (priv->parent_texture == NULL)) return; /* parent texture may have been hidden, so need to make sure it gets * realized */ - if (!CLUTTER_ACTOR_IS_REALIZED (parent_texture)) - clutter_actor_realize (CLUTTER_ACTOR (parent_texture)); + if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent_texture)) + clutter_actor_realize (CLUTTER_ACTOR (priv->parent_texture)); - cogl_texture = clutter_texture_get_cogl_texture (parent_texture); + cogl_texture = clutter_texture_get_cogl_texture (priv->parent_texture); if (cogl_texture == COGL_INVALID_HANDLE) return; - cogl_push_matrix (); - tex_width = cogl_texture_get_width (cogl_texture); tex_height = cogl_texture_get_height (cogl_texture); - clutter_actor_get_size (self, &width, &height); + clutter_actor_get_allocation_box (self, &box); + width = box.x2 - box.x1; + height = box.y2 - box.y1; - tx1 = CLUTTER_INT_TO_FIXED (priv->left) / tex_width; - tx2 = CLUTTER_INT_TO_FIXED (tex_width - priv->right) / tex_width; - ty1 = CLUTTER_INT_TO_FIXED (priv->top) / tex_height; - ty2 = CLUTTER_INT_TO_FIXED (tex_height - priv->bottom) / tex_height; - - col.alpha = clutter_actor_get_paint_opacity (self); - cogl_color (&col); + tx1 = priv->left / tex_width; + tx2 = (tex_width - priv->right) / tex_width; + ty1 = priv->top / tex_height; + ty2 = (tex_height - priv->bottom) / tex_height; ex = width - priv->right; if (ex < 0) @@ -112,222 +205,278 @@ tidy_texture_frame_paint (ClutterActor *self) if (ey < 0) ey = priv->bottom; /* FIXME ? */ -#define FX(x) CLUTTER_INT_TO_FIXED(x) + opacity = clutter_actor_get_paint_opacity (self); + + g_assert (priv->material != COGL_INVALID_HANDLE); + + /* set the source material using the parent texture's COGL handle */ + cogl_material_set_color4ub (priv->material, 255, 255, 255, opacity); + cogl_material_set_layer (priv->material, 0, cogl_texture); + cogl_set_source (priv->material); /* top left corner */ - cogl_texture_rectangle (cogl_texture, - 0, - 0, - FX(priv->left), /* FIXME: clip if smaller */ - FX(priv->top), - 0, - 0, - tx1, - ty1); + cogl_rectangle_with_texture_coords (0, 0, priv->left, priv->top, + 0.0, 0.0, + tx1, ty1); /* top middle */ - cogl_texture_rectangle (cogl_texture, - FX(priv->left), - FX(priv->top), - FX(ex), - 0, - tx1, - 0, - tx2, - ty1); + cogl_rectangle_with_texture_coords (priv->left, 0, ex, priv->top, + tx1, 0.0, + tx2, ty1); /* top right */ - cogl_texture_rectangle (cogl_texture, - FX(ex), - 0, - FX(width), - FX(priv->top), - tx2, - 0, - CFX_ONE, - ty1); + cogl_rectangle_with_texture_coords (ex, 0, width, priv->top, + tx2, 0.0, + 1.0, ty1); /* mid left */ - cogl_texture_rectangle (cogl_texture, - 0, - FX(priv->top), - FX(priv->left), - FX(ey), - 0, - ty1, - tx1, - ty2); + cogl_rectangle_with_texture_coords (0, priv->top, priv->left, ey, + 0.0, ty1, + tx1, ty2); /* center */ - cogl_texture_rectangle (cogl_texture, - FX(priv->left), - FX(priv->top), - FX(ex), - FX(ey), - tx1, - ty1, - tx2, - ty2); + cogl_rectangle_with_texture_coords (priv->left, priv->top, ex, ey, + tx1, ty1, + tx2, ty2); /* mid right */ - cogl_texture_rectangle (cogl_texture, - FX(ex), - FX(priv->top), - FX(width), - FX(ey), - tx2, - ty1, - CFX_ONE, - ty2); - + cogl_rectangle_with_texture_coords (ex, priv->top, width, ey, + tx2, ty1, + 1.0, ty2); + /* bottom left */ - cogl_texture_rectangle (cogl_texture, - 0, - FX(ey), - FX(priv->left), - FX(height), - 0, - ty2, - tx1, - CFX_ONE); + cogl_rectangle_with_texture_coords (0, ey, priv->left, height, + 0.0, ty2, + tx1, 1.0); /* bottom center */ - cogl_texture_rectangle (cogl_texture, - FX(priv->left), - FX(ey), - FX(ex), - FX(height), - tx1, - ty2, - tx2, - CFX_ONE); + cogl_rectangle_with_texture_coords (priv->left, ey, ex, height, + tx1, ty2, + tx2, 1.0); /* bottom right */ - cogl_texture_rectangle (cogl_texture, - FX(ex), - FX(ey), - FX(width), - FX(height), - tx2, - ty2, - CFX_ONE, - CFX_ONE); - - - cogl_pop_matrix (); + cogl_rectangle_with_texture_coords (ex, ey, width, height, + tx2, ty2, + 1.0, 1.0); } +static inline void +tidy_texture_frame_set_frame_internal (TidyTextureFrame *frame, + gfloat left, + gfloat top, + gfloat right, + gfloat bottom) +{ + TidyTextureFramePrivate *priv = frame->priv; + GObject *gobject = G_OBJECT (frame); + gboolean changed = FALSE; + + g_object_freeze_notify (gobject); + + if (priv->top != top) + { + priv->top = top; + g_object_notify (gobject, "top"); + changed = TRUE; + } + + if (priv->right != right) + { + priv->right = right; + g_object_notify (gobject, "right"); + changed = TRUE; + } + + if (priv->bottom != bottom) + { + priv->bottom = bottom; + g_object_notify (gobject, "bottom"); + changed = TRUE; + } + + if (priv->left != left) + { + priv->left = left; + g_object_notify (gobject, "left"); + changed = TRUE; + } + + if (changed && CLUTTER_ACTOR_IS_VISIBLE (frame)) + clutter_actor_queue_redraw (CLUTTER_ACTOR (frame)); + + g_object_thaw_notify (gobject); +} static void -tidy_texture_frame_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) +tidy_texture_frame_set_property (GObject *gobject, + guint prop_id, + const GValue *value, + GParamSpec *pspec) { - TidyTextureFrame *ctexture = TIDY_TEXTURE_FRAME (object); - TidyTextureFramePrivate *priv = ctexture->priv; + TidyTextureFrame *frame = TIDY_TEXTURE_FRAME (gobject); + TidyTextureFramePrivate *priv = frame->priv; switch (prop_id) { - case PROP_LEFT: - priv->left = g_value_get_int (value); + case PROP_PARENT_TEXTURE: + tidy_texture_frame_set_parent_texture (frame, + g_value_get_object (value)); break; + case PROP_TOP: - priv->top = g_value_get_int (value); + tidy_texture_frame_set_frame_internal (frame, + priv->left, + g_value_get_float (value), + priv->right, + priv->bottom); break; + case PROP_RIGHT: - priv->right = g_value_get_int (value); + tidy_texture_frame_set_frame_internal (frame, + priv->top, + g_value_get_float (value), + priv->bottom, + priv->left); break; + case PROP_BOTTOM: - priv->bottom = g_value_get_int (value); + tidy_texture_frame_set_frame_internal (frame, + priv->top, + priv->right, + g_value_get_float (value), + priv->left); break; + + case PROP_LEFT: + tidy_texture_frame_set_frame_internal (frame, + priv->top, + priv->right, + priv->bottom, + g_value_get_float (value)); + break; + default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } static void -tidy_texture_frame_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) +tidy_texture_frame_get_property (GObject *gobject, + guint prop_id, + GValue *value, + GParamSpec *pspec) { - TidyTextureFrame *ctexture = TIDY_TEXTURE_FRAME (object); - TidyTextureFramePrivate *priv = ctexture->priv; + TidyTextureFramePrivate *priv = TIDY_TEXTURE_FRAME (gobject)->priv; switch (prop_id) { + case PROP_PARENT_TEXTURE: + g_value_set_object (value, priv->parent_texture); + break; + case PROP_LEFT: - g_value_set_int (value, priv->left); + g_value_set_float (value, priv->left); break; + case PROP_TOP: - g_value_set_int (value, priv->top); + g_value_set_float (value, priv->top); break; + case PROP_RIGHT: - g_value_set_int (value, priv->right); + g_value_set_float (value, priv->right); break; + case PROP_BOTTOM: - g_value_set_int (value, priv->bottom); + g_value_set_float (value, priv->bottom); break; + default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } +static void +tidy_texture_frame_dispose (GObject *gobject) +{ + TidyTextureFramePrivate *priv = TIDY_TEXTURE_FRAME (gobject)->priv; + + if (priv->parent_texture) + { + g_object_unref (priv->parent_texture); + priv->parent_texture = NULL; + } + + if (priv->material) + { + cogl_material_unref (priv->material); + priv->material = COGL_INVALID_HANDLE; + } + + G_OBJECT_CLASS (tidy_texture_frame_parent_class)->dispose (gobject); +} + static void tidy_texture_frame_class_init (TidyTextureFrameClass *klass) { - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass); + GParamSpec *pspec; + g_type_class_add_private (gobject_class, sizeof (TidyTextureFramePrivate)); + + actor_class->get_preferred_width = + tidy_texture_frame_get_preferred_width; + actor_class->get_preferred_height = + tidy_texture_frame_get_preferred_height; + actor_class->realize = tidy_texture_frame_realize; + actor_class->unrealize = tidy_texture_frame_unrealize; actor_class->paint = tidy_texture_frame_paint; gobject_class->set_property = tidy_texture_frame_set_property; gobject_class->get_property = tidy_texture_frame_get_property; + gobject_class->dispose = tidy_texture_frame_dispose; - g_object_class_install_property - (gobject_class, - PROP_LEFT, - g_param_spec_int ("left", - "left", - "", - 0, G_MAXINT, - 0, - TIDY_PARAM_READWRITE)); + pspec = g_param_spec_object ("parent-texture", + "Parent Texture", + "The parent ClutterTexture", + CLUTTER_TYPE_TEXTURE, + TIDY_PARAM_READWRITE | + G_PARAM_CONSTRUCT); + g_object_class_install_property (gobject_class, PROP_PARENT_TEXTURE, pspec); - g_object_class_install_property - (gobject_class, - PROP_TOP, - g_param_spec_int ("top", - "top", - "", - 0, G_MAXINT, - 0, - TIDY_PARAM_READWRITE)); + pspec = g_param_spec_float ("left", + "Left", + "Left offset", + 0, G_MAXFLOAT, + 0, + TIDY_PARAM_READWRITE); + g_object_class_install_property (gobject_class, PROP_LEFT, pspec); - g_object_class_install_property - (gobject_class, - PROP_BOTTOM, - g_param_spec_int ("bottom", - "bottom", - "", - 0, G_MAXINT, - 0, - TIDY_PARAM_READWRITE)); + pspec = g_param_spec_float ("top", + "Top", + "Top offset", + 0, G_MAXFLOAT, + 0, + TIDY_PARAM_READWRITE); + g_object_class_install_property (gobject_class, PROP_TOP, pspec); - g_object_class_install_property - (gobject_class, - PROP_RIGHT, - g_param_spec_int ("right", - "right", - "", - 0, G_MAXINT, - 0, - TIDY_PARAM_READWRITE)); + pspec = g_param_spec_float ("bottom", + "Bottom", + "Bottom offset", + 0, G_MAXFLOAT, + 0, + TIDY_PARAM_READWRITE); + g_object_class_install_property (gobject_class, PROP_BOTTOM, pspec); - g_type_class_add_private (gobject_class, sizeof (TidyTextureFramePrivate)); + pspec = g_param_spec_float ("right", + "Right", + "Right offset", + 0, G_MAXFLOAT, + 0, + TIDY_PARAM_READWRITE); + g_object_class_install_property (gobject_class, PROP_RIGHT, pspec); } static void @@ -336,14 +485,33 @@ tidy_texture_frame_init (TidyTextureFrame *self) TidyTextureFramePrivate *priv; self->priv = priv = TIDY_TEXTURE_FRAME_GET_PRIVATE (self); + + priv->material = COGL_INVALID_HANDLE; } -ClutterActor * -tidy_texture_frame_new (ClutterTexture *texture, - gint left, - gint top, - gint right, - gint bottom) +/** + * tidy_texture_frame_new: + * @texture: a #ClutterTexture or %NULL + * @left: left margin preserving its content + * @top: top margin preserving its content + * @right: right margin preserving its content + * @bottom: bottom margin preserving its content + * + * A #TidyTextureFrame is a specialized texture that efficiently clones + * an area of the given @texture while keeping preserving portions of the + * same texture. + * + * A #TidyTextureFrame can be used to make a rectangular texture fit a + * given size without stretching its borders. + * + * Return value: the newly created #TidyTextureFrame + */ +ClutterActor* +tidy_texture_frame_new (ClutterTexture *texture, + gfloat left, + gfloat top, + gfloat right, + gfloat bottom) { g_return_val_if_fail (texture == NULL || CLUTTER_IS_TEXTURE (texture), NULL); @@ -356,3 +524,87 @@ tidy_texture_frame_new (ClutterTexture *texture, NULL); } +ClutterTexture * +tidy_texture_frame_get_parent_texture (TidyTextureFrame *frame) +{ + g_return_val_if_fail (TIDY_IS_TEXTURE_FRAME (frame), NULL); + + return frame->priv->parent_texture; +} + +void +tidy_texture_frame_set_parent_texture (TidyTextureFrame *frame, + ClutterTexture *texture) +{ + TidyTextureFramePrivate *priv; + gboolean was_visible; + + g_return_if_fail (TIDY_IS_TEXTURE_FRAME (frame)); + g_return_if_fail (texture == NULL || CLUTTER_IS_TEXTURE (texture)); + + priv = frame->priv; + + was_visible = CLUTTER_ACTOR_IS_VISIBLE (frame); + + if (priv->parent_texture == texture) + return; + + if (priv->parent_texture) + { + g_object_unref (priv->parent_texture); + priv->parent_texture = NULL; + + if (was_visible) + clutter_actor_hide (CLUTTER_ACTOR (frame)); + } + + if (texture) + { + priv->parent_texture = g_object_ref (texture); + + if (was_visible && CLUTTER_ACTOR_IS_VISIBLE (priv->parent_texture)) + clutter_actor_show (CLUTTER_ACTOR (frame)); + } + + clutter_actor_queue_relayout (CLUTTER_ACTOR (frame)); + + g_object_notify (G_OBJECT (frame), "parent-texture"); +} + +void +tidy_texture_frame_set_frame (TidyTextureFrame *frame, + gfloat top, + gfloat right, + gfloat bottom, + gfloat left) +{ + g_return_if_fail (TIDY_IS_TEXTURE_FRAME (frame)); + + tidy_texture_frame_set_frame_internal (frame, top, right, bottom, left); +} + +void +tidy_texture_frame_get_frame (TidyTextureFrame *frame, + gfloat *top, + gfloat *right, + gfloat *bottom, + gfloat *left) +{ + TidyTextureFramePrivate *priv; + + g_return_if_fail (TIDY_IS_TEXTURE_FRAME (frame)); + + priv = frame->priv; + + if (top) + *top = priv->top; + + if (right) + *right = priv->right; + + if (bottom) + *bottom = priv->bottom; + + if (left) + *left = priv->left; +} diff --git a/src/compositor/mutter/tidy/tidy-texture-frame.h b/src/compositor/mutter/tidy/tidy-texture-frame.h index e28432a2c..0c54bfea3 100644 --- a/src/compositor/mutter/tidy/tidy-texture-frame.h +++ b/src/compositor/mutter/tidy/tidy-texture-frame.h @@ -1,6 +1,7 @@ /* tidy-texture-frame.h: Expandible texture actor * - * Copyright (C) 2007 OpenedHand + * Copyright (C) 2007, 2008 OpenedHand Ltd + * Copyright (C) 2009 Intel Corp. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -25,43 +26,28 @@ G_BEGIN_DECLS -#define TIDY_TYPE_TEXTURE_FRAME (tidy_texture_frame_get_type ()) +#define TIDY_TYPE_TEXTURE_FRAME (tidy_texture_frame_get_type ()) +#define TIDY_TEXTURE_FRAME(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TIDY_TYPE_TEXTURE_FRAME, TidyTextureFrame)) +#define TIDY_TEXTURE_FRAME_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TIDY_TYPE_TEXTURE_FRAME, TidyTextureFrameClass)) +#define TIDY_IS_TEXTURE_FRAME(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TIDY_TYPE_TEXTURE_FRAME)) +#define TIDY_IS_TEXTURE_FRAME_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TIDY_TYPE_TEXTURE_FRAME)) +#define TIDY_TEXTURE_FRAME_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TIDY_TYPE_TEXTURE_FRAME, TidyTextureFrameClass)) -#define TIDY_TEXTURE_FRAME(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST ((obj), \ - TIDY_TYPE_TEXTURE_FRAME, TidyTextureFrame)) - -#define TIDY_TEXTURE_FRAME_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST ((klass), \ - TIDY_TYPE_TEXTURE_FRAME, TidyTextureFrameClass)) - -#define TIDY_IS_TEXTURE_FRAME(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \ - TIDY_TYPE_TEXTURE_FRAME)) - -#define TIDY_IS_TEXTURE_FRAME_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE ((klass), \ - TIDY_TYPE_TEXTURE_FRAME)) - -#define TIDY_TEXTURE_FRAME_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS ((obj), \ - TIDY_TYPE_TEXTURE_FRAME, TidyTextureFrameClass)) - -typedef struct _TidyTextureFrame TidyTextureFrame; -typedef struct _TidyTextureFramePrivate TidyTextureFramePrivate; -typedef struct _TidyTextureFrameClass TidyTextureFrameClass; +typedef struct _TidyTextureFrame TidyTextureFrame; +typedef struct _TidyTextureFramePrivate TidyTextureFramePrivate; +typedef struct _TidyTextureFrameClass TidyTextureFrameClass; struct _TidyTextureFrame { - ClutterCloneTexture parent; - - /*< priv >*/ + /*< private >*/ + ClutterActor parent_instance; + TidyTextureFramePrivate *priv; }; struct _TidyTextureFrameClass { - ClutterCloneTextureClass parent_class; + ClutterActorClass parent_class; /* padding for future expansion */ void (*_clutter_box_1) (void); @@ -70,13 +56,26 @@ struct _TidyTextureFrameClass void (*_clutter_box_4) (void); }; -GType tidy_texture_frame_get_type (void) G_GNUC_CONST; -ClutterActor *tidy_texture_frame_new (ClutterTexture *texture, - gint left, - gint top, - gint right, - gint bottom); - +GType tidy_texture_frame_get_type (void) G_GNUC_CONST; +ClutterActor * tidy_texture_frame_new (ClutterTexture *texture, + gfloat top, + gfloat right, + gfloat bottom, + gfloat left); +void tidy_texture_frame_set_parent_texture (TidyTextureFrame *frame, + ClutterTexture *texture); +ClutterTexture *tidy_texture_frame_get_parent_texture (TidyTextureFrame *frame); +void tidy_texture_frame_set_frame (TidyTextureFrame *frame, + gfloat top, + gfloat right, + gfloat bottom, + gfloat left); +void tidy_texture_frame_get_frame (TidyTextureFrame *frame, + gfloat *top, + gfloat *right, + gfloat *bottom, + gfloat *left); + G_END_DECLS #endif /* _HAVE_TIDY_TEXTURE_FRAME_H */