2004-01-26 David Jee <djee@redhat.com>
authorDavid Jee <djee@redhat.com>
Mon, 26 Jan 2004 21:55:42 +0000 (21:55 +0000)
committerDavid Jee <djee@gcc.gnu.org>
Mon, 26 Jan 2004 21:55:42 +0000 (21:55 +0000)
* gnu/java/awt/peer/gtk/GtkComponentPeer.java
(handleEvent): Implemented. Handles PaintEvents.
(paint): Implemented. Use GTK native methods to queue updates
        for this heavyweight peer.
* gnu/java/awt/peer/gtk/GtkContainerPeer.java
(handleEvent): Removed.
* java/awt/Component.java
(paint): Implemented. Explictly paint the heavyweight peer.
(update): Clear the background for heavyweight components.
(paintAll): No need to call peer.paint() anymore.
(processEvent): Don't process PaintEvents here. It's now done in
the peer's handleEvent().
(processPaintEvent): Removed.
* java/awt/Container.java
(paint): No need to call super.paint(). Visit heavyweight
children as well.
(update): Don't clear the background here.  It's done in
Component.update().
(visitChildren): Added check to not recurse into Containers.
* jni/gtk-peer/gnu_java_awt_peer_gtk_GtkComponentPeer.c
(filter_expose_event_handler): New method.  Filter unwanted
expose events while painting heavyweight peers.
(Java_gnu_java_awt_peer_gtk_GtkComponentPeer_addExposeFilter):
New method. Connect filter and block pre_event_handler.
(Java_gnu_java_awt_peer_gtk_GtkComponentPeer_removeExposeFilter):
New method. Disconnect filter and unblock pre_event_handler.
(Java_gnu_java_awt_peer_gtk_GtkComponentPeer_gtkWidgetQueueDrawArea):
New method. Invalidate and update given area.
* jni/gtk-peer/gnu_java_awt_peer_gtk_GtkEvents.c
(pre_event_handler): Add checks for unwanted expose events.

From-SVN: r76668

libjava/ChangeLog
libjava/gnu/java/awt/peer/gtk/GtkComponentPeer.java
libjava/gnu/java/awt/peer/gtk/GtkContainerPeer.java
libjava/java/awt/Component.java
libjava/java/awt/Container.java
libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkComponentPeer.c
libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkEvents.c

index 0e2e661..72c37c2 100644 (file)
@@ -1,5 +1,38 @@
 2004-01-26  David Jee  <djee@redhat.com>
 
+       * gnu/java/awt/peer/gtk/GtkComponentPeer.java
+       (handleEvent): Implemented. Handles PaintEvents.
+       (paint): Implemented. Use GTK native methods to queue updates
+        for this heavyweight peer.
+       * gnu/java/awt/peer/gtk/GtkContainerPeer.java
+       (handleEvent): Removed.
+       * java/awt/Component.java
+       (paint): Implemented. Explictly paint the heavyweight peer.
+       (update): Clear the background for heavyweight components.
+       (paintAll): No need to call peer.paint() anymore.
+       (processEvent): Don't process PaintEvents here. It's now done in
+       the peer's handleEvent().
+       (processPaintEvent): Removed.
+       * java/awt/Container.java
+       (paint): No need to call super.paint(). Visit heavyweight
+       children as well.
+       (update): Don't clear the background here.  It's done in
+       Component.update().
+       (visitChildren): Added check to not recurse into Containers.
+       * jni/gtk-peer/gnu_java_awt_peer_gtk_GtkComponentPeer.c
+       (filter_expose_event_handler): New method.  Filter unwanted
+       expose events while painting heavyweight peers.
+       (Java_gnu_java_awt_peer_gtk_GtkComponentPeer_addExposeFilter):
+       New method. Connect filter and block pre_event_handler.
+       (Java_gnu_java_awt_peer_gtk_GtkComponentPeer_removeExposeFilter):
+       New method. Disconnect filter and unblock pre_event_handler.
+       (Java_gnu_java_awt_peer_gtk_GtkComponentPeer_gtkWidgetQueueDrawArea):
+       New method. Invalidate and update given area.
+       * jni/gtk-peer/gnu_java_awt_peer_gtk_GtkEvents.c
+       (pre_event_handler): Add checks for unwanted expose events.
+
+2004-01-26  David Jee  <djee@redhat.com>
+
        * jni/gtk-peer/gnu_java_awt_peer_gtk_GtkComponentPeer.c
        (find_bg_color_widget): For GtkButton, return its child.
 
index 9a56619..4b29bcc 100644 (file)
@@ -91,6 +91,9 @@ public class GtkComponentPeer extends GtkGenericPeer
   native void gtkWidgetSetCursor (int type);
   native void gtkWidgetSetBackground (int red, int green, int blue);
   native void gtkWidgetSetForeground (int red, int green, int blue);
+  native void gtkWidgetQueueDrawArea(int x, int y, int width, int height);
+  native void addExposeFilter();
+  native void removeExposeFilter();
 
   void create ()
   {
@@ -217,6 +220,37 @@ public class GtkComponentPeer extends GtkGenericPeer
   
   public void handleEvent (AWTEvent event)
   {
+    int id = event.getID();
+
+    switch (id)
+      {
+      case PaintEvent.PAINT:
+      case PaintEvent.UPDATE:
+        {
+          try 
+            {
+              Graphics g = getGraphics ();
+          
+              // Some peers like GtkFileDialogPeer are repainted by Gtk itself
+              if (g == null)
+                break;
+
+              g.setClip (((PaintEvent)event).getUpdateRect());
+
+              if (id == PaintEvent.PAINT)
+                awtComponent.paint (g);
+              else
+                awtComponent.update (g);
+
+              g.dispose ();
+            }
+          catch (InternalError e)
+            {
+              System.err.println (e);
+            }
+        }
+        break;
+      }
   }
   
   public boolean isFocusTraversable () 
@@ -235,7 +269,21 @@ public class GtkComponentPeer extends GtkGenericPeer
 
   public void paint (Graphics g)
   {
-    awtComponent.paint (g);
+    Component parent = awtComponent.getParent();
+    GtkComponentPeer parentPeer = null;
+    if ((parent instanceof Container) && !parent.isLightweight())
+      parentPeer = (GtkComponentPeer) parent.getPeer();
+
+    addExposeFilter();
+    if (parentPeer != null)
+      parentPeer.addExposeFilter();
+
+    Rectangle clip = g.getClipBounds();
+    gtkWidgetQueueDrawArea(clip.x, clip.y, clip.width, clip.height);
+
+    removeExposeFilter();
+    if (parentPeer != null)
+      parentPeer.removeExposeFilter();
   }
 
   public Dimension preferredSize ()
index e888172..361dea7 100644 (file)
@@ -100,41 +100,6 @@ public class GtkContainerPeer extends GtkComponentPeer
     return new GdkGraphics (this);
   }
 
-  public void handleEvent (AWTEvent event)
-  {
-    int id = event.getID();
-      
-    switch (id)
-      {
-      case PaintEvent.PAINT:
-      case PaintEvent.UPDATE:
-       {
-         try 
-           {
-             Graphics g = getGraphics ();
-
-             // Some peers like GtkFileDialogPeer are repainted by Gtk itself
-             if (g == null)
-               break;
-
-             g.setClip (((PaintEvent)event).getUpdateRect());
-
-             if (id == PaintEvent.PAINT)
-               awtComponent.paint (g);
-             else
-               awtComponent.update (g);
-             
-             g.dispose ();
-           } 
-         catch (InternalError e)
-           { 
-             System.err.println (e);
-           }
-       }
-       break;
-      }
-  }
-
   public void beginLayout () { }
   public void endLayout () { }
   public boolean isPaintPending () { return false; }
index b440c51..87c73b5 100644 (file)
@@ -1702,6 +1702,9 @@ public abstract class Component
    */
   public void paint(Graphics g)
   {
+    // Paint the heavyweight peer
+    if (!isLightweight() && peer != null)
+      peer.paint(g);
   }
 
   /**
@@ -1719,6 +1722,15 @@ public abstract class Component
    */
   public void update(Graphics g)
   {
+    if (!isLightweight())
+      {
+        Rectangle clip = g.getClipBounds();
+        if (clip == null)
+          g.clearRect(0, 0, width, height);
+        else
+          g.clearRect(clip.x, clip.y, clip.width, clip.height);
+      }
+
     paint(g);
   }
 
@@ -1732,8 +1744,6 @@ public abstract class Component
   {
     if (! visible)
       return;
-    if (peer != null)
-      peer.paint(g);
     paint(g);
   }
 
@@ -2787,8 +2797,6 @@ public abstract class Component
 
     if (e instanceof FocusEvent)
       processFocusEvent((FocusEvent) e);
-    else if (e instanceof PaintEvent)
-      processPaintEvent((PaintEvent) e);
     else if (e instanceof MouseWheelEvent)
       processMouseWheelEvent((MouseWheelEvent) e);
     else if (e instanceof MouseEvent)
@@ -4225,42 +4233,6 @@ p   * <li>the set of backward traversal keys
   }
 
   /**
-   * Does the work for a paint event.
-   *
-   * @param event the event to process
-   */
-  private void processPaintEvent(PaintEvent event)
-  {
-    // Can't do graphics without peer
-    if (peer == null)
-      return;
-
-    Graphics gfx = getGraphics();
-    try
-      {
-       Shape clip = event.getUpdateRect();
-       gfx.setClip(clip);
-
-       switch (event.id)
-         {
-         case PaintEvent.PAINT:
-           paint(gfx);
-           break;
-         case PaintEvent.UPDATE:
-           update(gfx);
-           break;
-         default:
-           throw new IllegalArgumentException("unknown paint event");
-         }
-       event.consume ();
-      }
-    finally
-      {
-       gfx.dispose();
-      }
-  }
-
-  /**
    * This method is used to implement transferFocus(). CHILD is the child
    * making the request. This is overridden by Container; when called for an
    * ordinary component there is no child and so we always return null.
index 5d176be..57cd833 100644 (file)
@@ -663,8 +663,9 @@ public class Container extends Component
   {
     if (!isShowing())
       return;
-    super.paint(g);
-    visitChildren(g, GfxPaintVisitor.INSTANCE, true);
+    // Visit heavyweights as well, in case they were
+    // erased when we cleared the background for this container.
+    visitChildren(g, GfxPaintVisitor.INSTANCE, false);
   }
 
   /**
@@ -678,11 +679,6 @@ public class Container extends Component
    */
   public void update(Graphics g)
   {
-    Rectangle clip = g.getClipBounds();
-    if (clip == null)
-      g.clearRect(0, 0, width, height);
-    else
-      g.clearRect(clip.x, clip.y, clip.width, clip.height);
     super.update(g);
   }
 
@@ -1204,8 +1200,12 @@ public class Container extends Component
         for (int i = ncomponents - 1; i >= 0; --i)
           {
             Component comp = component[i];
+            // If we're visiting heavyweights as well,
+            // don't recurse into Containers here. This avoids
+            // painting the same nested child multiple times.
             boolean applicable = comp.isVisible()
-              && (comp.isLightweight() || !lightweightOnly);
+              && (comp.isLightweight()
+                  || !lightweightOnly && ! (comp instanceof Container));
 
             if (applicable)
               visitChild(gfx, visitor, comp);
index 1966227..725c89e 100644 (file)
@@ -575,6 +575,80 @@ Java_gnu_java_awt_peer_gtk_GtkComponentPeer_set__Ljava_lang_String_2Ljava_lang_O
   (*env)->ReleaseStringUTFChars (env, jname, name);
 }
 
+gboolean
+filter_expose_event_handler (GtkWidget *widget, GdkEvent *event, jobject peer)
+{
+  // Prevent the default event handler from getting this signal if applicable
+  // FIXME: I came up with these filters by looking for patterns in the unwanted
+  //        expose events that are fed back to us from gtk/X. Perhaps there is
+  //        a way to prevent them from occuring in the first place.
+  if (event->type == GDK_EXPOSE && (!GTK_IS_LAYOUT(widget)
+                                    || event->any.window != widget->window))
+    {
+      g_signal_stop_emission_by_name(GTK_OBJECT(widget), "event");
+      return FALSE;
+    }
+  else
+    {
+      // There may be non-expose events that are triggered while we're
+      // painting a heavyweight peer.
+      return pre_event_handler(widget, event, peer);
+    }
+}
+
+JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GtkComponentPeer_addExposeFilter
+  (JNIEnv *env, jobject obj)
+{
+  void *ptr = NSA_GET_PTR (env, obj);
+  jobject *gref = NSA_GET_GLOBAL_REF (env, obj);
+  g_assert (gref);
+
+  gdk_threads_enter ();
+
+  g_signal_handlers_block_by_func (GTK_OBJECT(ptr), *pre_event_handler, *gref);
+  g_signal_connect( GTK_OBJECT(ptr), "event",
+                    G_CALLBACK(filter_expose_event_handler), *gref);
+
+  gdk_threads_leave ();
+}
+
+JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GtkComponentPeer_removeExposeFilter
+  (JNIEnv *env, jobject obj)
+{
+  void *ptr = NSA_GET_PTR (env, obj);
+  jobject *gref = NSA_GET_GLOBAL_REF (env, obj);
+  g_assert (gref);
+
+  gdk_threads_enter ();
+
+  g_signal_handlers_disconnect_by_func (GTK_OBJECT(ptr),
+                                        *filter_expose_event_handler, *gref);
+  g_signal_handlers_unblock_by_func (GTK_OBJECT(ptr), *pre_event_handler, *gref);
+
+  gdk_threads_leave ();
+}
+
+JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GtkComponentPeer_gtkWidgetQueueDrawArea
+  (JNIEnv *env, jobject obj, jint x, jint y, jint width, jint height)
+{
+  GdkRectangle rect;
+  void *ptr;
+
+  ptr = NSA_GET_PTR (env, obj);
+
+  rect.x = x + GTK_WIDGET(ptr)->allocation.x;
+  rect.y = y + GTK_WIDGET(ptr)->allocation.y;
+  rect.width = width;
+  rect.height = height;
+
+  gdk_threads_enter ();
+
+  gdk_window_invalidate_rect (GTK_WIDGET (ptr)->window, &rect, 0);
+  gdk_window_process_all_updates();
+
+  gdk_threads_leave ();
+}
+
 JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GtkComponentPeer_connectJObject
   (JNIEnv *env, jobject obj)
 {
index 6004847..64b2995 100644 (file)
@@ -1012,12 +1012,21 @@ pre_event_handler (GtkWidget *widget, GdkEvent *event, jobject peer)
       break;
     case GDK_EXPOSE:
       {
-       (*gdk_env)->CallVoidMethod (gdk_env, peer,
-                                   postExposeEventID,
-                                   (jint)event->expose.area.x,
-                                   (jint)event->expose.area.y,
-                                   (jint)event->expose.area.width,
-                                   (jint)event->expose.area.height);
+        // This filters out unwanted feedback expose events from gtk/X
+        // when we explictly invalidate and update heavyweight components,
+        // thus avoiding an infinite loop.
+        // FIXME: I'm not quite sure why we're getting these expose events. 
+        //        Maybe there is a way to avoid them?
+        if((event->any.window == widget->window && event->any.send_event)
+           || GTK_IS_LAYOUT(widget))
+          {
+           (*gdk_env)->CallVoidMethod (gdk_env, peer,
+                                       postExposeEventID,
+                                       (jint)event->expose.area.x,
+                                       (jint)event->expose.area.y,
+                                       (jint)event->expose.area.width,
+                                       (jint)event->expose.area.height);
+          }
       }
       break;
     case GDK_FOCUS_CHANGE: