1 package org
.argeo
.minidesktop
;
3 import java
.lang
.management
.ManagementFactory
;
4 import java
.net
.InetAddress
;
5 import java
.net
.UnknownHostException
;
6 import java
.nio
.file
.Path
;
7 import java
.util
.Arrays
;
10 import org
.eclipse
.swt
.SWT
;
11 import org
.eclipse
.swt
.custom
.CTabFolder
;
12 import org
.eclipse
.swt
.custom
.CTabItem
;
13 import org
.eclipse
.swt
.events
.SelectionAdapter
;
14 import org
.eclipse
.swt
.events
.SelectionEvent
;
15 import org
.eclipse
.swt
.graphics
.Color
;
16 import org
.eclipse
.swt
.graphics
.Image
;
17 import org
.eclipse
.swt
.graphics
.Point
;
18 import org
.eclipse
.swt
.graphics
.Rectangle
;
19 import org
.eclipse
.swt
.layout
.GridData
;
20 import org
.eclipse
.swt
.layout
.GridLayout
;
21 import org
.eclipse
.swt
.widgets
.Composite
;
22 import org
.eclipse
.swt
.widgets
.Control
;
23 import org
.eclipse
.swt
.widgets
.Display
;
24 import org
.eclipse
.swt
.widgets
.Shell
;
25 import org
.eclipse
.swt
.widgets
.ToolBar
;
26 import org
.eclipse
.swt
.widgets
.ToolItem
;
28 /** A very minimalistic desktop manager based on Java and Eclipse SWT. */
29 public class MiniDesktopManager
{
30 private Display display
;
32 private Shell rootShell
;
33 private Shell toolBarShell
;
34 private CTabFolder tabFolder
;
35 private int maxTabTitleLength
= 16;
37 private final boolean fullscreen
;
38 private final boolean stacking
;
40 private MiniDesktopImages images
;
42 public MiniDesktopManager(boolean fullscreen
, boolean stacking
) {
43 this.fullscreen
= fullscreen
;
44 this.stacking
= stacking
;
47 public MiniDesktopManager() {
57 if (display
!= null) {
58 display
.syncExec(() -> {
66 Display
.setAppName("Mini SWT Desktop");
67 display
= Display
.getCurrent();
69 throw new IllegalStateException("Already a display " + display
);
70 display
= Display
.getDefault();
72 display
.syncExec(() -> {
73 if (display
.getTouchEnabled()) {
74 System
.out
.println("Touch enabled.");
77 images
= new MiniDesktopImages(display
);
82 rootShell
= new Shell(display
, SWT
.NO_TRIM
);
83 rootShell
.setFullScreen(true);
84 Rectangle bounds
= display
.getBounds();
85 rootShell
.setLocation(0, 0);
86 rootShell
.setSize(bounds
.width
, bounds
.height
);
88 rootShell
= new Shell(display
, SWT
.CLOSE
| SWT
.RESIZE
);
89 Rectangle shellArea
= rootShell
.computeTrim(200, 200, 800, 480);
90 rootShell
.setSize(shellArea
.width
, shellArea
.height
);
91 rootShell
.setText(Display
.getAppName());
92 rootShell
.setImage(images
.terminalIcon
);
95 rootShell
.setLayout(noSpaceGridLayout(new GridLayout(2, false)));
96 Composite toolBarArea
= new Composite(rootShell
, SWT
.NONE
);
97 toolBarArea
.setLayoutData(new GridData(toolBarSize
, rootShell
.getSize().y
));
100 if (isFullscreen()) {
101 toolBarShell
= new Shell(rootShell
, SWT
.NO_TRIM
| SWT
.ON_TOP
);
102 toolBar
= new ToolBar(toolBarShell
, SWT
.VERTICAL
| SWT
.FLAT
| SWT
.BORDER
);
105 toolBarArea
.setLayoutData(new GridData(toolBar
.getSize().x
, toolBar
.getSize().y
));
107 toolBar
= new ToolBar(toolBarArea
, SWT
.VERTICAL
| SWT
.FLAT
| SWT
.BORDER
);
109 toolBarArea
.setLayoutData(new GridData(SWT
.FILL
, SWT
.CENTER
, false, false));
113 tabFolder
= new CTabFolder(rootShell
, SWT
.MULTI
| SWT
.BORDER
| SWT
.BOTTOM
);
114 tabFolder
.setLayout(noSpaceGridLayout(new GridLayout()));
115 tabFolder
.setLayoutData(new GridData(SWT
.FILL
, SWT
.FILL
, true, true));
117 Color selectionBackground
= display
.getSystemColor(SWT
.COLOR_LIST_SELECTION
);
118 tabFolder
.setSelectionBackground(selectionBackground
);
121 Control background
= createBackground(tabFolder
);
122 CTabItem homeTabItem
= new CTabItem(tabFolder
, SWT
.NONE
);
123 homeTabItem
.setText("Home");
124 homeTabItem
.setImage(images
.homeIcon
);
125 homeTabItem
.setControl(background
);
126 tabFolder
.setFocus();
128 createBackground(rootShell
);
132 // rootShell.layout(true, true);
134 if (toolBarShell
!= null) {
135 int toolBarShellY
= (display
.getBounds().height
- toolBar
.getSize().y
) / 2;
136 toolBarShell
.setLocation(0, toolBarShellY
);
140 long jvmUptime
= ManagementFactory
.getRuntimeMXBean().getUptime();
141 System
.out
.println("SWT Mini Desktop Manager available in " + jvmUptime
+ " ms.");
145 protected void createDock(ToolBar toolBar
) {
147 addToolItem(toolBar
, images
.terminalIcon
, "Terminal", () -> {
148 String url
= System
.getProperty("user.home");
149 AppContext appContext
= createAppParent(images
.terminalIcon
);
150 new MiniTerminal(appContext
.getAppParent(), url
) {
153 protected void exitCalled() {
154 if (appContext
.shell
!= null)
155 appContext
.shell
.dispose();
156 if (appContext
.tabItem
!= null)
157 appContext
.tabItem
.dispose();
162 title
= System
.getProperty("user.name") + "@" + InetAddress
.getLocalHost().getHostName();
163 } catch (UnknownHostException e
) {
164 title
= System
.getProperty("user.name") + "@localhost";
166 if (appContext
.shell
!= null)
167 appContext
.shell
.setText(title
);
168 if (appContext
.tabItem
!= null) {
169 appContext
.tabItem
.setText(tabTitle(title
));
170 appContext
.tabItem
.setToolTipText(title
);
176 addToolItem(toolBar
, images
.browserIcon
, "Browser", () -> {
177 String url
= "https://start.duckduckgo.com/";
178 AppContext appContext
= createAppParent(images
.browserIcon
);
179 new MiniBrowser(appContext
.getAppParent(), url
, false, false) {
181 public void titleChanged(String title
) {
182 if (appContext
.shell
!= null)
183 appContext
.shell
.setText(title
);
184 if (appContext
.tabItem
!= null) {
185 appContext
.tabItem
.setText(tabTitle(title
));
186 appContext
.tabItem
.setToolTipText(title
);
194 addToolItem(toolBar
, images
.explorerIcon
, "Explorer", () -> {
195 String url
= System
.getProperty("user.home");
196 AppContext appContext
= createAppParent(images
.explorerIcon
);
197 new MiniExplorer(appContext
.getAppParent(), url
) {
200 protected void pathChanged(Path path
) {
201 if (appContext
.shell
!= null)
202 appContext
.shell
.setText(path
.toString());
203 if (appContext
.tabItem
!= null) {
204 appContext
.tabItem
.setText(path
.getFileName().toString());
205 appContext
.tabItem
.setToolTipText(path
.toString());
213 new ToolItem(toolBar
, SWT
.SEPARATOR
);
216 addToolItem(toolBar
, images
.exitIcon
, "Exit", () -> rootShell
.dispose());
221 protected String
tabTitle(String title
) {
222 return title
.length() > maxTabTitleLength ? title
.substring(0, maxTabTitleLength
) : title
;
225 protected void addToolItem(ToolBar toolBar
, Image icon
, String name
, Runnable action
) {
226 ToolItem searchI
= new ToolItem(toolBar
, SWT
.PUSH
);
227 searchI
.setImage(icon
);
228 searchI
.setToolTipText(name
);
229 searchI
.addSelectionListener(new SelectionAdapter() {
232 public void widgetSelected(SelectionEvent e
) {
239 protected AppContext
createAppParent(Image icon
) {
241 Composite appParent
= new Composite(tabFolder
, SWT
.CLOSE
);
242 appParent
.setLayout(noSpaceGridLayout(new GridLayout()));
243 CTabItem item
= new CTabItem(tabFolder
, SWT
.CLOSE
);
245 item
.setControl(appParent
);
246 return new AppContext(item
);
248 Shell shell
= isFullscreen() ?
new Shell(rootShell
, SWT
.SHELL_TRIM
)
249 : new Shell(rootShell
.getDisplay(), SWT
.SHELL_TRIM
);
250 shell
.setImage(icon
);
251 return new AppContext(shell
);
255 protected void openApp(AppContext appContext
) {
256 if (appContext
.shell
!= null) {
257 Shell shell
= (Shell
) appContext
.shell
;
259 shell
.setSize(new Point(800, 480));
261 if (appContext
.tabItem
!= null) {
262 tabFolder
.setFocus();
263 tabFolder
.setSelection(appContext
.tabItem
);
267 protected Control
createBackground(Composite parent
) {
268 Composite backgroundArea
= new Composite(parent
, SWT
.NONE
);
269 backgroundArea
.setLayoutData(new GridData(SWT
.FILL
, SWT
.FILL
, true, true));
270 initBackground(backgroundArea
);
271 return backgroundArea
;
274 protected void initBackground(Composite backgroundArea
) {
275 MiniHomePart homePart
= new MiniHomePart() {
278 protected void fillAppsToolBar(ToolBar toolBar
) {
282 homePart
.createUiPart(backgroundArea
, null);
286 while (!rootShell
.isDisposed()) {
287 if (!display
.readAndDispatch())
292 public void dispose() {
293 if (!rootShell
.isDisposed()) {
294 rootShell
.getDisplay().syncExec(() -> {
300 protected boolean isFullscreen() {
304 protected boolean isStacking() {
308 protected Image
getIconForExt(String ext
) {
309 // Program program = Program.findProgram(ext);
310 // if (program == null)
311 return display
.getSystemImage(SWT
.ICON_INFORMATION
);
313 // ImageData iconData = program.getImageData();
314 // if (iconData == null) {
315 // return display.getSystemImage(SWT.ICON_INFORMATION);
317 // return new Image(display, iconData);
322 private static GridLayout
noSpaceGridLayout(GridLayout layout
) {
323 layout
.horizontalSpacing
= 0;
324 layout
.verticalSpacing
= 0;
325 layout
.marginWidth
= 0;
326 layout
.marginHeight
= 0;
330 public static void main(String
[] args
) {
331 List
<String
> options
= Arrays
.asList(args
);
332 if (options
.contains("--help")) {
333 System
.out
.println("Usage: java " + MiniDesktopManager
.class.getName().replace('.', '/') + " [OPTION]");
334 System
.out
.println("A minimalistic desktop manager based on Java and Eclipse SWT.");
335 System
.out
.println(" --fullscreen : take control of the whole screen (default is to run in a window)");
336 System
.out
.println(" --stacking : open apps as tabs (default is to create new windows)");
337 System
.out
.println(" --help : print this help and exit");
340 boolean fullscreen
= options
.contains("--fullscreen");
341 boolean stacking
= options
.contains("--stacking");
343 MiniDesktopManager desktopManager
= new MiniDesktopManager(fullscreen
, stacking
);
344 desktopManager
.init();
345 desktopManager
.run();
346 desktopManager
.dispose();
352 private CTabItem tabItem
;
354 public AppContext(Shell shell
) {
358 public AppContext(CTabItem tabItem
) {
359 this.tabItem
= tabItem
;
362 Composite
getAppParent() {
366 return (Composite
) tabItem
.getControl();
367 throw new IllegalStateException();