home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / lib / libmocha / et_mocha.c next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  63.1 KB  |  2,457 lines

  1. /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  2.  *
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  *
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  *
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18. /*
  19.  * Messages passing from the mozilla thread to the mocha thread
  20.  */
  21. #include "lm.h"
  22. #include "xp.h"
  23. #include "fe_proto.h"
  24. #include "proto.h"
  25. #include "net.h"
  26. #include "structs.h"
  27. #include "prmon.h"
  28. #include "prthread.h"
  29. #ifdef XP_MAC
  30. #include "prpriv.h"
  31. #else
  32. #include "private/prpriv.h" /* For PR_NewNamedMonitor */
  33. #endif
  34. #include "layout.h"    /* XXX for lo_ContextToCell and lo_FormData */
  35. #include "libimg.h"
  36. #include "java.h"
  37. #include "pa_tags.h"
  38. #include "css.h"
  39. #include "pa_parse.h"
  40. #include "jsjava.h"
  41. #include "intl_csi.h"
  42.  
  43. QueueStackElement * et_TopQueue = NULL;
  44.  
  45. PRIVATE PRMonitor * lm_queue_monitor = NULL;
  46. PRIVATE JSBool lm_InterruptCurrentOp = JS_FALSE;
  47.  
  48. #ifdef XP_WIN16
  49. #define MOCHA_NORMAL_PRIORITY PR_PRIORITY_NORMAL
  50. extern PRThread     *lm_InterpretThread;
  51. #endif
  52.  
  53. /**********************************************************************/
  54.  
  55.  
  56. #define MAKE_EAGER_INHERIT(e)                             \
  57.                       if (et_TopQueue->inherit_parent &&             \
  58.               e->ce.handle_eagerly == JS_FALSE &&             \
  59.               e->ce.context->grid_parent) {                 \
  60.               e->ce.handle_eagerly =                  \
  61.                 (XP_DOCID(e->ce.context->grid_parent) ==         \
  62.                  et_TopQueue->doc_id);                 \
  63.               }
  64.  
  65. #define MAKE_EAGER(e) if (et_TopQueue->doc_id == 0 &&                  \
  66.               et_TopQueue->context == e->ce.context) {         \
  67.               et_TopQueue->doc_id = XP_DOCID(e->ce.context);     \
  68.               e->ce.handle_eagerly = JS_TRUE;             \
  69.               } else {                             \
  70.               e->ce.handle_eagerly =                  \
  71.                 (XP_DOCID(e->ce.context) == et_TopQueue->doc_id);\
  72.               }                                 \
  73.                       MAKE_EAGER_INHERIT(e)
  74.               
  75. /**********************************************************************/
  76.  
  77. static void
  78. et_event_to_mocha(ETEvent * e)
  79. {
  80.     JSBool canDoJS;
  81.     
  82.     if(e->context) {
  83.     e->doc_id = XP_DOCID(e->context);
  84.     canDoJS = LM_CanDoJS(e->context);
  85.     } else {
  86.     /* source of event must be timeout or someone else who can do mocha*/
  87.     canDoJS = JS_TRUE;
  88.     }
  89.     
  90.     if (!lm_InterpretQueue || !canDoJS) {
  91.     e->event.destructor((PREvent *) e);
  92.     return;
  93.     }
  94.  
  95.     /*
  96.      * Decide which queue to put this event on.  The et_TopQueue may
  97.      *   actually be the same as lm_InterpretQueue
  98.      */
  99.     if (e->handle_eagerly) 
  100.     PR_PostEvent(et_TopQueue->queue, &e->event);
  101.     else
  102.     PR_PostEvent(lm_InterpretQueue, &e->event);
  103.  
  104. #ifdef XP_WIN16
  105.     /* Raise the mocha thread priority, otherwise mocha may not get 
  106.      *   time slices, because user's program java threads have higher
  107.      *   priority ( 15 ). If mocha is starving events are not transfered 
  108.      *   to the mozilla-event-queue and Navigator stops reacting to 
  109.      *   the input events
  110.      */
  111.     PR_SetThreadPriority ( lm_InterpretThread, PR_PRIORITY_URGENT );
  112. #endif
  113.  
  114.     if(lm_queue_monitor) {
  115.         /* wake up the processing routine */
  116.         PR_EnterMonitor(lm_queue_monitor);
  117.         PR_Notify(lm_queue_monitor);
  118.         PR_ExitMonitor(lm_queue_monitor);
  119.     }
  120.  
  121. }
  122.  
  123. /**********************************************************************/
  124.  
  125. /* By wrapping the following macros around an event handler callback,
  126.    we can verify that the MWContext to which the event was directed
  127.    hasn't gone away. As a side effect, the local variable 'decoder'
  128.    is established within the macros:
  129.  
  130.    void foo_handler(JSEvent* e) {
  131.      ET_BEGIN_EVENT_HANDLER(e);
  132.      ... decoder ...
  133.      ET_END_EVENT_HANDLER(e);
  134.    }
  135.  
  136.  */
  137. #define ET_BEGIN_EVENT_HANDLER(jsevent)                  \
  138. {                                  \
  139.     MWContext* _c = (jsevent)->ce.context;              \
  140.     MochaDecoder* decoder;                      \
  141.     if (_c == NULL) {                          \
  142.     goto _quit;                          \
  143.     }                                  \
  144.     decoder = LM_GetMochaDecoder(_c);                  \
  145.     if (decoder == NULL) {                      \
  146.     goto _quit;                          \
  147.     }                                  \
  148.  
  149. #define ET_END_EVENT_HANDLER(e)                      \
  150.   _quit:                              \
  151.     if (decoder != NULL) {                      \
  152.     LM_PutMochaDecoder(decoder);                  \
  153.     }                                  \
  154. }                                  \
  155.  
  156. /**********************************************************************/
  157.  
  158. /*
  159.  * Trash our event when we get done with it
  160.  */
  161. PR_STATIC_CALLBACK(void)
  162. et_event_destructor(JSEvent * pEvent)
  163. {
  164.     if (!pEvent->saved)
  165.     XP_FREE(pEvent);
  166. }
  167.  
  168. /*
  169.  * Actual handler routine
  170.  */
  171. PR_STATIC_CALLBACK(void)
  172. et_event_handler(JSEvent * e)
  173. {
  174.  
  175.     LO_Element        * lo_element = NULL;
  176.     ETEventStatus     status = EVENT_OK;
  177.     jsval        rval;
  178.  
  179.     ET_BEGIN_EVENT_HANDLER(e);
  180.  
  181.     LO_LockLayout();
  182.  
  183.     /* verify that this document is still valid */
  184.     if(e->ce.doc_id != XP_DOCID(e->ce.context) && e->type != EVENT_UNLOAD) {
  185.         status = EVENT_PANIC;
  186.     LO_UnlockLayout();
  187.         goto done;
  188.     }
  189.  
  190.     decoder->doc_id = e->ce.doc_id;
  191.  
  192.     /* find the element that caused this event */
  193.     lo_element = e->lo_element;
  194.  
  195.     /* figure out who to call */
  196.     switch(e->type) {
  197.  
  198.     case EVENT_SCROLL:
  199.     case EVENT_DRAGDROP:
  200.     case EVENT_MOVE:
  201.     case EVENT_RESIZE:
  202.     case EVENT_HELP:
  203.      /* These are all window level events only, TRUE unless explicitly denied */
  204.        LO_UnlockLayout();
  205.         
  206.     if (!(decoder->event_mask & e->type)) {
  207.         decoder->event_mask |= e->type;
  208.         if (lm_SendEvent(e->ce.context, decoder->window_object, e, &rval) &&
  209.         rval == JSVAL_FALSE) {
  210.         status = EVENT_CANCEL;
  211.          }
  212.         decoder->event_mask &= ~e->type;
  213.     }
  214.      break;
  215.  
  216.     /*BEGIN Events occurring in the following cases must LO_UnlockLayout themselves. */
  217.     case EVENT_CLICK:
  218.     case EVENT_MOUSEDOWN:
  219.     case EVENT_MOUSEUP:
  220.     case EVENT_DBLCLICK:
  221.         /* TRUE unless explicitly denied */
  222.     if (lm_MouseInputEvent(e->ce.context, lo_element, e, &rval) &&
  223.         rval == JSVAL_FALSE) {
  224.             status = EVENT_CANCEL;
  225.         }
  226.  
  227.         /* 
  228.          * If this was the submit button we want to send a submit 
  229.          *   event here
  230.          */
  231.         break;    
  232.     case EVENT_KEYDOWN:
  233.     case EVENT_KEYUP:
  234.     case EVENT_KEYPRESS:
  235.         /* TRUE unless explicitly denied */
  236.         if (lm_KeyInputEvent(e->ce.context, lo_element, e, &rval) &&
  237.         rval == JSVAL_FALSE) {
  238.             status = EVENT_CANCEL;
  239.         }
  240.         break;    
  241.     case EVENT_BLUR:
  242.     case EVENT_FOCUS:
  243.     case EVENT_SELECT:
  244.     case EVENT_MOUSEOUT:
  245.     case EVENT_CHANGE:
  246.         /* TRUE unless explicitly denied */
  247.         if (lm_InputEvent(e->ce.context, lo_element, e, &rval) &&
  248.         rval == JSVAL_FALSE) {
  249.             status = EVENT_CANCEL;
  250.         }
  251.         break;    
  252.     case EVENT_MOUSEMOVE:
  253.         /* There are two reasons this event could be here
  254.      * 1. The script is capturing this event.
  255.      * 2. The script has a handler defined for onmousemove and we
  256.      *    are assuming they intend the capure this event.  Since the 
  257.      *    time it takes to handle a mousedown event and start capturing
  258.      *    would cause lossage of mousemove messages we're sending all
  259.      *    mousemoves between mousedowns and ups so that if the scripts
  260.      *    starts capturing during the onmousedown handler, the mousemoves
  261.      *    we would have lost will be sitting on the JS queue.
  262.     /* TRUE unless explicitly denied */
  263.     if (LM_EventCaptureCheck(e->ce.context, EVENT_MOUSEMOVE)) {
  264.         if (lm_InputEvent(e->ce.context, lo_element, e, &rval) &&
  265.         rval == JSVAL_FALSE) {
  266.         status = EVENT_CANCEL;
  267.         }
  268.     }
  269.     else
  270.         LO_UnlockLayout();
  271.         break;    
  272.     case EVENT_MOUSEOVER:
  273.         /* FALSE unless explicitly set */
  274.         status = EVENT_CANCEL;
  275.         if (lm_InputEvent(e->ce.context, lo_element, e, &rval) &&
  276.         rval == JSVAL_TRUE) {
  277.             status = EVENT_OK;
  278.         }
  279.         break;    
  280.    
  281.     case EVENT_SUBMIT:
  282.     if(lm_SendOnSubmit(e->ce.context, e,  lo_element))
  283.         status = EVENT_OK;
  284.     else
  285.         status = EVENT_CANCEL;
  286.     /*LO_UnlockLayout called in form_event;*/
  287.     break;
  288.  
  289.  
  290.     case EVENT_RESET:
  291.     if(lm_SendOnReset(e->ce.context, e, lo_element))
  292.         status = EVENT_OK;
  293.     else
  294.         status = EVENT_CANCEL;
  295.     /*LO_UnlockLayout called in form_event;*/
  296.     break;
  297.    /*END asymmetric layout unlocking.*/
  298.  
  299.     default:
  300.     LO_UnlockLayout();
  301.     XP_TRACE(("Mocha thread: Got event %d that I didn't expect", e->type));
  302.         break;
  303.     }
  304.   
  305.     /* clear the mask */
  306.  
  307.     /* check again to make sure the document hasn't changed */
  308.     if(e->ce.doc_id != XP_DOCID(e->ce.context))
  309.         status = EVENT_PANIC;
  310.  
  311. done:
  312.     /* Post an event to call the front-end closuer */
  313.     if(e->fnClosure)
  314.         ET_PostJsEventAck(e->ce.context, lo_element,
  315.                           e->type, e->fnClosure,
  316.                           e->whatever, status);
  317.  
  318. #ifdef XPWIN16
  319.     /* Return to the normal mocha thread priority, after mocha thread
  320.      *   has transfered event to the mozilla-event-queue ( if necessary, 
  321.      *   i.e. if e->fnClosure != NULL 
  322.      */
  323.     PR_SetThreadPriority ( lm_InterpretThread, MOCHA_NORMAL_PRIORITY );
  324. #endif
  325.  
  326.     ET_END_EVENT_HANDLER(e);
  327. }
  328.  
  329.  
  330.  
  331. /*
  332.  * Tell the backend about a new event.
  333.  * fnClosure should be allowed to be NULL
  334.  */
  335. JSBool
  336. ET_SendEvent(MWContext * pContext, LO_Element *pElement, JSEvent *pEvent, 
  337.              ETClosureFunc fnClosure, void * whatever) 
  338. {
  339.     /* make sure we are able to process Mocha events before bothering */
  340.     if (!LM_CanDoJS(pContext) || EDT_IS_EDITOR(pContext)) {
  341.     ETEventStatus     status = EVENT_OK;
  342.     if (pEvent->type == EVENT_MOUSEOVER)
  343.         status = EVENT_CANCEL;
  344.     if (fnClosure)
  345.         fnClosure(pContext, pElement, pEvent->type, whatever, status);
  346.     XP_FREE(pEvent);
  347.     return(JS_TRUE);
  348.     }
  349.  
  350.     PR_InitEvent(&pEvent->ce.event, pContext,
  351.                  (PRHandleEventProc)et_event_handler, 
  352.                  (PRDestroyEventProc)et_event_destructor);
  353.  
  354.     pEvent->ce.context = pContext;
  355.     MAKE_EAGER_INHERIT(pEvent);
  356.     if(pElement)
  357.     pEvent->id = pElement->lo_any.ele_id;
  358.     pEvent->lo_element = pElement;
  359.     pEvent->fnClosure = fnClosure;
  360.     pEvent->whatever = whatever;
  361.  
  362.     et_event_to_mocha(&pEvent->ce);
  363.  
  364.     return(JS_TRUE);
  365.  
  366. }
  367.  
  368. /**********************************************************************/
  369.  
  370. typedef struct {
  371.     ETEvent            ce;
  372.     int32        type;
  373.     ETVoidPtrFunc    fnClosure;
  374.     void          * data;
  375.     int32               layer_id;
  376.     JSBool              resize_reload;
  377. } LoadEvent;
  378.  
  379. PR_STATIC_CALLBACK(void)
  380. et_load_event_handler(LoadEvent * e)
  381. {
  382.  
  383.     ETEventStatus     status = EVENT_OK;
  384.  
  385.     ET_BEGIN_EVENT_HANDLER(e);
  386.  
  387.     LO_LockLayout();
  388.  
  389.     /* verify that this document is still valid */
  390.     if(e->ce.doc_id != XP_DOCID(e->ce.context) && e->type != EVENT_UNLOAD) {
  391.         status = EVENT_PANIC;
  392.     LO_UnlockLayout();
  393.         goto done;
  394.     }
  395.  
  396.     LO_UnlockLayout();
  397.  
  398.     decoder->doc_id = e->ce.doc_id;
  399.  
  400.     /* figure out who to call */
  401.     if (e->layer_id == LO_DOCUMENT_LAYER_ID) {
  402.         if (e->type == EVENT_LOAD)
  403.             lm_ClearDecoderStream(decoder, JS_TRUE);
  404.  
  405.         lm_SendLoadEvent(e->ce.context, e->type, e->resize_reload);
  406.     }
  407.     else {
  408.         if ((decoder->stream_owner == e->layer_id) && (e->type == EVENT_LOAD))
  409.             lm_ClearDecoderStream(decoder, JS_TRUE);
  410.             
  411.         /* 
  412.          * If the load event has already been sent, this is a layer whose
  413.          * src has been dynamically changed. In that case, we want to fire
  414.          * a load event irrespective of whether this context had been
  415.          * resized.
  416.          */
  417.         lm_SendLayerLoadEvent(e->ce.context, e->type, e->layer_id, 
  418.                      decoder->load_event_sent ? JS_FALSE : e->resize_reload);
  419.     }
  420.  
  421. done:
  422.     /* Post an event to call the front-end closure */
  423.     if(e->fnClosure)
  424.         ET_moz_CallFunctionAsync(e->fnClosure, e->data);
  425.  
  426.     ET_END_EVENT_HANDLER(e);
  427. }
  428.  
  429. PR_STATIC_CALLBACK(void)
  430. et_generic_destructor(void * event)
  431. {
  432.     XP_FREE(event);
  433. }
  434.  
  435. /*
  436.  * Tell the backend about a new load event.
  437.  */
  438. void
  439. ET_SendLoadEvent(MWContext * pContext, int32 type, ETVoidPtrFunc fnClosure,
  440.          NET_StreamClass *stream, int32 layer_id, Bool resize_reload)
  441. {
  442.  
  443.     LoadEvent * pEvent;
  444.  
  445.     /* 
  446.      * Make sure we are allowed to do mocha stuff in this context
  447.      *   before bothering to send the event
  448.      */
  449.     if (!LM_CanDoJS(pContext)) {
  450.     if(fnClosure)
  451.         fnClosure(stream);
  452.     return;
  453.     }
  454.  
  455.     pEvent = (LoadEvent *) XP_NEW_ZAP(LoadEvent);
  456.     if(!pEvent)
  457.         return;
  458.  
  459.     PR_InitEvent(&pEvent->ce.event, pContext,
  460.                  (PRHandleEventProc)et_load_event_handler, 
  461.                  (PRDestroyEventProc)et_generic_destructor);
  462.  
  463.     pEvent->type = type;
  464.     pEvent->ce.context = pContext;
  465.     MAKE_EAGER(pEvent);
  466.     pEvent->layer_id = layer_id;
  467.     pEvent->fnClosure = fnClosure;
  468.     pEvent->data = stream;
  469.     pEvent->resize_reload = (JSBool)resize_reload;
  470.  
  471.     /* add the event to the event queue */
  472.     et_event_to_mocha(&pEvent->ce);
  473.  
  474. }
  475.  
  476. /**********************************************************************/
  477.  
  478. PR_STATIC_CALLBACK(void)
  479. et_setactiveform_handler(JSEvent * e)
  480. {
  481.     ET_BEGIN_EVENT_HANDLER(e);
  482.  
  483.     /* verify that this document is still valid */
  484.     if(e->ce.doc_id != XP_DOCID(e->ce.context))
  485.     return;
  486.  
  487.     lm_SetActiveForm(e->ce.context, e->type);
  488.  
  489.     ET_END_EVENT_HANDLER(e);
  490. }
  491.  
  492. /*
  493.  */
  494. void
  495. ET_SetActiveForm(MWContext * pContext, lo_FormData * form)
  496. {
  497.  
  498.     JSEvent      * pEvent = (JSEvent *) XP_NEW_ZAP(JSEvent);
  499.     if(!pEvent)
  500.         return;
  501.  
  502.     PR_InitEvent(&pEvent->ce.event, pContext,
  503.                  (PRHandleEventProc)et_setactiveform_handler, 
  504.                  (PRDestroyEventProc)et_generic_destructor);
  505.  
  506.     pEvent->ce.context = pContext;
  507.     MAKE_EAGER(pEvent);
  508.  
  509.     /* form can be NULL when there should be no active form */
  510.     if(form)
  511.     pEvent->type = form->id;
  512.     else
  513.     pEvent->type = 0;
  514.  
  515.     et_event_to_mocha(&pEvent->ce);
  516.  
  517. }
  518.  
  519.  
  520.  
  521. /**********************************************************************/
  522.  
  523. PR_STATIC_CALLBACK(void)
  524. et_setactivelayer_handler(JSEvent * e)
  525. {
  526.     ET_BEGIN_EVENT_HANDLER(e);
  527.  
  528.     /* verify that this document is still valid */
  529.     if(e->ce.doc_id != XP_DOCID(e->ce.context))
  530.     return;
  531.  
  532.     LM_SetActiveLayer(e->ce.context, e->layer_id);
  533.  
  534.     ET_END_EVENT_HANDLER(e);
  535. }
  536.  
  537. /*
  538.  */
  539. void
  540. ET_SetActiveLayer(MWContext * pContext, int32 layer_id)
  541. {
  542.  
  543.     JSEvent      * pEvent = (JSEvent *) XP_NEW_ZAP(JSEvent);
  544.     if(!pEvent)
  545.         return;
  546.  
  547.     PR_InitEvent(&pEvent->ce.event, pContext,
  548.                  (PRHandleEventProc)et_setactivelayer_handler, 
  549.                  (PRDestroyEventProc)et_generic_destructor);
  550.  
  551.     pEvent->ce.context = pContext;
  552.     pEvent->layer_id = layer_id;
  553.     et_event_to_mocha(&pEvent->ce);
  554. }
  555.  
  556. /**********************************************************************/
  557.  
  558. /* 
  559.  * Mocha is about to process or is processing an event for the given
  560.  *   context.  Verify we haven't been asked to interrupt it
  561.  */
  562. JSBool
  563. ET_ContinueProcessing(MWContext * context)
  564. {
  565.     return (JSBool)(lm_InterruptCurrentOp == JS_FALSE);
  566. }
  567.  
  568. /**********************************************************************/
  569.  
  570. static void
  571. et_RevokeEvents(MWContext * pContext)
  572. {
  573.     QueueStackElement *qse;
  574.  
  575.     for (qse = et_TopQueue; qse; qse = qse->down) {
  576.         PR_RevokeEvents(qse->queue, pContext);
  577.     }
  578.     for (qse = et_TopQueue->up; qse; qse = qse->up) {
  579.         PR_RevokeEvents(qse->queue, pContext);
  580.     }
  581. }
  582.  
  583. void
  584. ET_InterruptContext(MWContext * pContext)
  585. {
  586.  
  587.     /* make sure the context can do mocha before bothering */
  588.     if (!lm_queue_monitor || !LM_CanDoJS(pContext))
  589.     return;
  590.  
  591.     /* need to lock the JS-thread from starting new events */
  592.     PR_EnterMonitor(lm_queue_monitor);
  593.  
  594.     /* Is our context currently running in mocha ? */
  595.     if (LM_JSLockGetContext() == pContext) {
  596.     /* 
  597.      * if the owner of the JSLock is the context we are
  598.      *   interrupting set a flag so it will stop soon
  599.      */
  600.     lm_InterruptCurrentOp = JS_TRUE;
  601.  
  602.     }
  603.  
  604.     /* clear events for this context off of the interpret queue */
  605.     et_RevokeEvents(pContext);
  606.  
  607.     /* need to unlock the JS-thread from starting new events */
  608.     PR_ExitMonitor(lm_queue_monitor);
  609.  
  610.     /* Interrupt the JS image context. */
  611.     if (pContext->mocha_context)
  612.     ET_InterruptImgCX(pContext);
  613. }
  614.  
  615. /**********************************************************************/
  616.  
  617. /*
  618.  * Actual handler routine for image events
  619.  */
  620. PR_STATIC_CALLBACK(void)
  621. et_image_event_handler(JSEvent * e)
  622. {
  623.  
  624.     ETEventStatus     status = EVENT_OK;
  625.     LO_ImageStruct  * image;
  626.     JSObject        * obj;
  627.  
  628.     ET_BEGIN_EVENT_HANDLER(e);
  629.  
  630.     LO_LockLayout();
  631.  
  632.     /* verify that this document is still valid */
  633.     if(e->ce.doc_id != XP_DOCID(e->ce.context)) {
  634.         status = EVENT_PANIC;
  635.     LO_UnlockLayout();
  636.         goto done;
  637.     }
  638.  
  639.     /* 
  640.      * Remember the ID of the document that spaned this call stack
  641.      */
  642.     if(decoder) 
  643.     decoder->doc_id = e->ce.doc_id;
  644.  
  645.     /* XXX chouck - do we need to set a mask so we don't loop infinitely? */
  646.  
  647.     /* find the element that caused this event */
  648.     if(e->id)
  649.     image = LO_GetImageByIndex(e->ce.context, e->layer_id, e->id);
  650.     else
  651.     image = (LO_ImageStruct *) e->lo_element;
  652.  
  653.     if (!image || (image->type != LO_IMAGE)) {
  654.     LO_UnlockLayout();
  655.     goto done;
  656.     }
  657.  
  658.     obj = image->mocha_object;
  659.  
  660.     /* OK, we've gotten our pointer, let layout be happy again */
  661.     LO_UnlockLayout();
  662.  
  663.     /* If we actually had an object send the event for it */
  664.     if(obj) 
  665.     lm_ProcessImageEvent(e->ce.context, obj, (LM_ImageEvent) e->type);
  666.  
  667.     /* clear the mask */
  668.  
  669.     /* check again to make sure the document hasn't changed */
  670.     if(e->ce.doc_id != XP_DOCID(e->ce.context))
  671.         status = EVENT_PANIC;
  672.  
  673. done:
  674.     ET_END_EVENT_HANDLER(e);
  675.  
  676.     return;
  677. }
  678.  
  679.  
  680. void
  681. ET_SendImageEvent(MWContext * pContext, LO_ImageStruct *image_data,
  682.                   LM_ImageEvent event)
  683. {
  684.     JSEvent      * pEvent;
  685.  
  686.     if (!LM_CanDoJS(pContext))
  687.     return;
  688.     
  689.     pEvent = (JSEvent *) XP_NEW_ZAP(JSEvent);
  690.     if(!pEvent)
  691.         return;
  692.  
  693.     PR_InitEvent(&pEvent->ce.event, pContext,
  694.          (PRHandleEventProc)et_image_event_handler, 
  695.          (PRDestroyEventProc)et_event_destructor);
  696.  
  697.     pEvent->type = event;
  698.     pEvent->ce.context = pContext;
  699.  
  700.     if(image_data) {
  701.     pEvent->id = image_data->seq_num;
  702.         pEvent->layer_id = image_data->layer_id;
  703.     }
  704.     pEvent->lo_element = (LO_Element *) image_data;
  705.  
  706.     et_event_to_mocha(&pEvent->ce);
  707.  
  708. }
  709.  
  710. /**********************************************************************/
  711.  
  712. typedef struct {
  713.     ETEvent            ce;
  714.     int32               layer_id;
  715.     void              * lo_ele;
  716.     void              * pa_tag;
  717.     ReflectedObject    type;
  718.     uint        index;
  719. } Reflect_Event;
  720.  
  721. /*
  722.  * Make the appropriate LM_Reflect() call.  Since we store a pointer
  723.  *   to the newly created JSObject as part of the layout object it
  724.  *   represents, we need to lock layout while doing this so layout
  725.  *   doesn't take our object away out from under us.
  726.  * If any of the reflection routines take us back into the mozilla 
  727.  *   thread we run the risk of deadlocking on the LO_LockLayout()
  728.  *   call.
  729.  */
  730. PR_STATIC_CALLBACK(void)
  731. et_reflect_handler(Reflect_Event * e)
  732. {
  733.     ETEventStatus     status = EVENT_OK;
  734.  
  735.     ET_BEGIN_EVENT_HANDLER(e);
  736.  
  737.     /*
  738.      * Make sure the layout objects don't go away while we are 
  739.      *   reflecting them
  740.      */
  741.     LO_LockLayout();
  742.  
  743.     /* verify that this document is still valid */
  744.     if(e->ce.doc_id != XP_DOCID(e->ce.context)) {
  745.         status = EVENT_PANIC;
  746.         goto done;
  747.     }
  748.  
  749.     switch(e->type) {
  750.     case LM_APPLETS:
  751. #ifdef JAVA
  752.     LM_ReflectApplet(e->ce.context, (LO_JavaAppStruct *) e->lo_ele, 
  753.                      e->pa_tag, e->layer_id, e->index);
  754. #endif
  755.         break;
  756.     case LM_EMBEDS:
  757. #ifdef JAVA
  758.     LM_ReflectEmbed(e->ce.context, e->lo_ele, e->pa_tag, 
  759.                         e->layer_id, e->index);
  760. #endif
  761.     break;
  762.     case LM_IMAGES:
  763.     LM_ReflectImage(e->ce.context, e->lo_ele, e->pa_tag, 
  764.                         e->layer_id, e->index);
  765.     break;
  766.     case LM_LINKS:
  767.     LM_ReflectLink(e->ce.context, (LO_AnchorData *) e->lo_ele, 
  768.                e->pa_tag, e->layer_id, e->index);
  769.         break;
  770.     case LM_FORMS:
  771.     LM_ReflectForm(e->ce.context, (lo_FormData *) e->lo_ele, 
  772.                e->pa_tag, e->layer_id, e->index);
  773.         break;
  774.     case LM_NAMEDANCHORS:
  775.         LM_ReflectNamedAnchor(e->ce.context, (lo_NameList *) e->lo_ele,
  776.                               e->pa_tag, e->layer_id, e->index);
  777.         break;
  778.     case LM_FORMELEMENTS:
  779.     XP_ASSERT(0);
  780.     break;
  781.     case LM_LAYERS:
  782.         LM_ReflectLayer(e->ce.context, e->index, e->layer_id, e->pa_tag);
  783.         break;
  784.     default:
  785.     XP_ASSERT(0);
  786.     break;
  787.     }
  788.  
  789. done:
  790.  
  791.     /*
  792.      * We are done with the reflection so unlock layout 
  793.      */ 
  794.     LO_UnlockLayout();
  795.  
  796.     ET_END_EVENT_HANDLER(e);
  797.  
  798.     return;
  799. }
  800.  
  801. /*
  802.  * Free our memory
  803.  */
  804. PR_STATIC_CALLBACK(void)
  805. et_reflect_destructor(Reflect_Event * e)
  806. {
  807.     /* we explictly duplicated our tag when we created this event
  808.      *   object so make sure to get rid of it now
  809.      */
  810.     if (e->pa_tag)
  811.         PA_FreeTag(e->pa_tag);
  812.  
  813.     XP_FREE(e);
  814. }
  815.  
  816. /*
  817.  * Reflect the given object.
  818.  */
  819. void
  820. ET_ReflectObject(MWContext * pContext, void * lo_ele, void * tag, 
  821.                  int32 layer_id, uint index, ReflectedObject type)
  822. {
  823.     /* create our event object */
  824.     Reflect_Event * pEvent = (Reflect_Event *) XP_NEW_ZAP(Reflect_Event);
  825.     if(!pEvent)
  826.         return;
  827.  
  828. #ifdef JAVA
  829.     /* before we can call java on the mocha thread we need
  830.      * to initialize moja.  this isn't safe to do with the
  831.      * layout lock held, so we do it here. */
  832.     if (type == LM_APPLETS || type == LM_EMBEDS)
  833.         ET_InitMoja(pContext);
  834. #endif
  835.  
  836.     /* do a PR_InitEvent on the event structure */
  837.     PR_InitEvent(&pEvent->ce.event, pContext,
  838.          (PRHandleEventProc)et_reflect_handler, 
  839.          (PRDestroyEventProc)et_reflect_destructor);
  840.  
  841.     /* fill in the non-PR fields we care about */
  842.     pEvent->type = type;
  843.     pEvent->ce.context = pContext;
  844.     pEvent->lo_ele = lo_ele;
  845.     if(tag)
  846.         pEvent->pa_tag = (void *) PA_CloneMDLTag(tag);
  847.     else
  848.         pEvent->pa_tag = NULL;
  849.  
  850.     pEvent->index = index;
  851.     pEvent->layer_id = layer_id;
  852.     MAKE_EAGER(pEvent);
  853.  
  854.     /* add the event to the event queue */
  855.     et_event_to_mocha(&pEvent->ce);
  856.  
  857. }
  858.  
  859. /**********************************************************************/
  860.  
  861. typedef struct {
  862.     ETEvent            ce;
  863.     int32               layer_id;
  864.     void              * pa_tag;
  865.     uint        element_index;
  866.     uint        form_index;
  867. } ReflectForm_Event;
  868.  
  869.  
  870. /*
  871.  * Make the appropriate LM_Reflect() call.  Since we store a pointer
  872.  *   to the newly created JSObject as part of the layout object it
  873.  *   represents, we need to lock layout while doing this so layout
  874.  *   doesn't take our object away out from under us.
  875.  * If any of the reflection routines take us back into the mozilla 
  876.  *   thread we run the risk of deadlocking on the LO_LockLayout()
  877.  *   call.
  878.  */
  879. PR_STATIC_CALLBACK(void)
  880. et_reflectElement_handler(ReflectForm_Event * e)
  881. {
  882.  
  883.     ET_BEGIN_EVENT_HANDLER(e);
  884.  
  885.     /*
  886.      * Make sure the layout objects don't go away while we are 
  887.      *   reflecting them
  888.      */
  889.     LO_LockLayout();
  890.  
  891.     if (!decoder)
  892.     goto done;
  893.     
  894.     /* verify that this document is still valid */
  895.     if (e->ce.doc_id != XP_DOCID(e->ce.context))
  896.         goto done;
  897.  
  898.     /* reflect the form element */
  899.     LM_ReflectFormElement(e->ce.context, e->layer_id,
  900.               e->form_index, e->element_index, e->pa_tag);
  901.  
  902. done:
  903.  
  904.     LO_UnlockLayout();
  905.     ET_END_EVENT_HANDLER(e);
  906.  
  907. }
  908.  
  909. PR_STATIC_CALLBACK(void)
  910. et_reflectElement_destructor(ReflectForm_Event * e)
  911. {
  912.     /* 
  913.      * We explictly duplicated our tag when we created this event
  914.      *   object so make sure to get rid of it now
  915.      */
  916.     if(e->pa_tag) {
  917.     PA_Tag * tag = (PA_Tag *) e->pa_tag;
  918.     if(tag->data)
  919.         PA_FREE(tag->data);
  920.     PA_FREE(tag);
  921.     }
  922.  
  923.     XP_FREE(e);
  924. }
  925.  
  926. /*
  927.  * Reflect a form element.  This is enough of a special case that
  928.  *   its been pulled out of the generic reflect object
  929.  */
  930. void
  931. ET_ReflectFormElement(MWContext * pContext, void * form,
  932.               LO_FormElementStruct * form_element, PA_Tag * tag)
  933. {
  934.     /* create our event object */
  935.     ReflectForm_Event * pEvent;
  936.  
  937.     if (!form || !form_element)
  938.     return;
  939.  
  940.     pEvent = (ReflectForm_Event *) XP_NEW_ZAP(ReflectForm_Event);
  941.     if (!pEvent)
  942.         return;
  943.  
  944.     PR_InitEvent(&pEvent->ce.event, pContext,
  945.          (PRHandleEventProc)et_reflectElement_handler, 
  946.          (PRDestroyEventProc)et_reflectElement_destructor);
  947.  
  948.     pEvent->ce.context = pContext;
  949.     if(tag)
  950.         pEvent->pa_tag = (void *) PA_CloneMDLTag(tag);
  951.     else
  952.         pEvent->pa_tag = NULL;
  953.  
  954.     pEvent->element_index = form_element->element_index;
  955.     pEvent->form_index = ((lo_FormData *)form)->id;
  956.     pEvent->layer_id = form_element->layer_id;
  957.     MAKE_EAGER(pEvent);
  958.  
  959.     et_event_to_mocha(&pEvent->ce);
  960.  
  961. }
  962.  
  963. /**********************************************************************/
  964.  
  965. typedef struct {
  966.     ETEvent             ce;
  967.     void               * buffer;
  968.     ETEvalStuff        * stuff;
  969.     ETEvalAckFunc        fn;
  970. } EvalStruct;
  971.  
  972.  
  973. PR_STATIC_CALLBACK(void)
  974. et_evalbuffer_handler(EvalStruct * e)
  975. {
  976.     JSContext     * cx;
  977.     JSPrincipals * principals = NULL;
  978.     JSPrincipals * event_principals = NULL;
  979.     jsval       rv;
  980.     JSBool       ok;
  981.     size_t         result_len;
  982.     char         * result_str;
  983.     char         * wysiwyg_url;
  984.     char     * base_href;
  985.     uint       len, line_no;
  986.  
  987.     ET_BEGIN_EVENT_HANDLER(e);
  988.  
  989.     LO_LockLayout();
  990.  
  991.     /* 
  992.      * If the current document is the same as the document that sent
  993.      *   the evaluate event we want to continue to evaluate and remember
  994.      *   the doc_id so we can see if the document changes out from under
  995.      *   us
  996.      */     
  997.     if(e->ce.doc_id != XP_DOCID(e->ce.context)) {
  998.     LO_UnlockLayout();
  999.         goto done;
  1000.     }
  1001.  
  1002.     decoder->doc_id = e->ce.doc_id;
  1003.  
  1004.     LO_UnlockLayout();
  1005.  
  1006.     len = e->stuff->len;
  1007.     line_no = e->stuff->line_no;
  1008.     lm_SetVersion(decoder, e->stuff->version);
  1009.     event_principals = e->stuff->principals;
  1010.  
  1011.     cx = decoder->js_context;
  1012.     if (event_principals) {
  1013.         /* First appearance on this thread. Create a root. */
  1014.         JSPRINCIPALS_HOLD(cx, event_principals);
  1015.     }
  1016.     principals = lm_GetCompilationPrincipals(decoder, event_principals);
  1017.     if (principals) {
  1018.         JSPRINCIPALS_HOLD(cx, principals);
  1019.     ok = LM_EvaluateBuffer(decoder, e->buffer, len, line_no, 
  1020.                    e->stuff->scope_to, principals, 
  1021.                    e->stuff->unicode, &rv);
  1022.  
  1023.     } 
  1024.     else {
  1025.         ok = JS_FALSE;
  1026.     }
  1027.     if (event_principals) {
  1028.         /* We're done with e->principals */
  1029.         JSPRINCIPALS_DROP(cx, event_principals);
  1030.     }
  1031.  
  1032.     /* make sure the document hasn't changed out from under us */
  1033.     if(e->ce.doc_id != XP_DOCID(e->ce.context))
  1034.         goto done;
  1035.  
  1036.     if(!ok) {
  1037.         ET_PostEvalAck(e->ce.context, e->ce.doc_id, e->stuff->data, 
  1038.                NULL, 0, NULL, NULL, FALSE, e->fn);
  1039.         goto done;
  1040.     }
  1041.  
  1042.     if (!e->stuff->want_result)
  1043.     rv = JSVAL_VOID;
  1044.     if (rv == JSVAL_VOID || 
  1045.     !JS_ConvertValue(cx, rv, JSTYPE_STRING, &rv)) {
  1046.         ET_PostEvalAck(e->ce.context, e->ce.doc_id, e->stuff->data, 
  1047.                NULL, 0, NULL, NULL, JS_TRUE, e->fn);
  1048.         goto done;
  1049.     }
  1050.  
  1051.     result_len = JS_GetStringLength(JSVAL_TO_STRING(rv));
  1052.     result_str = JS_malloc(cx, result_len + 1);
  1053.     if (result_str) {
  1054.     /* XXXunicode or is this binary data going to imagelib ? */
  1055.     XP_MEMCPY(result_str, JS_GetStringBytes(JSVAL_TO_STRING(rv)),
  1056.           result_len);
  1057.     result_str[result_len] = '\0';
  1058.     }
  1059.  
  1060.     wysiwyg_url = lm_MakeWysiwygUrl(cx, decoder, decoder->active_layer_id, 
  1061.                                     principals);
  1062.     base_href = LM_GetBaseHrefTag(cx, principals);
  1063.  
  1064.     ET_PostEvalAck(e->ce.context, 
  1065.            e->ce.doc_id, 
  1066.            e->stuff->data, 
  1067.            result_str,
  1068.            result_len,
  1069.                    wysiwyg_url, 
  1070.            base_href, 
  1071.            JS_TRUE, 
  1072.            e->fn);
  1073. done:
  1074.     if (principals)
  1075.         JSPRINCIPALS_DROP(cx, principals);
  1076.     ET_END_EVENT_HANDLER(e);
  1077. }
  1078.  
  1079. PR_STATIC_CALLBACK(void)
  1080. et_evalbuffer_destructor(EvalStruct * e)
  1081. {
  1082.     XP_FREEIF(e->stuff->scope_to);
  1083.     XP_FREE(e->buffer);
  1084.     XP_FREE(e->stuff);
  1085.     XP_FREE(e);
  1086. }
  1087.  
  1088. /*
  1089.  * This sucks a lot.  The ET_EvaluateBuffer() API needed to change
  1090.  *   but the security code is on a tagged release and can't be changed.  
  1091.  */
  1092. void
  1093. ET_EvaluateBuffer(MWContext * context, char * buffer, uint buflen,
  1094.           uint line_no, char * scope_to, JSBool want_result,
  1095.           ETEvalAckFunc fn, void * data,
  1096.           JSVersion ver, struct JSPrincipals * hi)
  1097. {
  1098.     /* call ET_EvaluateScript(), please */
  1099.     XP_ASSERT(0);
  1100. }
  1101.  
  1102. /*
  1103.  * Evaluate the given script.  I'm sure this is going to need a
  1104.  *   callback or compeletion routine
  1105.  */
  1106. void
  1107. ET_EvaluateScript(MWContext * pContext, char * buffer, ETEvalStuff * stuff,
  1108.           ETEvalAckFunc fn)
  1109. {
  1110.  
  1111.     EvalStruct * pEvent;
  1112.     int len;
  1113.     int16 charset;
  1114.  
  1115.     /*
  1116.      * make sure this context can do mocha, if not, don't bother
  1117.      *   sending the event over, just call the closure function and
  1118.      *   go home
  1119.      */
  1120.     if (!LM_CanDoJS(pContext)) {
  1121.     fn(stuff->data, NULL, 0, NULL, NULL, JS_FALSE);
  1122.     XP_FREE(stuff);
  1123.     return;
  1124.     }
  1125.     
  1126.     /* create our event object */
  1127.     pEvent = (EvalStruct *) XP_NEW_ZAP(EvalStruct);
  1128.     if (!pEvent) {
  1129.     XP_FREE(stuff);
  1130.         return;
  1131.     }
  1132.  
  1133.     /* do a PR_InitEvent on the event structure */
  1134.     PR_InitEvent(&pEvent->ce.event, pContext,
  1135.          (PRHandleEventProc)et_evalbuffer_handler, 
  1136.          (PRDestroyEventProc)et_evalbuffer_destructor);
  1137.  
  1138.     pEvent->ce.context = pContext;
  1139.     MAKE_EAGER(pEvent);
  1140.  
  1141.     /*
  1142.      * We are going to make our own copy of the buffer in order
  1143.      *   to be safe.  If we are on an non-ascii page just do the
  1144.      *   conversion to unicode here.  Since the JS engine is all
  1145.      *   unicode in 5.x maybe we should always just do the 
  1146.      *   transformation here.
  1147.      */
  1148.     len = stuff->len;
  1149.     charset = INTL_GetCSIWinCSID(LO_GetDocumentCharacterSetInfo(pContext));
  1150.  
  1151.     if (charset == CS_DEFAULT || charset == CS_ASCII || charset == CS_LATIN1) {
  1152.     char * buf;
  1153.     buf = XP_ALLOC(sizeof(char)* (len + 1));
  1154.     if (!buf) {
  1155.         XP_FREE(stuff);
  1156.         return;
  1157.     }
  1158.     strncpy(buf, buffer, len);
  1159.     buf[len] = '\0';
  1160.     pEvent->buffer = buf;
  1161.     stuff->unicode = JS_FALSE;
  1162.     }
  1163.     else {
  1164.     uint32 unicodeLen;
  1165.  
  1166.     /* find out how many unicode characters we'll end up with */
  1167.     unicodeLen = INTL_TextToUnicodeLen(charset, 
  1168.                     (unsigned char *) buffer,
  1169.                     len);
  1170.     pEvent->buffer = XP_ALLOC(sizeof(INTL_Unicode) * unicodeLen);
  1171.     if (!pEvent->buffer) {
  1172.         XP_FREE(stuff);
  1173.         return;
  1174.     }
  1175.  
  1176.     /* do the conversion */
  1177.     stuff->len = INTL_TextToUnicode(charset,
  1178.                         (unsigned char *) buffer,
  1179.                         len,
  1180.                         pEvent->buffer,
  1181.                         unicodeLen);
  1182.  
  1183.     stuff->unicode = JS_TRUE;
  1184.  
  1185.     }
  1186.     pEvent->stuff = stuff;
  1187.     pEvent->fn = fn;
  1188.  
  1189.     /* add the event to the event queue */
  1190.     et_event_to_mocha(&pEvent->ce);
  1191.  
  1192. }
  1193.  
  1194. /**********************************************************************/
  1195.  
  1196. PR_STATIC_CALLBACK(void)
  1197. et_firetimeout_handler(MozillaEvent_Timeout * e)
  1198. {
  1199. /*    ET_BEGIN_EVENT_HANDLER(e);*/    /* since we don't use the MWContext */
  1200.  
  1201.     (e->fnCallback) ((void *)e);
  1202.  
  1203. /*    ET_END_EVENT_HANDLER(e);*/
  1204. }
  1205.  
  1206. void
  1207. ET_FireTimeoutCallBack(void * obj)
  1208. {
  1209.     /*
  1210.      * our closure is actually the original event that we sent to 
  1211.      *   the mozilla thread to get this whole party started.
  1212.      * we own the freeing of this storage so macke sure we have a 
  1213.      *   valid destructor function
  1214.      */
  1215.     MozillaEvent_Timeout * pEvent = (MozillaEvent_Timeout *) obj;
  1216.  
  1217.     /* reuse our event */    
  1218.     PR_InitEvent(&pEvent->ce.event, NULL,
  1219.          (PRHandleEventProc)et_firetimeout_handler, 
  1220.          (PRDestroyEventProc)et_generic_destructor);
  1221.  
  1222.     /* add the event to the event queue */
  1223.     et_event_to_mocha(&pEvent->ce);
  1224.  
  1225. }
  1226.  
  1227. /**********************************************************************/
  1228.  
  1229. typedef struct {
  1230.     ETEvent               ce;
  1231.     NET_StreamClass      * stream;
  1232.     NET_StreamClass     * old_stream;
  1233.     URL_Struct             * url_struct;
  1234.     JSBool                 free_stream_on_close;
  1235. } DecoderStreamStruct;
  1236.  
  1237. PR_STATIC_CALLBACK(void)
  1238. et_setstream_handler(DecoderStreamStruct * e)
  1239. {
  1240.     ET_BEGIN_EVENT_HANDLER(e);
  1241.  
  1242.     /* This will hold a ref on e->url_struct from the context's decoder. */
  1243.     LM_SetDecoderStream(e->ce.context, e->stream, e->url_struct,
  1244.                         e->free_stream_on_close);
  1245.     
  1246.     /* Drop the reference held below when e was constructed. */
  1247.     NET_DropURLStruct(e->url_struct);
  1248.  
  1249.     ET_END_EVENT_HANDLER(e);
  1250. }
  1251.  
  1252. /*
  1253.  */
  1254. void
  1255. ET_SetDecoderStream(MWContext * pContext, NET_StreamClass *stream,
  1256.                 URL_Struct *url_struct, JSBool free_stream_on_close)
  1257. {
  1258.     /* create our event object */
  1259.     DecoderStreamStruct * pEvent = XP_NEW_ZAP(DecoderStreamStruct);
  1260.     if(!pEvent)
  1261.         return;
  1262.  
  1263.     /* do a PR_InitEvent on the event structure */
  1264.     PR_InitEvent(&pEvent->ce.event, pContext,
  1265.                  (PRHandleEventProc)et_setstream_handler, 
  1266.                  (PRDestroyEventProc)et_generic_destructor);
  1267.  
  1268.     /* fill in the non-PR fields we care about */
  1269.     pEvent->ce.context = pContext;
  1270.     pEvent->stream = stream;
  1271.     pEvent->url_struct = url_struct;
  1272.     pEvent->free_stream_on_close = free_stream_on_close;
  1273.  
  1274.     /* we are holding a copy of the URL_struct across thread boundaries */
  1275.     NET_HoldURLStruct(url_struct);
  1276.  
  1277.     /* add the event to the event queue */
  1278.     et_event_to_mocha(&pEvent->ce);
  1279.  
  1280. }
  1281.  
  1282. /**********************************************************************/
  1283.  
  1284. PR_STATIC_CALLBACK(void)
  1285. et_clearstream_handler(DecoderStreamStruct * e)
  1286. {
  1287.     ET_BEGIN_EVENT_HANDLER(e);
  1288.  
  1289.     lm_ClearDecoderStream(decoder, JS_TRUE);
  1290.     if (e->old_stream)
  1291.         XP_FREE(e->old_stream);
  1292.  
  1293.     ET_END_EVENT_HANDLER(e);
  1294. }
  1295.  
  1296. /*
  1297.  */
  1298. void
  1299. ET_ClearDecoderStream(MWContext * pContext, NET_StreamClass * old_stream)
  1300. {
  1301.     /* create our event object */
  1302.     DecoderStreamStruct * pEvent = XP_NEW_ZAP(DecoderStreamStruct);
  1303.     if(!pEvent)
  1304.         return;
  1305.  
  1306.     /* do a PR_InitEvent on the event structure */
  1307.     PR_InitEvent(&pEvent->ce.event, pContext,
  1308.         (PRHandleEventProc)et_clearstream_handler, 
  1309.         (PRDestroyEventProc)et_generic_destructor);
  1310.  
  1311.     /* fill in the non-PR fields we care about */
  1312.     pEvent->ce.context = pContext;
  1313.     pEvent->old_stream = old_stream;
  1314.  
  1315.     /* add the event to the event queue */
  1316.     et_event_to_mocha(&pEvent->ce);
  1317.  
  1318. }
  1319.  
  1320. /**********************************************************************/
  1321.  
  1322. typedef struct {
  1323.     ETEvent    ce;
  1324.     JSObject   *layer_obj;
  1325. } DestroyLayerStruct;
  1326.  
  1327. PR_STATIC_CALLBACK(void)
  1328. et_destroylayer_handler(DestroyLayerStruct * e)
  1329. {
  1330.     ET_BEGIN_EVENT_HANDLER(e);
  1331.  
  1332.     lm_DestroyLayer(e->ce.context, e->layer_obj);
  1333.  
  1334.     ET_END_EVENT_HANDLER(e);
  1335. }
  1336.  
  1337. void
  1338. ET_DestroyLayer(MWContext * pContext, JSObject *layer_obj)
  1339. {
  1340.     DestroyLayerStruct * pEvent = XP_NEW_ZAP(DestroyLayerStruct);
  1341.     if(!pEvent)
  1342.         return;
  1343.  
  1344.     PR_InitEvent(&pEvent->ce.event, pContext,
  1345.          (PRHandleEventProc)et_destroylayer_handler, 
  1346.          (PRDestroyEventProc)et_generic_destructor);
  1347.  
  1348.     pEvent->ce.context = pContext;
  1349.     MAKE_EAGER(pEvent);
  1350.     pEvent->layer_obj = layer_obj;
  1351.     et_event_to_mocha(&pEvent->ce);
  1352. }
  1353.  
  1354. /**********************************************************************/
  1355.  
  1356. typedef struct {
  1357.     ETEvent    ce;
  1358.     JSBool    resize_reload;
  1359. } ReleaseDocStruct;
  1360.  
  1361. PR_STATIC_CALLBACK(void)
  1362. et_releasedocument_handler(ReleaseDocStruct * e)
  1363. {
  1364.     ET_BEGIN_EVENT_HANDLER(e);
  1365.  
  1366.     LM_ReleaseDocument(e->ce.context, e->resize_reload);
  1367.  
  1368.     ET_END_EVENT_HANDLER(e);
  1369. }
  1370.  
  1371. void
  1372. ET_ReleaseDocument(MWContext * pContext, JSBool resize_reload)
  1373. {
  1374.     /* create our event object */
  1375.     ReleaseDocStruct * pEvent = XP_NEW_ZAP(ReleaseDocStruct);
  1376.     if(!pEvent)
  1377.         return;
  1378.  
  1379.     /* 
  1380.      * give this event a NULL owner so it can't get revoked by an
  1381.      *   errant intertupt
  1382.      */
  1383.     PR_InitEvent(&pEvent->ce.event, NULL,
  1384.          (PRHandleEventProc)et_releasedocument_handler, 
  1385.          (PRDestroyEventProc)et_generic_destructor);
  1386.  
  1387.     pEvent->ce.context = pContext;
  1388.     MAKE_EAGER(pEvent);
  1389.     pEvent->resize_reload = resize_reload;
  1390.     et_event_to_mocha(&pEvent->ce);
  1391.  
  1392. }
  1393.  
  1394. /**********************************************************************/
  1395.  
  1396. typedef struct {
  1397.     ETEvent              ce;
  1398.    IL_GroupContext *img_cx;
  1399. } InterruptImgCXEvent;
  1400.  
  1401.  
  1402. PR_STATIC_CALLBACK(void)
  1403. et_moz_interruptimgcx_func(void *data)
  1404. {
  1405.     InterruptImgCXEvent *e = data;
  1406.  
  1407.     IL_InterruptContext(e->img_cx);    
  1408. }
  1409.  
  1410.  
  1411. PR_STATIC_CALLBACK(void)
  1412. et_interruptimgcx_handler(InterruptImgCXEvent *e)
  1413. {
  1414.     ET_BEGIN_EVENT_HANDLER(e);
  1415.  
  1416.     e->img_cx = decoder->image_context;
  1417.     ET_moz_CallFunction(et_moz_interruptimgcx_func, e);
  1418.  
  1419.     ET_END_EVENT_HANDLER(e);
  1420. }
  1421.  
  1422. void
  1423. ET_InterruptImgCX(MWContext * pContext)
  1424. {
  1425.     InterruptImgCXEvent * pEvent = XP_NEW_ZAP(InterruptImgCXEvent);
  1426.     if(!pEvent)
  1427.         return;
  1428.  
  1429.     PR_InitEvent(&pEvent->ce.event, pContext,
  1430.          (PRHandleEventProc)et_interruptimgcx_handler, 
  1431.          (PRDestroyEventProc)et_generic_destructor);
  1432.  
  1433.     pEvent->ce.context = pContext;
  1434.     et_event_to_mocha(&pEvent->ce);
  1435.  
  1436. }
  1437.  
  1438. /**********************************************************************/
  1439.  
  1440. typedef struct {
  1441.     ETEvent          ce;
  1442.     char        * szUrl;
  1443. } NestingUrlEvent;
  1444.  
  1445. PR_STATIC_CALLBACK(void)
  1446. et_nestingurl_handler(NestingUrlEvent * e)
  1447. {
  1448.     JSNestingUrl * url;
  1449.     ET_BEGIN_EVENT_HANDLER(e);
  1450.  
  1451.     if (e->szUrl) {
  1452.     /* push a new url */
  1453.     url = XP_NEW(JSNestingUrl);
  1454.     url->str = e->szUrl;
  1455.     url->next = decoder->nesting_url;
  1456.     decoder->nesting_url = url;
  1457.     e->szUrl = NULL; /* don't free below */
  1458.     }
  1459.     else {
  1460.     /* pop an old url */
  1461.     url = decoder->nesting_url;
  1462.     if (url) {
  1463.         decoder->nesting_url = url->next;
  1464.         XP_FREE(url->str);
  1465.         XP_FREE(url);
  1466.     }
  1467.     }
  1468.  
  1469.     ET_END_EVENT_HANDLER(e);
  1470. }
  1471.  
  1472. PR_STATIC_CALLBACK(void)
  1473. et_nestingurl_destructor(NestingUrlEvent * e)
  1474. {
  1475.     XP_FREEIF(e->szUrl);
  1476.     XP_FREE(e);
  1477. }
  1478.  
  1479. void
  1480. ET_SetNestingUrl(MWContext * pContext, char * url)
  1481. {
  1482.     NestingUrlEvent * pEvent = XP_NEW_ZAP(NestingUrlEvent);
  1483.     if(!pEvent)
  1484.         return;
  1485.  
  1486.     PR_InitEvent(&pEvent->ce.event, pContext,
  1487.          (PRHandleEventProc)et_nestingurl_handler, 
  1488.          (PRDestroyEventProc)et_nestingurl_destructor);
  1489.  
  1490.     pEvent->ce.context = pContext;
  1491.     MAKE_EAGER(pEvent);
  1492.     if(url)
  1493.     pEvent->szUrl = XP_STRDUP(url);
  1494.     else
  1495.     pEvent->szUrl = NULL;
  1496.  
  1497.     et_event_to_mocha(&pEvent->ce);
  1498.  
  1499. }
  1500.  
  1501.  
  1502. /**********************************************************************/
  1503.  
  1504. typedef struct {
  1505.     ETEvent          ce;
  1506.     JSVersion             version;
  1507. } VersionEvent;
  1508.  
  1509. PR_STATIC_CALLBACK(void)
  1510. et_version_handler(VersionEvent * e)
  1511. {
  1512.     ET_BEGIN_EVENT_HANDLER(e);
  1513.  
  1514.     JS_SetVersion(decoder->js_context, e->version);
  1515.  
  1516.     ET_END_EVENT_HANDLER(e);
  1517. }
  1518.  
  1519. void
  1520. ET_SetVersion(MWContext * pContext, JSVersion version)
  1521. {
  1522.     VersionEvent * pEvent = XP_NEW_ZAP(VersionEvent);
  1523.     if (pEvent == NULL)
  1524.         return;
  1525.  
  1526.     PR_InitEvent(&pEvent->ce.event, pContext,
  1527.          (PRHandleEventProc)et_version_handler, 
  1528.          (PRDestroyEventProc)et_generic_destructor);
  1529.  
  1530.     pEvent->ce.context = pContext;
  1531.     pEvent->version = version;
  1532.     et_event_to_mocha(&pEvent->ce);
  1533.  
  1534. }
  1535.  
  1536.  
  1537. /**********************************************************************/
  1538.  
  1539. typedef struct {
  1540.     ETEvent              ce;
  1541.     void                * data;
  1542.     ETVoidPtrFunc         fn;
  1543.     History_entry    * he;
  1544. } RemoveWindowEvent;
  1545.  
  1546. PR_STATIC_CALLBACK(void)
  1547. et_moz_removewindow_epilog(void *data)
  1548. {
  1549.     RemoveWindowEvent *e = data;
  1550.  
  1551.     /* Do this before calling e->fn, which nukes e->ce.context! */
  1552.     if (e->he)
  1553.         SHIST_DropEntry(e->ce.context, e->he);
  1554.  
  1555.     /* Call the FE to destroy the context, finally. */
  1556.     e->fn(e->data);
  1557. }
  1558.  
  1559. /*
  1560.  * Don't try to get the MochaDecoder in here with the
  1561.  *   ET_BEGIN_EVENT_HANDLER() stuff since the decoder
  1562.  *   already partially destroyed
  1563.  */
  1564. PR_STATIC_CALLBACK(void)
  1565. et_removewindow_handler(RemoveWindowEvent * e)
  1566. {
  1567.     LM_RemoveWindowContext(e->ce.context, e->he);
  1568.  
  1569.     /* remove any messages for this context that are waiting for us */
  1570.     /* what prevents one from getting added while running this? 
  1571.        A: Being in the monitor of lm_InterpretQueue, both when you do
  1572.        this, and when you deliver the events. -Warren */
  1573. /*    XP_ASSERT(PR_InMonitor(lm_queue_monitor));*/
  1574.     et_RevokeEvents(e->ce.context);
  1575.  
  1576.     ET_moz_CallFunction(et_moz_removewindow_epilog, e);
  1577. }
  1578.  
  1579. void
  1580. ET_RemoveWindowContext(MWContext * pContext, ETVoidPtrFunc fn, void * data)
  1581. {
  1582.     /* create our event object */
  1583.     RemoveWindowEvent * pEvent;
  1584.     History_entry * he = NULL;
  1585.  
  1586.     /* 
  1587.      * If mocha is disabled or this is a non-JS aware context don't 
  1588.      *   bother creating an event, just call the closure directly
  1589.      */
  1590.     if (!LM_CanDoJS(pContext)) {
  1591.     ET_moz_CallFunctionAsync(fn, data);
  1592.     return;
  1593.     }    
  1594.  
  1595.     /*
  1596.      * Allocate an event before possibly holding a history entry, so we can
  1597.      * return early without possibly having to drop.
  1598.      */
  1599.     pEvent = XP_NEW_ZAP(RemoveWindowEvent);
  1600.     if (!pEvent)
  1601.         return;
  1602.  
  1603.     /*
  1604.      * Frames are special, because their contexts are destroyed and recreated
  1605.      * when they're reloaded, even when resizing.
  1606.      */
  1607.     if (pContext->is_grid_cell) {
  1608.     lo_GridRec *grid = 0;
  1609.     lo_GridCellRec *rec = lo_ContextToCell(pContext, FALSE, &grid);
  1610.  
  1611.     if (rec && rec->hist_indx > 0) {
  1612.         he = (History_entry *)rec->hist_array[rec->hist_indx - 1].hist;
  1613.         SHIST_HoldEntry(he);
  1614.     }
  1615.     }
  1616.  
  1617.     PR_InitEvent(&pEvent->ce.event, pContext,
  1618.          (PRHandleEventProc)et_removewindow_handler, 
  1619.          (PRDestroyEventProc)et_generic_destructor);
  1620.  
  1621.     pEvent->ce.context = pContext;
  1622.     pEvent->fn = fn;
  1623.     pEvent->data = data;
  1624.     pEvent->he = he;
  1625.  
  1626.     /* set the doc_id so that we don't try to reuse this context */
  1627.     pContext->doc_id = -1;
  1628.  
  1629.     et_event_to_mocha(&pEvent->ce);
  1630.  
  1631. }
  1632.  
  1633.  
  1634. /**********************************************************************/
  1635.  
  1636. typedef struct {
  1637.     ETEvent              ce;
  1638.     MochaDecoder        * decoder;
  1639. } PutDecoderEvent;
  1640.  
  1641. PR_STATIC_CALLBACK(void)
  1642. et_putdecoder_handler(PutDecoderEvent * e)
  1643. {
  1644.     LM_PutMochaDecoder(e->decoder);
  1645. }
  1646.  
  1647. /*
  1648.  * The mozilla thread is, in general, not allowed into the world of
  1649.  *   MochaDecoders, but one could have been stashed in a session
  1650.  *   history object.  If so, provide a way for the mozilla thread to
  1651.  *   release the decoder when the history object goes away.
  1652.  */
  1653. void
  1654. et_PutMochaDecoder(MWContext *pContext, MochaDecoder *decoder)
  1655. {
  1656.     PutDecoderEvent * pEvent;
  1657.     pEvent = XP_NEW_ZAP(PutDecoderEvent);
  1658.     if (!pEvent)
  1659.         return;
  1660.  
  1661.     PR_InitEvent(&pEvent->ce.event, pContext,
  1662.          (PRHandleEventProc)et_putdecoder_handler,
  1663.          (PRDestroyEventProc)et_generic_destructor);
  1664.  
  1665.     pEvent->ce.context = pContext;
  1666.     pEvent->decoder = decoder;
  1667.     et_event_to_mocha(&pEvent->ce);
  1668.  
  1669. }
  1670.  
  1671. /**********************************************************************/
  1672.  
  1673.  typedef struct {
  1674.      ETEvent              ce;
  1675.      void *       app;
  1676.  } SetPluginWindowEvent;
  1677.  
  1678.  PR_EXTERN(void) NPL_SetPluginWindow(void *);
  1679.  
  1680.  PR_STATIC_CALLBACK(void)
  1681.  et_SetPluginWindow_handler(SetPluginWindowEvent * e)
  1682.  {
  1683.      NPL_SetPluginWindow(e->app);
  1684.  }
  1685.  
  1686.  void
  1687.  ET_SetPluginWindow(MWContext *pContext, void* app)
  1688.  {
  1689.      SetPluginWindowEvent * pEvent;
  1690.      pEvent = XP_NEW_ZAP(SetPluginWindowEvent);
  1691.      if (!pEvent)
  1692.          return;
  1693.  
  1694.      PR_InitEvent(&pEvent->ce.event, pContext,
  1695.           (PRHandleEventProc)et_SetPluginWindow_handler,
  1696.           (PRDestroyEventProc)et_generic_destructor);
  1697.  
  1698.      pEvent->ce.context = pContext;
  1699.      pEvent->app = app;
  1700.      et_event_to_mocha(&pEvent->ce);
  1701.  }
  1702. /**********************************************************************/
  1703.  
  1704. typedef struct {
  1705.     ETEvent    ce;
  1706.     void      * buf;
  1707.     int        len;
  1708.     int        status;
  1709.     char      * content_type;
  1710.     Bool    isUnicode;
  1711. } StreamEvent;
  1712.  
  1713. PR_STATIC_CALLBACK(void)
  1714. et_streamcomplete_handler(StreamEvent * e)
  1715. {
  1716.     jsval result;
  1717.     JSContext * cx;
  1718.     char *scope = NULL;
  1719.     JSNestingUrl * url;
  1720.  
  1721.     ET_BEGIN_EVENT_HANDLER(e);
  1722.  
  1723.     cx = decoder->js_context;
  1724.  
  1725.     if(e->content_type) {
  1726.     if(!strcasecomp(e->content_type, TEXT_JSSS)) {
  1727.         /* scope to document */
  1728.         scope = lm_document_str;
  1729.     }
  1730.     else if(!strcasecomp(e->content_type, TEXT_CSS)) {
  1731.         /* convert to JS and scope to document */
  1732.         char *new_buffer;
  1733.         int32 new_buffer_length;
  1734.  
  1735.         CSS_ConvertToJS(e->buf, 
  1736.                 e->len,
  1737.                 &new_buffer,
  1738.                 &new_buffer_length);
  1739.  
  1740.             XP_FREE(e->buf);
  1741.         e->buf = new_buffer;
  1742.         e->len = new_buffer_length;
  1743.  
  1744.         if(e->len)
  1745.         e->len--; /* hack: subtract one to remove final \n */
  1746.  
  1747.         scope = lm_document_str;
  1748.     }
  1749.     }
  1750.  
  1751. #ifdef JSDEBUGGER
  1752.     if( LM_GetJSDebugActive() )
  1753.         LM_JamSourceIntoJSDebug( LM_GetSourceURL(decoder), 
  1754.                                  e->buf, e->len, e->ce.context );
  1755. #endif /* JSDEBUGGER */
  1756.  
  1757.     LM_EvaluateBuffer(decoder, e->buf, e->len, 1, scope, NULL, 
  1758.               (JSBool) e->isUnicode, &result);
  1759.  
  1760.     url = decoder->nesting_url;
  1761.     if (decoder->stream && !url) {
  1762.     /* complete and remove the stream */
  1763.     ET_moz_CallFunction( (ETVoidPtrFunc) decoder->stream->complete, 
  1764.                 (void *)decoder->stream);
  1765.         XP_DELETE(decoder->stream); 
  1766.         decoder->stream = 0;
  1767.         decoder->stream_owner = LO_DOCUMENT_LAYER_ID;
  1768.         decoder->free_stream_on_close = JS_FALSE;
  1769.     }
  1770.  
  1771.     if (url) {
  1772.     decoder->nesting_url = url->next;
  1773.     XP_FREE(url->str);
  1774.     XP_FREE(url);
  1775.     ET_PostEvalAck(e->ce.context, XP_DOCID(e->ce.context),
  1776.                e->ce.context, NULL, 0, NULL, NULL, FALSE,
  1777.                lo_ScriptEvalExitFn);
  1778.     }
  1779.     
  1780.     ET_END_EVENT_HANDLER(e);
  1781. }
  1782.  
  1783. PR_STATIC_CALLBACK(void)
  1784. et_streamcomplete_destructor(StreamEvent * e)
  1785. {
  1786.     if(e->buf)
  1787.     XP_FREE(e->buf);
  1788.     XP_FREEIF(e->content_type);
  1789.     XP_FREE(e);
  1790. }
  1791.  
  1792. /*
  1793.  * A mocha stream from netlib has compeleted, eveluate the contents
  1794.  *   and pass them up our stream.  We will take ownership of the 
  1795.  *   buf argument and are responsible for freeing it
  1796.  */
  1797. void
  1798. ET_MochaStreamComplete(MWContext * pContext, void * buf, int len, 
  1799.                char *content_type, Bool isUnicode)
  1800. {
  1801.     StreamEvent * pEvent;
  1802.  
  1803.     pEvent = XP_NEW_ZAP(StreamEvent);
  1804.     if(!pEvent) {
  1805.     XP_FREE(buf);
  1806.         return;
  1807.     }
  1808.  
  1809.     PR_InitEvent(&pEvent->ce.event, pContext,
  1810.          (PRHandleEventProc)et_streamcomplete_handler, 
  1811.          (PRDestroyEventProc)et_streamcomplete_destructor);
  1812.  
  1813.     pEvent->ce.context = pContext;    
  1814.     MAKE_EAGER(pEvent);
  1815.     pEvent->buf = buf;
  1816.     pEvent->len = len;
  1817.     pEvent->isUnicode = isUnicode;
  1818.     if (content_type)
  1819.     pEvent->content_type = XP_STRDUP(content_type);
  1820.  
  1821.     et_event_to_mocha(&pEvent->ce);
  1822.  
  1823. }
  1824.  
  1825. /**********************************************************************/
  1826.  
  1827. PR_STATIC_CALLBACK(void)
  1828. et_streamabort_handler(StreamEvent * e)
  1829. {
  1830.     ET_BEGIN_EVENT_HANDLER(e);
  1831.  
  1832.     if (decoder->stream && !decoder->nesting_url) {
  1833.         ET_moz_Abort(decoder->stream->abort, decoder->stream, e->status);
  1834.         XP_DELETE(decoder->stream);
  1835.         decoder->stream = 0;
  1836.         decoder->free_stream_on_close = JS_FALSE;
  1837.         decoder->stream_owner = LO_DOCUMENT_LAYER_ID;
  1838.     }
  1839.  
  1840.     ET_END_EVENT_HANDLER(e);
  1841. }
  1842.  
  1843. /*
  1844.  * A mocha stream from netlib has aborted
  1845.  */
  1846. void
  1847. ET_MochaStreamAbort(MWContext * context, int status)
  1848. {
  1849.  
  1850.     StreamEvent * pEvent = XP_NEW_ZAP(StreamEvent);
  1851.  
  1852.     if(!pEvent)
  1853.         return;
  1854.  
  1855.     PR_InitEvent(&pEvent->ce.event, context,
  1856.                  (PRHandleEventProc)et_streamabort_handler, 
  1857.                  (PRDestroyEventProc)et_generic_destructor);
  1858.  
  1859.     pEvent->ce.context = context;
  1860.     pEvent->status = status;
  1861.     et_event_to_mocha(&pEvent->ce);
  1862.  
  1863. }
  1864.  
  1865. /**********************************************************************/
  1866.  
  1867. PR_STATIC_CALLBACK(void)
  1868. et_newlayerdoc_handler(JSEvent * e)
  1869. {
  1870.     ET_BEGIN_EVENT_HANDLER(e);
  1871.  
  1872.     lm_NewLayerDocument(decoder, e->layer_id);
  1873.  
  1874.     ET_END_EVENT_HANDLER(e);
  1875. }
  1876.  
  1877. /*
  1878.  * A mocha stream from netlib has aborted
  1879.  */
  1880. void
  1881. ET_NewLayerDocument(MWContext * context, int32 layer_id)
  1882. {
  1883.  
  1884.     JSEvent * pEvent = XP_NEW_ZAP(JSEvent);
  1885.  
  1886.     if(!pEvent)
  1887.         return;
  1888.  
  1889.     /* do a PR_InitEvent on the event structure */
  1890.     PR_InitEvent(&pEvent->ce.event, context,
  1891.          (PRHandleEventProc)et_newlayerdoc_handler, 
  1892.          (PRDestroyEventProc)et_generic_destructor);
  1893.  
  1894.     pEvent->ce.context = context;
  1895.     pEvent->layer_id = layer_id;
  1896.     et_event_to_mocha(&pEvent->ce);
  1897.  
  1898. }
  1899.  
  1900. /**********************************************************************/
  1901.  
  1902. typedef struct {
  1903.     ETEvent ce;
  1904.     int32 layer_id;
  1905.     LO_BlockInitializeStruct *param;
  1906.     ETRestoreAckFunc fn;
  1907.     void *data;
  1908. } RestoreStruct;
  1909.  
  1910.  
  1911. PR_STATIC_CALLBACK(void)
  1912. et_restorelayerstate_handler(RestoreStruct * e)
  1913. {
  1914.     ET_BEGIN_EVENT_HANDLER(e);
  1915.  
  1916.     lm_RestoreLayerState(e->ce.context, e->layer_id, 
  1917.                          e->param);
  1918.  
  1919.     ET_PostRestoreAck(e->data, e->param, e->fn);
  1920.  
  1921.     ET_END_EVENT_HANDLER(e);
  1922. }
  1923.  
  1924. void 
  1925. ET_RestoreLayerState(MWContext *context, int32 layer_id,
  1926.                      LO_BlockInitializeStruct *param, ETRestoreAckFunc fn,
  1927.                      void *data)
  1928. {
  1929.  
  1930.     RestoreStruct * pEvent = XP_NEW_ZAP(RestoreStruct);
  1931.  
  1932.     if(!pEvent)
  1933.         return;
  1934.  
  1935.     PR_InitEvent(&pEvent->ce.event, context,
  1936.          (PRHandleEventProc)et_restorelayerstate_handler, 
  1937.          (PRDestroyEventProc)et_generic_destructor);
  1938.  
  1939.     pEvent->ce.context = context;
  1940.     pEvent->layer_id = layer_id;
  1941.     pEvent->param = param;
  1942.     pEvent->fn = fn;
  1943.     pEvent->data = data;
  1944.     MAKE_EAGER(pEvent);
  1945.     et_event_to_mocha(&pEvent->ce);
  1946. }
  1947.  
  1948.  
  1949. /**********************************************************************/
  1950.  
  1951. typedef struct {
  1952.     ETEvent    ce;
  1953.     PA_Block    onload;
  1954.     PA_Block    onunload;
  1955.     PA_Block    onfocus;
  1956.     PA_Block    onblur;
  1957.     PA_Block    onhelp;
  1958.     PA_Block    onmouseover;
  1959.     PA_Block    onmouseout;
  1960.     PA_Block    ondragdrop;
  1961.     PA_Block    onmove;
  1962.     PA_Block    onresize;
  1963.     PA_Block    id;
  1964.     char        *all;
  1965.     Bool    bDelete;
  1966.     int        newline_count;
  1967. } ReflectWindowEvent;
  1968.  
  1969. PR_STATIC_CALLBACK(void)
  1970. et_reflectwindow_handler(ReflectWindowEvent * e)
  1971. {
  1972.     JSObject *obj;
  1973.  
  1974.     ET_BEGIN_EVENT_HANDLER(e);
  1975.  
  1976.     obj = decoder->window_object;
  1977.  
  1978.     if (e->onload) {
  1979.     (void) lm_CompileEventHandler(decoder, e->id, (PA_Block) e->all, 
  1980.                       e->newline_count, 
  1981.                       obj, PARAM_ONLOAD, e->onload);
  1982.     }
  1983.     if (e->onunload) {
  1984.     (void) lm_CompileEventHandler(decoder, e->id, (PA_Block) e->all, 
  1985.                       e->newline_count, 
  1986.                       obj, PARAM_ONUNLOAD, e->onunload);    
  1987.     }
  1988.     if (e->onfocus) {
  1989.     (void) lm_CompileEventHandler(decoder, e->id, (PA_Block) e->all, 
  1990.                       e->newline_count, 
  1991.                       obj, PARAM_ONFOCUS, e->onfocus);    
  1992.     }
  1993.     if (e->onblur) {
  1994.     (void) lm_CompileEventHandler(decoder, e->id, (PA_Block) e->all, 
  1995.                       e->newline_count, 
  1996.                       obj, PARAM_ONBLUR, e->onblur);    
  1997.     }
  1998.  
  1999.     if (e->onhelp) {
  2000.     (void) lm_CompileEventHandler(decoder, e->id, (PA_Block) e->all, 
  2001.                       e->newline_count, 
  2002.                       obj, PARAM_ONHELP, e->onhelp);    
  2003.     }
  2004.  
  2005.     if (e->onmouseover) {
  2006.     (void) lm_CompileEventHandler(decoder, e->id, (PA_Block) e->all, 
  2007.                       e->newline_count, 
  2008.                       obj, PARAM_ONMOUSEOVER, e->onmouseover);    
  2009.     }
  2010.  
  2011.     if (e->onmouseout) {
  2012.     (void) lm_CompileEventHandler(decoder, e->id, (PA_Block) e->all, 
  2013.                       e->newline_count, 
  2014.                       obj, PARAM_ONMOUSEOUT, e->onmouseout);    
  2015.     }
  2016.  
  2017.     if (e->ondragdrop) {
  2018.     (void) lm_CompileEventHandler(decoder, e->id, (PA_Block) e->all, 
  2019.                       e->newline_count, 
  2020.                       obj, PARAM_ONDRAGDROP, e->ondragdrop);    
  2021.     }
  2022.  
  2023.     if (e->onmove) {
  2024.     (void) lm_CompileEventHandler(decoder, e->id, (PA_Block) e->all, 
  2025.                       e->newline_count, 
  2026.                       obj, PARAM_ONMOVE, e->onmove);    
  2027.     }
  2028.  
  2029.     if (e->onresize) {
  2030.     (void) lm_CompileEventHandler(decoder, e->id, (PA_Block) e->all, 
  2031.                       e->newline_count, 
  2032.                       obj, PARAM_ONRESIZE, e->onresize);    
  2033.     }
  2034.  
  2035.     if (e->bDelete) {
  2036.     if(e->onload)
  2037.         XP_FREE(e->onload);
  2038.     if(e->onunload)
  2039.         XP_FREE(e->onunload);
  2040.     if(e->onfocus)
  2041.         XP_FREE(e->onfocus);
  2042.     if(e->onblur)
  2043.         XP_FREE(e->onblur);
  2044.     if(e->onhelp)
  2045.         XP_FREE(e->onhelp);
  2046.     if(e->onmouseover)
  2047.         XP_FREE(e->onmouseover);
  2048.     if(e->onmouseout)
  2049.         XP_FREE(e->onmouseout);
  2050.     if(e->ondragdrop)
  2051.         XP_FREE(e->ondragdrop);
  2052.     if(e->onmove)
  2053.         XP_FREE(e->onmove);
  2054.     if(e->onresize)
  2055.         XP_FREE(e->onresize);
  2056.     if(e->id)
  2057.         XP_FREE(e->id);
  2058.     if(e->all)
  2059.         XP_FREE(e->all);
  2060.     }
  2061.  
  2062.     ET_END_EVENT_HANDLER(e);
  2063. }
  2064.  
  2065. /*
  2066.  * Reflect window events
  2067.  */
  2068. void
  2069. ET_ReflectWindow(MWContext * pContext, 
  2070.          PA_Block onLoad, PA_Block onUnload, 
  2071.          PA_Block onFocus, PA_Block onBlur, PA_Block onHelp,
  2072.          PA_Block onMouseOver, PA_Block onMouseOut, PA_Block onDragDrop,
  2073.          PA_Block onMove, PA_Block onResize,
  2074.                  PA_Block id, char *all, Bool bDelete, 
  2075.                  int newline_count)
  2076. {
  2077.  
  2078.     ReflectWindowEvent * pEvent = XP_NEW_ZAP(ReflectWindowEvent);
  2079.     if(!pEvent)
  2080.         return;
  2081.  
  2082.     PR_InitEvent(&pEvent->ce.event, pContext,
  2083.          (PRHandleEventProc)et_reflectwindow_handler, 
  2084.          (PRDestroyEventProc)et_generic_destructor);
  2085.  
  2086.     pEvent->ce.context = pContext;
  2087.     MAKE_EAGER(pEvent);
  2088.     pEvent->onload = onLoad;
  2089.     pEvent->onunload = onUnload;
  2090.     pEvent->onfocus = onFocus;
  2091.     pEvent->onblur = onBlur;
  2092.     pEvent->onhelp = onHelp;
  2093.     pEvent->onmouseover = onMouseOver;
  2094.     pEvent->onmouseout = onMouseOut;
  2095.     pEvent->ondragdrop = onDragDrop;
  2096.     pEvent->onmove = onMove;
  2097.     pEvent->onresize = onResize;
  2098.     pEvent->id = id;
  2099.     pEvent->all = all;
  2100.     pEvent->bDelete = bDelete;
  2101.     pEvent->newline_count = newline_count;
  2102.  
  2103.     /* add the event to the event queue */
  2104.     et_event_to_mocha(&pEvent->ce);
  2105.  
  2106. }
  2107.  
  2108. /**********************************************************************/
  2109.  
  2110. #ifdef DEBUG
  2111. PR_STATIC_CALLBACK(void)
  2112. lm_dump_named_root(const char *name, void *rp, void *data)
  2113. {
  2114.     XP_TRACE(("Leaked named root \"%s\" at 0x%x", name, rp));
  2115. }
  2116. #endif
  2117.  
  2118. PR_STATIC_CALLBACK(void)
  2119. et_FinishMochaHandler(JSEvent * e)
  2120. {
  2121.     MochaDecoder *decoder;
  2122.  
  2123.     decoder = lm_crippled_decoder;
  2124.     if (decoder) {
  2125.     LM_PutMochaDecoder(decoder);
  2126.     lm_crippled_decoder = 0;
  2127.     }
  2128.  
  2129. #ifdef JAVA
  2130.     JSJ_Finish();
  2131. #endif
  2132. #ifdef DEBUG
  2133.     JS_DumpNamedRoots(lm_runtime, lm_dump_named_root, NULL);
  2134. #endif
  2135.     JS_Finish(lm_runtime);
  2136.  
  2137.     /* turn off the mocha thread here! */
  2138.  
  2139. }
  2140.  
  2141. void
  2142. ET_FinishMocha(void)
  2143. {
  2144.  
  2145.     JSEvent * pEvent;
  2146.  
  2147.     /*
  2148.      * Annoyingly, the winfe might call us without event actually
  2149.      *   initializing mocha (if an instance is already running)
  2150.      */
  2151.     if (!lm_InterpretQueue)
  2152.     return;
  2153.  
  2154.     pEvent = XP_NEW_ZAP(JSEvent);
  2155.     if (!pEvent)
  2156.         return;
  2157.  
  2158.     PR_InitEvent(&pEvent->ce.event, NULL,
  2159.          (PRHandleEventProc)et_FinishMochaHandler, 
  2160.          (PRDestroyEventProc)et_generic_destructor);
  2161.  
  2162.     et_event_to_mocha(&pEvent->ce);
  2163.  
  2164. }
  2165.  
  2166. /**********************************************************************/
  2167.  
  2168. typedef struct {
  2169.     ETEvent    ce;
  2170.     void      * data;
  2171.     JSBool    processed;
  2172. } DocWriteAckEvent;
  2173.  
  2174. PR_STATIC_CALLBACK(void)
  2175. et_docwriteack_handler(DocWriteAckEvent * e)
  2176. {
  2177.     e->processed = JS_TRUE;
  2178.     et_TopQueue->done = TRUE;
  2179.     et_TopQueue->retval = e->data;
  2180. }
  2181.  
  2182. PR_STATIC_CALLBACK(void)
  2183. et_docwriteack_destructor(DocWriteAckEvent * e)
  2184. {
  2185.     if (!e->processed)
  2186.     et_docwriteack_handler(e);
  2187.     XP_FREE(e);
  2188. }              
  2189.  
  2190. void
  2191. ET_DocWriteAck(MWContext * context, int status)
  2192. {
  2193.     DocWriteAckEvent * pEvent;
  2194.  
  2195.     pEvent = XP_NEW_ZAP(DocWriteAckEvent);
  2196.     if (!pEvent)
  2197.         return;
  2198.  
  2199.     PR_InitEvent(&pEvent->ce.event, context,
  2200.          (PRHandleEventProc)et_docwriteack_handler, 
  2201.          (PRDestroyEventProc)et_docwriteack_destructor);
  2202.  
  2203.     pEvent->ce.context = context;
  2204.     pEvent->ce.handle_eagerly = TRUE;
  2205.     pEvent->data = (void *)status;
  2206.     et_event_to_mocha(&pEvent->ce);
  2207. }
  2208.  
  2209. /**********************************************************************/
  2210.  
  2211. void
  2212. et_SubEventLoop(QueueStackElement * qse)
  2213. {
  2214.     PREvent      * pEvent;
  2215.  
  2216.     /* while there are events process them */
  2217.     while (!qse->done) {
  2218.  
  2219.     /* can't be interrupted yet */
  2220.     lm_InterruptCurrentOp = JS_FALSE;
  2221.  
  2222.         LM_LockJS();
  2223.     /* need to interlock the getting of an event with ET_Interrupt */
  2224.         PR_EnterMonitor(lm_queue_monitor);
  2225.         pEvent = PR_GetEvent(qse->queue);
  2226.  
  2227.     /* if we got an event handle it else wait for something */
  2228.         if(pEvent) {
  2229.             PR_ExitMonitor(lm_queue_monitor);
  2230.         LM_JSLockSetContext(((ETEvent *)pEvent)->context);
  2231.             PR_HandleEvent(pEvent);
  2232.             LM_UnlockJS();
  2233. #ifdef DEBUG
  2234.         /* make sure we don't have the layout lock */
  2235.         while(!LO_VerifyUnlockedLayout()) {
  2236.         XP_ASSERT(0);
  2237.         LO_UnlockLayout();
  2238.         }
  2239. #endif
  2240.  
  2241.         }
  2242.         else {
  2243.             /* queue is empty, wait for something to show up */
  2244.             LM_UnlockJS();
  2245.             PR_Wait(lm_queue_monitor, PR_INTERVAL_NO_TIMEOUT);
  2246.             PR_ExitMonitor(lm_queue_monitor);
  2247.         }
  2248.          
  2249.     }
  2250. }
  2251.  
  2252. extern PRThread            *lm_InterpretThread;
  2253. extern PRMonitor *lm_owner_mon;
  2254.  
  2255. /*
  2256.  * Sit around in the mocha thread waiting for events to show up
  2257.  */
  2258. void PR_CALLBACK
  2259. lm_wait_for_events(void * pB)
  2260. {
  2261.     XP_ASSERT(et_TopQueue);
  2262.  
  2263.     /*
  2264.      * In NSPR 2.0 this thread could get created and it could start
  2265.      *   running before our parent is done initializing our state.
  2266.      *   The mozilla thread will have done a PR_EnterMonitor() on
  2267.      *   the lm_owner_mon before creating the mocha thread and will
  2268.      *   not exit the monitor until all of the state is initialized.
  2269.      *   So we are assured that if we can get the monitor here the
  2270.      *   mozilla thread has released it and we are OK to run.
  2271.      */
  2272.     PR_EnterMonitor(lm_owner_mon);
  2273.     PR_ExitMonitor(lm_owner_mon);
  2274.  
  2275.     /* set up the initial queue stack pointers */
  2276.     et_TopQueue->queue = lm_InterpretQueue;
  2277.  
  2278.     /* create our monitor if it doesn't exist already */
  2279.     if(lm_queue_monitor == NULL) {
  2280.         lm_queue_monitor = PR_NewNamedMonitor("lm-queue-monitor");
  2281.         if(!lm_queue_monitor)
  2282.             return;
  2283.     }
  2284.  
  2285.     while (TRUE) {
  2286.     et_SubEventLoop(et_TopQueue);
  2287.  
  2288.     /* should never get here but just in case behave nicely */
  2289.     XP_ASSERT(0);
  2290.     et_TopQueue->done = FALSE;
  2291.     }
  2292.  
  2293. }
  2294.  
  2295. /**********************************************************************/
  2296.  
  2297. typedef struct {
  2298.     ETEvent        ce;
  2299.     char       *name;
  2300.     ETBoolPtrFunc   active_callback;
  2301.     ETVoidPtrFunc   startup_callback;
  2302. } RegComponentStruct;
  2303.  
  2304. PR_STATIC_CALLBACK(void)
  2305. et_registercomponent_handler(RegComponentStruct * e)
  2306. {
  2307.     lm_RegisterComponent(e->name, e->active_callback, e->startup_callback);
  2308. }
  2309.  
  2310. PR_STATIC_CALLBACK(void)
  2311. et_registercomponent_destructor(RegComponentStruct * e)
  2312. {
  2313.     if (e->name)
  2314.         XP_FREE(e->name);
  2315.  
  2316.     XP_FREE(e);
  2317. }
  2318.  
  2319. void
  2320. ET_RegisterComponent(char *name, void *active_callback, void *startup_callback)
  2321. {
  2322.     /* create our event object */
  2323.     RegComponentStruct * pEvent = XP_NEW_ZAP(RegComponentStruct);
  2324.     if(!pEvent)
  2325.         return;
  2326.  
  2327.     /* do a PR_InitEvent on the event structure */
  2328.     PR_InitEvent(&pEvent->ce.event, NULL,
  2329.          (PRHandleEventProc)et_registercomponent_handler, 
  2330.          (PRDestroyEventProc)et_registercomponent_destructor);
  2331.  
  2332.     /* fill in the non-PR fields we care about */
  2333.     if (name)
  2334.     pEvent->name = XP_STRDUP(name);
  2335.     else
  2336.     pEvent->name = NULL;
  2337.     pEvent->active_callback = (ETBoolPtrFunc)active_callback;
  2338.     pEvent->startup_callback = (ETVoidPtrFunc)startup_callback;
  2339.  
  2340.     /* add the event to the event queue */
  2341.     et_event_to_mocha(&pEvent->ce);
  2342. }
  2343.  
  2344. /**********************************************************************/
  2345.  
  2346. typedef struct {
  2347.     ETEvent    ce;
  2348.     char       *comp;
  2349.     char       *name;
  2350.     uint8    retType;
  2351.     void       *setter;
  2352.     void       *getter;
  2353. } RegComponentPropStruct;
  2354.  
  2355. PR_STATIC_CALLBACK(void)
  2356. et_registercomponentprop_handler(RegComponentPropStruct * e)
  2357. {
  2358.     lm_RegisterComponentProp(e->comp, e->name, e->retType, 
  2359.     (ETCompPropSetterFunc)e->setter, (ETCompPropGetterFunc)e->getter); 
  2360. }
  2361.  
  2362. PR_STATIC_CALLBACK(void)
  2363. et_registercomponentprop_destructor(RegComponentPropStruct * e)
  2364. {
  2365.     if (e->comp)
  2366.         XP_FREE(e->comp);
  2367.     if (e->name)
  2368.         XP_FREE(e->name);
  2369.  
  2370.     XP_FREE(e);
  2371. }
  2372.  
  2373. void
  2374. ET_RegisterComponentProp(char *comp, char *name, uint8 retType, void *setter, 
  2375.              void *getter)
  2376. {
  2377.     /* create our event object */
  2378.     RegComponentPropStruct * pEvent = XP_NEW_ZAP(RegComponentPropStruct);
  2379.     if(!pEvent)
  2380.         return;
  2381.  
  2382.     /* this won't work without a component and property name. */
  2383.     if (!comp || !name)
  2384.     return;
  2385.  
  2386.     /* do a PR_InitEvent on the event structure */
  2387.     PR_InitEvent(&pEvent->ce.event, NULL,
  2388.          (PRHandleEventProc)et_registercomponentprop_handler, 
  2389.          (PRDestroyEventProc)et_registercomponentprop_destructor);
  2390.  
  2391.     /* fill in the non-PR fields we care about */
  2392.     pEvent->comp = XP_STRDUP(comp);
  2393.     pEvent->name = XP_STRDUP(name);
  2394.     pEvent->retType = retType;
  2395.     pEvent->setter = setter;
  2396.     pEvent->getter = getter;
  2397.  
  2398.     /* add the event to the event queue */
  2399.     et_event_to_mocha(&pEvent->ce);
  2400. }
  2401.  
  2402. /**********************************************************************/
  2403.  
  2404. typedef struct {
  2405.     ETEvent    ce;
  2406.     char       *comp;
  2407.     char       *name;
  2408.     uint8    retType;
  2409.     void       *method;
  2410.     int32    argc;
  2411. } RegComponentMethodStruct;
  2412.  
  2413. PR_STATIC_CALLBACK(void)
  2414. et_registercomponentmethod_handler(RegComponentMethodStruct * e)
  2415. {
  2416.     lm_RegisterComponentMethod(e->comp, e->name, e->retType, (ETCompMethodFunc)e->method, e->argc); 
  2417. }
  2418.  
  2419. PR_STATIC_CALLBACK(void)
  2420. et_registercomponentmethod_destructor(RegComponentMethodStruct * e)
  2421. {
  2422.     if (e->comp)
  2423.         XP_FREE(e->comp);
  2424.     if (e->name)
  2425.         XP_FREE(e->name);
  2426.     XP_FREE(e);
  2427. }
  2428.  
  2429. void
  2430. ET_RegisterComponentMethod(char *comp, char *name, uint8 retType, void *method, 
  2431.                int32 argc)
  2432. {
  2433.     /* create our event object */
  2434.     RegComponentMethodStruct * pEvent = XP_NEW_ZAP(RegComponentMethodStruct);
  2435.     if(!pEvent)
  2436.         return;
  2437.  
  2438.     /* do a PR_InitEvent on the event structure */
  2439.     PR_InitEvent(&pEvent->ce.event, NULL,
  2440.          (PRHandleEventProc)et_registercomponentmethod_handler, 
  2441.          (PRDestroyEventProc)et_registercomponentmethod_destructor);
  2442.  
  2443.     /* fill in the non-PR fields we care about */
  2444.     pEvent->comp = XP_STRDUP(comp);
  2445.     pEvent->name = XP_STRDUP(name);
  2446.     pEvent->retType = retType;
  2447.     pEvent->method = method;
  2448.     pEvent->argc = argc;
  2449.  
  2450.     /* add the event to the event queue */
  2451.     et_event_to_mocha(&pEvent->ce);
  2452. }
  2453.  
  2454.  
  2455.  
  2456.  
  2457.