From dc5a3e01ac8108f85c58f2e51e05baf72f178129 Mon Sep 17 00:00:00 2001 From: Lyubomir Marinov Date: Thu, 9 Feb 2012 18:06:13 +0000 Subject: [PATCH] Fixes (on Java 1.6+ and not 1.5) a leak of pretty much all Window instances created by the application. ChatWindow and CallDialog are still leaked though because they have other, remaining retain paths. --- .../java/sip/communicator/util/GuiUtils.java | 126 ++++++++++++++---- 1 file changed, 103 insertions(+), 23 deletions(-) diff --git a/src/net/java/sip/communicator/util/GuiUtils.java b/src/net/java/sip/communicator/util/GuiUtils.java index 76b77625c..c1b5c6eb7 100644 --- a/src/net/java/sip/communicator/util/GuiUtils.java +++ b/src/net/java/sip/communicator/util/GuiUtils.java @@ -9,7 +9,9 @@ import java.awt.*; import java.awt.font.*; import java.awt.geom.*; +import java.lang.reflect.*; import java.util.*; +import java.util.List; import javax.swing.*; @@ -18,20 +20,19 @@ * some special operations with strings. * * @author Yana Stamcheva - * @author Lubomir Marinov + * @author Lyubomir Marinov * @author Adam Netocny */ public class GuiUtils { /** - * List of all windows owned by the app. + * The list of all Windows owned by this application. */ - private static final ArrayList WINDOW_LIST - = new ArrayList(); + private static final List WINDOW_LIST; - private static Calendar c1 = Calendar.getInstance(); + private static final Calendar c1 = Calendar.getInstance(); - private static Calendar c2 = Calendar.getInstance(); + private static final Calendar c2 = Calendar.getInstance(); /** * Number of milliseconds in a second. @@ -57,9 +58,12 @@ public class GuiUtils // normalization purposes. Non-European digits that may be used in phone numbers are mapped to a // European equivalent. private static final Map DIGIT_MAPPINGS; - static { + + static + { HashMap digitMap = new HashMap(50); + digitMap.put('0', '0'); digitMap.put('\uFF10', '0'); // Fullwidth digit 0 digitMap.put('\u0660', '0'); // Arabic-indic digit 0 @@ -91,6 +95,30 @@ public class GuiUtils digitMap.put('\uFF19', '9'); // Fullwidth digit 9 digitMap.put('\u0669', '9'); // Arabic-indic digit 9 DIGIT_MAPPINGS = Collections.unmodifiableMap(digitMap); + + /* + * WINDOW_LIST is flawed because there are more calls to addWindow than + * to removeWindow. Java 6 has introduced Window#getWindows so try to + * use it instead. + */ + Method Window_getWindows = null; + + try + { + Window_getWindows = Window.class.getMethod("getWindows"); + } + catch (NoSuchMethodException nsme) + { + /* + * Ignore the exception because we are just checking whether the + * method exists. + */ + } + catch (SecurityException se) + { + } + WINDOW_LIST + = (Window_getWindows == null) ? new ArrayList() : null; } /** @@ -142,9 +170,7 @@ public static Dimension getStringSize(Component c, String text) public static Rectangle2D getDefaultStringSize(String text) { Font font = UIManager.getFont("Label.font"); - FontRenderContext frc = new FontRenderContext(null, true, false); - TextLayout layout = new TextLayout(text, font, frc); return layout.getBounds(); @@ -161,12 +187,11 @@ public static Rectangle2D getDefaultStringSize(String text) public static int countOccurrences(String text, char needle) { int count = 0; + for (char c : text.toCharArray()) { if (c == needle) - { ++count; - } } return count; } @@ -459,15 +484,60 @@ public static String formatSeconds(long millis) */ public static Window[] getWindows() { - Window[] retVal = new Window[WINDOW_LIST.size()]; + if (WINDOW_LIST == null) + { + Method Window_getWindows = null; + + try + { + Window_getWindows = Window.class.getMethod("getWindows"); + } + catch (NoSuchMethodException nsme) + { + /* Ignore it because we cannot really do anything useful. */ + } + catch (SecurityException se) + { + } + + Object windows = null; + + if (Window_getWindows != null) + { + try + { + windows = Window_getWindows.invoke(null); + } + catch (ExceptionInInitializerError eiie) + { + /* Ignore it because we cannot really do anything useful. */ + } + catch (IllegalAccessException iae) + { + } + catch (IllegalArgumentException iae) + { + } + catch (InvocationTargetException ite) + { + } + catch (NullPointerException npe) + { + } + } - int c = 0; - for(Window w : WINDOW_LIST) + return + (windows instanceof Window[]) + ? (Window[]) windows + : new Window[0]; + } + else { - retVal[c++] = w; + synchronized (WINDOW_LIST) + { + return WINDOW_LIST.toArray(new Window[WINDOW_LIST.size()]); + } } - - return retVal; } /** @@ -476,7 +546,14 @@ public static Window[] getWindows() */ public static void addWindow(Window w) { - WINDOW_LIST.add(w); + if (WINDOW_LIST != null) + { + synchronized (WINDOW_LIST) + { + if (!WINDOW_LIST.contains(w)) + WINDOW_LIST.add(w); + } + } } /** @@ -485,7 +562,13 @@ public static void addWindow(Window w) */ public static void removeWindow(Window w) { - WINDOW_LIST.remove(w); + if (WINDOW_LIST != null) + { + synchronized (WINDOW_LIST) + { + WINDOW_LIST.remove(w); + } + } } /** @@ -513,12 +596,11 @@ public static void updateComponentTreeUI(Component c) */ public static int getComponentIndex(Component c, Container container) { - for (int i = 0; i < container.getComponentCount(); i++) + for (int i = 0, count = container.getComponentCount(); i < count; i++) { if (container.getComponent(i).equals(c)) return i; } - return -1; } @@ -552,9 +634,7 @@ else if (c instanceof java.awt.Container) if (children != null) { for(int i = 0; i < children.length; i++) - { updateComponentTreeUI0(children[i]); - } } } }