Bug 792688 - Failed mail print operation causes crash
[evolution.git] / src / libgnomecanvas / gnome-canvas-widget.c
blob7593970eb355d892a984af9d8e3d0e2d174e5f28
1 /*
2 * Copyright (C) 1997, 1998, 1999, 2000 Free Software Foundation
3 * All rights reserved.
5 * This file is part of the Gnome Library.
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU Lesser General Public License as published by
9 * published by the Free Software Foundation; either the
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * License along with the Gnome Library; see the file COPYING.LIB. If not,
20 @NOTATION@
22 /* Widget item type for GnomeCanvas widget
24 * GnomeCanvas is basically a port of the Tk toolkit's most excellent canvas
25 * widget. Tk is copyrighted by the Regents of the University of California,
26 * Sun Microsystems, and other parties.
29 * Author: Federico Mena <federico@nuclecu.unam.mx>
32 #include "evolution-config.h"
34 #include <math.h>
35 #include "gnome-canvas-widget.h"
37 enum {
38 PROP_0,
39 PROP_WIDGET,
40 PROP_X,
41 PROP_Y,
42 PROP_WIDTH,
43 PROP_HEIGHT,
44 PROP_SIZE_PIXELS
47 static void gnome_canvas_widget_dispose (GnomeCanvasItem *object);
48 static void gnome_canvas_widget_get_property (GObject *object,
49 guint param_id,
50 GValue *value,
51 GParamSpec *pspec);
52 static void gnome_canvas_widget_set_property (GObject *object,
53 guint param_id,
54 const GValue *value,
55 GParamSpec *pspec);
57 static void gnome_canvas_widget_update (GnomeCanvasItem *item,
58 const cairo_matrix_t *matrix,
59 gint flags);
60 static GnomeCanvasItem *gnome_canvas_widget_point (GnomeCanvasItem *item,
61 gdouble x,
62 gdouble y,
63 gint cx,
64 gint cy);
65 static void gnome_canvas_widget_bounds (GnomeCanvasItem *item,
66 gdouble *x1,
67 gdouble *y1,
68 gdouble *x2,
69 gdouble *y2);
71 static void gnome_canvas_widget_draw (GnomeCanvasItem *item,
72 cairo_t *cr,
73 gint x,
74 gint y,
75 gint width,
76 gint height);
78 G_DEFINE_TYPE (
79 GnomeCanvasWidget,
80 gnome_canvas_widget,
81 GNOME_TYPE_CANVAS_ITEM)
83 static void
84 gnome_canvas_widget_class_init (GnomeCanvasWidgetClass *class)
86 GObjectClass *gobject_class;
87 GnomeCanvasItemClass *item_class;
89 gobject_class = (GObjectClass *) class;
90 item_class = (GnomeCanvasItemClass *) class;
92 gobject_class->set_property = gnome_canvas_widget_set_property;
93 gobject_class->get_property = gnome_canvas_widget_get_property;
95 g_object_class_install_property
96 (gobject_class,
97 PROP_WIDGET,
98 g_param_spec_object ("widget", NULL, NULL,
99 GTK_TYPE_WIDGET,
100 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
101 g_object_class_install_property
102 (gobject_class,
103 PROP_X,
104 g_param_spec_double ("x", NULL, NULL,
105 -G_MAXDOUBLE, G_MAXDOUBLE, 0.0,
106 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
107 g_object_class_install_property
108 (gobject_class,
109 PROP_Y,
110 g_param_spec_double ("y", NULL, NULL,
111 -G_MAXDOUBLE, G_MAXDOUBLE, 0.0,
112 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
113 g_object_class_install_property
114 (gobject_class,
115 PROP_WIDTH,
116 g_param_spec_double ("width", NULL, NULL,
117 -G_MAXDOUBLE, G_MAXDOUBLE, 0.0,
118 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
119 g_object_class_install_property
120 (gobject_class,
121 PROP_HEIGHT,
122 g_param_spec_double ("height", NULL, NULL,
123 -G_MAXDOUBLE, G_MAXDOUBLE, 0.0,
124 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
125 g_object_class_install_property
126 (gobject_class,
127 PROP_SIZE_PIXELS,
128 g_param_spec_boolean ("size_pixels", NULL, NULL,
129 FALSE,
130 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
132 item_class->dispose = gnome_canvas_widget_dispose;
133 item_class->update = gnome_canvas_widget_update;
134 item_class->point = gnome_canvas_widget_point;
135 item_class->bounds = gnome_canvas_widget_bounds;
136 item_class->draw = gnome_canvas_widget_draw;
139 static void
140 do_destroy (gpointer data,
141 GObject *gone_object)
143 GnomeCanvasWidget *witem;
145 witem = data;
147 if (!witem->in_destroy) {
148 witem->in_destroy = TRUE;
149 g_object_run_dispose (G_OBJECT (witem));
153 static void
154 gnome_canvas_widget_init (GnomeCanvasWidget *witem)
156 witem->x = 0.0;
157 witem->y = 0.0;
158 witem->width = 0.0;
159 witem->height = 0.0;
160 witem->size_pixels = FALSE;
163 static void
164 gnome_canvas_widget_dispose (GnomeCanvasItem *object)
166 GnomeCanvasWidget *witem;
168 g_return_if_fail (object != NULL);
169 g_return_if_fail (GNOME_IS_CANVAS_WIDGET (object));
171 witem = GNOME_CANVAS_WIDGET (object);
173 if (witem->widget && !witem->in_destroy) {
174 g_object_weak_unref (G_OBJECT (witem->widget), do_destroy, witem);
175 gtk_widget_destroy (witem->widget);
176 witem->widget = NULL;
179 GNOME_CANVAS_ITEM_CLASS (gnome_canvas_widget_parent_class)->
180 dispose (object);
183 static gboolean
184 reposition_widget_cb (gpointer user_data)
186 GnomeCanvasWidget *witem = user_data;
188 g_return_val_if_fail (GNOME_IS_CANVAS_WIDGET (witem), FALSE);
190 if (witem->widget)
191 gtk_widget_queue_resize (witem->widget);
193 return FALSE;
196 static void
197 recalc_bounds (GnomeCanvasWidget *witem)
199 GnomeCanvasItem *item;
200 gdouble wx, wy;
202 item = GNOME_CANVAS_ITEM (witem);
204 /* Get world coordinates */
206 wx = witem->x;
207 wy = witem->y;
208 gnome_canvas_item_i2w (item, &wx, &wy);
210 /* Get canvas pixel coordinates */
212 gnome_canvas_w2c (item->canvas, wx, wy, &witem->cx, &witem->cy);
214 /* Bounds */
216 item->x1 = witem->cx;
217 item->y1 = witem->cy;
218 item->x2 = witem->cx + witem->cwidth;
219 item->y2 = witem->cy + witem->cheight;
221 if (witem->widget) {
222 gint current_x = 0, current_y = 0;
224 gtk_container_child_get (GTK_CONTAINER (item->canvas), witem->widget,
225 "x", &current_x,
226 "y", &current_y,
227 NULL);
229 if (current_x != ((gint) (witem->cx + item->canvas->zoom_xofs)) ||
230 current_y != ((gint) (witem->cy + item->canvas->zoom_yofs))) {
231 gtk_layout_move (
232 GTK_LAYOUT (item->canvas), witem->widget,
233 witem->cx + item->canvas->zoom_xofs,
234 witem->cy + item->canvas->zoom_yofs);
236 /* This is needed, because the gtk_layout_move() calls gtk_widget_queue_resize(),
237 which can be silently ignored when called inside "size-allocate" handler, causing
238 misposition of the child widget. */
239 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
240 reposition_widget_cb, g_object_ref (witem), g_object_unref);
245 static void
246 gnome_canvas_widget_set_property (GObject *object,
247 guint param_id,
248 const GValue *value,
249 GParamSpec *pspec)
251 GnomeCanvasItem *item;
252 GnomeCanvasWidget *witem;
253 GObject *obj;
254 gint update;
255 gint calc_bounds;
257 g_return_if_fail (object != NULL);
258 g_return_if_fail (GNOME_IS_CANVAS_WIDGET (object));
260 item = GNOME_CANVAS_ITEM (object);
261 witem = GNOME_CANVAS_WIDGET (object);
263 update = FALSE;
264 calc_bounds = FALSE;
266 switch (param_id) {
267 case PROP_WIDGET:
268 if (witem->widget) {
269 g_object_weak_unref (G_OBJECT (witem->widget), do_destroy, witem);
270 gtk_container_remove (GTK_CONTAINER (item->canvas), witem->widget);
273 obj = g_value_get_object (value);
274 if (obj) {
275 witem->widget = GTK_WIDGET (obj);
276 g_object_weak_ref (obj, do_destroy, witem);
277 gtk_layout_put (
278 GTK_LAYOUT (item->canvas), witem->widget,
279 witem->cx + item->canvas->zoom_xofs,
280 witem->cy + item->canvas->zoom_yofs);
283 update = TRUE;
284 break;
286 case PROP_X:
287 if (witem->x != g_value_get_double (value))
289 witem->x = g_value_get_double (value);
290 calc_bounds = TRUE;
292 break;
294 case PROP_Y:
295 if (witem->y != g_value_get_double (value))
297 witem->y = g_value_get_double (value);
298 calc_bounds = TRUE;
300 break;
302 case PROP_WIDTH:
303 if (witem->width != fabs (g_value_get_double (value)))
305 witem->width = fabs (g_value_get_double (value));
306 update = TRUE;
308 break;
310 case PROP_HEIGHT:
311 if (witem->height != fabs (g_value_get_double (value)))
313 witem->height = fabs (g_value_get_double (value));
314 update = TRUE;
316 break;
318 case PROP_SIZE_PIXELS:
319 if (witem->size_pixels != g_value_get_boolean (value))
321 witem->size_pixels = g_value_get_boolean (value);
322 update = TRUE;
324 break;
326 default:
327 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
328 break;
331 if (update)
332 (* GNOME_CANVAS_ITEM_GET_CLASS (item)->update) (item, NULL, 0);
334 if (calc_bounds)
335 recalc_bounds (witem);
338 static void
339 gnome_canvas_widget_get_property (GObject *object,
340 guint param_id,
341 GValue *value,
342 GParamSpec *pspec)
344 GnomeCanvasWidget *witem;
346 g_return_if_fail (object != NULL);
347 g_return_if_fail (GNOME_IS_CANVAS_WIDGET (object));
349 witem = GNOME_CANVAS_WIDGET (object);
351 switch (param_id) {
352 case PROP_WIDGET:
353 g_value_set_object (value, (GObject *) witem->widget);
354 break;
356 case PROP_X:
357 g_value_set_double (value, witem->x);
358 break;
360 case PROP_Y:
361 g_value_set_double (value, witem->y);
362 break;
364 case PROP_WIDTH:
365 g_value_set_double (value, witem->width);
366 break;
368 case PROP_HEIGHT:
369 g_value_set_double (value, witem->height);
370 break;
372 case PROP_SIZE_PIXELS:
373 g_value_set_boolean (value, witem->size_pixels);
374 break;
376 default:
377 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
378 break;
382 static void
383 gnome_canvas_widget_update (GnomeCanvasItem *item,
384 const cairo_matrix_t *matrix,
385 gint flags)
387 GnomeCanvasWidget *witem;
389 witem = GNOME_CANVAS_WIDGET (item);
391 GNOME_CANVAS_ITEM_CLASS (gnome_canvas_widget_parent_class)->
392 update (item, matrix, flags);
394 if (witem->widget) {
395 witem->cwidth = (gint) (witem->width + 0.5);
396 witem->cheight = (gint) (witem->height + 0.5);
398 gtk_widget_set_size_request (witem->widget, witem->cwidth, witem->cheight);
399 } else {
400 witem->cwidth = 0.0;
401 witem->cheight = 0.0;
404 recalc_bounds (witem);
407 static void
408 gnome_canvas_widget_draw (GnomeCanvasItem *item,
409 cairo_t *cr,
410 gint x,
411 gint y,
412 gint width,
413 gint height)
415 #if 0
416 GnomeCanvasWidget *witem;
418 witem = GNOME_CANVAS_WIDGET (item);
420 if (witem->widget)
421 gtk_widget_queue_draw (witem->widget);
422 #endif
425 static GnomeCanvasItem *
426 gnome_canvas_widget_point (GnomeCanvasItem *item,
427 gdouble x,
428 gdouble y,
429 gint cx,
430 gint cy)
432 GnomeCanvasWidget *witem;
433 gdouble x1, y1, x2, y2;
435 witem = GNOME_CANVAS_WIDGET (item);
437 gnome_canvas_c2w (item->canvas, witem->cx, witem->cy, &x1, &y1);
439 x2 = x1 + (witem->cwidth - 1);
440 y2 = y1 + (witem->cheight - 1);
442 /* Is point inside widget bounds? */
444 if ((x >= x1) && (y >= y1) && (x <= x2) && (y <= y2))
445 return item;
447 /* Point is outside widget bounds */
448 return NULL;
451 static void
452 gnome_canvas_widget_bounds (GnomeCanvasItem *item,
453 gdouble *x1,
454 gdouble *y1,
455 gdouble *x2,
456 gdouble *y2)
458 GnomeCanvasWidget *witem;
460 witem = GNOME_CANVAS_WIDGET (item);
462 *x1 = witem->x;
463 *y1 = witem->y;
465 *x2 = *x1 + witem->width;
466 *y2 = *y1 + witem->height;