Make window shadows globally configurable

Instead of setting shadow parameters on individual windows, add the
idea of a "shadow class". Windows have default shadow classes based
on their frame and window type, which can be overriden by setting
the shadow-class property.

Each shadow class has separably configurable parameters for the
focused and unfocused state. New shadow classes can be defined with
arbitrary names.

https://bugzilla.gnome.org/show_bug.cgi?id=592382
This commit is contained in:
Owen W. Taylor 2010-11-11 16:24:43 -05:00
parent 7952feb48b
commit 1bbaec81ce
6 changed files with 411 additions and 184 deletions

View File

@ -11,6 +11,7 @@
#include "compositor-mutter.h" #include "compositor-mutter.h"
#include "xprops.h" #include "xprops.h"
#include "prefs.h" #include "prefs.h"
#include "meta-shadow-factory.h"
#include "meta-window-actor-private.h" #include "meta-window-actor-private.h"
#include "meta-window-group.h" #include "meta-window-group.h"
#include "../core/window-private.h" /* to check window->hidden */ #include "../core/window-private.h" /* to check window->hidden */
@ -1017,6 +1018,26 @@ meta_repaint_func (gpointer data)
return TRUE; return TRUE;
} }
static void
on_shadow_factory_changed (MetaShadowFactory *factory,
MetaCompositor *compositor)
{
GSList *screens = meta_display_get_screens (compositor->display);
GList *l;
GSList *sl;
for (sl = screens; sl; sl = sl->next)
{
MetaScreen *screen = sl->data;
MetaCompScreen *info = meta_screen_get_compositor_data (screen);
if (!info)
continue;
for (l = info->windows; l; l = l->next)
meta_window_actor_invalidate_shadow (l->data);
}
}
/** /**
* meta_compositor_new: (skip) * meta_compositor_new: (skip)
* *
@ -1047,6 +1068,11 @@ meta_compositor_new (MetaDisplay *display)
XInternAtoms (xdisplay, atom_names, G_N_ELEMENTS (atom_names), XInternAtoms (xdisplay, atom_names, G_N_ELEMENTS (atom_names),
False, atoms); False, atoms);
g_signal_connect (meta_shadow_factory_get_default (),
"changed",
G_CALLBACK (on_shadow_factory_changed),
compositor);
compositor->atom_x_root_pixmap = atoms[0]; compositor->atom_x_root_pixmap = atoms[0];
compositor->atom_x_set_root = atoms[1]; compositor->atom_x_set_root = atoms[1];
compositor->atom_net_wm_window_opacity = atoms[2]; compositor->atom_net_wm_window_opacity = atoms[2];

View File

@ -60,7 +60,7 @@ MetaShadow * meta_shadow_factory_get_shadow (MetaShadowFactory *factory,
MetaWindowShape *shape, MetaWindowShape *shape,
int width, int width,
int height, int height,
int radius, const char *class_name,
int top_fade); gboolean focused);
#endif /* __META_SHADOW_FACTORY_PRIVATE_H__ */ #endif /* __META_SHADOW_FACTORY_PRIVATE_H__ */

View File

@ -49,6 +49,7 @@
*/ */
typedef struct _MetaShadowCacheKey MetaShadowCacheKey; typedef struct _MetaShadowCacheKey MetaShadowCacheKey;
typedef struct _MetaShadowClassInfo MetaShadowClassInfo;
struct _MetaShadowCacheKey struct _MetaShadowCacheKey
{ {
@ -82,6 +83,13 @@ struct _MetaShadow
guint scale_height : 1; guint scale_height : 1;
}; };
struct _MetaShadowClassInfo
{
const char *name; /* const so we can reuse for static definitions */
MetaShadowParams focused;
MetaShadowParams unfocused;
};
struct _MetaShadowFactory struct _MetaShadowFactory
{ {
GObject parent_instance; GObject parent_instance;
@ -89,6 +97,9 @@ struct _MetaShadowFactory
/* MetaShadowCacheKey => MetaShadow; the shadows are not referenced /* MetaShadowCacheKey => MetaShadow; the shadows are not referenced
* by the factory, they are simply removed from the table when freed */ * by the factory, they are simply removed from the table when freed */
GHashTable *shadows; GHashTable *shadows;
/* class name => MetaShadowClassInfo */
GHashTable *shadow_classes;
}; };
struct _MetaShadowFactoryClass struct _MetaShadowFactoryClass
@ -96,6 +107,31 @@ struct _MetaShadowFactoryClass
GObjectClass parent_class; GObjectClass parent_class;
}; };
enum
{
CHANGED,
LAST_SIGNAL
};
static guint signals[LAST_SIGNAL] = { 0 };
/* The first element in this array also defines the default parameters
* for newly created classes */
MetaShadowClassInfo default_shadow_classes[] = {
{ "normal", { 12, -1, 0, 8, 255 }, { 6, -1, 0, 4, 255 } },
{ "dialog", { 12, -1, 0, 8, 255 }, { 6, -1, 0, 4, 255 } },
{ "modal_dialog", { 12, -1, 0, 8, 255 }, { 6, -1, 0, 4, 255 } },
{ "utility", { 12, -1, 0, 8, 255 }, { 6, -1, 0, 4, 255 } },
{ "border", { 12, -1, 0, 8, 255 }, { 6, -1, 0, 4, 255 } },
{ "menu", { 12, -1, 0, 8, 255 }, { 6, -1, 0, 4, 255 } },
{ "popup-menu", { 6, -1, 0, 4, 255 }, { 6, -1, 0, 4, 255 } },
{ "dropdown-menu", { 6, 25, 0, 4, 255 }, { 6, 100, 0, 4, 255 } },
{ "attached", { 6, 25, 0, 4, 255 }, { 6, 100, 0, 4, 255 } }
};
G_DEFINE_TYPE (MetaShadowFactory, meta_shadow_factory, G_TYPE_OBJECT); G_DEFINE_TYPE (MetaShadowFactory, meta_shadow_factory, G_TYPE_OBJECT);
static guint static guint
@ -262,11 +298,36 @@ meta_shadow_get_bounds (MetaShadow *shadow,
bounds->height = window_height + shadow->outer_border_top + shadow->outer_border_bottom; bounds->height = window_height + shadow->outer_border_top + shadow->outer_border_bottom;
} }
static void
meta_shadow_class_info_free (MetaShadowClassInfo *class_info)
{
g_free ((char *)class_info->name);
g_slice_free (MetaShadowClassInfo, class_info);
}
static void static void
meta_shadow_factory_init (MetaShadowFactory *factory) meta_shadow_factory_init (MetaShadowFactory *factory)
{ {
guint i;
factory->shadows = g_hash_table_new (meta_shadow_cache_key_hash, factory->shadows = g_hash_table_new (meta_shadow_cache_key_hash,
meta_shadow_cache_key_equal); meta_shadow_cache_key_equal);
factory->shadow_classes = g_hash_table_new_full (g_str_hash,
g_str_equal,
NULL,
(GDestroyNotify)meta_shadow_class_info_free);
for (i = 0; i < G_N_ELEMENTS (default_shadow_classes); i++)
{
MetaShadowClassInfo *class_info = g_slice_new (MetaShadowClassInfo);
*class_info = default_shadow_classes[i];
class_info->name = g_strdup (class_info->name);
g_hash_table_insert (factory->shadow_classes,
(char *)class_info->name, class_info);
}
} }
static void static void
@ -286,6 +347,7 @@ meta_shadow_factory_finalize (GObject *object)
} }
g_hash_table_destroy (factory->shadows); g_hash_table_destroy (factory->shadows);
g_hash_table_destroy (factory->shadow_classes);
G_OBJECT_CLASS (meta_shadow_factory_parent_class)->finalize (object); G_OBJECT_CLASS (meta_shadow_factory_parent_class)->finalize (object);
} }
@ -296,6 +358,15 @@ meta_shadow_factory_class_init (MetaShadowFactoryClass *klass)
GObjectClass *object_class = G_OBJECT_CLASS (klass); GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = meta_shadow_factory_finalize; object_class->finalize = meta_shadow_factory_finalize;
signals[CHANGED] =
g_signal_new ("changed",
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
0,
NULL, NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
} }
MetaShadowFactory * MetaShadowFactory *
@ -657,15 +728,45 @@ make_shadow (MetaShadow *shadow,
cogl_material_set_layer (shadow->material, 0, shadow->texture); cogl_material_set_layer (shadow->material, 0, shadow->texture);
} }
static MetaShadowParams *
get_shadow_params (MetaShadowFactory *factory,
const char *class_name,
gboolean focused,
gboolean create)
{
MetaShadowClassInfo *class_info = g_hash_table_lookup (factory->shadow_classes,
class_name);
if (class_info == NULL)
{
if (create)
{
class_info = g_slice_new0 (MetaShadowClassInfo);
*class_info = default_shadow_classes[0];
class_info->name = g_strdup (class_info->name);
g_hash_table_insert (factory->shadow_classes,
(char *)class_info->name, class_info);
}
else
{
class_info = &default_shadow_classes[0];
}
}
if (focused)
return &class_info->focused;
else
return &class_info->unfocused;
}
/** /**
* meta_shadow_factory_get_shadow: * meta_shadow_factory_get_shadow:
* @factory: a #MetaShadowFactory * @factory: a #MetaShadowFactory
* @shape: the size-invariant shape of the window's region * @shape: the size-invariant shape of the window's region
* @width: the actual width of the window's region * @width: the actual width of the window's region
* @width: the actual height of the window's region * @height: the actual height of the window's region
* @radius: the radius (gaussian standard deviation) of the shadow * @class_name: name of the class of window shadows
* @top_fade: if >= 0, the shadow doesn't extend above the top * @focused: whether the shadow is for a focused window
* of the shape, and fades out over the given number of pixels
* *
* Gets the appropriate shadow object for drawing shadows for the * Gets the appropriate shadow object for drawing shadows for the
* specified window shape. The region that we are shadowing is specified * specified window shape. The region that we are shadowing is specified
@ -681,9 +782,10 @@ meta_shadow_factory_get_shadow (MetaShadowFactory *factory,
MetaWindowShape *shape, MetaWindowShape *shape,
int width, int width,
int height, int height,
int radius, const char *class_name,
int top_fade) gboolean focused)
{ {
MetaShadowParams *params;
MetaShadowCacheKey key; MetaShadowCacheKey key;
MetaShadow *shadow; MetaShadow *shadow;
cairo_region_t *region; cairo_region_t *region;
@ -721,15 +823,18 @@ meta_shadow_factory_get_shadow (MetaShadowFactory *factory,
* In the case where we are fading a the top, that also has to fit * In the case where we are fading a the top, that also has to fit
* within the top unscaled border. * within the top unscaled border.
*/ */
spread = get_shadow_spread (radius);
params = get_shadow_params (factory, class_name, focused, FALSE);
spread = get_shadow_spread (params->radius);
meta_window_shape_get_borders (shape, meta_window_shape_get_borders (shape,
&shape_border_top, &shape_border_top,
&shape_border_right, &shape_border_right,
&shape_border_bottom, &shape_border_bottom,
&shape_border_left); &shape_border_left);
inner_border_top = MAX (shape_border_top + spread, top_fade); inner_border_top = MAX (shape_border_top + spread, params->top_fade);
outer_border_top = top_fade >= 0 ? 0 : spread; outer_border_top = params->top_fade >= 0 ? 0 : spread;
inner_border_right = shape_border_right + spread; inner_border_right = shape_border_right + spread;
outer_border_right = spread; outer_border_right = spread;
inner_border_bottom = shape_border_bottom + spread; inner_border_bottom = shape_border_bottom + spread;
@ -744,8 +849,8 @@ meta_shadow_factory_get_shadow (MetaShadowFactory *factory,
if (cacheable) if (cacheable)
{ {
key.shape = shape; key.shape = shape;
key.radius = radius; key.radius = params->radius;
key.top_fade = top_fade; key.top_fade = params->top_fade;
shadow = g_hash_table_lookup (factory->shadows, &key); shadow = g_hash_table_lookup (factory->shadows, &key);
if (shadow) if (shadow)
@ -757,8 +862,8 @@ meta_shadow_factory_get_shadow (MetaShadowFactory *factory,
shadow->ref_count = 1; shadow->ref_count = 1;
shadow->factory = factory; shadow->factory = factory;
shadow->key.shape = meta_window_shape_ref (shape); shadow->key.shape = meta_window_shape_ref (shape);
shadow->key.radius = radius; shadow->key.radius = params->radius;
shadow->key.top_fade = top_fade; shadow->key.top_fade = params->top_fade;
shadow->outer_border_top = outer_border_top; shadow->outer_border_top = outer_border_top;
shadow->inner_border_top = inner_border_top; shadow->inner_border_top = inner_border_top;
@ -793,3 +898,69 @@ meta_shadow_factory_get_shadow (MetaShadowFactory *factory,
return shadow; return shadow;
} }
/**
* meta_shadow_factory_set_params:
* @factory: a #MetaShadowFactory
* @class_name: name of the class of shadow to set the params for.
* the default shadow classes are the names of the different
* theme frame types (normal, dialog, modal_dialog, utility,
* border, menu, attached) and in addition, popup-menu
* and dropdown-menu.
* @focused: whether the shadow is for a focused window
* @params: new parameter values
*
* Updates the shadow parameters for a particular class of shadows
* for either the focused or unfocused state. If the class name
* does not name an existing class, a new class will be created
* (the other focus state for that class will have default values
* assigned to it.)
*/
void
meta_shadow_factory_set_params (MetaShadowFactory *factory,
const char *class_name,
gboolean focused,
MetaShadowParams *params)
{
MetaShadowParams *stored_params;
g_return_if_fail (META_IS_SHADOW_FACTORY (factory));
g_return_if_fail (class_name != NULL);
g_return_if_fail (params != NULL);
g_return_if_fail (params->radius >= 0);
stored_params = get_shadow_params (factory, class_name, focused, TRUE);
*stored_params = *params;
g_signal_emit (factory, signals[CHANGED], 0);
}
/**
* meta_shadow_factory_get_params:
* @factory: a #MetaShadowFactory
* @class_name: name of the class of shadow to get the params for
* @focused: whether the shadow is for a focused window
* @params: (out caller-allocates): location to store the current parameter values
*
* Gets the shadow parameters for a particular class of shadows
* for either the focused or unfocused state. If the class name
* does not name an existing class, default values will be returned
* without printing an error.
*/
void
meta_shadow_factory_get_params (MetaShadowFactory *factory,
const char *class_name,
gboolean focused,
MetaShadowParams *params)
{
MetaShadowParams *stored_params;
g_return_if_fail (META_IS_SHADOW_FACTORY (factory));
g_return_if_fail (class_name != NULL);
stored_params = get_shadow_params (factory, class_name, focused, FALSE);
if (params)
*params = *stored_params;
}

View File

@ -28,6 +28,8 @@ void meta_window_actor_process_damage (MetaWindowActor *self,
XDamageNotifyEvent *event); XDamageNotifyEvent *event);
void meta_window_actor_pre_paint (MetaWindowActor *self); void meta_window_actor_pre_paint (MetaWindowActor *self);
void meta_window_actor_invalidate_shadow (MetaWindowActor *self);
gboolean meta_window_actor_effect_in_progress (MetaWindowActor *self); gboolean meta_window_actor_effect_in_progress (MetaWindowActor *self);
void meta_window_actor_sync_actor_position (MetaWindowActor *self); void meta_window_actor_sync_actor_position (MetaWindowActor *self);
void meta_window_actor_sync_visibility (MetaWindowActor *self); void meta_window_actor_sync_visibility (MetaWindowActor *self);

View File

@ -30,7 +30,21 @@ struct _MetaWindowActorPrivate
MetaScreen *screen; MetaScreen *screen;
ClutterActor *actor; ClutterActor *actor;
MetaShadow *shadow;
/* MetaShadowFactory only caches shadows that are actually in use;
* to avoid unnecessary recomputation we do two things: 1) we store
* both a focused and unfocused shadow for the window. If the window
* doesn't have different focused and unfocused shadow parameters,
* these will be the same. 2) when the shadow potentially changes we
* don't immediately unreference the old shadow, we just flag it as
* dirty and recompute it when we next need it (recompute_focused_shadow,
* recompute_unfocused_shadow.) Because of our extraction of
* size-invariant window shape, we'll often find that the new shadow
* is the same as the old shadow.
*/
MetaShadow *focused_shadow;
MetaShadow *unfocused_shadow;
Pixmap back_pixmap; Pixmap back_pixmap;
Damage damage; Damage damage;
@ -51,10 +65,7 @@ struct _MetaWindowActorPrivate
gint freeze_count; gint freeze_count;
gint shadow_radius; char * shadow_class;
gint shadow_top_fade;
gint shadow_x_offset;
gint shadow_y_offset;
/* /*
* These need to be counters rather than flags, since more plugins * These need to be counters rather than flags, since more plugins
@ -79,7 +90,8 @@ struct _MetaWindowActorPrivate
guint needs_pixmap : 1; guint needs_pixmap : 1;
guint needs_reshape : 1; guint needs_reshape : 1;
guint recompute_shadow : 1; guint recompute_focused_shadow : 1;
guint recompute_unfocused_shadow : 1;
guint paint_shadow : 1; guint paint_shadow : 1;
guint size_changed : 1; guint size_changed : 1;
@ -97,11 +109,7 @@ enum
PROP_X_WINDOW, PROP_X_WINDOW,
PROP_X_WINDOW_ATTRIBUTES, PROP_X_WINDOW_ATTRIBUTES,
PROP_NO_SHADOW, PROP_NO_SHADOW,
PROP_SHADOW_RADIUS, PROP_SHADOW_CLASS
PROP_SHADOW_TOP_FADE,
PROP_SHADOW_X_OFFSET,
PROP_SHADOW_Y_OFFSET,
PROP_SHADOW_OPACITY
}; };
#define DEFAULT_SHADOW_RADIUS 12 #define DEFAULT_SHADOW_RADIUS 12
@ -246,56 +254,14 @@ meta_window_actor_class_init (MetaWindowActorClass *klass)
PROP_NO_SHADOW, PROP_NO_SHADOW,
pspec); pspec);
pspec = g_param_spec_int ("shadow-radius", pspec = g_param_spec_string ("shadow-class",
"Shadow Radius", "Name of the shadow class for this window.",
"Radius (standard deviation of gaussian blur) of window's shadow", "NULL means to use the default shadow class for this window type",
0, 128, DEFAULT_SHADOW_RADIUS, NULL,
G_PARAM_READWRITE); G_PARAM_READWRITE);
g_object_class_install_property (object_class, g_object_class_install_property (object_class,
PROP_SHADOW_RADIUS, PROP_SHADOW_CLASS,
pspec);
pspec = g_param_spec_int ("shadow-top-fade",
"Shadow Top Fade",
"If >= 0, the shadow doesn't extend above the top "
"of the window, and fades out over the given number of pixels",
-1, G_MAXINT, -1,
G_PARAM_READWRITE);
g_object_class_install_property (object_class,
PROP_SHADOW_TOP_FADE,
pspec);
pspec = g_param_spec_int ("shadow-x-offset",
"Shadow X Offset",
"Distance shadow is offset in the horizontal direction in pixels",
G_MININT, G_MAXINT, DEFAULT_SHADOW_X_OFFSET,
G_PARAM_READWRITE);
g_object_class_install_property (object_class,
PROP_SHADOW_X_OFFSET,
pspec);
pspec = g_param_spec_int ("shadow-y-offset",
"Shadow Y Offset",
"Distance shadow is offset in the vertical direction in piyels",
G_MININT, G_MAXINT, DEFAULT_SHADOW_Y_OFFSET,
G_PARAM_READWRITE);
g_object_class_install_property (object_class,
PROP_SHADOW_Y_OFFSET,
pspec);
pspec = g_param_spec_uint ("shadow-opacity",
"Shadow Opacity",
"Opacity of the window's shadow",
0, 255,
255,
G_PARAM_READWRITE);
g_object_class_install_property (object_class,
PROP_SHADOW_OPACITY,
pspec); pspec);
} }
@ -308,11 +274,7 @@ meta_window_actor_init (MetaWindowActor *self)
META_TYPE_WINDOW_ACTOR, META_TYPE_WINDOW_ACTOR,
MetaWindowActorPrivate); MetaWindowActorPrivate);
priv->opacity = 0xff; priv->opacity = 0xff;
priv->shadow_radius = DEFAULT_SHADOW_RADIUS; priv->shadow_class = NULL;
priv->shadow_top_fade = -1;
priv->shadow_x_offset = DEFAULT_SHADOW_X_OFFSET;
priv->shadow_y_offset = DEFAULT_SHADOW_Y_OFFSET;
priv->shadow_opacity = 0xff;
priv->paint_shadow = TRUE; priv->paint_shadow = TRUE;
} }
@ -470,10 +432,22 @@ meta_window_actor_dispose (GObject *object)
meta_window_actor_clear_shape_region (self); meta_window_actor_clear_shape_region (self);
meta_window_actor_clear_bounding_region (self); meta_window_actor_clear_bounding_region (self);
if (priv->shadow != NULL) if (priv->shadow_class != NULL)
{ {
meta_shadow_unref (priv->shadow); g_free (priv->shadow_class);
priv->shadow = NULL; priv->shadow_class = NULL;
}
if (priv->focused_shadow != NULL)
{
meta_shadow_unref (priv->focused_shadow);
priv->focused_shadow = NULL;
}
if (priv->unfocused_shadow != NULL)
{
meta_shadow_unref (priv->unfocused_shadow);
priv->unfocused_shadow = NULL;
} }
if (priv->shadow_shape != NULL) if (priv->shadow_shape != NULL)
@ -545,65 +519,20 @@ meta_window_actor_set_property (GObject *object,
priv->no_shadow = newv; priv->no_shadow = newv;
priv->recompute_shadow = TRUE; meta_window_actor_invalidate_shadow (self);
clutter_actor_queue_redraw (CLUTTER_ACTOR (self));
} }
break; break;
case PROP_SHADOW_RADIUS: case PROP_SHADOW_CLASS:
{ {
gint newv = g_value_get_int (value); const char *newv = g_value_get_string (value);
if (newv == priv->shadow_radius) if (g_strcmp0 (newv, priv->shadow_class) == 0)
return; return;
priv->shadow_radius = newv; g_free (priv->shadow_class);
priv->recompute_shadow = TRUE; priv->shadow_class = g_strdup (newv);
clutter_actor_queue_redraw (CLUTTER_ACTOR (self));
}
break;
case PROP_SHADOW_TOP_FADE:
{
gint newv = g_value_get_int (value);
if (newv == priv->shadow_top_fade) meta_window_actor_invalidate_shadow (self);
return;
priv->shadow_top_fade = newv;
priv->recompute_shadow = TRUE;
clutter_actor_queue_redraw (CLUTTER_ACTOR (self));
}
break;
case PROP_SHADOW_X_OFFSET:
{
gint newv = g_value_get_int (value);
if (newv == priv->shadow_x_offset)
return;
priv->shadow_x_offset = newv;
clutter_actor_queue_redraw (CLUTTER_ACTOR (self));
}
break;
case PROP_SHADOW_Y_OFFSET:
{
gint newv = g_value_get_int (value);
if (newv == priv->shadow_y_offset)
return;
priv->shadow_y_offset = newv;
clutter_actor_queue_redraw (CLUTTER_ACTOR (self));
}
break;
case PROP_SHADOW_OPACITY:
{
guint newv = g_value_get_uint (value);
if (newv == priv->shadow_opacity)
return;
priv->shadow_opacity = newv;
clutter_actor_queue_redraw (CLUTTER_ACTOR (self));
} }
break; break;
default: default:
@ -637,26 +566,53 @@ meta_window_actor_get_property (GObject *object,
case PROP_NO_SHADOW: case PROP_NO_SHADOW:
g_value_set_boolean (value, priv->no_shadow); g_value_set_boolean (value, priv->no_shadow);
break; break;
case PROP_SHADOW_RADIUS: case PROP_SHADOW_CLASS:
g_value_set_int (value, priv->shadow_radius); g_value_set_string (value, priv->shadow_class);
break; break;
case PROP_SHADOW_TOP_FADE:
g_value_set_int (value, priv->shadow_top_fade);
break;
case PROP_SHADOW_X_OFFSET:
g_value_set_int (value, priv->shadow_x_offset);
break;
case PROP_SHADOW_Y_OFFSET:
g_value_set_int (value, priv->shadow_y_offset);
break;
case PROP_SHADOW_OPACITY:
g_value_set_uint (value, priv->shadow_opacity);
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break; break;
} }
} }
static const char *
meta_window_actor_get_shadow_class (MetaWindowActor *self)
{
MetaWindowActorPrivate *priv = self->priv;
if (priv->shadow_class != NULL)
return priv->shadow_class;
else
{
MetaWindowType window_type = meta_window_get_window_type (priv->window);
switch (window_type)
{
case META_WINDOW_DROPDOWN_MENU:
return "dropdown-menu";
case META_WINDOW_POPUP_MENU:
return "popup-menu";
default:
{
MetaFrameType frame_type = meta_window_get_frame_type (priv->window);
return meta_frame_type_to_string (frame_type);
}
}
}
}
static void
meta_window_actor_get_shadow_params (MetaWindowActor *self,
gboolean appears_focused,
MetaShadowParams *params)
{
const char *shadow_class = meta_window_actor_get_shadow_class (self);
meta_shadow_factory_get_params (meta_shadow_factory_get_default (),
shadow_class, appears_focused,
params);
}
static void static void
meta_window_actor_get_shape_bounds (MetaWindowActor *self, meta_window_actor_get_shape_bounds (MetaWindowActor *self,
cairo_rectangle_int_t *bounds) cairo_rectangle_int_t *bounds)
@ -675,17 +631,26 @@ meta_window_actor_paint (ClutterActor *actor)
MetaWindowActor *self = META_WINDOW_ACTOR (actor); MetaWindowActor *self = META_WINDOW_ACTOR (actor);
MetaWindowActorPrivate *priv = self->priv; MetaWindowActorPrivate *priv = self->priv;
if (priv->shadow != NULL && priv->paint_shadow) if (priv->paint_shadow)
{ {
cairo_rectangle_int_t shape_bounds; gboolean appears_focused = meta_window_appears_focused (priv->window);
meta_window_actor_get_shape_bounds (self, &shape_bounds); MetaShadow *shadow = appears_focused ? priv->focused_shadow : priv->unfocused_shadow;
meta_shadow_paint (priv->shadow, if (shadow != NULL)
priv->shadow_x_offset + shape_bounds.x, {
priv->shadow_y_offset + shape_bounds.y, MetaShadowParams params;
cairo_rectangle_int_t shape_bounds;
meta_window_actor_get_shape_bounds (self, &shape_bounds);
meta_window_actor_get_shadow_params (self, appears_focused, &params);
meta_shadow_paint (shadow,
params.x_offset + shape_bounds.x,
params.y_offset + shape_bounds.y,
shape_bounds.width, shape_bounds.width,
shape_bounds.height, shape_bounds.height,
(clutter_actor_get_paint_opacity (actor) * priv->shadow_opacity) / 255); (clutter_actor_get_paint_opacity (actor) * params.opacity) / 255);
}
} }
CLUTTER_ACTOR_CLASS (meta_window_actor_parent_class)->paint (actor); CLUTTER_ACTOR_CLASS (meta_window_actor_parent_class)->paint (actor);
@ -719,9 +684,6 @@ meta_window_actor_has_shadow (MetaWindowActor *self)
if (priv->no_shadow) if (priv->no_shadow)
return FALSE; return FALSE;
if (priv->shadow_radius == 0)
return FALSE;
/* /*
* Always put a shadow around windows with a frame - This should override * Always put a shadow around windows with a frame - This should override
* the restriction about not putting a shadow around ARGB windows. * the restriction about not putting a shadow around ARGB windows.
@ -1536,7 +1498,7 @@ meta_window_actor_update_bounding_region (MetaWindowActor *self,
* the shadow when the size changes. * the shadow when the size changes.
*/ */
if (!priv->shaped) if (!priv->shaped)
priv->recompute_shadow = TRUE; meta_window_actor_invalidate_shadow (self);
} }
static void static void
@ -1666,8 +1628,10 @@ meta_window_actor_set_visible_region_beneath (MetaWindowActor *self,
{ {
MetaWindowActorPrivate *priv = self->priv; MetaWindowActorPrivate *priv = self->priv;
if (priv->shadow) if (priv->focused_shadow)
{ {
gboolean appears_focused = meta_window_appears_focused (priv->window);
MetaShadowParams params;
cairo_rectangle_int_t shape_bounds; cairo_rectangle_int_t shape_bounds;
cairo_rectangle_int_t shadow_bounds; cairo_rectangle_int_t shadow_bounds;
cairo_region_overlap_t overlap; cairo_region_overlap_t overlap;
@ -1679,10 +1643,11 @@ meta_window_actor_set_visible_region_beneath (MetaWindowActor *self,
* at all. * at all.
*/ */
meta_window_actor_get_shape_bounds (self, &shape_bounds); meta_window_actor_get_shape_bounds (self, &shape_bounds);
meta_window_actor_get_shadow_params (self, appears_focused, &params);
meta_shadow_get_bounds (priv->shadow, meta_shadow_get_bounds (appears_focused ? priv->focused_shadow : priv->unfocused_shadow,
priv->shadow_x_offset + shape_bounds.x, params.x_offset + shape_bounds.x,
priv->shadow_y_offset + shape_bounds.y, params.y_offset + shape_bounds.y,
shape_bounds.width, shape_bounds.width,
shape_bounds.height, shape_bounds.height,
&shadow_bounds); &shadow_bounds);
@ -1804,7 +1769,10 @@ check_needs_shadow (MetaWindowActor *self)
{ {
MetaWindowActorPrivate *priv = self->priv; MetaWindowActorPrivate *priv = self->priv;
MetaShadow *old_shadow = NULL; MetaShadow *old_shadow = NULL;
MetaShadow **shadow_location;
gboolean recompute_shadow;
gboolean should_have_shadow; gboolean should_have_shadow;
gboolean appears_focused;
if (!priv->mapped) if (!priv->mapped)
return; return;
@ -1817,16 +1785,34 @@ check_needs_shadow (MetaWindowActor *self)
*/ */
should_have_shadow = meta_window_actor_has_shadow (self); should_have_shadow = meta_window_actor_has_shadow (self);
appears_focused = meta_window_appears_focused (priv->window);
if (priv->shadow != NULL && (!should_have_shadow || priv->recompute_shadow)) if (appears_focused)
{ {
old_shadow = priv->shadow; recompute_shadow = priv->recompute_focused_shadow;
priv->shadow = NULL; priv->recompute_focused_shadow = FALSE;
shadow_location = &priv->focused_shadow;
}
else
{
recompute_shadow = priv->recompute_unfocused_shadow;
priv->recompute_unfocused_shadow = FALSE;
shadow_location = &priv->unfocused_shadow;
} }
if (priv->shadow == NULL && should_have_shadow) if (!should_have_shadow || recompute_shadow)
{
if (*shadow_location != NULL)
{
old_shadow = *shadow_location;
*shadow_location = NULL;
}
}
if (*shadow_location == NULL && should_have_shadow)
{ {
MetaShadowFactory *factory = meta_shadow_factory_get_default (); MetaShadowFactory *factory = meta_shadow_factory_get_default ();
const char *shadow_class = meta_window_actor_get_shadow_class (self);
cairo_rectangle_int_t shape_bounds; cairo_rectangle_int_t shape_bounds;
if (priv->shadow_shape == NULL) if (priv->shadow_shape == NULL)
@ -1839,16 +1825,14 @@ check_needs_shadow (MetaWindowActor *self)
meta_window_actor_get_shape_bounds (self, &shape_bounds); meta_window_actor_get_shape_bounds (self, &shape_bounds);
priv->shadow = meta_shadow_factory_get_shadow (factory, *shadow_location = meta_shadow_factory_get_shadow (factory,
priv->shadow_shape, priv->shadow_shape,
shape_bounds.width, shape_bounds.height, shape_bounds.width, shape_bounds.height,
priv->shadow_radius, priv->shadow_top_fade); shadow_class, appears_focused);
} }
if (old_shadow != NULL) if (old_shadow != NULL)
meta_shadow_unref (old_shadow); meta_shadow_unref (old_shadow);
priv->recompute_shadow = FALSE;
} }
static gboolean static gboolean
@ -1949,7 +1933,7 @@ check_needs_reshape (MetaWindowActor *self)
#endif #endif
priv->needs_reshape = FALSE; priv->needs_reshape = FALSE;
priv->recompute_shadow = TRUE; meta_window_actor_invalidate_shadow (self);
} }
void void
@ -1997,6 +1981,16 @@ meta_window_actor_pre_paint (MetaWindowActor *self)
check_needs_shadow (self); check_needs_shadow (self);
} }
void
meta_window_actor_invalidate_shadow (MetaWindowActor *self)
{
MetaWindowActorPrivate *priv = self->priv;
priv->recompute_focused_shadow = TRUE;
priv->recompute_unfocused_shadow = TRUE;
clutter_actor_queue_redraw (CLUTTER_ACTOR (self));
}
void void
meta_window_actor_update_opacity (MetaWindowActor *self) meta_window_actor_update_opacity (MetaWindowActor *self)
{ {

View File

@ -27,6 +27,31 @@
#include <glib-object.h> #include <glib-object.h>
/**
* MetaShadowParams:
* The #MetaShadowParams structure holds information about how to draw
* a particular style of shadow.
* @radius: the radius (gaussian standard deviation) of the shadow
* @top_fade: if >= 0, the shadow doesn't extend above the top
* of the shape, and fades out over the given number of pixels
* @x_offset: horizontal offset of the shadow with respect to the
* shape being shadowed, in pixels
* @y_offset: vertical offset of the shadow with respect to the
* shape being shadowed, in pixels
* @opacity: opacity of the shadow, from 0 to 255
*/
typedef struct _MetaShadowParams MetaShadowParams;
struct _MetaShadowParams
{
int radius;
int top_fade;
int x_offset;
int y_offset;
guint8 opacity;
};
#define META_TYPE_SHADOW_FACTORY (meta_shadow_factory_get_type ()) #define META_TYPE_SHADOW_FACTORY (meta_shadow_factory_get_type ())
#define META_SHADOW_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_SHADOW_FACTORY, MetaShadowFactory)) #define META_SHADOW_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_SHADOW_FACTORY, MetaShadowFactory))
#define META_SHADOW_FACTORY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_SHADOW_FACTORY, MetaShadowFactoryClass)) #define META_SHADOW_FACTORY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_SHADOW_FACTORY, MetaShadowFactoryClass))
@ -47,4 +72,13 @@ MetaShadowFactory *meta_shadow_factory_get_default (void);
GType meta_shadow_factory_get_type (void); GType meta_shadow_factory_get_type (void);
void meta_shadow_factory_set_params (MetaShadowFactory *factory,
const char *class_name,
gboolean focused,
MetaShadowParams *params);
void meta_shadow_factory_get_params (MetaShadowFactory *factory,
const char *class_name,
gboolean focused,
MetaShadowParams *params);
#endif /* __META_SHADOW_FACTORY_H__ */ #endif /* __META_SHADOW_FACTORY_H__ */