1 package org.eclipse.tips.manual.tests;
2 
3 import java.io.ByteArrayOutputStream;
4 import java.io.PrintStream;
5 
6 /*
7  * Copyright (c) 2000, 2018 IBM Corp.  All rights reserved.
8  * This file is made available under the terms of the Common Public License v1.0
9  * which accompanies this distribution, and is available at
10  * http://www.eclipse.org/legal/cpl-v10.html
11  */
12 import org.eclipse.swt.SWT;
13 import org.eclipse.swt.graphics.Color;
14 import org.eclipse.swt.graphics.Cursor;
15 import org.eclipse.swt.graphics.DeviceData;
16 import org.eclipse.swt.graphics.Font;
17 import org.eclipse.swt.graphics.FontData;
18 import org.eclipse.swt.graphics.GC;
19 import org.eclipse.swt.graphics.Image;
20 import org.eclipse.swt.graphics.Point;
21 import org.eclipse.swt.graphics.Rectangle;
22 import org.eclipse.swt.graphics.Region;
23 import org.eclipse.swt.widgets.Button;
24 import org.eclipse.swt.widgets.Canvas;
25 import org.eclipse.swt.widgets.Display;
26 import org.eclipse.swt.widgets.Event;
27 import org.eclipse.swt.widgets.Label;
28 import org.eclipse.swt.widgets.List;
29 import org.eclipse.swt.widgets.MessageBox;
30 import org.eclipse.swt.widgets.Shell;
31 import org.eclipse.swt.widgets.Text;
32 
33 public class Sleak {
34 	Display display;
35 	Shell shell;
36 	List list;
37 	Canvas canvas;
38 	Button start, stop, check;
39 	Text text;
40 	Label label;
41 
42 	Object[] oldObjects = new Object[0];
43 	Error[] oldErrors = new Error[0];
44 	Object[] objects = new Object[0];
45 	Error[] errors = new Error[0];
46 
open()47 	public void open() {
48 		display = Display.getCurrent();
49 		shell = new Shell(display);
50 		shell.setText("S-Leak");
51 		list = new List(shell, SWT.BORDER | SWT.V_SCROLL);
52 		list.addListener(SWT.Selection, event -> refreshObject());
53 		text = new Text(shell, SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL);
54 		canvas = new Canvas(shell, SWT.BORDER);
55 		canvas.addListener(SWT.Paint, event -> paintCanvas(event));
56 		check = new Button(shell, SWT.CHECK);
57 		check.setText("Stack");
58 		check.addListener(SWT.Selection, e -> toggleStackTrace());
59 		start = new Button(shell, SWT.PUSH);
60 		start.setText("Snap");
61 		start.addListener(SWT.Selection, event -> refreshAll());
62 		stop = new Button(shell, SWT.PUSH);
63 		stop.setText("Diff");
64 		stop.addListener(SWT.Selection, event -> refreshDifference());
65 		label = new Label(shell, SWT.BORDER);
66 		label.setText("0 object(s)");
67 		shell.addListener(SWT.Resize, e -> layout());
68 		check.setSelection(false);
69 		text.setVisible(false);
70 		Point size = shell.getSize();
71 		shell.setSize(size.x / 2, size.y / 2);
72 		shell.open();
73 		refreshAll();
74 	}
75 
refreshLabel()76 	void refreshLabel() {
77 		int colors = 0, cursors = 0, fonts = 0, gcs = 0, images = 0;
78 		for (Object object : objects) {
79 			if (object instanceof Color) {
80 				colors++;
81 			}
82 			if (object instanceof Cursor) {
83 				cursors++;
84 			}
85 			if (object instanceof Font) {
86 				fonts++;
87 			}
88 			if (object instanceof GC) {
89 				gcs++;
90 			}
91 			if (object instanceof Image) {
92 				images++;
93 			}
94 		}
95 		String string = "";
96 		if (colors != 0) {
97 			string += colors + " Color(s)\n";
98 		}
99 		if (cursors != 0) {
100 			string += cursors + " Cursor(s)\n";
101 		}
102 		if (fonts != 0) {
103 			string += fonts + " Font(s)\n";
104 		}
105 		if (gcs != 0) {
106 			string += gcs + " GC(s)\n";
107 		}
108 		if (images != 0) {
109 			string += images + " Image(s)\n";
110 		}
111 		/* Currently regions are not counted. */
112 		// if (regions != 0) string += regions + " Region(s)\n";
113 		if (string.length() != 0) {
114 			string = string.substring(0, string.length() - 1);
115 		}
116 		label.setText(string);
117 	}
118 
refreshDifference()119 	void refreshDifference() {
120 		DeviceData info = display.getDeviceData();
121 		if (!info.tracking) {
122 			MessageBox dialog = new MessageBox(shell, SWT.ICON_WARNING | SWT.OK);
123 			dialog.setText(shell.getText());
124 			dialog.setMessage("Warning: Device is not tracking resource allocation");
125 			dialog.open();
126 		}
127 		Object[] newObjects = info.objects;
128 		Error[] newErrors = info.errors;
129 		Object[] diffObjects = new Object[newObjects.length];
130 		Error[] diffErrors = new Error[newErrors.length];
131 		int count = 0;
132 		for (int i = 0; i < newObjects.length; i++) {
133 			int index = 0;
134 			while (index < oldObjects.length) {
135 				if (newObjects[i] == oldObjects[index]) {
136 					break;
137 				}
138 				index++;
139 			}
140 			if (index == oldObjects.length) {
141 				diffObjects[count] = newObjects[i];
142 				diffErrors[count] = newErrors[i];
143 				count++;
144 			}
145 		}
146 		objects = new Object[count];
147 		errors = new Error[count];
148 		System.arraycopy(diffObjects, 0, objects, 0, count);
149 		System.arraycopy(diffErrors, 0, errors, 0, count);
150 		list.removeAll();
151 		text.setText("");
152 		canvas.redraw();
153 		for (Object object : objects) {
154 			list.add(objectName(object));
155 		}
156 		refreshLabel();
157 		layout();
158 	}
159 
objectName(Object object)160 	String objectName(Object object) {
161 		String string = object.toString();
162 		int index = string.lastIndexOf('.');
163 		if (index == -1) {
164 			return string;
165 		}
166 		return string.substring(index + 1, string.length());
167 	}
168 
toggleStackTrace()169 	void toggleStackTrace() {
170 		refreshObject();
171 		layout();
172 	}
173 
paintCanvas(Event event)174 	void paintCanvas(Event event) {
175 		canvas.setCursor(null);
176 		int index = list.getSelectionIndex();
177 		if (index == -1) {
178 			return;
179 		}
180 		GC gc = event.gc;
181 		Object object = objects[index];
182 		if (object instanceof Color) {
183 			if (((Color) object).isDisposed()) {
184 				return;
185 			}
186 			gc.setBackground((Color) object);
187 			gc.fillRectangle(canvas.getClientArea());
188 			return;
189 		}
190 		if (object instanceof Cursor) {
191 			if (((Cursor) object).isDisposed()) {
192 				return;
193 			}
194 			canvas.setCursor((Cursor) object);
195 			return;
196 		}
197 		if (object instanceof Font) {
198 			if (((Font) object).isDisposed()) {
199 				return;
200 			}
201 			gc.setFont((Font) object);
202 			FontData[] array = gc.getFont().getFontData();
203 			String string = "";
204 			String lf = text.getLineDelimiter();
205 			for (FontData data : array) {
206 				String style = "NORMAL";
207 				int bits = data.getStyle();
208 				if (bits != 0) {
209 					if ((bits & SWT.BOLD) != 0) {
210 						style = "BOLD ";
211 					}
212 					if ((bits & SWT.ITALIC) != 0) {
213 						style += "ITALIC";
214 					}
215 				}
216 				string += data.getName() + " " + data.getHeight() + " " + style + lf;
217 			}
218 			gc.drawString(string, 0, 0);
219 			return;
220 		}
221 		// NOTHING TO DRAW FOR GC
222 		// if (object instanceof GC) {
223 		// return;
224 		// }
225 		if (object instanceof Image) {
226 			if (((Image) object).isDisposed()) {
227 				return;
228 			}
229 			gc.drawImage((Image) object, 0, 0);
230 			return;
231 		}
232 		if (object instanceof Region) {
233 			if (((Region) object).isDisposed()) {
234 				return;
235 			}
236 			String string = ((Region) object).getBounds().toString();
237 			gc.drawString(string, 0, 0);
238 			return;
239 		}
240 	}
241 
refreshObject()242 	void refreshObject() {
243 		int index = list.getSelectionIndex();
244 		if (index == -1) {
245 			return;
246 		}
247 		if (check.getSelection()) {
248 			ByteArrayOutputStream stream = new ByteArrayOutputStream();
249 			PrintStream s = new PrintStream(stream);
250 			errors[index].printStackTrace(s);
251 			text.setText(stream.toString());
252 			text.setVisible(true);
253 			canvas.setVisible(false);
254 		} else {
255 			canvas.setVisible(true);
256 			text.setVisible(false);
257 			canvas.redraw();
258 		}
259 	}
260 
refreshAll()261 	void refreshAll() {
262 		oldObjects = new Object[0];
263 		oldErrors = new Error[0];
264 		refreshDifference();
265 		oldObjects = objects;
266 		oldErrors = errors;
267 	}
268 
layout()269 	void layout() {
270 		Rectangle rect = shell.getClientArea();
271 		int width = 0;
272 		String[] items = list.getItems();
273 		GC gc = new GC(list);
274 		for (int i = 0; i < objects.length; i++) {
275 			width = Math.max(width, gc.stringExtent(items[i]).x);
276 		}
277 		gc.dispose();
278 		Point size1 = start.computeSize(SWT.DEFAULT, SWT.DEFAULT);
279 		Point size2 = stop.computeSize(SWT.DEFAULT, SWT.DEFAULT);
280 		Point size3 = check.computeSize(SWT.DEFAULT, SWT.DEFAULT);
281 		Point size4 = label.computeSize(SWT.DEFAULT, SWT.DEFAULT);
282 		width = Math.max(size1.x, Math.max(size2.x, Math.max(size3.x, width)));
283 		width = Math.max(64, Math.max(size4.x, list.computeSize(width, SWT.DEFAULT).x));
284 		start.setBounds(0, 0, width, size1.y);
285 		stop.setBounds(0, size1.y, width, size2.y);
286 		check.setBounds(0, size1.y + size2.y, width, size3.y);
287 		label.setBounds(0, rect.height - size4.y, width, size4.y);
288 		int height = size1.y + size2.y + size3.y;
289 		list.setBounds(0, height, width, rect.height - height - size4.y);
290 		text.setBounds(width, 0, rect.width - width, rect.height);
291 		canvas.setBounds(width, 0, rect.width - width, rect.height);
292 	}
293 
main(String[] args)294 	public static void main(String[] args) {
295 		Display display = new Display();
296 		Sleak sleak = new Sleak();
297 		sleak.open();
298 		while (!sleak.shell.isDisposed()) {
299 			if (!display.readAndDispatch()) {
300 				display.sleep();
301 			}
302 		}
303 		display.dispose();
304 	}
305 
306 }
307