Mercurial > hg > icedtea8
changeset 1950:03e2ef9b5c6b
Netx: add support for desktop shortcuts
2009-07-29 Omair Majid <omajid@redhat.com>
* netx/net/sourceforge/jnlp/IconDesc.java: Add new icon kind SHORTCUT.
* netx/net/sourceforge/jnlp/Launcher.java: Move StreamEater class to ...
* netx/net/sourceforge/jnlp/StreamEater.java: New file.
* netx/net/sourceforge/jnlp/resources/Messages.properties: Add
SDesktopShortcut.
* netx/net/sourceforge/jnlp/runtime/ApplicationInstance.java
(initialize): Call addMenuAndDesktopEntries.
(addMenuAndDesktopEntries): New function.
* netx/net/sourceforge/jnlp/security/SecurityWarningDialog.java: Add
CREATE_DESKTOP_SHORTCUT to AccessType.
* netx/net/sourceforge/jnlp/security/AccessWarningPane.java
(installComponents): Add a case for CREATE_DESKTOP_SHORTCUT
* netx/net/sourceforge/jnlp/services/ServiceUtil.java
Remove duplicate enum AccessType.
(checkAccess): New function.
(checkAccess): Add a new argument app.
* netx/net/sourceforge/jnlp/services/SingleInstanceLock.java
(getLockFileName): Call FileUtils.sanitizeFileName to sanitize the
filename.
* netx/net/sourceforge/jnlp/util/FileUtils.java: New file.
* netx/net/sourceforge/jnlp/util/XDesktopEntry.java: New file.
author | Omair Majid <omajid@redhat.com> |
---|---|
date | Wed, 29 Jul 2009 10:57:38 -0400 |
parents | 324662e5e611 |
children | 88c498641265 |
files | ChangeLog netx/net/sourceforge/jnlp/IconDesc.java netx/net/sourceforge/jnlp/Launcher.java netx/net/sourceforge/jnlp/StreamEater.java netx/net/sourceforge/jnlp/resources/Messages.properties netx/net/sourceforge/jnlp/runtime/ApplicationInstance.java netx/net/sourceforge/jnlp/security/AccessWarningPane.java netx/net/sourceforge/jnlp/security/SecurityWarningDialog.java netx/net/sourceforge/jnlp/services/ServiceUtil.java netx/net/sourceforge/jnlp/services/SingleInstanceLock.java netx/net/sourceforge/jnlp/util/FileUtils.java netx/net/sourceforge/jnlp/util/XDesktopEntry.java |
diffstat | 12 files changed, 386 insertions(+), 45 deletions(-) [+] |
line wrap: on
line diff
--- a/ChangeLog Wed Jul 29 10:48:43 2009 -0400 +++ b/ChangeLog Wed Jul 29 10:57:38 2009 -0400 @@ -1,3 +1,27 @@ +2009-07-29 Omair Majid <omajid@redhat.com> + + * netx/net/sourceforge/jnlp/IconDesc.java: Add new icon kind SHORTCUT. + * netx/net/sourceforge/jnlp/Launcher.java: Move StreamEater class to ... + * netx/net/sourceforge/jnlp/StreamEater.java: New file. + * netx/net/sourceforge/jnlp/resources/Messages.properties: Add + SDesktopShortcut. + * netx/net/sourceforge/jnlp/runtime/ApplicationInstance.java + (initialize): Call addMenuAndDesktopEntries. + (addMenuAndDesktopEntries): New function. + * netx/net/sourceforge/jnlp/security/SecurityWarningDialog.java: Add + CREATE_DESKTOP_SHORTCUT to AccessType. + * netx/net/sourceforge/jnlp/security/AccessWarningPane.java + (installComponents): Add a case for CREATE_DESKTOP_SHORTCUT + * netx/net/sourceforge/jnlp/services/ServiceUtil.java + Remove duplicate enum AccessType. + (checkAccess): New function. + (checkAccess): Add a new argument app. + * netx/net/sourceforge/jnlp/services/SingleInstanceLock.java + (getLockFileName): Call FileUtils.sanitizeFileName to sanitize the + filename. + * netx/net/sourceforge/jnlp/util/FileUtils.java: New file. + * netx/net/sourceforge/jnlp/util/XDesktopEntry.java: New file. + 2009-07-29 Omair Majid <omajid@redhat.com> * netx/net/sourceforge/jnlp/security/VariableX509TrustManager.java
--- a/netx/net/sourceforge/jnlp/IconDesc.java Wed Jul 29 10:48:43 2009 -0400 +++ b/netx/net/sourceforge/jnlp/IconDesc.java Wed Jul 29 10:57:38 2009 -0400 @@ -43,6 +43,9 @@ /** splash icon */ public static final Object SPLASH = "splash"; + + /** destop shortcut icon */ + public static final Object SHORTCUT = "shortcut"; /** the location of the icon */
--- a/netx/net/sourceforge/jnlp/Launcher.java Wed Jul 29 10:48:43 2009 -0400 +++ b/netx/net/sourceforge/jnlp/Launcher.java Wed Jul 29 10:57:38 2009 -0400 @@ -770,32 +770,6 @@ } }; - /** - * This class reads the output from a launched process and - * writes it to stdout. - */ - private static class StreamEater extends Thread { - private InputStream stream; - - StreamEater(InputStream stream) { - this.stream = new BufferedInputStream(stream); - } - - public void run() { - try { - while (true) { - int c = stream.read(); - if (c == -1) - break; - - System.out.write(c); - } - } - catch (IOException ex) { - } - } - }; - }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/netx/net/sourceforge/jnlp/StreamEater.java Wed Jul 29 10:57:38 2009 -0400 @@ -0,0 +1,45 @@ +// Copyright (C) 2001-2003 Jon A. Maxwell (JAM) +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +package net.sourceforge.jnlp; + +import java.io.BufferedInputStream; +import java.io.IOException; +import java.io.InputStream; + +/** + * This class reads the output from a launched process and writes it to stdout. + */ +public class StreamEater extends Thread { + private InputStream stream; + + public StreamEater(InputStream stream) { + this.stream = new BufferedInputStream(stream); + } + + public void run() { + try { + while (true) { + int c = stream.read(); + if (c == -1) + break; + + System.out.write(c); + } + } catch (IOException ex) { + } + } +}
--- a/netx/net/sourceforge/jnlp/resources/Messages.properties Wed Jul 29 10:48:43 2009 -0400 +++ b/netx/net/sourceforge/jnlp/resources/Messages.properties Wed Jul 29 10:57:38 2009 -0400 @@ -147,6 +147,7 @@ # Security SFileReadAccess=The application has requested read access to a file on the machine. Do you want to allow this action? SFileWriteAccess=The application has requested write access to a file on the machine. Do you want to allow this action? +SDesktopShortcut=The application has requested permission to create a desktop launcher. Do you want to allow this action? SSigUnverified=The application's digital signature cannot be verified. Do you want to run the application? SSigVerified=The application's digital signature has been verified. Do you want to run the application? SSignatureError=The application's digital signature has an error. Do you want to run the application?
--- a/netx/net/sourceforge/jnlp/runtime/ApplicationInstance.java Wed Jul 29 10:48:43 2009 -0400 +++ b/netx/net/sourceforge/jnlp/runtime/ApplicationInstance.java Wed Jul 29 10:57:38 2009 -0400 @@ -25,6 +25,8 @@ import net.sourceforge.jnlp.*; import net.sourceforge.jnlp.event.*; +import net.sourceforge.jnlp.security.SecurityWarningDialog.AccessType; +import net.sourceforge.jnlp.services.ServiceUtil; import net.sourceforge.jnlp.util.*; /** @@ -107,6 +109,32 @@ */ public void initialize() { installEnvironment(); + addMenuAndDesktopEntries(); + } + + /** + * Creates menu and desktop entries if required by the jnlp file + */ + + private void addMenuAndDesktopEntries() { + XDesktopEntry entry = new XDesktopEntry(file); + + if (file.getInformation().getShortcut().onDesktop()) { + if (ServiceUtil.checkAccess(this, AccessType.CREATE_DESTKOP_SHORTCUT)) { + entry.createDesktopShortcut(); + } + } + + if (file.getInformation().getShortcut().getMenu() != null) { + /* + * Sun's WebStart implementation doesnt seem to do anything under GNOME + */ + if (JNLPRuntime.isDebug()) { + System.err.println("ApplicationInstance.addMenuAndDesktopEntries():" + + " Adding menu entries NOT IMPLEMENTED"); + } + } + } /**
--- a/netx/net/sourceforge/jnlp/security/AccessWarningPane.java Wed Jul 29 10:48:43 2009 -0400 +++ b/netx/net/sourceforge/jnlp/security/AccessWarningPane.java Wed Jul 29 10:57:38 2009 -0400 @@ -121,6 +121,9 @@ case WRITE_FILE: topLabelText = R("SFileWriteAccess"); break; + case CREATE_DESTKOP_SHORTCUT: + topLabelText = R("SDesktopShortcut"); + break; case CLIPBOARD_READ: topLabelText = R("SClipboardReadAccess"); break;
--- a/netx/net/sourceforge/jnlp/security/SecurityWarningDialog.java Wed Jul 29 10:48:43 2009 -0400 +++ b/netx/net/sourceforge/jnlp/security/SecurityWarningDialog.java Wed Jul 29 10:57:38 2009 -0400 @@ -70,6 +70,7 @@ public static enum AccessType { READ_FILE, WRITE_FILE, + CREATE_DESTKOP_SHORTCUT, CLIPBOARD_READ, CLIPBOARD_WRITE, PRINTER,
--- a/netx/net/sourceforge/jnlp/services/ServiceUtil.java Wed Jul 29 10:48:43 2009 -0400 +++ b/netx/net/sourceforge/jnlp/services/ServiceUtil.java Wed Jul 29 10:57:38 2009 -0400 @@ -57,13 +57,6 @@ } /** - * Types of system access that may need permissions. - */ - public static enum AccessType { - READ_FILE, WRITE_FILE, CLIPBOARD_READ, CLIPBOARD_WRITE, PRINTER - } - - /** * Returns the BasicService reference, or null if the service is * unavailable. */ @@ -227,9 +220,29 @@ * @return true if the access was granted, false otherwise. */ public static boolean checkAccess(SecurityWarningDialog.AccessType type, + Object... extras) { + return checkAccess(null, type, extras); + } + + /** + * Returns whether the app requesting a service is signed. If the app is + * unsigned, the user is prompted with a dialog asking if the action + * should be allowed. + * @param app the application which is requesting the check. If null, the current + * application is used. + * @param type the type of access being requested + * @param extras extra Strings (usually) that are passed to the dialog for + * message formatting. + * @return true if the access was granted, false otherwise. + */ + public static boolean checkAccess(ApplicationInstance app, + SecurityWarningDialog.AccessType type, Object... extras) { - ApplicationInstance app = JNLPRuntime.getApplication(); + if (app == null) { + app = JNLPRuntime.getApplication(); + } + if (app != null) { if (!app.isSigned()) { final SecurityWarningDialog.AccessType tmpType = type;
--- a/netx/net/sourceforge/jnlp/services/SingleInstanceLock.java Wed Jul 29 10:48:43 2009 -0400 +++ b/netx/net/sourceforge/jnlp/services/SingleInstanceLock.java Wed Jul 29 10:57:38 2009 -0400 @@ -27,6 +27,7 @@ import net.sourceforge.jnlp.JNLPFile; import net.sourceforge.jnlp.runtime.JNLPRuntime; +import net.sourceforge.jnlp.util.FileUtils; /** * This class represents a Lock for single instance jnlp applications @@ -152,17 +153,7 @@ } initialName = initialName + getCurrentDisplay(); - String encodedName; - - /* - * FIXME - * - * Assuming safe characters are 'a-z','A-Z','0-9', '_', '.' - */ - - encodedName = initialName.replaceAll("[^a-zA-Z0-9.]", "_"); - - return encodedName; + return FileUtils.sanitizeFileName(initialName); }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/netx/net/sourceforge/jnlp/util/FileUtils.java Wed Jul 29 10:57:38 2009 -0400 @@ -0,0 +1,48 @@ +// Copyright (C) 2009 Red Hat, Inc. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + +package net.sourceforge.jnlp.util; + +/** + * This class contains a few file-related utility functions. + * + * @author Omair Majid + */ + +public class FileUtils { + + + /** + * Given an input, return a sanitized form of the input suitable for use as + * a file/directory name + * + * @param input + * @return a sanitized version of the input + */ + public static String sanitizeFileName(String input) { + + /* + * FIXME + * + * Assuming safe characters are 'a-z','A-Z','0-9', '_', '.' + */ + + String sanitizedName = input.replaceAll("[^a-zA-Z0-9.]", "_"); + return sanitizedName; + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/netx/net/sourceforge/jnlp/util/XDesktopEntry.java Wed Jul 29 10:57:38 2009 -0400 @@ -0,0 +1,210 @@ +// Copyright (C) 2009 Red Hat, Inc. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +package net.sourceforge.jnlp.util; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.io.Reader; +import java.io.StringReader; +import java.net.URL; +import java.nio.charset.Charset; +import java.util.Arrays; + +import net.sourceforge.jnlp.IconDesc; +import net.sourceforge.jnlp.JNLPFile; +import net.sourceforge.jnlp.StreamEater; +import net.sourceforge.jnlp.cache.CacheUtil; +import net.sourceforge.jnlp.cache.UpdatePolicy; +import net.sourceforge.jnlp.runtime.JNLPRuntime; + +/** + * This class builds a (freedesktop.org) desktop entry out of a {@link JNLPFile} + * . This entry can be used to install desktop shortcuts. See xdg-desktop-icon + * (1) and http://standards.freedesktop.org/desktop-entry-spec/latest/ for more + * information + * + * @author Omair Majid + * + */ +public class XDesktopEntry { + + public static final String JAVA_ICON_NAME = "java.png"; + + private JNLPFile file = null; + private int iconSize = -1; + private String iconLocation = null; + + private int[] VALID_ICON_SIZES = new int[] { 16, 22, 32, 48, 64, 128 }; + + /** + * Create a XDesktopEntry for the given JNLP file + * + * @param file a {@link JNLPFile} that indicates the application to launch + */ + public XDesktopEntry(JNLPFile file) { + this.file = file; + + /* looks like a good initial value */ + iconSize = VALID_ICON_SIZES[2]; + } + + /** + * Returns the contents of the {@link XDesktopEntry} through the + * {@link Reader} interface. + */ + public Reader getContentsAsReader() { + + String pathToJavaws = System.getProperty("java.home") + File.separator + "bin" + + File.separator + "javaws"; + + String fileContents = "[Desktop Entry]\n"; + fileContents += "Version=1.0\n"; + fileContents += "Name=" + file.getTitle() + "\n"; + fileContents += "GenericName=Java Web Start Application\n"; + fileContents += "Comment=" + file.getInformation().getDescription() + "\n"; + fileContents += "Type=Application\n"; + if (iconLocation != null) { + fileContents += "Icon=" + iconLocation + "\n"; + } else { + fileContents += "Icon=" + JAVA_ICON_NAME + "\n"; + + } + if (file.getInformation().getVendor() != null) { + fileContents += "Vendor=" + file.getInformation().getVendor() + "\n"; + } + fileContents += "Exec=" + pathToJavaws + " \"" + file.getSourceLocation() + "\"\n"; + + return new StringReader(fileContents); + + } + + /** + * Get the size of the icon (in pixels) for the desktop shortcut + */ + public int getIconSize() { + return iconSize; + } + + /** + * Set the icon size to use for the desktop shortcut + * + * @param size the size (in pixels) of the icon to use. Commonly used sizes + * are of 16, 22, 32, 48, 64 and 128 + */ + public void setIconSize(int size) { + iconSize = size; + } + + /** + * Create a desktop shortcut for this desktop entry + */ + public void createDesktopShortcut() { + try { + cacheIcon(); + installDesktopLauncher(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * Install this XDesktopEntry into the user's desktop as a launcher + */ + private void installDesktopLauncher() { + File shortcutFile = new File(JNLPRuntime.TMP_DIR + File.separator + + FileUtils.sanitizeFileName(file.getTitle()) + ".desktop"); + try { + + /* + * Write out a Java String (UTF-16) as a UTF-8 file + */ + + OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(shortcutFile), + Charset.forName("UTF-8")); + Reader reader = getContentsAsReader(); + + char[] buffer = new char[1024]; + int ret = 0; + while (-1 != (ret = reader.read(buffer))) { + writer.write(buffer, 0, ret); + } + + reader.close(); + writer.close(); + + /* + * Install the desktop entry + */ + + String[] execString = new String[] { "xdg-desktop-icon", "install", "--novendor", + shortcutFile.getCanonicalPath() }; + if (JNLPRuntime.isDebug()) { + System.err.println("Execing: " + Arrays.toString(execString)); + } + Process installer = Runtime.getRuntime().exec(execString); + new StreamEater(installer.getInputStream()).start(); + new StreamEater(installer.getErrorStream()).start(); + + try { + installer.waitFor(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + if (!shortcutFile.delete()) { + throw new IOException("Unable to delete temporary file:" + shortcutFile); + } + + } catch (FileNotFoundException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + /** + * Cache the icon for the desktop entry + */ + private void cacheIcon() { + + URL iconLocation = file.getInformation().getIconLocation(IconDesc.SHORTCUT, iconSize, + iconSize); + + if (iconLocation == null) { + iconLocation = file.getInformation().getIconLocation(IconDesc.DEFAULT, iconSize, + iconSize); + } + + if (iconLocation != null) { + String location = CacheUtil.getCachedResource(iconLocation, null, UpdatePolicy.SESSION) + .toString(); + if (!location.startsWith("file:")) { + throw new RuntimeException("Unable to cache icon"); + } + + this.iconLocation = location.substring("file:".length()); + + if (JNLPRuntime.isDebug()) { + System.err.println("Cached desktop shortcut icon: " + this.iconLocation); + } + } + } + +}