Milán Major

netscape-revival

1 branch
Code

lib/libjava/lj_embed.c

/* -*- Mode: C; tab-width: 4; -*- */

/* From mozilla */
#include "lj.h"
#include "client.h"
#include "structs.h"
#include "shist.h"
#include "fe_proto.h"
#include "libmocha.h"
#include "layout.h"

/* From nspr */
#include "prfile.h"
#include "prlog.h"
#include "prmem.h"
#include "prmon.h"

#include "oobj.h"
#include "interpreter.h"		/* for CLASSPATH() */

#define IMPLEMENT_netscape_applet_MozillaAppletContext
#ifndef XP_MAC
#include "netscape_applet_MozillaAppletContext.h"
#else
#include "n_applet_MozillaAppletContext.h"
#endif

extern PRLogModule NSJAVALog;

int lj_init_failed = 0;
int lj_java_enabled = 1;

#ifdef xDEBUG
static void
DumpArgs(LO_JavaAppStruct *java)
{
    int i;
    char *cp;

    fprintf(stderr, "<applet ");

    PA_LOCK(cp, char*, java->attr_code);
    fprintf(stderr, "code=%s ", cp ? cp : "NULL");
    PA_UNLOCK(java->attr_code);

    PA_LOCK(cp, char*, java->attr_codebase);
    fprintf(stderr, "codebase=%s ", cp ? cp : "NULL");
    PA_UNLOCK(java->attr_codebase);

    PA_LOCK(cp, char*, java->attr_archive);
    fprintf(stderr, "archive=%s ", cp ? cp : "NULL");
    PA_UNLOCK(java->attr_archive);

    PA_LOCK(cp, char*, java->attr_name);
    fprintf(stderr, "name=%s ", cp ? cp : "NULL");
    PA_UNLOCK(java->attr_name);

    fprintf(stderr, ">\n");

    for(i=0; i<java->param_cnt; i++)
    {
        if(java->param_names[i] && java->param_values[i])
        {
            fprintf(stderr, "<param name=%s value=%s>\n", java->param_names[i],
					java->param_values[i]);
        }
    }

    fprintf(stderr, "</applet>\n");
}
#endif

void
LJ_ReportJavaStartupError(MWContext* cx, int rv)
{
    char *s;
    switch (rv) {
      case LJ_INIT_NO_CLASSES:
		lj_init_failed = 1;
		s = PR_smprintf(
			"Unable to start a java applet: Can't find \"%s\" in your\n"
			"CLASSPATH. Read the release notes and install \"%s\"\n"
			"properly before restarting.\n\nCurrent value of CLASSPATH:\n%s\n",
			lj_zip_name, lj_zip_name, (CLASSPATH() ? CLASSPATH() : "<none>")); /* i18n */
		if (s) {
			FE_Alert(cx, s);
			free(s);
		}
        return;

      case LJ_INIT_VERSION_WRONG:
		lj_init_failed = 1;
		if (lj_bad_version == 0) {
			s = PR_smprintf(
				"Unable to start a java applet: the zip file is so old that it\n"
				"doesn't have a version number.\n");
		} else {
			s = PR_smprintf(
				"Unable to start a java applet: the version number for your\n"
				"classes is wrong. The version number found was %d. The correct\n"
				"version number is %d.\n",
				lj_bad_version,
				lj_correct_version);
		}
		if (s) {
			FE_Alert(cx, s);
			free(s);
		}
        return;

	  case LJ_INIT_FAILED_LAST_TIME:
	  case LJ_INIT_OK:
      default:
		return;
    }
}

void
LJ_CreateApplet(LO_JavaAppStruct *java, MWContext* cx)
{
    LJAppletData *ad;
    History_entry *history_element;
    int rv;

    if (lj_init_failed || !lj_java_enabled) return;

#ifdef xDEBUG
    if (PR_LOG_TEST(NSJAVA, warn)) {
		PR_LOG(NSJAVA, warn, ("LJ_CreateApplet called: "));
		DumpArgs(java);
    }
#endif

    /* Make sure that this applet has the required parameters */
    if (!java->attr_code) {
		/* Malformed tag. */
		/* XXX need to reflect error back to user */
		return;
    }

    /* Provide missing defaults */
    if (!java->width) java->width = 50;
    if (!java->height) java->height = 50;

    /* Start up the runtime; if that doesn't work we are hosed */
    rv = LJ_StartupJava();
	if (rv != LJ_INIT_OK) {
		LJ_ReportJavaStartupError(cx, rv);
		return;
	}

    /*
    ** Create the applet data object to hold the browser side applet
    ** state
    */
    ad = (LJAppletData*) calloc(1, sizeof(LJAppletData));
    if (!ad) {
        if (ad) free(ad);
        return;
    }

    ad->context = cx;
	ad->reloadMethod = NET_NORMAL_RELOAD;

    history_element = SHIST_GetCurrent(&cx->hist);
    if (history_element) {
		ad->docID = history_element->unique_id;
    } else {
		/*
		** XXX What to do? This can happen for instance when printing a
		** mail message that contains an applet.
		*/
		static int32 unique_number;
		ad->docID = --unique_number;
    }

    ad->mayscript = java->may_script;

    /*
    ** Record the parent context. On the java side of the world all of
    ** the applets for a particular parent context are kept aggregated in
    ** history order so that they can be destroyed when resources get
    ** tight
    */
    if (cx->is_grid_cell) {
		MWContext* ctxt = cx;
		while (ctxt->is_grid_cell)
			ctxt = ctxt->grid_parent;
		ad->parentContext = ctxt;
    } else {
		ad->parentContext = cx;
    }

    java->session_data = ad;
}

void 
LJ_Applet_getSize(LJAppletData* ad)
{
}

void
LJ_Applet_display(LJAppletData* ad, int iloc)
{
}

void
LJ_DeleteSessionData(MWContext* cx, void* sdata)
{
    LJAppletData* ad = (LJAppletData*)sdata;
    
    if (ad == NULL || lj_init_failed) return;
    if (cx != ad->context) return;

    FE_FreeJavaAppElement(ad->context, ad);
}

void
LJ_Applet_destroy(LJAppletData* ad)
{
    if (ad == NULL || lj_init_failed) return;

    PR_LOG(NSJAVA, warn, ("Destroy applet"));

    /* Don't check lj_java_enabled flag here because we need to
       be able to destroy an applet if we disable java and then
       leave a page that has an applet running */

    LJ_InvokeMethod(methodID_netscape_applet_MozillaAppletContext_destroyApplet_1,
					ad->docID, ad);
    ad->context = NULL;
    if (ad->documentURL) free(ad->documentURL);
    free(ad);
}

void
LJ_SetJavaEnabled(int onoff)
{
    if (!lj_init_failed && lj_java_enabled && !onoff) {
		/* Nuke the currently running applets */
		LJ_InvokeMethod(methodID_netscape_applet_MozillaAppletContext_destroyAll);
    }
    /*
    ** Don't actually turn it off until we've made it through the
    ** destroyAll, above.
    */
    lj_java_enabled = onoff;
}

Bool
LJ_GetJavaEnabled(void)
{
    if(lj_init_failed)
	   return FALSE;
	else
	  return lj_java_enabled;
}

/*******************************************************************************
 * Mozilla Events
 ******************************************************************************/

PR_LOG_DEFINE(Event);

typedef struct MozillaEvent_MochaOnLoad {
    MWContextEvent	ce;
    int             status;
} MozillaEvent_MochaOnLoad;

static void
lj_HandleEvent_MochaOnLoad(MozillaEvent_MochaOnLoad* e)
{
#ifdef MOCHA
  /* here we need only decrement the number of applets expected to load */
    int32 doc_id;
    lo_TopState *top_state;

    doc_id = XP_DOCID(e->ce.context);
    top_state = lo_FetchTopState(doc_id);
  
	/* only wait on applets if onload flag */
    if(top_state && top_state->mocha_has_onload
       && top_state->mocha_loading_applets_count) {
		top_state->mocha_loading_applets_count--;
		LM_SendLoadEvent(e->ce.context, LM_XFER_DONE);
    }
#endif /* MOCHA */
}

static void
lj_DestroyEvent_MochaOnLoad(MozillaEvent_MochaOnLoad* event)
{
    XP_FREE(event);
}

void
LJ_PostMochaOnLoad(MWContext* context,int status)
{
    MozillaEvent_MochaOnLoad* event = PR_NEW(MozillaEvent_MochaOnLoad);

	/* if unable to allocate event return, this could cause Navigator
	 * to hang on a page.
	 */
	if(event == NULL){
		/* make another attempt for the Mac */
		event = PR_NEW(MozillaEvent_MochaOnLoad);
		if(event == NULL)
			return;
	}

    PR_InitEvent(&event->ce.event,
				 (PRHandleEventProc)lj_HandleEvent_MochaOnLoad,
				 (PRDestroyEventProc)lj_DestroyEvent_MochaOnLoad);
    event->ce.context = context;
	event->status     = status;
    PR_PostEvent(mozilla_event_queue, &event->ce.event);
}

/******************************************************************************/


typedef struct MozillaEvent_ShowStatus {
    MWContextEvent	ce;
    const char*		statusMessage;	/* string freed by receiver */
} MozillaEvent_ShowStatus;

void PR_CALLBACK
lj_HandleEvent_ShowStatus(MozillaEvent_ShowStatus* e)
{
    FE_Progress(e->ce.context, e->statusMessage);
}

void PR_CALLBACK
lj_DestroyEvent_ShowStatus(MozillaEvent_ShowStatus* event)
{
    XP_FREE((char*)event->statusMessage);
    XP_FREE(event);
}

void
LJ_PostShowStatus(MWContext* context, const char* message)
{
    MozillaEvent_ShowStatus* event = PR_NEW(MozillaEvent_ShowStatus);
	if (event == NULL) return;
    PR_InitEvent(&event->ce.event,
				 (PRHandleEventProc)lj_HandleEvent_ShowStatus,
				 (PRDestroyEventProc)lj_DestroyEvent_ShowStatus);
    event->ce.context = context;
    event->statusMessage = strdup(message);
    PR_PostEvent(mozilla_event_queue, &event->ce.event);
}

/******************************************************************************/

typedef struct MozillaEvent_ShowDocument {
    MWContextEvent	ce;
    char*			url;	/* string freed by receiver */
    char*			addr;	/* string freed by receiver */
    char*			target;	/* string freed by receiver */
} MozillaEvent_ShowDocument;


void PR_CALLBACK
lj_HandleEvent_ShowDocument(MozillaEvent_ShowDocument* e)
{
    URL_Struct* url_s;
    MWContext* targetContext;
		
    url_s = NET_CreateURLStruct(e->url, NET_NORMAL_RELOAD);
    if (e->addr && url_s) {
        if (NET_SetURLIPAddressString(url_s, e->addr)) {
            /* out of memory */
            NET_FreeURLStruct(url_s);
            url_s = NULL;
        }
    }
    if (url_s == NULL)
		return;

    targetContext = XP_FindNamedContextInList(e->ce.context, e->target);
    if (targetContext == NULL) {
		targetContext = FE_MakeNewWindow(e->ce.context,
										 url_s, e->target, NULL);
		if (targetContext == NULL) {
			NET_FreeURLStruct(url_s);
			return;
		}
    }
	else
		FE_GetURL(targetContext, url_s);
}

void PR_CALLBACK
lj_DestroyEvent_ShowDocument(MozillaEvent_ShowDocument* event)
{
    XP_FREE((char*)event->url);
    XP_FREE((char*)event->addr);
    XP_FREE((char*)event->target);
    XP_FREE(event);
}

void
LJ_PostShowDocument(MWContext* context, char* url, char* addr, char* target)
{
    MozillaEvent_ShowDocument* event = PR_NEW(MozillaEvent_ShowDocument);
	if (event == NULL) return;
    PR_InitEvent(&event->ce.event,
				 (PRHandleEventProc)lj_HandleEvent_ShowDocument,
				 (PRDestroyEventProc)lj_DestroyEvent_ShowDocument);
    event->ce.context = context;
    event->url = strdup(url);
    event->addr = addr ? strdup(addr) : NULL;
    event->target = strdup(target);
    PR_PostEvent(mozilla_event_queue, &event->ce.event);
}

/******************************************************************************/

void
LJ_ProcessEvent()
{
    PREvent* event;

    for (;;) {
        PR_LOG_BEGIN(Event, debug, ("$$$ getting event\n"));
    
        event = PR_GetEvent(mozilla_event_queue);
        if (event == NULL) {
            return;
        }
    
        PR_HandleEvent(event);
        PR_LOG_END(Event, debug, ("$$$ done with event\n"));
        PR_DestroyEvent(event);
    }
}

void PR_CALLBACK
lj_DiscardEventForContext(MWContextEvent* ce, MWContext* context,
			  PREventQueue* queue)
{
    if (ce->context == context) {
		PR_LOG(Event, debug,
			   ("$$$ \tdropping event %d for context %d\n",
				ce, SHIST_GetCurrent(&ce->context->hist)));
		PR_DequeueEvent(&ce->event, queue);
		PR_DestroyEvent(&ce->event);
    }
    else {
		PR_LOG(Event, debug,
			   ("$$$ \tskipping event %d for context %d\n",
				ce, SHIST_GetCurrent(&ce->context->hist)));
    }
}

void
LJ_DiscardEventsForContext(MWContext* context)
{
    PR_LOG_BEGIN(Event, debug, ("$$$ destroying context %d\n", 
								SHIST_GetCurrent(&context->hist)));

    /*
    ** First we enter the monitor so that no one else can post any events
    ** to the queue:
    */
    PR_EnterMonitor(mozilla_event_queue->monitor);
    PR_LOG(Event, debug,
		   ("$$$ destroying context %d, entered monitor\n",
			SHIST_GetCurrent(&context->hist)));

    /*
    ** Discard any pending events for this context:
    */
    PR_MapEvents(mozilla_event_queue,
				 (PR_EventFunPtr)lj_DiscardEventForContext,
				 context);

    nsn_JavaContext_breakLinkage(context);

    PR_ExitMonitor(mozilla_event_queue->monitor);

    PR_LOG_END(Event, debug,
			   ("$$$ destroying context %d, exited monitor\n", 
				SHIST_GetCurrent(&context->hist)));
}

/******************************************************************************/