My cut at fixing the GnomeCanvas focus and grab issues



Here's my cut at fixing a few problems in GnomeCanvas. I decoupled
current_item from grabbed_item, fixed handling of GDK_FOCUS_CHANGE events so
we don't get multiple events and miss some we should get, and removed some
dead code.

The GnomeCanvasRichText fix is separate. I ran into that problem while
testing the changes with canvas_demo.

By the way, it's confusing that left_grabbed_item has nothing to do with
grabbed_item. It's a totally separate concept of grabbed that means "item
you moused down on" that works even if you don't call gnome_canvas_item_grab
at all.

Index: libgnomecanvas/gnome-canvas-rich-text.c
===================================================================
RCS file: 
/cvs/gnome/libgnomecanvas/libgnomecanvas/gnome-canvas-rich-text.c,v
retrieving revision 1.12
diff -p -u -r1.12 gnome-canvas-rich-text.c
--- libgnomecanvas/gnome-canvas-rich-text.c    2001/11/06 07:18:55    1.12
+++ libgnomecanvas/gnome-canvas-rich-text.c    2001/12/07 00:25:09
@@ -1850,8 +1850,9 @@ gnome_canvas_rich_text_update(GnomeCanva
     get_bounds(text, &x1, &y1, &x2, &y2);
 
     gtk_text_buffer_get_iter_at_offset(text->_priv->buffer, &start, 0);
-    gtk_text_layout_validate_yrange(
-        text->_priv->layout, &start, 0, y2 - y1);
+    if (text->_priv->layout)
+        gtk_text_layout_validate_yrange(
+            text->_priv->layout, &start, 0, y2 - y1);
 
     gnome_canvas_update_bbox(item, x1, y1, x2, y2);
 } /* gnome_canvas_rich_text_update */
Index: libgnomecanvas/gnome-canvas.c
===================================================================
RCS file: /cvs/gnome/libgnomecanvas/libgnomecanvas/gnome-canvas.c,v
retrieving revision 1.140
diff -p -u -r1.140 gnome-canvas.c
--- libgnomecanvas/gnome-canvas.c    2001/12/06 22:51:35    1.140
+++ libgnomecanvas/gnome-canvas.c    2001/12/07 00:25:09
@@ -1007,7 +1007,6 @@ gnome_canvas_item_grab (GnomeCanvasItem
 
     item->canvas->grabbed_item = item;
     item->canvas->grabbed_event_mask = event_mask;
-    item->canvas->current_item = item; /* So that events go to the grabbed
item */
 
     return retval;
 }
@@ -1202,34 +1201,45 @@ gnome_canvas_item_reparent (GnomeCanvasI
 void
 gnome_canvas_item_grab_focus (GnomeCanvasItem *item)
 {
-    GnomeCanvasItem *focused_item;
     GdkEvent ev;
 
     g_return_if_fail (GNOME_IS_CANVAS_ITEM (item));
     g_return_if_fail (GTK_WIDGET_CAN_FOCUS (GTK_WIDGET (item->canvas)));
 
-    focused_item = item->canvas->focused_item;
+    /* If we have to grab focus, the GDK_FOCUS_CHANGE event that
+     * comes in from GTK will suffice so we don't need to send any
+     * events of our own. Also, it doesn't matter what the old
+     * value of focused_item is, since the canvas itself wasn't
+     * focused.
+     */
+    if (! GTK_WIDGET_HAS_FOCUS (GTK_WIDGET (item->canvas))) {
+        item->canvas->focused_item = item;
+        gtk_widget_grab_focus (GTK_WIDGET (item->canvas));
+        return;
+    }
+    
+    /* If the canvas is focused and the correct item is focused,
+     * we have no work to do.
+     */
+    if (item->canvas->focused_item == item)
+        return;
 
-    if (focused_item) {
-        ev.focus_change.type = GDK_FOCUS_CHANGE;
-        ev.focus_change.window = GTK_LAYOUT (item->canvas)->bin_window;
-        ev.focus_change.send_event = FALSE;
+    /* Send focus change events explicitly, since we aren't
+     * changing the focus at the GTK level.
+     */
+    ev.focus_change.type = GDK_FOCUS_CHANGE;
+    ev.focus_change.window = GTK_LAYOUT (item->canvas)->bin_window;
+    ev.focus_change.send_event = FALSE;
+    
+    if (item->canvas->focused_item) {
         ev.focus_change.in = FALSE;
-
         emit_event (item->canvas, &ev);
     }
-
+    
     item->canvas->focused_item = item;
-    gtk_widget_grab_focus (GTK_WIDGET (item->canvas));
-
-    if (focused_item) {
-        ev.focus_change.type = GDK_FOCUS_CHANGE;
-        ev.focus_change.window = GTK_LAYOUT (item->canvas)->bin_window;
-        ev.focus_change.send_event = FALSE;
-        ev.focus_change.in = TRUE;
-
-        emit_event (item->canvas, &ev);
-    }             
+    
+    ev.focus_change.in = TRUE;
+    emit_event (item->canvas, &ev);
 }
 
 
@@ -2496,62 +2506,7 @@ emit_event (GnomeCanvas *canvas, GdkEven
     GnomeCanvasItem *item;
     GnomeCanvasItem *parent;
     guint mask;
-        guint signal_num;
-
-    /* Perform checks for grabbed items */
-
-    if (canvas->grabbed_item &&
-        !is_descendant (canvas->current_item, canvas->grabbed_item)) {
-                g_warning ("emit_event() returning FALSE!\n");
-        return FALSE;
-        }
-
-        signal_num = -1;
-
-    if (canvas->grabbed_item) {
-        switch (event->type) {
-        case GDK_ENTER_NOTIFY:
-            mask = GDK_ENTER_NOTIFY_MASK;
-            break;
-
-        case GDK_LEAVE_NOTIFY:
-            mask = GDK_LEAVE_NOTIFY_MASK;
-            break;
-
-        case GDK_MOTION_NOTIFY:
-            mask = GDK_POINTER_MOTION_MASK;
-            break;
-
-        case GDK_BUTTON_PRESS:
-        case GDK_2BUTTON_PRESS:
-        case GDK_3BUTTON_PRESS:
-            mask = GDK_BUTTON_PRESS_MASK;
-            break;
-
-        case GDK_BUTTON_RELEASE:
-            mask = GDK_BUTTON_RELEASE_MASK;
-            break;
-
-        case GDK_KEY_PRESS:
-                        signal_num = ITEM_KEY_PRESS_EVENT;
-            mask = GDK_KEY_PRESS_MASK;
-            break;
-
-        case GDK_KEY_RELEASE:
-                        signal_num = ITEM_KEY_RELEASE_EVENT;
-            mask = GDK_KEY_RELEASE_MASK;
-            break;
 
-        default:
-                        signal_num = -1;
-            mask = 0;
-            break;
-        }
-
-        if (!(mask & canvas->grabbed_event_mask))
-            return FALSE;
-    }
-
     /* Convert to world coordinates -- we have two cases because of
diferent
      * offsets of the fields in the event structures.
      */
@@ -2600,6 +2555,43 @@ emit_event (GnomeCanvas *canvas, GdkEven
         (event->type == GDK_KEY_RELEASE) ||
         (event->type == GDK_FOCUS_CHANGE)))
         item = canvas->focused_item;
+
+    if (canvas->grabbed_item) {
+        switch (event->type) {
+        case GDK_ENTER_NOTIFY:
+            mask = GDK_ENTER_NOTIFY_MASK;
+            break;
+
+        case GDK_LEAVE_NOTIFY:
+            mask = GDK_LEAVE_NOTIFY_MASK;
+            break;
+
+        case GDK_MOTION_NOTIFY:
+            mask = GDK_POINTER_MOTION_MASK;
+            break;
+
+        case GDK_BUTTON_PRESS:
+        case GDK_2BUTTON_PRESS:
+        case GDK_3BUTTON_PRESS:
+            mask = GDK_BUTTON_PRESS_MASK;
+            break;
+
+        case GDK_BUTTON_RELEASE:
+            mask = GDK_BUTTON_RELEASE_MASK;
+            break;
+
+        default:
+            mask = 0;
+            break;
+        }
+
+        if (mask) {
+            if (mask & canvas->grabbed_event_mask)
+                item = canvas->grabbed_item;
+            else
+                item = NULL;
+        }
+    }
 
     /* The event is propagated up the hierarchy (for if someone connected
to
      * a group instead of a leaf event), and emission is stopped if a
===================================================================

    -- Darin




[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]