[gnome-desktop] Fix drawing gradients and always clip to the monitor region
- From: William Jon McCann <mccann src gnome org>
- To: svn-commits-list gnome org
- Cc:
- Subject: [gnome-desktop] Fix drawing gradients and always clip to the monitor region
- Date: Sat, 12 Dec 2009 01:30:33 +0000 (UTC)
commit 5a080e8f12ed6da1b1d1df545d15870742b99c2b
Author: William Jon McCann <jmccann redhat com>
Date: Fri Dec 11 16:23:10 2009 -0500
Fix drawing gradients and always clip to the monitor region
libgnome-desktop/gnome-bg.c | 342 +++++++++++++++++++-------------
libgnome-desktop/libgnomeui/gnome-bg.h | 3 +-
2 files changed, 207 insertions(+), 138 deletions(-)
---
diff --git a/libgnome-desktop/gnome-bg.c b/libgnome-desktop/gnome-bg.c
index f050e70..a539e06 100644
--- a/libgnome-desktop/gnome-bg.c
+++ b/libgnome-desktop/gnome-bg.c
@@ -144,10 +144,11 @@ static GdkPixbuf *pixbuf_scale_to_fit (GdkPixbuf *src,
static GdkPixbuf *pixbuf_scale_to_min (GdkPixbuf *src,
int min_width,
int min_height);
-static void pixbuf_draw_gradient (GdkPixbuf *pixbuf,
- gboolean horizontal,
- GdkColor *c1,
- GdkColor *c2);
+static void pixbuf_draw_gradient (GdkPixbuf *pixbuf,
+ gboolean horizontal,
+ GdkColor *c1,
+ GdkColor *c2,
+ GdkRectangle *rect);
static void pixbuf_tile (GdkPixbuf *src,
GdkPixbuf *dest);
static void pixbuf_blend (GdkPixbuf *src,
@@ -619,13 +620,15 @@ gnome_bg_set_filename (GnomeBG *bg,
}
static void
-draw_color (GnomeBG *bg, GdkPixbuf *dest)
+draw_color_area (GnomeBG *bg,
+ GdkPixbuf *dest,
+ GdkRectangle *rect)
{
guint32 pixel;
- switch (bg->color_type)
- {
+ switch (bg->color_type) {
case GNOME_BG_COLOR_SOLID:
+ /* not really a big deal to ignore the area of interest */
pixel = ((bg->primary.red >> 8) << 24) |
((bg->primary.green >> 8) << 16) |
((bg->primary.blue >> 8) << 8) |
@@ -635,11 +638,11 @@ draw_color (GnomeBG *bg, GdkPixbuf *dest)
break;
case GNOME_BG_COLOR_H_GRADIENT:
- pixbuf_draw_gradient (dest, TRUE, &(bg->primary), &(bg->secondary));
+ pixbuf_draw_gradient (dest, TRUE, &(bg->primary), &(bg->secondary), rect);
break;
case GNOME_BG_COLOR_V_GRADIENT:
- pixbuf_draw_gradient (dest, FALSE, &(bg->primary), &(bg->secondary));
+ pixbuf_draw_gradient (dest, FALSE, &(bg->primary), &(bg->secondary), rect);
break;
default:
@@ -647,14 +650,77 @@ draw_color (GnomeBG *bg, GdkPixbuf *dest)
}
}
+static void
+draw_color (GnomeBG *bg,
+ GdkPixbuf *dest,
+ GdkScreen *screen)
+{
+ GdkRectangle rect;
+ rect.x = 0;
+ rect.y = 0;
+ rect.width = gdk_pixbuf_get_width (dest);
+ rect.height = gdk_pixbuf_get_height (dest);
+ draw_color_area (bg, dest, &rect);
+}
+
+static void
+draw_color_each_monitor (GnomeBG *bg,
+ GdkPixbuf *dest,
+ GdkScreen *screen)
+{
+ GdkRectangle rect;
+ gint num_monitors;
+ int monitor;
+
+ num_monitors = gdk_screen_get_n_monitors (screen);
+ for (monitor = 0; monitor < num_monitors; monitor++) {
+ gdk_screen_get_monitor_geometry (screen, monitor, &rect);
+ draw_color_area (bg, dest, &rect);
+ }
+}
+
+static GdkPixbuf *
+pixbuf_clip_to_fit (GdkPixbuf *src,
+ int max_width,
+ int max_height)
+{
+ int src_width, src_height;
+ int w, h;
+ int src_x, src_y;
+ GdkPixbuf *pixbuf;
+
+ src_width = gdk_pixbuf_get_width (src);
+ src_height = gdk_pixbuf_get_height (src);
+
+ if (src_width < max_width && src_height < max_height)
+ return g_object_ref (src);
+
+ w = MIN(src_width, max_width);
+ h = MIN(src_height, max_height);
+
+ pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
+ gdk_pixbuf_get_has_alpha (src),
+ 8, w, h);
+
+ src_x = (src_width - w) / 2;
+ src_y = (src_height - h) / 2;
+ gdk_pixbuf_copy_area (src,
+ src_x, src_y,
+ w, h,
+ pixbuf,
+ 0, 0);
+ return pixbuf;
+}
+
static GdkPixbuf *
get_scaled_pixbuf (GnomeBGPlacement placement,
GdkPixbuf *pixbuf,
int width, int height,
- int *x, int *y, int *w, int *h)
+ int *x, int *y,
+ int *w, int *h)
{
GdkPixbuf *new;
-
+
#if 0
g_print ("original_width: %d %d\n",
gdk_pixbuf_get_width (pixbuf),
@@ -678,7 +744,7 @@ get_scaled_pixbuf (GnomeBGPlacement placement,
case GNOME_BG_PLACEMENT_CENTERED:
case GNOME_BG_PLACEMENT_TILED:
default:
- new = g_object_ref (pixbuf);
+ new = pixbuf_clip_to_fit (pixbuf, width, height);
break;
}
@@ -703,9 +769,8 @@ draw_image_area (GnomeBGPlacement placement,
if (!pixbuf)
return;
-
- scaled = get_scaled_pixbuf (
- placement, pixbuf, dest_width, dest_height, &x, &y, &w, &h);
+
+ scaled = get_scaled_pixbuf (placement, pixbuf, dest_width, dest_height, &x, &y, &w, &h);
switch (placement) {
case GNOME_BG_PLACEMENT_TILED:
@@ -741,44 +806,57 @@ draw_image (GnomeBGPlacement placement,
}
static void
+draw_once (GnomeBG *bg,
+ GdkPixbuf *dest,
+ GdkScreen *screen)
+{
+ GdkRectangle rect;
+
+ rect.x = 0;
+ rect.y = 0;
+ rect.width = gdk_pixbuf_get_width (dest);
+ rect.height = gdk_pixbuf_get_height (dest);
+
+ draw_image_area (bg->placement,
+ get_pixbuf_for_size (bg, gdk_pixbuf_get_width (dest), gdk_pixbuf_get_height (dest)),
+ dest,
+ &rect);
+}
+
+static void
draw_each_monitor (GnomeBG *bg,
GdkPixbuf *dest,
GdkScreen *screen)
{
GdkRectangle rect;
+ gint num_monitors;
+ int monitor;
- if (bg->placement == GNOME_BG_PLACEMENT_TILED) {
- GdkScreen *screen;
-
- /* don't worry about aligning on every monitor */
- screen = gdk_screen_get_default ();
- gdk_screen_get_monitor_geometry (screen, 0, &rect);
- draw_image (bg->placement,
- get_pixbuf_for_size (bg, rect.width, rect.height),
- dest);
- } else {
- gint num_monitors;
- int monitor;
-
- num_monitors = gdk_screen_get_n_monitors (screen);
- for (monitor = 0; monitor < num_monitors; monitor++) {
- gdk_screen_get_monitor_geometry (screen, monitor, &rect);
- draw_image_area (bg->placement,
- get_pixbuf_for_size (bg, rect.width, rect.height),
- dest, &rect);
- }
+ num_monitors = gdk_screen_get_n_monitors (screen);
+ for (monitor = 0; monitor < num_monitors; monitor++) {
+ gdk_screen_get_monitor_geometry (screen, monitor, &rect);
+ draw_image_area (bg->placement,
+ get_pixbuf_for_size (bg, rect.width, rect.height),
+ dest, &rect);
}
}
void
-gnome_bg_draw (GnomeBG *bg, GdkPixbuf *dest, GdkScreen *screen)
+gnome_bg_draw (GnomeBG *bg,
+ GdkPixbuf *dest,
+ GdkScreen *screen,
+ gboolean is_root)
{
if (!bg)
return;
-
- draw_color (bg, dest);
-
- draw_each_monitor (bg, dest, screen);
+
+ if (is_root) {
+ draw_color_each_monitor (bg, dest, screen);
+ draw_each_monitor (bg, dest, screen);
+ } else {
+ draw_color (bg, dest, screen);
+ draw_once (bg, dest, screen);
+ }
}
gboolean
@@ -803,7 +881,6 @@ gnome_bg_get_pixmap_size (GnomeBG *bg,
int *pixmap_height)
{
int dummy;
- int pb_width, pb_height;
if (!pixmap_width)
pixmap_width = &dummy;
@@ -821,46 +898,12 @@ gnome_bg_get_pixmap_size (GnomeBG *bg,
break;
case GNOME_BG_COLOR_H_GRADIENT:
- *pixmap_width = width;
- *pixmap_height = GRADIENT_PIXMAP_TILE_SIZE;
- break;
-
case GNOME_BG_COLOR_V_GRADIENT:
- *pixmap_width = GRADIENT_PIXMAP_TILE_SIZE;
- *pixmap_height = height;
break;
}
return;
}
-
- if (bg->placement == GNOME_BG_PLACEMENT_TILED) {
- GdkPixbuf *pixbuf;
- pixbuf = get_pixbuf_for_size (bg, width, height);
- pb_width = gdk_pixbuf_get_width (pixbuf);
- pb_height = gdk_pixbuf_get_height (pixbuf);
-
- if (gdk_pixbuf_get_has_alpha (pixbuf) &&
- bg->color_type != GNOME_BG_COLOR_SOLID) {
- if (bg->color_type == GNOME_BG_COLOR_H_GRADIENT) {
- /* FIXME: Should this be
- * MAX (GRADIENT_TILE_SIZE, pb_height)?
- */
- *pixmap_height = pb_height;
- *pixmap_width = width;
- }
- else {
- /* FIXME: Should this be
- * MAX (GRAIDENT_TILE_SIZE, pb_width? */
- *pixmap_width = pb_width;
- *pixmap_height = height;
- }
- }
- else {
- *pixmap_width = pb_width;
- *pixmap_height = pb_height;
- }
- }
}
/**
@@ -882,7 +925,7 @@ gnome_bg_create_pixmap (GnomeBG *bg,
GdkWindow *window,
int width,
int height,
- gboolean root)
+ gboolean is_root)
{
int pm_width, pm_height;
GdkPixmap *pixmap;
@@ -903,7 +946,7 @@ gnome_bg_create_pixmap (GnomeBG *bg,
/* has the side effect of loading and caching pixbuf only when in tile mode */
gnome_bg_get_pixmap_size (bg, width, height, &pm_width, &pm_height);
- if (root) {
+ if (is_root) {
pixmap = make_root_pixmap (gdk_drawable_get_screen (window),
pm_width, pm_height);
}
@@ -924,7 +967,7 @@ gnome_bg_create_pixmap (GnomeBG *bg,
pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8,
width, height);
- gnome_bg_draw (bg, pixbuf, gdk_drawable_get_screen (GDK_DRAWABLE (window)));
+ gnome_bg_draw (bg, pixbuf, gdk_drawable_get_screen (GDK_DRAWABLE (window)), is_root);
gdk_draw_pixbuf (pixmap, NULL, pixbuf,
0, 0,
0, 0, width, height,
@@ -1121,7 +1164,7 @@ gnome_bg_create_thumbnail (GnomeBG *bg,
result = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, dest_width, dest_height);
- draw_color (bg, result);
+ draw_color (bg, result, screen);
thumb = create_img_thumbnail (bg, factory, screen, dest_width, dest_height, -1);
@@ -1820,9 +1863,8 @@ create_img_thumbnail (GnomeBG *bg,
GdkPixbuf *thumb = get_as_thumbnail (bg, factory, bg->filename);
if (thumb) {
- return scale_thumbnail (
- bg->placement, bg->filename,
- thumb, screen, dest_width, dest_height);
+ return scale_thumbnail (bg->placement, bg->filename,
+ thumb, screen, dest_width, dest_height);
}
else {
SlideShow *show = get_as_slideshow (bg, bg->filename);
@@ -1844,8 +1886,7 @@ create_img_thumbnail (GnomeBG *bg,
fs = find_best_size (slide->file1, dest_width, dest_height);
tmp = get_as_thumbnail (bg, factory, fs->file);
if (tmp)
- thumb = scale_thumbnail (
- bg->placement, fs->file,
+ thumb = scale_thumbnail (bg->placement, fs->file,
tmp, screen, dest_width, dest_height);
}
else {
@@ -1860,13 +1901,11 @@ create_img_thumbnail (GnomeBG *bg,
if (p1 && p2) {
GdkPixbuf *thumb1, *thumb2;
- thumb1 = scale_thumbnail (
- bg->placement, fs1->file,
- p1, screen, dest_width, dest_height);
+ thumb1 = scale_thumbnail (bg->placement, fs1->file,
+ p1, screen, dest_width, dest_height);
- thumb2 = scale_thumbnail (
- bg->placement, fs2->file,
- p2, screen, dest_width, dest_height);
+ thumb2 = scale_thumbnail (bg->placement, fs2->file,
+ p2, screen, dest_width, dest_height);
thumb = blend (thumb1, thumb2, alpha);
@@ -2145,22 +2184,38 @@ pixbuf_scale_to_min (GdkPixbuf *src, int min_width, int min_height)
double factor;
int src_width, src_height;
int new_width, new_height;
-
+ GdkPixbuf *dest;
+
src_width = gdk_pixbuf_get_width (src);
src_height = gdk_pixbuf_get_height (src);
-
+
factor = MAX (min_width / (double) src_width, min_height / (double) src_height);
-
+
new_width = floor (src_width * factor + 0.5);
new_height = floor (src_height * factor + 0.5);
-
- return gdk_pixbuf_scale_simple (src, new_width, new_height, GDK_INTERP_BILINEAR);
+
+ dest = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
+ gdk_pixbuf_get_has_alpha (src),
+ 8, min_width, min_height);
+ if (!dest)
+ return NULL;
+
+ /* crop the result */
+ gdk_pixbuf_scale (src, dest,
+ 0, 0,
+ min_width, min_height,
+ (new_width - min_width) / -2,
+ (new_height - min_height) / -2,
+ factor,
+ factor,
+ GDK_INTERP_BILINEAR);
+ return dest;
}
static guchar *
create_gradient (const GdkColor *primary,
const GdkColor *secondary,
- int n_pixels)
+ int n_pixels)
{
guchar *result = g_malloc (n_pixels * 3);
int i;
@@ -2177,43 +2232,56 @@ create_gradient (const GdkColor *primary,
}
static void
-pixbuf_draw_gradient (GdkPixbuf *pixbuf,
- gboolean horizontal,
- GdkColor *primary,
- GdkColor *secondary)
-{
- int width = gdk_pixbuf_get_width (pixbuf);
- int height = gdk_pixbuf_get_height (pixbuf);
- int rowstride = gdk_pixbuf_get_rowstride (pixbuf);
- guchar *dst = gdk_pixbuf_get_pixels (pixbuf);
- guchar *dst_limit = dst + height * rowstride;
-
+pixbuf_draw_gradient (GdkPixbuf *pixbuf,
+ gboolean horizontal,
+ GdkColor *primary,
+ GdkColor *secondary,
+ GdkRectangle *rect)
+{
+ int width;
+ int height;
+ int rowstride;
+ guchar *dst;
+ guchar *dst_limit;
+ int n_channels = 3;
+
+ rowstride = gdk_pixbuf_get_rowstride (pixbuf);
+ width = rect->width;
+ height = rect->height;
+ dst = gdk_pixbuf_get_pixels (pixbuf) + rect->x * n_channels + rowstride * rect->y;
+ dst_limit = dst + height * rowstride;
+
if (horizontal) {
guchar *gradient = create_gradient (primary, secondary, width);
- int copy_bytes_per_row = width * 3;
-
- while (dst < dst_limit) {
- memcpy (dst, gradient, copy_bytes_per_row);
- dst += rowstride;
+ int copy_bytes_per_row = width * n_channels;
+ int i;
+
+ for (i = 0; i < height; i++) {
+ guchar *d;
+ d = dst + rowstride * i;
+ memcpy (d, gradient, copy_bytes_per_row);
}
g_free (gradient);
} else {
guchar *gb, *gradient;
-
- gb = gradient = create_gradient (primary, secondary, height);
- while (dst < dst_limit) {
- int i;
- guchar *d = dst;
- guchar r = *gb++;
- guchar g = *gb++;
- guchar b = *gb++;
- for (i = 0; i < width; i++) {
- *d++ = r;
- *d++ = g;
- *d++ = b;
+ int i;
+
+ gradient = create_gradient (primary, secondary, height);
+ for (i = 0; i < height; i++) {
+ int j;
+ guchar *d;
+
+ d = dst + rowstride * i;
+ gb = gradient + n_channels * i;
+ for (j = width; j > 0; j--) {
+ int k;
+
+ for (k = 0; k < n_channels; k++) {
+ *(d++) = gb[k];
+ }
}
- dst += rowstride;
}
+
g_free (gradient);
}
}
@@ -2223,8 +2291,8 @@ pixbuf_blend (GdkPixbuf *src,
GdkPixbuf *dest,
int src_x,
int src_y,
- int width,
- int height,
+ int src_width,
+ int src_height,
int dest_x,
int dest_y,
double alpha)
@@ -2234,11 +2302,11 @@ pixbuf_blend (GdkPixbuf *src,
int offset_x = dest_x - src_x;
int offset_y = dest_y - src_y;
- if (width < 0)
- width = gdk_pixbuf_get_width (src);
+ if (src_width < 0)
+ src_width = gdk_pixbuf_get_width (src);
- if (height < 0)
- height = gdk_pixbuf_get_height (src);
+ if (src_height < 0)
+ src_height = gdk_pixbuf_get_height (src);
if (dest_x < 0)
dest_x = 0;
@@ -2246,17 +2314,17 @@ pixbuf_blend (GdkPixbuf *src,
if (dest_y < 0)
dest_y = 0;
- if (dest_x + width > dest_width) {
- width = dest_width - dest_x;
+ if (dest_x + src_width > dest_width) {
+ src_width = dest_width - dest_x;
}
- if (dest_y + height > dest_height) {
- height = dest_height - dest_y;
+ if (dest_y + src_height > dest_height) {
+ src_height = dest_height - dest_y;
}
gdk_pixbuf_composite (src, dest,
dest_x, dest_y,
- width, height,
+ src_width, src_height,
offset_x, offset_y,
1, 1, GDK_INTERP_NEAREST,
alpha * 0xFF + 0.5);
@@ -2773,7 +2841,7 @@ gnome_bg_create_frame_thumbnail (GnomeBG *bg,
result = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, dest_width, dest_height);
- draw_color (bg, result);
+ draw_color (bg, result, screen);
thumb = create_img_thumbnail (bg, factory, screen, dest_width, dest_height, frame_num + skipped);
diff --git a/libgnome-desktop/libgnomeui/gnome-bg.h b/libgnome-desktop/libgnomeui/gnome-bg.h
index ddf9e5c..6ab2cb0 100644
--- a/libgnome-desktop/libgnomeui/gnome-bg.h
+++ b/libgnome-desktop/libgnomeui/gnome-bg.h
@@ -88,7 +88,8 @@ const gchar * gnome_bg_get_filename (GnomeBG *bg);
/* Drawing and thumbnailing */
void gnome_bg_draw (GnomeBG *bg,
GdkPixbuf *dest,
- GdkScreen *screen);
+ GdkScreen *screen,
+ gboolean is_root);
GdkPixmap * gnome_bg_create_pixmap (GnomeBG *bg,
GdkWindow *window,
int width,
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]