blob: aad0dcbf21ba286418e2c278d1b5759a52136ae4 [file] [log] [blame]
package org.eclipse.swt.program;
/*
* (c) Copyright IBM Corp. 2000, 2001.
* All Rights Reserved
*/
import org.eclipse.swt.internal.*;
import org.eclipse.swt.internal.motif.*;
import org.eclipse.swt.*;
import org.eclipse.swt.graphics.*;
import org.eclipse.swt.widgets.Display;
import java.io.*;
import java.util.Iterator;
import java.util.Hashtable;
import java.util.Vector;
/**
* Instances of this class represent programs and
* their assoicated file extensions in the operating
* system.
*/
public final class Program {
String name;
String extension;
String command;
Display display;
static private final String cdeShell = "Program_CDE_SHELL"; // hidden shell used for DtAppInitialize and DtActionInvoke
static private final String[] cdeIconExt = { ".m.pm", ".l.pm", ".s.pm", ".t.pm" };
static private final String[] cdeMaskExt = { ".m_m.bm", ".l_m.bm", ".s_m.bm", ".t_m.bm" };
static private final String desktopData = "Program_DESKTOP";
static final int DESKTOP_UNKNOWN = 0;
static final int DESKTOP_KDE = 1;
static final int DESKTOP_GNOME = 2;
static final int DESKTOP_CDE = 3;
/**
* Prevents uninitialized instances from being created outside the package.
*/
Program () {
}
/* Determine the desktop for the given display. */
static int getDesktop( Display display ) {
if (display == null) return DESKTOP_UNKNOWN;
// If the desktop type for this display is already known, return it.
Integer desktopValue = (Integer) display.getData( desktopData );
if (desktopValue != null) {
return desktopValue.intValue();
}
// Obtain the atoms for the various window manager signature properties.
int desktop = DESKTOP_UNKNOWN;
int xDisplay = display.xDisplay;
/* Use the character encoding for the default locale */
byte[] gnomeName = Converter.wcsToMbcs (null, "GNOME_NAME_SERVER", true);
byte[] cdeName = Converter.wcsToMbcs (null, "DTWM_IS_RUNNING", true);
byte[] kdeName = Converter.wcsToMbcs (null, "KWIN_RUNNING", true);
int gnome = OS.XInternAtom( xDisplay, gnomeName, true );
int cde = OS.XInternAtom( xDisplay, cdeName, true );
int kde = OS.XInternAtom( xDisplay, kdeName, true );
// Get the list of properties on the root window.
int rootWindow = OS.XDefaultRootWindow( xDisplay );
int[] numProp = new int[1];
int propList = OS.XListProperties( xDisplay, rootWindow, numProp );
if (propList == 0) return DESKTOP_UNKNOWN;
int[] property = new int[ numProp[0] ];
OS.memmove( property, propList, (property.length * 4) );
OS.XFree( propList );
// A given WM (desktop) is active if the property exists on the root window.
for (int index = 0; desktop == DESKTOP_UNKNOWN && index < property.length; index++) {
if (property[ index ] == OS.None) continue; // do not match atoms that do not exist
if (property[ index ] == gnome) {
if (gnome_init()) desktop = DESKTOP_GNOME;
}
if (property[ index ] == cde) {
if (cde_init( display )) desktop = DESKTOP_CDE;
}
if (property[ index ] == kde) {
if (kde_init()) desktop = DESKTOP_KDE;
}
}
// Save the desktop type on the display itself.
display.setData( desktopData, new Integer(desktop) );
return desktop;
}
/**
* Finds the program that is associated with an extension.
* The extension may or may not begin with a '.'.
*
* @param extension the program extension
* @return the program or nil
*
* @exception SWTError <ul>
* <li>ERROR_NULL_ARGUMENT when extension is null</li>
* </ul>
*/
public static Program findProgram (String extension) {
return findProgram( Display.getCurrent(), extension );
}
/*
* API: When support for multiple displays is added, this method will
* become public and the original method above can be deprecated.
*/
private static Program findProgram( Display display, String extension ) {
if (extension == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
if (extension.length () == 0) return null;
if (extension.charAt (0) != '.') extension = "." + extension;
String command = null;
String name = null;
int desktop = getDesktop( display );
Hashtable mimeInfo = null;
if (desktop == DESKTOP_KDE) mimeInfo = kde_getMimeInfo();
if (desktop == DESKTOP_GNOME) mimeInfo = gnome_getMimeInfo();
if (desktop == DESKTOP_CDE) mimeInfo = cde_getDataTypeInfo();
if (mimeInfo == null) return null;
// Find the data type matching the extension.
Iterator keys = mimeInfo.keySet().iterator();
while (name == null && keys.hasNext()) {
String mimeType = (String) keys.next();
Vector mimeExts = (Vector) mimeInfo.get( mimeType );
for (int index = 0; index < mimeExts.size(); index++){
if (extension.equals( mimeExts.elementAt( index ) )) {
name = mimeType;
}
}
}
if (name == null) return null;
// Get the corresponding command for the mime type.
if (desktop == DESKTOP_KDE) command = kde_getMimeTypeCommand( name );
if (desktop == DESKTOP_GNOME) command = gnome_getMimeValue( name, "open" );
if (desktop == DESKTOP_CDE) command = cde_getAction( name );
if (command == null) return null;
// Return the corresponding program.
Program program = new Program ();
program.name = name;
program.command = command;
program.extension = extension;
program.display = display;
return program;
}
/**
* Answer all program extensions in the operating system.
*
* @return an array of extensions
*/
public static String [] getExtensions () {
return getExtensions( Display.getCurrent() );
}
/*
* API: When support for multiple displays is added, this method will
* become public and the original method above can be deprecated.
*/
private static String[] getExtensions( Display display ) {
int desktop = getDesktop( display );
Hashtable mimeInfo = null;
if (desktop == DESKTOP_KDE) mimeInfo = kde_getMimeInfo();
if (desktop == DESKTOP_GNOME) mimeInfo = gnome_getMimeInfo();
if (desktop == DESKTOP_CDE) mimeInfo = cde_getDataTypeInfo();
if (mimeInfo == null) return new String[0];
// Create a unique set of the file extensions.
Vector extensions = new Vector();
Iterator keys = mimeInfo.keySet().iterator();
while (keys.hasNext()) {
String mimeType = (String) keys.next();
Vector mimeExts = (Vector) mimeInfo.get( mimeType );
for (int index = 0; index < mimeExts.size(); index++){
if (!extensions.contains( mimeExts.elementAt( index ) )) {
extensions.addElement( mimeExts.elementAt( index ) );
}
}
}
// Return the list of extensions.
String[] extStrings = new String[ extensions.size() ];
for (int index = 0; index < extensions.size(); index++) {
extStrings[ index ] = (String) extensions.elementAt( index );
}
return extStrings;
}
/**
* Answers all available programs in the operating system.
*
* @return an array of programs
*/
public static Program [] getPrograms () {
return getPrograms( Display.getCurrent() );
}
/*
* API: When support for multiple displays is added, this method will
* become public and the original method above can be deprecated.
*/
private static Program[] getPrograms( Display display ) {
int desktop = getDesktop( display );
Hashtable mimeInfo = null;
if (desktop == DESKTOP_KDE) mimeInfo = kde_getMimeInfo();
if (desktop == DESKTOP_GNOME) mimeInfo = gnome_getMimeInfo();
if (desktop == DESKTOP_CDE) mimeInfo = cde_getDataTypeInfo();
if (mimeInfo == null) return new Program[0];
// Create a list of programs with commands.
Vector programs = new Vector();
Iterator keys = mimeInfo.keySet().iterator();
while (keys.hasNext()) {
String mimeType = (String) keys.next();
Vector mimeExts = (Vector) mimeInfo.get( mimeType );
String extension = "";
if (mimeExts.size() > 0){
extension = (String) mimeExts.elementAt( 0 );
}
String command = null;
if (desktop == DESKTOP_KDE) command = kde_getMimeTypeCommand( mimeType );
if (desktop == DESKTOP_GNOME) command = gnome_getMimeValue( mimeType, "open" );
if (desktop == DESKTOP_CDE) command = cde_getAction( mimeType );
if (command != null) {
Program program = new Program ();
program.name = mimeType;
program.command = command;
program.extension = extension;
program.display = display;
programs.addElement( program );
}
}
// Return the list of programs to the user.
Program[] programList = new Program[ programs.size() ];
for (int index = 0; index < programList.length; index++) {
programList[ index ] = (Program) programs.elementAt( index );
}
return programList;
}
/*
* Obtain the registered mime type information and
* return it in a map. The key of each entry
* in the map is the mime type name. The value is
* a vector of the associated file extensions.
*/
private static Hashtable gnome_getMimeInfo() {
Hashtable mimeInfo = new Hashtable();
// Extract the mime info from the system directory.
String mimeDirectory = gnome_getDataDirectory ("mime-info");
gnome_getMimeInfoFromDirectory( mimeInfo, new File( mimeDirectory ) );
// Append the mime info from the user's directory (if it exists).
String userDirectory = gnome_getHomeDirectory();
if (userDirectory != null) {
userDirectory = userDirectory + File.separator + ".gnome" + File.separator + "mime-info";
gnome_getMimeInfoFromDirectory( mimeInfo, new File( userDirectory ) );
}
return mimeInfo;
}
// Given a map and a directory, find all of the
// mime information files (*.mime) and parse them for
// relavent mime type information. Each entry in the
// map corresponds to one mime type, and its
// associated file extensions.
private static void gnome_getMimeInfoFromDirectory( Hashtable info, File directory ) {
// For each entry in the given directory (if it exists)
if (directory.exists()) {
File[] files = directory.listFiles();
for (int i = 0; i < files.length; i++) {
// If the entry is a subdirectory, process it and
// merge the mime type into the given map.
if (files[i].isDirectory()) {
gnome_getMimeInfoFromDirectory( info, files[i] );
}
// else if the entry is a mime info file (*.mime)
else if (files[i].getName().endsWith(".mime")) {
try {
// Parse the mime file and merge the info
// into the given map.
FileReader in = new FileReader( files[i] );
BufferedReader reader = new BufferedReader( in );
gnome_parseMimeFile( info, reader );
reader.close();
in.close();
}
catch (IOException e) {
// Ignore file exceptions silently. If we
// can't read it, the info is not available.
}
}
}
}
}
private static void gnome_parseMimeFile( Hashtable info, BufferedReader reader ) {
Vector mimeExts = null;
String mimeType = null;
boolean saveType = false;
String line = "#";
while (line != null) {
// Determine if the line contains a mime type name.
boolean newType = (line.length() > 0 && Compatibility.isLetter( line.charAt(0) ));
// If there is valid data on this line to be processed
String data = line.trim();
if (data.length() > 0 && data.charAt(0) != '#') {
// If this line defines a new mime type
if (newType) {
// If a previous mime type has not be saved yet
if (mimeType != null) {
// Save the type and process this line again.
saveType = true;
}
// else initialize the mime type info
else {
int colon = data.indexOf( ':' );
if (colon != -1) {
mimeType = data.substring( 0, colon );
}
else {
mimeType = data;
}
mimeExts = new Vector();
}
}
// else if the line defines a list of extensions
else if (data.indexOf( "ext" ) == 0 && mimeType != null) {
// Get the extensions defined on the line
String exts = "";
int colon = data.indexOf( ':' );
if ((colon != -1) && ((colon+1) < data.length())) {
exts = data.substring( (colon+1) ).trim();
}
// While there are extensions to be processed (use space as separator)
exts = exts.replace( '\t', ' ' );
exts = exts.replace( ',', ' ' );
while (exts.length() != 0) {
// Extract the next entension from the list
String newExt;
int space = exts.indexOf( ' ' );
if (space != -1) {
newExt = exts.substring( 0, space );
exts = exts.substring( space ).trim();
}
else {
newExt = exts;
exts = "";
}
// Prefix an extension with a period.
if (newExt.charAt(0) != '.') {
newExt = "." + newExt;
}
mimeExts.addElement( newExt );
}
}
// else if the line defines a list of regular expressions
else if (data.indexOf( "regex" ) == 0 && mimeType != null) {
// Do nothing with these right now.
}
}
// If the current mime type is still being processed
if (!saveType) {
// Get the next line
try {
line = reader.readLine();
}
catch (IOException e) {
line = null;
}
}
// If the current type should be saved or if the end
// of the file was reached
if (saveType || (line == null)) {
// If there is a mime type to be saved
if (mimeType != null) {
// If the mime type does not exist in the map, add it.
Vector prevExts = (Vector) info.get( mimeType );
if (prevExts == null) {
info.put( mimeType, mimeExts );
}
// else append the new list of extensions.
else {
for (int i = 0; i < mimeExts.size(); i++) {
prevExts.add( mimeExts.elementAt( i ) );
}
}
}
mimeType = null;
mimeExts = null;
saveType = false;
}
}
}
// Private method for parsing a command line into its arguments.
private static String[] parseCommand( String cmd ) {
Vector args = new Vector();
int sIndex = 0;
int eIndex;
while (sIndex < cmd.length()) {
// Trim initial white space of argument.
while (sIndex < cmd.length() && Compatibility.isWhitespace( cmd.charAt(sIndex) )) {
sIndex++;
}
if (sIndex < cmd.length()) {
// If the command is a quoted string
if (cmd.charAt(sIndex) == '"' || cmd.charAt(sIndex) == '\''){
// Find the terminating quote (or end of line).
// This code currently does not handle escaped characters (e.g., " a\"b").
eIndex = sIndex + 1;
while (eIndex < cmd.length() && cmd.charAt(eIndex) != cmd.charAt(sIndex)) {
eIndex++;
}
if (eIndex >= cmd.length()) { // the terminating quote was not found
// Add the argument as is with only one initial quote.
args.addElement( cmd.substring( sIndex, eIndex ) );
}
// else add the argument, trimming off the quotes.
else {
args.addElement( cmd.substring( sIndex+1, eIndex ) );
}
sIndex = eIndex + 1;
}
// else use white space for the delimiters.
else {
eIndex = sIndex;
while (eIndex < cmd.length() && !Compatibility.isWhitespace( cmd.charAt(eIndex) )) {
eIndex++;
}
args.addElement( cmd.substring( sIndex, eIndex ) );
sIndex = eIndex + 1;
}
}
}
String[] strings = new String[ args.size() ];
for (int index =0; index < args.size(); index++) {
strings[ index ] = (String) args.elementAt( index );
}
return strings;
}
static String gnome_getDataDirectory(String dirName) {
/* Use the character encoding for the default locale */
byte [] nameBuffer = Converter.wcsToMbcs (null, dirName, true);
int ptr = GNOME.gnome_datadir_file(nameBuffer);
if (ptr == 0) return null;
int length = OS.strlen(ptr);
byte[] dirBuffer = new byte[length];
OS.memmove(dirBuffer, ptr, length);
/* Use the character encoding for the default locale */
return new String(Converter.mbcsToWcs(null, dirBuffer));
}
static String gnome_getHomeDirectory() {
int ptr = GNOME.g_get_home_dir();
if (ptr == 0) return null;
int length = OS.strlen(ptr);
byte[] homeDirBuffer = new byte[length];
OS.memmove(homeDirBuffer, ptr, length);
/* Use the character encoding for the default locale */
return new String(Converter.mbcsToWcs(null, homeDirBuffer));
}
static String gnome_getMimeType(String name) {
/* Use the character encoding for the default locale */
byte [] nameBuffer = Converter.wcsToMbcs (null, name, true);
int ptr = GNOME.gnome_mime_type(nameBuffer);
if (ptr == 0) return null;
int length = OS.strlen(ptr);
byte[] mimeBuffer = new byte[length];
OS.memmove(mimeBuffer, ptr, length);
/* Use the character encoding for the default locale */
return new String(Converter.mbcsToWcs(null, mimeBuffer));
}
static String gnome_getMimeValue(String mimeType, String key) {
/* Use the character encoding for the default locale */
byte [] typeBuffer = Converter.wcsToMbcs (null, mimeType, true);
byte [] keyBuffer = Converter.wcsToMbcs (null, key, true);
int ptr = GNOME.gnome_mime_get_value(typeBuffer, keyBuffer);
if (ptr == 0) return null;
StringBuffer stringBuffer = new StringBuffer();
int length = OS.strlen(ptr);
byte[] valueBuffer = new byte[length];
OS.memmove(valueBuffer, ptr, length);
/* Use the character encoding for the default locale */
return new String(Converter.mbcsToWcs(null, valueBuffer));
}
static boolean kde_init () {
/* TEMPORARY CODE */
if (true) return false;
try {
Callback.loadLibrary("swt-kde");
} catch (SWTError e) {
return false;
}
/* Use the character encoding for the default locale */
byte [] nameBuffer = Converter.wcsToMbcs( null, "SWT", true );
int qcString = KDE.QCString_new( nameBuffer );
KDE.KApplication_new( qcString );
KDE.QCString_delete( qcString );
return true;
}
private static String kde_getMimeTypeCommand( String mimeType ) {
/* Use the character encoding for the default locale */
byte [] buffer = Converter.wcsToMbcs (null, mimeType, true);
int qMimeType = KDE.QString_new( buffer );
int serviceList = KDE.KMimeType_offers( qMimeType );
KDE.QString_delete( qMimeType );
if (serviceList == 0) return null;
KDE.KServiceList_delete( serviceList );
return "KRun::runURL(url,mimeType)";
}
/*
* Obtain the registered mime type information and
* return it in a map. The key of each entry
* in the map is the mime type name. The value is
* a vector of the associated file extensions.
*/
private static Hashtable kde_getMimeInfo() {
Hashtable mimeInfo = new Hashtable();
Vector mimeExts = null;
String mimeType;
// Get the list of all mime types available.
int mimeTypeList = KDE.KMimeType_allMimeTypes();
int iterator = KDE.KMimeTypeList_begin( mimeTypeList );
int listEnd = KDE.KMimeTypeList_end( mimeTypeList );
while (KDE.KMimeTypeListIterator_equals( iterator, listEnd ) == 0) {
// Get the next KMimeType from the list.
int kMimeType = KDE.KMimeTypeListIterator_dereference( iterator );
// Get the mime type name.
int mimeName = KDE.KMimeType_name( kMimeType );
mimeType = kde_convertQStringAndFree( mimeName );
// Get the list of extension patterns.
mimeExts = new Vector();
String extension;
// Add the mime type to the hash table with its extensions.
int patternList = KDE.KMimeType_patterns( kMimeType );
int patIterator = KDE.QStringList_begin( patternList );
int patListEnd = KDE.QStringList_end( patternList );
while (KDE.QStringListIterator_equals( patIterator, patListEnd ) == 0) {
// Get the next extension pattern from the list.
int patString = KDE.QStringListIterator_dereference( patIterator );
extension = kde_convertQStringAndFree( patString );
int period = extension.indexOf( '.' );
if (period != -1) {
mimeExts.addElement( extension.substring( period ) );
}
// Advance to the next pattern.
KDE.QStringListIterator_increment( patIterator );
}
KDE.QStringListIterator_delete( patIterator );
KDE.QStringListIterator_delete( patListEnd );
KDE.QStringList_delete( patternList );
// If there is at least one extension, save the mime type.
if (mimeExts.size() > 0) {
mimeInfo.put( mimeType, mimeExts );
}
// Advance to the next mime type.
KDE.KMimeTypeListIterator_increment( iterator );
}
KDE.KMimeTypeListIterator_delete( iterator );
KDE.KMimeTypeListIterator_delete( listEnd );
KDE.KMimeTypeList_delete( mimeTypeList );
return mimeInfo;
}
static String kde_convertQStringAndFree (int qString) {
int qCString = KDE.QString_utf8 (qString);
int charString = KDE.QCString_data (qCString);
StringBuffer stringBuffer = new StringBuffer ();
int length = KDE.strlen (charString);
byte[] buffer = new byte [length];
KDE.memmove (buffer, charString, length);
/* Use the character encoding for the default locale */
String answer = new String (Converter.mbcsToWcs (null, buffer));
KDE.QCString_delete (qCString);
KDE.QString_delete (qString);
return answer;
}
/**
* Launches the executable associated with the file in
* the operating system. If the file is an executable,
* then the executable is launched.
*
* @param fileName the file or program name
* @return <code>true</code> if the file is launched, otherwise <code>false</code>
*
* @exception SWTError <ul>
* <li>ERROR_NULL_ARGUMENT when fileName is null</li>
* </ul>
*/
public static boolean launch (String fileName) {
return launch( Display.getCurrent(), fileName );
}
/*
* API: When support for multiple displays is added, this method will
* become public and the original method above can be deprecated.
*/
private static boolean launch( Display display, String fileName ) {
if (fileName == null) SWT.error( SWT.ERROR_NULL_ARGUMENT );
// If the argument appears to be a data file (it has an extension)
int index = fileName.lastIndexOf('.');
if (index > 0) {
// Find the associated program, if one is defined.
String extension = fileName.substring( index );
Program program = Program.findProgram( display, extension );
// If the associated program is defined and can be executed, return.
if (program != null && program.execute( fileName )) return true;
}
// Otherwise, the argument was the program itself.
try {
Compatibility.exec(fileName);
return true;
} catch (IOException e) {
return false;
}
}
/**
* Executes the program with the file as the single argument
* in the operating system. It is the responsibility of the
* programmer to ensure that the file contains valid data for
* this program.
*
* @param fileName is the argument (typically a file) for the program
* @return <code>true</code> if the file is launched, otherwise <code>false</code>
*
* @exception SWTError <ul>
* <li>ERROR_NULL_ARGUMENT when fileName is null</li>
* </ul>
*/
public boolean execute (String fileName) {
if (fileName == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
switch (getDesktop( display )) {
case DESKTOP_KDE: {
String urlString = "file://" + fileName;
/* Use the character encoding for the default locale */
byte[] buffer = Converter.wcsToMbcs( null, urlString, true );
int qString = KDE.QString_new( buffer );
int url = KDE.KURL_new( qString );
KDE.QString_delete( qString );
/* Use the character encoding for the default locale */
buffer = Converter.wcsToMbcs (null, name, true);
int mimeTypeName = KDE.QString_new( buffer );
int pid = KDE.KRun_runURL( url, mimeTypeName );
KDE.KURL_delete( url );
KDE.QString_delete( mimeTypeName );
return (pid != 0);
}
case DESKTOP_GNOME: {
// Parse the command into its individual arguments.
String[] args = parseCommand( command );
int fileArg = -1;
int index;
for (index=0; index < args.length; index++) {
int j = args[ index ].indexOf( "%f" );
if (j != -1) {
String value = args[ index ];
fileArg = index;
args[ index ] = value.substring(0,j) + fileName + value.substring(j+2);
}
}
// If a file name was given but the command did not have "%f"
if ((fileName.length() > 0) && (fileArg < 0)) {
String[] newArgs = new String[ args.length + 1 ];
for (index=0; index < args.length; index++)
newArgs[ index ] = args[ index ];
newArgs[ args.length ] = fileName;
args = newArgs;
}
// Execute the command.
try {
Compatibility.exec(args);
} catch (IOException e) {
return false;
}
return true;
}
case DESKTOP_CDE: {
/* Use the character encoding for the default locale */
byte[] action = Converter.wcsToMbcs( null, command, true );
byte[] fileArg = Converter.wcsToMbcs( null, fileName, true );
Integer shell = (Integer) display.getData( cdeShell );
int actionID = 0;
if (shell != null) {
actionID = CDE.DtActionInvoke( shell.intValue(), action, fileArg, 1, null, null, null, 1, 0, 0 );
}
return (actionID != 0);
}
}
return false;
}
/**
* Returns the receiver's image data. This is the icon
* that is associated with the reciever in the operating
* system.
*
* @return the image data for the program, may be null
*/
public ImageData getImageData () {
String iconPath = null;
switch (getDesktop( display )) {
case DESKTOP_KDE: {
/* Use the character encoding for the default locale */
byte [] buffer = Converter.wcsToMbcs (null, name, true);
int mimeTypeName = KDE.QString_new( buffer );
int mimeType = KDE.KMimeType_mimeType( mimeTypeName );
KDE.QString_delete( mimeTypeName );
if (mimeType == 0) return null;
int mimeIcon = KDE.KMimeType_icon(mimeType, 0, 0);
int loader = KDE.KGlobal_iconLoader();
int path = KDE.KIconLoader_iconPath(loader, mimeIcon, KDE.KICON_SMALL, 1);
if (path == 0) return null;
iconPath = kde_convertQStringAndFree(path);
break;
}
case DESKTOP_GNOME: {
String fakeFileName = "file" + extension;
String mime = gnome_getMimeType(fakeFileName);
if (mime == null) return null;
iconPath = gnome_getMimeValue(mime, "icon-filename");
if (iconPath == null) return null;
break;
}
case DESKTOP_CDE: {
return cde_getImageData();
}
case DESKTOP_UNKNOWN: {
return null;
}
}
if (iconPath.endsWith ("xpm")) {
int xDisplay = display.xDisplay;
int screen = OS.XDefaultScreenOfDisplay( xDisplay );
int fgPixel = OS.XWhitePixel( display.xDisplay, OS.XDefaultScreen( xDisplay ) );
int bgPixel = OS.XBlackPixel( display.xDisplay, OS.XDefaultScreen( xDisplay ) );
/* Use the character encoding for the default locale */
byte [] iconName = Converter.wcsToMbcs (null, iconPath, true);
int pixmap = OS.XmGetPixmap( screen, iconName, fgPixel, bgPixel );
if (pixmap == OS.XmUNSPECIFIED_PIXMAP) return null;
Image image = Image.motif_new (display, SWT.BITMAP, pixmap, 0);
ImageData imageData = image.getImageData ();
// The pixmap returned from XmGetPixmap is cached by Motif
// and must be deleted by XmDestroyPixmap. Because it cannot
// be deleted directly by XFreePixmap, image.dispose() must not
// be called. The following code should do an equivalent image.dispose().
OS.XmDestroyPixmap( screen, pixmap );
return imageData;
}
try {
return new ImageData (iconPath);
} catch (Exception e) {
return null;
}
}
/**
* Returns the receiver's name. This is as short and
* descriptive a name as possible for the program. If
* the program has no descriptive name, this string may
* be the executable name, path or empty.
*
* @return an the name of the program
*/
public String getName () {
return name;
}
/**
* Returns true if the receiver and the argument represent
* the same program.
*
* @return true if the programs are the same
*/
public boolean equals(Object other) {
if (this == other) return true;
if (other instanceof Program) {
final Program program = (Program) other;
return display == program.display && extension.equals(program.extension) &&
name.equals(program.name) && command.equals(program.command);
}
return false;
}
/**
* Returns a hash code suitable for this object.
*
* @return a hash code
*/
public int hashCode() {
return extension.hashCode() ^ name.hashCode() ^ command.hashCode() ^ display.hashCode();
}
public String toString () {
return "Program {" + name + "}";
}
static boolean gnome_init () {
try {
Callback.loadLibrary("swt-gnome");
} catch (SWTError e) {
return false;
}
return true;
}
/* CDE - Get Attribute Value
*
* This method takes a data type name and an attribute name, and returns
* the corresponding attribute value.
*/
static String cde_getAttribute(String dataType, String attrName) {
/* Use the character encoding for the default locale */
byte [] dataTypeBuf = Converter.wcsToMbcs (null, dataType, true);
byte [] attrNameBuf = Converter.wcsToMbcs (null, attrName, true);
byte [] optNameBuf = null;
int attrValue = CDE.DtDtsDataTypeToAttributeValue( dataTypeBuf, attrNameBuf, optNameBuf );
if (attrValue == 0) return null;
int length = OS.strlen(attrValue);
byte[] attrValueBuf = new byte[length];
OS.memmove(attrValueBuf, attrValue, length);
CDE.DtDtsFreeAttributeValue( attrValue );
/* Use the character encoding for the default locale */
return new String(Converter.mbcsToWcs(null, attrValueBuf));
}
/* CDE - Get Default Action of Data Type
*
* This method takes a data type and returns the corresponding default action.
* By default, the "Open" action is used if it is available. If it is not
* available, the first action in the list is used. Typically, if Open is not
* available, there is usually only one action anyways.
*/
static String cde_getAction(String dataType) {
String action = null;
String actions = cde_getAttribute( dataType, CDE.DtDTS_DA_ACTION_LIST );
if (actions != null) {
int index = actions.indexOf( "Open" );
if (index != -1) {
action = actions.substring( index, index+4 );
}
else {
index = actions.indexOf( "," );
if (index != -1) {
action = actions.substring( 0, index );
}
else {
action = actions;
}
}
}
return action;
}
/* CDE - Get Extension of Data Type
*
* This method takes a data type and returns the corresponding extension.
* The extension is obtained from the NAME TEMPLATE attribute.
*/
static String cde_getExtension(String dataType) {
String fileExt = cde_getAttribute( dataType, CDE.DtDTS_DA_NAME_TEMPLATE );
if (fileExt == null || fileExt.indexOf( "%s." ) == -1) return null;
int dot = fileExt.indexOf( "." );
return fileExt.substring( dot );
}
/* CDE - Get Data Types
*
* This method returns the list of data type names available.
* Each data type returned is valid, meaning it has an action and
* an extension.
*/
static Hashtable cde_getDataTypeInfo() {
Hashtable dataTypeInfo = new Hashtable();
int index;
int dataTypeList = CDE.DtDtsDataTypeNames();
if (dataTypeList != 0) {
// For each data type name in the list
index = 0;
int dataType = CDE.listElementAt( dataTypeList, index++ );
while (dataType != 0) {
int length = OS.strlen(dataType);
byte[] dataTypeBuf = new byte[length];
OS.memmove(dataTypeBuf, dataType, length);
/* Use the character encoding for the default locale */
String dataTypeName = new String(Converter.mbcsToWcs(null, dataTypeBuf));
// The data type is valid if it is not an action, and it has an extension and an action.
String extension = cde_getExtension( dataTypeName );
if (!CDE.DtDtsDataTypeIsAction( dataTypeBuf ) &&
extension != null && cde_getAction( dataTypeName ) != null) {
Vector exts = new Vector();
exts.addElement( extension );
dataTypeInfo.put( dataTypeName, exts );
}
dataType = CDE.listElementAt( dataTypeList, index++ );
}
CDE.DtDtsFreeDataTypeNames( dataTypeList );
}
return dataTypeInfo;
}
/* CDE - Get Image Data
*
* This method returns the image data of the icon associated with
* the data type. Since CDE supports multiple sizes of icons, several
* attempts are made to locate an icon of the desired size and format.
* CDE supports the sizes: tiny, small, medium and large. The best
* search order is medium, large, small and then tiny. Althoug CDE supports
* colour and monochrome bitmaps, only colour icons are tried. (The order is
* defined by the cdeIconExt and cdeMaskExt arrays above.)
*/
ImageData cde_getImageData() {
int xDisplay = display.xDisplay;
int screen = OS.XDefaultScreenOfDisplay( xDisplay );
int fgPixel = OS.XWhitePixel( display.xDisplay, OS.XDefaultScreen( xDisplay ) );
int bgPixel = OS.XBlackPixel( display.xDisplay, OS.XDefaultScreen( xDisplay ) );
String icon = cde_getAttribute( name, CDE.DtDTS_DA_ICON );
byte [] iconName;
byte [] maskName = null;
int pixmap = 0;
for (int index = 0; index < cdeIconExt.length && pixmap == 0; index++) {
/* Use the character encoding for the default locale */
iconName = Converter.wcsToMbcs (null, icon + cdeIconExt[ index ], true);
maskName = Converter.wcsToMbcs (null, icon + cdeMaskExt[ index ], true);
pixmap = OS.XmGetPixmap( screen, iconName, fgPixel, bgPixel );
if (pixmap == OS.XmUNSPECIFIED_PIXMAP) pixmap = 0;
}
if (pixmap != 0) {
int type = SWT.ICON;
// When creating the mask pixmap, do not use the screen's white and black
// pixel for the foreground and background respectively, because on some
// X servers (e.g., Solaris) pixel 0 is white and pixel 1 is black. Passing
// (screen, name, whitePixel, blackPixel, 1) to get the mask pixmap will
// result in an inverted mask. Instead explicitly use 1 (FG) and 0 (BG).
int mask = OS.XmGetPixmapByDepth( screen, maskName, 1, 0, 1 );
if (mask == OS.XmUNSPECIFIED_PIXMAP) {
type = SWT.BITMAP;
mask = 0;
}
Image image = Image.motif_new (display, type, pixmap, mask );
ImageData imageData = image.getImageData();
// The pixmaps returned from XmGetPixmap... are cached by Motif
// and must be deleted by XmDestroyPixmap. Because they cannot
// be deleted directly by XFreePixmap, image.dispose() must not
// be called. The following code should do an equivalent image.dispose().
OS.XmDestroyPixmap( screen, pixmap );
if (mask != 0) OS.XmDestroyPixmap( screen, mask );
return imageData;
}
return null;
}
/* CDE - Initialize
*
* This method loads the swt-cde library and initializes CDE itself.
* The shell created fo DtAppInitialize is kept for DtActionInvoke calls.
*/
static boolean cde_init( Display display ) {
try {
Callback.loadLibrary("swt-cde");
} catch (SWTError e) {
return false;
}
/* Use the character encoding for the default locale */
byte[] appName = Converter.wcsToMbcs( null, "SWT", true );
int xtContext = OS.XtDisplayToApplicationContext( display.xDisplay );
int widgetClass = OS.TopLevelShellWidgetClass();
int shell = OS.XtAppCreateShell( appName, appName, widgetClass, display.xDisplay, null, 0 );
boolean initOK = CDE.DtAppInitialize( xtContext, display.xDisplay, shell, appName, appName );
if (!initOK) {
OS.XtDestroyWidget( shell );
}
else {
CDE.DtDbLoad();
display.setData( cdeShell, new Integer(shell) );
display.disposeExec( new Runnable() {
public void run() {
// This logic assumes that when the corresponding display is
// being disposed, it must be the current one.
Integer shell = (Integer) Display.getCurrent().getData( cdeShell );
if (shell != null) {
OS.XtDestroyWidget( shell.intValue() );
}
}
});
}
return initOK;
}
}