mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-01 06:35:42 +00:00
3506 lines
91 KiB
C
3506 lines
91 KiB
C
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
*
|
|
* The contents of this file are subject to the Netscape Public License
|
|
* Version 1.0 (the "NPL"); you may not use this file except in
|
|
* compliance with the NPL. You may obtain a copy of the NPL at
|
|
* http://www.mozilla.org/NPL/
|
|
*
|
|
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
|
* for the specific language governing rights and limitations under the
|
|
* NPL.
|
|
*
|
|
* The Initial Developer of this code under the NPL is Netscape
|
|
* Communications Corporation. Portions created by Netscape are
|
|
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
|
* Reserved.
|
|
*/
|
|
/*
|
|
forms.c --- creating and displaying forms widgets
|
|
Created: Jamie Zawinski <jwz@netscape.com>, 21-Jul-94.
|
|
Whacked into a completely new form: Chris Toshok <toshok@netscape.com>, 29-Oct-1997.
|
|
*/
|
|
|
|
|
|
#include "mozilla.h"
|
|
#include "xfe.h"
|
|
#include "fonts.h"
|
|
#include "felocale.h"
|
|
#include "xpform.h"
|
|
#include "layers.h"
|
|
|
|
#include <plevent.h> /* for mocha */
|
|
#include <prtypes.h>
|
|
#include <libevent.h>
|
|
|
|
#include <libi18n.h>
|
|
#include "intl_csi.h"
|
|
#include "fonts.h"
|
|
#ifndef NO_WEB_FONTS
|
|
#include "nf.h"
|
|
#include "Mnfrc.h"
|
|
#include "Mnfrf.h"
|
|
#endif
|
|
|
|
#include "DtWidgets/ComboBoxP.h"
|
|
|
|
#include <Xfe/XfeP.h> /* for xfe widgets and utilities */
|
|
|
|
/* XXX */
|
|
/* #define NO_NEW_DEFAULT_SIZES 1 */
|
|
|
|
/* for XP_GetString() */
|
|
#include <xpgetstr.h>
|
|
extern int XFE_ERROR_OPENING_FILE;
|
|
|
|
/* Kludge around conflicts between Motif and xp_core.h... */
|
|
#undef Bool
|
|
#define Bool char
|
|
|
|
/* #define FORMS_ARE_FONTIFIED */
|
|
/* #define FORMS_ARE_COLORED */
|
|
|
|
|
|
/* Kludge kludge kludge, should be in resources... */
|
|
#define fe_FORM_LEFT_MARGIN 0
|
|
#define fe_FORM_RIGHT_MARGIN 0
|
|
#define fe_FORM_TOP_MARGIN 4
|
|
#define fe_FORM_BOTTOM_MARGIN 4
|
|
|
|
static void fe_form_file_browse_cb (Widget, XtPointer, XtPointer);
|
|
static void fe_activate_submit_cb (Widget, XtPointer, XtPointer);
|
|
static void fe_submit_form_cb (Widget, XtPointer, XtPointer);
|
|
static void fe_reset_form_cb (Widget, XtPointer, XtPointer);
|
|
static void fe_radio_form_cb (Widget, XtPointer, XtPointer);
|
|
static void fe_check_form_cb (Widget, XtPointer, XtPointer);
|
|
static void fe_button_form_cb (Widget, XtPointer, XtPointer);
|
|
static void fe_combo_form_cb(Widget, XtPointer, XtPointer);
|
|
static void fe_got_focus_cb (Widget, XtPointer, XtPointer);
|
|
static void fe_list_form_cb (Widget, XtPointer, XtPointer);
|
|
static void fe_lost_focus_cb (Widget, XtPointer, XtPointer);
|
|
static void fe_mocha_focus_notify_eh (Widget w,
|
|
XtPointer closure,
|
|
XEvent *ev,
|
|
Boolean *cont);
|
|
|
|
static void fe_key_handler(Widget w, XtPointer client_data, XEvent * xevent, Boolean * bcontinue);
|
|
static void fe_complete_js_event(JSEvent *js_event, XEvent *x_event, XP_Bool do_geometry);
|
|
|
|
#ifdef DEBUG
|
|
static char * private_precondition_format = "debug: precondition violation at %s:%d\n";
|
|
static char * private_check_format = "debug: check violation at %s:%d\n";
|
|
#endif
|
|
|
|
typedef struct fe_form_vtable FEFormVtable;
|
|
typedef struct fe_form_data FEFormData;
|
|
|
|
struct fe_form_vtable
|
|
{
|
|
void (*create_widget_func)(FEFormData *, LO_FormElementStruct *);
|
|
void (*get_size_func)(FEFormData *, LO_FormElementStruct *);
|
|
void (*element_is_submit_func)(FEFormData *, LO_FormElementStruct *);
|
|
void (*display_element_func)(FEFormData *, LO_FormElementStruct *);
|
|
void (*get_element_value)(FEFormData *, LO_FormElementStruct *, XP_Bool);
|
|
void (*free_element_func)(FEFormData *, LO_FormElementData *);
|
|
void (*reset_element)(FEFormData *, LO_FormElementStruct *);
|
|
void (*select_element_func)(FEFormData *, LO_FormElementStruct *);
|
|
void (*change_element_func)(FEFormData *, LO_FormElementStruct *);
|
|
void (*focus_element_func)(FEFormData *, LO_FormElementStruct *);
|
|
void (*lost_focus_func)(FEFormData *);
|
|
};
|
|
|
|
struct fe_form_data {
|
|
FEFormVtable vtbl;
|
|
LO_FormElementStruct *form;
|
|
Widget widget;
|
|
MWContext *context;
|
|
};
|
|
|
|
typedef struct {
|
|
FEFormData form_data;
|
|
|
|
Widget rowcolumn;
|
|
Widget browse_button;
|
|
Widget file_widget;
|
|
} FEFileFormData;
|
|
|
|
typedef struct {
|
|
FEFormData form_data;
|
|
|
|
Widget text_widget; /* form_data.widget is the scrolled window. */
|
|
} FETextAreaFormData;
|
|
|
|
typedef struct {
|
|
FEFormData form_data;
|
|
|
|
Widget list_widget; /* form_data.widget is the scrolled window. */
|
|
int nkids;
|
|
char *selected_p;
|
|
} FESelectMultFormData;
|
|
|
|
typedef FESelectMultFormData FESelectOneFormData;
|
|
|
|
static FEFormData* alloc_form_data(int32 type);
|
|
|
|
static void text_create_widget(FEFormData *, LO_FormElementStruct *);
|
|
static void text_display(FEFormData *, LO_FormElementStruct *);
|
|
static void text_get_value(FEFormData *, LO_FormElementStruct *, XP_Bool);
|
|
static void text_reset(FEFormData *, LO_FormElementStruct *);
|
|
static void text_change(FEFormData *, LO_FormElementStruct *);
|
|
static void text_focus(FEFormData *, LO_FormElementStruct *);
|
|
static void text_lost_focus(FEFormData *);
|
|
static void text_select(FEFormData *, LO_FormElementStruct *);
|
|
|
|
static void file_create_widget(FEFormData *, LO_FormElementStruct *);
|
|
static void file_get_value(FEFormData *, LO_FormElementStruct *, XP_Bool);
|
|
static void file_free(FEFormData *, LO_FormElementData *);
|
|
|
|
static void button_create_widget(FEFormData *, LO_FormElementStruct *);
|
|
|
|
static void checkbox_create_widget(FEFormData *, LO_FormElementStruct *);
|
|
static void checkbox_get_value(FEFormData *, LO_FormElementStruct *, XP_Bool);
|
|
static void checkbox_change(FEFormData *, LO_FormElementStruct *);
|
|
|
|
static void select_create_widget(FEFormData *, LO_FormElementStruct *);
|
|
static void select_get_value(FEFormData *, LO_FormElementStruct *, XP_Bool);
|
|
static void select_free(FEFormData *, LO_FormElementData *);
|
|
static void select_reset(FEFormData *, LO_FormElementStruct *);
|
|
static void select_change(FEFormData *, LO_FormElementStruct *);
|
|
|
|
static void textarea_create_widget(FEFormData *, LO_FormElementStruct *);
|
|
static void textarea_display(FEFormData *, LO_FormElementStruct *);
|
|
static void textarea_get_value(FEFormData *, LO_FormElementStruct *, XP_Bool);
|
|
static void textarea_reset(FEFormData *, LO_FormElementStruct *);
|
|
static void textarea_lost_focus(FEFormData *);
|
|
|
|
static void form_element_display(FEFormData *, LO_FormElementStruct *);
|
|
static void form_element_get_size(FEFormData *, LO_FormElementStruct *);
|
|
static void form_element_is_submit(FEFormData *, LO_FormElementStruct *);
|
|
static void form_element_get_value(FEFormData *, LO_FormElementStruct *,
|
|
XP_Bool);
|
|
static void form_element_free(FEFormData *, LO_FormElementData *);
|
|
|
|
|
|
/* doubles as both the text and password vtable */
|
|
static FEFormVtable text_form_vtable = {
|
|
text_create_widget,
|
|
form_element_get_size,
|
|
form_element_is_submit,
|
|
text_display,
|
|
text_get_value,
|
|
form_element_free,
|
|
text_reset,
|
|
text_select,
|
|
text_change,
|
|
text_focus,
|
|
text_lost_focus
|
|
};
|
|
|
|
static FEFormVtable file_form_vtable = {
|
|
file_create_widget,
|
|
form_element_get_size,
|
|
form_element_is_submit,
|
|
text_display,
|
|
file_get_value,
|
|
file_free,
|
|
text_reset,
|
|
text_select,
|
|
text_change,
|
|
text_focus,
|
|
text_lost_focus
|
|
};
|
|
|
|
static FEFormVtable button_form_vtable = {
|
|
button_create_widget,
|
|
form_element_get_size,
|
|
NULL,
|
|
form_element_display,
|
|
form_element_get_value,
|
|
form_element_free,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL
|
|
};
|
|
|
|
static FEFormVtable checkbox_form_vtable = {
|
|
checkbox_create_widget,
|
|
form_element_get_size,
|
|
NULL,
|
|
form_element_display,
|
|
checkbox_get_value,
|
|
form_element_free,
|
|
NULL,
|
|
NULL,
|
|
checkbox_change,
|
|
NULL,
|
|
NULL
|
|
};
|
|
|
|
static FEFormVtable selectone_form_vtable = {
|
|
select_create_widget,
|
|
form_element_get_size,
|
|
NULL,
|
|
form_element_display,
|
|
select_get_value,
|
|
select_free,
|
|
select_reset,
|
|
NULL,
|
|
select_change,
|
|
NULL,
|
|
NULL
|
|
};
|
|
|
|
static FEFormVtable selectmult_form_vtable = {
|
|
select_create_widget,
|
|
form_element_get_size,
|
|
NULL,
|
|
form_element_display,
|
|
select_get_value,
|
|
select_free,
|
|
select_reset,
|
|
NULL,
|
|
select_change,
|
|
NULL,
|
|
NULL
|
|
};
|
|
|
|
static FEFormVtable textarea_form_vtable = {
|
|
textarea_create_widget,
|
|
form_element_get_size,
|
|
NULL,
|
|
textarea_display,
|
|
textarea_get_value,
|
|
form_element_free,
|
|
textarea_reset,
|
|
text_select,
|
|
text_change,
|
|
text_focus,
|
|
textarea_lost_focus
|
|
};
|
|
|
|
/*
|
|
** Why are these next two functions in this file?
|
|
*/
|
|
|
|
/*
|
|
* Raise the window to the top of the view order
|
|
*/
|
|
void
|
|
FE_RaiseWindow(MWContext *context)
|
|
{
|
|
#ifdef DEBUG_username
|
|
printf ("RaiseWindow: context 0x%x\n", context);
|
|
#endif
|
|
XtRealizeWidget (CONTEXT_WIDGET (context));
|
|
XtManageChild (CONTEXT_WIDGET (context));
|
|
/* XXX Uniconify the window if it was iconified */
|
|
XMapRaised(XtDisplay(CONTEXT_WIDGET(context)),
|
|
XtWindow(CONTEXT_WIDGET(context)));
|
|
XtPopup(CONTEXT_WIDGET(context),XtGrabNone);
|
|
}
|
|
|
|
/*
|
|
* Lower the window to the bottom of the view order
|
|
*/
|
|
void
|
|
FE_LowerWindow(MWContext *context)
|
|
{
|
|
#ifdef DEBUG_username
|
|
printf ("LowerWindow: context 0x%x\n", context);
|
|
#endif
|
|
if (!XtIsRealized(CONTEXT_WIDGET(context)))
|
|
return;
|
|
|
|
XLowerWindow(XtDisplay(CONTEXT_WIDGET(context)),
|
|
XtWindow(CONTEXT_WIDGET(context)));
|
|
}
|
|
|
|
static void
|
|
fe_font_list_metrics(MWContext *context, LO_FormElementStruct *form,
|
|
XmFontList font_list, int *ascentp, int *descentp)
|
|
{
|
|
fe_Font font;
|
|
LO_TextAttr *text = XP_GetFormTextAttr(form);
|
|
|
|
font = fe_LoadFontFromFace(context,text, &text->charset,
|
|
text->font_face,
|
|
text->size, text->fontmask);
|
|
if (!font)
|
|
{
|
|
*ascentp = 14;
|
|
*descentp = 3;
|
|
return;
|
|
}
|
|
FE_FONT_EXTENTS(text->charset, font, ascentp, descentp);
|
|
}
|
|
|
|
static void
|
|
fe_FontlistAndXmStringForFormElement(MWContext *context,
|
|
int32 form_type,
|
|
char *string,
|
|
LO_TextAttr *text_attr,
|
|
XmString *xmstring,
|
|
XmFontList *fontlist)
|
|
{
|
|
Widget parent = CONTEXT_DATA(context)->drawing_area;
|
|
XP_Bool use_UnicodePseudoFont;
|
|
fe_Font fe_font;
|
|
XmFontType type = 0; /* keep purify happy */
|
|
XmFontListEntry flentry;
|
|
int mask = text_attr->fontmask;
|
|
XmFontList unicodePseudo_font_list = NULL;
|
|
XmFontList locale_font_list = NULL;
|
|
|
|
use_UnicodePseudoFont = IS_UNICODE_CSID(text_attr->charset);
|
|
|
|
#ifdef DEBUG_username
|
|
printf ("fe_FontlistAndXmStringForFormElement(%s)\n", string);
|
|
#endif
|
|
|
|
switch (form_type)
|
|
{
|
|
case FORM_TYPE_FILE:
|
|
case FORM_TYPE_TEXT:
|
|
case FORM_TYPE_PASSWORD:
|
|
case FORM_TYPE_TEXTAREA:
|
|
case FORM_TYPE_READONLY:
|
|
/* Make sure text fields are non-bold, non-italic, fixed. */
|
|
mask &= (~ (LO_FONT_BOLD|LO_FONT_ITALIC));
|
|
mask |= LO_FONT_FIXED;
|
|
use_UnicodePseudoFont = FALSE; /* XmText doesn't use XmString */
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
/*
|
|
* Get the font info
|
|
*/
|
|
if (use_UnicodePseudoFont)
|
|
{
|
|
fe_font = fe_LoadUnicodeFont(NULL, "", 0, text_attr->size, mask,
|
|
0, 0, 0, XtDisplay(parent));
|
|
|
|
*fontlist = unicodePseudo_font_list;
|
|
}
|
|
else
|
|
{
|
|
fe_font = fe_GetFontOrFontSetFromFace(context, NULL,
|
|
text_attr->font_face,
|
|
text_attr->size,
|
|
mask, &type);
|
|
if (!fe_font)
|
|
return;
|
|
flentry = XmFontListEntryCreate(XmFONTLIST_DEFAULT_TAG, type, fe_font);
|
|
if (!flentry)
|
|
return;
|
|
locale_font_list = XmFontListAppendEntry(NULL, flentry);
|
|
if (!locale_font_list)
|
|
return;
|
|
XmFontListEntryFree(&flentry);
|
|
|
|
if (xmstring)
|
|
*xmstring = NULL;
|
|
|
|
*fontlist = locale_font_list;
|
|
}
|
|
|
|
if (string && xmstring)
|
|
*xmstring = fe_ConvertToXmString((unsigned char*)string,
|
|
text_attr->charset,
|
|
fe_font,
|
|
type,
|
|
fontlist);
|
|
}
|
|
|
|
static void
|
|
set_form_colors(FEFormData *fed,
|
|
LO_Color *lo_fg,
|
|
LO_Color *lo_bg)
|
|
{
|
|
Widget parent = CONTEXT_DATA (fed->context)->drawing_area;
|
|
Pixel fg, bg;
|
|
|
|
fg = fe_GetPixel (fed->context, lo_fg->red, lo_fg->green, lo_fg->blue);
|
|
bg = fe_GetPixel (fed->context, lo_bg->red, lo_bg->green, lo_bg->blue);
|
|
|
|
if (fg == bg)
|
|
{
|
|
/* the foreground and background are the same. Try to
|
|
choose something that will make things readable
|
|
(if a little ugly) */
|
|
|
|
XmGetColors(XtScreen(parent),
|
|
XfeColormap(parent),
|
|
bg,
|
|
&fg, NULL, NULL, NULL);
|
|
}
|
|
|
|
XtVaSetValues(fed->widget,
|
|
XmNforeground, fg,
|
|
XmNbackground, bg,
|
|
NULL);
|
|
}
|
|
|
|
static void
|
|
get_form_colors(FEFormData *fed,
|
|
LO_Color *lo_fg,
|
|
LO_Color *lo_bg,
|
|
Pixel *fg_r, Pixel *bg_r)
|
|
{
|
|
Widget parent = CONTEXT_DATA (fed->context)->drawing_area;
|
|
Pixel fg, bg;
|
|
|
|
fg = fe_GetPixel (fed->context, lo_fg->red, lo_fg->green, lo_fg->blue);
|
|
bg = fe_GetPixel (fed->context, lo_bg->red, lo_bg->green, lo_bg->blue);
|
|
|
|
if (fg == bg)
|
|
{
|
|
/* the foreground and background are the same. Try to
|
|
choose something that will make things readable
|
|
(if a little ugly) */
|
|
|
|
XmGetColors(XtScreen(parent),
|
|
XfeColormap(parent),
|
|
bg,
|
|
&fg, NULL, NULL, NULL);
|
|
}
|
|
|
|
*fg_r = fg;
|
|
*bg_r = bg;
|
|
}
|
|
|
|
/* Motif likes to complain when there are binary characters in
|
|
text strings.
|
|
*/
|
|
void
|
|
fe_forms_clean_text (MWContext *context,
|
|
int charset,
|
|
char *text,
|
|
Boolean newlines_too_p)
|
|
{
|
|
unsigned char *t = (unsigned char *) text;
|
|
for (; *t; t++)
|
|
{
|
|
unsigned char c = *t;
|
|
if ((newlines_too_p && (c == '\n' || c == '\r')) ||
|
|
(c < ' ' && c != '\t' && c != '\n' && c != '\r') ||
|
|
(c == 0x7f) ||
|
|
((INTL_CharSetType(charset) == SINGLEBYTE) &&
|
|
(0x7f <= c) && (c <= 0xa0)))
|
|
*t = ' ';
|
|
}
|
|
}
|
|
|
|
static void fe_HackTextTranslations_addCallbacks(Widget widget)
|
|
{
|
|
#if 0
|
|
/* make sure it gets added only once */
|
|
XtRemoveCallback(widget,
|
|
XmNmodifyVerifyCallback,
|
|
fe_textModifyVerifyCallback,
|
|
NULL);
|
|
XtRemoveCallback(widget,
|
|
XmNmotionVerifyCallback,
|
|
fe_textMotionVerifyCallback,
|
|
NULL);
|
|
#endif
|
|
XtAddCallback(widget,
|
|
XmNmotionVerifyCallback,
|
|
fe_textMotionVerifyCallback,
|
|
NULL);
|
|
XtAddCallback(widget,
|
|
XmNmodifyVerifyCallback,
|
|
fe_textModifyVerifyCallback,
|
|
NULL);
|
|
XtVaSetValues(widget,
|
|
XmNverifyBell,False,
|
|
NULL);
|
|
}
|
|
|
|
/*
|
|
* A list key event handler.
|
|
* This will search for a key in the XmList and shift the location cursor
|
|
* to a match.
|
|
*/
|
|
static void
|
|
fe_list_find_eh(Widget widget, XtPointer closure, XEvent* event,
|
|
Boolean* continue_to_dispatch)
|
|
{
|
|
MWContext *context = (MWContext *) closure;
|
|
Boolean usedEvent_p = False;
|
|
|
|
Modifiers mods;
|
|
KeySym k;
|
|
char *s;
|
|
int i;
|
|
int index; /* index is 1 based */
|
|
XmString *items;
|
|
int nitems;
|
|
|
|
#define MILLI_500_SECS 500
|
|
#define _LIST_MAX_CHARS 100
|
|
static char input[_LIST_MAX_CHARS] = {0};
|
|
static Time prev_time;
|
|
static Widget w = 0;
|
|
static Boolean is_prev_found = False;
|
|
|
|
if (!context || !event) return;
|
|
|
|
fe_UserActivity (context);
|
|
|
|
if (event->type == KeyPress) {
|
|
if (!(k = XtGetActionKeysym (event, &mods))) return;
|
|
if (!(s = XKeysymToString (k))) return;
|
|
if (!s || !*s || s[1]) return; /* no or more than 1 char */
|
|
if (!isprint(*s)) return; /* unprintable */
|
|
|
|
if ((widget == w) && (event->xkey.time - prev_time < MILLI_500_SECS)) {
|
|
/* Continue search */
|
|
if (is_prev_found) strcat(input, s);
|
|
else return;
|
|
}
|
|
else {
|
|
/* Fresh search */
|
|
is_prev_found = False;
|
|
strcpy(input, s);
|
|
}
|
|
w = widget;
|
|
prev_time = event->xkey.time;
|
|
index = XmListGetKbdItemPos(widget);
|
|
if (!index) return; /* List is empty */
|
|
|
|
/* Wrap search for input[] in List */
|
|
i = index;
|
|
i = (i == nitems) ? 1 : i+1; /* Increment i */
|
|
XtVaGetValues(widget, XmNitems, &items, XmNitemCount, &nitems, 0);
|
|
while (i != index) {
|
|
if (!XmStringGetLtoR(items[i-1], XmSTRING_DEFAULT_CHARSET, &s))
|
|
continue;
|
|
if (!strncmp(s, input, strlen(input))) {
|
|
/* Found */
|
|
XP_FREE(s);
|
|
XmListSetKbdItemPos(widget, i);
|
|
is_prev_found = True;
|
|
break;
|
|
}
|
|
XP_FREE(s);
|
|
i = (i == nitems) ? 1 : i+1; /* Increment i */
|
|
}
|
|
usedEvent_p = True;
|
|
}
|
|
|
|
if (usedEvent_p) *continue_to_dispatch = False;
|
|
}
|
|
|
|
/*
|
|
**
|
|
** VTABLE for "superclass", form_element.
|
|
**
|
|
*/
|
|
static void
|
|
form_element_display(FEFormData *fed,
|
|
LO_FormElementStruct *form)
|
|
{
|
|
MWContext *context = fed->context;
|
|
Arg av[10];
|
|
int ac;
|
|
uint16 attrmask = XP_GetFormEleAttrmask(form);
|
|
Position x;
|
|
Position y;
|
|
|
|
x = (form->x + form->x_offset
|
|
- CONTEXT_DATA (context)->document_x);
|
|
y = (form->y + form->y_offset
|
|
- CONTEXT_DATA (context)->document_y);
|
|
x += fe_FORM_LEFT_MARGIN;
|
|
y += fe_FORM_TOP_MARGIN;
|
|
|
|
if (!XtIsManaged(fed->widget))
|
|
{
|
|
Dimension bw = 0;
|
|
Dimension width = form->width;
|
|
Dimension height = form->height;
|
|
|
|
XtVaGetValues (fed->widget, XmNborderWidth, &bw, 0);
|
|
/* Since I told layout that width was width+bw+bw (for its sizing and
|
|
positioning purposes), subtract it out again when setting the size of
|
|
the text area. X thinks the borders are outside the WxH rectangle,
|
|
not inside, but thinks that the borders are below and to the right of
|
|
the X,Y origin, instead of up and to the left as you would expect
|
|
given the WxH behavior!!
|
|
*/
|
|
width -= (bw * 2);
|
|
height -= (bw * 2);
|
|
/* x += bw; */
|
|
/* y += bw;*/
|
|
|
|
width -= fe_FORM_LEFT_MARGIN + fe_FORM_RIGHT_MARGIN;
|
|
height -= fe_FORM_TOP_MARGIN + fe_FORM_BOTTOM_MARGIN;
|
|
|
|
/*
|
|
* Move to 0 before moving to where we want so it ends up
|
|
* where we want.
|
|
*/
|
|
ac = 0;
|
|
XtSetArg (av [ac], XmNx, 0); ac++;
|
|
XtSetArg (av [ac], XmNy, 0); ac++;
|
|
XtSetValues (fed->widget, av, ac);
|
|
|
|
|
|
#ifdef DEBUG_username
|
|
printf ("DisplayFormElement: width = %d; height = %d\n", width, height);
|
|
#endif
|
|
|
|
ac = 0;
|
|
XtSetArg (av [ac], XmNx, (Position)x); ac++;
|
|
XtSetArg (av [ac], XmNy, (Position)y); ac++;
|
|
XtSetArg (av [ac], XmNwidth, (Dimension)width); ac++;
|
|
XtSetArg (av [ac], XmNheight, (Dimension)height); ac++;
|
|
XtSetValues (fed->widget, av, ac);
|
|
|
|
XtSetMappedWhenManaged(fed->widget,
|
|
!(attrmask & LO_ELE_INVISIBLE));
|
|
|
|
XtManageChild (fed->widget);
|
|
}
|
|
else
|
|
{
|
|
XtSetMappedWhenManaged(fed->widget,
|
|
!(attrmask & LO_ELE_INVISIBLE));
|
|
|
|
XtMoveWidget(fed->widget, x, y);
|
|
}
|
|
}
|
|
|
|
static void
|
|
form_element_get_size(FEFormData *fed,
|
|
LO_FormElementStruct *form)
|
|
{
|
|
MWContext *context = fed->context;
|
|
Dimension width = 0;
|
|
Dimension height = 0;
|
|
Dimension bw = 0;
|
|
Dimension st = 0;
|
|
Dimension ht = 0;
|
|
Dimension margin_height = 0;
|
|
Dimension bottom = 0;
|
|
int ascent, descent;
|
|
XmFontList font_list;
|
|
LO_FormElementData *form_data = XP_GetFormElementData(form);
|
|
int32 form_type = XP_FormGetType(form_data);
|
|
Widget element_widget;
|
|
|
|
if (form_type == FORM_TYPE_FILE)
|
|
element_widget = ((FEFileFormData*)fed)->rowcolumn;
|
|
else
|
|
element_widget = fed->widget;
|
|
|
|
font_list = 0;
|
|
XtVaGetValues (element_widget, XmNfontList, &font_list, 0);
|
|
|
|
fe_HackTranslations (context, element_widget);
|
|
|
|
fe_font_list_metrics (context, form, font_list, &ascent, &descent);
|
|
|
|
XtRealizeWidget(element_widget);
|
|
|
|
if (fe_globalData.fe_guffaw_scroll == 1)
|
|
{
|
|
XSetWindowAttributes attr;
|
|
unsigned long valuemask;
|
|
|
|
valuemask = CWBitGravity | CWWinGravity;
|
|
attr.win_gravity = StaticGravity;
|
|
attr.bit_gravity = StaticGravity;
|
|
XChangeWindowAttributes (XtDisplay (element_widget),
|
|
XtWindow (element_widget),
|
|
valuemask, &attr);
|
|
}
|
|
|
|
XtVaGetValues (element_widget,
|
|
XmNwidth, &width,
|
|
XmNheight, &height,
|
|
XmNborderWidth, &bw,
|
|
XmNshadowThickness, &st,
|
|
XmNhighlightThickness, &ht,
|
|
XmNmarginHeight, &margin_height,
|
|
XmNmarginBottom, &bottom,
|
|
0);
|
|
|
|
#ifdef DEBUG_username
|
|
printf ("form before: width = %d; height = %d\n", width, height);
|
|
#endif
|
|
width += fe_FORM_LEFT_MARGIN + fe_FORM_RIGHT_MARGIN;
|
|
height += fe_FORM_TOP_MARGIN + fe_FORM_BOTTOM_MARGIN;
|
|
|
|
/* The WxH doesn't take into account the border width; so add that in
|
|
for layout's benefit. We subtract it again later. */
|
|
width += (bw * 2);
|
|
height += (bw * 2);
|
|
#ifdef DEBUG_username
|
|
printf ("form after: width = %d; height = %d\n", width, height);
|
|
#endif
|
|
form->width = width;
|
|
form->height = height;
|
|
|
|
/* Yeah. Uh huh. */
|
|
if (form_type == FORM_TYPE_RADIO ||
|
|
form_type == FORM_TYPE_CHECKBOX)
|
|
{
|
|
bottom = 0;
|
|
descent = bw;
|
|
}
|
|
|
|
form->baseline = height - (bottom + margin_height + st + bw + ht + descent
|
|
+ fe_FORM_BOTTOM_MARGIN);
|
|
}
|
|
|
|
static void
|
|
form_element_is_submit(FEFormData *fed,
|
|
LO_FormElementStruct *form)
|
|
{
|
|
XtRemoveCallback (fed->widget,
|
|
XmNactivateCallback, fe_activate_submit_cb, fed);
|
|
|
|
XtAddCallback (fed->widget,
|
|
XmNactivateCallback, fe_activate_submit_cb, fed);
|
|
|
|
if (fe_globalData.terminal_text_translations)
|
|
XtOverrideTranslations (fed->widget,
|
|
fe_globalData.terminal_text_translations);
|
|
}
|
|
|
|
static void
|
|
form_element_get_value(FEFormData *fed,
|
|
LO_FormElementStruct *form,
|
|
XP_Bool delete_p)
|
|
{
|
|
if (delete_p)
|
|
{
|
|
XtDestroyWidget(fed->widget);
|
|
fed->widget = 0;
|
|
}
|
|
}
|
|
|
|
static void
|
|
form_element_free(FEFormData *fed,
|
|
LO_FormElementData *form)
|
|
{
|
|
if (fed->widget)
|
|
XtDestroyWidget(fed->widget);
|
|
|
|
fed->widget = 0;
|
|
|
|
XP_FREE(fed);
|
|
}
|
|
|
|
/*
|
|
**
|
|
** VTABLE for Text like form elements (TEXT, TEXTAREA, and FILE)
|
|
**
|
|
*/
|
|
static void
|
|
text_create_widget(FEFormData *fed,
|
|
LO_FormElementStruct *form)
|
|
{
|
|
MWContext *context = fed->context;
|
|
Widget parent;
|
|
int16 charset;
|
|
LO_FormElementData *form_data;
|
|
int32 form_type;
|
|
int32 text_size;
|
|
int32 max_size;
|
|
int columns;
|
|
char *tmp_text = 0;
|
|
char *text;
|
|
unsigned char *loc;
|
|
XmFontList font_list;
|
|
Arg av [50];
|
|
int ac;
|
|
LO_TextAttr *text_attr;
|
|
|
|
parent = CONTEXT_DATA (context)->drawing_area;
|
|
form_data = XP_GetFormElementData(form);
|
|
form_type = XP_FormGetType(form_data);
|
|
text_size = XP_FormTextGetSize(form_data);
|
|
max_size = XP_FormTextGetMaxSize(form_data);
|
|
text_attr = XP_GetFormTextAttr(form);
|
|
text = (char*)XP_FormGetDefaultText(form_data);
|
|
charset = text_attr->charset;
|
|
|
|
/* from bstell: in multibyte (asian) locales, characters tend to be twice
|
|
as wide as in non-multibyte locales. To make things look correct,
|
|
we divide the column number in half in those cases. */
|
|
columns = ((fe_LocaleCharSetID & MULTIBYTE) ?
|
|
(text_size + 1) / 2 : text_size);
|
|
|
|
/* the default size for text fields is 20 columns.
|
|
XX Shouldn't the backend just fill it in with 20? */
|
|
if (columns == 0) columns = 20;
|
|
|
|
|
|
if (!text) text = "";
|
|
|
|
if (max_size > 0 && (int) XP_STRLEN (text) >= max_size) {
|
|
tmp_text = XP_STRDUP (text);
|
|
tmp_text [max_size] = '\0';
|
|
text = tmp_text;
|
|
}
|
|
|
|
fe_forms_clean_text (context, charset, text, True);
|
|
|
|
fe_FontlistAndXmStringForFormElement(context,
|
|
form_type,
|
|
text,
|
|
text_attr,
|
|
NULL,
|
|
&font_list);
|
|
if (!font_list)
|
|
return;
|
|
|
|
ac = 0;
|
|
/* Ok, let's try using the fixed font for text areas only. */
|
|
/*#ifdef FORMS_ARE_FONTIFIED*/
|
|
XtSetArg (av [ac], XmNfontList, font_list); ac++;
|
|
/*#endif*/
|
|
XtSetArg (av [ac], XmNcolumns, columns); ac++;
|
|
|
|
if (form_type == FORM_TYPE_READONLY)
|
|
{
|
|
XtSetArg (av [ac], XmNeditable, False); ac++;
|
|
XtSetArg (av [ac], XmNcursorPositionVisible, False); ac++;
|
|
}
|
|
|
|
if (max_size > 0)
|
|
{
|
|
XtSetArg (av [ac], XmNmaxLength, max_size); ac++;
|
|
}
|
|
|
|
fed->widget = fe_CreateTextField (parent, "textForm", av, ac);
|
|
|
|
/*#ifdef FORMS_ARE_COLORED*/
|
|
if (form_type == FORM_TYPE_READONLY)
|
|
set_form_colors(fed, &text_attr->fg, &text_attr->bg);
|
|
/*#endif*/
|
|
|
|
/* Install in javascript form elemement text field translation */
|
|
fe_HackFormTextTranslations(fed->widget);
|
|
|
|
XtAddCallback(fed->widget, XmNlosingFocusCallback,
|
|
fe_lost_focus_cb, fed);
|
|
XtAddCallback(fed->widget, XmNfocusCallback, fe_got_focus_cb, fed);
|
|
|
|
|
|
/* This is changed later for self-submitting fields. */
|
|
if (fe_globalData.nonterminal_text_translations)
|
|
XtOverrideTranslations (fed->widget, fe_globalData.
|
|
nonterminal_text_translations);
|
|
|
|
if (form_type == FORM_TYPE_PASSWORD)
|
|
{
|
|
fe_SetupPasswdText (fed->widget, (max_size > 0 ? max_size : 1024));
|
|
fe_MarkPasswdTextAsFormElement(fed->widget);
|
|
}
|
|
|
|
/* Must be after passwd setup. */
|
|
XtVaSetValues (fed->widget, XmNcursorPosition, 0, 0);
|
|
loc = fe_ConvertToLocaleEncoding (charset, (unsigned char *)text);
|
|
/* Add verify callbacks to implement JS key events */
|
|
fe_HackTextTranslations_addCallbacks(fed->widget);
|
|
/*
|
|
* I don't know whether it is SGI or some version of Motif,but
|
|
* doing a XtVaSetValues() here will execute the
|
|
* valueChangedCallback but ignore its changes.
|
|
* XmTextFieldSetString() works as expected.
|
|
*/
|
|
XmTextFieldSetString (fed->widget, loc);
|
|
if (((char *) loc) != text) {
|
|
XP_FREE (loc);
|
|
}
|
|
if (tmp_text) XP_FREE (tmp_text);
|
|
}
|
|
|
|
static void
|
|
text_display(FEFormData *fed,
|
|
LO_FormElementStruct *form)
|
|
{
|
|
MWContext *context = fed->context;
|
|
Widget widget_to_manage;
|
|
uint16 attrmask = XP_GetFormEleAttrmask(form);
|
|
LO_FormElementData *form_data = XP_GetFormElementData(form);
|
|
Position x;
|
|
Position y;
|
|
Arg av[10];
|
|
int ac = 0;
|
|
unsigned char *loc = 0;
|
|
char *current_text = (char*)XP_FormGetCurrentText(form_data);
|
|
int32 max_size = XP_FormTextGetMaxSize(form_data);
|
|
int32 form_type = XP_FormGetType(form_data);
|
|
LO_TextAttr *text_attr = XP_GetFormTextAttr(form);
|
|
uint16 charset = text_attr->charset;
|
|
|
|
x = (form->x + form->x_offset
|
|
- CONTEXT_DATA (context)->document_x);
|
|
y = (form->y + form->y_offset
|
|
- CONTEXT_DATA (context)->document_y);
|
|
x += fe_FORM_LEFT_MARGIN;
|
|
y += fe_FORM_TOP_MARGIN;
|
|
|
|
if (form_type == FORM_TYPE_FILE)
|
|
widget_to_manage = ((FEFileFormData*)fed)->rowcolumn;
|
|
else
|
|
widget_to_manage = fed->widget;
|
|
|
|
if (!XtIsManaged(widget_to_manage))
|
|
{
|
|
Dimension bw = 0;
|
|
Dimension width = form->width;
|
|
Dimension height = form->height;
|
|
|
|
XtVaGetValues (widget_to_manage, XmNborderWidth, &bw, 0);
|
|
/* Since I told layout that width was width+bw+bw (for its sizing and
|
|
positioning purposes), subtract it out again when setting the size of
|
|
the text area. X thinks the borders are outside the WxH rectangle,
|
|
not inside, but thinks that the borders are below and to the right of
|
|
the X,Y origin, instead of up and to the left as you would expect
|
|
given the WxH behavior!!
|
|
*/
|
|
width -= (bw * 2);
|
|
height -= (bw * 2);
|
|
/* x += bw; */
|
|
/* y += bw;*/
|
|
|
|
width -= fe_FORM_LEFT_MARGIN + fe_FORM_RIGHT_MARGIN;
|
|
height -= fe_FORM_TOP_MARGIN + fe_FORM_BOTTOM_MARGIN;
|
|
|
|
if (max_size > 0)
|
|
{
|
|
XtSetArg (av [ac], XmNmaxLength, max_size); ac++;
|
|
}
|
|
|
|
if (form_type == FORM_TYPE_TEXT) {
|
|
if (current_text) {
|
|
loc = fe_ConvertToLocaleEncoding (charset,
|
|
(unsigned char *)current_text);
|
|
XtSetArg (av[ac], XmNvalue, loc); ac++;
|
|
}
|
|
}
|
|
|
|
if (ac)
|
|
XtSetValues(widget_to_manage, av, ac);
|
|
|
|
ac = 0;
|
|
XtSetArg (av [ac], XmNx, x); ac++;
|
|
XtSetArg (av [ac], XmNy, y); ac++;
|
|
XtSetArg (av [ac], XmNwidth, width); ac++;
|
|
XtSetArg (av [ac], XmNheight, height); ac++;
|
|
XtSetValues (widget_to_manage, av, ac);
|
|
|
|
XtSetMappedWhenManaged(widget_to_manage,
|
|
!(attrmask & LO_ELE_INVISIBLE));
|
|
|
|
XtManageChild(widget_to_manage);
|
|
}
|
|
else
|
|
{
|
|
XtSetMappedWhenManaged(widget_to_manage,
|
|
!(attrmask & LO_ELE_INVISIBLE));
|
|
|
|
XtMoveWidget(widget_to_manage, x, y);
|
|
}
|
|
}
|
|
|
|
static void
|
|
text_get_value(FEFormData *fed,
|
|
LO_FormElementStruct *form,
|
|
XP_Bool delete_p)
|
|
{
|
|
MWContext *context = fed->context;
|
|
INTL_CharSetInfo c = LO_GetDocumentCharacterSetInfo(context);
|
|
LO_FormElementData *form_data = XP_GetFormElementData(form);
|
|
char *text = 0;
|
|
int32 form_type;
|
|
PA_Block new_current;
|
|
PA_Block cur_current;
|
|
PA_Block default_txt;
|
|
|
|
form_type = XP_FormGetType(form_data);
|
|
|
|
if (form_type == FORM_TYPE_TEXT)
|
|
{
|
|
/* gross, since for password type form elements, we get back a malloc'ed
|
|
area of memory, and for text form elements, we get XtMalloc'ed. */
|
|
char *non_motif_text = NULL;
|
|
XtVaGetValues (fed->widget, XmNvalue, &text, 0);
|
|
if (text != NULL)
|
|
{
|
|
non_motif_text = XP_STRDUP(text);
|
|
XtFree(text);
|
|
}
|
|
text = non_motif_text;
|
|
}
|
|
else if (form_type == FORM_TYPE_PASSWORD)
|
|
text = fe_GetPasswdText (fed->widget);
|
|
|
|
cur_current = XP_FormGetCurrentText(form_data);
|
|
default_txt = XP_FormGetDefaultText(form_data);
|
|
|
|
if (cur_current && cur_current != default_txt)
|
|
free ((char*)cur_current);
|
|
|
|
new_current = (PA_Block)fe_ConvertFromLocaleEncoding(INTL_GetCSIWinCSID(c),
|
|
(unsigned char *)text);
|
|
|
|
XP_FormSetCurrentText(form_data, new_current);
|
|
|
|
if ((char*)new_current != text)
|
|
free (text);
|
|
|
|
form_element_get_value(fed, form, delete_p);
|
|
}
|
|
|
|
static void
|
|
text_reset(FEFormData *fed,
|
|
LO_FormElementStruct *form)
|
|
{
|
|
LO_FormElementData *form_data = XP_GetFormElementData(form);
|
|
char *default_text = (char*)XP_FormGetDefaultText(form_data);
|
|
LO_TextAttr *text_attr = XP_GetFormTextAttr(form);
|
|
char *tmp_text = 0;
|
|
unsigned char *loc;
|
|
int16 charset = text_attr->charset;
|
|
Widget w = fed->widget;
|
|
int32 max_size = XP_FormTextGetMaxSize(form_data);
|
|
int32 form_type;
|
|
|
|
form_type = XP_FormGetType(form_data);
|
|
|
|
if (!default_text) default_text = "";
|
|
|
|
if (max_size > 0 && (int) XP_STRLEN (default_text) >= max_size)
|
|
{
|
|
tmp_text = XP_STRDUP (default_text);
|
|
tmp_text [max_size] = '\0';
|
|
default_text = tmp_text;
|
|
}
|
|
|
|
fe_forms_clean_text (fed->context, charset, default_text, True);
|
|
|
|
XtVaSetValues (w, XmNcursorPosition, 0, 0);
|
|
|
|
loc = fe_ConvertToLocaleEncoding (charset, (unsigned char*)default_text);
|
|
/*
|
|
* I don't know whether it is SGI or some version of Motif,
|
|
* but doing a XtVaSetValues() here will execute the
|
|
* valueChangedCallback but ignore its changes.
|
|
* XmTextFieldSetString() works as expected.
|
|
*/
|
|
XmTextFieldSetString (w, loc);
|
|
if (((char *) loc) != default_text)
|
|
{
|
|
XP_FREE (loc);
|
|
}
|
|
|
|
if (tmp_text) XP_FREE (tmp_text);
|
|
}
|
|
|
|
static void
|
|
text_change(FEFormData *fed,
|
|
LO_FormElementStruct *form)
|
|
{
|
|
LO_FormElementData *form_data = XP_GetFormElementData(form);
|
|
int32 form_type = XP_FormGetType(form_data);
|
|
char *text = (char*)XP_FormGetCurrentText(form_data);
|
|
LO_TextAttr *text_attr = XP_GetFormTextAttr(form);
|
|
unsigned char *loc;
|
|
int16 charset = text_attr->charset;
|
|
|
|
if (!text) text = (char*)XP_FormGetDefaultText(form_data);
|
|
loc = fe_ConvertToLocaleEncoding(charset, (unsigned char*)text);
|
|
|
|
if (form_type == FORM_TYPE_TEXTAREA)
|
|
XmTextSetString(fed->widget, loc);
|
|
else
|
|
XmTextFieldSetString(fed->widget, loc);
|
|
|
|
if (((char *) loc) != text)
|
|
{
|
|
XP_FREE (loc);
|
|
}
|
|
}
|
|
|
|
static void
|
|
text_select(FEFormData *fed,
|
|
LO_FormElementStruct *form)
|
|
{
|
|
XmTextSetSelection (fed->widget, 0,
|
|
XmTextGetMaxLength (fed->widget), CurrentTime);
|
|
}
|
|
|
|
static void
|
|
text_focus(FEFormData *fed,
|
|
LO_FormElementStruct *form)
|
|
{
|
|
XmProcessTraversal(fed->widget, XmTRAVERSE_CURRENT);
|
|
}
|
|
|
|
static void
|
|
text_lost_focus(FEFormData *fed)
|
|
{
|
|
LO_FormElementData *form_data;
|
|
char *text;
|
|
XP_Bool text_changed = False;
|
|
int32 form_type;
|
|
PA_Block current_text;
|
|
JSEvent *event;
|
|
|
|
form_data = XP_GetFormElementData(fed->form);
|
|
form_type = XP_FormGetType(form_data);
|
|
|
|
if (form_type == FORM_TYPE_READONLY) return;
|
|
|
|
current_text = XP_FormGetCurrentText(form_data);
|
|
|
|
if (form_type == FORM_TYPE_PASSWORD)
|
|
text = fe_GetPasswdText (fed->widget);
|
|
else
|
|
XtVaGetValues (fed->widget, XmNvalue, &text, 0);
|
|
|
|
if (!current_text || XP_STRCMP((char*)current_text, text))
|
|
text_changed = True;
|
|
|
|
if (((char*) current_text) != text) {
|
|
XtFree (text);
|
|
}
|
|
|
|
/* if the text has changed, call get_element_value to copy it into the form
|
|
element, and send a CHANGE event to the javascript thread. */
|
|
if (text_changed)
|
|
{
|
|
(*fed->vtbl.get_element_value)(fed, fed->form, FALSE);
|
|
|
|
event = XP_NEW_ZAP(JSEvent);
|
|
|
|
event->type = EVENT_CHANGE;
|
|
|
|
ET_SendEvent (fed->context, (LO_Element *) fed->form, event,
|
|
NULL, NULL);
|
|
}
|
|
}
|
|
|
|
/*
|
|
**
|
|
** VTABLE for the FILE form element.
|
|
**
|
|
*/
|
|
static void
|
|
file_create_widget(FEFormData *fed,
|
|
LO_FormElementStruct *form)
|
|
{
|
|
FEFileFormData *filefed = (FEFileFormData*)fed;
|
|
MWContext *context = fed->context;
|
|
Widget parent;
|
|
int16 charset;
|
|
LO_FormElementData *form_data;
|
|
int32 form_type;
|
|
int32 text_size;
|
|
int32 max_size;
|
|
int columns;
|
|
char *tmp_text = 0;
|
|
char *text;
|
|
unsigned char *loc;
|
|
XmFontList font_list;
|
|
Arg av [50];
|
|
int ac;
|
|
LO_TextAttr *text_attr;
|
|
Pixel fg, bg;
|
|
|
|
parent = CONTEXT_DATA (context)->drawing_area;
|
|
form_data = XP_GetFormElementData(form);
|
|
form_type = XP_FormGetType(form_data);
|
|
text_size = XP_FormTextGetSize(form_data);
|
|
max_size = XP_FormTextGetMaxSize(form_data);
|
|
text_attr = XP_GetFormTextAttr(form);
|
|
text = (char*)XP_FormGetDefaultText(form_data);
|
|
charset = text_attr->charset;
|
|
|
|
/* from bstell: in multibyte (asian) locales, characters tend to be twice
|
|
as wide as in non-multibyte locales. To make things look correct,
|
|
we divide the column number in half in those cases. */
|
|
columns = ((fe_LocaleCharSetID & MULTIBYTE) ?
|
|
(text_size + 1) / 2 : text_size);
|
|
|
|
/* the default size for text fields is 20 columns.
|
|
XX Shouldn't the backend just fill it in with 20? */
|
|
if (columns == 0) columns = 20;
|
|
|
|
|
|
if (!text) text = "";
|
|
|
|
if (max_size > 0 && (int) XP_STRLEN (text) >= max_size) {
|
|
tmp_text = XP_STRDUP (text);
|
|
tmp_text [max_size] = '\0';
|
|
text = tmp_text;
|
|
}
|
|
|
|
fe_forms_clean_text (context, charset, text, True);
|
|
|
|
fe_FontlistAndXmStringForFormElement(context,
|
|
form_type,
|
|
text,
|
|
text_attr,
|
|
NULL,
|
|
&font_list);
|
|
if (!font_list)
|
|
return;
|
|
|
|
get_form_colors(fed, &text_attr->fg, &text_attr->bg, &fg, &bg);
|
|
|
|
/* Create a RowColumn widget to handle both the text and its
|
|
associated browseButton */
|
|
ac = 0;
|
|
XtSetArg (av [ac], XmNpacking, XmPACK_TIGHT); ac++;
|
|
XtSetArg (av [ac], XmNorientation, XmHORIZONTAL); ac++;
|
|
XtSetArg (av [ac], XmNnumColumns, 2); ac++;
|
|
XtSetArg (av [ac], XmNspacing, 5); ac++;
|
|
XtSetArg (av [ac], XmNmarginWidth, 0); ac++;
|
|
XtSetArg (av [ac], XmNmarginHeight, 0); ac++;
|
|
filefed->rowcolumn = XmCreateRowColumn(parent, "formRowCol", av, ac);
|
|
|
|
ac = 0;
|
|
/* Ok, let's try using the fixed font for text areas only. */
|
|
/*#ifdef FORMS_ARE_FONTIFIED*/
|
|
XtSetArg (av [ac], XmNfontList, font_list); ac++;
|
|
/*#endif*/
|
|
XtSetArg (av [ac], XmNcolumns, columns); ac++;
|
|
|
|
if (max_size > 0)
|
|
{
|
|
XtSetArg (av [ac], XmNmaxLength, max_size); ac++;
|
|
}
|
|
|
|
#ifdef FORMS_ARE_COLORED
|
|
XtSetArg (av [ac], XmNforeground, fg); ac++;
|
|
XtSetArg (av [ac], XmNbackground, bg); ac++;
|
|
#endif
|
|
|
|
fed->widget = fe_CreateTextField (filefed->rowcolumn, "textForm", av, ac);
|
|
|
|
/* Install in javascript form elemement text field translation */
|
|
fe_HackFormTextTranslations(fed->widget);
|
|
|
|
XtAddCallback(fed->widget, XmNlosingFocusCallback,
|
|
fe_lost_focus_cb, fed);
|
|
XtAddCallback(fed->widget, XmNfocusCallback, fe_got_focus_cb, fed);
|
|
|
|
|
|
XtManageChild(fed->widget);
|
|
|
|
ac = 0;
|
|
XtSetArg (av [ac], XmNfontList, font_list); ac++;
|
|
XtSetArg (av [ac], XmNforeground, fg); ac++;
|
|
XtSetArg (av [ac], XmNbackground, bg); ac++;
|
|
filefed->browse_button = XmCreatePushButton (filefed->rowcolumn,
|
|
"formFileBrowseButton",
|
|
av, ac);
|
|
XtAddCallback(filefed->browse_button, XmNactivateCallback,
|
|
fe_form_file_browse_cb, fed);
|
|
XtManageChild(filefed->browse_button);
|
|
|
|
/* This is changed later for self-submitting fields. */
|
|
if (fe_globalData.nonterminal_text_translations)
|
|
XtOverrideTranslations (fed->widget, fe_globalData.
|
|
nonterminal_text_translations);
|
|
|
|
XtVaSetValues (fed->widget, XmNcursorPosition, 0, 0);
|
|
loc = fe_ConvertToLocaleEncoding (charset, (unsigned char *)text);
|
|
/* Add verify callbacks to implement JS key events */
|
|
fe_HackTextTranslations_addCallbacks(fed->widget);
|
|
/*
|
|
* I don't know whether it is SGI or some version of Motif
|
|
* but doing a XtVaSetValues() here will execute the
|
|
* valueChangedCallback but ignore its changes.
|
|
* XmTextFieldSetString() works as expected.
|
|
*/
|
|
XmTextFieldSetString (fed->widget, loc);
|
|
if (((char *) loc) != text) {
|
|
XP_FREE (loc);
|
|
}
|
|
if (tmp_text) XP_FREE (tmp_text);
|
|
}
|
|
|
|
static void
|
|
file_get_value(FEFormData *fed,
|
|
LO_FormElementStruct *form,
|
|
XP_Bool delete_p)
|
|
{
|
|
FEFileFormData *filefed = (FEFileFormData*)fed;
|
|
|
|
text_get_value(fed, form, delete_p);
|
|
|
|
/* if delete_p is true, then form_element_get_value will have destroyed
|
|
fed->widget (our text field.) We need to finish the job here. */
|
|
if (delete_p)
|
|
{
|
|
XtDestroyWidget(filefed->rowcolumn);
|
|
|
|
filefed->rowcolumn = 0;
|
|
}
|
|
}
|
|
|
|
static void
|
|
file_free(FEFormData *fed,
|
|
LO_FormElementData *form)
|
|
{
|
|
FEFileFormData *filefed = (FEFileFormData*)fed;
|
|
|
|
if (filefed->rowcolumn)
|
|
XtDestroyWidget(filefed->rowcolumn);
|
|
|
|
filefed->rowcolumn = 0;
|
|
fed->widget = 0;
|
|
|
|
XP_FREE(fed);
|
|
}
|
|
|
|
/*
|
|
**
|
|
** VTABLE for Text like button elements (BUTTON, RESET, SUBMIT).
|
|
**
|
|
*/
|
|
static void
|
|
button_create_widget(FEFormData *fed,
|
|
LO_FormElementStruct *form)
|
|
{
|
|
MWContext *context = fed->context;
|
|
LO_FormElementData *form_data;
|
|
Widget parent;
|
|
int32 form_type;
|
|
unsigned char *string;
|
|
char *name;
|
|
LO_TextAttr *text_attr;
|
|
XmFontList font_list = NULL;
|
|
XmString xmstring = NULL;
|
|
Arg av [50];
|
|
int ac;
|
|
|
|
text_attr = XP_GetFormTextAttr(form);
|
|
parent = CONTEXT_DATA (context)->drawing_area;
|
|
form_data = XP_GetFormElementData(form);
|
|
form_type = XP_FormGetType(form_data);
|
|
string = (unsigned char*)XP_FormGetValue(form_data);
|
|
name = (form_type == FORM_TYPE_SUBMIT
|
|
? "formSubmitButton"
|
|
: (form_type == FORM_TYPE_RESET
|
|
? "formResetButton"
|
|
: "formButton"));
|
|
|
|
fe_FontlistAndXmStringForFormElement(context,
|
|
form_type,
|
|
(char*)string,
|
|
text_attr,
|
|
&xmstring,
|
|
&font_list);
|
|
|
|
#ifdef DEBUG_username
|
|
if (xmstring == NULL) printf ("xmstring is NULL\n");
|
|
#endif
|
|
|
|
ac = 0;
|
|
|
|
if (xmstring)
|
|
{
|
|
XtSetArg (av [ac], XmNlabelString, xmstring); ac++;
|
|
}
|
|
/*#ifdef FORMS_ARE_FONTIFIED*/
|
|
if (font_list)
|
|
{
|
|
XtSetArg (av [ac], XmNfontList, font_list); ac++;
|
|
}
|
|
/*#endif*/
|
|
/* Ok, buttons are always text-colored, because OptionMenu buttons
|
|
must be, and making buttons be a different color looks
|
|
inconsistent.
|
|
*/
|
|
if (form_type == FORM_TYPE_SUBMIT)
|
|
{
|
|
XtSetArg (av [ac], XmNshowAsDefault, 1); ac++;
|
|
}
|
|
|
|
fed->widget = XmCreatePushButton (parent, name, av, ac);
|
|
|
|
if (xmstring)
|
|
XmStringFree (xmstring);
|
|
|
|
/*#ifdef FORMS_ARE_COLORED*/
|
|
set_form_colors(fed, &text_attr->fg, &text_attr->bg);
|
|
/*#endif*/
|
|
|
|
#ifndef NO_NEW_DEFAULT_SIZES
|
|
/* added so the security people (or anyone needing an HTML area with
|
|
form elements in it) could specify a wider default width than
|
|
what motif computes based on the font */
|
|
if (form->width > 0
|
|
|| form->height > 0)
|
|
{
|
|
Dimension width;
|
|
Dimension height;
|
|
Dimension bw;
|
|
|
|
XtVaGetValues(fed->widget,
|
|
XmNheight, &height,
|
|
XmNwidth, &width,
|
|
XmNborderWidth, &bw,
|
|
NULL);
|
|
|
|
/* take into account our padding */
|
|
width += fe_FORM_LEFT_MARGIN + fe_FORM_RIGHT_MARGIN;
|
|
height += fe_FORM_TOP_MARGIN + fe_FORM_BOTTOM_MARGIN;
|
|
width += (bw * 2);
|
|
height += (bw * 2);
|
|
|
|
if (form->width > width)
|
|
width = form->width;
|
|
if (form->height > height)
|
|
height = form->height;
|
|
|
|
XtVaSetValues(fed->widget,
|
|
XmNheight, height,
|
|
XmNwidth, width,
|
|
NULL);
|
|
}
|
|
#endif
|
|
|
|
switch (form_type)
|
|
{
|
|
case FORM_TYPE_SUBMIT:
|
|
XtAddCallback (fed->widget,
|
|
XmNactivateCallback, fe_submit_form_cb, fed);
|
|
break;
|
|
case FORM_TYPE_RESET:
|
|
XtAddCallback (fed->widget,
|
|
XmNactivateCallback, fe_reset_form_cb, fed);
|
|
break;
|
|
case FORM_TYPE_BUTTON:
|
|
XtAddCallback (fed->widget,
|
|
XmNactivateCallback, fe_button_form_cb, fed);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
**
|
|
** Vtable routines for the radio and checkbox form elements.
|
|
**
|
|
*/
|
|
static void
|
|
checkbox_create_widget(FEFormData *fed,
|
|
LO_FormElementStruct *form)
|
|
{
|
|
MWContext *context = fed->context;
|
|
Widget parent = CONTEXT_DATA (context)->drawing_area;
|
|
LO_FormElementData *form_data;
|
|
int32 form_type;
|
|
XmString xmstring;
|
|
int margin = 2; /* leave some slack... */
|
|
int size;
|
|
int descent;
|
|
XmFontList locale_font_list = NULL;
|
|
Arg av[10];
|
|
int ac;
|
|
LO_TextAttr *text_attr;
|
|
|
|
form_data = XP_GetFormElementData(form);
|
|
form_type = XP_FormGetType(form_data);
|
|
|
|
text_attr = XP_GetFormTextAttr(form);
|
|
|
|
fe_font_list_metrics (context, form, locale_font_list, &size, &descent);
|
|
size += (margin * 2);
|
|
|
|
XP_FormSetElementToggled(form_data,
|
|
XP_FormGetDefaultToggled(form_data));
|
|
|
|
ac = 0;
|
|
xmstring = XmStringCreate (" ", XmFONTLIST_DEFAULT_TAG);
|
|
/* These always use our font list, for proper sizing. */
|
|
XtSetArg (av [ac], XmNfontList, locale_font_list); ac++;
|
|
XtSetArg (av [ac], XmNwidth, size); ac++;
|
|
XtSetArg (av [ac], XmNheight, size); ac++;
|
|
XtSetArg (av [ac], XmNresize, False); ac++;
|
|
XtSetArg (av [ac], XmNspacing, 2); ac++;
|
|
XtSetArg (av [ac], XmNlabelString, xmstring); ac++;
|
|
XtSetArg (av [ac], XmNvisibleWhenOff, True); ac++;
|
|
XtSetArg (av [ac], XmNset, XP_FormGetDefaultToggled(form_data)); ac++;
|
|
XtSetArg (av [ac], XmNindicatorType,
|
|
(form_type == FORM_TYPE_RADIO
|
|
? XmONE_OF_MANY : XmN_OF_MANY)); ac++;
|
|
|
|
fed->widget = XmCreateToggleButton (parent, "toggleForm", av, ac);
|
|
|
|
/* These must always be the prevailing color of the text,
|
|
or they look silly. */
|
|
#ifdef FORMS_ARE_COLORED
|
|
set_form_colors(fed, &text_attr->fg, &text_attr->bg);
|
|
#endif
|
|
|
|
if (form_type == FORM_TYPE_RADIO)
|
|
XtAddCallback (fed->widget, XmNvalueChangedCallback,
|
|
fe_radio_form_cb, fed);
|
|
else
|
|
XtAddCallback (fed->widget, XmNvalueChangedCallback,
|
|
fe_check_form_cb, fed);
|
|
|
|
XmStringFree (xmstring);
|
|
}
|
|
|
|
static void
|
|
checkbox_get_value(FEFormData *fed,
|
|
LO_FormElementStruct *form,
|
|
XP_Bool delete_p)
|
|
{
|
|
LO_FormElementData *form_data = XP_GetFormElementData(form);
|
|
Boolean set = False;
|
|
|
|
XtVaGetValues(fed->widget, XmNset, &set, NULL);
|
|
|
|
XP_FormSetElementToggled(form_data, set);
|
|
|
|
form_element_get_value(fed, form, delete_p);
|
|
}
|
|
|
|
static void
|
|
checkbox_change(FEFormData *fed,
|
|
LO_FormElementStruct *form)
|
|
{
|
|
LO_FormElementData *form_data = XP_GetFormElementData(form);
|
|
int32 form_type = XP_FormGetType(form_data);
|
|
XP_Bool toggled = XP_FormGetElementToggled(form_data);
|
|
|
|
switch (form_type)
|
|
{
|
|
case FORM_TYPE_RADIO:
|
|
if (toggled) LO_FormRadioSet (fed->context, form);
|
|
/* SPECIAL: If this was the only radio button in the radio group,
|
|
LO_FormRadioSet() will turn it back ON again if Mocha tried to
|
|
turn it OFF. We want to let mocha be able to turn ON/OFF
|
|
radio buttons. So we are going to override that and let mocha
|
|
have its way.
|
|
*/
|
|
XFE_SetFormElementToggle(fed->context, form, toggled);
|
|
break;
|
|
case FORM_TYPE_CHECKBOX:
|
|
XtVaSetValues (fed->widget, XmNset, toggled, 0);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
**
|
|
** Vtable entries for FORM_TYPE_SELECT_MULT
|
|
**
|
|
*/
|
|
|
|
static void
|
|
select_create_widget(FEFormData *fed,
|
|
LO_FormElementStruct *form)
|
|
{
|
|
FESelectMultFormData *sel_fed = (FESelectMultFormData*)fed;
|
|
MWContext *context = fed->context;
|
|
Widget parent = CONTEXT_DATA(context)->drawing_area;
|
|
LO_FormElementData *form_data = XP_GetFormElementData(form);
|
|
int32 form_type = XP_FormGetType(form_data);
|
|
LO_TextAttr *text_attr;
|
|
int nitems = XP_FormSelectGetOptionsCount(form_data);
|
|
int vlines;
|
|
XmString *items = NULL;
|
|
char *selected_p = NULL;
|
|
int i;
|
|
Arg av[30];
|
|
int ac;
|
|
XmFontList font_list = NULL;
|
|
|
|
text_attr = XP_GetFormTextAttr(form);
|
|
|
|
vlines = XP_FormSelectGetSize(form_data);
|
|
|
|
if (vlines <= 0) vlines = nitems;
|
|
|
|
if (nitems > 0) {
|
|
items = (XmString *) malloc (sizeof (XmString) * nitems);
|
|
selected_p = (char *) calloc (nitems, sizeof (char));
|
|
}
|
|
|
|
for (i = 0; i < nitems; i++)
|
|
{
|
|
lo_FormElementOptionData *d2 =
|
|
XP_FormSelectGetOption(form_data, i);
|
|
|
|
fe_FontlistAndXmStringForFormElement(context,
|
|
form_type,
|
|
(d2->text_value
|
|
? (char *) d2->text_value
|
|
: "---\?\?\?---"),
|
|
text_attr,
|
|
&items[i],
|
|
&font_list);
|
|
|
|
selected_p [i] = !!d2->def_selected;
|
|
d2->selected = d2->def_selected;
|
|
}
|
|
|
|
ac = 0;
|
|
/* #ifdef FORMS_ARE_FONTIFIED */
|
|
XtSetArg (av [ac], XmNfontList, font_list); ac++;
|
|
/* #endif */
|
|
XtSetArg (av [ac], XmNspacing, 0); ac++;
|
|
|
|
if (nitems) {
|
|
XtSetArg (av [ac], XmNitems, items); ac++;
|
|
XtSetArg (av [ac], XmNitemCount, nitems); ac++;
|
|
}
|
|
|
|
if (form_type == FORM_TYPE_SELECT_MULT)
|
|
{
|
|
XtSetArg (av [ac], XmNvisibleItemCount, vlines); ac++;
|
|
XtSetArg (av [ac], XmNlistSizePolicy, XmRESIZE_IF_POSSIBLE); ac++;
|
|
XtSetArg (av [ac], XmNselectionPolicy,
|
|
(XP_FormSelectGetMultiple(form_data)
|
|
? XmMULTIPLE_SELECT
|
|
: XmSINGLE_SELECT)); ac++;
|
|
XtSetArg(av[ac], XmNx, -15000); ac++;
|
|
}
|
|
else /* FORM_TYPE_SELECT_ONE */
|
|
{
|
|
Visual *v = 0;
|
|
Colormap cmap = 0;
|
|
Cardinal depth = 0;
|
|
|
|
fe_getVisualOfContext (context, &v, &cmap, &depth);
|
|
|
|
XtSetArg (av [ac], XmNshadowThickness, 1); ac++;
|
|
XtSetArg (av [ac], XmNarrowType, XmMOTIF); ac++;
|
|
XtSetArg (av [ac], XmNtype, XmDROP_DOWN_LIST_BOX); ac++;
|
|
XtSetArg (av [ac], XmNvisual, v); ac++;
|
|
XtSetArg (av [ac], XmNcolormap, cmap); ac++;
|
|
XtSetArg (av [ac], XmNdepth, depth); ac++;
|
|
}
|
|
|
|
if (form_type == FORM_TYPE_SELECT_MULT)
|
|
{
|
|
sel_fed->list_widget = XmCreateScrolledList (parent, "list", av, ac);
|
|
fed->widget = XtParent(sel_fed->list_widget);
|
|
/*
|
|
* We need this Unmanage because otherwise XtIsManaged on the
|
|
* parent fails later. It seems XmCreateScrolledList() creates
|
|
* an unmanaged list with a managed scrolled window parent.
|
|
* How stupid.
|
|
*/
|
|
XtUnmanageChild (fed->widget);
|
|
XtManageChild (sel_fed->list_widget);
|
|
}
|
|
else /* FORM_TYPE_SELECT_ONE */
|
|
{
|
|
/* we also need to set the fontlist explicitly on the label, for
|
|
some reason... */
|
|
Widget label;
|
|
|
|
fed->widget = DtCreateComboBox(parent, "list", av, ac);
|
|
XtVaGetValues(fed->widget,
|
|
XmNlist, &sel_fed->list_widget,
|
|
NULL);
|
|
|
|
label = ((DtComboBoxWidget)fed->widget)->combo_box.label;
|
|
|
|
ac = 0;
|
|
/* #ifdef FORMS_ARE_FONTIFIED */
|
|
XtSetArg (av [ac], XmNfontList, font_list); ac++;
|
|
XtSetValues(label, av, ac);
|
|
}
|
|
|
|
#ifdef FORMS_ARE_COLORED
|
|
set_form_colors(fed, &text_attr->fg, &text_attr->bg);
|
|
#endif
|
|
|
|
#ifndef NO_NEW_DEFAULT_SIZES
|
|
/* added so the security people (or anyone needing an HTML area with
|
|
form elements in it) could specify a wider default width (or higher
|
|
default height) than what motif computes based on the font */
|
|
if (form->width > 0)
|
|
{
|
|
Dimension width;
|
|
Dimension height;
|
|
Dimension bw;
|
|
|
|
XtVaGetValues(sel_fed->list_widget,
|
|
XmNwidth, &width,
|
|
XmNheight, &height,
|
|
XmNborderWidth, &bw,
|
|
NULL);
|
|
|
|
/* take into account our padding */
|
|
width += fe_FORM_LEFT_MARGIN + fe_FORM_RIGHT_MARGIN;
|
|
height += fe_FORM_TOP_MARGIN + fe_FORM_BOTTOM_MARGIN;
|
|
width += (bw * 2);
|
|
height += (bw * 2);
|
|
|
|
if (form->width > width)
|
|
width = form->width;
|
|
|
|
if (form->height > height)
|
|
height = form->height;
|
|
|
|
XtVaSetValues(sel_fed->list_widget,
|
|
XmNwidth, width,
|
|
XmNheight, height,
|
|
NULL);
|
|
}
|
|
#endif
|
|
|
|
for (i = 0; i < nitems; i++)
|
|
if (selected_p[i])
|
|
if (form_type == FORM_TYPE_SELECT_MULT)
|
|
XmListSelectPos(sel_fed->list_widget, i+1, False);
|
|
else /* FORM_TYPE_SELECT_ONE */
|
|
DtComboBoxSelectItem(fed->widget, items[i]);
|
|
|
|
if (form_type == FORM_TYPE_SELECT_MULT)
|
|
{
|
|
XtAddCallback (sel_fed->list_widget,
|
|
XmNdefaultActionCallback, fe_list_form_cb, fed);
|
|
XtAddCallback (sel_fed->list_widget,
|
|
XmNsingleSelectionCallback, fe_list_form_cb, fed);
|
|
XtAddCallback (sel_fed->list_widget,
|
|
XmNmultipleSelectionCallback, fe_list_form_cb, fed);
|
|
XtAddCallback (sel_fed->list_widget,
|
|
XmNextendedSelectionCallback, fe_list_form_cb, fed);
|
|
XtInsertEventHandler(sel_fed->list_widget,
|
|
KeyPressMask, False,
|
|
fe_list_find_eh, context, XtListHead);
|
|
XtAddEventHandler(sel_fed->list_widget,
|
|
FocusChangeMask, FALSE,
|
|
(XtEventHandler)fe_mocha_focus_notify_eh,
|
|
fed);
|
|
}
|
|
else
|
|
{
|
|
XtAddCallback(fed->widget,
|
|
XmNselectionCallback, fe_combo_form_cb, sel_fed);
|
|
}
|
|
|
|
sel_fed->nkids = nitems;
|
|
sel_fed->selected_p = selected_p;
|
|
}
|
|
|
|
static void
|
|
select_get_value(FEFormData *fed,
|
|
LO_FormElementStruct *form,
|
|
XP_Bool delete_p)
|
|
{
|
|
FESelectMultFormData *sel_fed = (FESelectMultFormData*)fed;
|
|
LO_FormElementData *form_data = XP_GetFormElementData(form);
|
|
int i;
|
|
|
|
for (i = 0; i < sel_fed->nkids; i ++)
|
|
{
|
|
lo_FormElementOptionData *option_data =
|
|
XP_FormSelectGetOption(form_data, i);
|
|
|
|
XP_FormOptionSetSelected(option_data,
|
|
sel_fed->selected_p[i]);
|
|
}
|
|
|
|
form_element_get_value(fed, form, delete_p);
|
|
}
|
|
|
|
static void
|
|
select_free(FEFormData *fed,
|
|
LO_FormElementData *form_data)
|
|
{
|
|
FESelectMultFormData *sel_fed = (FESelectMultFormData*)fed;
|
|
|
|
if (sel_fed->selected_p)
|
|
free(sel_fed->selected_p);
|
|
|
|
form_element_free(fed, form_data);
|
|
}
|
|
|
|
static void
|
|
select_reset(FEFormData *fed,
|
|
LO_FormElementStruct *form)
|
|
{
|
|
FESelectMultFormData *sel_fed = (FESelectMultFormData*)fed;
|
|
LO_FormElementData *form_data = XP_GetFormElementData(form);
|
|
int32 form_type = XP_FormGetType(form_data);
|
|
int nitems = XP_FormSelectGetOptionsCount(form_data);
|
|
int i;
|
|
XmString *items;
|
|
|
|
XtVaGetValues(sel_fed->list_widget, XmNitems, &items, NULL);
|
|
|
|
for (i = 0; i < nitems; i++)
|
|
{
|
|
lo_FormElementOptionData *option = XP_FormSelectGetOption(form_data, i);
|
|
XP_Bool selected;
|
|
|
|
XP_FormOptionSetSelected(option, XP_FormOptionGetDefaultSelected(option));
|
|
|
|
selected = XP_FormOptionGetSelected(option);
|
|
if (selected) {
|
|
/* Highlight the item at pos i+1 if it is not already */
|
|
if (!sel_fed->selected_p[i])
|
|
if (form_type == FORM_TYPE_SELECT_MULT)
|
|
XmListSelectPos(sel_fed->list_widget, i+1, False);
|
|
else /* FORM_TYPE_SELECT_ONE */
|
|
DtComboBoxSelectItem(fed->widget, items[i]);
|
|
}
|
|
else
|
|
XmListDeselectPos(sel_fed->list_widget, i+1);
|
|
sel_fed->selected_p [i] = selected;
|
|
}
|
|
}
|
|
|
|
static void
|
|
select_change(FEFormData *fed,
|
|
LO_FormElementStruct *form)
|
|
{
|
|
FESelectMultFormData *sel_fed = (FESelectMultFormData*)fed;
|
|
LO_FormElementData *form_data = XP_GetFormElementData(form);
|
|
int32 form_type = XP_FormGetType(form_data);
|
|
fe_Font fe_font;
|
|
LO_TextAttr *text_attr;
|
|
uint16 mask;
|
|
XmString *new_items;
|
|
char* new_selected_p;
|
|
int nitems;
|
|
int i;
|
|
int16 charset;
|
|
XmFontList unicodePseudo_font_list = NULL;
|
|
XP_Bool item_selected = FALSE;
|
|
|
|
nitems = XP_FormSelectGetOptionsCount(form_data);
|
|
text_attr = XP_GetFormTextAttr(form);
|
|
mask = text_attr->fontmask;
|
|
charset = text_attr->charset;
|
|
|
|
fe_font = fe_LoadUnicodeFont(NULL, "", 0, text_attr->size, mask, 0, 0, 0,
|
|
XtDisplay(CONTEXT_WIDGET(fed->context)));
|
|
|
|
if (nitems > 0)
|
|
{
|
|
new_items = (XmString *) malloc (sizeof (XmString) * nitems);
|
|
new_selected_p = (char *) calloc (nitems, sizeof (char));
|
|
}
|
|
|
|
#ifdef DEBUG_username
|
|
printf ("nitems = %d\n", nitems);
|
|
#endif
|
|
|
|
for (i = 0; i < nitems; i ++)
|
|
{
|
|
char *str;
|
|
lo_FormElementOptionData *option_data =
|
|
XP_FormSelectGetOption(form_data, i);
|
|
|
|
str = (option_data->text_value
|
|
? ((*((char *) option_data->text_value))
|
|
? ((char *) option_data->text_value)
|
|
: " ")
|
|
: "---\?\?\?---");
|
|
|
|
new_items [i] = fe_ConvertToXmString(str, charset, fe_font,
|
|
XmFONT_IS_FONT,
|
|
&unicodePseudo_font_list);
|
|
new_selected_p [i] = !!XP_FormOptionGetSelected(option_data);
|
|
|
|
#ifdef DEBUG_username
|
|
printf ("items[%d] = %s\n", i, str);
|
|
#endif
|
|
}
|
|
|
|
XmListDeselectAllItems(sel_fed->list_widget);
|
|
|
|
XtVaSetValues(sel_fed->list_widget,
|
|
XmNitems, new_items,
|
|
XmNitemCount, nitems,
|
|
NULL);
|
|
|
|
for (i = 0; i < nitems; i++)
|
|
if (new_selected_p[i])
|
|
if (form_type == FORM_TYPE_SELECT_MULT)
|
|
XmListSelectPos(sel_fed->list_widget, i+1, False);
|
|
else /* FORM_TYPE_SELECT_ONE */
|
|
{
|
|
DtComboBoxSelectItem(fed->widget, new_items[i]);
|
|
item_selected = TRUE;
|
|
}
|
|
|
|
if (sel_fed->selected_p)
|
|
free(sel_fed->selected_p);
|
|
|
|
sel_fed->selected_p = new_selected_p;
|
|
sel_fed->nkids = nitems;
|
|
}
|
|
|
|
/*
|
|
**
|
|
** Vtable entries for FORM_TYPE_TEXTAREA
|
|
**
|
|
*/
|
|
|
|
static void
|
|
textarea_create_widget(FEFormData *fed,
|
|
LO_FormElementStruct *form)
|
|
{
|
|
FETextAreaFormData *ta_fed = (FETextAreaFormData*)fed;
|
|
MWContext *context = fed->context;
|
|
Widget parent;
|
|
int16 charset;
|
|
LO_FormElementData *form_data;
|
|
int32 form_type;
|
|
int32 rows, cols;
|
|
char *text;
|
|
unsigned char *loc;
|
|
XmFontList locale_font_list;
|
|
Arg av [50];
|
|
int ac;
|
|
LO_TextAttr *text_attr;
|
|
|
|
parent = CONTEXT_DATA (context)->drawing_area;
|
|
form_data = XP_GetFormElementData(form);
|
|
form_type = XP_FormGetType(form_data);
|
|
text_attr = XP_GetFormTextAttr(form);
|
|
text = (char*)XP_FormGetDefaultText(form_data);
|
|
charset = text_attr->charset;
|
|
|
|
XP_FormTextAreaGetDimensions(form_data,
|
|
&rows, &cols);
|
|
|
|
|
|
/* the default size for text fields is 20 columns.
|
|
XX Shouldn't the backend just fill it in with 20? */
|
|
if (cols == 0) cols = 20;
|
|
|
|
if (!text) text = "";
|
|
|
|
fe_forms_clean_text (context, charset, text, False);
|
|
loc = fe_ConvertToLocaleEncoding (charset, text);
|
|
|
|
fe_FontlistAndXmStringForFormElement(context,
|
|
form_type,
|
|
loc,
|
|
text_attr,
|
|
NULL,
|
|
&locale_font_list);
|
|
if (!locale_font_list)
|
|
return;
|
|
|
|
ac = 0;
|
|
|
|
XtSetArg (av[ac], XmNscrollingPolicy, XmAUTOMATIC); ac++;
|
|
XtSetArg (av[ac], XmNvisualPolicy, XmCONSTANT); ac++;
|
|
XtSetArg (av[ac], XmNscrollBarDisplayPolicy, XmSTATIC); ac++;
|
|
|
|
XtSetArg (av[ac], XmNvalue, loc); ac++;
|
|
XtSetArg (av[ac], XmNcursorPosition, 0); ac++;
|
|
/* from bstell: in multibyte (asian) locales, characters tend to be twice
|
|
as wide as in non-multibyte locales. To make things look correct,
|
|
we divide the column number in half in those cases. */
|
|
XtSetArg (av[ac], XmNcolumns, ((fe_LocaleCharSetID & MULTIBYTE) ?
|
|
(cols + 1) / 2 : cols)); ac++;
|
|
XtSetArg (av[ac], XmNrows, rows); ac++;
|
|
/*
|
|
* Gotta love Motif. No matter what wordWrap is set to, if
|
|
* there is a horizontal scrollbar present it won't wrap.
|
|
* Of course the documentation mentions this nowhere.
|
|
* "Use the source Luke!"
|
|
*/
|
|
if (XP_FormTextAreaGetAutowrap(form_data) != TEXTAREA_WRAP_OFF)
|
|
{
|
|
XtSetArg (av[ac], XmNscrollHorizontal, FALSE); ac++;
|
|
XtSetArg (av[ac], XmNwordWrap, TRUE); ac++;
|
|
}
|
|
XtSetArg (av[ac], XmNeditMode, XmMULTI_LINE_EDIT); ac++;
|
|
/* Ok, let's try using the fixed font for text areas only. */
|
|
/*#ifdef FORMS_ARE_FONTIFIED*/
|
|
XtSetArg (av[ac], XmNfontList, locale_font_list); ac++;
|
|
/*#endif*/
|
|
XtSetArg(av[ac], XmNx, -15000); ac++;
|
|
ta_fed->text_widget = XmCreateScrolledText (parent, "formText", av, ac);
|
|
ta_fed->form_data.widget = XtParent(ta_fed->text_widget);
|
|
|
|
/* The scroller must have the prevailing color of the text,
|
|
or it looks funny.*/
|
|
#ifdef FORMS_ARE_COLORED
|
|
set_form_colors(fed, &text_attr->fg, &text_attr->bg);
|
|
#endif
|
|
|
|
if (((char *) loc) != text)
|
|
{
|
|
XP_FREE (loc);
|
|
}
|
|
|
|
XtAddCallback(ta_fed->text_widget, XmNlosingFocusCallback,
|
|
fe_lost_focus_cb, fed);
|
|
XtAddCallback(ta_fed->text_widget, XmNfocusCallback, fe_got_focus_cb, fed);
|
|
XtAddEventHandler(ta_fed->text_widget,
|
|
KeyPressMask | KeyReleaseMask,
|
|
FALSE, /* don't care about nonmaskable events */
|
|
fe_key_handler,
|
|
ta_fed);
|
|
|
|
/* Add verify callbacks to implement JS key events */
|
|
fe_HackTextTranslations_addCallbacks(ta_fed->text_widget);
|
|
|
|
XtUnmanageChild (ta_fed->form_data.widget);
|
|
XtManageChild (ta_fed->text_widget);
|
|
}
|
|
|
|
static void
|
|
textarea_display(FEFormData *fed,
|
|
LO_FormElementStruct *form)
|
|
{
|
|
form_element_display(fed, form);
|
|
}
|
|
|
|
static void
|
|
textarea_get_value(FEFormData *fed,
|
|
LO_FormElementStruct *form,
|
|
XP_Bool delete_p)
|
|
{
|
|
MWContext *context = fed->context;
|
|
LO_FormElementData *form_data = XP_GetFormElementData(form);
|
|
FETextAreaFormData *ta_fed = (FETextAreaFormData*)fed;
|
|
INTL_CharSetInfo c = LO_GetDocumentCharacterSetInfo(context);
|
|
char *text = 0;
|
|
int32 cols;
|
|
PA_Block current_text, new_current_text;
|
|
PA_Block default_text;
|
|
|
|
XP_FormTextAreaGetDimensions(form_data, NULL, &cols);
|
|
|
|
XtVaGetValues (ta_fed->text_widget, XmNvalue, &text, 0);
|
|
if (! text) return;
|
|
if (XP_FormTextAreaGetAutowrap(form_data) == TEXTAREA_WRAP_HARD) {
|
|
char *tmp = XP_WordWrap(fe_LocaleCharSetID, text, cols, 0);
|
|
if (text) XtFree(text);
|
|
if (!tmp) return;
|
|
text = tmp;
|
|
}
|
|
|
|
current_text = XP_FormGetCurrentText(form_data);
|
|
default_text = XP_FormGetDefaultText(form_data);
|
|
|
|
if (current_text && current_text != default_text)
|
|
free (current_text);
|
|
|
|
new_current_text =
|
|
(PA_Block)fe_ConvertFromLocaleEncoding (INTL_GetCSIWinCSID(c),
|
|
(unsigned char *) text);
|
|
|
|
XP_FormSetCurrentText(form_data, new_current_text);
|
|
|
|
if (((char *) new_current_text) != text) {
|
|
free (text);
|
|
}
|
|
|
|
form_element_get_value(fed, form, delete_p);
|
|
}
|
|
|
|
static void
|
|
textarea_reset(FEFormData *fed,
|
|
LO_FormElementStruct *form)
|
|
{
|
|
LO_FormElementData *form_data = XP_GetFormElementData(form);
|
|
FETextAreaFormData *ta_fed = (FETextAreaFormData*)fed;
|
|
char *default_text = (char*)XP_FormGetDefaultText(form_data);
|
|
LO_TextAttr *text_attr = XP_GetFormTextAttr(form);
|
|
int16 charset = text_attr->charset;
|
|
unsigned char *loc;
|
|
|
|
fe_forms_clean_text (fed->context, charset, default_text, False);
|
|
|
|
XtVaSetValues (ta_fed->text_widget, XmNcursorPosition, 0, 0);
|
|
|
|
loc = fe_ConvertToLocaleEncoding (charset, (unsigned char*)default_text);
|
|
|
|
XtVaSetValues (ta_fed->text_widget, XmNvalue, loc, 0);
|
|
|
|
if (((char *) loc) != default_text)
|
|
{
|
|
XP_FREE (loc);
|
|
}
|
|
}
|
|
|
|
static void
|
|
textarea_lost_focus(FEFormData *fed)
|
|
{
|
|
FETextAreaFormData *ta_fed = (FETextAreaFormData*)fed;
|
|
LO_FormElementData *form_data;
|
|
char *text;
|
|
XP_Bool text_changed = False;
|
|
PA_Block current_text;
|
|
JSEvent *event;
|
|
|
|
form_data = XP_GetFormElementData(fed->form);
|
|
|
|
current_text = XP_FormGetCurrentText(form_data);
|
|
|
|
XtVaGetValues (ta_fed->text_widget, XmNvalue, &text, 0);
|
|
|
|
if (!current_text || XP_STRCMP((char*)current_text, text))
|
|
text_changed = True;
|
|
|
|
if (((char*) current_text) != text) {
|
|
XtFree (text);
|
|
}
|
|
|
|
/* if the text has changed, call get_element_value to copy it into the form
|
|
element, and send a CHANGE event to the javascript thread. */
|
|
if (text_changed)
|
|
{
|
|
(*fed->vtbl.get_element_value)(fed, fed->form, FALSE);
|
|
|
|
event = XP_NEW_ZAP(JSEvent);
|
|
|
|
event->type = EVENT_CHANGE;
|
|
|
|
ET_SendEvent (fed->context, (LO_Element *) fed->form, event,
|
|
NULL, NULL);
|
|
}
|
|
}
|
|
|
|
static FEFormData *
|
|
alloc_form_data(int32 form_type)
|
|
{
|
|
FEFormData *data;
|
|
|
|
switch (form_type)
|
|
{
|
|
case FORM_TYPE_TEXT:
|
|
case FORM_TYPE_PASSWORD:
|
|
case FORM_TYPE_READONLY:
|
|
data = (FEFormData*)XP_NEW_ZAP(FEFormData);
|
|
data->vtbl = text_form_vtable;
|
|
return data;
|
|
|
|
case FORM_TYPE_FILE:
|
|
data = (FEFormData*)XP_NEW_ZAP(FEFileFormData);
|
|
data->vtbl = file_form_vtable;
|
|
return data;
|
|
|
|
case FORM_TYPE_SUBMIT:
|
|
case FORM_TYPE_RESET:
|
|
case FORM_TYPE_BUTTON:
|
|
data = (FEFormData*)XP_NEW_ZAP(FEFormData);
|
|
data->vtbl = button_form_vtable;
|
|
return data;
|
|
|
|
case FORM_TYPE_RADIO:
|
|
case FORM_TYPE_CHECKBOX:
|
|
data = (FEFormData*)XP_NEW_ZAP(FEFormData);
|
|
data->vtbl = checkbox_form_vtable;
|
|
return data;
|
|
|
|
case FORM_TYPE_SELECT_ONE:
|
|
data = (FEFormData*)XP_NEW_ZAP(FESelectOneFormData);
|
|
data->vtbl = selectone_form_vtable;
|
|
return data;
|
|
|
|
case FORM_TYPE_TEXTAREA:
|
|
data = (FEFormData*)XP_NEW_ZAP(FETextAreaFormData);
|
|
data->vtbl = textarea_form_vtable;
|
|
return data;
|
|
|
|
case FORM_TYPE_SELECT_MULT:
|
|
data = (FEFormData*)XP_NEW_ZAP(FESelectMultFormData);
|
|
data->vtbl = selectmult_form_vtable;
|
|
return data;
|
|
|
|
case FORM_TYPE_HIDDEN:
|
|
case FORM_TYPE_JOT:
|
|
case FORM_TYPE_ISINDEX:
|
|
case FORM_TYPE_IMAGE:
|
|
case FORM_TYPE_KEYGEN:
|
|
case FORM_TYPE_OBJECT:
|
|
default:
|
|
XP_ASSERT(0);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
/*
|
|
** This method can be called more than once for the same front end form element.
|
|
**
|
|
** In those cases we don't reallocate the FEData*, and also don't recreate the widget,
|
|
** but we do set the form and context pointers in FEData, and we call the get_size
|
|
** method.
|
|
**
|
|
** The two cases I know of where layout calls this function more than once are:
|
|
** when laying out a table with form elements in it -- layout moves our fe data
|
|
** over to the new LO_FormElementStruct, but we have to sync up our pointer to
|
|
** the new.
|
|
** when reloading a page with frames in it. In this case, the context is different,
|
|
** so need to always set that as well.
|
|
**
|
|
** Also, layout could have told us to delete the widget without freeing our FEData*
|
|
** (this happens with delete_p is TRUE in XFE_GetFormElementValue.) In this case,
|
|
** we need to recreate the widget.
|
|
**
|
|
** yuck.
|
|
*/
|
|
void
|
|
XFE_GetFormElementInfo(MWContext *context,
|
|
LO_FormElementStruct *form)
|
|
{
|
|
LO_FormElementData *form_data = XP_GetFormElementData(form);
|
|
FEFormData *fed;
|
|
|
|
#ifdef DEBUG_username
|
|
printf ("XFE_GetFormElementInfo\n");
|
|
#endif
|
|
|
|
if (!form_data)
|
|
return;
|
|
|
|
fed = (FEFormData*)XP_FormGetFEData(form_data);
|
|
if (!fed)
|
|
{
|
|
int32 form_type = XP_FormGetType(form_data);
|
|
|
|
fed = alloc_form_data(form_type);
|
|
|
|
XP_ASSERT(fed);
|
|
if (!fed) return;
|
|
|
|
XP_FormSetFEData(form_data, fed);
|
|
}
|
|
|
|
fed->form = form;
|
|
fed->context = context;
|
|
|
|
if (!fed->widget)
|
|
{
|
|
XP_ASSERT(fed->vtbl.create_widget_func);
|
|
|
|
(*fed->vtbl.create_widget_func)(fed, form);
|
|
}
|
|
|
|
XP_ASSERT(fed->vtbl.get_size_func);
|
|
|
|
(*fed->vtbl.get_size_func)(fed, form);
|
|
}
|
|
|
|
void
|
|
XFE_DisplayFormElement(MWContext *context, int iLocation,
|
|
LO_FormElementStruct *form)
|
|
{
|
|
LO_FormElementData *form_data = XP_GetFormElementData(form);
|
|
FEFormData *fed;
|
|
|
|
#ifdef DEBUG_username
|
|
printf ("XFE_DisplayFormElement\n");
|
|
#endif
|
|
|
|
if (!form_data)
|
|
return;
|
|
|
|
fed = (FEFormData*)XP_FormGetFEData(form_data);
|
|
|
|
XP_ASSERT(fed);
|
|
if (!fed) return;
|
|
|
|
if (fed->vtbl.display_element_func)
|
|
(*fed->vtbl.display_element_func)(fed, form);
|
|
}
|
|
|
|
void
|
|
XFE_FormTextIsSubmit (MWContext *context, LO_FormElementStruct *form)
|
|
{
|
|
LO_FormElementData *form_data = XP_GetFormElementData(form);
|
|
FEFormData *fed;
|
|
|
|
if (!form_data)
|
|
return;
|
|
|
|
fed = (FEFormData*)XP_FormGetFEData(form_data);
|
|
|
|
XP_ASSERT(fed);
|
|
if (!fed) return;
|
|
|
|
if (fed->vtbl.element_is_submit_func)
|
|
(*fed->vtbl.element_is_submit_func)(fed, form);
|
|
}
|
|
|
|
void
|
|
XFE_GetFormElementValue (MWContext *context, LO_FormElementStruct *form,
|
|
XP_Bool delete_p)
|
|
{
|
|
LO_FormElementData *form_data = XP_GetFormElementData(form);
|
|
FEFormData *fed;
|
|
|
|
#ifdef DEBUG_username
|
|
printf ("XFE_GetFormElementValue (delete_p = %d)\n", delete_p);
|
|
#endif
|
|
|
|
if (!form_data)
|
|
return;
|
|
|
|
fed = (FEFormData*)XP_FormGetFEData(form_data);
|
|
|
|
XP_ASSERT(fed);
|
|
if (!fed) return;
|
|
|
|
if (fed->vtbl.get_element_value)
|
|
(*fed->vtbl.get_element_value)(fed, form, delete_p);
|
|
}
|
|
|
|
void
|
|
FE_FreeFormElement(MWContext *context,
|
|
LO_FormElementData *form_data)
|
|
{
|
|
FEFormData *fed;
|
|
|
|
#ifdef DEBUG_username
|
|
printf ("XFE_FreeFormElement. \n");
|
|
#endif
|
|
|
|
if (!form_data)
|
|
return;
|
|
|
|
fed = (FEFormData*)XP_FormGetFEData(form_data);
|
|
|
|
/* this assert gets tripped by HIDDEN form elements, since we have no
|
|
FE data associated with them. */
|
|
/*XP_ASSERT(fed);*/
|
|
if (!fed) return;
|
|
|
|
if (fed->vtbl.free_element_func)
|
|
(*fed->vtbl.free_element_func)(fed, form_data);
|
|
|
|
/* clear out the FE data, so we don't try anything funny from now on. */
|
|
XP_FormSetFEData(form_data, NULL);
|
|
}
|
|
|
|
void
|
|
FE_FocusInputElement(MWContext *context,
|
|
LO_Element *element)
|
|
{
|
|
if (element)
|
|
{
|
|
LO_FormElementData *form_data =
|
|
XP_GetFormElementData((LO_FormElementStruct*)element);
|
|
FEFormData* fed;
|
|
|
|
if (!form_data)
|
|
return;
|
|
|
|
fed = (FEFormData*)XP_FormGetFEData(form_data);
|
|
|
|
if (fed->vtbl.focus_element_func)
|
|
(*fed->vtbl.focus_element_func)(fed, (LO_FormElementStruct*)element);
|
|
}
|
|
else
|
|
{
|
|
JSEvent *event;
|
|
|
|
if (context->is_grid_cell)
|
|
fe_SetGridFocus (context);
|
|
XmProcessTraversal (CONTEXT_WIDGET(context), XmTRAVERSE_CURRENT);
|
|
FE_RaiseWindow(context);
|
|
|
|
event = XP_NEW_ZAP(JSEvent);
|
|
event->type = EVENT_FOCUS;
|
|
ET_SendEvent (context, element, event, NULL, NULL);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Force input to be defocused from an element in the given window.
|
|
* It's ok if the input didn't have input focus.
|
|
*/
|
|
void
|
|
FE_BlurInputElement(MWContext *context, LO_Element *element)
|
|
{
|
|
/* Just blow away focus */
|
|
TRACEMSG(("XFE_BlurInputElement: element->type = %d\n"));
|
|
|
|
if (!context) return;
|
|
|
|
/* I was told by brendan that this is unnecessary - ramiro */
|
|
#if 0
|
|
if (form == NULL || form->element_data == NULL) {
|
|
#ifdef DEBUG_spence
|
|
printf ("BlurInputElement: form is invalid\n");
|
|
#endif
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
fe_NeutralizeFocus (context);
|
|
|
|
if (!element) {
|
|
FE_LowerWindow(context);
|
|
|
|
fe_MochaBlurNotify(context, element);
|
|
}
|
|
}
|
|
|
|
void
|
|
FE_SelectInputElement(MWContext *context, LO_Element *element)
|
|
{
|
|
LO_FormElementStruct *form = (LO_FormElementStruct*)element;
|
|
LO_FormElementData *form_data = XP_GetFormElementData(form);
|
|
FEFormData *fed;
|
|
|
|
if (!form_data)
|
|
return;
|
|
|
|
fed = (FEFormData*)XP_FormGetFEData(form_data);
|
|
|
|
XP_ASSERT(fed);
|
|
if (!fed) return;
|
|
|
|
if (fed->vtbl.select_element_func)
|
|
(*fed->vtbl.select_element_func)(fed, form);
|
|
}
|
|
|
|
void
|
|
FE_ChangeInputElement(MWContext *context,
|
|
LO_Element *element)
|
|
{
|
|
LO_FormElementStruct *form = (LO_FormElementStruct*)element;
|
|
LO_FormElementData *form_data = XP_GetFormElementData(form);
|
|
FEFormData *fed;
|
|
int32 type;
|
|
|
|
if (!form_data)
|
|
return;
|
|
|
|
fed = (FEFormData*)XP_FormGetFEData(form_data);
|
|
type = XP_FormGetType(form_data);
|
|
|
|
/* this assert gets tripped by HIDDEN form elements, since we have no
|
|
FE data associated with them. */
|
|
/*XP_ASSERT(fed);*/
|
|
if (!fed) return;
|
|
|
|
if (fed->vtbl.change_element_func)
|
|
{
|
|
LO_LockLayout();
|
|
|
|
(*fed->vtbl.change_element_func)(fed, form);
|
|
|
|
LO_UnlockLayout();
|
|
}
|
|
}
|
|
|
|
/*
|
|
** Tell the FE that a form is being submitted without a UI gesture indicating
|
|
** that fact, i.e., in a Mocha-automated fashion ("document.myform.submit()").
|
|
** The FE is responsible for emulating whatever happens when the user hits the
|
|
** submit button, or auto-submits by typing Enter in a single-field form.
|
|
*/
|
|
void
|
|
FE_SubmitInputElement(MWContext *context, LO_Element *element)
|
|
{
|
|
LO_FormSubmitData *submit;
|
|
URL_Struct *url;
|
|
History_entry *he = NULL;
|
|
|
|
TRACEMSG(("XFE_SubmitInputElement: element->type = %d\n"));
|
|
if (!context) return;
|
|
|
|
if (element == NULL) {
|
|
#ifdef DEBUG_username
|
|
printf ("SubmitInputElement: form is invalid\n");
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
submit = LO_SubmitForm (context, (LO_FormElementStruct *) element);
|
|
if (!submit)
|
|
return;
|
|
|
|
/* Create the URL to load */
|
|
url = NET_CreateURLStruct((char *)submit->action, NET_DONT_RELOAD);
|
|
|
|
/* ... add the form data */
|
|
NET_AddLOSubmitDataToURLStruct(submit, url);
|
|
|
|
/* referrer field if there is one */
|
|
he = SHIST_GetCurrent (&context->hist);
|
|
url->referer = fe_GetURLForReferral(he);
|
|
|
|
fe_GetURL (context, url, FALSE);
|
|
LO_FreeSubmitData (submit);
|
|
}
|
|
|
|
/*
|
|
* Emulate a button or HREF anchor click for element.
|
|
*/
|
|
void
|
|
FE_ClickInputElement(MWContext *context, LO_Element *xref)
|
|
{
|
|
LO_FormElementStruct *form = (LO_FormElementStruct *) xref;
|
|
LO_FormElementData *form_data;
|
|
FEFormData *fed;
|
|
|
|
if (!form)
|
|
return;
|
|
|
|
form_data = XP_GetFormElementData(form);
|
|
if (!form_data)
|
|
return;
|
|
|
|
fed = XP_FormGetFEData(form_data);
|
|
|
|
switch (xref->type) {
|
|
case LO_FORM_ELE:
|
|
{
|
|
XmPushButtonCallbackStruct cb;
|
|
cb.reason = XmCR_ACTIVATE;
|
|
cb.event = 0;
|
|
cb.click_count = 1;
|
|
XtCallCallbacks (fed->widget, XmNactivateCallback, &cb);
|
|
}
|
|
break;
|
|
case LO_IMAGE:
|
|
case LO_TEXT:
|
|
{
|
|
CL_Event layer_event;
|
|
fe_EventStruct fe_event;
|
|
XEvent event;
|
|
|
|
event.type = ButtonPress;
|
|
event.xbutton.time = XtLastTimestampProcessed (XtDisplay(CONTEXT_WIDGET (context)));
|
|
/* We only fill in the fields that we need. */
|
|
#ifdef LAYERS_FULL_FE_EVENT
|
|
fe_event.event = &event;
|
|
#else
|
|
fe_event_stuff(context,&fe_event,&event,0,0,FE_INVALID_MOUSE_ACTION);
|
|
layer_event.fe_event_size = sizeof(fe_event);
|
|
#endif
|
|
layer_event.fe_event = (void*)&fe_event;
|
|
layer_event.x = xref->lo_image.x;
|
|
layer_event.y = xref->lo_image.y;
|
|
(void) fe_HandleHREF (context, xref, False, False, &layer_event, 0);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
fe_form_file_browse_cb (Widget widget, XtPointer closure, XtPointer call_data)
|
|
{
|
|
FEFormData *fed = (FEFormData*) closure;
|
|
char *filename;
|
|
XmString xm_title = 0;
|
|
char *title = 0;
|
|
|
|
XtVaGetValues (widget, XmNlabelString, &xm_title, 0);
|
|
if (xm_title)
|
|
XmStringGetLtoR (xm_title,
|
|
XmFONTLIST_DEFAULT_TAG, &title); /* title - XtMalloc*/
|
|
XmStringFree(xm_title);
|
|
|
|
filename = fe_ReadFileName( fed->context, title, 0, FALSE, 0);
|
|
XtFree(title);
|
|
|
|
if (filename) {
|
|
XP_StatStruct st;
|
|
char buf [2048];
|
|
if (stat(filename, &st) < 0)
|
|
{
|
|
/* Error: Cant stat */
|
|
PR_snprintf (buf, sizeof (buf),
|
|
XP_GetString(XFE_ERROR_OPENING_FILE), filename);
|
|
FE_Alert(fed->context, buf);
|
|
}
|
|
else
|
|
{
|
|
/* The file was found. Stick the name into the text field. */
|
|
XmTextFieldSetString (fed->widget, filename);
|
|
|
|
/* resync up the backend with the current value in the text field. */
|
|
XFE_GetFormElementValue(fed->context, fed->form, False);
|
|
}
|
|
|
|
XP_FREE(filename);
|
|
}
|
|
}
|
|
|
|
/* This happens for self submiting forms. */
|
|
static void
|
|
fe_activate_submit_cb (Widget widget, XtPointer closure, XtPointer call_data)
|
|
{
|
|
FEFormData *fed = (FEFormData*)closure;
|
|
|
|
/* Move focus out of the current focus widget. This will make any OnChange
|
|
* calls to mocha.
|
|
*/
|
|
fe_NeutralizeFocus(fed->context);
|
|
|
|
fe_submit_form_cb(widget, closure, call_data);
|
|
}
|
|
|
|
static void
|
|
fe_mocha_focus_notify_eh (Widget w,
|
|
XtPointer closure,
|
|
XEvent *ev,
|
|
Boolean *cont)
|
|
{
|
|
FEFormData *fed = (FEFormData *) closure;
|
|
MWContext *context = (MWContext *) fed->context;
|
|
|
|
TRACEMSG (("fe_focus_notify_eh\n"));
|
|
switch (ev->type) {
|
|
case FocusIn:
|
|
TRACEMSG (("focus in\n"));
|
|
fe_MochaFocusNotify(context, (LO_Element*)fed->form);
|
|
break;
|
|
case FocusOut:
|
|
TRACEMSG (("focus out\n"));
|
|
fe_MochaBlurNotify(context, (LO_Element*)fed->form);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
fe_mocha_submit_form_cb (MWContext *context, LO_Element *element, int32 event,
|
|
void *closure, ETEventStatus status)
|
|
{
|
|
LO_FormSubmitData *data;
|
|
URL_Struct *url;
|
|
|
|
if (status != EVENT_OK)
|
|
return;
|
|
|
|
data = LO_SubmitForm (context, (LO_FormElementStruct *) element);
|
|
if (! data) return;
|
|
url = NET_CreateURLStruct ((char *) data->action, FALSE);
|
|
|
|
/* Add the referer to the URL. */
|
|
{
|
|
History_entry *he = SHIST_GetCurrent (&context->hist);
|
|
if (url->referer)
|
|
free (url->referer);
|
|
url->referer = fe_GetURLForReferral(he);
|
|
}
|
|
|
|
NET_AddLOSubmitDataToURLStruct (data, url);
|
|
|
|
fe_GetURL (context, url, FALSE);
|
|
LO_FreeSubmitData (data);
|
|
}
|
|
|
|
|
|
static void
|
|
fe_mocha_submit_click_form_cb(MWContext *context, LO_Element *element,
|
|
int32 event, void *closure,
|
|
ETEventStatus status)
|
|
{
|
|
FEFormData *fed = (FEFormData *) closure;
|
|
|
|
if (status != EVENT_OK)
|
|
return;
|
|
|
|
/* Load the element value before telling mocha about the submit.
|
|
* This needs to be done if we came here not because of the user
|
|
* clicking on the submit button, like hitting RETURN on a text field.
|
|
*/
|
|
XFE_GetFormElementValue(fed->context, fed->form, False);
|
|
|
|
{
|
|
JSEvent *event = XP_NEW_ZAP(JSEvent);
|
|
|
|
event->type = EVENT_SUBMIT;
|
|
|
|
ET_SendEvent (fed->context, (LO_Element *) fed->form, event,
|
|
fe_mocha_submit_form_cb, NULL);
|
|
}
|
|
}
|
|
|
|
static void
|
|
fe_submit_form_cb (Widget widget, XtPointer closure, XtPointer call_data)
|
|
/*
|
|
* description:
|
|
* This function was registered as an XmNactivateCallback for
|
|
* a Motif PushButton widget created in XFE_GetFormElementInfo().
|
|
*
|
|
* preconditions:
|
|
* widget != 0 && closure != 0 && call_data != 0
|
|
*
|
|
* returns:
|
|
* not applicable
|
|
*
|
|
**********************************************************************/
|
|
{
|
|
FEFormData *fed = (FEFormData *) closure;
|
|
/*LO_FormSubmitData *data;*/
|
|
/*URL_Struct *url;*/
|
|
|
|
#ifdef DEBUG
|
|
/* check preconditions in debug mode */
|
|
if (widget == 0 || closure == 0 || call_data == 0) {
|
|
fprintf(stderr, private_precondition_format, __FILE__, __LINE__);
|
|
fflush(stderr);
|
|
}
|
|
#endif
|
|
|
|
|
|
{
|
|
XEvent *x_event;
|
|
JSEvent *js_event;
|
|
XP_Bool do_geometry = FALSE;
|
|
|
|
/*
|
|
* The Motif documentation for XmPushButton informs that call_data
|
|
* is a pointer to XmPushButtonCallbackStruct, declared in Xm/Xm.h.
|
|
*/
|
|
x_event = ((XmPushButtonCallbackStruct*)call_data)->event;
|
|
js_event = XP_NEW_ZAP(JSEvent);
|
|
|
|
js_event->type = EVENT_CLICK;
|
|
fe_complete_js_event(js_event, x_event, do_geometry);
|
|
|
|
/* Lord Whorfin says: send me a click, dammit! */
|
|
ET_SendEvent (fed->context, (LO_Element *) fed->form, js_event,
|
|
fe_mocha_submit_click_form_cb, closure);
|
|
}
|
|
}
|
|
|
|
static void
|
|
fe_mocha_button_form_cb (MWContext *context, LO_Element *element, int32 event,
|
|
void *closure, ETEventStatus status)
|
|
{
|
|
if (status != EVENT_OK)
|
|
return;
|
|
|
|
XFE_GetFormElementValue (context, (LO_FormElementStruct *) element, False);
|
|
}
|
|
|
|
|
|
|
|
/**********************************************************************
|
|
*/
|
|
|
|
static void
|
|
fe_button_form_cb (Widget widget, /* in: a non-NULL valid widget */
|
|
XtPointer closure, /* in: registered by us in XtAddCallback() */
|
|
XtPointer call_data) /* in: from Xt */
|
|
|
|
/*
|
|
* description:
|
|
* Called when a form button is clicked.
|
|
* This function was registered as an XmNactivateCallback for
|
|
* a Motif PushButton widget created in XFE_GetFormElementInfo().
|
|
*
|
|
* preconditions:
|
|
* widget != 0 && closure != 0 && call_data != 0
|
|
*
|
|
* returns:
|
|
* not applicable
|
|
*
|
|
**********************************************************************/
|
|
{
|
|
FEFormData *form_data = (FEFormData *) closure;
|
|
XEvent *x_event; /* X Windows event structure */
|
|
JSEvent *js_event; /* Javascript event */
|
|
XP_Bool do_geometry = FALSE;
|
|
|
|
#ifdef DEBUG
|
|
/* check preconditions in debug mode */
|
|
if (widget == 0 || closure == 0 || call_data == 0) {
|
|
fprintf(stderr, private_precondition_format, __FILE__, __LINE__);
|
|
fflush(stderr);
|
|
}
|
|
#endif
|
|
/*
|
|
* The Motif documentation for XmPushButton informs that call_data
|
|
* is a pointer to XmPushButtonCallbackStruct, declared in Xm/Xm.h.
|
|
*/
|
|
x_event = ((XmPushButtonCallbackStruct*)call_data)->event;
|
|
js_event = XP_NEW_ZAP(JSEvent);
|
|
|
|
js_event->type = EVENT_CLICK;
|
|
fe_complete_js_event(js_event, x_event, do_geometry);
|
|
ET_SendEvent (form_data->context,
|
|
(LO_Element *) form_data->form,
|
|
js_event,
|
|
fe_mocha_button_form_cb,
|
|
NULL);
|
|
}
|
|
|
|
static void
|
|
fe_mocha_reset_form_cb (MWContext *context, LO_Element *element, int32 event,
|
|
void *closure, ETEventStatus status)
|
|
{
|
|
if (status != EVENT_OK)
|
|
return;
|
|
|
|
LO_ResetForm (context, (LO_FormElementStruct *) element);
|
|
}
|
|
|
|
/**********************************************************************
|
|
*/
|
|
|
|
static void
|
|
fe_reset_form_cb (Widget widget, XtPointer closure, XtPointer call_data)
|
|
|
|
/*
|
|
* description:
|
|
* This function was registered as an XmNactivateCallback for
|
|
* a Motif PushButton widget created in XFE_GetFormElementInfo().
|
|
*
|
|
* preconditions:
|
|
* widget != 0 && closure != 0 && call_data != 0
|
|
*
|
|
* returns:
|
|
* not applicable
|
|
*
|
|
**********************************************************************/
|
|
{
|
|
FEFormData *fed = (FEFormData *) closure;
|
|
|
|
#ifdef DEBUG
|
|
/* check preconditions in debug mode */
|
|
if (widget == 0 || closure == 0 || call_data == 0) {
|
|
fprintf(stderr, private_precondition_format, __FILE__, __LINE__);
|
|
fflush(stderr);
|
|
}
|
|
#endif
|
|
|
|
{
|
|
XEvent *x_event;
|
|
JSEvent *js_event;
|
|
XP_Bool do_geometry = FALSE;
|
|
|
|
/*
|
|
* The Motif documentation for XmPushButton informs that call_data
|
|
* is a pointer to XmPushButtonCallbackStruct, declared in Xm/Xm.h.
|
|
*/
|
|
x_event = ((XmPushButtonCallbackStruct*)call_data)->event;
|
|
js_event = XP_NEW_ZAP(JSEvent);
|
|
|
|
js_event->type = EVENT_CLICK;
|
|
fe_complete_js_event(js_event, x_event, do_geometry);
|
|
|
|
ET_SendEvent (fed->context, (LO_Element *) fed->form, js_event,
|
|
fe_mocha_reset_form_cb, NULL);
|
|
}
|
|
}
|
|
|
|
|
|
static void
|
|
fe_got_focus_cb (Widget widget, XtPointer closure, XtPointer call_data)
|
|
{
|
|
FEFormData *fed = (FEFormData *) closure;
|
|
JSEvent *event;
|
|
|
|
TRACEMSG(("fe_got_focus_c:\n"));
|
|
|
|
event = XP_NEW_ZAP(JSEvent);
|
|
event->type = EVENT_FOCUS;
|
|
|
|
ET_SendEvent (fed->context, (LO_Element *) fed->form, event, NULL, NULL);
|
|
}
|
|
|
|
static void
|
|
fe_lost_focus_cb (Widget widget, XtPointer closure, XtPointer call_data)
|
|
{
|
|
FEFormData *fed = (FEFormData *) closure;
|
|
|
|
if (!fed) return;
|
|
|
|
if (fed->vtbl.lost_focus_func)
|
|
(*fed->vtbl.lost_focus_func)(fed);
|
|
|
|
/* always send a blur event. */
|
|
fe_MochaBlurNotify(fed->context, (LO_Element*)fed->form);
|
|
}
|
|
|
|
static void
|
|
fe_complete_js_event(JSEvent *js_event, /* inout */
|
|
XEvent *x_event, /* in */
|
|
XP_Bool do_geometry) /* in */
|
|
|
|
/*
|
|
* description:
|
|
* Updates js_event fields from an X event.
|
|
* Consolidates common code inside various callback
|
|
* functions within this module.
|
|
*
|
|
* preconditions:
|
|
* js_event != 0 && x_event != 0
|
|
* The js_event must already have an assigned type.
|
|
*
|
|
* returns:
|
|
* not applicable
|
|
*
|
|
****************************************/
|
|
{
|
|
unsigned int state_of_buttons_and_modifiers = 0;
|
|
|
|
#ifdef DEBUG
|
|
/* check preconditions in debug mode */
|
|
if (js_event == 0 || x_event == 0 || js_event->type == 0) {
|
|
fprintf(stderr, private_precondition_format, __FILE__, __LINE__);
|
|
fflush(stderr);
|
|
}
|
|
#endif
|
|
|
|
state_of_buttons_and_modifiers = x_event->xbutton.state;
|
|
|
|
switch(js_event->type) {
|
|
case EVENT_CLICK:
|
|
#ifdef DEBUG_rodt
|
|
/* check in debug mode */
|
|
/* Expect to be processing ButtonRelease */
|
|
if (x_event->type != ButtonRelease) {
|
|
fprintf(stderr, private_check_format, __FILE__, __LINE__);
|
|
fflush(stderr);
|
|
}
|
|
#endif
|
|
{
|
|
unsigned int button;
|
|
|
|
button = x_event->xbutton.button;
|
|
|
|
/*
|
|
* MOUSE BUTTON
|
|
*
|
|
* Only verified that left button is 1. 2 should be
|
|
* middle button and 3 should be right button.
|
|
*/
|
|
js_event->which = button;
|
|
|
|
}
|
|
break;
|
|
case EVENT_KEYDOWN:
|
|
case EVENT_KEYUP:
|
|
case EVENT_KEYPRESS:
|
|
#ifdef DEBUG
|
|
/* check in debug mode */
|
|
/* Expect to be processing KeyPress or KeyRelease */
|
|
if (x_event->type != KeyPress && x_event->type != KeyRelease) {
|
|
fprintf(stderr, private_check_format, __FILE__, __LINE__);
|
|
fflush(stderr);
|
|
}
|
|
#endif
|
|
{
|
|
int buffer_length;
|
|
char buffer[32];
|
|
KeySym keysym;
|
|
XComposeStatus * compose_status;
|
|
|
|
/*
|
|
* DETERMINE ASCII VALUE OF KEY PRESSED FOR JAVASCRIPT
|
|
*
|
|
* The following code needs to be checked on corner cases.
|
|
*
|
|
*/
|
|
|
|
/*
|
|
* Ignore compose status.
|
|
* This may need to be changed.
|
|
*/
|
|
compose_status = 0;
|
|
|
|
/*
|
|
* The XEvent structure is converted to a keysym as well as a
|
|
* string (possibly more than one character) which represents
|
|
* the keysym.
|
|
*
|
|
*/
|
|
buffer_length = XLookupString(&(x_event->xkey),
|
|
buffer,
|
|
31,
|
|
&keysym,
|
|
compose_status);
|
|
if (buffer_length == 1)
|
|
{
|
|
js_event->which = buffer[0];
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* Force all other cases to return a zero to
|
|
* expose bugs which indicate that this code needs
|
|
* to be modified.
|
|
*/
|
|
js_event->which = 0;
|
|
}
|
|
|
|
if (do_geometry) {
|
|
js_event->x = x_event->xkey.x;
|
|
js_event->y = x_event->xkey.y;
|
|
js_event->screenx = x_event->xkey.x_root;
|
|
js_event->screeny = x_event->xkey.y_root;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
/*
|
|
* ASSIGN MODIFIERS
|
|
*/
|
|
if (state_of_buttons_and_modifiers) {
|
|
/*
|
|
* MODIFIER KEYS (ALT, CONTROL, SHIFT, META)
|
|
* EVENT_xxx_MASK's are from ns/include/libevent.h
|
|
*/
|
|
if (state_of_buttons_and_modifiers & ControlMask)
|
|
js_event->modifiers |= EVENT_CONTROL_MASK;
|
|
if (state_of_buttons_and_modifiers & ShiftMask)
|
|
js_event->modifiers |= EVENT_SHIFT_MASK;
|
|
|
|
/*
|
|
* Only verified meta on Solaris 2.5 dtwm (mwm workalike)
|
|
*/
|
|
if (state_of_buttons_and_modifiers & Mod4Mask)
|
|
js_event->modifiers |= EVENT_META_MASK;
|
|
}
|
|
}
|
|
|
|
static void
|
|
fe_key_handler(Widget widget, /* in */
|
|
XtPointer closure, /* in */
|
|
XEvent * x_event, /* in */
|
|
Boolean * bcontinue) /* out */
|
|
|
|
/*
|
|
* description:
|
|
* Handles XEvents of type KeyPress and KeyRelease in order
|
|
* to pass these along to JavaScript. JavaScript recognizes
|
|
* three key events:
|
|
* EVENT_KEYDOWN corresponds to the X Event KeyPress
|
|
* EVENT_KEYUP corresponds to the X Event KeyRelease
|
|
* EVENT_KEYPRESS corresponds to the X Event KeyPress followed by KeyRelease
|
|
*
|
|
* Do not confuse EVENT_KEYPRESS with the X Event KeyPress!
|
|
*
|
|
* returns:
|
|
* Not applicable. Note that currently bcontinue is not modified.
|
|
*
|
|
* end:
|
|
****************************************/
|
|
{
|
|
FEFormData *form_data;
|
|
JSEvent *js_event = 0; /* Javascript event */
|
|
static int32 previous_js_event_type = 0;
|
|
static int32 previous_js_event_which = 0;
|
|
|
|
|
|
#ifdef DEBUG
|
|
/* check preconditions in debug mode */
|
|
if (widget == 0 || closure == 0 || x_event == 0 || bcontinue == 0) {
|
|
fprintf(stderr, private_precondition_format, __FILE__, __LINE__);
|
|
fflush(stderr);
|
|
}
|
|
#endif
|
|
|
|
form_data = (FEFormData *) closure;
|
|
|
|
if (x_event->type == KeyPress) {
|
|
js_event = XP_NEW_ZAP(JSEvent);
|
|
js_event->type = EVENT_KEYDOWN;
|
|
}
|
|
else if (x_event->type == KeyRelease) {
|
|
js_event = XP_NEW_ZAP(JSEvent);
|
|
js_event->type = EVENT_KEYUP;
|
|
}
|
|
|
|
/*
|
|
* Do further work only on KeyPress and KeyRelease
|
|
*/
|
|
if (js_event) {
|
|
XP_Bool do_geometry = TRUE;
|
|
|
|
fe_complete_js_event(js_event, x_event, do_geometry);
|
|
|
|
/*
|
|
* SYNTHESIZE AND SEND EVENT_KEYPRESS
|
|
*/
|
|
if (previous_js_event_type == EVENT_KEYDOWN
|
|
&& js_event->type == EVENT_KEYUP
|
|
&& previous_js_event_which == js_event->which)
|
|
{
|
|
JSEvent *synthesized_js_event;
|
|
|
|
synthesized_js_event = XP_NEW_ZAP(JSEvent);
|
|
XP_MEMCPY(synthesized_js_event, js_event, sizeof(JSEvent));
|
|
synthesized_js_event->type = EVENT_KEYPRESS;
|
|
ET_SendEvent(form_data->context,
|
|
(LO_Element *) form_data->form,
|
|
synthesized_js_event,
|
|
NULL,
|
|
NULL);
|
|
}
|
|
|
|
/*
|
|
* SEND EVENT_KEYDOWN/UP
|
|
*/
|
|
previous_js_event_type = js_event->type;
|
|
previous_js_event_which = js_event->which;
|
|
ET_SendEvent(form_data->context,
|
|
(LO_Element *) form_data->form,
|
|
js_event,
|
|
NULL,
|
|
NULL);
|
|
}
|
|
}
|
|
|
|
static void
|
|
fe_mocha_radio_form_cb (MWContext *context, LO_Element *element,
|
|
int32 event, void *closure, ETEventStatus status)
|
|
{
|
|
XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct *)closure;
|
|
LO_FormElementStruct *save;
|
|
|
|
if (status == EVENT_OK) {
|
|
if (cb->set)
|
|
save = LO_FormRadioSet (context, (LO_FormElementStruct *) element);
|
|
/* it's possible for save to be null here. it's a legal
|
|
return value from LO_FormRadioSet
|
|
*/
|
|
if (cb->set && save && save != (LO_FormElementStruct *) element)
|
|
{
|
|
XFE_SetFormElementToggle (context, save, TRUE);
|
|
LO_FormRadioSet (context, save);
|
|
}
|
|
|
|
XFE_GetFormElementValue (context, (LO_FormElementStruct *) element, False);
|
|
}
|
|
XP_FREE (cb);
|
|
}
|
|
|
|
/**********************************************************************
|
|
*/
|
|
|
|
static void
|
|
fe_radio_form_cb (Widget widget, XtPointer closure, XtPointer call_data)
|
|
|
|
/*
|
|
* description:
|
|
* This function was registered as an XmNvalueChangedCallback for
|
|
* a Motif ToggleButton widget created in XFE_GetFormElementInfo().
|
|
*
|
|
* preconditions:
|
|
* widget != 0 && closure != 0 && call_data != 0
|
|
*
|
|
* returns:
|
|
* not applicable
|
|
*
|
|
**********************************************************************/
|
|
{
|
|
FEFormData *fed = (FEFormData *) closure;
|
|
XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct *)call_data;
|
|
LO_FormElementStruct *save;
|
|
|
|
#ifdef DEBUG
|
|
/* check preconditions in debug mode */
|
|
if (widget == 0 || closure == 0 || call_data == 0) {
|
|
fprintf(stderr, private_precondition_format, __FILE__, __LINE__);
|
|
fflush(stderr);
|
|
}
|
|
#endif
|
|
|
|
if (cb->set)
|
|
save = LO_FormRadioSet (fed->context, fed->form);
|
|
else
|
|
/* Don't allow the user to ever toggle a button off - exactly one
|
|
must be selected at all times. */
|
|
XtVaSetValues (widget, XmNset, True, 0);
|
|
|
|
XFE_GetFormElementValue (fed->context, fed->form, False);
|
|
|
|
{
|
|
XEvent *x_event;
|
|
JSEvent *js_event;
|
|
XP_Bool do_geometry = FALSE;
|
|
XmToggleButtonCallbackStruct *cb_closure;
|
|
|
|
cb_closure = XP_NEW_ZAP (XmToggleButtonCallbackStruct);
|
|
XP_MEMCPY (cb_closure, cb, sizeof (XmToggleButtonCallbackStruct));
|
|
|
|
x_event = cb_closure->event;
|
|
js_event = XP_NEW_ZAP(JSEvent);
|
|
js_event->type = EVENT_CLICK;
|
|
fe_complete_js_event(js_event, x_event, do_geometry);
|
|
|
|
ET_SendEvent (fed->context, (LO_Element *) fed->form, js_event,
|
|
fe_mocha_radio_form_cb, cb_closure);
|
|
}
|
|
}
|
|
|
|
static void
|
|
fe_check_form_cb (Widget widget, XtPointer closure, XtPointer call_data)
|
|
|
|
/*
|
|
* description:
|
|
* This function was registered as an XmNvalueChangedCallback for
|
|
* a Motif ToggleButton widget created in XFE_GetFormElementInfo().
|
|
*
|
|
* preconditions:
|
|
* widget != 0 && closure != 0 && call_data != 0
|
|
*
|
|
* returns:
|
|
* not applicable
|
|
*
|
|
**********************************************************************/
|
|
{
|
|
FEFormData *form_data = (FEFormData *) closure;
|
|
XEvent *x_event; /* X Windows event structure */
|
|
JSEvent *js_event;
|
|
XP_Bool do_geometry = FALSE;
|
|
lo_FormElementToggleData *data;
|
|
Bool save;
|
|
|
|
#ifdef DEBUG
|
|
/* check preconditions in debug mode */
|
|
if (widget == 0 || closure == 0 || call_data == 0) {
|
|
fprintf(stderr, private_precondition_format, __FILE__, __LINE__);
|
|
fflush(stderr);
|
|
}
|
|
#endif
|
|
|
|
data = &form_data->form->element_data->ele_toggle;
|
|
save = data->toggled;
|
|
|
|
XFE_GetFormElementValue (form_data->context, form_data->form, False);
|
|
|
|
/*
|
|
* The Motif documentation for XmToggleButton informs that call_data
|
|
* is a pointer to XmToggleButtonCallbackStruct, declared in Xm/Xm.h.
|
|
*/
|
|
x_event = ((XmToggleButtonCallbackStruct*)call_data)->event;
|
|
js_event = XP_NEW_ZAP(JSEvent);
|
|
js_event->type = EVENT_CLICK;
|
|
fe_complete_js_event(js_event, x_event, do_geometry);
|
|
|
|
ET_SendEvent (form_data->context,
|
|
(LO_Element *) form_data->form,
|
|
js_event,
|
|
NULL,
|
|
NULL);
|
|
}
|
|
|
|
static void
|
|
fe_combo_form_cb(Widget widget, XtPointer closure, XtPointer call_data)
|
|
{
|
|
FESelectOneFormData *sel_fed = (FESelectOneFormData *) closure;
|
|
DtComboBoxCallbackStruct *cb = (DtComboBoxCallbackStruct *) call_data;
|
|
LO_FormElementData *form_data;
|
|
lo_FormElementOptionData *option_data;
|
|
int i;
|
|
|
|
form_data = XP_GetFormElementData(sel_fed->form_data.form);
|
|
|
|
for (i = 0; i < sel_fed->nkids; i++)
|
|
{
|
|
option_data = XP_FormSelectGetOption(form_data,
|
|
i);
|
|
|
|
/* combo boxes start the item ordering at 0, not 1. */
|
|
sel_fed->selected_p [i] = (i == cb->item_position);
|
|
|
|
XP_FormOptionSetSelected(option_data, sel_fed->selected_p[i]);
|
|
}
|
|
{
|
|
JSEvent *event = XP_NEW_ZAP(JSEvent);
|
|
|
|
event->type = EVENT_CHANGE;
|
|
|
|
ET_SendEvent (sel_fed->form_data.context,
|
|
(LO_Element *) sel_fed->form_data.form,
|
|
event,
|
|
NULL, NULL);
|
|
}
|
|
}
|
|
|
|
static void
|
|
fe_list_form_cb (Widget widget, XtPointer closure, XtPointer call_data)
|
|
{
|
|
FESelectMultFormData *sel_fed = (FESelectMultFormData *) closure;
|
|
XmListCallbackStruct *cb = (XmListCallbackStruct *) call_data;
|
|
LO_FormElementData *form_data;
|
|
lo_FormElementOptionData *option_data;
|
|
int i, j;
|
|
|
|
form_data = XP_GetFormElementData(sel_fed->form_data.form);
|
|
|
|
switch (cb->reason)
|
|
{
|
|
case XmCR_SINGLE_SELECT:
|
|
case XmCR_BROWSE_SELECT:
|
|
for (i = 0; i < sel_fed->nkids; i++)
|
|
{
|
|
option_data = XP_FormSelectGetOption(form_data,
|
|
i);
|
|
|
|
/* Note that the item_position starts at 1, not 0!!!! */
|
|
sel_fed->selected_p [i] = (cb->selected_item_count &&
|
|
i == (cb->item_position - 1));
|
|
|
|
XP_FormOptionSetSelected(option_data, sel_fed->selected_p[i]);
|
|
}
|
|
break;
|
|
case XmCR_MULTIPLE_SELECT:
|
|
case XmCR_EXTENDED_SELECT:
|
|
for (i = 0; i < sel_fed->nkids; i++)
|
|
{
|
|
/*
|
|
**
|
|
** toshok -- this is extremely gross and inefficient. must
|
|
** revisit it. XXXXX
|
|
**
|
|
*/
|
|
option_data = XP_FormSelectGetOption(form_data,
|
|
i);
|
|
|
|
sel_fed->selected_p [i] = 0;
|
|
XP_FormOptionSetSelected(option_data, sel_fed->selected_p[i]);
|
|
|
|
for (j = 0; j < cb->selected_item_count; j++)
|
|
if (i == (cb->selected_item_positions [j] - 1))
|
|
{
|
|
sel_fed->selected_p [i] = 1;
|
|
XP_FormOptionSetSelected(option_data, sel_fed->selected_p[i]);
|
|
}
|
|
}
|
|
break;
|
|
case XmCR_DEFAULT_ACTION:
|
|
break;
|
|
default:
|
|
assert (0);
|
|
return;
|
|
}
|
|
|
|
{
|
|
JSEvent *event = XP_NEW_ZAP(JSEvent);
|
|
|
|
event->type = EVENT_CHANGE;
|
|
|
|
ET_SendEvent (sel_fed->form_data.context,
|
|
(LO_Element *) sel_fed->form_data.form,
|
|
event,
|
|
NULL, NULL);
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
XFE_ResetFormElement (MWContext *context, LO_FormElementStruct *form)
|
|
{
|
|
LO_FormElementData *form_data = XP_GetFormElementData(form);
|
|
FEFormData *fed = (FEFormData*)XP_FormGetFEData(form_data);
|
|
|
|
XP_ASSERT(fed);
|
|
if (!fed) return;
|
|
|
|
if (fed->vtbl.reset_element)
|
|
(*fed->vtbl.reset_element)(fed, form);
|
|
}
|
|
|
|
/* don't *really* need a vtable entry for this one... or maybe we do. */
|
|
void
|
|
XFE_SetFormElementToggle (MWContext *context, LO_FormElementStruct *form,
|
|
XP_Bool state)
|
|
{
|
|
LO_FormElementData *form_data = XP_GetFormElementData(form);
|
|
FEFormData *fed;
|
|
int32 form_type;
|
|
|
|
if (form_data == NULL) {
|
|
#ifdef DEBUG_username
|
|
printf ("forms.c:%d; form_data == NULL\n", __LINE__);
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
fed = (FEFormData*)XP_FormGetFEData(form_data);
|
|
form_type = XP_FormGetType(form_data);
|
|
|
|
XP_ASSERT(form_type == FORM_TYPE_CHECKBOX ||
|
|
form_type == FORM_TYPE_RADIO);
|
|
if (form_type != FORM_TYPE_CHECKBOX
|
|
&& form_type != FORM_TYPE_RADIO)
|
|
return;
|
|
|
|
XtVaSetValues (fed->widget, XmNset, state, 0);
|
|
}
|
|
|
|
void
|
|
fe_SetFormsGravity (MWContext *context, int gravity)
|
|
{
|
|
Widget *kids;
|
|
Widget area;
|
|
Cardinal nkids = 0;
|
|
XSetWindowAttributes attr;
|
|
unsigned long valuemask;
|
|
|
|
|
|
XtVaGetValues (CONTEXT_DATA (context)->drawing_area,
|
|
XmNchildren, &kids, XmNnumChildren, &nkids,
|
|
0);
|
|
|
|
valuemask = CWBitGravity | CWWinGravity;
|
|
attr.win_gravity = gravity;
|
|
attr.bit_gravity = gravity;
|
|
area = CONTEXT_DATA (context)->drawing_area;
|
|
XChangeWindowAttributes (XtDisplay(area), XtWindow(area), valuemask, &attr);
|
|
while (nkids--)
|
|
{
|
|
if (XtIsManaged (kids[nkids]))
|
|
XChangeWindowAttributes (XtDisplay(kids[nkids]), XtWindow(kids[nkids]),
|
|
valuemask, &attr);
|
|
}
|
|
}
|
|
|
|
void
|
|
fe_ScrollForms (MWContext *context, int x_off, int y_off)
|
|
{
|
|
Widget *kids;
|
|
Cardinal nkids = 0;
|
|
|
|
if (x_off == 0 && y_off == 0)
|
|
return;
|
|
|
|
XtVaGetValues (CONTEXT_DATA (context)->drawing_area,
|
|
XmNchildren, &kids, XmNnumChildren, &nkids,
|
|
0);
|
|
while (nkids--)
|
|
XtMoveWidget (kids [nkids],
|
|
_XfeX(kids [nkids]) + x_off,
|
|
_XfeY(kids [nkids]) + y_off);
|
|
}
|
|
|
|
|
|
void
|
|
fe_GravityCorrectForms (MWContext *context, int x_off, int y_off)
|
|
{
|
|
Widget *kids;
|
|
Cardinal nkids = 0;
|
|
|
|
if (x_off == 0 && y_off == 0)
|
|
return;
|
|
|
|
XtVaGetValues (CONTEXT_DATA (context)->drawing_area,
|
|
XmNchildren, &kids, XmNnumChildren, &nkids,
|
|
0);
|
|
|
|
while (nkids--)
|
|
{
|
|
if (XtIsManaged (kids[nkids]))
|
|
{
|
|
_XfeX(kids[nkids]) = _XfeX(kids[nkids]) + x_off;
|
|
_XfeY(kids[nkids]) = _XfeY(kids[nkids]) + y_off;
|
|
}
|
|
}
|
|
}
|
|
|