2 // Getdown - application installer, patcher and launcher
3 // Copyright (C) 2004-2018 Getdown authors
4 // https://github.com/threerings/getdown/blob/master/LICENSE
6 package com.threerings.getdown.launcher;
9 import java.awt.Container;
10 import java.awt.Image;
11 import java.awt.event.ActionEvent;
12 import java.awt.event.KeyEvent;
13 import java.awt.event.WindowAdapter;
14 import java.awt.event.WindowEvent;
15 import java.io.BufferedOutputStream;
17 import java.io.FileOutputStream;
18 import java.io.IOException;
19 import java.io.PrintStream;
20 import java.util.ArrayList;
21 import java.util.List;
23 import javax.swing.AbstractAction;
24 import javax.swing.JComponent;
25 import javax.swing.JFrame;
26 import javax.swing.KeyStroke;
27 import javax.swing.WindowConstants;
29 import com.samskivert.swing.util.SwingUtil;
30 import com.threerings.getdown.data.Application;
31 import com.threerings.getdown.data.Build;
32 import com.threerings.getdown.data.EnvConfig;
33 import com.threerings.getdown.data.SysProps;
34 import com.threerings.getdown.util.LaunchUtil;
35 import com.threerings.getdown.util.StringUtil;
36 import static com.threerings.getdown.Log.log;
37 import jalview.bin.StartupNotificationListener;
38 import jalview.util.HttpUtils;
41 * The main application entry point for Getdown.
43 public class GetdownApp
45 public static List<String> startupFilesParameters = new ArrayList<>();
47 * The main entry point of the Getdown launcher application.
49 public static void main (String[] argv) {
52 } catch (Exception e) {
53 log.warning("main() failed.", e);
58 * Runs Getdown as an application, using the arguments supplie as {@code argv}.
59 * @return the {@code Getdown} instance that is running. {@link Getdown#start} will have been
61 * @throws Exception if anything goes wrong starting Getdown.
63 public static Getdown start (String[] argv) throws Exception {
64 List<EnvConfig.Note> notes = new ArrayList<>();
65 EnvConfig envc = EnvConfig.create(argv, notes);
67 if (!notes.isEmpty()) for (EnvConfig.Note n : notes) System.err.println(n.message);
68 else System.err.println("Usage: java -jar getdown.jar [app_dir] [app_id] [app args]");
72 // pipe our output into a file in the application directory
73 if (!SysProps.noLogRedir()) {
74 File logFile = new File(envc.appDir, "launcher.log");
76 PrintStream logOut = new PrintStream(
77 new BufferedOutputStream(new FileOutputStream(logFile)), true);
78 System.setOut(logOut);
79 System.setErr(logOut);
80 } catch (IOException ioe) {
81 log.warning("Unable to redirect output to '" + logFile + "': " + ioe);
85 // report any notes from reading our env config, and abort if necessary
86 boolean abort = false;
87 for (EnvConfig.Note note : notes) {
89 case INFO: log.info(note.message); break;
90 case WARN: log.warning(note.message); break;
91 case ERROR: log.error(note.message); abort = true; break;
94 if (abort) System.exit(-1);
96 log.info("Starting ...");
99 jalview.bin.StartupNotificationListener.setListener();
100 } catch (Exception e)
103 } catch (NoClassDefFoundError e)
105 log.warning("Starting without install4j classes");
106 } catch (Throwable t)
111 // record a few things for posterity
112 log.info("------------------ VM Info ------------------");
113 log.info("-- OS Name: " + System.getProperty("os.name"));
114 log.info("-- OS Arch: " + System.getProperty("os.arch"));
115 log.info("-- OS Vers: " + System.getProperty("os.version"));
116 log.info("-- Java Vers: " + System.getProperty("java.version"));
117 log.info("-- Java Home: " + System.getProperty("java.home"));
118 log.info("-- Install4j Vers: " + Application.i4jVersion);
119 log.info("-- Install4j Template Vers: " + System.getProperty("installer_template_version"));
120 log.info("-- User Name: " + System.getProperty("user.name"));
121 log.info("-- User Home: " + System.getProperty("user.home"));
122 log.info("-- Cur dir: " + System.getProperty("user.dir"));
123 log.info("-- Launcher version: "+Build.version());
124 log.info("-- startupFilesParameterString: " + getStartupFilesParameterString(getStartupFilesParameters(), false));
125 log.info("-- getStartupFilesParameterString(): " + getStartupFilesParameterString(getStartupFilesParameters(), true));
126 log.info("---------------------------------------------");
128 Getdown app = new Getdown(envc) {
130 protected Container createContainer () {
131 // create our user interface, and display it
132 if (_frame == null) {
133 _frame = new JFrame("");
134 _frame.addWindowListener(new WindowAdapter() {
136 public void windowClosing (WindowEvent evt) {
144 } catch (Exception e) {
145 log.warning("Error reading config for keep_on_top");
147 // move window to top, always on top
148 if (_ifc.keepOnTop) {
149 log.info("Keep on top set to ", "keep_on_top", _ifc.keepOnTop);
150 _frame.setAlwaysOnTop(true);
153 // handle close on ESC
154 String cancelId = "Cancel"; // $NON-NLS-1$
155 _frame.getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
156 KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), cancelId);
157 _frame.getRootPane().getActionMap().put(cancelId, new AbstractAction() {
158 public void actionPerformed (ActionEvent e) {
162 // this cannot be called in configureContainer as it is only allowed before the
163 // frame has been displayed for the first time
164 _frame.setUndecorated(_ifc.hideDecorations);
165 _frame.setResizable(false);
167 _frame.getContentPane().removeAll();
169 _frame.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
170 return _frame.getContentPane();
174 protected void configureContainer () {
175 if (_frame == null) return;
177 _frame.setTitle(_ifc.name);
180 _frame.setBackground(new Color(_ifc.background, true));
181 } catch (Exception e) {
182 log.warning("Failed to set background", "bg", _ifc.background, e);
185 if (_ifc.iconImages != null && _ifc.iconImages.size() > 0) {
186 ArrayList<Image> icons = new ArrayList<>();
187 for (String path : _ifc.iconImages) {
188 Image img = loadImage(path);
190 log.warning("Error loading icon image", "path", path);
195 if (icons.isEmpty()) {
196 log.warning("Failed to load any icons", "iconImages", _ifc.iconImages);
198 _frame.setIconImages(icons);
204 protected void showContainer () {
205 if (_frame != null) {
207 SwingUtil.centerWindow(_frame);
208 _frame.setVisible(true);
210 _shownContainer = true;
214 protected void disposeContainer () {
215 if (_frame != null) {
222 protected void showDocument (String url) {
223 if (!StringUtil.couldBeValidUrl(url)) {
224 // command injection would be possible if we allowed e.g. spaces and double quotes
225 log.warning("Invalid document URL.", "url", url);
229 if (LaunchUtil.isWindows()) {
230 String osName = System.getProperty("os.name", "");
231 if (osName.indexOf("9") != -1 || osName.indexOf("Me") != -1) {
232 cmdarray = new String[] {
233 "command.com", "/c", "start", "\"" + url + "\"" };
235 cmdarray = new String[] {
236 "cmd.exe", "/c", "start", "\"\"", "\"" + url + "\"" };
238 } else if (LaunchUtil.isMacOS()) {
239 cmdarray = new String[] { "open", url };
240 } else { // Linux, Solaris, etc.
241 cmdarray = new String[] { "firefox", url };
244 Runtime.getRuntime().exec(cmdarray);
245 } catch (Exception e) {
246 log.warning("Failed to open browser.", "cmdarray", cmdarray, e);
251 protected void exit (int exitCode) {
252 // if we're running the app in the same JVM, don't call System.exit, but do
253 // make double sure that the download window is closed.
254 if (invokeDirect()) {
257 System.exit(exitCode);
262 protected void fail (String message) {
264 // super.fail causes the UI to be created (if needed) on the next UI tick, so we
265 // want to wait until that happens before we attempt to redecorate the window
266 EQinvoke(new Runnable() {
269 // if the frame was set to be undecorated, make window decoration available
270 // to allow the user to close the window
271 if (_frame != null && _frame.isUndecorated()) {
273 Color bg = _frame.getBackground();
274 if (bg != null && bg.getAlpha() < 255) {
275 // decorated windows do not allow alpha backgrounds
276 _frame.setBackground(
277 new Color(bg.getRed(), bg.getGreen(), bg.getBlue()));
279 _frame.setUndecorated(false);
286 protected JFrame _frame;
289 if (getStartupFilesParameters().size() > 0) {
290 Application.setStartupFilesFromParameters(getStartupFilesParameters());
297 public static void addStartupFilesParameter(String parameter) {
298 startupFilesParameters.add(parameter);
301 public static List<String> getStartupFilesParameters() {
302 return startupFilesParameters;
305 public static String getStartupFilesParameterString(List<String> parameters, boolean changeJalviewSchemeUris) {
306 StringBuilder sb = new StringBuilder();
307 boolean first = true;
308 for(String f : parameters) {
314 String p = changeJalviewSchemeUris && HttpUtils.isJalviewSchemeUri(f) ? HttpUtils.equivalentJalviewUrl(f) : f;
315 if (p.contains(" ")) {
323 return sb.toString();