view src/gui.c @ 2720:6fa9919a9a0b

[xemacs-hg @ 2005-04-08 23:10:01 by crestani] ChangeLog addition: 2005-04-01  Marcus Crestani  <crestani@xemacs.org>         The new allocator.         New configure flag: `MC_ALLOC':         * configure.ac (XE_COMPLEX_ARG_ENABLE): Add `--enable-mc-alloc' as         a new configure flag.         * configure.in (AC_INIT_PARSE_ARGS): Add `--mc-alloc' as a new         configure flag.         * configure.usage: Add description for `mc-alloc'.         DUMP_IN_EXEC:         * Makefile.in.in: Condition the installation of a separate dump         file on !DUMP_ON_EXEC.         * configure.ac (XE_COMPLEX_ARG_ENABLE): Add         `--enable-dump-in-exec' as a new configure flag.         * configure.ac: DUMP_IN_EXEC is define as default for PDUMP but         not default for MC_ALLOC.         * configure.in (AC_INIT_PARSE_ARGS): Add `--dump-in-exec' as a         new configure flag.         * configure.in: DUMP_IN_EXEC is define as default for PDUMP but         not default for MC_ALLOC.         * configure.usage: Add description for `dump-in-exec'. lib-src/ChangeLog addition: 2005-04-01  Marcus Crestani  <crestani@xemacs.org>         The new allocator.         DUMP_IN_EXEC:                  * Makefile.in.in: Only compile insert-data-in-exec if         DUMP_IN_EXEC is defined. lisp/ChangeLog addition: 2005-04-01  Marcus Crestani  <crestani@xemacs.org>         The new allocator.         MEMORY_USAGE_STATS         * diagnose.el: Add new lisp function to pretty print statistics         about the new allocator.         * diagnose.el (show-mc-alloc-memory-usage): New. modules/ChangeLog addition: 2005-04-01  Marcus Crestani  <crestani@xemacs.org>         The new allocator.         Remove Lcrecords:                  * postgresql/postgresql.c (allocate_pgconn): Allocate with new         allocator.         * postgresql/postgresql.c (allocate_pgresult): Allocate PGresult         with new allocator.           * postgresql/postgresql.h (struct Lisp_PGconn): Add         lrecord_header.         * postgresql/postgresql.h (struct Lisp_PGresult): Add         lrecord_header.         * ldap/eldap.c (allocate_ldap): Allocate with new allocator.         * ldap/eldap.h (struct Lisp_LDAP): Add lrecord_header. nt/ChangeLog addition: 2005-04-01  Marcus Crestani  <crestani@xemacs.org>         The new allocator.         New configure flag: `MC_ALLOC':         * config.inc.samp: Add new flag `MC_ALLOC'.         * xemacs.mak: Add flag and configuration output for `MC_ALLOC'.         New files:         * xemacs.dsp: Add source files mc-alloc.c and mc-alloc.h.         * xemacs.mak: Add new object file mc-alloc.obj to dependencies. src/ChangeLog addition: 2005-04-01  Marcus Crestani  <crestani@xemacs.org>         The new allocator.         New configure flag: `MC_ALLOC':         * config.h.in: Add new flag `MC_ALLOC'.         New files:         * Makefile.in.in: Add new object file mc-alloc.o.         * depend: Add new files to dependencies.         * mc-alloc.c: New.         * mc-alloc.h: New.         Running the new allocator from XEmacs:         * alloc.c (deadbeef_memory): Moved to mc-alloc.c.         * emacs.c (main_1): Initialize the new allocator and add         syms_of_mc_alloc.         * symsinit.h: Add syms_of_mc_alloc.         New lrecord allocation and free functions:         * alloc.c (alloc_lrecord): New. Allocates an lrecord, includes         type checking and initializing of the lrecord_header.         * alloc.c (noseeum_alloc_lrecord): Same as above, but increments         the NOSEEUM cons counter.         * alloc.c (free_lrecord): New. Calls the finalizer and frees the         lrecord.         * lrecord.h: Add lrecord allocation prototypes and comments.         Remove old lrecord FROB block allocation:                  * alloc.c (allocate_lisp_storage): Former function to expand         heap. Not needed anymore, remove.         * alloc.c: Completely remove `Fixed-size type macros'         * alloc.c (release_breathing_space): Remove.         * alloc.c (memory_full): Remove release_breathing_space.         * alloc.c (refill_memory_reserve): Remove.         * alloc.c (TYPE_ALLOC_SIZE): Remove.         * alloc.c (DECLARE_FIXED_TYPE_ALLOC): Remove.         * alloc.c (ALLOCATE_FIXED_TYPE_FROM_BLOCK): Remove.         * alloc.c (ALLOCATE_FIXED_TYPE_1): Remove.         * alloc.c (ALLOCATE_FIXED_TYPE): Remove.         * alloc.c (NOSEEUM_ALLOCATE_FIXED_TYPE): Remove.         * alloc.c (struct Lisp_Free): Remove.         * alloc.c (LRECORD_FREE_P): Remove.         * alloc.c (MARK_LRECORD_AS_FREE): Remove.         * alloc.c (MARK_LRECORD_AS_NOT_FREE): Remove.         * alloc.c (PUT_FIXED_TYPE_ON_FREE_LIST): Remove.         * alloc.c (FREE_FIXED_TYPE): Remove.         * alloc.c (FREE_FIXED_TYPE_WHEN_NOT_IN_GC): Remove.         Allocate old lrecords with new allocator:                  * alloc.c: DECLARE_FIXED_TYPE_ALLOC removed for all lrecords         defined in alloc.c.         * alloc.c (Fcons): Allocate with new allocator.         * alloc.c (noseeum_cons): Allocate with new allocator.         * alloc.c (make_float): Allocate with new allocator.         * alloc.c (make_bignum): Allocate with new allocator.         * alloc.c (make_bignum_bg): Allocate with new allocator.         * alloc.c (make_ratio): Allocate with new allocator.         * alloc.c (make_ratio_bg): Allocate with new allocator.         * alloc.c (make_ratio_rt): Allocate with new allocator.         * alloc.c (make_bigfloat): Allocate with new allocator.         * alloc.c (make_bigfloat_bf): Allocate with new allocator.         * alloc.c (make_compiled_function): Allocate with new allocator.         * alloc.c (Fmake_symbol): Allocate with new allocator.         * alloc.c (allocate_extent): Allocate with new allocator.         * alloc.c (allocate_event): Allocate with new allocator.         * alloc.c (make_key_data): Allocate with new allocator.         * alloc.c (make_button_data): Allocate with new allocator.         * alloc.c (make_motion_data): Allocate with new allocator.         * alloc.c (make_process_data): Allocate with new allocator.         * alloc.c (make_timeout_data): Allocate with new allocator.         * alloc.c (make_magic_data): Allocate with new allocator.         * alloc.c (make_magic_eval_data): Allocate with new allocator.         * alloc.c (make_eval_data): Allocate with new allocator.         * alloc.c (make_misc_user_data): Allocate with new allocator.         * alloc.c (Fmake_marker): Allocate with new allocator.         * alloc.c (noseeum_make_marker): Allocate with new allocator.         * alloc.c (make_uninit_string): Allocate with new allocator.         * alloc.c (resize_string): Allocate with new allocator.         * alloc.c (make_string_nocopy): Allocate with new allocator.         Garbage Collection:         * alloc.c (GC_CHECK_NOT_FREE): Remove obsolete assertions.         * alloc.c (SWEEP_FIXED_TYPE_BLOCK): Remove.         * alloc.c (SWEEP_FIXED_TYPE_BLOCK_1): Remove.         * alloc.c (sweep_conses): Remove.         * alloc.c (free_cons): Use new allocator to free.         * alloc.c (sweep_compiled_functions): Remove.         * alloc.c (sweep_floats): Remove.         * alloc.c (sweep_bignums): Remove.         * alloc.c (sweep_ratios): Remove.         * alloc.c (sweep_bigfloats): Remove.         * alloc.c (sweep_symbols): Remove.         * alloc.c (sweep_extents): Remove.         * alloc.c (sweep_events): Remove.         * alloc.c (sweep_key_data): Remove.         * alloc.c (free_key_data): Use new allocator to free.         * alloc.c (sweep_button_data): Remove.         * alloc.c (free_button_data): Use new allocator to free.         * alloc.c (sweep_motion_data): Remove.         * alloc.c (free_motion_data): Use new allocator to free.         * alloc.c (sweep_process_data): Remove.         * alloc.c (free_process_data): Use new allocator to free.         * alloc.c (sweep_timeout_data): Remove.         * alloc.c (free_timeout_data): Use new allocator to free.         * alloc.c (sweep_magic_data): Remove.         * alloc.c (free_magic_data): Use new allocator to free.         * alloc.c (sweep_magic_eval_data): Remove.         * alloc.c (free_magic_eval_data): Use new allocator to free.         * alloc.c (sweep_eval_data): Remove.         * alloc.c (free_eval_data): Use new allocator to free.         * alloc.c (sweep_misc_user_data): Remove.         * alloc.c (free_misc_user_data): Use new allocator to free.         * alloc.c (sweep_markers): Remove.         * alloc.c (free_marker): Use new allocator to free.         * alloc.c (garbage_collect_1): Remove release_breathing_space.         * alloc.c (gc_sweep): Remove all the old lcrecord and lrecord         related stuff. Sweeping now works like this: compact string         chars, finalize, sweep.         * alloc.c (common_init_alloc_early): Remove old lrecord         initializations, remove breathing_space.         * emacs.c (Fdump_emacs): Remove release_breathing_space.         * lisp.h: Remove prototype for release_breathing_space.         * lisp.h: Adjust the special cons mark makros.         Lrecord Finalizer:         * alloc.c: Add finalizer to lrecord definition.         * alloc.c (finalize_string): Add finalizer for string.         * bytecode.c: Add finalizer to lrecord definition.         * bytecode.c (finalize_compiled_function): Add finalizer for         compiled function.         * marker.c: Add finalizer to lrecord definition.         * marker.c (finalize_marker): Add finalizer for marker.         These changes build the interface to mc-alloc:         * lrecord.h (MC_ALLOC_CALL_FINALIZER): Tell mc-alloc how to         finalize lrecords.         * lrecord.h (MC_ALLOC_CALL_FINALIZER_FOR_DISKSAVE): Tell         mc-alloc how to finalize for disksave.         Unify lrecords and lcrecords:         * lisp.h (struct Lisp_String): Adjust string union hack to         new lrecord header.         * lrecord.h: Adjust comments.         * lrecord.h (struct lrecord_header): The new lrecord header         includes type, lisp-readonly, free, and uid.         * lrecord.h (set_lheader_implementation): Adjust to new         lrecord_header.         * lrecord.h (struct lrecord_implementation): The field basic_p         for indication of an old lrecord is not needed anymore, remove.         * lrecord.h (MAKE_LRECORD_IMPLEMENTATION): Remove basic_p.         * lrecord.h (MAKE_EXTERNAL_LRECORD_IMPLEMENTATION): Remove         basic_p.         * lrecord.h (copy_sized_lrecord): Remove distinction between         old lrecords and lcrecords.         * lrecord.h (copy_lrecord): Remove distinction between old         lrecords and lcrecords.         * lrecord.h (zero_sized_lrecord): Remove distinction between         old lrecords and lcrecords.         * lrecord.h (zero_lrecord): Remove distinction between old         lrecords and lcrecords.         Remove lcrecords and lcrecord lists:         * alloc.c (basic_alloc_lcrecord): Not needed anymore, remove.         * alloc.c (very_old_free_lcrecord): Not needed anymore, remove.         * alloc.c (copy_lisp_object): No more distinction between         lrecords and lcrecords.         * alloc.c (all_lcrecords): Not needed anymore, remove.         * alloc.c (make_vector_internal): Allocate as lrecord.         * alloc.c (make_bit_vector_internal): Allocate as lrecord.         * alloc.c: Completely remove `lcrecord lists'.         * alloc.c (free_description): Remove.         * alloc.c (lcrecord_list_description): Remove.         * alloc.c (mark_lcrecord_list): Remove.         * alloc.c (make_lcrecord_list): Remove.         * alloc.c (alloc_managed_lcrecord): Remove.         * alloc.c (free_managed_lcrecord): Remove.         * alloc.c (alloc_automanaged_lcrecord): Remove.         * alloc.c (free_lcrecord): Remove.         * alloc.c (lcrecord_stats): Remove.         * alloc.c (tick_lcrecord_stats): Remove.         * alloc.c (disksave_object_finalization_1): Add call to         mc_finalize_for_disksave. Remove the lcrecord way to visit all         objects.         * alloc.c (kkcc_marking): Remove XD_FLAG_FREE_LISP_OBJECT         * alloc.c (sweep_lcrecords_1): Remove.         * alloc.c (common_init_alloc_early): Remove everything related         to lcrecords, remove old lrecord initializations,         * alloc.c (init_lcrecord_lists): Not needed anymore, remove.         * alloc.c (reinit_alloc_early): Remove everything related to         lcrecords.         * alloc.c (init_alloc_once_early): Remove everything related to         lcrecords.         * buffer.c (allocate_buffer): Allocate as lrecord.         * buffer.c (nuke_all_buffer_slots): Use lrecord functions.         * buffer.c (common_init_complex_vars_of_buffer): Allocate as         lrecord.         * buffer.h (struct buffer): Add lrecord_header.         * casetab.c (allocate_case_table): Allocate as lrecord.         * casetab.h (struct Lisp_Case_Table): Add lrecord_header.         * charset.h (struct Lisp_Charset): Add lrecord_header.         * chartab.c (fill_char_table): Use lrecord functions.         * chartab.c (Fmake_char_table): Allocate as lrecord.         * chartab.c (make_char_table_entry): Allocate as lrecord.         * chartab.c (copy_char_table_entry): Allocate as lrecord.         * chartab.c (Fcopy_char_table): Allocate as lrecord.         * chartab.c (put_char_table): Use lrecord functions.         * chartab.h (struct Lisp_Char_Table_Entry): Add lrecord_header.         * chartab.h (struct Lisp_Char_Table): Add lrecord_header.         * console-impl.h (struct console): Add lrecord_header.         * console-msw-impl.h (struct Lisp_Devmode): Add lrecord_header.         * console-msw-impl.h (struct mswindows_dialog_id): Add         lrecord_header.         * console.c (allocate_console): Allocate as lrecord.         * console.c (nuke_all_console_slots): Use lrecord functions.         * console.c (common_init_complex_vars_of_console): Allocate as         lrecord.         * data.c (make_weak_list): Allocate as lrecord.         * data.c (make_weak_box): Allocate as lrecord.         * data.c (make_ephemeron): Allocate as lrecord.         * database.c (struct Lisp_Database): Add lrecord_header.         * database.c (allocate_database): Allocate as lrecord.         * device-impl.h (struct device): Add lrecord_header.         * device-msw.c (allocate_devmode): Allocate as lrecord.         * device.c (nuke_all_device_slots): Use lrecord functions.         * device.c (allocate_device): Allocate as lrecord.         * dialog-msw.c (handle_question_dialog_box): Allocate as lrecord.         * elhash.c (struct Lisp_Hash_Table): Add lrecord_header.         * elhash.c (make_general_lisp_hash_table): Allocate as lrecord.         * elhash.c (Fcopy_hash_table): Allocate as lrecord.         * event-stream.c: Lcrecord lists Vcommand_builder_free_list and         Vtimeout_free_list are no longer needed. Remove.         * event-stream.c (allocate_command_builder): Allocate as lrecord.         * event-stream.c (free_command_builder): Use lrecord functions.         * event-stream.c (event_stream_generate_wakeup): Allocate as         lrecord.         * event-stream.c (event_stream_resignal_wakeup): Use lrecord         functions.         * event-stream.c (event_stream_disable_wakeup): Use lrecord         functions.         * event-stream.c (reinit_vars_of_event_stream): Lcrecord lists         remove.         * events.h (struct Lisp_Timeout): Add lrecord_header.         * events.h (struct command_builder): Add lrecord_header.         * extents-impl.h (struct extent_auxiliary): Add lrecord_header.         * extents-impl.h (struct extent_info): Add lrecord_header.         * extents.c (allocate_extent_auxiliary): Allocate as lrecord.         * extents.c (allocate_extent_info): Allocate as lrecord.         * extents.c (copy_extent): Allocate as lrecord.         * faces.c (allocate_face): Allocate as lrecord.         * faces.h (struct Lisp_Face): Add lrecord_header.         * file-coding.c (allocate_coding_system): Allocate as lrecord.         * file-coding.c (Fcopy_coding_system): Allocate as lrecord.         * file-coding.h (struct Lisp_Coding_System): Add lrecord_header.         * fns.c (Ffillarray): Allocate as lrecord.         * frame-impl.h (struct frame): Add lrecord_header.         * frame.c (nuke_all_frame_slots): Use lrecord functions.         * frame.c (allocate_frame_core): Allocate as lrecord.         * glyphs.c (allocate_image_instance): Allocate as lrecord.         * glyphs.c (Fcolorize_image_instance): Allocate as lrecord.         * glyphs.c (allocate_glyph): Allocate as lrecord.         * glyphs.h (struct Lisp_Image_Instance): Add lrecord_header.         * glyphs.h (struct Lisp_Glyph): Add lrecord_header.         * gui.c (allocate_gui_item): Allocate as lrecord.         * gui.h (struct Lisp_Gui_Item): Add lrecord_header.         * keymap.c (struct Lisp_Keymap): Add lrecord_header.         * keymap.c (make_keymap): Allocate as lrecord.         * lisp.h (struct Lisp_Vector): Add lrecord_header.         * lisp.h (struct Lisp_Bit_Vector): Add lrecord_header.         * lisp.h (struct weak_box): Add lrecord_header.         * lisp.h (struct ephemeron): Add lrecord_header.         * lisp.h (struct weak_list): Add lrecord_header.         * lrecord.h (struct lcrecord_header): Not used, remove.         * lrecord.h (struct free_lcrecord_header): Not used, remove.         * lrecord.h (struct lcrecord_list): Not needed anymore, remove.         * lrecord.h (lcrecord_list): Not needed anymore, remove.         * lrecord.h: (enum data_description_entry_flags): Remove         XD_FLAG_FREE_LISP_OBJECT.         * lstream.c: Lrecord list Vlstream_free_list remove.         * lstream.c (Lstream_new): Allocate as lrecord.         * lstream.c (Lstream_delete): Use lrecod functions.         * lstream.c (reinit_vars_of_lstream): Vlstream_free_list         initialization remove.           * lstream.h (struct lstream): Add lrecord_header.         * emacs.c (main_1): Remove lstream initialization.         * mule-charset.c (make_charset): Allocate as lrecord.         * objects-impl.h (struct Lisp_Color_Instance): Add         lrecord_header.         * objects-impl.h (struct Lisp_Font_Instance): Add lrecord_header.         * objects.c (Fmake_color_instance): Allocate as lrecord.         * objects.c (Fmake_font_instance): Allocate as lrecord.         * objects.c (reinit_vars_of_objects): Allocate as lrecord.         * opaque.c: Lcreord list Vopaque_ptr_list remove.         * opaque.c (make_opaque): Allocate as lrecord.         * opaque.c (make_opaque_ptr): Allocate as lrecord.         * opaque.c (free_opaque_ptr): Use lrecord functions.         * opaque.c (reinit_opaque_early):         * opaque.c (init_opaque_once_early): Vopaque_ptr_list         initialization remove.         * opaque.h (Lisp_Opaque): Add lrecord_header.         * opaque.h (Lisp_Opaque_Ptr): Add lrecord_header.         * emacs.c (main_1): Remove opaque variable initialization.         * print.c (default_object_printer): Use new lrecord_header.         * print.c (print_internal): Use new lrecord_header.         * print.c (debug_p4): Use new lrecord_header.         * process.c (make_process_internal): Allocate as lrecord.         * procimpl.h (struct Lisp_Process): Add lrecord_header.         * rangetab.c (Fmake_range_table): Allocate as lrecord.         * rangetab.c (Fcopy_range_table): Allocate as lrecord.         * rangetab.h (struct Lisp_Range_Table): Add lrecord_header.         * scrollbar.c (create_scrollbar_instance): Allocate as lrecord.         * scrollbar.h (struct scrollbar_instance): Add lrecord_header.         * specifier.c (make_specifier_internal): Allocate as lrecord.         * specifier.h (struct Lisp_Specifier): Add lrecord_header.         * symbols.c:         * symbols.c (Fmake_variable_buffer_local): Allocate as lrecord.         * symbols.c (Fdontusethis_set_symbol_value_handler): Allocate         as lrecord.         * symbols.c (Fdefvaralias): Allocate as lrecord.         * symeval.h (struct symbol_value_magic): Add lrecord_header.         * toolbar.c (update_toolbar_button): Allocate as lrecord.         * toolbar.h (struct toolbar_button): Add lrecord_header.         * tooltalk.c (struct Lisp_Tooltalk_Message): Add lrecord_header.         * tooltalk.c (make_tooltalk_message): Allocate as lrecord.         * tooltalk.c (struct Lisp_Tooltalk_Pattern): Add lrecord_header.         * tooltalk.c (make_tooltalk_pattern): Allocate as lrecord.         * ui-gtk.c (allocate_ffi_data): Allocate as lrecord.         * ui-gtk.c (allocate_emacs_gtk_object_data): Allocate as lrecord.         * ui-gtk.c (allocate_emacs_gtk_boxed_data): Allocate as lrecord.         * ui-gtk.h (structs): Add lrecord_header.         * window-impl.h (struct window): Add lrecord_header.         * window-impl.h (struct window_mirror): Add lrecord_header.         * window.c (allocate_window): Allocate as lrecord.         * window.c (new_window_mirror): Allocate as lrecord.         * window.c (make_dummy_parent): Allocate as lrecord.         MEMORY_USAGE_STATS         * alloc.c (fixed_type_block_overhead): Not used anymore, remove.         * buffer.c (compute_buffer_usage): Get storage size from new         allocator.         * marker.c (compute_buffer_marker_usage): Get storage size from         new allocator.         * mule-charset.c (compute_charset_usage): Get storage size from         new allocator.         * scrollbar-gtk.c (gtk_compute_scrollbar_instance_usage): Get         storage size from new allocator.         * scrollbar-msw.c (mswindows_compute_scrollbar_instance_usage):         Get storage size from new allocator.         * scrollbar-x.c (x_compute_scrollbar_instance_usage): Get         storage size from new allocator.         * scrollbar.c (compute_scrollbar_instance_usage): Get storage         size from new allocator.         * unicode.c (compute_from_unicode_table_size_1): Get storage         size from new allocator.         * unicode.c (compute_to_unicode_table_size_1): Get storage size         from new allocator.         * window.c (compute_window_mirror_usage): Get storage size from         new allocator.         * window.c (compute_window_usage): Get storage size from new         allocator.         MC_ALLOC_TYPE_STATS:         * alloc.c (alloc_lrecord): Bump lrecord count.         * alloc.c (noseeum_alloc_lrecord): Bump lrecord count.         * alloc.c (struct lrecord_stats): Storage for counts.         * alloc.c (init_lrecord_stats): Zero statistics.         * alloc.c (inc_lrecord_stats): Increase the statistic.         * alloc.c (dec_lrecord_stats): Decrease the statistic.         * alloc.c (gc_plist_hack): Used to print the information.         * alloc.c (Fgarbage_collect): Return the collected information.         * mc-alloc.c (remove_cell): Decrease lrecord count.         * mc-alloc.h: Set flag MC_ALLOC_TYPE_STATS.         * emacs.c (main_1): Init lrecord statistics.         * lrecord.h: Add prototypes for *_lrecord_stats.         Strings:         * alloc.c (Fmake_string): Initialize ascii_begin to zero.         * alloc.c (gc_count_num_short_string_in_use): Remove.         * alloc.c (gc_count_string_total_size): Remove.         * alloc.c (gc_count_short_string_total_size): Remove.         * alloc.c (debug_string_purity): Remove.         * alloc.c (debug_string_purity_print): Remove.         * alloc.c (sweep_strings): Remove.                  Remove static C-readonly Lisp objects:         * alloc.c (c_readonly): Not needed anymore, remove.         * alloc.c (GC_CHECK_LHEADER_INVARIANTS): Remove some obsolete         lheader invariants assertions.         * buffer.c (DEFVAR_BUFFER_LOCAL_1): Allocate dynamically.         * console.c (DEFVAR_CONSOLE_LOCAL_1): Allocate dynamically.         * gpmevent.c: Indirection via MC_ALLOC_Freceive_gpm_event.         * gpmevent.c (Fgpm_enable): Allocate dynamically.         * gpmevent.c (syms_of_gpmevent): Allocate dynamically.         * lisp.h (C_READONLY): Not needed anymore, remove.         * lisp.h (DEFUN): Allocate dynamically.         * lrecord.h (C_READONLY_RECORD_HEADER_P): Not needed anymore,         remove.         * lrecord.h (SET_C_READONLY_RECORD_HEADER): Not needed anymore,         remove.         * symbols.c (guts_of_unbound_marker):         * symeval.h (defsubr): Allocate dynamically.         * symeval.h (DEFSUBR_MACRO): Allocate dynamically.         * symeval.h (DEFVAR_ SYMVAL_FWD): Allocate dynamically.         * tests.c (TESTS_DEFSUBR): Allocate dynamically.         Definition of mcpro:         * lisp.h: Add mcpro prototypes.         * alloc.c (common_init_alloc_early): Add initialization for         mcpros.         * alloc.c (mcpro_description_1): New.         * alloc.c (mcpro_description): New.         * alloc.c (mcpros_description_1): New.         * alloc.c (mcpros_description): New.         * alloc.c (mcpro_one_name_description_1): New.         * alloc.c (mcpro_one_name_description): New.         * alloc.c (mcpro_names_description_1): New.         * alloc.c (mcpro_names_description): New.         * alloc.c (mcpros): New.         * alloc.c (mcpro_names): New.         * alloc.c (mcpro_1): New.         * alloc.c (mc_pro): New.         * alloc.c (garbage_collect_1): Add mcpros to root set.         Usage of mcpro:         * alloc.c (make_string_nocopy): Add string to root set.         * symbols.c (init_symbols_once_early): Add Qunbound to root set.         Changes to the Portable Dumper:                  * alloc.c (FREE_OR_REALLOC_BEGIN): Since dumped objects can be         freed with the new allocator, remove assertion for !DUMPEDP.         * dumper.c: Adjust comments, increase PDUMP_HASHSIZE.         * dumper.c (pdump_make_hash): Shift address only 2 bytes, to         avoid collisions.         * dumper.c (pdump_objects_unmark): No more mark bits within         the object, remove.         * dumper.c (mc_addr_elt): New. Element data structure for mc         hash table.         * dumper.c (pdump_mc_hash): New hash table: `lookup table'.         * dumper.c (pdump_get_mc_addr): New. Lookup for hash table.         * dumper.c (pdump_get_indirect_mc_addr): New. Lookup for         convertibles.         * dumper.c (pdump_put_mc_addr): New. Putter for hash table.         * dumper.c (pdump_dump_mc_data): New. Writes the table for         relocation at load time to the dump file.         * dumper.c (pdump_scan_lisp_objects_by_alignment): New.         Visits all dumped Lisp objects.         * dumper.c (pdump_scan_non_lisp_objects_by_alignment): New.         Visits all other dumped objects.         * dumper.c (pdump_reloc_one_mc): New. Updates all pointers         of an object by using the hash table pdump_mc_hash.         * dumper.c (pdump_reloc_one): Replaced by pdump_reloc_one_mc.         * dumper.c (pdump): Change the structure of the dump file, add         the mc post dump relocation table to dump file.         * dumper.c (pdump_load_finish): Hand all dumped objects to the         new allocator and use the mc post dump relocation table for         relocating the dumped objects at dump file load time, free not         longer used data structures.         * dumper.c (pdump_load): Free the dump file.         * dumper.h: Remove pdump_objects_unmark.         * lrecord.h (DUMPEDP): Dumped objects can be freed, remove.              DUMP_IN_EXEC:         * Makefile.in.in: Linking for and with dump in executable only if         DUMP_IN_EXEC is defined.         * config.h.in: Add new flag `DUMP_IN_EXEC'         * emacs.c: Condition dump-data.h on DUMP_IN_EXEC.         * emacs.c (main_1): Flag `-si' only works if dump image is         written into executable.         Miscellanious         * lrecord.h (enum lrecord_type): Added numbers to all types,         very handy for debugging.         * xemacs.def.in.in: Add mc-alloc functions to make them visible         to the modules.
author crestani
date Fri, 08 Apr 2005 23:11:35 +0000
parents ecf1ebac70d8
children 1e7cc382eb16
line wrap: on
line source

/* Generic GUI code. (menubars, scrollbars, toolbars, dialogs)
   Copyright (C) 1995 Board of Trustees, University of Illinois.
   Copyright (C) 1995, 1996, 2000, 2001, 2002, 2003 Ben Wing.
   Copyright (C) 1995 Sun Microsystems, Inc.
   Copyright (C) 1998 Free Software Foundation, Inc.

This file is part of XEmacs.

XEmacs 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.

XEmacs 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.  */

/* Synched up with: Not in FSF. */

/* This file Mule-ized by Ben Wing, 3-24-02. */

#include <config.h>
#include "lisp.h"

#include "buffer.h"
#include "bytecode.h"
#include "elhash.h"
#include "gui.h"
#include "menubar.h"
#include "redisplay.h"

Lisp_Object Qmenu_no_selection_hook;
Lisp_Object Vmenu_no_selection_hook;

static Lisp_Object parse_gui_item_tree_list (Lisp_Object list);
Lisp_Object find_keyword_in_vector (Lisp_Object vector, Lisp_Object keyword);

Lisp_Object Qgui_error;

#ifdef HAVE_POPUPS

/* count of menus/dboxes currently up */
int popup_up_p;

DEFUN ("popup-up-p", Fpopup_up_p, 0, 0, 0, /*
Return t if a popup menu or dialog box is up, nil otherwise.
See `popup-menu' and `popup-dialog-box'.
*/
       ())
{
  return popup_up_p ? Qt : Qnil;
}
#endif /* HAVE_POPUPS */

int
separator_string_p (const Ibyte *s)
{
  const Ibyte *p;
  Ibyte first;

  if (!s || s[0] == '\0')
    return 0;
  first = s[0];
  if (first != '-' && first != '=')
    return 0;
  for (p = s; *p == first; p++)
    ;

  return (*p == '!' || *p == ':' || *p == '\0');
}

/* Massage DATA to find the correct function and argument.  Used by
   popup_selection_callback() and the msw code. */
void
get_gui_callback (Lisp_Object data, Lisp_Object *fn, Lisp_Object *arg)
{
  if (EQ (data, Qquit))
    {
      *fn = Qeval;
      *arg = list3 (Qsignal, list2 (Qquote, Qquit), Qnil);
      Vquit_flag = Qt;
    }
  else if (SYMBOLP (data)
	   || (COMPILED_FUNCTIONP (data)
	       && XCOMPILED_FUNCTION (data)->flags.interactivep)
	   || (CONSP (data) && (EQ (XCAR (data), Qlambda))
	       && !NILP (Fassq (Qinteractive, Fcdr (Fcdr (data))))))
    {
      *fn = Qcall_interactively;
      *arg = data;
    }
  else if (CONSP (data))
    {
      *fn = Qeval;
      *arg = data;
    }
  else
    {
      *fn = Qeval;
      *arg = list3 (Qsignal,
		    list2 (Qquote, Qerror),
		    list2 (Qquote, list2 (build_msg_string
					  ("illegal callback"),
					  data)));
    }
}

/*
 * Add a value VAL associated with keyword KEY into PGUI_ITEM
 * structure. If KEY is not a keyword, or is an unknown keyword, then
 * error is signaled.
 */
int
gui_item_add_keyval_pair (Lisp_Object gui_item,
			  Lisp_Object key, Lisp_Object val,
			  Error_Behavior errb)
{
  Lisp_Gui_Item *pgui_item = XGUI_ITEM (gui_item);
  int retval = 0;

  if (!KEYWORDP (key))
    sferror_2 ("Non-keyword in gui item", key, pgui_item->name);

  if (EQ (key, Q_descriptor))
    {
      if (!EQ (pgui_item->name, val))
	{
	  retval = 1;
	  pgui_item->name   = val;
	}
    }
#define FROB(slot)				\
  else if (EQ (key, Q_##slot))			\
  {						\
    if (!EQ (pgui_item->slot, val))		\
      {						\
	retval = 1;				\
	pgui_item->slot   = val;		\
      }						\
  }
  FROB (suffix)
  FROB (active)
  FROB (included)
  FROB (config)
  FROB (filter)
  FROB (style)
  FROB (selected)
  FROB (keys)
  FROB (callback)
  FROB (callback_ex)
  FROB (value)
#undef FROB
  else if (EQ (key, Q_key_sequence)) ;   /* ignored for FSF compatibility */
  else if (EQ (key, Q_label)) ;   /* ignored for 21.0 implement in 21.2  */
  else if (EQ (key, Q_accelerator))
    {
      if (!EQ (pgui_item->accelerator, val))
	{
	  retval = 1;
	  if (SYMBOLP (val) || CHARP (val))
	    pgui_item->accelerator = val;
	  else if (ERRB_EQ (errb, ERROR_ME))
	    invalid_argument ("Bad keyboard accelerator", val);
	}
    }
  else if (ERRB_EQ (errb, ERROR_ME))
    invalid_argument_2 ("Unknown keyword in gui item", key, pgui_item->name);
  return retval;
}

void
gui_item_init (Lisp_Object gui_item)
{
  Lisp_Gui_Item *lp = XGUI_ITEM (gui_item);

  lp->name     = Qnil;
  lp->callback = Qnil;
  lp->callback_ex = Qnil;
  lp->suffix   = Qnil;
  lp->active   = Qt;
  lp->included = Qt;
  lp->config   = Qnil;
  lp->filter   = Qnil;
  lp->style    = Qnil;
  lp->selected = Qnil;
  lp->keys     = Qnil;
  lp->accelerator     = Qnil;
  lp->value = Qnil;
}

Lisp_Object
allocate_gui_item (void)
{
#ifdef MC_ALLOC
  Lisp_Gui_Item *lp = alloc_lrecord_type (Lisp_Gui_Item, &lrecord_gui_item);
#else /* not MC_ALLOC */
  Lisp_Gui_Item *lp = alloc_lcrecord_type (Lisp_Gui_Item, &lrecord_gui_item);
#endif /* not MC_ALLOC */
  Lisp_Object val;

  val = wrap_gui_item (lp);

  gui_item_init (val);

  return val;
}

/*
 * ITEM is a lisp vector, describing a menu item or a button. The
 * function extracts the description of the item into the PGUI_ITEM
 * structure.
 */
static Lisp_Object
make_gui_item_from_keywords_internal (Lisp_Object item,
				      Error_Behavior errb)
{
  int length, plist_p, start;
  Lisp_Object *contents;
  Lisp_Object gui_item = allocate_gui_item ();
  Lisp_Gui_Item *pgui_item = XGUI_ITEM (gui_item);

  CHECK_VECTOR (item);
  length = XVECTOR_LENGTH (item);
  contents = XVECTOR_DATA (item);

  if (length < 1)
    sferror ("GUI item descriptors must be at least 1 elts long", item);

  /* length 1:     		[ "name" ]
     length 2:		[ "name" callback ]
     length 3:		[ "name" callback active-p ]
     		   or	[ "name" keyword  value  ]
     length 4:		[ "name" callback active-p suffix ]
     		   or	[ "name" callback keyword  value  ]
     length 5+:		[ "name" callback [ keyword value ]+ ]
     		   or	[ "name" [ keyword value ]+ ]
  */
  plist_p = (length > 2 && (KEYWORDP (contents [1])
			    || KEYWORDP (contents [2])));

  pgui_item->name = contents [0];
  if (length > 1 && !KEYWORDP (contents [1]))
    {
      pgui_item->callback = contents [1];
      start = 2;
    }
  else
    start =1;

  if (!plist_p && length > 2)
    /* the old way */
    {
      pgui_item->active = contents [2];
      if (length == 4)
	pgui_item->suffix = contents [3];
    }
  else
    /* the new way */
    {
      int i;
      if ((length - start) & 1)
	sferror (
		"GUI item descriptor has an odd number of keywords and values",
		 item);

      for (i = start; i < length;)
	{
	  Lisp_Object key = contents [i++];
	  Lisp_Object val = contents [i++];
	  gui_item_add_keyval_pair (gui_item, key, val, errb);
	}
    }
  return gui_item;
}

/* This will only work with descriptors in the new format. */
Lisp_Object
widget_gui_parse_item_keywords (Lisp_Object item)
{
  int i, length;
  Lisp_Object *contents;
  Lisp_Object gui_item = allocate_gui_item ();
  Lisp_Object desc = find_keyword_in_vector (item, Q_descriptor);

  CHECK_VECTOR (item);
  length = XVECTOR_LENGTH (item);
  contents = XVECTOR_DATA (item);

  if (!NILP (desc) && !STRINGP (desc) && !VECTORP (desc))
    sferror ("Invalid GUI item descriptor", item);

  if (length & 1)
    {
      if (!SYMBOLP (contents [0]))
	sferror ("Invalid GUI item descriptor", item);
      contents++;			/* Ignore the leading symbol. */
      length--;
    }

  for (i = 0; i < length;)
    {
      Lisp_Object key = contents [i++];
      Lisp_Object val = contents [i++];
      gui_item_add_keyval_pair (gui_item, key, val, ERROR_ME_NOT);
    }

  return gui_item;
}

/* Update a gui item from a partial descriptor. */
int
update_gui_item_keywords (Lisp_Object gui_item, Lisp_Object item)
{
  int i, length, retval = 0;
  Lisp_Object *contents;

  CHECK_VECTOR (item);
  length = XVECTOR_LENGTH (item);
  contents = XVECTOR_DATA (item);

 if (length & 1)
    {
      if (!SYMBOLP (contents [0]))
	sferror ("Invalid GUI item descriptor", item);
      contents++;			/* Ignore the leading symbol. */
      length--;
    }

  for (i = 0; i < length;)
    {
      Lisp_Object key = contents [i++];
      Lisp_Object val = contents [i++];
      if (gui_item_add_keyval_pair (gui_item, key, val, ERROR_ME_DEBUG_WARN))
	retval = 1;
    }
  return retval;
}

Lisp_Object
gui_parse_item_keywords (Lisp_Object item)
{
  return make_gui_item_from_keywords_internal (item, ERROR_ME);
}

Lisp_Object
gui_parse_item_keywords_no_errors (Lisp_Object item)
{
  return make_gui_item_from_keywords_internal (item, ERROR_ME_DEBUG_WARN);
}

/* convert a gui item into plist properties */
void
gui_add_item_keywords_to_plist (Lisp_Object plist, Lisp_Object gui_item)
{
  Lisp_Gui_Item *pgui_item = XGUI_ITEM (gui_item);

  if (!NILP (pgui_item->callback))
    Fplist_put (plist, Q_callback, pgui_item->callback);
  if (!NILP (pgui_item->callback_ex))
    Fplist_put (plist, Q_callback_ex, pgui_item->callback_ex);
  if (!NILP (pgui_item->suffix))
    Fplist_put (plist, Q_suffix, pgui_item->suffix);
  if (!NILP (pgui_item->active))
    Fplist_put (plist, Q_active, pgui_item->active);
  if (!NILP (pgui_item->included))
    Fplist_put (plist, Q_included, pgui_item->included);
  if (!NILP (pgui_item->config))
    Fplist_put (plist, Q_config, pgui_item->config);
  if (!NILP (pgui_item->filter))
    Fplist_put (plist, Q_filter, pgui_item->filter);
  if (!NILP (pgui_item->style))
    Fplist_put (plist, Q_style, pgui_item->style);
  if (!NILP (pgui_item->selected))
    Fplist_put (plist, Q_selected, pgui_item->selected);
  if (!NILP (pgui_item->keys))
    Fplist_put (plist, Q_keys, pgui_item->keys);
  if (!NILP (pgui_item->accelerator))
    Fplist_put (plist, Q_accelerator, pgui_item->accelerator);
  if (!NILP (pgui_item->value))
    Fplist_put (plist, Q_value, pgui_item->value);
}

static int
gui_item_value (Lisp_Object form)
{
  /* This function can call Lisp. */

#ifndef ERROR_CHECK_DISPLAY
  /* Shortcut to avoid evaluating Qt/Qnil each time; but don't do it when
     error-checking so we catch unprotected eval within redisplay quicker */
  if (NILP (form))
    return 0;
  if (EQ (form, Qt))
    return 1;
#endif
  return !NILP (in_display ? eval_within_redisplay (form) : Feval (form));
}

/*
 * Decide whether a GUI item is active by evaluating its :active form
 * if any
 */
int
gui_item_active_p (Lisp_Object gui_item)
{
  return gui_item_value (XGUI_ITEM (gui_item)->active);
}

/* set menu accelerator key to first underlined character in menu name */
Lisp_Object
gui_item_accelerator (Lisp_Object gui_item)
{
  Lisp_Gui_Item *pgui = XGUI_ITEM (gui_item);

  if (!NILP (pgui->accelerator))
    return pgui->accelerator;

  else
    return gui_name_accelerator (pgui->name);
}

Lisp_Object
gui_name_accelerator (Lisp_Object nm)
{
  Ibyte *name = XSTRING_DATA (nm);

  while (*name)
    {
      if (*name == '%')
	{
	  ++name;
	  if (!(*name))
	    return Qnil;
	  if (*name == '_' && *(name + 1))
	    {
	      Ichar accelerator = itext_ichar (name + 1);
	      return make_char (DOWNCASE (0, accelerator));
	    }
	}
	INC_IBYTEPTR (name);
    }
  return make_char (DOWNCASE (0, itext_ichar (XSTRING_DATA (nm))));
}

/*
 * Decide whether a GUI item is selected by evaluating its :selected form
 * if any
 */
int
gui_item_selected_p (Lisp_Object gui_item)
{
  return gui_item_value (XGUI_ITEM (gui_item)->selected);
}

Lisp_Object
gui_item_list_find_selected (Lisp_Object gui_item_list)
{
  /* This function can call Lisp but cannot GC because it is called within
     redisplay, and redisplay disables GC. */
  Lisp_Object rest;
  LIST_LOOP (rest, gui_item_list)
    {
      if (gui_item_selected_p (XCAR (rest)))
	return XCAR (rest);
    }
  return XCAR (gui_item_list);
}

/*
 * Decide whether a GUI item is included by evaluating its :included
 * form if given, and testing its :config form against supplied CONFLIST
 * configuration variable
 */
int
gui_item_included_p (Lisp_Object gui_item, Lisp_Object conflist)
{
  /* This function can call lisp */
  Lisp_Gui_Item *pgui_item = XGUI_ITEM (gui_item);

  /* Evaluate :included first. Shortcut to avoid evaluating Qt each time */
  if (!gui_item_value (pgui_item->included))
    return 0;

  /* Do :config if conflist is given */
  if (!NILP (conflist) && !NILP (pgui_item->config)
      && NILP (Fmemq (pgui_item->config, conflist)))
    return 0;

  return 1;
}

/*
 * Format "left flush" display portion of an item.
 */
Lisp_Object
gui_item_display_flush_left (Lisp_Object gui_item)
{
  /* This function can call lisp */
  Lisp_Gui_Item *pgui_item = XGUI_ITEM (gui_item);
  Lisp_Object retval;

  CHECK_STRING (pgui_item->name);
  retval = pgui_item->name;

  if (!NILP (pgui_item->suffix))
    {
      Lisp_Object suffix = pgui_item->suffix;
      /* Shortcut to avoid evaluating suffix each time */
      if (!STRINGP (suffix))
	{
	  suffix = Feval (suffix);
	  CHECK_STRING (suffix);
	}

      retval = concat3 (pgui_item->name, build_string (" "), suffix);
    }

  return retval;
}

/*
 * Format "right flush" display portion of an item into BUF.
 */
Lisp_Object
gui_item_display_flush_right (Lisp_Object gui_item)
{
  Lisp_Gui_Item *pgui_item = XGUI_ITEM (gui_item);

#ifdef HAVE_MENUBARS
  /* Have keys? */
  if (!menubar_show_keybindings)
    return Qnil;
#endif

  /* Try :keys first */
  if (!NILP (pgui_item->keys))
    {
      CHECK_STRING (pgui_item->keys);
      return pgui_item->keys;
    }

  /* See if we can derive keys out of callback symbol */
  if (SYMBOLP (pgui_item->callback))
    {
      DECLARE_EISTRING_MALLOC (buf);
      Lisp_Object str;
      
      where_is_to_char (pgui_item->callback, buf);
      str = eimake_string (buf);
      eifree (buf);
      return str;
    }

  /* No keys - no right flush display */
  return Qnil;
}

static const struct memory_description gui_item_description [] = {
  { XD_LISP_OBJECT, offsetof (struct Lisp_Gui_Item, name) },
  { XD_LISP_OBJECT, offsetof (struct Lisp_Gui_Item, callback) },
  { XD_LISP_OBJECT, offsetof (struct Lisp_Gui_Item, callback_ex) },
  { XD_LISP_OBJECT, offsetof (struct Lisp_Gui_Item, suffix) },
  { XD_LISP_OBJECT, offsetof (struct Lisp_Gui_Item, active) },
  { XD_LISP_OBJECT, offsetof (struct Lisp_Gui_Item, included) },
  { XD_LISP_OBJECT, offsetof (struct Lisp_Gui_Item, config) },
  { XD_LISP_OBJECT, offsetof (struct Lisp_Gui_Item, filter) },
  { XD_LISP_OBJECT, offsetof (struct Lisp_Gui_Item, style) },
  { XD_LISP_OBJECT, offsetof (struct Lisp_Gui_Item, selected) },
  { XD_LISP_OBJECT, offsetof (struct Lisp_Gui_Item, keys) },
  { XD_LISP_OBJECT, offsetof (struct Lisp_Gui_Item, accelerator) },
  { XD_LISP_OBJECT, offsetof (struct Lisp_Gui_Item, value) },
  { XD_END }
};

static Lisp_Object
mark_gui_item (Lisp_Object obj)
{
  Lisp_Gui_Item *p = XGUI_ITEM (obj);

  mark_object (p->name);
  mark_object (p->callback);
  mark_object (p->callback_ex);
  mark_object (p->config);
  mark_object (p->suffix);
  mark_object (p->active);
  mark_object (p->included);
  mark_object (p->config);
  mark_object (p->filter);
  mark_object (p->style);
  mark_object (p->selected);
  mark_object (p->keys);
  mark_object (p->accelerator);
  mark_object (p->value);

  return Qnil;
}

static Hashcode
gui_item_hash (Lisp_Object obj, int depth)
{
  Lisp_Gui_Item *p = XGUI_ITEM (obj);

  return HASH2 (HASH6 (internal_hash (p->name, depth + 1),
		       internal_hash (p->callback, depth + 1),
		       internal_hash (p->callback_ex, depth + 1),
		       internal_hash (p->suffix, depth + 1),
		       internal_hash (p->active, depth + 1),
		       internal_hash (p->included, depth + 1)),
		HASH6 (internal_hash (p->config, depth + 1),
		       internal_hash (p->filter, depth + 1),
		       internal_hash (p->style, depth + 1),
		       internal_hash (p->selected, depth + 1),
		       internal_hash (p->keys, depth + 1),
		       internal_hash (p->value, depth + 1)));
}

int
gui_item_id_hash (Lisp_Object hashtable, Lisp_Object gitem, int slot)
{
  int hashid = gui_item_hash (gitem, 0);
  int id = GUI_ITEM_ID_BITS (hashid, slot);
  while (!UNBOUNDP (Fgethash (make_int (id), hashtable, Qunbound)))
    {
      id = GUI_ITEM_ID_BITS (id + 1, slot);
    }
  return id;
}

static int
gui_value_equal (Lisp_Object a, Lisp_Object b, int depth)
{
  if (in_display)
    return internal_equal_trapping_problems
      (Qredisplay, "Error calling function within redisplay", 0, 0,
       /* say they're not equal in case of error; code calling
	  gui_item_equal_sans_selected() in redisplay does extra stuff
	  only when equal */
       0, a, b, depth);
  else
    return internal_equal (a, b, depth);
}

int
gui_item_equal_sans_selected (Lisp_Object obj1, Lisp_Object obj2, int depth)
{
  Lisp_Gui_Item *p1 = XGUI_ITEM (obj1);
  Lisp_Gui_Item *p2 = XGUI_ITEM (obj2);

  if (!(gui_value_equal (p1->name, p2->name, depth + 1)
	&&
	gui_value_equal (p1->callback, p2->callback, depth + 1)
	&&
	gui_value_equal (p1->callback_ex, p2->callback_ex, depth + 1)
	&&
	EQ (p1->suffix, p2->suffix)
	&&
	EQ (p1->active, p2->active)
	&&
	EQ (p1->included, p2->included)
	&&
	EQ (p1->config, p2->config)
	&&
	EQ (p1->filter, p2->filter)
	&&
	EQ (p1->style, p2->style)
	&&
	EQ (p1->accelerator, p2->accelerator)
	&&
	EQ (p1->keys, p2->keys)
	&&
	EQ (p1->value, p2->value)))
    return 0;
  return 1;
}

static int
gui_item_equal (Lisp_Object obj1, Lisp_Object obj2, int depth)
{
  Lisp_Gui_Item *p1 = XGUI_ITEM (obj1);
  Lisp_Gui_Item *p2 = XGUI_ITEM (obj2);

  if (!(gui_item_equal_sans_selected (obj1, obj2, depth) &&
	EQ (p1->selected, p2->selected)))
    return 0;
  return 1;
}

static void
print_gui_item (Lisp_Object obj, Lisp_Object printcharfun,
		int UNUSED (escapeflag))
{
  Lisp_Gui_Item *g = XGUI_ITEM (obj);

  if (print_readably)
    printing_unreadable_object ("#<gui-item 0x%x>", g->header.uid);

  write_fmt_string (printcharfun, "#<gui-item 0x%x>", g->header.uid);
}

Lisp_Object
copy_gui_item (Lisp_Object gui_item)
{
  Lisp_Object  ret = allocate_gui_item ();
  Lisp_Gui_Item *lp, *g = XGUI_ITEM (gui_item);

  lp = XGUI_ITEM (ret);
  lp->name     = g->name;
  lp->callback = g->callback;
  lp->callback_ex = g->callback_ex;
  lp->suffix   = g->suffix;
  lp->active   = g->active;
  lp->included = g->included;
  lp->config   = g->config;
  lp->filter   = g->filter;
  lp->style    = g->style;
  lp->selected = g->selected;
  lp->keys     = g->keys;
  lp->accelerator     = g->accelerator;
  lp->value = g->value;

  return ret;
}

Lisp_Object
copy_gui_item_tree (Lisp_Object arg)
{
  if (CONSP (arg))
    {
      Lisp_Object rest = arg = Fcopy_sequence (arg);
      while (CONSP (rest))
	{
	  XCAR (rest) = copy_gui_item_tree (XCAR (rest));
	  rest = XCDR (rest);
	}
      return arg;
    }
  else if (GUI_ITEMP (arg))
    return copy_gui_item (arg);
  else
    return arg;
}

/* parse a glyph descriptor into a tree of gui items.

   The gui_item slot of an image instance can be a single item or an
   arbitrarily nested hierarchy of item lists. */

static Lisp_Object
parse_gui_item_tree_item (Lisp_Object entry)
{
  Lisp_Object ret = entry;
  struct gcpro gcpro1;

  GCPRO1 (ret);

  if (VECTORP (entry))
    {
      ret = gui_parse_item_keywords_no_errors (entry);
    }
  else if (STRINGP (entry))
    {
      CHECK_STRING (entry);
    }
  else
    sferror ("item must be a vector or a string", entry);

  RETURN_UNGCPRO (ret);
}

Lisp_Object
parse_gui_item_tree_children (Lisp_Object list)
{
  Lisp_Object rest, ret = Qnil, sub = Qnil;
  struct gcpro gcpro1, gcpro2;

  GCPRO2 (ret, sub);
  CHECK_CONS (list);
  /* recursively add items to the tree view */
  LIST_LOOP (rest, list)
    {
      if (CONSP (XCAR (rest)))
	sub = parse_gui_item_tree_list (XCAR (rest));
      else
	sub = parse_gui_item_tree_item (XCAR (rest));

      ret = Fcons (sub, ret);
    }
  /* make the order the same as the items we have parsed */
  RETURN_UNGCPRO (Fnreverse (ret));
}

static Lisp_Object
parse_gui_item_tree_list (Lisp_Object list)
{
  Lisp_Object ret;
  struct gcpro gcpro1;
  CHECK_CONS (list);
  /* first one can never be a list */
  ret = parse_gui_item_tree_item (XCAR (list));
  GCPRO1 (ret);
  ret = Fcons (ret, parse_gui_item_tree_children (XCDR (list)));
  RETURN_UNGCPRO (ret);
}

static void
finalize_gui_item (void *UNUSED (header), int UNUSED (for_disksave))
{
}

DEFINE_LRECORD_IMPLEMENTATION ("gui-item", gui_item,
			       0, /*dumpable-flag*/
			       mark_gui_item, print_gui_item,
			       finalize_gui_item, gui_item_equal,
			       gui_item_hash,
			       gui_item_description,
			       Lisp_Gui_Item);

DOESNT_RETURN
gui_error (const Ascbyte *reason, Lisp_Object frob)
{
  signal_error (Qgui_error, reason, frob);
}

DOESNT_RETURN
gui_error_2 (const Ascbyte *reason, Lisp_Object frob0, Lisp_Object frob1)
{
  signal_error_2 (Qgui_error, reason, frob0, frob1);
}

void
syms_of_gui (void)
{
  INIT_LRECORD_IMPLEMENTATION (gui_item);

  DEFSYMBOL (Qmenu_no_selection_hook);

  DEFERROR_STANDARD (Qgui_error, Qio_error);

#ifdef HAVE_POPUPS
  DEFSUBR (Fpopup_up_p);
#endif
}

void
vars_of_gui (void)
{
  DEFVAR_LISP ("menu-no-selection-hook", &Vmenu_no_selection_hook /*
Function or functions to call when a menu or dialog box is dismissed
without a selection having been made.
*/ );
  Vmenu_no_selection_hook = Qnil;
}