Make MiniDesktop RAP compatible.
authorMathieu Baudier <mbaudier@argeo.org>
Sun, 10 Jul 2022 10:10:24 +0000 (12:10 +0200)
committerMathieu Baudier <mbaudier@argeo.org>
Sun, 10 Jul 2022 10:10:24 +0000 (12:10 +0200)
43 files changed:
rcp/org.argeo.swt.minidesktop/.classpath [deleted file]
rcp/org.argeo.swt.minidesktop/.gitignore [deleted file]
rcp/org.argeo.swt.minidesktop/.project [deleted file]
rcp/org.argeo.swt.minidesktop/META-INF/.gitignore [deleted file]
rcp/org.argeo.swt.minidesktop/bnd.bnd [deleted file]
rcp/org.argeo.swt.minidesktop/build.properties [deleted file]
rcp/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/MiniBrowser.java [deleted file]
rcp/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/MiniDesktopImages.java [deleted file]
rcp/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/MiniDesktopManager.java [deleted file]
rcp/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/MiniExplorer.java [deleted file]
rcp/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/MiniHomePart.java [deleted file]
rcp/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/MiniImageViewer.java [deleted file]
rcp/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/MiniTerminal.java [deleted file]
rcp/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/MiniTextEditor.java [deleted file]
rcp/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/cheatsheet_obj@2x.png [deleted file]
rcp/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/console_view@2x.png [deleted file]
rcp/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/delete@2x.png [deleted file]
rcp/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/external_browser@2x.png [deleted file]
rcp/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/file_obj@2x.png [deleted file]
rcp/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/fldr_obj@2x.png [deleted file]
rcp/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/nav_home@2x.png [deleted file]
swt/org.argeo.swt.minidesktop/.classpath [new file with mode: 0644]
swt/org.argeo.swt.minidesktop/.gitignore [new file with mode: 0644]
swt/org.argeo.swt.minidesktop/.project [new file with mode: 0644]
swt/org.argeo.swt.minidesktop/META-INF/.gitignore [new file with mode: 0644]
swt/org.argeo.swt.minidesktop/bnd.bnd [new file with mode: 0644]
swt/org.argeo.swt.minidesktop/build.properties [new file with mode: 0644]
swt/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/MiniBrowser.java [new file with mode: 0644]
swt/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/MiniDesktopImages.java [new file with mode: 0644]
swt/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/MiniDesktopManager.java [new file with mode: 0644]
swt/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/MiniExplorer.java [new file with mode: 0644]
swt/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/MiniHomePart.java [new file with mode: 0644]
swt/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/MiniImageViewer.java [new file with mode: 0644]
swt/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/MiniTerminal.java [new file with mode: 0644]
swt/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/MiniTextEditor.java [new file with mode: 0644]
swt/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/cheatsheet_obj@2x.png [new file with mode: 0644]
swt/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/console_view@2x.png [new file with mode: 0644]
swt/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/delete@2x.png [new file with mode: 0644]
swt/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/external_browser@2x.png [new file with mode: 0644]
swt/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/file_obj@2x.png [new file with mode: 0644]
swt/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/fldr_obj@2x.png [new file with mode: 0644]
swt/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/nav_home@2x.png [new file with mode: 0644]
swt/rap/org.argeo.cms.swt.rap.cli/src/org/argeo/cms/swt/rap/cli/RwtRunner.java

diff --git a/rcp/org.argeo.swt.minidesktop/.classpath b/rcp/org.argeo.swt.minidesktop/.classpath
deleted file mode 100644 (file)
index eca7bdb..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-<?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="bin"/>
-</classpath>
diff --git a/rcp/org.argeo.swt.minidesktop/.gitignore b/rcp/org.argeo.swt.minidesktop/.gitignore
deleted file mode 100644 (file)
index 97adb72..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-/bin/
-/target/
-*.log
\ No newline at end of file
diff --git a/rcp/org.argeo.swt.minidesktop/.project b/rcp/org.argeo.swt.minidesktop/.project
deleted file mode 100644 (file)
index b6c2c1a..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<projectDescription>
-       <name>org.argeo.swt.minidesktop</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>
-       </buildSpec>
-       <natures>
-               <nature>org.eclipse.pde.PluginNature</nature>
-               <nature>org.eclipse.jdt.core.javanature</nature>
-       </natures>
-</projectDescription>
diff --git a/rcp/org.argeo.swt.minidesktop/META-INF/.gitignore b/rcp/org.argeo.swt.minidesktop/META-INF/.gitignore
deleted file mode 100644 (file)
index 4854a41..0000000
+++ /dev/null
@@ -1 +0,0 @@
-/MANIFEST.MF
diff --git a/rcp/org.argeo.swt.minidesktop/bnd.bnd b/rcp/org.argeo.swt.minidesktop/bnd.bnd
deleted file mode 100644 (file)
index f3c13be..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-Import-Package: org.eclipse.swt,\
-*
diff --git a/rcp/org.argeo.swt.minidesktop/build.properties b/rcp/org.argeo.swt.minidesktop/build.properties
deleted file mode 100644 (file)
index 34d2e4d..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-source.. = src/
-output.. = bin/
-bin.includes = META-INF/,\
-               .
diff --git a/rcp/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/MiniBrowser.java b/rcp/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/MiniBrowser.java
deleted file mode 100644 (file)
index 406382b..0000000
+++ /dev/null
@@ -1,187 +0,0 @@
-package org.argeo.minidesktop;
-
-import java.util.Arrays;
-import java.util.List;
-
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.browser.Browser;
-import org.eclipse.swt.browser.LocationAdapter;
-import org.eclipse.swt.browser.LocationEvent;
-import org.eclipse.swt.events.KeyAdapter;
-import org.eclipse.swt.events.KeyEvent;
-import org.eclipse.swt.events.SelectionAdapter;
-import org.eclipse.swt.events.SelectionEvent;
-import org.eclipse.swt.graphics.Point;
-import org.eclipse.swt.graphics.Rectangle;
-import org.eclipse.swt.layout.FillLayout;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Display;
-import org.eclipse.swt.widgets.Shell;
-import org.eclipse.swt.widgets.Text;
-
-/** A very minimalistic web browser based on {@link Browser}. */
-public class MiniBrowser {
-       private static Point defaultShellSize = new Point(800, 480);
-
-       private Browser browser;
-       private Text addressT;
-
-       private final boolean fullscreen;
-       private final boolean appMode;
-
-       public MiniBrowser(Composite composite, String url, boolean fullscreen, boolean appMode) {
-               this.fullscreen = fullscreen;
-               this.appMode = appMode;
-               createUi(composite);
-               setUrl(url);
-       }
-
-       public Control createUi(Composite parent) {
-               parent.setLayout(noSpaceGridLayout(new GridLayout()));
-               if (!isAppMode()) {
-                       Control toolBar = createToolBar(parent);
-                       toolBar.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
-               }
-               Control body = createBody(parent);
-               body.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
-               return body;
-       }
-
-       protected Control createToolBar(Composite parent) {
-               Composite toolBar = new Composite(parent, SWT.NONE);
-               toolBar.setLayout(new FillLayout());
-               addressT = new Text(toolBar, SWT.SINGLE);
-               addressT.addSelectionListener(new SelectionAdapter() {
-
-                       @Override
-                       public void widgetDefaultSelected(SelectionEvent e) {
-                               setUrl(addressT.getText().trim());
-                       }
-               });
-               return toolBar;
-       }
-
-       protected Control createBody(Composite parent) {
-               browser = new Browser(parent, SWT.NONE);
-               if (isFullScreen())
-                       browser.addKeyListener(new KeyAdapter() {
-                               @Override
-                               public void keyPressed(KeyEvent e) {
-                                       if (e.keyCode == 0x77 && e.stateMask == 0x40000) {// Ctrl+W
-                                               browser.getShell().dispose();
-                                       }
-                               }
-                       });
-               browser.addLocationListener(new LocationAdapter() {
-                       @Override
-                       public void changed(LocationEvent event) {
-                               System.out.println(event);
-                               if (addressT != null)
-                                       addressT.setText(event.location);
-                       }
-
-               });
-               browser.addTitleListener(e -> titleChanged(e.title));
-               browser.addOpenWindowListener((e) -> {
-                       e.browser = openNewBrowserWindow();
-               });
-               return browser;
-       }
-
-       protected Browser openNewBrowserWindow() {
-
-               if (isFullScreen()) {
-                       // TODO manage multiple tabs?
-                       return browser;
-               } else {
-                       Shell newShell = new Shell(browser.getDisplay(), SWT.SHELL_TRIM);
-                       MiniBrowser newMiniBrowser = new MiniBrowser(newShell, null, false, isAppMode());
-                       newShell.setSize(defaultShellSize);
-                       newShell.open();
-                       return newMiniBrowser.browser;
-               }
-       }
-
-       protected boolean isFullScreen() {
-               return fullscreen;
-       }
-
-       void setUrl(String url) {
-               if (browser != null && url != null && !url.equals(browser.getUrl()))
-                       browser.setUrl(url.toString());
-       }
-
-       /** Called when URL changed; to be overridden, does nothing by default. */
-       protected void urlChanged(String url) {
-       }
-
-       /** Called when title changed; to be overridden, does nothing by default. */
-       protected void titleChanged(String title) {
-       }
-
-       protected Browser getBrowser() {
-               return browser;
-       }
-
-       protected boolean isAppMode() {
-               return appMode;
-       }
-
-       private static GridLayout noSpaceGridLayout(GridLayout layout) {
-               layout.horizontalSpacing = 0;
-               layout.verticalSpacing = 0;
-               layout.marginWidth = 0;
-               layout.marginHeight = 0;
-               return layout;
-       }
-
-       public static void main(String[] args) {
-               List<String> options = Arrays.asList(args);
-               if (options.contains("--help")) {
-                       System.out.println("Usage: java " + MiniBrowser.class.getName().replace('.', '/') + " [OPTION] [URL]");
-                       System.out.println("A minimalistic web browser Eclipse SWT Browser integration.");
-                       System.out.println("  --fullscreen : take control of the whole screen (default is to run in a window)");
-                       System.out.println("  --app        : open without an address bar and a toolbar");
-                       System.out.println("  --help       : print this help and exit");
-                       System.exit(1);
-               }
-               boolean fullscreen = options.contains("--fullscreen");
-               boolean appMode = options.contains("--app");
-               String url = "https://start.duckduckgo.com/";
-               if (options.size() > 0) {
-                       String last = options.get(options.size() - 1);
-                       if (!last.startsWith("--"))
-                               url = last.trim();
-               }
-
-               Display display = Display.getCurrent() == null ? new Display() : Display.getCurrent();
-               Shell shell;
-               if (fullscreen) {
-                       shell = new Shell(display, SWT.NO_TRIM);
-                       shell.setFullScreen(true);
-                       Rectangle bounds = display.getBounds();
-                       shell.setSize(bounds.width, bounds.height);
-               } else {
-                       shell = new Shell(display, SWT.SHELL_TRIM);
-                       shell.setSize(defaultShellSize);
-               }
-
-               new MiniBrowser(shell, url, fullscreen, appMode) {
-
-                       @Override
-                       protected void titleChanged(String title) {
-                               shell.setText(title);
-                       }
-               };
-               shell.open();
-
-               while (!shell.isDisposed()) {
-                       if (!display.readAndDispatch())
-                               display.sleep();
-               }
-       }
-
-}
diff --git a/rcp/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/MiniDesktopImages.java b/rcp/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/MiniDesktopImages.java
deleted file mode 100644 (file)
index db5e6f2..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-package org.argeo.minidesktop;
-
-import java.io.IOException;
-import java.io.InputStream;
-
-import org.eclipse.swt.SWTException;
-import org.eclipse.swt.graphics.Image;
-import org.eclipse.swt.widgets.Display;
-
-/** Icons. */
-public class MiniDesktopImages {
-
-       public final Image homeIcon;
-       public final Image exitIcon;
-       
-       public final Image terminalIcon;
-       public final Image browserIcon;
-       public final Image explorerIcon;
-       public final Image textEditorIcon;
-
-       public final Image folderIcon;
-       public final Image fileIcon;
-
-       public MiniDesktopImages(Display display) {
-               homeIcon = loadImage(display, "nav_home@2x.png");
-               exitIcon = loadImage(display, "delete@2x.png");
-
-               terminalIcon = loadImage(display, "console_view@2x.png");
-               browserIcon = loadImage(display, "external_browser@2x.png");
-               explorerIcon = loadImage(display, "fldr_obj@2x.png");
-               textEditorIcon = loadImage(display, "cheatsheet_obj@2x.png");
-
-               folderIcon = loadImage(display, "fldr_obj@2x.png");
-               fileIcon = loadImage(display, "file_obj@2x.png");
-       }
-
-       static Image loadImage(Display display, String path) {
-               InputStream stream = MiniDesktopImages.class.getResourceAsStream(path);
-               if (stream == null)
-                       throw new IllegalArgumentException("Image " + path + " not found");
-               Image image = null;
-               try {
-                       image = new Image(display, stream);
-               } catch (SWTException ex) {
-               } finally {
-                       try {
-                               stream.close();
-                       } catch (IOException ex) {
-                       }
-               }
-               return image;
-       }
-}
diff --git a/rcp/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/MiniDesktopManager.java b/rcp/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/MiniDesktopManager.java
deleted file mode 100644 (file)
index e0f483d..0000000
+++ /dev/null
@@ -1,349 +0,0 @@
-package org.argeo.minidesktop;
-
-import java.lang.management.ManagementFactory;
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.nio.file.Path;
-import java.util.Arrays;
-import java.util.List;
-
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.custom.CTabFolder;
-import org.eclipse.swt.custom.CTabItem;
-import org.eclipse.swt.events.SelectionAdapter;
-import org.eclipse.swt.events.SelectionEvent;
-import org.eclipse.swt.graphics.Color;
-import org.eclipse.swt.graphics.Image;
-import org.eclipse.swt.graphics.ImageData;
-import org.eclipse.swt.graphics.Point;
-import org.eclipse.swt.graphics.Rectangle;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.program.Program;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Display;
-import org.eclipse.swt.widgets.Shell;
-import org.eclipse.swt.widgets.ToolBar;
-import org.eclipse.swt.widgets.ToolItem;
-
-/** A very minimalistic desktop manager based on Java and Eclipse SWT. */
-public class MiniDesktopManager {
-       private Display display;
-
-       private Shell rootShell;
-       private Shell toolBarShell;
-       private CTabFolder tabFolder;
-       private int maxTabTitleLength = 16;
-
-       private final boolean fullscreen;
-       private final boolean stacking;
-
-       private MiniDesktopImages images;
-
-       public MiniDesktopManager(boolean fullscreen, boolean stacking) {
-               this.fullscreen = fullscreen;
-               this.stacking = stacking;
-       }
-
-       public void init() {
-               Display.setAppName("Mini SWT Desktop");
-               display = Display.getCurrent();
-               if (display != null)
-                       throw new IllegalStateException("Already a display " + display);
-               display = new Display();
-
-               if (display.getTouchEnabled()) {
-                       System.out.println("Touch enabled.");
-               }
-
-               images = new MiniDesktopImages(display);
-
-               int toolBarSize = 48;
-
-               if (isFullscreen()) {
-                       rootShell = new Shell(display, SWT.NO_TRIM);
-                       rootShell.setFullScreen(true);
-                       Rectangle bounds = display.getBounds();
-                       rootShell.setLocation(0, 0);
-                       rootShell.setSize(bounds.width, bounds.height);
-               } else {
-                       rootShell = new Shell(display, SWT.CLOSE | SWT.RESIZE);
-                       Rectangle shellArea = rootShell.computeTrim(200, 200, 800, 480);
-                       rootShell.setSize(shellArea.width, shellArea.height);
-                       rootShell.setText(Display.getAppName());
-                       rootShell.setImage(images.terminalIcon);
-               }
-
-               rootShell.setLayout(noSpaceGridLayout(new GridLayout(2, false)));
-               Composite toolBarArea = new Composite(rootShell, SWT.NONE);
-               toolBarArea.setLayoutData(new GridData(toolBarSize, rootShell.getSize().y));
-
-               ToolBar toolBar;
-               if (isFullscreen()) {
-                       toolBarShell = new Shell(rootShell, SWT.NO_TRIM | SWT.ON_TOP);
-                       toolBar = new ToolBar(toolBarShell, SWT.VERTICAL | SWT.FLAT | SWT.BORDER);
-                       createDock(toolBar);
-                       toolBarShell.pack();
-                       toolBarArea.setLayoutData(new GridData(toolBar.getSize().x, toolBar.getSize().y));
-               } else {
-                       toolBar = new ToolBar(toolBarArea, SWT.VERTICAL | SWT.FLAT | SWT.BORDER);
-                       createDock(toolBar);
-                       toolBarArea.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
-               }
-
-               if (isStacking()) {
-                       tabFolder = new CTabFolder(rootShell, SWT.MULTI | SWT.BORDER | SWT.BOTTOM);
-                       tabFolder.setLayout(noSpaceGridLayout(new GridLayout()));
-                       tabFolder.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
-
-                       Color selectionBackground = display.getSystemColor(SWT.COLOR_LIST_SELECTION);
-                       tabFolder.setSelectionBackground(selectionBackground);
-
-                       // background
-                       Control background = createBackground(tabFolder);
-                       CTabItem homeTabItem = new CTabItem(tabFolder, SWT.NONE);
-                       homeTabItem.setText("Home");
-                       homeTabItem.setImage(images.homeIcon);
-                       homeTabItem.setControl(background);
-                       tabFolder.setFocus();
-               } else {
-                       createBackground(rootShell);
-               }
-
-               rootShell.open();
-               // rootShell.layout(true, true);
-
-               if (toolBarShell != null) {
-                       int toolBarShellY = (display.getBounds().height - toolBar.getSize().y) / 2;
-                       toolBarShell.setLocation(0, toolBarShellY);
-                       toolBarShell.open();
-               }
-
-               long jvmUptime = ManagementFactory.getRuntimeMXBean().getUptime();
-               System.out.println("SWT Mini Desktop Manager available in " + jvmUptime + " ms.");
-       }
-
-       protected void createDock(ToolBar toolBar) {
-               // Terminal
-               addToolItem(toolBar, images.terminalIcon, "Terminal", () -> {
-                       String url = System.getProperty("user.home");
-                       AppContext appContext = createAppParent(images.terminalIcon);
-                       new MiniTerminal(appContext.getAppParent(), url) {
-
-                               @Override
-                               protected void exitCalled() {
-                                       if (appContext.shell != null)
-                                               appContext.shell.dispose();
-                                       if (appContext.tabItem != null)
-                                               appContext.tabItem.dispose();
-                               }
-                       };
-                       String title;
-                       try {
-                               title = System.getProperty("user.name") + "@" + InetAddress.getLocalHost().getHostName();
-                       } catch (UnknownHostException e) {
-                               title = System.getProperty("user.name") + "@localhost";
-                       }
-                       if (appContext.shell != null)
-                               appContext.shell.setText(title);
-                       if (appContext.tabItem != null) {
-                               appContext.tabItem.setText(tabTitle(title));
-                               appContext.tabItem.setToolTipText(title);
-                       }
-                       openApp(appContext);
-               });
-
-               // Web browser
-               addToolItem(toolBar, images.browserIcon, "Browser", () -> {
-                       String url = "https://start.duckduckgo.com/";
-                       AppContext appContext = createAppParent(images.browserIcon);
-                       new MiniBrowser(appContext.getAppParent(), url, false, false) {
-                               @Override
-                               protected void titleChanged(String title) {
-                                       if (appContext.shell != null)
-                                               appContext.shell.setText(title);
-                                       if (appContext.tabItem != null) {
-                                               appContext.tabItem.setText(tabTitle(title));
-                                               appContext.tabItem.setToolTipText(title);
-                                       }
-                               }
-                       };
-                       openApp(appContext);
-               });
-
-               // File explorer
-               addToolItem(toolBar, images.explorerIcon, "Explorer", () -> {
-                       String url = System.getProperty("user.home");
-                       AppContext appContext = createAppParent(images.explorerIcon);
-                       new MiniExplorer(appContext.getAppParent(), url) {
-
-                               @Override
-                               protected void pathChanged(Path path) {
-                                       if (appContext.shell != null)
-                                               appContext.shell.setText(path.toString());
-                                       if (appContext.tabItem != null) {
-                                               appContext.tabItem.setText(path.getFileName().toString());
-                                               appContext.tabItem.setToolTipText(path.toString());
-                                       }
-                               }
-                       };
-                       openApp(appContext);
-               });
-
-               // Separator
-               new ToolItem(toolBar, SWT.SEPARATOR);
-
-               // Exit
-               addToolItem(toolBar, images.exitIcon, "Exit", () -> rootShell.dispose());
-
-               toolBar.pack();
-       }
-
-       protected String tabTitle(String title) {
-               return title.length() > maxTabTitleLength ? title.substring(0, maxTabTitleLength) : title;
-       }
-
-       protected void addToolItem(ToolBar toolBar, Image icon, String name, Runnable action) {
-               ToolItem searchI = new ToolItem(toolBar, SWT.PUSH);
-               searchI.setImage(icon);
-               searchI.setToolTipText(name);
-               searchI.addSelectionListener(new SelectionAdapter() {
-
-                       @Override
-                       public void widgetSelected(SelectionEvent e) {
-                               action.run();
-                       }
-
-               });
-       }
-
-       protected AppContext createAppParent(Image icon) {
-               if (isStacking()) {
-                       Composite appParent = new Composite(tabFolder, SWT.CLOSE);
-                       appParent.setLayout(noSpaceGridLayout(new GridLayout()));
-                       CTabItem item = new CTabItem(tabFolder, SWT.CLOSE);
-                       item.setImage(icon);
-                       item.setControl(appParent);
-                       return new AppContext(item);
-               } else {
-                       Shell shell = isFullscreen() ? new Shell(rootShell, SWT.SHELL_TRIM)
-                                       : new Shell(rootShell.getDisplay(), SWT.SHELL_TRIM);
-                       shell.setImage(icon);
-                       return new AppContext(shell);
-               }
-       }
-
-       protected void openApp(AppContext appContext) {
-               if (appContext.shell != null) {
-                       Shell shell = (Shell) appContext.shell;
-                       shell.open();
-                       shell.setSize(new Point(800, 480));
-               }
-               if (appContext.tabItem != null) {
-                       tabFolder.setFocus();
-                       tabFolder.setSelection(appContext.tabItem);
-               }
-       }
-
-       protected Control createBackground(Composite parent) {
-               Composite backgroundArea = new Composite(parent, SWT.NONE);
-               backgroundArea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
-               initBackground(backgroundArea);
-               return backgroundArea;
-       }
-
-       protected void initBackground(Composite backgroundArea) {
-               MiniHomePart homePart = new MiniHomePart() {
-
-                       @Override
-                       protected void fillAppsToolBar(ToolBar toolBar) {
-                               createDock(toolBar);
-                       }
-               };
-               homePart.createUiPart(backgroundArea, null);
-       }
-
-       public void run() {
-               while (!rootShell.isDisposed()) {
-                       if (!display.readAndDispatch())
-                               display.sleep();
-               }
-       }
-
-       public void dispose() {
-               if (!rootShell.isDisposed())
-                       rootShell.dispose();
-       }
-
-       protected boolean isFullscreen() {
-               return fullscreen;
-       }
-
-       protected boolean isStacking() {
-               return stacking;
-       }
-
-       protected Image getIconForExt(String ext) {
-               Program program = Program.findProgram(ext);
-               if (program == null)
-                       return display.getSystemImage(SWT.ICON_INFORMATION);
-
-               ImageData iconData = program.getImageData();
-               if (iconData == null) {
-                       return display.getSystemImage(SWT.ICON_INFORMATION);
-               } else {
-                       return new Image(display, iconData);
-               }
-
-       }
-
-       private static GridLayout noSpaceGridLayout(GridLayout layout) {
-               layout.horizontalSpacing = 0;
-               layout.verticalSpacing = 0;
-               layout.marginWidth = 0;
-               layout.marginHeight = 0;
-               return layout;
-       }
-
-       public static void main(String[] args) {
-               List<String> options = Arrays.asList(args);
-               if (options.contains("--help")) {
-                       System.out.println("Usage: java " + MiniDesktopManager.class.getName().replace('.', '/') + " [OPTION]");
-                       System.out.println("A minimalistic desktop manager based on Java and Eclipse SWT.");
-                       System.out.println("  --fullscreen : take control of the whole screen (default is to run in a window)");
-                       System.out.println("  --stacking   : open apps as tabs (default is to create new windows)");
-                       System.out.println("  --help       : print this help and exit");
-                       System.exit(1);
-               }
-               boolean fullscreen = options.contains("--fullscreen");
-               boolean stacking = options.contains("--stacking");
-
-               MiniDesktopManager desktopManager = new MiniDesktopManager(fullscreen, stacking);
-               desktopManager.init();
-               desktopManager.run();
-               desktopManager.dispose();
-               System.exit(0);
-       }
-
-       class AppContext {
-               private Shell shell;
-               private CTabItem tabItem;
-
-               public AppContext(Shell shell) {
-                       this.shell = shell;
-               }
-
-               public AppContext(CTabItem tabItem) {
-                       this.tabItem = tabItem;
-               }
-
-               Composite getAppParent() {
-                       if (shell != null)
-                               return shell;
-                       if (tabItem != null)
-                               return (Composite) tabItem.getControl();
-                       throw new IllegalStateException();
-               }
-       }
-}
diff --git a/rcp/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/MiniExplorer.java b/rcp/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/MiniExplorer.java
deleted file mode 100644 (file)
index 1395c02..0000000
+++ /dev/null
@@ -1,165 +0,0 @@
-package org.argeo.minidesktop;
-
-import java.io.IOException;
-import java.nio.file.DirectoryStream;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.MouseAdapter;
-import org.eclipse.swt.events.MouseEvent;
-import org.eclipse.swt.events.SelectionAdapter;
-import org.eclipse.swt.events.SelectionEvent;
-import org.eclipse.swt.graphics.Point;
-import org.eclipse.swt.layout.FillLayout;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.program.Program;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Display;
-import org.eclipse.swt.widgets.Shell;
-import org.eclipse.swt.widgets.Table;
-import org.eclipse.swt.widgets.TableItem;
-import org.eclipse.swt.widgets.Text;
-
-public class MiniExplorer {
-       private Path path;
-       private Text addressT;
-       private Table browser;
-
-       private boolean showHidden = false;
-
-       public MiniExplorer(Composite parent, String url) {
-               this(parent);
-               setUrl(url);
-       }
-
-       public MiniExplorer(Composite parent) {
-               parent.setLayout(noSpaceGridLayout(new GridLayout()));
-
-               Composite toolBar = new Composite(parent, SWT.NONE);
-               toolBar.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
-               toolBar.setLayout(new FillLayout());
-               addressT = new Text(toolBar, SWT.SINGLE);
-               addressT.addSelectionListener(new SelectionAdapter() {
-
-                       @Override
-                       public void widgetDefaultSelected(SelectionEvent e) {
-                               setUrl(addressT.getText().trim());
-                       }
-               });
-               browser = createTable(parent, this.path);
-
-       }
-
-       public void setPath(Path url) {
-               this.path = url;
-               if (addressT != null)
-                       addressT.setText(url.toString());
-               if (browser != null) {
-                       Composite parent = browser.getParent();
-                       browser.dispose();
-                       browser = createTable(parent, this.path);
-                       parent.layout(true, true);
-               }
-               pathChanged(url);
-       }
-
-       protected void pathChanged(Path path) {
-
-       }
-
-       protected Table createTable(Composite parent, Path path) {
-               Table table = new Table(parent, SWT.BORDER);
-               table.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
-               table.addMouseListener(new MouseAdapter() {
-
-                       @Override
-                       public void mouseDoubleClick(MouseEvent e) {
-                               Point pt = new Point(e.x, e.y);
-                               TableItem item = table.getItem(pt);
-                               Path path = (Path) item.getData();
-                               if (Files.isDirectory(path)) {
-                                       setPath(path);
-                               } else {
-                                       Program.launch(path.toString());
-                               }
-                       }
-               });
-
-               if (path != null) {
-                       if (path.getParent() != null) {
-                               TableItem parentTI = new TableItem(table, SWT.NONE);
-                               parentTI.setText("..");
-                               parentTI.setData(path.getParent());
-                       }
-
-                       try {
-                               // directories
-                               DirectoryStream<Path> ds = Files.newDirectoryStream(path, p -> Files.isDirectory(p) && isShown(p));
-                               ds.forEach(p -> {
-                                       TableItem ti = new TableItem(table, SWT.NONE);
-                                       ti.setText(p.getFileName().toString() + "/");
-                                       ti.setData(p);
-                               });
-                               // files
-                               ds = Files.newDirectoryStream(path, p -> !Files.isDirectory(p) && isShown(p));
-                               ds.forEach(p -> {
-                                       TableItem ti = new TableItem(table, SWT.NONE);
-                                       ti.setText(p.getFileName().toString());
-                                       ti.setData(p);
-                               });
-                       } catch (IOException e1) {
-                               // TODO Auto-generated catch block
-                               e1.printStackTrace();
-                       }
-               }
-               return table;
-       }
-
-       protected boolean isShown(Path path) {
-               if (showHidden)
-                       return true;
-               try {
-                       return !Files.isHidden(path);
-               } catch (IOException e) {
-                       throw new IllegalArgumentException("Cannot check " + path, e);
-               }
-       }
-
-       public void setUrl(String url) {
-               setPath(Paths.get(url));
-       }
-
-       private static GridLayout noSpaceGridLayout(GridLayout layout) {
-               layout.horizontalSpacing = 0;
-               layout.verticalSpacing = 0;
-               layout.marginWidth = 0;
-               layout.marginHeight = 0;
-               return layout;
-       }
-
-       public static void main(String[] args) {
-               Display display = Display.getCurrent() == null ? new Display() : Display.getCurrent();
-               Shell shell = new Shell(display, SWT.SHELL_TRIM);
-
-               String url = args.length > 0 ? args[0] : System.getProperty("user.home");
-               new MiniExplorer(shell, url) {
-
-                       @Override
-                       protected void pathChanged(Path path) {
-                               shell.setText(path.toString());
-                       }
-
-               };
-
-               shell.open();
-               shell.setSize(new Point(800, 480));
-               while (!shell.isDisposed()) {
-                       if (!display.readAndDispatch())
-                               display.sleep();
-               }
-       }
-
-}
diff --git a/rcp/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/MiniHomePart.java b/rcp/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/MiniHomePart.java
deleted file mode 100644 (file)
index 877f643..0000000
+++ /dev/null
@@ -1,161 +0,0 @@
-package org.argeo.minidesktop;
-
-import java.net.InetAddress;
-import java.net.InterfaceAddress;
-import java.net.NetworkInterface;
-import java.net.SocketException;
-import java.net.UnknownHostException;
-import java.util.Enumeration;
-
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Display;
-import org.eclipse.swt.widgets.Group;
-import org.eclipse.swt.widgets.Label;
-import org.eclipse.swt.widgets.ProgressBar;
-import org.eclipse.swt.widgets.ToolBar;
-
-/** A start page displaying network information and resources. */
-public class MiniHomePart {
-
-       public Control createUiPart(Composite parent, Object context) {
-               parent.setLayout(new GridLayout(2, false));
-               Display display = parent.getDisplay();
-
-               // Apps
-               Group appsGroup = new Group(parent, SWT.NONE);
-               appsGroup.setText("Apps");
-               appsGroup.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false, 2, 1));
-               ToolBar appsToolBar = new ToolBar(appsGroup, SWT.HORIZONTAL | SWT.FLAT);
-               fillAppsToolBar(appsToolBar);
-
-               // Host
-               Group hostGroup = new Group(parent, SWT.NONE);
-               hostGroup.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false));
-               hostGroup.setText("Host");
-               hostGroup.setLayout(new GridLayout(2, false));
-               label(hostGroup, "Hostname: ");
-               try {
-                       InetAddress defaultAddr = InetAddress.getLocalHost();
-                       String hostname = defaultAddr.getHostName();
-                       label(hostGroup, hostname);
-                       label(hostGroup, "Address: ");
-                       label(hostGroup, defaultAddr.getHostAddress());
-               } catch (UnknownHostException e) {
-                       label(hostGroup, e.getMessage());
-               }
-
-               Enumeration<NetworkInterface> netInterfaces = null;
-               try {
-                       netInterfaces = NetworkInterface.getNetworkInterfaces();
-               } catch (SocketException e) {
-                       label(hostGroup, "Interfaces: ");
-                       label(hostGroup, e.getMessage());
-               }
-               if (netInterfaces != null)
-                       while (netInterfaces.hasMoreElements()) {
-                               NetworkInterface netInterface = netInterfaces.nextElement();
-                               byte[] hardwareAddress = null;
-                               try {
-                                       hardwareAddress = netInterface.getHardwareAddress();
-                                       if (hardwareAddress != null) {
-                                               label(hostGroup, convertHardwareAddress(hardwareAddress));
-                                               label(hostGroup, netInterface.getName());
-                                               for (InterfaceAddress addr : netInterface.getInterfaceAddresses()) {
-                                                       label(hostGroup, cleanHostAddress(addr.getAddress().getHostAddress()));
-                                                       label(hostGroup, Short.toString(addr.getNetworkPrefixLength()));
-                                               }
-                                       }
-                               } catch (SocketException e) {
-                                       label(hostGroup, e.getMessage());
-                               }
-                       }
-
-               // Resources
-               Group resGroup = new Group(parent, SWT.NONE);
-               resGroup.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
-               resGroup.setText("Resources");
-               resGroup.setLayout(new GridLayout(3, false));
-
-               Runtime runtime = Runtime.getRuntime();
-
-               String maxMemoryStr = Long.toString(runtime.maxMemory() / (1024 * 1024)) + " MB";
-               label(resGroup, "Max Java memory: ");
-               label(resGroup, maxMemoryStr);
-               label(resGroup, "Java version: " + Runtime.version().toString());
-
-               label(resGroup, "Usable Java memory: ");
-               Label totalMemory = label(resGroup, maxMemoryStr);
-               ProgressBar totalOnMax = new ProgressBar(resGroup, SWT.SMOOTH);
-               totalOnMax.setMaximum(100);
-               label(resGroup, "Used Java memory: ");
-               Label usedMemory = label(resGroup, maxMemoryStr);
-               ProgressBar usedOnTotal = new ProgressBar(resGroup, SWT.SMOOTH);
-               totalOnMax.setMaximum(100);
-               new Thread() {
-                       @Override
-                       public void run() {
-                               while (!totalOnMax.isDisposed()) {
-                                       display.asyncExec(() -> {
-                                               if (totalOnMax.isDisposed())
-                                                       return;
-                                               totalOnMax.setSelection(javaTotalOnMaxPerct(runtime));
-                                               usedOnTotal.setSelection(javaUsedOnTotalPerct(runtime));
-                                               totalMemory.setText(Long.toString(runtime.totalMemory() / (1024 * 1024)) + " MB");
-                                               usedMemory.setText(
-                                                               Long.toString((runtime.totalMemory() - runtime.freeMemory()) / (1024 * 1024)) + " MB");
-                                       });
-                                       try {
-                                               Thread.sleep(1000);
-                                       } catch (InterruptedException e) {
-                                               return;
-                                       }
-                               }
-                       }
-               }.start();
-               return parent;
-       }
-
-       protected void fillAppsToolBar(ToolBar toolBar) {
-
-       }
-
-       protected int javaUsedOnTotalPerct(Runtime runtime) {
-               return Math.toIntExact((runtime.totalMemory() - runtime.freeMemory()) * 100 / runtime.totalMemory());
-       }
-
-       protected int javaTotalOnMaxPerct(Runtime runtime) {
-               return Math.toIntExact((runtime.totalMemory()) * 100 / runtime.maxMemory());
-       }
-
-       protected Label label(Composite parent, String text) {
-               Label label = new Label(parent, SWT.WRAP);
-               label.setText(text);
-               return label;
-       }
-
-       protected String cleanHostAddress(String hostAddress) {
-               // remove % from Ipv6 addresses
-               int index = hostAddress.indexOf('%');
-               if (index > 0)
-                       return hostAddress.substring(0, index);
-               else
-                       return hostAddress;
-       }
-
-       protected String convertHardwareAddress(byte[] hardwareAddress) {
-               if (hardwareAddress == null)
-                       return "";
-               // from https://stackoverflow.com/a/2797498/7878010
-               StringBuilder sb = new StringBuilder(18);
-               for (byte b : hardwareAddress) {
-                       if (sb.length() > 0)
-                               sb.append(':');
-                       sb.append(String.format("%02x", b).toUpperCase());
-               }
-               return sb.toString();
-       }
-}
diff --git a/rcp/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/MiniImageViewer.java b/rcp/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/MiniImageViewer.java
deleted file mode 100644 (file)
index 86ff53f..0000000
+++ /dev/null
@@ -1,129 +0,0 @@
-package org.argeo.minidesktop;
-
-import java.io.IOException;
-import java.net.MalformedURLException;
-import java.net.URISyntaxException;
-import java.net.URL;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.PaintEvent;
-import org.eclipse.swt.events.PaintListener;
-import org.eclipse.swt.events.SelectionAdapter;
-import org.eclipse.swt.events.SelectionEvent;
-import org.eclipse.swt.graphics.Image;
-import org.eclipse.swt.graphics.ImageData;
-import org.eclipse.swt.graphics.ImageLoader;
-import org.eclipse.swt.graphics.Point;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.layout.RowLayout;
-import org.eclipse.swt.widgets.Button;
-import org.eclipse.swt.widgets.Canvas;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Display;
-import org.eclipse.swt.widgets.FileDialog;
-import org.eclipse.swt.widgets.Shell;
-
-public class MiniImageViewer implements PaintListener {
-       private URL url;
-       private Canvas area;
-
-       private Image image;
-
-       public MiniImageViewer(Composite parent, int style) {
-               parent.setLayout(new GridLayout());
-
-               Composite toolBar = new Composite(parent, SWT.NONE);
-               toolBar.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
-               toolBar.setLayout(new RowLayout());
-               Button load = new Button(toolBar, SWT.FLAT);
-               load.setText("\u2191");// up arrow
-               load.addSelectionListener(new SelectionAdapter() {
-
-                       @Override
-                       public void widgetSelected(SelectionEvent e) {
-                               FileDialog fileDialog = new FileDialog(area.getShell());
-                               String path = fileDialog.open();
-                               if (path != null) {
-                                       setUrl(path);
-                               }
-                       }
-
-               });
-
-               area = new Canvas(parent, SWT.NONE);
-               area.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
-               area.addPaintListener(this);
-       }
-
-       protected void load(URL url) {
-               try {
-                       ImageLoader imageLoader = new ImageLoader();
-                       ImageData[] data = imageLoader.load(url.openStream());
-                       image = new Image(area.getDisplay(), data[0]);
-               } catch (IOException e) {
-                       // TODO Auto-generated catch block
-                       e.printStackTrace();
-               }
-       }
-
-       @Override
-       public void paintControl(PaintEvent e) {
-               e.gc.drawImage(image, 0, 0);
-
-       }
-
-       protected Path url2path(URL url) {
-               try {
-                       Path path = Paths.get(url.toURI());
-                       return path;
-               } catch (URISyntaxException e) {
-                       throw new IllegalStateException("Cannot convert " + url + " to uri", e);
-               }
-       }
-
-       public void setUrl(URL url) {
-               this.url = url;
-               if (area != null)
-                       load(this.url);
-       }
-
-       public void setUrl(String url) {
-               try {
-                       setUrl(new URL(url));
-               } catch (MalformedURLException e) {
-                       // try with http
-                       try {
-                               setUrl(new URL("file://" + url));
-                               return;
-                       } catch (MalformedURLException e1) {
-                               // nevermind...
-                       }
-                       throw new IllegalArgumentException("Cannot interpret URL " + url, e);
-               }
-       }
-
-       public static void main(String[] args) {
-               Display display = Display.getCurrent() == null ? new Display() : Display.getCurrent();
-               Shell shell = new Shell(display, SWT.SHELL_TRIM);
-
-               MiniImageViewer miniBrowser = new MiniImageViewer(shell, SWT.NONE);
-               String url = args.length > 0 ? args[0] : "";
-               if (!url.trim().equals("")) {
-                       miniBrowser.setUrl(url);
-                       shell.setText(url);
-               } else {
-                       shell.setText("*");
-               }
-
-               shell.open();
-               shell.setSize(new Point(800, 480));
-               while (!shell.isDisposed()) {
-                       if (!display.readAndDispatch())
-                               display.sleep();
-               }
-       }
-
-}
diff --git a/rcp/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/MiniTerminal.java b/rcp/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/MiniTerminal.java
deleted file mode 100644 (file)
index 196ad0c..0000000
+++ /dev/null
@@ -1,342 +0,0 @@
-package org.argeo.minidesktop;
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.io.OutputStream;
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.nio.charset.Charset;
-import java.nio.charset.StandardCharsets;
-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.List;
-import java.util.StringTokenizer;
-
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.KeyEvent;
-import org.eclipse.swt.events.KeyListener;
-import org.eclipse.swt.events.PaintEvent;
-import org.eclipse.swt.events.PaintListener;
-import org.eclipse.swt.graphics.Font;
-import org.eclipse.swt.graphics.GC;
-import org.eclipse.swt.graphics.Point;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Canvas;
-import org.eclipse.swt.widgets.Caret;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Display;
-import org.eclipse.swt.widgets.Shell;
-
-public class MiniTerminal implements KeyListener, PaintListener {
-
-       private Canvas area;
-       private Caret caret;
-
-       private StringBuffer buf = new StringBuffer("");
-       private StringBuffer userInput = new StringBuffer("");
-       private List<String> history = new ArrayList<>();
-
-       private Point charExtent = null;
-       private int charsPerLine = 0;
-       private String[] lines = new String[0];
-       private List<String> logicalLines = new ArrayList<>();
-
-       private Font mono;
-       private Charset charset;
-
-       private Path currentDir;
-       private Path homeDir;
-       private String host = "localhost";
-       private String username;
-
-       // Sub process
-       private Process process;
-       private boolean running = false;
-       private OutputStream stdIn = null;
-
-       private Thread readOut;
-
-       public MiniTerminal(Composite parent, String url) {
-               this(parent);
-               setPath(url);
-       }
-
-       public MiniTerminal(Composite parent) {
-               charset = StandardCharsets.UTF_8;
-
-               Display display = parent.getDisplay();
-               // Linux-specific
-               mono = new Font(display, "Monospace", 10, SWT.NONE);
-
-               parent.setLayout(new GridLayout());
-               area = new Canvas(parent, SWT.NONE);
-               area.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
-               caret = new Caret(area, SWT.NONE);
-               area.setCaret(caret);
-
-               area.addKeyListener(this);
-               area.addPaintListener(this);
-
-               username = System.getProperty("user.name");
-               try {
-                       host = InetAddress.getLocalHost().getHostName();
-                       if (host.indexOf('.') > 0)
-                               host = host.substring(0, host.indexOf('.'));
-               } catch (UnknownHostException e) {
-                       host = "localhost";
-               }
-               homeDir = Paths.get(System.getProperty("user.home"));
-               currentDir = homeDir;
-
-               buf = new StringBuffer(prompt());
-       }
-
-       @Override
-       public void keyPressed(KeyEvent e) {
-       }
-
-       @Override
-       public void keyReleased(KeyEvent e) {
-               if (e.keyLocation != 0)
-                       return;// weird characters
-               // System.out.println(e.character);
-               if (e.keyCode == 0xd) {// return
-                       markLogicalLine();
-                       if (!running)
-                               processUserInput();
-                       // buf.append(prompt());
-               } else if (e.keyCode == 0x8) {// delete
-                       if (userInput.length() == 0)
-                               return;
-                       userInput.setLength(userInput.length() - 1);
-                       if (!running && buf.length() > 0)
-                               buf.setLength(buf.length() - 1);
-               } else if (e.stateMask == 0x40000 && e.keyCode == 0x63) {// Ctrl+C
-                       if (process != null)
-                               process.destroy();
-               } else if (e.stateMask == 0x40000 && e.keyCode == 0xdf) {// Ctrl+\
-                       if (process != null) {
-                               process.destroyForcibly();
-                       }
-               } else {
-                       // if (!running)
-                       buf.append(e.character);
-                       userInput.append(e.character);
-               }
-
-               if (area.isDisposed())
-                       return;
-               area.redraw();
-               // System.out.println("Append " + e);
-
-               if (running) {
-                       if (stdIn != null) {
-                               try {
-                                       stdIn.write(Character.toString(e.character).getBytes(charset));
-                               } catch (IOException e1) {
-                                       // TODO Auto-generated catch block
-                                       e1.printStackTrace();
-                               }
-                       }
-               }
-       }
-
-       protected String prompt() {
-               String fileName = currentDir.equals(homeDir) ? "~" : currentDir.getFileName().toString();
-               String end = username.equals("root") ? "]# " : "]$ ";
-               return "[" + username + "@" + host + " " + fileName + end;
-       }
-
-       private void displayPrompt() {
-               buf.append(prompt() + userInput);
-       }
-
-       protected void markLogicalLine() {
-               String str = buf.toString().trim();
-               logicalLines.add(str);
-               buf = new StringBuffer("");
-       }
-
-       private void processUserInput() {
-               String cmd = userInput.toString();
-               userInput = new StringBuffer("");
-               processUserInput(cmd);
-               history.add(cmd);
-       }
-
-       protected void processUserInput(String input) {
-               try {
-                       StringTokenizer st = new StringTokenizer(input);
-                       List<String> args = new ArrayList<>();
-                       while (st.hasMoreTokens())
-                               args.add(st.nextToken());
-                       if (args.size() == 0) {
-                               displayPrompt();
-                               return;
-                       }
-
-                       // change directory
-                       if (args.get(0).equals("cd")) {
-                               if (args.size() == 1) {
-                                       setPath(homeDir);
-                               } else {
-                                       Path newPath = currentDir.resolve(args.get(1));
-                                       if (!Files.exists(newPath) || !Files.isDirectory(newPath)) {
-                                               println(newPath + ": No such file or directory");
-                                               return;
-                                       }
-                                       setPath(newPath);
-                               }
-                               displayPrompt();
-                               return;
-                       }
-                       // show current directory
-                       else if (args.get(0).equals("pwd")) {
-                               println(currentDir);
-                               displayPrompt();
-                               return;
-                       }
-                       // exit
-                       else if (args.get(0).equals("exit")) {
-                               println("logout");
-                               exitCalled();
-                               return;
-                       }
-
-                       ProcessBuilder pb = new ProcessBuilder(args);
-                       pb.redirectErrorStream(true);
-                       pb.directory(currentDir.toFile());
-//                     Process process = Runtime.getRuntime().exec(input, null, currentPath.toFile());
-                       process = pb.start();
-
-                       stdIn = process.getOutputStream();
-                       readOut = new Thread("MiniTerminal read out") {
-                               @Override
-                               public void run() {
-                                       running = true;
-                                       try (BufferedReader in = new BufferedReader(
-                                                       new InputStreamReader(process.getInputStream(), charset))) {
-                                               String line = null;
-                                               while ((line = in.readLine()) != null) {
-                                                       println(line);
-                                               }
-                                       } catch (IOException e) {
-                                               println(e.getMessage());
-                                       }
-                                       stdIn = null;
-                                       displayPrompt();
-                                       running = false;
-                                       readOut = null;
-                                       process = null;
-                               }
-                       };
-                       readOut.start();
-               } catch (IOException e) {
-                       println(e.getMessage());
-                       displayPrompt();
-               }
-       }
-
-       protected int linesForLogicalLine(char[] line) {
-               return line.length / charsPerLine + 1;
-       }
-
-       protected void println(Object line) {
-               buf.append(line);
-               markLogicalLine();
-       }
-
-       protected void refreshLines(int charPerLine, int nbrOfLines) {
-               if (lines.length != nbrOfLines) {
-                       lines = new String[nbrOfLines];
-                       Arrays.fill(lines, null);
-               }
-               if (this.charsPerLine != charPerLine)
-                       this.charsPerLine = charPerLine;
-
-               int currentLine = nbrOfLines - 1;
-               // current line
-               if (buf.length() > 0) {
-                       lines[currentLine] = buf.toString();
-               } else {
-                       lines[currentLine] = "";
-               }
-               currentLine--;
-
-               logicalLines: for (int i = logicalLines.size() - 1; i >= 0; i--) {
-                       char[] logicalLine = logicalLines.get(i).toCharArray();
-                       int linesNeeded = linesForLogicalLine(logicalLine);
-                       for (int j = linesNeeded - 1; j >= 0; j--) {
-                               int from = j * charPerLine;
-                               int to = j == linesNeeded - 1 ? from + charPerLine : Math.min(from + charPerLine, logicalLine.length);
-                               lines[currentLine] = new String(Arrays.copyOfRange(logicalLine, from, to));
-//                             System.out.println("Set line " + currentLine + " to : " + lines[currentLine]);
-                               currentLine--;
-                               if (currentLine < 0)
-                                       break logicalLines;
-                       }
-               }
-       }
-
-       @Override
-       public void paintControl(PaintEvent e) {
-               GC gc = e.gc;
-               gc.setFont(mono);
-               if (charExtent == null)
-                       charExtent = gc.textExtent("a");
-
-               Point areaSize = area.getSize();
-               int charPerLine = areaSize.x / charExtent.x;
-               int nbrOfLines = areaSize.y / charExtent.y;
-               refreshLines(charPerLine, nbrOfLines);
-
-               for (int i = 0; i < lines.length; i++) {
-                       String line = lines[i];
-                       if (line != null)
-                               gc.drawString(line, 0, i * charExtent.y);
-               }
-//             String toDraw = buf.toString();
-//             gc.drawString(toDraw, 0, 0);
-//             area.setCaret(caret);
-       }
-
-       protected void exitCalled() {
-
-       }
-
-       public void setPath(String path) {
-               this.currentDir = Paths.get(path);
-       }
-
-       public void setPath(Path path) {
-               this.currentDir = path;
-       }
-
-       public static void main(String[] args) {
-               Display display = Display.getCurrent() == null ? new Display() : Display.getCurrent();
-               Shell shell = new Shell(display, SWT.SHELL_TRIM);
-
-               String url = args.length > 0 ? args[0] : System.getProperty("user.home");
-               new MiniTerminal(shell, url) {
-
-                       @Override
-                       protected void exitCalled() {
-                               shell.dispose();
-                               System.exit(0);
-                       }
-               };
-
-               shell.open();
-               shell.setSize(new Point(800, 480));
-               while (!shell.isDisposed()) {
-                       if (!display.readAndDispatch())
-                               display.sleep();
-               }
-       }
-
-}
diff --git a/rcp/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/MiniTextEditor.java b/rcp/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/MiniTextEditor.java
deleted file mode 100644 (file)
index 91cd19e..0000000
+++ /dev/null
@@ -1,161 +0,0 @@
-package org.argeo.minidesktop;
-
-import java.io.BufferedReader;
-import java.io.BufferedWriter;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.io.OutputStreamWriter;
-import java.net.MalformedURLException;
-import java.net.URISyntaxException;
-import java.net.URL;
-import java.nio.charset.StandardCharsets;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.SelectionAdapter;
-import org.eclipse.swt.events.SelectionEvent;
-import org.eclipse.swt.graphics.Point;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.layout.RowLayout;
-import org.eclipse.swt.widgets.Button;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Display;
-import org.eclipse.swt.widgets.FileDialog;
-import org.eclipse.swt.widgets.Shell;
-import org.eclipse.swt.widgets.Text;
-
-public class MiniTextEditor {
-       private URL url;
-       private Text text;
-
-       public MiniTextEditor(Composite parent, int style) {
-               parent.setLayout(new GridLayout());
-
-               Composite toolBar = new Composite(parent, SWT.NONE);
-               toolBar.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
-               toolBar.setLayout(new RowLayout());
-               Button load = new Button(toolBar, SWT.FLAT);
-               load.setText("\u2191");// up arrow
-               load.addSelectionListener(new SelectionAdapter() {
-
-                       @Override
-                       public void widgetSelected(SelectionEvent e) {
-                               FileDialog fileDialog = new FileDialog(text.getShell());
-                               String path = fileDialog.open();
-                               if (path != null) {
-                                       setUrl(path);
-                               }
-                       }
-
-               });
-
-               Button save = new Button(toolBar, SWT.FLAT);
-               save.setText("\u2193");// down arrow
-               // save.setText("\u1F609");// emoji
-               save.addSelectionListener(new SelectionAdapter() {
-
-                       @Override
-                       public void widgetSelected(SelectionEvent e) {
-                               save(url);
-                       }
-
-               });
-
-               text = new Text(parent, SWT.WRAP | SWT.MULTI | SWT.BORDER | SWT.V_SCROLL);
-               text.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
-       }
-
-       protected void load(URL url) {
-               text.setText("");
-               // TODO deal with encoding and binary data
-               try (BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream(), StandardCharsets.UTF_8))) {
-                       String line = null;
-                       while ((line = in.readLine()) != null) {
-                               text.append(line + "\n");
-                       }
-                       text.setEditable(true);
-               } catch (IOException e) {
-                       if (e instanceof FileNotFoundException) {
-                               Path path = url2path(url);
-                               try {
-                                       Files.createFile(path);
-                                       load(url);
-                                       return;
-                               } catch (IOException e1) {
-                                       e = e1;
-                               }
-                       }
-                       text.setText(e.getMessage());
-                       text.setEditable(false);
-                       e.printStackTrace();
-                       // throw new IllegalStateException("Cannot load " + url, e);
-               }
-       }
-
-       protected Path url2path(URL url) {
-               try {
-                       Path path = Paths.get(url.toURI());
-                       return path;
-               } catch (URISyntaxException e) {
-                       throw new IllegalStateException("Cannot convert " + url + " to uri", e);
-               }
-       }
-
-       protected void save(URL url) {
-               if (!url.getProtocol().equals("file"))
-                       throw new IllegalArgumentException(url.getProtocol() + " protocol is not supported for write");
-               Path path = url2path(url);
-               try (BufferedWriter out = new BufferedWriter(new OutputStreamWriter(Files.newOutputStream(path)))) {
-                       out.write(text.getText());
-               } catch (IOException e) {
-                       throw new IllegalStateException("Cannot save " + url + " to " + path, e);
-               }
-       }
-
-       public void setUrl(URL url) {
-               this.url = url;
-               if (text != null)
-                       load(url);
-       }
-
-       public void setUrl(String url) {
-               try {
-                       setUrl(new URL(url));
-               } catch (MalformedURLException e) {
-                       // try with http
-                       try {
-                               setUrl(new URL("file://" + url));
-                               return;
-                       } catch (MalformedURLException e1) {
-                               // nevermind...
-                       }
-                       throw new IllegalArgumentException("Cannot interpret URL " + url, e);
-               }
-       }
-
-       public static void main(String[] args) {
-               Display display = Display.getCurrent() == null ? new Display() : Display.getCurrent();
-               Shell shell = new Shell(display, SWT.SHELL_TRIM);
-
-               MiniTextEditor miniBrowser = new MiniTextEditor(shell, SWT.NONE);
-               String url = args.length > 0 ? args[0] : "";
-               if (!url.trim().equals("")) {
-                       miniBrowser.setUrl(url);
-                       shell.setText(url);
-               } else {
-                       shell.setText("*");
-               }
-
-               shell.open();
-               shell.setSize(new Point(800, 480));
-               while (!shell.isDisposed()) {
-                       if (!display.readAndDispatch())
-                               display.sleep();
-               }
-       }
-
-}
diff --git a/rcp/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/cheatsheet_obj@2x.png b/rcp/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/cheatsheet_obj@2x.png
deleted file mode 100644 (file)
index 55c614d..0000000
Binary files a/rcp/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/cheatsheet_obj@2x.png and /dev/null differ
diff --git a/rcp/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/console_view@2x.png b/rcp/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/console_view@2x.png
deleted file mode 100644 (file)
index 54ecae2..0000000
Binary files a/rcp/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/console_view@2x.png and /dev/null differ
diff --git a/rcp/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/delete@2x.png b/rcp/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/delete@2x.png
deleted file mode 100644 (file)
index eb2fc72..0000000
Binary files a/rcp/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/delete@2x.png and /dev/null differ
diff --git a/rcp/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/external_browser@2x.png b/rcp/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/external_browser@2x.png
deleted file mode 100644 (file)
index 06d337a..0000000
Binary files a/rcp/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/external_browser@2x.png and /dev/null differ
diff --git a/rcp/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/file_obj@2x.png b/rcp/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/file_obj@2x.png
deleted file mode 100644 (file)
index 31e671c..0000000
Binary files a/rcp/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/file_obj@2x.png and /dev/null differ
diff --git a/rcp/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/fldr_obj@2x.png b/rcp/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/fldr_obj@2x.png
deleted file mode 100644 (file)
index adb7c2c..0000000
Binary files a/rcp/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/fldr_obj@2x.png and /dev/null differ
diff --git a/rcp/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/nav_home@2x.png b/rcp/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/nav_home@2x.png
deleted file mode 100644 (file)
index 4c9a16c..0000000
Binary files a/rcp/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/nav_home@2x.png and /dev/null differ
diff --git a/swt/org.argeo.swt.minidesktop/.classpath b/swt/org.argeo.swt.minidesktop/.classpath
new file mode 100644 (file)
index 0000000..eca7bdb
--- /dev/null
@@ -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="bin"/>
+</classpath>
diff --git a/swt/org.argeo.swt.minidesktop/.gitignore b/swt/org.argeo.swt.minidesktop/.gitignore
new file mode 100644 (file)
index 0000000..97adb72
--- /dev/null
@@ -0,0 +1,3 @@
+/bin/
+/target/
+*.log
\ No newline at end of file
diff --git a/swt/org.argeo.swt.minidesktop/.project b/swt/org.argeo.swt.minidesktop/.project
new file mode 100644 (file)
index 0000000..b6c2c1a
--- /dev/null
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+       <name>org.argeo.swt.minidesktop</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>
+       </buildSpec>
+       <natures>
+               <nature>org.eclipse.pde.PluginNature</nature>
+               <nature>org.eclipse.jdt.core.javanature</nature>
+       </natures>
+</projectDescription>
diff --git a/swt/org.argeo.swt.minidesktop/META-INF/.gitignore b/swt/org.argeo.swt.minidesktop/META-INF/.gitignore
new file mode 100644 (file)
index 0000000..4854a41
--- /dev/null
@@ -0,0 +1 @@
+/MANIFEST.MF
diff --git a/swt/org.argeo.swt.minidesktop/bnd.bnd b/swt/org.argeo.swt.minidesktop/bnd.bnd
new file mode 100644 (file)
index 0000000..f3c13be
--- /dev/null
@@ -0,0 +1,2 @@
+Import-Package: org.eclipse.swt,\
+*
diff --git a/swt/org.argeo.swt.minidesktop/build.properties b/swt/org.argeo.swt.minidesktop/build.properties
new file mode 100644 (file)
index 0000000..34d2e4d
--- /dev/null
@@ -0,0 +1,4 @@
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+               .
diff --git a/swt/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/MiniBrowser.java b/swt/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/MiniBrowser.java
new file mode 100644 (file)
index 0000000..d4da349
--- /dev/null
@@ -0,0 +1,189 @@
+package org.argeo.minidesktop;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.browser.Browser;
+import org.eclipse.swt.browser.LocationAdapter;
+import org.eclipse.swt.browser.LocationEvent;
+import org.eclipse.swt.events.KeyAdapter;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+
+/** A very minimalistic web browser based on {@link Browser}. */
+public class MiniBrowser {
+       private static Point defaultShellSize = new Point(800, 480);
+
+       private Browser browser;
+       private Text addressT;
+
+       private final boolean fullscreen;
+       private final boolean appMode;
+
+       public MiniBrowser(Composite composite, String url, boolean fullscreen, boolean appMode) {
+               this.fullscreen = fullscreen;
+               this.appMode = appMode;
+               createUi(composite);
+               setUrl(url);
+       }
+
+       public Control createUi(Composite parent) {
+               parent.setLayout(noSpaceGridLayout(new GridLayout()));
+               if (!isAppMode()) {
+                       Control toolBar = createToolBar(parent);
+                       toolBar.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
+               }
+               Control body = createBody(parent);
+               body.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+               return body;
+       }
+
+       protected Control createToolBar(Composite parent) {
+               Composite toolBar = new Composite(parent, SWT.NONE);
+               toolBar.setLayout(new FillLayout());
+               addressT = new Text(toolBar, SWT.SINGLE);
+               addressT.addSelectionListener(new SelectionAdapter() {
+
+                       @Override
+                       public void widgetDefaultSelected(SelectionEvent e) {
+                               setUrl(addressT.getText().trim());
+                       }
+               });
+               return toolBar;
+       }
+
+       protected Control createBody(Composite parent) {
+               browser = new Browser(parent, SWT.NONE);
+               if (isFullScreen())
+                       browser.addKeyListener(new KeyAdapter() {
+                               @Override
+                               public void keyPressed(KeyEvent e) {
+                                       if (e.keyCode == 0x77 && e.stateMask == 0x40000) {// Ctrl+W
+                                               browser.getShell().dispose();
+                                       }
+                               }
+                       });
+               browser.addLocationListener(new LocationAdapter() {
+                       @Override
+                       public void changed(LocationEvent event) {
+                               System.out.println(event);
+                               if (addressT != null)
+                                       addressT.setText(event.location);
+                       }
+
+               });
+               
+               // FIXME make it portable
+//             browser.addTitleListener(e -> titleChanged(e.title));
+//             browser.addOpenWindowListener((e) -> {
+//                     e.browser = openNewBrowserWindow();
+//             });
+               return browser;
+       }
+
+       protected Browser openNewBrowserWindow() {
+
+               if (isFullScreen()) {
+                       // TODO manage multiple tabs?
+                       return browser;
+               } else {
+                       Shell newShell = new Shell(browser.getDisplay(), SWT.SHELL_TRIM);
+                       MiniBrowser newMiniBrowser = new MiniBrowser(newShell, null, false, isAppMode());
+                       newShell.setSize(defaultShellSize);
+                       newShell.open();
+                       return newMiniBrowser.browser;
+               }
+       }
+
+       protected boolean isFullScreen() {
+               return fullscreen;
+       }
+
+       void setUrl(String url) {
+               if (browser != null && url != null && !url.equals(browser.getUrl()))
+                       browser.setUrl(url.toString());
+       }
+
+       /** Called when URL changed; to be overridden, does nothing by default. */
+       protected void urlChanged(String url) {
+       }
+
+       /** Called when title changed; to be overridden, does nothing by default. */
+       protected void titleChanged(String title) {
+       }
+
+       protected Browser getBrowser() {
+               return browser;
+       }
+
+       protected boolean isAppMode() {
+               return appMode;
+       }
+
+       private static GridLayout noSpaceGridLayout(GridLayout layout) {
+               layout.horizontalSpacing = 0;
+               layout.verticalSpacing = 0;
+               layout.marginWidth = 0;
+               layout.marginHeight = 0;
+               return layout;
+       }
+
+       public static void main(String[] args) {
+               List<String> options = Arrays.asList(args);
+               if (options.contains("--help")) {
+                       System.out.println("Usage: java " + MiniBrowser.class.getName().replace('.', '/') + " [OPTION] [URL]");
+                       System.out.println("A minimalistic web browser Eclipse SWT Browser integration.");
+                       System.out.println("  --fullscreen : take control of the whole screen (default is to run in a window)");
+                       System.out.println("  --app        : open without an address bar and a toolbar");
+                       System.out.println("  --help       : print this help and exit");
+                       System.exit(1);
+               }
+               boolean fullscreen = options.contains("--fullscreen");
+               boolean appMode = options.contains("--app");
+               String url = "https://start.duckduckgo.com/";
+               if (options.size() > 0) {
+                       String last = options.get(options.size() - 1);
+                       if (!last.startsWith("--"))
+                               url = last.trim();
+               }
+
+               Display display = Display.getCurrent() == null ? new Display() : Display.getCurrent();
+               Shell shell;
+               if (fullscreen) {
+                       shell = new Shell(display, SWT.NO_TRIM);
+                       shell.setFullScreen(true);
+                       Rectangle bounds = display.getBounds();
+                       shell.setSize(bounds.width, bounds.height);
+               } else {
+                       shell = new Shell(display, SWT.SHELL_TRIM);
+                       shell.setSize(defaultShellSize);
+               }
+
+               new MiniBrowser(shell, url, fullscreen, appMode) {
+
+                       @Override
+                       protected void titleChanged(String title) {
+                               shell.setText(title);
+                       }
+               };
+               shell.open();
+
+               while (!shell.isDisposed()) {
+                       if (!display.readAndDispatch())
+                               display.sleep();
+               }
+       }
+
+}
diff --git a/swt/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/MiniDesktopImages.java b/swt/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/MiniDesktopImages.java
new file mode 100644 (file)
index 0000000..db5e6f2
--- /dev/null
@@ -0,0 +1,53 @@
+package org.argeo.minidesktop;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.eclipse.swt.SWTException;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Display;
+
+/** Icons. */
+public class MiniDesktopImages {
+
+       public final Image homeIcon;
+       public final Image exitIcon;
+       
+       public final Image terminalIcon;
+       public final Image browserIcon;
+       public final Image explorerIcon;
+       public final Image textEditorIcon;
+
+       public final Image folderIcon;
+       public final Image fileIcon;
+
+       public MiniDesktopImages(Display display) {
+               homeIcon = loadImage(display, "nav_home@2x.png");
+               exitIcon = loadImage(display, "delete@2x.png");
+
+               terminalIcon = loadImage(display, "console_view@2x.png");
+               browserIcon = loadImage(display, "external_browser@2x.png");
+               explorerIcon = loadImage(display, "fldr_obj@2x.png");
+               textEditorIcon = loadImage(display, "cheatsheet_obj@2x.png");
+
+               folderIcon = loadImage(display, "fldr_obj@2x.png");
+               fileIcon = loadImage(display, "file_obj@2x.png");
+       }
+
+       static Image loadImage(Display display, String path) {
+               InputStream stream = MiniDesktopImages.class.getResourceAsStream(path);
+               if (stream == null)
+                       throw new IllegalArgumentException("Image " + path + " not found");
+               Image image = null;
+               try {
+                       image = new Image(display, stream);
+               } catch (SWTException ex) {
+               } finally {
+                       try {
+                               stream.close();
+                       } catch (IOException ex) {
+                       }
+               }
+               return image;
+       }
+}
diff --git a/swt/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/MiniDesktopManager.java b/swt/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/MiniDesktopManager.java
new file mode 100644 (file)
index 0000000..6af59d9
--- /dev/null
@@ -0,0 +1,347 @@
+package org.argeo.minidesktop;
+
+import java.lang.management.ManagementFactory;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.nio.file.Path;
+import java.util.Arrays;
+import java.util.List;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.CTabFolder;
+import org.eclipse.swt.custom.CTabItem;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.ToolBar;
+import org.eclipse.swt.widgets.ToolItem;
+
+/** A very minimalistic desktop manager based on Java and Eclipse SWT. */
+public class MiniDesktopManager {
+       private Display display;
+
+       private Shell rootShell;
+       private Shell toolBarShell;
+       private CTabFolder tabFolder;
+       private int maxTabTitleLength = 16;
+
+       private final boolean fullscreen;
+       private final boolean stacking;
+
+       private MiniDesktopImages images;
+
+       public MiniDesktopManager(boolean fullscreen, boolean stacking) {
+               this.fullscreen = fullscreen;
+               this.stacking = stacking;
+       }
+
+       public void init() {
+               Display.setAppName("Mini SWT Desktop");
+               display = Display.getCurrent();
+               if (display != null)
+                       throw new IllegalStateException("Already a display " + display);
+               display = new Display();
+
+               if (display.getTouchEnabled()) {
+                       System.out.println("Touch enabled.");
+               }
+
+               images = new MiniDesktopImages(display);
+
+               int toolBarSize = 48;
+
+               if (isFullscreen()) {
+                       rootShell = new Shell(display, SWT.NO_TRIM);
+                       rootShell.setFullScreen(true);
+                       Rectangle bounds = display.getBounds();
+                       rootShell.setLocation(0, 0);
+                       rootShell.setSize(bounds.width, bounds.height);
+               } else {
+                       rootShell = new Shell(display, SWT.CLOSE | SWT.RESIZE);
+                       Rectangle shellArea = rootShell.computeTrim(200, 200, 800, 480);
+                       rootShell.setSize(shellArea.width, shellArea.height);
+                       rootShell.setText(Display.getAppName());
+                       rootShell.setImage(images.terminalIcon);
+               }
+
+               rootShell.setLayout(noSpaceGridLayout(new GridLayout(2, false)));
+               Composite toolBarArea = new Composite(rootShell, SWT.NONE);
+               toolBarArea.setLayoutData(new GridData(toolBarSize, rootShell.getSize().y));
+
+               ToolBar toolBar;
+               if (isFullscreen()) {
+                       toolBarShell = new Shell(rootShell, SWT.NO_TRIM | SWT.ON_TOP);
+                       toolBar = new ToolBar(toolBarShell, SWT.VERTICAL | SWT.FLAT | SWT.BORDER);
+                       createDock(toolBar);
+                       toolBarShell.pack();
+                       toolBarArea.setLayoutData(new GridData(toolBar.getSize().x, toolBar.getSize().y));
+               } else {
+                       toolBar = new ToolBar(toolBarArea, SWT.VERTICAL | SWT.FLAT | SWT.BORDER);
+                       createDock(toolBar);
+                       toolBarArea.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
+               }
+
+               if (isStacking()) {
+                       tabFolder = new CTabFolder(rootShell, SWT.MULTI | SWT.BORDER | SWT.BOTTOM);
+                       tabFolder.setLayout(noSpaceGridLayout(new GridLayout()));
+                       tabFolder.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+
+                       Color selectionBackground = display.getSystemColor(SWT.COLOR_LIST_SELECTION);
+                       tabFolder.setSelectionBackground(selectionBackground);
+
+                       // background
+                       Control background = createBackground(tabFolder);
+                       CTabItem homeTabItem = new CTabItem(tabFolder, SWT.NONE);
+                       homeTabItem.setText("Home");
+                       homeTabItem.setImage(images.homeIcon);
+                       homeTabItem.setControl(background);
+                       tabFolder.setFocus();
+               } else {
+                       createBackground(rootShell);
+               }
+
+               rootShell.open();
+               // rootShell.layout(true, true);
+
+               if (toolBarShell != null) {
+                       int toolBarShellY = (display.getBounds().height - toolBar.getSize().y) / 2;
+                       toolBarShell.setLocation(0, toolBarShellY);
+                       toolBarShell.open();
+               }
+
+               long jvmUptime = ManagementFactory.getRuntimeMXBean().getUptime();
+               System.out.println("SWT Mini Desktop Manager available in " + jvmUptime + " ms.");
+       }
+
+       protected void createDock(ToolBar toolBar) {
+               // Terminal
+               addToolItem(toolBar, images.terminalIcon, "Terminal", () -> {
+                       String url = System.getProperty("user.home");
+                       AppContext appContext = createAppParent(images.terminalIcon);
+                       new MiniTerminal(appContext.getAppParent(), url) {
+
+                               @Override
+                               protected void exitCalled() {
+                                       if (appContext.shell != null)
+                                               appContext.shell.dispose();
+                                       if (appContext.tabItem != null)
+                                               appContext.tabItem.dispose();
+                               }
+                       };
+                       String title;
+                       try {
+                               title = System.getProperty("user.name") + "@" + InetAddress.getLocalHost().getHostName();
+                       } catch (UnknownHostException e) {
+                               title = System.getProperty("user.name") + "@localhost";
+                       }
+                       if (appContext.shell != null)
+                               appContext.shell.setText(title);
+                       if (appContext.tabItem != null) {
+                               appContext.tabItem.setText(tabTitle(title));
+                               appContext.tabItem.setToolTipText(title);
+                       }
+                       openApp(appContext);
+               });
+
+               // Web browser
+               addToolItem(toolBar, images.browserIcon, "Browser", () -> {
+                       String url = "https://start.duckduckgo.com/";
+                       AppContext appContext = createAppParent(images.browserIcon);
+                       new MiniBrowser(appContext.getAppParent(), url, false, false) {
+                               @Override
+                               protected void titleChanged(String title) {
+                                       if (appContext.shell != null)
+                                               appContext.shell.setText(title);
+                                       if (appContext.tabItem != null) {
+                                               appContext.tabItem.setText(tabTitle(title));
+                                               appContext.tabItem.setToolTipText(title);
+                                       }
+                               }
+                       };
+                       openApp(appContext);
+               });
+
+               // File explorer
+               addToolItem(toolBar, images.explorerIcon, "Explorer", () -> {
+                       String url = System.getProperty("user.home");
+                       AppContext appContext = createAppParent(images.explorerIcon);
+                       new MiniExplorer(appContext.getAppParent(), url) {
+
+                               @Override
+                               protected void pathChanged(Path path) {
+                                       if (appContext.shell != null)
+                                               appContext.shell.setText(path.toString());
+                                       if (appContext.tabItem != null) {
+                                               appContext.tabItem.setText(path.getFileName().toString());
+                                               appContext.tabItem.setToolTipText(path.toString());
+                                       }
+                               }
+                       };
+                       openApp(appContext);
+               });
+
+               // Separator
+               new ToolItem(toolBar, SWT.SEPARATOR);
+
+               // Exit
+               addToolItem(toolBar, images.exitIcon, "Exit", () -> rootShell.dispose());
+
+               toolBar.pack();
+       }
+
+       protected String tabTitle(String title) {
+               return title.length() > maxTabTitleLength ? title.substring(0, maxTabTitleLength) : title;
+       }
+
+       protected void addToolItem(ToolBar toolBar, Image icon, String name, Runnable action) {
+               ToolItem searchI = new ToolItem(toolBar, SWT.PUSH);
+               searchI.setImage(icon);
+               searchI.setToolTipText(name);
+               searchI.addSelectionListener(new SelectionAdapter() {
+
+                       @Override
+                       public void widgetSelected(SelectionEvent e) {
+                               action.run();
+                       }
+
+               });
+       }
+
+       protected AppContext createAppParent(Image icon) {
+               if (isStacking()) {
+                       Composite appParent = new Composite(tabFolder, SWT.CLOSE);
+                       appParent.setLayout(noSpaceGridLayout(new GridLayout()));
+                       CTabItem item = new CTabItem(tabFolder, SWT.CLOSE);
+                       item.setImage(icon);
+                       item.setControl(appParent);
+                       return new AppContext(item);
+               } else {
+                       Shell shell = isFullscreen() ? new Shell(rootShell, SWT.SHELL_TRIM)
+                                       : new Shell(rootShell.getDisplay(), SWT.SHELL_TRIM);
+                       shell.setImage(icon);
+                       return new AppContext(shell);
+               }
+       }
+
+       protected void openApp(AppContext appContext) {
+               if (appContext.shell != null) {
+                       Shell shell = (Shell) appContext.shell;
+                       shell.open();
+                       shell.setSize(new Point(800, 480));
+               }
+               if (appContext.tabItem != null) {
+                       tabFolder.setFocus();
+                       tabFolder.setSelection(appContext.tabItem);
+               }
+       }
+
+       protected Control createBackground(Composite parent) {
+               Composite backgroundArea = new Composite(parent, SWT.NONE);
+               backgroundArea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+               initBackground(backgroundArea);
+               return backgroundArea;
+       }
+
+       protected void initBackground(Composite backgroundArea) {
+               MiniHomePart homePart = new MiniHomePart() {
+
+                       @Override
+                       protected void fillAppsToolBar(ToolBar toolBar) {
+                               createDock(toolBar);
+                       }
+               };
+               homePart.createUiPart(backgroundArea, null);
+       }
+
+       public void run() {
+               while (!rootShell.isDisposed()) {
+                       if (!display.readAndDispatch())
+                               display.sleep();
+               }
+       }
+
+       public void dispose() {
+               if (!rootShell.isDisposed())
+                       rootShell.dispose();
+       }
+
+       protected boolean isFullscreen() {
+               return fullscreen;
+       }
+
+       protected boolean isStacking() {
+               return stacking;
+       }
+
+       protected Image getIconForExt(String ext) {
+//             Program program = Program.findProgram(ext);
+//             if (program == null)
+                       return display.getSystemImage(SWT.ICON_INFORMATION);
+
+//             ImageData iconData = program.getImageData();
+//             if (iconData == null) {
+//                     return display.getSystemImage(SWT.ICON_INFORMATION);
+//             } else {
+//                     return new Image(display, iconData);
+//             }
+
+       }
+
+       private static GridLayout noSpaceGridLayout(GridLayout layout) {
+               layout.horizontalSpacing = 0;
+               layout.verticalSpacing = 0;
+               layout.marginWidth = 0;
+               layout.marginHeight = 0;
+               return layout;
+       }
+
+       public static void main(String[] args) {
+               List<String> options = Arrays.asList(args);
+               if (options.contains("--help")) {
+                       System.out.println("Usage: java " + MiniDesktopManager.class.getName().replace('.', '/') + " [OPTION]");
+                       System.out.println("A minimalistic desktop manager based on Java and Eclipse SWT.");
+                       System.out.println("  --fullscreen : take control of the whole screen (default is to run in a window)");
+                       System.out.println("  --stacking   : open apps as tabs (default is to create new windows)");
+                       System.out.println("  --help       : print this help and exit");
+                       System.exit(1);
+               }
+               boolean fullscreen = options.contains("--fullscreen");
+               boolean stacking = options.contains("--stacking");
+
+               MiniDesktopManager desktopManager = new MiniDesktopManager(fullscreen, stacking);
+               desktopManager.init();
+               desktopManager.run();
+               desktopManager.dispose();
+               System.exit(0);
+       }
+
+       class AppContext {
+               private Shell shell;
+               private CTabItem tabItem;
+
+               public AppContext(Shell shell) {
+                       this.shell = shell;
+               }
+
+               public AppContext(CTabItem tabItem) {
+                       this.tabItem = tabItem;
+               }
+
+               Composite getAppParent() {
+                       if (shell != null)
+                               return shell;
+                       if (tabItem != null)
+                               return (Composite) tabItem.getControl();
+                       throw new IllegalStateException();
+               }
+       }
+}
diff --git a/swt/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/MiniExplorer.java b/swt/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/MiniExplorer.java
new file mode 100644 (file)
index 0000000..9a967a2
--- /dev/null
@@ -0,0 +1,164 @@
+package org.argeo.minidesktop;
+
+import java.io.IOException;
+import java.nio.file.DirectoryStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.MouseAdapter;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.layout.FillLayout;
+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.Shell;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableItem;
+import org.eclipse.swt.widgets.Text;
+
+public class MiniExplorer {
+       private Path path;
+       private Text addressT;
+       private Table browser;
+
+       private boolean showHidden = false;
+
+       public MiniExplorer(Composite parent, String url) {
+               this(parent);
+               setUrl(url);
+       }
+
+       public MiniExplorer(Composite parent) {
+               parent.setLayout(noSpaceGridLayout(new GridLayout()));
+
+               Composite toolBar = new Composite(parent, SWT.NONE);
+               toolBar.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
+               toolBar.setLayout(new FillLayout());
+               addressT = new Text(toolBar, SWT.SINGLE);
+               addressT.addSelectionListener(new SelectionAdapter() {
+
+                       @Override
+                       public void widgetDefaultSelected(SelectionEvent e) {
+                               setUrl(addressT.getText().trim());
+                       }
+               });
+               browser = createTable(parent, this.path);
+
+       }
+
+       public void setPath(Path url) {
+               this.path = url;
+               if (addressT != null)
+                       addressT.setText(url.toString());
+               if (browser != null) {
+                       Composite parent = browser.getParent();
+                       browser.dispose();
+                       browser = createTable(parent, this.path);
+                       parent.layout(true, true);
+               }
+               pathChanged(url);
+       }
+
+       protected void pathChanged(Path path) {
+
+       }
+
+       protected Table createTable(Composite parent, Path path) {
+               Table table = new Table(parent, SWT.BORDER);
+               table.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+               table.addMouseListener(new MouseAdapter() {
+
+                       @Override
+                       public void mouseDoubleClick(MouseEvent e) {
+                               Point pt = new Point(e.x, e.y);
+                               TableItem item = table.getItem(pt);
+                               Path path = (Path) item.getData();
+                               if (Files.isDirectory(path)) {
+                                       setPath(path);
+                               } else {
+                                       //Program.launch(path.toString());
+                               }
+                       }
+               });
+
+               if (path != null) {
+                       if (path.getParent() != null) {
+                               TableItem parentTI = new TableItem(table, SWT.NONE);
+                               parentTI.setText("..");
+                               parentTI.setData(path.getParent());
+                       }
+
+                       try {
+                               // directories
+                               DirectoryStream<Path> ds = Files.newDirectoryStream(path, p -> Files.isDirectory(p) && isShown(p));
+                               ds.forEach(p -> {
+                                       TableItem ti = new TableItem(table, SWT.NONE);
+                                       ti.setText(p.getFileName().toString() + "/");
+                                       ti.setData(p);
+                               });
+                               // files
+                               ds = Files.newDirectoryStream(path, p -> !Files.isDirectory(p) && isShown(p));
+                               ds.forEach(p -> {
+                                       TableItem ti = new TableItem(table, SWT.NONE);
+                                       ti.setText(p.getFileName().toString());
+                                       ti.setData(p);
+                               });
+                       } catch (IOException e1) {
+                               // TODO Auto-generated catch block
+                               e1.printStackTrace();
+                       }
+               }
+               return table;
+       }
+
+       protected boolean isShown(Path path) {
+               if (showHidden)
+                       return true;
+               try {
+                       return !Files.isHidden(path);
+               } catch (IOException e) {
+                       throw new IllegalArgumentException("Cannot check " + path, e);
+               }
+       }
+
+       public void setUrl(String url) {
+               setPath(Paths.get(url));
+       }
+
+       private static GridLayout noSpaceGridLayout(GridLayout layout) {
+               layout.horizontalSpacing = 0;
+               layout.verticalSpacing = 0;
+               layout.marginWidth = 0;
+               layout.marginHeight = 0;
+               return layout;
+       }
+
+       public static void main(String[] args) {
+               Display display = Display.getCurrent() == null ? new Display() : Display.getCurrent();
+               Shell shell = new Shell(display, SWT.SHELL_TRIM);
+
+               String url = args.length > 0 ? args[0] : System.getProperty("user.home");
+               new MiniExplorer(shell, url) {
+
+                       @Override
+                       protected void pathChanged(Path path) {
+                               shell.setText(path.toString());
+                       }
+
+               };
+
+               shell.open();
+               shell.setSize(new Point(800, 480));
+               while (!shell.isDisposed()) {
+                       if (!display.readAndDispatch())
+                               display.sleep();
+               }
+       }
+
+}
diff --git a/swt/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/MiniHomePart.java b/swt/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/MiniHomePart.java
new file mode 100644 (file)
index 0000000..877f643
--- /dev/null
@@ -0,0 +1,161 @@
+package org.argeo.minidesktop;
+
+import java.net.InetAddress;
+import java.net.InterfaceAddress;
+import java.net.NetworkInterface;
+import java.net.SocketException;
+import java.net.UnknownHostException;
+import java.util.Enumeration;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Group;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.ProgressBar;
+import org.eclipse.swt.widgets.ToolBar;
+
+/** A start page displaying network information and resources. */
+public class MiniHomePart {
+
+       public Control createUiPart(Composite parent, Object context) {
+               parent.setLayout(new GridLayout(2, false));
+               Display display = parent.getDisplay();
+
+               // Apps
+               Group appsGroup = new Group(parent, SWT.NONE);
+               appsGroup.setText("Apps");
+               appsGroup.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false, 2, 1));
+               ToolBar appsToolBar = new ToolBar(appsGroup, SWT.HORIZONTAL | SWT.FLAT);
+               fillAppsToolBar(appsToolBar);
+
+               // Host
+               Group hostGroup = new Group(parent, SWT.NONE);
+               hostGroup.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false));
+               hostGroup.setText("Host");
+               hostGroup.setLayout(new GridLayout(2, false));
+               label(hostGroup, "Hostname: ");
+               try {
+                       InetAddress defaultAddr = InetAddress.getLocalHost();
+                       String hostname = defaultAddr.getHostName();
+                       label(hostGroup, hostname);
+                       label(hostGroup, "Address: ");
+                       label(hostGroup, defaultAddr.getHostAddress());
+               } catch (UnknownHostException e) {
+                       label(hostGroup, e.getMessage());
+               }
+
+               Enumeration<NetworkInterface> netInterfaces = null;
+               try {
+                       netInterfaces = NetworkInterface.getNetworkInterfaces();
+               } catch (SocketException e) {
+                       label(hostGroup, "Interfaces: ");
+                       label(hostGroup, e.getMessage());
+               }
+               if (netInterfaces != null)
+                       while (netInterfaces.hasMoreElements()) {
+                               NetworkInterface netInterface = netInterfaces.nextElement();
+                               byte[] hardwareAddress = null;
+                               try {
+                                       hardwareAddress = netInterface.getHardwareAddress();
+                                       if (hardwareAddress != null) {
+                                               label(hostGroup, convertHardwareAddress(hardwareAddress));
+                                               label(hostGroup, netInterface.getName());
+                                               for (InterfaceAddress addr : netInterface.getInterfaceAddresses()) {
+                                                       label(hostGroup, cleanHostAddress(addr.getAddress().getHostAddress()));
+                                                       label(hostGroup, Short.toString(addr.getNetworkPrefixLength()));
+                                               }
+                                       }
+                               } catch (SocketException e) {
+                                       label(hostGroup, e.getMessage());
+                               }
+                       }
+
+               // Resources
+               Group resGroup = new Group(parent, SWT.NONE);
+               resGroup.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
+               resGroup.setText("Resources");
+               resGroup.setLayout(new GridLayout(3, false));
+
+               Runtime runtime = Runtime.getRuntime();
+
+               String maxMemoryStr = Long.toString(runtime.maxMemory() / (1024 * 1024)) + " MB";
+               label(resGroup, "Max Java memory: ");
+               label(resGroup, maxMemoryStr);
+               label(resGroup, "Java version: " + Runtime.version().toString());
+
+               label(resGroup, "Usable Java memory: ");
+               Label totalMemory = label(resGroup, maxMemoryStr);
+               ProgressBar totalOnMax = new ProgressBar(resGroup, SWT.SMOOTH);
+               totalOnMax.setMaximum(100);
+               label(resGroup, "Used Java memory: ");
+               Label usedMemory = label(resGroup, maxMemoryStr);
+               ProgressBar usedOnTotal = new ProgressBar(resGroup, SWT.SMOOTH);
+               totalOnMax.setMaximum(100);
+               new Thread() {
+                       @Override
+                       public void run() {
+                               while (!totalOnMax.isDisposed()) {
+                                       display.asyncExec(() -> {
+                                               if (totalOnMax.isDisposed())
+                                                       return;
+                                               totalOnMax.setSelection(javaTotalOnMaxPerct(runtime));
+                                               usedOnTotal.setSelection(javaUsedOnTotalPerct(runtime));
+                                               totalMemory.setText(Long.toString(runtime.totalMemory() / (1024 * 1024)) + " MB");
+                                               usedMemory.setText(
+                                                               Long.toString((runtime.totalMemory() - runtime.freeMemory()) / (1024 * 1024)) + " MB");
+                                       });
+                                       try {
+                                               Thread.sleep(1000);
+                                       } catch (InterruptedException e) {
+                                               return;
+                                       }
+                               }
+                       }
+               }.start();
+               return parent;
+       }
+
+       protected void fillAppsToolBar(ToolBar toolBar) {
+
+       }
+
+       protected int javaUsedOnTotalPerct(Runtime runtime) {
+               return Math.toIntExact((runtime.totalMemory() - runtime.freeMemory()) * 100 / runtime.totalMemory());
+       }
+
+       protected int javaTotalOnMaxPerct(Runtime runtime) {
+               return Math.toIntExact((runtime.totalMemory()) * 100 / runtime.maxMemory());
+       }
+
+       protected Label label(Composite parent, String text) {
+               Label label = new Label(parent, SWT.WRAP);
+               label.setText(text);
+               return label;
+       }
+
+       protected String cleanHostAddress(String hostAddress) {
+               // remove % from Ipv6 addresses
+               int index = hostAddress.indexOf('%');
+               if (index > 0)
+                       return hostAddress.substring(0, index);
+               else
+                       return hostAddress;
+       }
+
+       protected String convertHardwareAddress(byte[] hardwareAddress) {
+               if (hardwareAddress == null)
+                       return "";
+               // from https://stackoverflow.com/a/2797498/7878010
+               StringBuilder sb = new StringBuilder(18);
+               for (byte b : hardwareAddress) {
+                       if (sb.length() > 0)
+                               sb.append(':');
+                       sb.append(String.format("%02x", b).toUpperCase());
+               }
+               return sb.toString();
+       }
+}
diff --git a/swt/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/MiniImageViewer.java b/swt/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/MiniImageViewer.java
new file mode 100644 (file)
index 0000000..86ff53f
--- /dev/null
@@ -0,0 +1,129 @@
+package org.argeo.minidesktop;
+
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.PaintEvent;
+import org.eclipse.swt.events.PaintListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.ImageData;
+import org.eclipse.swt.graphics.ImageLoader;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.layout.RowLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Canvas;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.FileDialog;
+import org.eclipse.swt.widgets.Shell;
+
+public class MiniImageViewer implements PaintListener {
+       private URL url;
+       private Canvas area;
+
+       private Image image;
+
+       public MiniImageViewer(Composite parent, int style) {
+               parent.setLayout(new GridLayout());
+
+               Composite toolBar = new Composite(parent, SWT.NONE);
+               toolBar.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
+               toolBar.setLayout(new RowLayout());
+               Button load = new Button(toolBar, SWT.FLAT);
+               load.setText("\u2191");// up arrow
+               load.addSelectionListener(new SelectionAdapter() {
+
+                       @Override
+                       public void widgetSelected(SelectionEvent e) {
+                               FileDialog fileDialog = new FileDialog(area.getShell());
+                               String path = fileDialog.open();
+                               if (path != null) {
+                                       setUrl(path);
+                               }
+                       }
+
+               });
+
+               area = new Canvas(parent, SWT.NONE);
+               area.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+               area.addPaintListener(this);
+       }
+
+       protected void load(URL url) {
+               try {
+                       ImageLoader imageLoader = new ImageLoader();
+                       ImageData[] data = imageLoader.load(url.openStream());
+                       image = new Image(area.getDisplay(), data[0]);
+               } catch (IOException e) {
+                       // TODO Auto-generated catch block
+                       e.printStackTrace();
+               }
+       }
+
+       @Override
+       public void paintControl(PaintEvent e) {
+               e.gc.drawImage(image, 0, 0);
+
+       }
+
+       protected Path url2path(URL url) {
+               try {
+                       Path path = Paths.get(url.toURI());
+                       return path;
+               } catch (URISyntaxException e) {
+                       throw new IllegalStateException("Cannot convert " + url + " to uri", e);
+               }
+       }
+
+       public void setUrl(URL url) {
+               this.url = url;
+               if (area != null)
+                       load(this.url);
+       }
+
+       public void setUrl(String url) {
+               try {
+                       setUrl(new URL(url));
+               } catch (MalformedURLException e) {
+                       // try with http
+                       try {
+                               setUrl(new URL("file://" + url));
+                               return;
+                       } catch (MalformedURLException e1) {
+                               // nevermind...
+                       }
+                       throw new IllegalArgumentException("Cannot interpret URL " + url, e);
+               }
+       }
+
+       public static void main(String[] args) {
+               Display display = Display.getCurrent() == null ? new Display() : Display.getCurrent();
+               Shell shell = new Shell(display, SWT.SHELL_TRIM);
+
+               MiniImageViewer miniBrowser = new MiniImageViewer(shell, SWT.NONE);
+               String url = args.length > 0 ? args[0] : "";
+               if (!url.trim().equals("")) {
+                       miniBrowser.setUrl(url);
+                       shell.setText(url);
+               } else {
+                       shell.setText("*");
+               }
+
+               shell.open();
+               shell.setSize(new Point(800, 480));
+               while (!shell.isDisposed()) {
+                       if (!display.readAndDispatch())
+                               display.sleep();
+               }
+       }
+
+}
diff --git a/swt/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/MiniTerminal.java b/swt/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/MiniTerminal.java
new file mode 100644 (file)
index 0000000..cd1a9f2
--- /dev/null
@@ -0,0 +1,342 @@
+package org.argeo.minidesktop;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+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.List;
+import java.util.StringTokenizer;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.events.KeyListener;
+import org.eclipse.swt.events.PaintEvent;
+import org.eclipse.swt.events.PaintListener;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Canvas;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+
+public class MiniTerminal implements KeyListener, PaintListener {
+
+       private Canvas area;
+//     private Caret caret;
+
+       private StringBuffer buf = new StringBuffer("");
+       private StringBuffer userInput = new StringBuffer("");
+       private List<String> history = new ArrayList<>();
+
+       private Point charExtent = null;
+       private int charsPerLine = 0;
+       private String[] lines = new String[0];
+       private List<String> logicalLines = new ArrayList<>();
+
+       private Font mono;
+       private Charset charset;
+
+       private Path currentDir;
+       private Path homeDir;
+       private String host = "localhost";
+       private String username;
+
+       // Sub process
+       private Process process;
+       private boolean running = false;
+       private OutputStream stdIn = null;
+
+       private Thread readOut;
+
+       public MiniTerminal(Composite parent, String url) {
+               this(parent);
+               setPath(url);
+       }
+
+       public MiniTerminal(Composite parent) {
+               charset = StandardCharsets.UTF_8;
+
+               Display display = parent.getDisplay();
+               // Linux-specific
+               mono = new Font(display, "Monospace", 10, SWT.NONE);
+
+               parent.setLayout(new GridLayout());
+               area = new Canvas(parent, SWT.NONE);
+               area.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+//             caret = new Caret(area, SWT.NONE);
+//             area.setCaret(caret);
+
+               area.addKeyListener(this);
+               area.addPaintListener(this);
+
+               username = System.getProperty("user.name");
+               try {
+                       host = InetAddress.getLocalHost().getHostName();
+                       if (host.indexOf('.') > 0)
+                               host = host.substring(0, host.indexOf('.'));
+               } catch (UnknownHostException e) {
+                       host = "localhost";
+               }
+               homeDir = Paths.get(System.getProperty("user.home"));
+               currentDir = homeDir;
+
+               buf = new StringBuffer(prompt());
+       }
+
+       @Override
+       public void keyPressed(KeyEvent e) {
+       }
+
+       @Override
+       public void keyReleased(KeyEvent e) {
+//             if (e.keyLocation != 0)
+//                     return;// weird characters
+               
+               // System.out.println(e.character);
+               if (e.keyCode == 0xd) {// return
+                       markLogicalLine();
+                       if (!running)
+                               processUserInput();
+                       // buf.append(prompt());
+               } else if (e.keyCode == 0x8) {// delete
+                       if (userInput.length() == 0)
+                               return;
+                       userInput.setLength(userInput.length() - 1);
+                       if (!running && buf.length() > 0)
+                               buf.setLength(buf.length() - 1);
+               } else if (e.stateMask == 0x40000 && e.keyCode == 0x63) {// Ctrl+C
+                       if (process != null)
+                               process.destroy();
+               } else if (e.stateMask == 0x40000 && e.keyCode == 0xdf) {// Ctrl+\
+                       if (process != null) {
+                               process.destroyForcibly();
+                       }
+               } else {
+                       // if (!running)
+                       buf.append(e.character);
+                       userInput.append(e.character);
+               }
+
+               if (area.isDisposed())
+                       return;
+               area.redraw();
+               // System.out.println("Append " + e);
+
+               if (running) {
+                       if (stdIn != null) {
+                               try {
+                                       stdIn.write(Character.toString(e.character).getBytes(charset));
+                               } catch (IOException e1) {
+                                       // TODO Auto-generated catch block
+                                       e1.printStackTrace();
+                               }
+                       }
+               }
+       }
+
+       protected String prompt() {
+               String fileName = currentDir.equals(homeDir) ? "~" : currentDir.getFileName().toString();
+               String end = username.equals("root") ? "]# " : "]$ ";
+               return "[" + username + "@" + host + " " + fileName + end;
+       }
+
+       private void displayPrompt() {
+               buf.append(prompt() + userInput);
+       }
+
+       protected void markLogicalLine() {
+               String str = buf.toString().trim();
+               logicalLines.add(str);
+               buf = new StringBuffer("");
+       }
+
+       private void processUserInput() {
+               String cmd = userInput.toString();
+               userInput = new StringBuffer("");
+               processUserInput(cmd);
+               history.add(cmd);
+       }
+
+       protected void processUserInput(String input) {
+               try {
+                       StringTokenizer st = new StringTokenizer(input);
+                       List<String> args = new ArrayList<>();
+                       while (st.hasMoreTokens())
+                               args.add(st.nextToken());
+                       if (args.size() == 0) {
+                               displayPrompt();
+                               return;
+                       }
+
+                       // change directory
+                       if (args.get(0).equals("cd")) {
+                               if (args.size() == 1) {
+                                       setPath(homeDir);
+                               } else {
+                                       Path newPath = currentDir.resolve(args.get(1));
+                                       if (!Files.exists(newPath) || !Files.isDirectory(newPath)) {
+                                               println(newPath + ": No such file or directory");
+                                               return;
+                                       }
+                                       setPath(newPath);
+                               }
+                               displayPrompt();
+                               return;
+                       }
+                       // show current directory
+                       else if (args.get(0).equals("pwd")) {
+                               println(currentDir);
+                               displayPrompt();
+                               return;
+                       }
+                       // exit
+                       else if (args.get(0).equals("exit")) {
+                               println("logout");
+                               exitCalled();
+                               return;
+                       }
+
+                       ProcessBuilder pb = new ProcessBuilder(args);
+                       pb.redirectErrorStream(true);
+                       pb.directory(currentDir.toFile());
+//                     Process process = Runtime.getRuntime().exec(input, null, currentPath.toFile());
+                       process = pb.start();
+
+                       stdIn = process.getOutputStream();
+                       readOut = new Thread("MiniTerminal read out") {
+                               @Override
+                               public void run() {
+                                       running = true;
+                                       try (BufferedReader in = new BufferedReader(
+                                                       new InputStreamReader(process.getInputStream(), charset))) {
+                                               String line = null;
+                                               while ((line = in.readLine()) != null) {
+                                                       println(line);
+                                               }
+                                       } catch (IOException e) {
+                                               println(e.getMessage());
+                                       }
+                                       stdIn = null;
+                                       displayPrompt();
+                                       running = false;
+                                       readOut = null;
+                                       process = null;
+                               }
+                       };
+                       readOut.start();
+               } catch (IOException e) {
+                       println(e.getMessage());
+                       displayPrompt();
+               }
+       }
+
+       protected int linesForLogicalLine(char[] line) {
+               return line.length / charsPerLine + 1;
+       }
+
+       protected void println(Object line) {
+               buf.append(line);
+               markLogicalLine();
+       }
+
+       protected void refreshLines(int charPerLine, int nbrOfLines) {
+               if (lines.length != nbrOfLines) {
+                       lines = new String[nbrOfLines];
+                       Arrays.fill(lines, null);
+               }
+               if (this.charsPerLine != charPerLine)
+                       this.charsPerLine = charPerLine;
+
+               int currentLine = nbrOfLines - 1;
+               // current line
+               if (buf.length() > 0) {
+                       lines[currentLine] = buf.toString();
+               } else {
+                       lines[currentLine] = "";
+               }
+               currentLine--;
+
+               logicalLines: for (int i = logicalLines.size() - 1; i >= 0; i--) {
+                       char[] logicalLine = logicalLines.get(i).toCharArray();
+                       int linesNeeded = linesForLogicalLine(logicalLine);
+                       for (int j = linesNeeded - 1; j >= 0; j--) {
+                               int from = j * charPerLine;
+                               int to = j == linesNeeded - 1 ? from + charPerLine : Math.min(from + charPerLine, logicalLine.length);
+                               lines[currentLine] = new String(Arrays.copyOfRange(logicalLine, from, to));
+//                             System.out.println("Set line " + currentLine + " to : " + lines[currentLine]);
+                               currentLine--;
+                               if (currentLine < 0)
+                                       break logicalLines;
+                       }
+               }
+       }
+
+       @Override
+       public void paintControl(PaintEvent e) {
+               GC gc = e.gc;
+               gc.setFont(mono);
+               if (charExtent == null)
+                       charExtent = gc.textExtent("a");
+
+               Point areaSize = area.getSize();
+               int charPerLine = areaSize.x / charExtent.x;
+               int nbrOfLines = areaSize.y / charExtent.y;
+               refreshLines(charPerLine, nbrOfLines);
+
+               for (int i = 0; i < lines.length; i++) {
+                       String line = lines[i];
+                       if (line != null)
+                               gc.drawString(line, 0, i * charExtent.y);
+               }
+//             String toDraw = buf.toString();
+//             gc.drawString(toDraw, 0, 0);
+//             area.setCaret(caret);
+       }
+
+       protected void exitCalled() {
+
+       }
+
+       public void setPath(String path) {
+               this.currentDir = Paths.get(path);
+       }
+
+       public void setPath(Path path) {
+               this.currentDir = path;
+       }
+
+       public static void main(String[] args) {
+               Display display = Display.getCurrent() == null ? new Display() : Display.getCurrent();
+               Shell shell = new Shell(display, SWT.SHELL_TRIM);
+
+               String url = args.length > 0 ? args[0] : System.getProperty("user.home");
+               new MiniTerminal(shell, url) {
+
+                       @Override
+                       protected void exitCalled() {
+                               shell.dispose();
+                               System.exit(0);
+                       }
+               };
+
+               shell.open();
+               shell.setSize(new Point(800, 480));
+               while (!shell.isDisposed()) {
+                       if (!display.readAndDispatch())
+                               display.sleep();
+               }
+       }
+
+}
diff --git a/swt/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/MiniTextEditor.java b/swt/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/MiniTextEditor.java
new file mode 100644 (file)
index 0000000..91cd19e
--- /dev/null
@@ -0,0 +1,161 @@
+package org.argeo.minidesktop;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.net.MalformedURLException;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.layout.RowLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.FileDialog;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+
+public class MiniTextEditor {
+       private URL url;
+       private Text text;
+
+       public MiniTextEditor(Composite parent, int style) {
+               parent.setLayout(new GridLayout());
+
+               Composite toolBar = new Composite(parent, SWT.NONE);
+               toolBar.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
+               toolBar.setLayout(new RowLayout());
+               Button load = new Button(toolBar, SWT.FLAT);
+               load.setText("\u2191");// up arrow
+               load.addSelectionListener(new SelectionAdapter() {
+
+                       @Override
+                       public void widgetSelected(SelectionEvent e) {
+                               FileDialog fileDialog = new FileDialog(text.getShell());
+                               String path = fileDialog.open();
+                               if (path != null) {
+                                       setUrl(path);
+                               }
+                       }
+
+               });
+
+               Button save = new Button(toolBar, SWT.FLAT);
+               save.setText("\u2193");// down arrow
+               // save.setText("\u1F609");// emoji
+               save.addSelectionListener(new SelectionAdapter() {
+
+                       @Override
+                       public void widgetSelected(SelectionEvent e) {
+                               save(url);
+                       }
+
+               });
+
+               text = new Text(parent, SWT.WRAP | SWT.MULTI | SWT.BORDER | SWT.V_SCROLL);
+               text.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+       }
+
+       protected void load(URL url) {
+               text.setText("");
+               // TODO deal with encoding and binary data
+               try (BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream(), StandardCharsets.UTF_8))) {
+                       String line = null;
+                       while ((line = in.readLine()) != null) {
+                               text.append(line + "\n");
+                       }
+                       text.setEditable(true);
+               } catch (IOException e) {
+                       if (e instanceof FileNotFoundException) {
+                               Path path = url2path(url);
+                               try {
+                                       Files.createFile(path);
+                                       load(url);
+                                       return;
+                               } catch (IOException e1) {
+                                       e = e1;
+                               }
+                       }
+                       text.setText(e.getMessage());
+                       text.setEditable(false);
+                       e.printStackTrace();
+                       // throw new IllegalStateException("Cannot load " + url, e);
+               }
+       }
+
+       protected Path url2path(URL url) {
+               try {
+                       Path path = Paths.get(url.toURI());
+                       return path;
+               } catch (URISyntaxException e) {
+                       throw new IllegalStateException("Cannot convert " + url + " to uri", e);
+               }
+       }
+
+       protected void save(URL url) {
+               if (!url.getProtocol().equals("file"))
+                       throw new IllegalArgumentException(url.getProtocol() + " protocol is not supported for write");
+               Path path = url2path(url);
+               try (BufferedWriter out = new BufferedWriter(new OutputStreamWriter(Files.newOutputStream(path)))) {
+                       out.write(text.getText());
+               } catch (IOException e) {
+                       throw new IllegalStateException("Cannot save " + url + " to " + path, e);
+               }
+       }
+
+       public void setUrl(URL url) {
+               this.url = url;
+               if (text != null)
+                       load(url);
+       }
+
+       public void setUrl(String url) {
+               try {
+                       setUrl(new URL(url));
+               } catch (MalformedURLException e) {
+                       // try with http
+                       try {
+                               setUrl(new URL("file://" + url));
+                               return;
+                       } catch (MalformedURLException e1) {
+                               // nevermind...
+                       }
+                       throw new IllegalArgumentException("Cannot interpret URL " + url, e);
+               }
+       }
+
+       public static void main(String[] args) {
+               Display display = Display.getCurrent() == null ? new Display() : Display.getCurrent();
+               Shell shell = new Shell(display, SWT.SHELL_TRIM);
+
+               MiniTextEditor miniBrowser = new MiniTextEditor(shell, SWT.NONE);
+               String url = args.length > 0 ? args[0] : "";
+               if (!url.trim().equals("")) {
+                       miniBrowser.setUrl(url);
+                       shell.setText(url);
+               } else {
+                       shell.setText("*");
+               }
+
+               shell.open();
+               shell.setSize(new Point(800, 480));
+               while (!shell.isDisposed()) {
+                       if (!display.readAndDispatch())
+                               display.sleep();
+               }
+       }
+
+}
diff --git a/swt/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/cheatsheet_obj@2x.png b/swt/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/cheatsheet_obj@2x.png
new file mode 100644 (file)
index 0000000..55c614d
Binary files /dev/null and b/swt/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/cheatsheet_obj@2x.png differ
diff --git a/swt/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/console_view@2x.png b/swt/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/console_view@2x.png
new file mode 100644 (file)
index 0000000..54ecae2
Binary files /dev/null and b/swt/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/console_view@2x.png differ
diff --git a/swt/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/delete@2x.png b/swt/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/delete@2x.png
new file mode 100644 (file)
index 0000000..eb2fc72
Binary files /dev/null and b/swt/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/delete@2x.png differ
diff --git a/swt/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/external_browser@2x.png b/swt/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/external_browser@2x.png
new file mode 100644 (file)
index 0000000..06d337a
Binary files /dev/null and b/swt/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/external_browser@2x.png differ
diff --git a/swt/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/file_obj@2x.png b/swt/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/file_obj@2x.png
new file mode 100644 (file)
index 0000000..31e671c
Binary files /dev/null and b/swt/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/file_obj@2x.png differ
diff --git a/swt/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/fldr_obj@2x.png b/swt/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/fldr_obj@2x.png
new file mode 100644 (file)
index 0000000..adb7c2c
Binary files /dev/null and b/swt/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/fldr_obj@2x.png differ
diff --git a/swt/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/nav_home@2x.png b/swt/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/nav_home@2x.png
new file mode 100644 (file)
index 0000000..4c9a16c
Binary files /dev/null and b/swt/org.argeo.swt.minidesktop/src/org/argeo/minidesktop/nav_home@2x.png differ
index 6b678a83c3e8b666712054b25920c8c95e136ce2..b03939f8139dea5ad9f8d8e7d22753d4fee3e173 100644 (file)
@@ -9,6 +9,7 @@ import java.util.Objects;
 import javax.servlet.ServletContextEvent;
 import javax.servlet.ServletContextListener;
 
+import org.argeo.minidesktop.MiniDesktopManager;
 import org.eclipse.jetty.server.Connector;
 import org.eclipse.jetty.server.Server;
 import org.eclipse.jetty.server.ServerConnector;
@@ -17,9 +18,10 @@ import org.eclipse.jetty.servlet.ServletContextHandler;
 import org.eclipse.jetty.servlet.ServletHolder;
 import org.eclipse.jetty.util.resource.Resource;
 import org.eclipse.jetty.util.thread.QueuedThreadPool;
-import org.eclipse.rap.rwt.application.AbstractEntryPoint;
 import org.eclipse.rap.rwt.application.ApplicationConfiguration;
 import org.eclipse.rap.rwt.application.ApplicationRunner;
+import org.eclipse.rap.rwt.application.EntryPoint;
+import org.eclipse.rap.rwt.application.Application.OperationMode;
 import org.eclipse.rap.rwt.engine.RWTServlet;
 import org.eclipse.swt.widgets.Composite;
 import org.eclipse.swt.widgets.Control;
@@ -52,7 +54,7 @@ public class RwtRunner {
                context.setContextPath("/");
                server.setHandler(context);
 
-               String entryPoint = "data";
+               String entryPoint = "app";
 
                // rwt-resources requires a file system
                try {
@@ -119,16 +121,18 @@ public class RwtRunner {
                RwtRunner rwtRunner = new RwtRunner();
 
                String entryPoint = "app";
-               ApplicationConfiguration applicationConfiguration = (application) -> application.addEntryPoint("/" + entryPoint,
-                               () -> new AbstractEntryPoint() {
-                                       private static final long serialVersionUID = 5678385921969090733L;
-
-                                       @Override
-                                       protected void createContents(Composite parent) {
-                                               Label label = new Label(parent, 0);
-                                               label.setText("Hello world!");
-                                       }
-                               }, null);
+               ApplicationConfiguration applicationConfiguration = (application) -> {
+                       application.setOperationMode(OperationMode.SWT_COMPATIBILITY);
+                       application.addEntryPoint("/" + entryPoint, () -> new EntryPoint() {
+                               @Override
+                               public int createUI() {
+                                       MiniDesktopManager miniDesktopManager = new MiniDesktopManager(false, false);
+                                       miniDesktopManager.init();
+                                       miniDesktopManager.run();
+                                       return 0;
+                               }
+                       }, null);
+               };
 
                rwtRunner.setApplicationConfiguration(applicationConfiguration);
                rwtRunner.init();