evolution-3.6.4/widgets/misc/e-canvas.c

Location Tool Test ID Function Issue
e-canvas.c:711:6 clang-analyzer Access to field 'flags' results in a dereference of a null pointer (loaded from variable 'item')
e-canvas.c:711:6 clang-analyzer Access to field 'flags' results in a dereference of a null pointer (loaded from variable 'item')
  1 /*
  2  * This program is free software; you can redistribute it and/or
  3  * modify it under the terms of the GNU Lesser General Public
  4  * License as published by the Free Software Foundation; either
  5  * version 2 of the License, or (at your option) version 3.
  6  *
  7  * This program is distributed in the hope that it will be useful,
  8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 10  * Lesser General Public License for more details.
 11  *
 12  * You should have received a copy of the GNU Lesser General Public
 13  * License along with the program; if not, see <http://www.gnu.org/licenses/>
 14  *
 15  *
 16  * Authors:
 17  *		Chris Lahey <clahey@ximian.com>
 18  *
 19  * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 20  *
 21  */
 22 
 23 #ifdef HAVE_CONFIG_H
 24 #include <config.h>
 25 #endif
 26 
 27 #include <gtk/gtk.h>
 28 
 29 #include "e-util/e-util.h"
 30 
 31 #include "e-canvas.h"
 32 
 33 #define d(x)
 34 
 35 enum {
 36 	REFLOW,
 37 	LAST_SIGNAL
 38 };
 39 
 40 static guint signals[LAST_SIGNAL];
 41 
 42 G_DEFINE_TYPE (
 43 	ECanvas,
 44 	e_canvas,
 45 	GNOME_TYPE_CANVAS)
 46 
 47 /* Emits an event for an item in the canvas, be it the current
 48  * item, grabbed item, or focused item, as appropriate. */
 49 static gint
 50 canvas_emit_event (GnomeCanvas *canvas,
 51                    GdkEvent *event)
 52 {
 53 	GdkEvent *ev;
 54 	gint finished;
 55 	GnomeCanvasItem *item;
 56 	GnomeCanvasItem *parent;
 57 	guint mask;
 58 
 59 	/* Choose where we send the event */
 60 
 61 	item = canvas->current_item;
 62 
 63 	if (canvas->focused_item &&
 64 		((event->type == GDK_KEY_PRESS) ||
 65 		 (event->type == GDK_KEY_RELEASE) ||
 66 		 (event->type == GDK_FOCUS_CHANGE)))
 67 		item = canvas->focused_item;
 68 
 69 	if (canvas->grabbed_item)
 70 		item = canvas->grabbed_item;
 71 
 72 	/* Perform checks for grabbed items */
 73 
 74 	if (canvas->grabbed_item) {
 75 		switch (event->type) {
 76 			case GDK_ENTER_NOTIFY:
 77 				mask = GDK_ENTER_NOTIFY_MASK;
 78 				break;
 79 
 80 			case GDK_LEAVE_NOTIFY:
 81 				mask = GDK_LEAVE_NOTIFY_MASK;
 82 				break;
 83 
 84 			case GDK_MOTION_NOTIFY:
 85 				mask = GDK_POINTER_MOTION_MASK;
 86 				break;
 87 
 88 			case GDK_BUTTON_PRESS:
 89 			case GDK_2BUTTON_PRESS:
 90 			case GDK_3BUTTON_PRESS:
 91 				mask = GDK_BUTTON_PRESS_MASK;
 92 				break;
 93 
 94 			case GDK_BUTTON_RELEASE:
 95 				mask = GDK_BUTTON_RELEASE_MASK;
 96 				break;
 97 
 98 			case GDK_KEY_PRESS:
 99 				mask = GDK_KEY_PRESS_MASK;
100 				break;
101 
102 			case GDK_KEY_RELEASE:
103 				mask = GDK_KEY_RELEASE_MASK;
104 				break;
105 
106 			default:
107 				mask = 0;
108 				break;
109 		}
110 
111 		if (!(mask & canvas->grabbed_event_mask))
112 			return FALSE;
113 	}
114 
115 	/* Convert to world coordinates -- we have two cases because of
116 	 * different offsets of the fields in the event structures. */
117 
118 	ev = gdk_event_copy (event);
119 
120 	switch (ev->type) {
121 		case GDK_ENTER_NOTIFY:
122 		case GDK_LEAVE_NOTIFY:
123 			gnome_canvas_window_to_world (
124 				canvas,
125 				ev->crossing.x, ev->crossing.y,
126 				&ev->crossing.x, &ev->crossing.y);
127 			break;
128 
129 		case GDK_MOTION_NOTIFY:
130 		case GDK_BUTTON_PRESS:
131 		case GDK_2BUTTON_PRESS:
132 		case GDK_3BUTTON_PRESS:
133 		case GDK_BUTTON_RELEASE:
134 			gnome_canvas_window_to_world (
135 				canvas,
136 				ev->motion.x, ev->motion.y,
137 				&ev->motion.x, &ev->motion.y);
138 			break;
139 
140 		default:
141 			break;
142 	}
143 
144 	/* The event is propagated up the hierarchy (for if someone connected
145 	 * to a group instead of a leaf event), and emission is stopped if a
146 	 * handler returns TRUE, just like for GtkWidget events. */
147 
148 	finished = FALSE;
149 
150 	while (item && !finished) {
151 		g_object_ref (item);
152 
153 		g_signal_emit_by_name (item, "event", ev, &finished);
154 
155 		parent = item->parent;
156 		g_object_unref (item);
157 
158 		item = parent;
159 	}
160 
161 	gdk_event_free (ev);
162 
163 	return finished;
164 }
165 
166 /* This routine invokes the point method of the item.  The argument x, y
167  * should be in the parent's item-relative coordinate system.  This routine
168  * applies the inverse of the item's transform, maintaining the affine
169  * invariant. */
170 static GnomeCanvasItem *
171 gnome_canvas_item_invoke_point (GnomeCanvasItem *item,
172                                 gdouble x,
173                                 gdouble y,
174                                 gint cx,
175                                 gint cy)
176 {
177 	cairo_matrix_t inverse;
178 
179 	/* Calculate x & y in item local coordinates */
180 	inverse = item->matrix;
181 	if (cairo_matrix_invert (&inverse) != CAIRO_STATUS_SUCCESS)
182 		return NULL;
183 
184 	cairo_matrix_transform_point (&inverse, &x, &y);
185 
186 	if (GNOME_CANVAS_ITEM_GET_CLASS (item)->point)
187 		return GNOME_CANVAS_ITEM_GET_CLASS (item)->point (item, x, y, cx, cy);
188 
189 	return NULL;
190 }
191 
192 /* Re-picks the current item in the canvas, based on the event's coordinates.
193  * Also emits enter/leave events for items as appropriate.
194  */
195 #define DISPLAY_X1(canvas) (GNOME_CANVAS (canvas)->layout.xoffset)
196 #define DISPLAY_Y1(canvas) (GNOME_CANVAS (canvas)->layout.yoffset)
197 static gint
198 pick_current_item (GnomeCanvas *canvas,
199                    GdkEvent *event)
200 {
201 	gint button_down;
202 	gdouble x, y;
203 	gint cx, cy;
204 	gint retval;
205 
206 	retval = FALSE;
207 
208 	/* If a button is down, we'll perform enter and leave events on the
209 	 * current item, but not enter on any other item.  This is more or less
210 	 * like X pointer grabbing for canvas items.
211 	 */
212 	button_down = canvas->state & (GDK_BUTTON1_MASK
213 				       | GDK_BUTTON2_MASK
214 				       | GDK_BUTTON3_MASK
215 				       | GDK_BUTTON4_MASK
216 				       | GDK_BUTTON5_MASK);
217 	if (!button_down)
218 		canvas->left_grabbed_item = FALSE;
219 
220 	/* Save the event in the canvas.  This is used to synthesize enter and
221 	 * leave events in case the current item changes.  It is also used to
222 	 * re-pick the current item if the current one gets deleted.  Also,
223 	 * synthesize an enter event.
224 	 */
225 	if (event != &canvas->pick_event) {
226 		if ((event->type == GDK_MOTION_NOTIFY) ||
227 		    (event->type == GDK_BUTTON_RELEASE)) {
228 			/* these fields have the same offsets in both types of events */
229 
230 			canvas->pick_event.crossing.type       = GDK_ENTER_NOTIFY;
231 			canvas->pick_event.crossing.window     = event->motion.window;
232 			canvas->pick_event.crossing.send_event = event->motion.send_event;
233 			canvas->pick_event.crossing.subwindow  = NULL;
234 			canvas->pick_event.crossing.x          = event->motion.x;
235 			canvas->pick_event.crossing.y          = event->motion.y;
236 			canvas->pick_event.crossing.mode       = GDK_CROSSING_NORMAL;
237 			canvas->pick_event.crossing.detail     = GDK_NOTIFY_NONLINEAR;
238 			canvas->pick_event.crossing.focus      = FALSE;
239 			canvas->pick_event.crossing.state      = event->motion.state;
240 
241 			/* these fields don't have the same offsets in both types of events */
242 
243 			if (event->type == GDK_MOTION_NOTIFY) {
244 				canvas->pick_event.crossing.x_root = event->motion.x_root;
245 				canvas->pick_event.crossing.y_root = event->motion.y_root;
246 			} else {
247 				canvas->pick_event.crossing.x_root = event->button.x_root;
248 				canvas->pick_event.crossing.y_root = event->button.y_root;
249 			}
250 		} else
251 			canvas->pick_event = *event;
252 	}
253 
254 	/* Don't do anything else if this is a recursive call */
255 
256 	if (canvas->in_repick)
257 		return retval;
258 
259 	/* LeaveNotify means that there is no current item, so we don't look for one */
260 
261 	if (canvas->pick_event.type != GDK_LEAVE_NOTIFY) {
262 		/* these fields don't have the same offsets in both types of events */
263 
264 		if (canvas->pick_event.type == GDK_ENTER_NOTIFY) {
265 			x = canvas->pick_event.crossing.x +
266 				canvas->scroll_x1 - canvas->zoom_xofs;
267 			y = canvas->pick_event.crossing.y +
268 				canvas->scroll_y1 - canvas->zoom_yofs;
269 		} else {
270 			x = canvas->pick_event.motion.x +
271 				canvas->scroll_x1 - canvas->zoom_xofs;
272 			y = canvas->pick_event.motion.y +
273 				canvas->scroll_y1 - canvas->zoom_yofs;
274 		}
275 
276 		/* canvas pixel coords */
277 
278 		cx = (gint) (x + 0.5);
279 		cy = (gint) (y + 0.5);
280 
281 		/* world coords */
282 
283 		x = canvas->scroll_x1 + x;
284 		y = canvas->scroll_y1 + y;
285 
286 		/* find the closest item */
287 
288 		if (canvas->root->flags & GNOME_CANVAS_ITEM_VISIBLE)
289 			canvas->new_current_item =
290 				gnome_canvas_item_invoke_point (
291 				canvas->root, x, y, cx, cy);
292 		else
293 			canvas->new_current_item = NULL;
294 	} else
295 		canvas->new_current_item = NULL;
296 
297 	if ((canvas->new_current_item == canvas->current_item) &&
298 			!canvas->left_grabbed_item)
299 		return retval; /* current item did not change */
300 
301 	/* Synthesize events for old and new current items */
302 
303 	if ((canvas->new_current_item != canvas->current_item)
304 	    && (canvas->current_item != NULL)
305 	    && !canvas->left_grabbed_item) {
306 		GdkEvent new_event = { 0 };
307 
308 		new_event = canvas->pick_event;
309 		new_event.type = GDK_LEAVE_NOTIFY;
310 
311 		new_event.crossing.detail = GDK_NOTIFY_ANCESTOR;
312 		new_event.crossing.subwindow = NULL;
313 		canvas->in_repick = TRUE;
314 		retval = canvas_emit_event (canvas, &new_event);
315 		canvas->in_repick = FALSE;
316 	}
317 
318 	/* new_current_item may have been set to NULL during
319 	 * the call to canvas_emit_event() above. */
320 
321 	if ((canvas->new_current_item != canvas->current_item) && button_down) {
322 		canvas->left_grabbed_item = TRUE;
323 		return retval;
324 	}
325 
326 	/* Handle the rest of cases */
327 
328 	canvas->left_grabbed_item = FALSE;
329 	canvas->current_item = canvas->new_current_item;
330 
331 	if (canvas->current_item != NULL) {
332 		GdkEvent new_event = { 0 };
333 
334 		new_event = canvas->pick_event;
335 		new_event.type = GDK_ENTER_NOTIFY;
336 		new_event.crossing.detail = GDK_NOTIFY_ANCESTOR;
337 		new_event.crossing.subwindow = NULL;
338 		retval = canvas_emit_event (canvas, &new_event);
339 	}
340 
341 	return retval;
342 }
343 
344 static void
345 canvas_style_set_recursive (GnomeCanvasItem *item,
346                             GtkStyle *previous_style)
347 {
348 	guint signal_id = g_signal_lookup ("style_set", G_OBJECT_TYPE (item));
349 	if (signal_id >= 1) {
350 		GSignalQuery query;
351 		g_signal_query (signal_id, &query);
352 		if (query.return_type == G_TYPE_NONE &&
353 			query.n_params == 1 &&
354 			query.param_types[0] == GTK_TYPE_STYLE) {
355 			g_signal_emit (item, signal_id, 0, previous_style);
356 		}
357 	}
358 
359 	if (GNOME_IS_CANVAS_GROUP (item)) {
360 		GList *items = GNOME_CANVAS_GROUP (item)->item_list;
361 		for (; items; items = items->next)
362 			canvas_style_set_recursive (
363 				items->data, previous_style);
364 	}
365 }
366 
367 static void
368 canvas_dispose (GObject *object)
369 {
370 	ECanvas *canvas = E_CANVAS (object);
371 
372 	if (canvas->idle_id)
373 		g_source_remove (canvas->idle_id);
374 	canvas->idle_id = 0;
375 
376 	if (canvas->grab_cancelled_check_id)
377 		g_source_remove (canvas->grab_cancelled_check_id);
378 	canvas->grab_cancelled_check_id = 0;
379 
380 	if (canvas->toplevel) {
381 		if (canvas->visibility_notify_id)
382 			g_signal_handler_disconnect (
383 				canvas->toplevel,
384 				canvas->visibility_notify_id);
385 		canvas->visibility_notify_id = 0;
386 
387 		g_object_unref (canvas->toplevel);
388 		canvas->toplevel = NULL;
389 	}
390 
391 	if (canvas->im_context) {
392 		g_object_unref (canvas->im_context);
393 		canvas->im_context = NULL;
394 	}
395 
396 	/* Chain up to parent's dispose() method. */
397 	G_OBJECT_CLASS (e_canvas_parent_class)->dispose (object);
398 }
399 
400 static void
401 canvas_realize (GtkWidget *widget)
402 {
403 	ECanvas *ecanvas = E_CANVAS (widget);
404 	GdkWindow *window;
405 
406 	/* Chain up to parent's realize() method. */
407 	GTK_WIDGET_CLASS (e_canvas_parent_class)->realize (widget);
408 
409 	window = gtk_layout_get_bin_window (GTK_LAYOUT (widget));
410 	gdk_window_set_background_pattern (window, NULL);
411 
412 	window = gtk_widget_get_window (widget);
413 	gtk_im_context_set_client_window (ecanvas->im_context, window);
414 }
415 
416 static void
417 canvas_unrealize (GtkWidget *widget)
418 {
419 	ECanvas * ecanvas = E_CANVAS (widget);
420 
421 	if (ecanvas->idle_id) {
422 		g_source_remove (ecanvas->idle_id);
423 		ecanvas->idle_id = 0;
424 	}
425 
426 	gtk_im_context_set_client_window (ecanvas->im_context, NULL);
427 
428 	/* Chain up to parent's unrealize() method. */
429 	GTK_WIDGET_CLASS (e_canvas_parent_class)->unrealize (widget);
430 }
431 
432 static void
433 canvas_style_set (GtkWidget *widget,
434                   GtkStyle *previous_style)
435 {
436 	canvas_style_set_recursive (
437 		GNOME_CANVAS_ITEM (gnome_canvas_root (
438 		GNOME_CANVAS (widget))), previous_style);
439 }
440 
441 static gint
442 canvas_button_event (GtkWidget *widget,
443                      GdkEventButton *event)
444 {
445 	GnomeCanvas *canvas;
446 	GdkWindow *bin_window;
447 	gint mask;
448 	gint retval;
449 
450 	g_return_val_if_fail (GNOME_IS_CANVAS (widget), FALSE);
451 	g_return_val_if_fail (event != NULL, FALSE);
452 
453 	retval = FALSE;
454 
455 	canvas = GNOME_CANVAS (widget);
456 	bin_window = gtk_layout_get_bin_window (GTK_LAYOUT (canvas));
457 
458 	d (
459 		g_print ("button %d, event type %d, grabbed=%p, current=%p\n",
460 		event->button,
461 		event->type,
462 		canvas->grabbed_item,
463 		canvas->current_item));
464 
465         /* dispatch normally regardless of the event's window if an item has
466 	   has a pointer grab in effect */
467 	if (!canvas->grabbed_item && event->window != bin_window)
468 		return retval;
469 
470 	switch (event->button) {
471 		case 1:
472 			mask = GDK_BUTTON1_MASK;
473 			break;
474 		case 2:
475 			mask = GDK_BUTTON2_MASK;
476 			break;
477 		case 3:
478 			mask = GDK_BUTTON3_MASK;
479 			break;
480 		case 4:
481 			mask = GDK_BUTTON4_MASK;
482 			break;
483 		case 5:
484 			mask = GDK_BUTTON5_MASK;
485 			break;
486 		default:
487 			mask = 0;
488 	}
489 
490 	switch (event->type) {
491 		case GDK_BUTTON_PRESS:
492 		case GDK_2BUTTON_PRESS:
493 		case GDK_3BUTTON_PRESS:
494 			/* Pick the current item as if the button were not
495 			 * pressed, and then process the event. */
496 			canvas->state = event->state;
497 			pick_current_item (canvas, (GdkEvent *) event);
498 			canvas->state ^= mask;
499 			retval = canvas_emit_event (canvas, (GdkEvent *) event);
500 			break;
501 
502 		case GDK_BUTTON_RELEASE:
503 			/* Process the event as if the button were pressed,
504 			 * then repick after the button has been released. */
505 			canvas->state = event->state;
506 			retval = canvas_emit_event (canvas, (GdkEvent *) event);
507 			event->state ^= mask;
508 			canvas->state = event->state;
509 			pick_current_item (canvas, (GdkEvent *) event);
510 			event->state ^= mask;
511 			break;
512 
513 		default:
514 			g_return_val_if_reached (0);
515 	}
516 
517 	return retval;
518 }
519 
520 static gint
521 canvas_key_event (GtkWidget *widget,
522                   GdkEventKey *event)
523 {
524 	GnomeCanvas *canvas;
525 	GdkEvent full_event = { 0 };
526 
527 	g_return_val_if_fail (GNOME_IS_CANVAS (widget), FALSE);
528 	g_return_val_if_fail (event != NULL, FALSE);
529 
530 	canvas = GNOME_CANVAS (widget);
531 
532 	full_event.type = event->type;
533 	full_event.key = *event;
534 
535 	return canvas_emit_event (canvas, &full_event);
536 }
537 
538 static gint
539 canvas_focus_in_event (GtkWidget *widget,
540                        GdkEventFocus *event)
541 {
542 	GnomeCanvas *canvas;
543 	ECanvas *ecanvas;
544 	GdkEvent full_event = { 0 };
545 
546 	canvas = GNOME_CANVAS (widget);
547 	ecanvas = E_CANVAS (widget);
548 
549 	/* XXX Can't access flags directly anymore, but is it really needed?
550 	 *     If so, could we call gtk_widget_send_focus_change() instead? */
551 #if 0
552 	GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS);
553 #endif
554 
555 	gtk_im_context_focus_in (ecanvas->im_context);
556 
557 	if (canvas->focused_item) {
558 		full_event.type = event->type;
559 		full_event.focus_change = *event;
560 		return canvas_emit_event (canvas, &full_event);
561 	} else {
562 		return FALSE;
563 	}
564 }
565 
566 static gint
567 canvas_focus_out_event (GtkWidget *widget,
568                         GdkEventFocus *event)
569 {
570 	GnomeCanvas *canvas;
571 	ECanvas *ecanvas;
572 	GdkEvent full_event = { 0 };
573 
574 	canvas = GNOME_CANVAS (widget);
575 	ecanvas = E_CANVAS (widget);
576 
577 	/* XXX Can't access flags directly anymore, but is it really needed?
578 	 *     If so, could we call gtk_widget_send_focus_change() instead? */
579 #if 0
580 	GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
581 #endif
582 
583 	gtk_im_context_focus_out (ecanvas->im_context);
584 
585 	if (canvas->focused_item) {
586 		full_event.type = event->type;
587 		full_event.focus_change = *event;
588 		return canvas_emit_event (canvas, &full_event);
589 	} else {
590 		return FALSE;
591 	}
592 }
593 
594 static void
595 canvas_reflow (ECanvas *canvas)
596 {
597 	/* Placeholder so subclasses can safely chain up. */
598 }
599 
600 static void
601 e_canvas_class_init (ECanvasClass *class)
602 {
603 	GObjectClass *object_class;
604 	GtkWidgetClass *widget_class;
605 
606 	object_class = G_OBJECT_CLASS (class);
607 	object_class->dispose = canvas_dispose;
608 
609 	widget_class = GTK_WIDGET_CLASS (class);
610 	widget_class->realize = canvas_realize;
611 	widget_class->unrealize = canvas_unrealize;
612 	widget_class->style_set = canvas_style_set;
613 	widget_class->button_press_event = canvas_button_event;
614 	widget_class->button_release_event = canvas_button_event;
615 	widget_class->key_press_event = canvas_key_event;
616 	widget_class->key_release_event = canvas_key_event;
617 	widget_class->focus_in_event = canvas_focus_in_event;
618 	widget_class->focus_out_event = canvas_focus_out_event;
619 
620 	class->reflow = canvas_reflow;
621 
622 	signals[REFLOW] = g_signal_new (
623 		"reflow",
624 		G_OBJECT_CLASS_TYPE (object_class),
625 		G_SIGNAL_RUN_LAST,
626 		G_STRUCT_OFFSET (ECanvasClass, reflow),
627 		NULL, NULL,
628 		g_cclosure_marshal_VOID__VOID,
629 		G_TYPE_NONE, 0);
630 }
631 
632 static void
633 e_canvas_init (ECanvas *canvas)
634 {
635 	canvas->im_context = gtk_im_multicontext_new ();
636 }
637 
638 GtkWidget *
639 e_canvas_new (void)
640 {
641 	return g_object_new (E_TYPE_CANVAS, NULL);
642 }
643 
644 /**
645  * e_canvas_item_grab_focus:
646  * @item: A canvas item.
647  * @widget_too: Whether or not to grab the widget-level focus too
648  *
649  * Makes the specified item take the keyboard focus, so all keyboard
650  * events will be sent to it. If the canvas widget itself did not have
651  * the focus and @widget_too is %TRUE, it grabs that focus as well.
652  **/
653 void
654 e_canvas_item_grab_focus (GnomeCanvasItem *item,
655                           gboolean widget_too)
656 {
657 	GnomeCanvasItem *focused_item;
658 	GdkWindow *bin_window;
659 	GdkEvent ev = { 0 };
660 
661 	g_return_if_fail (GNOME_IS_CANVAS_ITEM (item));
662 	g_return_if_fail (gtk_widget_get_can_focus (GTK_WIDGET (item->canvas)));
663 
664 	bin_window = gtk_layout_get_bin_window (GTK_LAYOUT (item->canvas));
665 
666 	focused_item = item->canvas->focused_item;
667 
668 	if (focused_item) {
669 		ev.type = GDK_FOCUS_CHANGE;
670 		ev.focus_change.type = GDK_FOCUS_CHANGE;
671 		ev.focus_change.window = bin_window;
672 		ev.focus_change.send_event = FALSE;
673 		ev.focus_change.in = FALSE;
674 
675 		canvas_emit_event (item->canvas, &ev);
676 	}
677 
678 	item->canvas->focused_item = item;
679 
680 	if (widget_too && !gtk_widget_has_focus (GTK_WIDGET (item->canvas))) {
681 		gtk_widget_grab_focus (GTK_WIDGET (item->canvas));
682 	}
683 
684 	if (item) {
685 		ev.focus_change.type = GDK_FOCUS_CHANGE;
686 		ev.focus_change.window = bin_window;
687 		ev.focus_change.send_event = FALSE;
688 		ev.focus_change.in = TRUE;
689 
690 		canvas_emit_event (item->canvas, &ev);
691 	}
692 }
693 
694 static void
695 e_canvas_item_invoke_reflow (GnomeCanvasItem *item,
696                              gint flags)
697 {
698 	GnomeCanvasGroup *group;
699 	GList *list;
700 	GnomeCanvasItem *child;
701 
702 	if (GNOME_IS_CANVAS_GROUP (item)) {
703 		group = GNOME_CANVAS_GROUP (item);
704 		for (list = group->item_list; list; list = list->next) {
705 			child = GNOME_CANVAS_ITEM (list->data);
706 			if (child->flags & E_CANVAS_ITEM_DESCENDENT_NEEDS_REFLOW)
707 				e_canvas_item_invoke_reflow (child, flags);
708 		}
709 	}
710 
711 	if (item->flags & E_CANVAS_ITEM_NEEDS_REFLOW) {
Access to field 'flags' results in a dereference of a null pointer (loaded from variable 'item')
(emitted by clang-analyzer)

TODO: a detailed trace is available in the data model (not yet rendered in this report)

Access to field 'flags' results in a dereference of a null pointer (loaded from variable 'item')
(emitted by clang-analyzer)

TODO: a detailed trace is available in the data model (not yet rendered in this report)

712 ECanvasItemReflowFunc func; 713 func = (ECanvasItemReflowFunc) 714 g_object_get_data ( 715 G_OBJECT (item), 716 "ECanvasItem::reflow_callback"); 717 if (func) 718 func (item, flags); 719 } 720 721 item->flags &= ~E_CANVAS_ITEM_NEEDS_REFLOW; 722 item->flags &= ~E_CANVAS_ITEM_DESCENDENT_NEEDS_REFLOW; 723 } 724 725 static void 726 do_reflow (ECanvas *canvas) 727 { 728 if (GNOME_CANVAS (canvas)->root->flags & E_CANVAS_ITEM_DESCENDENT_NEEDS_REFLOW) 729 e_canvas_item_invoke_reflow (GNOME_CANVAS (canvas)->root, 0); 730 } 731 732 /* Idle handler for the e-canvas. It deals with pending reflows. */ 733 static gint 734 idle_handler (gpointer data) 735 { 736 ECanvas *canvas; 737 738 canvas = E_CANVAS (data); 739 do_reflow (canvas); 740 741 /* Reset idle id */ 742 canvas->idle_id = 0; 743 744 g_signal_emit (canvas, signals[REFLOW], 0); 745 746 return FALSE; 747 } 748 749 /* Convenience function to add an idle handler to a canvas */ 750 static void 751 add_idle (ECanvas *canvas) 752 { 753 if (canvas->idle_id != 0) 754 return; 755 756 canvas->idle_id = g_idle_add_full ( 757 G_PRIORITY_HIGH_IDLE, idle_handler, (gpointer) canvas, NULL); 758 } 759 760 static void 761 e_canvas_item_descendent_needs_reflow (GnomeCanvasItem *item) 762 { 763 if (item->flags & E_CANVAS_ITEM_DESCENDENT_NEEDS_REFLOW) 764 return; 765 766 item->flags |= E_CANVAS_ITEM_DESCENDENT_NEEDS_REFLOW; 767 if (item->parent) 768 e_canvas_item_descendent_needs_reflow (item->parent); 769 } 770 771 void 772 e_canvas_item_request_reflow (GnomeCanvasItem *item) 773 { 774 g_return_if_fail (GNOME_IS_CANVAS_ITEM (item)); 775 776 if (item->flags & GNOME_CANVAS_ITEM_REALIZED) { 777 item->flags |= E_CANVAS_ITEM_NEEDS_REFLOW; 778 e_canvas_item_descendent_needs_reflow (item); 779 add_idle (E_CANVAS (item->canvas)); 780 } 781 } 782 783 void 784 e_canvas_item_request_parent_reflow (GnomeCanvasItem *item) 785 { 786 g_return_if_fail (GNOME_IS_CANVAS_ITEM (item)); 787 788 e_canvas_item_request_reflow (item->parent); 789 } 790 791 void 792 e_canvas_item_set_reflow_callback (GnomeCanvasItem *item, 793 ECanvasItemReflowFunc func) 794 { 795 g_return_if_fail (GNOME_IS_CANVAS_ITEM (item)); 796 g_return_if_fail (func != NULL); 797 798 g_object_set_data ( 799 G_OBJECT (item), "ECanvasItem::reflow_callback", 800 (gpointer) func); 801 } 802 803 static gboolean 804 grab_cancelled_check (gpointer data) 805 { 806 ECanvas *canvas = data; 807 808 if (GNOME_CANVAS (canvas)->grabbed_item == NULL) { 809 canvas->grab_cancelled_cb = NULL; 810 canvas->grab_cancelled_check_id = 0; 811 canvas->grab_cancelled_time = 0; 812 canvas->grab_cancelled_data = NULL; 813 return FALSE; 814 } 815 816 if (gtk_grab_get_current ()) { 817 gnome_canvas_item_ungrab ( 818 GNOME_CANVAS (canvas)->grabbed_item, 819 canvas->grab_cancelled_time); 820 if (canvas->grab_cancelled_cb) 821 canvas->grab_cancelled_cb ( 822 canvas, GNOME_CANVAS (canvas)->grabbed_item, 823 canvas->grab_cancelled_data); 824 canvas->grab_cancelled_cb = NULL; 825 canvas->grab_cancelled_check_id = 0; 826 canvas->grab_cancelled_time = 0; 827 canvas->grab_cancelled_data = NULL; 828 return FALSE; 829 } 830 return TRUE; 831 } 832 833 gint 834 e_canvas_item_grab (ECanvas *canvas, 835 GnomeCanvasItem *item, 836 guint event_mask, 837 GdkCursor *cursor, 838 guint32 etime, 839 ECanvasItemGrabCancelled cancelled_cb, 840 gpointer cancelled_data) 841 { 842 gint ret_val; 843 844 g_return_val_if_fail (E_IS_CANVAS (canvas), -1); 845 g_return_val_if_fail (GNOME_IS_CANVAS_ITEM (item), -1); 846 847 if (gtk_grab_get_current ()) 848 return GDK_GRAB_ALREADY_GRABBED; 849 850 ret_val = gnome_canvas_item_grab ( 851 item, event_mask, cursor, etime); 852 if (ret_val == GDK_GRAB_SUCCESS) { 853 canvas->grab_cancelled_cb = cancelled_cb; 854 canvas->grab_cancelled_check_id = g_timeout_add_full ( 855 G_PRIORITY_LOW, 100, 856 grab_cancelled_check, canvas, NULL); 857 canvas->grab_cancelled_time = etime; 858 canvas->grab_cancelled_data = cancelled_data; 859 } 860 861 return ret_val; 862 } 863 864 void 865 e_canvas_item_ungrab (ECanvas *canvas, 866 GnomeCanvasItem *item, 867 guint32 etime) 868 { 869 g_return_if_fail (E_IS_CANVAS (canvas)); 870 g_return_if_fail (GNOME_IS_CANVAS_ITEM (item)); 871 872 if (canvas->grab_cancelled_check_id) { 873 g_source_remove (canvas->grab_cancelled_check_id); 874 canvas->grab_cancelled_cb = NULL; 875 canvas->grab_cancelled_check_id = 0; 876 canvas->grab_cancelled_time = 0; 877 canvas->grab_cancelled_data = NULL; 878 gnome_canvas_item_ungrab (item, etime); 879 } 880 }