1
/* sand-window.gob - Sand window widget implementation
3
* Copyright (C) 1999, 2000 Jochen Voss.
5
* $Id: sand-window.gob,v 1.10 2002/01/12 14:12:49 voss Rel $ */
9
#include <libgnomeui/gnome-canvas.h>
14
#include "../pixmaps/icon24.xbm"
17
mask_get_value (unsigned char *source, int width, int height, int i, int j)
19
int jj = j+0.5*ABS(width/2-i);
21
if (jj >= height) return 0;
22
return source[jj*width+i]/255.0;
26
mask_set_value (unsigned char *target, unsigned char *source, double x,
27
int width, int height, int i, int j)
29
int jj = j+0.5*ABS(width/2-i);
31
if (jj >= height) return;
32
target[jj*width+i] = x*source[jj*width+i];
36
class Sand:Window from Gtk:Window {
40
public gboolean decorations;
41
argument BOOL decorations
42
set { self->decorations = ARG; set_decorations (self); }
43
get { ARG = self->decorations; };
45
public GnomeWinLayer layer = WIN_LAYER_NORMAL;
47
public GtkWidget *canvas;
48
public GnomeCanvasItem *back;
49
public GnomeCanvasItem *front;
50
public GnomeCanvasItem *mid;
51
public GdkImlibImage *sand;
53
public guint8 r; /* The sand's color */
57
public double ratio; /* The elapsed time: 0.0=start, 1.0=end */
59
protected unsigned char *mask;
62
protected double fill;
65
/**********************************************************************
66
* widget class implementation
70
create_shape (self, int image_width, int image_height)
78
/* Create the initial mask and clear it */
79
mask = gdk_pixmap_new (GTK_WIDGET (self)->window,
80
image_width, image_height, 1);
82
mgc = gdk_gc_new (mask);
84
gdk_gc_set_foreground (mgc, &c);
85
gdk_draw_rectangle (mask, mgc, TRUE, 0, 0, image_width, image_height);
88
gdk_gc_set_foreground (mgc, &c);
90
/* Paint the mask of the image */
91
im = GNOME_CANVAS_IMAGE (self->back)->im;
92
gdk_imlib_render (im, image_width, image_height);
93
im_mask = gdk_imlib_move_mask (im);
96
gdk_draw_pixmap (mask, mgc, im_mask,
97
0, 0, 0, 0, image_width, image_height);
98
gdk_imlib_free_bitmap (im_mask);
100
gdk_draw_rectangle (mask, mgc, TRUE,
101
0, 0, image_width, image_height);
104
if (!GTK_WIDGET_REALIZED (self))
105
gtk_widget_realize (GTK_WIDGET (self));
107
gtk_widget_shape_combine_mask (GTK_WIDGET (self), mask, 0, 0);
108
gdk_bitmap_unref (mask);
112
override (Gtk:Widget) void
113
size_request (GtkWidget *widget (check null), GtkRequisition *requisition)
118
self = SAND_WINDOW (widget);
120
/* Get size of icon image */
121
args[0].name = "width";
122
args[1].name = "height";
123
gtk_object_getv (GTK_OBJECT (self->back), 2, args);
124
requisition->width = GTK_VALUE_DOUBLE (args[0]);
125
requisition->height = GTK_VALUE_DOUBLE (args[1]);
129
drop_handler (GtkWidget *widget,
130
GdkDragContext *context,
133
GtkSelectionData *selection_data,
138
SandWindow *sand_window = SAND_WINDOW (widget);
142
if (selection_data->length < 0) return;
144
if ((selection_data->format != 16) || (selection_data->length != 8)) {
145
g_warning ("Received invalid color data");
149
vals = (guint16 *)selection_data->data;
151
r = (gdouble)vals[0] / 0xffff;
152
g = (gdouble)vals[1] / 0xffff;
153
b = (gdouble)vals[2] / 0xffff;
155
set_color (sand_window, r*255, g*255, b*255);
158
override (Gtk:Widget) void
159
realize (GtkWidget *widget (check null))
162
static const GtkTargetEntry targets[] = {
163
{ "application/x-color", 0 }
166
g_return_if_fail (SAND_IS_WINDOW (widget));
168
PARENT_HANDLER (widget);
170
/* Set the proper GNOME hints */
171
gnome_win_hints_init ();
172
icon = gdk_bitmap_create_from_data (widget->window, icon24_bits,
173
icon24_width, icon24_height);
174
gdk_window_set_icon (widget->window, NULL, icon, NULL);
175
gdk_window_set_functions (widget->window, GDK_FUNC_MOVE|GDK_FUNC_CLOSE);
176
set_decorations (SAND_WINDOW (widget));
177
if (gnome_win_hints_wm_exists ()) {
178
gnome_win_hints_set_hints(widget, WIN_HINTS_DO_NOT_COVER);
179
gnome_win_hints_set_layer (widget, SAND_WINDOW (widget)->layer);
182
gtk_drag_dest_set (widget, GTK_DEST_DEFAULT_ALL,
183
targets, 1, GDK_ACTION_COPY);
185
gtk_signal_connect (GTK_OBJECT (widget),
186
"drag_data_received",
187
GTK_SIGNAL_FUNC (drop_handler),
192
size_allocate_handler (GtkWidget *widget, GtkAllocation *allocation,
197
self = SAND_WINDOW (widget);
198
gnome_canvas_set_scroll_region (GNOME_CANVAS(self->canvas),
200
allocation->width, allocation->height);
201
create_shape (self, allocation->width, allocation->height);
206
GdkImlibImage *back, *sand, *front;
208
/* Set the window policy */
209
gtk_window_set_policy (GTK_WINDOW (swindow), FALSE, FALSE, TRUE);
210
gtk_window_set_wmclass (GTK_WINDOW (swindow),
211
"sandUhrTimer", "SandUhrTimer");
213
/* Create the canvas */
214
gtk_widget_push_visual (gdk_rgb_get_visual ());
215
gtk_widget_push_colormap (gdk_rgb_get_cmap ());
216
swindow->canvas = gnome_canvas_new_aa ();
217
gtk_widget_pop_colormap ();
218
gtk_widget_pop_visual ();
220
gtk_container_add (GTK_CONTAINER (swindow), swindow->canvas);
221
gtk_widget_show (swindow->canvas);
223
/* Create the image items */
224
fname = get_pixmap_file ("back.png");
225
back = gdk_imlib_load_image (fname);
228
= gnome_canvas_item_new(gnome_canvas_root(GNOME_CANVAS(swindow->canvas)),
229
gnome_canvas_image_get_type (),
231
"width", (double) back->rgb_width,
232
"height", (double) back->rgb_height,
233
"anchor", GTK_ANCHOR_NW,
236
fname = get_pixmap_file ("mask.png");
237
sand = gnome_canvas_load_alpha (fname);
239
swindow->sand = sand;
240
swindow->mask = g_malloc (sand->rgb_width*sand->rgb_height);
241
memcpy (swindow->mask, sand->alpha_data, sand->rgb_width*sand->rgb_height);
244
= gnome_canvas_item_new (gnome_canvas_root (GNOME_CANVAS(swindow->canvas)),
245
gnome_canvas_image_get_type (),
247
"width", (double) sand->rgb_width,
248
"height", (double) sand->rgb_height,
249
"anchor", GTK_ANCHOR_NW,
252
fname = get_pixmap_file ("front.png");
253
front = gnome_canvas_load_alpha (fname);
256
= gnome_canvas_item_new(gnome_canvas_root(GNOME_CANVAS(swindow->canvas)),
257
gnome_canvas_image_get_type (),
258
"anchor", GTK_ANCHOR_NW,
260
"width", (double) front->rgb_width,
261
"height", (double) front->rgb_height,
264
gtk_signal_connect (GTK_OBJECT (swindow), "size_allocate",
265
(GtkSignalFunc) size_allocate_handler,
268
swindow->ratio = 0.0;
273
swindow->decorations = FALSE;
276
override (Gtk:Object) void
277
destroy (GtkObject *object (check null))
281
self = SAND_WINDOW (object);
284
PARENT_HANDLER (object);
292
ret = GTK_WIDGET (GET_NEW);
296
/**********************************************************************
297
* window manager interaction
301
set_decorations (self)
303
GtkWidget *widget = GTK_WIDGET (self);
304
gboolean fix_broken_wm;
307
if (! GTK_WIDGET_REALIZED (self)) return;
309
/* work around broken window managers */
310
fix_broken_wm = GTK_WIDGET_MAPPED (self);
312
gdk_window_get_position (widget->window, &x, &y);
313
gdk_window_hide (widget->window);
316
if (self->decorations) {
317
gdk_window_set_decorations (widget->window, GDK_DECOR_TITLE);
319
gdk_window_set_decorations (widget->window, 0);
323
gdk_window_show (widget->window);
324
gdk_window_move (widget->window, x, y);
331
if (gnome_win_hints_wm_exists ()) {
332
return gnome_win_hints_get_layer (GTK_WIDGET(self));
338
set_layer (self, GnomeWinLayer layer)
341
if (GTK_WIDGET_REALIZED (self) && gnome_win_hints_wm_exists ()) {
342
gnome_win_hints_set_layer (GTK_WIDGET(self), layer);
346
/**********************************************************************
351
init_color (self, guint8 r, guint8 g, guint8 b)
352
/* Set the sand color to the RGB value (R,G,B). */
354
GdkImlibImage *sand = self->sand;
357
for (i=0; i<sand->rgb_width*sand->rgb_height; ++i) {
358
sand->rgb_data [3*i] = r;
359
sand->rgb_data [3*i+1] = g;
360
sand->rgb_data [3*i+2] = b;
365
set_mask (self, double q)
367
GdkImlibImage *sand = self->sand;
368
int width = sand->rgb_width;
369
int height = sand->rgb_height;
373
if (! self->mask) return;
377
rest = self->A-(1-q)*self->fill;
378
for (j=0; j<height/2; ++j) {
382
/* row is completely filled */
383
for (i=0; i<width; ++i) {
384
sand->alpha_data[j*width+i] = self->mask[j*width+i];
387
for (i=0; i<width; ++i) current += self->mask[j*width+i]/255.0;
390
/* row is partially filled */
391
double x = (a - rest)/current;
392
for (i=0; i<width; ++i) {
393
sand->alpha_data[j*width+i] = x*self->mask[j*width+i];
396
/* row is completely empty */
397
for (i=0; i<width; ++i) {
398
sand->alpha_data[j*width+i] = 0;
406
rest = self->B-q*self->fill;
407
for (j=height/2; j<height; ++j) {
411
/* row is completely filled */
412
for (i=0; i<width; ++i) {
413
mask_set_value (sand->alpha_data, self->mask, 1,
414
width, height, i, j);
417
for (i=0; i<width; ++i) {
418
current += mask_get_value (self->mask, width, height, i, j);
422
/* row is partially filled */
423
double x = (a - rest)/current;
424
for (i=0; i<width; ++i) {
425
mask_set_value (sand->alpha_data, self->mask, x,
426
width, height, i, j);
429
/* row is completely empty */
430
for (i=0; i<width; ++i) {
431
mask_set_value (sand->alpha_data, self->mask, 0,
432
width, height, i, j);
434
if (q<0.995) sand->alpha_data[j*width+width/2] = 48;
443
gtk_object_set (GTK_OBJECT (self->mid),
451
init_color (self, self->r, self->g, self->b);
452
set_mask (self, self->ratio);
459
GdkImlibImage *sand = self->sand;
460
double A=0, B=0, fill;
463
g_assert (self->mask);
464
init_color (self, self->r, self->g, self->b);
466
mid = sand->rgb_height/2;
467
for (i=0; i<sand->rgb_width*mid; ++i) {
468
A += self->mask [i]/255.0;
470
for (i=sand->rgb_width*mid; i<sand->rgb_width*sand->rgb_height; ++i) {
471
B += self->mask [i]/255.0;
475
g_assert (fill >= 50);
480
/* TODO: do the remaining stuff */
485
/**********************************************************************
490
get_color (self, guint8 *r, guint8 *g, guint8 *b)
498
set_color (self, guint8 r, guint8 g, guint8 b)
507
flood (self, double q)