X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/f25d58a47c5b869b9325e9b411151e128537b14e..51b23c448632f4947fb0e364b8f7d35b90c04e39:/lwlib/lwlib-Xm.c diff --git a/lwlib/lwlib-Xm.c b/lwlib/lwlib-Xm.c index 340c8fda78..ed203e26bf 100644 --- a/lwlib/lwlib-Xm.c +++ b/lwlib/lwlib-Xm.c @@ -1,22 +1,25 @@ /* The lwlib interface to Motif widgets. + Copyright (C) 1994, 1995, 1996, 1997, 1999, 2000, 2001, 2002, 2003, + 2004, 2005, 2006, 2007, 2008, 2009, 2010 + Free Software Foundation, Inc. Copyright (C) 1992 Lucid, Inc. This file is part of the Lucid Widget Library. -The Lucid Widget Library is free software; you can redistribute it and/or +The Lucid Widget Library is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 1, or (at your option) any later version. The Lucid Widget Library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of +but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Emacs; see the file COPYING. If not, write to -the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ +the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +Boston, MA 02110-1301, USA. */ #ifdef HAVE_CONFIG_H #include @@ -24,6 +27,7 @@ Boston, MA 02111-1307, USA. */ #include #include +#include #include #include @@ -31,6 +35,8 @@ Boston, MA 02111-1307, USA. */ #include #include +#include "../src/lisp.h" + #include "lwlib-Xm.h" #include "lwlib-utils.h" @@ -59,6 +65,7 @@ Boston, MA 02111-1307, USA. */ #include #include +#undef P_ #if defined __STDC__ || defined PROTOTYPES #define P_(X) X #else @@ -69,7 +76,7 @@ enum do_call_type { pre_activate, selection, no_selection, post_activate }; /* Structures to keep destroyed instances */ -typedef struct _destroyed_instance +typedef struct _destroyed_instance { char* name; char* type; @@ -139,6 +146,32 @@ void xm_manage_resizing P_ ((Widget, Boolean)); #endif +#if 0 + +/* Print the complete X resource name of widget WIDGET to stderr. + This is sometimes handy to have available. */ + +void +x_print_complete_resource_name (widget) + Widget widget; +{ + int i; + String names[100]; + + for (i = 0; i < 100 && widget != NULL; ++i) + { + names[i] = XtName (widget); + widget = XtParent (widget); + } + + for (--i; i >= 1; --i) + fprintf (stderr, "%s.", names[i]); + fprintf (stderr, "%s\n", names[0]); +} + +#endif /* 0 */ + + static destroyed_instance *all_destroyed_instances = NULL; static destroyed_instance* @@ -159,7 +192,7 @@ make_destroyed_instance (name, type, widget, parent, pop_up_p) instance->next = NULL; return instance; } - + static void free_destroyed_instance (instance) destroyed_instance* instance; @@ -181,7 +214,7 @@ Boolean lw_motif_widget_p (widget) Widget widget; { - return + return XtClass (widget) == xmDialogShellWidgetClass || XmIsPrimitive (widget) || XmIsManager (widget) || XmIsGadget (widget); } @@ -193,7 +226,7 @@ resource_motif_string (widget, name) { XtResource resource; XmString result = 0; - + resource.resource_name = name; resource.resource_class = XmCXmString; resource.resource_type = XmRXmString; @@ -225,7 +258,7 @@ destroy_all_children (widget, first_child_to_destroy) XtUnmanageChildren (children + first_child_to_destroy, number - first_child_to_destroy); - /* Unmanage all children and destroy them. They will only be + /* Unmanage all children and destroy them. They will only be really destroyed when we get out of DispatchEvent. */ for (i = first_child_to_destroy; i < number; i++) { @@ -236,10 +269,13 @@ destroy_all_children (widget, first_child_to_destroy) 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); + XtSetArg (al[0], XmNsubMenuId, &submenu); XtGetValues (children[i], al, 1); if (submenu) - XtDestroyWidget (submenu); + { + destroy_all_children (submenu, 0); + XtDestroyWidget (submenu); + } XtDestroyWidget (children[i]); } @@ -297,7 +333,7 @@ xm_arm_callback (w, client_data, call_data) 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 @@ -336,16 +372,16 @@ xm_update_label (instance, widget, val) else { built_string = - XmStringCreateLtoR (val->value, XmSTRING_DEFAULT_CHARSET); + XmStringCreateLocalized (val->value); XtSetArg (al [ac], XmNlabelString, built_string); ac++; } - + XtSetArg (al [ac], XmNlabelType, XmSTRING); ac++; } - + if (val->key) { - key_string = XmStringCreateLtoR (val->key, XmSTRING_DEFAULT_CHARSET); + key_string = XmStringCreateLocalized (val->key); XtSetArg (al [ac], XmNacceleratorText, key_string); ac++; } @@ -374,7 +410,7 @@ xm_update_list (instance, widget, val) for (cur = val->contents, i = 0; cur; cur = cur->next) if (cur->value) { - XmString xmstr = XmStringCreate (cur->value, XmSTRING_DEFAULT_CHARSET); + XmString xmstr = XmStringCreateLocalized (cur->value); i += 1; XmListAddItem (widget, xmstr, 0); if (cur->selected) @@ -490,10 +526,15 @@ make_menu_in_widget (instance, widget, val, keep_first_children) Widget* old_children; unsigned int old_num_children; + /* Disable drag and drop for labels in menu bar. */ + static char overrideTrans[] = ": Noop()"; + XtTranslations override = XtParseTranslationTable (overrideTrans); + old_children = XtCompositeChildren (widget, &old_num_children); /* Allocate the children array */ - for (num_children = 0, cur = val; cur; num_children++, cur = cur->next); + for (num_children = 0, cur = val; cur; num_children++, cur = cur->next) + ; children = (Widget*)XtMalloc (num_children * sizeof (Widget)); /* WIDGET should be a RowColumn. */ @@ -533,7 +574,7 @@ make_menu_in_widget (instance, widget, val, keep_first_children) 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 && !lw_separator_p (cur->name, &separator, 1)) { @@ -572,9 +613,9 @@ make_menu_in_widget (instance, widget, val, keep_first_children) XtAddCallback (button, XmNarmCallback, xm_arm_callback, cur); XtAddCallback (button, XmNdisarmCallback, xm_arm_callback, cur); } - + xm_update_label (instance, button, cur); - + /* Add a callback that is called when the button is selected. Toggle buttons don't support XmNactivateCallback, we use XmNvalueChangedCallback in @@ -597,6 +638,8 @@ make_menu_in_widget (instance, widget, val, keep_first_children) XtAddCallback (button, XmNcascadingCallback, xm_pull_down_callback, (XtPointer)instance); + XtOverrideTranslations (button, override); + } children[child_index] = button; @@ -610,12 +653,6 @@ make_menu_in_widget (instance, widget, val, keep_first_children) if (button) XtVaSetValues (widget, XmNmenuHelpWidget, button, NULL); - /* 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, NULL); - if (num_children) XtManageChildren (children, num_children); @@ -657,7 +694,7 @@ update_one_menu_entry (instance, widget, val, deep_p) menu = NULL; XtSetArg (al [ac], XmNsubMenuId, &menu); ac++; XtGetValues (widget, al, ac); - + contents = val->contents; if (!menu) @@ -688,8 +725,8 @@ update_one_menu_entry (instance, widget, val, deep_p) else { Widget button; - - /* The current menuitem is a XmPushButtonGadget, it + + /* 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); @@ -705,11 +742,14 @@ update_one_menu_entry (instance, widget, val, deep_p) #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); } + + if (widget_list) + XtFree ((char*) widget_list); } } else if (!contents) @@ -749,7 +789,7 @@ xm_update_menu (instance, widget, val, deep_p) { if (children) { - for (i = 0, cur = val->contents; + for (i = 0, cur = val->contents; (i < num_children && cur); /* how else to ditch unwanted children ?? - mgd */ i++, cur = cur->next) @@ -789,7 +829,7 @@ xm_update_menu (instance, widget, val, deep_p) { destroy_all_children (widget, num_children_to_keep); make_menu_in_widget (instance, widget, val->contents, - num_children_to_keep); + num_children_to_keep); } XtFree ((char *) children); @@ -837,18 +877,18 @@ xm_update_one_widget (instance, widget, val, deep_p) Boolean deep_p; { WidgetClass class; - + /* Mark as not edited */ val->edited = False; /* Common to all widget types */ XtSetSensitive (widget, val->enabled); XtVaSetValues (widget, XmNuserData, val->call_data, NULL); - + /* Common to all label like widgets */ if (XtIsSubclass (widget, xmLabelWidgetClass)) xm_update_label (instance, widget, val); - + class = XtClass (widget); /* Class specific things */ if (class == xmPushButtonWidgetClass || @@ -870,10 +910,10 @@ xm_update_one_widget (instance, widget, val, deep_p) Boolean radiobox = 0; int ac = 0; Arg al [1]; - + XtSetArg (al [ac], XmNradioBehavior, &radiobox); ac++; XtGetValues (widget, al, ac); - + if (radiobox) xm_update_radiobox (instance, widget, val); else @@ -910,7 +950,7 @@ xm_update_one_value (instance, widget, val) val->call_data = old_wv->call_data; break; } - + if (class == xmToggleButtonWidgetClass || class == xmToggleButtonGadgetClass) { XtVaGetValues (widget, XmNset, &val->selected, NULL); @@ -918,15 +958,13 @@ xm_update_one_value (instance, widget, val) } else if (class == xmTextWidgetClass) { - if (val->value) - free (val->value); + free (val->value); val->value = XmTextGetString (widget); val->edited = True; } else if (class == xmTextFieldWidgetClass) { - if (val->value) - free (val->value); + free (val->value); val->value = XmTextFieldGetString (widget); val->edited = True; } @@ -935,10 +973,10 @@ xm_update_one_value (instance, widget, val) Boolean radiobox = 0; int ac = 0; Arg al [1]; - + XtSetArg (al [ac], XmNradioBehavior, &radiobox); ac++; XtGetValues (widget, al, ac); - + if (radiobox) { CompositeWidget radio = (CompositeWidget)widget; @@ -947,12 +985,11 @@ xm_update_one_value (instance, widget, val) { int set = False; Widget toggle = radio->composite.children [i]; - + XtVaGetValues (toggle, XmNset, &set, NULL); if (set) { - if (val->value) - free (val->value); + free (val->value); val->value = safe_strdup (XtName (toggle)); } } @@ -990,7 +1027,7 @@ xm_update_one_value (instance, widget, val) /* This function is for activating a button from a program. It's wrong because we pass a NULL argument in the call_data which is not Motif compatible. This is used from the XmNdefaultAction callback of the List widgets to - have a double-click put down a dialog box like the button would do. + have a double-click put down a dialog box like the button would do. I could not find a way to do that with accelerators. */ static void @@ -1005,6 +1042,33 @@ activate_button (widget, closure, call_data) /* creation functions */ +/* Called for key press in dialogs. Used to pop down dialog on ESC. */ +static void +dialog_key_cb (widget, closure, event, continue_to_dispatch) + Widget widget; + XtPointer closure; + XEvent *event; + Boolean *continue_to_dispatch; +{ + KeySym sym = 0; + Modifiers modif_ret; + + XtTranslateKeycode (event->xkey.display, event->xkey.keycode, 0, + &modif_ret, &sym); + + if (sym == osfXK_Cancel) + { + Widget w = *((Widget *) closure); + + while (w && ! XtIsShell (w)) + w = XtParent (w); + + if (XtIsShell (w)) XtPopdown (w); + } + + *continue_to_dispatch = TRUE; +} + /* dialogs */ static Widget make_dialog (name, parent, pop_up_p, shell_title, icon_name, text_input_slot, @@ -1034,7 +1098,7 @@ make_dialog (name, parent, pop_up_p, shell_title, icon_name, text_input_slot, Arg al[64]; /* Arg List */ int ac; /* Arg Count */ int i; - + if (pop_up_p) { ac = 0; @@ -1059,9 +1123,9 @@ make_dialog (name, parent, pop_up_p, shell_title, icon_name, text_input_slot, n_children = left_buttons + right_buttons + 1; ac = 0; - XtSetArg(al[ac], XmNpacking, n_children == 3? + XtSetArg(al[ac], XmNpacking, n_children == 3? XmPACK_COLUMN: XmPACK_TIGHT); ac++; - XtSetArg(al[ac], XmNorientation, n_children == 3? + XtSetArg(al[ac], XmNorientation, n_children == 3? XmVERTICAL: XmHORIZONTAL); ac++; XtSetArg(al[ac], XmNnumColumns, left_buttons + right_buttons + 1); ac++; XtSetArg(al[ac], XmNmarginWidth, 0); ac++; @@ -1078,7 +1142,7 @@ make_dialog (name, parent, pop_up_p, shell_title, icon_name, text_input_slot, XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++; XtSetArg(al[ac], XmNrightOffset, 13); ac++; row = XmCreateRowColumn (form, "row", al, ac); - + n_children = 0; for (i = 0; i < left_buttons; i++) { @@ -1093,6 +1157,8 @@ make_dialog (name, parent, pop_up_p, shell_title, icon_name, text_input_slot, XtSetArg(al[ac], XmNmarginWidth, 10); ac++; XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; children [n_children] = XmCreatePushButton (row, button_name, al, ac); + XtAddEventHandler (children [n_children], + KeyPressMask, False, dialog_key_cb, result); if (i == 0) { @@ -1110,7 +1176,7 @@ make_dialog (name, parent, pop_up_p, shell_title, icon_name, text_input_slot, XtSetArg (al[ac], XmNmappedWhenManaged, FALSE); ac++; children [n_children] = XmCreateLabel (row, "separator_button", al, ac); n_children++; - + for (i = 0; i < right_buttons; i++) { char button_name [16]; @@ -1119,12 +1185,15 @@ make_dialog (name, parent, pop_up_p, shell_title, icon_name, text_input_slot, XtSetArg(al[ac], XmNmarginWidth, 10); ac++; XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; children [n_children] = XmCreatePushButton (row, button_name, al, ac); + XtAddEventHandler (children [n_children], + KeyPressMask, False, dialog_key_cb, result); + if (! button) button = children [n_children]; n_children++; } - + XtManageChildren (children, n_children); - + ac = 0; XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++; XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++; @@ -1220,7 +1289,7 @@ make_dialog (name, parent, pop_up_p, shell_title, icon_name, text_input_slot, list activate the default button */ XtAddCallback (value, XmNdefaultActionCallback, activate_button, button); } - + ac = 0; XtSetArg(al[ac], XmNalignment, XmALIGNMENT_BEGINNING); ac++; XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++; @@ -1235,7 +1304,7 @@ make_dialog (name, parent, pop_up_p, shell_title, icon_name, text_input_slot, XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++; XtSetArg(al[ac], XmNrightOffset, 13); ac++; message = XmCreateLabel (form, "message", al, ac); - + if (list) XtManageChild (value); @@ -1250,7 +1319,7 @@ make_dialog (name, parent, pop_up_p, shell_title, icon_name, text_input_slot, children [i] = icon; i++; children [i] = icon_separator; i++; XtManageChildren (children, i); - + if (text_input_slot || list) { XtInstallAccelerators (value, button); @@ -1261,7 +1330,7 @@ make_dialog (name, parent, pop_up_p, shell_title, icon_name, text_input_slot, XtInstallAccelerators (form, button); XtSetKeyboardFocus (result, button); } - + return result; } @@ -1334,7 +1403,7 @@ recenter_widget (widget) x = (((Position)parent_width) - ((Position)child_width)) / 2; y = (((Position)parent_height) - ((Position)child_height)) / 2; - + XtTranslateCoords (parent, x, y, &x, &y); if (x + child_width > screen_width) @@ -1374,7 +1443,7 @@ recycle_instance (instance) focus = XtNameToWidget (widget, "*button1"); if (focus) XtSetKeyboardFocus (widget, focus); - + /* shrink the separator label back to their original size */ separator = XtNameToWidget (widget, "*separator_button"); if (separator) @@ -1442,7 +1511,7 @@ xm_create_dialog (instance) shell_name = "Question"; break; } - + total_buttons = name [1] - '0'; if (name [3] == 'T' || name [3] == 't') @@ -1452,15 +1521,16 @@ xm_create_dialog (instance) } else if (name [3]) right_buttons = name [4] - '0'; - + left_buttons = total_buttons - right_buttons; - + widget = make_dialog (name, parent, pop_up_p, shell_name, icon_name, text_input_slot, radio_box, list, left_buttons, right_buttons); XtAddCallback (widget, XmNpopdownCallback, xm_nosel_callback, (XtPointer) instance); + return widget; } @@ -1625,7 +1695,7 @@ make_project_display_dialog (widget_instance* instance) #endif /* ENERGIZE */ widget_creation_entry -xm_creation_table [] = +xm_creation_table [] = { {"menubar", make_menubar}, {"popup", make_popup_menu}, @@ -1714,7 +1784,7 @@ xm_popup_menu (widget, event) /* This is so totally ridiculous: there's NO WAY to tell Motif that *any* button can select a menu item. Only one button can have that honor. */ - + char *trans = 0; if (event->xbutton.state & Button5Mask) trans = ""; else if (event->xbutton.state & Button4Mask) trans = ""; @@ -1724,10 +1794,10 @@ xm_popup_menu (widget, event) if (trans) XtVaSetValues (widget, XmNmenuPost, trans, NULL); } #endif - + XmMenuPosition (widget, (XButtonPressedEvent *) event); } - + XtManageChild (widget); } @@ -1765,12 +1835,12 @@ xm_pop_instance (instance, up) if (up) XtManageChild (widget); else - XtUnmanageChild (widget); + XtUnmanageChild (widget); } } -/* motif callback */ +/* motif callback */ static void do_call (widget, closure, type) @@ -1799,36 +1869,36 @@ do_call (widget, closure, type) user_data = NULL; XtSetArg (al [ac], XmNuserData, &user_data); ac++; XtGetValues (widget, al, ac); - + switch (type) { case pre_activate: if (instance->info->pre_activate_cb) instance->info->pre_activate_cb (widget, id, user_data); break; - + case selection: if (instance->info->selection_cb) instance->info->selection_cb (widget, id, user_data); break; - + case no_selection: if (instance->info->selection_cb) instance->info->selection_cb (widget, id, (XtPointer) -1); break; - + case post_activate: if (instance->info->post_activate_cb) instance->info->post_activate_cb (widget, id, user_data); break; - + default: abort (); } } /* Like lw_internal_update_other_instances except that it does not do - anything if its shell parent is not managed. This is to protect + anything if its shell parent is not managed. This is to protect lw_internal_update_other_instances to dereference freed memory if the widget was ``destroyed'' by caching it in the all_destroyed_instances list */ @@ -1894,7 +1964,7 @@ xm_pull_down_callback (widget, closure, call_data) /* XmNpopdownCallback for MenuShell widgets. WIDGET is the MenuShell, - CLOSURE is a pointer to the widget_instance of the shell, + CLOSURE is a pointer to the widget_instance of the shell, Note that this callback is called for each cascade button in a menu, whether or not its submenu is visible. */ @@ -1906,7 +1976,6 @@ xm_pop_down_callback (widget, closure, call_data) XtPointer call_data; { widget_instance *instance = (widget_instance *) closure; - fprintf (stderr, "%p\n", call_data); if ((!instance->pop_up_p && XtParent (widget) == instance->widget) || XtParent (widget) == instance->parent) @@ -1947,3 +2016,6 @@ xm_manage_resizing (w, flag) { XtVaSetValues (w, XtNallowShellResize, flag, NULL); } + +/* arch-tag: 73976f64-73b2-4600-aa13-d9ede20ee965 + (do not change this comment) */