Mercurial > hg > xemacs-beta
view lwlib/lwlib-Xm.c @ 5127:a9c41067dd88 ben-lisp-object
more cleanups, terminology clarification, lots of doc work
-------------------- ChangeLog entries follow: --------------------
man/ChangeLog addition:
2010-03-05 Ben Wing <ben@xemacs.org>
* internals/internals.texi (Introduction to Allocation):
* internals/internals.texi (Integers and Characters):
* internals/internals.texi (Allocation from Frob Blocks):
* internals/internals.texi (lrecords):
* internals/internals.texi (Low-level allocation):
Rewrite section on allocation of Lisp objects to reflect the new
reality. Remove references to nonexistent XSETINT and XSETCHAR.
modules/ChangeLog addition:
2010-03-05 Ben Wing <ben@xemacs.org>
* postgresql/postgresql.c (allocate_pgconn):
* postgresql/postgresql.c (allocate_pgresult):
* postgresql/postgresql.h (struct Lisp_PGconn):
* postgresql/postgresql.h (struct Lisp_PGresult):
* ldap/eldap.c (allocate_ldap):
* ldap/eldap.h (struct Lisp_LDAP):
Same changes as in src/ dir. See large log there in ChangeLog,
but basically:
ALLOC_LISP_OBJECT -> ALLOC_NORMAL_LISP_OBJECT
LISP_OBJECT_HEADER -> NORMAL_LISP_OBJECT_HEADER
../hlo/src/ChangeLog addition:
2010-03-05 Ben Wing <ben@xemacs.org>
* alloc.c:
* alloc.c (old_alloc_sized_lcrecord):
* alloc.c (very_old_free_lcrecord):
* alloc.c (copy_lisp_object):
* alloc.c (zero_sized_lisp_object):
* alloc.c (zero_nonsized_lisp_object):
* alloc.c (lisp_object_storage_size):
* alloc.c (free_normal_lisp_object):
* alloc.c (FREE_FIXED_TYPE_WHEN_NOT_IN_GC):
* alloc.c (ALLOC_FROB_BLOCK_LISP_OBJECT):
* alloc.c (Fcons):
* alloc.c (noseeum_cons):
* alloc.c (make_float):
* alloc.c (make_bignum):
* alloc.c (make_bignum_bg):
* alloc.c (make_ratio):
* alloc.c (make_ratio_bg):
* alloc.c (make_ratio_rt):
* alloc.c (make_bigfloat):
* alloc.c (make_bigfloat_bf):
* alloc.c (size_vector):
* alloc.c (make_compiled_function):
* alloc.c (Fmake_symbol):
* alloc.c (allocate_extent):
* alloc.c (allocate_event):
* alloc.c (make_key_data):
* alloc.c (make_button_data):
* alloc.c (make_motion_data):
* alloc.c (make_process_data):
* alloc.c (make_timeout_data):
* alloc.c (make_magic_data):
* alloc.c (make_magic_eval_data):
* alloc.c (make_eval_data):
* alloc.c (make_misc_user_data):
* alloc.c (Fmake_marker):
* alloc.c (noseeum_make_marker):
* alloc.c (size_string_direct_data):
* alloc.c (make_uninit_string):
* alloc.c (make_string_nocopy):
* alloc.c (mark_lcrecord_list):
* alloc.c (alloc_managed_lcrecord):
* alloc.c (free_managed_lcrecord):
* alloc.c (sweep_lcrecords_1):
* alloc.c (malloced_storage_size):
* buffer.c (allocate_buffer):
* buffer.c (compute_buffer_usage):
* buffer.c (DEFVAR_BUFFER_LOCAL_1):
* buffer.c (nuke_all_buffer_slots):
* buffer.c (common_init_complex_vars_of_buffer):
* buffer.h (struct buffer_text):
* buffer.h (struct buffer):
* bytecode.c:
* bytecode.c (make_compiled_function_args):
* bytecode.c (size_compiled_function_args):
* bytecode.h (struct compiled_function_args):
* casetab.c (allocate_case_table):
* casetab.h (struct Lisp_Case_Table):
* charset.h (struct Lisp_Charset):
* chartab.c (fill_char_table):
* chartab.c (Fmake_char_table):
* chartab.c (make_char_table_entry):
* chartab.c (copy_char_table_entry):
* chartab.c (Fcopy_char_table):
* chartab.c (put_char_table):
* chartab.h (struct Lisp_Char_Table_Entry):
* chartab.h (struct Lisp_Char_Table):
* console-gtk-impl.h (struct gtk_device):
* console-gtk-impl.h (struct gtk_frame):
* console-impl.h (struct console):
* console-msw-impl.h (struct Lisp_Devmode):
* console-msw-impl.h (struct mswindows_device):
* console-msw-impl.h (struct msprinter_device):
* console-msw-impl.h (struct mswindows_frame):
* console-msw-impl.h (struct mswindows_dialog_id):
* console-stream-impl.h (struct stream_console):
* console-stream.c (stream_init_console):
* console-tty-impl.h (struct tty_console):
* console-tty-impl.h (struct tty_device):
* console-tty.c (allocate_tty_console_struct):
* console-x-impl.h (struct x_device):
* console-x-impl.h (struct x_frame):
* console.c (allocate_console):
* console.c (nuke_all_console_slots):
* console.c (DEFVAR_CONSOLE_LOCAL_1):
* console.c (common_init_complex_vars_of_console):
* data.c (make_weak_list):
* data.c (make_weak_box):
* data.c (make_ephemeron):
* database.c:
* database.c (struct Lisp_Database):
* database.c (allocate_database):
* database.c (finalize_database):
* device-gtk.c (allocate_gtk_device_struct):
* device-impl.h (struct device):
* device-msw.c:
* device-msw.c (mswindows_init_device):
* device-msw.c (msprinter_init_device):
* device-msw.c (finalize_devmode):
* device-msw.c (allocate_devmode):
* device-tty.c (allocate_tty_device_struct):
* device-x.c (allocate_x_device_struct):
* device.c:
* device.c (nuke_all_device_slots):
* device.c (allocate_device):
* dialog-msw.c (handle_question_dialog_box):
* elhash.c:
* elhash.c (struct Lisp_Hash_Table):
* elhash.c (finalize_hash_table):
* elhash.c (make_general_lisp_hash_table):
* elhash.c (Fcopy_hash_table):
* elhash.h (htentry):
* emacs.c (main_1):
* eval.c:
* eval.c (size_multiple_value):
* event-stream.c (finalize_command_builder):
* event-stream.c (allocate_command_builder):
* event-stream.c (free_command_builder):
* event-stream.c (event_stream_generate_wakeup):
* event-stream.c (event_stream_resignal_wakeup):
* event-stream.c (event_stream_disable_wakeup):
* event-stream.c (event_stream_wakeup_pending_p):
* events.h (struct Lisp_Timeout):
* events.h (struct command_builder):
* extents-impl.h:
* extents-impl.h (struct extent_auxiliary):
* extents-impl.h (struct extent_info):
* extents-impl.h (set_extent_no_chase_aux_field):
* extents-impl.h (set_extent_no_chase_normal_field):
* extents.c:
* extents.c (gap_array_marker):
* extents.c (gap_array):
* extents.c (extent_list_marker):
* extents.c (extent_list):
* extents.c (stack_of_extents):
* extents.c (gap_array_make_marker):
* extents.c (extent_list_make_marker):
* extents.c (allocate_extent_list):
* extents.c (SLOT):
* extents.c (mark_extent_auxiliary):
* extents.c (allocate_extent_auxiliary):
* extents.c (attach_extent_auxiliary):
* extents.c (size_gap_array):
* extents.c (finalize_extent_info):
* extents.c (allocate_extent_info):
* extents.c (uninit_buffer_extents):
* extents.c (allocate_soe):
* extents.c (copy_extent):
* extents.c (vars_of_extents):
* extents.h:
* faces.c (allocate_face):
* faces.h (struct Lisp_Face):
* faces.h (struct face_cachel):
* file-coding.c:
* file-coding.c (finalize_coding_system):
* file-coding.c (sizeof_coding_system):
* file-coding.c (Fcopy_coding_system):
* file-coding.h (struct Lisp_Coding_System):
* file-coding.h (MARKED_SLOT):
* fns.c (size_bit_vector):
* font-mgr.c:
* font-mgr.c (finalize_fc_pattern):
* font-mgr.c (print_fc_pattern):
* font-mgr.c (Ffc_pattern_p):
* font-mgr.c (Ffc_pattern_create):
* font-mgr.c (Ffc_name_parse):
* font-mgr.c (Ffc_name_unparse):
* font-mgr.c (Ffc_pattern_duplicate):
* font-mgr.c (Ffc_pattern_add):
* font-mgr.c (Ffc_pattern_del):
* font-mgr.c (Ffc_pattern_get):
* font-mgr.c (fc_config_create_using):
* font-mgr.c (fc_strlist_to_lisp_using):
* font-mgr.c (fontset_to_list):
* font-mgr.c (Ffc_config_p):
* font-mgr.c (Ffc_config_up_to_date):
* font-mgr.c (Ffc_config_build_fonts):
* font-mgr.c (Ffc_config_get_cache):
* font-mgr.c (Ffc_config_get_fonts):
* font-mgr.c (Ffc_config_set_current):
* font-mgr.c (Ffc_config_get_blanks):
* font-mgr.c (Ffc_config_get_rescan_interval):
* font-mgr.c (Ffc_config_set_rescan_interval):
* font-mgr.c (Ffc_config_app_font_add_file):
* font-mgr.c (Ffc_config_app_font_add_dir):
* font-mgr.c (Ffc_config_app_font_clear):
* font-mgr.c (size):
* font-mgr.c (Ffc_config_substitute):
* font-mgr.c (Ffc_font_render_prepare):
* font-mgr.c (Ffc_font_match):
* font-mgr.c (Ffc_font_sort):
* font-mgr.c (finalize_fc_config):
* font-mgr.c (print_fc_config):
* font-mgr.h:
* font-mgr.h (struct fc_pattern):
* font-mgr.h (XFC_PATTERN):
* font-mgr.h (struct fc_config):
* font-mgr.h (XFC_CONFIG):
* frame-gtk.c (allocate_gtk_frame_struct):
* frame-impl.h (struct frame):
* frame-msw.c (mswindows_init_frame_1):
* frame-x.c (allocate_x_frame_struct):
* frame.c (nuke_all_frame_slots):
* frame.c (allocate_frame_core):
* gc.c:
* gc.c (GC_CHECK_NOT_FREE):
* glyphs.c (finalize_image_instance):
* glyphs.c (allocate_image_instance):
* glyphs.c (Fcolorize_image_instance):
* glyphs.c (allocate_glyph):
* glyphs.c (unmap_subwindow_instance_cache_mapper):
* glyphs.c (register_ignored_expose):
* glyphs.h (struct Lisp_Image_Instance):
* glyphs.h (struct Lisp_Glyph):
* glyphs.h (struct glyph_cachel):
* glyphs.h (struct expose_ignore):
* gui.c (allocate_gui_item):
* gui.h (struct Lisp_Gui_Item):
* keymap.c (struct Lisp_Keymap):
* keymap.c (make_keymap):
* lisp.h:
* lisp.h (struct Lisp_String_Direct_Data):
* lisp.h (struct Lisp_String_Indirect_Data):
* lisp.h (struct Lisp_Vector):
* lisp.h (struct Lisp_Bit_Vector):
* lisp.h (DECLARE_INLINE_LISP_BIT_VECTOR):
* lisp.h (struct weak_box):
* lisp.h (struct ephemeron):
* lisp.h (struct weak_list):
* lrecord.h:
* lrecord.h (struct lrecord_implementation):
* lrecord.h (MC_ALLOC_CALL_FINALIZER):
* lrecord.h (struct lcrecord_list):
* lstream.c (finalize_lstream):
* lstream.c (sizeof_lstream):
* lstream.c (Lstream_new):
* lstream.c (Lstream_delete):
* lstream.h (struct lstream):
* marker.c:
* marker.c (finalize_marker):
* marker.c (compute_buffer_marker_usage):
* mule-charset.c:
* mule-charset.c (make_charset):
* mule-charset.c (compute_charset_usage):
* objects-impl.h (struct Lisp_Color_Instance):
* objects-impl.h (struct Lisp_Font_Instance):
* objects-tty-impl.h (struct tty_color_instance_data):
* objects-tty-impl.h (struct tty_font_instance_data):
* objects-tty.c (tty_initialize_color_instance):
* objects-tty.c (tty_initialize_font_instance):
* objects.c (finalize_color_instance):
* objects.c (Fmake_color_instance):
* objects.c (finalize_font_instance):
* objects.c (Fmake_font_instance):
* objects.c (reinit_vars_of_objects):
* opaque.c:
* opaque.c (sizeof_opaque):
* opaque.c (make_opaque_ptr):
* opaque.c (free_opaque_ptr):
* opaque.h:
* opaque.h (Lisp_Opaque):
* opaque.h (Lisp_Opaque_Ptr):
* print.c (printing_unreadable_lcrecord):
* print.c (external_object_printer):
* print.c (debug_p4):
* process.c (finalize_process):
* process.c (make_process_internal):
* procimpl.h (struct Lisp_Process):
* rangetab.c (Fmake_range_table):
* rangetab.c (Fcopy_range_table):
* rangetab.h (struct Lisp_Range_Table):
* scrollbar.c:
* scrollbar.c (create_scrollbar_instance):
* scrollbar.c (compute_scrollbar_instance_usage):
* scrollbar.h (struct scrollbar_instance):
* specifier.c (finalize_specifier):
* specifier.c (sizeof_specifier):
* specifier.c (set_specifier_caching):
* specifier.h (struct Lisp_Specifier):
* specifier.h (struct specifier_caching):
* symeval.h:
* symeval.h (SYMBOL_VALUE_MAGIC_P):
* symeval.h (DEFVAR_SYMVAL_FWD):
* symsinit.h:
* syntax.c (init_buffer_syntax_cache):
* syntax.h (struct syntax_cache):
* toolbar.c:
* toolbar.c (allocate_toolbar_button):
* toolbar.c (update_toolbar_button):
* toolbar.h (struct toolbar_button):
* tooltalk.c (struct Lisp_Tooltalk_Message):
* tooltalk.c (make_tooltalk_message):
* tooltalk.c (struct Lisp_Tooltalk_Pattern):
* tooltalk.c (make_tooltalk_pattern):
* ui-gtk.c:
* ui-gtk.c (allocate_ffi_data):
* ui-gtk.c (emacs_gtk_object_finalizer):
* ui-gtk.c (allocate_emacs_gtk_object_data):
* ui-gtk.c (allocate_emacs_gtk_boxed_data):
* ui-gtk.h:
* window-impl.h (struct window):
* window-impl.h (struct window_mirror):
* window.c (finalize_window):
* window.c (allocate_window):
* window.c (new_window_mirror):
* window.c (mark_window_as_deleted):
* window.c (make_dummy_parent):
* window.c (compute_window_mirror_usage):
* window.c (compute_window_usage):
Overall point of this change and previous ones in this repository:
(1) Introduce new, clearer terminology: everything other than int
or char is a "record" object, which comes in two types: "normal
objects" and "frob-block objects". Fix up all places that
referred to frob-block objects as "simple", "basic", etc.
(2) Provide an advertised interface for doing operations on Lisp
objects, including creating new types, that is clean and
consistent in its naming, uses the above-referenced terms and
avoids referencing "lrecords", "old lcrecords", etc., which should
hide under the surface.
(3) Make the size_in_bytes and finalizer methods take a
Lisp_Object rather than a void * for consistency with other methods.
(4) Separate finalizer method into finalizer and disksaver, so
that normal finalize methods don't have to worry about disksaving.
Other specifics:
(1) Renaming:
LISP_OBJECT_HEADER -> NORMAL_LISP_OBJECT_HEADER
ALLOC_LISP_OBJECT -> ALLOC_NORMAL_LISP_OBJECT
implementation->basic_p -> implementation->frob_block_p
ALLOCATE_FIXED_TYPE_AND_SET_IMPL -> ALLOC_FROB_BLOCK_LISP_OBJECT
*FCCONFIG*, wrap_fcconfig -> *FC_CONFIG*, wrap_fc_config
*FCPATTERN*, wrap_fcpattern -> *FC_PATTERN*, wrap_fc_pattern
(the last two changes make the naming of these macros consistent
with the naming of all other macros, since the objects are named
fc-config and fc-pattern with a hyphen)
(2) Lots of documentation fixes in lrecord.h.
(3) Eliminate macros for copying, freeing, zeroing objects, getting
their storage size. Instead, new functions:
zero_sized_lisp_object()
zero_nonsized_lisp_object()
lisp_object_storage_size()
free_normal_lisp_object()
(copy_lisp_object() already exists)
LISP_OBJECT_FROB_BLOCK_P() (actually a macro)
Eliminated:
free_lrecord()
zero_lrecord()
copy_lrecord()
copy_sized_lrecord()
old_copy_lcrecord()
old_copy_sized_lcrecord()
old_zero_lcrecord()
old_zero_sized_lcrecord()
LISP_OBJECT_STORAGE_SIZE()
COPY_SIZED_LISP_OBJECT()
COPY_SIZED_LCRECORD()
COPY_LISP_OBJECT()
ZERO_LISP_OBJECT()
FREE_LISP_OBJECT()
(4) Catch the remaining places where lrecord stuff was used directly
and use the advertised interface, e.g. alloc_sized_lrecord() ->
ALLOC_SIZED_LISP_OBJECT().
(5) Make certain statically-declared pseudo-objects
(buffer_local_flags, console_local_flags) have their lheader
initialized correctly, so things like copy_lisp_object() can work
on them. Make extent_auxiliary_defaults a proper heap object
Vextent_auxiliary_defaults, and make extent auxiliaries dumpable
so that this object can be dumped. allocate_extent_auxiliary()
now just creates the object, and attach_extent_auxiliary()
creates an extent auxiliary and attaches to an extent, like the
old allocate_extent_auxiliary().
(6) Create EXTENT_AUXILIARY_SLOTS macro, similar to the foo-slots.h
files but in a macro instead of a file. The purpose is to avoid
duplication when iterating over all the slots in an extent auxiliary.
Use it.
(7) In lstream.c, don't zero out object after allocation because
allocation routines take care of this.
(8) In marker.c, fix a mistake in computing marker overhead.
(9) In print.c, clean up printing_unreadable_lcrecord(),
external_object_printer() to avoid lots of ifdef NEW_GC's.
(10) Separate toolbar-button allocation into a separate
allocate_toolbar_button() function for use in the example code
in lrecord.h.
author | Ben Wing <ben@xemacs.org> |
---|---|
date | Fri, 05 Mar 2010 04:08:17 -0600 |
parents | 726060ee587c |
children | ade4c7e2c6cb |
line wrap: on
line source
/* The lwlib interface to Motif widgets. Copyright (C) 1992, 1993, 1994 Lucid, Inc. Copyright (C) 1995 Tinker Systems and INS Engineering Corp. This file is part of the Lucid Widget Library. 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 2, 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 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 XEmacs; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include <config.h> #include <stdlib.h> #include <string.h> #include <stdio.h> #include <limits.h> #ifdef HAVE_UNISTD_H #include <unistd.h> #endif #include <X11/StringDefs.h> #include <X11/IntrinsicP.h> #include <X11/ObjectP.h> #include <X11/CoreP.h> #include <X11/CompositeP.h> #include "lwlib-Xm.h" #include "lwlib-utils.h" #include <Xm/Xm.h> #include <Xm/BulletinB.h> #include <Xm/CascadeB.h> #include <Xm/DrawingA.h> #include <Xm/FileSB.h> #include <Xm/Label.h> #include <Xm/List.h> #include <Xm/MenuShell.h> #include <Xm/MessageB.h> #include <Xm/PushB.h> #include <Xm/PushBG.h> #include <Xm/ArrowB.h> #include <Xm/ScrollBar.h> #include <Xm/SelectioB.h> #include <Xm/Text.h> #include <Xm/TextF.h> #include <Xm/ToggleB.h> #include <Xm/ToggleBG.h> #include <Xm/RowColumn.h> #include <Xm/ScrolledW.h> #include <Xm/Separator.h> #include <Xm/DialogS.h> #include <Xm/Form.h> #ifdef LWLIB_WIDGETS_MOTIF #include <Xm/Scale.h> #if XmVERSION > 1 #include <Xm/ComboBoxP.h> #endif #endif #ifdef LWLIB_MENUBARS_MOTIF static void xm_pull_down_callback (Widget, XtPointer, XtPointer); #endif static void xm_internal_update_other_instances (Widget, XtPointer, XtPointer); /* static void xm_pop_down_callback (Widget, XtPointer, XtPointer); */ static void xm_generic_callback (Widget, XtPointer, XtPointer); #if defined (LWLIB_DIALOGS_MOTIF) || defined (LWLIB_WIDGETS_MOTIF) static void mark_dead_instance_destroyed (Widget widget, XtPointer closure, XtPointer call_data); static void xm_nosel_callback (Widget, XtPointer, XtPointer); #endif #ifdef LWLIB_SCROLLBARS_MOTIF static void xm_scrollbar_callback (Widget, XtPointer, XtPointer); #endif #ifdef LWLIB_MENUBARS_MOTIF static void xm_update_menu (widget_instance* instance, Widget widget, widget_value* val, Boolean deep_p); #endif /* Structures to keep destroyed instances */ typedef struct _destroyed_instance { char* name; char* type; Widget widget; Widget parent; Boolean pop_up_p; struct _destroyed_instance* next; } destroyed_instance; static destroyed_instance* all_destroyed_instances = NULL; /* Utility function. */ static char * safe_strdup (char* s) { char *result; if (! s) return 0; result = (char *) malloc (strlen (s) + 1); if (! result) return 0; strcpy (result, s); return result; } static destroyed_instance* make_destroyed_instance (char* name, char* type, Widget widget, Widget parent, Boolean pop_up_p) { destroyed_instance* instance = (destroyed_instance*) malloc (sizeof (destroyed_instance)); instance->name = safe_strdup (name); instance->type = safe_strdup (type); instance->widget = widget; instance->parent = parent; instance->pop_up_p = pop_up_p; instance->next = NULL; return instance; } #ifdef LWLIB_DIALOGS_MOTIF static void free_destroyed_instance (destroyed_instance* instance) { free (instance->name); free (instance->type); free (instance); } #endif /* LWLIB_DIALOGS_MOTIF */ /* motif utility functions */ Widget first_child (Widget widget) { return ((CompositeWidget)widget)->composite.children [0]; } Boolean lw_motif_widget_p (Widget widget) { return #ifdef LWLIB_DIALOGS_MOTIF XtClass (widget) == xmDialogShellWidgetClass || #endif XmIsPrimitive (widget) || XmIsManager (widget) || XmIsGadget (widget); } static char * resource_string (Widget widget, char *name) { XtResource resource; char *result = NULL; resource.resource_name = "labelString"; resource.resource_class = "LabelString"; /* #### should be Xmsomething... */ resource.resource_type = XtRString; resource.resource_size = sizeof (String); resource.resource_offset = 0; resource.default_type = XtRImmediate; resource.default_addr = 0; XtGetSubresources (widget, (XtPointer)&result, name, name, &resource, 1, NULL, 0); return result; } #ifdef LWLIB_DIALOGS_MOTIF static Boolean is_in_dialog_box (Widget w) { Widget wmshell; wmshell = XtParent (w); while (wmshell && (XtClass (wmshell) != xmDialogShellWidgetClass)) wmshell = XtParent (wmshell); if (wmshell && XtClass (wmshell) == xmDialogShellWidgetClass) return True; else return False; } #endif /* LWLIB_DIALOGS_MOTIF */ #if defined (LWLIB_DIALOGS_MOTIF) || defined (LWLIB_MENUBARS_MOTIF) || defined (LWLIB_WIDGETS_MOTIF) /* update the label of anything subclass of a label */ static void xm_update_label (widget_instance* UNUSED (instance), Widget widget, widget_value* val) { XmString built_string = NULL; XmString key_string = NULL; XmString val_string = NULL; XmString name_string = NULL; Arg al [20]; int ac = 0; int type; /* Don't clobber pixmap types. */ Xt_GET_VALUE (widget, XmNlabelType, &type); if (type == XmPIXMAP) return; if (val->value) { /* #### Temporary fix. I though Motif was supposed to grok %_ type things. */ lw_remove_accelerator_spec (val->value); #ifdef LWLIB_DIALOGS_MOTIF /* * Sigh. The main text of a label is the name field for menubar * entries. The value field is a possible additional field to be * concatenated on to the name field. HOWEVER, with dialog boxes * the value field is the complete text which is supposed to be * displayed as the label. Yuck. */ if (is_in_dialog_box (widget)) { char *value_name = NULL; value_name = resource_string (widget, val->value); if (!value_name) value_name = val->value; built_string = XmStringCreateLtoR (value_name, XmSTRING_DEFAULT_CHARSET); } else #endif /* LWLIB_DIALOGS_MOTIF */ { char *value_name = NULL; char *res_name = NULL; res_name = resource_string (widget, val->name); /* Concatenating the value with itself seems just plain daft. */ if (!res_name) { built_string = XmStringCreateLtoR (val->value, XmSTRING_DEFAULT_CHARSET); } else { name_string = XmStringCreateLtoR (res_name, XmSTRING_DEFAULT_CHARSET); value_name = XtMalloc (strlen (val->value) + 2); *value_name = 0; strcat (value_name, " "); strcat (value_name, val->value); val_string = XmStringCreateLtoR (value_name, XmSTRING_DEFAULT_CHARSET); built_string = XmStringConcat (name_string, val_string); XtFree (value_name); } } Xt_SET_ARG (al [ac], XmNlabelString, built_string); ac++; Xt_SET_ARG (al [ac], XmNlabelType, XmSTRING); ac++; } if (val->key) { key_string = XmStringCreateLtoR (val->key, XmSTRING_DEFAULT_CHARSET); Xt_SET_ARG (al [ac], XmNacceleratorText, key_string); ac++; } if (ac) XtSetValues (widget, al, ac); if (built_string) XmStringFree (built_string); if (key_string) XmStringFree (key_string); if (name_string) XmStringFree (name_string); if (val_string) XmStringFree (val_string); } static void xm_safe_update_label (widget_instance* instance, Widget widget, widget_value* val) { /* Don't clobber non-labels. */ if (XtIsSubclass (widget, xmLabelWidgetClass)) xm_update_label (instance, widget, val); } #endif /* defined (LWLIB_DIALOGS_MOTIF) || defined (LWLIB_MENUBARS_MOTIF) */ /* update of list */ static void xm_update_list (widget_instance* instance, Widget widget, widget_value* val) { widget_value* cur; int i; XtRemoveAllCallbacks (widget, XmNsingleSelectionCallback); XtAddCallback (widget, XmNsingleSelectionCallback, xm_generic_callback, instance); for (cur = val->contents, i = 0; cur; cur = cur->next) if (cur->value) { XmString xmstr = XmStringCreate (cur->value, XmSTRING_DEFAULT_CHARSET); i += 1; XmListAddItem (widget, xmstr, 0); if (cur->selected) XmListSelectPos (widget, i, False); XmStringFree (xmstr); } } /* update of buttons */ static void xm_update_pushbutton (widget_instance* instance, Widget widget, widget_value* UNUSED (val)) { Xt_SET_VALUE (widget, XmNalignment, XmALIGNMENT_CENTER); XtRemoveAllCallbacks (widget, XmNactivateCallback); XtAddCallback (widget, XmNactivateCallback, xm_generic_callback, instance); } #ifdef LWLIB_WIDGETS_MOTIF static void xm_update_progress (widget_instance* UNUSED (instance), Widget scale, widget_value* val) { Arg al[20]; int ac = 0; Dimension height = 0; Dimension width = 0; if (!val->call_data) { Xt_SET_ARG (al [ac], XmNeditable, False); ac++; } else { Xt_SET_ARG (al [ac], XmNeditable, val->enabled); ac++; } height = (Dimension) lw_get_value_arg (val, XtNheight); width = (Dimension) lw_get_value_arg (val, XtNwidth); if (height > 0) { Xt_SET_ARG (al [ac], XmNscaleHeight, height); ac++; } if (width > 0) { Xt_SET_ARG (al [ac], XmNscaleWidth, width); ac++; } XtSetValues (scale, al, ac); } #endif /* LWLIB_WIDGETS_MOTIF */ #ifdef LWLIB_MENUBARS_MOTIF static void xm_update_cascadebutton (widget_instance* instance, Widget widget, widget_value* val) { /* Should also rebuild the menu by calling ...update_menu... */ if (val && val->type == CASCADE_TYPE && val->contents && val->contents->type == INCREMENTAL_TYPE) { /* okay, we're now doing a lisp callback to incrementally generate more of the menu. */ XtRemoveAllCallbacks (widget, XmNcascadingCallback); XtAddCallback (widget, XmNcascadingCallback, xm_pull_down_callback, instance); XtCallCallbacks ((Widget)widget, XmNcascadingCallback, (XtPointer)val->contents); } else { XtRemoveAllCallbacks (widget, XmNcascadingCallback); XtAddCallback (widget, XmNcascadingCallback, xm_pull_down_callback, instance); } } #endif /* LWLIB_MENUBARS_MOTIF */ /* update toggle and radiobox */ static void xm_update_toggle (widget_instance* instance, Widget widget, widget_value* val) { Arg al [2]; XtRemoveAllCallbacks (widget, XmNvalueChangedCallback); XtAddCallback (widget, XmNvalueChangedCallback, xm_generic_callback, instance); Xt_SET_ARG (al [0], XmNset, val->selected); Xt_SET_ARG (al [1], XmNalignment, XmALIGNMENT_BEGINNING); XtSetValues (widget, al, 1); } static void xm_update_radiobox (widget_instance* instance, Widget widget, widget_value* val) { Widget toggle; widget_value* cur; /* update the callback */ XtRemoveAllCallbacks (widget, XmNentryCallback); XtAddCallback (widget, XmNentryCallback, xm_generic_callback, instance); /* first update all the toggles */ /* Energize kernel interface is currently bad. It sets the selected widget with the selected flag but returns it by its name. So we currently have to support both setting the selection with the selected slot of val contents and setting it with the "value" slot of val. The latter has a higher priority. This to be removed when the kernel is fixed. */ for (cur = val->contents; cur; cur = cur->next) { toggle = XtNameToWidget (widget, cur->value); if (toggle) { Arg al [2]; Xt_SET_ARG (al [0], XmNsensitive, cur->enabled); Xt_SET_ARG (al [1], XmNset, (!val->value && cur->selected ? cur->selected : False)); XtSetValues (toggle, al, 2); } } /* The selected was specified by the value slot */ if (val->value) { toggle = XtNameToWidget (widget, val->value); if (toggle) Xt_SET_VALUE (toggle, XmNset, True); } } #if defined (LWLIB_WIDGETS_MOTIF) && XmVERSION > 1 /* update of combo box */ static void xm_update_combo_box (widget_instance* instance, Widget widget, widget_value* val) { widget_value* cur; int i; XtRemoveAllCallbacks (widget, XmNselectionCallback); XtAddCallback (widget, XmNselectionCallback, xm_generic_callback, instance); for (cur = val->contents, i = 0; cur; cur = cur->next) if (cur->value) { XmString xmstr = XmStringCreate (cur->value, XmSTRING_DEFAULT_CHARSET); i += 1; XmListAddItem (CB_List (widget), xmstr, 0); if (cur->selected) XmListSelectPos (CB_List (widget), i, False); XmStringFree (xmstr); } } #endif #ifdef LWLIB_MENUBARS_MOTIF /* update a popup menu, pulldown menu or a menubar */ static void make_menu_in_widget (widget_instance* instance, Widget widget, widget_value* val) { Widget* children = 0; int num_children; int child_index; widget_value* cur; Widget button = 0; Widget menu; Arg al [256]; int ac; Boolean menubar_p = False; /* 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... */ Xt_GET_VALUE (widget, XmNisHomogeneous, &menubar_p); /* add the unmap callback for popups and pulldowns */ /*** this sounds bogus ***/ /* probably because it is -- cet */ /* if (!menubar_p) XtAddCallback (XtParent (widget), XmNpopdownCallback, xm_pop_down_callback, (XtPointer)instance); */ num_children = 0; for (child_index = 0, cur = val; cur; child_index++, cur = cur->next) { ac = 0; button = 0; Xt_SET_ARG (al [ac], XmNsensitive, cur->enabled); ac++; Xt_SET_ARG (al [ac], XmNalignment, XmALIGNMENT_BEGINNING); ac++; Xt_SET_ARG (al [ac], XmNuserData, cur->call_data); ac++; switch (cur->type) { case PUSHRIGHT_TYPE: /* A pushright marker which is not needed for the real Motif menubar. */ break; case SEPARATOR_TYPE: ac = 0; if (cur->value) { /* #### - xlwmenu.h supports several types that motif does not. Also, motif supports pixmaps w/ type NO_LINE and lwlib provides no way to access that functionality. --Stig */ Xt_SET_ARG (al [ac], XmNseparatorType, cur->value); ac++; } button = XmCreateSeparator (widget, "separator", al, ac); break; case CASCADE_TYPE: menu = XmCreatePulldownMenu (widget, "pulldown", NULL, 0); make_menu_in_widget (instance, menu, cur->contents); Xt_SET_ARG (al [ac], XmNsubMenuId, menu); ac++; button = XmCreateCascadeButton (widget, cur->name, al, ac); xm_safe_update_label (instance, button, cur); XtAddCallback (button, XmNcascadingCallback, xm_pull_down_callback, (XtPointer)instance); break; default: if (menubar_p) button = XmCreateCascadeButton (widget, cur->name, al, ac); else if (!cur->call_data) button = XmCreateLabel (widget, cur->name, al, ac); else if (cur->type == TOGGLE_TYPE || cur->type == RADIO_TYPE) { Xt_SET_ARG (al [ac], XmNindicatorType, (cur->type == TOGGLE_TYPE ? XmN_OF_MANY : XmONE_OF_MANY)); ac++; Xt_SET_ARG (al [ac], XmNvisibleWhenOff, True); ac++; button = XmCreateToggleButtonGadget (widget, cur->name, al, ac); } else button = XmCreatePushButtonGadget (widget, cur->name, al, ac); xm_safe_update_label (instance, button, cur); /* don't add a callback to a simple label */ if (cur->type == TOGGLE_TYPE || cur->type == RADIO_TYPE) xm_update_toggle (instance, button, cur); else if (cur->call_data) XtAddCallback (button, XmNactivateCallback, xm_generic_callback, (XtPointer)instance); } /* switch (cur->type) */ if (button) children [num_children++] = button; } /* Last entry is the help button. This used be done after managing the buttons. The comment claimed that it had to be done this way otherwise the menubar ended up only 4 pixels high. That must have been in the Old World. In the New World it stays the proper height if you don't manage them until after you set this and as a bonus the Help menu ends up where it is supposed to. */ if (button) Xt_SET_VALUE (widget, XmNmenuHelpWidget, button); if (num_children) XtManageChildren (children, num_children); XtFree ((char *) children); } static void update_one_menu_entry (widget_instance* instance, Widget widget, widget_value* val, Boolean deep_p) { Arg al [2]; int ac; Widget menu; widget_value* contents; if (val->change == NO_CHANGE) return; /* update the sensitivity and userdata */ /* Common to all widget types */ Xt_SET_ARG (al [0], XmNsensitive, val->enabled); Xt_SET_ARG (al [1], XmNuserData, val->call_data); XtSetValues (widget, al, 2); /* update the menu button as a label. */ if (val->change >= VISIBLE_CHANGE) { xm_safe_update_label (instance, widget, val); if (XtClass (widget) == xmToggleButtonWidgetClass || XtClass (widget) == xmToggleButtonGadgetClass) { xm_update_toggle (instance, widget, val); } } /* update the pulldown/pullaside as needed */ menu = NULL; Xt_GET_VALUE (widget, XmNsubMenuId, &menu); contents = val->contents; if (!menu) { if (contents) { menu = XmCreatePulldownMenu (widget, "pulldown", NULL, 0); make_menu_in_widget (instance, menu, contents); Xt_SET_VALUE (widget, XmNsubMenuId, menu); } } else if (!contents) { Xt_SET_VALUE (widget, XmNsubMenuId, NULL); XtDestroyWidget (menu); } else if (deep_p && contents->change != NO_CHANGE) xm_update_menu (instance, menu, val, 1); } static void xm_update_menu (widget_instance* instance, Widget widget, widget_value* val, Boolean deep_p) { /* 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) { destroy_all_children (widget); make_menu_in_widget (instance, widget, val->contents); } else { /* Update all the buttons of the RowColumn in order. */ Widget* children; unsigned int num_children; int i; widget_value *cur = 0; children = XtCompositeChildren (widget, &num_children); if (children) { for (i = 0, cur = val->contents; i < num_children; i++) { if (!cur) abort (); /* skip if this is a pushright marker or a separator */ if (cur->type == PUSHRIGHT_TYPE || cur->type == SEPARATOR_TYPE) { cur = cur->next; #if 0 /* #### - this could puke if you have a separator as the last item on a pullright menu. */ if (!cur) abort (); #else if (!cur) continue; #endif } 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; } XtFree ((char *) children); } if (cur) abort (); } } #endif /* LWLIB_MENUBARS_MOTIF */ /* update text widgets */ static void xm_update_text (widget_instance* instance, Widget widget, widget_value* val) { XmTextSetString (widget, val->value ? val->value : (char *) ""); XtRemoveAllCallbacks (widget, XmNactivateCallback); XtAddCallback (widget, XmNactivateCallback, xm_generic_callback, instance); XtRemoveAllCallbacks (widget, XmNvalueChangedCallback); XtAddCallback (widget, XmNvalueChangedCallback, xm_internal_update_other_instances, instance); } static void xm_update_text_field (widget_instance* instance, Widget widget, widget_value* val) { XmTextFieldSetString (widget, val->value ? val->value : (char *) ""); XtRemoveAllCallbacks (widget, XmNactivateCallback); XtAddCallback (widget, XmNactivateCallback, xm_generic_callback, instance); XtRemoveAllCallbacks (widget, XmNvalueChangedCallback); XtAddCallback (widget, XmNvalueChangedCallback, xm_internal_update_other_instances, instance); } #ifdef LWLIB_SCROLLBARS_MOTIF /* * If this function looks like it does a lot more work than it needs to, * you're right. Blame the Motif scrollbar for not being smart about * updating its appearance. */ static void xm_update_scrollbar (widget_instance *instance, Widget widget, widget_value *val) { if (val->scrollbar_data) { scrollbar_values *data = val->scrollbar_data; int widget_sliderSize, widget_val; int new_sliderSize, new_value; double percent; double h_water, l_water; Arg al [4]; /* First size and position the scrollbar widget. */ Xt_SET_ARG (al [0], XtNx, data->scrollbar_x); Xt_SET_ARG (al [1], XtNy, data->scrollbar_y); Xt_SET_ARG (al [2], XtNwidth, data->scrollbar_width); Xt_SET_ARG (al [3], XtNheight, data->scrollbar_height); XtSetValues (widget, al, 4); /* Now size the scrollbar's slider. */ Xt_SET_ARG (al [0], XmNsliderSize, &widget_sliderSize); Xt_SET_ARG (al [1], XmNvalue, &widget_val); XtGetValues (widget, al, 2); percent = (double) data->slider_size / (double) (data->maximum - data->minimum); new_sliderSize = (int) ((double) (INT_MAX - 1) * percent); percent = (double) (data->slider_position - data->minimum) / (double) (data->maximum - data->minimum); new_value = (int) ((double) (INT_MAX - 1) * percent); if (new_sliderSize > (INT_MAX - 1)) new_sliderSize = INT_MAX - 1; else if (new_sliderSize < 1) new_sliderSize = 1; if (new_value > (INT_MAX - new_sliderSize)) new_value = INT_MAX - new_sliderSize; else if (new_value < 1) new_value = 1; h_water = 1.05; l_water = 0.95; if (new_sliderSize != widget_sliderSize || new_value != widget_val) { int force = ((INT_MAX - widget_sliderSize - widget_val) ? 0 : (INT_MAX - new_sliderSize - new_value)); if (force || (double)new_sliderSize < (l_water * (double)widget_sliderSize) || (double)new_sliderSize > (h_water * (double)widget_sliderSize) || (double)new_value < (l_water * (double)widget_val) || (double)new_value > (h_water * (double)widget_val)) { XmScrollBarSetValues (widget, new_value, new_sliderSize, 1, 1, False); } } } } #endif /* LWLIB_SCROLLBARS_MOTIF */ /* update a motif widget */ void xm_update_one_widget (widget_instance* instance, Widget widget, widget_value* val, #ifdef LWLIB_MENUBARS_MOTIF Boolean deep_p #else Boolean UNUSED (deep_p) #endif ) { WidgetClass class_; Arg al [20]; int ac = 0; /* Mark as not edited */ val->edited = False; /* Common to all widget types */ Xt_SET_ARG (al [ac], XmNsensitive, val->enabled); ac++; Xt_SET_ARG (al [ac], XmNuserData, val->call_data); ac++; XtSetValues (widget, al, ac); #if defined (LWLIB_DIALOGS_MOTIF) || defined (LWLIB_MENUBARS_MOTIF) || defined (LWLIB_WIDGETS_MOTIF) /* Common to all label like widgets */ xm_safe_update_label (instance, widget, val); #endif class_ = XtClass (widget); /* Class specific things */ if (class_ == xmPushButtonWidgetClass || class_ == xmArrowButtonWidgetClass) { xm_update_pushbutton (instance, widget, val); } #ifdef LWLIB_MENUBARS_MOTIF else if (class_ == xmCascadeButtonWidgetClass) { xm_update_cascadebutton (instance, widget, val); } #endif else if (class_ == xmToggleButtonWidgetClass || class_ == xmToggleButtonGadgetClass) { xm_update_toggle (instance, widget, val); } else if (class_ == xmRowColumnWidgetClass) { Boolean radiobox = 0; Xt_GET_VALUE (widget, XmNradioBehavior, &radiobox); if (radiobox) xm_update_radiobox (instance, widget, val); #ifdef LWLIB_MENUBARS_MOTIF else xm_update_menu (instance, widget, val, deep_p); #endif } else if (class_ == xmTextWidgetClass) { xm_update_text (instance, widget, val); } else if (class_ == xmTextFieldWidgetClass) { xm_update_text_field (instance, widget, val); } else if (class_ == xmListWidgetClass) { xm_update_list (instance, widget, val); } #if defined (LWLIB_WIDGETS_MOTIF) && XmVERSION > 1 else if (class_ == xmComboBoxWidgetClass) { xm_update_combo_box (instance, widget, val); } #endif #ifdef LWLIB_SCROLLBARS_MOTIF else if (class_ == xmScrollBarWidgetClass) { xm_update_scrollbar (instance, widget, val); } #endif #ifdef LWLIB_WIDGETS_MOTIF else if (class_ == xmScaleWidgetClass) { xm_update_progress (instance, widget, val); } #endif /* Lastly update our global arg values. */ if (val->args && val->args->nargs) XtSetValues (widget, val->args->args, val->args->nargs); } /* getting the value back */ void xm_update_one_value (widget_instance* instance, Widget widget, widget_value* val) { WidgetClass class_ = XtClass (widget); widget_value *old_wv; /* copy the call_data slot into the "return" widget_value */ for (old_wv = instance->info->val->contents; old_wv; old_wv = old_wv->next) if (!strcmp (val->name, old_wv->name)) { val->call_data = old_wv->call_data; break; } if (class_ == xmToggleButtonWidgetClass || class_ == xmToggleButtonGadgetClass) { Xt_GET_VALUE (widget, XmNset, &val->selected); val->edited = True; } else if (class_ == xmTextWidgetClass) { if (val->value) XtFree (val->value); val->value = XmTextGetString (widget); val->edited = True; } else if (class_ == xmTextFieldWidgetClass) { if (val->value) XtFree (val->value); val->value = XmTextFieldGetString (widget); val->edited = True; } else if (class_ == xmRowColumnWidgetClass) { Boolean radiobox = 0; Xt_GET_VALUE (widget, XmNradioBehavior, &radiobox); if (radiobox) { CompositeWidget radio = (CompositeWidget)widget; unsigned int i; for (i = 0; i < radio->composite.num_children; i++) { int set = False; Widget toggle = radio->composite.children [i]; Xt_GET_VALUE (toggle, XmNset, &set); if (set) { if (val->value) free (val->value); val->value = safe_strdup (XtName (toggle)); } } val->edited = True; } } else if (class_ == xmListWidgetClass #if defined (LWLIB_WIDGETS_MOTIF) && XmVERSION > 1 || class_ == xmComboBoxWidgetClass #endif ) { int pos_cnt; int* pos_list; Widget list = widget; #if defined (LWLIB_WIDGETS_MOTIF) && XmVERSION > 1 if (class_ == xmComboBoxWidgetClass) list = CB_List (widget); #endif if (XmListGetSelectedPos (list, &pos_list, &pos_cnt)) { int i; widget_value* cur; for (cur = val->contents, i = 0; cur; cur = cur->next) if (cur->value) { int j; cur->selected = False; i += 1; for (j = 0; j < pos_cnt; j++) if (pos_list [j] == i) { cur->selected = True; val->value = safe_strdup (cur->name); } } val->edited = 1; XtFree ((char *) pos_list); } } #ifdef LWLIB_SCROLLBARS_MOTIF else if (class_ == xmScrollBarWidgetClass) { /* This function is not used by the scrollbar. */ return; } #endif } #ifdef LWLIB_DIALOGS_MOTIF /* 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. I could not find a way to do that with accelerators. */ static void activate_button (Widget UNUSED (widget), XtPointer closure, XtPointer UNUSED (call_data)) { Widget button = (Widget)closure; XtCallCallbacks (button, XmNactivateCallback, NULL); } /* creation functions */ /* dialogs */ #if (XmVersion >= 1002) # define ARMANDACTIVATE_KLUDGE # define DND_KLUDGE #endif #ifdef ARMANDACTIVATE_KLUDGE /* We want typing Return at a dialog box to select the default button; but we're satisfied with having it select the leftmost button instead. In Motif 1.1.5 we could do this by putting this resource in the app-defaults file: *dialog*button1.accelerators:#override\ <KeyPress>Return: ArmAndActivate()\n\ <KeyPress>KP_Enter: ArmAndActivate()\n\ Ctrl<KeyPress>m: ArmAndActivate()\n but that doesn't work with 1.2.1 and I don't understand why. However, doing the equivalent C code does work, with the notable disadvantage that the user can't override it. So that's what we do until we figure out something better.... */ static char button_trans[] = "\ <KeyPress>Return: ArmAndActivate()\n\ <KeyPress>KP_Enter: ArmAndActivate()\n\ Ctrl<KeyPress>m: ArmAndActivate()\n"; #endif /* ARMANDACTIVATE_KLUDGE */ #ifdef DND_KLUDGE /* This is a kludge to disable drag-and-drop in dialog boxes. The symptom was a segv down in libXm somewhere if you used the middle button on a dialog box to begin a drag; when you released the button to make a drop things would lose if you were not over the button where you started the drag (canceling the operation). This was probably due to the fact that the dialog boxes were not set up to handle a drag but were trying to do so anyway for some reason. So we disable drag-and-drop in dialog boxes by turning off the binding for Btn2Down which, by default, initiates a drag. Clearly this is a shitty solution as it only works in default configurations, but... */ static char disable_dnd_trans[] = "<Btn2Down>: "; #endif /* DND_KLUDGE */ static Widget make_dialog (char* UNUSED (name), Widget parent, Boolean pop_up_p, const char* shell_title, const char* icon_name, Boolean text_input_slot, Boolean radio_box, Boolean list, int left_buttons, int right_buttons) { Widget result; Widget form; Widget row; Widget icon; Widget icon_separator; Widget message; Widget value = 0; Widget separator; Widget button = 0; Widget children [16]; /* for the final XtManageChildren */ int n_children; Arg al[64]; /* Arg List */ int ac; /* Arg Count */ int i; #ifdef DND_KLUDGE XtTranslations dnd_override = XtParseTranslationTable (disable_dnd_trans); # define DO_DND_KLUDGE(widget) XtOverrideTranslations ((widget), dnd_override) #else /* ! DND_KLUDGE */ # define DO_DND_KLUDGE(widget) #endif /* ! DND_KLUDGE */ if (pop_up_p) { ac = 0; Xt_SET_ARG(al[ac], XmNtitle, shell_title); ac++; Xt_SET_ARG(al[ac], XtNallowShellResize, True); ac++; Xt_SET_ARG(al[ac], XmNdeleteResponse, XmUNMAP); ac++; result = XmCreateDialogShell (parent, "dialog", al, ac); Xt_SET_ARG(al[ac], XmNautoUnmanage, FALSE); ac++; /* Xt_SET_ARG(al[ac], XmNautoUnmanage, TRUE); ac++; */ /* ####is this ok? */ Xt_SET_ARG(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; form = XmCreateForm (result, (char *) shell_title, al, ac); } else { ac = 0; Xt_SET_ARG(al[ac], XmNautoUnmanage, FALSE); ac++; Xt_SET_ARG(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; form = XmCreateForm (parent, (char *) shell_title, al, ac); result = form; } ac = 0; Xt_SET_ARG(al[ac], XmNpacking, XmPACK_COLUMN); ac++; Xt_SET_ARG(al[ac], XmNorientation, XmVERTICAL); ac++; Xt_SET_ARG(al[ac], XmNnumColumns, left_buttons + right_buttons + 1); ac++; Xt_SET_ARG(al[ac], XmNmarginWidth, 0); ac++; Xt_SET_ARG(al[ac], XmNmarginHeight, 0); ac++; Xt_SET_ARG(al[ac], XmNspacing, 13); ac++; Xt_SET_ARG(al[ac], XmNadjustLast, False); ac++; Xt_SET_ARG(al[ac], XmNalignment, XmALIGNMENT_CENTER); ac++; Xt_SET_ARG(al[ac], XmNisAligned, True); ac++; Xt_SET_ARG(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++; Xt_SET_ARG(al[ac], XmNbottomAttachment, XmATTACH_FORM); ac++; Xt_SET_ARG(al[ac], XmNbottomOffset, 13); ac++; Xt_SET_ARG(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++; Xt_SET_ARG(al[ac], XmNleftOffset, 13); ac++; Xt_SET_ARG(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++; Xt_SET_ARG(al[ac], XmNrightOffset, 13); ac++; row = XmCreateRowColumn (form, "row", al, ac); n_children = 0; for (i = 0; i < left_buttons; i++) { char button_name [16]; sprintf (button_name, "button%d", i + 1); ac = 0; if (i == 0) { Xt_SET_ARG(al[ac], XmNhighlightThickness, 1); ac++; Xt_SET_ARG(al[ac], XmNshowAsDefault, TRUE); ac++; } Xt_SET_ARG(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; children [n_children] = XmCreatePushButton (row, button_name, al, ac); DO_DND_KLUDGE (children [n_children]); if (i == 0) { button = children [n_children]; ac = 0; Xt_SET_ARG(al[ac], XmNdefaultButton, button); ac++; XtSetValues (row, al, ac); #ifdef ARMANDACTIVATE_KLUDGE /* See comment above */ { XtTranslations losers = XtParseTranslationTable (button_trans); XtOverrideTranslations (button, losers); XtFree ((char *) losers); } #endif /* ARMANDACTIVATE_KLUDGE */ } n_children++; } /* invisible separator button */ ac = 0; Xt_SET_ARG (al[ac], XmNmappedWhenManaged, FALSE); ac++; children [n_children] = XmCreateLabel (row, "separator_button", al, ac); DO_DND_KLUDGE (children [n_children]); n_children++; for (i = 0; i < right_buttons; i++) { char button_name [16]; sprintf (button_name, "button%d", left_buttons + i + 1); ac = 0; Xt_SET_ARG(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; children [n_children] = XmCreatePushButton (row, button_name, al, ac); DO_DND_KLUDGE (children [n_children]); if (! button) button = children [n_children]; n_children++; } XtManageChildren (children, n_children); ac = 0; Xt_SET_ARG(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++; Xt_SET_ARG(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++; Xt_SET_ARG(al[ac], XmNbottomOffset, 13); ac++; Xt_SET_ARG(al[ac], XmNbottomWidget, row); ac++; Xt_SET_ARG(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++; Xt_SET_ARG(al[ac], XmNleftOffset, 0); ac++; Xt_SET_ARG(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++; Xt_SET_ARG(al[ac], XmNrightOffset, 0); ac++; separator = XmCreateSeparator (form, "", al, ac); ac = 0; Xt_SET_ARG(al[ac], XmNlabelType, XmPIXMAP); ac++; Xt_SET_ARG(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++; Xt_SET_ARG(al[ac], XmNtopOffset, 13); ac++; Xt_SET_ARG(al[ac], XmNbottomAttachment, XmATTACH_NONE); ac++; Xt_SET_ARG(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++; Xt_SET_ARG(al[ac], XmNleftOffset, 13); ac++; Xt_SET_ARG(al[ac], XmNrightAttachment, XmATTACH_NONE); ac++; icon = XmCreateLabel (form, (char *) icon_name, al, ac); DO_DND_KLUDGE (icon); ac = 0; Xt_SET_ARG(al[ac], XmNmappedWhenManaged, FALSE); ac++; Xt_SET_ARG(al[ac], XmNtopAttachment, XmATTACH_WIDGET); ac++; Xt_SET_ARG(al[ac], XmNtopOffset, 6); ac++; Xt_SET_ARG(al[ac], XmNtopWidget, icon); ac++; Xt_SET_ARG(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++; Xt_SET_ARG(al[ac], XmNbottomOffset, 6); ac++; Xt_SET_ARG(al[ac], XmNbottomWidget, separator); ac++; Xt_SET_ARG(al[ac], XmNleftAttachment, XmATTACH_NONE); ac++; Xt_SET_ARG(al[ac], XmNrightAttachment, XmATTACH_NONE); ac++; icon_separator = XmCreateLabel (form, "", al, ac); DO_DND_KLUDGE (icon_separator); if (text_input_slot) { ac = 0; Xt_SET_ARG(al[ac], XmNcolumns, 50); ac++; Xt_SET_ARG(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++; Xt_SET_ARG(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++; Xt_SET_ARG(al[ac], XmNbottomOffset, 13); ac++; Xt_SET_ARG(al[ac], XmNbottomWidget, separator); ac++; Xt_SET_ARG(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++; Xt_SET_ARG(al[ac], XmNleftOffset, 13); ac++; Xt_SET_ARG(al[ac], XmNleftWidget, icon); ac++; Xt_SET_ARG(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++; Xt_SET_ARG(al[ac], XmNrightOffset, 13); ac++; value = XmCreateTextField (form, "value", al, ac); DO_DND_KLUDGE (value); } else if (radio_box) { Widget radio_butt; ac = 0; Xt_SET_ARG(al[ac], XmNmarginWidth, 0); ac++; Xt_SET_ARG(al[ac], XmNmarginHeight, 0); ac++; Xt_SET_ARG(al[ac], XmNspacing, 13); ac++; Xt_SET_ARG(al[ac], XmNalignment, XmALIGNMENT_CENTER); ac++; Xt_SET_ARG(al[ac], XmNorientation, XmHORIZONTAL); ac++; Xt_SET_ARG(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++; Xt_SET_ARG(al[ac], XmNbottomOffset, 13); ac++; Xt_SET_ARG(al[ac], XmNbottomWidget, separator); ac++; Xt_SET_ARG(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++; Xt_SET_ARG(al[ac], XmNleftOffset, 13); ac++; Xt_SET_ARG(al[ac], XmNleftWidget, icon); ac++; Xt_SET_ARG(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++; Xt_SET_ARG(al[ac], XmNrightOffset, 13); ac++; value = XmCreateRadioBox (form, "radiobutton1", al, ac); ac = 0; i = 0; radio_butt = XmCreateToggleButtonGadget (value, "radio1", al, ac); children [i++] = radio_butt; radio_butt = XmCreateToggleButtonGadget (value, "radio2", al, ac); children [i++] = radio_butt; radio_butt = XmCreateToggleButtonGadget (value, "radio3", al, ac); children [i++] = radio_butt; XtManageChildren (children, i); } else if (list) { ac = 0; Xt_SET_ARG(al[ac], XmNvisibleItemCount, 5); ac++; Xt_SET_ARG(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++; Xt_SET_ARG(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++; Xt_SET_ARG(al[ac], XmNbottomOffset, 13); ac++; Xt_SET_ARG(al[ac], XmNbottomWidget, separator); ac++; Xt_SET_ARG(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++; Xt_SET_ARG(al[ac], XmNleftOffset, 13); ac++; Xt_SET_ARG(al[ac], XmNleftWidget, icon); ac++; Xt_SET_ARG(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++; Xt_SET_ARG(al[ac], XmNrightOffset, 13); ac++; value = XmCreateScrolledList (form, "list", al, ac); /* this is the easiest way I found to have the double click in the list activate the default button */ XtAddCallback (value, XmNdefaultActionCallback, activate_button, button); } /* else add nothing; it's a separator */ ac = 0; Xt_SET_ARG(al[ac], XmNalignment, XmALIGNMENT_BEGINNING); ac++; Xt_SET_ARG(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++; Xt_SET_ARG(al[ac], XmNtopOffset, 13); ac++; Xt_SET_ARG(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++; Xt_SET_ARG(al[ac], XmNbottomOffset, 13); ac++; Xt_SET_ARG(al[ac], XmNbottomWidget, text_input_slot || radio_box || list ? value : separator); ac++; Xt_SET_ARG(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++; Xt_SET_ARG(al[ac], XmNleftOffset, 13); ac++; Xt_SET_ARG(al[ac], XmNleftWidget, icon); ac++; Xt_SET_ARG(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++; Xt_SET_ARG(al[ac], XmNrightOffset, 13); ac++; message = XmCreateLabel (form, "message", al, ac); DO_DND_KLUDGE (message); if (list) XtManageChild (value); i = 0; children [i] = row; i++; children [i] = separator; i++; if (text_input_slot || radio_box) { children [i] = value; i++; } children [i] = message; i++; children [i] = icon; i++; children [i] = icon_separator; i++; XtManageChildren (children, i); if (text_input_slot || list) { XtInstallAccelerators (value, button); XmProcessTraversal(value, XmTRAVERSE_CURRENT); } else if (radio_box) { XtInstallAccelerators (form, button); XmProcessTraversal(value, XmTRAVERSE_CURRENT); } /* else we don' need no STEENKIN' assellerators. */ #ifdef DND_KLUDGE XtFree ((char *) dnd_override); #endif #undef DO_DND_KLUDGE return result; } static destroyed_instance* find_matching_instance (widget_instance* instance) { destroyed_instance* cur; destroyed_instance* prev; char* type = instance->info->type; char* name = instance->info->name; for (prev = NULL, cur = all_destroyed_instances; cur; prev = cur, cur = cur->next) { if (!strcmp (cur->name, name) && !strcmp (cur->type, type) && cur->parent == instance->parent && cur->pop_up_p == instance->pop_up_p) { if (prev) prev->next = cur->next; else all_destroyed_instances = cur->next; return cur; } /* do some cleanup */ else if (!cur->widget) { if (prev) prev->next = cur->next; else all_destroyed_instances = cur->next; free_destroyed_instance (cur); cur = prev ? prev : all_destroyed_instances; } } return NULL; } static void recenter_widget (Widget widget) { Widget parent = XtParent (widget); Screen* screen = XtScreen (widget); Dimension screen_width = WidthOfScreen (screen); Dimension screen_height = HeightOfScreen (screen); Dimension parent_width = 0; Dimension parent_height = 0; Dimension child_width = 0; Dimension child_height = 0; Position x; Position y; Arg al [2]; Xt_SET_ARG (al [0], XtNwidth, &child_width); Xt_SET_ARG (al [1], XtNheight, &child_height); XtGetValues (widget, al, 2); Xt_SET_ARG (al [0], XtNwidth, &parent_width); Xt_SET_ARG (al [1], XtNheight, &parent_height); XtGetValues (parent, al, 2); x = (Position) ((parent_width - child_width) / 2); y = (Position) ((parent_height - child_height) / 2); XtTranslateCoords (parent, x, y, &x, &y); if ((Dimension) (x + child_width) > screen_width) x = screen_width - child_width; if (x < 0) x = 0; if ((Dimension) (y + child_height) > screen_height) y = screen_height - child_height; if (y < 0) y = 0; Xt_SET_ARG (al [0], XtNx, x); Xt_SET_ARG (al [1], XtNy, y); XtSetValues (widget, al, 2); } static Widget recycle_instance (destroyed_instance* instance) { Widget widget = instance->widget; /* widget is NULL if the parent was destroyed. */ if (widget) { Widget focus; Widget separator; /* Remove the destroy callback as the instance is not in the list anymore */ XtRemoveCallback (instance->parent, XtNdestroyCallback, mark_dead_instance_destroyed, (XtPointer)instance); /* Give the focus to the initial item */ focus = XtNameToWidget (widget, "*value"); if (!focus) focus = XtNameToWidget (widget, "*button1"); if (focus) XmProcessTraversal(focus, XmTRAVERSE_CURRENT); /* shrink the separator label back to their original size */ separator = XtNameToWidget (widget, "*separator_button"); if (separator) { Arg al [2]; Xt_SET_ARG (al [0], XtNwidth, 5); Xt_SET_ARG (al [1], XtNheight, 5); XtSetValues (separator, al, 2); } /* Center the dialog in its parent */ recenter_widget (widget); } free_destroyed_instance (instance); return widget; } Widget xm_create_dialog (widget_instance* instance) { char* name = instance->info->type; Widget parent = instance->parent; Widget widget; Boolean pop_up_p = instance->pop_up_p; const char* shell_name = 0; const char* icon_name = 0; Boolean text_input_slot = False; Boolean radio_box = False; Boolean list = False; int total_buttons; int left_buttons = 0; int right_buttons = 1; destroyed_instance* dead_one; /* try to find a widget to recycle */ dead_one = find_matching_instance (instance); if (dead_one) { Widget recycled_widget = recycle_instance (dead_one); if (recycled_widget) return recycled_widget; } switch (name [0]){ case 'E': case 'e': icon_name = "dbox-error"; shell_name = "Error"; break; case 'I': case 'i': icon_name = "dbox-info"; shell_name = "Information"; break; case 'L': case 'l': list = True; icon_name = "dbox-question"; shell_name = "Prompt"; break; case 'P': case 'p': text_input_slot = True; icon_name = "dbox-question"; shell_name = "Prompt"; break; case 'Q': case 'q': icon_name = "dbox-question"; shell_name = "Question"; break; } total_buttons = name [1] - '0'; if (name [3] == 'T' || name [3] == 't') { text_input_slot = False; radio_box = True; } 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; } #endif /* LWLIB_DIALOGS_MOTIF */ #ifdef LWLIB_MENUBARS_MOTIF static Widget make_menubar (widget_instance* instance) { Arg al[10]; int ac = 0; Xt_SET_ARG(al[ac], XmNmarginHeight, 0); ac++; Xt_SET_ARG(al[ac], XmNshadowThickness, 3); ac++; return XmCreateMenuBar (instance->parent, instance->info->name, al, ac); } static void remove_grabs (Widget shell, XtPointer closure, XtPointer call_data) { Widget menu = (Widget) closure; XmRemoveFromPostFromList (menu, XtParent (XtParent ((Widget) menu))); } static Widget make_popup_menu (widget_instance* instance) { Widget parent = instance->parent; Window parent_window = parent->core.window; Widget result; /* sets the parent window to 0 to fool Motif into not generating a grab */ parent->core.window = 0; result = XmCreatePopupMenu (parent, instance->info->name, NULL, 0); XtAddCallback (XtParent (result), XmNpopdownCallback, remove_grabs, (XtPointer)result); parent->core.window = parent_window; return result; } #endif /* LWLIB_MENUBARS_MOTIF */ #ifdef LWLIB_SCROLLBARS_MOTIF static Widget make_scrollbar (widget_instance *instance, int vertical) { Arg al[20]; int ac = 0; static XtCallbackRec callbacks[2] = { {xm_scrollbar_callback, NULL}, {NULL, NULL} }; callbacks[0].closure = (XtPointer) instance; Xt_SET_ARG (al[ac], XmNminimum, 1); ac++; Xt_SET_ARG (al[ac], XmNmaximum, INT_MAX); ac++; Xt_SET_ARG (al[ac], XmNincrement, 1); ac++; Xt_SET_ARG (al[ac], XmNpageIncrement, 1); ac++; Xt_SET_ARG (al[ac], XmNborderWidth, 0); ac++; Xt_SET_ARG (al[ac], XmNorientation, vertical ? XmVERTICAL : XmHORIZONTAL); ac++; Xt_SET_ARG (al[ac], XmNdecrementCallback, callbacks); ac++; Xt_SET_ARG (al[ac], XmNdragCallback, callbacks); ac++; Xt_SET_ARG (al[ac], XmNincrementCallback, callbacks); ac++; Xt_SET_ARG (al[ac], XmNpageDecrementCallback, callbacks); ac++; Xt_SET_ARG (al[ac], XmNpageIncrementCallback, callbacks); ac++; Xt_SET_ARG (al[ac], XmNtoBottomCallback, callbacks); ac++; Xt_SET_ARG (al[ac], XmNtoTopCallback, callbacks); ac++; Xt_SET_ARG (al[ac], XmNvalueChangedCallback, callbacks); ac++; return XmCreateScrollBar (instance->parent, instance->info->name, al, ac); } static Widget make_vertical_scrollbar (widget_instance *instance) { return make_scrollbar (instance, 1); } static Widget make_horizontal_scrollbar (widget_instance *instance) { return make_scrollbar (instance, 0); } #endif /* LWLIB_SCROLLBARS_MOTIF */ #ifdef LWLIB_WIDGETS_MOTIF /* glyph widgets */ static Widget xm_create_button (widget_instance *instance) { Arg al[20]; int ac = 0; Widget button = 0; widget_value* val = instance->info->val; Xt_SET_ARG (al [ac], XmNsensitive, val->enabled); ac++; Xt_SET_ARG (al [ac], XmNalignment, XmALIGNMENT_BEGINNING); ac++; Xt_SET_ARG (al [ac], XmNuserData, val->call_data); ac++; Xt_SET_ARG (al [ac], XmNmappedWhenManaged, FALSE); ac++; /* The highlight doesn't appear to be dynamically set which makes it look ugly. I think this may be a LessTif bug but for now we just get rid of it. */ Xt_SET_ARG (al [ac], XmNhighlightThickness, (Dimension)0); ac++; /* add any args the user supplied for creation time */ lw_add_value_args_to_args (val, al, &ac); if (!val->call_data) button = XmCreateLabel (instance->parent, val->name, al, ac); else if (val->type == TOGGLE_TYPE || val->type == RADIO_TYPE) { Xt_SET_ARG (al [ac], XmNset, val->selected); ac++; Xt_SET_ARG (al [ac], XmNindicatorType, (val->type == TOGGLE_TYPE ? XmN_OF_MANY : XmONE_OF_MANY)); ac++; Xt_SET_ARG (al [ac], XmNvisibleWhenOff, True); ac++; button = XmCreateToggleButton (instance->parent, val->name, al, ac); XtRemoveAllCallbacks (button, XmNvalueChangedCallback); XtAddCallback (button, XmNvalueChangedCallback, xm_generic_callback, (XtPointer)instance); } else { button = XmCreatePushButton (instance->parent, val->name, al, ac); XtAddCallback (button, XmNactivateCallback, xm_generic_callback, (XtPointer)instance); } XtManageChild (button); return button; } static Widget xm_create_progress (widget_instance *instance) { Arg al[20]; int ac = 0; Dimension height = 0; Dimension width = 0; Widget scale = 0; widget_value* val = instance->info->val; if (!val->call_data) { Xt_SET_ARG (al [ac], XmNeditable, False); ac++; } else { Xt_SET_ARG (al [ac], XmNeditable, val->enabled); ac++; } Xt_SET_ARG (al [ac], XmNalignment, XmALIGNMENT_BEGINNING); ac++; Xt_SET_ARG (al [ac], XmNuserData, val->call_data); ac++; Xt_SET_ARG (al [ac], XmNmappedWhenManaged, FALSE); ac++; Xt_SET_ARG (al [ac], XmNorientation, XmHORIZONTAL); ac++; /* The highlight doesn't appear to be dynamically set which makes it look ugly. I think this may be a LessTif bug but for now we just get rid of it. */ Xt_SET_ARG (al [ac], XmNhighlightThickness, (Dimension)0); ac++; height = (Dimension)lw_get_value_arg (val, XtNheight); width = (Dimension)lw_get_value_arg (val, XtNwidth); if (height > 0) { Xt_SET_ARG (al [ac], XmNscaleHeight, height); ac++; } if (width > 0) { Xt_SET_ARG (al [ac], XmNscaleWidth, width); ac++; } /* add any args the user supplied for creation time */ lw_add_value_args_to_args (val, al, &ac); scale = XmCreateScale (instance->parent, val->name, al, ac); if (val->call_data) XtAddCallback (scale, XmNvalueChangedCallback, xm_generic_callback, (XtPointer)instance); XtManageChild (scale); return scale; } static Widget xm_create_text_field (widget_instance *instance) { Arg al[20]; int ac = 0; Widget text = 0; widget_value* val = instance->info->val; Xt_SET_ARG (al [ac], XmNsensitive, val->enabled); ac++; Xt_SET_ARG (al [ac], XmNalignment, XmALIGNMENT_BEGINNING); ac++; Xt_SET_ARG (al [ac], XmNuserData, val->call_data); ac++; Xt_SET_ARG (al [ac], XmNmappedWhenManaged, FALSE); ac++; /* The highlight doesn't appear to be dynamically set which makes it look ugly. I think this may be a LessTif bug but for now we just get rid of it. */ Xt_SET_ARG (al [ac], XmNhighlightThickness, (Dimension)0); ac++; /* add any args the user supplied for creation time */ lw_add_value_args_to_args (val, al, &ac); text = XmCreateTextField (instance->parent, val->name, al, ac); if (val->call_data) XtAddCallback (text, XmNvalueChangedCallback, xm_generic_callback, (XtPointer)instance); XtManageChild (text); return text; } static Widget xm_create_label_field (widget_instance *instance) { return xm_create_label (instance->parent, instance->info->val); } Widget xm_create_label (Widget parent, widget_value* val) { Arg al[20]; int ac = 0; Widget label = 0; Xt_SET_ARG (al [ac], XmNsensitive, val->enabled); ac++; Xt_SET_ARG (al [ac], XmNalignment, XmALIGNMENT_BEGINNING); ac++; Xt_SET_ARG (al [ac], XmNmappedWhenManaged, FALSE); ac++; /* The highlight doesn't appear to be dynamically set which makes it look ugly. I think this may be a LessTif bug but for now we just get rid of it. */ Xt_SET_ARG (al [ac], XmNhighlightThickness, (Dimension)0); ac++; /* add any args the user supplied for creation time */ lw_add_value_args_to_args (val, al, &ac); label = XmCreateLabel (parent, val->name, al, ac); XtManageChild (label); /* Do it again for arguments that have no effect until the widget is realized. */ ac = 0; lw_add_value_args_to_args (val, al, &ac); XtSetValues (label, al, ac); return label; } #if XmVERSION > 1 static Widget xm_create_combo_box (widget_instance *instance) { Arg al[20]; int ac = 0; Widget combo = 0; widget_value* val = instance->info->val; Xt_SET_ARG (al [ac], XmNsensitive, val->enabled); ac++; Xt_SET_ARG (al [ac], XmNalignment, XmALIGNMENT_BEGINNING); ac++; Xt_SET_ARG (al [ac], XmNuserData, val->call_data); ac++; Xt_SET_ARG (al [ac], XmNmappedWhenManaged, FALSE); ac++; /* The highlight doesn't appear to be dynamically set which makes it look ugly. I think this may be a LessTif bug but for now we just get rid of it. */ Xt_SET_ARG (al [ac], XmNhighlightThickness, (Dimension)0); ac++; /* add any args the user supplied for creation time */ lw_add_value_args_to_args (val, al, &ac); combo = XmCreateDropDownComboBox (instance->parent, val->name, al, ac); if (val->call_data) XtAddCallback (combo, XmNselectionCallback, xm_generic_callback, (XtPointer)instance); XtManageChild (combo); return combo; } #endif #endif /* LWLIB_WIDGETS_MOTIF */ /* Table of functions to create widgets */ const widget_creation_entry xm_creation_table [] = { #ifdef LWLIB_MENUBARS_MOTIF {"menubar", make_menubar}, {"popup", make_popup_menu}, #endif #ifdef LWLIB_SCROLLBARS_MOTIF {"vertical-scrollbar", make_vertical_scrollbar}, {"horizontal-scrollbar", make_horizontal_scrollbar}, #endif #ifdef LWLIB_WIDGETS_MOTIF {"button", xm_create_button}, {"progress", xm_create_progress}, {"text-field", xm_create_text_field}, {"label", xm_create_label_field}, #if XmVERSION > 1 {"combo-box", xm_create_combo_box}, #endif #endif {NULL, NULL} }; /* Destruction of instances */ void xm_destroy_instance ( #if defined (LWLIB_DIALOGS_MOTIF) || defined (LWLIB_WIDGETS_MOTIF) widget_instance* instance #else widget_instance* UNUSED (instance) #endif ) { #if defined (LWLIB_DIALOGS_MOTIF) || defined (LWLIB_WIDGETS_MOTIF) /* It appears that this is used only for dialog boxes. */ Widget widget = instance->widget; /* recycle the dialog boxes */ /* Disable the recycling until we can find a way to have the dialog box get reasonable layout after we modify its contents. */ if (0 && XtClass (widget) == xmDialogShellWidgetClass) { destroyed_instance* dead_instance = make_destroyed_instance (instance->info->name, instance->info->type, instance->widget, instance->parent, instance->pop_up_p); dead_instance->next = all_destroyed_instances; all_destroyed_instances = dead_instance; XtUnmanageChild (first_child (instance->widget)); XFlush (XtDisplay (instance->widget)); XtAddCallback (instance->parent, XtNdestroyCallback, mark_dead_instance_destroyed, (XtPointer)dead_instance); } else { /* This might not be necessary now that the nosel is attached to popdown instead of destroy, but it can't hurt. */ XtRemoveCallback (instance->widget, XtNdestroyCallback, xm_nosel_callback, (XtPointer)instance); XtDestroyWidget (instance->widget); } #endif /* LWLIB_DIALOGS_MOTIF || LWLIB_WIDGETS_MOTIF */ } /* popup utility */ #ifdef LWLIB_MENUBARS_MOTIF void xm_popup_menu (Widget widget, XEvent *event) { if (event->type == ButtonPress || event->type == ButtonRelease) { /* 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 = "<Btn5Down>"; else if (event->xbutton.state & Button4Mask) trans = "<Btn4Down>"; else if (event->xbutton.state & Button3Mask) trans = "<Btn3Down>"; else if (event->xbutton.state & Button2Mask) trans = "<Btn2Down>"; else if (event->xbutton.state & Button1Mask) trans = "<Btn1Down>"; if (trans) { Arg al [1]; Xt_SET_ARG (al [0], XmNmenuPost, trans); XtSetValues (widget, al, 1); } XmMenuPosition (widget, (XButtonPressedEvent *) event); } XtManageChild (widget); } #endif #ifdef LWLIB_DIALOGS_MOTIF static void set_min_dialog_size (Widget w) { short width; short height; Arg al [2]; Xt_SET_ARG (al [0], XmNwidth, &width); Xt_SET_ARG (al [1], XmNheight, &height); XtGetValues (w, al, 2); Xt_SET_ARG (al [0], XmNminWidth, width); Xt_SET_ARG (al [1], XmNminHeight, height); XtSetValues (w, al, 2); } #endif void xm_pop_instance (widget_instance* instance, Boolean up) { Widget widget = instance->widget; #ifdef LWLIB_DIALOGS_MOTIF if (XtClass (widget) == xmDialogShellWidgetClass) { Widget widget_to_manage = first_child (widget); if (up) { XtManageChild (widget_to_manage); set_min_dialog_size (widget); XmProcessTraversal(widget, XmTRAVERSE_CURRENT); } else XtUnmanageChild (widget_to_manage); } else #endif { if (up) XtManageChild (widget); else XtUnmanageChild (widget); } } /* motif callback */ enum do_call_type { pre_activate, selection, no_selection, post_activate }; static void do_call (Widget widget, XtPointer closure, enum do_call_type type) { XtPointer user_data; widget_instance* instance = (widget_instance*)closure; Widget instance_widget; LWLIB_ID id; if (!instance) return; if (widget->core.being_destroyed) return; instance_widget = instance->widget; if (!instance_widget) return; id = instance->info->id; user_data = NULL; Xt_GET_VALUE (widget, XmNuserData, &user_data); 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 lw_internal_update_other_instances to dereference freed memory if the widget was ``destroyed'' by caching it in the all_destroyed_instances list */ static void xm_internal_update_other_instances (Widget widget, XtPointer closure, XtPointer call_data) { Widget parent; for (parent = widget; parent; parent = XtParent (parent)) if (XtIsShell (parent)) break; else if (!XtIsManaged (parent)) return; lw_internal_update_other_instances (widget, closure, call_data); } static void xm_generic_callback (Widget widget, XtPointer closure, XtPointer call_data) { #if (defined (LWLIB_MENUBARS_MOTIF) || defined (LWLIB_DIALOGS_MOTIF) || defined (LWLIB_WIDGETS_MOTIF)) /* We want the selected status to change only when we decide it should change. Yuck but correct. */ if (XtClass (widget) == xmToggleButtonWidgetClass || XtClass (widget) == xmToggleButtonGadgetClass) { Boolean check; Xt_GET_VALUE (widget, XmNset, &check); Xt_SET_VALUE (widget, XmNset, !check); } #endif lw_internal_update_other_instances (widget, closure, call_data); do_call (widget, closure, selection); } #if 0 /* Caller above is commented out */ static void xm_pop_down_callback (Widget widget, XtPointer closure, XtPointer call_data) { do_call (widget, closure, post_activate); } #endif /* 0 */ #ifdef LWLIB_MENUBARS_MOTIF static void xm_pull_down_callback (Widget widget, XtPointer closure, XtPointer call_data) { #if 0 if (call_data) { /* new behavior for incremental menu construction */ } else #endif do_call (widget, closure, pre_activate); } #endif /* LWLIB_MENUBARS_MOTIF */ #ifdef LWLIB_SCROLLBARS_MOTIF static void xm_scrollbar_callback (Widget widget, XtPointer closure, XtPointer call_data) { widget_instance *instance = (widget_instance *) closure; LWLIB_ID id; XmScrollBarCallbackStruct *data = (XmScrollBarCallbackStruct *) call_data; scroll_event event_data; scrollbar_values *val = (scrollbar_values *) instance->info->val->scrollbar_data; double percent; if (!instance || widget->core.being_destroyed) return; id = instance->info->id; percent = (double) (data->value - 1) / (double) (INT_MAX - 1); event_data.slider_value = (int) (percent * (double) (val->maximum - val->minimum)) + val->minimum; if (event_data.slider_value > (val->maximum - val->slider_size)) event_data.slider_value = val->maximum - val->slider_size; else if (event_data.slider_value < 1) event_data.slider_value = 1; if (data->event) { switch (data->event->xany.type) { case KeyPress: case KeyRelease: event_data.time = data->event->xkey.time; break; case ButtonPress: case ButtonRelease: event_data.time = data->event->xbutton.time; break; case MotionNotify: event_data.time = data->event->xmotion.time; break; case EnterNotify: case LeaveNotify: event_data.time = data->event->xcrossing.time; break; default: event_data.time = 0; break; } } else event_data.time = 0; switch (data->reason) { case XmCR_DECREMENT: event_data.action = SCROLLBAR_LINE_UP; break; case XmCR_INCREMENT: event_data.action = SCROLLBAR_LINE_DOWN; break; case XmCR_PAGE_DECREMENT: event_data.action = SCROLLBAR_PAGE_UP; break; case XmCR_PAGE_INCREMENT: event_data.action = SCROLLBAR_PAGE_DOWN; break; case XmCR_TO_TOP: event_data.action = SCROLLBAR_TOP; break; case XmCR_TO_BOTTOM: event_data.action = SCROLLBAR_BOTTOM; break; case XmCR_DRAG: event_data.action = SCROLLBAR_DRAG; break; case XmCR_VALUE_CHANGED: event_data.action = SCROLLBAR_CHANGE; break; default: event_data.action = SCROLLBAR_CHANGE; break; } if (instance->info->pre_activate_cb) instance->info->pre_activate_cb (widget, id, (XtPointer) &event_data); } #endif /* LWLIB_SCROLLBARS_MOTIF */ #if defined (LWLIB_DIALOGS_MOTIF) || defined (LWLIB_WIDGETS_MOTIF) static void mark_dead_instance_destroyed (Widget UNUSED (widget), XtPointer closure, XtPointer UNUSED (call_data)) { destroyed_instance* instance = (destroyed_instance*)closure; instance->widget = NULL; } static void xm_nosel_callback (Widget widget, XtPointer closure, XtPointer UNUSED (call_data)) { /* This callback is only called when a dialog box is dismissed with the wm's destroy button (WM_DELETE_WINDOW.) We want the dialog box to be destroyed in that case, not just unmapped, so that it releases its keyboard grabs. But there are problems with running our callbacks while the widget is in the process of being destroyed, so we set XmNdeleteResponse to XmUNMAP instead of XmDESTROY and then destroy it ourself after having run the callback. */ do_call (widget, closure, no_selection); XtDestroyWidget (widget); } #endif /* set the keyboard focus */ void xm_set_keyboard_focus (Widget UNUSED (parent), Widget w) { XmProcessTraversal (w, XmTRAVERSE_CURRENT); /* At some point we believed that it was necessary to use XtSetKeyboardFocus instead of XmProcessTraversal when using Motif >= 1.2.1, but that's bogus. Presumably the problem was elsewhere, and is now gone... */ }