1 /* GTK - The GIMP Toolkit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
18 */
19
20 /*
21 * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
22 * file for a list of people on the GTK+ Team. See the ChangeLog
23 * files for a list of changes. These files are distributed with
24 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
25 */
26
27 #include <string.h>
28 #include "gtkbgbox.h"
29 #include "bg.h"
30 #include <gdk/gdk.h>
31 #include <gdk/gdkx.h>
32 #include <gdk/gdkpixmap.h>
33 #include <gdk/gdkprivate.h>
34 #include <glib.h>
35 #include <glib-object.h>
36
37
38 //#define DEBUGPRN
39 #include "dbg.h"
40
41 typedef struct {
42 GdkPixmap *pixmap;
43 guint32 tintcolor;
44 gint alpha;
45 int bg_type;
46 FbBg *bg;
47 gulong sid;
48 } GtkBgboxPrivate;
49
50
51
52 #define GTK_BGBOX_GET_PRIVATE(obj) G_TYPE_INSTANCE_GET_PRIVATE((obj), GTK_TYPE_BGBOX, GtkBgboxPrivate)
53
54 static void gtk_bgbox_class_init (GtkBgboxClass *klass);
55 static void gtk_bgbox_init (GtkBgbox *bgbox);
56 static void gtk_bgbox_realize (GtkWidget *widget);
57 static void gtk_bgbox_size_request (GtkWidget *widget, GtkRequisition *requisition);
58 static void gtk_bgbox_size_allocate (GtkWidget *widget, GtkAllocation *allocation);
59 static void gtk_bgbox_style_set (GtkWidget *widget, GtkStyle *previous_style);
60 static gboolean gtk_bgbox_configure_event(GtkWidget *widget, GdkEventConfigure *e);
61 #if 0
62 static gboolean gtk_bgbox_destroy_event (GtkWidget *widget, GdkEventAny *event);
63 static gboolean gtk_bgbox_delete_event (GtkWidget *widget, GdkEventAny *event);
64 #endif
65
66 static void gtk_bgbox_finalize (GObject *object);
67
68 static void gtk_bgbox_set_bg_root(GtkWidget *widget, GtkBgboxPrivate *priv);
69 static void gtk_bgbox_set_bg_inherit(GtkWidget *widget, GtkBgboxPrivate *priv);
70 static void gtk_bgbox_bg_changed(FbBg *bg, GtkWidget *widget);
71
72 static GtkBinClass *parent_class = NULL;
73
74 GType
gtk_bgbox_get_type(void)75 gtk_bgbox_get_type (void)
76 {
77 static GType bgbox_type = 0;
78
79 if (!bgbox_type)
80 {
81 static const GTypeInfo bgbox_info =
82 {
83 sizeof (GtkBgboxClass),
84 NULL, /* base_init */
85 NULL, /* base_finalize */
86 (GClassInitFunc) gtk_bgbox_class_init,
87 NULL, /* class_finalize */
88 NULL, /* class_data */
89 sizeof (GtkBgbox),
90 0, /* n_preallocs */
91 (GInstanceInitFunc) gtk_bgbox_init,
92 };
93
94 bgbox_type = g_type_register_static (GTK_TYPE_BIN, "GtkBgbox",
95 &bgbox_info, 0);
96 }
97
98 return bgbox_type;
99 }
100
101 static void
gtk_bgbox_class_init(GtkBgboxClass * class)102 gtk_bgbox_class_init (GtkBgboxClass *class)
103 {
104 GObjectClass *object_class = G_OBJECT_CLASS (class);
105 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
106
107 parent_class = g_type_class_peek_parent (class);
108
109 widget_class->realize = gtk_bgbox_realize;
110 widget_class->size_request = gtk_bgbox_size_request;
111 widget_class->size_allocate = gtk_bgbox_size_allocate;
112 widget_class->style_set = gtk_bgbox_style_set;
113 widget_class->configure_event = gtk_bgbox_configure_event;
114 //widget_class->destroy_event = gtk_bgbox_destroy_event;
115 //widget_class->delete_event = gtk_bgbox_delete_event;
116
117 object_class->finalize = gtk_bgbox_finalize;
118 g_type_class_add_private (class, sizeof (GtkBgboxPrivate));
119 }
120
121 static void
gtk_bgbox_init(GtkBgbox * bgbox)122 gtk_bgbox_init (GtkBgbox *bgbox)
123 {
124 GtkBgboxPrivate *priv;
125
126 ENTER;
127 GTK_WIDGET_UNSET_FLAGS (bgbox, GTK_NO_WINDOW);
128
129 priv = GTK_BGBOX_GET_PRIVATE (bgbox);
130 priv->bg_type = BG_NONE;
131 priv->sid = 0;
132 RET();
133 }
134
135 GtkWidget*
gtk_bgbox_new(void)136 gtk_bgbox_new (void)
137 {
138 ENTER;
139 RET(g_object_new (GTK_TYPE_BGBOX, NULL));
140 }
141
142 static void
gtk_bgbox_finalize(GObject * object)143 gtk_bgbox_finalize (GObject *object)
144 {
145 GtkBgboxPrivate *priv;
146
147 ENTER;
148 priv = GTK_BGBOX_GET_PRIVATE(GTK_WIDGET(object));
149 if (priv->pixmap) {
150 g_object_unref(priv->pixmap);
151 priv->pixmap = NULL;
152 }
153 if (priv->sid) {
154 g_signal_handler_disconnect(priv->bg, priv->sid);
155 priv->sid = 0;
156 }
157 if (priv->bg) {
158 g_object_unref(priv->bg);
159 priv->bg = NULL;
160 }
161 RET();
162 }
163
164 static GdkFilterReturn
gtk_bgbox_event_filter(GdkXEvent * xevent,GdkEvent * event,GtkWidget * widget)165 gtk_bgbox_event_filter(GdkXEvent *xevent, GdkEvent *event, GtkWidget *widget)
166 {
167 XEvent *ev = (XEvent *) xevent;
168
169 ENTER;
170 if (ev->type == ConfigureNotify) {
171 gtk_widget_queue_draw(widget);
172 //gtk_bgbox_style_set(widget, NULL);
173 DBG("ConfigureNotify %d %d %d %d\n",
174 ev->xconfigure.x,
175 ev->xconfigure.y,
176 ev->xconfigure.width,
177 ev->xconfigure.height
178 );
179 }
180 RET(GDK_FILTER_CONTINUE);
181 }
182
183 static void
gtk_bgbox_realize(GtkWidget * widget)184 gtk_bgbox_realize (GtkWidget *widget)
185 {
186 GdkWindowAttr attributes;
187 gint attributes_mask;
188 gint border_width;
189 GtkBgboxPrivate *priv;
190
191 ENTER;
192 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
193
194 border_width = GTK_CONTAINER (widget)->border_width;
195
196 attributes.x = widget->allocation.x + border_width;
197 attributes.y = widget->allocation.y + border_width;
198 attributes.width = widget->allocation.width - 2*border_width;
199 attributes.height = widget->allocation.height - 2*border_width;
200 attributes.window_type = GDK_WINDOW_CHILD;
201 attributes.event_mask = gtk_widget_get_events (widget)
202 | GDK_BUTTON_MOTION_MASK
203 | GDK_BUTTON_PRESS_MASK
204 | GDK_BUTTON_RELEASE_MASK
205 | GDK_ENTER_NOTIFY_MASK
206 | GDK_LEAVE_NOTIFY_MASK
207 | GDK_EXPOSURE_MASK
208 | GDK_STRUCTURE_MASK;
209
210 priv = GTK_BGBOX_GET_PRIVATE (widget);
211
212 attributes.visual = gtk_widget_get_visual (widget);
213 attributes.colormap = gtk_widget_get_colormap (widget);
214 attributes.wclass = GDK_INPUT_OUTPUT;
215
216 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
217
218 widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
219 &attributes, attributes_mask);
220 gdk_window_set_user_data (widget->window, widget);
221 widget->style = gtk_style_attach (widget->style, widget->window);
222 if (priv->bg_type == BG_NONE)
223 gtk_bgbox_set_background(widget, BG_STYLE, 0, 0);
224 gdk_window_add_filter(widget->window, (GdkFilterFunc) gtk_bgbox_event_filter, widget);
225 RET();
226 }
227
228
229 static void
gtk_bgbox_style_set(GtkWidget * widget,GtkStyle * previous_style)230 gtk_bgbox_style_set (GtkWidget *widget, GtkStyle *previous_style)
231 {
232 GtkBgboxPrivate *priv;
233
234 ENTER;
235 priv = GTK_BGBOX_GET_PRIVATE (widget);
236 if (GTK_WIDGET_REALIZED (widget) && !GTK_WIDGET_NO_WINDOW (widget)) {
237 gtk_bgbox_set_background(widget, priv->bg_type, priv->tintcolor, priv->alpha);
238 }
239 RET();
240 }
241
242 /* gtk discards configure_event for GTK_WINDOW_CHILD. too pitty */
243 static gboolean
gtk_bgbox_configure_event(GtkWidget * widget,GdkEventConfigure * e)244 gtk_bgbox_configure_event (GtkWidget *widget, GdkEventConfigure *e)
245 {
246 ENTER;
247 DBG("geom: size (%d, %d). pos (%d, %d)\n", e->width, e->height, e->x, e->y);
248 RET(FALSE);
249
250 }
251
252 static void
gtk_bgbox_size_request(GtkWidget * widget,GtkRequisition * requisition)253 gtk_bgbox_size_request (GtkWidget *widget, GtkRequisition *requisition)
254 {
255 GtkBin *bin = GTK_BIN (widget);
256 ENTER;
257 requisition->width = GTK_CONTAINER (widget)->border_width * 2;
258 requisition->height = GTK_CONTAINER (widget)->border_width * 2;
259
260 if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
261 {
262 GtkRequisition child_requisition;
263
264 gtk_widget_size_request (bin->child, &child_requisition);
265
266 requisition->width += child_requisition.width;
267 requisition->height += child_requisition.height;
268 }
269 RET();
270 }
271
272 /* calls with same allocation are usually refer to exactly same background
273 * and we just skip them for optimization reason.
274 * so if you see artifacts or unupdated background - reallocate bg on every call
275 */
276 static void
gtk_bgbox_size_allocate(GtkWidget * widget,GtkAllocation * wa)277 gtk_bgbox_size_allocate (GtkWidget *widget, GtkAllocation *wa)
278 {
279 GtkBin *bin;
280 GtkAllocation ca;
281 GtkBgboxPrivate *priv;
282 int same_alloc, border;
283
284 ENTER;
285 same_alloc = !memcmp(&widget->allocation, wa, sizeof(*wa));
286 DBG("same alloc = %d\n", same_alloc);
287 DBG("x=%d y=%d w=%d h=%d\n", wa->x, wa->y, wa->width, wa->height);
288 DBG("x=%d y=%d w=%d h=%d\n", widget->allocation.x, widget->allocation.y,
289 widget->allocation.width, widget->allocation.height);
290 widget->allocation = *wa;
291 bin = GTK_BIN (widget);
292 border = GTK_CONTAINER (widget)->border_width;
293 ca.x = border;
294 ca.y = border;
295 ca.width = MAX (wa->width - border * 2, 0);
296 ca.height = MAX (wa->height - border * 2, 0);
297
298 if (GTK_WIDGET_REALIZED (widget) && !GTK_WIDGET_NO_WINDOW (widget)
299 && !same_alloc) {
300 priv = GTK_BGBOX_GET_PRIVATE (widget);
301 DBG("move resize pos=%d,%d geom=%dx%d\n", wa->x, wa->y, wa->width,
302 wa->height);
303 gdk_window_move_resize (widget->window, wa->x, wa->y, wa->width, wa->height);
304 gtk_bgbox_set_background(widget, priv->bg_type, priv->tintcolor, priv->alpha);
305 }
306
307 if (bin->child)
308 gtk_widget_size_allocate (bin->child, &ca);
309 RET();
310 }
311
312
313 static void
gtk_bgbox_bg_changed(FbBg * bg,GtkWidget * widget)314 gtk_bgbox_bg_changed(FbBg *bg, GtkWidget *widget)
315 {
316 GtkBgboxPrivate *priv;
317
318 ENTER;
319 priv = GTK_BGBOX_GET_PRIVATE (widget);
320 if (GTK_WIDGET_REALIZED (widget) && !GTK_WIDGET_NO_WINDOW (widget)) {
321 gtk_bgbox_set_background(widget, priv->bg_type, priv->tintcolor, priv->alpha);
322 }
323 RET();
324 }
325
326 void
gtk_bgbox_set_background(GtkWidget * widget,int bg_type,guint32 tintcolor,gint alpha)327 gtk_bgbox_set_background(GtkWidget *widget, int bg_type, guint32 tintcolor, gint alpha)
328 {
329 GtkBgboxPrivate *priv;
330
331 ENTER;
332 if (!(GTK_IS_BGBOX (widget)))
333 RET();
334
335 priv = GTK_BGBOX_GET_PRIVATE (widget);
336 DBG("widget=%p bg_type old:%d new:%d\n", widget, priv->bg_type, bg_type);
337 if (priv->pixmap) {
338 g_object_unref(priv->pixmap);
339 priv->pixmap = NULL;
340 }
341 priv->bg_type = bg_type;
342 if (priv->bg_type == BG_STYLE) {
343 gtk_style_set_background(widget->style, widget->window, widget->state);
344 if (priv->sid) {
345 g_signal_handler_disconnect(priv->bg, priv->sid);
346 priv->sid = 0;
347 }
348 if (priv->bg) {
349 g_object_unref(priv->bg);
350 priv->bg = NULL;
351 }
352 } else {
353 if (!priv->bg)
354 priv->bg = fb_bg_get_for_display();
355 if (!priv->sid)
356 priv->sid = g_signal_connect(G_OBJECT(priv->bg), "changed", G_CALLBACK(gtk_bgbox_bg_changed), widget);
357
358 if (priv->bg_type == BG_ROOT) {
359 priv->tintcolor = tintcolor;
360 priv->alpha = alpha;
361 gtk_bgbox_set_bg_root(widget, priv);
362 } else if (priv->bg_type == BG_INHERIT) {
363 gtk_bgbox_set_bg_inherit(widget, priv);
364 }
365 }
366 gtk_widget_queue_draw(widget);
367 g_object_notify(G_OBJECT (widget), "style");
368
369 DBG("queue draw all %p\n", widget);
370 RET();
371 }
372
373 static void
gtk_bgbox_set_bg_root(GtkWidget * widget,GtkBgboxPrivate * priv)374 gtk_bgbox_set_bg_root(GtkWidget *widget, GtkBgboxPrivate *priv)
375 {
376 priv = GTK_BGBOX_GET_PRIVATE (widget);
377
378 ENTER;
379 priv->pixmap = fb_bg_get_xroot_pix_for_win(priv->bg, widget);
380 if (!priv->pixmap || priv->pixmap == GDK_NO_BG) {
381 //priv->bg_type = BG_NONE;
382 priv->pixmap = NULL;
383 gtk_style_set_background(widget->style, widget->window, widget->state);
384 gtk_widget_queue_draw_area(widget, 0, 0,
385 widget->allocation.width, widget->allocation.height);
386 DBG("no root pixmap was found\n");
387 RET();
388 }
389 if (priv->alpha)
390 fb_bg_composite(priv->pixmap, widget->style->black_gc,
391 priv->tintcolor, priv->alpha);
392 gdk_window_set_back_pixmap(widget->window, priv->pixmap, FALSE);
393 RET();
394 }
395
396 static void
gtk_bgbox_set_bg_inherit(GtkWidget * widget,GtkBgboxPrivate * priv)397 gtk_bgbox_set_bg_inherit(GtkWidget *widget, GtkBgboxPrivate *priv)
398 {
399 priv = GTK_BGBOX_GET_PRIVATE (widget);
400
401 ENTER;
402 gdk_window_set_back_pixmap(widget->window, NULL, TRUE);
403 RET();
404 }
405