Mercurial > hg > xemacs-beta
annotate src/event-gtk.c @ 4952:19a72041c5ed
Mule-izing, various fixes related to char * arguments
-------------------- ChangeLog entries follow: --------------------
modules/ChangeLog addition:
2010-01-26 Ben Wing <ben@xemacs.org>
* postgresql/postgresql.c:
* postgresql/postgresql.c (CHECK_LIVE_CONNECTION):
* postgresql/postgresql.c (print_pgresult):
* postgresql/postgresql.c (Fpq_conn_defaults):
* postgresql/postgresql.c (Fpq_connectdb):
* postgresql/postgresql.c (Fpq_connect_start):
* postgresql/postgresql.c (Fpq_result_status):
* postgresql/postgresql.c (Fpq_res_status):
Mule-ize large parts of it.
2010-01-26 Ben Wing <ben@xemacs.org>
* ldap/eldap.c (print_ldap):
* ldap/eldap.c (allocate_ldap):
Use write_ascstring().
src/ChangeLog addition:
2010-01-26 Ben Wing <ben@xemacs.org>
* alloc.c:
* alloc.c (build_ascstring):
* alloc.c (build_msg_cistring):
* alloc.c (staticpro_1):
* alloc.c (staticpro_name):
* alloc.c (staticpro_nodump_1):
* alloc.c (staticpro_nodump_name):
* alloc.c (unstaticpro_nodump_1):
* alloc.c (mcpro_1):
* alloc.c (mcpro_name):
* alloc.c (object_memory_usage_stats):
* alloc.c (common_init_alloc_early):
* alloc.c (init_alloc_once_early):
* buffer.c (print_buffer):
* buffer.c (vars_of_buffer):
* buffer.c (common_init_complex_vars_of_buffer):
* buffer.c (init_initial_directory):
* bytecode.c (invalid_byte_code):
* bytecode.c (print_compiled_function):
* bytecode.c (mark_compiled_function):
* chartab.c (print_table_entry):
* chartab.c (print_char_table):
* config.h.in:
* console-gtk.c:
* console-gtk.c (gtk_device_to_console_connection):
* console-gtk.c (gtk_semi_canonicalize_console_connection):
* console-gtk.c (gtk_canonicalize_console_connection):
* console-gtk.c (gtk_semi_canonicalize_device_connection):
* console-gtk.c (gtk_canonicalize_device_connection):
* console-stream.c (stream_init_frame_1):
* console-stream.c (vars_of_console_stream):
* console-stream.c (init_console_stream):
* console-x.c (x_semi_canonicalize_console_connection):
* console-x.c (x_semi_canonicalize_device_connection):
* console-x.c (x_canonicalize_device_connection):
* console-x.h:
* data.c (eq_with_ebola_notice):
* data.c (Fsubr_interactive):
* data.c (Fnumber_to_string):
* data.c (digit_to_number):
* device-gtk.c (gtk_init_device):
* device-msw.c (print_devmode):
* device-x.c (x_event_name):
* dialog-msw.c (handle_directory_dialog_box):
* dialog-msw.c (handle_file_dialog_box):
* dialog-msw.c (vars_of_dialog_mswindows):
* doc.c (weird_doc):
* doc.c (Fsnarf_documentation):
* doc.c (vars_of_doc):
* dumper.c (pdump):
* dynarr.c:
* dynarr.c (Dynarr_realloc):
* editfns.c (Fuser_real_login_name):
* editfns.c (get_home_directory):
* elhash.c (print_hash_table_data):
* elhash.c (print_hash_table):
* emacs.c (main_1):
* emacs.c (vars_of_emacs):
* emodules.c:
* emodules.c (_emodules_list):
* emodules.c (Fload_module):
* emodules.c (Funload_module):
* emodules.c (Flist_modules):
* emodules.c (find_make_module):
* emodules.c (attempt_module_delete):
* emodules.c (emodules_load):
* emodules.c (emodules_doc_subr):
* emodules.c (emodules_doc_sym):
* emodules.c (syms_of_module):
* emodules.c (vars_of_module):
* emodules.h:
* eval.c (print_subr):
* eval.c (signal_call_debugger):
* eval.c (build_error_data):
* eval.c (signal_error):
* eval.c (maybe_signal_error):
* eval.c (signal_continuable_error):
* eval.c (maybe_signal_continuable_error):
* eval.c (signal_error_2):
* eval.c (maybe_signal_error_2):
* eval.c (signal_continuable_error_2):
* eval.c (maybe_signal_continuable_error_2):
* eval.c (signal_ferror):
* eval.c (maybe_signal_ferror):
* eval.c (signal_continuable_ferror):
* eval.c (maybe_signal_continuable_ferror):
* eval.c (signal_ferror_with_frob):
* eval.c (maybe_signal_ferror_with_frob):
* eval.c (signal_continuable_ferror_with_frob):
* eval.c (maybe_signal_continuable_ferror_with_frob):
* eval.c (syntax_error):
* eval.c (syntax_error_2):
* eval.c (maybe_syntax_error):
* eval.c (sferror):
* eval.c (sferror_2):
* eval.c (maybe_sferror):
* eval.c (invalid_argument):
* eval.c (invalid_argument_2):
* eval.c (maybe_invalid_argument):
* eval.c (invalid_constant):
* eval.c (invalid_constant_2):
* eval.c (maybe_invalid_constant):
* eval.c (invalid_operation):
* eval.c (invalid_operation_2):
* eval.c (maybe_invalid_operation):
* eval.c (invalid_change):
* eval.c (invalid_change_2):
* eval.c (maybe_invalid_change):
* eval.c (invalid_state):
* eval.c (invalid_state_2):
* eval.c (maybe_invalid_state):
* eval.c (wtaerror):
* eval.c (stack_overflow):
* eval.c (out_of_memory):
* eval.c (print_multiple_value):
* eval.c (issue_call_trapping_problems_warning):
* eval.c (backtrace_specials):
* eval.c (backtrace_unevalled_args):
* eval.c (Fbacktrace):
* eval.c (warn_when_safe):
* event-Xt.c (modwarn):
* event-Xt.c (modbarf):
* event-Xt.c (check_modifier):
* event-Xt.c (store_modifier):
* event-Xt.c (emacs_Xt_format_magic_event):
* event-Xt.c (describe_event):
* event-gtk.c (dragndrop_data_received):
* event-gtk.c (store_modifier):
* event-gtk.c (gtk_reset_modifier_mapping):
* event-msw.c (dde_eval_string):
* event-msw.c (Fdde_alloc_advise_item):
* event-msw.c (mswindows_dde_callback):
* event-msw.c (FROB):
* event-msw.c (emacs_mswindows_format_magic_event):
* event-stream.c (external_debugging_print_event):
* event-stream.c (execute_help_form):
* event-stream.c (vars_of_event_stream):
* events.c (print_event_1):
* events.c (print_event):
* events.c (event_equal):
* extents.c (print_extent_1):
* extents.c (print_extent):
* extents.c (vars_of_extents):
* faces.c (print_face):
* faces.c (complex_vars_of_faces):
* file-coding.c:
* file-coding.c (print_coding_system):
* file-coding.c (print_coding_system_in_print_method):
* file-coding.c (default_query_method):
* file-coding.c (find_coding_system):
* file-coding.c (make_coding_system_1):
* file-coding.c (chain_print):
* file-coding.c (undecided_print):
* file-coding.c (gzip_print):
* file-coding.c (vars_of_file_coding):
* file-coding.c (complex_vars_of_file_coding):
* fileio.c:
* fileio.c (report_file_type_error):
* fileio.c (report_error_with_errno):
* fileio.c (report_file_error):
* fileio.c (barf_or_query_if_file_exists):
* fileio.c (vars_of_fileio):
* floatfns.c (matherr):
* fns.c (print_bit_vector):
* fns.c (Fmapconcat):
* fns.c (add_suffix_to_symbol):
* fns.c (add_prefix_to_symbol):
* frame-gtk.c:
* frame-gtk.c (Fgtk_window_id):
* frame-x.c (def):
* frame-x.c (x_cde_transfer_callback):
* frame.c:
* frame.c (Fmake_frame):
* gc.c (show_gc_cursor_and_message):
* gc.c (vars_of_gc):
* glyphs-eimage.c (png_instantiate):
* glyphs-eimage.c (tiff_instantiate):
* glyphs-gtk.c (gtk_print_image_instance):
* glyphs-msw.c (mswindows_print_image_instance):
* glyphs-x.c (x_print_image_instance):
* glyphs-x.c (update_widget_face):
* glyphs.c (make_string_from_file):
* glyphs.c (print_image_instance):
* glyphs.c (signal_image_error):
* glyphs.c (signal_image_error_2):
* glyphs.c (signal_double_image_error):
* glyphs.c (signal_double_image_error_2):
* glyphs.c (xbm_mask_file_munging):
* glyphs.c (pixmap_to_lisp_data):
* glyphs.h:
* gui.c (gui_item_display_flush_left):
* hpplay.c (player_error_internal):
* hpplay.c (myHandler):
* intl-win32.c:
* intl-win32.c (langcode_to_lang):
* intl-win32.c (sublangcode_to_lang):
* intl-win32.c (Fmswindows_get_locale_info):
* intl-win32.c (lcid_to_locale_mule_or_no):
* intl-win32.c (mswindows_multibyte_to_unicode_print):
* intl-win32.c (complex_vars_of_intl_win32):
* keymap.c:
* keymap.c (print_keymap):
* keymap.c (ensure_meta_prefix_char_keymapp):
* keymap.c (Fkey_description):
* keymap.c (Ftext_char_description):
* lisp.h:
* lisp.h (struct):
* lisp.h (DECLARE_INLINE_HEADER):
* lread.c (Fload_internal):
* lread.c (locate_file):
* lread.c (read_escape):
* lread.c (read_raw_string):
* lread.c (read1):
* lread.c (read_list):
* lread.c (read_compiled_function):
* lread.c (init_lread):
* lrecord.h:
* marker.c (print_marker):
* marker.c (marker_equal):
* menubar-msw.c (displayable_menu_item):
* menubar-x.c (command_builder_operate_menu_accelerator):
* menubar.c (vars_of_menubar):
* minibuf.c (reinit_complex_vars_of_minibuf):
* minibuf.c (complex_vars_of_minibuf):
* mule-charset.c (Fmake_charset):
* mule-charset.c (complex_vars_of_mule_charset):
* mule-coding.c (iso2022_print):
* mule-coding.c (fixed_width_query):
* number.c (bignum_print):
* number.c (ratio_print):
* number.c (bigfloat_print):
* number.c (bigfloat_finalize):
* objects-msw.c:
* objects-msw.c (mswindows_color_to_string):
* objects-msw.c (mswindows_color_list):
* objects-tty.c:
* objects-tty.c (tty_font_list):
* objects-tty.c (tty_find_charset_font):
* objects-xlike-inc.c (xft_find_charset_font):
* objects-xlike-inc.c (endif):
* print.c:
* print.c (write_istring):
* print.c (write_ascstring):
* print.c (Fterpri):
* print.c (Fprint):
* print.c (print_error_message):
* print.c (print_vector_internal):
* print.c (print_cons):
* print.c (print_string):
* print.c (printing_unreadable_object):
* print.c (print_internal):
* print.c (print_float):
* print.c (print_symbol):
* process-nt.c (mswindows_report_winsock_error):
* process-nt.c (nt_canonicalize_host_name):
* process-unix.c (unix_canonicalize_host_name):
* process.c (print_process):
* process.c (report_process_error):
* process.c (report_network_error):
* process.c (make_process_internal):
* process.c (Fstart_process_internal):
* process.c (status_message):
* process.c (putenv_internal):
* process.c (vars_of_process):
* process.h:
* profile.c (vars_of_profile):
* rangetab.c (print_range_table):
* realpath.c (vars_of_realpath):
* redisplay.c (vars_of_redisplay):
* search.c (wordify):
* search.c (Freplace_match):
* sheap.c (sheap_adjust_h):
* sound.c (report_sound_error):
* sound.c (Fplay_sound_file):
* specifier.c (print_specifier):
* symbols.c (Fsubr_name):
* symbols.c (do_symval_forwarding):
* symbols.c (set_default_buffer_slot_variable):
* symbols.c (set_default_console_slot_variable):
* symbols.c (store_symval_forwarding):
* symbols.c (default_value):
* symbols.c (defsymbol_massage_name_1):
* symbols.c (defsymbol_massage_name_nodump):
* symbols.c (defsymbol_massage_name):
* symbols.c (defsymbol_massage_multiword_predicate_nodump):
* symbols.c (defsymbol_massage_multiword_predicate):
* symbols.c (defsymbol_nodump):
* symbols.c (defsymbol):
* symbols.c (defkeyword):
* symbols.c (defkeyword_massage_name):
* symbols.c (check_module_subr):
* symbols.c (deferror_1):
* symbols.c (deferror):
* symbols.c (deferror_massage_name):
* symbols.c (deferror_massage_name_and_message):
* symbols.c (defvar_magic):
* symeval.h:
* symeval.h (DEFVAR_SYMVAL_FWD):
* sysdep.c:
* sysdep.c (init_system_name):
* sysdll.c:
* sysdll.c (MAYBE_PREPEND_UNDERSCORE):
* sysdll.c (dll_function):
* sysdll.c (dll_variable):
* sysdll.c (dll_error):
* sysdll.c (dll_open):
* sysdll.c (dll_close):
* sysdll.c (image_for_address):
* sysdll.c (my_find_image):
* sysdll.c (search_linked_libs):
* sysdll.h:
* sysfile.h:
* sysfile.h (DEFAULT_DIRECTORY_FALLBACK):
* syswindows.h:
* tests.c (DFC_CHECK_LENGTH):
* tests.c (DFC_CHECK_CONTENT):
* tests.c (Ftest_hash_tables):
* text.c (vars_of_text):
* text.h:
* tooltalk.c (tt_opnum_string):
* tooltalk.c (tt_message_arg_ival_string):
* tooltalk.c (Ftooltalk_default_procid):
* tooltalk.c (Ftooltalk_default_session):
* tooltalk.c (init_tooltalk):
* tooltalk.c (vars_of_tooltalk):
* ui-gtk.c (Fdll_load):
* ui-gtk.c (type_to_marshaller_type):
* ui-gtk.c (Fgtk_import_function_internal):
* ui-gtk.c (emacs_gtk_object_printer):
* ui-gtk.c (emacs_gtk_boxed_printer):
* unicode.c (unicode_to_ichar):
* unicode.c (unicode_print):
* unicode.c (unicode_query):
* unicode.c (vars_of_unicode):
* unicode.c (complex_vars_of_unicode):
* win32.c:
* win32.c (mswindows_report_process_error):
* window.c (print_window):
* xemacs.def.in.in:
BASIC IDEA: Further fixing up uses of char * and CIbyte *
to reflect their actual semantics; Mule-izing some code;
redoing of the not-yet-working code to handle message translation.
Clean up code to handle message-translation (not yet working).
Create separate versions of build_msg_string() for working with
Ibyte *, CIbyte *, and Ascbyte * arguments. Assert that Ascbyte *
arguments are pure-ASCII. Make build_msg_string() be the same
as build_msg_ascstring(). Create same three versions of GETTEXT()
and DEFER_GETTEXT(). Also create build_defer_string() and
variants for the equivalent of DEFER_GETTEXT() when building a
string. Remove old CGETTEXT(). Clean up code where GETTEXT(),
DEFER_GETTEXT(), build_msg_string(), etc. was being called and
introduce some new calls to build_msg_string(), etc. Remove
GETTEXT() from calls to weird_doc() -- we assume that the
message snarfer knows about weird_doc(). Remove uses of
DEFER_GETTEXT() from error messages in sysdep.c and instead use
special comments /* @@@begin-snarf@@@ */ and /* @@@end-snarf@@@ */
that the message snarfer presumably knows about.
Create build_ascstring() and use it in many instances in place
of build_string(). The purpose of having Ascbyte * variants is
to make the code more self-documenting in terms of what sort of
semantics is expected for char * strings. In fact in the process
of looking for uses of build_string(), much improperly Mule-ized
was discovered.
Mule-ize a lot of code as described in previous paragraph,
e.g. in sysdep.c.
Make the error functions take Ascbyte * strings and fix up a
couple of places where non-pure-ASCII strings were being passed in
(file-coding.c, mule-coding.c, unicode.c). (It's debatable whether
we really need to make the error functions work this way. It
helps catch places where code is written in a way that message
translation won't work, but we may well never implement message
translation.)
Make staticpro() and friends take Ascbyte * strings instead of
raw char * strings. Create a const_Ascbyte_ptr dynarr type
to describe what's held by staticpro_names[] and friends,
create pdump descriptions for const_Ascbyte_ptr dynarrs, and
use them in place of specially-crafted staticpro descriptions.
Mule-ize certain other functions (e.g. x_event_name) by correcting
raw use of char * to Ascbyte *, Rawbyte * or another such type,
and raw use of char[] buffers to another type (usually Ascbyte[]).
Change many uses of write_c_string() to write_msg_string(),
write_ascstring(), etc.
Mule-ize emodules.c, emodules.h, sysdll.h.
Fix some un-Mule-ized code in intl-win32.c.
A comment in event-Xt.c and the limitations of the message
snarfer (make-msgfile or whatever) is presumably incorrect --
it should be smart enough to handle function calls spread over
more than one line. Clean up code in event-Xt.c that was
written awkwardly for this reason.
In config.h.in, instead of NEED_ERROR_CHECK_TYPES_INLINES,
create a more general XEMACS_DEFS_NEEDS_INLINE_DECLS to
indicate when inlined functions need to be declared in
xemacs.defs.in.in, and make use of it in xemacs.defs.in.in.
We need to do this because postgresql.c now calls qxestrdup(),
which is an inline function.
Make nconc2() and other such functions MODULE_API and put
them in xemacs.defs.in.in since postgresql.c now uses them.
Clean up indentation in lread.c and a few other places.
In text.h, document ASSERT_ASCTEXT_ASCII() and
ASSERT_ASCTEXT_ASCII_LEN(), group together the stand-in
encodings and add some more for DLL symbols, function and
variable names, etc.
author | Ben Wing <ben@xemacs.org> |
---|---|
date | Tue, 26 Jan 2010 23:22:30 -0600 |
parents | b3ea9c582280 |
children | 304aebb79cd3 |
rev | line source |
---|---|
462 | 1 /* The event_stream interface for X11 with gtk, and/or tty frames. |
2 Copyright (C) 1991-5, 1997 Free Software Foundation, Inc. | |
3 Copyright (C) 1995 Sun Microsystems, Inc. | |
1268 | 4 Copyright (C) 1996, 2001, 2002, 2003 Ben Wing. |
462 | 5 Copyright (C) 2000 William Perry. |
6 | |
7 This file is part of XEmacs. | |
8 | |
9 XEmacs is free software; you can redistribute it and/or modify it | |
10 under the terms of the GNU General Public License as published by the | |
11 Free Software Foundation; either version 2, or (at your option) any | |
12 later version. | |
13 | |
14 XEmacs is distributed in the hope that it will be useful, but WITHOUT | |
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
16 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
17 for more details. | |
18 | |
19 You should have received a copy of the GNU General Public License | |
20 along with XEmacs; see the file COPYING. If not, write to | |
21 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |
22 Boston, MA 02111-1307, USA. */ | |
23 | |
24 /* This file is heavily based upon event-Xt.c */ | |
25 | |
26 /* Synched up with: Not in FSF. */ | |
27 | |
28 #include <config.h> | |
29 #include "lisp.h" | |
30 | |
31 #include "blocktype.h" | |
32 #include "buffer.h" | |
33 #include "commands.h" | |
34 #include "console.h" | |
872 | 35 #include "device-impl.h" |
36 #include "elhash.h" | |
462 | 37 #include "events.h" |
872 | 38 #include "file-coding.h" |
39 #include "frame-impl.h" | |
40 #include "lstream.h" | |
462 | 41 #include "process.h" |
42 #include "redisplay.h" | |
809 | 43 #include "window.h" |
872 | 44 |
45 #include "console-tty.h" | |
46 | |
47 #include "console-gtk-impl.h" | |
48 #include "objects-gtk.h" | |
462 | 49 |
50 #include "gtk-xemacs.h" | |
51 | |
52 #include "systime.h" | |
53 #include "sysproc.h" /* for MAXDESC */ | |
54 | |
55 #include <gdk/gdkkeysyms.h> | |
56 | |
57 #ifdef HAVE_DRAGNDROP | |
58 #include "dragdrop.h" | |
59 #endif | |
60 | |
2081 | 61 #ifdef HAVE_MENUBARS |
62 # include "menubar.h" | |
63 #endif | |
64 | |
778 | 65 #include <gdk/gdkx.h> |
462 | 66 |
778 | 67 #include "event-gtk.h" |
462 | 68 |
69 static struct event_stream *gtk_event_stream; | |
70 | |
1292 | 71 #ifdef WIN32_ANY |
72 extern int mswindows_is_blocking; | |
73 #endif | |
74 | |
462 | 75 /* Do we accept events sent by other clients? */ |
76 int gtk_allow_sendevents; | |
77 | |
78 static int process_events_occurred; | |
79 static int tty_events_occurred; | |
80 | |
81 /* Mask of bits indicating the descriptors that we wait for input on */ | |
1415 | 82 extern SELECT_TYPE input_wait_mask, non_fake_input_wait_mask; |
83 extern SELECT_TYPE process_only_mask, tty_only_mask; | |
462 | 84 |
2054 | 85 static Lisp_Object gtk_keysym_to_emacs_keysym (guint keysym, int simple_p); |
462 | 86 void debug_process_finalization (struct Lisp_Process *p); |
87 gboolean emacs_gtk_event_handler (GtkWidget *wid /* unused */, | |
88 GdkEvent *event, | |
89 gpointer closure /* unused */); | |
90 | |
91 static int last_quit_check_signal_tick_count; | |
92 | |
93 Lisp_Object Qsans_modifiers; | |
94 | |
2489 | 95 /* |
96 * Identify if the keysym is a modifier. This implementation mirrors x.org's | |
97 * IsModifierKey(), but for GDK keysyms. | |
98 */ | |
99 #ifdef GDK_ISO_Lock | |
100 #define IS_MODIFIER_KEY(keysym) \ | |
101 ((((keysym) >= GDK_Shift_L) && ((keysym) <= GDK_Hyper_R)) \ | |
102 || (((keysym) >= GDK_ISO_Lock) && \ | |
103 ((keysym) <= GDK_ISO_Last_Group_Lock)) \ | |
104 || ((keysym) == GDK_Mode_switch) \ | |
105 || ((keysym) == GDK_Num_Lock)) | |
106 #else | |
462 | 107 #define IS_MODIFIER_KEY(keysym) \ |
108 ((((keysym) >= GDK_Shift_L) && ((keysym) <= GDK_Hyper_R)) \ | |
109 || ((keysym) == GDK_Mode_switch) \ | |
110 || ((keysym) == GDK_Num_Lock)) | |
2489 | 111 #endif |
462 | 112 |
1268 | 113 #define THIS_IS_GTK |
114 #include "event-xlike-inc.c" | |
462 | 115 |
116 | |
117 /************************************************************************/ | |
118 /* magic-event handling */ | |
119 /************************************************************************/ | |
120 static void | |
121 handle_focus_event_1 (struct frame *f, int in_p) | |
122 { | |
123 /* We don't want to handle the focus change now, because we might | |
124 be in an accept-process-output, sleep-for, or sit-for. So | |
125 we enqueue it. | |
126 | |
127 Actually, we half handle it: we handle it as far as changing the | |
128 box cursor for redisplay, but we don't call any hooks or do any | |
129 select-frame stuff until after the sit-for. | |
130 */ | |
131 | |
132 if (in_p) | |
133 { | |
134 GTK_WIDGET_SET_FLAGS (FRAME_GTK_TEXT_WIDGET (f), GTK_HAS_FOCUS); | |
135 } | |
136 else | |
137 { | |
138 GTK_WIDGET_UNSET_FLAGS (FRAME_GTK_TEXT_WIDGET (f), GTK_HAS_FOCUS); | |
139 } | |
140 gtk_widget_grab_focus (FRAME_GTK_TEXT_WIDGET (f)); | |
141 gtk_widget_draw_focus (FRAME_GTK_TEXT_WIDGET (f)); | |
142 | |
143 { | |
144 Lisp_Object frm; | |
145 Lisp_Object conser; | |
146 struct gcpro gcpro1; | |
147 | |
793 | 148 frm = wrap_frame (f); |
462 | 149 conser = Fcons (frm, Fcons (FRAME_DEVICE (f), in_p ? Qt : Qnil)); |
150 GCPRO1 (conser); | |
151 | |
152 emacs_handle_focus_change_preliminary (conser); | |
153 enqueue_magic_eval_event (emacs_handle_focus_change_final, | |
154 conser); | |
155 UNGCPRO; | |
156 } | |
157 } | |
158 | |
159 /* both GDK_MAP and GDK_VISIBILITY_NOTIFY can cause this | |
160 JV is_visible has the same semantics as f->visible*/ | |
161 static void | |
162 change_frame_visibility (struct frame *f, int is_visible) | |
163 { | |
793 | 164 Lisp_Object frame = wrap_frame (f); |
462 | 165 |
166 | |
167 if (!FRAME_VISIBLE_P (f) && is_visible) | |
168 { | |
169 FRAME_VISIBLE_P (f) = is_visible; | |
872 | 170 /* [[ This improves the double flicker when uniconifying a frame |
462 | 171 some. A lot of it is not showing a buffer which has changed |
172 while the frame was iconified. To fix it further requires | |
872 | 173 the good 'ol double redisplay structure. ]] -- comment is |
174 invalid, obviously predates 19.12, when the double redisplay | |
175 structure (i.e. current + desired) was put back in. --ben */ | |
462 | 176 MARK_FRAME_WINDOWS_STRUCTURE_CHANGED (f); |
177 va_run_hook_with_args (Qmap_frame_hook, 1, frame); | |
178 } | |
179 else if (FRAME_VISIBLE_P (f) && !is_visible) | |
180 { | |
181 FRAME_VISIBLE_P (f) = 0; | |
182 va_run_hook_with_args (Qunmap_frame_hook, 1, frame); | |
183 } | |
184 else if (FRAME_VISIBLE_P (f) * is_visible < 0) | |
185 { | |
186 FRAME_VISIBLE_P(f) = - FRAME_VISIBLE_P(f); | |
187 if (FRAME_REPAINT_P (f)) | |
188 MARK_FRAME_WINDOWS_STRUCTURE_CHANGED (f); | |
189 va_run_hook_with_args (Qmap_frame_hook, 1, frame); | |
190 } | |
191 } | |
192 | |
193 static void | |
194 handle_map_event (struct frame *f, GdkEvent *event) | |
195 { | |
793 | 196 Lisp_Object frame = wrap_frame (f); |
462 | 197 |
198 if (event->any.type == GDK_MAP) | |
199 { | |
200 FRAME_GTK_TOTALLY_VISIBLE_P (f) = 1; | |
201 change_frame_visibility (f, 1); | |
202 } | |
203 else | |
204 { | |
205 FRAME_GTK_TOTALLY_VISIBLE_P (f) = 0; | |
206 change_frame_visibility (f, 0); | |
207 /* Calling Fframe_iconified_p is the only way we have to | |
208 correctly update FRAME_ICONIFIED_P */ | |
209 Fframe_iconified_p (frame); | |
210 } | |
211 } | |
212 | |
213 static void | |
214 handle_client_message (struct frame *f, GdkEvent *event) | |
215 { | |
216 /* The event-Xt code used to handle WM_DELETE_WINDOW here, but we | |
217 handle that directly in frame-gtk.c */ | |
218 | |
219 if (event->client.message_type == gdk_atom_intern ("WM_PROTOCOLS", 0) && | |
220 (GdkAtom) event->client.data.l[0] == gdk_atom_intern ("WM_TAKE_FOCUS", 0)) | |
221 { | |
222 handle_focus_event_1 (f, 1); | |
223 } | |
224 } | |
225 | |
226 static void | |
788 | 227 emacs_gtk_format_magic_event (Lisp_Event *emacs_event, Lisp_Object pstream) |
228 { | |
789 | 229 Lisp_Object console = CDFW_CONSOLE (EVENT_CHANNEL (emacs_event)); |
788 | 230 if (CONSOLE_GTK_P (XCONSOLE (console))) |
826 | 231 write_c_string |
232 (pstream, | |
1204 | 233 gtk_event_name (EVENT_MAGIC_GDK_EVENT (emacs_event).type)); |
788 | 234 } |
235 | |
236 static int | |
237 emacs_gtk_compare_magic_event (Lisp_Event *e1, Lisp_Event *e2) | |
238 { | |
239 if (CONSOLE_GTK_P (XCONSOLE (CDFW_CONSOLE (EVENT_CHANNEL (e1)))) && | |
240 CONSOLE_GTK_P (XCONSOLE (CDFW_CONSOLE (EVENT_CHANNEL (e2))))) | |
1204 | 241 return (!memcmp (&EVENT_MAGIC_GDK_EVENT (e1), |
242 &EVENT_MAGIC_GDK_EVENT (e2), | |
788 | 243 sizeof (GdkEvent))); |
244 if (CONSOLE_GTK_P (XCONSOLE (CDFW_CONSOLE (EVENT_CHANNEL (e1)))) || | |
245 CONSOLE_GTK_P (XCONSOLE (CDFW_CONSOLE (EVENT_CHANNEL (e2))))) | |
246 return 0; | |
247 return 1; | |
248 } | |
249 | |
250 static Hashcode | |
251 emacs_gtk_hash_magic_event (Lisp_Event *e) | |
252 { | |
253 Lisp_Object console = CDFW_CONSOLE (EVENT_CHANNEL (e)); | |
254 if (CONSOLE_GTK_P (XCONSOLE (console))) | |
1204 | 255 return memory_hash (&EVENT_MAGIC_GDK_EVENT (e), |
788 | 256 sizeof (GdkEvent)); |
257 return 0; | |
258 } | |
259 | |
260 static void | |
462 | 261 emacs_gtk_handle_magic_event (struct Lisp_Event *emacs_event) |
262 { | |
263 /* This function can GC */ | |
1204 | 264 GdkEvent *event = &EVENT_MAGIC_GDK_EVENT (emacs_event); |
462 | 265 struct frame *f = XFRAME (EVENT_CHANNEL (emacs_event)); |
266 | |
267 if (!FRAME_LIVE_P (f)) | |
268 return; | |
269 | |
270 switch (event->any.type) | |
271 { | |
272 case GDK_CLIENT_EVENT: | |
273 handle_client_message (f, event); | |
274 break; | |
275 | |
276 case GDK_FOCUS_CHANGE: | |
277 handle_focus_event_1 (f, event->focus_change.in); | |
278 break; | |
279 | |
280 case GDK_MAP: | |
281 case GDK_UNMAP: | |
282 handle_map_event (f, event); | |
283 break; | |
284 | |
285 case GDK_ENTER_NOTIFY: | |
286 if (event->crossing.detail != GDK_NOTIFY_INFERIOR) | |
287 { | |
793 | 288 Lisp_Object frame = wrap_frame (f); |
462 | 289 |
290 /* FRAME_X_MOUSE_P (f) = 1; */ | |
291 va_run_hook_with_args (Qmouse_enter_frame_hook, 1, frame); | |
292 } | |
293 break; | |
294 | |
295 case GDK_LEAVE_NOTIFY: | |
296 if (event->crossing.detail != GDK_NOTIFY_INFERIOR) | |
297 { | |
793 | 298 Lisp_Object frame = wrap_frame (f); |
462 | 299 |
300 /* FRAME_X_MOUSE_P (f) = 0; */ | |
301 va_run_hook_with_args (Qmouse_leave_frame_hook, 1, frame); | |
302 } | |
303 break; | |
304 | |
305 case GDK_VISIBILITY_NOTIFY: /* window visiblity has changed */ | |
306 if (event->visibility.window == GET_GTK_WIDGET_WINDOW (FRAME_GTK_SHELL_WIDGET (f))) | |
307 { | |
308 FRAME_GTK_TOTALLY_VISIBLE_P (f) = | |
309 (event->visibility.state == GDK_VISIBILITY_UNOBSCURED); | |
310 /* Note that the fvwm pager only sends VisibilityNotify when | |
311 changing pages. Is this all we need to do ? JV */ | |
312 /* Nope. We must at least trigger a redisplay here. | |
313 Since this case seems similar to MapNotify, I've | |
314 factored out some code to change_frame_visibility(). | |
315 This triggers the necessary redisplay and runs | |
316 (un)map-frame-hook. - dkindred@cs.cmu.edu */ | |
317 /* Changed it again to support the tristate visibility flag */ | |
318 change_frame_visibility (f, (event->visibility.state | |
319 != GDK_VISIBILITY_FULLY_OBSCURED) ? 1 : -1); | |
320 } | |
321 break; | |
322 | |
323 default: | |
324 break; | |
325 } | |
326 } | |
327 | |
328 /************************************************************************/ | |
329 /* Gtk to Emacs event conversion */ | |
330 /************************************************************************/ | |
331 | |
332 static int | |
333 keysym_obeys_caps_lock_p (guint sym, struct device *d) | |
334 { | |
335 struct gtk_device *gd = DEVICE_GTK_DATA (d); | |
336 /* Eeeeevil hack. Don't apply Caps_Lock to things that aren't alphabetic | |
337 characters, where "alphabetic" means something more than simply A-Z. | |
338 That is, if Caps_Lock is down, typing ESC doesn't produce Shift-ESC. | |
339 But if shift-lock is down, then it does. */ | |
340 if (gd->lock_interpretation == GDK_Shift_Lock) | |
341 return 1; | |
342 | |
343 return | |
344 ((sym >= GDK_A) && (sym <= GDK_Z)) || | |
345 ((sym >= GDK_a) && (sym <= GDK_z)) || | |
346 ((sym >= GDK_Agrave) && (sym <= GDK_Odiaeresis)) || | |
347 ((sym >= GDK_agrave) && (sym <= GDK_odiaeresis)) || | |
348 ((sym >= GDK_Ooblique) && (sym <= GDK_Thorn)) || | |
349 ((sym >= GDK_oslash) && (sym <= GDK_thorn)); | |
350 } | |
351 | |
352 static void | |
353 set_last_server_timestamp (struct device *d, GdkEvent *gdk_event) | |
354 { | |
355 guint32 t; | |
356 switch (gdk_event->type) | |
357 { | |
358 case GDK_KEY_PRESS: | |
359 case GDK_KEY_RELEASE: t = gdk_event->key.time; break; | |
360 case GDK_BUTTON_PRESS: | |
361 case GDK_2BUTTON_PRESS: | |
362 case GDK_3BUTTON_PRESS: | |
363 case GDK_BUTTON_RELEASE: t = gdk_event->button.time; break; | |
364 case GDK_ENTER_NOTIFY: | |
365 case GDK_LEAVE_NOTIFY: t = gdk_event->crossing.time; break; | |
366 case GDK_MOTION_NOTIFY: t = gdk_event->motion.time; break; | |
367 case GDK_PROPERTY_NOTIFY: t = gdk_event->property.time; break; | |
368 case GDK_SELECTION_CLEAR: | |
369 case GDK_SELECTION_REQUEST: | |
370 case GDK_SELECTION_NOTIFY: t = gdk_event->selection.time; break; | |
371 default: return; | |
372 } | |
373 DEVICE_GTK_LAST_SERVER_TIMESTAMP (d) = t; | |
374 } | |
375 | |
376 static Lisp_Object | |
377 gtk_keysym_to_emacs_keysym (guint keysym, int simple_p) | |
378 { | |
379 char *name; | |
380 if (keysym >= GDK_exclam && keysym <= GDK_asciitilde) | |
381 /* We must assume that the X keysym numbers for the ASCII graphic | |
382 characters are the same as their ASCII codes. */ | |
383 return make_char (keysym); | |
384 | |
385 switch (keysym) | |
386 { | |
387 /* These would be handled correctly by the default case, but by | |
388 special-casing them here we don't garbage a string or call | |
389 intern(). */ | |
390 case GDK_BackSpace: return QKbackspace; | |
391 case GDK_Tab: return QKtab; | |
392 case GDK_Linefeed: return QKlinefeed; | |
393 case GDK_Return: return QKreturn; | |
394 case GDK_Escape: return QKescape; | |
395 case GDK_space: return QKspace; | |
396 case GDK_Delete: return QKdelete; | |
397 case 0: return Qnil; | |
398 default: | |
399 if (simple_p) return Qnil; | |
400 /* !!#### not Mule-ized */ | |
401 name = gdk_keyval_name (keysym); | |
402 if (!name || !name[0]) | |
403 /* This happens if there is a mismatch between the Xlib of | |
404 XEmacs and the Xlib of the X server... | |
405 | |
406 Let's hard-code in some knowledge of common keysyms introduced | |
407 in recent X11 releases. Snarfed from X11/keysymdef.h | |
408 | |
409 Probably we should add some stuff here for X11R6. */ | |
410 switch (keysym) | |
411 { | |
412 case 0xFF95: return KEYSYM ("kp-home"); | |
413 case 0xFF96: return KEYSYM ("kp-left"); | |
414 case 0xFF97: return KEYSYM ("kp-up"); | |
415 case 0xFF98: return KEYSYM ("kp-right"); | |
416 case 0xFF99: return KEYSYM ("kp-down"); | |
417 case 0xFF9A: return KEYSYM ("kp-prior"); | |
418 case 0xFF9B: return KEYSYM ("kp-next"); | |
419 case 0xFF9C: return KEYSYM ("kp-end"); | |
420 case 0xFF9D: return KEYSYM ("kp-begin"); | |
421 case 0xFF9E: return KEYSYM ("kp-insert"); | |
422 case 0xFF9F: return KEYSYM ("kp-delete"); | |
423 | |
424 case 0x1005FF10: return KEYSYM ("SunF36"); /* labeled F11 */ | |
425 case 0x1005FF11: return KEYSYM ("SunF37"); /* labeled F12 */ | |
426 default: | |
427 { | |
428 char buf [64]; | |
429 sprintf (buf, "unknown-keysym-0x%X", (int) keysym); | |
430 return KEYSYM (buf); | |
431 } | |
432 } | |
433 /* If it's got a one-character name, that's good enough. */ | |
434 if (!name[1]) | |
435 return make_char (name[0]); | |
436 | |
437 /* If it's in the "Keyboard" character set, downcase it. | |
438 The case of those keysyms is too totally random for us to | |
439 force anyone to remember them. | |
440 The case of the other character sets is significant, however. | |
441 */ | |
442 if ((((unsigned int) keysym) & (~0x1FF)) == ((unsigned int) 0xFE00)) | |
443 { | |
444 char buf [255]; | |
445 char *s1, *s2; | |
446 for (s1 = name, s2 = buf; *s1; s1++, s2++) { | |
447 if (*s1 == '_') { | |
448 *s2 = '-'; | |
449 } else { | |
450 *s2 = tolower (* (unsigned char *) s1); | |
451 } | |
452 } | |
453 *s2 = 0; | |
454 return KEYSYM (buf); | |
455 } | |
456 return KEYSYM (name); | |
457 } | |
458 } | |
459 | |
460 static Lisp_Object | |
461 gtk_to_emacs_keysym (struct device *d, GdkEventKey *event, int simple_p) | |
462 /* simple_p means don't try too hard (ASCII only) */ | |
463 { | |
464 if (event->length != 1) | |
771 | 465 { |
462 | 466 /* Generate multiple emacs events */ |
867 | 467 Ichar ch; |
462 | 468 Lisp_Object instream, fb_instream; |
469 Lstream *istr; | |
470 struct gcpro gcpro1, gcpro2; | |
471 | |
472 fb_instream = | |
771 | 473 make_fixed_buffer_input_stream ((unsigned char *) event->string, event->length); |
462 | 474 |
771 | 475 /* #### Use get_coding_system_for_text_file |
476 (Vcomposed_input_coding_system, 0) */ | |
462 | 477 instream = |
771 | 478 make_coding_input_stream (XLSTREAM (fb_instream), |
800 | 479 Qundecided, CODING_DECODE, 0); |
462 | 480 |
481 istr = XLSTREAM (instream); | |
482 | |
483 GCPRO2 (instream, fb_instream); | |
867 | 484 while ((ch = Lstream_get_ichar (istr)) != EOF) |
771 | 485 { |
462 | 486 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil); |
1204 | 487 Lisp_Event *ev = XEVENT (emacs_event); |
488 ev->channel = DEVICE_CONSOLE (d); | |
462 | 489 ev->timestamp = event->time; |
1204 | 490 XSET_EVENT_TYPE (emacs_event, key_press_event); |
491 XSET_EVENT_KEY_MODIFIERS (emacs_event, 0); | |
492 XSET_EVENT_KEY_KEYSYM (emacs_event, make_char (ch)); | |
493 enqueue_dispatch_event (emacs_event); | |
771 | 494 } |
462 | 495 Lstream_close (istr); |
496 UNGCPRO; | |
497 Lstream_delete (istr); | |
498 Lstream_delete (XLSTREAM (fb_instream)); | |
499 if (IS_MODIFIER_KEY (event->keyval) || (event->keyval == GDK_Mode_switch)) | |
771 | 500 return (Qnil); |
462 | 501 return (gtk_keysym_to_emacs_keysym (event->keyval, simple_p)); |
771 | 502 } |
462 | 503 else |
771 | 504 { |
462 | 505 if (IS_MODIFIER_KEY (event->keyval) || (event->keyval == GDK_Mode_switch)) |
771 | 506 return (Qnil); |
462 | 507 return (gtk_keysym_to_emacs_keysym (event->keyval, simple_p)); |
771 | 508 } |
462 | 509 } |
510 | |
511 | |
512 /************************************************************************/ | |
513 /* timeout events */ | |
514 /************************************************************************/ | |
515 | |
516 static int timeout_id_tick; | |
517 | |
853 | 518 struct GTK_timeout |
519 { | |
520 int id; | |
521 guint timeout_id; | |
522 struct GTK_timeout *next; | |
462 | 523 } *pending_timeouts, *completed_timeouts; |
524 | |
525 struct GTK_timeout_blocktype | |
526 { | |
527 Blocktype_declare (struct GTK_timeout); | |
528 } *the_GTK_timeout_blocktype; | |
529 | |
530 /* called by the gtk main loop */ | |
531 static gint | |
532 gtk_timeout_callback (gpointer closure) | |
533 { | |
534 struct GTK_timeout *timeout = (struct GTK_timeout *) closure; | |
535 struct GTK_timeout *t2 = pending_timeouts; | |
536 | |
537 /* Remove this one from the list of pending timeouts */ | |
538 if (t2 == timeout) | |
539 pending_timeouts = pending_timeouts->next; | |
540 else | |
541 { | |
542 while (t2->next && t2->next != timeout) t2 = t2->next; | |
543 assert (t2->next); | |
544 t2->next = t2->next->next; | |
545 } | |
546 /* Add this one to the list of completed timeouts */ | |
547 timeout->next = completed_timeouts; | |
548 completed_timeouts = timeout; | |
853 | 549 return FALSE; |
462 | 550 } |
551 | |
552 static int | |
553 emacs_gtk_add_timeout (EMACS_TIME thyme) | |
554 { | |
555 struct GTK_timeout *timeout = Blocktype_alloc (the_GTK_timeout_blocktype); | |
556 EMACS_TIME current_time; | |
557 int milliseconds; | |
558 | |
559 timeout->id = timeout_id_tick++; | |
560 timeout->next = pending_timeouts; | |
561 pending_timeouts = timeout; | |
562 EMACS_GET_TIME (current_time); | |
563 EMACS_SUB_TIME (thyme, thyme, current_time); | |
564 milliseconds = EMACS_SECS (thyme) * 1000 + | |
565 EMACS_USECS (thyme) / 1000; | |
566 if (milliseconds < 1) | |
567 milliseconds = 1; | |
568 timeout->timeout_id = gtk_timeout_add (milliseconds, | |
569 gtk_timeout_callback, | |
570 (gpointer) timeout); | |
571 return timeout->id; | |
572 } | |
573 | |
574 static void | |
575 emacs_gtk_remove_timeout (int id) | |
576 { | |
577 struct GTK_timeout *timeout, *t2; | |
578 | |
579 timeout = NULL; | |
580 | |
581 /* Find the timeout on the list of pending ones, if it's still there. */ | |
582 if (pending_timeouts) | |
583 { | |
584 if (id == pending_timeouts->id) | |
585 { | |
586 timeout = pending_timeouts; | |
587 pending_timeouts = pending_timeouts->next; | |
588 } | |
589 else | |
590 { | |
591 t2 = pending_timeouts; | |
592 while (t2->next && t2->next->id != id) t2 = t2->next; | |
593 if ( t2->next) /*found it */ | |
594 { | |
595 timeout = t2->next; | |
596 t2->next = t2->next->next; | |
597 } | |
598 } | |
599 /* if it was pending, we have removed it from the list */ | |
600 if (timeout) | |
601 gtk_timeout_remove (timeout->timeout_id); | |
602 } | |
603 | |
604 /* It could be that the call back was already called but we didn't convert | |
605 into an Emacs event yet */ | |
606 if (!timeout && completed_timeouts) | |
607 { | |
608 /* Code duplication! */ | |
609 if (id == completed_timeouts->id) | |
610 { | |
611 timeout = completed_timeouts; | |
612 completed_timeouts = completed_timeouts->next; | |
613 } | |
614 else | |
615 { | |
616 t2 = completed_timeouts; | |
617 while (t2->next && t2->next->id != id) t2 = t2->next; | |
618 if ( t2->next) /*found it */ | |
619 { | |
620 timeout = t2->next; | |
621 t2->next = t2->next->next; | |
622 } | |
623 } | |
624 } | |
625 | |
626 /* If we found the thing on the lists of timeouts, | |
627 and removed it, deallocate | |
628 */ | |
629 if (timeout) | |
630 Blocktype_free (the_GTK_timeout_blocktype, timeout); | |
631 } | |
632 | |
633 static void | |
634 gtk_timeout_to_emacs_event (struct Lisp_Event *emacs_event) | |
635 { | |
636 struct GTK_timeout *timeout = completed_timeouts; | |
637 assert (timeout); | |
638 completed_timeouts = completed_timeouts->next; | |
639 /* timeout events have nil as channel */ | |
1204 | 640 set_event_type (emacs_event, timeout_event); |
641 SET_EVENT_TIMESTAMP_ZERO (emacs_event); /* #### wrong!! */ | |
642 SET_EVENT_TIMEOUT_INTERVAL_ID (emacs_event, timeout->id); | |
643 SET_EVENT_TIMEOUT_FUNCTION (emacs_event, Qnil); | |
644 SET_EVENT_TIMEOUT_OBJECT (emacs_event, Qnil); | |
462 | 645 Blocktype_free (the_GTK_timeout_blocktype, timeout); |
646 } | |
647 | |
648 | |
649 /************************************************************************/ | |
650 /* process and tty events */ | |
651 /************************************************************************/ | |
652 | |
653 struct what_is_ready_closure | |
654 { | |
655 int fd; | |
656 Lisp_Object what; | |
657 gint id; | |
658 }; | |
659 | |
660 static Lisp_Object *filedesc_with_input; | |
661 static struct what_is_ready_closure **filedesc_to_what_closure; | |
662 | |
663 static void | |
664 init_what_input_once (void) | |
665 { | |
666 int i; | |
667 | |
668 filedesc_with_input = xnew_array (Lisp_Object, MAXDESC); | |
669 filedesc_to_what_closure = | |
670 xnew_array (struct what_is_ready_closure *, MAXDESC); | |
671 | |
672 for (i = 0; i < MAXDESC; i++) | |
673 { | |
674 filedesc_to_what_closure[i] = 0; | |
675 filedesc_with_input[i] = Qnil; | |
676 } | |
677 | |
678 process_events_occurred = 0; | |
679 tty_events_occurred = 0; | |
680 } | |
681 | |
682 static void | |
683 mark_what_as_being_ready (struct what_is_ready_closure *closure) | |
684 { | |
685 if (NILP (filedesc_with_input[closure->fd])) | |
686 { | |
687 SELECT_TYPE temp_mask; | |
688 FD_ZERO (&temp_mask); | |
689 FD_SET (closure->fd, &temp_mask); | |
690 /* Check to make sure there's *really* input available. | |
691 Sometimes things seem to get confused and this gets called | |
692 for the tty fd when there's really only input available | |
693 on some process's fd. (It will subsequently get called | |
694 for that process's fd, so returning without setting any | |
695 flags will take care of it.) To see the problem, uncomment | |
696 the stderr_out below, turn NORMAL_QUIT_CHECK_TIMEOUT_MSECS | |
697 down to 25, do sh -c 'xemacs -nw -q -f shell 2>/tmp/log' | |
698 and press return repeatedly. (Seen under AIX & Linux.) | |
699 -dkindred@cs.cmu.edu */ | |
700 if (!poll_fds_for_input (temp_mask)) | |
701 { | |
702 #if 0 | |
703 stderr_out ("mark_what_as_being_ready: no input available (fd=%d)\n", | |
704 closure->fd); | |
705 #endif | |
706 return; | |
707 } | |
708 filedesc_with_input[closure->fd] = closure->what; | |
709 if (PROCESSP (closure->what)) | |
853 | 710 /* Don't increment this if the current process is already marked |
711 * as having input. */ | |
712 process_events_occurred++; | |
462 | 713 else |
853 | 714 tty_events_occurred++; |
462 | 715 } |
716 } | |
717 | |
718 static void | |
2286 | 719 gtk_what_callback (gpointer closure, gint UNUSED (source), |
720 GdkInputCondition UNUSED (why)) | |
462 | 721 { |
722 /* If closure is 0, then we got a fake event from a signal handler. | |
723 The only purpose of this is to make XtAppProcessEvent() stop | |
724 blocking. */ | |
725 if (closure) | |
726 mark_what_as_being_ready ((struct what_is_ready_closure *) closure); | |
727 else | |
728 { | |
729 fake_event_occurred++; | |
730 drain_signal_event_pipe (); | |
731 } | |
732 } | |
733 | |
734 static void | |
735 select_filedesc (int fd, Lisp_Object what) | |
736 { | |
737 struct what_is_ready_closure *closure; | |
738 | |
739 /* If somebody is trying to select something that's already selected | |
740 for, then something went wrong. The generic routines ought to | |
741 detect this and error before here. */ | |
742 assert (!filedesc_to_what_closure[fd]); | |
743 | |
744 closure = xnew (struct what_is_ready_closure); | |
745 closure->fd = fd; | |
746 closure->what = what; | |
747 closure->id = gdk_input_add (fd, GDK_INPUT_READ, | |
748 (GdkInputFunction) gtk_what_callback, closure); | |
749 filedesc_to_what_closure[fd] = closure; | |
750 } | |
751 | |
752 static void | |
753 unselect_filedesc (int fd) | |
754 { | |
755 struct what_is_ready_closure *closure = filedesc_to_what_closure[fd]; | |
756 | |
757 assert (closure); | |
758 if (!NILP (filedesc_with_input[fd])) | |
759 { | |
760 /* We are unselecting this process before we have drained the rest of | |
761 the input from it, probably from status_notify() in the command loop. | |
762 This can happen like so: | |
763 | |
764 - We are waiting in XtAppNextEvent() | |
765 - Process generates output | |
766 - Process is marked as being ready | |
767 - Process dies, SIGCHLD gets generated before we return (!?) | |
768 It could happen I guess. | |
769 - sigchld_handler() marks process as dead | |
770 - Somehow we end up getting a new KeyPress event on the queue | |
771 at the same time (I'm really so sure how that happens but I'm | |
772 not sure it can't either so let's assume it can...). | |
773 - Key events have priority so we return that instead of the proc. | |
774 - Before dispatching the lisp key event we call status_notify() | |
775 - Which deselects the process that SIGCHLD marked as dead. | |
776 | |
777 Thus we never remove it from _with_input and turn it into a lisp | |
778 event, so we need to do it here. But this does not mean that we're | |
779 throwing away the last block of output - status_notify() has already | |
780 taken care of running the proc filter or whatever. | |
781 */ | |
782 filedesc_with_input[fd] = Qnil; | |
783 if (PROCESSP (closure->what)) | |
784 { | |
785 assert (process_events_occurred > 0); | |
786 process_events_occurred--; | |
787 } | |
788 else | |
789 { | |
790 assert (tty_events_occurred > 0); | |
791 tty_events_occurred--; | |
792 } | |
793 } | |
794 gdk_input_remove (closure->id); | |
1726 | 795 xfree (closure, struct what_is_ready_closure *); |
462 | 796 filedesc_to_what_closure[fd] = 0; |
797 } | |
798 | |
799 static void | |
853 | 800 emacs_gtk_select_process (Lisp_Process *process, int doin, int doerr) |
462 | 801 { |
853 | 802 Lisp_Object proc; |
803 int infd, errfd; | |
804 | |
805 event_stream_unixoid_select_process (process, doin, doerr, &infd, &errfd); | |
806 | |
807 proc = wrap_process (process); | |
808 if (doin) | |
809 select_filedesc (infd, proc); | |
810 if (doerr) | |
811 select_filedesc (errfd, proc); | |
812 } | |
462 | 813 |
853 | 814 static void |
815 emacs_gtk_unselect_process (Lisp_Process *process, int doin, int doerr) | |
816 { | |
817 int infd, errfd; | |
818 | |
819 event_stream_unixoid_unselect_process (process, doin, doerr, &infd, &errfd); | |
820 | |
821 if (doin) | |
822 unselect_filedesc (infd); | |
823 if (doerr) | |
824 unselect_filedesc (errfd); | |
462 | 825 } |
826 | |
827 static void | |
853 | 828 emacs_gtk_create_io_streams (void *inhandle, void *outhandle, |
829 void *errhandle, Lisp_Object *instream, | |
830 Lisp_Object *outstream, | |
831 Lisp_Object *errstream, | |
832 USID *in_usid, | |
833 USID *err_usid, | |
834 int flags) | |
462 | 835 { |
853 | 836 event_stream_unixoid_create_io_streams |
837 (inhandle, outhandle, errhandle, instream, outstream, | |
838 errstream, in_usid, err_usid, flags); | |
839 if (*in_usid != USID_ERROR) | |
840 *in_usid = USID_DONTHASH; | |
841 if (*err_usid != USID_ERROR) | |
842 *err_usid = USID_DONTHASH; | |
462 | 843 } |
844 | |
853 | 845 static void |
846 emacs_gtk_delete_io_streams (Lisp_Object instream, | |
847 Lisp_Object outstream, | |
848 Lisp_Object errstream, | |
849 USID *in_usid, | |
850 USID *err_usid) | |
462 | 851 { |
853 | 852 event_stream_unixoid_delete_io_streams |
853 (instream, outstream, errstream, in_usid, err_usid); | |
854 *in_usid = USID_DONTHASH; | |
855 *err_usid = USID_DONTHASH; | |
462 | 856 } |
857 | |
858 /* This is called from GC when a process object is about to be freed. | |
859 If we've still got pointers to it in this file, we're gonna lose hard. | |
860 */ | |
861 void | |
2286 | 862 debug_process_finalization (struct Lisp_Process *UNUSED (p)) |
462 | 863 { |
864 #if 0 /* #### */ | |
865 int i; | |
866 Lisp_Object instr, outstr; | |
867 | |
868 get_process_streams (p, &instr, &outstr); | |
869 /* if it still has fds, then it hasn't been killed yet. */ | |
870 assert (NILP(instr)); | |
871 assert (NILP(outstr)); | |
872 /* Better not still be in the "with input" table; we know it's got no fds. */ | |
873 for (i = 0; i < MAXDESC; i++) | |
874 { | |
875 Lisp_Object process = filedesc_fds_with_input [i]; | |
876 assert (!PROCESSP (process) || XPROCESS (process) != p); | |
877 } | |
878 #endif | |
879 } | |
880 | |
881 static void | |
882 gtk_process_to_emacs_event (struct Lisp_Event *emacs_event) | |
883 { | |
884 int i; | |
885 | |
886 assert (process_events_occurred > 0); | |
1204 | 887 |
462 | 888 for (i = 0; i < MAXDESC; i++) |
889 { | |
1204 | 890 Lisp_Object process = filedesc_with_input[i]; |
462 | 891 if (PROCESSP (process)) |
1204 | 892 { |
893 filedesc_with_input[i] = Qnil; | |
894 process_events_occurred--; | |
895 /* process events have nil as channel */ | |
896 set_event_type (emacs_event, process_event); | |
897 SET_EVENT_TIMESTAMP_ZERO (emacs_event); /* #### */ | |
898 SET_EVENT_PROCESS_PROCESS (emacs_event, process); | |
899 return; | |
900 } | |
462 | 901 } |
2500 | 902 ABORT (); |
462 | 903 } |
904 | |
905 static void | |
906 emacs_gtk_select_console (struct console *con) | |
907 { | |
908 Lisp_Object console; | |
909 int infd; | |
910 | |
911 if (CONSOLE_GTK_P (con)) | |
912 return; /* Gtk consoles are automatically selected for when we initialize them */ | |
913 infd = event_stream_unixoid_select_console (con); | |
793 | 914 console = wrap_console (con); |
462 | 915 select_filedesc (infd, console); |
916 } | |
917 | |
918 static void | |
919 emacs_gtk_unselect_console (struct console *con) | |
920 { | |
921 Lisp_Object console; | |
922 int infd; | |
923 | |
924 if (CONSOLE_GTK_P (con)) | |
925 return; /* X consoles are automatically selected for when we initialize them */ | |
926 infd = event_stream_unixoid_unselect_console (con); | |
793 | 927 console = wrap_console (con); |
462 | 928 unselect_filedesc (infd); |
929 } | |
930 | |
931 /* read an event from a tty, if one is available. Returns non-zero | |
932 if an event was available. Note that when this function is | |
933 called, there should always be a tty marked as ready for input. | |
934 However, the input condition might actually be EOF, so there | |
935 may not really be any input available. (In this case, | |
936 read_event_from_tty_or_stream_desc() will arrange for the TTY device | |
937 to be deleted.) */ | |
938 | |
939 static int | |
940 gtk_tty_to_emacs_event (struct Lisp_Event *emacs_event) | |
941 { | |
942 int i; | |
943 | |
944 assert (tty_events_occurred > 0); | |
945 for (i = 0; i < MAXDESC; i++) | |
946 { | |
947 Lisp_Object console = filedesc_with_input[i]; | |
948 if (CONSOLEP (console)) | |
949 { | |
950 assert (tty_events_occurred > 0); | |
951 tty_events_occurred--; | |
952 filedesc_with_input[i] = Qnil; | |
771 | 953 if (read_event_from_tty_or_stream_desc (emacs_event, |
954 XCONSOLE (console))) | |
462 | 955 return 1; |
956 } | |
957 } | |
958 | |
959 return 0; | |
960 } | |
961 | |
962 | |
963 /************************************************************************/ | |
964 /* Drag 'n Drop handling */ | |
965 /************************************************************************/ | |
966 #ifdef HAVE_DRAGNDROP | |
967 #define TARGET_URI_LIST 0x00 | |
968 #define TARGET_TEXT_PLAIN 0x01 | |
969 #define TARGET_FILE_NAME 0x02 | |
970 #define TARGET_NETSCAPE 0x03 | |
971 | |
972 static GdkAtom preferred_targets[10]; | |
973 | |
974 void | |
975 dragndrop_data_received (GtkWidget *widget, | |
976 GdkDragContext *context, | |
977 gint x, | |
978 gint y, | |
979 GtkSelectionData *data, | |
2286 | 980 guint UNUSED (info), |
462 | 981 guint time) |
982 { | |
983 Lisp_Object event = Fmake_event (Qnil, Qnil); | |
984 struct device *d = gtk_any_window_to_device (widget->window); | |
985 struct frame *f = gtk_any_widget_or_parent_to_frame (d, widget); | |
986 struct Lisp_Event *ev = XEVENT (event); | |
987 Lisp_Object l_type = Qnil, l_data = Qnil; | |
988 Lisp_Object l_dndlist = Qnil, l_item = Qnil; | |
989 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4; | |
990 | |
991 GCPRO4 (l_type, l_data, l_dndlist, l_item); | |
992 | |
1204 | 993 set_event_type (ev, misc_user_event); |
994 SET_EVENT_CHANNEL (ev, wrap_frame (f)); | |
995 SET_EVENT_TIMESTAMP (ev, time); | |
996 SET_EVENT_MISC_USER_X (ev, x); | |
997 SET_EVENT_MISC_USER_Y (ev, y); | |
462 | 998 |
999 if (data->type == preferred_targets[TARGET_URI_LIST]) | |
1000 { | |
1001 /* newline-separated list of URLs */ | |
1002 int start, end; | |
1003 const char *string_data = (char *) data->data; | |
1004 | |
1005 l_type = Qdragdrop_URL; | |
1006 | |
1007 for (start = 0, end = 0; string_data && string_data[end]; end++) | |
1008 { | |
1009 if ((string_data[end] == '\r') && (string_data[end+1] == '\n')) | |
1010 { | |
1011 l_item = make_string (&string_data[start], end - start); | |
1012 l_dndlist = Fcons (l_item, l_dndlist); | |
1013 ++end; | |
1014 start = ++end; | |
1015 } | |
1016 } | |
1017 } | |
1018 else if (data->type == preferred_targets[TARGET_TEXT_PLAIN]) | |
1019 { | |
1020 /* Arbitrary string */ | |
1021 l_type = Qdragdrop_MIME; | |
4952
19a72041c5ed
Mule-izing, various fixes related to char * arguments
Ben Wing <ben@xemacs.org>
parents:
4834
diff
changeset
|
1022 l_dndlist = list1 (list3 (list1 (build_ascstring ("text/plain")), |
19a72041c5ed
Mule-izing, various fixes related to char * arguments
Ben Wing <ben@xemacs.org>
parents:
4834
diff
changeset
|
1023 build_ascstring ("8_bit"), |
462 | 1024 make_ext_string (data->data, |
1025 strlen ((char *)data->data), | |
1026 Qctext))); | |
1027 } | |
1028 else if (data->type == preferred_targets[TARGET_FILE_NAME]) | |
1029 { | |
1030 /* Random filename */ | |
1031 char *hurl = dnd_url_hexify_string (data->data, "file:"); | |
1032 | |
867 | 1033 l_dndlist = list1 (make_string ((Ibyte *)hurl, strlen (hurl))); |
462 | 1034 l_type = Qdragdrop_URL; |
1035 | |
1726 | 1036 xfree (hurl, char *); |
462 | 1037 } |
1038 else if (data->type == preferred_targets[TARGET_NETSCAPE]) | |
1039 { | |
1040 /* Single URL */ | |
1041 l_dndlist = list1 (make_string ((Extbyte *)data->data, | |
1042 strlen ((char *)data->data))); | |
1043 l_type = Qdragdrop_URL; | |
1044 } | |
1045 else | |
1046 { | |
1047 /* Unknown type - what to do? | |
1048 We just pass it up to lisp - we already have a mime type. | |
1049 */ | |
1050 l_type = Qdragdrop_MIME; | |
1051 l_dndlist = list1 (list3 (list1 (build_string (gdk_atom_name (data->type))), | |
4952
19a72041c5ed
Mule-izing, various fixes related to char * arguments
Ben Wing <ben@xemacs.org>
parents:
4834
diff
changeset
|
1052 build_ascstring ("8bit"), |
462 | 1053 make_ext_string ((Extbyte *) data->data, |
1054 data->length, Qbinary))); | |
1055 } | |
1056 | |
1204 | 1057 |
1058 SET_EVENT_MISC_USER_FUNCTION (ev, Qdragdrop_drop_dispatch); | |
1059 SET_EVENT_MISC_USER_OBJECT (ev, Fcons (l_type, l_dndlist)); | |
462 | 1060 |
1061 UNGCPRO; | |
1062 | |
1063 gtk_drag_finish (context, TRUE, FALSE, time); | |
1204 | 1064 enqueue_dispatch_event (event); |
462 | 1065 } |
1066 | |
1067 gboolean | |
2286 | 1068 dragndrop_dropped (GtkWidget *UNUSED (widget), |
462 | 1069 GdkDragContext *drag_context, |
2286 | 1070 gint UNUSED (x), |
1071 gint UNUSED (y), | |
462 | 1072 guint time, |
1073 gpointer user_data) | |
1074 { | |
1075 /* Netscape drops things like: | |
1076 STRING | |
1077 _SGI_ICON | |
1078 _SGI_ICON_TYPE | |
1079 SGI_FILE | |
1080 FILE_NAME | |
1081 _NETSCAPE_URL | |
1082 | |
1083 gmc drops things like | |
1084 application/x-mc-desktop-icon | |
1085 text/uri-list | |
1086 text/plain | |
1087 _NETSCAPE_URL | |
1088 | |
1089 We prefer: | |
1090 text/uri-list | |
1091 text/plain | |
1092 FILE_NAME | |
1093 _NETSCAPE_URL | |
1094 first one | |
1095 */ | |
1096 GdkAtom found = 0; | |
1097 GList *list = drag_context->targets; | |
1098 | |
1099 int i; | |
1100 | |
1101 if (!preferred_targets[0]) | |
1102 { | |
1103 preferred_targets[TARGET_URI_LIST] = gdk_atom_intern ("text/uri-list", FALSE); | |
1104 preferred_targets[TARGET_TEXT_PLAIN] = gdk_atom_intern ("text/plain", FALSE); | |
1105 preferred_targets[TARGET_FILE_NAME] = gdk_atom_intern ("FILE_NAME", FALSE); | |
1106 preferred_targets[TARGET_NETSCAPE] = gdk_atom_intern ("_NETSCAPE_URL", FALSE); | |
1107 } | |
1108 | |
1109 #if 0 | |
1110 stderr_out ("Drop info available in the following formats: \n"); | |
1111 while (list) | |
1112 { | |
1113 stderr_out ("\t%s\n", gdk_atom_name ((GdkAtom)list->data)); | |
1114 list = list->next; | |
1115 } | |
1116 list = drag_context->targets; | |
1117 #endif | |
1118 | |
1119 while (list && !found) | |
1120 { | |
1121 for (i = 0; preferred_targets[i] && !found; i++) | |
1122 { | |
1123 if ((GdkAtom) list->data == preferred_targets[i]) | |
1124 { | |
1125 found = (GdkAtom) list->data; | |
1126 } | |
1127 } | |
1128 list = list->next; | |
1129 } | |
1130 | |
1131 if (!found) | |
1132 { | |
1133 found = (GdkAtom) drag_context->targets->data; | |
1134 } | |
1135 | |
1136 gtk_drag_get_data (GTK_WIDGET (user_data), drag_context, found, time); | |
1137 return (TRUE); | |
1138 } | |
1139 #endif /* HAVE_DRAGNDROP */ | |
1140 | |
1141 | |
1142 /************************************************************************/ | |
1143 /* get the next event from gtk */ | |
1144 /************************************************************************/ | |
1145 | |
1146 /* This business exists because menu events "happen" when | |
1147 menubar_selection_callback() is called from somewhere deep | |
1148 within XtAppProcessEvent in emacs_Xt_next_event(). The | |
1149 callback needs to terminate the modal loop in that function | |
1150 or else it will continue waiting until another event is | |
1151 received. | |
1152 | |
1153 Same business applies to scrollbar events. */ | |
1154 | |
1155 void | |
1156 signal_special_gtk_user_event (Lisp_Object channel, Lisp_Object function, | |
1157 Lisp_Object object) | |
1158 { | |
1159 Lisp_Object event = Fmake_event (Qnil, Qnil); | |
1160 | |
1204 | 1161 XSET_EVENT_TYPE (event, misc_user_event); |
1162 XSET_EVENT_CHANNEL (event, channel); | |
1163 XSET_EVENT_MISC_USER_FUNCTION (event, function); | |
1164 XSET_EVENT_MISC_USER_OBJECT (event, object); | |
1165 enqueue_dispatch_event (event); | |
462 | 1166 } |
1167 | |
1168 static void | |
1169 emacs_gtk_next_event (struct Lisp_Event *emacs_event) | |
1170 { | |
1171 we_didnt_get_an_event: | |
1172 | |
1173 while (NILP (dispatch_event_queue) && | |
1174 !completed_timeouts && | |
1175 !fake_event_occurred && | |
1176 !process_events_occurred && | |
1177 !tty_events_occurred) | |
1178 { | |
1292 | 1179 #ifdef WIN32_ANY |
1180 mswindows_is_blocking = 1; | |
1181 #endif | |
1182 gtk_main_iteration (); | |
1183 #ifdef WIN32_ANY | |
1184 mswindows_is_blocking = 0; | |
1185 #endif | |
462 | 1186 } |
1187 | |
1188 if (!NILP (dispatch_event_queue)) | |
1189 { | |
1190 Lisp_Object event, event2; | |
793 | 1191 event2 = wrap_event (emacs_event); |
1204 | 1192 event = dequeue_dispatch_event (); |
462 | 1193 Fcopy_event (event, event2); |
1194 Fdeallocate_event (event); | |
1195 } | |
1196 else if (tty_events_occurred) | |
1197 { | |
1198 if (!gtk_tty_to_emacs_event (emacs_event)) | |
1199 goto we_didnt_get_an_event; | |
1200 } | |
1201 else if (completed_timeouts) | |
1202 gtk_timeout_to_emacs_event (emacs_event); | |
1203 else if (fake_event_occurred) | |
1204 { | |
1205 /* A dummy event, so that a cycle of the command loop will occur. */ | |
1206 fake_event_occurred = 0; | |
1207 /* eval events have nil as channel */ | |
1204 | 1208 set_event_type (emacs_event, eval_event); |
1209 SET_EVENT_EVAL_FUNCTION (emacs_event, Qidentity); | |
1210 SET_EVENT_EVAL_OBJECT (emacs_event, Qnil); | |
462 | 1211 } |
1212 else /* if (process_events_occurred) */ | |
1213 gtk_process_to_emacs_event (emacs_event); | |
1214 } | |
1215 | |
1216 int | |
1217 gtk_event_to_emacs_event (struct frame *frame, GdkEvent *gdk_event, struct Lisp_Event *emacs_event) | |
1218 { | |
1219 struct device *d = NULL; | |
1220 struct gtk_device *gd = NULL; | |
1221 gboolean accept_any_window = FALSE; | |
1222 | |
872 | 1223 /* #### Under what circumstances can this happen???? Hunt out the code that |
1224 sets frame to 0 and fix it instead. */ | |
462 | 1225 if (!frame) |
1226 { | |
872 | 1227 frame = XFRAME (Fselected_frame (get_default_device (Qgtk))); |
462 | 1228 accept_any_window = TRUE; |
1229 } | |
1230 | |
1231 d = XDEVICE (FRAME_DEVICE (frame)); | |
1232 gd = DEVICE_GTK_DATA (d); | |
1233 | |
1234 set_last_server_timestamp (d, gdk_event); | |
1235 | |
1236 switch (gdk_event->type) | |
1237 { | |
1238 /* XEmacs handles double and triple clicking on its own, and if | |
1239 we capture these events, it royally confuses the code in | |
1240 ../lisp/mouse.el */ | |
1241 case GDK_2BUTTON_PRESS: | |
1242 case GDK_3BUTTON_PRESS: | |
1243 return (0); | |
1244 | |
1245 case GDK_BUTTON_PRESS: | |
1246 case GDK_BUTTON_RELEASE: | |
1247 /* We need to ignore button events outside our main window or | |
1248 things get ugly. The standard scrollbars in Gtk try to be | |
1249 nice and pass the button press events up to the parent | |
1250 widget. This causes us no end of grief though. Effects | |
1251 range from setting point to the wrong place to selecting | |
1252 new windows. */ | |
1253 { | |
1254 GdkWindow *w = gdk_window_at_pointer (NULL, NULL); | |
1255 | |
1256 /* If you press mouse button and drag it around, and release | |
1257 it outside the window, you will get a NULL GdkWindow at | |
1258 pointer. We need to forward these events on to XEmacs so | |
1259 that the mouse selection voodoo works. | |
1260 */ | |
1261 if (w && (w != gdk_window_lookup (GDK_ROOT_WINDOW ()))) | |
1262 { | |
1263 GdkEvent ev; | |
1264 GtkWidget *wid = NULL; | |
1265 | |
1266 ev.any.window = w; | |
1267 wid = gtk_get_event_widget (&ev); | |
1268 | |
1269 if (!GTK_IS_XEMACS (wid) && !accept_any_window) | |
1270 { | |
1271 return (0); | |
1272 } | |
1273 } | |
1274 if (!accept_any_window) | |
1275 gtk_widget_grab_focus (FRAME_GTK_TEXT_WIDGET (frame)); | |
1276 } | |
1277 /* Fall through */ | |
1278 case GDK_KEY_PRESS: | |
1279 { | |
1280 unsigned int modifiers = 0; | |
1281 int shift_p, lock_p; | |
1282 gboolean key_event_p = (gdk_event->type == GDK_KEY_PRESS); | |
1283 unsigned int *state = | |
1284 key_event_p ? &gdk_event->key.state : &gdk_event->button.state; | |
1285 | |
1286 /* If this is a synthetic KeyPress or Button event, and the user | |
1287 has expressed a disinterest in this security hole, then drop | |
1288 it on the floor. */ | |
1289 /* #### BILL!!! Should this be a generic check for ANY synthetic | |
1290 event? */ | |
1291 if ((gdk_event->any.send_event) && !gtk_allow_sendevents) | |
1292 return 0; | |
1293 | |
1294 DEVICE_GTK_MOUSE_TIMESTAMP (d) = | |
1295 DEVICE_GTK_GLOBAL_MOUSE_TIMESTAMP (d) = | |
1296 key_event_p ? gdk_event->key.time : gdk_event->button.time; | |
1297 | |
1298 if (*state & GDK_CONTROL_MASK) modifiers |= XEMACS_MOD_CONTROL; | |
1299 if (*state & gd->MetaMask) modifiers |= XEMACS_MOD_META; | |
1300 if (*state & gd->SuperMask) modifiers |= XEMACS_MOD_SUPER; | |
1301 if (*state & gd->HyperMask) modifiers |= XEMACS_MOD_HYPER; | |
1302 if (*state & gd->AltMask) modifiers |= XEMACS_MOD_ALT; | |
1303 | |
589 | 1304 { |
1305 int numero_de_botao = -1; | |
1306 | |
1307 if (!key_event_p) | |
1308 numero_de_botao = gdk_event->button.button; | |
1309 | |
1310 /* the button gets noted either in the button or the modifiers | |
1311 field, but not both. */ | |
1312 if (numero_de_botao != 1 && (*state & GDK_BUTTON1_MASK)) | |
1313 modifiers |= XEMACS_MOD_BUTTON1; | |
1314 if (numero_de_botao != 2 && (*state & GDK_BUTTON2_MASK)) | |
1315 modifiers |= XEMACS_MOD_BUTTON2; | |
1316 if (numero_de_botao != 3 && (*state & GDK_BUTTON3_MASK)) | |
1317 modifiers |= XEMACS_MOD_BUTTON3; | |
1318 if (numero_de_botao != 4 && (*state & GDK_BUTTON4_MASK)) | |
1319 modifiers |= XEMACS_MOD_BUTTON4; | |
1320 if (numero_de_botao != 5 && (*state & GDK_BUTTON5_MASK)) | |
1321 modifiers |= XEMACS_MOD_BUTTON5; | |
1322 } | |
1323 | |
462 | 1324 /* Ignore the Caps_Lock key if: |
1325 - any other modifiers are down, so that Caps_Lock doesn't | |
1326 turn C-x into C-X, which would suck. | |
1327 - the event was a mouse event. */ | |
1328 if (modifiers || ! key_event_p) | |
1329 *state &= (~GDK_LOCK_MASK); | |
1330 | |
1331 shift_p = *state & GDK_SHIFT_MASK; | |
1332 lock_p = *state & GDK_LOCK_MASK; | |
1333 | |
1334 if (shift_p || lock_p) | |
1335 modifiers |= XEMACS_MOD_SHIFT; | |
1336 | |
1337 if (key_event_p) | |
1338 { | |
1339 GdkEventKey *key_event = &gdk_event->key; | |
1340 Lisp_Object keysym; | |
1341 | |
2081 | 1342 #ifdef HAVE_MENUBARS |
1343 /* If the user wants see if the event is a menu bar accelerator. | |
1344 The process of checking absorbs the event and starts menu | |
1345 processing so send a null event into XEmacs to make sure it | |
1346 does nothing. | |
1347 */ | |
1348 if (!NILP (Vmenu_accelerator_enabled) | |
1349 && gtk_accel_groups_activate(GTK_OBJECT (FRAME_GTK_SHELL_WIDGET(frame)), | |
1350 key_event->keyval, | |
1351 (GdkModifierType) *state)) | |
1352 { | |
1353 zero_event(emacs_event); | |
1354 return 1; | |
1355 } | |
1356 #endif | |
1357 | |
462 | 1358 /* This used to compute the frame from the given X window and |
1359 store it here, but we really don't care about the frame. */ | |
1360 emacs_event->channel = DEVICE_CONSOLE (d); | |
1361 | |
1362 /* Keysym mucking has already been done inside the | |
1363 GdkEventKey parsing */ | |
1364 keysym = gtk_to_emacs_keysym (d, key_event, 0); | |
1365 | |
1366 /* If the emacs keysym is nil, then that means that the X | |
1367 keysym was either a Modifier or NoSymbol, which | |
1368 probably means that we're in the midst of reading a | |
1369 Multi_key sequence, or a "dead" key prefix, or XIM | |
1370 input. Ignore it. */ | |
1371 if (NILP (keysym)) | |
1372 return 0; | |
1373 | |
1374 /* More Caps_Lock garbage: Caps_Lock should *only* add the | |
1375 shift modifier to two-case keys (that is, A-Z and | |
1376 related characters). So at this point (after looking up | |
1377 the keysym) if the keysym isn't a dual-case alphabetic, | |
1378 and if the caps lock key was down but the shift key | |
1379 wasn't, then turn off the shift modifier. Gag barf */ | |
1380 /* #### type lossage: assuming equivalence of emacs and | |
1381 X keysyms */ | |
1382 /* !!#### maybe fix for Mule */ | |
1383 if (lock_p && !shift_p && | |
1384 ! (CHAR_OR_CHAR_INTP (keysym) | |
1385 && keysym_obeys_caps_lock_p | |
1386 ((guint) XCHAR_OR_CHAR_INT (keysym), d))) | |
1387 modifiers &= (~XEMACS_MOD_SHIFT); | |
1388 | |
1389 /* If this key contains two distinct keysyms, that is, | |
1390 "shift" generates a different keysym than the | |
1391 non-shifted key, then don't apply the shift modifier | |
1392 bit: it's implicit. Otherwise, if there would be no | |
1393 other way to tell the difference between the shifted | |
1394 and unshifted version of this key, apply the shift bit. | |
1395 Non-graphics, like Backspace and F1 get the shift bit | |
1396 in the modifiers slot. Neither the characters "a", | |
1397 "A", "2", nor "@" normally have the shift bit set. | |
1398 However, "F1" normally does. */ | |
1399 if (modifiers & XEMACS_MOD_SHIFT) | |
1400 { | |
1401 if (CHAR_OR_CHAR_INTP (keysym)) | |
1402 { | |
1403 modifiers &= ~XEMACS_MOD_SHIFT; | |
1404 } | |
1405 } | |
1406 | |
1204 | 1407 set_event_type (emacs_event, key_press_event); |
1408 SET_EVENT_TIMESTAMP (emacs_event, key_event->time); | |
1409 SET_EVENT_KEY_MODIFIERS (emacs_event, modifiers); | |
1410 SET_EVENT_KEY_KEYSYM (emacs_event, keysym); | |
462 | 1411 } |
1412 else /* Mouse press/release event */ | |
1413 { | |
1414 GdkEventButton *button_event = &gdk_event->button; | |
1415 | |
1204 | 1416 set_event_type (emacs_event, |
1417 button_event->type == GDK_BUTTON_RELEASE ? | |
1418 button_release_event : button_press_event); | |
1419 SET_EVENT_CHANNEL (emacs_event, wrap_frame (frame)); | |
462 | 1420 |
1204 | 1421 SET_EVENT_BUTTON_MODIFIERS (emacs_event, modifiers); |
1422 SET_EVENT_TIMESTAMP (emacs_event, button_event->time); | |
1423 SET_EVENT_BUTTON_BUTTON (emacs_event, button_event->button); | |
2054 | 1424 SET_EVENT_BUTTON_X (emacs_event, (int) button_event->x); |
1425 SET_EVENT_BUTTON_Y (emacs_event, (int) button_event->y); | |
462 | 1426 } |
1427 } | |
1428 break; | |
1429 case GDK_KEY_RELEASE: | |
1430 return 0; | |
1431 break; | |
1432 case GDK_MOTION_NOTIFY: | |
1433 { | |
1434 GdkEventMotion *ev = &gdk_event->motion; | |
1435 unsigned int modifiers = 0; | |
1436 gint x,y; | |
1437 GdkModifierType mask; | |
1438 | |
1439 /* We use MOTION_HINT_MASK, so we will get only one motion | |
1440 event until the next time we call gdk_window_get_pointer or | |
1441 the user clicks the mouse. So call gdk_window_get_pointer | |
1442 now (meaning that the event will be in sync with the server | |
1443 just before Fnext_event() returns). If the mouse is still | |
1444 in motion, then the server will immediately generate | |
1445 exactly one more motion event, which will be on the queue | |
1446 waiting for us next time around. */ | |
1447 gdk_window_get_pointer (ev->window, &x, &y, &mask); | |
1448 | |
1449 DEVICE_GTK_MOUSE_TIMESTAMP (d) = ev->time; | |
1450 | |
1204 | 1451 SET_EVENT_CHANNEL (emacs_event, wrap_frame (frame)); |
1452 set_event_type (emacs_event, pointer_motion_event); | |
1453 SET_EVENT_TIMESTAMP (emacs_event, ev->time); | |
1454 SET_EVENT_MOTION_X (emacs_event, x); | |
1455 SET_EVENT_MOTION_Y (emacs_event, y); | |
1456 | |
462 | 1457 if (mask & GDK_SHIFT_MASK) modifiers |= XEMACS_MOD_SHIFT; |
1458 if (mask & GDK_CONTROL_MASK) modifiers |= XEMACS_MOD_CONTROL; | |
1459 if (mask & gd->MetaMask) modifiers |= XEMACS_MOD_META; | |
1460 if (mask & gd->SuperMask) modifiers |= XEMACS_MOD_SUPER; | |
1461 if (mask & gd->HyperMask) modifiers |= XEMACS_MOD_HYPER; | |
1462 if (mask & gd->AltMask) modifiers |= XEMACS_MOD_ALT; | |
589 | 1463 if (mask & GDK_BUTTON1_MASK) modifiers |= XEMACS_MOD_BUTTON1; |
1464 if (mask & GDK_BUTTON2_MASK) modifiers |= XEMACS_MOD_BUTTON2; | |
1465 if (mask & GDK_BUTTON3_MASK) modifiers |= XEMACS_MOD_BUTTON3; | |
1466 if (mask & GDK_BUTTON4_MASK) modifiers |= XEMACS_MOD_BUTTON4; | |
1467 if (mask & GDK_BUTTON5_MASK) modifiers |= XEMACS_MOD_BUTTON5; | |
1468 | |
462 | 1469 /* Currently ignores Shift_Lock but probably shouldn't |
1470 (but it definitely should ignore Caps_Lock). */ | |
1204 | 1471 SET_EVENT_MOTION_MODIFIERS (emacs_event, modifiers); |
462 | 1472 } |
1473 break; | |
1474 | |
1475 default: /* it's a magic event */ | |
1476 return (0); | |
1477 break; | |
1478 } | |
1479 return 1; | |
1480 } | |
1481 | |
1482 static const char *event_name (GdkEvent *); | |
1483 | |
1484 static gboolean | |
1485 generic_event_handler (GtkWidget *widget, GdkEvent *event) | |
1486 { | |
1487 Lisp_Object emacs_event = Qnil; | |
1488 if (!GTK_IS_XEMACS (widget)) | |
1489 { | |
1490 stderr_out ("Got a %s event for a non-XEmacs widget\n",event_name (event)); | |
1491 return (FALSE); | |
1492 } | |
1493 | |
1494 emacs_event = Fmake_event (Qnil, Qnil); | |
1495 | |
1496 if (gtk_event_to_emacs_event (GTK_XEMACS_FRAME (widget), event, XEVENT (emacs_event))) | |
1497 { | |
1204 | 1498 enqueue_dispatch_event (emacs_event); |
462 | 1499 return (TRUE); |
1500 } | |
1501 else | |
1502 { | |
1503 Fdeallocate_event (emacs_event); | |
1504 } | |
1505 return (FALSE); | |
1506 } | |
1507 | |
1416 | 1508 gint |
1509 emacs_gtk_key_event_handler (GtkWidget *widget, GdkEventKey *event) | |
462 | 1510 { |
1511 return (generic_event_handler (widget, (GdkEvent *) event)); | |
1512 } | |
1513 | |
1416 | 1514 gint |
1515 emacs_gtk_button_event_handler (GtkWidget *widget, GdkEventButton *event) | |
462 | 1516 { |
1517 return (generic_event_handler (widget, (GdkEvent *) event)); | |
1518 } | |
1519 | |
1416 | 1520 gint |
1521 emacs_gtk_motion_event_handler (GtkWidget *widget, GdkEventMotion *event) | |
462 | 1522 { |
1523 return (generic_event_handler (widget, (GdkEvent *) event)); | |
1524 } | |
1525 | |
1526 gboolean | |
2286 | 1527 emacs_shell_event_handler (GtkWidget *UNUSED (wid), |
462 | 1528 GdkEvent *event, |
1529 gpointer closure) | |
1530 { | |
1531 struct frame *frame = (struct frame *) closure; | |
1532 Lisp_Object lisp_event = Fmake_event (Qnil, Qnil); | |
1533 struct Lisp_Event *emacs_event = XEVENT (lisp_event); | |
1204 | 1534 GdkEvent *gdk_event_copy = &EVENT_MAGIC_GDK_EVENT (emacs_event); |
462 | 1535 struct device *d = XDEVICE (FRAME_DEVICE (frame)); |
1536 gboolean ignore_p = FALSE; | |
1537 | |
1538 set_last_server_timestamp (d, event); | |
1539 | |
1540 #define FROB(event_member) gdk_event_copy->event_member = event->event_member | |
1541 | |
1542 switch (event->type) | |
1543 { | |
1544 case GDK_SELECTION_REQUEST: | |
1545 case GDK_SELECTION_CLEAR: | |
1546 case GDK_SELECTION_NOTIFY: FROB(selection); break; | |
1547 case GDK_PROPERTY_NOTIFY: FROB(property); break; | |
1548 case GDK_CLIENT_EVENT: FROB(client); break; | |
1549 case GDK_MAP: | |
1550 case GDK_UNMAP: FROB(any); break; | |
1551 case GDK_CONFIGURE: FROB(configure); break; | |
1552 case GDK_ENTER_NOTIFY: | |
1553 case GDK_LEAVE_NOTIFY: FROB(crossing); break; | |
1554 case GDK_FOCUS_CHANGE: FROB(focus_change); break; | |
1555 case GDK_VISIBILITY_NOTIFY: FROB(visibility); break; | |
1556 default: | |
1557 ignore_p = TRUE; | |
1558 /* Hrmm... do we really want to swallow all the other events as magic? */ | |
1559 *gdk_event_copy = *event; | |
1560 break; | |
1561 } | |
1562 #undef FROB | |
1563 | |
1564 emacs_event->event_type = magic_event; | |
793 | 1565 emacs_event->channel = wrap_frame (frame); |
462 | 1566 |
1567 if (ignore_p) | |
793 | 1568 { |
462 | 1569 stderr_out ("Ignoring event... (%s)\n", event_name (event)); |
1570 Fdeallocate_event (lisp_event); | |
1571 return (FALSE); | |
793 | 1572 } |
462 | 1573 else |
793 | 1574 { |
1204 | 1575 enqueue_dispatch_event (lisp_event); |
462 | 1576 return (TRUE); |
793 | 1577 } |
462 | 1578 } |
1579 | |
1580 | |
1581 /************************************************************************/ | |
1582 /* input pending / C-g checking */ | |
1583 /************************************************************************/ | |
1584 | |
1585 #include <gdk/gdkx.h> | |
1586 | |
1587 static void | |
1204 | 1588 emacs_gtk_drain_queue (void) |
462 | 1589 |
1590 { | |
1591 /* We can't just spin through here and wait for GTKs idea of the | |
1592 event queue to get empty, or the queue never gets drained. The | |
1593 situation is as follows. A process event gets signalled, we put | |
1594 it on the queue, then we go into Fnext_event(), which calls | |
1204 | 1595 emacs_gtk_drain_queue(). But gtk_events_pending() will always return |
462 | 1596 TRUE if there are file-descriptor (aka our process) events |
1597 pending. Using GDK_events_pending() only shows us windowing | |
1598 system events. | |
1599 */ | |
1600 if (GDK_DISPLAY ()) | |
1601 while (gdk_events_pending ()) | |
1602 gtk_main_iteration (); | |
1204 | 1603 |
1268 | 1604 #ifdef HAVE_TTY |
1204 | 1605 drain_tty_devices (); |
462 | 1606 #endif |
1607 } | |
1608 | |
790 | 1609 static void |
2286 | 1610 emacs_gtk_force_event_pending (struct frame* UNUSED (f)) |
790 | 1611 { |
1612 #if 0 | |
1613 stderr_out ("Force event pending called on frame %p!\n", f); | |
1614 #endif | |
1615 } | |
1616 | |
462 | 1617 |
1618 /************************************************************************/ | |
1619 /* initialization */ | |
1620 /************************************************************************/ | |
1621 | |
1622 void | |
1623 syms_of_event_gtk (void) | |
1624 { | |
563 | 1625 DEFSYMBOL (Qsans_modifiers); |
462 | 1626 } |
1627 | |
1416 | 1628 void |
1629 reinit_vars_of_event_gtk (void) | |
462 | 1630 { |
1204 | 1631 gtk_event_stream = xnew_and_zero (struct event_stream); |
462 | 1632 gtk_event_stream->event_pending_p = emacs_gtk_event_pending_p; |
1633 gtk_event_stream->next_event_cb = emacs_gtk_next_event; | |
1634 gtk_event_stream->handle_magic_event_cb= emacs_gtk_handle_magic_event; | |
788 | 1635 gtk_event_stream->format_magic_event_cb= emacs_gtk_format_magic_event; |
1636 gtk_event_stream->compare_magic_event_cb= emacs_gtk_compare_magic_event; | |
1637 gtk_event_stream->hash_magic_event_cb = emacs_gtk_hash_magic_event; | |
462 | 1638 gtk_event_stream->add_timeout_cb = emacs_gtk_add_timeout; |
1639 gtk_event_stream->remove_timeout_cb = emacs_gtk_remove_timeout; | |
1640 gtk_event_stream->select_console_cb = emacs_gtk_select_console; | |
1641 gtk_event_stream->unselect_console_cb = emacs_gtk_unselect_console; | |
1642 gtk_event_stream->select_process_cb = emacs_gtk_select_process; | |
1643 gtk_event_stream->unselect_process_cb = emacs_gtk_unselect_process; | |
1204 | 1644 gtk_event_stream->drain_queue_cb = emacs_gtk_drain_queue; |
876 | 1645 gtk_event_stream->create_io_streams_cb= emacs_gtk_create_io_streams; |
1646 gtk_event_stream->delete_io_streams_cb= emacs_gtk_delete_io_streams; | |
1204 | 1647 gtk_event_stream->force_event_pending_cb= emacs_gtk_force_event_pending; |
462 | 1648 |
1649 the_GTK_timeout_blocktype = Blocktype_new (struct GTK_timeout_blocktype); | |
1650 | |
1651 /* this function only makes safe calls */ | |
1652 init_what_input_once (); | |
1653 } | |
1654 | |
1655 void | |
1656 vars_of_event_gtk (void) | |
1657 { | |
1658 DEFVAR_BOOL ("gtk-allow-sendevents", >k_allow_sendevents /* | |
1659 *Non-nil means to allow synthetic events. Nil means they are ignored. | |
1660 Beware: allowing emacs to process SendEvents opens a big security hole. | |
1661 */ ); | |
1662 gtk_allow_sendevents = 0; | |
1663 | |
1664 last_quit_check_signal_tick_count = 0; | |
1665 } | |
1666 | |
1667 void | |
1668 init_event_gtk_late (void) /* called when already initialized */ | |
1669 { | |
1670 timeout_id_tick = 1; | |
1671 pending_timeouts = 0; | |
1672 completed_timeouts = 0; | |
1673 | |
1674 event_stream = gtk_event_stream; | |
1675 | |
1676 #if 0 | |
1677 /* Shut GDK the hell up */ | |
1678 gdk_error_trap_push (); | |
1679 #endif | |
1680 | |
1681 gdk_input_add (signal_event_pipe[0], GDK_INPUT_READ, | |
1682 (GdkInputFunction) gtk_what_callback, NULL); | |
1683 } | |
1684 | |
1685 /* Bogus utility routines */ | |
1416 | 1686 static const char * |
1687 event_name (GdkEvent *ev) | |
462 | 1688 { |
1689 return (gtk_event_name (ev->any.type)); | |
1690 } | |
1691 | |
1692 /* This is down at the bottom of the file so I can avoid polluting the | |
1693 generic code with this X specific CRAP! */ | |
1694 | |
1695 #include <gdk/gdkx.h> | |
1696 #include <X11/keysym.h> | |
1697 /* #### BILL!!! Fix this please! */ | |
1698 | |
1699 | |
1700 /************************************************************************/ | |
1701 /* keymap handling */ | |
1702 /************************************************************************/ | |
1703 | |
1704 /* X bogusly doesn't define the interpretations of any bits besides | |
1705 ModControl, ModShift, and ModLock; so the Interclient Communication | |
1706 Conventions Manual says that we have to bend over backwards to figure | |
1707 out what the other modifier bits mean. According to ICCCM: | |
1708 | |
1709 - Any keycode which is assigned ModControl is a "control" key. | |
1710 | |
1711 - Any modifier bit which is assigned to a keycode which generates Meta_L | |
1712 or Meta_R is the modifier bit meaning "meta". Likewise for Super, Hyper, | |
1713 etc. | |
1714 | |
1715 - Any keypress event which contains ModControl in its state should be | |
1716 interpreted as a "control" character. | |
1717 | |
1718 - Any keypress event which contains a modifier bit in its state which is | |
1719 generated by a keycode whose corresponding keysym is Meta_L or Meta_R | |
1720 should be interpreted as a "meta" character. Likewise for Super, Hyper, | |
1721 etc. | |
1722 | |
1723 - It is illegal for a keysym to be associated with more than one modifier | |
1724 bit. | |
1725 | |
1726 This means that the only thing that emacs can reasonably interpret as a | |
1727 "meta" key is a key whose keysym is Meta_L or Meta_R, and which generates | |
1728 one of the modifier bits Mod1-Mod5. | |
1729 | |
1730 Unfortunately, many keyboards don't have Meta keys in their default | |
1731 configuration. So, if there are no Meta keys, but there are "Alt" keys, | |
1732 emacs will interpret Alt as Meta. If there are both Meta and Alt keys, | |
1733 then the Meta keys mean "Meta", and the Alt keys mean "Alt" (it used to | |
1734 mean "Symbol," but that just confused the hell out of way too many people). | |
1735 | |
1736 This works with the default configurations of the 19 keyboard-types I've | |
1737 checked. | |
1738 | |
1739 Emacs detects keyboard configurations which violate the above rules, and | |
1740 prints an error message on the standard-error-output. (Perhaps it should | |
1741 use a pop-up-window instead.) | |
1742 */ | |
1743 | |
1744 static void | |
1745 gtk_reset_key_mapping (struct device *d) | |
1746 { | |
1747 Display *display = GDK_DISPLAY (); | |
1748 struct gtk_device *xd = DEVICE_GTK_DATA (d); | |
1749 KeySym *keysym, *keysym_end; | |
1750 Lisp_Object hashtable; | |
1751 int key_code_count, keysyms_per_code; | |
1752 | |
2054 | 1753 if (xd->x_keysym_map) |
1754 XFree ((char *) xd->x_keysym_map); | |
462 | 1755 XDisplayKeycodes (display, |
1756 &xd->x_keysym_map_min_code, | |
1757 &xd->x_keysym_map_max_code); | |
1758 key_code_count = xd->x_keysym_map_max_code - xd->x_keysym_map_min_code + 1; | |
2054 | 1759 xd->x_keysym_map = |
462 | 1760 XGetKeyboardMapping (display, xd->x_keysym_map_min_code, key_code_count, |
1761 &xd->x_keysym_map_keysyms_per_code); | |
1762 | |
1763 hashtable = xd->x_keysym_map_hashtable; | |
1764 if (HASH_TABLEP (hashtable)) | |
1765 { | |
1766 Fclrhash (hashtable); | |
1767 } | |
1768 else | |
1769 { | |
1770 xd->x_keysym_map_hashtable = hashtable = | |
1771 make_lisp_hash_table (128, HASH_TABLE_NON_WEAK, HASH_TABLE_EQUAL); | |
1772 } | |
1773 | |
2054 | 1774 for (keysym = xd->x_keysym_map, |
462 | 1775 keysyms_per_code = xd->x_keysym_map_keysyms_per_code, |
1776 keysym_end = keysym + (key_code_count * keysyms_per_code); | |
1777 keysym < keysym_end; | |
1778 keysym += keysyms_per_code) | |
1779 { | |
1780 int j; | |
1781 | |
1782 if (keysym[0] == NoSymbol) | |
1783 continue; | |
1784 | |
1785 { | |
771 | 1786 Extbyte *name = XKeysymToString (keysym[0]); |
462 | 1787 Lisp_Object sym = gtk_keysym_to_emacs_keysym (keysym[0], 0); |
1788 if (name) | |
1789 { | |
4834
b3ea9c582280
Use new cygwin_conv_path API with Cygwin 1.7 for converting names between Win32 and POSIX, UTF-8-aware, with attendant changes elsewhere
Ben Wing <ben@xemacs.org>
parents:
4790
diff
changeset
|
1790 Fputhash (build_ext_string (name, Qx_keysym_encoding), |
b3ea9c582280
Use new cygwin_conv_path API with Cygwin 1.7 for converting names between Win32 and POSIX, UTF-8-aware, with attendant changes elsewhere
Ben Wing <ben@xemacs.org>
parents:
4790
diff
changeset
|
1791 Qsans_modifiers, hashtable); |
462 | 1792 Fputhash (sym, Qsans_modifiers, hashtable); |
1793 } | |
1794 } | |
1795 | |
1796 for (j = 1; j < keysyms_per_code; j++) | |
1797 { | |
1798 if (keysym[j] != keysym[0] && | |
1799 keysym[j] != NoSymbol) | |
1800 { | |
771 | 1801 Extbyte *name = XKeysymToString (keysym[j]); |
462 | 1802 Lisp_Object sym = gtk_keysym_to_emacs_keysym (keysym[j], 0); |
1803 if (name && NILP (Fgethash (sym, hashtable, Qnil))) | |
1804 { | |
4834
b3ea9c582280
Use new cygwin_conv_path API with Cygwin 1.7 for converting names between Win32 and POSIX, UTF-8-aware, with attendant changes elsewhere
Ben Wing <ben@xemacs.org>
parents:
4790
diff
changeset
|
1805 Fputhash (build_ext_string (name, Qx_keysym_encoding), |
b3ea9c582280
Use new cygwin_conv_path API with Cygwin 1.7 for converting names between Win32 and POSIX, UTF-8-aware, with attendant changes elsewhere
Ben Wing <ben@xemacs.org>
parents:
4790
diff
changeset
|
1806 Qt, hashtable); |
462 | 1807 Fputhash (sym, Qt, hashtable); |
1808 } | |
1809 } | |
1810 } | |
1811 } | |
1812 } | |
1813 | |
1814 static const char * | |
1815 index_to_name (int indice) | |
1816 { | |
1817 switch (indice) | |
1818 { | |
1819 case ShiftMapIndex: return "ModShift"; | |
1820 case LockMapIndex: return "ModLock"; | |
1821 case ControlMapIndex: return "ModControl"; | |
1822 case Mod1MapIndex: return "Mod1"; | |
1823 case Mod2MapIndex: return "Mod2"; | |
1824 case Mod3MapIndex: return "Mod3"; | |
1825 case Mod4MapIndex: return "Mod4"; | |
1826 case Mod5MapIndex: return "Mod5"; | |
1827 default: return "???"; | |
1828 } | |
1829 } | |
1830 | |
1831 /* Boy, I really wish C had local functions... */ | |
1832 struct c_doesnt_have_closures /* #### not yet used */ | |
1833 { | |
1834 int warned_about_overlapping_modifiers; | |
1835 int warned_about_predefined_modifiers; | |
1836 int warned_about_duplicate_modifiers; | |
1837 int meta_bit; | |
1838 int hyper_bit; | |
1839 int super_bit; | |
1840 int alt_bit; | |
1841 int mode_bit; | |
1842 }; | |
1843 | |
1844 static void | |
1845 gtk_reset_modifier_mapping (struct device *d) | |
1846 { | |
1847 Display *display = GDK_DISPLAY (); | |
1848 struct gtk_device *xd = DEVICE_GTK_DATA (d); | |
1849 int modifier_index, modifier_key, column, mkpm; | |
1850 int warned_about_overlapping_modifiers = 0; | |
1851 /* int warned_about_predefined_modifiers = 0; */ | |
1852 /* int warned_about_duplicate_modifiers = 0; */ | |
1853 int meta_bit = 0; | |
1854 int hyper_bit = 0; | |
1855 int super_bit = 0; | |
1856 int alt_bit = 0; | |
1857 int mode_bit = 0; | |
1858 XModifierKeymap *map = (XModifierKeymap *) xd->x_modifier_keymap; | |
1859 | |
1860 xd->lock_interpretation = 0; | |
1861 | |
1862 if (map) | |
3949 | 1863 { |
1864 XFreeModifiermap (xd->x_modifier_keymap); | |
1865 /* Set it to NULL in case we receive two MappingModifier events in a | |
1866 row, and the second is processed during some CHECK_QUITs within | |
1867 x_reset_key_mapping. If that happens, XFreeModifierMap will be | |
1868 called twice on the same map, and we crash. */ | |
1869 xd->x_modifier_keymap = NULL; | |
1870 } | |
462 | 1871 |
1872 gtk_reset_key_mapping (d); | |
1873 | |
1874 xd->x_modifier_keymap = map = XGetModifierMapping (display); | |
1875 | |
1876 /* Boy, I really wish C had local functions... | |
1877 */ | |
1878 | |
1879 #define store_modifier(name,old) \ | |
1880 old = modifier_index; | |
1881 | |
1882 mkpm = map->max_keypermod; | |
1883 for (modifier_index = 0; modifier_index < 8; modifier_index++) | |
1884 for (modifier_key = 0; modifier_key < mkpm; modifier_key++) { | |
1885 KeySym last_sym = 0; | |
1886 for (column = 0; column < 4; column += 2) { | |
1887 KeyCode code = map->modifiermap[modifier_index * mkpm | |
1888 + modifier_key]; | |
1889 KeySym sym = (code ? XKeycodeToKeysym (display, code, column) : 0); | |
1890 if (sym == last_sym) continue; | |
1891 last_sym = sym; | |
1892 switch (sym) { | |
1893 case XK_Mode_switch:store_modifier ("Mode_switch", mode_bit); break; | |
1894 case XK_Meta_L: store_modifier ("Meta_L", meta_bit); break; | |
1895 case XK_Meta_R: store_modifier ("Meta_R", meta_bit); break; | |
1896 case XK_Super_L: store_modifier ("Super_L", super_bit); break; | |
1897 case XK_Super_R: store_modifier ("Super_R", super_bit); break; | |
1898 case XK_Hyper_L: store_modifier ("Hyper_L", hyper_bit); break; | |
1899 case XK_Hyper_R: store_modifier ("Hyper_R", hyper_bit); break; | |
1900 case XK_Alt_L: store_modifier ("Alt_L", alt_bit); break; | |
1901 case XK_Alt_R: store_modifier ("Alt_R", alt_bit); break; | |
1902 #if 0 | |
1903 case XK_Control_L: check_modifier ("Control_L", ControlMask); break; | |
1904 case XK_Control_R: check_modifier ("Control_R", ControlMask); break; | |
1905 case XK_Shift_L: check_modifier ("Shift_L", ShiftMask); break; | |
1906 case XK_Shift_R: check_modifier ("Shift_R", ShiftMask); break; | |
1907 #endif | |
1908 case XK_Shift_Lock: /* check_modifier ("Shift_Lock", LockMask); */ | |
1909 xd->lock_interpretation = XK_Shift_Lock; break; | |
1910 case XK_Caps_Lock: /* check_modifier ("Caps_Lock", LockMask); */ | |
1911 xd->lock_interpretation = XK_Caps_Lock; break; | |
1912 | |
1913 /* It probably doesn't make any sense for a modifier bit to be | |
1914 assigned to a key that is not one of the above, but OpenWindows | |
1915 assigns modifier bits to a couple of random function keys for | |
1916 no reason that I can discern, so printing a warning here would | |
1917 be annoying. */ | |
1918 } | |
1919 } | |
1920 } | |
1921 #undef store_modifier | |
1922 #undef check_modifier | |
1923 #undef modwarn | |
1924 #undef modbarf | |
1925 | |
1926 /* If there was no Meta key, then try using the Alt key instead. | |
1927 If there is both a Meta key and an Alt key, then the Alt key | |
1928 is not disturbed and remains an Alt key. */ | |
1929 if (! meta_bit && alt_bit) | |
1930 meta_bit = alt_bit, alt_bit = 0; | |
1931 | |
1932 /* mode_bit overrides everything, since it's processed down inside of | |
1933 XLookupString() instead of by us. If Meta and Mode_switch both | |
1934 generate the same modifier bit (which is an error), then we don't | |
1935 interpret that bit as Meta, because we can't make XLookupString() | |
1936 not interpret it as Mode_switch; and interpreting it as both would | |
1937 be totally wrong. */ | |
1938 if (mode_bit) | |
1939 { | |
1940 const char *warn = 0; | |
1941 if (mode_bit == meta_bit) warn = "Meta", meta_bit = 0; | |
1942 else if (mode_bit == hyper_bit) warn = "Hyper", hyper_bit = 0; | |
1943 else if (mode_bit == super_bit) warn = "Super", super_bit = 0; | |
1944 else if (mode_bit == alt_bit) warn = "Alt", alt_bit = 0; | |
1945 if (warn) | |
1946 { | |
1947 warn_when_safe | |
1948 (Qkey_mapping, Qwarning, | |
1949 "XEmacs: %s is being used for both Mode_switch and %s.", | |
1950 index_to_name (mode_bit), warn), | |
1951 warned_about_overlapping_modifiers = 1; | |
1952 } | |
1953 } | |
1954 #undef index_to_name | |
1955 | |
1956 xd->MetaMask = (meta_bit ? (1 << meta_bit) : 0); | |
1957 xd->HyperMask = (hyper_bit ? (1 << hyper_bit) : 0); | |
1958 xd->SuperMask = (super_bit ? (1 << super_bit) : 0); | |
1959 xd->AltMask = (alt_bit ? (1 << alt_bit) : 0); | |
1960 xd->ModeMask = (mode_bit ? (1 << mode_bit) : 0); /* unused */ | |
1961 | |
1962 } | |
1963 | |
1964 void | |
1965 gtk_init_modifier_mapping (struct device *d) | |
1966 { | |
1967 struct gtk_device *gd = DEVICE_GTK_DATA (d); | |
1968 gd->x_keysym_map_hashtable = Qnil; | |
1969 gd->x_keysym_map = NULL; | |
1970 gd->x_modifier_keymap = NULL; | |
1971 gtk_reset_modifier_mapping (d); | |
1972 } | |
1973 | |
1974 #if 0 | |
1975 static int | |
1976 gtk_key_is_modifier_p (KeyCode keycode, struct device *d) | |
1977 { | |
1978 struct gtk_device *xd = DEVICE_GTK_DATA (d); | |
1979 KeySym *syms; | |
1980 KeySym *map = (KeySym *) xd->x_keysym_map; | |
1981 int i; | |
1982 | |
1983 if (keycode < xd->x_keysym_map_min_code || | |
1984 keycode > xd->x_keysym_map_max_code) | |
1985 return 0; | |
1986 | |
1987 syms = &map [(keycode - xd->x_keysym_map_min_code) * | |
1988 xd->x_keysym_map_keysyms_per_code]; | |
1989 for (i = 0; i < xd->x_keysym_map_keysyms_per_code; i++) | |
1990 if (IsModifierKey (syms [i]) || | |
1991 syms [i] == XK_Mode_switch) /* why doesn't IsModifierKey count this? */ | |
1992 return 1; | |
1993 return 0; | |
1994 } | |
1995 #endif |