1/* The lwlib interface to Motif widgets. 2 Copyright (C) 1994, 1995, 1996, 1997, 1999, 2000, 2001, 2002, 2003, 3 2004, 2005, 2006, 2007 Free Software Foundation, Inc. 4 Copyright (C) 1992 Lucid, Inc. 5 6This file is part of the Lucid Widget Library. 7 8The Lucid Widget Library is free software; you can redistribute it and/or 9modify it under the terms of the GNU General Public License as published by 10the Free Software Foundation; either version 1, or (at your option) 11any later version. 12 13The Lucid Widget Library is distributed in the hope that it will be useful, 14but WITHOUT ANY WARRANTY; without even the implied warranty of 15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16GNU General Public License for more details. 17 18You should have received a copy of the GNU General Public License 19along with GNU Emacs; see the file COPYING. If not, write to 20the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 21Boston, MA 02110-1301, USA. */ 22 23#ifdef HAVE_CONFIG_H 24#include <config.h> 25#endif 26 27#include <unistd.h> 28#include <stdio.h> 29 30#include <X11/StringDefs.h> 31#include <X11/IntrinsicP.h> 32#include <X11/ObjectP.h> 33#include <X11/CoreP.h> 34#include <X11/CompositeP.h> 35 36#include "../src/lisp.h" 37 38#include "lwlib-Xm.h" 39#include "lwlib-utils.h" 40 41#include <Xm/BulletinB.h> 42#include <Xm/CascadeB.h> 43#include <Xm/CascadeBG.h> 44#include <Xm/DrawingA.h> 45#include <Xm/FileSB.h> 46#include <Xm/Label.h> 47#include <Xm/List.h> 48#include <Xm/MainW.h> 49#include <Xm/MenuShell.h> 50#include <Xm/MessageB.h> 51#include <Xm/PanedW.h> 52#include <Xm/PushB.h> 53#include <Xm/PushBG.h> 54#include <Xm/ArrowB.h> 55#include <Xm/SelectioB.h> 56#include <Xm/Text.h> 57#include <Xm/TextF.h> 58#include <Xm/ToggleB.h> 59#include <Xm/ToggleBG.h> 60#include <Xm/RowColumn.h> 61#include <Xm/ScrolledW.h> 62#include <Xm/Separator.h> 63#include <Xm/DialogS.h> 64#include <Xm/Form.h> 65 66#undef P_ 67#if defined __STDC__ || defined PROTOTYPES 68#define P_(X) X 69#else 70#define P_(X) () 71#endif 72 73enum do_call_type { pre_activate, selection, no_selection, post_activate }; 74 75 76/* Structures to keep destroyed instances */ 77typedef struct _destroyed_instance 78{ 79 char* name; 80 char* type; 81 Widget widget; 82 Widget parent; 83 Boolean pop_up_p; 84 struct _destroyed_instance* next; 85} destroyed_instance; 86 87static destroyed_instance *make_destroyed_instance P_ ((char *, char *, 88 Widget, Widget, 89 Boolean)); 90static void free_destroyed_instance P_ ((destroyed_instance*)); 91Widget first_child P_ ((Widget)); 92Boolean lw_motif_widget_p P_ ((Widget)); 93static XmString resource_motif_string P_ ((Widget, char *)); 94static void destroy_all_children P_ ((Widget, int)); 95static void xm_update_label P_ ((widget_instance *, Widget, widget_value *)); 96static void xm_update_list P_ ((widget_instance *, Widget, widget_value *)); 97static void xm_update_pushbutton P_ ((widget_instance *, Widget, 98 widget_value *)); 99static void xm_update_cascadebutton P_ ((widget_instance *, Widget, 100 widget_value *)); 101static void xm_update_toggle P_ ((widget_instance *, Widget, widget_value *)); 102static void xm_update_radiobox P_ ((widget_instance *, Widget, widget_value *)); 103static void make_menu_in_widget P_ ((widget_instance *, Widget, 104 widget_value *, int)); 105static void update_one_menu_entry P_ ((widget_instance *, Widget, 106 widget_value *, Boolean)); 107static void xm_update_menu P_ ((widget_instance *, Widget, widget_value *, 108 Boolean)); 109static void xm_update_text P_ ((widget_instance *, Widget, widget_value *)); 110static void xm_update_text_field P_ ((widget_instance *, Widget, 111 widget_value *)); 112void xm_update_one_value P_ ((widget_instance *, Widget, widget_value *)); 113static void activate_button P_ ((Widget, XtPointer, XtPointer)); 114static Widget make_dialog P_ ((char *, Widget, Boolean, char *, char *, 115 Boolean, Boolean, Boolean, int, int)); 116static destroyed_instance* find_matching_instance P_ ((widget_instance*)); 117static void mark_dead_instance_destroyed P_ ((Widget, XtPointer, XtPointer)); 118static void recenter_widget P_ ((Widget)); 119static Widget recycle_instance P_ ((destroyed_instance*)); 120Widget xm_create_dialog P_ ((widget_instance*)); 121static Widget make_menubar P_ ((widget_instance*)); 122static void remove_grabs P_ ((Widget, XtPointer, XtPointer)); 123static Widget make_popup_menu P_ ((widget_instance*)); 124static Widget make_main P_ ((widget_instance*)); 125void xm_destroy_instance P_ ((widget_instance*)); 126void xm_popup_menu P_ ((Widget, XEvent *)); 127static void set_min_dialog_size P_ ((Widget)); 128static void do_call P_ ((Widget, XtPointer, enum do_call_type)); 129static void xm_generic_callback P_ ((Widget, XtPointer, XtPointer)); 130static void xm_nosel_callback P_ ((Widget, XtPointer, XtPointer)); 131static void xm_pull_down_callback P_ ((Widget, XtPointer, XtPointer)); 132static void xm_pop_down_callback P_ ((Widget, XtPointer, XtPointer)); 133void xm_set_keyboard_focus P_ ((Widget, Widget)); 134void xm_set_main_areas P_ ((Widget, Widget, Widget)); 135static void xm_internal_update_other_instances P_ ((Widget, XtPointer, 136 XtPointer)); 137static void xm_arm_callback P_ ((Widget, XtPointer, XtPointer)); 138 139#if 0 140void xm_update_one_widget P_ ((widget_instance *, Widget, widget_value *, 141 Boolean)); 142void xm_pop_instance P_ ((widget_instance*, Boolean)); 143void xm_manage_resizing P_ ((Widget, Boolean)); 144#endif 145 146 147#if 0 148 149/* Print the complete X resource name of widget WIDGET to stderr. 150 This is sometimes handy to have available. */ 151 152void 153x_print_complete_resource_name (widget) 154 Widget widget; 155{ 156 int i; 157 String names[100]; 158 159 for (i = 0; i < 100 && widget != NULL; ++i) 160 { 161 names[i] = XtName (widget); 162 widget = XtParent (widget); 163 } 164 165 for (--i; i >= 1; --i) 166 fprintf (stderr, "%s.", names[i]); 167 fprintf (stderr, "%s\n", names[0]); 168} 169 170#endif /* 0 */ 171 172 173static destroyed_instance *all_destroyed_instances = NULL; 174 175static destroyed_instance* 176make_destroyed_instance (name, type, widget, parent, pop_up_p) 177 char* name; 178 char* type; 179 Widget widget; 180 Widget parent; 181 Boolean pop_up_p; 182{ 183 destroyed_instance* instance = 184 (destroyed_instance*)malloc (sizeof (destroyed_instance)); 185 instance->name = safe_strdup (name); 186 instance->type = safe_strdup (type); 187 instance->widget = widget; 188 instance->parent = parent; 189 instance->pop_up_p = pop_up_p; 190 instance->next = NULL; 191 return instance; 192} 193 194static void 195free_destroyed_instance (instance) 196 destroyed_instance* instance; 197{ 198 free (instance->name); 199 free (instance->type); 200 free (instance); 201} 202 203/* motif utility functions */ 204Widget 205first_child (widget) 206 Widget widget; 207{ 208 return ((CompositeWidget)widget)->composite.children [0]; 209} 210 211Boolean 212lw_motif_widget_p (widget) 213 Widget widget; 214{ 215 return 216 XtClass (widget) == xmDialogShellWidgetClass 217 || XmIsPrimitive (widget) || XmIsManager (widget) || XmIsGadget (widget); 218} 219 220static XmString 221resource_motif_string (widget, name) 222 Widget widget; 223 char* name; 224{ 225 XtResource resource; 226 XmString result = 0; 227 228 resource.resource_name = name; 229 resource.resource_class = XmCXmString; 230 resource.resource_type = XmRXmString; 231 resource.resource_size = sizeof (XmString); 232 resource.resource_offset = 0; 233 resource.default_type = XtRImmediate; 234 resource.default_addr = 0; 235 236 XtGetSubresources (widget, (XtPointer)&result, "dialogString", 237 "DialogString", &resource, 1, NULL, 0); 238 return result; 239} 240 241/* Destroy all of the children of WIDGET 242 starting with number FIRST_CHILD_TO_DESTROY. */ 243 244static void 245destroy_all_children (widget, first_child_to_destroy) 246 Widget widget; 247 int first_child_to_destroy; 248{ 249 Widget* children; 250 unsigned int number; 251 int i; 252 253 children = XtCompositeChildren (widget, &number); 254 if (children) 255 { 256 XtUnmanageChildren (children + first_child_to_destroy, 257 number - first_child_to_destroy); 258 259 /* Unmanage all children and destroy them. They will only be 260 really destroyed when we get out of DispatchEvent. */ 261 for (i = first_child_to_destroy; i < number; i++) 262 { 263 Arg al[2]; 264 Widget submenu = 0; 265 /* Cascade buttons have submenus,and these submenus 266 need to be freed. But they are not included in 267 XtCompositeChildren. So get it out of the cascade button 268 and free it. If this child is not a cascade button, 269 then submenu should remain unchanged. */ 270 XtSetArg (al[0], XmNsubMenuId, &submenu); 271 XtGetValues (children[i], al, 1); 272 if (submenu) 273 { 274 destroy_all_children (submenu, 0); 275 XtDestroyWidget (submenu); 276 } 277 XtDestroyWidget (children[i]); 278 } 279 280 XtFree ((char *) children); 281 } 282} 283 284 285 286/* Callback XmNarmCallback and XmNdisarmCallback for buttons in a 287 menu. CLIENT_DATA contains a pointer to the widget_value 288 corresponding to widget W. CALL_DATA contains a 289 XmPushButtonCallbackStruct containing the reason why the callback 290 is called. */ 291 292static void 293xm_arm_callback (w, client_data, call_data) 294 Widget w; 295 XtPointer client_data, call_data; 296{ 297 XmPushButtonCallbackStruct *cbs = (XmPushButtonCallbackStruct *) call_data; 298 widget_value *wv = (widget_value *) client_data; 299 widget_instance *instance; 300 301 /* Get the id of the menu bar or popup menu this widget is in. */ 302 while (w != NULL) 303 { 304 if (XmIsRowColumn (w)) 305 { 306 unsigned char type = 0xff; 307 308 XtVaGetValues (w, XmNrowColumnType, &type, NULL); 309 if (type == XmMENU_BAR || type == XmMENU_POPUP) 310 break; 311 } 312 313 w = XtParent (w); 314 } 315 316 if (w != NULL) 317 { 318 instance = lw_get_widget_instance (w); 319 if (instance && instance->info->highlight_cb) 320 { 321 call_data = cbs->reason == XmCR_DISARM ? NULL : wv; 322 instance->info->highlight_cb (w, instance->info->id, call_data); 323 } 324 } 325} 326 327 328 329/* Update the label of widget WIDGET. WIDGET must be a Label widget 330 or a subclass of Label. WIDGET_INSTANCE is unused. VAL contains 331 the value to update. 332 333 Menus: 334 335 Emacs fills VAL->name with the text to display in the menu, and 336 sets VAL->value to null. Function make_menu_in_widget creates 337 widgets with VAL->name as resource name. This works because the 338 Label widget uses its resource name for display if no 339 XmNlabelString is set. 340 341 Dialogs: 342 343 VAL->name is again set to the resource name, but VAL->value is 344 not null, and contains the label string to display. */ 345 346static void 347xm_update_label (instance, widget, val) 348 widget_instance* instance; 349 Widget widget; 350 widget_value* val; 351{ 352 XmString res_string = 0; 353 XmString built_string = 0; 354 XmString key_string = 0; 355 Arg al [256]; 356 int ac; 357 358 ac = 0; 359 360 if (val->value) 361 { 362 /* A label string is specified, i.e. we are in a dialog. First 363 see if it is overridden by something from the resource file. */ 364 res_string = resource_motif_string (widget, val->value); 365 366 if (res_string) 367 { 368 XtSetArg (al [ac], XmNlabelString, res_string); ac++; 369 } 370 else 371 { 372 built_string = 373 XmStringCreateLocalized (val->value); 374 XtSetArg (al [ac], XmNlabelString, built_string); ac++; 375 } 376 377 XtSetArg (al [ac], XmNlabelType, XmSTRING); ac++; 378 } 379 380 if (val->key) 381 { 382 key_string = XmStringCreateLocalized (val->key); 383 XtSetArg (al [ac], XmNacceleratorText, key_string); ac++; 384 } 385 386 if (ac) 387 XtSetValues (widget, al, ac); 388 389 if (built_string) 390 XmStringFree (built_string); 391 392 if (key_string) 393 XmStringFree (key_string); 394} 395 396/* update of list */ 397static void 398xm_update_list (instance, widget, val) 399 widget_instance* instance; 400 Widget widget; 401 widget_value* val; 402{ 403 widget_value* cur; 404 int i; 405 XtRemoveAllCallbacks (widget, XmNsingleSelectionCallback); 406 XtAddCallback (widget, XmNsingleSelectionCallback, xm_generic_callback, 407 instance); 408 for (cur = val->contents, i = 0; cur; cur = cur->next) 409 if (cur->value) 410 { 411 XmString xmstr = XmStringCreateLocalized (cur->value); 412 i += 1; 413 XmListAddItem (widget, xmstr, 0); 414 if (cur->selected) 415 XmListSelectPos (widget, i, False); 416 XmStringFree (xmstr); 417 } 418} 419 420/* update of buttons */ 421static void 422xm_update_pushbutton (instance, widget, val) 423 widget_instance* instance; 424 Widget widget; 425 widget_value* val; 426{ 427 XtVaSetValues (widget, XmNalignment, XmALIGNMENT_CENTER, NULL); 428 XtRemoveAllCallbacks (widget, XmNactivateCallback); 429 XtAddCallback (widget, XmNactivateCallback, xm_generic_callback, instance); 430} 431 432static void 433xm_update_cascadebutton (instance, widget, val) 434 widget_instance* instance; 435 Widget widget; 436 widget_value* val; 437{ 438 /* Should also rebuild the menu by calling ...update_menu... */ 439 XtRemoveAllCallbacks (widget, XmNcascadingCallback); 440 XtAddCallback (widget, XmNcascadingCallback, xm_pull_down_callback, 441 instance); 442} 443 444/* update toggle and radiobox */ 445static void 446xm_update_toggle (instance, widget, val) 447 widget_instance* instance; 448 Widget widget; 449 widget_value* val; 450{ 451 XtRemoveAllCallbacks (widget, XmNvalueChangedCallback); 452 XtAddCallback (widget, XmNvalueChangedCallback, 453 xm_generic_callback, instance); 454 XtVaSetValues (widget, XmNset, val->selected, 455 XmNalignment, XmALIGNMENT_BEGINNING, NULL); 456} 457 458static void 459xm_update_radiobox (instance, widget, val) 460 widget_instance* instance; 461 Widget widget; 462 widget_value* val; 463 464{ 465 Widget toggle; 466 widget_value* cur; 467 468 /* update the callback */ 469 XtRemoveAllCallbacks (widget, XmNentryCallback); 470 XtAddCallback (widget, XmNentryCallback, xm_generic_callback, instance); 471 472 /* first update all the toggles */ 473 /* Energize kernel interface is currently bad. It sets the selected widget 474 with the selected flag but returns it by its name. So we currently 475 have to support both setting the selection with the selected slot 476 of val contents and setting it with the "value" slot of val. The latter 477 has a higher priority. This to be removed when the kernel is fixed. */ 478 for (cur = val->contents; cur; cur = cur->next) 479 { 480 toggle = XtNameToWidget (widget, cur->value); 481 if (toggle) 482 { 483 XtSetSensitive (toggle, cur->enabled); 484 if (!val->value && cur->selected) 485 XtVaSetValues (toggle, XmNset, cur->selected, NULL); 486 if (val->value && strcmp (val->value, cur->value)) 487 XtVaSetValues (toggle, XmNset, False, NULL); 488 } 489 } 490 491 /* The selected was specified by the value slot */ 492 if (val->value) 493 { 494 toggle = XtNameToWidget (widget, val->value); 495 if (toggle) 496 XtVaSetValues (toggle, XmNset, True, NULL); 497 } 498} 499 500 501/* update a popup menu, pulldown menu or a menubar */ 502 503/* KEEP_FIRST_CHILDREN gives the number of initial children to keep. */ 504 505static void 506make_menu_in_widget (instance, widget, val, keep_first_children) 507 widget_instance* instance; 508 Widget widget; 509 widget_value* val; 510 int keep_first_children; 511{ 512 Widget* children = 0; 513 int num_children; 514 int child_index; 515 widget_value* cur; 516 Widget button = 0; 517 Widget title = 0; 518 Widget menu; 519 Arg al [256]; 520 int ac; 521 Boolean menubar_p; 522 unsigned char type; 523 524 Widget* old_children; 525 unsigned int old_num_children; 526 527 /* Disable drag and drop for labels in menu bar. */ 528 static char overrideTrans[] = "<Btn2Down>: Noop()"; 529 XtTranslations override = XtParseTranslationTable (overrideTrans); 530 531 old_children = XtCompositeChildren (widget, &old_num_children); 532 533 /* Allocate the children array */ 534 for (num_children = 0, cur = val; cur; num_children++, cur = cur->next) 535 ; 536 children = (Widget*)XtMalloc (num_children * sizeof (Widget)); 537 538 /* WIDGET should be a RowColumn. */ 539 if (!XmIsRowColumn (widget)) 540 abort (); 541 542 /* Determine whether WIDGET is a menu bar. */ 543 type = -1; 544 XtSetArg (al[0], XmNrowColumnType, &type); 545 XtGetValues (widget, al, 1); 546 if (type != XmMENU_BAR && type != XmMENU_PULLDOWN && type != XmMENU_POPUP) 547 abort (); 548 menubar_p = type == XmMENU_BAR; 549 550 /* Add a callback to popups and pulldowns that is called when 551 it is made invisible again. */ 552 if (!menubar_p) 553 XtAddCallback (XtParent (widget), XmNpopdownCallback, 554 xm_pop_down_callback, (XtPointer)instance); 555 556 /* Preserve the first KEEP_FIRST_CHILDREN old children. */ 557 for (child_index = 0, cur = val; child_index < keep_first_children; 558 child_index++, cur = cur->next) 559 children[child_index] = old_children[child_index]; 560 561 /* Check that those are all we have 562 (the caller should have deleted the rest). */ 563 if (old_num_children != keep_first_children) 564 abort (); 565 566 /* Create the rest. */ 567 for (child_index = keep_first_children; cur; child_index++, cur = cur->next) 568 { 569 enum menu_separator separator; 570 571 ac = 0; 572 XtSetArg (al[ac], XmNsensitive, cur->enabled); ac++; 573 XtSetArg (al[ac], XmNalignment, XmALIGNMENT_BEGINNING); ac++; 574 XtSetArg (al[ac], XmNuserData, cur->call_data); ac++; 575 576 if (instance->pop_up_p && !cur->contents && !cur->call_data 577 && !lw_separator_p (cur->name, &separator, 1)) 578 { 579 ac = 0; 580 XtSetArg (al[ac], XmNalignment, XmALIGNMENT_CENTER); ac++; 581 title = button = XmCreateLabel (widget, cur->name, al, ac); 582 } 583 else if (lw_separator_p (cur->name, &separator, 1)) 584 { 585 ac = 0; 586 XtSetArg (al[ac], XmNseparatorType, separator); ++ac; 587 button = XmCreateSeparator (widget, cur->name, al, ac); 588 } 589 else if (!cur->contents) 590 { 591 if (menubar_p) 592 button = XmCreateCascadeButton (widget, cur->name, al, ac); 593 else if (!cur->call_data) 594 button = XmCreateLabel (widget, cur->name, al, ac); 595 else if (cur->button_type == BUTTON_TYPE_TOGGLE 596 || cur->button_type == BUTTON_TYPE_RADIO) 597 { 598 XtSetArg (al[ac], XmNset, cur->selected); ++ac; 599 XtSetArg (al[ac], XmNvisibleWhenOff, True); ++ac; 600 XtSetArg (al[ac], XmNindicatorType, 601 (cur->button_type == BUTTON_TYPE_TOGGLE 602 ? XmN_OF_MANY : XmONE_OF_MANY)); 603 ++ac; 604 button = XmCreateToggleButton (widget, cur->name, al, ac); 605 XtAddCallback (button, XmNarmCallback, xm_arm_callback, cur); 606 XtAddCallback (button, XmNdisarmCallback, xm_arm_callback, cur); 607 } 608 else 609 { 610 button = XmCreatePushButton (widget, cur->name, al, ac); 611 XtAddCallback (button, XmNarmCallback, xm_arm_callback, cur); 612 XtAddCallback (button, XmNdisarmCallback, xm_arm_callback, cur); 613 } 614 615 xm_update_label (instance, button, cur); 616 617 /* Add a callback that is called when the button is 618 selected. Toggle buttons don't support 619 XmNactivateCallback, we use XmNvalueChangedCallback in 620 that case. Don't add a callback to a simple label. */ 621 if (cur->button_type) 622 xm_update_toggle (instance, button, cur); 623 else if (cur->call_data) 624 XtAddCallback (button, XmNactivateCallback, xm_generic_callback, 625 (XtPointer)instance); 626 } 627 else 628 { 629 menu = XmCreatePulldownMenu (widget, cur->name, NULL, 0); 630 631 make_menu_in_widget (instance, menu, cur->contents, 0); 632 XtSetArg (al[ac], XmNsubMenuId, menu); ac++; 633 button = XmCreateCascadeButton (widget, cur->name, al, ac); 634 635 xm_update_label (instance, button, cur); 636 637 XtAddCallback (button, XmNcascadingCallback, xm_pull_down_callback, 638 (XtPointer)instance); 639 XtOverrideTranslations (button, override); 640 641 } 642 643 children[child_index] = button; 644 } 645 646 /* Last entry is the help button. The original comment read "Has to 647 be done after managing the buttons otherwise the menubar is only 648 4 pixels high." This is no longer true, and to make 649 XmNmenuHelpWidget work, we need to set it before managing the 650 children.. --gerd. */ 651 if (button) 652 XtVaSetValues (widget, XmNmenuHelpWidget, button, NULL); 653 654 if (num_children) 655 XtManageChildren (children, num_children); 656 657 XtFree ((char *) children); 658 if (old_children) 659 XtFree ((char *) old_children); 660} 661 662static void 663update_one_menu_entry (instance, widget, val, deep_p) 664 widget_instance* instance; 665 Widget widget; 666 widget_value* val; 667 Boolean deep_p; 668{ 669 Arg al [256]; 670 int ac; 671 Widget menu; 672 widget_value* contents; 673 674 if (val->this_one_change == NO_CHANGE) 675 return; 676 677 /* update the sensitivity and userdata */ 678 /* Common to all widget types */ 679 XtSetSensitive (widget, val->enabled); 680 XtVaSetValues (widget, XmNuserData, val->call_data, NULL); 681 682 /* update the menu button as a label. */ 683 if (val->this_one_change >= VISIBLE_CHANGE) 684 { 685 xm_update_label (instance, widget, val); 686 if (val->button_type) 687 xm_update_toggle (instance, widget, val); 688 } 689 690 /* update the pulldown/pullaside as needed */ 691 ac = 0; 692 menu = NULL; 693 XtSetArg (al [ac], XmNsubMenuId, &menu); ac++; 694 XtGetValues (widget, al, ac); 695 696 contents = val->contents; 697 698 if (!menu) 699 { 700 if (contents) 701 { 702 unsigned int old_num_children, i; 703 Widget parent; 704 Widget *widget_list; 705 706 parent = XtParent (widget); 707 widget_list = XtCompositeChildren (parent, &old_num_children); 708 709 /* Find the widget position within the parent's widget list. */ 710 for (i = 0; i < old_num_children; i++) 711 if (strcmp (XtName (widget_list[i]), XtName (widget)) == 0) 712 break; 713 if (i == old_num_children) 714 abort (); 715 if (XmIsCascadeButton (widget_list[i])) 716 { 717 menu = XmCreatePulldownMenu (parent, XtName(widget), NULL, 0); 718 make_menu_in_widget (instance, menu, contents, 0); 719 ac = 0; 720 XtSetArg (al [ac], XmNsubMenuId, menu); ac++; 721 XtSetValues (widget, al, ac); 722 } 723 else 724 { 725 Widget button; 726 727 /* The current menuitem is a XmPushButtonGadget, it 728 needs to be replaced by a CascadeButtonGadget */ 729 XtDestroyWidget (widget_list[i]); 730 menu = XmCreatePulldownMenu (parent, val->name, NULL, 0); 731 make_menu_in_widget (instance, menu, contents, 0); 732 ac = 0; 733 XtSetArg (al [ac], XmNsubMenuId, menu); ac++; 734 /* Non-zero values don't work reliably in 735 conjunction with Emacs' event loop */ 736 XtSetArg (al [ac], XmNmappingDelay, 0); ac++; 737#ifdef XmNpositionIndex /* This is undefined on SCO ODT 2.0. */ 738 /* Tell Motif to put it in the right place */ 739 XtSetArg (al [ac], XmNpositionIndex , i); ac++; 740#endif 741 button = XmCreateCascadeButton (parent, val->name, al, ac); 742 xm_update_label (instance, button, val); 743 744 XtAddCallback (button, XmNcascadingCallback, xm_pull_down_callback, 745 (XtPointer)instance); 746 XtManageChild (button); 747 } 748 749 if (widget_list) 750 XtFree ((char*) widget_list); 751 } 752 } 753 else if (!contents) 754 { 755 ac = 0; 756 XtSetArg (al [ac], XmNsubMenuId, NULL); ac++; 757 XtSetValues (widget, al, ac); 758 XtDestroyWidget (menu); 759 } 760 else if (deep_p && contents->change != NO_CHANGE) 761 xm_update_menu (instance, menu, val, 1); 762} 763 764static void 765xm_update_menu (instance, widget, val, deep_p) 766 widget_instance* instance; 767 Widget widget; 768 widget_value* val; 769 Boolean deep_p; 770{ 771 Widget* children; 772 unsigned int num_children; 773 int num_children_to_keep = 0; 774 int i; 775 widget_value* cur; 776 777 children = XtCompositeChildren (widget, &num_children); 778 779 /* Widget is a RowColumn widget whose contents have to be updated 780 * to reflect the list of items in val->contents */ 781 782 /* See how many buttons we can keep, and how many we 783 must completely replace. */ 784 if (val->contents == 0) 785 num_children_to_keep = 0; 786 else if (val->contents->change == STRUCTURAL_CHANGE) 787 { 788 if (children) 789 { 790 for (i = 0, cur = val->contents; 791 (i < num_children 792 && cur); /* how else to ditch unwanted children ?? - mgd */ 793 i++, cur = cur->next) 794 { 795 if (cur->this_one_change == STRUCTURAL_CHANGE) 796 break; 797 } 798 799 num_children_to_keep = i; 800 } 801 } 802 else 803 num_children_to_keep = num_children; 804 805 /* Update all the buttons of the RowColumn, in order, 806 except for those we are going to replace entirely. */ 807 if (children) 808 { 809 for (i = 0, cur = val->contents; i < num_children_to_keep; i++) 810 { 811 if (!cur) 812 { 813 num_children_to_keep = i; 814 break; 815 } 816 if (children [i]->core.being_destroyed 817 || strcmp (XtName (children [i]), cur->name)) 818 continue; 819 update_one_menu_entry (instance, children [i], cur, deep_p); 820 cur = cur->next; 821 } 822 } 823 824 /* Now replace from scratch all the buttons after the last 825 place that the top-level structure changed. */ 826 if (val->contents->change == STRUCTURAL_CHANGE) 827 { 828 destroy_all_children (widget, num_children_to_keep); 829 make_menu_in_widget (instance, widget, val->contents, 830 num_children_to_keep); 831 } 832 833 XtFree ((char *) children); 834} 835 836 837/* update text widgets */ 838 839static void 840xm_update_text (instance, widget, val) 841 widget_instance* instance; 842 Widget widget; 843 widget_value* val; 844{ 845 XmTextSetString (widget, val->value ? val->value : ""); 846 XtRemoveAllCallbacks (widget, XmNactivateCallback); 847 XtAddCallback (widget, XmNactivateCallback, xm_generic_callback, instance); 848 XtRemoveAllCallbacks (widget, XmNvalueChangedCallback); 849 XtAddCallback (widget, XmNvalueChangedCallback, 850 xm_internal_update_other_instances, instance); 851} 852 853static void 854xm_update_text_field (instance, widget, val) 855 widget_instance* instance; 856 Widget widget; 857 widget_value* val; 858{ 859 XmTextFieldSetString (widget, val->value ? val->value : ""); 860 XtRemoveAllCallbacks (widget, XmNactivateCallback); 861 XtAddCallback (widget, XmNactivateCallback, xm_generic_callback, instance); 862 XtRemoveAllCallbacks (widget, XmNvalueChangedCallback); 863 XtAddCallback (widget, XmNvalueChangedCallback, 864 xm_internal_update_other_instances, instance); 865} 866 867 868/* update a motif widget */ 869 870void 871xm_update_one_widget (instance, widget, val, deep_p) 872 widget_instance* instance; 873 Widget widget; 874 widget_value* val; 875 Boolean deep_p; 876{ 877 WidgetClass class; 878 879 /* Mark as not edited */ 880 val->edited = False; 881 882 /* Common to all widget types */ 883 XtSetSensitive (widget, val->enabled); 884 XtVaSetValues (widget, XmNuserData, val->call_data, NULL); 885 886 /* Common to all label like widgets */ 887 if (XtIsSubclass (widget, xmLabelWidgetClass)) 888 xm_update_label (instance, widget, val); 889 890 class = XtClass (widget); 891 /* Class specific things */ 892 if (class == xmPushButtonWidgetClass || 893 class == xmArrowButtonWidgetClass) 894 { 895 xm_update_pushbutton (instance, widget, val); 896 } 897 else if (class == xmCascadeButtonWidgetClass) 898 { 899 xm_update_cascadebutton (instance, widget, val); 900 } 901 else if (class == xmToggleButtonWidgetClass 902 || class == xmToggleButtonGadgetClass) 903 { 904 xm_update_toggle (instance, widget, val); 905 } 906 else if (class == xmRowColumnWidgetClass) 907 { 908 Boolean radiobox = 0; 909 int ac = 0; 910 Arg al [1]; 911 912 XtSetArg (al [ac], XmNradioBehavior, &radiobox); ac++; 913 XtGetValues (widget, al, ac); 914 915 if (radiobox) 916 xm_update_radiobox (instance, widget, val); 917 else 918 xm_update_menu (instance, widget, val, deep_p); 919 } 920 else if (class == xmTextWidgetClass) 921 { 922 xm_update_text (instance, widget, val); 923 } 924 else if (class == xmTextFieldWidgetClass) 925 { 926 xm_update_text_field (instance, widget, val); 927 } 928 else if (class == xmListWidgetClass) 929 { 930 xm_update_list (instance, widget, val); 931 } 932} 933 934/* getting the value back */ 935void 936xm_update_one_value (instance, widget, val) 937 widget_instance* instance; 938 Widget widget; 939 widget_value* val; 940{ 941 WidgetClass class = XtClass (widget); 942 widget_value *old_wv; 943 944 /* copy the call_data slot into the "return" widget_value */ 945 for (old_wv = instance->info->val->contents; old_wv; old_wv = old_wv->next) 946 if (!strcmp (val->name, old_wv->name)) 947 { 948 val->call_data = old_wv->call_data; 949 break; 950 } 951 952 if (class == xmToggleButtonWidgetClass || class == xmToggleButtonGadgetClass) 953 { 954 XtVaGetValues (widget, XmNset, &val->selected, NULL); 955 val->edited = True; 956 } 957 else if (class == xmTextWidgetClass) 958 { 959 if (val->value) 960 free (val->value); 961 val->value = XmTextGetString (widget); 962 val->edited = True; 963 } 964 else if (class == xmTextFieldWidgetClass) 965 { 966 if (val->value) 967 free (val->value); 968 val->value = XmTextFieldGetString (widget); 969 val->edited = True; 970 } 971 else if (class == xmRowColumnWidgetClass) 972 { 973 Boolean radiobox = 0; 974 int ac = 0; 975 Arg al [1]; 976 977 XtSetArg (al [ac], XmNradioBehavior, &radiobox); ac++; 978 XtGetValues (widget, al, ac); 979 980 if (radiobox) 981 { 982 CompositeWidget radio = (CompositeWidget)widget; 983 int i; 984 for (i = 0; i < radio->composite.num_children; i++) 985 { 986 int set = False; 987 Widget toggle = radio->composite.children [i]; 988 989 XtVaGetValues (toggle, XmNset, &set, NULL); 990 if (set) 991 { 992 if (val->value) 993 free (val->value); 994 val->value = safe_strdup (XtName (toggle)); 995 } 996 } 997 val->edited = True; 998 } 999 } 1000 else if (class == xmListWidgetClass) 1001 { 1002 int pos_cnt; 1003 int* pos_list; 1004 if (XmListGetSelectedPos (widget, &pos_list, &pos_cnt)) 1005 { 1006 int i; 1007 widget_value* cur; 1008 for (cur = val->contents, i = 0; cur; cur = cur->next) 1009 if (cur->value) 1010 { 1011 int j; 1012 cur->selected = False; 1013 i += 1; 1014 for (j = 0; j < pos_cnt; j++) 1015 if (pos_list [j] == i) 1016 { 1017 cur->selected = True; 1018 val->value = safe_strdup (cur->name); 1019 } 1020 } 1021 val->edited = 1; 1022 XtFree ((char *) pos_list); 1023 } 1024 } 1025} 1026 1027 1028/* This function is for activating a button from a program. It's wrong because 1029 we pass a NULL argument in the call_data which is not Motif compatible. 1030 This is used from the XmNdefaultAction callback of the List widgets to 1031 have a double-click put down a dialog box like the button would do. 1032 I could not find a way to do that with accelerators. 1033 */ 1034static void 1035activate_button (widget, closure, call_data) 1036 Widget widget; 1037 XtPointer closure; 1038 XtPointer call_data; 1039{ 1040 Widget button = (Widget)closure; 1041 XtCallCallbacks (button, XmNactivateCallback, NULL); 1042} 1043 1044/* creation functions */ 1045 1046/* Called for key press in dialogs. Used to pop down dialog on ESC. */ 1047static void 1048dialog_key_cb (widget, closure, event, continue_to_dispatch) 1049 Widget widget; 1050 XtPointer closure; 1051 XEvent *event; 1052 Boolean *continue_to_dispatch; 1053{ 1054 KeySym sym = 0; 1055 Modifiers modif_ret; 1056 1057 XtTranslateKeycode (event->xkey.display, event->xkey.keycode, 0, 1058 &modif_ret, &sym); 1059 1060 if (sym == osfXK_Cancel) 1061 { 1062 Widget w = *((Widget *) closure); 1063 1064 while (w && ! XtIsShell (w)) 1065 w = XtParent (w); 1066 1067 if (XtIsShell (w)) XtPopdown (w); 1068 } 1069 1070 *continue_to_dispatch = TRUE; 1071} 1072 1073/* dialogs */ 1074static Widget 1075make_dialog (name, parent, pop_up_p, shell_title, icon_name, text_input_slot, 1076 radio_box, list, left_buttons, right_buttons) 1077 char* name; 1078 Widget parent; 1079 Boolean pop_up_p; 1080 char* shell_title; 1081 char* icon_name; 1082 Boolean text_input_slot; 1083 Boolean radio_box; 1084 Boolean list; 1085 int left_buttons; 1086 int right_buttons; 1087{ 1088 Widget result; 1089 Widget form; 1090 Widget row; 1091 Widget icon; 1092 Widget icon_separator; 1093 Widget message; 1094 Widget value = 0; 1095 Widget separator; 1096 Widget button = 0; 1097 Widget children [16]; /* for the final XtManageChildren */ 1098 int n_children; 1099 Arg al[64]; /* Arg List */ 1100 int ac; /* Arg Count */ 1101 int i; 1102 1103 if (pop_up_p) 1104 { 1105 ac = 0; 1106 XtSetArg(al[ac], XmNtitle, shell_title); ac++; 1107 XtSetArg(al[ac], XtNallowShellResize, True); ac++; 1108 XtSetArg(al[ac], XmNdeleteResponse, XmUNMAP); ac++; 1109 result = XmCreateDialogShell (parent, "dialog", al, ac); 1110 ac = 0; 1111 XtSetArg(al[ac], XmNautoUnmanage, FALSE); ac++; 1112/* XtSetArg(al[ac], XmNautoUnmanage, TRUE); ac++; */ /* ####is this ok? */ 1113 XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; 1114 form = XmCreateForm (result, shell_title, al, ac); 1115 } 1116 else 1117 { 1118 ac = 0; 1119 XtSetArg(al[ac], XmNautoUnmanage, FALSE); ac++; 1120 XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; 1121 form = XmCreateForm (parent, shell_title, al, ac); 1122 result = form; 1123 } 1124 1125 n_children = left_buttons + right_buttons + 1; 1126 ac = 0; 1127 XtSetArg(al[ac], XmNpacking, n_children == 3? 1128 XmPACK_COLUMN: XmPACK_TIGHT); ac++; 1129 XtSetArg(al[ac], XmNorientation, n_children == 3? 1130 XmVERTICAL: XmHORIZONTAL); ac++; 1131 XtSetArg(al[ac], XmNnumColumns, left_buttons + right_buttons + 1); ac++; 1132 XtSetArg(al[ac], XmNmarginWidth, 0); ac++; 1133 XtSetArg(al[ac], XmNmarginHeight, 0); ac++; 1134 XtSetArg(al[ac], XmNspacing, 13); ac++; 1135 XtSetArg(al[ac], XmNadjustLast, False); ac++; 1136 XtSetArg(al[ac], XmNalignment, XmALIGNMENT_CENTER); ac++; 1137 XtSetArg(al[ac], XmNisAligned, True); ac++; 1138 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++; 1139 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_FORM); ac++; 1140 XtSetArg(al[ac], XmNbottomOffset, 13); ac++; 1141 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++; 1142 XtSetArg(al[ac], XmNleftOffset, 13); ac++; 1143 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++; 1144 XtSetArg(al[ac], XmNrightOffset, 13); ac++; 1145 row = XmCreateRowColumn (form, "row", al, ac); 1146 1147 n_children = 0; 1148 for (i = 0; i < left_buttons; i++) 1149 { 1150 char button_name [16]; 1151 sprintf (button_name, "button%d", i + 1); 1152 ac = 0; 1153 if (i == 0) 1154 { 1155 XtSetArg(al[ac], XmNhighlightThickness, 1); ac++; 1156 XtSetArg(al[ac], XmNshowAsDefault, TRUE); ac++; 1157 } 1158 XtSetArg(al[ac], XmNmarginWidth, 10); ac++; 1159 XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; 1160 children [n_children] = XmCreatePushButton (row, button_name, al, ac); 1161 XtAddEventHandler (children [n_children], 1162 KeyPressMask, False, dialog_key_cb, result); 1163 1164 if (i == 0) 1165 { 1166 button = children [n_children]; 1167 ac = 0; 1168 XtSetArg(al[ac], XmNdefaultButton, button); ac++; 1169 XtSetValues (row, al, ac); 1170 } 1171 1172 n_children++; 1173 } 1174 1175 /* invisible separator button */ 1176 ac = 0; 1177 XtSetArg (al[ac], XmNmappedWhenManaged, FALSE); ac++; 1178 children [n_children] = XmCreateLabel (row, "separator_button", al, ac); 1179 n_children++; 1180 1181 for (i = 0; i < right_buttons; i++) 1182 { 1183 char button_name [16]; 1184 sprintf (button_name, "button%d", left_buttons + i + 1); 1185 ac = 0; 1186 XtSetArg(al[ac], XmNmarginWidth, 10); ac++; 1187 XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; 1188 children [n_children] = XmCreatePushButton (row, button_name, al, ac); 1189 XtAddEventHandler (children [n_children], 1190 KeyPressMask, False, dialog_key_cb, result); 1191 1192 if (! button) button = children [n_children]; 1193 n_children++; 1194 } 1195 1196 XtManageChildren (children, n_children); 1197 1198 ac = 0; 1199 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++; 1200 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++; 1201 XtSetArg(al[ac], XmNbottomOffset, 13); ac++; 1202 XtSetArg(al[ac], XmNbottomWidget, row); ac++; 1203 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++; 1204 XtSetArg(al[ac], XmNleftOffset, 0); ac++; 1205 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++; 1206 XtSetArg(al[ac], XmNrightOffset, 0); ac++; 1207 separator = XmCreateSeparator (form, "", al, ac); 1208 1209 ac = 0; 1210 XtSetArg(al[ac], XmNlabelType, XmPIXMAP); ac++; 1211 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++; 1212 XtSetArg(al[ac], XmNtopOffset, 13); ac++; 1213 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_NONE); ac++; 1214 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++; 1215 XtSetArg(al[ac], XmNleftOffset, 13); ac++; 1216 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_NONE); ac++; 1217 icon = XmCreateLabel (form, icon_name, al, ac); 1218 1219 ac = 0; 1220 XtSetArg(al[ac], XmNmappedWhenManaged, FALSE); ac++; 1221 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_WIDGET); ac++; 1222 XtSetArg(al[ac], XmNtopOffset, 6); ac++; 1223 XtSetArg(al[ac], XmNtopWidget, icon); ac++; 1224 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++; 1225 XtSetArg(al[ac], XmNbottomOffset, 6); ac++; 1226 XtSetArg(al[ac], XmNbottomWidget, separator); ac++; 1227 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_NONE); ac++; 1228 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_NONE); ac++; 1229 icon_separator = XmCreateLabel (form, "", al, ac); 1230 1231 if (text_input_slot) 1232 { 1233 ac = 0; 1234 XtSetArg(al[ac], XmNcolumns, 50); ac++; 1235 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++; 1236 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++; 1237 XtSetArg(al[ac], XmNbottomOffset, 13); ac++; 1238 XtSetArg(al[ac], XmNbottomWidget, separator); ac++; 1239 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++; 1240 XtSetArg(al[ac], XmNleftOffset, 13); ac++; 1241 XtSetArg(al[ac], XmNleftWidget, icon); ac++; 1242 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++; 1243 XtSetArg(al[ac], XmNrightOffset, 13); ac++; 1244 value = XmCreateTextField (form, "value", al, ac); 1245 } 1246 else if (radio_box) 1247 { 1248 Widget radio_butt; 1249 ac = 0; 1250 XtSetArg(al[ac], XmNmarginWidth, 0); ac++; 1251 XtSetArg(al[ac], XmNmarginHeight, 0); ac++; 1252 XtSetArg(al[ac], XmNspacing, 13); ac++; 1253 XtSetArg(al[ac], XmNalignment, XmALIGNMENT_CENTER); ac++; 1254 XtSetArg(al[ac], XmNorientation, XmHORIZONTAL); ac++; 1255 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++; 1256 XtSetArg(al[ac], XmNbottomOffset, 13); ac++; 1257 XtSetArg(al[ac], XmNbottomWidget, separator); ac++; 1258 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++; 1259 XtSetArg(al[ac], XmNleftOffset, 13); ac++; 1260 XtSetArg(al[ac], XmNleftWidget, icon); ac++; 1261 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++; 1262 XtSetArg(al[ac], XmNrightOffset, 13); ac++; 1263 value = XmCreateRadioBox (form, "radiobutton1", al, ac); 1264 ac = 0; 1265 i = 0; 1266 radio_butt = XmCreateToggleButtonGadget (value, "radio1", al, ac); 1267 children [i++] = radio_butt; 1268 radio_butt = XmCreateToggleButtonGadget (value, "radio2", al, ac); 1269 children [i++] = radio_butt; 1270 radio_butt = XmCreateToggleButtonGadget (value, "radio3", al, ac); 1271 children [i++] = radio_butt; 1272 XtManageChildren (children, i); 1273 } 1274 else if (list) 1275 { 1276 ac = 0; 1277 XtSetArg(al[ac], XmNvisibleItemCount, 5); ac++; 1278 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++; 1279 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++; 1280 XtSetArg(al[ac], XmNbottomOffset, 13); ac++; 1281 XtSetArg(al[ac], XmNbottomWidget, separator); ac++; 1282 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++; 1283 XtSetArg(al[ac], XmNleftOffset, 13); ac++; 1284 XtSetArg(al[ac], XmNleftWidget, icon); ac++; 1285 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++; 1286 XtSetArg(al[ac], XmNrightOffset, 13); ac++; 1287 value = XmCreateScrolledList (form, "list", al, ac); 1288 1289 /* this is the easiest way I found to have the dble click in the 1290 list activate the default button */ 1291 XtAddCallback (value, XmNdefaultActionCallback, activate_button, button); 1292 } 1293 1294 ac = 0; 1295 XtSetArg(al[ac], XmNalignment, XmALIGNMENT_BEGINNING); ac++; 1296 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++; 1297 XtSetArg(al[ac], XmNtopOffset, 13); ac++; 1298 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++; 1299 XtSetArg(al[ac], XmNbottomOffset, 13); ac++; 1300 XtSetArg(al[ac], XmNbottomWidget, 1301 text_input_slot || radio_box || list ? value : separator); ac++; 1302 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++; 1303 XtSetArg(al[ac], XmNleftOffset, 13); ac++; 1304 XtSetArg(al[ac], XmNleftWidget, icon); ac++; 1305 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++; 1306 XtSetArg(al[ac], XmNrightOffset, 13); ac++; 1307 message = XmCreateLabel (form, "message", al, ac); 1308 1309 if (list) 1310 XtManageChild (value); 1311 1312 i = 0; 1313 children [i] = row; i++; 1314 children [i] = separator; i++; 1315 if (text_input_slot || radio_box) 1316 { 1317 children [i] = value; i++; 1318 } 1319 children [i] = message; i++; 1320 children [i] = icon; i++; 1321 children [i] = icon_separator; i++; 1322 XtManageChildren (children, i); 1323 1324 if (text_input_slot || list) 1325 { 1326 XtInstallAccelerators (value, button); 1327 XtSetKeyboardFocus (result, value); 1328 } 1329 else 1330 { 1331 XtInstallAccelerators (form, button); 1332 XtSetKeyboardFocus (result, button); 1333 } 1334 1335 return result; 1336} 1337 1338static destroyed_instance* 1339find_matching_instance (instance) 1340 widget_instance* instance; 1341{ 1342 destroyed_instance* cur; 1343 destroyed_instance* prev; 1344 char* type = instance->info->type; 1345 char* name = instance->info->name; 1346 1347 for (prev = NULL, cur = all_destroyed_instances; 1348 cur; 1349 prev = cur, cur = cur->next) 1350 { 1351 if (!strcmp (cur->name, name) 1352 && !strcmp (cur->type, type) 1353 && cur->parent == instance->parent 1354 && cur->pop_up_p == instance->pop_up_p) 1355 { 1356 if (prev) 1357 prev->next = cur->next; 1358 else 1359 all_destroyed_instances = cur->next; 1360 return cur; 1361 } 1362 /* do some cleanup */ 1363 else if (!cur->widget) 1364 { 1365 if (prev) 1366 prev->next = cur->next; 1367 else 1368 all_destroyed_instances = cur->next; 1369 free_destroyed_instance (cur); 1370 cur = prev ? prev : all_destroyed_instances; 1371 } 1372 } 1373 return NULL; 1374} 1375 1376static void 1377mark_dead_instance_destroyed (widget, closure, call_data) 1378 Widget widget; 1379 XtPointer closure; 1380 XtPointer call_data; 1381{ 1382 destroyed_instance* instance = (destroyed_instance*)closure; 1383 instance->widget = NULL; 1384} 1385 1386static void 1387recenter_widget (widget) 1388 Widget widget; 1389{ 1390 Widget parent = XtParent (widget); 1391 Screen* screen = XtScreen (widget); 1392 Dimension screen_width = WidthOfScreen (screen); 1393 Dimension screen_height = HeightOfScreen (screen); 1394 Dimension parent_width = 0; 1395 Dimension parent_height = 0; 1396 Dimension child_width = 0; 1397 Dimension child_height = 0; 1398 Position x; 1399 Position y; 1400 1401 XtVaGetValues (widget, XtNwidth, &child_width, XtNheight, &child_height, NULL); 1402 XtVaGetValues (parent, XtNwidth, &parent_width, XtNheight, &parent_height, 1403 NULL); 1404 1405 x = (((Position)parent_width) - ((Position)child_width)) / 2; 1406 y = (((Position)parent_height) - ((Position)child_height)) / 2; 1407 1408 XtTranslateCoords (parent, x, y, &x, &y); 1409 1410 if (x + child_width > screen_width) 1411 x = screen_width - child_width; 1412 if (x < 0) 1413 x = 0; 1414 1415 if (y + child_height > screen_height) 1416 y = screen_height - child_height; 1417 if (y < 0) 1418 y = 0; 1419 1420 XtVaSetValues (widget, XtNx, x, XtNy, y, NULL); 1421} 1422 1423static Widget 1424recycle_instance (instance) 1425 destroyed_instance* instance; 1426{ 1427 Widget widget = instance->widget; 1428 1429 /* widget is NULL if the parent was destroyed. */ 1430 if (widget) 1431 { 1432 Widget focus; 1433 Widget separator; 1434 1435 /* Remove the destroy callback as the instance is not in the list 1436 anymore */ 1437 XtRemoveCallback (instance->parent, XtNdestroyCallback, 1438 mark_dead_instance_destroyed, 1439 (XtPointer)instance); 1440 1441 /* Give the focus to the initial item */ 1442 focus = XtNameToWidget (widget, "*value"); 1443 if (!focus) 1444 focus = XtNameToWidget (widget, "*button1"); 1445 if (focus) 1446 XtSetKeyboardFocus (widget, focus); 1447 1448 /* shrink the separator label back to their original size */ 1449 separator = XtNameToWidget (widget, "*separator_button"); 1450 if (separator) 1451 XtVaSetValues (separator, XtNwidth, 5, XtNheight, 5, NULL); 1452 1453 /* Center the dialog in its parent */ 1454 recenter_widget (widget); 1455 } 1456 free_destroyed_instance (instance); 1457 return widget; 1458} 1459 1460Widget 1461xm_create_dialog (instance) 1462 widget_instance* instance; 1463{ 1464 char* name = instance->info->type; 1465 Widget parent = instance->parent; 1466 Widget widget; 1467 Boolean pop_up_p = instance->pop_up_p; 1468 char* shell_name = 0; 1469 char* icon_name = 0; 1470 Boolean text_input_slot = False; 1471 Boolean radio_box = False; 1472 Boolean list = False; 1473 int total_buttons; 1474 int left_buttons = 0; 1475 int right_buttons = 1; 1476 destroyed_instance* dead_one; 1477 1478 /* try to find a widget to recycle */ 1479 dead_one = find_matching_instance (instance); 1480 if (dead_one) 1481 { 1482 Widget recycled_widget = recycle_instance (dead_one); 1483 if (recycled_widget) 1484 return recycled_widget; 1485 } 1486 1487 switch (name [0]){ 1488 case 'E': case 'e': 1489 icon_name = "dbox-error"; 1490 shell_name = "Error"; 1491 break; 1492 1493 case 'I': case 'i': 1494 icon_name = "dbox-info"; 1495 shell_name = "Information"; 1496 break; 1497 1498 case 'L': case 'l': 1499 list = True; 1500 icon_name = "dbox-question"; 1501 shell_name = "Prompt"; 1502 break; 1503 1504 case 'P': case 'p': 1505 text_input_slot = True; 1506 icon_name = "dbox-question"; 1507 shell_name = "Prompt"; 1508 break; 1509 1510 case 'Q': case 'q': 1511 icon_name = "dbox-question"; 1512 shell_name = "Question"; 1513 break; 1514 } 1515 1516 total_buttons = name [1] - '0'; 1517 1518 if (name [3] == 'T' || name [3] == 't') 1519 { 1520 text_input_slot = False; 1521 radio_box = True; 1522 } 1523 else if (name [3]) 1524 right_buttons = name [4] - '0'; 1525 1526 left_buttons = total_buttons - right_buttons; 1527 1528 widget = make_dialog (name, parent, pop_up_p, 1529 shell_name, icon_name, text_input_slot, radio_box, 1530 list, left_buttons, right_buttons); 1531 1532 XtAddCallback (widget, XmNpopdownCallback, xm_nosel_callback, 1533 (XtPointer) instance); 1534 1535 return widget; 1536} 1537 1538/* Create a menu bar. We turn off the f10 key 1539 because we have not yet managed to make it work right in Motif. */ 1540 1541static Widget 1542make_menubar (instance) 1543 widget_instance* instance; 1544{ 1545 Arg al[3]; 1546 int ac; 1547 1548 ac = 0; 1549 XtSetArg(al[ac], XmNmenuAccelerator, 0); ++ac; 1550 return XmCreateMenuBar (instance->parent, instance->info->name, al, ac); 1551} 1552 1553static void 1554remove_grabs (shell, closure, call_data) 1555 Widget shell; 1556 XtPointer closure; 1557 XtPointer call_data; 1558{ 1559 Widget menu = (Widget) closure; 1560 XmRemoveFromPostFromList (menu, XtParent (XtParent (menu))); 1561} 1562 1563static Widget 1564make_popup_menu (instance) 1565 widget_instance* instance; 1566{ 1567 Widget parent = instance->parent; 1568 Window parent_window = parent->core.window; 1569 Widget result; 1570 1571 /* sets the parent window to 0 to fool Motif into not generating a grab */ 1572 parent->core.window = 0; 1573 result = XmCreatePopupMenu (parent, instance->info->name, NULL, 0); 1574 XtAddCallback (XtParent (result), XmNpopdownCallback, remove_grabs, 1575 (XtPointer)result); 1576 parent->core.window = parent_window; 1577 return result; 1578} 1579 1580static Widget 1581make_main (instance) 1582 widget_instance* instance; 1583{ 1584 Widget parent = instance->parent; 1585 Widget result; 1586 Arg al[2]; 1587 int ac; 1588 1589 ac = 0; 1590 XtSetArg (al[ac], XtNborderWidth, 0); ac++; 1591 XtSetArg (al[ac], XmNspacing, 0); ac++; 1592 result = XmCreateMainWindow (parent, instance->info->name, al, ac); 1593 return result; 1594} 1595 1596/* Table of functions to create widgets */ 1597 1598#ifdef ENERGIZE 1599 1600/* interface with the XDesigner generated functions */ 1601typedef Widget (*widget_maker) (Widget); 1602extern Widget create_project_p_sheet (Widget parent); 1603extern Widget create_debugger_p_sheet (Widget parent); 1604extern Widget create_breaklist_p_sheet (Widget parent); 1605extern Widget create_le_browser_p_sheet (Widget parent); 1606extern Widget create_class_browser_p_sheet (Widget parent); 1607extern Widget create_call_browser_p_sheet (Widget parent); 1608extern Widget create_build_dialog (Widget parent); 1609extern Widget create_editmode_dialog (Widget parent); 1610extern Widget create_search_dialog (Widget parent); 1611extern Widget create_project_display_dialog (Widget parent); 1612 1613static Widget 1614make_one (widget_instance* instance, widget_maker fn) 1615{ 1616 Widget result; 1617 Arg al [64]; 1618 int ac = 0; 1619 1620 if (instance->pop_up_p) 1621 { 1622 XtSetArg (al [ac], XmNallowShellResize, TRUE); ac++; 1623 result = XmCreateDialogShell (instance->parent, "dialog", NULL, 0); 1624 XtAddCallback (result, XmNpopdownCallback, &xm_nosel_callback, 1625 (XtPointer) instance); 1626 (*fn) (result); 1627 } 1628 else 1629 { 1630 result = (*fn) (instance->parent); 1631 XtRealizeWidget (result); 1632 } 1633 return result; 1634} 1635 1636static Widget 1637make_project_p_sheet (widget_instance* instance) 1638{ 1639 return make_one (instance, create_project_p_sheet); 1640} 1641 1642static Widget 1643make_debugger_p_sheet (widget_instance* instance) 1644{ 1645 return make_one (instance, create_debugger_p_sheet); 1646} 1647 1648static Widget 1649make_breaklist_p_sheet (widget_instance* instance) 1650{ 1651 return make_one (instance, create_breaklist_p_sheet); 1652} 1653 1654static Widget 1655make_le_browser_p_sheet (widget_instance* instance) 1656{ 1657 return make_one (instance, create_le_browser_p_sheet); 1658} 1659 1660static Widget 1661make_class_browser_p_sheet (widget_instance* instance) 1662{ 1663 return make_one (instance, create_class_browser_p_sheet); 1664} 1665 1666static Widget 1667make_call_browser_p_sheet (widget_instance* instance) 1668{ 1669 return make_one (instance, create_call_browser_p_sheet); 1670} 1671 1672static Widget 1673make_build_dialog (widget_instance* instance) 1674{ 1675 return make_one (instance, create_build_dialog); 1676} 1677 1678static Widget 1679make_editmode_dialog (widget_instance* instance) 1680{ 1681 return make_one (instance, create_editmode_dialog); 1682} 1683 1684static Widget 1685make_search_dialog (widget_instance* instance) 1686{ 1687 return make_one (instance, create_search_dialog); 1688} 1689 1690static Widget 1691make_project_display_dialog (widget_instance* instance) 1692{ 1693 return make_one (instance, create_project_display_dialog); 1694} 1695 1696#endif /* ENERGIZE */ 1697 1698widget_creation_entry 1699xm_creation_table [] = 1700{ 1701 {"menubar", make_menubar}, 1702 {"popup", make_popup_menu}, 1703 {"main", make_main}, 1704#ifdef ENERGIZE 1705 {"project_p_sheet", make_project_p_sheet}, 1706 {"debugger_p_sheet", make_debugger_p_sheet}, 1707 {"breaklist_psheet", make_breaklist_p_sheet}, 1708 {"leb_psheet", make_le_browser_p_sheet}, 1709 {"class_browser_psheet", make_class_browser_p_sheet}, 1710 {"ctree_browser_psheet", make_call_browser_p_sheet}, 1711 {"build", make_build_dialog}, 1712 {"editmode", make_editmode_dialog}, 1713 {"search", make_search_dialog}, 1714 {"project_display", make_project_display_dialog}, 1715#endif /* ENERGIZE */ 1716 {NULL, NULL} 1717}; 1718 1719/* Destruction of instances */ 1720void 1721xm_destroy_instance (instance) 1722 widget_instance* instance; 1723{ 1724 Widget widget = instance->widget; 1725 /* recycle the dialog boxes */ 1726 /* Disable the recycling until we can find a way to have the dialog box 1727 get reasonable layout after we modify its contents. */ 1728 if (0 1729 && XtClass (widget) == xmDialogShellWidgetClass) 1730 { 1731 destroyed_instance* dead_instance = 1732 make_destroyed_instance (instance->info->name, 1733 instance->info->type, 1734 instance->widget, 1735 instance->parent, 1736 instance->pop_up_p); 1737 dead_instance->next = all_destroyed_instances; 1738 all_destroyed_instances = dead_instance; 1739 XtUnmanageChild (first_child (instance->widget)); 1740 XFlush (XtDisplay (instance->widget)); 1741 XtAddCallback (instance->parent, XtNdestroyCallback, 1742 mark_dead_instance_destroyed, (XtPointer)dead_instance); 1743 } 1744 else 1745 { 1746 /* This might not be necessary now that the nosel is attached to 1747 popdown instead of destroy, but it can't hurt. */ 1748 XtRemoveCallback (instance->widget, XtNdestroyCallback, 1749 xm_nosel_callback, (XtPointer)instance); 1750 XtDestroyWidget (instance->widget); 1751 } 1752} 1753 1754/* popup utility */ 1755void 1756xm_popup_menu (widget, event) 1757 Widget widget; 1758 XEvent *event; 1759{ 1760 XButtonPressedEvent dummy; 1761 1762 if (event == 0) 1763 { 1764 dummy.type = ButtonPress; 1765 dummy.serial = 0; 1766 dummy.send_event = 0; 1767 dummy.display = XtDisplay (widget); 1768 dummy.window = XtWindow (XtParent (widget)); 1769 dummy.time = 0; 1770 dummy.button = 0; 1771 XQueryPointer (dummy.display, dummy.window, &dummy.root, 1772 &dummy.subwindow, &dummy.x_root, &dummy.y_root, 1773 &dummy.x, &dummy.y, &dummy.state); 1774 event = (XEvent *) &dummy; 1775 } 1776 1777 if (event->type == ButtonPress || event->type == ButtonRelease) 1778 { 1779 /* Setting the menuPost resource only required by Motif 1.1 and 1780 LessTif 0.84 and earlier. With later versions of LessTif, 1781 setting menuPost is unnecessary and may cause problems, so 1782 don't do it. */ 1783#if XmVersion < 1002 || (defined LESSTIF_VERSION && LESSTIF_VERSION < 84) 1784 { 1785 /* This is so totally ridiculous: there's NO WAY to tell Motif 1786 that *any* button can select a menu item. Only one button 1787 can have that honor. */ 1788 1789 char *trans = 0; 1790 if (event->xbutton.state & Button5Mask) trans = "<Btn5Down>"; 1791 else if (event->xbutton.state & Button4Mask) trans = "<Btn4Down>"; 1792 else if (event->xbutton.state & Button3Mask) trans = "<Btn3Down>"; 1793 else if (event->xbutton.state & Button2Mask) trans = "<Btn2Down>"; 1794 else if (event->xbutton.state & Button1Mask) trans = "<Btn1Down>"; 1795 if (trans) XtVaSetValues (widget, XmNmenuPost, trans, NULL); 1796 } 1797#endif 1798 1799 XmMenuPosition (widget, (XButtonPressedEvent *) event); 1800 } 1801 1802 XtManageChild (widget); 1803} 1804 1805static void 1806set_min_dialog_size (w) 1807 Widget w; 1808{ 1809 short width; 1810 short height; 1811 XtVaGetValues (w, XmNwidth, &width, XmNheight, &height, NULL); 1812 XtVaSetValues (w, XmNminWidth, width, XmNminHeight, height, NULL); 1813} 1814 1815void 1816xm_pop_instance (instance, up) 1817 widget_instance* instance; 1818 Boolean up; 1819{ 1820 Widget widget = instance->widget; 1821 1822 if (XtClass (widget) == xmDialogShellWidgetClass) 1823 { 1824 Widget widget_to_manage = first_child (widget); 1825 if (up) 1826 { 1827 XtManageChild (widget_to_manage); 1828 set_min_dialog_size (widget); 1829 XtSetKeyboardFocus (instance->parent, widget); 1830 } 1831 else 1832 XtUnmanageChild (widget_to_manage); 1833 } 1834 else 1835 { 1836 if (up) 1837 XtManageChild (widget); 1838 else 1839 XtUnmanageChild (widget); 1840 } 1841} 1842 1843 1844/* motif callback */ 1845 1846static void 1847do_call (widget, closure, type) 1848 Widget widget; 1849 XtPointer closure; 1850 enum do_call_type type; 1851{ 1852 Arg al [256]; 1853 int ac; 1854 XtPointer user_data; 1855 widget_instance* instance = (widget_instance*)closure; 1856 Widget instance_widget; 1857 LWLIB_ID id; 1858 1859 if (!instance) 1860 return; 1861 if (widget->core.being_destroyed) 1862 return; 1863 1864 instance_widget = instance->widget; 1865 if (!instance_widget) 1866 return; 1867 1868 id = instance->info->id; 1869 ac = 0; 1870 user_data = NULL; 1871 XtSetArg (al [ac], XmNuserData, &user_data); ac++; 1872 XtGetValues (widget, al, ac); 1873 1874 switch (type) 1875 { 1876 case pre_activate: 1877 if (instance->info->pre_activate_cb) 1878 instance->info->pre_activate_cb (widget, id, user_data); 1879 break; 1880 1881 case selection: 1882 if (instance->info->selection_cb) 1883 instance->info->selection_cb (widget, id, user_data); 1884 break; 1885 1886 case no_selection: 1887 if (instance->info->selection_cb) 1888 instance->info->selection_cb (widget, id, (XtPointer) -1); 1889 break; 1890 1891 case post_activate: 1892 if (instance->info->post_activate_cb) 1893 instance->info->post_activate_cb (widget, id, user_data); 1894 break; 1895 1896 default: 1897 abort (); 1898 } 1899} 1900 1901/* Like lw_internal_update_other_instances except that it does not do 1902 anything if its shell parent is not managed. This is to protect 1903 lw_internal_update_other_instances to dereference freed memory 1904 if the widget was ``destroyed'' by caching it in the all_destroyed_instances 1905 list */ 1906static void 1907xm_internal_update_other_instances (widget, closure, call_data) 1908 Widget widget; 1909 XtPointer closure; 1910 XtPointer call_data; 1911{ 1912 Widget parent; 1913 for (parent = widget; parent; parent = XtParent (parent)) 1914 if (XtIsShell (parent)) 1915 break; 1916 else if (!XtIsManaged (parent)) 1917 return; 1918 lw_internal_update_other_instances (widget, closure, call_data); 1919} 1920 1921static void 1922xm_generic_callback (widget, closure, call_data) 1923 Widget widget; 1924 XtPointer closure; 1925 XtPointer call_data; 1926{ 1927 lw_internal_update_other_instances (widget, closure, call_data); 1928 do_call (widget, closure, selection); 1929} 1930 1931static void 1932xm_nosel_callback (widget, closure, call_data) 1933 Widget widget; 1934 XtPointer closure; 1935 XtPointer call_data; 1936{ 1937 /* This callback is only called when a dialog box is dismissed with 1938 the wm's destroy button (WM_DELETE_WINDOW.) We want the dialog 1939 box to be destroyed in that case, not just unmapped, so that it 1940 releases its keyboard grabs. But there are problems with running 1941 our callbacks while the widget is in the process of being 1942 destroyed, so we set XmNdeleteResponse to XmUNMAP instead of 1943 XmDESTROY and then destroy it ourself after having run the 1944 callback. */ 1945 do_call (widget, closure, no_selection); 1946 XtDestroyWidget (widget); 1947} 1948 1949static void 1950xm_pull_down_callback (widget, closure, call_data) 1951 Widget widget; 1952 XtPointer closure; 1953 XtPointer call_data; 1954{ 1955 Widget parent = XtParent (widget); 1956 1957 if (XmIsRowColumn (parent)) 1958 { 1959 unsigned char type = 0xff; 1960 XtVaGetValues (parent, XmNrowColumnType, &type, NULL); 1961 if (type == XmMENU_BAR) 1962 do_call (widget, closure, pre_activate); 1963 } 1964} 1965 1966 1967/* XmNpopdownCallback for MenuShell widgets. WIDGET is the MenuShell, 1968 CLOSURE is a pointer to the widget_instance of the shell, 1969 1970 Note that this callback is called for each cascade button in a 1971 menu, whether or not its submenu is visible. */ 1972 1973static void 1974xm_pop_down_callback (widget, closure, call_data) 1975 Widget widget; 1976 XtPointer closure; 1977 XtPointer call_data; 1978{ 1979 widget_instance *instance = (widget_instance *) closure; 1980 1981 if ((!instance->pop_up_p && XtParent (widget) == instance->widget) 1982 || XtParent (widget) == instance->parent) 1983 do_call (widget, closure, post_activate); 1984} 1985 1986 1987/* set the keyboard focus */ 1988void 1989xm_set_keyboard_focus (parent, w) 1990 Widget parent; 1991 Widget w; 1992{ 1993 XmProcessTraversal (w, 0); 1994 XtSetKeyboardFocus (parent, w); 1995} 1996 1997/* Motif hack to set the main window areas. */ 1998void 1999xm_set_main_areas (parent, menubar, work_area) 2000 Widget parent; 2001 Widget menubar; 2002 Widget work_area; 2003{ 2004 XmMainWindowSetAreas (parent, 2005 menubar, /* menubar (maybe 0) */ 2006 0, /* command area (psheets) */ 2007 0, /* horizontal scroll */ 2008 0, /* vertical scroll */ 2009 work_area); /* work area */ 2010} 2011 2012/* Motif hack to control resizing on the menubar. */ 2013void 2014xm_manage_resizing (w, flag) 2015 Widget w; 2016 Boolean flag; 2017{ 2018 XtVaSetValues (w, XtNallowShellResize, flag, NULL); 2019} 2020 2021/* arch-tag: 73976f64-73b2-4600-aa13-d9ede20ee965 2022 (do not change this comment) */ 2023