Mercurial > projects > dwt-linux
diff dwt/program/Program.d @ 191:5db57b8ff1a9
Added Program
author | Frank Benoit <benoit@tionex.de> |
---|---|
date | Tue, 04 Mar 2008 00:42:45 +0100 |
parents | |
children | 3cb84407dc3e |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dwt/program/Program.d Tue Mar 04 00:42:45 2008 +0100 @@ -0,0 +1,944 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Port to the D programming language: + * Frank Benoit <benoit@tionex.de> + *******************************************************************************/ +module dwt.program.Program; + +import dwt.DWT; +import dwt.graphics.ImageData; +import dwt.internal.Compatibility; +import dwt.internal.Converter; +import dwt.internal.Library; +import dwt.internal.gtk.OS; +import dwt.widgets.Display; +import dwt.widgets.Event; +import dwt.widgets.Listener; +import dwt.dwthelper.utils; + +import tango.sys.SharedLib; +import tango.stdc.stringz; +import tango.core.Exception; +import tango.core.Array; +import tango.text.convert.Format; + +version( build ){ + pragma(link, "gnomeui-2" ); +} + +private extern(C) { + alias int GnomeIconLookupResultFlags; + alias int GnomeIconLookupFlags; + GnomeIconTheme *gnome_icon_theme_new (); + char *gnome_icon_lookup ( + GtkIconTheme *icon_theme, + void *thumbnail_factory, + char *file_uri, + char *custom_icon, + void *file_info, + char *mime_type, + GnomeIconLookupFlags flags, + GnomeIconLookupResultFlags *result); + int gnome_vfs_init(); + char* gnome_icon_theme_lookup_icon(GnomeIconTheme *theme,char *icon_name,int size, GnomeIconData **icon_data, int *base_size) ; + + alias void GnomeIconTheme; + alias void GnomeIconData; + + struct GnomeVFSMimeApplication{ + /*< public > */ + char *id; + char *name; + + /*< private > */ + char *command; + int can_open_multiple_files; + int expects_uris; + GList *supported_uri_schemes; + int requires_terminal; + + /* Padded to avoid future breaks in ABI compatibility */ + void * reserved1; + + void * priv; + } +} + +struct GNOME { + private static extern(C){ + enum { + GNOME_ICON_LOOKUP_FLAGS_NONE = 0, + GNOME_ICON_LOOKUP_FLAGS_EMBEDDING_TEXT = 1<<0, + GNOME_ICON_LOOKUP_FLAGS_SHOW_SMALL_IMAGES_AS_THEMSELVES = 1<<1, + GNOME_ICON_LOOKUP_FLAGS_ALLOW_SVG_AS_THEMSELVES = 1<<2 + } + enum { + GNOME_VFS_MAKE_URI_DIR_NONE = 0, + GNOME_VFS_MAKE_URI_DIR_HOMEDIR = 1 << 0, + GNOME_VFS_MAKE_URI_DIR_CURRENT = 1 << 1 + } + alias int GnomeVFSMakeURIDirs; + enum { + GNOME_VFS_OK, + GNOME_VFS_ERROR_NOT_FOUND, + GNOME_VFS_ERROR_GENERIC, + GNOME_VFS_ERROR_INTERNAL, + GNOME_VFS_ERROR_BAD_PARAMETERS, + GNOME_VFS_ERROR_NOT_SUPPORTED, + GNOME_VFS_ERROR_IO, + GNOME_VFS_ERROR_CORRUPTED_DATA, + GNOME_VFS_ERROR_WRONG_FORMAT, + GNOME_VFS_ERROR_BAD_FILE, + GNOME_VFS_ERROR_TOO_BIG, + GNOME_VFS_ERROR_NO_SPACE, + GNOME_VFS_ERROR_READ_ONLY, + GNOME_VFS_ERROR_INVALID_URI, + GNOME_VFS_ERROR_NOT_OPEN, + GNOME_VFS_ERROR_INVALID_OPEN_MODE, + GNOME_VFS_ERROR_ACCESS_DENIED, + GNOME_VFS_ERROR_TOO_MANY_OPEN_FILES, + GNOME_VFS_ERROR_EOF, + GNOME_VFS_ERROR_NOT_A_DIRECTORY, + GNOME_VFS_ERROR_IN_PROGRESS, + GNOME_VFS_ERROR_INTERRUPTED, + GNOME_VFS_ERROR_FILE_EXISTS, + GNOME_VFS_ERROR_LOOP, + GNOME_VFS_ERROR_NOT_PERMITTED, + GNOME_VFS_ERROR_IS_DIRECTORY, + GNOME_VFS_ERROR_NO_MEMORY, + GNOME_VFS_ERROR_HOST_NOT_FOUND, + GNOME_VFS_ERROR_INVALID_HOST_NAME, + GNOME_VFS_ERROR_HOST_HAS_NO_ADDRESS, + GNOME_VFS_ERROR_LOGIN_FAILED, + GNOME_VFS_ERROR_CANCELLED, + GNOME_VFS_ERROR_DIRECTORY_BUSY, + GNOME_VFS_ERROR_DIRECTORY_NOT_EMPTY, + GNOME_VFS_ERROR_TOO_MANY_LINKS, + GNOME_VFS_ERROR_READ_ONLY_FILE_SYSTEM, + GNOME_VFS_ERROR_NOT_SAME_FILE_SYSTEM, + GNOME_VFS_ERROR_NAME_TOO_LONG, + GNOME_VFS_ERROR_SERVICE_NOT_AVAILABLE, + GNOME_VFS_ERROR_SERVICE_OBSOLETE, + GNOME_VFS_ERROR_PROTOCOL_ERROR, + GNOME_VFS_ERROR_NO_MASTER_BROWSER, + GNOME_VFS_ERROR_NO_DEFAULT, + GNOME_VFS_ERROR_NO_HANDLER, + GNOME_VFS_ERROR_PARSE, + GNOME_VFS_ERROR_LAUNCH, + GNOME_VFS_ERROR_TIMEOUT, + GNOME_VFS_ERROR_NAMESERVER, + GNOME_VFS_ERROR_LOCKED, + GNOME_VFS_ERROR_DEPRECATED_FUNCTION, + GNOME_VFS_ERROR_INVALID_FILENAME, + GNOME_VFS_ERROR_NOT_A_SYMBOLIC_LINK, + GNOME_VFS_NUM_ERRORS + } + alias int GnomeVFSResult; + + enum { + GNOME_VFS_MIME_APPLICATION_ARGUMENT_TYPE_URIS, + GNOME_VFS_MIME_APPLICATION_ARGUMENT_TYPE_PATHS, + GNOME_VFS_MIME_APPLICATION_ARGUMENT_TYPE_URIS_FOR_NON_FILES + } + + alias GtkIconTheme GnomeIconTheme; + alias .gnome_icon_theme_lookup_icon gnome_icon_theme_lookup_icon; + alias .gnome_vfs_init gnome_vfs_init; + alias .gnome_icon_lookup gnome_icon_lookup; + alias .gnome_icon_theme_new gnome_icon_theme_new; + + + GnomeVFSMimeApplication * function ( char *mime_type ) gnome_vfs_mime_get_default_application; + char* function(char*, int ) gnome_vfs_make_uri_from_input_with_dirs; + GnomeVFSResult function( GnomeVFSMimeApplication*, GList*) gnome_vfs_mime_application_launch; + void function(GnomeVFSMimeApplication*) gnome_vfs_mime_application_free; + GList* function(char*) gnome_vfs_mime_get_extensions_list; + void function(GList*) gnome_vfs_mime_extensions_list_free; + void function(GList*) gnome_vfs_mime_registered_mime_type_list_free; + GnomeVFSResult function(char*) gnome_vfs_url_show; + char* function(char*) gnome_vfs_make_uri_from_input; + GList* function() gnome_vfs_get_registered_mime_types; + char* function(char*) gnome_vfs_mime_type_from_name; + } +} + +/** + * Instances of this class represent programs and + * their associated file extensions in the operating + * system. + */ +public final class Program { + char[] name; + char[] command; + char[] iconPath; + Display display; + + /* Gnome specific + * true if command expects a URI + * false if expects a path + */ + bool gnomeExpectUri; + + static int /*long*/ cdeShell; + + static const char[][] CDE_ICON_EXT = [ ".m.pm"[], ".l.pm", ".s.pm", ".t.pm" ]; + static const char[][] CDE_MASK_EXT = [ ".m_m.bm"[], ".l_m.bm", ".s_m.bm", ".t_m.bm" ]; + static const char[] DESKTOP_DATA = "Program_DESKTOP"; + static const char[] ICON_THEME_DATA = "Program_GNOME_ICON_THEME"; + static const int DESKTOP_UNKNOWN = 0; + static const int DESKTOP_GNOME = 1; + static const int DESKTOP_GNOME_24 = 2; + static const int DESKTOP_CDE = 3; + static const int PREFERRED_ICON_SIZE = 16; + +/** + * Prevents uninitialized instances from being created outside the package. + */ +this() { +} + +/* Determine the desktop for the given display. */ +static int getDesktop(Display display) { + if (display is null) return DESKTOP_UNKNOWN; + ValueWrapperInt desktopValue = cast(ValueWrapperInt)display.getData(DESKTOP_DATA); + if (desktopValue !is null) return desktopValue.value; + int desktop = DESKTOP_UNKNOWN; + + /* Get the list of properties on the root window. */ + void* xDisplay = OS.GDK_DISPLAY(); + uint rootWindow = OS.XDefaultRootWindow(xDisplay); + int numProp; + uint* propList = OS.XListProperties(xDisplay, rootWindow, &numProp); + uint[] property = new uint[numProp]; + if (propList !is null) { + property[ 0 .. numProp ] = propList[ 0 .. numProp ]; + OS.XFree(propList); + } + + /* + * Feature in Linux Desktop. There is currently no official way to + * determine whether the Gnome window manager or gnome-vfs is + * available. Earlier versions including Red Hat 9 and Suse 9 provide + * a documented Gnome specific property on the root window + * WIN_SUPPORTING_WM_CHECK. This property is no longer supported in newer + * versions such as Fedora Core 2. + * The workaround is to simply check that the window manager is a + * compliant one (property _NET_SUPPORTING_WM_CHECK) and to attempt to load + * our native library that depends on gnome-vfs. + */ + if (desktop is DESKTOP_UNKNOWN) { + char[] gnomeName = "_NET_SUPPORTING_WM_CHECK"; + int /*long*/ gnome = OS.XInternAtom(xDisplay, gnomeName.ptr, true); + if (gnome !is OS.None && gnome_init()) { + desktop = DESKTOP_GNOME; + int icon_theme = cast(int)GNOME.gnome_icon_theme_new(); + display.setData(ICON_THEME_DATA, new ValueWrapperInt(icon_theme)); + display.addListener(DWT.Dispose, new class(display) Listener { + Display display; + this( Display display ){ this.display = display; } + public void handleEvent(Event event) { + ValueWrapperInt gnomeIconTheme = cast(ValueWrapperInt)display.getData(ICON_THEME_DATA); + if (gnomeIconTheme is null) return; + display.setData(ICON_THEME_DATA, null); + /* + * Note. gnome_icon_theme_new uses g_object_new to allocate the + * data it returns. Use g_object_unref to free the pointer it returns. + */ + if (gnomeIconTheme.value !is 0) OS.g_object_unref( cast(void*)gnomeIconTheme.value); + } + }); + /* Check for libgnomevfs-2 version 2.4 */ + char[] buffer = "libgnomevfs-2.so.0"; + auto libgnomevfs = SharedLib.load(buffer ); + if (libgnomevfs !is null) { + buffer = "gnome_vfs_url_show"; + void* gnome_vfs_url_show = libgnomevfs.getSymbol( buffer.ptr ); + if (gnome_vfs_url_show !is null) { + desktop = DESKTOP_GNOME_24; + } + *cast(void**)&GNOME.gnome_vfs_mime_get_default_application = libgnomevfs.getSymbol( "gnome_vfs_mime_get_default_application" ); + *cast(void**)&GNOME.gnome_vfs_make_uri_from_input_with_dirs = libgnomevfs.getSymbol( "gnome_vfs_make_uri_from_input_with_dirs" ); + *cast(void**)&GNOME.gnome_vfs_mime_application_launch = libgnomevfs.getSymbol( "gnome_vfs_mime_application_launch" ); + *cast(void**)&GNOME.gnome_vfs_mime_application_free = libgnomevfs.getSymbol( "gnome_vfs_mime_application_free" ); + *cast(void**)&GNOME.gnome_vfs_url_show = libgnomevfs.getSymbol( "gnome_vfs_url_show" ); + *cast(void**)&GNOME.gnome_vfs_make_uri_from_input = libgnomevfs.getSymbol( "gnome_vfs_make_uri_from_input" ); + *cast(void**)&GNOME.gnome_vfs_get_registered_mime_types = libgnomevfs.getSymbol( "gnome_vfs_get_registered_mime_types" ); + *cast(void**)&GNOME.gnome_vfs_mime_get_extensions_list = libgnomevfs.getSymbol( "gnome_vfs_mime_get_extensions_list" ); + *cast(void**)&GNOME.gnome_vfs_mime_extensions_list_free = libgnomevfs.getSymbol( "gnome_vfs_mime_extensions_list_free" ); + *cast(void**)&GNOME.gnome_vfs_mime_registered_mime_type_list_free = libgnomevfs.getSymbol( "gnome_vfs_mime_registered_mime_type_list_free" ); + *cast(void**)&GNOME.gnome_vfs_mime_type_from_name = libgnomevfs.getSymbol( "gnome_vfs_mime_type_from_name" ); + } + } + } + +// PORTING CDE not supported +/+ + /* + * On CDE, the atom below may exist without DTWM running. If the atom + * below is defined, the CDE database exists and the available + * applications can be queried. + */ + if (desktop is DESKTOP_UNKNOWN) { + char[] cdeName = "_DT_SM_PREFERENCES"; + int /*long*/ cde = OS.XInternAtom(xDisplay, cdeName.ptr, true); + for (int index = 0; desktop is DESKTOP_UNKNOWN && index < property.length; index++) { + if (property[index] is OS.None) continue; /* do not match atoms that do not exist */ + if (property[index] is cde && cde_init(display)) desktop = DESKTOP_CDE; + } + } ++/ + + display.setData(DESKTOP_DATA, new ValueWrapperInt(desktop)); + return desktop; +} + +// PORTING CDE not supported +/+ +bool cde_execute(char[] fileName) { + /* Use the character encoding for the default locale */ + char* action = toStringz(command); + char* ptr = cast(char*)OS.g_malloc(fileName.length+1); + ptr[ 0 .. fileName.length ] = fileName; + ptr[ fileName.length ] = 0; + DtActionArg args = new DtActionArg(); + args.argClass = CDE.DtACTION_FILE; + args.name = ptr; + long actionID = CDE.DtActionInvoke(cdeShell, action, args, 1, null, null, null, 1, 0, 0); + OS.g_free(ptr); + return actionID !is 0; +} + +static char[] cde_getAction(char[] dataType) { + char[] action = null; + char[] actions = cde_getAttribute(dataType, CDE.DtDTS_DA_ACTION_LIST); + if (actions !is null) { + int index = actions.indexOf("Open"); + if (index !is -1) { + action = actions.substring(index, index + 4); + } else { + index = actions.indexOf(","); + action = index !is -1 ? actions.substring(0, index) : actions; + } + } + return action; +} + +static char[] cde_getAttribute(char[] dataType, char[] 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 /*long*/ attrValue = CDE.DtDtsDataTypeToAttributeValue(dataTypeBuf, attrNameBuf, optNameBuf); + if (attrValue is 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 char[](Converter.mbcsToWcs(null, attrValueBuf)); +} + +static char[][][ char[] ] cde_getDataTypeInfo() { + char[][][ char[] ] dataTypeInfo; + int index; + int /*long*/ dataTypeList = CDE.DtDtsDataTypeNames(); + if (dataTypeList !is 0) { + /* For each data type name in the list */ + index = 0; + int /*long*/ [] dataType = new int /*long*/ [1]; + OS.memmove(dataType, dataTypeList + (index++ * 4), 4); + while (dataType[0] !is 0) { + int length = OS.strlen(dataType[0]); + byte[] dataTypeBuf = new byte[length]; + OS.memmove(dataTypeBuf, dataType[0], length); + /* Use the character encoding for the default locale */ + char[] dataTypeName = new char[](Converter.mbcsToWcs(null, dataTypeBuf)); + + /* The data type is valid if it is not an action, and it has an extension and an action. */ + char[] extension = cde_getExtension(dataTypeName); + if (!CDE.DtDtsDataTypeIsAction(dataTypeBuf) && + extension !is null && cde_getAction(dataTypeName) !is null) { + char[][] exts; + exts ~= extension; + dataTypeInfo[ dataTypeName ] = exts; + } + OS.memmove(dataType, dataTypeList + (index++ * 4), 4); + } + CDE.DtDtsFreeDataTypeNames(dataTypeList); + } + + return dataTypeInfo; +} + +static char[] cde_getExtension(char[] dataType) { + char[] fileExt = cde_getAttribute(dataType, CDE.DtDTS_DA_NAME_TEMPLATE); + if (fileExt is null || fileExt.indexOf("%s.") is -1) return null; + int dot = fileExt.indexOf("."); + return fileExt.substring(dot); +} + +/** + * 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() { + // TODO + return null; +} + +static char[] cde_getMimeType(char[] extension) { + char[] mimeType = null; + char[][][ char[] ] mimeInfo = cde_getDataTypeInfo(); + if (mimeInfo is null) return null; + char[][] keys = mimeInfo.keys(); + int keyIdx = 0; + while (mimeType is null && keyIdx < keys.length ) { + char[] type = keys[ keyIdx ]; + char[][] mimeExts = mimeInfo[type]; + for (int index = 0; index < mimeExts.length; index++){ + if (extension.equals(mimeExts[index])) { + mimeType = type; + break; + } + } + keyIdx++; + } + return mimeType; +} + +static Program cde_getProgram(Display display, char[] mimeType) { + Program program = new Program(); + program.display = display; + program.name = mimeType; + program.command = cde_getAction(mimeType); + program.iconPath = cde_getAttribute(program.name, CDE.DtDTS_DA_ICON); + return program; +} + +static bool cde_init(Display display) { + try { + Library.loadLibrary("swt-cde"); + } catch (Throwable e) { + return false; + } + + /* Use the character encoding for the default locale */ + CDE.XtToolkitInitialize(); + int /*long*/ xtContext = CDE.XtCreateApplicationContext (); + int /*long*/ xDisplay = OS.GDK_DISPLAY(); + byte[] appName = Converter.wcsToMbcs(null, "CDE", true); + byte[] appClass = Converter.wcsToMbcs(null, "CDE", true); + int /*long*/ [] argc = [0]; + CDE.XtDisplayInitialize(xtContext, xDisplay, appName, appClass, 0, 0, argc, 0); + int /*long*/ widgetClass = CDE.topLevelShellWidgetClass (); + cdeShell = CDE.XtAppCreateShell (appName, appClass, widgetClass, xDisplay, null, 0); + CDE.XtSetMappedWhenManaged (cdeShell, false); + CDE.XtResizeWidget (cdeShell, 10, 10, 0); + CDE.XtRealizeWidget (cdeShell); + bool initOK = CDE.DtAppInitialize(xtContext, xDisplay, cdeShell, appName, appName); + if (initOK) CDE.DtDbLoad(); + return initOK; +} ++/ + +static char[][] parseCommand(char[] cmd) { + char[][] args; + 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) is '"' || cmd.charAt(sIndex) is '\'') { + /* 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) !is 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 ~= cmd.substring(sIndex, eIndex); + } else { + /* Add the argument, trimming off the quotes. */ + args ~= cmd.substring(sIndex + 1, eIndex); + } + sIndex = eIndex + 1; + } + else { + /* Use white space for the delimiters. */ + eIndex = sIndex; + while (eIndex < cmd.length && !Compatibility.isWhitespace( firstCodePoint( cmd[ eIndex .. $ ]))) eIndex++; + args ~= cmd.substring(sIndex, eIndex); + sIndex = eIndex + 1; + } + } + } + + char[][] strings = new char[][args.length]; + for (int index =0; index < args.length; index++) { + strings[index] = args[index]; + } + return strings; +} + +/** + * GNOME 2.4 - Execute the program for the given file. + */ +bool gnome_24_execute(char[] fileName) { + char* mimeTypeBuffer = toStringz(name); + auto ptr = GNOME.gnome_vfs_mime_get_default_application(mimeTypeBuffer); + char* fileNameBuffer = toStringz(fileName); + char* uri = GNOME.gnome_vfs_make_uri_from_input_with_dirs(fileNameBuffer, GNOME.GNOME_VFS_MAKE_URI_DIR_CURRENT); + GList* list = OS.g_list_append( null, uri); + int result = GNOME.gnome_vfs_mime_application_launch(ptr, list); + GNOME.gnome_vfs_mime_application_free(ptr); + OS.g_free(uri); + OS.g_list_free(list); + return result is GNOME.GNOME_VFS_OK; +} + +/** + * GNOME 2.4 - Launch the default program for the given file. + */ +static bool gnome_24_launch(char[] fileName) { + char* fileNameBuffer = toStringz(fileName); + char* uri = GNOME.gnome_vfs_make_uri_from_input_with_dirs(fileNameBuffer, GNOME.GNOME_VFS_MAKE_URI_DIR_CURRENT); + int result = GNOME.gnome_vfs_url_show(uri); + OS.g_free(uri); + return (result is GNOME.GNOME_VFS_OK); +} + +/** + * GNOME 2.2 - Execute the program for the given file. + */ +bool gnome_execute(char[] fileName) { + if (gnomeExpectUri) { + /* Convert the given path into a URL */ + char* fileNameBuffer = toStringz(fileName); + char* uri = GNOME.gnome_vfs_make_uri_from_input(fileNameBuffer); + if (uri !is null) { + fileName = fromStringz( uri ).dup; + OS.g_free(uri); + } + } + + /* Parse the command into its individual arguments. */ + char[][] args = parseCommand(command); + int fileArg = -1; + int index; + for (index = 0; index < args.length; index++) { + int j = args[index].indexOf("%f"); + if (j !is -1) { + char[] 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)) { + char[][] newArgs = new char[][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; +} + +/** + * GNOME - Get Image Data + * + */ +ImageData gnome_getImageData() { + if (iconPath is null) return null; + try { + return new ImageData(iconPath); + } catch (Exception e) {} + return null; +} + +/** + * GNOME - Get mime types + * + * 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. + */ +static char[][][ char[] ] gnome_getMimeInfo() { + char[][][ char[] ] mimeInfo; + GList* mimeList = GNOME.gnome_vfs_get_registered_mime_types(); + GList* mimeElement = mimeList; + while (mimeElement !is null) { + char* mimePtr = cast(char*) OS.g_list_data(mimeElement); + char[] mimeTypeBuffer = fromStringz(mimePtr).dup; + char[] mimeType = mimeTypeBuffer;//new char[](Converter.mbcsToWcs(null, mimeTypeBuffer)); + GList* extensionList = GNOME.gnome_vfs_mime_get_extensions_list(mimePtr); + if (extensionList !is null) { + char[][] extensions; + GList* extensionElement = extensionList; + while (extensionElement !is null) { + char* extensionPtr = cast(char*) OS.g_list_data(extensionElement); + char[] extensionBuffer = fromStringz(extensionPtr).dup; + char[] extension = extensionBuffer; + extension = '.' ~ extension; + extensions ~= extension; + extensionElement = OS.g_list_next(extensionElement); + } + GNOME.gnome_vfs_mime_extensions_list_free(extensionList); + if (extensions.length > 0) mimeInfo[ mimeType ] = extensions; + } + mimeElement = OS.g_list_next(mimeElement); + } + if (mimeList !is null) GNOME.gnome_vfs_mime_registered_mime_type_list_free(mimeList); + return mimeInfo; +} + +static char[] gnome_getMimeType(char[] extension) { + char[] mimeType = null; + char[] fileName = "swt" ~ extension; + char* extensionBuffer = toStringz(fileName); + char* typeName = GNOME.gnome_vfs_mime_type_from_name(extensionBuffer); + if (typeName !is null) { + mimeType = fromStringz(typeName).dup; + } + return mimeType; +} + +static Program gnome_getProgram(Display display, char[] mimeType) { + Program program = null; + char* mimeTypeBuffer = toStringz(mimeType); + GnomeVFSMimeApplication* ptr = GNOME.gnome_vfs_mime_get_default_application(mimeTypeBuffer); + if (ptr !is null) { + program = new Program(); + program.display = display; + program.name = mimeType; + GnomeVFSMimeApplication* application = ptr; + char[] buffer = fromStringz(application.command).dup; + program.command = buffer; + program.gnomeExpectUri = application.expects_uris is GNOME.GNOME_VFS_MIME_APPLICATION_ARGUMENT_TYPE_URIS; + + buffer = fromStringz( application.id) ~ \0; + ValueWrapperInt gnomeIconTheme = cast(ValueWrapperInt)display.getData(ICON_THEME_DATA); + char* icon_name = GNOME.gnome_icon_lookup( cast(GtkIconTheme*) gnomeIconTheme.value, null, null, buffer.ptr, null, mimeTypeBuffer, + GNOME.GNOME_ICON_LOOKUP_FLAGS_NONE, null); + char* path = null; + if (icon_name !is null) path = GNOME.gnome_icon_theme_lookup_icon(cast(GtkIconTheme*)gnomeIconTheme.value, icon_name, PREFERRED_ICON_SIZE, null, null); + if (path !is null) { + program.iconPath = fromStringz( path).dup; + OS.g_free(path); + } + if (icon_name !is null) OS.g_free(icon_name); + GNOME.gnome_vfs_mime_application_free(ptr); + } + return program; +} + +static bool gnome_init() { + return cast(bool) GNOME.gnome_vfs_init(); +} + +/** + * Finds the program that is associated with an extension. + * The extension may or may not begin with a '.'. Note that + * a <code>Display</code> must already exist to guarantee that + * this method returns an appropriate result. + * + * @param extension the program extension + * @return the program or <code>null</code> + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT when extension is null</li> + * </ul> + */ +public static Program findProgram(char[] 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. + */ +static Program findProgram(Display display, char[] extension) { + if (extension is null) DWT.error(DWT.ERROR_NULL_ARGUMENT); + if (extension.length is 0) return null; + if (extension.charAt(0) !is '.') extension = "." ~ extension; + int desktop = getDesktop(display); + char[] mimeType = null; + switch (desktop) { + case DESKTOP_GNOME_24: + case DESKTOP_GNOME: mimeType = gnome_getMimeType(extension); break; + //case DESKTOP_CDE: mimeType = cde_getMimeType(extension); break; + default: + } + if (mimeType is null) return null; + Program program = null; + switch (desktop) { + case DESKTOP_GNOME_24: + case DESKTOP_GNOME: program = gnome_getProgram(display, mimeType); break; + //case DESKTOP_CDE: program = cde_getProgram(display, mimeType); break; + default: + } + return program; +} + +/** + * Answer all program extensions in the operating system. Note + * that a <code>Display</code> must already exist to guarantee + * that this method returns an appropriate result. + * + * @return an array of extensions + */ +public static char[][] 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. + */ +static char[][] getExtensions(Display display) { + int desktop = getDesktop(display); + char[][][ char[] ] mimeInfo = null; + switch (desktop) { + case DESKTOP_GNOME_24: break; + case DESKTOP_GNOME: mimeInfo = gnome_getMimeInfo(); break; + //case DESKTOP_CDE: mimeInfo = cde_getDataTypeInfo(); break; + default: + } + if (mimeInfo is null) return new char[][0]; + + /* Create a unique set of the file extensions. */ + char[][] extensions; + char[][] keys = mimeInfo.keys; + int keyIdx = 0; + while ( keyIdx < keys.length ) { + char[] mimeType = keys[ keyIdx ]; + char[][] mimeExts = mimeInfo[mimeType]; + for (int index = 0; index < mimeExts.length; index++){ + if (!extensions.contains(mimeExts[index])) { + extensions ~= mimeExts[index]; + } + } + keyIdx++; + } + + /* Return the list of extensions. */ + char[][] extStrings = new char[][]( extensions.length ); + for (int index = 0; index < extensions.length; index++) { + extStrings[index] = extensions[index]; + } + return extStrings; +} + +/** + * Answers all available programs in the operating system. Note + * that a <code>Display</code> must already exist to guarantee + * that this method returns an appropriate result. + * + * @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. + */ +static Program[] getPrograms(Display display) { + int desktop = getDesktop(display); + char[][][ char[] ] mimeInfo = null; + switch (desktop) { + case DESKTOP_GNOME_24: break; + case DESKTOP_GNOME: mimeInfo = gnome_getMimeInfo(); break; + //case DESKTOP_CDE: mimeInfo = cde_getDataTypeInfo(); break; + default: + } + if (mimeInfo is null) return new Program[0]; + Program[] programs; + char[][] keys = mimeInfo.keys; + int keyIdx = 0; + while ( keyIdx < keys.length ) { + char[] mimeType = keys[ keyIdx ]; + Program program = null; + switch (desktop) { + case DESKTOP_GNOME: program = gnome_getProgram(display, mimeType); break; + //case DESKTOP_CDE: program = cde_getProgram(display, mimeType); break; + default: + } + if (program !is null) programs ~= program; + keyIdx++; + } + Program[] programList = new Program[programs.length]; + for (int index = 0; index < programList.length; index++) { + programList[index] = programs[index]; + } + return programList; +} + +/** + * Launches the executable associated with the file in + * the operating system. If the file is an executable, + * then the executable is launched. Note that a <code>Display</code> + * must already exist to guarantee that this method returns + * an appropriate result. + * + * @param fileName the file or program name + * @return <code>true</code> if the file is launched, otherwise <code>false</code> + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT when fileName is null</li> + * </ul> + */ +public static bool launch(char[] 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. + */ +static bool launch(Display display, char[] fileName) { + if (fileName is null) DWT.error (DWT.ERROR_NULL_ARGUMENT); + switch(getDesktop(display)) { + case DESKTOP_GNOME_24: + if (gnome_24_launch (fileName)) return true; + default: + int index = fileName.lastIndexOf('.'); + if (index !is -1) { + char[] extension = fileName.substring (index); + Program program = Program.findProgram (display, extension); + if (program !is null && program.execute (fileName)) return true; + } + break; + } + try { + Compatibility.exec (fileName); + return true; + } catch (IOException e) { + return false; + } +} + +/** + * Compares the argument to the receiver, and returns true + * if they represent the <em>same</em> object using a class + * specific comparison. + * + * @param other the object to compare with this object + * @return <code>true</code> if the object is the same as this object and <code>false</code> otherwise + * + * @see #hashCode() + */ +public override int opEquals(Object other) { + if (this is other) return true; + if (!(cast(Program)other)) return false; + Program program = cast(Program)other; + return display is program.display && name.equals(program.name) && command.equals(program.command); +} + +/** + * 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 the file or program name + * @return <code>true</code> if the file is launched, otherwise <code>false</code> + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT when fileName is null</li> + * </ul> + */ +public bool execute(char[] fileName) { + if (fileName is null) DWT.error(DWT.ERROR_NULL_ARGUMENT); + int desktop = getDesktop(display); + switch (desktop) { + case DESKTOP_GNOME_24: return gnome_24_execute(fileName); + case DESKTOP_GNOME: return gnome_execute(fileName); + //case DESKTOP_CDE: return cde_execute(fileName); + default: + } + return false; +} + +/** + * Returns the receiver's image data. This is the icon + * that is associated with the receiver in the operating + * system. + * + * @return the image data for the program, may be null + */ +public ImageData getImageData() { + switch (getDesktop(display)) { + case DESKTOP_GNOME_24: + case DESKTOP_GNOME: return gnome_getImageData(); + //case DESKTOP_CDE: return cde_getImageData(); + default: + } + 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 the name of the program + */ +public char[] getName() { + return name; +} + +/** + * Returns an integer hash code for the receiver. Any two + * objects that return <code>true</code> when passed to + * <code>equals</code> must return the same value for this + * method. + * + * @return the receiver's hash + * + * @see #equals(Object) + */ +public override hash_t toHash() { + return .toHash(name) ^ .toHash(command) ^ display.toHash(); +} + +/** + * Returns a string containing a concise, human-readable + * description of the receiver. + * + * @return a string representation of the program + */ +public char[] toString() { + return Format( "Program {{{}}", name ); +} +}