Allow shaped windows _with frames_ to have shadows.

2008-03-18  Iain Holmes  <iain@gnome.org>

        * src/core/compositor.c (window_has_shadow): Allow shaped 
windows
        _with frames_ to have shadows.
        (meta_compositor_set_active_window): Watch for the focus of 
windows
        and change the size of the drop shadows.
        (generate_shadows): Create differently sized shadows.
        (meta_compositor_get_window_pixmap): Get the xwindow correctly.

        * src/core/window.c (meta_window_notify_focus): Set the active 
window
        in the compositor.


svn path=/trunk/; revision=3653
This commit is contained in:
Iain Holmes 2008-03-18 23:42:20 +00:00 committed by Iain Holmes
parent 3299427097
commit e629364582
4 changed files with 266 additions and 68 deletions

View File

@ -1,3 +1,15 @@
2008-03-18 Iain Holmes <iain@gnome.org>
* src/core/compositor.c (window_has_shadow): Allow shaped windows
_with frames_ to have shadows.
(meta_compositor_set_active_window): Watch for the focus of windows
and change the size of the drop shadows.
(generate_shadows): Create differently sized shadows.
(meta_compositor_get_window_pixmap): Get the xwindow correctly.
* src/core/window.c (meta_window_notify_focus): Set the active window
in the compositor.
2008-03-18 Marco Pesenti Gritti <mpgritti@gmail.com> 2008-03-18 Marco Pesenti Gritti <mpgritti@gmail.com>
* src/core/window.c (window_would_be_covered): newly created windows * src/core/window.c (window_would_be_covered): newly created windows

View File

@ -83,6 +83,14 @@ typedef enum _MetaCompWindowType
META_COMP_WINDOW_DOCK META_COMP_WINDOW_DOCK
} MetaCompWindowType; } MetaCompWindowType;
typedef enum _MetaShadowType
{
META_SHADOW_SMALL,
META_SHADOW_MEDIUM,
META_SHADOW_LARGE,
LAST_SHADOW_TYPE
} MetaShadowType;
struct _MetaCompositor struct _MetaCompositor
{ {
MetaDisplay *display; MetaDisplay *display;
@ -106,18 +114,25 @@ typedef struct _conv
double *data; double *data;
} conv; } conv;
typedef struct _shadow
{
conv *gaussian_map;
guchar *shadow_corner;
guchar *shadow_top;
} shadow;
typedef struct _MetaCompScreen typedef struct _MetaCompScreen
{ {
MetaScreen *screen; MetaScreen *screen;
GList *windows; GList *windows;
GHashTable *windows_by_xid; GHashTable *windows_by_xid;
MetaWindow *focus_window;
Window output; Window output;
gboolean have_shadows; gboolean have_shadows;
conv *gaussian_map; shadow *shadows[LAST_SHADOW_TYPE];
guchar *shadow_corner;
guchar *shadow_top;
Picture root_picture; Picture root_picture;
Picture root_buffer; Picture root_buffer;
@ -154,13 +169,15 @@ typedef struct _MetaCompWindow
gboolean damaged; gboolean damaged;
gboolean shaped; gboolean shaped;
gboolean needs_shadow;
MetaCompWindowType type; MetaCompWindowType type;
Damage damage; Damage damage;
Picture picture; Picture picture;
Picture alpha_pict; Picture alpha_pict;
gboolean needs_shadow;
MetaShadowType shadow_type;
Picture shadow_pict; Picture shadow_pict;
XserverRegion border_size; XserverRegion border_size;
@ -185,9 +202,16 @@ typedef struct _MetaCompWindow
#define WINDOW_SOLID 0 #define WINDOW_SOLID 0
#define WINDOW_ARGB 1 #define WINDOW_ARGB 1
#define SHADOW_RADIUS 6.0 #define SHADOW_SMALL_RADIUS 3.0
#define SHADOW_OFFSET_X (SHADOW_RADIUS * -3 / 2) #define SHADOW_MEDIUM_RADIUS 6.0
#define SHADOW_OFFSET_Y (SHADOW_RADIUS * -5 / 4) #define SHADOW_LARGE_RADIUS 12.0
#define SHADOW_SMALL_OFFSET_X (SHADOW_SMALL_RADIUS * -3 / 2)
#define SHADOW_SMALL_OFFSET_Y (SHADOW_SMALL_RADIUS * -3 / 2)
#define SHADOW_MEDIUM_OFFSET_X (SHADOW_MEDIUM_RADIUS * -3 / 2)
#define SHADOW_MEDIUM_OFFSET_Y (SHADOW_MEDIUM_RADIUS * -5 / 4)
#define SHADOW_LARGE_OFFSET_X -15
#define SHADOW_LARGE_OFFSET_Y -15
#define SHADOW_OPACITY 0.66 #define SHADOW_OPACITY 0.66
@ -343,73 +367,93 @@ sum_gaussian (conv *map,
/* precompute shadow corners and sides to save time for large windows */ /* precompute shadow corners and sides to save time for large windows */
static void static void
presum_gaussian (MetaCompScreen *info) presum_gaussian (shadow *shad)
{ {
int centre; int centre;
int opacity, x, y; int opacity, x, y;
int msize; int msize;
conv *map; conv *map;
map = info->gaussian_map; map = shad->gaussian_map;
msize = map->size; msize = map->size;
centre = map->size / 2; centre = map->size / 2;
if (info->shadow_corner) if (shad->shadow_corner)
g_free (info->shadow_corner); g_free (shad->shadow_corner);
if (info->shadow_top) if (shad->shadow_top)
g_free (info->shadow_top); g_free (shad->shadow_top);
info->shadow_corner = (guchar *)(g_malloc ((msize + 1) * (msize + 1) * 26)); shad->shadow_corner = (guchar *)(g_malloc ((msize + 1) * (msize + 1) * 26));
info->shadow_top = (guchar *) (g_malloc ((msize + 1) * 26)); shad->shadow_top = (guchar *) (g_malloc ((msize + 1) * 26));
for (x = 0; x <= msize; x++) for (x = 0; x <= msize; x++)
{ {
info->shadow_top[25 * (msize + 1) + x] = shad->shadow_top[25 * (msize + 1) + x] =
sum_gaussian (map, 1, x - centre, centre, msize * 2, msize * 2); sum_gaussian (map, 1, x - centre, centre, msize * 2, msize * 2);
for (opacity = 0; opacity < 25; opacity++) for (opacity = 0; opacity < 25; opacity++)
{ {
info->shadow_top[opacity * (msize + 1) + x] = shad->shadow_top[opacity * (msize + 1) + x] =
info->shadow_top[25 * (msize + 1) + x] * opacity / 25; shad->shadow_top[25 * (msize + 1) + x] * opacity / 25;
} }
for (y = 0; y <= x; y++) for (y = 0; y <= x; y++)
{ {
info->shadow_corner[25 * (msize + 1) * (msize + 1) shad->shadow_corner[25 * (msize + 1) * (msize + 1)
+ y * (msize + 1) + y * (msize + 1)
+ x] + x]
= sum_gaussian (map, 1, x - centre, y - centre, = sum_gaussian (map, 1, x - centre, y - centre,
msize * 2, msize * 2); msize * 2, msize * 2);
info->shadow_corner[25 * (msize + 1) * (msize + 1) shad->shadow_corner[25 * (msize + 1) * (msize + 1)
+ x * (msize + 1) + y] = + x * (msize + 1) + y] =
info->shadow_corner[25 * (msize + 1) * (msize + 1) shad->shadow_corner[25 * (msize + 1) * (msize + 1)
+ y * (msize + 1) + x]; + y * (msize + 1) + x];
for (opacity = 0; opacity < 25; opacity++) for (opacity = 0; opacity < 25; opacity++)
{ {
info->shadow_corner[opacity * (msize + 1) * (msize + 1) shad->shadow_corner[opacity * (msize + 1) * (msize + 1)
+ y * (msize + 1) + x] + y * (msize + 1) + x]
= info->shadow_corner[opacity * (msize + 1) * (msize + 1) = shad->shadow_corner[opacity * (msize + 1) * (msize + 1)
+ x * (msize + 1) + y] + x * (msize + 1) + y]
= info->shadow_corner[25 * (msize + 1) * (msize + 1) = shad->shadow_corner[25 * (msize + 1) * (msize + 1)
+ y * (msize + 1) + x] * opacity / 25; + y * (msize + 1) + x] * opacity / 25;
} }
} }
} }
} }
static void
generate_shadows (MetaCompScreen *info)
{
double radii[LAST_SHADOW_TYPE] = {SHADOW_SMALL_RADIUS,
SHADOW_MEDIUM_RADIUS,
SHADOW_LARGE_RADIUS};
int i;
for (i = 0; i < LAST_SHADOW_TYPE; i++) {
shadow *shad = g_new0 (shadow, 1);
shad->gaussian_map = make_gaussian_map (radii[i]);
presum_gaussian (shad);
info->shadows[i] = shad;
}
}
static XImage * static XImage *
make_shadow (MetaDisplay *display, make_shadow (MetaDisplay *display,
MetaScreen *screen, MetaScreen *screen,
double opacity, MetaShadowType shadow_type,
int width, double opacity,
int height) int width,
int height)
{ {
MetaCompScreen *info = screen->compositor_data; MetaCompScreen *info = screen->compositor_data;
XImage *ximage; XImage *ximage;
guchar *data; guchar *data;
int msize = info->gaussian_map->size; shadow *shad = info->shadows[shadow_type];
int msize = shad->gaussian_map->size;
int ylimit, xlimit; int ylimit, xlimit;
int swidth = width + msize; int swidth = width + msize;
int sheight = height + msize; int sheight = height + msize;
@ -439,9 +483,9 @@ make_shadow (MetaDisplay *display,
* centre (fill the complete data array * centre (fill the complete data array
*/ */
if (msize > 0) if (msize > 0)
d = info->shadow_top[opacity_int * (msize + 1) + msize]; d = shad->shadow_top[opacity_int * (msize + 1) + msize];
else else
d = sum_gaussian (info->gaussian_map, opacity, centre, d = sum_gaussian (shad->gaussian_map, opacity, centre,
centre, width, height); centre, width, height);
memset (data, d, sheight * swidth); memset (data, d, sheight * swidth);
@ -462,9 +506,9 @@ make_shadow (MetaDisplay *display,
{ {
if (xlimit == msize && ylimit == msize) if (xlimit == msize && ylimit == msize)
d = info->shadow_corner[opacity_int * (msize + 1) * (msize + 1) + y * (msize + 1) + x]; d = shad->shadow_corner[opacity_int * (msize + 1) * (msize + 1) + y * (msize + 1) + x];
else else
d = sum_gaussian (info->gaussian_map, opacity, x - centre, d = sum_gaussian (shad->gaussian_map, opacity, x - centre,
y - centre, width, height); y - centre, width, height);
data[y * swidth + x] = d; data[y * swidth + x] = d;
@ -481,9 +525,9 @@ make_shadow (MetaDisplay *display,
for (y = 0; y < ylimit; y++) for (y = 0; y < ylimit; y++)
{ {
if (ylimit == msize) if (ylimit == msize)
d = info->shadow_top[opacity_int * (msize + 1) + y]; d = shad->shadow_top[opacity_int * (msize + 1) + y];
else else
d = sum_gaussian (info->gaussian_map, opacity, centre, d = sum_gaussian (shad->gaussian_map, opacity, centre,
y - centre, width, height); y - centre, width, height);
memset (&data[y * swidth + msize], d, x_diff); memset (&data[y * swidth + msize], d, x_diff);
@ -497,10 +541,10 @@ make_shadow (MetaDisplay *display,
for (x = 0; x < xlimit; x++) for (x = 0; x < xlimit; x++)
{ {
if (xlimit == msize) if (xlimit == msize)
d = info->shadow_top[opacity_int * (msize + 1) + x]; d = shad->shadow_top[opacity_int * (msize + 1) + x];
else else
d = sum_gaussian (info->gaussian_map, opacity, x - centre, d = sum_gaussian (shad->gaussian_map, opacity, x - centre,
centre, width, height); centre, width, height);
for (y = msize; y < sheight - msize; y++) for (y = msize; y < sheight - msize; y++)
{ {
@ -513,21 +557,23 @@ make_shadow (MetaDisplay *display,
} }
static Picture static Picture
shadow_picture (MetaDisplay *display, shadow_picture (MetaDisplay *display,
MetaScreen *screen, MetaScreen *screen,
double opacity, MetaShadowType shadow_type,
Picture alpha_pict, double opacity,
int width, Picture alpha_pict,
int height, int width,
int *wp, int height,
int *hp) int *wp,
int *hp)
{ {
XImage *shadow_image; XImage *shadow_image;
Pixmap shadow_pixmap; Pixmap shadow_pixmap;
Picture shadow_picture; Picture shadow_picture;
GC gc; GC gc;
shadow_image = make_shadow (display, screen, opacity, width, height); shadow_image = make_shadow (display, screen, shadow_type,
opacity, width, height);
if (!shadow_image) if (!shadow_image)
return None; return None;
@ -777,13 +823,9 @@ window_has_shadow (MetaCompWindow *cw)
if (((MetaCompScreen *)cw->screen->compositor_data)->have_shadows == FALSE) if (((MetaCompScreen *)cw->screen->compositor_data)->have_shadows == FALSE)
return FALSE; return FALSE;
/* Never put a shadow around shaped windows */ /* Always put a shadow around windows with a frame - This should override
if (cw->shaped) { the restriction about not putting a shadow around shaped windows
meta_verbose ("Window has no shadow as it is shaped\n"); as the frame might be the reason the window is shaped */
return FALSE;
}
/* Always put a shadow around windows with a frame */
if (cw->window) if (cw->window)
{ {
if (cw->window->frame) { if (cw->window->frame) {
@ -792,6 +834,12 @@ window_has_shadow (MetaCompWindow *cw)
} }
} }
/* Never put a shadow around shaped windows */
if (cw->shaped) {
meta_verbose ("Window has no shadow as it is shaped\n");
return FALSE;
}
/* Don't put shadow around DND icon windows */ /* Don't put shadow around DND icon windows */
if (cw->type == META_COMP_WINDOW_DND || if (cw->type == META_COMP_WINDOW_DND ||
cw->type == META_COMP_WINDOW_DESKTOP) { cw->type == META_COMP_WINDOW_DESKTOP) {
@ -808,6 +856,12 @@ window_has_shadow (MetaCompWindow *cw)
return FALSE; return FALSE;
} }
double shadow_offsets_x[LAST_SHADOW_TYPE] = {SHADOW_SMALL_OFFSET_X,
SHADOW_MEDIUM_OFFSET_X,
SHADOW_LARGE_OFFSET_X};
double shadow_offsets_y[LAST_SHADOW_TYPE] = {SHADOW_SMALL_OFFSET_Y,
SHADOW_MEDIUM_OFFSET_Y,
SHADOW_LARGE_OFFSET_Y};
static XserverRegion static XserverRegion
win_extents (MetaCompWindow *cw) win_extents (MetaCompWindow *cw)
{ {
@ -829,8 +883,8 @@ win_extents (MetaCompWindow *cw)
{ {
XRectangle sr; XRectangle sr;
cw->shadow_dx = SHADOW_OFFSET_X; cw->shadow_dx = shadow_offsets_x [cw->shadow_type];
cw->shadow_dy = SHADOW_OFFSET_Y; cw->shadow_dy = shadow_offsets_y [cw->shadow_type];
if (!cw->shadow) if (!cw->shadow)
{ {
@ -838,7 +892,8 @@ win_extents (MetaCompWindow *cw)
if (cw->opacity != (guint) OPAQUE) if (cw->opacity != (guint) OPAQUE)
opacity = opacity * ((double) cw->opacity) / ((double) OPAQUE); opacity = opacity * ((double) cw->opacity) / ((double) OPAQUE);
cw->shadow = shadow_picture (display, screen, opacity, cw->alpha_pict, cw->shadow = shadow_picture (display, screen, cw->shadow_type,
opacity, cw->alpha_pict,
cw->attrs.width + cw->attrs.border_width * 2, cw->attrs.width + cw->attrs.border_width * 2,
cw->attrs.height + cw->attrs.border_width * 2, cw->attrs.height + cw->attrs.border_width * 2,
&cw->shadow_width, &cw->shadow_height); &cw->shadow_width, &cw->shadow_height);
@ -1692,6 +1747,12 @@ add_win (MetaScreen *screen,
cw->shadow_dy = 0; cw->shadow_dy = 0;
cw->shadow_width = 0; cw->shadow_width = 0;
cw->shadow_height = 0; cw->shadow_height = 0;
if (window && window->has_focus)
cw->shadow_type = META_SHADOW_LARGE;
else
cw->shadow_type = META_SHADOW_MEDIUM;
cw->opacity = OPAQUE; cw->opacity = OPAQUE;
cw->border_clip = None; cw->border_clip = None;
@ -2437,13 +2498,20 @@ meta_compositor_manage_screen (MetaCompositor *compositor,
info->windows = NULL; info->windows = NULL;
info->windows_by_xid = g_hash_table_new (g_direct_hash, g_direct_equal); info->windows_by_xid = g_hash_table_new (g_direct_hash, g_direct_equal);
info->focus_window = display->focus_window;
info->compositor_active = TRUE; info->compositor_active = TRUE;
info->overlays = 0; info->overlays = 0;
info->clip_changed = TRUE; info->clip_changed = TRUE;
info->have_shadows = (g_getenv("META_DEBUG_NO_SHADOW") == NULL); info->have_shadows = (g_getenv("META_DEBUG_NO_SHADOW") == NULL);
info->gaussian_map = make_gaussian_map (SHADOW_RADIUS); if (info->have_shadows)
presum_gaussian (info); {
meta_verbose ("Enabling shadows\n");
generate_shadows (info);
}
else
meta_verbose ("Disabling shadows\n");
XClearArea (display->xdisplay, info->output, 0, 0, 0, 0, TRUE); XClearArea (display->xdisplay, info->output, 0, 0, 0, 0, TRUE);
@ -2484,7 +2552,13 @@ meta_compositor_unmanage_screen (MetaCompositor *compositor,
if (info->black_picture) if (info->black_picture)
XRenderFreePicture (display->xdisplay, info->black_picture); XRenderFreePicture (display->xdisplay, info->black_picture);
g_free (info->gaussian_map); if (info->have_shadows)
{
int i;
for (i = 0; i < LAST_SHADOW_TYPE; i++)
g_free (info->shadows[i]->gaussian_map);
}
XCompositeUnredirectSubwindows (display->xdisplay, screen->xroot, XCompositeUnredirectSubwindows (display->xdisplay, screen->xroot,
CompositeRedirectManual); CompositeRedirectManual);
@ -2637,13 +2711,9 @@ meta_compositor_get_window_pixmap (MetaCompositor *compositor,
#ifdef HAVE_COMPOSITE_EXTENSIONS #ifdef HAVE_COMPOSITE_EXTENSIONS
MetaCompWindow *cw = NULL; MetaCompWindow *cw = NULL;
if (window->frame) cw = find_window_for_screen (window->screen,
{ window->frame ? window->frame->xwindow :
cw = find_window_for_screen (window->screen, window->frame->xwindow); window->xwindow);
if (cw == NULL)
cw = find_window_for_screen (window->screen, window->xwindow);
}
if (cw == NULL) if (cw == NULL)
return None; return None;
@ -2660,3 +2730,115 @@ meta_compositor_get_window_pixmap (MetaCompositor *compositor,
return None; return None;
#endif #endif
} }
void
meta_compositor_set_active_window (MetaCompositor *compositor,
MetaWindow *window)
{
#ifdef HAVE_COMPOSITE_EXTENSIONS
MetaDisplay *display = compositor->display;
Display *xdisplay = display->xdisplay;
MetaScreen *screen = window->screen;
MetaCompWindow *old_focus = NULL, *new_focus = NULL;
MetaCompScreen *info = screen->compositor_data;
MetaWindow *old_focus_win = info->focus_window;
if (old_focus_win)
{
old_focus = find_window_for_screen (screen,
old_focus_win->frame ? old_focus_win->frame->xwindow :
old_focus_win->xwindow);
}
new_focus = find_window_for_screen (screen,
window->frame ? window->frame->xwindow :
window->xwindow);
info->focus_window = window;
if (old_focus)
{
XserverRegion damage;
/* Tear down old shadows */
old_focus->shadow_type = META_SHADOW_MEDIUM;
determine_mode (display, screen, old_focus);
old_focus->needs_shadow = window_has_shadow (old_focus);
if (old_focus->attrs.map_state == IsViewable)
{
if (old_focus->shadow)
{
XRenderFreePicture (xdisplay, old_focus->shadow);
old_focus->shadow = None;
}
if (old_focus->extents)
{
damage = XFixesCreateRegion (xdisplay, NULL, 0);
XFixesCopyRegion (xdisplay, damage, old_focus->extents);
XFixesDestroyRegion (xdisplay, old_focus->extents);
}
else
damage = None;
/* Build new extents */
old_focus->extents = win_extents (old_focus);
if (damage)
XFixesUnionRegion (xdisplay, damage, damage, old_focus->extents);
else
{
damage = XFixesCreateRegion (xdisplay, NULL, 0);
XFixesCopyRegion (xdisplay, damage, old_focus->extents);
}
dump_xserver_region ("resize_win", display, damage);
add_damage (screen, damage);
info->clip_changed = TRUE;
}
}
if (new_focus)
{
XserverRegion damage;
new_focus->shadow_type = META_SHADOW_LARGE;
determine_mode (display, screen, new_focus);
new_focus->needs_shadow = window_has_shadow (new_focus);
if (new_focus->shadow)
{
XRenderFreePicture (xdisplay, new_focus->shadow);
new_focus->shadow = None;
}
if (new_focus->extents)
{
damage = XFixesCreateRegion (xdisplay, NULL, 0);
XFixesCopyRegion (xdisplay, damage, new_focus->extents);
XFixesDestroyRegion (xdisplay, new_focus->extents);
}
else
damage = None;
/* Build new extents */
new_focus->extents = win_extents (new_focus);
if (damage)
XFixesUnionRegion (xdisplay, damage, damage, new_focus->extents);
else
{
damage = XFixesCreateRegion (xdisplay, NULL, 0);
XFixesCopyRegion (xdisplay, damage, new_focus->extents);
}
dump_xserver_region ("resize_win", display, damage);
add_damage (screen, damage);
info->clip_changed = TRUE;
}
#ifdef USE_IDLE_REPAINT
add_repair (display);
#endif
#endif
}

View File

@ -64,5 +64,7 @@ void meta_compositor_free_window (MetaCompositor *compositor,
MetaWindow *window); MetaWindow *window);
Pixmap meta_compositor_get_window_pixmap (MetaCompositor *compositor, Pixmap meta_compositor_get_window_pixmap (MetaCompositor *compositor,
MetaWindow *window); MetaWindow *window);
void meta_compositor_set_active_window (MetaCompositor *compositor,
MetaWindow *window);
#endif /* META_COMPOSITOR_H */ #endif /* META_COMPOSITOR_H */

View File

@ -5203,6 +5203,8 @@ meta_window_notify_focus (MetaWindow *window,
"* Focus --> %s\n", window->desc); "* Focus --> %s\n", window->desc);
window->display->focus_window = window; window->display->focus_window = window;
window->has_focus = TRUE; window->has_focus = TRUE;
meta_compositor_set_active_window (window->display->compositor,
window);
/* Move to the front of the focusing workspace's MRU list. /* Move to the front of the focusing workspace's MRU list.
* We should only be "removing" it from the MRU list if it's * We should only be "removing" it from the MRU list if it's