Merging upstream version 0.8.0 (Closes: #639729, #761971).
[debian/lxpanel.git] / src / bg.c
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 <gtk/gtk.h>
32 #include <X11/Xlib.h>
33 #include <X11/Xatom.h>
34
35 #if !GTK_CHECK_VERSION(3, 0, 0)
36 /* we don't provide these APIs for GTK+ 3.0 */
37
38 #include "bg.h"
39
40 //#define DEBUG
41 #include "dbg.h"
42
43 enum {
44 CHANGED,
45 LAST_SIGNAL
46 };
47
48
49 struct _FbBgClass {
50 GObjectClass parent_class;
51 void (*changed) (FbBg *monitor);
52 };
53
54 struct _FbBg {
55 GObject parent_instance;
56
57 Window xroot;
58 Atom id;
59 GC gc;
60 Display *dpy;
61 Pixmap pixmap;
62 };
63
64 static void fb_bg_class_init (FbBgClass *klass);
65 static void fb_bg_init (FbBg *monitor);
66 static void fb_bg_finalize (GObject *object);
67 static Pixmap fb_bg_get_xrootpmap(FbBg *monitor);
68 static void fb_bg_changed(FbBg *monitor);
69
70
71 static guint signals [LAST_SIGNAL] = { 0 };
72
73 static FbBg *default_bg = NULL;
74
75 GType
76 fb_bg_get_type (void)
77 {
78 static GType object_type = 0;
79
80 if (!object_type) {
81 static const GTypeInfo object_info = {
82 sizeof (FbBgClass),
83 (GBaseInitFunc) NULL,
84 (GBaseFinalizeFunc) NULL,
85 (GClassInitFunc) fb_bg_class_init,
86 NULL, /* class_finalize */
87 NULL, /* class_data */
88 sizeof (FbBg),
89 0, /* n_preallocs */
90 (GInstanceInitFunc) fb_bg_init,
91 };
92
93 object_type = g_type_register_static (
94 G_TYPE_OBJECT, "FbBg", &object_info, 0);
95 }
96
97 return object_type;
98 }
99
100
101
102 static void
103 fb_bg_class_init (FbBgClass *klass)
104 {
105 GObjectClass *object_class = G_OBJECT_CLASS (klass);
106 ENTER;
107 signals [CHANGED] =
108 g_signal_new ("changed",
109 G_OBJECT_CLASS_TYPE (object_class),
110 G_SIGNAL_RUN_FIRST,
111 G_STRUCT_OFFSET (FbBgClass, changed),
112 NULL, NULL,
113 g_cclosure_marshal_VOID__VOID,
114 G_TYPE_NONE, 0);
115 klass->changed = fb_bg_changed;
116 object_class->finalize = fb_bg_finalize;
117 RET();
118 }
119
120 static void
121 fb_bg_init (FbBg *bg)
122 {
123 XGCValues gcv;
124 uint mask;
125
126 ENTER;
127 bg->dpy = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
128 bg->xroot = DefaultRootWindow(bg->dpy);
129 bg->id = gdk_x11_get_xatom_by_name("_XROOTPMAP_ID");
130 bg->pixmap = fb_bg_get_xrootpmap(bg);
131 gcv.ts_x_origin = 0;
132 gcv.ts_y_origin = 0;
133 gcv.fill_style = FillTiled;
134 mask = GCTileStipXOrigin | GCTileStipYOrigin | GCFillStyle;
135 if (bg->pixmap != None) {
136 gcv.tile = bg->pixmap;
137 mask |= GCTile ;
138 }
139 bg->gc = XCreateGC (bg->dpy, bg->xroot, mask, &gcv) ;
140 RET();
141 }
142
143 static void
144 fb_bg_finalize (GObject *object)
145 {
146 FbBg *bg;
147
148 ENTER;
149 bg = FB_BG (object);
150 XFreeGC(bg->dpy, bg->gc);
151 RET();
152 }
153
154
155 static Pixmap
156 fb_bg_get_xrootpmap(FbBg *bg)
157 {
158 Pixmap ret = None;
159
160 ENTER;
161 if (bg->id) {
162 int act_format, c = 2 ;
163 u_long nitems ;
164 u_long bytes_after ;
165 u_char *prop = NULL;
166 Atom ret_type;
167
168 do {
169 if (XGetWindowProperty(bg->dpy, bg->xroot, bg->id, 0, 1,
170 False, XA_PIXMAP, &ret_type, &act_format,
171 &nitems, &bytes_after, &prop) == Success) {
172 if (ret_type == XA_PIXMAP) {
173 ret = *((Pixmap *)prop);
174 XFree(prop);
175 break;
176 }
177 }
178 } while (--c > 0);
179 }
180 RET(ret);
181
182 }
183
184
185 GdkPixmap *
186 fb_bg_get_xroot_pix_for_win(FbBg *bg, GtkWidget *widget)
187 {
188 Window win;
189 Window dummy;
190 Pixmap bgpix;
191 GdkPixmap *gbgpix;
192 guint width, height, border, depth;
193 int x, y;
194
195 ENTER;
196 win = GDK_WINDOW_XWINDOW(gtk_widget_get_window(widget));
197 if (!XGetGeometry(bg->dpy, win, &dummy, &x, &y, &width, &height, &border,
198 &depth)) {
199 g_warning("XGetGeometry failed\n");
200 RET(NULL);
201 }
202 XTranslateCoordinates(bg->dpy, win, bg->xroot, 0, 0, &x, &y, &dummy);
203 DBG("win=%x %dx%d%+d%+d\n", win, width, height, x, y);
204 gbgpix = gdk_pixmap_new(NULL, width, height, depth);
205 if (!gbgpix) {
206 g_critical("gdk_pixmap_new failed");
207 RET(NULL);
208 }
209 bgpix = gdk_x11_drawable_get_xid(gbgpix);
210 XSetTSOrigin(bg->dpy, bg->gc, -x, -y) ;
211 XFillRectangle(bg->dpy, bgpix, bg->gc, 0, 0, width, height);
212 RET(gbgpix);
213 }
214
215 void
216 fb_bg_composite(GdkDrawable *base, GdkColor *tintcolor, gint alpha)
217 {
218 cairo_t *cr;
219 FbBg *bg;
220
221 ENTER;
222 cr = gdk_cairo_create(base);
223 gdk_cairo_set_source_color(cr, tintcolor);
224 cairo_paint_with_alpha(cr, (double) alpha/255);
225 check_cairo_status(cr);
226 cairo_destroy(cr);
227 bg = fb_bg_get_for_display();
228 fb_bg_changed(bg);
229 g_object_unref(bg);
230 RET();
231 }
232
233
234 static void
235 fb_bg_changed(FbBg *bg)
236 {
237 ENTER;
238 bg->pixmap = fb_bg_get_xrootpmap(bg);
239 if (bg->pixmap != None) {
240 XGCValues gcv;
241
242 gcv.tile = bg->pixmap;
243 XChangeGC(bg->dpy, bg->gc, GCTile, &gcv);
244 DBG("changed\n");
245 }
246 RET();
247 }
248
249 inline void fb_bg_notify_changed_bg(FbBg *bg)
250 {
251 ENTER;
252 g_signal_emit (bg, signals [CHANGED], 0);
253 RET();
254 }
255
256 FbBg *fb_bg_get_for_display(void)
257 {
258 ENTER;
259 if (!default_bg)
260 {
261 default_bg = fb_bg_new();
262 g_object_add_weak_pointer( G_OBJECT(default_bg),
263 (gpointer)&default_bg );
264 }
265 else
266 g_object_ref(default_bg);
267 RET(default_bg);
268 }
269
270 GdkPixmap *
271 fb_bg_get_pix_from_file(GtkWidget *widget, const char *filename)
272 {
273 ENTER;
274 GdkPixbuf *pixbuf;
275 cairo_t *cr;
276 GdkPixmap *pixmap;
277
278 pixbuf = gdk_pixbuf_new_from_file(filename, NULL);
279 if (!pixbuf) {
280 GtkStyle *style = gtk_widget_get_style(widget);
281 if (style->bg_pixmap[0])
282 g_object_ref(style->bg_pixmap[0]);
283 RET(style->bg_pixmap[0]);
284 }
285 pixmap = gdk_pixmap_new(gtk_widget_get_window(widget), gdk_pixbuf_get_width(pixbuf),
286 gdk_pixbuf_get_height(pixbuf), -1);
287 cr = gdk_cairo_create(pixmap);
288 gdk_cairo_set_source_pixbuf(cr, pixbuf, 0, 0);
289 cairo_paint(cr);
290 check_cairo_status(cr);
291 cairo_destroy(cr);
292
293 g_object_unref( pixbuf );
294 RET(pixmap);
295 }
296 #endif /* GTK_CHECK_VERSION */