/*
 * Copyright (c) 1995, 2004, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code 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 General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

#ifdef HEADLESS
    #error This file should not be included in headless library
#endif

#include "awt_p.h"
#include <Xm/AtomMgr.h>
#include <Xm/Protocols.h>
#include <sys/param.h>
#include <string.h>
#include <stdlib.h>
#include "awt_p.h"
#include "java_awt_FileDialog.h"
#include "java_awt_event_MouseWheelEvent.h"
#include "sun_awt_motif_MFileDialogPeer.h"
#include "sun_awt_motif_MComponentPeer.h"
#include "multi_font.h"

#include "awt_Component.h"

#include <jni.h>
#include <jni_util.h>
#include <Xm/FileSB.h>

#define MAX_DIR_PATH_LEN    1024

extern void Text_handlePaste(Widget w, XtPointer client_data, XEvent * event,
                             Boolean * cont);

extern struct MComponentPeerIDs mComponentPeerIDs;

extern AwtGraphicsConfigDataPtr
    copyGraphicsConfigToPeer(JNIEnv *env, jobject this);

/* fieldIDs for FileDialog fields and methods that may be accessed from C */
static struct FileDialogIDs {
    jfieldID mode;
    jfieldID file;
} fileDialogIDs;

/* the field to store the default search procedure */
static XmSearchProc DefaultSearchProc = NULL;

/* mouse wheel handler for scrolling */
void File_handleWheel(Widget w, XtPointer client_data, XEvent* event, Boolean* cont);

/*
 * Class:     java_awt_FileDialog
 * Method:    initIDs
 * Signature: ()V
 */

/* This function gets called from the static initializer for FileDialog.java
   to initialize the fieldIDs for fields that may be accessed from C */

JNIEXPORT void JNICALL
Java_java_awt_FileDialog_initIDs
  (JNIEnv *env, jclass cls)
{
    fileDialogIDs.mode = (*env)->GetFieldID(env, cls, "mode", "I");
    fileDialogIDs.file =
      (*env)->GetFieldID(env, cls, "file", "Ljava/lang/String;");

    DASSERT(fileDialogIDs.mode != NULL);
    DASSERT(fileDialogIDs.file != NULL);
}

/*
 * client_data is MFileDialogPeer instance pointer
 */
static void
FileDialog_OK(Widget w,
              void *client_data,
              XmFileSelectionBoxCallbackStruct * call_data)
{
    JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
    jobject this = (jobject) client_data;
    struct FrameData *fdata;
    char *file;
    jstring jstr;
    XmStringContext   stringContext;
    XmStringDirection direction;
    XmStringCharSet   charset;
    Boolean           separator;

    fdata = (struct FrameData *)JNU_GetLongFieldAsPtr(env,this,mComponentPeerIDs.pData);

    if ((*env)->EnsureLocalCapacity(env, 1) < 0)
        return;

    if (!XmStringInitContext(&stringContext, call_data->value))
        return;

    if (!XmStringGetNextSegment(stringContext, &file, &charset,
                                &direction, &separator))
        file = NULL;

    if (file == NULL)
        jstr = NULL;
    else
        jstr = JNU_NewStringPlatform(env, (const char *) file);

    if (jstr != 0) {
        JNU_CallMethodByName(env, NULL, this, "handleSelected",
                             "(Ljava/lang/String;)V", jstr);
        (*env)->DeleteLocalRef(env, jstr);
    }
    if ((*env)->ExceptionOccurred(env)) {
        (*env)->ExceptionDescribe(env);
        (*env)->ExceptionClear(env);
    }

    XmStringFreeContext(stringContext);
    if (file != NULL)
        XtFree(file);
}

/*
 * client_data is MFileDialogPeer instance pointer
 */
static void
FileDialog_CANCEL(Widget w,
                  void *client_data,
                  XmFileSelectionBoxCallbackStruct * call_data)
{
    JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
    jobject this = (jobject) client_data;
    struct FrameData *fdata;

    fdata = (struct FrameData *) JNU_GetLongFieldAsPtr(env,this,mComponentPeerIDs.pData);

    JNU_CallMethodByName(env, NULL, (jobject) client_data, "handleCancel", "()V");
    if ((*env)->ExceptionOccurred(env)) {
        (*env)->ExceptionDescribe(env);
        (*env)->ExceptionClear(env);
    }
}


/*
 * client_data is MFileDialogPeer instance pointer
 */
static void
FileDialog_quit(Widget w,
                XtPointer client_data,
                XtPointer call_data)
{
    JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);

    JNU_CallMethodByName(env, NULL, (jobject) client_data, "handleQuit", "()V");
    if ((*env)->ExceptionOccurred(env)) {
        (*env)->ExceptionDescribe(env);
        (*env)->ExceptionClear(env);
    }
}

static void
setDeleteCallback(jobject this, struct FrameData *wdata)
{
    Atom xa_WM_DELETE_WINDOW;
    Atom xa_WM_PROTOCOLS;

    XtVaSetValues(wdata->winData.shell,
                  XmNdeleteResponse, XmDO_NOTHING,
                  NULL);
    xa_WM_DELETE_WINDOW = XmInternAtom(XtDisplay(wdata->winData.shell),
                                       "WM_DELETE_WINDOW", False);
    xa_WM_PROTOCOLS = XmInternAtom(XtDisplay(wdata->winData.shell),
                                   "WM_PROTOCOLS", False);

    XmAddProtocolCallback(wdata->winData.shell,
                          xa_WM_PROTOCOLS,
                          xa_WM_DELETE_WINDOW,
                          FileDialog_quit, (XtPointer) this);
}

void
setFSBDirAndFile(Widget w, char *dir, char *file,
                 XmString *ffiles, int count)
{
    Widget textField, list;
    char dirbuf[MAX_DIR_PATH_LEN];
    XmString xim, item;
    size_t lastSelect;

    dirbuf[0] = (char) '\0';

    if (dir != NULL && strlen(dir) < MAX_DIR_PATH_LEN)
        strcpy(dirbuf, dir);

    /* -----> make sure dir ends in '/' */
    if (dirbuf[0] != (char) '\0') {
        if (dirbuf[strlen(dirbuf) - 1] != (char) '/')
            strcat(dirbuf, "/");
    } else {
        getcwd(dirbuf, MAX_DIR_PATH_LEN - 16);
        strcat(dirbuf, "/");
    }

    strcat(dirbuf, "[^.]*");
    xim = XmStringCreate(dirbuf, XmSTRING_DEFAULT_CHARSET);
    XtVaSetValues(w, XmNdirMask, xim, NULL);

    if (ffiles != NULL)
      XtVaSetValues(w,
                    XmNfileListItems, (count > 0) ? ffiles : NULL,
                    XmNfileListItemCount, count,
                    XmNlistUpdated, True, NULL);

    XmStringFree(xim);

    /*
     * Select the filename from the filelist if it exists.
     */

    textField = XmFileSelectionBoxGetChild(w, XmDIALOG_TEXT);
    list = XmFileSelectionBoxGetChild(w, XmDIALOG_LIST);

    if (textField != 0 && file != 0) {
        lastSelect = strlen(file);
        XtVaSetValues(textField, XmNvalue, file, NULL);
        XmTextFieldSetSelection(textField, 0, lastSelect, CurrentTime);

        item = XmStringCreateLocalized(file);
        XmListSelectItem(list, item, NULL);
        XmStringFree(item);
    }
}

static void
changeBackground(Widget w, void *bg)
{
    /*
    ** This is a work-around for bug 4325443, caused by motif bug 4345559,
    ** XmCombobox dosn't return all children, so give it some help ...
    */
    Widget grabShell;
    grabShell = XtNameToWidget(w, "GrabShell");
    if (grabShell != NULL) {
        awt_util_mapChildren(grabShell, changeBackground, 0, (void *) bg);
    }

    XmChangeColor(w, (Pixel) bg);
}

void
ourSearchProc(Widget w, XtPointer p) {
    JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
    struct FrameData *wdata;
    XtPointer peer;
    jobject this;
    jboolean res;
    char * dir = NULL;
    jstring dir_o;
    int32_t i, filecount = 0;
    XmString * filelist = NULL;
    jobjectArray nffiles = NULL;
    jclass clazz = NULL;
    jstring jfilename = NULL;
    char * cfilename = NULL;
    XmFileSelectionBoxCallbackStruct * vals = (XmFileSelectionBoxCallbackStruct *)p;

    XtVaGetValues(w, XmNuserData, &peer, NULL);
    this = (jobject)peer;
    if (JNU_IsNull(env, this) ) {
        return;
    }
    wdata = (struct FrameData *) JNU_GetLongFieldAsPtr(env,this,mComponentPeerIDs.pData);
    if (wdata == 0 ||
        wdata->winData.comp.widget == 0 ||
        wdata->winData.shell == 0 || p == NULL ) {
        return;
    }

    if ((*env)->EnsureLocalCapacity(env, 1) < 0) {
        return;
    }

    if (DefaultSearchProc != NULL) {
        /* Unmap the widget temporary. If it takes a long time to generate
           the list items some visual artifacts may be caused. However,
           we need to do this to have the widget that works as we expect.
         */
        XtSetMappedWhenManaged(w, False);
        /* Call the default Motif search procedure to take the
           native filtered file list.
         */
        DefaultSearchProc(w, vals);
        XtSetMappedWhenManaged(w, True);
        XtVaGetValues(w,
                      XmNlistItemCount, &filecount,
                      XmNlistItems, &filelist,
                      NULL);
        /* We need to construct the new String array to pass it to
           the Java code.
         */
        clazz = (*env)->FindClass(env, "java/lang/String");
        /* It is ok if filecount is 0. */
        nffiles = (*env)->NewObjectArray(env, filecount, clazz, NULL);
        if (JNU_IsNull(env, nffiles)) {
            nffiles = NULL;
            JNU_ThrowOutOfMemoryError(env, "OutOfMemoryError");
        } else {
            for (i = 0; i < filecount; i++) {
                DASSERT(filelist[i] != NULL);

                XmStringGetLtoR(filelist[i], XmFONTLIST_DEFAULT_TAG, &cfilename);
                jfilename = JNU_NewStringPlatform(env, cfilename);

                if (JNU_IsNull(env, jfilename)) {
                    XtFree(cfilename);
                    nffiles = NULL;
                    JNU_ThrowOutOfMemoryError(env, "OutOfMemoryError");
                    break;
                }

                (*env)->SetObjectArrayElement(env, nffiles, i, jfilename);

                (*env)->DeleteLocalRef(env, jfilename);
                XtFree(cfilename);
            }
        }
    }

    XmStringGetLtoR(vals->dir, XmFONTLIST_DEFAULT_TAG, &dir);
    dir_o = JNU_NewStringPlatform(env, dir);
    res = JNU_CallMethodByName(env, NULL, this,
                               "proceedFiltering",
                               "(Ljava/lang/String;[Ljava/lang/String;Z)Z",
                               dir_o, nffiles,
                               awt_currentThreadIsPrivileged(env)).z;

    if ((*env)->ExceptionOccurred(env)) {
        (*env)->ExceptionDescribe(env);
        (*env)->ExceptionClear(env);
    }

    XtVaSetValues(w,
                  XmNlistUpdated, res,
                  NULL);
    (*env)->DeleteLocalRef(env, dir_o);
    free(dir);
}

/*
 * Class:     sun_awt_motif_MFileDialogPeer
 * Method:    create
 * Signature: (Lsun/awt/motif/MComponentPeer;)V
 */
JNIEXPORT void JNICALL Java_sun_awt_motif_MFileDialogPeer_create
  (JNIEnv *env, jobject this, jobject parent)
{
    struct FrameData *fdata;
    struct CanvasData *wdata;
    int32_t argc;
#define MAX_ARGC 20
    Arg args[MAX_ARGC];
    Widget child, textField, dirList, fileList;
    XmString xim;
    Pixel bg;
    jobject target;
    jstring file;
    jobject globalRef = awtJNI_CreateAndSetGlobalRef(env, this);
    AwtGraphicsConfigDataPtr adata;
#ifndef NOMODALFIX
    extern void awt_shellPoppedUp(Widget shell, XtPointer c, XtPointer d);
    extern void awt_shellPoppedDown(Widget shell, XtPointer c, XtPointer d);
#endif NOMODALFIX

    target = (*env)->GetObjectField(env, this, mComponentPeerIDs.target);

    if (JNU_IsNull(env, parent) || JNU_IsNull(env, target)) {
        JNU_ThrowNullPointerException(env, "NullPointerException");
        return;
    }
    AWT_LOCK();

    adata = copyGraphicsConfigToPeer(env, this);

    wdata = (struct CanvasData *) JNU_GetLongFieldAsPtr(env,parent,mComponentPeerIDs.pData);

    fdata = ZALLOC(FrameData);
    JNU_SetLongFieldFromPtr(env,this,mComponentPeerIDs.pData,fdata);

    if (fdata == NULL) {
        JNU_ThrowOutOfMemoryError(env, "OutOfMemoryError");
        AWT_UNLOCK();
        return;
    }
    XtVaGetValues(wdata->comp.widget, XmNbackground, &bg, NULL);

    /*
     * XXX: this code uses FrameData but doesn't bother to init a lot
     * of its memebers.  This confuses the hell out of the code in
     * awt_TopLevel.c that gets passes such half-inited FrameData.
     */
    fdata->decor = MWM_DECOR_ALL;

    argc = 0;
    XtSetArg(args[argc], XmNmustMatch, False);
    argc++;
    XtSetArg(args[argc], XmNautoUnmanage, False);
    argc++;
    XtSetArg(args[argc], XmNbackground, bg);
    argc++;
    XtSetArg(args[argc], XmNvisual, adata->awt_visInfo.visual);
    argc++;
    XtSetArg(args[argc], XmNdialogStyle, XmDIALOG_FULL_APPLICATION_MODAL);
    argc++;
    XtSetArg (args[argc], XmNscreen,
              ScreenOfDisplay(awt_display, adata->awt_visInfo.screen));
    argc++;
    XtSetArg(args[argc], XmNuserData, (XtPointer)globalRef);
    argc++;
    XtSetArg(args[argc], XmNresizePolicy, XmRESIZE_NONE);
    argc++;

    XtSetArg(args[argc], XmNbuttonFontList,  getMotifFontList());
    argc++;
    XtSetArg(args[argc], XmNlabelFontList,   getMotifFontList());
    argc++;
    XtSetArg(args[argc], XmNtextFontList,    getMotifFontList());
    argc++;

    DASSERT(!(argc > MAX_ARGC));

    fdata->winData.comp.widget = XmCreateFileSelectionDialog(wdata->shell,
                                                             "",
                                                             args,
                                                             argc);
    fdata->winData.shell = XtParent(fdata->winData.comp.widget);
    awt_util_mapChildren(fdata->winData.shell, changeBackground, 0,
                         (void *) bg);
    child = XmFileSelectionBoxGetChild(fdata->winData.comp.widget,
                                       XmDIALOG_HELP_BUTTON);

    /* We should save a pointer to the default search procedure
       to do some things that we cannot do else. For instance,
       apply the native pattern.
     */
    XtVaGetValues(fdata->winData.comp.widget,
                  XmNfileSearchProc, &DefaultSearchProc,
                  NULL);
    XtVaSetValues(fdata->winData.comp.widget,
                  XmNfileSearchProc, ourSearchProc,
                  NULL);

    /*
     * Get textfield in FileDialog.
     */
    textField = XmFileSelectionBoxGetChild(fdata->winData.comp.widget,
                                           XmDIALOG_TEXT);
    if (child != NULL) {
        /*
         * Workaround for Bug Id 4415659.
         * If the dialog child is unmanaged before the dialog is managed,
         * the Motif drop site hierarchy may be broken if we associate
         * a drop target with the dialog before it is shown.
         */
        XtSetMappedWhenManaged(fdata->winData.shell, False);
        XtManageChild(fdata->winData.comp.widget);
        XtUnmanageChild(fdata->winData.comp.widget);
        XtSetMappedWhenManaged(fdata->winData.shell, True);
        XtUnmanageChild(child);
    }
    if (!awtJNI_IsMultiFont(env, awtJNI_GetFont(env, this))) {
        /* This process should not be done other than English language
           locale. */
        child = XmFileSelectionBoxGetChild(fdata->winData.comp.widget,
                                           XmDIALOG_DEFAULT_BUTTON);
        if (child != NULL) {
            XmString xim;

            switch ((*env)->GetIntField(env, target, fileDialogIDs.mode)) {
                case java_awt_FileDialog_LOAD:
                    xim = XmStringCreate("Open", "labelFont");
                    XtVaSetValues(child, XmNlabelString, xim, NULL);
                    XmStringFree(xim);
                    break;

                case java_awt_FileDialog_SAVE:
                    xim = XmStringCreate("Save", "labelFont");
                    XtVaSetValues(child, XmNlabelString, xim, NULL);
                    XmStringFree(xim);
                    break;

                default:
                    break;
            }
        }
    }
    XtAddCallback(fdata->winData.comp.widget,
                  XmNokCallback,
                  (XtCallbackProc) FileDialog_OK,
                  (XtPointer) globalRef);
    XtAddCallback(fdata->winData.comp.widget,
                  XmNcancelCallback,
                  (XtCallbackProc) FileDialog_CANCEL,
                  (XtPointer) globalRef);

#ifndef NOMODALFIX
    XtAddCallback(fdata->winData.shell,
                      XtNpopupCallback,
                      awt_shellPoppedUp,
                      NULL);
    XtAddCallback(fdata->winData.shell,
                      XtNpopdownCallback,
                      awt_shellPoppedDown,
                      NULL);
#endif NOMODALFIX

    setDeleteCallback(globalRef, fdata);

    if (textField != NULL)  {
        /*
         * Insert event handler to correctly process cut/copy/paste keys
         * such that interaction with our own clipboard mechanism will work
         * properly.
         *
         * The Text_handlePaste() event handler is also used by both
         * TextField/TextArea.
         */
        XtInsertEventHandler(textField,
                         KeyPressMask,
                         False, Text_handlePaste, (XtPointer) globalRef,
                         XtListHead);
    }

    /* To get wheel scrolling, we add an event handler to the directory list and
     * file list widgets to handle mouse wheels */
    dirList = XmFileSelectionBoxGetChild(fdata->winData.comp.widget, XmDIALOG_DIR_LIST);
    if (dirList != NULL) {
        XtAddEventHandler(dirList, ButtonPressMask, False, File_handleWheel,
                          (XtPointer) globalRef);
    }

    fileList = XmFileSelectionBoxGetChild(fdata->winData.comp.widget, XmDIALOG_LIST);
    if (fileList != NULL) {
        XtAddEventHandler(fileList, ButtonPressMask, False, File_handleWheel,
                          (XtPointer) globalRef);
    }

    file = (*env)->GetObjectField(env, target, fileDialogIDs.file);
    if (JNU_IsNull(env, file)) {
        setFSBDirAndFile(fdata->winData.comp.widget, ".", "", NULL, -1);
    } else {
        char *fileString;

        fileString = (char *) JNU_GetStringPlatformChars(env, file, NULL);
        setFSBDirAndFile(fdata->winData.comp.widget, ".", fileString, NULL, -1);
        JNU_ReleaseStringPlatformChars(env, file, (const char *) fileString);
    }
    AWT_UNLOCK();
}

/* Event handler for making scrolling happen when the mouse wheel is rotated */
void File_handleWheel(Widget w, XtPointer client_data, XEvent* event, Boolean* cont) {
    unsigned int btn;
    Widget scrolledWindow = NULL;

    /* only registered for ButtonPress, so don't need to check event type  */
    btn = event->xbutton.button;
    /* wheel up and wheel down show up as button 4 and 5, respectively */
    if (btn == 4 || btn == 5) {
        scrolledWindow = XtParent(w);
        if (scrolledWindow == NULL) {
            return;
        }
        awt_util_do_wheel_scroll(scrolledWindow,
                             java_awt_event_MouseWheelEvent_WHEEL_UNIT_SCROLL,
                             3,
                             btn == 4 ? -1 : 1);
    }
}


/*
 * Class:     sun_awt_motif_MFileDialogPeer
 * Method:    pReshape
 * Signature: (IIII)V
 */
JNIEXPORT void JNICALL Java_sun_awt_motif_MFileDialogPeer_pReshape
  (JNIEnv *env, jobject this, jint x, jint y, jint w, jint h)
{
    struct FrameData *wdata;

    AWT_LOCK();
    wdata = (struct FrameData *) JNU_GetLongFieldAsPtr(env,this,mComponentPeerIDs.pData);
    if (wdata == NULL || wdata->winData.shell == NULL) {
        JNU_ThrowNullPointerException(env, "NullPointerException");
        AWT_UNLOCK();
        return;
    }
    /* GES: AVH's hack from awt_util.c:
     * Motif ignores attempts to move a toplevel window to 0,0.
     * Instead we set the position to 1,1. The expected value is
     * returned by Frame.getBounds() since it uses the internally
     * held rectangle rather than querying the peer.
     */

    if ((x == 0) && (y == 0)) {
        XtVaSetValues(wdata->winData.shell, XmNx, 1, XmNy, 1, NULL);
    }
    XtVaSetValues(wdata->winData.shell,
                  XtNx, (XtArgVal) x,
                  XtNy, (XtArgVal) y,
                  NULL);

    AWT_FLUSH_UNLOCK();
}

/*
 * Class:     sun_awt_motif_MFileDialogPeer
 * Method:    pDispose
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_sun_awt_motif_MFileDialogPeer_pDispose
  (JNIEnv *env, jobject this)
{
    struct FrameData *wdata;

    AWT_LOCK();
    wdata = (struct FrameData *) JNU_GetLongFieldAsPtr(env,this,mComponentPeerIDs.pData);
    if (wdata == NULL ||
        wdata->winData.comp.widget == NULL ||
        wdata->winData.shell == NULL) {
        JNU_ThrowNullPointerException(env, "NullPointerException");
        AWT_UNLOCK();
        return;
    }
    XtUnmanageChild(wdata->winData.shell);
    awt_util_consumeAllXEvents(wdata->winData.shell);
    XtDestroyWidget(wdata->winData.shell);
    free((void *) wdata);
    JNU_SetLongFieldFromPtr(env,this,mComponentPeerIDs.pData,NULL);
    awtJNI_DeleteGlobalRef(env, this);

    AWT_UNLOCK();
}

/*
 * Class:     sun_awt_motif_MFileDialogPeer
 * Method:    pShow
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_sun_awt_motif_MFileDialogPeer_pShow
  (JNIEnv *env, jobject this)
{
    struct FrameData *wdata;
    XmString dirMask = NULL;

    AWT_LOCK();
    wdata = (struct FrameData *) JNU_GetLongFieldAsPtr(env,this,mComponentPeerIDs.pData);
    if (wdata == NULL ||
        wdata->winData.comp.widget == NULL ||
        wdata->winData.shell == NULL) {
        JNU_ThrowNullPointerException(env, "NullPointerException");
        AWT_UNLOCK();
        return;
    }
    XtManageChild(wdata->winData.comp.widget);

    AWT_FLUSH_UNLOCK();
}

/*
 * Class:     sun_awt_motif_MFileDialogPeer
 * Method:    pHide
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_sun_awt_motif_MFileDialogPeer_pHide
  (JNIEnv *env, jobject this)
{
    struct FrameData *wdata;

    AWT_LOCK();
    wdata = (struct FrameData *) JNU_GetLongFieldAsPtr(env,this,mComponentPeerIDs.pData);
    if (wdata == NULL ||
        wdata->winData.comp.widget == NULL ||
        wdata->winData.shell == NULL) {
        JNU_ThrowNullPointerException(env, "NullPointerException");
        AWT_UNLOCK();
        return;
    }
    if (XtIsManaged(wdata->winData.comp.widget)) {
        XtUnmanageChild(wdata->winData.comp.widget);
    }

    AWT_FLUSH_UNLOCK();
}

/*
 * Class:     sun_awt_motif_MFileDialogPeer
 * Method:    setFileEntry
 * Signature: (Ljava/lang/String;Ljava/lang/String;)V
 */
JNIEXPORT void JNICALL Java_sun_awt_motif_MFileDialogPeer_setFileEntry
  (JNIEnv *env, jobject this, jstring dir, jstring file, jobjectArray ffiles)
{
    struct ComponentData *cdata;
    char *cdir;
    char *cfile;
    char *cf;
    struct FrameData *wdata;
    int32_t length, i;
    XmString * files = NULL;
    jstring jf;

    AWT_LOCK();
    wdata = (struct FrameData *)
        JNU_GetLongFieldAsPtr(env,this,mComponentPeerIDs.pData);
    if (wdata == NULL || wdata->winData.comp.widget == NULL) {
        JNU_ThrowNullPointerException(env, "NullPointerException");
        return;
    }

    cdir = (JNU_IsNull(env, dir))
               ? NULL
               : (char *) JNU_GetStringPlatformChars(env, dir, NULL);

    cfile = (JNU_IsNull(env, file))
               ? NULL
               : (char *) JNU_GetStringPlatformChars(env, file, NULL);

    if (ffiles != NULL) {
        length = (*env)->GetArrayLength(env, ffiles);
        files = (XmString*)calloc(length, sizeof(XmString));

        for (i = 0; i < length; i++) {
            jf = (jstring)(*env)->GetObjectArrayElement(env, ffiles, i);
            cf = (char *) JNU_GetStringPlatformChars(env, jf, NULL);

            if ((*env)->GetStringLength(env, jf) == 0 && length == 1) {
              length = 0;
              files[0] = NULL;
            }
            else
              files[i] = XmStringCreateLocalized(cf);

            if (cf)
                JNU_ReleaseStringPlatformChars(env, jf, (const char *) cf);
        }

        setFSBDirAndFile(wdata->winData.comp.widget, (cdir) ? cdir : "",
                         (cfile) ? cfile : "", files, length);
        while(i > 0) {
            XmStringFree(files[--i]);
        }
        if (files != NULL) {
            free(files);
        }
    }
    else
      setFSBDirAndFile(wdata->winData.comp.widget, (cdir) ? cdir : "",
                       (cfile) ? cfile : "", NULL, -1);

    if (cdir) {
        JNU_ReleaseStringPlatformChars(env, dir, (const char *) cdir);
    }

    if (cfile) {
        JNU_ReleaseStringPlatformChars(env, file, (const char *) cfile);
    }

    AWT_FLUSH_UNLOCK();
}

static void
changeFont(Widget w, void *fontList)
{
    XtVaSetValues(w, XmNfontList, fontList, NULL);
}

/*
 * Class:     sun_awt_motif_MFileDialogPeer
 * Method:    setFont
 * Signature: (Ljava/awt/Font;)V
 */
JNIEXPORT void JNICALL Java_sun_awt_motif_MFileDialogPeer_setFont
  (JNIEnv *env, jobject this, jobject f)
{
    struct ComponentData *tdata;
    struct FontData *fdata;
    XmFontListEntry fontentry;
    XmFontList fontlist;
    char *err;

    if (JNU_IsNull(env, f)) {
        JNU_ThrowNullPointerException(env, "NullPointerException");
        return;
    }
    AWT_LOCK();
    fdata = awtJNI_GetFontData(env, f, &err);
    if (fdata == NULL) {
        JNU_ThrowInternalError(env, err);
        AWT_UNLOCK();
        return;
    }
    tdata = (struct ComponentData *) JNU_GetLongFieldAsPtr(env,this,mComponentPeerIDs.pData);
    if (tdata == NULL || tdata->widget == NULL) {
        JNU_ThrowNullPointerException(env, "NullPointerException");
        AWT_UNLOCK();
        return;
    }
    if (awtJNI_IsMultiFont(env, f)) {
        if (fdata->xfs == NULL) {
            fdata->xfs = awtJNI_MakeFontSet(env, f);
        }
        if (fdata->xfs != NULL) {
            fontentry = XmFontListEntryCreate("labelFont",
                                              XmFONT_IS_FONTSET,
                                              (XtPointer) (fdata->xfs));
            fontlist = XmFontListAppendEntry(NULL, fontentry);
            /*
             * Some versions of motif have a bug in
             * XmFontListEntryFree() which causes it to free more than it
             * should.  Use XtFree() instead.  See O'Reilly's
             * Motif Reference Manual for more information.
             */
            XmFontListEntryFree(&fontentry);
        } else {
            fontlist = XmFontListCreate(fdata->xfont, "labelFont");
        }
    } else {
        fontlist = XmFontListCreate(fdata->xfont, "labelFont");
    }

    if (fontlist != NULL) {
     /* setting the fontlist in the FileSelectionBox is not good enough --
        you have to set the resource for all the descendants individually */
        awt_util_mapChildren(tdata->widget, changeFont, 1, (void *)fontlist);
        XmFontListFree(fontlist);
    } else {
        JNU_ThrowNullPointerException(env, "NullPointerException");
    }

    AWT_UNLOCK();
}

/*
 * Class:     sun_awt_motif_MFileDialogPeer
 * Method:    insertReplaceFileDialogText
 * Signature: (Ljava/lang/String;)V
 */
JNIEXPORT void JNICALL Java_sun_awt_motif_MFileDialogPeer_insertReplaceFileDialogText
  (JNIEnv *env, jobject this, jstring l)
{
    struct ComponentData *cdata;
    char *cl;
    XmTextPosition start, end;
    Widget textField;
    jobject font;

    /*
     * Replaces the text in the FileDialog's textfield with the passed
     * string.
     */

    AWT_LOCK();
    cdata = (struct ComponentData *)
      JNU_GetLongFieldAsPtr(env,this,mComponentPeerIDs.pData);
    if (cdata == NULL || cdata->widget == NULL) {
        JNU_ThrowNullPointerException(env, "NullPointerException");
        AWT_UNLOCK();
        return;
    }

    textField = XmFileSelectionBoxGetChild(cdata->widget, XmDIALOG_TEXT);

    if (textField == NULL)  {
        JNU_ThrowNullPointerException(env, "Null TextField in FileDialog");
        AWT_UNLOCK();
        return;
    }

    font = awtJNI_GetFont(env, this);

    if (JNU_IsNull(env, l)) {
        cl = NULL;
    } else {
        /*
         * We use makePlatformCString() to convert unicode to EUC here,
         * although output only components (Label/Button/Menu..)
         * is not using make/allocCString() functions anymore.
         * Because Motif TextFiled widget does not support multi-font
         * compound string.
         */

        cl = (char *) JNU_GetStringPlatformChars(env, l, NULL);
    }

    if (!XmTextGetSelectionPosition(textField, &start, &end)) {
        start = end = XmTextGetInsertionPosition(textField);
    }
    XmTextReplace(textField, start, end, cl);

    if (cl != NULL && cl !="") {
        JNU_ReleaseStringPlatformChars(env, l, cl);
    }
    AWT_FLUSH_UNLOCK();
}
