Merging upstream version 0.7.0 (Closes: #493243, #510888, #567617, #699414, #709777...
[debian/lxpanel.git] / src / bg.c
CommitLineData
6cc5e1a6
DB
1/*
2 * fb-background-monitor.c:
3 *
4 * Copyright (C) 2001, 2002 Ian McKellar <yakk@yakk.net>
5 * 2002 Sun Microsystems, Inc.
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
16 *
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
20 * MA 02110-1301, USA.
21 *
22 * Authors:
23 * Ian McKellar <yakk@yakk.net>
24 * Mark McLoughlin <mark@skynet.ie>
25 */
26
27#include <glib.h>
28#include <glib-object.h>
29#include <gdk/gdk.h>
30#include <gdk/gdkx.h>
31#include <X11/Xlib.h>
32#include <X11/Xatom.h>
33
34#include "bg.h"
35
36//#define DEBUG
37#include "dbg.h"
38
39
40enum {
41 CHANGED,
42 LAST_SIGNAL
43};
44
45
46struct _FbBgClass {
47 GObjectClass parent_class;
48 void (*changed) (FbBg *monitor);
49};
50
51struct _FbBg {
52 GObject parent_instance;
53
54 Window xroot;
55 Atom id;
56 GC gc;
57 Display *dpy;
58 Pixmap pixmap;
59};
60
61static void fb_bg_class_init (FbBgClass *klass);
62static void fb_bg_init (FbBg *monitor);
63static void fb_bg_finalize (GObject *object);
64static Pixmap fb_bg_get_xrootpmap(FbBg *monitor);
65static void fb_bg_changed(FbBg *monitor);
66
67
68static guint signals [LAST_SIGNAL] = { 0 };
69
70static FbBg *default_bg = NULL;
71
72GType
73fb_bg_get_type (void)
74{
75 static GType object_type = 0;
76
77 if (!object_type) {
78 static const GTypeInfo object_info = {
79 sizeof (FbBgClass),
80 (GBaseInitFunc) NULL,
81 (GBaseFinalizeFunc) NULL,
82 (GClassInitFunc) fb_bg_class_init,
83 NULL, /* class_finalize */
84 NULL, /* class_data */
85 sizeof (FbBg),
86 0, /* n_preallocs */
87 (GInstanceInitFunc) fb_bg_init,
88 };
89
90 object_type = g_type_register_static (
91 G_TYPE_OBJECT, "FbBg", &object_info, 0);
92 }
93
94 return object_type;
95}
96
97
98
99static void
100fb_bg_class_init (FbBgClass *klass)
101{
102 GObjectClass *object_class = G_OBJECT_CLASS (klass);
103 ENTER;
104 signals [CHANGED] =
105 g_signal_new ("changed",
106 G_OBJECT_CLASS_TYPE (object_class),
107 G_SIGNAL_RUN_FIRST,
108 G_STRUCT_OFFSET (FbBgClass, changed),
109 NULL, NULL,
110 g_cclosure_marshal_VOID__VOID,
111 G_TYPE_NONE, 0);
112 klass->changed = fb_bg_changed;
113 object_class->finalize = fb_bg_finalize;
114 RET();
115}
116
117static void
118fb_bg_init (FbBg *bg)
119{
120 XGCValues gcv;
121 uint mask;
122
123 ENTER;
00916e98 124 bg->dpy = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
6cc5e1a6 125 bg->xroot = DefaultRootWindow(bg->dpy);
10862fa6 126 bg->id = gdk_x11_get_xatom_by_name("_XROOTPMAP_ID");
6cc5e1a6
DB
127 bg->pixmap = fb_bg_get_xrootpmap(bg);
128 gcv.ts_x_origin = 0;
129 gcv.ts_y_origin = 0;
130 gcv.fill_style = FillTiled;
131 mask = GCTileStipXOrigin | GCTileStipYOrigin | GCFillStyle;
132 if (bg->pixmap != None) {
133 gcv.tile = bg->pixmap;
134 mask |= GCTile ;
135 }
136 bg->gc = XCreateGC (bg->dpy, bg->xroot, mask, &gcv) ;
137 RET();
138}
139
6cc5e1a6
DB
140static void
141fb_bg_finalize (GObject *object)
142{
143 FbBg *bg;
144
145 ENTER;
146 bg = FB_BG (object);
147 XFreeGC(bg->dpy, bg->gc);
148 RET();
149}
150
151
152static Pixmap
153fb_bg_get_xrootpmap(FbBg *bg)
154{
155 Pixmap ret = None;
156
157 ENTER;
158 if (bg->id) {
159 int act_format, c = 2 ;
160 u_long nitems ;
161 u_long bytes_after ;
162 u_char *prop = NULL;
163 Atom ret_type;
164
165 do {
166 if (XGetWindowProperty(bg->dpy, bg->xroot, bg->id, 0, 1,
167 False, XA_PIXMAP, &ret_type, &act_format,
168 &nitems, &bytes_after, &prop) == Success) {
169 if (ret_type == XA_PIXMAP) {
170 ret = *((Pixmap *)prop);
171 XFree(prop);
172 break;
173 }
174 }
175 } while (--c > 0);
176 }
177 RET(ret);
178
179}
180
181
182GdkPixmap *
183fb_bg_get_xroot_pix_for_win(FbBg *bg, GtkWidget *widget)
184{
185 Window win;
186 Window dummy;
187 Pixmap bgpix;
188 GdkPixmap *gbgpix;
189 guint width, height, border, depth;
190 int x, y;
191
192 ENTER;
00916e98 193 win = GDK_WINDOW_XWINDOW(gtk_widget_get_window(widget));
6cc5e1a6
DB
194 if (!XGetGeometry(bg->dpy, win, &dummy, &x, &y, &width, &height, &border,
195 &depth)) {
00916e98 196 g_warning("XGetGeometry failed\n");
6cc5e1a6
DB
197 RET(NULL);
198 }
199 XTranslateCoordinates(bg->dpy, win, bg->xroot, 0, 0, &x, &y, &dummy);
200 DBG("win=%x %dx%d%+d%+d\n", win, width, height, x, y);
201 gbgpix = gdk_pixmap_new(NULL, width, height, depth);
202 if (!gbgpix) {
00916e98 203 g_critical("gdk_pixmap_new failed");
6cc5e1a6
DB
204 RET(NULL);
205 }
206 bgpix = gdk_x11_drawable_get_xid(gbgpix);
207 XSetTSOrigin(bg->dpy, bg->gc, -x, -y) ;
208 XFillRectangle(bg->dpy, bgpix, bg->gc, 0, 0, width, height);
209 RET(gbgpix);
210}
211
212void
0f7f2ef3 213fb_bg_composite(GdkDrawable *base, GdkColor *tintcolor, gint alpha)
6cc5e1a6 214{
0f7f2ef3 215 cairo_t *cr;
00916e98 216 FbBg *bg;
6cc5e1a6
DB
217
218 ENTER;
0f7f2ef3
AL
219 cr = gdk_cairo_create(base);
220 gdk_cairo_set_source_color(cr, tintcolor);
221 cairo_paint_with_alpha(cr, (double) alpha/255);
222 check_cairo_status(cr);
223 cairo_destroy(cr);
00916e98
AG
224 bg = fb_bg_get_for_display();
225 fb_bg_changed(bg);
226 g_object_unref(bg);
6cc5e1a6
DB
227 RET();
228}
229
230
231static void
232fb_bg_changed(FbBg *bg)
233{
234 ENTER;
235 bg->pixmap = fb_bg_get_xrootpmap(bg);
236 if (bg->pixmap != None) {
237 XGCValues gcv;
238
239 gcv.tile = bg->pixmap;
240 XChangeGC(bg->dpy, bg->gc, GCTile, &gcv);
241 DBG("changed\n");
242 }
243 RET();
244}
245
10862fa6 246inline void fb_bg_notify_changed_bg(FbBg *bg)
6cc5e1a6
DB
247{
248 ENTER;
249 g_signal_emit (bg, signals [CHANGED], 0);
250 RET();
251}
252
253FbBg *fb_bg_get_for_display(void)
254{
255 ENTER;
256 if (!default_bg)
257 {
258 default_bg = fb_bg_new();
00916e98 259 g_object_add_weak_pointer( G_OBJECT(default_bg),
10862fa6 260 (gpointer)&default_bg );
6cc5e1a6
DB
261 }
262 else
263 g_object_ref(default_bg);
264 RET(default_bg);
265}
266
267GdkPixmap *
268fb_bg_get_pix_from_file(GtkWidget *widget, const char *filename)
269{
270 ENTER;
271 GdkPixbuf *pixbuf;
0f7f2ef3 272 cairo_t *cr;
6cc5e1a6
DB
273 GdkPixmap *pixmap;
274
275 pixbuf = gdk_pixbuf_new_from_file(filename, NULL);
276 if (!pixbuf) {
00916e98
AG
277 GtkStyle *style = gtk_widget_get_style(widget);
278 if (style->bg_pixmap[0])
279 g_object_ref(style->bg_pixmap[0]);
280 RET(style->bg_pixmap[0]);
6cc5e1a6 281 }
00916e98
AG
282 pixmap = gdk_pixmap_new(gtk_widget_get_window(widget), gdk_pixbuf_get_width(pixbuf),
283 gdk_pixbuf_get_height(pixbuf), -1);
0f7f2ef3
AL
284 cr = gdk_cairo_create(pixmap);
285 gdk_cairo_set_source_pixbuf(cr, pixbuf, 0, 0);
286 cairo_paint(cr);
287 check_cairo_status(cr);
288 cairo_destroy(cr);
6cc5e1a6
DB
289
290 g_object_unref( pixbuf );
291 RET(pixmap);
292}