gnome-control-center/libbackground/applier.c
jacob berkman 50b3bfe107 use a gc for the pixmap not the root window
2002-05-21  jacob berkman  <jacob@ximian.com>

	* applier.c (render_to_screen): use a gc for the pixmap not the
	root window
	(bg_applier_get_preview_widget): don't create the pixmap until we
	are realized
	(make_root_pixmap): use gdk_get_display(), not getenv ("DISPLAY"),
	and set the colormap for our GdkPixmap so we can draw on it
	(preview_realized_cb): create the pixmap here, and set it on our
	GtkImage

	fixes #73496
2002-05-21 22:13:38 +00:00

1548 lines
44 KiB
C

/* -*- mode: c; style: linux -*- */
/* applier.c
* Copyright (C) 2001 Ximian, Inc.
*
* Written by Bradford Hovinen <hovinen@ximian.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <string.h>
#include <gnome.h>
#include <gdk/gdk.h>
#include <gdk/gdkx.h>
#include <gdk/gdkprivate.h>
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <unistd.h>
#include <bonobo.h>
#include "applier.h"
#define MONITOR_CONTENTS_X 0
#define MONITOR_CONTENTS_Y 0
#define MONITOR_CONTENTS_DEFAULT_WIDTH 64
#define MONITOR_CONTENTS_DEFAULT_HEIGHT 48
enum {
PROP_0,
PROP_TYPE,
PROP_PREVIEW_WIDTH,
PROP_PREVIEW_HEIGHT
};
struct _BGApplierPrivate
{
GtkWidget *preview_widget; /* The widget for previewing
* -- this is not used for
* actual rendering; it is
* returned if requested */
BGPreferences *last_prefs; /* A cache of the last
* bg_preferences structure to
* be applied */
GdkPixbuf *wallpaper_pixbuf; /* The "raw" wallpaper pixbuf */
BGApplierType type; /* Whether we render to the
* root or the preview */
/* Where on the pixmap we should render the background image. Should
* have origin 0,0 and width and height equal to the desktop size if we
* are rendering to the desktop. The area to which we render the pixbuf
* will be smaller if we are rendering a centered image smaller than the
* screen or scaling and keeping aspect ratio and the background color
* is solid. */
GdkRectangle render_geom;
/* Where to render the pixbuf, relative to the pixmap. This will be the
* same as render_geom above if we have no solid color area to worry
* about. By convention, a negative value means that the pixbuf is
* larger than the pixmap, so the region should be fetched from a subset
* of the pixbuf. */
GdkRectangle pixbuf_render_geom;
/* Where to fetch the data from the pixbuf. We use this in case we are
* rendering a centered image that is larger than the size of the
* desktop. Otherwise it is (0,0) */
GdkPoint pixbuf_xlate;
/* Geometry of the pixbuf used to render the gradient. If the wallpaper
* is not enabled, we use the following optimization: On one dimension,
* this should be equal to the dimension of render_geom, while on the
* other dimension it should be the constant 32. This avoids wasting
* memory with rendundant data. */
GdkPoint grad_geom;
GdkPixbuf *pixbuf; /* "working" pixbuf - All data
* are rendered onto this for
* display */
GdkPixmap *pixmap; /* Pixmap onto which we dump the
* pixbuf above when we are ready
* to render to the screen */
gboolean pixmap_is_set; /* TRUE iff the pixmap above
* has been set as the root
* pixmap */
guint timeout; /* "Cleanup" timeout handler;
* reset to 30 seconds every
* time apply is called. */
};
static GObjectClass *parent_class;
static void bg_applier_init (BGApplier *prefs,
BGApplierClass *class);
static void bg_applier_class_init (BGApplierClass *class);
static void bg_applier_base_init (BGApplierClass *class);
static void bg_applier_set_prop (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec);
static void bg_applier_get_prop (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec);
static void bg_applier_dispose (GObject *object);
static void bg_applier_finalize (GObject *object);
static void run_render_pipeline (BGApplier *bg_applier,
const BGPreferences *prefs);
static void draw_disabled_message (GtkWidget *widget,
const guint width,
const guint height);
static void render_background (BGApplier *bg_applier,
const BGPreferences *prefs);
static void render_wallpaper (BGApplier *bg_applier,
const BGPreferences *prefs);
static void render_to_screen (BGApplier *bg_applier,
const BGPreferences *prefs);
static void create_pixmap (BGApplier *bg_applier,
const BGPreferences *prefs);
static void get_geometry (wallpaper_type_t wallpaper_type,
GdkPixbuf *pixbuf,
GdkRectangle *field_geom,
GdkRectangle *virtual_geom,
GdkRectangle *dest_geom,
GdkRectangle *src_geom);
static GdkPixbuf *place_pixbuf (GdkPixbuf *dest_pixbuf,
GdkPixbuf *src_pixbuf,
GdkRectangle *dest_geom,
GdkRectangle *src_geom,
guint alpha,
GdkColor *bg_color);
static GdkPixbuf *tile_pixbuf (GdkPixbuf *dest_pixbuf,
GdkPixbuf *src_pixbuf,
GdkRectangle *field_geom,
guint alpha,
GdkColor *bg_color);
static void fill_gradient (GdkPixbuf *pixbuf,
GdkColor *c1,
GdkColor *c2,
orientation_t orientation);
static gboolean need_wallpaper_load_p (const BGApplier *bg_applier,
const BGPreferences *prefs);
static gboolean need_root_pixmap_p (const BGApplier *bg_applier,
const BGPreferences *prefs);
static gboolean wallpaper_full_cover_p (const BGApplier *bg_applier,
const BGPreferences *prefs);
static gboolean render_small_pixmap_p (const BGPreferences *prefs);
static GdkPixmap *make_root_pixmap (gint width,
gint height);
static void set_root_pixmap (GdkPixmap *pixmap);
static gboolean is_nautilus_running (void);
static gboolean cleanup_cb (BGApplier *bg_applier);
static void preview_realized_cb (GtkWidget *preview,
BGApplier *bg_applier);
GType
bg_applier_get_type (void)
{
static GType bg_applier_type = 0;
if (!bg_applier_type) {
static GTypeInfo bg_applier_info = {
sizeof (BGApplierClass),
(GBaseInitFunc) bg_applier_base_init,
NULL, /* GBaseFinalizeFunc */
(GClassInitFunc) bg_applier_class_init,
NULL, /* GClassFinalizeFunc */
NULL, /* user-supplied data */
sizeof (BGApplier),
0, /* n_preallocs */
(GInstanceInitFunc) bg_applier_init,
NULL
};
bg_applier_type =
g_type_register_static (G_TYPE_OBJECT,
"BGApplier",
&bg_applier_info, 0);
}
return bg_applier_type;
}
static void
bg_applier_init (BGApplier *bg_applier, BGApplierClass *class)
{
bg_applier->p = g_new0 (BGApplierPrivate, 1);
bg_applier->p->last_prefs = NULL;
bg_applier->p->pixbuf = NULL;
bg_applier->p->wallpaper_pixbuf = NULL;
bg_applier->p->timeout = 0;
bg_applier->p->render_geom.width = -1;
bg_applier->p->render_geom.height = -1;
}
static void
bg_applier_class_init (BGApplierClass *class)
{
GObjectClass *object_class;
object_class = G_OBJECT_CLASS (class);
object_class->dispose = bg_applier_dispose;
object_class->finalize = bg_applier_finalize;
object_class->set_property = bg_applier_set_prop;
object_class->get_property = bg_applier_get_prop;
g_object_class_install_property
(object_class, PROP_TYPE,
g_param_spec_int ("type",
_("Type"),
_("Type of bg_applier: BG_APPLIER_ROOT for root window or BG_APPLIER_PREVIEW for preview"),
0, 1, 0,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
g_object_class_install_property
(object_class, PROP_PREVIEW_WIDTH,
g_param_spec_uint ("preview_width",
_("Preview Width"),
_("Width if applier is a preview: Defaults to 64."),
1, 65535, MONITOR_CONTENTS_DEFAULT_WIDTH,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
g_object_class_install_property
(object_class, PROP_PREVIEW_HEIGHT,
g_param_spec_uint ("preview_height",
_("Preview Height"),
_("Height if applier is a preview: Defaults to 48."),
1, 65535, MONITOR_CONTENTS_DEFAULT_HEIGHT,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
parent_class =
G_OBJECT_CLASS (g_type_class_ref (G_TYPE_OBJECT));
}
static void
bg_applier_base_init (BGApplierClass *class)
{
}
static void
bg_applier_set_prop (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
{
BGApplier *bg_applier;
g_return_if_fail (object != NULL);
g_return_if_fail (IS_BG_APPLIER (object));
bg_applier = BG_APPLIER (object);
switch (prop_id) {
case PROP_TYPE:
bg_applier->p->type = g_value_get_int (value);
switch (bg_applier->p->type) {
case BG_APPLIER_ROOT:
bg_applier->p->render_geom.x = 0;
bg_applier->p->render_geom.y = 0;
bg_applier->p->render_geom.width = gdk_screen_width ();
bg_applier->p->render_geom.height = gdk_screen_height ();
bg_applier->p->pixmap = NULL;
bg_applier->p->pixmap_is_set = FALSE;
break;
case BG_APPLIER_PREVIEW:
bg_applier->p->render_geom.x = MONITOR_CONTENTS_X;
bg_applier->p->render_geom.y = MONITOR_CONTENTS_Y;
if (bg_applier->p->render_geom.width == -1)
{
bg_applier->p->render_geom.width = MONITOR_CONTENTS_DEFAULT_WIDTH;
bg_applier->p->render_geom.height = MONITOR_CONTENTS_DEFAULT_HEIGHT;
}
break;
default:
g_critical ("Bad bg_applier type: %d", bg_applier->p->type);
break;
}
break;
case PROP_PREVIEW_WIDTH:
if (bg_applier->p->type == BG_APPLIER_PREVIEW)
bg_applier->p->render_geom.width = g_value_get_uint (value);
break;
case PROP_PREVIEW_HEIGHT:
if (bg_applier->p->type == BG_APPLIER_PREVIEW)
bg_applier->p->render_geom.height = g_value_get_uint (value);
break;
default:
g_warning ("Bad property set");
break;
}
}
static void
bg_applier_get_prop (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
{
BGApplier *bg_applier;
g_return_if_fail (object != NULL);
g_return_if_fail (IS_BG_APPLIER (object));
bg_applier = BG_APPLIER (object);
switch (prop_id) {
case PROP_TYPE:
g_value_set_int (value, bg_applier->p->type);
break;
default:
g_warning ("Bad property get");
break;
}
}
static void
bg_applier_dispose (GObject *object)
{
BGApplier *bg_applier;
g_return_if_fail (object != NULL);
g_return_if_fail (IS_BG_APPLIER (object));
bg_applier = BG_APPLIER (object);
g_assert (bg_applier->p->pixbuf == NULL);
if (bg_applier->p->last_prefs != NULL)
g_object_unref (G_OBJECT (bg_applier->p->last_prefs));
if (bg_applier->p->wallpaper_pixbuf != NULL)
g_object_unref (G_OBJECT (bg_applier->p->wallpaper_pixbuf));
parent_class->dispose (object);
}
static void
bg_applier_finalize (GObject *object)
{
BGApplier *bg_applier;
g_return_if_fail (object != NULL);
g_return_if_fail (IS_BG_APPLIER (object));
bg_applier = BG_APPLIER (object);
g_free (bg_applier->p);
parent_class->finalize (object);
}
GObject *
bg_applier_new (BGApplierType type)
{
GObject *object;
object = g_object_new (bg_applier_get_type (),
"type", type,
NULL);
return object;
}
GObject *
bg_applier_new_at_size (BGApplierType type,
const guint width,
const guint height)
{
GObject *object;
object = g_object_new (bg_applier_get_type (),
"type", type,
"preview_width", width,
"preview_height", height,
NULL);
return object;
}
void
bg_applier_apply_prefs (BGApplier *bg_applier,
const BGPreferences *prefs)
{
BGPreferences *new_prefs;
g_return_if_fail (bg_applier != NULL);
g_return_if_fail (IS_BG_APPLIER (bg_applier));
new_prefs = BG_PREFERENCES (bg_preferences_clone (prefs));
if (new_prefs->wallpaper_type == WPTYPE_NONE)
{
new_prefs->wallpaper_enabled = FALSE;
new_prefs->wallpaper_type = WPTYPE_CENTERED;
}
if (bg_applier->p->type == BG_APPLIER_ROOT && is_nautilus_running ()) {
set_root_pixmap ((GdkPixmap *) -1);
return;
}
if (!new_prefs->enabled) {
if (bg_applier->p->type == BG_APPLIER_PREVIEW)
draw_disabled_message (bg_applier_get_preview_widget (bg_applier), bg_applier->p->render_geom.width, bg_applier->p->render_geom.height);
return;
}
if (need_wallpaper_load_p (bg_applier, new_prefs)) {
if (bg_applier->p->wallpaper_pixbuf != NULL)
g_object_unref (G_OBJECT (bg_applier->p->wallpaper_pixbuf));
bg_applier->p->wallpaper_pixbuf = NULL;
if (new_prefs->wallpaper_enabled) {
g_return_if_fail (new_prefs->wallpaper_filename != NULL);
bg_applier->p->wallpaper_pixbuf =
gdk_pixbuf_new_from_file (new_prefs->wallpaper_filename, NULL);
if (bg_applier->p->wallpaper_pixbuf == NULL) {
new_prefs->wallpaper_enabled = FALSE;
}
else if (bg_applier->p->type == BG_APPLIER_ROOT) {
if (bg_applier->p->timeout)
g_source_remove (bg_applier->p->timeout);
bg_applier->p->timeout = g_timeout_add (30000, (GSourceFunc) cleanup_cb, bg_applier);
}
}
}
if (bg_applier->p->type == BG_APPLIER_ROOT)
nice (20);
run_render_pipeline (bg_applier, new_prefs);
if (bg_applier->p->last_prefs != NULL)
g_object_unref (G_OBJECT (bg_applier->p->last_prefs));
bg_applier->p->last_prefs = new_prefs;
if (bg_applier->p->type == BG_APPLIER_PREVIEW && bg_applier->p->preview_widget != NULL)
gtk_widget_queue_draw (bg_applier->p->preview_widget);
}
gboolean
bg_applier_render_color_p (const BGApplier *bg_applier, const BGPreferences *prefs)
{
g_return_val_if_fail (bg_applier != NULL, FALSE);
g_return_val_if_fail (IS_BG_APPLIER (bg_applier), FALSE);
g_return_val_if_fail (prefs != NULL, FALSE);
g_return_val_if_fail (IS_BG_PREFERENCES (prefs), FALSE);
return prefs->enabled && !wallpaper_full_cover_p (bg_applier, prefs);
}
GtkWidget *
bg_applier_get_preview_widget (BGApplier *bg_applier)
{
if (bg_applier->p->preview_widget == NULL)
{
bg_applier->p->preview_widget = gtk_image_new ();
/* We need to initialize the pixmap, but this
* needs GCs, so we have to wait until realize. */
g_signal_connect (G_OBJECT (bg_applier->p->preview_widget),
"realize",
(GCallback) preview_realized_cb,
bg_applier);
}
return bg_applier->p->preview_widget;
}
GdkPixbuf *
bg_applier_get_wallpaper_pixbuf (BGApplier *bg_applier)
{
g_return_val_if_fail (bg_applier != NULL, NULL);
g_return_val_if_fail (IS_BG_APPLIER (bg_applier), NULL);
return bg_applier->p->wallpaper_pixbuf;
}
static void
draw_disabled_message (GtkWidget *widget, const guint w, const guint h)
{
GdkPixmap *pixmap;
GdkColor color;
PangoLayout *layout;
PangoRectangle extents;
GdkGC *gc;
gint x, y;
const char *disabled_string = _("Disabled");
g_return_if_fail (widget != NULL);
g_return_if_fail (GTK_IS_IMAGE (widget));
x = MONITOR_CONTENTS_X;
y = MONITOR_CONTENTS_Y;
if (!GTK_WIDGET_REALIZED (widget)) {
gtk_widget_realize (widget);
}
gtk_image_get_pixmap (GTK_IMAGE (widget), &pixmap, NULL);
gc = gdk_gc_new (widget->window);
color.red = 0x0;
color.green = 0x0;
color.blue = 0x0;
gdk_gc_set_rgb_fg_color (gc, &color);
gdk_draw_rectangle (pixmap, gc, TRUE, x, y, w, h);
layout = gtk_widget_create_pango_layout (widget, disabled_string);
pango_layout_get_pixel_extents (layout, &extents, NULL);
color.red = 0xffff;
color.green = 0xffff;
color.blue = 0xffff;
gdk_gc_set_rgb_fg_color (gc, &color);
/* fixme: I do not understand the logic (Lauris) */
gdk_draw_layout (widget->window,
gc,
x + (w - extents.width) / 2,
y + (h - extents.height) / 2 + extents.height / 2,
layout);
g_object_unref (G_OBJECT (gc));
g_object_unref (G_OBJECT (layout));
}
static void
run_render_pipeline (BGApplier *bg_applier, const BGPreferences *prefs)
{
g_return_if_fail (bg_applier != NULL);
g_return_if_fail (IS_BG_APPLIER (bg_applier));
g_return_if_fail (prefs != NULL);
g_return_if_fail (IS_BG_PREFERENCES (prefs));
g_assert (bg_applier->p->pixbuf == NULL);
/* Initialize bg_applier->p->render_geom */
bg_applier->p->pixbuf_render_geom.x = bg_applier->p->render_geom.x;
bg_applier->p->pixbuf_render_geom.y = bg_applier->p->render_geom.y;
bg_applier->p->pixbuf_render_geom.width = bg_applier->p->render_geom.width;
bg_applier->p->pixbuf_render_geom.height = bg_applier->p->render_geom.height;
bg_applier->p->pixbuf_xlate.x = 0;
bg_applier->p->pixbuf_xlate.y = 0;
render_background (bg_applier, prefs);
if (need_root_pixmap_p (bg_applier, prefs))
create_pixmap (bg_applier, prefs);
render_wallpaper (bg_applier, prefs);
render_to_screen (bg_applier, prefs);
if (bg_applier->p->pixbuf != NULL) {
g_object_unref (G_OBJECT (bg_applier->p->pixbuf));
bg_applier->p->pixbuf = NULL;
}
}
/* Create the gradient image if necessary and put it into a fresh pixbuf
*
* Preconditions:
* 1. prefs is valid
* 2. The old bg_applier->p->pixbuf, if it existed, has been destroyed
*
* Postconditions (assuming gradient is enabled):
* 1. bg_applier->p->pixbuf contains a newly rendered gradient
*/
static void
render_background (BGApplier *bg_applier, const BGPreferences *prefs)
{
g_return_if_fail (bg_applier != NULL);
g_return_if_fail (IS_BG_APPLIER (bg_applier));
g_return_if_fail (prefs != NULL);
g_return_if_fail (IS_BG_PREFERENCES (prefs));
if (prefs->gradient_enabled && !wallpaper_full_cover_p (bg_applier, prefs)) {
bg_applier->p->grad_geom.x = bg_applier->p->render_geom.width;
bg_applier->p->grad_geom.y = bg_applier->p->render_geom.height;
if (bg_applier->p->type == BG_APPLIER_ROOT && !prefs->wallpaper_enabled) {
if (prefs->orientation == ORIENTATION_HORIZ)
bg_applier->p->grad_geom.y = 32;
else
bg_applier->p->grad_geom.x = 32;
}
bg_applier->p->pixbuf =
gdk_pixbuf_new (GDK_COLORSPACE_RGB,
FALSE, 8,
bg_applier->p->grad_geom.x,
bg_applier->p->grad_geom.y);
fill_gradient (bg_applier->p->pixbuf,
prefs->color1, prefs->color2,
prefs->orientation);
bg_applier->p->pixbuf_render_geom.width = bg_applier->p->grad_geom.x;
bg_applier->p->pixbuf_render_geom.height = bg_applier->p->grad_geom.y;
}
}
/* Render the wallpaper onto the pixbuf-in-progress.
*
* Preconditions:
* 1. The wallpaper pixbuf has been loaded and is in
* bg_applier->p->wallpaper_pixbuf.
* 2. The structure bg_applier->p->render_geom is filled out properly as
* described in the documentation above (this should be invariant).
* 3. The various fields in prefs are valid
*
* Postconditions (assuming wallpaper is enabled):
* 1. bg_applier->p->pixbuf contains the pixbuf-in-progress with the wallpaper
* correctly rendered.
* 2. bg_applier->p->pixbuf_render_geom has been modified, if necessary,
* according to the requirements of the wallpaper; it should be set by
* default to be the same as bg_applier->p->render_geom.
*/
static void
render_wallpaper (BGApplier *bg_applier, const BGPreferences *prefs)
{
GdkRectangle src_geom;
GdkRectangle dest_geom;
GdkRectangle virtual_geom;
GdkPixbuf *prescaled_pixbuf = NULL;
guint alpha;
gint tmp1, tmp2;
gint pwidth, pheight;
g_return_if_fail (bg_applier != NULL);
g_return_if_fail (IS_BG_APPLIER (bg_applier));
g_return_if_fail (prefs != NULL);
g_return_if_fail (IS_BG_PREFERENCES (prefs));
if (prefs->wallpaper_enabled) {
if (bg_applier->p->wallpaper_pixbuf == NULL)
return;
gdk_drawable_get_size (gdk_get_default_root_window (), &tmp1, &tmp2);
virtual_geom.x = virtual_geom.y = 0;
virtual_geom.width = tmp1;
virtual_geom.height = tmp2;
pwidth = gdk_pixbuf_get_width (bg_applier->p->wallpaper_pixbuf);
pheight = gdk_pixbuf_get_height (bg_applier->p->wallpaper_pixbuf);
get_geometry (prefs->wallpaper_type,
bg_applier->p->wallpaper_pixbuf,
&(bg_applier->p->render_geom),
&virtual_geom, &dest_geom, &src_geom);
/* Modify bg_applier->p->pixbuf_render_geom if necessary */
if (bg_applier->p->pixbuf == NULL) { /* This means we didn't render a gradient */
bg_applier->p->pixbuf_render_geom.x = dest_geom.x + bg_applier->p->render_geom.x;
bg_applier->p->pixbuf_render_geom.y = dest_geom.y + bg_applier->p->render_geom.y;
bg_applier->p->pixbuf_render_geom.width = dest_geom.width;
bg_applier->p->pixbuf_render_geom.height = dest_geom.height;
}
if (prefs->wallpaper_type == WPTYPE_TILED) {
if (dest_geom.width != pwidth || dest_geom.height != pheight) {
prescaled_pixbuf = gdk_pixbuf_scale_simple
(bg_applier->p->wallpaper_pixbuf,
pwidth * bg_applier->p->render_geom.width / virtual_geom.width,
pheight * bg_applier->p->render_geom.height / virtual_geom.height,
GDK_INTERP_BILINEAR);
} else {
prescaled_pixbuf = bg_applier->p->wallpaper_pixbuf;
g_object_ref (G_OBJECT (prescaled_pixbuf));
}
}
if (prefs->adjust_opacity) {
alpha = 2.56 * prefs->opacity;
alpha = alpha * alpha / 256;
alpha = CLAMP (alpha, 0, 255);
} else {
alpha = 255;
}
if (prefs->wallpaper_type == WPTYPE_TILED)
bg_applier->p->pixbuf = tile_pixbuf (bg_applier->p->pixbuf,
prescaled_pixbuf,
&(bg_applier->p->render_geom),
alpha, prefs->color1);
else
bg_applier->p->pixbuf = place_pixbuf (bg_applier->p->pixbuf,
bg_applier->p->wallpaper_pixbuf,
&dest_geom, &src_geom,
alpha, prefs->color1);
if (bg_applier->p->pixbuf == bg_applier->p->wallpaper_pixbuf) {
bg_applier->p->pixbuf_xlate.x = src_geom.x;
bg_applier->p->pixbuf_xlate.y = src_geom.y;
}
if (prescaled_pixbuf != NULL)
g_object_unref (G_OBJECT (prescaled_pixbuf));
}
}
/* Take whatever we have rendered and transfer it to the display.
*
* Preconditions:
* 1. We have already rendered the gradient and wallpaper, and
* bg_applier->p->pixbuf is a valid GdkPixbuf containing that rendered data.
* 2. The structure bg_applier->p->pixbuf_render_geom contains the coordonites on
* the destination visual to which we should render the contents of
* bg_applier->p->pixbuf
* 3. The structure bg_applier->p->render_geom contains the total area that the
* background should cover (i.e. the whole desktop if we are rendering to
* the root window, or the region inside the monitor if we are rendering to
* the preview).
* 4. The strucutre prefs->color1 contains the background color to be used on
* areas not covered by the above pixbuf.
*/
static void
render_to_screen (BGApplier *bg_applier, const BGPreferences *prefs)
{
GdkGC *gc;
g_return_if_fail (bg_applier != NULL);
g_return_if_fail (IS_BG_APPLIER (bg_applier));
g_return_if_fail (prefs != NULL);
g_return_if_fail (IS_BG_PREFERENCES (prefs));
gc = gdk_gc_new (bg_applier->p->pixmap);
if (bg_applier->p->pixbuf != NULL) {
if (bg_applier->p->pixbuf_render_geom.x != 0 ||
bg_applier->p->pixbuf_render_geom.y != 0 ||
bg_applier->p->pixbuf_render_geom.width != bg_applier->p->render_geom.width ||
bg_applier->p->pixbuf_render_geom.height != bg_applier->p->render_geom.height)
{
gboolean success;
#if 0
gdk_color_alloc (gdk_window_get_colormap (gdk_get_default_root_window ()), prefs->color1);
#else
gdk_colormap_alloc_colors (gdk_drawable_get_colormap (gdk_get_default_root_window ()),
prefs->color1, 1, FALSE, TRUE, &success);
#endif
gdk_gc_set_foreground (gc, prefs->color1);
gdk_draw_rectangle (bg_applier->p->pixmap, gc, TRUE,
bg_applier->p->render_geom.x,
bg_applier->p->render_geom.y,
bg_applier->p->render_geom.width,
bg_applier->p->render_geom.height);
}
gdk_pixbuf_render_to_drawable
(bg_applier->p->pixbuf,
bg_applier->p->pixmap, gc,
bg_applier->p->pixbuf_xlate.x,
bg_applier->p->pixbuf_xlate.y,
bg_applier->p->pixbuf_render_geom.x,
bg_applier->p->pixbuf_render_geom.y,
bg_applier->p->pixbuf_render_geom.width,
bg_applier->p->pixbuf_render_geom.height,
GDK_RGB_DITHER_MAX, 0, 0);
} else {
if (bg_applier->p->type == BG_APPLIER_ROOT) {
gboolean success;
#if 0
gdk_color_alloc (gdk_window_get_colormap (gdk_get_default_root_window()), prefs->color1);
#else
gdk_colormap_alloc_colors (gdk_drawable_get_colormap (gdk_get_default_root_window ()),
prefs->color1, 1, FALSE, TRUE, &success);
#endif
gdk_window_set_background (gdk_get_default_root_window (), prefs->color1);
gdk_window_clear (gdk_get_default_root_window ());
}
else if (bg_applier->p->type == BG_APPLIER_PREVIEW) {
gboolean success;
#if 0
gdk_color_alloc (gdk_window_get_colormap (bg_applier->p->preview_widget->window), prefs->color1);
#else
gdk_colormap_alloc_colors (gdk_drawable_get_colormap (gdk_get_default_root_window ()),
prefs->color1, 1, FALSE, TRUE, &success);
#endif
if (bg_applier->p->type == BG_APPLIER_PREVIEW) {
gdk_gc_set_foreground (gc, prefs->color1);
gdk_draw_rectangle (bg_applier->p->pixmap, gc, TRUE,
bg_applier->p->render_geom.x,
bg_applier->p->render_geom.y,
bg_applier->p->render_geom.width,
bg_applier->p->render_geom.height);
}
else if (bg_applier->p->type == BG_APPLIER_ROOT) {
gdk_window_set_back_pixmap (gdk_get_default_root_window (), NULL, FALSE);
gdk_window_set_background (gdk_get_default_root_window (), prefs->color1);
}
}
}
if (bg_applier->p->type == BG_APPLIER_ROOT && !bg_applier->p->pixmap_is_set &&
(prefs->wallpaper_enabled || prefs->gradient_enabled))
set_root_pixmap (bg_applier->p->pixmap);
else if (bg_applier->p->type == BG_APPLIER_ROOT && !bg_applier->p->pixmap_is_set)
set_root_pixmap (NULL);
g_object_unref (G_OBJECT (gc));
}
/* Create a pixmap that will replace the current root pixmap. This function has
* no effect if the bg_applier is for the preview window
*/
static void
create_pixmap (BGApplier *bg_applier, const BGPreferences *prefs)
{
gint width, height;
g_return_if_fail (bg_applier != NULL);
g_return_if_fail (IS_BG_APPLIER (bg_applier));
g_return_if_fail (prefs != NULL);
g_return_if_fail (IS_BG_PREFERENCES (prefs));
switch (bg_applier->p->type) {
case BG_APPLIER_ROOT:
if (prefs->gradient_enabled && !prefs->wallpaper_enabled) {
width = bg_applier->p->grad_geom.x;
height = bg_applier->p->grad_geom.y;
} else {
width = bg_applier->p->render_geom.width;
height = bg_applier->p->render_geom.height;
}
bg_applier->p->pixmap = make_root_pixmap (width, height);
bg_applier->p->pixmap_is_set = FALSE;
break;
case BG_APPLIER_PREVIEW:
bg_applier_get_preview_widget (bg_applier);
if (!GTK_WIDGET_REALIZED (bg_applier->p->preview_widget))
gtk_widget_realize (bg_applier->p->preview_widget);
#if 0
bg_applier->p->pixmap = GTK_PIXMAP (bg_applier->p->preview_widget)->pixmap;
#else
if (!bg_applier->p->pixmap)
gtk_image_get_pixmap (GTK_IMAGE (bg_applier->p->preview_widget), &bg_applier->p->pixmap, NULL);
#endif
bg_applier->p->pixmap_is_set = TRUE;
break;
}
}
/* Compute geometry information based on the wallpaper type. In particular,
* determine where on the destination visual the wallpaper should be rendered
* and where the data from the source pixbuf the image should be fetched.
*/
static void
get_geometry (wallpaper_type_t wallpaper_type,
GdkPixbuf *pixbuf,
GdkRectangle *field_geom,
GdkRectangle *virtual_geom,
GdkRectangle *dest_geom,
GdkRectangle *src_geom)
{
gdouble asp, xfactor, yfactor;
gint pwidth, pheight;
gint st = 0;
if (field_geom->width != virtual_geom->width)
xfactor = (gdouble) field_geom->width / (gdouble) virtual_geom->width;
else
xfactor = 1.0;
if (field_geom->height != virtual_geom->height)
yfactor = (gdouble) field_geom->height / (gdouble) virtual_geom->height;
else
yfactor = 1.0;
pwidth = gdk_pixbuf_get_width (pixbuf);
pheight = gdk_pixbuf_get_height (pixbuf);
switch (wallpaper_type) {
case WPTYPE_TILED:
src_geom->x = src_geom->y = 0;
dest_geom->x = dest_geom->y = 0;
src_geom->width = pwidth;
src_geom->height = pheight;
dest_geom->width = field_geom->width;
dest_geom->height = field_geom->height;
break;
case WPTYPE_CENTERED:
if (virtual_geom->width < pwidth) {
src_geom->width = virtual_geom->width;
src_geom->x = (pwidth - virtual_geom->width) / 2;
dest_geom->width = field_geom->width;
dest_geom->x = 0;
} else {
src_geom->width = pwidth;
src_geom->x = 0;
dest_geom->width = MIN ((gdouble) src_geom->width * xfactor, field_geom->width);
dest_geom->x = (field_geom->width - dest_geom->width) / 2;
}
if (virtual_geom->height < pheight) {
src_geom->height = virtual_geom->height;
src_geom->y = (pheight - virtual_geom->height) / 2;
dest_geom->height = field_geom->height;
dest_geom->y = 0;
} else {
src_geom->height = pheight;
src_geom->y = 0;
dest_geom->height = MIN ((gdouble) src_geom->height * yfactor, field_geom->height);
dest_geom->y = (field_geom->height - dest_geom->height) / 2;
}
break;
case WPTYPE_SCALED:
asp = (gdouble) pwidth / (gdouble) virtual_geom->width;
if (asp < (gdouble) pheight / virtual_geom->height) {
asp = (gdouble) pheight / (gdouble) virtual_geom->height;
st = 1;
}
if (st) {
dest_geom->width = pwidth / asp * xfactor;
dest_geom->height = field_geom->height;
dest_geom->x = (field_geom->width - dest_geom->width) / 2;
dest_geom->y = 0;
} else {
dest_geom->height = pheight / asp * yfactor;
dest_geom->width = field_geom->width;
dest_geom->x = 0;
dest_geom->y = (field_geom->height - dest_geom->height) / 2;
}
src_geom->x = src_geom->y = 0;
src_geom->width = pwidth;
src_geom->height = pheight;
break;
case WPTYPE_STRETCHED:
dest_geom->width = field_geom->width;
dest_geom->height = field_geom->height;
dest_geom->x = 0;
dest_geom->y = 0;
src_geom->x = src_geom->y = 0;
src_geom->width = pwidth;
src_geom->height = pheight;
break;
default:
g_error ("Bad wallpaper type");
break;
}
}
/* Place one pixbuf onto another, compositing and scaling as necessary */
static GdkPixbuf *
place_pixbuf (GdkPixbuf *dest_pixbuf,
GdkPixbuf *src_pixbuf,
GdkRectangle *dest_geom,
GdkRectangle *src_geom,
guint alpha,
GdkColor *bg_color)
{
gboolean need_composite;
gboolean need_scaling;
gdouble scale_x, scale_y;
gint real_dest_x, real_dest_y;
guint colorv;
need_composite = (alpha < 255 || gdk_pixbuf_get_has_alpha (src_pixbuf));
need_scaling = ((dest_geom->width != src_geom->width) || (dest_geom->height != src_geom->height));
if (need_scaling) {
scale_x = (gdouble) dest_geom->width / (gdouble) src_geom->width;
scale_y = (gdouble) dest_geom->height / (gdouble) src_geom->height;
} else {
scale_x = scale_y = 1.0;
}
if (need_composite && dest_pixbuf != NULL) {
gdk_pixbuf_composite
(src_pixbuf, dest_pixbuf,
dest_geom->x, dest_geom->y,
dest_geom->width,
dest_geom->height,
dest_geom->x - src_geom->x * scale_x,
dest_geom->y - src_geom->y * scale_y,
scale_x, scale_y,
GDK_INTERP_BILINEAR,
alpha);
}
else if (need_composite) {
dest_pixbuf = gdk_pixbuf_new
(GDK_COLORSPACE_RGB, FALSE, 8,
dest_geom->width, dest_geom->height);
colorv = ((bg_color->red & 0xff00) << 8) |
(bg_color->green & 0xff00) |
((bg_color->blue & 0xff00) >> 8);
gdk_pixbuf_composite_color
(src_pixbuf, dest_pixbuf,
0, 0,
dest_geom->width,
dest_geom->height,
-src_geom->x * scale_x,
-src_geom->y * scale_y,
scale_x, scale_y,
GDK_INTERP_BILINEAR,
alpha, 0, 0, 65536,
colorv, colorv);
}
else if (need_scaling) {
if (dest_pixbuf == NULL) {
dest_pixbuf = gdk_pixbuf_new
(GDK_COLORSPACE_RGB, FALSE, 8,
dest_geom->width, dest_geom->height);
real_dest_x = real_dest_y = 0;
} else {
real_dest_x = dest_geom->x;
real_dest_y = dest_geom->y;
}
gdk_pixbuf_scale
(src_pixbuf, dest_pixbuf,
real_dest_x, real_dest_y,
dest_geom->width,
dest_geom->height,
real_dest_x - src_geom->x * scale_x,
real_dest_y - src_geom->y * scale_y,
scale_x, scale_y,
GDK_INTERP_BILINEAR);
}
else if (dest_pixbuf != NULL) {
gdk_pixbuf_copy_area
(src_pixbuf,
src_geom->x, src_geom->y,
src_geom->width,
src_geom->height,
dest_pixbuf,
dest_geom->x, dest_geom->y);
} else {
dest_pixbuf = src_pixbuf;
g_object_ref (G_OBJECT (dest_pixbuf));
}
return dest_pixbuf;
}
/* Tile one pixbuf repeatedly onto another, compositing as necessary. Assumes
* that the source pixbuf has already been scaled properly
*/
static GdkPixbuf *
tile_pixbuf (GdkPixbuf *dest_pixbuf,
GdkPixbuf *src_pixbuf,
GdkRectangle *field_geom,
guint alpha,
GdkColor *bg_color)
{
gboolean need_composite;
gboolean use_simple;
gdouble cx, cy;
gdouble colorv;
gint pwidth, pheight;
need_composite = (alpha < 255 || gdk_pixbuf_get_has_alpha (src_pixbuf));
use_simple = (dest_pixbuf == NULL);
if (dest_pixbuf == NULL)
dest_pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, field_geom->width, field_geom->height);
if (need_composite && use_simple)
colorv = ((bg_color->red & 0xff00) << 8) |
(bg_color->green & 0xff00) |
((bg_color->blue & 0xff00) >> 8);
else
colorv = 0;
pwidth = gdk_pixbuf_get_width (src_pixbuf);
pheight = gdk_pixbuf_get_height (src_pixbuf);
for (cy = 0; cy < field_geom->height; cy += pheight) {
for (cx = 0; cx < field_geom->width; cx += pwidth) {
if (need_composite && !use_simple)
gdk_pixbuf_composite
(src_pixbuf, dest_pixbuf,
cx, cy,
MIN (pwidth, field_geom->width - cx),
MIN (pheight, field_geom->height - cy),
cx, cy,
1.0, 1.0,
GDK_INTERP_BILINEAR,
alpha);
else if (need_composite && use_simple)
gdk_pixbuf_composite_color
(src_pixbuf, dest_pixbuf,
cx, cy,
MIN (pwidth, field_geom->width - cx),
MIN (pheight, field_geom->height - cy),
cx, cy,
1.0, 1.0,
GDK_INTERP_BILINEAR,
alpha,
65536, 65536, 65536,
colorv, colorv);
else
gdk_pixbuf_copy_area
(src_pixbuf,
0, 0,
MIN (pwidth, field_geom->width - cx),
MIN (pheight, field_geom->height - cy),
dest_pixbuf,
cx, cy);
}
}
return dest_pixbuf;
}
/* Fill a raw character array with gradient data; the data may then be imported
* into a GdkPixbuf
*/
static void
fill_gradient (GdkPixbuf *pixbuf,
GdkColor *c1,
GdkColor *c2,
orientation_t orientation)
{
int i, j;
int dr, dg, db;
int gs1;
int vc = ((orientation == ORIENTATION_HORIZ) || (c1 == c2));
int w = gdk_pixbuf_get_width (pixbuf);
int h = gdk_pixbuf_get_height (pixbuf);
guchar *b, *row;
guchar *d = gdk_pixbuf_get_pixels (pixbuf);
int rowstride = gdk_pixbuf_get_rowstride (pixbuf);
#define R1 c1->red
#define G1 c1->green
#define B1 c1->blue
#define R2 c2->red
#define G2 c2->green
#define B2 c2->blue
dr = R2 - R1;
dg = G2 - G1;
db = B2 - B1;
gs1 = (orientation == ORIENTATION_VERT) ? h-1 : w-1;
row = g_new (unsigned char, rowstride);
if (vc) {
b = row;
for (j = 0; j < w; j++) {
*b++ = (R1 + (j * dr) / gs1) >> 8;
*b++ = (G1 + (j * dg) / gs1) >> 8;
*b++ = (B1 + (j * db) / gs1) >> 8;
}
}
for (i = 0; i < h; i++) {
if (!vc) {
unsigned char cr, cg, cb;
cr = (R1 + (i * dr) / gs1) >> 8;
cg = (G1 + (i * dg) / gs1) >> 8;
cb = (B1 + (i * db) / gs1) >> 8;
b = row;
for (j = 0; j < w; j++) {
*b++ = cr;
*b++ = cg;
*b++ = cb;
}
}
memcpy (d, row, w * 3);
d += rowstride;
}
#undef R1
#undef G1
#undef B1
#undef R2
#undef G2
#undef B2
g_free (row);
}
/* Boolean predicates to assist optimization and rendering */
/* Return TRUE iff the wallpaper filename or enabled settings have changed
* between old_prefs and new_prefs
*/
static gboolean
need_wallpaper_load_p (const BGApplier *bg_applier, const BGPreferences *prefs)
{
if (bg_applier->p->last_prefs == NULL)
return TRUE;
else if (prefs->wallpaper_enabled && bg_applier->p->wallpaper_pixbuf == NULL)
return TRUE;
else if (bg_applier->p->last_prefs->wallpaper_enabled != prefs->wallpaper_enabled)
return TRUE;
else if (!bg_applier->p->last_prefs->wallpaper_enabled && !prefs->wallpaper_enabled)
return FALSE;
else if (strcmp (bg_applier->p->last_prefs->wallpaper_filename, prefs->wallpaper_filename))
return TRUE;
else
return FALSE;
}
/* Return TRUE iff we need to create a new root pixmap */
static gboolean
need_root_pixmap_p (const BGApplier *bg_applier, const BGPreferences *prefs)
{
if (bg_applier->p->pixmap == NULL)
return TRUE;
else if (prefs->wallpaper_enabled == FALSE && prefs->gradient_enabled == FALSE)
return FALSE;
else if (bg_applier->p->last_prefs == NULL)
return TRUE;
else if (bg_applier->p->last_prefs->wallpaper_enabled == FALSE && bg_applier->p->last_prefs->gradient_enabled == FALSE)
return TRUE;
else if (render_small_pixmap_p (bg_applier->p->last_prefs) != render_small_pixmap_p (prefs))
return TRUE;
else if (!render_small_pixmap_p (bg_applier->p->last_prefs) &&
!render_small_pixmap_p (prefs))
return FALSE;
else if (bg_applier->p->last_prefs->orientation != prefs->orientation)
return TRUE;
else
return FALSE;
}
/* Return TRUE iff the colors are equal */
/* Return TRUE iff the wallpaper completely covers the colors in the given
* bg_preferences structure, assuming we have already loaded the wallpaper pixbuf */
static gboolean
wallpaper_full_cover_p (const BGApplier *bg_applier, const BGPreferences *prefs)
{
gint swidth, sheight;
gint pwidth, pheight;
gdouble asp1, asp2;
if (bg_applier->p->wallpaper_pixbuf == NULL)
return FALSE;
else if (gdk_pixbuf_get_has_alpha (bg_applier->p->wallpaper_pixbuf))
return FALSE;
else if (prefs->wallpaper_type == WPTYPE_TILED)
return TRUE;
else if (prefs->wallpaper_type == WPTYPE_STRETCHED)
return TRUE;
gdk_drawable_get_size (gdk_get_default_root_window (), &swidth, &sheight);
pwidth = gdk_pixbuf_get_width (bg_applier->p->wallpaper_pixbuf);
pheight = gdk_pixbuf_get_height (bg_applier->p->wallpaper_pixbuf);
if (prefs->wallpaper_type == WPTYPE_CENTERED) {
if (pwidth >= swidth && pheight >= sheight)
return TRUE;
else
return FALSE;
}
else if (prefs->wallpaper_type == WPTYPE_SCALED) {
asp1 = (gdouble) swidth / (gdouble) sheight;
asp2 = (gdouble) pwidth / (gdouble) pheight;
if (swidth * (asp1 - asp2) < 1 && swidth * (asp2 - asp1) < 1)
return TRUE;
else
return FALSE;
}
return FALSE;
}
/* Return TRUE if we can optimize the rendering by using a small thin pixmap */
static gboolean
render_small_pixmap_p (const BGPreferences *prefs)
{
return prefs->gradient_enabled && !prefs->wallpaper_enabled;
}
/* Create a persistant pixmap. We create a separate display
* and set the closedown mode on it to RetainPermanent
*/
static GdkPixmap *
make_root_pixmap (gint width, gint height)
{
Display *display;
Pixmap xpixmap;
GdkPixmap *gdkpixmap;
display = XOpenDisplay (gdk_get_display ());
XSetCloseDownMode (display, RetainPermanent);
xpixmap = XCreatePixmap (display,
DefaultRootWindow (display),
width, height,
DefaultDepthOfScreen (DefaultScreenOfDisplay (GDK_DISPLAY ())));
XCloseDisplay (display);
gdkpixmap = gdk_pixmap_foreign_new (xpixmap);
gdk_drawable_set_colormap (GDK_DRAWABLE (gdkpixmap),
gdk_drawable_get_colormap (gdk_get_default_root_window ()));
return gdkpixmap;
}
/* Set the root pixmap, and properties pointing to it. We
* do this atomically with XGrabServer to make sure that
* we won't leak the pixmap if somebody else it setting
* it at the same time. (This assumes that they follow the
* same conventions we do)
*/
static void
set_root_pixmap (GdkPixmap *pixmap)
{
Atom type;
gulong nitems, bytes_after;
gint format;
guchar *data_esetroot;
Pixmap pixmap_id;
if (pixmap != NULL && pixmap != (GdkPixmap *) -1)
pixmap_id = GDK_WINDOW_XWINDOW (pixmap);
else
pixmap_id = 0;
XGrabServer (GDK_DISPLAY ());
XGetWindowProperty (GDK_DISPLAY (), GDK_ROOT_WINDOW (),
XInternAtom (GDK_DISPLAY (), "ESETROOT_PMAP_ID", False),
0L, 1L, False, XA_PIXMAP,
&type, &format, &nitems, &bytes_after,
&data_esetroot);
if (type == XA_PIXMAP) {
if (format == 32 && nitems == 1) {
Pixmap old_pixmap;
old_pixmap = *((Pixmap *) data_esetroot);
if (pixmap != (GdkPixmap *) -1 && old_pixmap != pixmap_id)
XKillClient (GDK_DISPLAY (), old_pixmap);
else if (pixmap == (GdkPixmap *) -1)
pixmap_id = old_pixmap;
}
XFree (data_esetroot);
}
if (pixmap != NULL && pixmap != (GdkPixmap *) -1) {
XChangeProperty (GDK_DISPLAY (), GDK_ROOT_WINDOW (),
XInternAtom (GDK_DISPLAY (), "ESETROOT_PMAP_ID", FALSE),
XA_PIXMAP, 32, PropModeReplace,
(guchar *) &pixmap_id, 1);
XChangeProperty (GDK_DISPLAY (), GDK_ROOT_WINDOW (),
XInternAtom (GDK_DISPLAY (), "_XROOTPMAP_ID", FALSE),
XA_PIXMAP, 32, PropModeReplace,
(guchar *) &pixmap_id, 1);
XSetWindowBackgroundPixmap (GDK_DISPLAY (), GDK_ROOT_WINDOW (),
pixmap_id);
} else if (pixmap == NULL) {
XDeleteProperty (GDK_DISPLAY (), GDK_ROOT_WINDOW (),
XInternAtom (GDK_DISPLAY (), "ESETROOT_PMAP_ID", FALSE));
XDeleteProperty (GDK_DISPLAY (), GDK_ROOT_WINDOW (),
XInternAtom (GDK_DISPLAY (), "_XROOTPMAP_ID", FALSE));
}
XClearWindow (GDK_DISPLAY (), GDK_ROOT_WINDOW ());
XUngrabServer (GDK_DISPLAY ());
XFlush (GDK_DISPLAY ());
}
static gboolean
is_nautilus_running (void)
{
Atom window_id_atom;
Window nautilus_xid;
Atom actual_type;
int actual_format;
unsigned long nitems, bytes_after;
unsigned char *data;
int retval;
Atom wmclass_atom;
gboolean running;
gint error;
window_id_atom = XInternAtom (GDK_DISPLAY (),
"NAUTILUS_DESKTOP_WINDOW_ID", True);
if (window_id_atom == None) return FALSE;
retval = XGetWindowProperty (GDK_DISPLAY (), GDK_ROOT_WINDOW (),
window_id_atom, 0, 1, False, XA_WINDOW,
&actual_type, &actual_format, &nitems,
&bytes_after, &data);
if (data != NULL) {
nautilus_xid = *(Window *) data;
XFree (data);
} else {
return FALSE;
}
if (actual_type != XA_WINDOW) return FALSE;
if (actual_format != 32) return FALSE;
wmclass_atom = XInternAtom (GDK_DISPLAY (), "WM_CLASS", False);
gdk_error_trap_push ();
retval = XGetWindowProperty (GDK_DISPLAY (), nautilus_xid,
wmclass_atom, 0, 24, False, XA_STRING,
&actual_type, &actual_format, &nitems,
&bytes_after, &data);
error = gdk_error_trap_pop ();
if (error == BadWindow) return FALSE;
if (actual_type == XA_STRING &&
nitems == 24 &&
bytes_after == 0 &&
actual_format == 8 &&
data != NULL &&
!strcmp (data, "desktop_window") &&
!strcmp (data + strlen (data) + 1, "Nautilus"))
running = TRUE;
else
running = FALSE;
if (data != NULL)
XFree (data);
return running;
}
static gboolean
cleanup_cb (BGApplier *bg_applier)
{
g_message ("cleanup_cb: Enter");
if (bg_applier->p->wallpaper_pixbuf != NULL) {
g_object_unref (G_OBJECT (bg_applier->p->wallpaper_pixbuf));
bg_applier->p->wallpaper_pixbuf = NULL;
}
if (bg_applier->p->pixbuf != NULL) {
g_object_unref (G_OBJECT (bg_applier->p->pixbuf));
bg_applier->p->pixbuf = NULL;
}
bg_applier->p->timeout = 0;
return FALSE;
}
static void
preview_realized_cb (GtkWidget *preview, BGApplier *bg_applier)
{
GdkPixmap *pixmap;
/* Only draw clean image if no pref set yet */
if (bg_applier->p->last_prefs)
return;
gtk_image_get_pixmap (GTK_IMAGE (preview), &pixmap, NULL);
if (!pixmap) {
pixmap = gdk_pixmap_new (preview->window,
bg_applier->p->render_geom.width,
bg_applier->p->render_geom.height,
-1);
gtk_image_set_from_pixmap (GTK_IMAGE (preview), pixmap, NULL);
}
gdk_draw_rectangle (pixmap,
preview->style->bg_gc[preview->state],
TRUE,
bg_applier->p->render_geom.x,
bg_applier->p->render_geom.y,
bg_applier->p->render_geom.width,
bg_applier->p->render_geom.height);
}