diff --git a/clutter/clutter-stage.c b/clutter/clutter-stage.c index 760bec193..32eac253f 100644 --- a/clutter/clutter-stage.c +++ b/clutter/clutter-stage.c @@ -96,6 +96,7 @@ struct _ClutterStagePrivate guint is_user_resizable : 1; guint use_fog : 1; guint throttle_motion_events : 1; + guint use_alpha : 1; }; enum @@ -110,7 +111,8 @@ enum PROP_TITLE, PROP_USER_RESIZE, PROP_USE_FOG, - PROP_FOG + PROP_FOG, + PROP_USE_ALPHA }; enum @@ -243,14 +245,25 @@ clutter_stage_paint (ClutterActor *self) { ClutterStagePrivate *priv = CLUTTER_STAGE (self)->priv; CoglColor stage_color; + guint8 real_alpha; CLUTTER_NOTE (PAINT, "Initializing stage paint"); + /* composite the opacity to the stage color */ + real_alpha = clutter_actor_get_opacity (self) + * priv->color.alpha + / 255; + + /* we use the real alpha to clear the stage if :use-alpha is + * set; the effect depends entirely on how the Clutter backend + */ cogl_color_set_from_4ub (&stage_color, priv->color.red, priv->color.green, priv->color.blue, - priv->color.alpha); + priv->use_alpha ? real_alpha + : 255); + cogl_color_premultiply (&stage_color); cogl_clear (&stage_color, COGL_BUFFER_BIT_COLOR | COGL_BUFFER_BIT_DEPTH); @@ -270,11 +283,6 @@ clutter_stage_paint (ClutterActor *self) else cogl_disable_fog (); -#if 0 - CLUTTER_NOTE (PAINT, "Proxying the paint to the stage implementation"); - _clutter_stage_window_paint (priv->impl); -#endif - /* this will take care of painting every child */ CLUTTER_ACTOR_CLASS (clutter_stage_parent_class)->paint (self); } @@ -287,9 +295,9 @@ clutter_stage_pick (ClutterActor *self, * emitted for the stage itself. The stage's pick id is effectively handled * by the call to cogl_clear done in clutter-main.c:_clutter_do_pick_async() */ - clutter_container_foreach (CLUTTER_CONTAINER (self), - CLUTTER_CALLBACK (clutter_actor_paint), NULL); + CLUTTER_CALLBACK (clutter_actor_paint), + NULL); } static void @@ -660,6 +668,10 @@ clutter_stage_set_property (GObject *object, clutter_stage_set_fog (stage, g_value_get_boxed (value)); break; + case PROP_USE_ALPHA: + clutter_stage_set_use_alpha (stage, g_value_get_boolean (value)); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -712,6 +724,10 @@ clutter_stage_get_property (GObject *gobject, g_value_set_boxed (value, &priv->fog); break; + case PROP_USE_ALPHA: + g_value_set_boolean (value, priv->use_alpha); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; @@ -939,6 +955,24 @@ clutter_stage_class_init (ClutterStageClass *klass) CLUTTER_PARAM_READWRITE); g_object_class_install_property (gobject_class, PROP_FOG, pspec); + /** + * ClutterStage:use-alpha: + * + * Whether the #ClutterStage should honour the alpha component of the + * #ClutterStage:color property when painting. If Clutter is run under + * a compositing manager this will result in the stage being blended + * with the underlying window(s) + * + * Since: 1.2 + */ + pspec = g_param_spec_boolean ("use-alpha", + "Use Alpha", + "Whether to honour the alpha component of " + "the stage color", + FALSE, + CLUTTER_PARAM_READWRITE); + g_object_class_install_property (gobject_class, PROP_USE_ALPHA, pspec); + /** * ClutterStage::fullscreen * @stage: the stage which was fullscreened @@ -2129,3 +2163,53 @@ clutter_stage_get_throttle_motion_events (ClutterStage *stage) return stage->priv->throttle_motion_events; } + +/** + * clutter_stage_set_use_alpha: + * @stage: a #ClutterStage + * @use_alpha: whether the stage should honour the opacity or the + * alpha channel of the stage color + * + * Sets whether the @stage should honour the #ClutterActor:opacity and + * the alpha channel of the #ClutterStage:color + * + * Since: 1.2 + */ +void +clutter_stage_set_use_alpha (ClutterStage *stage, + gboolean use_alpha) +{ + ClutterStagePrivate *priv; + + g_return_if_fail (CLUTTER_IS_STAGE (stage)); + + priv = stage->priv; + + if (priv->use_alpha != use_alpha) + { + priv->use_alpha = use_alpha; + + clutter_actor_queue_redraw (CLUTTER_ACTOR (stage)); + + g_object_notify (G_OBJECT (stage), "use-alpha"); + } +} + +/** + * clutter_stage_get_use_alpha: + * @stage: a #ClutterStage + * + * Retrieves the value set using clutter_stage_set_use_alpha() + * + * Return value: %TRUE if the stage should honour the opacity and the + * alpha channel of the stage color + * + * Since: 1.2 + */ +gboolean +clutter_stage_get_use_alpha (ClutterStage *stage) +{ + g_return_val_if_fail (CLUTTER_IS_STAGE (stage), FALSE); + + return stage->priv->use_alpha; +} diff --git a/clutter/clutter-stage.h b/clutter/clutter-stage.h index fc2e4e855..f6fa0cdba 100644 --- a/clutter/clutter-stage.h +++ b/clutter/clutter-stage.h @@ -239,6 +239,10 @@ void clutter_stage_set_throttle_motion_events (ClutterStage *stage, gboolean throttle); gboolean clutter_stage_get_throttle_motion_events (ClutterStage *stage); +void clutter_stage_set_use_alpha (ClutterStage *stage, + gboolean use_alpha); +gboolean clutter_stage_get_use_alpha (ClutterStage *stage); + /* Commodity macro, for mallum only */ #define clutter_stage_add(stage,actor) G_STMT_START { \ if (CLUTTER_IS_STAGE ((stage)) && CLUTTER_IS_ACTOR ((actor))) \ diff --git a/clutter/cogl/cogl/cogl-material.c b/clutter/cogl/cogl/cogl-material.c index 1a641a776..6c292ac67 100644 --- a/clutter/cogl/cogl/cogl-material.c +++ b/clutter/cogl/cogl/cogl-material.c @@ -106,7 +106,7 @@ _cogl_material_init_default_material (void) #ifndef HAVE_COGL_GLES material->blend_equation_rgb = GL_FUNC_ADD; material->blend_equation_alpha = GL_FUNC_ADD; - material->blend_src_factor_alpha = GL_SRC_ALPHA; + material->blend_src_factor_alpha = GL_ONE; material->blend_dst_factor_alpha = GL_ONE_MINUS_SRC_ALPHA; material->blend_constant[0] = 0; material->blend_constant[1] = 0; diff --git a/clutter/glx/clutter-backend-glx.c b/clutter/glx/clutter-backend-glx.c index 8870037b3..ce1256e6c 100644 --- a/clutter/glx/clutter-backend-glx.c +++ b/clutter/glx/clutter-backend-glx.c @@ -56,7 +56,7 @@ G_DEFINE_TYPE (ClutterBackendGLX, clutter_backend_glx, CLUTTER_TYPE_BACKEND_X11) /* singleton object */ static ClutterBackendGLX *backend_singleton = NULL; -static gchar *clutter_vblank_name = NULL; +static gchar *clutter_vblank_name = NULL; #ifdef __linux__ #define DRM_VBLANK_RELATIVE 0x1; @@ -354,6 +354,20 @@ clutter_backend_glx_get_features (ClutterBackend *backend) return flags; } +enum +{ + DRAWABLE_TYPE = 0, + RENDER_TYPE = 2, + DOUBLE_BUFFER = 4, + RED_SIZE = 6, + GREEN_SIZE = 8, + BLUE_SIZE = 10, + ALPHA_SIZE = 12, + DEPTH_SIZE = 14, + STENCIL_SIZE = 16, + TRANSPARENT_TYPE = 18 +}; + /* It seems the GLX spec never defined an invalid GLXFBConfig that * we could overload as an indication of error, so we have to return * an explicit boolean status. */ @@ -362,30 +376,43 @@ _clutter_backend_glx_get_fbconfig (ClutterBackendGLX *backend_glx, GLXFBConfig *config) { ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (backend_glx); - int attributes[] = { - GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT, - GLX_RENDER_TYPE, GLX_RGBA_BIT, - GLX_DOUBLEBUFFER, GL_TRUE, - GLX_RED_SIZE, 1, - GLX_GREEN_SIZE, 1, - GLX_BLUE_SIZE, 1, - GLX_ALPHA_SIZE, 1, - GLX_DEPTH_SIZE, 1, - GLX_STENCIL_SIZE, 1, + GLXFBConfig *configs = NULL; + gboolean retval = FALSE; + gboolean use_argb = clutter_x11_has_argb_visuals (); + int n_configs, i; + static int attributes[] = { + GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT, + GLX_RENDER_TYPE, GLX_RGBA_BIT, + GLX_DOUBLEBUFFER, GL_TRUE, + GLX_RED_SIZE, 1, + GLX_GREEN_SIZE, 1, + GLX_BLUE_SIZE, 1, + GLX_ALPHA_SIZE, 1, + GLX_DEPTH_SIZE, 1, + GLX_STENCIL_SIZE, 1, + GLX_TRANSPARENT_TYPE, GLX_NONE, None }; - GLXFBConfig *configs = NULL; - int n_configs; if (backend_x11->xdpy == None || backend_x11->xscreen == None) return FALSE; - if (backend_glx->found_fbconfig) + if (backend_glx->found_fbconfig > 0) { - *config = backend_glx->fbconfig; + if (use_argb && backend_glx->found_fbconfig == 2) + *config = backend_glx->fbconfig_rgba; + else + *config = backend_glx->fbconfig_rgb; + return TRUE; } + if (use_argb) + { + attributes[ALPHA_SIZE] = 8; + attributes[TRANSPARENT_TYPE] = GLX_TRANSPARENT_RGB; + } + CLUTTER_NOTE (BACKEND, "Retrieving GL fbconfig, dpy: %p, xscreen; %p (%d)", backend_x11->xdpy, @@ -396,16 +423,64 @@ _clutter_backend_glx_get_fbconfig (ClutterBackendGLX *backend_glx, backend_x11->xscreen_num, attributes, &n_configs); - if (configs) + if (!configs) + return FALSE; + + if (!use_argb) { *config = configs[0]; - backend_glx->found_fbconfig = TRUE; - backend_glx->fbconfig = configs[0]; - XFree (configs); - return TRUE; + + backend_glx->found_fbconfig = 1; + backend_glx->fbconfig_rgb = configs[0]; + + retval = TRUE; + + goto out; } - else - return FALSE; + + for (i = 0; i < n_configs; i++) + { + XVisualInfo *vinfo; + + vinfo = glXGetVisualFromFBConfig (backend_x11->xdpy, configs[i]); + if (vinfo == None) + continue; + + if (vinfo->depth == 32 && + (vinfo->red_mask == 0xff0000 && + vinfo->green_mask == 0x00ff00 && + vinfo->blue_mask == 0x0000ff)) + { + CLUTTER_NOTE (BACKEND, "Found GLX visual ARGB [index:%d]", i); + + *config = configs[i]; + + backend_glx->found_fbconfig = 2; + backend_glx->fbconfig_rgba = configs[i]; + + retval = TRUE; + + goto out; + } + } + + /* XXX - we might add a warning here */ + if (use_argb && !backend_glx->found_fbconfig != 2) + { + CLUTTER_NOTE (BACKEND, "ARGB visual requested, but none found"); + + *config = configs[0]; + + backend_glx->found_fbconfig = 1; + backend_glx->fbconfig_rgb = configs[0]; + + retval = TRUE; + } + +out: + XFree (configs); + + return retval; } static XVisualInfo * @@ -436,12 +511,14 @@ clutter_backend_glx_create_context (ClutterBackend *backend, { g_set_error (error, CLUTTER_INIT_ERROR, CLUTTER_INIT_ERROR_BACKEND, - "Unable to find suitable fbconfig for GL context"); + "Unable to find a suitable GLXFBConfig for " + "the GLX context"); return FALSE; } - CLUTTER_NOTE (GL, "Creating GL Context (display: %p)", + CLUTTER_NOTE (GL, "Creating GLX Context (display: %p)", backend_x11->xdpy); + backend_glx->gl_context = glXCreateNewContext (backend_x11->xdpy, config, @@ -460,7 +537,8 @@ clutter_backend_glx_create_context (ClutterBackend *backend, is_direct = glXIsDirect (backend_x11->xdpy, backend_glx->gl_context); - CLUTTER_NOTE (GL, "Setting %s context", + CLUTTER_NOTE (GL, + "Setting %s context", is_direct ? "direct" : "indirect"); _cogl_set_indirect_context (!is_direct); } diff --git a/clutter/glx/clutter-backend-glx.h b/clutter/glx/clutter-backend-glx.h index 2bd380813..e7d6d9836 100644 --- a/clutter/glx/clutter-backend-glx.h +++ b/clutter/glx/clutter-backend-glx.h @@ -63,8 +63,9 @@ struct _ClutterBackendGLX ClutterBackendX11 parent_instance; /* Single context for all wins */ - gboolean found_fbconfig; - GLXFBConfig fbconfig; + gint found_fbconfig; + GLXFBConfig fbconfig_rgb; + GLXFBConfig fbconfig_rgba; GLXContext gl_context; /* Vblank stuff */ diff --git a/clutter/glx/clutter-glx.h b/clutter/glx/clutter-glx.h index bb2455b8a..967cfec90 100644 --- a/clutter/glx/clutter-glx.h +++ b/clutter/glx/clutter-glx.h @@ -43,9 +43,4 @@ #include #include -G_BEGIN_DECLS - - -G_END_DECLS - #endif /* __CLUTTER_GLX_H__ */ diff --git a/clutter/glx/clutter-stage-glx.c b/clutter/glx/clutter-stage-glx.c index 9c1105b2e..f770c88d3 100644 --- a/clutter/glx/clutter-stage-glx.c +++ b/clutter/glx/clutter-stage-glx.c @@ -105,18 +105,11 @@ clutter_stage_glx_realize (ClutterStageWindow *stage_window) { XSetWindowAttributes xattr; unsigned long mask; - GLXFBConfig config; XVisualInfo *xvisinfo; CLUTTER_NOTE (MISC, "Creating stage X window"); - if (!_clutter_backend_glx_get_fbconfig (backend_glx, &config)) - { - g_critical ("Unable to find suitable FBConfig to realize stage."); - return FALSE; - } - - xvisinfo = glXGetVisualFromFBConfig (backend_x11->xdpy, config); + xvisinfo = clutter_backend_x11_get_visual_info (backend_x11); if (xvisinfo == NULL) { g_critical ("Unable to find suitable GL visual."); @@ -145,9 +138,9 @@ clutter_stage_glx_realize (ClutterStageWindow *stage_window) XFree (xvisinfo); } - if (clutter_x11_has_event_retrieval()) + if (clutter_x11_has_event_retrieval ()) { - if (clutter_x11_has_xinput()) + if (clutter_x11_has_xinput ()) { XSelectInput (backend_x11->xdpy, stage_x11->xwin, StructureNotifyMask | diff --git a/clutter/x11/clutter-backend-x11.c b/clutter/x11/clutter-backend-x11.c index ae6ff824c..ec9afebea 100644 --- a/clutter/x11/clutter-backend-x11.c +++ b/clutter/x11/clutter-backend-x11.c @@ -97,6 +97,7 @@ static ClutterBackendX11 *backend_singleton = NULL; /* various flags corresponding to pre init setup calls */ static gboolean _no_xevent_retrieval = FALSE; static gboolean clutter_enable_xinput = FALSE; +static gboolean clutter_enable_argb = TRUE; static Display *_foreign_dpy = NULL; /* options */ @@ -124,6 +125,13 @@ clutter_backend_x11_pre_parse (ClutterBackend *backend, env_string = NULL; } + env_string = g_getenv ("CLUTTER_DISABLE_ARGB_VISUAL"); + if (env_string) + { + clutter_enable_argb = FALSE; + env_string = NULL; + } + return TRUE; } @@ -980,6 +988,12 @@ clutter_x11_has_composite_extension (void) return have_composite; } +gboolean +clutter_x11_has_argb_visuals (void) +{ + return clutter_enable_argb; +} + XVisualInfo * clutter_backend_x11_get_visual_info (ClutterBackendX11 *backend_x11) { @@ -993,4 +1007,3 @@ clutter_backend_x11_get_visual_info (ClutterBackendX11 *backend_x11) return NULL; } - diff --git a/clutter/x11/clutter-x11.h b/clutter/x11/clutter-x11.h index 58fc7a63e..2b960578c 100644 --- a/clutter/x11/clutter-x11.h +++ b/clutter/x11/clutter-x11.h @@ -124,6 +124,8 @@ gboolean clutter_x11_has_xinput (void); gboolean clutter_x11_has_composite_extension (void); +gboolean clutter_x11_has_argb_visuals (void); + Time clutter_x11_get_current_event_time (void); G_END_DECLS diff --git a/doc/reference/clutter/clutter-sections.txt b/doc/reference/clutter/clutter-sections.txt index d1c34ba0a..27b5e89ea 100644 --- a/doc/reference/clutter/clutter-sections.txt +++ b/doc/reference/clutter/clutter-sections.txt @@ -524,6 +524,8 @@ clutter_stage_get_key_focus clutter_stage_read_pixels clutter_stage_set_throttle_motion_events clutter_stage_get_throttle_motion_events +clutter_stage_set_use_alpha +clutter_stage_get_use_alpha ClutterPerspective diff --git a/tests/interactive/test-paint-wrapper.c b/tests/interactive/test-paint-wrapper.c index 7b14cef42..3a654e4f5 100644 --- a/tests/interactive/test-paint-wrapper.c +++ b/tests/interactive/test-paint-wrapper.c @@ -31,6 +31,7 @@ typedef struct SuperOH } SuperOH; static gint n_hands = NHANDS; +static gint use_alpha = 255; static GOptionEntry super_oh_entries[] = { { @@ -39,6 +40,12 @@ static GOptionEntry super_oh_entries[] = { G_OPTION_ARG_INT, &n_hands, "Number of hands", "HANDS" }, + { + "use-alpha", 'a', + 0, + G_OPTION_ARG_INT, &use_alpha, + "Stage opacity", "VALUE" + }, { NULL } }; @@ -205,6 +212,12 @@ test_paint_wrapper_main (int argc, char *argv[]) stage = clutter_stage_get_default (); clutter_actor_set_size (stage, 800, 600); + if (use_alpha != 255) + { + clutter_stage_set_use_alpha (CLUTTER_STAGE (stage), TRUE); + clutter_actor_set_opacity (stage, use_alpha); + } + clutter_stage_set_title (CLUTTER_STAGE (stage), "Paint Test"); clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color);