POC for new Chromium support

This commit is contained in:
aboyko
2022-09-12 21:11:34 -04:00
parent 1012074a66
commit b91d7decaa
17 changed files with 2120 additions and 7 deletions

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
<classpathentry kind="src" path="src/"/>
<classpathentry kind="output" path="target/classes"/>
</classpath>

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
<classpathentry kind="output" path="bin"/>
</classpath>

View File

@@ -0,0 +1 @@
/lib/node_modules

View File

@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>org.springframework.ide.eclipse.xterm.macosx.aarch64</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.pde.ManifestBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.pde.SchemaBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.m2e.core.maven2Builder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.m2e.core.maven2Nature</nature>
<nature>org.eclipse.pde.PluginNature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>

View File

@@ -0,0 +1,11 @@
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Node-Xterm package for Mac OSX
Bundle-SymbolicName: org.springframework.ide.eclipse.xterm.macosx.aarch64
Bundle-Version: 4.16.0.qualifier
Bundle-Vendor: VMware
Fragment-Host: org.springframework.ide.eclipse.xterm;bundle-version="4.8.2"
Automatic-Module-Name: org.springframework.ide.eclipse.xterm.macosx.aarch64
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Eclipse-PlatformFilter: (& (osgi.ws=cocoa) (osgi.os=macosx) (|(osgi.arch=aarch64)(osgi.arch=ppc)))
Eclipse-BundleShape: dir

View File

@@ -0,0 +1,5 @@
source.. = src/
output.. = bin/
bin.includes = META-INF/,\
.,\
lib/

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,5 @@
{
"dependencies": {
"node-xterm": "^0.0.4"
}
}

View File

@@ -0,0 +1,105 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="https://maven.apache.org/POM/4.0.0"
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot.ide</groupId>
<artifactId>org.springframework.boot.ide</artifactId>
<version>4.16.0-SNAPSHOT</version>
<relativePath>../../eclipse-distribution/pom.xml</relativePath>
</parent>
<packaging>eclipse-plugin</packaging>
<artifactId>org.springframework.ide.eclipse.xterm.macosx.aarch64</artifactId>
<properties>
<archive-file>node-xterm-0.0.2-macosx-aarch64.zip</archive-file>
</properties>
<build>
<plugins>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
<configuration>
<filesets>
<fileset>
<directory>${project.basedir}</directory>
<includes>
<include>**/lib/**</include>
</includes>
<followSymlinks>false</followSymlinks>
</fileset>
</filesets>
</configuration>
</plugin>
<!-- download-maven-plugin fails to download archive files for mac and linux some times. Use
- wagon-maven-plugin for downloading
- maven-antrun-plugin for unpacking and deleting the archive
-->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>wagon-maven-plugin</artifactId>
<version>2.0.0</version>
<executions>
<execution>
<id>download-nodejs-app</id>
<phase>generate-resources</phase>
<goals>
<goal>download-single</goal>
</goals>
<configuration>
<serverId>s3</serverId>
<url>https://dist.springsource.com/release/TOOLS/node-xterm</url>
<fromFile>${archive-file}</fromFile>
<toFile>${project.basedir}/lib/node-xterm.zip</toFile>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<phase>process-resources</phase>
<configuration>
<tasks>
<echo message="unzipping node-xterm.zip" />
<unzip src="${project.basedir}/lib/node-xterm.zip"
dest="lib/" />
<delete>
<fileset dir="${project.basedir}/lib"
includes="node-xterm.zip" />
</delete>
</tasks>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.eclipse.tycho</groupId>
<artifactId>target-platform-configuration</artifactId>
<version>${tycho-version}</version>
<configuration>
<resolver>p2</resolver>
<pomDependencies>ignore</pomDependencies>
<environments>
<environment>
<os>macosx</os>
<ws>cocoa</ws>
<arch>x86_64</arch>
</environment>
</environments>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@@ -1,5 +1,6 @@
/target/
/.settings/
/lib/
.DS_Store
/**/.DS_Store
.project

View File

@@ -13,7 +13,10 @@ Require-Bundle: org.eclipse.ui;bundle-version="3.115.0",
org.apache.httpcomponents.httpcore,
org.eclipse.wildwebdeveloper.embedder.node
Import-Package: javax.inject
Bundle-ClassPath: .
Bundle-ClassPath: .,
lib/ipcsocket-1.4.0.jar,
lib/jna-5.8.0.jar,
lib/jna-platform-5.8.0.jar
Bundle-ActivationPolicy: lazy
Export-Package: org.springframework.ide.eclipse.xterm,
org.springframework.ide.eclipse.xterm.views

View File

@@ -4,4 +4,8 @@ bin.includes = META-INF/,\
.,\
plugin.xml,\
css/,\
icons/
icons/,\
lib/,\
lib/ipcsocket-1.4.0.jar,\
lib/jna-5.8.0.jar,\
lib/jna-platform-5.8.0.jar

View File

@@ -11,6 +11,14 @@
</parent>
<packaging>eclipse-plugin</packaging>
<artifactId>org.springframework.ide.eclipse.xterm</artifactId>
<dependencies>
<dependency>
<groupId>org.scala-sbt.ipcsocket</groupId>
<artifactId>ipcsocket</artifactId>
<version>1.4.0</version>
</dependency>
</dependencies>
<build>
<plugins>
@@ -60,6 +68,48 @@
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<?m2e execute onConfiguration?>
<id>get-libs</id>
<goals>
<goal>copy</goal>
</goals>
<phase>validate</phase>
</execution>
</executions>
<configuration>
<skip>false</skip>
<artifactItems>
<artifactItem>
<groupId>org.scala-sbt.ipcsocket</groupId>
<artifactId>ipcsocket</artifactId>
<version>1.4.0</version>
<overWrite>true</overWrite>
</artifactItem>
<artifactItem>
<groupId>net.java.dev.jna</groupId>
<artifactId>jna-platform</artifactId>
<version>5.8.0</version>
</artifactItem>
<artifactItem>
<groupId>net.java.dev.jna</groupId>
<artifactId>jna</artifactId>
<version>5.8.0</version>
</artifactItem>
</artifactItems>
<outputDirectory>${basedir}/lib/</outputDirectory>
<!-- baseVersion is to avoid SNAPSHOT dependencies being copied with
ever daily changing timestamp -->
<useBaseVersion>true</useBaseVersion>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@@ -0,0 +1,611 @@
package org.springframework.ide.eclipse.chromium.browser;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ControlEvent;
import org.eclipse.swt.events.ControlListener;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.KeyListener;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseListener;
import org.eclipse.swt.events.MouseMoveListener;
import org.eclipse.swt.events.MouseWheelListener;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.graphics.Cursor;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.graphics.PaletteData;
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.scalasbt.ipcsocket.UnixDomainServerSocket;
import org.scalasbt.ipcsocket.Win32NamedPipeServerSocket;
import org.scalasbt.ipcsocket.Win32SecurityLevel;
public class ElectronBrowserCanvas extends Canvas
{
private Image image;
private GC gc;
private Image createImage(int width, int height)
{
ImageData data = new ImageData(width, height, 32, new PaletteData(0xff0000,0x00ff00, 0x0000ff));
data.setAlpha(0, 0, 0);
Arrays.fill(data.alphaData, (byte) -1);
Arrays.fill(data.data, (byte) -1);
return new Image(null, data);
}
public ElectronBrowserCanvas(Composite parent)
{
this(parent, true);
}
public ElectronBrowserCanvas(Composite parent, boolean startElectron)
{
super(parent, SWT.NO_REDRAW_RESIZE | SWT.DOUBLE_BUFFERED | SWT.NO_BACKGROUND);
Display display = getDisplay();
image = createImage(display.getBounds().width, display.getBounds().height);
gc = new GC(image);
FPSText.initGC(gc);
addControlListener(new ControlListener() {
@Override
public void controlResized(ControlEvent e)
{
Rectangle oldBounds = image.getBounds();
Rectangle newBounds = getBounds();
if (oldBounds.width < newBounds.width || oldBounds.height < newBounds.height)
{
image.dispose();
image = createImage(newBounds.width, newBounds.height);
gc = new GC(image);
FPSText.initGC(gc);
}
sendResize(newBounds);
}
@Override
public void controlMoved(ControlEvent e)
{
}
});
addPaintListener(new PaintListener() {
@Override
public void paintControl(PaintEvent event)
{
event.gc.drawImage(image, event.x, event.y, event.width, event.height, event.x, event.y, event.width, event.height);
}
});
addMouseListener(new MouseListener() {
@Override
public void mouseUp(MouseEvent e)
{
handleEvent("mouseUp", e);
}
@Override
public void mouseDown(MouseEvent e)
{
handleEvent("mouseDown", e);
}
@Override
public void mouseDoubleClick(MouseEvent e)
{
}
});
addMouseMoveListener(new MouseMoveListener() {
@Override
public void mouseMove(MouseEvent e)
{
handleEvent("mouseMove", e);
}
});
addKeyListener(new KeyListener() {
@Override
public void keyReleased(KeyEvent e)
{
handleEvent("keyUp", e);
}
@Override
public void keyPressed(KeyEvent e)
{
handleEvent("keyDown", e);
handleEvent("char", e);
}
});
addMouseWheelListener(new MouseWheelListener() {
@Override
public void mouseScrolled(MouseEvent e)
{
if (e.count != 0)
{
handleEvent("mouseWheel", e); // TODO how to correctly calculate deltaY etc.
}
}
});
addDisposeListener(new DisposeListener() {
@Override
public void widgetDisposed(DisposeEvent e)
{
sendMessage("{\n" +
" \"type\":\"quit\"\n" + "}");
if (process != null) process.destroy();
}
});
new Thread(() -> {
listen();
}).start();
if (startElectron)
{
unzipAndStartElectron();
}
}
private ServerSocket server;
private void listen()
{
try
{
boolean win = System.getProperty("os.name", "").toLowerCase().startsWith("win");
String socketName;
if (win)
{
socketName = "\\\\.\\pipe\\electron_pipe";
server = new Win32NamedPipeServerSocket(socketName, false, Win32SecurityLevel.LOGON_DACL);
}
else
{
//Path pipe = Files.createTempDirectory("electron_pipe").resolve("electron.pipe");
Path pipe = Files.createDirectories(Paths.get("/tmp/electron_pipe")).resolve("electron.pipe");
Files.deleteIfExists(pipe);
socketName = pipe.toString();
server = new UnixDomainServerSocket(socketName, false);
}
//server = new ServerSocket(9090);
}
catch (IOException e)
{
System.err.println("Could not open socket.");
System.exit(-1);
}
new Thread(() -> {
while (!isDisposed())
{
run();
try
{
Thread.sleep(100);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
}).start();
}
private PrintWriter out;
private void run()
{
try
{
System.out.println("Open connection");
final Socket socket = server.accept();
final InputStream inputStream = socket.getInputStream();
final BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream);
out = new PrintWriter(socket.getOutputStream());
Display display = getDisplay();
display.asyncExec(() -> sendResize(getBounds()));
browse("");
FPSText fps = new FPSText();
String command = null;
while (!isDisposed() && (command = new String(readBytesFromInputStream(bufferedInputStream, 32), "UTF-8")) != null)
{
if (command.startsWith("cursor:"))
{
String type = (command.substring("cursor:".length()).split(","))[0];
display.asyncExec(() -> setCursor(type));
}
else if (command.startsWith("paint:"))
{
String[] split = command.substring("paint:".length()).split(",");
Point point = new Point(Integer.parseInt(split[0]), Integer.parseInt(split[1]));
Image newImage = new Image(null, new PartialInputStream(bufferedInputStream, Integer.parseInt(split[2])));
Rectangle bounds = newImage.getBounds();
if (isDisposed()) break;
display.syncExec(() -> { // TODO sync or async?
if (isDisposed()) return;
gc.drawImage(newImage, point.x, point.y);
fps.drawFPS(gc, this, point.x, point.y);
//gc.drawRectangle(point.x, point.y, bounds.width - 1, bounds.height - 1);
redraw(point.x, point.y, bounds.width, bounds.height, false);
newImage.dispose();
});
fps.calcFPS();
sendMessage("accept", Collections.singletonMap("imageCount", split[3]));
}
else
{
throw new IOException("Invalid command");
}
}
}
catch (IOException e)
{
out = null;
System.err.println("Error: " + e.getMessage());
e.printStackTrace();
}
}
private byte[] readBytesFromInputStream(final InputStream inputStream, final int numberOfBytes) throws IOException
{
int bytesToRead = numberOfBytes;
int bytesRead = 0;
byte[] bytes = new byte[numberOfBytes];
while (bytesToRead > 0 && (bytesRead = inputStream.read(bytes, numberOfBytes - bytesToRead, bytesToRead)) > -1)
{
bytesToRead -= bytesRead;
}
return bytes;
}
private void sendMessage(String type, Map<String, String> parameters)
{
StringBuilder builder = new StringBuilder();
parameters.forEach((key, value) -> builder.append(",\n" + " \"" + key + "\":" + value));
sendMessage("{\n" + " \"type\":\"" + type + "\"" + builder.toString() + "\n" + "}");
}
private void sendMessage(String message)
{
if (out != null)
{
out.write(message + "\n");
out.flush();
}
}
public void browse(String url)
{
sendMessage("browse", Collections.singletonMap("url", "\"" + url + "\""));
}
private void sendResize(Rectangle bounds)
{
Map<String, String> params = new LinkedHashMap<>();
params.put("width", Integer.toString(bounds.width));
params.put("height", Integer.toString(bounds.height));
sendMessage("resize", params);
}
private void handleEvent(String type, MouseEvent e)
{
Map<String, String> params = new LinkedHashMap<>();
if ((e.stateMask & SWT.BUTTON_MASK) != 0)
{
List<String> modifiers = new ArrayList<>();
if ((e.stateMask & SWT.BUTTON1) != 0)
{
modifiers.add("\"leftButtonDown\"");
}
if ((e.stateMask & SWT.BUTTON2) != 0)
{
modifiers.add("\"middleButtonDown\"");
}
if ((e.stateMask & SWT.BUTTON3) != 0)
{
modifiers.add("\"rightButtonDown\"");
}
params.put("modifiers", "[" + String.join(",", modifiers) + "]");
}
String button;
switch (e.button)
{
case 1:
button = "left";
break;
case 2:
button = "middle";
break;
case 3:
button = "right";
break;
default:
button = null;
break;
}
params.put("x", Integer.toString(e.x));
params.put("y", Integer.toString(e.y));
/*if (oldMouseEvent != null && e.time - oldMouseEvent.time < 1000)
{
params.put("movementX", Integer.toString(oldMouseEvent.x - e.x));
params.put("movementY", Integer.toString(oldMouseEvent.y - e.y));
}
oldMouseEvent = e;*/
if (button != null) params.put("button", "\"" + button + "\"");
if (!"mouseWheel".equals(type))
{
params.put("clickCount", Integer.toString(e.count));
}
else
{
params.put("deltaY", Integer.toString(e.count * 100 / 3));
}
sendMessage(type, params);
}
private void handleEvent(String type, KeyEvent e)
{
String keyCode = null;
if (Character.isLetterOrDigit(e.character))
{
keyCode = Character.toString(e.character);
}
else
{
String c = null;
switch (e.keyCode)
{
case 8:
keyCode = "Backspace";
break;
case 9:
keyCode = "Tab";
break;
case 13:
keyCode = "Return";
c = "Return";
break;
case 27:
keyCode = "Escape";
break;
case 32:
keyCode = "Space";
c = " ";
break;
case 50:
keyCode = "\\\"";
c = keyCode;
break;
case SWT.ARROW_UP:
keyCode = "Up";
break;
case SWT.ARROW_DOWN:
keyCode = "Down";
break;
case SWT.ARROW_LEFT:
keyCode = "Left";
break;
case SWT.ARROW_RIGHT:
keyCode = "Right";
break;
case SWT.PAGE_UP:
keyCode = "PageUp";
break;
case SWT.PAGE_DOWN:
keyCode = "PageDown";
break;
case SWT.HOME:
keyCode = "Home";
break;
case SWT.END:
keyCode = "End";
break;
case SWT.KEYPAD_ADD:
keyCode = "numadd";
c = "+";
break;
case SWT.KEYPAD_SUBTRACT:
keyCode = "numsub";
c = "-";
break;
case SWT.KEYPAD_MULTIPLY:
keyCode = "nummult";
c = "*";
break;
case SWT.KEYPAD_DIVIDE:
keyCode = "numdiv";
c = "/";
break;
case SWT.KEYPAD_DECIMAL:
keyCode = "numdec";
c = ",";
break;
case SWT.KEYPAD_CR:
keyCode = "Enter";
break;
case SWT.KEYPAD_0:
case SWT.KEYPAD_1:
case SWT.KEYPAD_2:
case SWT.KEYPAD_3:
case SWT.KEYPAD_4:
case SWT.KEYPAD_5:
case SWT.KEYPAD_6:
case SWT.KEYPAD_7:
case SWT.KEYPAD_8:
case SWT.KEYPAD_9:
keyCode = "num" + (e.keyCode - SWT.KEYPAD_0);
break;
case SWT.F1:
case SWT.F2:
case SWT.F3:
case SWT.F4:
case SWT.F5:
case SWT.F6:
case SWT.F7:
case SWT.F8:
case SWT.F9:
case SWT.F10:
case SWT.F11:
case SWT.F12:
keyCode = "F" + (e.keyCode - SWT.F1 + 1);
break;
default:
break;
}
if (keyCode == null)
{
if (e.character == 0)
return;
keyCode = Character.toString(e.character);
}
else if ("char".equals(type))
{
if (c == null)
return;
keyCode = c;
}
}
sendMessage(type, Collections.singletonMap("keyCode", "\"" + keyCode + "\""));
}
private Map<String, Integer> cursorMapping;
private void setCursor(String type)
{
if (cursorMapping == null)
{
cursorMapping = new HashMap<>();
// TODO col-resize, row-resize, m-panning, e-panning, n-panning, ne-panning, nw-panning, s-panning, se-panning, sw-panning, w-panning, move, vertical-text, cell, context-menu, alias, progress, nodrop, copy, not-allowed, zoom-in, zoom-out, grab, grabbing
cursorMapping.put("default", SWT.CURSOR_ARROW);
cursorMapping.put("crosshair", SWT.CURSOR_CROSS);
cursorMapping.put("pointer", SWT.CURSOR_HAND);
cursorMapping.put("text", SWT.CURSOR_IBEAM);
cursorMapping.put("wait", SWT.CURSOR_WAIT);
cursorMapping.put("help", SWT.CURSOR_HELP);
cursorMapping.put("e-resize", SWT.CURSOR_SIZEE);
cursorMapping.put("n-resize", SWT.CURSOR_SIZEN);
cursorMapping.put("ne-resize", SWT.CURSOR_SIZENE);
cursorMapping.put("nw-resize", SWT.CURSOR_SIZENW);
cursorMapping.put("s-resize", SWT.CURSOR_SIZES);
cursorMapping.put("se-resize", SWT.CURSOR_SIZESE);
cursorMapping.put("sw-resize", SWT.CURSOR_SIZESW);
cursorMapping.put("w-resize", SWT.CURSOR_SIZEW);
cursorMapping.put("ns-resize", SWT.CURSOR_SIZENS);
cursorMapping.put("ew-resize", SWT.CURSOR_SIZEWE);
cursorMapping.put("nesw-resize", SWT.CURSOR_SIZENESW);
cursorMapping.put("nwse-resize", SWT.CURSOR_SIZENWSE);
cursorMapping.put("none", SWT.CURSOR_NO);
//cursorMapping.put("", SWT.CURSOR_SIZEALL);
}
Integer swtType = cursorMapping.get(type);
if (swtType == null)
{
System.out.println("Cursor not found:" + type);
swtType = SWT.CURSOR_ARROW;
}
Cursor cursor = new Cursor(getDisplay(), swtType);
setCursor(cursor);
}
private Process process;
private void unzipAndStartElectron()
{
File tempDir = new File(System.getProperty("java.io.tmpdir") + File.separator + "headless-electron"); // TODO unzip to AppData
if(!tempDir.exists())
{
tempDir.mkdirs();
}
try
{
// TODO add Linux and Mac
unzip(getClass().getResourceAsStream("/headless-electron-darwin-x64-0.0.1.zip"), tempDir);
ProcessBuilder processBuilder = new ProcessBuilder(tempDir + File.separator + "headless-electron.app/Contents/MacOS/headless-electron");
process = processBuilder.start();
}
catch (IOException e1)
{
e1.printStackTrace();
}
}
private void unzip(InputStream is, File dest) throws IOException
{
try (ZipInputStream zip = new ZipInputStream(is))
{
ZipEntry entry = zip.getNextEntry();
while (entry != null)
{
File out = new File(dest, entry.getName());
File parentFile = out.getParentFile();
if (!parentFile.exists())
{
parentFile.mkdirs();
}
if (!entry.isDirectory())
{
byte[] buffer = new byte[4096];
try (BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(out)))
{
int count = 0;
while ((count = zip.read(buffer)) != -1)
{
bos.write(buffer, 0, count);
}
}
}
else
{
out.mkdirs();
}
zip.closeEntry();
entry = zip.getNextEntry();
}
}
}
}

View File

@@ -0,0 +1,45 @@
package org.springframework.ide.eclipse.chromium.browser;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.widgets.Composite;
public class FPSText
{
private long start = System.currentTimeMillis();
private long frames = 0;
private String fps = "";
public void calcFPS()
{
long end = System.currentTimeMillis();
frames++;
if (end - start > 1000)
{
fps = "FPS: " + String.format("%.2f", frames / ((end - start) / 1000.0));
frames = 0;
start = end;
}
}
public void drawFPS(GC gc, Composite comp, int x, int y)
{
Point textSize = gc.textExtent(fps);
int width = comp.getBounds().width;
int posX = width - textSize.x;
if ((x > posX && y < textSize.y) || frames == 0);
{
gc.drawText(fps, posX, 0, false);
comp.redraw(posX, 0, width, textSize.y, false);
}
}
public static void initGC(GC gc)
{
gc.setFont(new Font(null,"Arial", 16, SWT.BOLD ));
gc.setForeground(new Color(null, 255, 0, 0));
}
}

View File

@@ -0,0 +1,73 @@
package org.springframework.ide.eclipse.chromium.browser;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
class PartialInputStream extends FilterInputStream
{
private int bytesToRead;
protected PartialInputStream(InputStream in, int size)
{
super(in);
bytesToRead = size;
}
@Override
public int available() throws IOException
{
return Math.min(super.available(), bytesToRead);
}
@Override
public void close() throws IOException
{
bytesToRead = 0;
}
@Override
public synchronized void mark(int readlimit)
{
throw new UnsupportedOperationException("mark not supported");
}
@Override
public boolean markSupported()
{
return false;
}
@Override
public int read() throws IOException
{
if (bytesToRead == 0) return -1;
int read = super.read();
if (read != -1) bytesToRead--;
return read;
}
@Override
public int read(byte[] b, int off, int len) throws IOException
{
if (bytesToRead == 0) return -1;
int read = super.read(b, off, Math.min(len, bytesToRead));
bytesToRead -= read;
return read;
}
@Override
public synchronized void reset() throws IOException
{
throw new UnsupportedOperationException("reset not supported");
}
@Override
public long skip(long n) throws IOException
{
long skip = super.skip(Math.min(n, bytesToRead));
bytesToRead -= skip;
return skip;
}
}

View File

@@ -20,16 +20,20 @@ import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.layout.GridLayoutFactory;
import org.eclipse.jface.resource.ColorRegistry;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.swt.SWT;
import org.eclipse.swt.browser.Browser;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.graphics.RGBA;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.IMemento;
import org.eclipse.ui.IViewSite;
@@ -38,6 +42,7 @@ import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.part.ViewPart;
import org.eclipse.ui.themes.ITheme;
import org.springframework.ide.eclipse.chromium.browser.ElectronBrowserCanvas;
import org.springframework.ide.eclipse.xterm.XtermPlugin;
public class TerminalView extends ViewPart {
@@ -58,7 +63,8 @@ public class TerminalView extends ViewPart {
private Action refreshAction;
private Browser browser;
private ElectronBrowserCanvas browser;
private Text addressBar;
private String terminalId = DEFAULT_TERMINAL_ID;
@@ -68,6 +74,8 @@ public class TerminalView extends ViewPart {
private boolean isNewView;
private Composite parent;
private final IPropertyChangeListener PROPERTY_LISTENER = new IPropertyChangeListener() {
@Override
@@ -89,8 +97,41 @@ public class TerminalView extends ViewPart {
@Override
public void createPartControl(Composite parent) {
this.parent = parent;
PlatformUI.getWorkbench().getThemeManager().addPropertyChangeListener(PROPERTY_LISTENER);
browser = new Browser(parent, SWT.CHROMIUM);
Composite shell = new Composite(parent, SWT.None);
GridLayout layout = new GridLayout(1, false);
layout.marginHeight = 0;
layout.marginWidth = 0;
shell.setLayout(layout);
String url = "https://google.com";
addressBar = new Text(shell, SWT.SINGLE);
addressBar.setText(url);
GridData layoutData1 = new GridData(SWT.FILL, SWT.CENTER, true, false);
addressBar.setLayoutData(layoutData1);
browser = new ElectronBrowserCanvas(shell, false);
GridData layoutData2 = new GridData(SWT.FILL, SWT.FILL, true, true);
browser.setLayoutData(layoutData2);
addressBar.addListener(SWT.Traverse, event -> {
if (event.detail == SWT.TRAVERSE_RETURN)
{
String text = addressBar.getText();
if (!text.startsWith("http") && !text.isEmpty())
{
text = "http://" + text;
addressBar.setText(text);
}
browser.browse(text);
}
});
// browser = new ElectronBrowserCanvas(parent, false);
// browser.setLayoutData(GridDataFactory.fillDefaults().grab(true, true).create());
makeActions();
contributeToActionBars();
if (isNewView) {
@@ -147,7 +188,10 @@ public class TerminalView extends ViewPart {
String serviceUrl = XtermPlugin.getDefault().xtermUrl(10_000).get();
if (Display.getCurrent() != null) {
if (browser != null && !browser.isDisposed() && terminalId.equals(TerminalView.this.terminalId)) {
browser.setUrl(createUrl(serviceUrl, terminalId, cmd, cwd));
String url = createUrl(serviceUrl, terminalId, cmd, cwd);
addressBar.setText(url);
XtermPlugin.getDefault().getLog().info("Navigating to " + url);
browser.browse(url);
}
} else {
Display display = PlatformUI.getWorkbench().getDisplay();
@@ -155,7 +199,9 @@ public class TerminalView extends ViewPart {
display.asyncExec(() -> {
if (browser != null && !browser.isDisposed() && terminalId.equals(TerminalView.this.terminalId)) {
String url = createUrl(serviceUrl, terminalId, cmd, cwd);
browser.setUrl(url);
addressBar.setText(url);
XtermPlugin.getDefault().getLog().info("Navigating to " + url);
browser.browse(url);
}
});
}