Fix memory leak in the global AWT listener
authorSergey Malenkov <Sergey.Malenkov@jetbrains.com>
Thu, 10 Mar 2016 19:55:44 +0000 (22:55 +0300)
committerSergey Malenkov <Sergey.Malenkov@jetbrains.com>
Thu, 10 Mar 2016 20:04:51 +0000 (23:04 +0300)
platform/platform-api/src/com/intellij/util/ui/ButtonlessScrollBarUI.java

index ced4089f0a84b4482f4becf983a29053233d5886..cc45e4795f5934e3a120ac634cb7707c87553d84 100644 (file)
@@ -39,6 +39,7 @@ import javax.swing.plaf.ScrollBarUI;
 import javax.swing.plaf.basic.BasicScrollBarUI;
 import java.awt.*;
 import java.awt.event.*;
+import java.lang.ref.WeakReference;
 import java.lang.reflect.Method;
 
 /**
@@ -99,7 +100,8 @@ public class ButtonlessScrollBarUI extends BasicScrollBarUI {
   private final MouseMotionAdapter myMouseMotionListener;
   private final MouseAdapter myMouseListener;
   private final HierarchyListener myHierarchyListener;
-  private final AWTEventListener myAWTMouseListener;
+  private final AWTEventListener myAWTMouseListener; // holds strong reference while a scroll bar in the hierarchy
+  private final AWTEventListener myWeakListener;
   private final NSScrollerHelper.ScrollbarStyleListener myNSScrollerListener;
   private boolean myGlobalListenersAdded;
 
@@ -248,6 +250,7 @@ public class ButtonlessScrollBarUI extends BasicScrollBarUI {
         }
       }
     };
+    myWeakListener = new WeakLestener(myAWTMouseListener);
     myNSScrollerListener = new NSScrollerHelper.ScrollbarStyleListener() {
       @Override
       public void styleChanged() {
@@ -507,13 +510,13 @@ public class ButtonlessScrollBarUI extends BasicScrollBarUI {
     boolean shouldAdd = scrollbar.isDisplayable();
 
     if (myGlobalListenersAdded && (!shouldAdd || forceRemove)) {
-      Toolkit.getDefaultToolkit().removeAWTEventListener(myAWTMouseListener);
+      Toolkit.getDefaultToolkit().removeAWTEventListener(myWeakListener);
       NSScrollerHelper.removeScrollbarStyleListener(myNSScrollerListener);
       myGlobalListenersAdded = false;
     }
 
     if (!myGlobalListenersAdded && shouldAdd && !forceRemove) {
-      Toolkit.getDefaultToolkit().addAWTEventListener(myAWTMouseListener, AWTEvent.MOUSE_MOTION_EVENT_MASK);
+      Toolkit.getDefaultToolkit().addAWTEventListener(myWeakListener, AWTEvent.MOUSE_MOTION_EVENT_MASK);
       NSScrollerHelper.addScrollbarStyleListener(myNSScrollerListener);
       myGlobalListenersAdded = true;
     }
@@ -1136,4 +1139,23 @@ public class ButtonlessScrollBarUI extends BasicScrollBarUI {
       }
     }
   }
+
+  private static final class WeakLestener implements AWTEventListener {
+    private final WeakReference<AWTEventListener> myReference;
+
+    private WeakLestener(AWTEventListener listener) {
+      myReference = new WeakReference<AWTEventListener>(listener);
+    }
+
+    @Override
+    public void eventDispatched(AWTEvent event) {
+      AWTEventListener listener = myReference.get();
+      if (listener != null) {
+        listener.eventDispatched(event);
+      }
+      else {
+        Toolkit.getDefaultToolkit().removeAWTEventListener(this);
+      }
+    }
+  }
 }