2015-10-22 00:25:12 +02:00
|
|
|
/*******************************************************************************
|
2021-01-09 14:26:49 +01:00
|
|
|
* Copyright (c) 2015-2021 MINRES Technologies GmbH and others.
|
2015-10-22 00:25:12 +02:00
|
|
|
* All rights reserved. This program and the accompanying materials
|
|
|
|
* are made available under the terms of the Eclipse Public License v1.0
|
|
|
|
* which accompanies this distribution, and is available at
|
|
|
|
* http://www.eclipse.org/legal/epl-v10.html
|
|
|
|
*
|
|
|
|
* Contributors:
|
|
|
|
* MINRES Technologies GmbH - initial API and implementation
|
|
|
|
*******************************************************************************/
|
2015-11-12 23:35:13 +01:00
|
|
|
package com.minres.scviewer.e4.application.internal.status;
|
2021-01-09 22:23:38 +01:00
|
|
|
|
|
|
|
import java.lang.ref.WeakReference;
|
2015-10-22 00:05:29 +02:00
|
|
|
import java.lang.reflect.Method;
|
|
|
|
|
|
|
|
import org.eclipse.core.runtime.preferences.IEclipsePreferences;
|
|
|
|
import org.eclipse.core.runtime.preferences.IEclipsePreferences.IPreferenceChangeListener;
|
|
|
|
import org.eclipse.jface.action.Action;
|
|
|
|
import org.eclipse.jface.action.IAction;
|
|
|
|
import org.eclipse.jface.action.IMenuManager;
|
|
|
|
import org.eclipse.jface.action.MenuManager;
|
|
|
|
import org.eclipse.jface.resource.ImageDescriptor;
|
|
|
|
import org.eclipse.swt.SWT;
|
|
|
|
import org.eclipse.swt.graphics.Color;
|
|
|
|
import org.eclipse.swt.graphics.GC;
|
|
|
|
import org.eclipse.swt.graphics.Image;
|
|
|
|
import org.eclipse.swt.graphics.Point;
|
|
|
|
import org.eclipse.swt.graphics.Rectangle;
|
|
|
|
import org.eclipse.swt.widgets.Canvas;
|
|
|
|
import org.eclipse.swt.widgets.Composite;
|
|
|
|
import org.eclipse.swt.widgets.Display;
|
|
|
|
import org.eclipse.swt.widgets.Listener;
|
|
|
|
import org.eclipse.swt.widgets.Menu;
|
|
|
|
import org.eclipse.wb.swt.ResourceManager;
|
2015-11-13 18:58:14 +01:00
|
|
|
import org.eclipse.wb.swt.SWTResourceManager;
|
2015-10-24 23:15:07 +02:00
|
|
|
import org.osgi.service.prefs.Preferences;
|
2015-10-22 00:05:29 +02:00
|
|
|
|
2021-01-09 20:10:58 +01:00
|
|
|
import com.minres.scviewer.e4.application.Constants;
|
|
|
|
|
2015-10-22 00:05:29 +02:00
|
|
|
/**
|
2021-01-09 22:23:38 +01:00
|
|
|
* The Heap Status control, which shows the heap usage statistics in the window
|
|
|
|
* trim. Part of the code is taken from the eclipse internal implementation
|
2015-10-22 00:05:29 +02:00
|
|
|
*/
|
|
|
|
public class HeapStatus extends Composite {
|
|
|
|
|
2015-11-22 12:47:07 +01:00
|
|
|
/** The armed. */
|
2015-10-22 00:05:29 +02:00
|
|
|
private boolean armed;
|
2021-01-09 22:23:38 +01:00
|
|
|
|
2015-11-22 12:47:07 +01:00
|
|
|
/** The gc image. */
|
2015-10-22 00:05:29 +02:00
|
|
|
private Image gcImage;
|
2021-01-09 22:23:38 +01:00
|
|
|
|
2015-11-22 12:47:07 +01:00
|
|
|
/** The disabled gc image. */
|
2015-10-22 00:05:29 +02:00
|
|
|
private Image disabledGcImage;
|
2021-01-09 22:23:38 +01:00
|
|
|
|
2015-11-22 12:47:07 +01:00
|
|
|
/** The arm col. */
|
2021-01-09 23:24:00 +01:00
|
|
|
private Color bgCol;
|
|
|
|
|
|
|
|
/** The used mem col. */
|
|
|
|
private Color usedMemCol;
|
|
|
|
|
|
|
|
/** The low mem col. */
|
|
|
|
private Color lowMemCol;
|
|
|
|
|
|
|
|
/** The free mem col. */
|
|
|
|
private Color freeMemCol;
|
|
|
|
|
|
|
|
/** The top left col. */
|
|
|
|
private Color topLeftCol;
|
|
|
|
|
|
|
|
/** The bottom right col. */
|
|
|
|
private Color bottomRightCol;
|
|
|
|
|
|
|
|
/** The sep col. */
|
|
|
|
private Color sepCol;
|
|
|
|
|
|
|
|
/** The text col. */
|
|
|
|
private Color textCol;
|
|
|
|
|
|
|
|
/** The mark col. */
|
|
|
|
private Color markCol;
|
|
|
|
|
|
|
|
/** The arm col. */
|
|
|
|
private Color armCol;
|
2021-01-09 22:23:38 +01:00
|
|
|
|
|
|
|
/** The button. */
|
|
|
|
private Canvas button;
|
|
|
|
|
2015-11-22 12:47:07 +01:00
|
|
|
/** The preferences. */
|
2015-10-24 23:15:07 +02:00
|
|
|
private Preferences preferences;
|
2021-01-09 22:23:38 +01:00
|
|
|
|
2015-11-22 12:47:07 +01:00
|
|
|
/** The update interval. */
|
2015-10-22 00:05:29 +02:00
|
|
|
private int updateInterval;
|
2021-01-09 22:23:38 +01:00
|
|
|
|
2015-11-22 12:47:07 +01:00
|
|
|
/** The show max. */
|
2015-10-22 00:05:29 +02:00
|
|
|
private boolean showMax;
|
2021-01-09 22:23:38 +01:00
|
|
|
|
|
|
|
/** The total mem. */
|
|
|
|
private long totalMem;
|
|
|
|
|
|
|
|
/** The prev total mem. */
|
|
|
|
private long prevTotalMem = -1L;
|
|
|
|
|
|
|
|
/** The prev used mem. */
|
|
|
|
private long prevUsedMem = -1L;
|
|
|
|
|
|
|
|
/** The has changed. */
|
|
|
|
private boolean hasChanged;
|
|
|
|
|
|
|
|
/** The used mem. */
|
|
|
|
private long usedMem;
|
|
|
|
|
|
|
|
/** The mark. */
|
|
|
|
private long mark = -1;
|
|
|
|
|
|
|
|
/** The img bounds. */
|
|
|
|
// start with 12x12
|
|
|
|
private Rectangle imgBounds = new Rectangle(0, 0, 12, 12);
|
|
|
|
|
2015-11-22 12:47:07 +01:00
|
|
|
/** The max mem. */
|
2015-10-22 00:05:29 +02:00
|
|
|
private long maxMem = Long.MAX_VALUE;
|
2021-01-09 22:23:38 +01:00
|
|
|
|
2015-11-22 12:47:07 +01:00
|
|
|
/** The max mem known. */
|
2015-10-22 00:05:29 +02:00
|
|
|
private boolean maxMemKnown;
|
2021-01-09 22:23:38 +01:00
|
|
|
|
2015-11-22 12:47:07 +01:00
|
|
|
/** The low mem threshold. */
|
2015-10-22 00:05:29 +02:00
|
|
|
private float lowMemThreshold = 0.05f;
|
2021-01-09 22:23:38 +01:00
|
|
|
|
2015-11-22 12:47:07 +01:00
|
|
|
/** The show low mem threshold. */
|
2015-10-22 00:05:29 +02:00
|
|
|
private boolean showLowMemThreshold = true;
|
2021-01-09 22:23:38 +01:00
|
|
|
|
2015-11-22 12:47:07 +01:00
|
|
|
/** The update tooltip. */
|
2015-10-22 00:05:29 +02:00
|
|
|
private boolean updateTooltip = false;
|
|
|
|
|
2015-11-22 12:47:07 +01:00
|
|
|
/** The is in gc. */
|
2015-10-22 00:05:29 +02:00
|
|
|
protected volatile boolean isInGC = false;
|
|
|
|
|
2021-01-09 22:23:38 +01:00
|
|
|
/** The timer. */
|
|
|
|
private final Runnable timer = new Runnable() {
|
2015-10-22 00:05:29 +02:00
|
|
|
@Override
|
2021-01-09 22:23:38 +01:00
|
|
|
public void run() {
|
|
|
|
if (!isDisposed()) {
|
|
|
|
updateStats();
|
|
|
|
if (hasChanged) {
|
|
|
|
if (updateTooltip) {
|
|
|
|
updateToolTip();
|
|
|
|
}
|
|
|
|
redraw();
|
|
|
|
hasChanged = false;
|
|
|
|
}
|
|
|
|
getDisplay().timerExec(updateInterval, this);
|
2015-10-22 00:05:29 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2021-01-09 22:23:38 +01:00
|
|
|
/** The pref listener. */
|
|
|
|
private final IPreferenceChangeListener prefListener = event -> {
|
|
|
|
if (IHeapStatusConstants.PREF_UPDATE_INTERVAL.equals(event.getKey())) {
|
|
|
|
setUpdateIntervalInMS(preferences.getInt(IHeapStatusConstants.PREF_UPDATE_INTERVAL, 100));
|
|
|
|
} else if (IHeapStatusConstants.PREF_SHOW_MAX.equals(event.getKey())) {
|
|
|
|
showMax = preferences.getBoolean(IHeapStatusConstants.PREF_SHOW_MAX, true);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Creates a new heap status control with the given parent, and using the given
|
|
|
|
* preference store to obtain settings such as the refresh interval.
|
|
|
|
*
|
|
|
|
* @param parent the parent composite
|
|
|
|
* @param preferences the preference store
|
|
|
|
*/
|
2015-10-24 23:15:07 +02:00
|
|
|
public HeapStatus(Composite parent, Preferences preferences) {
|
2015-10-22 00:05:29 +02:00
|
|
|
super(parent, SWT.NONE);
|
|
|
|
|
|
|
|
maxMem = getMaxMem();
|
|
|
|
maxMemKnown = maxMem != Long.MAX_VALUE;
|
|
|
|
|
2021-01-09 22:23:38 +01:00
|
|
|
this.preferences = preferences;
|
|
|
|
if (this.preferences instanceof IEclipsePreferences)
|
|
|
|
((IEclipsePreferences) this.preferences).addPreferenceChangeListener(prefListener);
|
2015-10-22 00:05:29 +02:00
|
|
|
|
2021-01-09 22:23:38 +01:00
|
|
|
setUpdateIntervalInMS(preferences.getInt(IHeapStatusConstants.PREF_UPDATE_INTERVAL, 100));
|
|
|
|
showMax = preferences.getBoolean(IHeapStatusConstants.PREF_SHOW_MAX, true);
|
2015-10-22 00:05:29 +02:00
|
|
|
|
2021-01-09 22:23:38 +01:00
|
|
|
button = new Canvas(this, SWT.NONE);
|
|
|
|
button.setToolTipText("Run Garbage Collection");
|
2015-10-22 00:05:29 +02:00
|
|
|
|
2021-01-09 20:10:58 +01:00
|
|
|
ImageDescriptor imageDesc = ResourceManager.getPluginImageDescriptor(Constants.PLUGIN_ID, "icons/trash.png"); //$NON-NLS-1$
|
2015-10-22 00:05:29 +02:00
|
|
|
Display display = getDisplay();
|
|
|
|
gcImage = imageDesc.createImage();
|
|
|
|
if (gcImage != null) {
|
|
|
|
imgBounds = gcImage.getBounds();
|
|
|
|
disabledGcImage = new Image(display, gcImage, SWT.IMAGE_DISABLE);
|
|
|
|
}
|
|
|
|
usedMemCol = display.getSystemColor(SWT.COLOR_INFO_BACKGROUND);
|
2021-01-09 22:23:38 +01:00
|
|
|
lowMemCol = SWTResourceManager.getColor(255, 70, 70); // medium red
|
|
|
|
freeMemCol = SWTResourceManager.getColor(255, 190, 125); // light orange
|
2015-11-13 18:58:14 +01:00
|
|
|
bgCol = SWTResourceManager.getColor(SWT.COLOR_WIDGET_BACKGROUND);
|
|
|
|
sepCol = topLeftCol = armCol = SWTResourceManager.getColor(SWT.COLOR_WIDGET_NORMAL_SHADOW);
|
|
|
|
bottomRightCol = SWTResourceManager.getColor(SWT.COLOR_WIDGET_HIGHLIGHT_SHADOW);
|
|
|
|
markCol = textCol = SWTResourceManager.getColor(SWT.COLOR_INFO_FOREGROUND);
|
2015-10-22 00:05:29 +02:00
|
|
|
|
|
|
|
createContextMenu();
|
|
|
|
|
2021-01-09 22:23:38 +01:00
|
|
|
Listener listener = event -> {
|
|
|
|
switch (event.type) {
|
|
|
|
case SWT.Dispose:
|
|
|
|
doDispose();
|
|
|
|
break;
|
|
|
|
case SWT.Resize:
|
|
|
|
Rectangle rect = getClientArea();
|
|
|
|
button.setBounds(rect.width - imgBounds.width - 1, 1, imgBounds.width, rect.height - 2);
|
|
|
|
break;
|
|
|
|
case SWT.Paint:
|
|
|
|
if (event.widget == HeapStatus.this) {
|
|
|
|
paintComposite(event.gc);
|
|
|
|
} else if (event.widget == button) {
|
|
|
|
paintButton(event.gc);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case SWT.MouseUp:
|
|
|
|
if (event.button == 1 && !isInGC) {
|
|
|
|
arm(false);
|
|
|
|
gc();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case SWT.MouseDown:
|
|
|
|
if (event.button == 1) {
|
|
|
|
if (event.widget == HeapStatus.this) {
|
|
|
|
setMark();
|
|
|
|
} else if (event.widget == button && !isInGC)
|
|
|
|
arm(true);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case SWT.MouseEnter:
|
|
|
|
HeapStatus.this.updateTooltip = true;
|
|
|
|
updateToolTip();
|
|
|
|
break;
|
|
|
|
case SWT.MouseExit:
|
|
|
|
if (event.widget == HeapStatus.this) {
|
|
|
|
HeapStatus.this.updateTooltip = false;
|
|
|
|
} else if (event.widget == button) {
|
|
|
|
arm(false);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
addListener(SWT.Dispose, listener);
|
|
|
|
addListener(SWT.MouseDown, listener);
|
|
|
|
addListener(SWT.Paint, listener);
|
|
|
|
addListener(SWT.Resize, listener);
|
|
|
|
addListener(SWT.MouseEnter, listener);
|
|
|
|
addListener(SWT.MouseExit, listener);
|
|
|
|
button.addListener(SWT.MouseDown, listener);
|
|
|
|
button.addListener(SWT.MouseExit, listener);
|
|
|
|
button.addListener(SWT.MouseUp, listener);
|
|
|
|
button.addListener(SWT.Paint, listener);
|
2015-10-22 00:05:29 +02:00
|
|
|
|
|
|
|
// make sure stats are updated before first paint
|
|
|
|
updateStats();
|
|
|
|
|
2021-01-09 22:23:38 +01:00
|
|
|
getDisplay().asyncExec(() -> {
|
|
|
|
if (!isDisposed()) {
|
|
|
|
getDisplay().timerExec(updateInterval, timer);
|
2015-10-22 00:05:29 +02:00
|
|
|
}
|
|
|
|
});
|
2021-01-09 22:23:38 +01:00
|
|
|
}
|
2015-10-22 00:05:29 +02:00
|
|
|
|
2021-01-09 23:24:00 +01:00
|
|
|
/**
|
|
|
|
* Sets the background.
|
|
|
|
*
|
|
|
|
* @param color the new background
|
|
|
|
*/
|
2021-01-09 22:23:38 +01:00
|
|
|
/*
|
|
|
|
* (non-Javadoc)
|
|
|
|
*
|
|
|
|
* @see
|
|
|
|
* org.eclipse.swt.widgets.Control#setBackground(org.eclipse.swt.graphics.Color)
|
2015-11-22 12:47:07 +01:00
|
|
|
*/
|
2015-10-22 00:05:29 +02:00
|
|
|
@Override
|
|
|
|
public void setBackground(Color color) {
|
|
|
|
bgCol = color;
|
|
|
|
button.redraw();
|
|
|
|
button.update();
|
|
|
|
}
|
|
|
|
|
2021-01-09 23:24:00 +01:00
|
|
|
/**
|
|
|
|
* Sets the foreground.
|
|
|
|
*
|
|
|
|
* @param color the new foreground
|
|
|
|
*/
|
2021-01-09 22:23:38 +01:00
|
|
|
/*
|
|
|
|
* (non-Javadoc)
|
|
|
|
*
|
|
|
|
* @see
|
|
|
|
* org.eclipse.swt.widgets.Control#setForeground(org.eclipse.swt.graphics.Color)
|
2015-11-22 12:47:07 +01:00
|
|
|
*/
|
2015-10-22 00:05:29 +02:00
|
|
|
@Override
|
|
|
|
public void setForeground(Color color) {
|
|
|
|
if (color == null) {
|
|
|
|
usedMemCol = getDisplay().getSystemColor(SWT.COLOR_INFO_BACKGROUND);
|
|
|
|
} else {
|
|
|
|
usedMemCol = color;
|
|
|
|
}
|
|
|
|
|
|
|
|
button.redraw();
|
|
|
|
button.update();
|
|
|
|
}
|
|
|
|
|
2021-01-09 23:24:00 +01:00
|
|
|
/**
|
|
|
|
* Gets the foreground.
|
|
|
|
*
|
|
|
|
* @return the foreground
|
|
|
|
*/
|
2021-01-09 22:23:38 +01:00
|
|
|
/*
|
|
|
|
* (non-Javadoc)
|
|
|
|
*
|
2015-11-22 12:47:07 +01:00
|
|
|
* @see org.eclipse.swt.widgets.Control#getForeground()
|
|
|
|
*/
|
2015-10-22 00:05:29 +02:00
|
|
|
@Override
|
|
|
|
public Color getForeground() {
|
|
|
|
if (usedMemCol != null) {
|
|
|
|
return usedMemCol;
|
|
|
|
}
|
|
|
|
return getDisplay().getSystemColor(SWT.COLOR_INFO_BACKGROUND);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the maximum memory limit, or Long.MAX_VALUE if the max is not known.
|
2015-11-22 12:47:07 +01:00
|
|
|
*
|
|
|
|
* @return the max mem
|
2015-10-22 00:05:29 +02:00
|
|
|
*/
|
|
|
|
private long getMaxMem() {
|
|
|
|
long max = Long.MAX_VALUE;
|
|
|
|
try {
|
|
|
|
// Must use reflect to allow compilation against JCL/Foundation
|
2021-01-09 20:10:58 +01:00
|
|
|
Method maxMemMethod = Runtime.class.getMethod("maxMemory"); //$NON-NLS-1$
|
|
|
|
Object o = maxMemMethod.invoke(Runtime.getRuntime());
|
2015-10-22 00:05:29 +02:00
|
|
|
if (o instanceof Long) {
|
|
|
|
max = ((Long) o).longValue();
|
|
|
|
}
|
2021-01-09 22:23:38 +01:00
|
|
|
} catch (Exception e) {
|
|
|
|
// ignore if method missing or if there are other failures trying to determine
|
|
|
|
// the max
|
2015-10-22 00:05:29 +02:00
|
|
|
}
|
|
|
|
return max;
|
|
|
|
}
|
|
|
|
|
2015-11-22 12:47:07 +01:00
|
|
|
/**
|
|
|
|
* Sets the update interval in ms.
|
|
|
|
*
|
|
|
|
* @param interval the new update interval in ms
|
|
|
|
*/
|
2015-10-22 00:05:29 +02:00
|
|
|
private void setUpdateIntervalInMS(int interval) {
|
|
|
|
updateInterval = Math.max(100, interval);
|
|
|
|
}
|
|
|
|
|
2015-11-22 12:47:07 +01:00
|
|
|
/**
|
|
|
|
* Do dispose.
|
|
|
|
*/
|
2015-10-22 00:05:29 +02:00
|
|
|
private void doDispose() {
|
2021-01-09 22:23:38 +01:00
|
|
|
if (preferences instanceof IEclipsePreferences)
|
|
|
|
((IEclipsePreferences) preferences).removePreferenceChangeListener(prefListener);
|
|
|
|
if (gcImage != null) {
|
2015-10-22 00:05:29 +02:00
|
|
|
gcImage.dispose();
|
|
|
|
}
|
|
|
|
if (disabledGcImage != null) {
|
|
|
|
disabledGcImage.dispose();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-09 23:24:00 +01:00
|
|
|
/**
|
|
|
|
* Compute size.
|
|
|
|
*
|
|
|
|
* @param wHint the w hint
|
|
|
|
* @param hHint the h hint
|
|
|
|
* @param changed the changed
|
|
|
|
* @return the point
|
|
|
|
*/
|
2021-01-09 22:23:38 +01:00
|
|
|
/*
|
|
|
|
* (non-Javadoc)
|
|
|
|
*
|
2015-11-22 12:47:07 +01:00
|
|
|
* @see org.eclipse.swt.widgets.Composite#computeSize(int, int, boolean)
|
|
|
|
*/
|
2015-10-22 00:05:29 +02:00
|
|
|
@Override
|
|
|
|
public Point computeSize(int wHint, int hHint, boolean changed) {
|
2021-01-09 22:23:38 +01:00
|
|
|
GC gc = new GC(this);
|
|
|
|
Point p = gc.textExtent("MMMMMMMMMMMM");
|
|
|
|
int height = imgBounds.height;
|
|
|
|
// choose the largest of
|
|
|
|
// - Text height + margins
|
|
|
|
// - Image height + margins
|
|
|
|
// - Default Trim heightin
|
|
|
|
height = Math.max(height, p.y) + 4;
|
|
|
|
height = Math.max(TrimUtil.TRIM_DEFAULT_HEIGHT, height);
|
|
|
|
gc.dispose();
|
2015-10-22 00:05:29 +02:00
|
|
|
return new Point(p.x + 15, height);
|
|
|
|
}
|
|
|
|
|
2021-01-09 22:23:38 +01:00
|
|
|
/**
|
|
|
|
* Arm.
|
|
|
|
*
|
|
|
|
* @param armed the armed
|
|
|
|
*/
|
|
|
|
private void arm(boolean armed) {
|
|
|
|
if (this.armed == armed) {
|
2015-10-22 00:05:29 +02:00
|
|
|
return;
|
|
|
|
}
|
2021-01-09 22:23:38 +01:00
|
|
|
this.armed = armed;
|
|
|
|
button.redraw();
|
|
|
|
button.update();
|
|
|
|
}
|
2015-10-22 00:05:29 +02:00
|
|
|
|
2015-11-22 12:47:07 +01:00
|
|
|
/**
|
|
|
|
* Gc running.
|
|
|
|
*
|
|
|
|
* @param isInGC the is in gc
|
|
|
|
*/
|
2015-10-22 00:05:29 +02:00
|
|
|
private void gcRunning(boolean isInGC) {
|
|
|
|
if (this.isInGC == isInGC) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
this.isInGC = isInGC;
|
2021-01-09 22:23:38 +01:00
|
|
|
button.redraw();
|
|
|
|
button.update();
|
2015-10-22 00:05:29 +02:00
|
|
|
}
|
|
|
|
|
2021-01-09 22:23:38 +01:00
|
|
|
/**
|
|
|
|
* Creates the context menu.
|
|
|
|
*/
|
|
|
|
private void createContextMenu() {
|
|
|
|
MenuManager menuMgr = new MenuManager();
|
|
|
|
menuMgr.setRemoveAllWhenShown(true);
|
|
|
|
menuMgr.addMenuListener(mgr -> fillMenu(mgr));
|
|
|
|
Menu menu = menuMgr.createContextMenu(this);
|
|
|
|
setMenu(menu);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Fill menu.
|
|
|
|
*
|
|
|
|
* @param menuMgr the menu mgr
|
|
|
|
*/
|
|
|
|
private void fillMenu(IMenuManager menuMgr) {
|
|
|
|
menuMgr.add(new SetMarkAction());
|
|
|
|
menuMgr.add(new ClearMarkAction());
|
|
|
|
menuMgr.add(new ShowMaxAction());
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sets the mark to the current usedMem level.
|
|
|
|
*/
|
|
|
|
private void setMark() {
|
|
|
|
updateStats(); // get up-to-date stats before taking the mark
|
|
|
|
mark = usedMem;
|
|
|
|
hasChanged = true;
|
|
|
|
redraw();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Clears the mark.
|
|
|
|
*/
|
|
|
|
private void clearMark() {
|
|
|
|
mark = -1;
|
|
|
|
hasChanged = true;
|
|
|
|
redraw();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Gc.
|
|
|
|
*/
|
|
|
|
private void gc() {
|
2015-10-22 00:05:29 +02:00
|
|
|
gcRunning(true);
|
|
|
|
Thread t = new Thread() {
|
|
|
|
@Override
|
|
|
|
public void run() {
|
|
|
|
busyGC();
|
2021-01-09 22:23:38 +01:00
|
|
|
getDisplay().asyncExec(() -> {
|
|
|
|
if (!isDisposed())
|
|
|
|
gcRunning(false);
|
|
|
|
});
|
2015-10-22 00:05:29 +02:00
|
|
|
}
|
|
|
|
};
|
2021-01-14 23:14:22 +01:00
|
|
|
t.setDaemon(true);
|
2015-10-22 00:05:29 +02:00
|
|
|
t.start();
|
2021-01-09 22:23:38 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Busy gc.
|
|
|
|
*/
|
|
|
|
private void busyGC() {
|
|
|
|
Object obj = new Object();
|
|
|
|
WeakReference<Object> ref = new WeakReference<>(obj);
|
|
|
|
obj = null;
|
|
|
|
do {
|
|
|
|
System.gc();
|
|
|
|
System.runFinalization();
|
|
|
|
} while (ref.get() != null);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Paint button.
|
|
|
|
*
|
|
|
|
* @param gc the gc
|
|
|
|
*/
|
|
|
|
private void paintButton(GC gc) {
|
|
|
|
Rectangle rect = button.getClientArea();
|
2015-10-22 00:05:29 +02:00
|
|
|
if (isInGC) {
|
|
|
|
if (disabledGcImage != null) {
|
|
|
|
int buttonY = (rect.height - imgBounds.height) / 2 + rect.y;
|
|
|
|
gc.drawImage(disabledGcImage, rect.x, buttonY);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
2021-01-09 22:23:38 +01:00
|
|
|
if (armed) {
|
|
|
|
gc.setBackground(armCol);
|
|
|
|
gc.fillRectangle(rect.x, rect.y, rect.width, rect.height);
|
|
|
|
}
|
|
|
|
if (gcImage != null) {
|
2015-10-22 00:05:29 +02:00
|
|
|
int by = (rect.height - imgBounds.height) / 2 + rect.y; // button y
|
|
|
|
gc.drawImage(gcImage, rect.x, by);
|
2021-01-09 22:23:38 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Paint composite.
|
|
|
|
*
|
|
|
|
* @param gc the gc
|
|
|
|
*/
|
|
|
|
private void paintComposite(GC gc) {
|
2015-10-22 00:05:29 +02:00
|
|
|
if (showMax && maxMemKnown) {
|
|
|
|
paintCompositeMaxKnown(gc);
|
|
|
|
} else {
|
|
|
|
paintCompositeMaxUnknown(gc);
|
|
|
|
}
|
2021-01-09 22:23:38 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Paint composite max unknown.
|
|
|
|
*
|
|
|
|
* @param gc the gc
|
|
|
|
*/
|
|
|
|
private void paintCompositeMaxUnknown(GC gc) {
|
|
|
|
Rectangle rect = getClientArea();
|
|
|
|
int x = rect.x;
|
|
|
|
int y = rect.y;
|
|
|
|
int w = rect.width;
|
|
|
|
int h = rect.height;
|
|
|
|
int bw = imgBounds.width; // button width
|
|
|
|
int dx = x + w - bw - 2; // divider x
|
|
|
|
int sw = w - bw - 3; // status width
|
|
|
|
int uw = (int) (sw * usedMem / totalMem); // used mem width
|
|
|
|
int ux = x + 1 + uw; // used mem right edge
|
|
|
|
if (bgCol != null) {
|
2015-10-22 00:05:29 +02:00
|
|
|
gc.setBackground(bgCol);
|
|
|
|
}
|
2021-01-09 22:23:38 +01:00
|
|
|
gc.fillRectangle(rect);
|
|
|
|
gc.setForeground(sepCol);
|
2015-10-22 00:05:29 +02:00
|
|
|
gc.drawLine(dx, y, dx, y + h);
|
|
|
|
gc.drawLine(ux, y, ux, y + h);
|
2021-01-09 22:23:38 +01:00
|
|
|
gc.setForeground(topLeftCol);
|
|
|
|
gc.drawLine(x, y, x + w, y);
|
|
|
|
gc.drawLine(x, y, x, y + h);
|
2015-10-22 00:05:29 +02:00
|
|
|
gc.setForeground(bottomRightCol);
|
2021-01-09 22:23:38 +01:00
|
|
|
gc.drawLine(x + w - 1, y, x + w - 1, y + h);
|
|
|
|
gc.drawLine(x, y + h - 1, x + w, y + h - 1);
|
2015-10-22 00:05:29 +02:00
|
|
|
|
|
|
|
gc.setBackground(usedMemCol);
|
2021-01-09 22:23:38 +01:00
|
|
|
gc.fillRectangle(x + 1, y + 1, uw, h - 2);
|
|
|
|
|
|
|
|
String s = convertToMegString(usedMem) + " of " + convertToMegString(totalMem);
|
|
|
|
Point p = gc.textExtent(s);
|
|
|
|
int sx = (rect.width - 15 - p.x) / 2 + rect.x + 1;
|
|
|
|
int sy = (rect.height - 2 - p.y) / 2 + rect.y + 1;
|
|
|
|
gc.setForeground(textCol);
|
|
|
|
gc.drawString(s, sx, sy, true);
|
|
|
|
|
|
|
|
// draw an I-shaped bar in the foreground colour for the mark (if present)
|
|
|
|
if (mark != -1) {
|
|
|
|
int ssx = (int) (sw * mark / totalMem) + x + 1;
|
|
|
|
paintMark(gc, ssx, y, h);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Paint composite max known.
|
|
|
|
*
|
|
|
|
* @param gc the gc
|
|
|
|
*/
|
|
|
|
private void paintCompositeMaxKnown(GC gc) {
|
|
|
|
Rectangle rect = getClientArea();
|
|
|
|
int x = rect.x;
|
|
|
|
int y = rect.y;
|
|
|
|
int w = rect.width;
|
|
|
|
int h = rect.height;
|
|
|
|
int bw = imgBounds.width; // button width
|
|
|
|
int dx = x + w - bw - 2; // divider x
|
|
|
|
int sw = w - bw - 3; // status width
|
|
|
|
int uw = (int) (sw * usedMem / maxMem); // used mem width
|
|
|
|
int ux = x + 1 + uw; // used mem right edge
|
|
|
|
int tw = (int) (sw * totalMem / maxMem); // current total mem width
|
|
|
|
int tx = x + 1 + tw; // current total mem right edge
|
|
|
|
|
|
|
|
if (bgCol != null) {
|
2015-11-13 18:58:14 +01:00
|
|
|
gc.setBackground(bgCol);
|
|
|
|
}
|
2021-01-09 22:23:38 +01:00
|
|
|
gc.fillRectangle(rect);
|
|
|
|
gc.setForeground(sepCol);
|
2015-10-22 00:05:29 +02:00
|
|
|
gc.drawLine(dx, y, dx, y + h);
|
|
|
|
gc.drawLine(ux, y, ux, y + h);
|
|
|
|
gc.drawLine(tx, y, tx, y + h);
|
2021-01-09 22:23:38 +01:00
|
|
|
gc.setForeground(topLeftCol);
|
|
|
|
gc.drawLine(x, y, x + w, y);
|
|
|
|
gc.drawLine(x, y, x, y + h);
|
2015-10-22 00:05:29 +02:00
|
|
|
gc.setForeground(bottomRightCol);
|
2021-01-09 22:23:38 +01:00
|
|
|
gc.drawLine(x + w - 1, y, x + w - 1, y + h);
|
|
|
|
gc.drawLine(x, y + h - 1, x + w, y + h - 1);
|
|
|
|
|
|
|
|
if (lowMemThreshold != 0 && ((double) (maxMem - usedMem) / (double) maxMem < lowMemThreshold)) {
|
|
|
|
gc.setBackground(lowMemCol);
|
|
|
|
} else {
|
|
|
|
gc.setBackground(usedMemCol);
|
|
|
|
}
|
|
|
|
gc.fillRectangle(x + 1, y + 1, uw, h - 2);
|
|
|
|
|
|
|
|
gc.setBackground(freeMemCol);
|
|
|
|
gc.fillRectangle(ux + 1, y + 1, tx - (ux + 1), h - 2);
|
|
|
|
|
|
|
|
// paint line for low memory threshold
|
|
|
|
if (showLowMemThreshold && lowMemThreshold != 0) {
|
|
|
|
gc.setForeground(lowMemCol);
|
|
|
|
int thresholdX = x + 1 + (int) (sw * (1.0 - lowMemThreshold));
|
|
|
|
gc.drawLine(thresholdX, y + 1, thresholdX, y + h - 2);
|
|
|
|
}
|
|
|
|
|
|
|
|
String s = convertToMegString(usedMem) + " of " + convertToMegString(totalMem);
|
|
|
|
Point p = gc.textExtent(s);
|
|
|
|
int sx = (rect.width - 15 - p.x) / 2 + rect.x + 1;
|
|
|
|
int sy = (rect.height - 2 - p.y) / 2 + rect.y + 1;
|
|
|
|
gc.setForeground(textCol);
|
|
|
|
gc.drawString(s, sx, sy, true);
|
|
|
|
|
|
|
|
// draw an I-shaped bar in the foreground colour for the mark (if present)
|
|
|
|
if (mark != -1) {
|
|
|
|
int ssx = (int) (sw * mark / maxMem) + x + 1;
|
|
|
|
paintMark(gc, ssx, y, h);
|
|
|
|
}
|
|
|
|
}
|
2015-10-22 00:05:29 +02:00
|
|
|
|
2015-11-22 12:47:07 +01:00
|
|
|
/**
|
|
|
|
* Paint mark.
|
|
|
|
*
|
|
|
|
* @param gc the gc
|
2021-01-09 22:23:38 +01:00
|
|
|
* @param x the x
|
|
|
|
* @param y the y
|
|
|
|
* @param h the h
|
2015-11-22 12:47:07 +01:00
|
|
|
*/
|
2015-10-22 00:05:29 +02:00
|
|
|
private void paintMark(GC gc, int x, int y, int h) {
|
2021-01-09 22:23:38 +01:00
|
|
|
gc.setForeground(markCol);
|
|
|
|
gc.drawLine(x, y + 1, x, y + h - 2);
|
|
|
|
gc.drawLine(x - 1, y + 1, x + 1, y + 1);
|
|
|
|
gc.drawLine(x - 1, y + h - 2, x + 1, y + h - 2);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Update stats.
|
|
|
|
*/
|
|
|
|
private void updateStats() {
|
|
|
|
Runtime runtime = Runtime.getRuntime();
|
|
|
|
totalMem = runtime.totalMemory();
|
|
|
|
long freeMem = runtime.freeMemory();
|
|
|
|
usedMem = totalMem - freeMem;
|
|
|
|
|
|
|
|
if (convertToMeg(prevUsedMem) != convertToMeg(usedMem)) {
|
|
|
|
prevUsedMem = usedMem;
|
|
|
|
this.hasChanged = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (prevTotalMem != totalMem) {
|
|
|
|
prevTotalMem = totalMem;
|
|
|
|
this.hasChanged = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Update tool tip.
|
|
|
|
*/
|
|
|
|
private void updateToolTip() {
|
|
|
|
String usedStr = convertToMegString(usedMem);
|
|
|
|
String totalStr = convertToMegString(totalMem);
|
|
|
|
String maxStr = maxMemKnown ? convertToMegString(maxMem) : "<unknown>";
|
|
|
|
String markStr = mark == -1 ? "<none>" : convertToMegString(mark);
|
|
|
|
String toolTip = "Heap size: " + usedStr + " of total: " + totalStr + " max: " + maxStr + " mark: " + markStr;
|
|
|
|
if (!toolTip.equals(getToolTipText())) {
|
|
|
|
setToolTipText(toolTip);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Converts the given number of bytes to a printable number of megabytes
|
|
|
|
* (rounded up).
|
|
|
|
*
|
|
|
|
* @param numBytes the num bytes
|
|
|
|
* @return the string
|
|
|
|
*/
|
|
|
|
private String convertToMegString(long numBytes) {
|
|
|
|
return Long.toString(convertToMeg(numBytes)) + "M";
|
2015-10-22 00:05:29 +02:00
|
|
|
}
|
|
|
|
|
2021-01-09 22:23:38 +01:00
|
|
|
/**
|
|
|
|
* Converts the given number of bytes to the corresponding number of megabytes
|
|
|
|
* (rounded up).
|
|
|
|
*
|
|
|
|
* @param numBytes the num bytes
|
|
|
|
* @return the long
|
|
|
|
*/
|
2015-10-22 00:05:29 +02:00
|
|
|
private long convertToMeg(long numBytes) {
|
|
|
|
return (numBytes + (512 * 1024)) / (1024 * 1024);
|
|
|
|
}
|
|
|
|
|
2021-01-09 22:23:38 +01:00
|
|
|
/**
|
|
|
|
* The Class SetMarkAction.
|
|
|
|
*/
|
|
|
|
class SetMarkAction extends Action {
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Instantiates a new sets the mark action.
|
|
|
|
*/
|
|
|
|
SetMarkAction() {
|
|
|
|
super("&Set Mark");
|
|
|
|
}
|
2015-10-22 00:05:29 +02:00
|
|
|
|
2021-01-09 23:24:00 +01:00
|
|
|
/**
|
|
|
|
* Run.
|
|
|
|
*/
|
2021-01-09 22:23:38 +01:00
|
|
|
/*
|
|
|
|
* (non-Javadoc)
|
|
|
|
*
|
|
|
|
* @see org.eclipse.jface.action.Action#run()
|
|
|
|
*/
|
|
|
|
@Override
|
2015-10-22 00:05:29 +02:00
|
|
|
public void run() {
|
2021-01-09 22:23:38 +01:00
|
|
|
setMark();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The Class ClearMarkAction.
|
|
|
|
*/
|
|
|
|
class ClearMarkAction extends Action {
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Instantiates a new clear mark action.
|
|
|
|
*/
|
|
|
|
ClearMarkAction() {
|
|
|
|
super("&Clear Mark");
|
|
|
|
}
|
|
|
|
|
2021-01-09 23:24:00 +01:00
|
|
|
/**
|
|
|
|
* Run.
|
|
|
|
*/
|
2021-01-09 22:23:38 +01:00
|
|
|
/*
|
|
|
|
* (non-Javadoc)
|
|
|
|
*
|
|
|
|
* @see org.eclipse.jface.action.Action#run()
|
|
|
|
*/
|
|
|
|
@Override
|
2015-10-22 00:05:29 +02:00
|
|
|
public void run() {
|
2021-01-09 22:23:38 +01:00
|
|
|
clearMark();
|
|
|
|
}
|
|
|
|
}
|
2015-10-22 00:05:29 +02:00
|
|
|
|
2021-01-09 22:23:38 +01:00
|
|
|
/**
|
|
|
|
* The Class ShowMaxAction.
|
|
|
|
*/
|
|
|
|
class ShowMaxAction extends Action {
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Instantiates a new show max action.
|
|
|
|
*/
|
|
|
|
ShowMaxAction() {
|
|
|
|
super("Show &Max Heap", IAction.AS_CHECK_BOX);
|
|
|
|
setEnabled(maxMemKnown);
|
|
|
|
setChecked(showMax);
|
|
|
|
}
|
2015-10-22 00:05:29 +02:00
|
|
|
|
2021-01-09 23:24:00 +01:00
|
|
|
/**
|
|
|
|
* Run.
|
|
|
|
*/
|
2021-01-09 22:23:38 +01:00
|
|
|
/*
|
|
|
|
* (non-Javadoc)
|
|
|
|
*
|
|
|
|
* @see org.eclipse.jface.action.Action#run()
|
|
|
|
*/
|
|
|
|
@Override
|
|
|
|
public void run() {
|
|
|
|
preferences.putBoolean(IHeapStatusConstants.PREF_SHOW_MAX, isChecked());
|
|
|
|
redraw();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|