#include <Xm/BulletinB.h>
#include <Xm/CascadeB.h>
+#include <Xm/CascadeBG.h>
#include <Xm/DrawingA.h>
#include <Xm/FileSB.h>
#include <Xm/Label.h>
#include <Xm/DialogS.h>
#include <Xm/Form.h>
-static void xm_pull_down_callback (/* Widget, XtPointer, XtPointer */);
-static void xm_internal_update_other_instances (/* Widget, XtPointer,
- XtPointer */);
-static void xm_generic_callback (/* Widget, XtPointer, XtPointer */);
-static void xm_nosel_callback (/* Widget, XtPointer, XtPointer */);
-static void xm_pop_down_callback (/* Widget, XtPointer, XtPointer */);
+#ifdef __STDC__
+#define P_(X) X
+#else
+#define P_(X) ()
+#endif
-static void xm_update_menu (/* widget_instance*, Widget, widget_value*,
- Boolean) */);
+enum do_call_type { pre_activate, selection, no_selection, post_activate };
\f/* Structures to keep destroyed instances */
struct _destroyed_instance* next;
} destroyed_instance;
+static destroyed_instance *make_destroyed_instance P_ ((char *, char *,
+ Widget, Widget,
+ Boolean));
+static void free_destroyed_instance P_ ((destroyed_instance*));
+Widget first_child P_ ((Widget));
+Boolean lw_motif_widget_p P_ ((Widget));
+static XmString resource_motif_string P_ ((Widget, char *));
+static void destroy_all_children P_ ((Widget, int));
+static void xm_update_label P_ ((widget_instance *, Widget, widget_value *));
+static void xm_update_list P_ ((widget_instance *, Widget, widget_value *));
+static void xm_update_pushbutton P_ ((widget_instance *, Widget,
+ widget_value *));
+static void xm_update_cascadebutton P_ ((widget_instance *, Widget,
+ widget_value *));
+static void xm_update_toggle P_ ((widget_instance *, Widget, widget_value *));
+static void xm_update_radiobox P_ ((widget_instance *, Widget, widget_value *));
+static void make_menu_in_widget P_ ((widget_instance *, Widget,
+ widget_value *, int));
+static void update_one_menu_entry P_ ((widget_instance *, Widget,
+ widget_value *, Boolean));
+static void xm_update_menu P_ ((widget_instance *, Widget, widget_value *,
+ Boolean));
+static void xm_update_text P_ ((widget_instance *, Widget, widget_value *));
+static void xm_update_text_field P_ ((widget_instance *, Widget,
+ widget_value *));
+void xm_update_one_value P_ ((widget_instance *, Widget, widget_value *));
+static void activate_button P_ ((Widget, XtPointer, XtPointer));
+static Widget make_dialog P_ ((char *, Widget, Boolean, char *, char *,
+ Boolean, Boolean, Boolean, int, int));
+static destroyed_instance* find_matching_instance P_ ((widget_instance*));
+static void mark_dead_instance_destroyed P_ ((Widget, XtPointer, XtPointer));
+static void recenter_widget P_ ((Widget));
+static Widget recycle_instance P_ ((destroyed_instance*));
+Widget xm_create_dialog P_ ((widget_instance*));
+static Widget make_menubar P_ ((widget_instance*));
+static void remove_grabs P_ ((Widget, XtPointer, XtPointer));
+static Widget make_popup_menu P_ ((widget_instance*));
+static Widget make_main P_ ((widget_instance*));
+void xm_destroy_instance P_ ((widget_instance*));
+void xm_popup_menu P_ ((Widget, XEvent *));
+static void set_min_dialog_size P_ ((Widget));
+static void do_call P_ ((Widget, XtPointer, enum do_call_type));
+static void xm_generic_callback P_ ((Widget, XtPointer, XtPointer));
+static void xm_nosel_callback P_ ((Widget, XtPointer, XtPointer));
+static void xm_pull_down_callback P_ ((Widget, XtPointer, XtPointer));
+static void xm_pop_down_callback P_ ((Widget, XtPointer, XtPointer));
+void xm_set_keyboard_focus P_ ((Widget, Widget));
+void xm_set_main_areas P_ ((Widget, Widget, Widget));
+static void xm_internal_update_other_instances P_ ((Widget, XtPointer,
+ XtPointer));
+
+#if 0
+void xm_update_one_widget P_ ((widget_instance *, Widget, widget_value *,
+ Boolean));
+void xm_pop_instance P_ ((widget_instance*, Boolean));
+void xm_manage_resizing P_ ((Widget, Boolean));
+#endif
+
+
static destroyed_instance*
all_destroyed_instances = NULL;
return result;
}
+/* Destroy all of the children of WIDGET
+ starting with number FIRST_CHILD_TO_DESTROY. */
+
static void
-destroy_all_children (widget)
+destroy_all_children (widget, first_child_to_destroy)
Widget widget;
+ int first_child_to_destroy;
{
Widget* children;
unsigned int number;
children = XtCompositeChildren (widget, &number);
if (children)
{
+ XtUnmanageChildren (children + first_child_to_destroy,
+ number - first_child_to_destroy);
+
/* Unmanage all children and destroy them. They will only be
- * really destroyed when we get out of DispatchEvent. */
- for (i = 0; i < number; i++)
+ really destroyed when we get out of DispatchEvent. */
+ for (i = first_child_to_destroy; i < number; i++)
{
- Widget child = children [i];
- if (!child->core.being_destroyed)
- {
- XtUnmanageChild (child);
- XtDestroyWidget (child);
- }
+ Arg al[2];
+ Widget submenu = 0;
+ /* Cascade buttons have submenus,and these submenus
+ need to be freed. But they are not included in
+ XtCompositeChildren. So get it out of the cascade button
+ and free it. If this child is not a cascade button,
+ then submenu should remain unchanged. */
+ XtSetArg (al[0], XmNsubMenuId, &submenu);
+ XtGetValues (children[i], al, 1);
+ if (submenu)
+ XtDestroyWidget (submenu);
+ XtDestroyWidget (children[i]);
}
+
XtFree ((char *) children);
}
}
-\f/* update the label of anything subclass of a label */
+\f
+/* Update the label of widget WIDGET. WIDGET must be a Label widget
+ or a subclass of Label. WIDGET_INSTANCE is unused. VAL contains
+ the value to update.
+
+ Menus:
+
+ Emacs fills VAL->name with the text to display in the menu, and
+ sets VAL->value to null. Function make_menu_in_widget creates
+ widgets with VAL->name as resource name. This works because the
+ Label widget uses its resource name for display if no
+ XmNlabelString is set.
+
+ Dialogs:
+
+ VAL->name is again set to the resource name, but VAL->value is
+ not null, and contains the label string to display. */
+
static void
xm_update_label (instance, widget, val)
widget_instance* instance;
XmString key_string = 0;
Arg al [256];
int ac;
-
+
ac = 0;
if (val->value)
{
+ /* A label string is specified, i.e. we are in a dialog. First
+ see if it is overridden by something from the resource file. */
res_string = resource_motif_string (widget, val->value);
if (res_string)
XmStringCreateLtoR (val->value, XmSTRING_DEFAULT_CHARSET);
XtSetArg (al [ac], XmNlabelString, built_string); ac++;
}
+
XtSetArg (al [ac], XmNlabelType, XmSTRING); ac++;
}
{
XtRemoveAllCallbacks (widget, XmNvalueChangedCallback);
XtAddCallback (widget, XmNvalueChangedCallback,
- xm_internal_update_other_instances, instance);
+ xm_generic_callback, instance);
XtVaSetValues (widget, XmNset, val->selected,
XmNalignment, XmALIGNMENT_BEGINNING, 0);
}
}
}
-\f/* update a popup menu, pulldown menu or a menubar */
-static Boolean
-all_dashes_p (s)
- char* s;
-{
- char* t;
- for (t = s; *t; t++)
- if (*t != '-')
- return False;
- return True;
-}
+\f
+/* update a popup menu, pulldown menu or a menubar */
+
+/* KEEP_FIRST_CHILDREN gives the number of initial children to keep. */
static void
-make_menu_in_widget (instance, widget, val)
+make_menu_in_widget (instance, widget, val, keep_first_children)
widget_instance* instance;
Widget widget;
widget_value* val;
+ int keep_first_children;
{
Widget* children = 0;
int num_children;
int child_index;
widget_value* cur;
Widget button = 0;
+ Widget title = 0;
Widget menu;
Arg al [256];
int ac;
Boolean menubar_p;
+ unsigned char type;
+
+ Widget* old_children;
+ unsigned int old_num_children;
+
+ old_children = XtCompositeChildren (widget, &old_num_children);
/* Allocate the children array */
for (num_children = 0, cur = val; cur; num_children++, cur = cur->next);
children = (Widget*)XtMalloc (num_children * sizeof (Widget));
- /* tricky way to know if this RowColumn is a menubar or a pulldown... */
- menubar_p = False;
- XtSetArg (al[0], XmNisHomogeneous, &menubar_p);
+ /* WIDGET should be a RowColumn. */
+ if (!XmIsRowColumn (widget))
+ abort ();
+
+ /* Determine whether WIDGET is a menu bar. */
+ type = -1;
+ XtSetArg (al[0], XmNrowColumnType, &type);
XtGetValues (widget, al, 1);
+ if (type != XmMENU_BAR && type != XmMENU_PULLDOWN && type != XmMENU_POPUP)
+ abort ();
+ menubar_p = type == XmMENU_BAR;
- /* add the unmap callback for popups and pulldowns */
- /*** this sounds bogus ***/
+ /* Add a callback to popups and pulldowns that is called when
+ it is made invisible again. */
if (!menubar_p)
XtAddCallback (XtParent (widget), XmNpopdownCallback,
xm_pop_down_callback, (XtPointer)instance);
- for (child_index = 0, cur = val; cur; child_index++, cur = cur->next)
- {
+ /* Preserve the first KEEP_FIRST_CHILDREN old children. */
+ for (child_index = 0, cur = val; child_index < keep_first_children;
+ child_index++, cur = cur->next)
+ children[child_index] = old_children[child_index];
+
+ /* Check that those are all we have
+ (the caller should have deleted the rest). */
+ if (old_num_children != keep_first_children)
+ abort ();
+
+ /* Create the rest. */
+ for (child_index = keep_first_children; cur; child_index++, cur = cur->next)
+ {
+ enum menu_separator separator;
+
ac = 0;
- XtSetArg (al [ac], XmNsensitive, cur->enabled); ac++;
- XtSetArg (al [ac], XmNalignment, XmALIGNMENT_BEGINNING); ac++;
- XtSetArg (al [ac], XmNuserData, cur->call_data); ac++;
+ XtSetArg (al[ac], XmNsensitive, cur->enabled); ac++;
+ XtSetArg (al[ac], XmNalignment, XmALIGNMENT_BEGINNING); ac++;
+ XtSetArg (al[ac], XmNuserData, cur->call_data); ac++;
if (instance->pop_up_p && !cur->contents && !cur->call_data
- && !all_dashes_p (cur->name))
+ && !lw_separator_p (cur->name, &separator, 1))
{
ac = 0;
XtSetArg (al[ac], XmNalignment, XmALIGNMENT_CENTER); ac++;
- button = XmCreateLabel (widget, cur->name, al, ac);
+ title = button = XmCreateLabel (widget, cur->name, al, ac);
}
- else if (all_dashes_p (cur->name))
+ else if (lw_separator_p (cur->name, &separator, 1))
{
- button = XmCreateSeparator (widget, cur->name, NULL, 0);
+ ac = 0;
+ XtSetArg (al[ac], XmNseparatorType, separator); ++ac;
+ button = XmCreateSeparator (widget, cur->name, al, ac);
}
else if (!cur->contents)
{
button = XmCreateCascadeButton (widget, cur->name, al, ac);
else if (!cur->call_data)
button = XmCreateLabel (widget, cur->name, al, ac);
+ else if (cur->button_type == BUTTON_TYPE_TOGGLE
+ || cur->button_type == BUTTON_TYPE_RADIO)
+ {
+ XtSetArg (al[ac], XmNset, cur->selected); ++ac;
+ XtSetArg (al[ac], XmNvisibleWhenOff, True); ++ac;
+ XtSetArg (al[ac], XmNindicatorType,
+ (cur->button_type == BUTTON_TYPE_TOGGLE
+ ? XmN_OF_MANY : XmONE_OF_MANY));
+ ++ac;
+ button = XmCreateToggleButton (widget, cur->name, al, ac);
+ }
else
- button = XmCreatePushButtonGadget (widget, cur->name, al, ac);
+ button = XmCreatePushButton (widget, cur->name, al, ac);
xm_update_label (instance, button, cur);
-
- /* don't add a callback to a simple label */
- if (cur->call_data)
+
+ /* Add a callback that is called when the button is
+ selected. Toggle buttons don't support
+ XmNactivateCallback, we use XmNvalueChangedCallback in
+ that case. Don't add a callback to a simple label. */
+ if (cur->button_type)
+ xm_update_toggle (instance, button, cur);
+ else if (cur->call_data)
XtAddCallback (button, XmNactivateCallback, xm_generic_callback,
(XtPointer)instance);
}
else
{
menu = XmCreatePulldownMenu (widget, cur->name, NULL, 0);
- make_menu_in_widget (instance, menu, cur->contents);
- XtSetArg (al [ac], XmNsubMenuId, menu); ac++;
+ make_menu_in_widget (instance, menu, cur->contents, 0);
+ XtSetArg (al [ac], XmNsubMenuId, menu); ac++;
+ /* Non-zero values don't work reliably in conjunction with
+ Emacs' event loop */
+ XtSetArg (al [ac], XmNmappingDelay, 0); ac++;
button = XmCreateCascadeButton (widget, cur->name, al, ac);
xm_update_label (instance, button, cur);
(XtPointer)instance);
}
- children [child_index] = button;
+ children[child_index] = button;
}
- XtManageChildren (children, num_children);
-
- /* Last entry is the help button. Has to be done after managing
- * the buttons otherwise the menubar is only 4 pixels high... */
+ /* Last entry is the help button. The original comment read "Has to
+ be done after managing the buttons otherwise the menubar is only
+ 4 pixels high." This is no longer true, and to make
+ XmNmenuHelpWidget work, we need to set it before managing the
+ children.. --gerd. */
if (button)
- {
- ac = 0;
- XtSetArg (al [ac], XmNmenuHelpWidget, button); ac++;
- XtSetValues (widget, al, ac);
- }
+ XtVaSetValues (widget, XmNmenuHelpWidget, button, 0);
+
+ /* LessTif apparently doesn't recompute centered text when more
+ widgets are added. So, do it after all widgets have been
+ created. */
+ if (title)
+ XtVaSetValues (title, XmNalignment, XmALIGNMENT_CENTER, 0);
+
+ if (num_children)
+ XtManageChildren (children, num_children);
XtFree ((char *) children);
+ if (old_children)
+ XtFree ((char *) old_children);
}
static void
Widget menu;
widget_value* contents;
- if (val->change == NO_CHANGE)
+ if (val->this_one_change == NO_CHANGE)
return;
/* update the sensitivity and userdata */
0);
/* update the menu button as a label. */
- if (val->change >= VISIBLE_CHANGE)
- xm_update_label (instance, widget, val);
+ if (val->this_one_change >= VISIBLE_CHANGE)
+ {
+ xm_update_label (instance, widget, val);
+ if (val->button_type)
+ xm_update_toggle (instance, widget, val);
+ }
/* update the pulldown/pullaside as needed */
ac = 0;
{
if (contents)
{
- menu = XmCreatePulldownMenu (XtParent (widget), XtName (widget), NULL, 0);
- make_menu_in_widget (instance, menu, contents);
- ac = 0;
- XtSetArg (al [ac], XmNsubMenuId, menu); ac++;
- XtSetValues (widget, al, ac);
+ unsigned int old_num_children, i;
+ Widget parent;
+ Widget *widget_list;
+
+ parent = XtParent (widget);
+ widget_list = XtCompositeChildren (parent, &old_num_children);
+
+ /* Find the widget position within the parent's widget list. */
+ for (i = 0; i < old_num_children; i++)
+ if (strcmp (XtName (widget_list[i]), XtName (widget)) == 0)
+ break;
+ if (i == old_num_children)
+ abort ();
+ if (XmIsCascadeButton (widget_list[i]))
+ {
+ menu = XmCreatePulldownMenu (parent, XtName(widget), NULL, 0);
+ make_menu_in_widget (instance, menu, contents, 0);
+ ac = 0;
+ XtSetArg (al [ac], XmNsubMenuId, menu); ac++;
+ XtSetValues (widget, al, ac);
+ }
+ else
+ {
+ Widget button;
+
+ /* The current menuitem is a XmPushButtonGadget, it
+ needs to be replaced by a CascadeButtonGadget */
+ XtDestroyWidget (widget_list[i]);
+ menu = XmCreatePulldownMenu (parent, val->name, NULL, 0);
+ make_menu_in_widget (instance, menu, contents, 0);
+ ac = 0;
+ XtSetArg (al [ac], XmNsubMenuId, menu); ac++;
+ /* Non-zero values don't work reliably in
+ conjunction with Emacs' event loop */
+ XtSetArg (al [ac], XmNmappingDelay, 0); ac++;
+#ifdef XmNpositionIndex /* This is undefined on SCO ODT 2.0. */
+ /* Tell Motif to put it in the right place */
+ XtSetArg (al [ac], XmNpositionIndex , i); ac++;
+#endif
+ button = XmCreateCascadeButton (parent, val->name, al, ac);
+ xm_update_label (instance, button, val);
+
+ XtAddCallback (button, XmNcascadingCallback, xm_pull_down_callback,
+ (XtPointer)instance);
+ XtManageChild (button);
+ }
}
}
else if (!contents)
widget_value* val;
Boolean deep_p;
{
+ Widget* children;
+ unsigned int num_children;
+ int num_children_to_keep = 0;
+ int i;
+ widget_value* cur;
+
+ children = XtCompositeChildren (widget, &num_children);
+
/* Widget is a RowColumn widget whose contents have to be updated
* to reflect the list of items in val->contents */
- if (val->contents->change == STRUCTURAL_CHANGE)
+
+ /* See how many buttons we can keep, and how many we
+ must completely replace. */
+ if (val->contents == 0)
+ num_children_to_keep = 0;
+ else if (val->contents->change == STRUCTURAL_CHANGE)
{
- destroy_all_children (widget);
- make_menu_in_widget (instance, widget, val->contents);
+ if (children)
+ {
+ for (i = 0, cur = val->contents;
+ (i < num_children
+ && cur); /* how else to ditch unwanted children ?? - mgd */
+ i++, cur = cur->next)
+ {
+ if (cur->this_one_change == STRUCTURAL_CHANGE)
+ break;
+ }
+
+ num_children_to_keep = i;
+ }
}
else
- {
- /* Update all the buttons of the RowColumn in order. */
- Widget* children;
- unsigned int num_children;
- int i;
- widget_value* cur;
+ num_children_to_keep = num_children;
- children = XtCompositeChildren (widget, &num_children);
- if (children)
+ /* Update all the buttons of the RowColumn, in order,
+ except for those we are going to replace entirely. */
+ if (children)
+ {
+ for (i = 0, cur = val->contents; i < num_children_to_keep; i++)
{
- for (i = 0, cur = val->contents; i < num_children; i++)
+ if (!cur)
{
- if (!cur)
- abort ();
- if (children [i]->core.being_destroyed
- || strcmp (XtName (children [i]), cur->name))
- continue;
- update_one_menu_entry (instance, children [i], cur, deep_p);
- cur = cur->next;
+ num_children_to_keep = i;
+ break;
}
- XtFree ((char *) children);
+ if (children [i]->core.being_destroyed
+ || strcmp (XtName (children [i]), cur->name))
+ continue;
+ update_one_menu_entry (instance, children [i], cur, deep_p);
+ cur = cur->next;
}
- if (cur)
- abort ();
}
+
+ /* Now replace from scratch all the buttons after the last
+ place that the top-level structure changed. */
+ if (val->contents->change == STRUCTURAL_CHANGE)
+ {
+ destroy_all_children (widget, num_children_to_keep);
+ make_menu_in_widget (instance, widget, val->contents,
+ num_children_to_keep);
+ }
+
+ XtFree ((char *) children);
}
\f
return widget;
}
+/* Create a menu bar. We turn off the f10 key
+ because we have not yet managed to make it work right in Motif. */
+
static Widget
make_menubar (instance)
widget_instance* instance;
{
- return XmCreateMenuBar (instance->parent, instance->info->name, NULL, 0);
+ Arg al[1];
+ int ac;
+
+ ac = 0;
+ XtSetArg(al[0], XmNmenuAccelerator, 0);
+ return XmCreateMenuBar (instance->parent, instance->info->name, al, 1);
}
static void
parent->core.window = parent_window;
return result;
}
+
static Widget
make_main (instance)
widget_instance* instance;
\f
/* motif callback */
-enum do_call_type { pre_activate, selection, no_selection, post_activate };
-
static void
do_call (widget, closure, type)
Widget widget;