/******************************************************************************* * Copyright (c) 2007, 2011 Wind River Systems, Inc. and others. * 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: * Wind River Systems - initial API and implementation *******************************************************************************/ package org.eclipse.tm.internal.tcf.debug.ui.model; import java.io.IOException; import java.util.HashMap; import java.util.LinkedList; import java.util.Map; import org.eclipse.swt.SWT; import org.eclipse.swt.SWTException; import org.eclipse.swt.widgets.Display; import org.eclipse.tm.internal.tcf.debug.ui.Activator; import org.eclipse.tm.internal.tcf.debug.ui.ImageCache; import org.eclipse.tm.tcf.protocol.Protocol; import org.eclipse.ui.IWorkbenchPage; import org.eclipse.ui.IWorkbenchWindow; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.console.ConsolePlugin; import org.eclipse.ui.console.IConsole; import org.eclipse.ui.console.IConsoleConstants; import org.eclipse.ui.console.IConsoleManager; import org.eclipse.ui.console.IConsoleView; import org.eclipse.ui.console.IOConsole; import org.eclipse.ui.console.IOConsoleInputStream; import org.eclipse.ui.console.IOConsoleOutputStream; class TCFConsole { private final TCFModel model; private final IOConsole console; private final Display display; private final LinkedList<Message> out_queue; private static class Message { int stream_id; byte[] data; } private final Thread inp_thread = new Thread() { public void run() { try { IOConsoleInputStream inp = console.getInputStream(); final byte[] buf = new byte[0x100]; for (;;) { int len = inp.read(buf); if (len < 0) break; // TODO: Eclipse Console view has a bad habit of replacing CR with CR/LF if (len == 2 && buf[0] == '\r' && buf[1] == '\n') len = 1; final int n = len; Protocol.invokeAndWait(new Runnable() { public void run() { try { model.getLaunch().writeProcessInputStream(buf, 0, n); } catch (Exception x) { model.onProcessStreamError(null, 0, x, 0); } } }); } } catch (Throwable x) { Activator.log("Cannot read console input", x); } } }; private final Thread out_thread = new Thread() { public void run() { Map<Integer,IOConsoleOutputStream> out_streams = new HashMap<Integer,IOConsoleOutputStream>(); try { for (;;) { Message m = null; synchronized (out_queue) { while (out_queue.size() == 0) out_queue.wait(); m = out_queue.removeFirst(); } if (m.data == null) break; IOConsoleOutputStream stream = out_streams.get(m.stream_id); if (stream == null) { final int id = m.stream_id; final IOConsoleOutputStream s = stream = console.newOutputStream(); display.syncExec(new Runnable() { public void run() { try { int color_id = SWT.COLOR_BLACK; switch (id) { case 1: color_id = SWT.COLOR_RED; break; case 2: color_id = SWT.COLOR_BLUE; break; case 3: color_id = SWT.COLOR_GREEN; break; } s.setColor(display.getSystemColor(color_id)); } catch (Throwable x) { Activator.log("Cannot open console view", x); } } }); out_streams.put(m.stream_id, stream); } stream.write(m.data, 0, m.data.length); } } catch (Throwable x) { Activator.log("Cannot write console output", x); } for (IOConsoleOutputStream stream : out_streams.values()) { try { stream.close(); } catch (IOException x) { Activator.log("Cannot close console stream", x); } } try { console.getInputStream().close(); } catch (IOException x) { Activator.log("Cannot close console stream", x); } try { display.syncExec(new Runnable() { public void run() { IConsoleManager manager = ConsolePlugin.getDefault().getConsoleManager(); manager.removeConsoles(new IOConsole[]{ console }); } }); } catch (SWTException x) { if (x.code == SWT.ERROR_DEVICE_DISPOSED) return; Activator.log("Cannot remove console", x); } } }; TCFConsole(final TCFModel model, String process_id) { this.model = model; display = model.getDisplay(); out_queue = new LinkedList<Message>(); console = new IOConsole("TCF " + process_id, null, ImageCache.getImageDescriptor(ImageCache.IMG_TCF), "UTF-8", true); display.asyncExec(new Runnable() { public void run() { if (!PlatformUI.isWorkbenchRunning() || PlatformUI.getWorkbench().isStarting()) { display.timerExec(200, this); } else if (!PlatformUI.getWorkbench().isClosing()) { try { IConsoleManager manager = ConsolePlugin.getDefault().getConsoleManager(); manager.addConsoles(new IConsole[]{ console }); IWorkbenchWindow w = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); if (w == null) return; IWorkbenchPage page = w.getActivePage(); if (page == null) return; IConsoleView view = (IConsoleView)page.showView(IConsoleConstants.ID_CONSOLE_VIEW); view.display(console); } catch (Throwable x) { Activator.log("Cannot open console view", x); } } } }); inp_thread.setName("TCF Launch Console Input"); out_thread.setName("TCF Launch Console Output"); inp_thread.start(); out_thread.start(); } void write(final int stream_id, byte[] data) { if (data == null || data.length == 0) return; synchronized (out_queue) { Message m = new Message(); m.stream_id = stream_id; m.data = data; out_queue.add(m); out_queue.notify(); } } void close() { synchronized (out_queue) { out_queue.add(new Message()); out_queue.notify(); } } }