Milán Major

netscape-revival

1 branch
Code

lib/libmocha/lm_applt.c

/* -*- Mode: C; tab-width: 8; tabs-indent-mode: t -*- */

/*
** Mocha reflection of applets in the current document
*/

/* Please leave outside of ifdef for windows precompiled headers */
#include "lm.h"

#ifdef JAVA

#include "xp.h"
#include "layout.h"
#include "java.h"
#include "lj.h"		/* for LJ_InvokeMethod */
#define IMPLEMENT_netscape_applet_MozillaAppletContext
#ifdef XP_MAC
#include "n_applet_MozillaAppletContext.h"
#else
#include "netscape_applet_MozillaAppletContext.h"
#endif
#include "mo_java.h"
#include "mocha.h"
#include "prlog.h"

enum applet_array_slot {
    APPLET_ARRAY_LENGTH = -1
};

static MochaPropertySpec applet_array_props[] = {
    {lm_length_str,     APPLET_ARRAY_LENGTH,    MDF_ENUMERATE | MDF_READONLY},
    {0}
};

typedef struct MochaAppletArray {
    MochaDecoder        *decoder;
    uint		length;
} MochaAppletArray;

static MochaBoolean
applet_array_get_property(MochaContext *mc, MochaObject *obj,
			  MochaSlot slot, MochaDatum *dp)
{
    MochaAppletArray *array = obj->data;
    MochaDecoder *decoder;
    MWContext *context;
    uint count;
    LO_JavaAppStruct *applet_data;

    decoder = array->decoder;
    context = decoder->window_context;

    if (!context) return MOCHA_TRUE;

    switch (slot) {
      case APPLET_ARRAY_LENGTH:
	count = LO_EnumerateApplets(context);
	if (count > array->length)
	    array->length = count;
        MOCHA_INIT_DATUM(mc, dp, MOCHA_NUMBER, u.fval, array->length);
	break;

      default:
	if (slot < 0) {
	    /* Don't mess with user-defined or method properties. */
	    return MOCHA_TRUE;
	}
	applet_data = LO_GetAppletByIndex(context, (uint)slot);
	if (applet_data) {
            MochaObject *mo = LM_ReflectApplet(context, applet_data,
                                               (uint)slot);
            MOCHA_INIT_DATUM(mc, dp, MOCHA_OBJECT, u.obj, mo);

            if ((uint)slot >= array->length)
                array->length = slot + 1;
	} else {
            MOCHA_ReportError(mc, "no applet with index %d\n");
            return MOCHA_FALSE;
        }
	break;
    }
    return MOCHA_TRUE;
}

static void
applet_array_finalize(MochaContext *mc, MochaObject *obj)
{
    MochaAppletArray *array = obj->data;

    LM_UNLINK_OBJECT(array->decoder, obj);
    MOCHA_free(mc, array);
}

static MochaClass applet_array_class = {
    "AppletArray",
    applet_array_get_property, applet_array_get_property, MOCHA_ListPropStub,
    MOCHA_ResolveStub, MOCHA_ConvertStub, applet_array_finalize
};

MochaObject *
lm_GetAppletArray(MochaDecoder *decoder)
{
    MochaContext *mc = decoder->mocha_context;
    MochaObject *obj;
    MochaAppletArray *array;

    obj = decoder->applets;
    if (obj)
	return obj;

    array = MOCHA_malloc(mc, sizeof *array);
    if (!array)
        return 0;
    array->decoder = decoder;
    array->length = 0;

    obj = MOCHA_NewObject(mc, &applet_array_class, array, 0, 0,
			  applet_array_props, 0);
    LM_LINK_OBJECT(decoder, obj, "applets");
    decoder->applets = MOCHA_HoldObject(mc, obj);
    return obj;
}

/* this calls MozillaAppletContext to reflect the applet by
 * calling into mocha... yow! */
static MochaObject *
lm_ReallyReflectApplet(MWContext *context, LO_JavaAppStruct *lo_applet)
{
    MochaObject *obj;
    MochaDecoder *decoder;
    MochaContext *mc;
    LJAppletData *ad;
    jref japplet;

    PR_LOG(Moja, debug, ("really reflect applet 0x%x\n", lo_applet));

    if ((obj = lo_applet->mocha_object))
        return obj;

    decoder = LM_GetMochaDecoder(context);
    if (!decoder)
	return 0;
    mc = decoder->mocha_context;

    /* set the element to something bad if we can't get the java obj */
    if (!MOCHA_JavaGlueEnabled()) {
        PR_LOG(Moja, debug, ("reflected applet 0x%x as null\n",
                             lo_applet));
        return lo_applet->mocha_object = lm_DummyObject;
    }

    ad = (LJAppletData *) lo_applet->session_data;

    if (ad) {
        /* XXX probably need some work here to get the MochaContext
         * which is used in the reflection callback, and store it
         * in lj_mozilla_ee for the duration */
        /* XXX actually, this should be done in LJ_InvokeMethod */
        /*
          MochaContext *saved_context = lj_mozilla_ee->mocha_context;
          lj_mozilla_ee->mocha_context = decoder->mocha_context
         */

        /* MozillaAppletContext.reflectApplet adds it to the array from java */
        japplet = LJ_InvokeMethod(
	    methodID_netscape_applet_MozillaAppletContext_reflectApplet_1,
	    ad->docID, ad);

        obj = MOCHA_ReflectJObjectToMObject(decoder->mocha_context,
                                            (HObject *)japplet);
        /*
          lj_mozilla_ee->mocha_context = saved_context;
         */

        PR_LOG(Moja, debug, ("reflected applet 0x%x (java 0x%x) to 0x%x ok\n",
                             lo_applet, japplet, obj));

        return lo_applet->mocha_object = obj;
    } else {
        PR_LOG(Moja, warn, ("failed to reflect applet 0x%x\n", lo_applet));
        return 0;
    }
}


/* XXX what happens if this is called before java starts up?
 * or if java is disabled? */

MochaObject *
LM_ReflectApplet(MWContext *context, LO_JavaAppStruct *applet_data,
                 uint index)
{
    MochaObject *obj, *array_obj, *outer_obj;
    MochaDecoder *decoder;
    MochaAppletArray *array;
    MochaDatum datum;
    MochaContext *mc;
    char *name;

    obj = applet_data->mocha_object;
    if (obj)
	return obj;

    decoder = LM_GetMochaDecoder(context);
    if (!decoder)
	return 0;
    mc = decoder->mocha_context;

    /* get the name */
    if (applet_data->attr_name) {
        char *tmp;
        PA_LOCK(tmp, char *, applet_data->attr_name);
        name = MOCHA_strdup(mc, tmp);
        PA_UNLOCK(applet_data->attr_name);
    } else {
        name = 0;
    }

    array_obj = lm_GetAppletArray(decoder);
    if (!array_obj) {
        obj = 0;
        goto out;
    }
    array = (MochaAppletArray *) array_obj->data;

    /* XXX should pass thru ReallyReflectApplet to whatever calls NewObject */
    outer_obj = decoder->active_form ? decoder->active_form : decoder->document;

    /* this function does the real work */
    obj = lm_ReallyReflectApplet(context, applet_data);

    if (!obj) {
        /* reflection failed.  this usually means that javascript tried
         * to talk to the applet before it was ready.  there's not much
         * we can do about it */

        MOCHA_ReportError(mc, "Can't reflect applet \"%s\": not loaded yet", 
                          name);
        obj = 0;
        goto out;
    }

    /* put it in the applet array */
    MOCHA_INIT_FULL_DATUM(mc, &datum, MOCHA_OBJECT, MDF_ENUMERATE|MDF_READONLY,
			  MOCHA_TAINT_IDENTITY, u.obj, obj);
    MOCHA_SetProperty(mc, decoder->applets, name, index, datum);
    if (index >= array->length)
	array->length = index + 1;

    /* put it in the document scope */
    if (name) {
        if (!MOCHA_DefineObject(mc, outer_obj, name, obj,
				MDF_ENUMERATE | MDF_READONLY)) {
            PR_LOG(Moja, warn, ("failed to define applet 0x%x as %s\n",
                                applet_data, name));
	    /* XXX remove it altogether? */
        }
	MOCHA_free(mc, name);
    }

    /* cache it in layout data structure XXX lm_ReallyReflectApplet did this */
    XP_ASSERT(applet_data->mocha_object == obj);

  out:
    LM_PutMochaDecoder(decoder);
    return obj;
}

MochaObject *
LM_ReflectNamedApplet(MWContext *context, lo_NameList *name_rec, uint index)
{
    return 0;
}

#endif /* JAVA */