home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / cmd / xfe / forms.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  94.2 KB  |  3,506 lines

  1. /* -*- Mode: C; tab-width: 8; 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.    forms.c --- creating and displaying forms widgets
  20.    Created: Jamie Zawinski <jwz@netscape.com>, 21-Jul-94.
  21.    Whacked into a completely new form: Chris Toshok <toshok@netscape.com>, 29-Oct-1997.
  22.  */
  23.  
  24.  
  25. #include "mozilla.h"
  26. #include "xfe.h"
  27. #include "fonts.h"
  28. #include "felocale.h"
  29. #include "xpform.h"
  30. #include "layers.h"
  31.  
  32. #include <plevent.h>        /* for mocha */
  33. #include <prtypes.h>
  34. #include <libevent.h>
  35.  
  36. #include <libi18n.h>
  37. #include "intl_csi.h"
  38. #include "fonts.h"
  39. #ifndef NO_WEB_FONTS
  40. #include "nf.h"
  41. #include "Mnfrc.h"
  42. #include "Mnfrf.h"
  43. #endif
  44.  
  45. #include "DtWidgets/ComboBoxP.h"
  46.  
  47. #include <Xfe/XfeP.h>            /* for xfe widgets and utilities */
  48.  
  49. /* XXX */
  50. /* #define NO_NEW_DEFAULT_SIZES 1 */
  51.  
  52. /* for XP_GetString() */
  53. #include <xpgetstr.h>
  54. extern int XFE_ERROR_OPENING_FILE;
  55.  
  56. /* Kludge around conflicts between Motif and xp_core.h... */
  57. #undef Bool
  58. #define Bool char
  59.  
  60. /* #define FORMS_ARE_FONTIFIED */
  61. /* #define FORMS_ARE_COLORED */
  62.  
  63.  
  64. /* Kludge kludge kludge, should be in resources... */
  65. #define fe_FORM_LEFT_MARGIN   0
  66. #define fe_FORM_RIGHT_MARGIN  0
  67. #define fe_FORM_TOP_MARGIN    4
  68. #define fe_FORM_BOTTOM_MARGIN 4
  69.  
  70. static void fe_form_file_browse_cb (Widget, XtPointer, XtPointer);
  71. static void fe_activate_submit_cb (Widget, XtPointer, XtPointer);
  72. static void fe_submit_form_cb (Widget, XtPointer, XtPointer);
  73. static void fe_reset_form_cb (Widget, XtPointer, XtPointer);
  74. static void fe_radio_form_cb (Widget, XtPointer, XtPointer);
  75. static void fe_check_form_cb (Widget, XtPointer, XtPointer);
  76. static void fe_button_form_cb (Widget, XtPointer, XtPointer);
  77. static void fe_combo_form_cb(Widget, XtPointer, XtPointer);
  78. static void fe_got_focus_cb (Widget, XtPointer, XtPointer);
  79. static void fe_list_form_cb (Widget, XtPointer, XtPointer);
  80. static void fe_lost_focus_cb (Widget, XtPointer, XtPointer);
  81. static void fe_mocha_focus_notify_eh (Widget w, 
  82.               XtPointer closure, 
  83.               XEvent *ev, 
  84.               Boolean *cont);
  85.  
  86. static void fe_key_handler(Widget w, XtPointer client_data, XEvent * xevent, Boolean * bcontinue);
  87. static void fe_complete_js_event(JSEvent *js_event, XEvent *x_event, XP_Bool do_geometry);
  88.  
  89. #ifdef DEBUG
  90. static char * private_precondition_format = "debug: precondition violation at %s:%d\n";
  91. static char * private_check_format = "debug: check violation at %s:%d\n";
  92. #endif
  93.  
  94. typedef struct fe_form_vtable FEFormVtable;
  95. typedef struct fe_form_data FEFormData;
  96.  
  97. struct fe_form_vtable
  98. {
  99.   void (*create_widget_func)(FEFormData *, LO_FormElementStruct *);
  100.   void (*get_size_func)(FEFormData *, LO_FormElementStruct *);
  101.   void (*element_is_submit_func)(FEFormData *, LO_FormElementStruct *);
  102.   void (*display_element_func)(FEFormData *, LO_FormElementStruct  *);
  103.   void (*get_element_value)(FEFormData *, LO_FormElementStruct  *, XP_Bool);
  104.   void (*free_element_func)(FEFormData *, LO_FormElementData *);
  105.   void (*reset_element)(FEFormData *, LO_FormElementStruct *);
  106.   void (*select_element_func)(FEFormData *, LO_FormElementStruct *);
  107.   void (*change_element_func)(FEFormData *, LO_FormElementStruct *);
  108.   void (*focus_element_func)(FEFormData *, LO_FormElementStruct *);
  109.   void (*lost_focus_func)(FEFormData *);
  110. };
  111.  
  112. struct fe_form_data {
  113.   FEFormVtable vtbl;
  114.   LO_FormElementStruct *form;
  115.   Widget widget;
  116.   MWContext *context;
  117. };
  118.  
  119. typedef struct {
  120.   FEFormData form_data;
  121.  
  122.   Widget rowcolumn;
  123.   Widget browse_button;
  124.   Widget file_widget;
  125. } FEFileFormData;
  126.  
  127. typedef struct {
  128.   FEFormData form_data;
  129.  
  130.   Widget text_widget; /* form_data.widget is the scrolled window. */
  131. } FETextAreaFormData;
  132.  
  133. typedef struct {
  134.   FEFormData form_data;
  135.  
  136.   Widget list_widget; /* form_data.widget is the scrolled window. */
  137.   int nkids;
  138.   char *selected_p;
  139. } FESelectMultFormData;
  140.  
  141. typedef FESelectMultFormData FESelectOneFormData;
  142.  
  143. static FEFormData* alloc_form_data(int32 type);
  144.  
  145. static void text_create_widget(FEFormData *, LO_FormElementStruct *);
  146. static void text_display(FEFormData *, LO_FormElementStruct *);
  147. static void text_get_value(FEFormData *, LO_FormElementStruct *, XP_Bool);
  148. static void text_reset(FEFormData *, LO_FormElementStruct *);
  149. static void text_change(FEFormData *, LO_FormElementStruct *);
  150. static void text_focus(FEFormData *, LO_FormElementStruct *);
  151. static void text_lost_focus(FEFormData *);
  152. static void text_select(FEFormData *, LO_FormElementStruct *);
  153.  
  154. static void file_create_widget(FEFormData *, LO_FormElementStruct *);
  155. static void file_get_value(FEFormData *, LO_FormElementStruct *, XP_Bool);
  156. static void file_free(FEFormData *, LO_FormElementData *);
  157.  
  158. static void button_create_widget(FEFormData *, LO_FormElementStruct *);
  159.  
  160. static void checkbox_create_widget(FEFormData *, LO_FormElementStruct *);
  161. static void checkbox_get_value(FEFormData *, LO_FormElementStruct *, XP_Bool);
  162. static void checkbox_change(FEFormData *, LO_FormElementStruct *);
  163.  
  164. static void select_create_widget(FEFormData *, LO_FormElementStruct *);
  165. static void select_get_value(FEFormData *, LO_FormElementStruct *, XP_Bool);
  166. static void select_free(FEFormData *, LO_FormElementData *);
  167. static void select_reset(FEFormData *, LO_FormElementStruct *);
  168. static void select_change(FEFormData *, LO_FormElementStruct *);
  169.  
  170. static void textarea_create_widget(FEFormData *, LO_FormElementStruct *);
  171. static void textarea_display(FEFormData *, LO_FormElementStruct *);
  172. static void textarea_get_value(FEFormData *, LO_FormElementStruct *, XP_Bool);
  173. static void textarea_reset(FEFormData *, LO_FormElementStruct *);
  174. static void textarea_lost_focus(FEFormData *);
  175.  
  176. static void form_element_display(FEFormData *, LO_FormElementStruct *);
  177. static void form_element_get_size(FEFormData *, LO_FormElementStruct *);
  178. static void form_element_is_submit(FEFormData *, LO_FormElementStruct *);
  179. static void form_element_get_value(FEFormData *, LO_FormElementStruct *,
  180.                    XP_Bool);
  181. static void form_element_free(FEFormData *, LO_FormElementData *);
  182.  
  183.  
  184. /* doubles as both the text and password vtable */
  185. static FEFormVtable text_form_vtable = {
  186.   text_create_widget,
  187.   form_element_get_size,
  188.   form_element_is_submit,
  189.   text_display,
  190.   text_get_value,
  191.   form_element_free,
  192.   text_reset,
  193.   text_select,
  194.   text_change,
  195.   text_focus,
  196.   text_lost_focus
  197. };
  198.  
  199. static FEFormVtable file_form_vtable = {
  200.   file_create_widget,
  201.   form_element_get_size,
  202.   form_element_is_submit,
  203.   text_display,
  204.   file_get_value,
  205.   file_free,
  206.   text_reset,
  207.   text_select,
  208.   text_change,
  209.   text_focus,
  210.   text_lost_focus
  211. };
  212.  
  213. static FEFormVtable button_form_vtable = {
  214.   button_create_widget,
  215.   form_element_get_size,
  216.   NULL,
  217.   form_element_display,
  218.   form_element_get_value,
  219.   form_element_free,
  220.   NULL,
  221.   NULL,
  222.   NULL,
  223.   NULL,
  224.   NULL
  225. };
  226.  
  227. static FEFormVtable checkbox_form_vtable = {
  228.   checkbox_create_widget,
  229.   form_element_get_size,
  230.   NULL,
  231.   form_element_display,
  232.   checkbox_get_value,
  233.   form_element_free,
  234.   NULL,
  235.   NULL,
  236.   checkbox_change,
  237.   NULL,
  238.   NULL
  239. };
  240.  
  241. static FEFormVtable selectone_form_vtable = {
  242.   select_create_widget,
  243.   form_element_get_size,
  244.   NULL,
  245.   form_element_display,
  246.   select_get_value,
  247.   select_free,
  248.   select_reset,
  249.   NULL,
  250.   select_change,
  251.   NULL,
  252.   NULL
  253. };
  254.  
  255. static FEFormVtable selectmult_form_vtable = {
  256.   select_create_widget,
  257.   form_element_get_size,
  258.   NULL,
  259.   form_element_display,
  260.   select_get_value,
  261.   select_free,
  262.   select_reset,
  263.   NULL,
  264.   select_change,
  265.   NULL,
  266.   NULL
  267. };
  268.  
  269. static FEFormVtable textarea_form_vtable = {
  270.   textarea_create_widget,
  271.   form_element_get_size,
  272.   NULL,
  273.   textarea_display,
  274.   textarea_get_value,
  275.   form_element_free,
  276.   textarea_reset,
  277.   text_select,
  278.   text_change,
  279.   text_focus,
  280.   textarea_lost_focus
  281. };
  282.  
  283. /*
  284. ** Why are these next two functions in this file?
  285. */
  286.  
  287. /*
  288.  * Raise the window to the top of the view order
  289.  */
  290. void
  291. FE_RaiseWindow(MWContext *context)
  292. {
  293. #ifdef DEBUG_username
  294.   printf ("RaiseWindow: context 0x%x\n", context);
  295. #endif
  296.   XtRealizeWidget (CONTEXT_WIDGET (context));
  297.   XtManageChild (CONTEXT_WIDGET (context));
  298.   /* XXX Uniconify the window if it was iconified */
  299.   XMapRaised(XtDisplay(CONTEXT_WIDGET(context)),
  300.            XtWindow(CONTEXT_WIDGET(context)));
  301.   XtPopup(CONTEXT_WIDGET(context),XtGrabNone);
  302. }
  303.  
  304. /*
  305.  * Lower the window to the bottom of the view order
  306.  */
  307. void
  308. FE_LowerWindow(MWContext *context)
  309. {
  310. #ifdef DEBUG_username
  311.   printf ("LowerWindow: context 0x%x\n", context);
  312. #endif
  313.   if (!XtIsRealized(CONTEXT_WIDGET(context)))
  314.       return;
  315.  
  316.   XLowerWindow(XtDisplay(CONTEXT_WIDGET(context)),
  317.            XtWindow(CONTEXT_WIDGET(context)));
  318. }
  319.  
  320. static void
  321. fe_font_list_metrics(MWContext *context, LO_FormElementStruct *form,
  322.              XmFontList font_list, int *ascentp, int *descentp)
  323. {
  324.     fe_Font        font;
  325.     LO_TextAttr    *text = XP_GetFormTextAttr(form);
  326.  
  327.     font = fe_LoadFontFromFace(context,text, &text->charset,
  328.                    text->font_face,
  329.                    text->size, text->fontmask);
  330.     if (!font)
  331.     {
  332.         *ascentp = 14;
  333.         *descentp = 3;
  334.         return;
  335.     }
  336.     FE_FONT_EXTENTS(text->charset, font, ascentp, descentp);
  337. }
  338.  
  339. static void
  340. fe_FontlistAndXmStringForFormElement(MWContext *context,
  341.                      int32 form_type,
  342.                      char *string,
  343.                      LO_TextAttr *text_attr,
  344.                      XmString *xmstring,
  345.                      XmFontList *fontlist)
  346. {
  347.   Widget parent = CONTEXT_DATA(context)->drawing_area;
  348.   XP_Bool use_UnicodePseudoFont;
  349.   fe_Font fe_font;
  350.   XmFontType type = 0; /* keep purify happy */
  351.   XmFontListEntry flentry;
  352.   int mask = text_attr->fontmask;
  353.   XmFontList unicodePseudo_font_list = NULL;
  354.   XmFontList locale_font_list = NULL;
  355.  
  356.   use_UnicodePseudoFont = IS_UNICODE_CSID(text_attr->charset);
  357.  
  358. #ifdef DEBUG_username
  359.   printf ("fe_FontlistAndXmStringForFormElement(%s)\n", string);
  360. #endif
  361.  
  362.   switch (form_type)
  363.     {
  364.     case FORM_TYPE_FILE:
  365.     case FORM_TYPE_TEXT:
  366.     case FORM_TYPE_PASSWORD:
  367.     case FORM_TYPE_TEXTAREA:
  368.     case FORM_TYPE_READONLY:
  369.       /* Make sure text fields are non-bold, non-italic, fixed. */
  370.       mask &= (~ (LO_FONT_BOLD|LO_FONT_ITALIC));
  371.       mask |= LO_FONT_FIXED;
  372.       use_UnicodePseudoFont = FALSE; /* XmText doesn't use XmString */
  373.       break;
  374.     default:
  375.       break;
  376.     }
  377.  
  378.   /*
  379.    * Get the font info
  380.    */
  381.   if (use_UnicodePseudoFont) 
  382.     {
  383.       fe_font = fe_LoadUnicodeFont(NULL, "", 0, text_attr->size, mask,
  384.                    0, 0, 0, XtDisplay(parent));
  385.  
  386.       *fontlist = unicodePseudo_font_list;
  387.     }
  388.   else
  389.     {
  390.       fe_font = fe_GetFontOrFontSetFromFace(context, NULL,
  391.                         text_attr->font_face,
  392.                         text_attr->size,
  393.                         mask, &type);
  394.       if (!fe_font)
  395.     return;
  396.       flentry = XmFontListEntryCreate(XmFONTLIST_DEFAULT_TAG, type, fe_font);
  397.       if (!flentry)
  398.     return;
  399.       locale_font_list = XmFontListAppendEntry(NULL, flentry);
  400.       if (!locale_font_list)
  401.     return;
  402.       XmFontListEntryFree(&flentry);
  403.       
  404.       if (xmstring)
  405.     *xmstring = NULL;
  406.  
  407.       *fontlist = locale_font_list;
  408.     }
  409.  
  410.   if (string && xmstring)
  411.     *xmstring = fe_ConvertToXmString((unsigned char*)string,
  412.                      text_attr->charset,
  413.                      fe_font,
  414.                      type,
  415.                      fontlist);
  416. }
  417.  
  418. static void
  419. set_form_colors(FEFormData *fed,
  420.         LO_Color *lo_fg,
  421.         LO_Color *lo_bg)
  422. {
  423.   Widget parent = CONTEXT_DATA (fed->context)->drawing_area;
  424.   Pixel fg, bg;
  425.  
  426.   fg = fe_GetPixel (fed->context, lo_fg->red, lo_fg->green, lo_fg->blue);
  427.   bg = fe_GetPixel (fed->context, lo_bg->red, lo_bg->green, lo_bg->blue);
  428.   
  429.   if (fg == bg)
  430.     {
  431.       /* the foreground and background are the same.  Try to
  432.          choose something that will make things readable 
  433.          (if a little ugly) */
  434.       
  435.       XmGetColors(XtScreen(parent),
  436.               XfeColormap(parent),
  437.               bg,
  438.               &fg, NULL, NULL, NULL);
  439.     }
  440.  
  441.   XtVaSetValues(fed->widget,
  442.         XmNforeground, fg,
  443.         XmNbackground, bg,
  444.         NULL);
  445. }
  446.  
  447. static void
  448. get_form_colors(FEFormData *fed,
  449.         LO_Color *lo_fg,
  450.         LO_Color *lo_bg,
  451.         Pixel *fg_r, Pixel *bg_r)
  452. {
  453.   Widget parent = CONTEXT_DATA (fed->context)->drawing_area;
  454.   Pixel fg, bg;
  455.  
  456.   fg = fe_GetPixel (fed->context, lo_fg->red, lo_fg->green, lo_fg->blue);
  457.   bg = fe_GetPixel (fed->context, lo_bg->red, lo_bg->green, lo_bg->blue);
  458.   
  459.   if (fg == bg)
  460.     {
  461.       /* the foreground and background are the same.  Try to
  462.          choose something that will make things readable 
  463.          (if a little ugly) */
  464.       
  465.       XmGetColors(XtScreen(parent),
  466.               XfeColormap(parent),
  467.               bg,
  468.               &fg, NULL, NULL, NULL);
  469.     }
  470.  
  471.   *fg_r = fg;
  472.   *bg_r = bg;
  473. }
  474.  
  475. /* Motif likes to complain when there are binary characters in
  476.    text strings.
  477.  */
  478. void
  479. fe_forms_clean_text (MWContext *context,
  480.              int charset,
  481.              char *text,
  482.              Boolean newlines_too_p)
  483. {
  484.   unsigned char *t = (unsigned char *) text;
  485.   for (; *t; t++)
  486.     {
  487.       unsigned char c = *t;
  488.       if ((newlines_too_p && (c == '\n' || c == '\r')) ||
  489.       (c < ' ' && c != '\t' && c != '\n' && c != '\r') ||
  490.       (c == 0x7f) ||
  491.       ((INTL_CharSetType(charset) == SINGLEBYTE) &&
  492.        (0x7f <= c) && (c <= 0xa0)))
  493.     *t = ' ';
  494.     }
  495. }
  496.  
  497. static void fe_HackTextTranslations_addCallbacks(Widget widget)
  498. {
  499. #if 0
  500.   /* make sure it gets added only once */
  501.   XtRemoveCallback(widget,
  502.            XmNmodifyVerifyCallback,
  503.            fe_textModifyVerifyCallback,
  504.            NULL);
  505.   XtRemoveCallback(widget,
  506.            XmNmotionVerifyCallback,
  507.            fe_textMotionVerifyCallback,
  508.            NULL);
  509. #endif
  510.   XtAddCallback(widget,
  511.         XmNmotionVerifyCallback,
  512.         fe_textMotionVerifyCallback,
  513.         NULL);
  514.   XtAddCallback(widget,
  515.         XmNmodifyVerifyCallback,
  516.         fe_textModifyVerifyCallback,
  517.         NULL);
  518.   XtVaSetValues(widget,
  519.         XmNverifyBell,False,
  520.         NULL);
  521. }
  522.  
  523. /*
  524.  * A list key event handler.
  525.  * This will search for a key in the XmList and shift the location cursor
  526.  * to a match.
  527.  */
  528. static void
  529. fe_list_find_eh(Widget widget, XtPointer closure, XEvent* event,
  530.         Boolean* continue_to_dispatch)
  531. {
  532.   MWContext *context = (MWContext *) closure;
  533.   Boolean usedEvent_p = False;
  534.  
  535.   Modifiers mods;
  536.   KeySym k;
  537.   char *s;
  538.   int i;
  539.   int index;                /* index is 1 based */
  540.   XmString *items;
  541.   int nitems;
  542.  
  543. #define MILLI_500_SECS    500
  544. #define _LIST_MAX_CHARS    100
  545.   static char input[_LIST_MAX_CHARS] = {0};
  546.   static Time prev_time;
  547.   static Widget w = 0;
  548.   static Boolean is_prev_found = False;
  549.  
  550.   if (!context || !event) return;
  551.  
  552.   fe_UserActivity (context);
  553.  
  554.   if (event->type == KeyPress) {
  555.     if (!(k = XtGetActionKeysym (event, &mods))) return;
  556.     if (!(s = XKeysymToString (k))) return;
  557.     if (!s || !*s || s[1]) return;        /* no or more than 1 char */
  558.     if (!isprint(*s)) return;            /* unprintable */
  559.  
  560.     if ((widget == w) && (event->xkey.time - prev_time < MILLI_500_SECS)) {
  561.     /* Continue search */
  562.     if (is_prev_found) strcat(input, s);
  563.     else return;
  564.     }
  565.     else {
  566.     /* Fresh search */
  567.     is_prev_found = False;
  568.     strcpy(input, s);
  569.     }
  570.     w = widget;
  571.     prev_time = event->xkey.time;
  572.     index = XmListGetKbdItemPos(widget);
  573.     if (!index) return;                /* List is empty */
  574.  
  575.     /* Wrap search for input[] in List */
  576.     i = index;
  577.     i = (i == nitems) ? 1 : i+1;        /* Increment i */
  578.     XtVaGetValues(widget, XmNitems, &items, XmNitemCount, &nitems, 0);
  579.     while (i != index) {
  580.     if (!XmStringGetLtoR(items[i-1], XmSTRING_DEFAULT_CHARSET, &s))
  581.         continue;
  582.     if (!strncmp(s, input, strlen(input))) {
  583.         /* Found */
  584.         XP_FREE(s);
  585.         XmListSetKbdItemPos(widget, i);
  586.         is_prev_found = True;
  587.         break;
  588.     }
  589.     XP_FREE(s);
  590.     i = (i == nitems) ? 1 : i+1;    /* Increment i */
  591.     }
  592.     usedEvent_p = True;
  593.   }
  594.  
  595.   if (usedEvent_p) *continue_to_dispatch = False;
  596. }
  597.  
  598. /*
  599. **
  600. ** VTABLE for "superclass", form_element.
  601. **
  602. */
  603. static void
  604. form_element_display(FEFormData *fed,
  605.              LO_FormElementStruct *form)
  606. {
  607.   MWContext *context = fed->context;
  608.   Arg av[10];
  609.   int ac;
  610.   uint16 attrmask = XP_GetFormEleAttrmask(form);
  611.   Position x;
  612.   Position y;
  613.  
  614.   x = (form->x + form->x_offset
  615.        - CONTEXT_DATA (context)->document_x);
  616.   y = (form->y + form->y_offset
  617.        - CONTEXT_DATA (context)->document_y);
  618.   x += fe_FORM_LEFT_MARGIN;
  619.   y += fe_FORM_TOP_MARGIN;
  620.  
  621.   if (!XtIsManaged(fed->widget)) 
  622.     {
  623.       Dimension bw = 0;
  624.       Dimension width = form->width;
  625.       Dimension height = form->height;
  626.  
  627.       XtVaGetValues (fed->widget, XmNborderWidth, &bw, 0);
  628.       /* Since I told layout that width was width+bw+bw (for its sizing and
  629.      positioning purposes), subtract it out again when setting the size of
  630.      the text area.  X thinks the borders are outside the WxH rectangle,
  631.      not inside, but thinks that the borders are below and to the right of
  632.      the X,Y origin, instead of up and to the left as you would expect
  633.      given the WxH behavior!!
  634.       */
  635.       width -= (bw * 2);
  636.       height -= (bw * 2);
  637.       /* x += bw; */
  638.       /* y += bw;*/
  639.       
  640.       width  -= fe_FORM_LEFT_MARGIN + fe_FORM_RIGHT_MARGIN;
  641.       height -= fe_FORM_TOP_MARGIN + fe_FORM_BOTTOM_MARGIN;
  642.       
  643.       /*
  644.        * Move to 0 before moving to where we want so it ends up
  645.        * where we want.
  646.        */
  647.       ac = 0;
  648.       XtSetArg (av [ac], XmNx, 0); ac++;
  649.       XtSetArg (av [ac], XmNy, 0); ac++;
  650.       XtSetValues (fed->widget, av, ac);
  651.       
  652.       
  653. #ifdef DEBUG_username
  654.       printf ("DisplayFormElement: width = %d; height = %d\n", width, height);
  655. #endif
  656.       
  657.       ac = 0;
  658.       XtSetArg (av [ac], XmNx, (Position)x); ac++;
  659.       XtSetArg (av [ac], XmNy, (Position)y); ac++;
  660.       XtSetArg (av [ac], XmNwidth, (Dimension)width); ac++;
  661.       XtSetArg (av [ac], XmNheight, (Dimension)height); ac++;
  662.       XtSetValues (fed->widget, av, ac);
  663.       
  664.       XtSetMappedWhenManaged(fed->widget,
  665.                  !(attrmask & LO_ELE_INVISIBLE));
  666.       
  667.       XtManageChild (fed->widget);
  668.     }
  669.   else
  670.     {
  671.       XtSetMappedWhenManaged(fed->widget,
  672.                  !(attrmask & LO_ELE_INVISIBLE));
  673.       
  674.       XtMoveWidget(fed->widget, x, y);
  675.     }
  676. }
  677.  
  678. static void
  679. form_element_get_size(FEFormData *fed,
  680.               LO_FormElementStruct *form)
  681. {
  682.   MWContext *context = fed->context;
  683.   Dimension width = 0;
  684.   Dimension height = 0;
  685.   Dimension bw = 0;
  686.   Dimension st = 0;
  687.   Dimension ht = 0;
  688.   Dimension margin_height = 0;
  689.   Dimension bottom = 0;
  690.   int ascent, descent;
  691.   XmFontList font_list;
  692.   LO_FormElementData *form_data = XP_GetFormElementData(form);
  693.   int32 form_type = XP_FormGetType(form_data);
  694.   Widget element_widget;
  695.  
  696.   if (form_type == FORM_TYPE_FILE)
  697.     element_widget = ((FEFileFormData*)fed)->rowcolumn;
  698.   else
  699.     element_widget = fed->widget;
  700.  
  701.   font_list = 0;
  702.   XtVaGetValues (element_widget, XmNfontList, &font_list, 0);
  703.   
  704.   fe_HackTranslations (context, element_widget);
  705.  
  706.   fe_font_list_metrics (context, form, font_list, &ascent, &descent);
  707.  
  708.   XtRealizeWidget(element_widget);
  709.  
  710.   if (fe_globalData.fe_guffaw_scroll == 1)
  711.     {
  712.       XSetWindowAttributes attr;
  713.       unsigned long valuemask;
  714.       
  715.       valuemask = CWBitGravity | CWWinGravity;
  716.       attr.win_gravity = StaticGravity;
  717.       attr.bit_gravity = StaticGravity;
  718.       XChangeWindowAttributes (XtDisplay (element_widget),
  719.                    XtWindow (element_widget),
  720.                    valuemask, &attr);
  721.     }
  722.  
  723.   XtVaGetValues (element_widget,
  724.          XmNwidth,          &width,
  725.          XmNheight,          &height,
  726.          XmNborderWidth,      &bw,
  727.          XmNshadowThickness,      &st,
  728.          XmNhighlightThickness, &ht,
  729.          XmNmarginHeight,      &margin_height,
  730.          XmNmarginBottom,      &bottom,
  731.          0);
  732.   
  733. #ifdef DEBUG_username
  734.   printf ("form before: width = %d; height = %d\n", width, height);
  735. #endif
  736.   width  += fe_FORM_LEFT_MARGIN + fe_FORM_RIGHT_MARGIN;
  737.   height += fe_FORM_TOP_MARGIN + fe_FORM_BOTTOM_MARGIN;
  738.   
  739.   /* The WxH doesn't take into account the border width; so add that in
  740.      for layout's benefit.  We subtract it again later. */
  741.   width  += (bw * 2);
  742.   height += (bw * 2);
  743. #ifdef DEBUG_username
  744.   printf ("form after: width = %d; height = %d\n", width, height);
  745. #endif
  746.   form->width  = width;
  747.   form->height = height;
  748.   
  749.   /* Yeah.  Uh huh. */
  750.   if (form_type == FORM_TYPE_RADIO ||
  751.       form_type == FORM_TYPE_CHECKBOX)
  752.     {
  753.       bottom = 0;
  754.       descent = bw;
  755.     }
  756.   
  757.   form->baseline = height - (bottom + margin_height + st + bw + ht + descent
  758.                  + fe_FORM_BOTTOM_MARGIN);
  759. }
  760.  
  761. static void
  762. form_element_is_submit(FEFormData *fed,
  763.                LO_FormElementStruct *form)
  764. {
  765.   XtRemoveCallback (fed->widget,
  766.             XmNactivateCallback, fe_activate_submit_cb, fed);
  767.   
  768.   XtAddCallback (fed->widget,
  769.          XmNactivateCallback, fe_activate_submit_cb, fed);
  770.   
  771.   if (fe_globalData.terminal_text_translations)
  772.     XtOverrideTranslations (fed->widget,
  773.                 fe_globalData.terminal_text_translations);
  774. }
  775.  
  776. static void
  777. form_element_get_value(FEFormData *fed,
  778.                LO_FormElementStruct *form,
  779.                XP_Bool delete_p)
  780. {
  781.   if (delete_p)
  782.     {
  783.       XtDestroyWidget(fed->widget);
  784.       fed->widget = 0;
  785.     }
  786. }
  787.  
  788. static void
  789. form_element_free(FEFormData *fed,
  790.           LO_FormElementData *form)
  791. {
  792.   if (fed->widget)
  793.     XtDestroyWidget(fed->widget);
  794.  
  795.   fed->widget = 0;
  796.  
  797.   XP_FREE(fed);
  798. }
  799.  
  800. /*
  801. **
  802. ** VTABLE for Text like form elements (TEXT, TEXTAREA, and FILE)
  803. **
  804. */
  805. static void
  806. text_create_widget(FEFormData *fed,
  807.            LO_FormElementStruct *form)
  808. {
  809.   MWContext *context = fed->context;
  810.   Widget parent;
  811.   int16 charset;
  812.   LO_FormElementData *form_data;
  813.   int32 form_type;
  814.   int32 text_size;
  815.   int32 max_size;
  816.   int columns;
  817.   char *tmp_text = 0;
  818.   char *text;
  819.   unsigned char *loc;
  820.   XmFontList font_list;
  821.   Arg av [50];
  822.   int ac;
  823.   LO_TextAttr *text_attr;
  824.  
  825.   parent = CONTEXT_DATA (context)->drawing_area;
  826.   form_data = XP_GetFormElementData(form);
  827.   form_type = XP_FormGetType(form_data);
  828.   text_size = XP_FormTextGetSize(form_data);
  829.   max_size = XP_FormTextGetMaxSize(form_data);
  830.   text_attr = XP_GetFormTextAttr(form);
  831.   text = (char*)XP_FormGetDefaultText(form_data);
  832.   charset = text_attr->charset;
  833.  
  834.   /* from bstell: in multibyte (asian) locales, characters tend to be twice
  835.      as wide as in non-multibyte locales.  To make things look correct,
  836.      we divide the column number in half in those cases. */
  837.   columns = ((fe_LocaleCharSetID & MULTIBYTE) ?
  838.          (text_size + 1) / 2 : text_size);
  839.  
  840.   /* the default size for text fields is 20 columns. 
  841.      XX Shouldn't the backend just fill it in with 20? */
  842.   if (columns == 0) columns = 20;
  843.  
  844.  
  845.   if (!text) text = "";
  846.  
  847.   if (max_size > 0 && (int) XP_STRLEN (text) >= max_size) {
  848.     tmp_text = XP_STRDUP (text);
  849.     tmp_text [max_size] = '\0';
  850.     text = tmp_text;
  851.   }
  852.  
  853.   fe_forms_clean_text (context, charset, text, True);
  854.  
  855.   fe_FontlistAndXmStringForFormElement(context,
  856.                        form_type,
  857.                        text,
  858.                        text_attr,
  859.                        NULL,
  860.                        &font_list);
  861.   if (!font_list)
  862.     return;
  863.  
  864.   ac = 0;
  865.   /* Ok, let's try using the fixed font for text areas only. */
  866. /*#ifdef FORMS_ARE_FONTIFIED*/
  867.   XtSetArg (av [ac], XmNfontList, font_list); ac++;
  868. /*#endif*/
  869.   XtSetArg (av [ac], XmNcolumns, columns); ac++;
  870.  
  871.   if (form_type == FORM_TYPE_READONLY)
  872.     {
  873.       XtSetArg (av [ac], XmNeditable, False); ac++;
  874.       XtSetArg (av [ac], XmNcursorPositionVisible, False); ac++;
  875.     }
  876.  
  877.   if (max_size > 0)
  878.     {
  879.       XtSetArg (av [ac], XmNmaxLength, max_size); ac++;
  880.     }
  881.  
  882.   fed->widget = fe_CreateTextField (parent, "textForm", av, ac);
  883.  
  884.   /*#ifdef FORMS_ARE_COLORED*/
  885.   if (form_type == FORM_TYPE_READONLY)
  886.     set_form_colors(fed, &text_attr->fg, &text_attr->bg);
  887.   /*#endif*/
  888.  
  889.   /* Install in javascript form elemement text field translation */
  890.   fe_HackFormTextTranslations(fed->widget);
  891.  
  892.   XtAddCallback(fed->widget, XmNlosingFocusCallback,
  893.                 fe_lost_focus_cb, fed);
  894.   XtAddCallback(fed->widget, XmNfocusCallback, fe_got_focus_cb, fed);
  895.  
  896.  
  897.   /* This is changed later for self-submitting fields. */
  898.   if (fe_globalData.nonterminal_text_translations)
  899.     XtOverrideTranslations (fed->widget, fe_globalData.
  900.                 nonterminal_text_translations);
  901.  
  902.   if (form_type == FORM_TYPE_PASSWORD)
  903.     {
  904.       fe_SetupPasswdText (fed->widget, (max_size > 0 ? max_size : 1024));
  905.       fe_MarkPasswdTextAsFormElement(fed->widget);
  906.     }
  907.  
  908.   /* Must be after passwd setup. */
  909.   XtVaSetValues (fed->widget, XmNcursorPosition, 0, 0);
  910.   loc = fe_ConvertToLocaleEncoding (charset, (unsigned char *)text);
  911.   /* Add verify callbacks to implement JS key events */
  912.   fe_HackTextTranslations_addCallbacks(fed->widget);
  913.   /*
  914.    * I don't know whether it is SGI or some version of Motif,but
  915.    * doing a XtVaSetValues() here will execute the
  916.    * valueChangedCallback but ignore its changes.
  917.    * XmTextFieldSetString() works as expected.
  918.    */
  919.   XmTextFieldSetString (fed->widget, loc);
  920.   if (((char *) loc) != text) {
  921.     XP_FREE (loc);
  922.   }
  923.   if (tmp_text) XP_FREE (tmp_text);
  924. }
  925.  
  926. static void
  927. text_display(FEFormData *fed,
  928.          LO_FormElementStruct *form)
  929. {
  930.   MWContext *context = fed->context;
  931.   Widget widget_to_manage;
  932.   uint16 attrmask = XP_GetFormEleAttrmask(form);
  933.   LO_FormElementData *form_data = XP_GetFormElementData(form);
  934.   Position x;
  935.   Position y;
  936.   Arg av[10];
  937.   int ac = 0;
  938.   unsigned char *loc = 0;
  939.   char *current_text = (char*)XP_FormGetCurrentText(form_data);
  940.   int32 max_size = XP_FormTextGetMaxSize(form_data);
  941.   int32 form_type = XP_FormGetType(form_data);
  942.   LO_TextAttr *text_attr = XP_GetFormTextAttr(form);
  943.   uint16 charset = text_attr->charset;
  944.  
  945.   x = (form->x + form->x_offset
  946.        - CONTEXT_DATA (context)->document_x);
  947.   y = (form->y + form->y_offset
  948.        - CONTEXT_DATA (context)->document_y);
  949.   x += fe_FORM_LEFT_MARGIN;
  950.   y += fe_FORM_TOP_MARGIN;
  951.  
  952.   if (form_type == FORM_TYPE_FILE)
  953.     widget_to_manage = ((FEFileFormData*)fed)->rowcolumn;
  954.   else
  955.     widget_to_manage = fed->widget;
  956.  
  957.   if (!XtIsManaged(widget_to_manage))
  958.     {
  959.       Dimension bw = 0;
  960.       Dimension width = form->width;
  961.       Dimension height = form->height;
  962.  
  963.       XtVaGetValues (widget_to_manage, XmNborderWidth, &bw, 0);
  964.       /* Since I told layout that width was width+bw+bw (for its sizing and
  965.      positioning purposes), subtract it out again when setting the size of
  966.      the text area.  X thinks the borders are outside the WxH rectangle,
  967.      not inside, but thinks that the borders are below and to the right of
  968.      the X,Y origin, instead of up and to the left as you would expect
  969.      given the WxH behavior!!
  970.        */
  971.       width -= (bw * 2);
  972.       height -= (bw * 2);
  973.       /* x += bw; */
  974.       /* y += bw;*/
  975.  
  976.       width  -= fe_FORM_LEFT_MARGIN + fe_FORM_RIGHT_MARGIN;
  977.       height -= fe_FORM_TOP_MARGIN + fe_FORM_BOTTOM_MARGIN;
  978.  
  979.       if (max_size > 0)
  980.     {
  981.       XtSetArg (av [ac], XmNmaxLength, max_size); ac++;
  982.     }
  983.       
  984.       if (form_type == FORM_TYPE_TEXT) {
  985.     if (current_text) {
  986.       loc = fe_ConvertToLocaleEncoding (charset,
  987.                         (unsigned char *)current_text);
  988.       XtSetArg (av[ac], XmNvalue, loc);  ac++;
  989.     }
  990.       }
  991.  
  992.       if (ac)
  993.     XtSetValues(widget_to_manage, av, ac);
  994.  
  995.       ac = 0;
  996.       XtSetArg (av [ac], XmNx, x); ac++;
  997.       XtSetArg (av [ac], XmNy, y); ac++;
  998.       XtSetArg (av [ac], XmNwidth, width); ac++;
  999.       XtSetArg (av [ac], XmNheight, height); ac++;
  1000.       XtSetValues (widget_to_manage, av, ac);
  1001.       
  1002.       XtSetMappedWhenManaged(widget_to_manage,
  1003.                  !(attrmask & LO_ELE_INVISIBLE));
  1004.       
  1005.       XtManageChild(widget_to_manage);
  1006.     }
  1007.   else
  1008.     {
  1009.       XtSetMappedWhenManaged(widget_to_manage,
  1010.                  !(attrmask & LO_ELE_INVISIBLE));
  1011.       
  1012.       XtMoveWidget(widget_to_manage, x, y);
  1013.     }
  1014. }
  1015.  
  1016. static void
  1017. text_get_value(FEFormData *fed,
  1018.            LO_FormElementStruct *form,
  1019.            XP_Bool delete_p)
  1020. {
  1021.   MWContext *context = fed->context;
  1022.   INTL_CharSetInfo c = LO_GetDocumentCharacterSetInfo(context);
  1023.   LO_FormElementData *form_data = XP_GetFormElementData(form);
  1024.   char *text = 0;
  1025.   int32 form_type;
  1026.   PA_Block new_current;
  1027.   PA_Block cur_current;
  1028.   PA_Block default_txt;
  1029.  
  1030.   form_type = XP_FormGetType(form_data);
  1031.  
  1032.   if (form_type == FORM_TYPE_TEXT)
  1033.     {
  1034.       /* gross, since for password type form elements, we get back a malloc'ed
  1035.      area of memory, and for text form elements, we get XtMalloc'ed. */
  1036.       char *non_motif_text = NULL;
  1037.       XtVaGetValues (fed->widget, XmNvalue, &text, 0);
  1038.       if (text != NULL)
  1039.     {
  1040.       non_motif_text = XP_STRDUP(text);
  1041.       XtFree(text);
  1042.     }
  1043.       text = non_motif_text;
  1044.     }
  1045.   else if (form_type == FORM_TYPE_PASSWORD)
  1046.     text = fe_GetPasswdText (fed->widget);
  1047.  
  1048.   cur_current = XP_FormGetCurrentText(form_data);
  1049.   default_txt = XP_FormGetDefaultText(form_data);
  1050.  
  1051.   if (cur_current && cur_current != default_txt)
  1052.     free ((char*)cur_current);
  1053.  
  1054.   new_current = (PA_Block)fe_ConvertFromLocaleEncoding(INTL_GetCSIWinCSID(c),
  1055.                                (unsigned char *)text);
  1056.   
  1057.   XP_FormSetCurrentText(form_data, new_current);
  1058.   
  1059.   if ((char*)new_current != text)
  1060.     free (text);
  1061.  
  1062.   form_element_get_value(fed, form, delete_p);
  1063. }
  1064.  
  1065. static void
  1066. text_reset(FEFormData *fed,
  1067.        LO_FormElementStruct *form)
  1068. {
  1069.   LO_FormElementData *form_data = XP_GetFormElementData(form);
  1070.   char *default_text = (char*)XP_FormGetDefaultText(form_data);
  1071.   LO_TextAttr *text_attr = XP_GetFormTextAttr(form);
  1072.   char *tmp_text = 0;
  1073.   unsigned char *loc;
  1074.   int16 charset = text_attr->charset;
  1075.   Widget w = fed->widget;
  1076.   int32 max_size = XP_FormTextGetMaxSize(form_data);
  1077.   int32 form_type;
  1078.  
  1079.   form_type = XP_FormGetType(form_data);
  1080.  
  1081.   if (!default_text) default_text = "";
  1082.  
  1083.   if (max_size > 0 && (int) XP_STRLEN (default_text) >= max_size) 
  1084.     {
  1085.       tmp_text = XP_STRDUP (default_text);
  1086.       tmp_text [max_size] = '\0';
  1087.       default_text = tmp_text;
  1088.     }
  1089.  
  1090.   fe_forms_clean_text (fed->context, charset, default_text, True);
  1091.  
  1092.   XtVaSetValues (w, XmNcursorPosition, 0, 0);
  1093.  
  1094.   loc = fe_ConvertToLocaleEncoding (charset, (unsigned char*)default_text);
  1095.   /*
  1096.    * I don't know whether it is SGI or some version of Motif,
  1097.    * but doing a XtVaSetValues() here will execute the
  1098.    * valueChangedCallback but ignore its changes.
  1099.    * XmTextFieldSetString() works as expected.
  1100.    */
  1101.   XmTextFieldSetString (w, loc);
  1102.   if (((char *) loc) != default_text)
  1103.     {
  1104.       XP_FREE (loc);
  1105.     }
  1106.  
  1107.   if (tmp_text) XP_FREE (tmp_text);
  1108. }
  1109.  
  1110. static void
  1111. text_change(FEFormData *fed,
  1112.         LO_FormElementStruct *form)
  1113. {
  1114.   LO_FormElementData *form_data = XP_GetFormElementData(form);
  1115.   int32 form_type = XP_FormGetType(form_data);
  1116.   char *text = (char*)XP_FormGetCurrentText(form_data);
  1117.   LO_TextAttr *text_attr = XP_GetFormTextAttr(form);
  1118.   unsigned char *loc;
  1119.   int16 charset = text_attr->charset;
  1120.  
  1121.   if (!text) text = (char*)XP_FormGetDefaultText(form_data);
  1122.   loc = fe_ConvertToLocaleEncoding(charset, (unsigned char*)text);
  1123.  
  1124.   if (form_type == FORM_TYPE_TEXTAREA)
  1125.     XmTextSetString(fed->widget, loc);
  1126.   else
  1127.     XmTextFieldSetString(fed->widget, loc);
  1128.  
  1129.   if (((char *) loc) != text)
  1130.     {
  1131.       XP_FREE (loc);
  1132.     }
  1133. }
  1134.  
  1135. static void
  1136. text_select(FEFormData *fed,
  1137.         LO_FormElementStruct *form)
  1138. {
  1139.   XmTextSetSelection (fed->widget, 0,
  1140.               XmTextGetMaxLength (fed->widget), CurrentTime);
  1141. }
  1142.  
  1143. static void
  1144. text_focus(FEFormData *fed,
  1145.        LO_FormElementStruct *form)
  1146. {
  1147.   XmProcessTraversal(fed->widget, XmTRAVERSE_CURRENT);
  1148. }
  1149.  
  1150. static void
  1151. text_lost_focus(FEFormData *fed)
  1152. {
  1153.   LO_FormElementData *form_data;
  1154.   char *text;
  1155.   XP_Bool text_changed = False;
  1156.   int32 form_type;
  1157.   PA_Block current_text;
  1158.   JSEvent *event;
  1159.  
  1160.   form_data = XP_GetFormElementData(fed->form);
  1161.   form_type = XP_FormGetType(form_data);
  1162.  
  1163.   if (form_type == FORM_TYPE_READONLY) return;
  1164.  
  1165.   current_text = XP_FormGetCurrentText(form_data);
  1166.  
  1167.   if (form_type == FORM_TYPE_PASSWORD)
  1168.     text = fe_GetPasswdText (fed->widget);
  1169.   else
  1170.     XtVaGetValues (fed->widget, XmNvalue, &text, 0);
  1171.  
  1172.   if (!current_text || XP_STRCMP((char*)current_text, text))
  1173.     text_changed = True;
  1174.  
  1175.   if (((char*) current_text) != text) {
  1176.     XtFree (text);
  1177.   }
  1178.  
  1179.   /* if the text has changed, call get_element_value to copy it into the form
  1180.      element, and send a CHANGE event to the javascript thread. */
  1181.   if (text_changed)
  1182.     {
  1183.           (*fed->vtbl.get_element_value)(fed, fed->form, FALSE);
  1184.  
  1185.           event = XP_NEW_ZAP(JSEvent);
  1186.  
  1187.           event->type = EVENT_CHANGE;
  1188.  
  1189.           ET_SendEvent (fed->context, (LO_Element *) fed->form, event,
  1190.                         NULL, NULL);
  1191.       }
  1192. }
  1193.  
  1194. /*
  1195. **
  1196. ** VTABLE for the FILE form element.
  1197. **
  1198. */
  1199. static void
  1200. file_create_widget(FEFormData *fed,
  1201.            LO_FormElementStruct *form)
  1202. {
  1203.   FEFileFormData *filefed = (FEFileFormData*)fed;
  1204.   MWContext *context = fed->context;
  1205.   Widget parent;
  1206.   int16 charset;
  1207.   LO_FormElementData *form_data;
  1208.   int32 form_type;
  1209.   int32 text_size;
  1210.   int32 max_size;
  1211.   int columns;
  1212.   char *tmp_text = 0;
  1213.   char *text;
  1214.   unsigned char *loc;
  1215.   XmFontList font_list;
  1216.   Arg av [50];
  1217.   int ac;
  1218.   LO_TextAttr *text_attr;
  1219.   Pixel fg, bg;
  1220.  
  1221.   parent = CONTEXT_DATA (context)->drawing_area;
  1222.   form_data = XP_GetFormElementData(form);
  1223.   form_type = XP_FormGetType(form_data);
  1224.   text_size = XP_FormTextGetSize(form_data);
  1225.   max_size = XP_FormTextGetMaxSize(form_data);
  1226.   text_attr = XP_GetFormTextAttr(form);
  1227.   text = (char*)XP_FormGetDefaultText(form_data);
  1228.   charset = text_attr->charset;
  1229.  
  1230.   /* from bstell: in multibyte (asian) locales, characters tend to be twice
  1231.      as wide as in non-multibyte locales.  To make things look correct,
  1232.      we divide the column number in half in those cases. */
  1233.   columns = ((fe_LocaleCharSetID & MULTIBYTE) ?
  1234.          (text_size + 1) / 2 : text_size);
  1235.  
  1236.   /* the default size for text fields is 20 columns. 
  1237.      XX Shouldn't the backend just fill it in with 20? */
  1238.   if (columns == 0) columns = 20;
  1239.  
  1240.  
  1241.   if (!text) text = "";
  1242.  
  1243.   if (max_size > 0 && (int) XP_STRLEN (text) >= max_size) {
  1244.     tmp_text = XP_STRDUP (text);
  1245.     tmp_text [max_size] = '\0';
  1246.     text = tmp_text;
  1247.   }
  1248.  
  1249.   fe_forms_clean_text (context, charset, text, True);
  1250.  
  1251.   fe_FontlistAndXmStringForFormElement(context,
  1252.                        form_type,
  1253.                        text,
  1254.                        text_attr,
  1255.                        NULL,
  1256.                        &font_list);
  1257.   if (!font_list)
  1258.     return;
  1259.  
  1260.   get_form_colors(fed, &text_attr->fg, &text_attr->bg, &fg, &bg);
  1261.  
  1262.   /* Create a RowColumn widget to handle both the text and its
  1263.      associated browseButton */
  1264.   ac = 0;
  1265.   XtSetArg (av [ac], XmNpacking, XmPACK_TIGHT); ac++;
  1266.   XtSetArg (av [ac], XmNorientation, XmHORIZONTAL); ac++;
  1267.   XtSetArg (av [ac], XmNnumColumns, 2); ac++;
  1268.   XtSetArg (av [ac], XmNspacing, 5); ac++;
  1269.   XtSetArg (av [ac], XmNmarginWidth, 0); ac++;
  1270.   XtSetArg (av [ac], XmNmarginHeight, 0); ac++;
  1271.   filefed->rowcolumn = XmCreateRowColumn(parent, "formRowCol", av, ac);
  1272.  
  1273.   ac = 0;
  1274.   /* Ok, let's try using the fixed font for text areas only. */
  1275. /*#ifdef FORMS_ARE_FONTIFIED*/
  1276.   XtSetArg (av [ac], XmNfontList, font_list); ac++;
  1277. /*#endif*/
  1278.   XtSetArg (av [ac], XmNcolumns, columns); ac++;
  1279.  
  1280.   if (max_size > 0)
  1281.     {
  1282.       XtSetArg (av [ac], XmNmaxLength, max_size); ac++;
  1283.     }
  1284.  
  1285. #ifdef FORMS_ARE_COLORED
  1286.   XtSetArg (av [ac], XmNforeground, fg); ac++;
  1287.   XtSetArg (av [ac], XmNbackground, bg); ac++;
  1288. #endif
  1289.  
  1290.   fed->widget = fe_CreateTextField (filefed->rowcolumn, "textForm", av, ac);
  1291.  
  1292.   /* Install in javascript form elemement text field translation */
  1293.   fe_HackFormTextTranslations(fed->widget);
  1294.  
  1295.   XtAddCallback(fed->widget, XmNlosingFocusCallback,
  1296.                 fe_lost_focus_cb, fed);
  1297.   XtAddCallback(fed->widget, XmNfocusCallback, fe_got_focus_cb, fed);
  1298.  
  1299.  
  1300.   XtManageChild(fed->widget);
  1301.   
  1302.   ac = 0;
  1303.   XtSetArg (av [ac], XmNfontList, font_list); ac++;
  1304.   XtSetArg (av [ac], XmNforeground, fg); ac++;
  1305.   XtSetArg (av [ac], XmNbackground, bg); ac++;
  1306.   filefed->browse_button = XmCreatePushButton (filefed->rowcolumn,
  1307.                            "formFileBrowseButton",
  1308.                            av, ac);
  1309.   XtAddCallback(filefed->browse_button, XmNactivateCallback,
  1310.         fe_form_file_browse_cb, fed);
  1311.   XtManageChild(filefed->browse_button);
  1312.  
  1313.   /* This is changed later for self-submitting fields. */
  1314.   if (fe_globalData.nonterminal_text_translations)
  1315.     XtOverrideTranslations (fed->widget, fe_globalData.
  1316.                 nonterminal_text_translations);
  1317.  
  1318.   XtVaSetValues (fed->widget, XmNcursorPosition, 0, 0);
  1319.   loc = fe_ConvertToLocaleEncoding (charset, (unsigned char *)text);
  1320.   /* Add verify callbacks to implement JS key events */
  1321.   fe_HackTextTranslations_addCallbacks(fed->widget);
  1322.   /*
  1323.    * I don't know whether it is SGI or some version of Motif
  1324.    * but doing a XtVaSetValues() here will execute the
  1325.    * valueChangedCallback but ignore its changes.
  1326.    * XmTextFieldSetString() works as expected.
  1327.    */
  1328.   XmTextFieldSetString (fed->widget, loc);
  1329.   if (((char *) loc) != text) {
  1330.     XP_FREE (loc);
  1331.   }
  1332.   if (tmp_text) XP_FREE (tmp_text);
  1333. }
  1334.  
  1335. static void
  1336. file_get_value(FEFormData *fed,
  1337.            LO_FormElementStruct *form,
  1338.            XP_Bool delete_p)
  1339. {
  1340.   FEFileFormData *filefed = (FEFileFormData*)fed;
  1341.   
  1342.   text_get_value(fed, form, delete_p);
  1343.  
  1344.   /* if delete_p is true, then form_element_get_value will have destroyed
  1345.      fed->widget (our text field.)  We need to finish the job here. */
  1346.   if (delete_p)
  1347.     {
  1348.       XtDestroyWidget(filefed->rowcolumn);
  1349.  
  1350.       filefed->rowcolumn = 0;
  1351.     }
  1352. }
  1353.  
  1354. static void
  1355. file_free(FEFormData *fed,
  1356.       LO_FormElementData *form)
  1357. {
  1358.   FEFileFormData *filefed = (FEFileFormData*)fed;
  1359.  
  1360.   if (filefed->rowcolumn)
  1361.     XtDestroyWidget(filefed->rowcolumn);
  1362.  
  1363.   filefed->rowcolumn = 0;
  1364.   fed->widget = 0;
  1365.  
  1366.   XP_FREE(fed);
  1367. }
  1368.  
  1369. /*
  1370. **
  1371. ** VTABLE for Text like button elements (BUTTON, RESET, SUBMIT).
  1372. **
  1373. */
  1374. static void
  1375. button_create_widget(FEFormData *fed,
  1376.              LO_FormElementStruct *form)
  1377. {
  1378.   MWContext *context = fed->context;
  1379.   LO_FormElementData *form_data;
  1380.   Widget parent;
  1381.   int32 form_type;
  1382.   unsigned char *string;
  1383.   char *name;
  1384.   LO_TextAttr *text_attr;
  1385.   XmFontList font_list = NULL;
  1386.   XmString xmstring = NULL;
  1387.   Arg av [50];
  1388.   int ac;
  1389.  
  1390.   text_attr = XP_GetFormTextAttr(form);
  1391.   parent = CONTEXT_DATA (context)->drawing_area;
  1392.   form_data = XP_GetFormElementData(form);
  1393.   form_type = XP_FormGetType(form_data);
  1394.   string = (unsigned char*)XP_FormGetValue(form_data);
  1395.   name  = (form_type == FORM_TYPE_SUBMIT
  1396.        ? "formSubmitButton"
  1397.        : (form_type == FORM_TYPE_RESET
  1398.           ? "formResetButton"
  1399.           : "formButton"));
  1400.  
  1401.   fe_FontlistAndXmStringForFormElement(context,
  1402.                        form_type,
  1403.                        (char*)string,
  1404.                        text_attr,
  1405.                        &xmstring,
  1406.                        &font_list);
  1407.  
  1408. #ifdef DEBUG_username
  1409.   if (xmstring == NULL) printf ("xmstring is NULL\n");
  1410. #endif
  1411.  
  1412.   ac = 0;
  1413.  
  1414.   if (xmstring)
  1415.     {
  1416.       XtSetArg (av [ac], XmNlabelString, xmstring); ac++;
  1417.     }
  1418.   /*#ifdef FORMS_ARE_FONTIFIED*/
  1419.   if (font_list)
  1420.     {
  1421.       XtSetArg (av [ac], XmNfontList, font_list); ac++;
  1422.     }
  1423.   /*#endif*/
  1424.   /* Ok, buttons are always text-colored, because OptionMenu buttons
  1425.      must be, and making buttons be a different color looks
  1426.      inconsistent.
  1427.   */
  1428.   if (form_type == FORM_TYPE_SUBMIT)
  1429.     {
  1430.       XtSetArg (av [ac], XmNshowAsDefault, 1); ac++;
  1431.     }
  1432.   
  1433.   fed->widget = XmCreatePushButton (parent, name, av, ac);
  1434.  
  1435.   if (xmstring)
  1436.     XmStringFree (xmstring);
  1437.  
  1438. /*#ifdef FORMS_ARE_COLORED*/
  1439.   set_form_colors(fed, &text_attr->fg, &text_attr->bg);
  1440. /*#endif*/
  1441.   
  1442. #ifndef NO_NEW_DEFAULT_SIZES
  1443.   /* added so the security people (or anyone needing an HTML area with
  1444.      form elements in it) could specify a wider default width than
  1445.      what motif computes based on the font */
  1446.   if (form->width > 0
  1447.       || form->height > 0)
  1448.     {
  1449.       Dimension width;
  1450.       Dimension height;
  1451.       Dimension bw;
  1452.       
  1453.       XtVaGetValues(fed->widget,
  1454.             XmNheight, &height,
  1455.             XmNwidth, &width,
  1456.             XmNborderWidth, &bw,
  1457.             NULL);
  1458.       
  1459.       /* take into account our padding */
  1460.       width  += fe_FORM_LEFT_MARGIN + fe_FORM_RIGHT_MARGIN;
  1461.       height += fe_FORM_TOP_MARGIN + fe_FORM_BOTTOM_MARGIN;
  1462.       width  += (bw * 2);
  1463.       height += (bw * 2);
  1464.       
  1465.       if (form->width > width)
  1466.     width = form->width;
  1467.       if (form->height > height)
  1468.     height = form->height;
  1469.       
  1470.       XtVaSetValues(fed->widget,
  1471.             XmNheight, height,
  1472.             XmNwidth, width,
  1473.             NULL);
  1474.     }
  1475. #endif
  1476.   
  1477.   switch (form_type)
  1478.     {
  1479.     case FORM_TYPE_SUBMIT:
  1480.       XtAddCallback (fed->widget,
  1481.              XmNactivateCallback, fe_submit_form_cb, fed);
  1482.       break;
  1483.     case FORM_TYPE_RESET:
  1484.       XtAddCallback (fed->widget,
  1485.              XmNactivateCallback, fe_reset_form_cb, fed);
  1486.       break;
  1487.     case FORM_TYPE_BUTTON:
  1488.       XtAddCallback (fed->widget,
  1489.              XmNactivateCallback, fe_button_form_cb, fed);
  1490.       break;
  1491.     }
  1492. }
  1493.  
  1494. /*
  1495. **
  1496. ** Vtable routines for the radio and checkbox form elements.
  1497. **
  1498. */
  1499. static void
  1500. checkbox_create_widget(FEFormData *fed,
  1501.                LO_FormElementStruct *form)
  1502. {
  1503.   MWContext *context = fed->context;
  1504.   Widget parent = CONTEXT_DATA (context)->drawing_area;
  1505.   LO_FormElementData *form_data;
  1506.   int32 form_type;
  1507.   XmString xmstring;
  1508.   int margin = 2; /* leave some slack... */
  1509.   int size;
  1510.   int descent;
  1511.   XmFontList locale_font_list = NULL;
  1512.   Arg av[10];
  1513.   int ac;
  1514.   LO_TextAttr *text_attr;
  1515.  
  1516.   form_data = XP_GetFormElementData(form);
  1517.   form_type = XP_FormGetType(form_data);
  1518.  
  1519.   text_attr = XP_GetFormTextAttr(form);
  1520.  
  1521.   fe_font_list_metrics (context, form, locale_font_list, &size, &descent);
  1522.   size += (margin * 2);
  1523.  
  1524.   XP_FormSetElementToggled(form_data,
  1525.                XP_FormGetDefaultToggled(form_data));
  1526.   
  1527.   ac = 0;
  1528.   xmstring = XmStringCreate (" ", XmFONTLIST_DEFAULT_TAG);
  1529.   /* These always use our font list, for proper sizing. */
  1530.   XtSetArg (av [ac], XmNfontList, locale_font_list); ac++;
  1531.   XtSetArg (av [ac], XmNwidth,  size); ac++;
  1532.   XtSetArg (av [ac], XmNheight, size); ac++;
  1533.   XtSetArg (av [ac], XmNresize, False); ac++;
  1534.   XtSetArg (av [ac], XmNspacing, 2); ac++;
  1535.   XtSetArg (av [ac], XmNlabelString, xmstring); ac++;
  1536.   XtSetArg (av [ac], XmNvisibleWhenOff, True); ac++;
  1537.   XtSetArg (av [ac], XmNset, XP_FormGetDefaultToggled(form_data)); ac++;
  1538.   XtSetArg (av [ac], XmNindicatorType,
  1539.         (form_type == FORM_TYPE_RADIO
  1540.          ? XmONE_OF_MANY : XmN_OF_MANY)); ac++;
  1541.  
  1542.   fed->widget = XmCreateToggleButton (parent, "toggleForm", av, ac);
  1543.  
  1544.   /* These must always be the prevailing color of the text,
  1545.      or they look silly. */
  1546. #ifdef FORMS_ARE_COLORED
  1547.   set_form_colors(fed, &text_attr->fg, &text_attr->bg);
  1548. #endif
  1549.  
  1550.   if (form_type == FORM_TYPE_RADIO)
  1551.     XtAddCallback (fed->widget, XmNvalueChangedCallback,
  1552.            fe_radio_form_cb, fed);
  1553.   else
  1554.     XtAddCallback (fed->widget, XmNvalueChangedCallback,
  1555.            fe_check_form_cb, fed);
  1556.  
  1557.   XmStringFree (xmstring);
  1558. }
  1559.  
  1560. static void
  1561. checkbox_get_value(FEFormData *fed,
  1562.            LO_FormElementStruct *form,
  1563.            XP_Bool delete_p)
  1564. {
  1565.   LO_FormElementData *form_data = XP_GetFormElementData(form);
  1566.   Boolean set = False;
  1567.  
  1568.   XtVaGetValues(fed->widget, XmNset, &set, NULL);
  1569.  
  1570.   XP_FormSetElementToggled(form_data, set);
  1571.  
  1572.   form_element_get_value(fed, form, delete_p);
  1573. }
  1574.  
  1575. static void
  1576. checkbox_change(FEFormData *fed,
  1577.         LO_FormElementStruct *form)
  1578. {
  1579.   LO_FormElementData *form_data = XP_GetFormElementData(form);
  1580.   int32 form_type = XP_FormGetType(form_data);
  1581.   XP_Bool toggled = XP_FormGetElementToggled(form_data);
  1582.  
  1583.   switch (form_type)
  1584.     {
  1585.     case FORM_TYPE_RADIO:
  1586.       if (toggled) LO_FormRadioSet (fed->context, form);
  1587.       /* SPECIAL: If this was the only radio button in the radio group,
  1588.      LO_FormRadioSet() will turn it back ON again if Mocha tried to
  1589.      turn it OFF. We want to let mocha be able to turn ON/OFF
  1590.      radio buttons. So we are going to override that and let mocha
  1591.      have its way.
  1592.       */
  1593.       XFE_SetFormElementToggle(fed->context, form, toggled);
  1594.       break;
  1595.     case FORM_TYPE_CHECKBOX:
  1596.       XtVaSetValues (fed->widget, XmNset, toggled, 0);
  1597.       break;
  1598.     }
  1599. }
  1600.  
  1601. /*
  1602. **
  1603. ** Vtable entries for FORM_TYPE_SELECT_MULT
  1604. **
  1605. */
  1606.  
  1607. static void 
  1608. select_create_widget(FEFormData *fed,
  1609.              LO_FormElementStruct *form)
  1610. {
  1611.   FESelectMultFormData *sel_fed = (FESelectMultFormData*)fed;
  1612.   MWContext *context = fed->context;
  1613.   Widget parent = CONTEXT_DATA(context)->drawing_area;
  1614.   LO_FormElementData *form_data = XP_GetFormElementData(form);
  1615.   int32 form_type = XP_FormGetType(form_data);
  1616.   LO_TextAttr *text_attr;
  1617.   int nitems = XP_FormSelectGetOptionsCount(form_data);
  1618.   int vlines;
  1619.   XmString *items = NULL;
  1620.   char *selected_p = NULL;
  1621.   int i;
  1622.   Arg av[30];
  1623.   int ac;
  1624.   XmFontList font_list = NULL;
  1625.  
  1626.   text_attr = XP_GetFormTextAttr(form);
  1627.  
  1628.   vlines = XP_FormSelectGetSize(form_data);
  1629.  
  1630.   if (vlines <= 0) vlines = nitems;
  1631.  
  1632.   if (nitems > 0) {
  1633.     items = (XmString *) malloc (sizeof (XmString) * nitems);
  1634.     selected_p = (char *) calloc (nitems, sizeof (char));
  1635.   }
  1636.   
  1637.   for (i = 0; i < nitems; i++)
  1638.     {
  1639.       lo_FormElementOptionData *d2 =
  1640.     XP_FormSelectGetOption(form_data, i);
  1641.  
  1642.       fe_FontlistAndXmStringForFormElement(context,
  1643.                        form_type,
  1644.                        (d2->text_value 
  1645.                         ? (char *) d2->text_value
  1646.                         : "---\?\?\?---"),
  1647.                        text_attr,
  1648.                        &items[i],
  1649.                        &font_list);
  1650.       
  1651.       selected_p [i] = !!d2->def_selected;
  1652.       d2->selected = d2->def_selected;
  1653.     }
  1654.  
  1655.   ac = 0;
  1656.   /* #ifdef FORMS_ARE_FONTIFIED */
  1657.   XtSetArg (av [ac], XmNfontList, font_list); ac++;
  1658.   /* #endif */
  1659.   XtSetArg (av [ac], XmNspacing, 0); ac++;
  1660.   
  1661.   if (nitems) {
  1662.     XtSetArg (av [ac], XmNitems, items); ac++;
  1663.     XtSetArg (av [ac], XmNitemCount, nitems); ac++;
  1664.   }
  1665.  
  1666.   if (form_type == FORM_TYPE_SELECT_MULT)
  1667.     {
  1668.       XtSetArg (av [ac], XmNvisibleItemCount, vlines); ac++;
  1669.       XtSetArg (av [ac], XmNlistSizePolicy, XmRESIZE_IF_POSSIBLE); ac++;
  1670.       XtSetArg (av [ac], XmNselectionPolicy,
  1671.         (XP_FormSelectGetMultiple(form_data)
  1672.          ? XmMULTIPLE_SELECT
  1673.          : XmSINGLE_SELECT)); ac++;
  1674.       XtSetArg(av[ac], XmNx, -15000); ac++;
  1675.     }
  1676.   else /* FORM_TYPE_SELECT_ONE */
  1677.     {
  1678.       Visual *v = 0;
  1679.       Colormap cmap = 0;
  1680.       Cardinal depth = 0;
  1681.  
  1682.       fe_getVisualOfContext (context, &v, &cmap, &depth);
  1683.  
  1684.       XtSetArg (av [ac], XmNshadowThickness, 1); ac++;
  1685.       XtSetArg (av [ac], XmNarrowType, XmMOTIF); ac++;
  1686.       XtSetArg (av [ac], XmNtype, XmDROP_DOWN_LIST_BOX); ac++;
  1687.       XtSetArg (av [ac], XmNvisual, v); ac++;
  1688.       XtSetArg (av [ac], XmNcolormap, cmap); ac++;
  1689.       XtSetArg (av [ac], XmNdepth, depth); ac++;
  1690.     }
  1691.  
  1692.   if (form_type == FORM_TYPE_SELECT_MULT)
  1693.     {
  1694.       sel_fed->list_widget = XmCreateScrolledList (parent, "list", av, ac);
  1695.       fed->widget = XtParent(sel_fed->list_widget);
  1696.       /*
  1697.        * We need this Unmanage because otherwise XtIsManaged on the
  1698.        * parent fails later.  It seems XmCreateScrolledList() creates
  1699.        * an unmanaged list with a managed scrolled window parent.
  1700.        * How stupid.
  1701.        */
  1702.       XtUnmanageChild (fed->widget);
  1703.       XtManageChild   (sel_fed->list_widget);
  1704.     }
  1705.   else /* FORM_TYPE_SELECT_ONE */
  1706.     {
  1707.       /* we also need to set the fontlist explicitly on the label, for
  1708.      some reason... */
  1709.       Widget label;
  1710.  
  1711.       fed->widget = DtCreateComboBox(parent, "list", av, ac);
  1712.       XtVaGetValues(fed->widget,
  1713.             XmNlist, &sel_fed->list_widget,
  1714.             NULL);
  1715.  
  1716.       label = ((DtComboBoxWidget)fed->widget)->combo_box.label;
  1717.  
  1718.       ac = 0;
  1719.       /* #ifdef FORMS_ARE_FONTIFIED */
  1720.       XtSetArg (av [ac], XmNfontList, font_list); ac++;
  1721.       XtSetValues(label, av, ac);
  1722.     }
  1723.  
  1724. #ifdef FORMS_ARE_COLORED
  1725.   set_form_colors(fed, &text_attr->fg, &text_attr->bg);
  1726. #endif
  1727.  
  1728. #ifndef NO_NEW_DEFAULT_SIZES
  1729.   /* added so the security people (or anyone needing an HTML area with
  1730.      form elements in it) could specify a wider default width (or higher
  1731.      default height) than what motif computes based on the font */
  1732.   if (form->width > 0)
  1733.     {
  1734.       Dimension width;
  1735.       Dimension height;
  1736.       Dimension bw;
  1737.       
  1738.       XtVaGetValues(sel_fed->list_widget,
  1739.             XmNwidth, &width,
  1740.             XmNheight, &height,
  1741.             XmNborderWidth, &bw,
  1742.             NULL);
  1743.       
  1744.       /* take into account our padding */
  1745.       width  += fe_FORM_LEFT_MARGIN + fe_FORM_RIGHT_MARGIN;
  1746.       height += fe_FORM_TOP_MARGIN + fe_FORM_BOTTOM_MARGIN;
  1747.       width  += (bw * 2);
  1748.       height += (bw * 2);
  1749.       
  1750.       if (form->width > width)
  1751.     width = form->width;
  1752.       
  1753.       if (form->height > height)
  1754.     height = form->height;
  1755.       
  1756.       XtVaSetValues(sel_fed->list_widget,
  1757.             XmNwidth, width,
  1758.             XmNheight, height,
  1759.             NULL);
  1760.     }
  1761. #endif
  1762.   
  1763.   for (i = 0; i < nitems; i++)
  1764.     if (selected_p[i])
  1765.       if (form_type == FORM_TYPE_SELECT_MULT)
  1766.     XmListSelectPos(sel_fed->list_widget, i+1, False);
  1767.       else /* FORM_TYPE_SELECT_ONE */
  1768.     DtComboBoxSelectItem(fed->widget, items[i]);
  1769.  
  1770.   if (form_type == FORM_TYPE_SELECT_MULT)
  1771.     {
  1772.       XtAddCallback (sel_fed->list_widget,
  1773.              XmNdefaultActionCallback, fe_list_form_cb, fed);
  1774.       XtAddCallback (sel_fed->list_widget,
  1775.              XmNsingleSelectionCallback, fe_list_form_cb, fed);
  1776.       XtAddCallback (sel_fed->list_widget,
  1777.              XmNmultipleSelectionCallback, fe_list_form_cb, fed);
  1778.       XtAddCallback (sel_fed->list_widget,
  1779.              XmNextendedSelectionCallback, fe_list_form_cb, fed);
  1780.       XtInsertEventHandler(sel_fed->list_widget,
  1781.                KeyPressMask, False,
  1782.                fe_list_find_eh, context, XtListHead);
  1783.       XtAddEventHandler(sel_fed->list_widget,
  1784.             FocusChangeMask, FALSE, 
  1785.             (XtEventHandler)fe_mocha_focus_notify_eh, 
  1786.             fed);
  1787.     }
  1788.   else
  1789.     {
  1790.       XtAddCallback(fed->widget,
  1791.             XmNselectionCallback, fe_combo_form_cb, sel_fed);
  1792.     }
  1793.   
  1794.   sel_fed->nkids = nitems;
  1795.   sel_fed->selected_p = selected_p;
  1796. }
  1797.  
  1798. static void 
  1799. select_get_value(FEFormData *fed,
  1800.              LO_FormElementStruct *form,
  1801.              XP_Bool delete_p)
  1802. {
  1803.   FESelectMultFormData *sel_fed = (FESelectMultFormData*)fed;
  1804.   LO_FormElementData *form_data = XP_GetFormElementData(form);
  1805.   int i;
  1806.   
  1807.   for (i = 0; i < sel_fed->nkids; i ++)
  1808.     {
  1809.       lo_FormElementOptionData *option_data =
  1810.     XP_FormSelectGetOption(form_data, i);
  1811.       
  1812.       XP_FormOptionSetSelected(option_data,
  1813.                    sel_fed->selected_p[i]);
  1814.     }
  1815.  
  1816.   form_element_get_value(fed, form, delete_p);
  1817. }
  1818.  
  1819. static void 
  1820. select_free(FEFormData *fed,
  1821.         LO_FormElementData *form_data)
  1822. {
  1823.   FESelectMultFormData *sel_fed = (FESelectMultFormData*)fed;
  1824.  
  1825.   if (sel_fed->selected_p)
  1826.     free(sel_fed->selected_p);
  1827.  
  1828.   form_element_free(fed, form_data);
  1829. }
  1830.  
  1831. static void 
  1832. select_reset(FEFormData *fed,
  1833.          LO_FormElementStruct *form)
  1834. {
  1835.   FESelectMultFormData *sel_fed = (FESelectMultFormData*)fed;
  1836.   LO_FormElementData *form_data = XP_GetFormElementData(form);
  1837.   int32 form_type = XP_FormGetType(form_data);
  1838.   int nitems = XP_FormSelectGetOptionsCount(form_data);
  1839.   int i;
  1840.   XmString *items;
  1841.  
  1842.   XtVaGetValues(sel_fed->list_widget, XmNitems, &items, NULL);
  1843.  
  1844.   for (i = 0; i < nitems; i++)
  1845.     {
  1846.       lo_FormElementOptionData *option = XP_FormSelectGetOption(form_data, i);
  1847.       XP_Bool selected;
  1848.  
  1849.       XP_FormOptionSetSelected(option, XP_FormOptionGetDefaultSelected(option));
  1850.  
  1851.       selected = XP_FormOptionGetSelected(option);
  1852.       if (selected) {
  1853.     /* Highlight the item at pos i+1 if it is not already */
  1854.     if (!sel_fed->selected_p[i])
  1855.       if (form_type == FORM_TYPE_SELECT_MULT)
  1856.         XmListSelectPos(sel_fed->list_widget, i+1, False);
  1857.       else /* FORM_TYPE_SELECT_ONE */
  1858.         DtComboBoxSelectItem(fed->widget, items[i]);
  1859.       }
  1860.       else
  1861.     XmListDeselectPos(sel_fed->list_widget, i+1);
  1862.       sel_fed->selected_p [i] = selected;
  1863.     }
  1864. }
  1865.  
  1866. static void 
  1867. select_change(FEFormData *fed,
  1868.           LO_FormElementStruct *form)
  1869. {
  1870.   FESelectMultFormData *sel_fed = (FESelectMultFormData*)fed;
  1871.   LO_FormElementData *form_data = XP_GetFormElementData(form);
  1872.   int32 form_type = XP_FormGetType(form_data);
  1873.   fe_Font fe_font;
  1874.   LO_TextAttr *text_attr;
  1875.   uint16 mask;
  1876.   XmString *new_items;
  1877.   char* new_selected_p;
  1878.   int nitems;
  1879.   int i;
  1880.   int16 charset;
  1881.   XmFontList unicodePseudo_font_list = NULL;
  1882.   XP_Bool item_selected = FALSE;
  1883.  
  1884.   nitems = XP_FormSelectGetOptionsCount(form_data);
  1885.   text_attr = XP_GetFormTextAttr(form);
  1886.   mask = text_attr->fontmask;
  1887.   charset = text_attr->charset;
  1888.   
  1889.   fe_font = fe_LoadUnicodeFont(NULL, "", 0, text_attr->size, mask, 0, 0, 0, 
  1890.                    XtDisplay(CONTEXT_WIDGET(fed->context)));
  1891.   
  1892.   if (nitems > 0)
  1893.     {
  1894.       new_items = (XmString *) malloc (sizeof (XmString) * nitems);
  1895.       new_selected_p = (char *) calloc (nitems, sizeof (char));
  1896.     }
  1897.  
  1898. #ifdef DEBUG_username
  1899.   printf ("nitems = %d\n", nitems);
  1900. #endif
  1901.  
  1902.   for (i = 0; i < nitems; i ++)
  1903.     {
  1904.       char *str;
  1905.       lo_FormElementOptionData *option_data =
  1906.     XP_FormSelectGetOption(form_data, i);
  1907.  
  1908.       str = (option_data->text_value 
  1909.          ? ((*((char *) option_data->text_value)) 
  1910.         ? ((char *) option_data->text_value) 
  1911.         : " ") 
  1912.          : "---\?\?\?---");
  1913.  
  1914.       new_items [i] = fe_ConvertToXmString(str, charset, fe_font,
  1915.                        XmFONT_IS_FONT,
  1916.                        &unicodePseudo_font_list);
  1917.       new_selected_p [i] = !!XP_FormOptionGetSelected(option_data);
  1918.  
  1919. #ifdef DEBUG_username
  1920.       printf ("items[%d] = %s\n", i, str);
  1921. #endif
  1922.     }
  1923.   
  1924.   XmListDeselectAllItems(sel_fed->list_widget);
  1925.  
  1926.   XtVaSetValues(sel_fed->list_widget,
  1927.         XmNitems, new_items,
  1928.         XmNitemCount, nitems,
  1929.         NULL);
  1930.  
  1931.   for (i = 0; i < nitems; i++)
  1932.     if (new_selected_p[i])
  1933.       if (form_type == FORM_TYPE_SELECT_MULT)
  1934.     XmListSelectPos(sel_fed->list_widget, i+1, False);
  1935.       else /* FORM_TYPE_SELECT_ONE */
  1936.     {
  1937.       DtComboBoxSelectItem(fed->widget, new_items[i]);
  1938.       item_selected = TRUE;
  1939.     }
  1940.  
  1941.   if (sel_fed->selected_p)
  1942.     free(sel_fed->selected_p);
  1943.  
  1944.   sel_fed->selected_p = new_selected_p;
  1945.   sel_fed->nkids = nitems;
  1946. }
  1947.  
  1948. /*
  1949. **
  1950. ** Vtable entries for FORM_TYPE_TEXTAREA
  1951. **
  1952. */
  1953.  
  1954. static void
  1955. textarea_create_widget(FEFormData *fed,
  1956.                LO_FormElementStruct *form)
  1957. {
  1958.   FETextAreaFormData *ta_fed = (FETextAreaFormData*)fed;
  1959.   MWContext *context = fed->context;
  1960.   Widget parent;
  1961.   int16 charset;
  1962.   LO_FormElementData *form_data;
  1963.   int32 form_type;
  1964.   int32 rows, cols;
  1965.   char *text;
  1966.   unsigned char *loc;
  1967.   XmFontList locale_font_list;
  1968.   Arg av [50];
  1969.   int ac;
  1970.   LO_TextAttr *text_attr;
  1971.  
  1972.   parent = CONTEXT_DATA (context)->drawing_area;
  1973.   form_data = XP_GetFormElementData(form);
  1974.   form_type = XP_FormGetType(form_data);
  1975.   text_attr = XP_GetFormTextAttr(form);
  1976.   text = (char*)XP_FormGetDefaultText(form_data);
  1977.   charset = text_attr->charset;
  1978.  
  1979.   XP_FormTextAreaGetDimensions(form_data,
  1980.                    &rows, &cols);
  1981.  
  1982.   
  1983.   /* the default size for text fields is 20 columns. 
  1984.      XX Shouldn't the backend just fill it in with 20? */
  1985.   if (cols == 0) cols = 20;
  1986.  
  1987.   if (!text) text = "";
  1988.  
  1989.   fe_forms_clean_text (context, charset, text, False);
  1990.   loc = fe_ConvertToLocaleEncoding (charset, text);
  1991.  
  1992.   fe_FontlistAndXmStringForFormElement(context,
  1993.                        form_type,
  1994.                        loc,
  1995.                        text_attr,
  1996.                        NULL,
  1997.                        &locale_font_list);
  1998.   if (!locale_font_list)
  1999.     return;
  2000.   
  2001.   ac = 0;
  2002.   
  2003.   XtSetArg (av[ac], XmNscrollingPolicy, XmAUTOMATIC); ac++;
  2004.   XtSetArg (av[ac], XmNvisualPolicy, XmCONSTANT); ac++;
  2005.   XtSetArg (av[ac], XmNscrollBarDisplayPolicy, XmSTATIC); ac++;
  2006.   
  2007.   XtSetArg (av[ac], XmNvalue, loc); ac++;
  2008.   XtSetArg (av[ac], XmNcursorPosition, 0); ac++;
  2009.   /* from bstell: in multibyte (asian) locales, characters tend to be twice
  2010.      as wide as in non-multibyte locales.  To make things look correct,
  2011.      we divide the column number in half in those cases. */
  2012.   XtSetArg (av[ac], XmNcolumns, ((fe_LocaleCharSetID & MULTIBYTE) ?
  2013.                  (cols + 1) / 2 : cols)); ac++;
  2014.   XtSetArg (av[ac], XmNrows, rows); ac++;
  2015.   /*
  2016.    * Gotta love Motif.  No matter what wordWrap is set to, if
  2017.    * there is a horizontal scrollbar present it won't wrap.
  2018.    * Of course the documentation mentions this nowhere.
  2019.    * "Use the source Luke!"
  2020.    */
  2021.   if (XP_FormTextAreaGetAutowrap(form_data) != TEXTAREA_WRAP_OFF)
  2022.     {
  2023.       XtSetArg (av[ac], XmNscrollHorizontal, FALSE); ac++;
  2024.       XtSetArg (av[ac], XmNwordWrap, TRUE); ac++;
  2025.     }
  2026.   XtSetArg (av[ac], XmNeditMode, XmMULTI_LINE_EDIT); ac++;
  2027.   /* Ok, let's try using the fixed font for text areas only. */
  2028.   /*#ifdef FORMS_ARE_FONTIFIED*/
  2029.   XtSetArg (av[ac], XmNfontList, locale_font_list); ac++;
  2030.   /*#endif*/
  2031.   XtSetArg(av[ac], XmNx, -15000); ac++;
  2032.   ta_fed->text_widget = XmCreateScrolledText (parent, "formText", av, ac);
  2033.   ta_fed->form_data.widget = XtParent(ta_fed->text_widget);
  2034.  
  2035.   /* The scroller must have the prevailing color of the text,
  2036.      or it looks funny.*/
  2037. #ifdef FORMS_ARE_COLORED
  2038.   set_form_colors(fed, &text_attr->fg, &text_attr->bg);
  2039. #endif
  2040.  
  2041.   if (((char *) loc) != text)
  2042.     {
  2043.       XP_FREE (loc);
  2044.     }
  2045.  
  2046.   XtAddCallback(ta_fed->text_widget, XmNlosingFocusCallback,
  2047.         fe_lost_focus_cb, fed);
  2048.   XtAddCallback(ta_fed->text_widget, XmNfocusCallback, fe_got_focus_cb, fed);
  2049.   XtAddEventHandler(ta_fed->text_widget,
  2050.             KeyPressMask | KeyReleaseMask,
  2051.             FALSE, /* don't care about nonmaskable events */
  2052.             fe_key_handler,
  2053.             ta_fed);
  2054.  
  2055.   /* Add verify callbacks to implement JS key events */
  2056.   fe_HackTextTranslations_addCallbacks(ta_fed->text_widget);
  2057.  
  2058.   XtUnmanageChild (ta_fed->form_data.widget);
  2059.   XtManageChild (ta_fed->text_widget);
  2060. }
  2061.  
  2062. static void
  2063. textarea_display(FEFormData *fed,
  2064.          LO_FormElementStruct *form)
  2065. {
  2066.   form_element_display(fed, form);
  2067. }
  2068.  
  2069. static void
  2070. textarea_get_value(FEFormData *fed,
  2071.            LO_FormElementStruct *form,
  2072.            XP_Bool delete_p)
  2073. {
  2074.   MWContext *context = fed->context;
  2075.   LO_FormElementData *form_data = XP_GetFormElementData(form);
  2076.   FETextAreaFormData *ta_fed = (FETextAreaFormData*)fed;
  2077.   INTL_CharSetInfo c = LO_GetDocumentCharacterSetInfo(context);
  2078.   char *text = 0;
  2079.   int32 cols;
  2080.   PA_Block current_text, new_current_text;
  2081.   PA_Block default_text;
  2082.  
  2083.   XP_FormTextAreaGetDimensions(form_data, NULL, &cols);
  2084.  
  2085.   XtVaGetValues (ta_fed->text_widget, XmNvalue, &text, 0);
  2086.   if (! text) return;
  2087.   if (XP_FormTextAreaGetAutowrap(form_data) == TEXTAREA_WRAP_HARD) {
  2088.     char *tmp = XP_WordWrap(fe_LocaleCharSetID, text, cols, 0);
  2089.     if (text) XtFree(text);
  2090.     if (!tmp) return;
  2091.     text = tmp;
  2092.   }
  2093.  
  2094.   current_text = XP_FormGetCurrentText(form_data);
  2095.   default_text = XP_FormGetDefaultText(form_data);
  2096.  
  2097.   if (current_text && current_text != default_text)
  2098.     free (current_text);
  2099.  
  2100.   new_current_text = 
  2101.     (PA_Block)fe_ConvertFromLocaleEncoding (INTL_GetCSIWinCSID(c),
  2102.                         (unsigned char *) text);
  2103.  
  2104.   XP_FormSetCurrentText(form_data, new_current_text);
  2105.  
  2106.   if (((char *) new_current_text) != text) {
  2107.     free (text);
  2108.   }
  2109.  
  2110.   form_element_get_value(fed, form, delete_p);
  2111. }
  2112.  
  2113. static void
  2114. textarea_reset(FEFormData *fed,
  2115.            LO_FormElementStruct *form)
  2116. {
  2117.   LO_FormElementData *form_data = XP_GetFormElementData(form);
  2118.   FETextAreaFormData *ta_fed = (FETextAreaFormData*)fed;
  2119.   char *default_text = (char*)XP_FormGetDefaultText(form_data);
  2120.   LO_TextAttr *text_attr = XP_GetFormTextAttr(form);
  2121.   int16 charset = text_attr->charset;
  2122.   unsigned char *loc;
  2123.  
  2124.   fe_forms_clean_text (fed->context, charset, default_text, False);
  2125.  
  2126.   XtVaSetValues (ta_fed->text_widget, XmNcursorPosition, 0, 0);
  2127.  
  2128.   loc = fe_ConvertToLocaleEncoding (charset, (unsigned char*)default_text);
  2129.  
  2130.   XtVaSetValues (ta_fed->text_widget, XmNvalue, loc, 0);
  2131.  
  2132.   if (((char *) loc) != default_text)
  2133.     {
  2134.       XP_FREE (loc);
  2135.     }
  2136. }
  2137.  
  2138. static void
  2139. textarea_lost_focus(FEFormData *fed)
  2140. {
  2141.   FETextAreaFormData *ta_fed = (FETextAreaFormData*)fed;
  2142.   LO_FormElementData *form_data;
  2143.   char *text;
  2144.   XP_Bool text_changed = False;
  2145.   PA_Block current_text;
  2146.   JSEvent *event;
  2147.  
  2148.   form_data = XP_GetFormElementData(fed->form);
  2149.  
  2150.   current_text = XP_FormGetCurrentText(form_data);
  2151.  
  2152.   XtVaGetValues (ta_fed->text_widget, XmNvalue, &text, 0);
  2153.  
  2154.   if (!current_text || XP_STRCMP((char*)current_text, text))
  2155.     text_changed = True;
  2156.  
  2157.   if (((char*) current_text) != text) {
  2158.     XtFree (text);
  2159.   }
  2160.  
  2161.   /* if the text has changed, call get_element_value to copy it into the form
  2162.      element, and send a CHANGE event to the javascript thread. */
  2163.   if (text_changed)
  2164.     {
  2165.           (*fed->vtbl.get_element_value)(fed, fed->form, FALSE);
  2166.  
  2167.           event = XP_NEW_ZAP(JSEvent);
  2168.  
  2169.           event->type = EVENT_CHANGE;
  2170.  
  2171.           ET_SendEvent (fed->context, (LO_Element *) fed->form, event,
  2172.                         NULL, NULL);
  2173.       }
  2174. }
  2175.  
  2176. static FEFormData *
  2177. alloc_form_data(int32 form_type)
  2178. {
  2179.   FEFormData *data;
  2180.  
  2181.   switch (form_type)
  2182.     {
  2183.     case FORM_TYPE_TEXT:
  2184.     case FORM_TYPE_PASSWORD:
  2185.     case FORM_TYPE_READONLY:
  2186.       data = (FEFormData*)XP_NEW_ZAP(FEFormData);
  2187.       data->vtbl = text_form_vtable;
  2188.       return data;
  2189.  
  2190.     case FORM_TYPE_FILE:
  2191.       data = (FEFormData*)XP_NEW_ZAP(FEFileFormData);
  2192.       data->vtbl = file_form_vtable;
  2193.       return data;
  2194.  
  2195.     case FORM_TYPE_SUBMIT:
  2196.     case FORM_TYPE_RESET:
  2197.     case FORM_TYPE_BUTTON:
  2198.       data = (FEFormData*)XP_NEW_ZAP(FEFormData);
  2199.       data->vtbl = button_form_vtable;
  2200.       return data;
  2201.  
  2202.     case FORM_TYPE_RADIO:
  2203.     case FORM_TYPE_CHECKBOX:
  2204.       data = (FEFormData*)XP_NEW_ZAP(FEFormData);
  2205.       data->vtbl = checkbox_form_vtable;
  2206.       return data;
  2207.  
  2208.     case FORM_TYPE_SELECT_ONE:
  2209.       data = (FEFormData*)XP_NEW_ZAP(FESelectOneFormData);
  2210.       data->vtbl = selectone_form_vtable;
  2211.       return data;
  2212.  
  2213.     case FORM_TYPE_TEXTAREA:
  2214.       data = (FEFormData*)XP_NEW_ZAP(FETextAreaFormData);
  2215.       data->vtbl = textarea_form_vtable;
  2216.       return data;
  2217.  
  2218.     case FORM_TYPE_SELECT_MULT:
  2219.       data = (FEFormData*)XP_NEW_ZAP(FESelectMultFormData);
  2220.       data->vtbl = selectmult_form_vtable;
  2221.       return data;
  2222.  
  2223.     case FORM_TYPE_HIDDEN:
  2224.     case FORM_TYPE_JOT:
  2225.     case FORM_TYPE_ISINDEX:
  2226.     case FORM_TYPE_IMAGE:
  2227.     case FORM_TYPE_KEYGEN:
  2228.     case FORM_TYPE_OBJECT:
  2229.     default:
  2230.       XP_ASSERT(0);
  2231.       return NULL;
  2232.     }
  2233. }
  2234.  
  2235. /*
  2236. ** This method can be called more than once for the same front end form element.
  2237. ** 
  2238. ** In those cases we don't reallocate the FEData*, and also don't recreate the widget,
  2239. ** but we do set the form and context pointers in FEData, and we call the get_size
  2240. ** method.
  2241. **
  2242. ** The two cases I know of where layout calls this function more than once are:
  2243. ** when laying out a table with form elements in it -- layout moves our fe data
  2244. ** over to the new LO_FormElementStruct, but we have to sync up our pointer to
  2245. ** the new.
  2246. ** when reloading a page with frames in it.  In this case, the context is different,
  2247. ** so need to always set that as well.
  2248. **
  2249. ** Also, layout could have told us to delete the widget without freeing our FEData*
  2250. ** (this happens with delete_p is TRUE in XFE_GetFormElementValue.)  In this case,
  2251. ** we need to recreate the widget.
  2252. **
  2253. ** yuck.
  2254. */
  2255. void
  2256. XFE_GetFormElementInfo(MWContext *context,
  2257.                LO_FormElementStruct *form)
  2258. {
  2259.   LO_FormElementData *form_data = XP_GetFormElementData(form);
  2260.   FEFormData *fed;
  2261.  
  2262. #ifdef DEBUG_username
  2263.   printf ("XFE_GetFormElementInfo\n");
  2264. #endif
  2265.  
  2266.   if (!form_data)
  2267.     return;
  2268.  
  2269.   fed = (FEFormData*)XP_FormGetFEData(form_data);
  2270.   if (!fed)
  2271.     {
  2272.       int32 form_type = XP_FormGetType(form_data);
  2273.  
  2274.       fed = alloc_form_data(form_type);
  2275.  
  2276.       XP_ASSERT(fed);
  2277.       if (!fed) return;
  2278.  
  2279.       XP_FormSetFEData(form_data, fed);
  2280.     }
  2281.  
  2282.   fed->form = form;
  2283.   fed->context = context;
  2284.  
  2285.   if (!fed->widget)
  2286.     {
  2287.       XP_ASSERT(fed->vtbl.create_widget_func);
  2288.  
  2289.       (*fed->vtbl.create_widget_func)(fed, form);
  2290.     }
  2291.       
  2292.   XP_ASSERT(fed->vtbl.get_size_func);
  2293.   
  2294.   (*fed->vtbl.get_size_func)(fed, form);
  2295. }
  2296.  
  2297. void
  2298. XFE_DisplayFormElement(MWContext *context, int iLocation,
  2299.                        LO_FormElementStruct *form)
  2300. {
  2301.   LO_FormElementData *form_data = XP_GetFormElementData(form);
  2302.   FEFormData *fed;
  2303.  
  2304. #ifdef DEBUG_username
  2305.   printf ("XFE_DisplayFormElement\n");
  2306. #endif
  2307.  
  2308.   if (!form_data)
  2309.     return;
  2310.  
  2311.   fed = (FEFormData*)XP_FormGetFEData(form_data);
  2312.  
  2313.   XP_ASSERT(fed);
  2314.   if (!fed) return;
  2315.  
  2316.   if (fed->vtbl.display_element_func)
  2317.     (*fed->vtbl.display_element_func)(fed, form);
  2318. }
  2319.  
  2320. void
  2321. XFE_FormTextIsSubmit (MWContext *context, LO_FormElementStruct *form)
  2322. {
  2323.   LO_FormElementData *form_data = XP_GetFormElementData(form);
  2324.   FEFormData *fed;
  2325.  
  2326.   if (!form_data)
  2327.     return;
  2328.  
  2329.   fed = (FEFormData*)XP_FormGetFEData(form_data);
  2330.  
  2331.   XP_ASSERT(fed);
  2332.   if (!fed) return;
  2333.  
  2334.   if (fed->vtbl.element_is_submit_func)
  2335.     (*fed->vtbl.element_is_submit_func)(fed, form);
  2336. }
  2337.  
  2338. void
  2339. XFE_GetFormElementValue (MWContext *context, LO_FormElementStruct *form,
  2340.                          XP_Bool delete_p)
  2341. {
  2342.   LO_FormElementData *form_data = XP_GetFormElementData(form);
  2343.   FEFormData *fed;
  2344.  
  2345. #ifdef DEBUG_username
  2346.   printf ("XFE_GetFormElementValue (delete_p = %d)\n", delete_p);
  2347. #endif
  2348.  
  2349.   if (!form_data)
  2350.     return;
  2351.  
  2352.   fed = (FEFormData*)XP_FormGetFEData(form_data);
  2353.  
  2354.   XP_ASSERT(fed);
  2355.   if (!fed) return;
  2356.  
  2357.   if (fed->vtbl.get_element_value)
  2358.     (*fed->vtbl.get_element_value)(fed, form, delete_p);
  2359. }
  2360.  
  2361. void
  2362. FE_FreeFormElement(MWContext *context,
  2363.            LO_FormElementData *form_data)
  2364. {
  2365.   FEFormData *fed;
  2366.  
  2367. #ifdef DEBUG_username
  2368.   printf ("XFE_FreeFormElement. \n");
  2369. #endif
  2370.  
  2371.   if (!form_data)
  2372.     return;
  2373.  
  2374.   fed = (FEFormData*)XP_FormGetFEData(form_data);
  2375.  
  2376.   /* this assert gets tripped by HIDDEN form elements, since we have no
  2377.      FE data associated with them. */
  2378.   /*XP_ASSERT(fed);*/
  2379.   if (!fed) return;
  2380.  
  2381.   if (fed->vtbl.free_element_func)
  2382.     (*fed->vtbl.free_element_func)(fed, form_data);
  2383.  
  2384.   /* clear out the FE data, so we don't try anything funny from now on. */
  2385.   XP_FormSetFEData(form_data, NULL);
  2386. }
  2387.  
  2388. void
  2389. FE_FocusInputElement(MWContext *context,
  2390.              LO_Element *element)
  2391. {
  2392.   if (element)
  2393.     {
  2394.       LO_FormElementData *form_data =
  2395.     XP_GetFormElementData((LO_FormElementStruct*)element);
  2396.       FEFormData* fed;
  2397.  
  2398.       if (!form_data)
  2399.     return;
  2400.       
  2401.       fed = (FEFormData*)XP_FormGetFEData(form_data);
  2402.  
  2403.       if (fed->vtbl.focus_element_func)
  2404.     (*fed->vtbl.focus_element_func)(fed, (LO_FormElementStruct*)element);
  2405.     }
  2406.   else
  2407.     {
  2408.       JSEvent *event;
  2409.       
  2410.       if (context->is_grid_cell)
  2411.     fe_SetGridFocus (context);
  2412.       XmProcessTraversal (CONTEXT_WIDGET(context), XmTRAVERSE_CURRENT);
  2413.       FE_RaiseWindow(context);
  2414.       
  2415.       event = XP_NEW_ZAP(JSEvent);
  2416.       event->type = EVENT_FOCUS;
  2417.       ET_SendEvent (context, element, event, NULL, NULL);
  2418.     }
  2419. }
  2420.  
  2421. /*
  2422.  * Force input to be defocused from an element in the given window.
  2423.  * It's ok if the input didn't have input focus.
  2424.  */
  2425. void
  2426. FE_BlurInputElement(MWContext *context, LO_Element *element)
  2427. {
  2428.   /* Just blow away focus */    
  2429.   TRACEMSG(("XFE_BlurInputElement: element->type = %d\n"));
  2430.  
  2431.   if (!context) return;
  2432.  
  2433.   /* I was told by brendan that this is unnecessary - ramiro */
  2434. #if 0
  2435.   if (form == NULL || form->element_data == NULL) {
  2436. #ifdef DEBUG_spence    
  2437.     printf ("BlurInputElement: form is invalid\n");
  2438. #endif
  2439.     return;
  2440.   }
  2441. #endif
  2442.  
  2443.   fe_NeutralizeFocus (context);
  2444.  
  2445.   if (!element) {
  2446.       FE_LowerWindow(context);
  2447.  
  2448.       fe_MochaBlurNotify(context, element);
  2449.   }
  2450. }
  2451.  
  2452. void
  2453. FE_SelectInputElement(MWContext *context, LO_Element *element)
  2454. {
  2455.   LO_FormElementStruct *form = (LO_FormElementStruct*)element;
  2456.   LO_FormElementData *form_data = XP_GetFormElementData(form);
  2457.   FEFormData *fed;
  2458.  
  2459.   if (!form_data)
  2460.     return;
  2461.  
  2462.   fed = (FEFormData*)XP_FormGetFEData(form_data);
  2463.  
  2464.   XP_ASSERT(fed);
  2465.   if (!fed) return;
  2466.  
  2467.   if (fed->vtbl.select_element_func)
  2468.       (*fed->vtbl.select_element_func)(fed, form);
  2469. }
  2470.  
  2471. void
  2472. FE_ChangeInputElement(MWContext *context,
  2473.               LO_Element *element)
  2474. {
  2475.   LO_FormElementStruct *form = (LO_FormElementStruct*)element;
  2476.   LO_FormElementData *form_data = XP_GetFormElementData(form);
  2477.   FEFormData *fed;
  2478.   int32 type;
  2479.  
  2480.   if (!form_data)
  2481.     return;
  2482.  
  2483.   fed = (FEFormData*)XP_FormGetFEData(form_data);
  2484.   type = XP_FormGetType(form_data);
  2485.  
  2486.   /* this assert gets tripped by HIDDEN form elements, since we have no
  2487.      FE data associated with them. */
  2488.   /*XP_ASSERT(fed);*/
  2489.   if (!fed) return;
  2490.  
  2491.   if (fed->vtbl.change_element_func)
  2492.     {
  2493.       LO_LockLayout();
  2494.  
  2495.       (*fed->vtbl.change_element_func)(fed, form);
  2496.       
  2497.       LO_UnlockLayout();
  2498.     }
  2499. }
  2500.  
  2501. /*
  2502. ** Tell the FE that a form is being submitted without a UI gesture indicating
  2503. ** that fact, i.e., in a Mocha-automated fashion ("document.myform.submit()").
  2504. ** The FE is responsible for emulating whatever happens when the user hits the
  2505. ** submit button, or auto-submits by typing Enter in a single-field form.
  2506. */
  2507. void
  2508. FE_SubmitInputElement(MWContext *context, LO_Element *element)
  2509. {
  2510.   LO_FormSubmitData *submit;
  2511.   URL_Struct        *url;
  2512.   History_entry *he = NULL;
  2513.  
  2514.   TRACEMSG(("XFE_SubmitInputElement: element->type = %d\n"));
  2515.   if (!context) return;
  2516.  
  2517.   if (element == NULL) {
  2518. #ifdef DEBUG_username    
  2519.     printf ("SubmitInputElement: form is invalid\n");
  2520. #endif
  2521.     return;
  2522.   }
  2523.  
  2524.   submit = LO_SubmitForm (context, (LO_FormElementStruct *) element);
  2525.   if (!submit)
  2526.     return;
  2527.  
  2528.   /* Create the URL to load */
  2529.   url = NET_CreateURLStruct((char *)submit->action, NET_DONT_RELOAD);
  2530.  
  2531.   /* ... add the form data */
  2532.   NET_AddLOSubmitDataToURLStruct(submit, url);
  2533.  
  2534.   /* referrer field if there is one */
  2535.   he = SHIST_GetCurrent (&context->hist);
  2536.   url->referer = fe_GetURLForReferral(he);
  2537.  
  2538.   fe_GetURL (context, url, FALSE);
  2539.   LO_FreeSubmitData (submit);
  2540. }
  2541.  
  2542. /*
  2543.  * Emulate a button or HREF anchor click for element.
  2544.  */
  2545. void
  2546. FE_ClickInputElement(MWContext *context, LO_Element *xref)
  2547. {
  2548.   LO_FormElementStruct *form = (LO_FormElementStruct *) xref;
  2549.   LO_FormElementData *form_data;
  2550.   FEFormData *fed;
  2551.  
  2552.   if (!form)
  2553.     return;
  2554.  
  2555.   form_data = XP_GetFormElementData(form);
  2556.   if (!form_data)
  2557.     return;
  2558.  
  2559.   fed = XP_FormGetFEData(form_data);
  2560.  
  2561.   switch (xref->type) {
  2562.   case LO_FORM_ELE:
  2563.     {
  2564.       XmPushButtonCallbackStruct cb;
  2565.       cb.reason = XmCR_ACTIVATE;
  2566.       cb.event = 0;
  2567.       cb.click_count = 1;
  2568.       XtCallCallbacks (fed->widget, XmNactivateCallback, &cb);
  2569.     }
  2570.     break;
  2571.   case LO_IMAGE:
  2572.   case LO_TEXT:
  2573.     {
  2574.       CL_Event layer_event;
  2575.       fe_EventStruct fe_event;
  2576.       XEvent event;
  2577.  
  2578.       event.type = ButtonPress;
  2579.       event.xbutton.time = XtLastTimestampProcessed (XtDisplay(CONTEXT_WIDGET (context)));
  2580.       /* We only fill in the fields that we need. */
  2581. #ifdef LAYERS_FULL_FE_EVENT
  2582.       fe_event.event = &event;
  2583. #else
  2584.       fe_event_stuff(context,&fe_event,&event,0,0,FE_INVALID_MOUSE_ACTION);
  2585.       layer_event.fe_event_size = sizeof(fe_event);
  2586. #endif
  2587.       layer_event.fe_event = (void*)&fe_event;
  2588.       layer_event.x = xref->lo_image.x;
  2589.       layer_event.y = xref->lo_image.y; 
  2590.       (void) fe_HandleHREF (context, xref, False, False, &layer_event, 0);
  2591.     }
  2592.     break;
  2593.   }
  2594. }
  2595.  
  2596. static void
  2597. fe_form_file_browse_cb (Widget widget, XtPointer closure, XtPointer call_data)
  2598. {
  2599.   FEFormData *fed = (FEFormData*) closure;
  2600.   char *filename;
  2601.   XmString xm_title = 0;
  2602.   char *title = 0;
  2603.  
  2604.   XtVaGetValues (widget, XmNlabelString, &xm_title, 0);
  2605.   if (xm_title)
  2606.     XmStringGetLtoR (xm_title,
  2607.              XmFONTLIST_DEFAULT_TAG, &title); /* title - XtMalloc*/
  2608.   XmStringFree(xm_title);
  2609.  
  2610.   filename = fe_ReadFileName( fed->context, title, 0, FALSE, 0);
  2611.   XtFree(title);
  2612.  
  2613.   if (filename) {
  2614.     XP_StatStruct st;
  2615.     char buf [2048];
  2616.     if (stat(filename, &st) < 0) 
  2617.       {
  2618.     /* Error: Cant stat */
  2619.     PR_snprintf (buf, sizeof (buf),
  2620.              XP_GetString(XFE_ERROR_OPENING_FILE), filename);
  2621.     FE_Alert(fed->context, buf);
  2622.       }
  2623.     else 
  2624.       {
  2625.     /* The file was found. Stick the name into the text field. */
  2626.     XmTextFieldSetString (fed->widget, filename);
  2627.     
  2628.     /* resync up the backend with the current value in the text field. */
  2629.     XFE_GetFormElementValue(fed->context, fed->form, False);
  2630.       }
  2631.  
  2632.     XP_FREE(filename);
  2633.   }
  2634. }
  2635.  
  2636. /* This happens for self submiting forms. */
  2637. static void
  2638. fe_activate_submit_cb (Widget widget, XtPointer closure, XtPointer call_data)
  2639. {
  2640.   FEFormData *fed = (FEFormData*)closure;
  2641.  
  2642.   /* Move focus out of the current focus widget. This will make any OnChange
  2643.    * calls to mocha.
  2644.    */
  2645.   fe_NeutralizeFocus(fed->context);
  2646.  
  2647.   fe_submit_form_cb(widget, closure, call_data);
  2648. }
  2649.  
  2650. static void
  2651. fe_mocha_focus_notify_eh (Widget w, 
  2652.               XtPointer closure, 
  2653.               XEvent *ev, 
  2654.               Boolean *cont)
  2655. {
  2656.   FEFormData *fed = (FEFormData *) closure;
  2657.   MWContext *context = (MWContext *) fed->context;
  2658.  
  2659.   TRACEMSG (("fe_focus_notify_eh\n"));
  2660.   switch (ev->type) {
  2661.   case FocusIn:
  2662.     TRACEMSG (("focus in\n"));
  2663.     fe_MochaFocusNotify(context, (LO_Element*)fed->form);
  2664.     break;
  2665.   case FocusOut:
  2666.     TRACEMSG (("focus out\n"));
  2667.     fe_MochaBlurNotify(context, (LO_Element*)fed->form);
  2668.     break;
  2669.   }
  2670. }
  2671.  
  2672. static void
  2673. fe_mocha_submit_form_cb (MWContext *context, LO_Element *element, int32 event,
  2674.              void *closure, ETEventStatus status)
  2675. {
  2676.   LO_FormSubmitData *data;
  2677.   URL_Struct *url;
  2678.   
  2679.   if (status != EVENT_OK)
  2680.     return;
  2681.   
  2682.   data = LO_SubmitForm (context, (LO_FormElementStruct *) element);
  2683.   if (! data) return;
  2684.   url = NET_CreateURLStruct ((char *) data->action, FALSE);
  2685.   
  2686.   /* Add the referer to the URL. */
  2687.   {
  2688.     History_entry *he = SHIST_GetCurrent (&context->hist);
  2689.     if (url->referer)
  2690.       free (url->referer);
  2691.     url->referer = fe_GetURLForReferral(he);
  2692.   }
  2693.  
  2694.   NET_AddLOSubmitDataToURLStruct (data, url);
  2695.  
  2696.   fe_GetURL (context, url, FALSE);
  2697.   LO_FreeSubmitData (data);
  2698. }
  2699.  
  2700.  
  2701. static void
  2702. fe_mocha_submit_click_form_cb(MWContext *context, LO_Element *element,
  2703.                   int32 event, void *closure,
  2704.                   ETEventStatus status)
  2705. {
  2706.   FEFormData *fed = (FEFormData *) closure;
  2707.  
  2708.   if (status != EVENT_OK)
  2709.     return;
  2710.  
  2711.   /* Load the element value before telling mocha about the submit.
  2712.    * This needs to be done if we came here not because of the user
  2713.    * clicking on the submit button, like hitting RETURN on a text field.
  2714.    */
  2715.   XFE_GetFormElementValue(fed->context, fed->form, False);
  2716.   
  2717.   {
  2718.     JSEvent *event = XP_NEW_ZAP(JSEvent);
  2719.  
  2720.     event->type = EVENT_SUBMIT;
  2721.  
  2722.     ET_SendEvent (fed->context, (LO_Element *) fed->form, event,
  2723.                   fe_mocha_submit_form_cb, NULL);
  2724.   }
  2725. }
  2726.  
  2727. static void
  2728. fe_submit_form_cb (Widget widget, XtPointer closure, XtPointer call_data)
  2729. /*
  2730.  * description:
  2731.  *    This function was registered as an XmNactivateCallback for
  2732.  *    a Motif PushButton widget created in XFE_GetFormElementInfo().  
  2733.  *
  2734.  * preconditions:
  2735.  *    widget != 0 && closure != 0 && call_data != 0
  2736.  *
  2737.  * returns:
  2738.  *    not applicable
  2739.  *
  2740.  **********************************************************************/
  2741. {
  2742.   FEFormData *fed = (FEFormData *) closure;
  2743.   /*LO_FormSubmitData *data;*/
  2744.   /*URL_Struct *url;*/
  2745.  
  2746. #ifdef DEBUG
  2747.   /* check preconditions in debug mode */
  2748.   if (widget == 0 || closure == 0 || call_data == 0) {
  2749.       fprintf(stderr, private_precondition_format, __FILE__, __LINE__);
  2750.       fflush(stderr);
  2751.     }
  2752. #endif
  2753.  
  2754.  
  2755.   {
  2756.     XEvent  *x_event;
  2757.     JSEvent *js_event;
  2758.     XP_Bool do_geometry = FALSE;
  2759.  
  2760.     /*
  2761.      * The Motif documentation for XmPushButton informs that call_data
  2762.      * is a pointer to XmPushButtonCallbackStruct, declared in Xm/Xm.h.
  2763.      */
  2764.     x_event = ((XmPushButtonCallbackStruct*)call_data)->event;
  2765.     js_event = XP_NEW_ZAP(JSEvent);
  2766.  
  2767.     js_event->type = EVENT_CLICK;
  2768.     fe_complete_js_event(js_event, x_event, do_geometry);
  2769.  
  2770.     /* Lord Whorfin says: send me a click, dammit! */
  2771.     ET_SendEvent (fed->context, (LO_Element *) fed->form, js_event,
  2772.           fe_mocha_submit_click_form_cb, closure);
  2773.   }
  2774. }
  2775.  
  2776. static void
  2777. fe_mocha_button_form_cb (MWContext *context, LO_Element *element, int32 event,
  2778.             void *closure, ETEventStatus status)
  2779. {
  2780.   if (status != EVENT_OK)
  2781.     return;
  2782.  
  2783.   XFE_GetFormElementValue (context, (LO_FormElementStruct *) element, False);
  2784. }
  2785.  
  2786.  
  2787.  
  2788. /**********************************************************************
  2789.  */
  2790.  
  2791. static void
  2792. fe_button_form_cb (Widget widget,       /* in: a non-NULL valid widget */
  2793.            XtPointer closure,   /* in: registered by us in XtAddCallback() */
  2794.            XtPointer call_data) /* in: from Xt */
  2795.  
  2796. /*
  2797.  * description:
  2798.  *    Called when a form button is clicked.
  2799.  *    This function was registered as an XmNactivateCallback for
  2800.  *    a Motif PushButton widget created in XFE_GetFormElementInfo().
  2801.  *
  2802.  * preconditions:
  2803.  *    widget != 0 && closure != 0 && call_data != 0
  2804.  *
  2805.  * returns:
  2806.  *    not applicable
  2807.  *
  2808.  **********************************************************************/
  2809. {
  2810.   FEFormData *form_data = (FEFormData *) closure;
  2811.   XEvent  *x_event;  /* X Windows event structure */
  2812.   JSEvent *js_event; /* Javascript event */
  2813.   XP_Bool do_geometry = FALSE;
  2814.  
  2815. #ifdef DEBUG
  2816.   /* check preconditions in debug mode */
  2817.   if (widget == 0 || closure == 0 || call_data == 0) {
  2818.       fprintf(stderr, private_precondition_format, __FILE__, __LINE__);
  2819.       fflush(stderr);
  2820.     }
  2821. #endif
  2822.   /*
  2823.    * The Motif documentation for XmPushButton informs that call_data
  2824.    * is a pointer to XmPushButtonCallbackStruct, declared in Xm/Xm.h.
  2825.    */
  2826.   x_event = ((XmPushButtonCallbackStruct*)call_data)->event;
  2827.   js_event = XP_NEW_ZAP(JSEvent);
  2828.  
  2829.   js_event->type = EVENT_CLICK;
  2830.   fe_complete_js_event(js_event, x_event, do_geometry);
  2831.   ET_SendEvent (form_data->context,
  2832.         (LO_Element *) form_data->form,
  2833.         js_event,
  2834.         fe_mocha_button_form_cb,
  2835.         NULL);
  2836. }
  2837.  
  2838. static void
  2839. fe_mocha_reset_form_cb (MWContext *context, LO_Element *element, int32 event,
  2840.             void *closure, ETEventStatus status)
  2841. {
  2842.   if (status != EVENT_OK)
  2843.     return;
  2844.  
  2845.   LO_ResetForm (context, (LO_FormElementStruct *) element);
  2846. }
  2847.  
  2848. /**********************************************************************
  2849.  */
  2850.  
  2851. static void
  2852. fe_reset_form_cb (Widget widget, XtPointer closure, XtPointer call_data)
  2853.  
  2854. /*
  2855.  * description:
  2856.  *    This function was registered as an XmNactivateCallback for
  2857.  *    a Motif PushButton widget created in XFE_GetFormElementInfo().  
  2858.  *
  2859.  * preconditions:
  2860.  *    widget != 0 && closure != 0 && call_data != 0
  2861.  *
  2862.  * returns:
  2863.  *    not applicable
  2864.  *
  2865.  **********************************************************************/
  2866. {
  2867.   FEFormData *fed = (FEFormData *) closure;
  2868.  
  2869. #ifdef DEBUG
  2870.   /* check preconditions in debug mode */
  2871.   if (widget == 0 || closure == 0 || call_data == 0) {
  2872.       fprintf(stderr, private_precondition_format, __FILE__, __LINE__);
  2873.       fflush(stderr);
  2874.     }
  2875. #endif
  2876.  
  2877.   {
  2878.     XEvent  *x_event;
  2879.     JSEvent *js_event;
  2880.     XP_Bool do_geometry = FALSE;
  2881.  
  2882.     /*
  2883.      * The Motif documentation for XmPushButton informs that call_data
  2884.      * is a pointer to XmPushButtonCallbackStruct, declared in Xm/Xm.h.
  2885.      */
  2886.     x_event = ((XmPushButtonCallbackStruct*)call_data)->event;
  2887.     js_event = XP_NEW_ZAP(JSEvent);
  2888.  
  2889.     js_event->type = EVENT_CLICK;
  2890.     fe_complete_js_event(js_event, x_event, do_geometry);
  2891.  
  2892.     ET_SendEvent (fed->context, (LO_Element *) fed->form, js_event,
  2893.           fe_mocha_reset_form_cb, NULL);
  2894.   }
  2895. }
  2896.  
  2897.  
  2898. static void
  2899. fe_got_focus_cb (Widget widget, XtPointer closure, XtPointer call_data)
  2900. {
  2901.   FEFormData *fed = (FEFormData *) closure;
  2902.   JSEvent *event;
  2903.  
  2904.   TRACEMSG(("fe_got_focus_c:\n"));
  2905.   
  2906.   event = XP_NEW_ZAP(JSEvent);
  2907.   event->type = EVENT_FOCUS;
  2908.   
  2909.   ET_SendEvent (fed->context, (LO_Element *) fed->form, event, NULL, NULL);
  2910. }
  2911.  
  2912. static void
  2913. fe_lost_focus_cb (Widget widget, XtPointer closure, XtPointer call_data)
  2914. {
  2915.   FEFormData *fed = (FEFormData *) closure;
  2916.  
  2917.   if (!fed) return;
  2918.  
  2919.   if (fed->vtbl.lost_focus_func)
  2920.     (*fed->vtbl.lost_focus_func)(fed);
  2921.  
  2922.   /* always send a blur event. */
  2923.   fe_MochaBlurNotify(fed->context, (LO_Element*)fed->form);
  2924. }
  2925.  
  2926. static void
  2927. fe_complete_js_event(JSEvent *js_event,    /* inout */
  2928.            XEvent  *x_event,     /* in */
  2929.            XP_Bool  do_geometry) /* in */
  2930.  
  2931. /*
  2932.  * description:
  2933.  *    Updates js_event fields from an X event.
  2934.  *    Consolidates common code inside various callback
  2935.  *    functions within this module.
  2936.  *
  2937.  * preconditions:
  2938.  *    js_event != 0 && x_event != 0
  2939.  *    The js_event must already have an assigned type.
  2940.  *
  2941.  * returns:
  2942.  *    not applicable
  2943.  *
  2944.  ****************************************/
  2945. {
  2946.   unsigned int state_of_buttons_and_modifiers = 0;
  2947.  
  2948. #ifdef DEBUG
  2949.   /* check preconditions in debug mode */
  2950.   if (js_event == 0 || x_event == 0 || js_event->type == 0) {
  2951.     fprintf(stderr, private_precondition_format, __FILE__, __LINE__);
  2952.     fflush(stderr);
  2953.   }
  2954. #endif
  2955.  
  2956.   state_of_buttons_and_modifiers  = x_event->xbutton.state;
  2957.  
  2958.   switch(js_event->type) {
  2959.   case EVENT_CLICK:
  2960. #ifdef DEBUG_rodt
  2961.     /* check in debug mode */
  2962.     /* Expect to be processing ButtonRelease */
  2963.     if (x_event->type != ButtonRelease) {
  2964.       fprintf(stderr, private_check_format, __FILE__, __LINE__);
  2965.       fflush(stderr);
  2966.     }
  2967. #endif
  2968.     {
  2969.       unsigned int button;
  2970.  
  2971.       button = x_event->xbutton.button;
  2972.  
  2973.       /*
  2974.        * MOUSE BUTTON
  2975.        *
  2976.        * Only verified that left button is 1.  2 should be
  2977.        * middle button and 3 should be right button.
  2978.        */
  2979.       js_event->which = button;
  2980.  
  2981.     }
  2982.     break;
  2983.   case EVENT_KEYDOWN:
  2984.   case EVENT_KEYUP:
  2985.   case EVENT_KEYPRESS:
  2986. #ifdef DEBUG
  2987.     /* check in debug mode */
  2988.     /* Expect to be processing KeyPress or KeyRelease */
  2989.     if (x_event->type != KeyPress && x_event->type != KeyRelease) {
  2990.       fprintf(stderr, private_check_format, __FILE__, __LINE__);
  2991.       fflush(stderr);
  2992.     }
  2993. #endif
  2994.     {
  2995.       int buffer_length;
  2996.       char buffer[32];
  2997.       KeySym keysym;
  2998.       XComposeStatus * compose_status;
  2999.  
  3000.       /*
  3001.        * DETERMINE ASCII VALUE OF KEY PRESSED FOR JAVASCRIPT
  3002.        *
  3003.        * The following code needs to be checked on corner cases.
  3004.        * 
  3005.        */
  3006.  
  3007.       /*
  3008.        * Ignore compose status.
  3009.        * This may need to be changed.
  3010.        */
  3011.       compose_status = 0;
  3012.  
  3013.       /*
  3014.        * The XEvent structure is converted to a keysym as well as a
  3015.        * string (possibly more than one character) which represents
  3016.        * the keysym.
  3017.        *
  3018.        */
  3019.       buffer_length = XLookupString(&(x_event->xkey),
  3020.                     buffer,
  3021.                     31,
  3022.                     &keysym,
  3023.                     compose_status);
  3024.       if (buffer_length == 1)
  3025.     {
  3026.       js_event->which = buffer[0];
  3027.     }
  3028.       else
  3029.     {
  3030.       /*
  3031.        * Force all other cases to return a zero to 
  3032.        * expose bugs which indicate that this code needs
  3033.        * to be modified.
  3034.        */
  3035.       js_event->which = 0;
  3036.     }
  3037.  
  3038.       if (do_geometry) {
  3039.       js_event->x       = x_event->xkey.x;
  3040.       js_event->y       = x_event->xkey.y;
  3041.       js_event->screenx = x_event->xkey.x_root;
  3042.       js_event->screeny = x_event->xkey.y_root;
  3043.       }
  3044.     }
  3045.   break;
  3046.   }
  3047.  
  3048.   /*
  3049.    * ASSIGN MODIFIERS
  3050.    */
  3051.   if (state_of_buttons_and_modifiers) {
  3052.     /*
  3053.      * MODIFIER KEYS (ALT, CONTROL, SHIFT, META)
  3054.      * EVENT_xxx_MASK's are from ns/include/libevent.h
  3055.      */
  3056.     if (state_of_buttons_and_modifiers & ControlMask)
  3057.       js_event->modifiers |= EVENT_CONTROL_MASK;
  3058.     if (state_of_buttons_and_modifiers & ShiftMask)
  3059.       js_event->modifiers |= EVENT_SHIFT_MASK;
  3060.  
  3061.     /*
  3062.      * Only verified meta on Solaris 2.5 dtwm (mwm workalike)
  3063.      */
  3064.     if (state_of_buttons_and_modifiers & Mod4Mask)
  3065.       js_event->modifiers |= EVENT_META_MASK;
  3066.   }
  3067. }
  3068.  
  3069. static void
  3070. fe_key_handler(Widget widget,       /* in */
  3071.            XtPointer closure,   /* in */
  3072.            XEvent * x_event,    /* in */
  3073.            Boolean * bcontinue) /* out */
  3074.  
  3075. /*
  3076.  * description:
  3077.  *    Handles XEvents of type KeyPress and KeyRelease in order
  3078.  *    to pass these along to JavaScript.  JavaScript recognizes
  3079.  *    three key events:
  3080.  *    EVENT_KEYDOWN  corresponds to the X Event KeyPress
  3081.  *    EVENT_KEYUP    corresponds to the X Event KeyRelease
  3082.  *    EVENT_KEYPRESS corresponds to the X Event KeyPress followed by KeyRelease
  3083.  *
  3084.  *    Do not confuse EVENT_KEYPRESS with the X Event KeyPress!
  3085.  *
  3086.  * returns:
  3087.  *    Not applicable.  Note that currently bcontinue is not modified.
  3088.  *
  3089.  * end:
  3090.  ****************************************/
  3091. {
  3092.   FEFormData *form_data;
  3093.   JSEvent *js_event = 0; /* Javascript event */
  3094.   static int32 previous_js_event_type = 0;
  3095.   static int32 previous_js_event_which = 0;
  3096.  
  3097.  
  3098. #ifdef DEBUG
  3099.   /* check preconditions in debug mode */
  3100.   if (widget == 0 || closure == 0 || x_event == 0 || bcontinue == 0) {
  3101.       fprintf(stderr, private_precondition_format, __FILE__, __LINE__);
  3102.       fflush(stderr);
  3103.     }
  3104. #endif
  3105.  
  3106.   form_data = (FEFormData *) closure;
  3107.  
  3108.   if (x_event->type == KeyPress) {
  3109.       js_event = XP_NEW_ZAP(JSEvent);
  3110.       js_event->type = EVENT_KEYDOWN;
  3111.   }
  3112.   else if (x_event->type == KeyRelease) {
  3113.       js_event = XP_NEW_ZAP(JSEvent);
  3114.       js_event->type = EVENT_KEYUP;
  3115.   }
  3116.  
  3117.   /*
  3118.    * Do further work only on KeyPress and KeyRelease
  3119.    */
  3120.   if (js_event) {
  3121.     XP_Bool do_geometry = TRUE;
  3122.  
  3123.     fe_complete_js_event(js_event, x_event, do_geometry);
  3124.  
  3125.     /*
  3126.      * SYNTHESIZE AND SEND EVENT_KEYPRESS
  3127.      */
  3128.     if (previous_js_event_type == EVENT_KEYDOWN
  3129.     && js_event->type == EVENT_KEYUP
  3130.     && previous_js_event_which == js_event->which)
  3131.       {
  3132.     JSEvent *synthesized_js_event;
  3133.     
  3134.     synthesized_js_event = XP_NEW_ZAP(JSEvent);
  3135.     XP_MEMCPY(synthesized_js_event, js_event, sizeof(JSEvent));
  3136.     synthesized_js_event->type = EVENT_KEYPRESS;
  3137.     ET_SendEvent(form_data->context,
  3138.              (LO_Element *) form_data->form,
  3139.              synthesized_js_event,
  3140.              NULL,
  3141.              NULL);
  3142.       }
  3143.  
  3144.     /*
  3145.      * SEND EVENT_KEYDOWN/UP
  3146.      */
  3147.     previous_js_event_type  = js_event->type;
  3148.     previous_js_event_which = js_event->which;
  3149.     ET_SendEvent(form_data->context,
  3150.          (LO_Element *) form_data->form,
  3151.          js_event,
  3152.          NULL,
  3153.          NULL);
  3154.   }
  3155. }
  3156.  
  3157. static void
  3158. fe_mocha_radio_form_cb (MWContext *context, LO_Element *element,
  3159.             int32 event, void *closure, ETEventStatus status)
  3160. {
  3161.   XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct *)closure;
  3162.   LO_FormElementStruct *save;
  3163.  
  3164.   if (status == EVENT_OK) {
  3165.     if (cb->set)
  3166.       save = LO_FormRadioSet (context, (LO_FormElementStruct *) element);
  3167.     /* it's possible for save to be null here. it's a legal
  3168.        return value from LO_FormRadioSet
  3169.        */
  3170.     if (cb->set && save && save != (LO_FormElementStruct *) element)
  3171.       {
  3172.     XFE_SetFormElementToggle (context, save, TRUE);
  3173.     LO_FormRadioSet (context, save);
  3174.       }
  3175.     
  3176.     XFE_GetFormElementValue (context, (LO_FormElementStruct *) element, False);
  3177.   }
  3178.   XP_FREE (cb);
  3179. }
  3180.  
  3181. /**********************************************************************
  3182.  */
  3183.  
  3184. static void
  3185. fe_radio_form_cb (Widget widget, XtPointer closure, XtPointer call_data)
  3186.  
  3187. /*
  3188.  * description:
  3189.  *    This function was registered as an XmNvalueChangedCallback for
  3190.  *    a Motif ToggleButton widget created in XFE_GetFormElementInfo().  
  3191.  *
  3192.  * preconditions:
  3193.  *    widget != 0 && closure != 0 && call_data != 0
  3194.  *
  3195.  * returns:
  3196.  *    not applicable
  3197.  *
  3198.  **********************************************************************/
  3199. {
  3200.   FEFormData *fed = (FEFormData *) closure;
  3201.   XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct *)call_data;
  3202.   LO_FormElementStruct *save;
  3203.  
  3204. #ifdef DEBUG
  3205.   /* check preconditions in debug mode */
  3206.   if (widget == 0 || closure == 0 || call_data == 0) {
  3207.       fprintf(stderr, private_precondition_format, __FILE__, __LINE__);
  3208.       fflush(stderr);
  3209.     }
  3210. #endif
  3211.  
  3212.   if (cb->set)
  3213.     save = LO_FormRadioSet (fed->context, fed->form);
  3214.   else
  3215.     /* Don't allow the user to ever toggle a button off - exactly one
  3216.        must be selected at all times. */
  3217.     XtVaSetValues (widget, XmNset, True, 0);
  3218.  
  3219.   XFE_GetFormElementValue (fed->context, fed->form, False);
  3220.  
  3221.   {
  3222.     XEvent  *x_event;
  3223.     JSEvent *js_event;
  3224.     XP_Bool do_geometry = FALSE;
  3225.     XmToggleButtonCallbackStruct *cb_closure;
  3226.  
  3227.     cb_closure = XP_NEW_ZAP (XmToggleButtonCallbackStruct);
  3228.     XP_MEMCPY (cb_closure, cb, sizeof (XmToggleButtonCallbackStruct));
  3229.  
  3230.     x_event  = cb_closure->event;
  3231.     js_event = XP_NEW_ZAP(JSEvent);
  3232.     js_event->type = EVENT_CLICK;
  3233.     fe_complete_js_event(js_event, x_event, do_geometry);
  3234.     
  3235.     ET_SendEvent (fed->context, (LO_Element *) fed->form, js_event,
  3236.           fe_mocha_radio_form_cb, cb_closure);
  3237.   }
  3238. }
  3239.  
  3240. static void
  3241. fe_check_form_cb (Widget widget, XtPointer closure, XtPointer call_data)
  3242.  
  3243. /*
  3244.  * description:
  3245.  *    This function was registered as an XmNvalueChangedCallback for
  3246.  *    a Motif ToggleButton widget created in XFE_GetFormElementInfo().  
  3247.  *
  3248.  * preconditions:
  3249.  *    widget != 0 && closure != 0 && call_data != 0
  3250.  *
  3251.  * returns:
  3252.  *    not applicable
  3253.  *
  3254.  **********************************************************************/
  3255. {
  3256.   FEFormData *form_data = (FEFormData *) closure;
  3257.   XEvent  *x_event;  /* X Windows event structure */
  3258.   JSEvent *js_event;
  3259.   XP_Bool do_geometry = FALSE;
  3260.   lo_FormElementToggleData *data;
  3261.   Bool save;
  3262.  
  3263. #ifdef DEBUG
  3264.   /* check preconditions in debug mode */
  3265.   if (widget == 0 || closure == 0 || call_data == 0) {
  3266.     fprintf(stderr, private_precondition_format, __FILE__, __LINE__);
  3267.     fflush(stderr);
  3268.   }
  3269. #endif
  3270.  
  3271.   data = &form_data->form->element_data->ele_toggle;
  3272.   save = data->toggled;
  3273.  
  3274.   XFE_GetFormElementValue (form_data->context, form_data->form, False);
  3275.  
  3276.   /*
  3277.    * The Motif documentation for XmToggleButton informs that call_data
  3278.    * is a pointer to XmToggleButtonCallbackStruct, declared in Xm/Xm.h.
  3279.    */
  3280.   x_event = ((XmToggleButtonCallbackStruct*)call_data)->event;
  3281.   js_event = XP_NEW_ZAP(JSEvent);
  3282.   js_event->type = EVENT_CLICK;
  3283.   fe_complete_js_event(js_event, x_event, do_geometry);
  3284.  
  3285.   ET_SendEvent (form_data->context,
  3286.         (LO_Element *) form_data->form,
  3287.         js_event,
  3288.         NULL,
  3289.         NULL);
  3290. }
  3291.  
  3292. static void
  3293. fe_combo_form_cb(Widget widget, XtPointer closure, XtPointer call_data)
  3294. {
  3295.   FESelectOneFormData *sel_fed = (FESelectOneFormData *) closure;
  3296.   DtComboBoxCallbackStruct *cb = (DtComboBoxCallbackStruct *) call_data;
  3297.   LO_FormElementData *form_data;
  3298.   lo_FormElementOptionData *option_data;
  3299.   int i;
  3300.  
  3301.   form_data = XP_GetFormElementData(sel_fed->form_data.form);
  3302.  
  3303.   for (i = 0; i < sel_fed->nkids; i++)
  3304.     {
  3305.       option_data = XP_FormSelectGetOption(form_data,
  3306.                        i);
  3307.  
  3308.       /* combo boxes start the item ordering at 0, not 1. */
  3309.       sel_fed->selected_p [i] = (i == cb->item_position);
  3310.       
  3311.       XP_FormOptionSetSelected(option_data, sel_fed->selected_p[i]);
  3312.     }
  3313.   {
  3314.       JSEvent *event = XP_NEW_ZAP(JSEvent);
  3315.  
  3316.       event->type = EVENT_CHANGE;
  3317.  
  3318.       ET_SendEvent (sel_fed->form_data.context,
  3319.             (LO_Element *) sel_fed->form_data.form,
  3320.             event,
  3321.             NULL, NULL);
  3322.   }
  3323. }
  3324.  
  3325. static void
  3326. fe_list_form_cb (Widget widget, XtPointer closure, XtPointer call_data)
  3327. {
  3328.   FESelectMultFormData *sel_fed = (FESelectMultFormData *) closure;
  3329.   XmListCallbackStruct *cb = (XmListCallbackStruct *) call_data;
  3330.   LO_FormElementData *form_data;
  3331.   lo_FormElementOptionData *option_data;
  3332.   int i, j;
  3333.  
  3334.   form_data = XP_GetFormElementData(sel_fed->form_data.form);
  3335.  
  3336.   switch (cb->reason)
  3337.     {
  3338.     case XmCR_SINGLE_SELECT:
  3339.     case XmCR_BROWSE_SELECT:
  3340.       for (i = 0; i < sel_fed->nkids; i++)
  3341.     {
  3342.       option_data = XP_FormSelectGetOption(form_data,
  3343.                            i);
  3344.  
  3345.       /* Note that the item_position starts at 1, not 0!!!! */
  3346.       sel_fed->selected_p [i] = (cb->selected_item_count &&
  3347.                      i == (cb->item_position - 1));
  3348.  
  3349.       XP_FormOptionSetSelected(option_data, sel_fed->selected_p[i]);
  3350.         }
  3351.       break;
  3352.     case XmCR_MULTIPLE_SELECT:
  3353.     case XmCR_EXTENDED_SELECT:
  3354.       for (i = 0; i < sel_fed->nkids; i++)
  3355.     {
  3356.       /*
  3357.       **
  3358.       ** toshok -- this is extremely gross and inefficient.  must
  3359.       ** revisit it.  XXXXX
  3360.       **
  3361.       */
  3362.       option_data = XP_FormSelectGetOption(form_data,
  3363.                            i);
  3364.       
  3365.       sel_fed->selected_p [i] = 0;
  3366.       XP_FormOptionSetSelected(option_data, sel_fed->selected_p[i]);
  3367.  
  3368.       for (j = 0; j < cb->selected_item_count; j++)
  3369.         if (i == (cb->selected_item_positions [j] - 1))
  3370.           {
  3371.             sel_fed->selected_p [i] = 1;
  3372.         XP_FormOptionSetSelected(option_data, sel_fed->selected_p[i]);
  3373.           }    
  3374.     }
  3375.       break;
  3376.     case XmCR_DEFAULT_ACTION:
  3377.       break;
  3378.     default:
  3379.       assert (0);
  3380.       return;
  3381.     }
  3382.  
  3383.   {
  3384.       JSEvent *event = XP_NEW_ZAP(JSEvent);
  3385.  
  3386.       event->type = EVENT_CHANGE;
  3387.  
  3388.       ET_SendEvent (sel_fed->form_data.context,
  3389.             (LO_Element *) sel_fed->form_data.form,
  3390.             event,
  3391.             NULL, NULL);
  3392.   }
  3393. }
  3394.  
  3395.  
  3396. void
  3397. XFE_ResetFormElement (MWContext *context, LO_FormElementStruct *form)
  3398. {
  3399.   LO_FormElementData *form_data = XP_GetFormElementData(form);
  3400.   FEFormData *fed = (FEFormData*)XP_FormGetFEData(form_data);
  3401.   
  3402.   XP_ASSERT(fed);
  3403.   if (!fed) return;
  3404.   
  3405.   if (fed->vtbl.reset_element)
  3406.     (*fed->vtbl.reset_element)(fed, form);
  3407. }
  3408.  
  3409. /* don't *really* need a vtable entry for this one... or maybe we do. */
  3410. void
  3411. XFE_SetFormElementToggle (MWContext *context, LO_FormElementStruct *form,
  3412.               XP_Bool state)
  3413. {
  3414.   LO_FormElementData *form_data = XP_GetFormElementData(form);
  3415.   FEFormData *fed;
  3416.   int32 form_type;
  3417.  
  3418.   if (form_data == NULL) {
  3419. #ifdef DEBUG_username
  3420.     printf ("forms.c:%d; form_data == NULL\n", __LINE__);
  3421. #endif
  3422.     return;
  3423.   }
  3424.   
  3425.   fed = (FEFormData*)XP_FormGetFEData(form_data);
  3426.   form_type = XP_FormGetType(form_data);
  3427.  
  3428.   XP_ASSERT(form_type == FORM_TYPE_CHECKBOX ||
  3429.         form_type == FORM_TYPE_RADIO);
  3430.   if (form_type != FORM_TYPE_CHECKBOX
  3431.       && form_type != FORM_TYPE_RADIO)
  3432.     return;
  3433.  
  3434.   XtVaSetValues (fed->widget, XmNset, state, 0);
  3435. }
  3436.  
  3437. void
  3438. fe_SetFormsGravity (MWContext *context, int gravity)
  3439. {
  3440.   Widget *kids;
  3441.   Widget area;
  3442.   Cardinal nkids = 0;
  3443.   XSetWindowAttributes attr;
  3444.   unsigned long valuemask;
  3445.  
  3446.  
  3447.   XtVaGetValues (CONTEXT_DATA (context)->drawing_area,
  3448.                  XmNchildren, &kids, XmNnumChildren, &nkids,
  3449.                  0);
  3450.  
  3451.   valuemask = CWBitGravity | CWWinGravity;
  3452.   attr.win_gravity = gravity;
  3453.   attr.bit_gravity = gravity;
  3454.   area = CONTEXT_DATA (context)->drawing_area;
  3455.   XChangeWindowAttributes (XtDisplay(area), XtWindow(area), valuemask, &attr);
  3456.   while (nkids--)
  3457.   {
  3458.     if (XtIsManaged (kids[nkids]))
  3459.       XChangeWindowAttributes (XtDisplay(kids[nkids]), XtWindow(kids[nkids]),
  3460.                 valuemask, &attr);
  3461.   }
  3462. }
  3463.  
  3464. void
  3465. fe_ScrollForms (MWContext *context, int x_off, int y_off)
  3466. {
  3467.   Widget *kids;
  3468.   Cardinal nkids = 0;
  3469.  
  3470.   if (x_off == 0 && y_off == 0)
  3471.     return;
  3472.  
  3473.   XtVaGetValues (CONTEXT_DATA (context)->drawing_area,
  3474.          XmNchildren, &kids, XmNnumChildren, &nkids,
  3475.          0);
  3476.   while (nkids--)
  3477.     XtMoveWidget (kids [nkids],
  3478.           _XfeX(kids [nkids]) + x_off,
  3479.           _XfeY(kids [nkids]) + y_off);
  3480. }
  3481.  
  3482.  
  3483. void
  3484. fe_GravityCorrectForms (MWContext *context, int x_off, int y_off)
  3485. {
  3486.   Widget *kids;
  3487.   Cardinal nkids = 0;
  3488.  
  3489.   if (x_off == 0 && y_off == 0)
  3490.     return;
  3491.  
  3492.   XtVaGetValues (CONTEXT_DATA (context)->drawing_area,
  3493.                  XmNchildren, &kids, XmNnumChildren, &nkids,
  3494.                  0);
  3495.  
  3496.   while (nkids--)
  3497.   {
  3498.     if (XtIsManaged (kids[nkids]))
  3499.     {
  3500.         _XfeX(kids[nkids]) = _XfeX(kids[nkids]) + x_off;
  3501.         _XfeY(kids[nkids]) = _XfeY(kids[nkids]) + y_off;
  3502.     }
  3503.   }
  3504. }
  3505.  
  3506.