Mercurial > hg > xemacs-beta
annotate src/event-msw.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 | 8b63e21b0436 |
children | 304aebb79cd3 |
rev | line source |
---|---|
442 | 1 /* The mswindows event_stream interface. |
428 | 2 Copyright (C) 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. |
3 Copyright (C) 1995 Sun Microsystems, Inc. | |
3025 | 4 Copyright (C) 1996, 2000, 2001, 2002, 2003, 2005 Ben Wing. |
428 | 5 Copyright (C) 1997 Jonathan Harris. |
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 /* Synched up with: Not in FSF. */ | |
25 | |
771 | 26 /* This file essentially Mule-ized (except perhaps some Unicode splitting). |
27 5-2000. */ | |
28 | |
428 | 29 /* Authorship: |
30 | |
31 Ultimately based on FSF. | |
32 Rewritten by Ben Wing. | |
33 Rewritten for mswindows by Jonathan Harris, November 1997 for 21.0. | |
34 Subprocess and modal loop support by Kirill M. Katsnelson. | |
35 */ | |
36 | |
771 | 37 #define NEED_MSWINDOWS_SHLOBJ /* for IShellLink */ |
38 | |
428 | 39 #include <config.h> |
40 #include "lisp.h" | |
41 | |
2286 | 42 #ifdef CYGWIN |
43 # define USED_IF_CYGWIN(decl) decl | |
44 # define UNUSED_IF_CYGWIN(decl) UNUSED (decl) | |
45 #else | |
46 # define USED_IF_CYGWIN(decl) UNUSED (decl) | |
47 # define UNUSED_IF_CYGWIN(decl) decl | |
48 #endif | |
49 | |
853 | 50 #if defined (CYGWIN) && !defined (HAVE_MSG_SELECT) |
51 #error We do not support non-select() versions (i.e. very old) of Cygwin. | |
52 #endif | |
53 | |
54 /* Acceptable are: | |
55 | |
56 WIN32_NATIVE and HAVE_WIN32_PROCESSES and nothing else | |
57 | |
58 CYGWIN and HAVE_MSG_SELECT and HAVE_UNIX_PROCESSES and nothing else | |
59 */ | |
60 #ifdef WIN32_NATIVE | |
856 | 61 # if !(defined (HAVE_WIN32_PROCESSES) && !defined (HAVE_UNIX_PROCESSES) && !defined (HAVE_MSG_SELECT) && !defined (CYGWIN)) |
853 | 62 # error Something is wrong with your process definitions for Windows native. |
63 # endif | |
64 #elif defined (CYGWIN) | |
65 # if !(defined (HAVE_UNIX_PROCESSES) && defined (HAVE_MSG_SELECT) && !defined (HAVE_WIN32_PROCESSES) && !defined (WIN32_NATIVE)) | |
66 # error Something is wrong with your process definitions for Cygwin. | |
67 # endif | |
68 #else | |
69 # error Something is wrong -- you are neither Windows native (possibly MinGW) nor Cygwin. | |
70 #endif | |
71 | |
800 | 72 #include "buffer.h" |
872 | 73 #include "device-impl.h" |
800 | 74 #include "events.h" |
75 #include "faces.h" | |
872 | 76 #include "frame-impl.h" |
800 | 77 #include "glyphs.h" |
78 #include "lstream.h" | |
79 #include "process.h" | |
80 #include "redisplay.h" | |
81 #include "sysdep.h" | |
82 #include "window.h" | |
83 | |
1204 | 84 #include "console-stream-impl.h" |
872 | 85 #include "console-msw-impl.h" |
86 #include "objects-msw-impl.h" | |
428 | 87 |
88 #ifdef HAVE_SCROLLBARS | |
89 # include "scrollbar-msw.h" | |
90 #endif | |
91 | |
92 #ifdef HAVE_MENUBARS | |
442 | 93 # include "menubar.h" |
428 | 94 #endif |
95 | |
96 #ifdef HAVE_DRAGNDROP | |
97 # include "dragdrop.h" | |
98 #endif | |
99 | |
558 | 100 #include "sysfile.h" |
428 | 101 #include "sysproc.h" |
558 | 102 #include "systime.h" |
428 | 103 #include "syswait.h" |
104 | |
105 #ifdef HAVE_MENUBARS | |
106 #define ADJR_MENUFLAG TRUE | |
107 #else | |
108 #define ADJR_MENUFLAG FALSE | |
109 #endif | |
110 | |
111 /* Timer ID used for button2 emulation */ | |
112 #define BUTTON_2_TIMER_ID 1 | |
113 | |
114 static Lisp_Object mswindows_find_console (HWND hwnd); | |
115 static Lisp_Object mswindows_key_to_emacs_keysym (int mswindows_key, int mods, | |
116 int extendedp); | |
771 | 117 static int mswindows_modifier_state (BYTE *keymap, DWORD fwKeys, |
442 | 118 int has_AltGr); |
428 | 119 static void mswindows_set_chord_timer (HWND hwnd); |
120 static int mswindows_button2_near_enough (POINTS p1, POINTS p2); | |
121 static int mswindows_current_layout_has_AltGr (void); | |
442 | 122 static int mswindows_handle_sticky_modifiers (WPARAM wParam, LPARAM lParam, |
123 int downp, int keyp); | |
428 | 124 |
125 static struct event_stream *mswindows_event_stream; | |
126 | |
853 | 127 #ifdef CYGWIN |
128 | |
428 | 129 extern SELECT_TYPE input_wait_mask, non_fake_input_wait_mask; |
130 extern SELECT_TYPE process_only_mask, tty_only_mask; | |
131 SELECT_TYPE zero_mask; | |
132 extern int signal_event_pipe_initialized; | |
133 int windows_fd; | |
853 | 134 |
135 #else | |
136 | |
856 | 137 /* The number of things we can wait on */ |
138 #define MAX_WAITABLE (MAXIMUM_WAIT_OBJECTS - 1) | |
139 | |
853 | 140 /* List of mswindows waitable handles. */ |
141 static HANDLE mswindows_waitable_handles[MAX_WAITABLE]; | |
142 | |
143 /* Number of wait handles */ | |
144 static int mswindows_waitable_count = 0; | |
145 | |
428 | 146 #endif |
147 | |
148 /* | |
1204 | 149 * We use an additional queue, as well as the normal dispatch queue, for |
150 * efficiency, the normal one for user events, and another (_s_) for non-user | |
151 * ones. We always return events out of the first one until it is empty and | |
152 * only then proceed with the second one. | |
428 | 153 */ |
1204 | 154 static Lisp_Object mswindows_s_dispatch_event_queue; |
155 static Lisp_Object mswindows_s_dispatch_event_queue_tail; | |
428 | 156 |
157 /* Brush for painting widgets */ | |
158 static HBRUSH widget_brush = 0; | |
159 static LONG last_widget_brushed = 0; | |
160 | |
161 /* These are Lisp integers; see DEFVARS in this file for description. */ | |
162 int mswindows_dynamic_frame_resize; | |
442 | 163 int mswindows_alt_by_itself_activates_menu; |
458 | 164 Fixnum mswindows_num_mouse_buttons; |
165 Fixnum mswindows_mouse_button_max_skew_x; | |
166 Fixnum mswindows_mouse_button_max_skew_y; | |
167 Fixnum mswindows_mouse_button_tolerance; | |
428 | 168 |
442 | 169 #ifdef DEBUG_XEMACS |
458 | 170 Fixnum debug_mswindows_events; |
593 | 171 |
172 static void debug_output_mswin_message (HWND hwnd, UINT message_, | |
173 WPARAM wParam, LPARAM lParam); | |
442 | 174 #endif |
175 | |
428 | 176 /* This is the event signaled by the event pump. |
177 See mswindows_pump_outstanding_events for comments */ | |
853 | 178 static int mswindows_error_caught_in_modal_loop; |
428 | 179 |
180 /* Count of wound timers */ | |
181 static int mswindows_pending_timers_count; | |
442 | 182 |
183 static DWORD mswindows_last_mouse_button_state; | |
853 | 184 |
1292 | 185 extern int mswindows_is_blocking; |
186 | |
428 | 187 |
853 | 188 #ifndef CYGWIN /* Skips past slurp, shove, or winsock streams */ |
189 | |
428 | 190 /************************************************************************/ |
191 /* Pipe instream - reads process output */ | |
192 /************************************************************************/ | |
193 | |
194 #define PIPE_READ_DELAY 20 | |
195 | |
196 #define HANDLE_TO_USID(h) ((USID)(h)) | |
197 | |
198 #define NTPIPE_SLURP_STREAM_DATA(stream) \ | |
199 LSTREAM_TYPE_DATA (stream, ntpipe_slurp) | |
200 | |
201 /* This structure is allocated by the main thread, and is deallocated | |
202 in the thread upon exit. There are situations when a thread | |
203 remains blocked for a long time, much longer than the lstream | |
204 exists. For example, "start notepad" command is issued from the | |
205 shell, then the shell is closed by C-c C-d. Although the shell | |
206 process exits, its output pipe will not get closed until the | |
656 | 207 notepad process exits also, because it inherits the pipe from the |
428 | 208 shell. In this case, we abandon the thread, and let it live until |
209 all such processes exit. While struct ntpipe_slurp_stream is | |
210 deallocated in this case, ntpipe_slurp_stream_shared_data are not. */ | |
211 | |
212 struct ntpipe_slurp_stream_shared_data | |
213 { | |
214 HANDLE hev_thread; /* Our thread blocks on this, signaled by caller */ | |
853 | 215 /* This is a manual-reset object. */ |
428 | 216 HANDLE hev_caller; /* Caller blocks on this, and we signal it */ |
853 | 217 /* This is a manual-reset object. */ |
428 | 218 HANDLE hev_unsleep; /* Pipe read delay is canceled if this is set */ |
853 | 219 /* This is a manual-reset object. */ |
428 | 220 HANDLE hpipe; /* Pipe read end handle. */ |
221 LONG die_p; /* Thread must exit ASAP if non-zero */ | |
222 BOOL eof_p : 1; /* Set when thread saw EOF */ | |
223 BOOL error_p : 1; /* Read error other than EOF/broken pipe */ | |
224 BOOL inuse_p : 1; /* this structure is in use */ | |
225 LONG lock_count; /* Client count of this struct, 0=safe to free */ | |
226 BYTE onebyte; /* One byte buffer read by thread */ | |
227 }; | |
228 | |
229 #define MAX_SLURP_STREAMS 32 | |
230 struct ntpipe_slurp_stream_shared_data | |
231 shared_data_block[MAX_SLURP_STREAMS]={{0}}; | |
232 | |
233 struct ntpipe_slurp_stream | |
234 { | |
235 LPARAM user_data; /* Any user data stored in the stream object */ | |
771 | 236 struct ntpipe_slurp_stream_shared_data *thread_data; |
428 | 237 }; |
238 | |
771 | 239 DEFINE_LSTREAM_IMPLEMENTATION ("ntpipe-input", ntpipe_slurp); |
428 | 240 |
241 /* This function is thread-safe, and is called from either thread | |
242 context. It serializes freeing shared data structure */ | |
243 static void | |
771 | 244 slurper_free_shared_data_maybe (struct ntpipe_slurp_stream_shared_data *s) |
428 | 245 { |
246 if (InterlockedDecrement (&s->lock_count) == 0) | |
247 { | |
248 /* Destroy events */ | |
249 CloseHandle (s->hev_thread); | |
250 CloseHandle (s->hev_caller); | |
251 CloseHandle (s->hev_unsleep); | |
673 | 252 CloseHandle (s->hpipe); |
428 | 253 s->inuse_p = 0; |
254 } | |
255 } | |
256 | |
771 | 257 static struct ntpipe_slurp_stream_shared_data * |
442 | 258 slurper_allocate_shared_data (void) |
428 | 259 { |
260 int i=0; | |
771 | 261 for (i = 0; i < MAX_SLURP_STREAMS; i++) |
428 | 262 { |
263 if (!shared_data_block[i].inuse_p) | |
264 { | |
771 | 265 shared_data_block[i].inuse_p = 1; |
428 | 266 return &shared_data_block[i]; |
267 } | |
268 } | |
771 | 269 return (struct ntpipe_slurp_stream_shared_data *)0; |
428 | 270 } |
271 | |
272 static DWORD WINAPI | |
273 slurp_thread (LPVOID vparam) | |
274 { | |
275 struct ntpipe_slurp_stream_shared_data *s = | |
771 | 276 (struct ntpipe_slurp_stream_shared_data *)vparam; |
428 | 277 |
278 for (;;) | |
279 { | |
280 /* Read one byte from the pipe */ | |
281 DWORD actually_read; | |
282 if (!ReadFile (s->hpipe, &s->onebyte, 1, &actually_read, NULL)) | |
283 { | |
284 DWORD err = GetLastError (); | |
285 if (err == ERROR_BROKEN_PIPE || err == ERROR_NO_DATA) | |
286 s->eof_p = TRUE; | |
287 else | |
288 s->error_p = TRUE; | |
289 } | |
290 else if (actually_read == 0) | |
291 s->eof_p = TRUE; | |
292 | |
293 /* We must terminate on an error or eof */ | |
294 if (s->eof_p || s->error_p) | |
295 InterlockedIncrement (&s->die_p); | |
296 | |
297 /* Before we notify caller, we unsignal our event. */ | |
298 ResetEvent (s->hev_thread); | |
299 | |
300 /* Now we got something to notify caller, either a byte or an | |
301 error/eof indication. Before we do, allow internal pipe | |
302 buffer to accumulate little bit more data. | |
303 Reader function pulses this event before waiting for | |
304 a character, to avoid pipe delay, and to get the byte | |
305 immediately. */ | |
306 if (!s->die_p) | |
307 WaitForSingleObject (s->hev_unsleep, PIPE_READ_DELAY); | |
308 | |
309 /* Either make event loop generate a process event, or | |
310 inblock reader */ | |
311 SetEvent (s->hev_caller); | |
312 | |
313 /* Cleanup and exit if we're shot off */ | |
314 if (s->die_p) | |
315 break; | |
316 | |
317 /* Block until the client finishes with retrieving the rest of | |
318 pipe data */ | |
319 WaitForSingleObject (s->hev_thread, INFINITE); | |
320 } | |
321 | |
322 slurper_free_shared_data_maybe (s); | |
323 | |
324 return 0; | |
325 } | |
326 | |
327 static Lisp_Object | |
328 make_ntpipe_input_stream (HANDLE hpipe, LPARAM param) | |
329 { | |
330 Lstream *lstr = Lstream_new (lstream_ntpipe_slurp, "r"); | |
771 | 331 struct ntpipe_slurp_stream *s = NTPIPE_SLURP_STREAM_DATA (lstr); |
428 | 332 DWORD thread_id_unused; |
333 HANDLE hthread; | |
334 | |
335 /* We deal only with pipes, for we're using PeekNamedPipe api */ | |
336 assert (GetFileType (hpipe) == FILE_TYPE_PIPE); | |
337 | |
338 s->thread_data = slurper_allocate_shared_data(); | |
339 | |
340 /* Create reader thread. This could fail, so do not create events | |
341 until thread is created */ | |
342 hthread = CreateThread (NULL, 0, slurp_thread, (LPVOID)s->thread_data, | |
343 CREATE_SUSPENDED, &thread_id_unused); | |
344 if (hthread == NULL) | |
345 { | |
346 Lstream_delete (lstr); | |
347 s->thread_data->inuse_p=0; | |
348 return Qnil; | |
349 } | |
350 | |
351 /* Shared data are initially owned by both main and slurper | |
352 threads. */ | |
353 s->thread_data->lock_count = 2; | |
354 s->thread_data->die_p = 0; | |
355 s->thread_data->eof_p = FALSE; | |
356 s->thread_data->error_p = FALSE; | |
357 s->thread_data->hpipe = hpipe; | |
358 s->user_data = param; | |
359 | |
360 /* hev_thread is a manual-reset event, initially signaled */ | |
771 | 361 s->thread_data->hev_thread = qxeCreateEvent (NULL, TRUE, TRUE, NULL); |
428 | 362 /* hev_caller is a manual-reset event, initially nonsignaled */ |
771 | 363 s->thread_data->hev_caller = qxeCreateEvent (NULL, TRUE, FALSE, NULL); |
428 | 364 /* hev_unsleep is a manual-reset event, initially nonsignaled */ |
771 | 365 s->thread_data->hev_unsleep = qxeCreateEvent (NULL, TRUE, FALSE, NULL); |
428 | 366 |
367 /* Now let it go */ | |
368 ResumeThread (hthread); | |
369 CloseHandle (hthread); | |
370 | |
371 lstr->flags |= LSTREAM_FL_CLOSE_AT_DISKSAVE; | |
793 | 372 return wrap_lstream (lstr); |
428 | 373 } |
374 | |
375 static LPARAM | |
376 get_ntpipe_input_stream_param (Lstream *stream) | |
377 { | |
771 | 378 struct ntpipe_slurp_stream *s = NTPIPE_SLURP_STREAM_DATA(stream); |
428 | 379 return s->user_data; |
380 } | |
381 | |
382 static HANDLE | |
383 get_ntpipe_input_stream_waitable (Lstream *stream) | |
384 { | |
771 | 385 struct ntpipe_slurp_stream *s = NTPIPE_SLURP_STREAM_DATA(stream); |
428 | 386 return s->thread_data->hev_caller; |
387 } | |
388 | |
665 | 389 static Bytecount |
462 | 390 ntpipe_slurp_reader (Lstream *stream, unsigned char *data, |
665 | 391 Bytecount size) |
428 | 392 { |
393 /* This function must be called from the main thread only */ | |
771 | 394 struct ntpipe_slurp_stream_shared_data *s = |
428 | 395 NTPIPE_SLURP_STREAM_DATA(stream)->thread_data; |
396 | |
397 if (!s->die_p) | |
398 { | |
399 DWORD wait_result; | |
400 /* Disallow pipe read delay for the thread: we need a character | |
401 ASAP */ | |
402 SetEvent (s->hev_unsleep); | |
403 | |
404 /* Check if we have a character ready. Give it a short delay, | |
771 | 405 for the thread to awake from pipe delay, just ion case */ |
428 | 406 wait_result = WaitForSingleObject (s->hev_caller, 2); |
407 | |
408 /* Revert to the normal sleep behavior. */ | |
409 ResetEvent (s->hev_unsleep); | |
410 | |
411 /* If there's no byte buffered yet, give up */ | |
412 if (wait_result == WAIT_TIMEOUT) | |
413 { | |
414 errno = EAGAIN; | |
415 return -1; | |
416 } | |
417 } | |
418 | |
419 /* Reset caller unlock event now, as we've handled the pending | |
420 process output event */ | |
421 ResetEvent (s->hev_caller); | |
422 | |
423 /* It is now safe to do anything with contents of S, except for | |
424 changing s->die_p, which still should be interlocked */ | |
425 | |
426 if (s->eof_p) | |
427 return 0; | |
428 if (s->error_p || s->die_p) | |
429 return -1; | |
430 | |
431 /* Ok, there were no error neither eof - we've got a byte from the | |
432 pipe */ | |
433 *(data++) = s->onebyte; | |
434 --size; | |
435 | |
436 { | |
437 DWORD bytes_read = 0; | |
438 if (size > 0) | |
439 { | |
440 DWORD bytes_available; | |
441 | |
442 /* If the api call fails, return at least one byte already | |
443 read. ReadFile in thread will return error */ | |
444 if (PeekNamedPipe (s->hpipe, NULL, 0, NULL, &bytes_available, NULL)) | |
445 { | |
446 | |
447 /* Fetch available bytes. The same consideration applies, | |
448 so do not check for errors. ReadFile in the thread will | |
449 fail if the next call fails. */ | |
450 if (bytes_available) | |
647 | 451 ReadFile (s->hpipe, data, min (bytes_available, (DWORD) size), |
428 | 452 &bytes_read, NULL); |
453 } | |
454 | |
455 /* Now we can unblock thread, so it attempts to read more */ | |
456 SetEvent (s->hev_thread); | |
457 return bytes_read + 1; | |
458 } | |
459 } | |
460 return 0; | |
461 } | |
462 | |
463 static int | |
464 ntpipe_slurp_closer (Lstream *stream) | |
465 { | |
466 /* This function must be called from the main thread only */ | |
771 | 467 struct ntpipe_slurp_stream_shared_data *s = |
428 | 468 NTPIPE_SLURP_STREAM_DATA(stream)->thread_data; |
469 | |
470 /* Force thread to stop */ | |
471 InterlockedIncrement (&s->die_p); | |
472 | |
473 /* Set events which could possibly block slurper. Let it finish soon | |
474 or later. */ | |
475 SetEvent (s->hev_unsleep); | |
476 SetEvent (s->hev_thread); | |
477 | |
478 /* Unlock and maybe free shared data */ | |
479 slurper_free_shared_data_maybe (s); | |
480 | |
481 return 0; | |
482 } | |
483 | |
484 static void | |
485 init_slurp_stream (void) | |
486 { | |
487 LSTREAM_HAS_METHOD (ntpipe_slurp, reader); | |
488 LSTREAM_HAS_METHOD (ntpipe_slurp, closer); | |
489 } | |
853 | 490 |
428 | 491 |
492 /************************************************************************/ | |
493 /* Pipe outstream - writes process input */ | |
494 /************************************************************************/ | |
495 | |
496 #define NTPIPE_SHOVE_STREAM_DATA(stream) \ | |
497 LSTREAM_TYPE_DATA (stream, ntpipe_shove) | |
498 | |
442 | 499 #define MAX_SHOVE_BUFFER_SIZE 512 |
428 | 500 |
501 struct ntpipe_shove_stream | |
502 { | |
503 LPARAM user_data; /* Any user data stored in the stream object */ | |
504 HANDLE hev_thread; /* Our thread blocks on this, signaled by caller */ | |
853 | 505 /* This is an auto-reset object. */ |
428 | 506 HANDLE hpipe; /* Pipe write end handle. */ |
507 HANDLE hthread; /* Reader thread handle. */ | |
508 char buffer[MAX_SHOVE_BUFFER_SIZE]; /* Buffer being written */ | |
509 DWORD size; /* Number of bytes to write */ | |
510 LONG die_p; /* Thread must exit ASAP if non-zero */ | |
511 LONG idle_p; /* Non-zero if thread is waiting for job */ | |
512 BOOL error_p : 1; /* Read error other than EOF/broken pipe */ | |
513 BOOL blocking_p : 1;/* Last write attempt would cause blocking */ | |
514 }; | |
515 | |
771 | 516 DEFINE_LSTREAM_IMPLEMENTATION ("ntpipe-output", ntpipe_shove); |
428 | 517 |
518 static DWORD WINAPI | |
519 shove_thread (LPVOID vparam) | |
520 { | |
771 | 521 struct ntpipe_shove_stream *s = (struct ntpipe_shove_stream *) vparam; |
428 | 522 |
523 for (;;) | |
524 { | |
525 DWORD bytes_written; | |
526 | |
527 /* Block on event and wait for a job */ | |
528 InterlockedIncrement (&s->idle_p); | |
529 WaitForSingleObject (s->hev_thread, INFINITE); | |
530 | |
771 | 531 if (s->die_p) |
532 break; | |
533 | |
442 | 534 /* Write passed buffer if any */ |
535 if (s->size > 0) | |
428 | 536 { |
442 | 537 if (!WriteFile (s->hpipe, s->buffer, s->size, &bytes_written, NULL) |
538 || bytes_written != s->size) | |
539 { | |
540 s->error_p = TRUE; | |
541 InterlockedIncrement (&s->die_p); | |
542 } | |
543 /* Set size to zero so we won't write it again if the closer sets | |
544 die_p and kicks us */ | |
545 s->size = 0; | |
428 | 546 } |
547 | |
548 if (s->die_p) | |
549 break; | |
550 } | |
551 | |
552 return 0; | |
553 } | |
554 | |
555 static Lisp_Object | |
556 make_ntpipe_output_stream (HANDLE hpipe, LPARAM param) | |
557 { | |
558 Lstream *lstr = Lstream_new (lstream_ntpipe_shove, "w"); | |
771 | 559 struct ntpipe_shove_stream *s = NTPIPE_SHOVE_STREAM_DATA (lstr); |
428 | 560 DWORD thread_id_unused; |
561 | |
562 s->die_p = 0; | |
563 s->error_p = FALSE; | |
564 s->hpipe = hpipe; | |
565 s->user_data = param; | |
566 | |
567 /* Create reader thread. This could fail, so do not | |
568 create the event until thread is created */ | |
569 s->hthread = CreateThread (NULL, 0, shove_thread, (LPVOID)s, | |
570 CREATE_SUSPENDED, &thread_id_unused); | |
571 if (s->hthread == NULL) | |
572 { | |
573 Lstream_delete (lstr); | |
574 return Qnil; | |
575 } | |
576 | |
442 | 577 /* Set the priority of the thread higher so we don't end up waiting |
578 on it to send things. */ | |
579 if (!SetThreadPriority (s->hthread, THREAD_PRIORITY_HIGHEST)) | |
580 { | |
581 CloseHandle (s->hthread); | |
582 Lstream_delete (lstr); | |
583 return Qnil; | |
584 } | |
585 | |
428 | 586 /* hev_thread is an auto-reset event, initially nonsignaled */ |
771 | 587 s->hev_thread = qxeCreateEvent (NULL, FALSE, FALSE, NULL); |
428 | 588 |
589 /* Now let it go */ | |
590 ResumeThread (s->hthread); | |
591 | |
592 lstr->flags |= LSTREAM_FL_CLOSE_AT_DISKSAVE; | |
793 | 593 return wrap_lstream (lstr); |
428 | 594 } |
595 | |
596 static LPARAM | |
597 get_ntpipe_output_stream_param (Lstream *stream) | |
598 { | |
771 | 599 struct ntpipe_shove_stream *s = NTPIPE_SHOVE_STREAM_DATA(stream); |
428 | 600 return s->user_data; |
601 } | |
602 | |
665 | 603 static Bytecount |
462 | 604 ntpipe_shove_writer (Lstream *stream, const unsigned char *data, |
665 | 605 Bytecount size) |
428 | 606 { |
771 | 607 struct ntpipe_shove_stream *s = NTPIPE_SHOVE_STREAM_DATA(stream); |
428 | 608 |
609 if (s->error_p) | |
610 return -1; | |
611 | |
612 s->blocking_p = !s->idle_p; | |
613 if (s->blocking_p) | |
614 return 0; | |
615 | |
616 if (size>MAX_SHOVE_BUFFER_SIZE) | |
617 return 0; | |
618 | |
619 memcpy (s->buffer, data, size); | |
620 s->size = size; | |
621 | |
622 /* Start output */ | |
623 InterlockedDecrement (&s->idle_p); | |
624 SetEvent (s->hev_thread); | |
442 | 625 /* Give it a chance to run -- this dramatically improves performance |
626 of things like crypt. */ | |
771 | 627 if (xSwitchToThread) /* not in Win9x */ |
442 | 628 (void) xSwitchToThread (); |
428 | 629 return size; |
630 } | |
631 | |
632 static int | |
633 ntpipe_shove_was_blocked_p (Lstream *stream) | |
634 { | |
771 | 635 struct ntpipe_shove_stream *s = NTPIPE_SHOVE_STREAM_DATA(stream); |
428 | 636 return s->blocking_p; |
637 } | |
638 | |
639 static int | |
640 ntpipe_shove_closer (Lstream *stream) | |
641 { | |
771 | 642 struct ntpipe_shove_stream *s = NTPIPE_SHOVE_STREAM_DATA(stream); |
428 | 643 |
644 /* Force thread stop */ | |
645 InterlockedIncrement (&s->die_p); | |
646 | |
771 | 647 /* Close pipe handle, possibly breaking it */ |
648 CloseHandle (s->hpipe); | |
649 | |
442 | 650 /* Thread will end upon unblocking. If it's already unblocked this will |
651 do nothing, but the thread won't look at die_p until it's written any | |
652 pending output. */ | |
428 | 653 SetEvent (s->hev_thread); |
654 | |
655 /* Wait while thread terminates */ | |
656 WaitForSingleObject (s->hthread, INFINITE); | |
442 | 657 |
658 /* Close the thread handle */ | |
428 | 659 CloseHandle (s->hthread); |
660 | |
661 /* Destroy the event */ | |
662 CloseHandle (s->hev_thread); | |
663 | |
664 return 0; | |
665 } | |
666 | |
667 static void | |
668 init_shove_stream (void) | |
669 { | |
670 LSTREAM_HAS_METHOD (ntpipe_shove, writer); | |
671 LSTREAM_HAS_METHOD (ntpipe_shove, was_blocked_p); | |
672 LSTREAM_HAS_METHOD (ntpipe_shove, closer); | |
673 } | |
674 | |
675 /************************************************************************/ | |
676 /* Winsock I/O stream */ | |
677 /************************************************************************/ | |
678 | |
679 #define WINSOCK_READ_BUFFER_SIZE 1024 | |
680 | |
681 struct winsock_stream | |
682 { | |
683 LPARAM user_data; /* Any user data stored in the stream object */ | |
684 SOCKET s; /* Socket handle (which is a Win32 handle) */ | |
685 OVERLAPPED ov; /* Overlapped I/O structure */ | |
647 | 686 void *buffer; /* Buffer. */ |
687 DWORD bufsize; /* Number of bytes last read */ | |
1204 | 688 DWORD charbpos; /* Position in buffer for next fetch */ |
428 | 689 unsigned int error_p :1; /* I/O Error seen */ |
690 unsigned int eof_p :1; /* EOF Error seen */ | |
691 unsigned int pending_p :1; /* There is a pending I/O operation */ | |
692 unsigned int blocking_p :1; /* Last write attempt would block */ | |
693 }; | |
694 | |
695 #define WINSOCK_STREAM_DATA(stream) LSTREAM_TYPE_DATA (stream, winsock) | |
696 | |
771 | 697 DEFINE_LSTREAM_IMPLEMENTATION ("winsock", winsock); |
428 | 698 |
699 static void | |
700 winsock_initiate_read (struct winsock_stream *str) | |
701 { | |
702 ResetEvent (str->ov.hEvent); | |
665 | 703 str->charbpos = 0; |
428 | 704 |
705 if (!ReadFile ((HANDLE)str->s, str->buffer, WINSOCK_READ_BUFFER_SIZE, | |
706 &str->bufsize, &str->ov)) | |
707 { | |
708 if (GetLastError () == ERROR_IO_PENDING) | |
709 str->pending_p = 1; | |
710 else if (GetLastError () == ERROR_HANDLE_EOF) | |
711 str->eof_p = 1; | |
712 else | |
713 str->error_p = 1; | |
714 } | |
715 else if (str->bufsize == 0) | |
716 str->eof_p = 1; | |
717 } | |
718 | |
665 | 719 static Bytecount |
720 winsock_reader (Lstream *stream, unsigned char *data, Bytecount size) | |
428 | 721 { |
722 struct winsock_stream *str = WINSOCK_STREAM_DATA (stream); | |
723 | |
724 /* If the current operation is not yet complete, there's nothing to | |
725 give back */ | |
726 if (str->pending_p) | |
727 { | |
728 if (WaitForSingleObject (str->ov.hEvent, 0) == WAIT_TIMEOUT) | |
729 { | |
730 errno = EAGAIN; | |
731 return -1; | |
732 } | |
733 else | |
734 { | |
1204 | 735 if (!GetOverlappedResult ((HANDLE)str->s, &str->ov, &str->bufsize, |
736 TRUE)) | |
428 | 737 { |
738 if (GetLastError() == ERROR_HANDLE_EOF) | |
739 str->bufsize = 0; | |
740 else | |
741 str->error_p = 1; | |
742 } | |
743 if (str->bufsize == 0) | |
744 str->eof_p = 1; | |
745 str->pending_p = 0; | |
746 } | |
747 } | |
748 | |
749 if (str->eof_p) | |
750 return 0; | |
751 if (str->error_p) | |
752 return -1; | |
753 | |
754 /* Return as much of buffer as we have */ | |
665 | 755 size = min (size, (Bytecount) (str->bufsize - str->charbpos)); |
771 | 756 memcpy (data, (void *) ((BYTE *) str->buffer + str->charbpos), size); |
665 | 757 str->charbpos += size; |
428 | 758 |
759 /* Read more if buffer is exhausted */ | |
665 | 760 if (str->bufsize == str->charbpos) |
428 | 761 winsock_initiate_read (str); |
762 | |
763 return size; | |
764 } | |
765 | |
665 | 766 static Bytecount |
462 | 767 winsock_writer (Lstream *stream, const unsigned char *data, |
665 | 768 Bytecount size) |
428 | 769 { |
770 struct winsock_stream *str = WINSOCK_STREAM_DATA (stream); | |
771 | |
772 if (str->pending_p) | |
773 { | |
774 if (WaitForSingleObject (str->ov.hEvent, 0) == WAIT_TIMEOUT) | |
775 { | |
776 str->blocking_p = 1; | |
777 return -1; | |
778 } | |
779 else | |
780 { | |
781 DWORD dw_unused; | |
1204 | 782 if (!GetOverlappedResult ((HANDLE)str->s, &str->ov, &dw_unused, |
783 TRUE)) | |
428 | 784 str->error_p = 1; |
785 str->pending_p = 0; | |
786 } | |
787 } | |
788 | |
789 str->blocking_p = 0; | |
790 | |
791 if (str->error_p) | |
792 return -1; | |
793 | |
794 if (size == 0) | |
795 return 0; | |
796 | |
558 | 797 ResetEvent (str->ov.hEvent); |
798 | |
799 /* According to WriteFile docs, we must hold onto the data we pass to it | |
800 and not make any changes until it finishes -- which may not be until | |
801 the next time we get here, since we use asynchronous I/O. We have | |
802 in fact seen data loss as a result of not doing this. */ | |
803 str->buffer = xrealloc (str->buffer, size); | |
804 memcpy (str->buffer, data, size); | |
805 | |
560 | 806 /* According to MSDN WriteFile docs, the fourth parameter cannot be NULL |
807 on Win95 even when doing an overlapped operation, as we are, where | |
808 the return value through that parameter is not meaningful. */ | |
809 if (WriteFile ((HANDLE)str->s, str->buffer, size, &str->bufsize, | |
558 | 810 &str->ov) |
811 || GetLastError() == ERROR_IO_PENDING) | |
812 str->pending_p = 1; | |
813 else | |
814 str->error_p = 1; | |
428 | 815 |
816 return str->error_p ? -1 : size; | |
817 } | |
818 | |
819 static int | |
820 winsock_closer (Lstream *lstr) | |
821 { | |
822 struct winsock_stream *str = WINSOCK_STREAM_DATA (lstr); | |
823 | |
824 if (lstr->flags & LSTREAM_FL_READ) | |
825 shutdown (str->s, 0); | |
826 else | |
827 shutdown (str->s, 1); | |
828 | |
986 | 829 closesocket (str->s); |
428 | 830 if (str->pending_p) |
831 WaitForSingleObject (str->ov.hEvent, INFINITE); | |
832 | |
558 | 833 if (str->buffer) |
560 | 834 { |
1726 | 835 xfree (str->buffer, void *); |
560 | 836 str->buffer = 0; |
837 } | |
428 | 838 |
839 CloseHandle (str->ov.hEvent); | |
840 return 0; | |
841 } | |
842 | |
843 static int | |
844 winsock_was_blocked_p (Lstream *stream) | |
845 { | |
846 struct winsock_stream *str = WINSOCK_STREAM_DATA (stream); | |
847 return str->blocking_p; | |
848 } | |
849 | |
850 static Lisp_Object | |
442 | 851 make_winsock_stream_1 (SOCKET s, LPARAM param, const char *mode) |
428 | 852 { |
853 Lstream *lstr = Lstream_new (lstream_winsock, mode); | |
854 struct winsock_stream *str = WINSOCK_STREAM_DATA (lstr); | |
855 | |
558 | 856 xzero (*str); |
428 | 857 str->s = s; |
858 str->user_data = param; | |
859 | |
771 | 860 str->ov.hEvent = qxeCreateEvent (NULL, TRUE, FALSE, NULL); |
428 | 861 |
862 if (lstr->flags & LSTREAM_FL_READ) | |
863 { | |
864 str->buffer = xmalloc (WINSOCK_READ_BUFFER_SIZE); | |
865 winsock_initiate_read (str); | |
866 } | |
867 | |
868 lstr->flags |= LSTREAM_FL_CLOSE_AT_DISKSAVE; | |
793 | 869 return wrap_lstream (lstr); |
428 | 870 } |
871 | |
872 static Lisp_Object | |
873 make_winsock_input_stream (SOCKET s, LPARAM param) | |
874 { | |
875 return make_winsock_stream_1 (s, param, "r"); | |
876 } | |
877 | |
878 static Lisp_Object | |
879 make_winsock_output_stream (SOCKET s, LPARAM param) | |
880 { | |
881 return make_winsock_stream_1 (s, param, "w"); | |
882 } | |
883 | |
884 static HANDLE | |
885 get_winsock_stream_waitable (Lstream *lstr) | |
886 { | |
887 struct winsock_stream *str = WINSOCK_STREAM_DATA (lstr); | |
888 return str->ov.hEvent; | |
889 } | |
890 | |
891 static LPARAM | |
892 get_winsock_stream_param (Lstream *lstr) | |
893 { | |
894 struct winsock_stream *str = WINSOCK_STREAM_DATA (lstr); | |
895 return str->user_data; | |
896 } | |
897 | |
898 static void | |
899 init_winsock_stream (void) | |
900 { | |
901 LSTREAM_HAS_METHOD (winsock, reader); | |
902 LSTREAM_HAS_METHOD (winsock, writer); | |
903 LSTREAM_HAS_METHOD (winsock, closer); | |
904 LSTREAM_HAS_METHOD (winsock, was_blocked_p); | |
905 } | |
853 | 906 #endif /* ! CYGWIN */ |
428 | 907 |
908 /************************************************************************/ | |
909 /* Dispatch queue management */ | |
910 /************************************************************************/ | |
911 | |
912 static int | |
771 | 913 mswindows_user_event_p (Lisp_Event *sevt) |
428 | 914 { |
915 return (sevt->event_type == key_press_event | |
916 || sevt->event_type == button_press_event | |
917 || sevt->event_type == button_release_event | |
918 || sevt->event_type == misc_user_event); | |
919 } | |
920 | |
921 /* | |
922 * Add an emacs event to the proper dispatch queue | |
923 */ | |
442 | 924 void |
428 | 925 mswindows_enqueue_dispatch_event (Lisp_Object event) |
926 { | |
1204 | 927 int user_p = mswindows_user_event_p (XEVENT (event)); |
928 if (user_p) | |
929 enqueue_dispatch_event (event); | |
930 else | |
931 enqueue_event (event, &mswindows_s_dispatch_event_queue, | |
932 &mswindows_s_dispatch_event_queue_tail); | |
428 | 933 |
934 /* Avoid blocking on WaitMessage */ | |
771 | 935 qxePostMessage (NULL, XM_BUMPQUEUE, 0, 0); |
428 | 936 } |
937 | |
938 /* | |
939 * Add a misc-user event to the dispatch queue. | |
940 */ | |
941 void | |
942 mswindows_enqueue_misc_user_event (Lisp_Object channel, Lisp_Object function, | |
943 Lisp_Object object) | |
944 { | |
945 Lisp_Object event = Fmake_event (Qnil, Qnil); | |
964 | 946 |
947 XSET_EVENT_TYPE (event, misc_user_event); | |
948 XSET_EVENT_CHANNEL (event, channel); | |
949 XSET_EVENT_TIMESTAMP (event, GetTickCount()); | |
1204 | 950 XSET_EVENT_MISC_USER_FUNCTION (event, function); |
951 XSET_EVENT_MISC_USER_OBJECT (event, object); | |
428 | 952 |
953 mswindows_enqueue_dispatch_event (event); | |
954 } | |
955 | |
956 void | |
440 | 957 mswindows_enqueue_magic_event (HWND hwnd, UINT msg) |
428 | 958 { |
959 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil); | |
964 | 960 |
1204 | 961 XSET_EVENT_CHANNEL (emacs_event, hwnd ? mswindows_find_frame (hwnd) : Qnil); |
964 | 962 XSET_EVENT_TIMESTAMP (emacs_event, GetMessageTime ()); |
963 XSET_EVENT_TYPE (emacs_event, magic_event); | |
1204 | 964 XSET_EVENT_MAGIC_MSWINDOWS_EVENT (emacs_event, msg); |
428 | 965 |
966 mswindows_enqueue_dispatch_event (emacs_event); | |
967 } | |
968 | |
969 static void | |
771 | 970 mswindows_enqueue_process_event (Lisp_Process *p) |
428 | 971 { |
972 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil); | |
793 | 973 Lisp_Object process = wrap_process (p); |
974 | |
964 | 975 XSET_EVENT_TYPE (emacs_event, process_event); |
1204 | 976 XSET_EVENT_TIMESTAMP (emacs_event, GetTickCount ()); |
977 XSET_EVENT_PROCESS_PROCESS (emacs_event, process); | |
428 | 978 |
979 mswindows_enqueue_dispatch_event (emacs_event); | |
980 } | |
981 | |
982 static void | |
442 | 983 mswindows_enqueue_mouse_button_event (HWND hwnd, UINT msg, POINTS where, |
984 int mods, DWORD when) | |
428 | 985 { |
442 | 986 int downp = (msg == WM_LBUTTONDOWN || msg == WM_MBUTTONDOWN || |
987 msg == WM_RBUTTONDOWN); | |
428 | 988 |
1622 | 989 /* Wheel rotation amount: positive is away from user, negative towards user */ |
990 int delta = (short) HIWORD (mods); | |
991 | |
428 | 992 /* We always use last message time, because mouse button |
993 events may get delayed, and XEmacs double click | |
994 recognition will fail */ | |
995 | |
996 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil); | |
442 | 997 |
998 mswindows_handle_sticky_modifiers (0, 0, downp, 0); | |
964 | 999 |
1000 if (downp) | |
1001 { | |
1002 XSET_EVENT_TYPE (emacs_event, button_press_event); | |
1003 } | |
1004 else | |
1005 { | |
1006 XSET_EVENT_TYPE (emacs_event, button_release_event); | |
1007 } | |
1008 | |
1009 XSET_EVENT_CHANNEL (emacs_event, mswindows_find_frame (hwnd)); | |
1010 XSET_EVENT_TIMESTAMP (emacs_event, when); | |
1204 | 1011 XSET_EVENT_BUTTON_BUTTON (emacs_event, |
1622 | 1012 (msg==WM_LBUTTONDOWN || msg==WM_LBUTTONUP) ? 1 : |
1013 (msg==WM_MBUTTONDOWN || msg==WM_MBUTTONUP) ? 2 : | |
1014 (msg==WM_RBUTTONDOWN || msg==WM_RBUTTONUP) ? 3 : | |
1015 (msg==WM_MOUSEWHEEL && delta>0) ? 4 : 5); | |
1204 | 1016 XSET_EVENT_BUTTON_X (emacs_event, where.x); |
1017 XSET_EVENT_BUTTON_Y (emacs_event, where.y); | |
1018 XSET_EVENT_BUTTON_MODIFIERS (emacs_event, | |
1019 mswindows_modifier_state (NULL, mods, 0)); | |
442 | 1020 |
1021 if (downp) | |
428 | 1022 { |
1023 SetCapture (hwnd); | |
1024 /* we need this to make sure the main window regains the focus | |
1025 from control subwindows */ | |
1026 if (GetFocus() != hwnd) | |
1027 { | |
1028 SetFocus (hwnd); | |
1029 mswindows_enqueue_magic_event (hwnd, WM_SETFOCUS); | |
1030 } | |
1031 } | |
1032 else | |
1033 { | |
1034 ReleaseCapture (); | |
1035 } | |
1036 | |
1037 mswindows_enqueue_dispatch_event (emacs_event); | |
1038 } | |
1039 | |
771 | 1040 static Lisp_Object |
428 | 1041 mswindows_enqueue_keypress_event (HWND hwnd, Lisp_Object keysym, int mods) |
1042 { | |
1043 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil); | |
964 | 1044 |
1045 XSET_EVENT_CHANNEL (emacs_event, mswindows_find_console(hwnd)); | |
1046 XSET_EVENT_TIMESTAMP (emacs_event, GetMessageTime()); | |
1047 XSET_EVENT_TYPE (emacs_event, key_press_event); | |
1204 | 1048 XSET_EVENT_KEY_KEYSYM (emacs_event, keysym); |
1049 XSET_EVENT_KEY_MODIFIERS (emacs_event, mods); | |
428 | 1050 mswindows_enqueue_dispatch_event (emacs_event); |
771 | 1051 return emacs_event; |
428 | 1052 } |
1053 | |
1054 /* | |
1055 * Remove and return the first emacs event on the dispatch queue. | |
1056 * Give a preference to user events over non-user ones. | |
1057 */ | |
1058 static Lisp_Object | |
442 | 1059 mswindows_dequeue_dispatch_event (void) |
428 | 1060 { |
1204 | 1061 assert (!NILP (dispatch_event_queue) || |
1062 !NILP (mswindows_s_dispatch_event_queue)); | |
1063 | |
1064 if (!NILP (dispatch_event_queue)) | |
1065 return dequeue_dispatch_event (); | |
1066 else | |
1067 return dequeue_event (&mswindows_s_dispatch_event_queue, | |
1068 &mswindows_s_dispatch_event_queue_tail); | |
428 | 1069 } |
1070 | |
853 | 1071 #ifndef CYGWIN |
428 | 1072 /************************************************************************/ |
1073 /* Waitable handles manipulation */ | |
1074 /************************************************************************/ | |
1075 static int | |
1076 find_waitable_handle (HANDLE h) | |
1077 { | |
1078 int i; | |
1079 for (i = 0; i < mswindows_waitable_count; ++i) | |
1080 if (mswindows_waitable_handles[i] == h) | |
1081 return i; | |
1082 | |
1083 return -1; | |
1084 } | |
1085 | |
1086 static BOOL | |
1087 add_waitable_handle (HANDLE h) | |
1088 { | |
1089 assert (find_waitable_handle (h) < 0); | |
1090 if (mswindows_waitable_count == MAX_WAITABLE) | |
1091 return FALSE; | |
1092 | |
1093 mswindows_waitable_handles [mswindows_waitable_count++] = h; | |
1094 return TRUE; | |
1095 } | |
1096 | |
1097 static void | |
1098 remove_waitable_handle (HANDLE h) | |
1099 { | |
1100 int ix = find_waitable_handle (h); | |
1101 if (ix < 0) | |
1102 return; | |
1103 | |
1104 mswindows_waitable_handles [ix] = | |
1105 mswindows_waitable_handles [--mswindows_waitable_count]; | |
1106 } | |
853 | 1107 |
1108 #endif /* CYGWIN */ | |
428 | 1109 |
791 | 1110 /* |
1111 * Given a lisp process pointer remove the corresponding process handle | |
1112 * from mswindows_waitable_handles if it is in it. Normally the handle is | |
1113 * removed when the process terminates, but if the lisp process structure | |
1114 * is deleted before the process terminates we must delete the process | |
1115 * handle since it will be invalid and will cause the wait to fail | |
1116 */ | |
1117 void | |
2286 | 1118 mswindows_unwait_process (Lisp_Process *UNUSED_IF_CYGWIN (p)) |
791 | 1119 { |
853 | 1120 #ifndef CYGWIN |
791 | 1121 remove_waitable_handle (get_nt_process_handle (p)); |
853 | 1122 #endif /* CYGWIN */ |
791 | 1123 } |
1124 | |
428 | 1125 |
1126 /************************************************************************/ | |
1127 /* Event pump */ | |
1128 /************************************************************************/ | |
1129 | |
771 | 1130 int |
1131 mswindows_window_is_xemacs (HWND hwnd) | |
1132 { | |
1133 /* GetClassName will truncate a longer class name. By adding one | |
1134 extra character, we are forcing textual comparison to fail | |
1135 if the name is longer than XEMACS_CLASS */ | |
1136 Extbyte class_name_buf[sizeof (XEMACS_CLASS) + 2]; | |
1137 | |
1138 /* Use GetClassNameA because XEMACS_CLASS is not in Unicode format. */ | |
1139 if (!GetClassNameA (hwnd, class_name_buf, sizeof (class_name_buf) - 1)) | |
1140 return 0; | |
1141 | |
1142 return !ascii_strcasecmp (class_name_buf, XEMACS_CLASS); | |
1143 } | |
1144 | |
428 | 1145 void |
1146 mswindows_unmodalize_signal_maybe (void) | |
1147 { | |
853 | 1148 mswindows_error_caught_in_modal_loop = 0; |
428 | 1149 } |
1150 | |
1151 /* | |
1152 * This is an unsafe part of event pump, guarded by | |
1153 * condition_case. See mswindows_pump_outstanding_events | |
1154 */ | |
1155 static Lisp_Object | |
2286 | 1156 mswindows_unsafe_pump_events (void *UNUSED (arg)) |
428 | 1157 { |
1158 /* This function can call lisp */ | |
1159 Lisp_Object event = Fmake_event (Qnil, Qnil); | |
1160 struct gcpro gcpro1; | |
1161 int do_redisplay = 0; | |
1162 GCPRO1 (event); | |
1163 | |
1268 | 1164 while (detect_input_pending (1)) |
428 | 1165 { |
1166 Fnext_event (event, Qnil); | |
1167 Fdispatch_event (event); | |
1168 do_redisplay = 1; | |
1169 } | |
1170 | |
1171 if (do_redisplay) | |
1172 redisplay (); | |
1173 | |
1174 Fdeallocate_event (event); | |
1175 UNGCPRO; | |
1176 | |
1177 /* Qt becomes return value of mswindows_pump_outstanding_events | |
1178 once we get here */ | |
1179 return Qt; | |
1180 } | |
1181 | |
1182 /* | |
1183 * This function pumps emacs events, while available, by using | |
1184 * next_message/dispatch_message loop. Errors are trapped around | |
1185 * the loop so the function always returns. | |
1186 * | |
1187 * Windows message queue is not looked into during the call, | |
1188 * neither are waitable handles checked. The function pumps | |
1189 * thus only dispatch events already queued, as well as those | |
1190 * resulted in dispatching thereof. This is done by setting | |
1268 | 1191 * in_modal_loop to nonzero. |
428 | 1192 * |
1193 * Return value is Qt if no errors was trapped, or Qunbound if | |
1194 * there was an error. | |
1195 * | |
853 | 1196 * In case of error, a warning is issued and the module local variable |
1197 * mswindows_error_caught_in_modal_loop is set to non-zero. Thus, | |
1198 * Windows internal modal loops are protected against throws, which | |
1199 * are proven to corrupt internal Windows structures. | |
428 | 1200 * |
1201 * In case of success, mswindows_error_caught_in_modal_loop is | |
853 | 1202 * assigned 0. |
428 | 1203 * |
1204 * If the value of mswindows_error_caught_in_modal_loop is not | |
853 | 1205 * zero already upon entry, the function just returns non-nil. |
428 | 1206 * This situation means that a new event has been queued while |
1207 * in cancel mode. The event will be dequeued on the next regular | |
1208 * call of next-event; the pump is off since error is caught. | |
1209 * The caller must *unconditionally* cancel modal loop if the | |
1210 * value returned by this function is nil. Otherwise, everything | |
1211 * will become frozen until the modal loop exits under normal | |
853 | 1212 * condition (scrollbar drag is released, menu closed etc.) */ |
428 | 1213 Lisp_Object |
1214 mswindows_pump_outstanding_events (void) | |
1215 { | |
1216 /* This function can call lisp */ | |
1217 | |
1218 Lisp_Object result = Qt; | |
1219 struct gcpro gcpro1; | |
1220 GCPRO1 (result); | |
1221 | |
853 | 1222 if (!mswindows_error_caught_in_modal_loop) |
1268 | 1223 result = event_stream_protect_modal_loop |
1224 ("Error during event handling", mswindows_unsafe_pump_events, 0, 0); | |
428 | 1225 UNGCPRO; |
1268 | 1226 if (UNBOUNDP (result)) |
1227 mswindows_error_caught_in_modal_loop = 1; | |
428 | 1228 return result; |
1229 } | |
1230 | |
440 | 1231 /* |
428 | 1232 * This is a special flavor of the mswindows_need_event function, |
1233 * used while in event pump. Actually, there is only kind of events | |
1234 * allowed while in event pump: a timer. An attempt to fetch any | |
1235 * other event leads to a deadlock, as there's no source of user input | |
1236 * ('cause event pump mirrors windows modal loop, which is a sole | |
1237 * owner of thread message queue). | |
1238 * | |
1239 * To detect this, we use a counter of active timers, and allow | |
1240 * fetching WM_TIMER messages. Instead of trying to fetch a WM_TIMER | |
1241 * which will never come when there are no pending timers, which leads | |
1242 * to deadlock, we simply signal an error. | |
487 | 1243 * |
1244 * It might be possible to combine this with mswindows_drain_windows_queue | |
1245 * which fetches events when not in a modal loop. It's not clear | |
1246 * whether the result would be more complex than is justified. | |
428 | 1247 */ |
1248 static void | |
1249 mswindows_need_event_in_modal_loop (int badly_p) | |
1250 { | |
1251 MSG msg; | |
1252 | |
1253 /* Check if already have one */ | |
1204 | 1254 if (!NILP (dispatch_event_queue) |
428 | 1255 || !NILP (mswindows_s_dispatch_event_queue)) |
1256 return; | |
1257 | |
1258 /* No event is ok */ | |
1259 if (!badly_p) | |
1260 return; | |
1261 | |
1204 | 1262 /* We do not check the user queue, because timers go to _s_ */ |
428 | 1263 while (NILP (mswindows_s_dispatch_event_queue)) |
1264 { | |
1265 /* We'll deadlock if go waiting */ | |
1266 if (mswindows_pending_timers_count == 0) | |
1204 | 1267 invalid_operation |
1268 ("Deadlock due to an attempt to call next-event in a wrong context", | |
1269 Qunbound); | |
428 | 1270 |
1271 /* Fetch and dispatch any pending timers */ | |
771 | 1272 if (qxeGetMessage (&msg, NULL, WM_TIMER, WM_TIMER) > 0) |
1273 qxeDispatchMessage (&msg); | |
428 | 1274 } |
1275 } | |
1276 | |
1268 | 1277 /* BADLY_P non-zero means we were called from mswindows_need_event(1). It |
1278 only matters when we are in a modal loop, and causes us to fetch timer | |
1279 events (the only kinds we can fetch in such a case). | |
1280 */ | |
1281 static void | |
1282 mswindows_drain_windows_queue (int badly_p) | |
1283 { | |
1284 MSG msg; | |
1285 | |
1286 if (in_modal_loop) | |
1287 mswindows_need_event_in_modal_loop (badly_p); | |
1288 else | |
1289 while (qxePeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) | |
1290 { | |
1291 #ifdef HAVE_DIALOGS | |
1292 /* Don't translate messages destined for a dialog box, this | |
1293 makes keyboard traversal work. I think?? */ | |
1294 if (mswindows_is_dialog_msg (&msg)) | |
1295 { | |
1296 mswindows_unmodalize_signal_maybe (); | |
1297 continue; | |
1298 } | |
1299 #endif /* HAVE_DIALOGS */ | |
1300 | |
1301 /* We have to translate messages that are not sent to an XEmacs | |
1302 frame. This is so that key presses work ok in things like | |
1303 edit fields. However, we *musn't* translate message for XEmacs | |
1304 frames as this is handled in the wnd proc. | |
1305 We also have to avoid generating paint magic events for windows | |
1306 that aren't XEmacs frames */ | |
1307 | |
1308 if (!mswindows_window_is_xemacs (msg.hwnd)) | |
1309 TranslateMessage (&msg); | |
1310 else if (msg.message == WM_PAINT) | |
1311 { | |
1312 struct mswindows_frame *msframe; | |
1313 | |
1314 /* hdc will be NULL unless this is a subwindow - in which case we | |
1315 shouldn't have received a paint message for it here. */ | |
1316 assert (msg.wParam == 0); | |
1317 | |
1318 /* Queue a magic event for handling when safe */ | |
1319 msframe = | |
1320 FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (msg.hwnd))); | |
1321 if (!msframe->paint_pending) | |
1322 { | |
1323 msframe->paint_pending = 1; | |
1324 mswindows_enqueue_magic_event (msg.hwnd, WM_PAINT); | |
1325 } | |
1326 /* Don't dispatch. WM_PAINT is always the last message in the | |
1327 queue so it's OK to just return. */ | |
1328 return; | |
1329 } | |
1330 qxeDispatchMessage (&msg); | |
1331 mswindows_unmodalize_signal_maybe (); | |
1332 } | |
1333 } | |
1334 | |
1335 static void | |
1336 emacs_mswindows_drain_queue (void) | |
1337 { | |
1318 | 1338 /* This can call Lisp */ |
1268 | 1339 mswindows_drain_windows_queue (0); |
1340 #ifdef HAVE_TTY | |
1341 drain_tty_devices (); | |
1342 #endif | |
1343 } | |
1344 | |
428 | 1345 /* |
1346 * This drains the event queue and fills up two internal queues until | |
1347 * an event of a type specified by USER_P is retrieved. | |
1348 * | |
1349 * | |
1350 * Used by emacs_mswindows_event_pending_p and emacs_mswindows_next_event | |
1351 */ | |
1352 static void | |
1353 mswindows_need_event (int badly_p) | |
1354 { | |
1204 | 1355 while (NILP (dispatch_event_queue) |
428 | 1356 && NILP (mswindows_s_dispatch_event_queue)) |
1357 { | |
853 | 1358 #ifdef CYGWIN |
428 | 1359 int i; |
647 | 1360 int active; |
428 | 1361 SELECT_TYPE temp_mask = input_wait_mask; |
1362 EMACS_TIME sometime; | |
1363 EMACS_SELECT_TIME select_time_to_block, *pointer_to_this; | |
1364 | |
1365 if (badly_p) | |
1366 pointer_to_this = 0; | |
1367 else | |
1368 { | |
1369 EMACS_SET_SECS_USECS (sometime, 0, 0); | |
1370 EMACS_TIME_TO_SELECT_TIME (sometime, select_time_to_block); | |
1371 pointer_to_this = &select_time_to_block; | |
1268 | 1372 if (in_modal_loop) |
534 | 1373 /* In modal loop with badly_p false, don't care about |
1374 Windows events. */ | |
1375 FD_CLR (windows_fd, &temp_mask); | |
428 | 1376 } |
1377 | |
1292 | 1378 mswindows_is_blocking = 1; |
428 | 1379 active = select (MAXDESC, &temp_mask, 0, 0, pointer_to_this); |
1292 | 1380 mswindows_is_blocking = 0; |
428 | 1381 |
1382 if (active == 0) | |
1383 { | |
1384 assert (!badly_p); | |
1385 return; /* timeout */ | |
1386 } | |
1387 else if (active > 0) | |
1388 { | |
1389 if (FD_ISSET (windows_fd, &temp_mask)) | |
1268 | 1390 mswindows_drain_windows_queue (badly_p); |
442 | 1391 else |
428 | 1392 { |
442 | 1393 #ifdef HAVE_TTY |
1394 /* Look for a TTY event */ | |
1204 | 1395 for (i = 0; i < MAXDESC; i++) |
428 | 1396 { |
442 | 1397 /* To avoid race conditions (among other things, an infinite |
1398 loop when called from Fdiscard_input()), we must return | |
1399 user events ahead of process events. */ | |
1400 if (FD_ISSET (i, &temp_mask) && FD_ISSET (i, &tty_only_mask)) | |
428 | 1401 { |
1204 | 1402 struct console *c = |
1403 find_tty_or_stream_console_from_fd (i); | |
442 | 1404 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil); |
771 | 1405 Lisp_Event *event = XEVENT (emacs_event); |
1406 | |
442 | 1407 assert (c); |
771 | 1408 if (read_event_from_tty_or_stream_desc (event, c)) |
442 | 1409 { |
1410 mswindows_enqueue_dispatch_event (emacs_event); | |
1411 return; | |
1412 } | |
428 | 1413 } |
1414 } | |
1415 #endif | |
442 | 1416 /* Look for a process event */ |
1204 | 1417 for (i = 0; i < MAXDESC; i++) |
428 | 1418 { |
442 | 1419 if (FD_ISSET (i, &temp_mask)) |
428 | 1420 { |
442 | 1421 if (FD_ISSET (i, &process_only_mask)) |
1422 { | |
1423 Lisp_Process *p = | |
1204 | 1424 get_process_from_usid (FD_TO_USID (i)); |
442 | 1425 |
1426 mswindows_enqueue_process_event (p); | |
1427 } | |
1428 else | |
1429 { | |
1430 /* We might get here when a fake event came | |
1431 through a signal. Return a dummy event, so | |
1432 that a cycle of the command loop will | |
1433 occur. */ | |
1434 drain_signal_event_pipe (); | |
1435 mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE); | |
1436 } | |
428 | 1437 } |
1438 } | |
1439 } | |
1440 } | |
771 | 1441 else if (active == -1) |
428 | 1442 { |
1443 if (errno != EINTR) | |
1444 { | |
1445 /* something bad happened */ | |
1204 | 1446 assert (0); |
428 | 1447 } |
1448 } | |
1449 else | |
1450 { | |
1204 | 1451 assert (0); |
428 | 1452 } |
853 | 1453 #else /* not CYGWIN */ |
428 | 1454 /* Now try getting a message or process event */ |
647 | 1455 DWORD active; |
487 | 1456 DWORD what_events; |
1268 | 1457 if (in_modal_loop) |
534 | 1458 /* In a modal loop, only look for timer events, and only if |
1459 we really need one. */ | |
1460 { | |
1461 if (badly_p) | |
1462 what_events = QS_TIMER; | |
1463 else | |
1464 what_events = 0; | |
1465 } | |
487 | 1466 else |
534 | 1467 /* Look for any event */ |
1468 what_events = QS_ALLINPUT; | |
487 | 1469 |
771 | 1470 /* |
1471 #### YUCK YUCK YUCK!!!! | |
1472 | |
1473 When running under a debugger, every time I hit F12 (which for me | |
1474 is mapped to right-brace) I hit a breakpoint inside of Windows! | |
1475 | |
1476 NTDLL! DbgBreakPoint@0 address 0x77f9eea9 | |
1477 KERNEL32! BaseAttachComplete@4 + 41 bytes | |
1478 KERNEL32! BaseAttachCompleteThunk@0 + 19 bytes | |
1479 USER32! MsgWaitForMultipleObjectsEx@20 + 224 bytes | |
1480 USER32! MsgWaitForMultipleObjects@20 + 30 bytes | |
1481 | |
1482 Microsoft says: | |
1483 | |
1484 (Knowledge Base Q130667, PRB: F12 Causes Hard-Coded Breakpoint | |
1485 Exception When Debugging) | |
1486 | |
1487 CAUSE | |
1488 | |
1489 When the F12 key is pressed and the application in focus is being | |
1490 debugged, Windows NT calls a function similar to DebugBreak(), | |
1491 which executes a hard coded breakpoint instruction. The integrated | |
1492 debugger then traps the exception generated by this instruction. | |
1493 | |
1494 This behavior is intentional and occurs with other debuggers such | |
1495 as WinDbg from the Windows 32-bit SDK. | |
1496 | |
1497 RESOLUTION | |
1498 | |
1499 While there is no way to disable this functionality, it doesn't | |
1500 affect the application that's being debugged other than to pause | |
1501 debugging and change focus. You can continue debugging by pressing | |
1502 the F5 key. | |
1503 | |
1504 This can be annoying if you have an application that heavily uses | |
1505 the F12 key, so you may want to temporarily assign another key to | |
1506 handle the F12 key functionality in your program when debugging. | |
1507 | |
1508 STATUS | |
1509 | |
1510 This behavior is by design. | |
1511 | |
1512 | |
1513 However, elsewhere I found this: | |
1514 | |
1515 UserDebuggerHotKey | |
1516 HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AeDebug | |
1517 | |
1518 Data type Range Default value | |
1519 REG_DWORD 0x0 - 0xFF 0x0 | |
1520 | |
1521 Description | |
1522 | |
1523 Specifies the key that, when pressed, establishes a breakpoint in | |
1524 code being debugged. | |
1525 | |
1526 The debugger interrupts code processing at the breakpoint so the | |
1527 programmer can examine a suspected problem. | |
1528 | |
1529 The key specified in this value only sets a breakpoint. It does | |
1530 not invoke the debugger (the debugger must be running before the | |
1531 key is pressed) and it does not switch the debugger to single-step | |
1532 mode. | |
1533 | |
1534 The value of this entry is a keyboard scan code. The default | |
1535 value, 0x0, represents the F12 key on a 101-key keyboard or the - | |
1536 (hyphen, VK_SUBTRACT) key on an 82-key keyboard. | |
1537 */ | |
1538 | |
853 | 1539 __try |
1540 { | |
923 | 1541 /* This fixes a long outstanding bug, where XEmacs would occasionally |
1542 * not redraw its window (or process other events) until "something | |
1543 * happened" - usually the mouse moving over a frame. | |
1544 * | |
1545 * The problem is that MsgWaitForMultipleObjects only checks to see | |
1546 * if NEW messages have been placed into the thread queue. So we | |
1547 * specifically check to see if the queue is empty (using PeekMessage | |
1548 * with the PM_NOREMOVE flag) before we wait. | |
1549 */ | |
1550 MSG msg; | |
1551 if (what_events == QS_ALLINPUT && badly_p && | |
1552 qxePeekMessage (&msg, 0, 0, 0, PM_NOREMOVE)) | |
1553 active = WAIT_OBJECT_0 + mswindows_waitable_count; | |
1554 else | |
1292 | 1555 { |
1556 mswindows_is_blocking = 1; | |
1557 active = MsgWaitForMultipleObjects (mswindows_waitable_count, | |
1558 mswindows_waitable_handles, | |
1559 FALSE, | |
1560 badly_p ? INFINITE : 0, | |
1561 what_events); | |
1562 mswindows_is_blocking = 0; | |
1563 } | |
853 | 1564 } |
1565 __except (GetExceptionCode () == EXCEPTION_BREAKPOINT ? | |
1566 EXCEPTION_CONTINUE_EXECUTION : | |
1567 EXCEPTION_CONTINUE_SEARCH) | |
1568 { | |
1569 } | |
442 | 1570 |
1571 /* This will assert if handle being waited for becomes abandoned. | |
1572 Not the case currently tho */ | |
1573 assert ((!badly_p && active == WAIT_TIMEOUT) || | |
1574 (active >= WAIT_OBJECT_0 && | |
1575 active <= WAIT_OBJECT_0 + mswindows_waitable_count)); | |
1576 | |
1577 if (active == WAIT_TIMEOUT) | |
1578 { | |
1579 /* No luck trying - just return what we've already got */ | |
1580 return; | |
1581 } | |
1582 else if (active == WAIT_OBJECT_0 + mswindows_waitable_count) | |
1268 | 1583 mswindows_drain_windows_queue (badly_p); |
442 | 1584 else |
1585 { | |
1586 int ix = active - WAIT_OBJECT_0; | |
1204 | 1587 |
1588 /* look for a stream console event; see | |
1589 emacs_mswindows_select_console below. */ | |
1590 LIST_LOOP_3 (porca_troia, Vconsole_list, vcontail) | |
442 | 1591 { |
1204 | 1592 struct console *con = XCONSOLE (porca_troia); |
1593 | |
1594 if (CONSOLE_STREAM_P (con)) | |
1595 { | |
1596 Lisp_Object instr = CONSOLE_STREAM_DATA (con)->instream; | |
1597 if (!NILP (instr) && !UNBOUNDP (instr) && | |
1598 get_ntpipe_input_stream_waitable (XLSTREAM (instr)) == | |
1599 mswindows_waitable_handles [ix]) | |
1600 { | |
1601 Ichar ch = Lstream_get_ichar (XLSTREAM (instr)); | |
1602 if (ch < 0) | |
1603 { | |
1604 /* deleting the console might not be safe right now | |
1605 ... */ | |
1606 enqueue_magic_eval_event (io_error_delete_console, | |
1607 porca_troia); | |
1608 /* but we definitely need to unselect it to avoid | |
1609 infinite loops reading EOF's */ | |
1610 Fconsole_disable_input (porca_troia); | |
1611 mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE); | |
1612 } | |
1613 else | |
1614 { | |
1615 Lisp_Object event = Fmake_event (Qnil, Qnil); | |
1616 /* Here we really do want to set the | |
1617 use_console_meta_flag because the char is from the | |
1618 TTY. */ | |
4780
2fd201d73a92
Call character_to_event on characters received from XIM, event-Xt.c
Aidan Kehoe <kehoea@parhasard.net>
parents:
4677
diff
changeset
|
1619 character_to_event (ch, XEVENT (event), con, |
2fd201d73a92
Call character_to_event on characters received from XIM, event-Xt.c
Aidan Kehoe <kehoea@parhasard.net>
parents:
4677
diff
changeset
|
1620 use_console_meta_flag, 1); |
1204 | 1621 XSET_EVENT_CHANNEL (event, porca_troia); |
1622 enqueue_dispatch_event (event); | |
1623 } | |
1624 break; | |
1625 } | |
1626 } | |
1627 } | |
1628 | |
1629 if (NILP (vcontail)) | |
1630 { /* no stream console event, look for process event */ | |
1631 /* First, try to find which process' output has signaled */ | |
1632 Lisp_Process *p = | |
1633 get_process_from_usid (HANDLE_TO_USID | |
1634 (mswindows_waitable_handles[ix])); | |
1635 if (p != NULL) | |
1636 /* Found a signaled process input handle */ | |
1637 mswindows_enqueue_process_event (p); | |
853 | 1638 else |
442 | 1639 { |
1204 | 1640 /* None. This means that the process handle itself has |
1641 signaled. Remove the handle from the wait vector, and | |
1642 make status_notify note the exited process. First | |
1643 find the process object if possible. */ | |
1644 LIST_LOOP_3 (vaffanculo, Vprocess_list, vproctail) | |
1645 if (get_nt_process_handle (XPROCESS (vaffanculo)) == | |
1646 mswindows_waitable_handles [ix]) | |
1647 break; | |
1648 mswindows_waitable_handles [ix] = | |
1649 mswindows_waitable_handles [--mswindows_waitable_count]; | |
1650 kick_status_notify (); | |
1651 /* We need to return a process event here so that (1) | |
1652 accept-process-output will return when called on this | |
1653 process, and (2) status notifications will happen in | |
1654 accept-process-output, sleep-for, and sit-for. */ | |
1655 if (!NILP (vproctail)) | |
1656 mswindows_enqueue_process_event (XPROCESS (vaffanculo)); | |
1657 else | |
1658 { | |
2500 | 1659 /* ABORT (); */ |
1204 | 1660 /* #### FUCKME! When can this happen? I hit this |
2500 | 1661 ABORT() when I tried enabling it. */ |
1204 | 1662 /* Have to return something: there may be no |
1663 accompanying process event */ | |
1664 mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE); | |
1665 } | |
442 | 1666 } |
1667 } | |
1668 } | |
853 | 1669 #endif /* not CYGWIN */ |
442 | 1670 } /* while */ |
428 | 1671 } |
1672 | |
1673 /************************************************************************/ | |
1674 /* Event generators */ | |
1675 /************************************************************************/ | |
1676 | |
1677 /* | |
1678 * Callback procedure for synchronous timer messages | |
1679 */ | |
1680 static void CALLBACK | |
2286 | 1681 mswindows_wm_timer_callback (HWND UNUSED (hwnd), UINT UNUSED (umsg), |
1682 UINT id_timer, DWORD dwtime) | |
428 | 1683 { |
1684 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil); | |
1685 | |
1686 if (KillTimer (NULL, id_timer)) | |
1687 --mswindows_pending_timers_count; | |
1688 | |
964 | 1689 XSET_EVENT_CHANNEL (emacs_event, Qnil); |
1690 XSET_EVENT_TIMESTAMP (emacs_event, dwtime); | |
1691 XSET_EVENT_TYPE (emacs_event, timeout_event); | |
1204 | 1692 XSET_EVENT_TIMEOUT_INTERVAL_ID (emacs_event, id_timer); |
1693 XSET_EVENT_TIMEOUT_FUNCTION (emacs_event, Qnil); | |
1694 XSET_EVENT_TIMEOUT_OBJECT (emacs_event, Qnil); | |
428 | 1695 |
1696 mswindows_enqueue_dispatch_event (emacs_event); | |
1697 } | |
1698 | |
1699 /* | |
1700 * Callback procedure for dde messages | |
1701 * | |
1702 * We execute a dde Open("file") by simulating a file drop, so dde support | |
1703 * depends on dnd support. | |
1704 */ | |
1705 #ifdef HAVE_DRAGNDROP | |
657 | 1706 extern int mswindows_dde_enable; |
1707 | |
903 | 1708 EXFUN(Fread_from_string, 3); |
1709 | |
1710 /* The following variables are used to maintain consistency of result and | |
1711 * error reporting to the client. | |
1712 * The basic protocol is to Execute a lisp form, and then Request one or | |
1713 * more of the following items: Status (1 = OK, 0 = Error), Result, or Error. | |
1714 * When the lisp form is queued, the dde_eval_pending flag is set to 1, | |
1715 * to indicate that the items are not yet available. The dde_eval_pending | |
1716 * flag is set to 0 when the evaluation is complete. Requests for the result | |
1717 * items will block while the dde_eval_pending flag is 1, to avoid clients | |
1718 * getting inconsistent results. | |
1719 */ | |
1720 static int dde_eval_pending; | |
1721 static Lisp_Object dde_eval_result; | |
1722 static Lisp_Object dde_eval_error; | |
1723 | |
1724 static Lisp_Object | |
2286 | 1725 dde_error (Lisp_Object err, Lisp_Object UNUSED (obj)) |
903 | 1726 { |
1727 dde_eval_error = err; | |
1728 return Qnil; | |
1729 } | |
1730 | |
1731 /* Read lisp forms from a string. Evaluate the forms as if they were | |
1732 * wrapped in a progn form. Return the result of the form. | |
1733 */ | |
1734 static Lisp_Object | |
1735 dde_eval_string (Lisp_Object str) | |
1736 { | |
1737 struct gcpro gcpro1, gcpro2; | |
1738 Lisp_Object args[3]; | |
1739 Lisp_Object obj; | |
1740 | |
1741 /* Heavy handed GCPROing, on the principle of it's better to be safe than | |
1742 * sorry... | |
1743 */ | |
1744 args[0] = Qnil; | |
1745 args[1] = Qnil; | |
1746 args[2] = Qnil; | |
1747 GCPRO2 (args[0], str); | |
1748 gcpro1.nvars = 3; | |
1749 | |
1750 /* Wrap the user supplied string in string "(progn ...)". | |
1751 * We can now just read-from-string a single form. If we | |
1752 * get an error, or finish before the end of the string, | |
1753 * we know the original string had syntax errors. | |
1754 */ | |
4952
19a72041c5ed
Mule-izing, various fixes related to char * arguments
Ben Wing <ben@xemacs.org>
parents:
4932
diff
changeset
|
1755 args[0] = build_ascstring ("(progn "); |
903 | 1756 args[1] = str; |
4952
19a72041c5ed
Mule-izing, various fixes related to char * arguments
Ben Wing <ben@xemacs.org>
parents:
4932
diff
changeset
|
1757 args[2] = build_ascstring (")"); |
903 | 1758 str = Fconcat (3, args); |
1759 | |
1760 obj = Fread_from_string (str, Qnil, Qnil); | |
1761 UNGCPRO; | |
1762 | |
1763 /* The following doesn't check that the length fits in an EMACS_INT. | |
1764 * This won't be a problem in reality...? | |
1765 * | |
1766 * If the read didn't get to the end of the string, we have a syntax | |
1767 * error in the string supplied by the user. | |
1768 */ | |
1769 if (XINT (XCDR (obj)) != XSTRING_LENGTH (str)) | |
1770 return Qnil; | |
1771 | |
1772 GCPRO1 (obj); | |
4677
8f1ee2d15784
Support full Common Lisp multiple values in C.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3263
diff
changeset
|
1773 obj = IGNORE_MULTIPLE_VALUES (Feval (XCAR (obj))); |
903 | 1774 |
1204 | 1775 RETURN_UNGCPRO (obj); |
903 | 1776 } |
1777 | |
1778 /* Evaluate the supplied string as a sequence of Lisp forms, wrapped in | |
1779 * a progn. Catch any evaluation errors. Set the evaluation status and | |
1780 * result variables. | |
1781 */ | |
1782 static void | |
1783 dde_eval (Lisp_Object str) | |
1784 { | |
1785 dde_eval_error = Qnil; | |
1786 dde_eval_result = condition_case_1 (Qt, dde_eval_string, str, | |
1787 dde_error, Qnil); | |
1788 dde_eval_pending = 0; | |
1789 | |
1790 /* Re-enable callbacks in case the client is waiting on a request */ | |
1791 DdeEnableCallback (mswindows_dde_mlid, NULL, EC_ENABLEALL); | |
1792 | |
1793 /* Post advise notifications on the result item */ | |
1794 DdePostAdvise (mswindows_dde_mlid, mswindows_dde_topic_eval, | |
1795 mswindows_dde_item_result); | |
1796 } | |
1797 | |
1798 /* A list of DDE advise tokens. Each token is an uninterned symbol, | |
1799 * whose value is the DDE string handle for its name (stored as a float, | |
1800 * as a Lisp int cannot hold a full C int). | |
3025 | 1801 * The token's `dde-data' property is used to store data for a dde-advise. |
903 | 1802 */ |
1803 Lisp_Object Vdde_advise_items; | |
1804 | |
3025 | 1805 /* The symbol `HSZ' */ |
903 | 1806 Lisp_Object QHSZ; |
1807 | |
1808 DEFUN("dde-alloc-advise-item", Fdde_alloc_advise_item, 0, 1, 0, /* | |
1809 Allocate an advise item, and return its token. | |
1810 */ | |
1811 (name)) | |
1812 { | |
1813 Lisp_Object token; | |
1814 Extbyte *str; | |
1815 HSZ hsz; | |
1816 struct gcpro gcpro1, gcpro2; | |
1817 | |
1818 if (!NILP (name)) | |
1819 CHECK_STRING (name); | |
1820 else | |
1821 { | |
1822 static int num = 0; | |
4952
19a72041c5ed
Mule-izing, various fixes related to char * arguments
Ben Wing <ben@xemacs.org>
parents:
4932
diff
changeset
|
1823 Ascbyte buf[20]; |
903 | 1824 sprintf (buf, "Tok%d", num); |
1825 ++num; | |
4952
19a72041c5ed
Mule-izing, various fixes related to char * arguments
Ben Wing <ben@xemacs.org>
parents:
4932
diff
changeset
|
1826 name = build_ascstring (buf); |
903 | 1827 } |
1828 | |
1829 token = Qnil; | |
1830 GCPRO2 (name, token); | |
1831 token = Fmake_symbol (name); | |
1832 TO_EXTERNAL_FORMAT (LISP_STRING, name, C_STRING_ALLOCA, str, | |
1833 Qmswindows_tstr); | |
1834 hsz = qxeDdeCreateStringHandle (mswindows_dde_mlid, str, | |
1835 XEUNICODE_P ? CP_WINUNICODE : CP_WINANSI); | |
1836 | |
1837 Fput(token, QHSZ, make_float ((int)hsz)); | |
1838 Vdde_advise_items = Fcons (token, Vdde_advise_items); | |
1839 | |
1204 | 1840 RETURN_UNGCPRO (token); |
903 | 1841 } |
1842 | |
1843 DEFUN("dde-free-advise-item", Fdde_free_advise_item, 1, 1, 0, /* | |
1844 Free the resources associated with advise item ITEM. | |
1845 | |
1846 Frees all resources allocated to allow clients to set up advise loops | |
1847 on ITEM. It is assumed that no active advise loops remain. However, no | |
1848 problems should arise if they do - it's just that we won't ever send any | |
1849 notifications again. | |
1850 | |
1851 If the user does not free an advise item, resources will be leaked. | |
1852 */ | |
1853 (item)) | |
1854 { | |
1855 HSZ hsz; | |
1856 Lisp_Object val; | |
1857 | |
1858 CHECK_SYMBOL (item); | |
1859 val = Fget (item, QHSZ, Qnil); | |
1860 if (!FLOATP (val)) | |
1861 return Qnil; | |
1862 hsz = (HSZ)(int)XFLOAT_DATA (val); | |
1863 DdeFreeStringHandle (mswindows_dde_mlid, hsz); | |
1864 Vdde_advise_items = delq_no_quit (item, Vdde_advise_items); | |
1865 return Qnil; | |
1866 } | |
1867 | |
1868 DEFUN("dde-advise", Fdde_advise, 2, 2, 0, /* | |
1869 Post a DDE advise for ITEM with associated data DATA. | |
1870 | |
1871 Records the value DATA for sending back to clients waiting for | |
1872 notifications on DDE item ITEM in the system topic, and posts | |
1873 the advise transaction. | |
1874 | |
1875 ITEM must be an advise token allocated using dde-alloc-advise-item. | |
1876 */ | |
1877 (item, data)) | |
1878 { | |
1879 HSZ hsz; | |
1880 Lisp_Object val; | |
1881 | |
1882 CHECK_SYMBOL (item); | |
1883 val = Fget (item, QHSZ, Qnil); | |
1884 if (!FLOATP (val)) | |
1885 return Qnil; | |
1886 hsz = (HSZ)(int)XFLOAT_DATA (val); | |
1887 | |
1888 Fset (item, data); | |
1889 DdePostAdvise (mswindows_dde_mlid, mswindows_dde_topic_eval, hsz); | |
1890 return Qnil; | |
1891 } | |
1892 | |
428 | 1893 HDDEDATA CALLBACK |
2286 | 1894 mswindows_dde_callback (UINT uType, UINT uFmt, HCONV UNUSED (hconv), |
428 | 1895 HSZ hszTopic, HSZ hszItem, HDDEDATA hdata, |
2286 | 1896 DWORD UNUSED (dwData1), DWORD UNUSED (dwData2)) |
428 | 1897 { |
1898 switch (uType) | |
1899 { | |
1900 case XTYP_CONNECT: | |
903 | 1901 if (!DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system) |
1902 || !DdeCmpStringHandles (hszTopic, mswindows_dde_topic_eval)) | |
853 | 1903 return (HDDEDATA) TRUE; |
1904 return (HDDEDATA) FALSE; | |
428 | 1905 |
1906 case XTYP_WILDCONNECT: | |
1907 { | |
903 | 1908 /* We support two {service,topic} pairs */ |
1909 HSZPAIR pairs[3] = | |
771 | 1910 { |
903 | 1911 { mswindows_dde_service, mswindows_dde_topic_system }, |
1912 { mswindows_dde_service, mswindows_dde_topic_eval }, | |
1913 { 0, 0 } | |
1914 }; | |
1915 | |
1916 if ((!hszItem | |
1917 || !DdeCmpStringHandles (hszItem, mswindows_dde_service)) && | |
1918 (!hszTopic | |
1919 || !DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system) | |
1920 || !DdeCmpStringHandles (hszTopic, mswindows_dde_topic_eval))) | |
853 | 1921 return (DdeCreateDataHandle (mswindows_dde_mlid, (LPBYTE) pairs, |
428 | 1922 sizeof (pairs), 0L, 0, uFmt, 0)); |
1923 } | |
853 | 1924 return (HDDEDATA) NULL; |
428 | 1925 |
903 | 1926 case XTYP_ADVSTART: |
1927 if (!mswindows_dde_enable) | |
1928 return (HDDEDATA) FALSE; | |
1929 | |
1930 /* We only support advise loops on the eval topic for text data */ | |
1931 if (!DdeCmpStringHandles (hszTopic, mswindows_dde_topic_eval) | |
1932 && (uFmt == CF_TEXT || uFmt == CF_UNICODETEXT)) | |
1933 { | |
1934 /* Only allocated items or Result, are allowed */ | |
1935 if (!DdeCmpStringHandles (hszItem, mswindows_dde_item_result)) | |
1936 return (HDDEDATA) TRUE; | |
1937 | |
1938 { | |
1939 EXTERNAL_LIST_LOOP_2 (elt, Vdde_advise_items) | |
1940 { | |
1941 Lisp_Object val; | |
1942 HSZ hsz; | |
1943 if (!SYMBOLP (elt)) | |
1944 continue; | |
1945 val = Fget (elt, QHSZ, Qnil); | |
1946 if (!FLOATP (val)) | |
1947 continue; | |
1948 hsz = (HSZ) (int) XFLOAT_DATA (val); | |
1949 if (!DdeCmpStringHandles (hszItem, hsz)) | |
1950 return (HDDEDATA) TRUE; | |
1951 } | |
1952 } | |
1953 } | |
1954 return (HDDEDATA) FALSE; | |
1955 | |
1956 /* Both advise requests and normal requests work the same */ | |
1957 case XTYP_ADVREQ: | |
1958 case XTYP_REQUEST: | |
1959 if (!mswindows_dde_enable) | |
1960 return (HDDEDATA) NULL; | |
1961 | |
1962 if (DdeCmpStringHandles (hszTopic, mswindows_dde_topic_eval) != 0) | |
1963 return (HDDEDATA) NULL; | |
1964 | |
1965 /* If this is a normal request and we're in the middle of | |
1966 * an Execute, block until the Execute completes. | |
1967 */ | |
1968 if (dde_eval_pending && uType == XTYP_REQUEST) | |
1969 return (HDDEDATA) CBR_BLOCK; | |
1970 | |
1971 /* We can only support requests for ANSI or Unicode text */ | |
1972 if (uFmt != CF_TEXT && uFmt != CF_UNICODETEXT) | |
1973 return (HDDEDATA) NULL; | |
1974 | |
1975 { | |
1976 Lisp_Object args[2]; | |
1977 struct gcpro gcpro1; | |
1978 Lisp_Object res; | |
1979 Extbyte *result; | |
1980 DWORD bytes; | |
1981 | |
1982 args[0] = Qnil; | |
1983 args[1] = Qnil; | |
1984 GCPRO1 (args[0]); | |
1985 gcpro1.nvars = 2; | |
1986 | |
1987 | |
1988 if (!DdeCmpStringHandles (hszItem, mswindows_dde_item_result)) | |
1989 { | |
1990 if (NILP (dde_eval_error)) | |
1991 { | |
4952
19a72041c5ed
Mule-izing, various fixes related to char * arguments
Ben Wing <ben@xemacs.org>
parents:
4932
diff
changeset
|
1992 args[0] = build_ascstring ("OK: %s"); |
903 | 1993 args[1] = dde_eval_result; |
1994 } | |
1995 else | |
1996 { | |
4952
19a72041c5ed
Mule-izing, various fixes related to char * arguments
Ben Wing <ben@xemacs.org>
parents:
4932
diff
changeset
|
1997 args[0] = build_ascstring ("ERR: %s"); |
903 | 1998 args[1] = dde_eval_error; |
1999 } | |
2000 } | |
2001 else | |
2002 { | |
2003 EXTERNAL_LIST_LOOP_2 (elt, Vdde_advise_items) | |
2004 { | |
2005 Lisp_Object val; | |
2006 HSZ hsz; | |
2007 if (!SYMBOLP (elt)) | |
2008 continue; | |
2009 val = Fget (elt, QHSZ, Qnil); | |
2010 if (!FLOATP (val)) | |
2011 continue; | |
2012 hsz = (HSZ) (int) XFLOAT_DATA (val); | |
2013 if (!DdeCmpStringHandles (hszItem, hsz)) | |
2014 args[1] = Fsymbol_value (elt); | |
2015 } | |
4952
19a72041c5ed
Mule-izing, various fixes related to char * arguments
Ben Wing <ben@xemacs.org>
parents:
4932
diff
changeset
|
2016 args[0] = build_ascstring ("%s"); |
903 | 2017 } |
2018 | |
2019 res = Fformat (2, args); | |
2020 UNGCPRO; | |
2021 | |
2022 bytes = (uFmt == CF_TEXT ? 1 : 2) * (XSTRING_LENGTH (res) + 1); | |
2023 TO_EXTERNAL_FORMAT (LISP_STRING, res, | |
2024 C_STRING_ALLOCA, result, | |
2025 uFmt == CF_TEXT ? Qmswindows_multibyte | |
2026 : Qmswindows_unicode); | |
2027 | |
2028 /* If we cannot create the data handle, this passes the null | |
2029 * return back to the client, which signals an error as we wish. | |
2030 */ | |
2031 return DdeCreateDataHandle (mswindows_dde_mlid, (LPBYTE)result, | |
2032 bytes, 0L, hszItem, uFmt, 0); | |
2033 } | |
2034 | |
428 | 2035 case XTYP_EXECUTE: |
657 | 2036 if (!mswindows_dde_enable) |
2037 return (HDDEDATA) DDE_FBUSY; | |
2038 | |
903 | 2039 if (!DdeCmpStringHandles (hszTopic, mswindows_dde_topic_eval)) |
2040 { | |
2041 DWORD len; | |
2042 LPBYTE extcmd; | |
2043 Lisp_Object tmp; | |
2044 | |
2045 /* Grab a pointer to the raw data supplied */ | |
2046 extcmd = DdeAccessData (hdata, &len); | |
2047 | |
2048 TO_INTERNAL_FORMAT (DATA, (extcmd, len), | |
2049 LISP_STRING, tmp, | |
2050 Qmswindows_tstr); | |
2051 | |
2052 /* Release and free the data handle */ | |
2053 DdeUnaccessData (hdata); | |
2054 DdeFreeDataHandle (hdata); | |
2055 | |
2056 /* Set a flag to say that the evaluation isn't yet complete, | |
2057 * enqueue the evaluation, send a dummy event to trigger the | |
2058 * event loop (I've no idea why this is needed, but it works...) | |
2059 * and return success to the client. | |
2060 */ | |
2061 dde_eval_pending = 1; | |
2062 enqueue_magic_eval_event (dde_eval, tmp); | |
2063 mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE); | |
2064 return (HDDEDATA) DDE_FACK; | |
2065 } | |
2066 else if (!DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system)) | |
428 | 2067 { |
2068 DWORD len = DdeGetData (hdata, NULL, 0, 0); | |
2367 | 2069 Extbyte *extcmd = alloca_extbytes (len + 1); |
867 | 2070 Ibyte *cmd; |
2071 Ibyte *end; | |
428 | 2072 struct gcpro gcpro1, gcpro2; |
657 | 2073 Lisp_Object l_dndlist = Qnil; |
428 | 2074 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil); |
2075 Lisp_Object frmcons, devcons, concons; | |
440 | 2076 Lisp_Event *event = XEVENT (emacs_event); |
428 | 2077 |
2367 | 2078 DdeGetData (hdata, (LPBYTE) extcmd, len, 0); |
428 | 2079 DdeFreeDataHandle (hdata); |
2080 | |
771 | 2081 TO_INTERNAL_FORMAT (DATA, (extcmd, len), |
2082 C_STRING_ALLOCA, cmd, | |
2083 Qmswindows_tstr); | |
2084 | |
428 | 2085 /* Check syntax & that it's an [Open("foo")] command, which we |
2086 * treat like a file drop */ | |
2087 if (*cmd == '[') | |
2088 cmd++; | |
2367 | 2089 if (qxestrncasecmp_ascii (cmd, MSWINDOWS_DDE_ITEM_OPEN, |
771 | 2090 strlen (MSWINDOWS_DDE_ITEM_OPEN))) |
428 | 2091 return DDE_FNOTPROCESSED; |
2092 cmd += strlen (MSWINDOWS_DDE_ITEM_OPEN); | |
771 | 2093 while (*cmd == ' ') |
428 | 2094 cmd++; |
771 | 2095 if (*cmd != '(' || *(cmd + 1) != '\"') |
428 | 2096 return DDE_FNOTPROCESSED; |
771 | 2097 end = (cmd += 2); |
2098 while (*end && *end != '\"') | |
428 | 2099 end++; |
2100 if (!*end) | |
2101 return DDE_FNOTPROCESSED; | |
2102 *end = '\0'; | |
771 | 2103 if (*++end != ')') |
428 | 2104 return DDE_FNOTPROCESSED; |
771 | 2105 if (*++end == ']') |
428 | 2106 end++; |
2107 if (*end) | |
2108 return DDE_FNOTPROCESSED; | |
2109 | |
771 | 2110 { |
2111 /* The drag-n-drop code in dragdrop.el expects pseudo-URL's, | |
2112 consisting of just file: followed by the filename. This | |
2113 should maybe work, but both Netscape and IE complain | |
2114 whenever they're not given the full file spec, like | |
2115 | |
2116 file:///C|/foo/bar/ or equivalently | |
2117 file:///C:/foo/bar/ (less portably) | |
2118 | |
2119 they don't allow relative paths at all! this is way bogus. */ | |
2120 cmd = urlify_filename (cmd); | |
2121 l_dndlist = build_intstring (cmd); | |
1726 | 2122 xfree (cmd, Ibyte *); |
771 | 2123 } |
428 | 2124 GCPRO2 (emacs_event, l_dndlist); |
2125 | |
2126 /* Find a mswindows frame */ | |
2127 event->channel = Qnil; | |
2128 FRAME_LOOP_NO_BREAK (frmcons, devcons, concons) | |
2129 { | |
2130 Lisp_Object frame = XCAR (frmcons); | |
2131 if (FRAME_TYPE_P (XFRAME (frame), mswindows)) | |
2132 event->channel = frame; | |
2133 }; | |
2134 assert (!NILP (event->channel)); | |
2135 | |
964 | 2136 SET_EVENT_TIMESTAMP (event, GetTickCount()); |
2137 SET_EVENT_TYPE (event, misc_user_event); | |
1204 | 2138 SET_EVENT_MISC_USER_BUTTON (event, 1); |
2139 SET_EVENT_MISC_USER_MODIFIERS (event, 0); | |
2140 SET_EVENT_MISC_USER_X (event, -1); | |
2141 SET_EVENT_MISC_USER_Y (event, -1); | |
2142 SET_EVENT_MISC_USER_FUNCTION (event, | |
964 | 2143 Qdragdrop_drop_dispatch); |
1204 | 2144 SET_EVENT_MISC_USER_OBJECT (event, |
964 | 2145 Fcons (Qdragdrop_URL, |
2146 Fcons (l_dndlist, Qnil))); | |
428 | 2147 mswindows_enqueue_dispatch_event (emacs_event); |
2148 UNGCPRO; | |
2149 return (HDDEDATA) DDE_FACK; | |
2150 } | |
2151 DdeFreeDataHandle (hdata); | |
2152 return (HDDEDATA) DDE_FNOTPROCESSED; | |
2153 | |
2154 default: | |
2155 return (HDDEDATA) NULL; | |
2156 } | |
2157 } | |
2158 #endif | |
2159 | |
2160 /* | |
442 | 2161 * Helper to do repainting - repaints can happen both from the windows |
2162 * procedure and from magic events | |
2163 */ | |
2164 static void | |
2165 mswindows_handle_paint (struct frame *frame) | |
2166 { | |
2167 HWND hwnd = FRAME_MSWINDOWS_HANDLE (frame); | |
2168 | |
2169 /* According to the docs we need to check GetUpdateRect() before | |
2170 actually doing a WM_PAINT */ | |
2171 if (GetUpdateRect (hwnd, NULL, FALSE)) | |
2172 { | |
2173 PAINTSTRUCT paintStruct; | |
2174 int x, y, width, height; | |
2175 | |
2176 BeginPaint (hwnd, &paintStruct); | |
2177 x = paintStruct.rcPaint.left; | |
2178 y = paintStruct.rcPaint.top; | |
2179 width = paintStruct.rcPaint.right - paintStruct.rcPaint.left; | |
2180 height = paintStruct.rcPaint.bottom - paintStruct.rcPaint.top; | |
2181 /* Normally we want to ignore expose events when child | |
2182 windows are unmapped, however once we are in the guts of | |
2183 WM_PAINT we need to make sure that we don't register | |
2184 unmaps then because they will not actually occur. */ | |
2185 /* #### commenting out the next line seems to fix some problems | |
2186 but not all. only andy currently understands this stuff and | |
2187 he needs to review it more carefully. --ben */ | |
2188 if (!check_for_ignored_expose (frame, x, y, width, height)) | |
2189 { | |
2190 hold_ignored_expose_registration = 1; | |
1318 | 2191 redisplay_redraw_exposed_area (frame, x, y, width, height); |
442 | 2192 hold_ignored_expose_registration = 0; |
2193 } | |
2194 EndPaint (hwnd, &paintStruct); | |
2195 } | |
2196 } | |
2197 | |
2198 /* | |
2199 * Returns 1 if a key is a real modifier or special key, which | |
440 | 2200 * is better handled by DefWindowProc |
2201 */ | |
2202 static int | |
2203 key_needs_default_processing_p (UINT vkey) | |
2204 { | |
442 | 2205 if (mswindows_alt_by_itself_activates_menu && vkey == VK_MENU |
2206 /* if we let ALT activate the menu like this, then sticky ALT-modified | |
2207 keystrokes become impossible. */ | |
2208 && !modifier_keys_are_sticky) | |
440 | 2209 return 1; |
2210 | |
2211 return 0; | |
2212 } | |
2213 | |
442 | 2214 /* key-handling code is always ugly. It just ends up working out |
2215 that way. | |
2216 | |
2217 #### Most of the sticky-modifier code below is copied from similar | |
2218 code in event-Xt.c. They should somehow or other be merged. | |
2219 | |
2220 Here are some pointers: | |
2221 | |
2222 -- DOWN_MASK indicates which modifiers should be treated as "down" | |
2223 when the corresponding upstroke happens. It gets reset for | |
2224 a particular modifier when that modifier goes up, and reset | |
2225 for all modifiers when a non-modifier key is pressed. Example: | |
2226 | |
2227 I press Control-A-Shift and then release Control-A-Shift. | |
2228 I want the Shift key to be sticky but not the Control key. | |
2229 | |
2230 -- If a modifier key is sticky, I can unstick it by pressing | |
2231 the modifier key again. */ | |
2232 | |
2233 static WPARAM last_downkey; | |
2234 static int need_to_add_mask, down_mask; | |
2235 | |
2236 #define XEMSW_LCONTROL (1<<0) | |
2237 #define XEMSW_RCONTROL (1<<1) | |
2238 #define XEMSW_LSHIFT (1<<2) | |
2239 #define XEMSW_RSHIFT (1<<3) | |
2240 #define XEMSW_LMENU (1<<4) | |
2241 #define XEMSW_RMENU (1<<5) | |
2242 | |
2243 static int | |
2244 mswindows_handle_sticky_modifiers (WPARAM wParam, LPARAM lParam, | |
2245 int downp, int keyp) | |
2246 { | |
2247 int mods = 0; | |
2248 | |
2249 if (!modifier_keys_are_sticky) /* Optimize for non-sticky modifiers */ | |
2250 return 0; | |
2251 | |
2252 if (! (keyp && | |
2253 (wParam == VK_CONTROL || wParam == VK_LCONTROL || | |
2254 wParam == VK_RCONTROL || | |
2255 wParam == VK_MENU || wParam == VK_LMENU || | |
2256 wParam == VK_RMENU || | |
2257 wParam == VK_SHIFT || wParam == VK_LSHIFT || | |
2258 wParam == VK_RSHIFT))) | |
2259 { /* Not a modifier key */ | |
2260 if (downp && keyp && !last_downkey) | |
2261 last_downkey = wParam; | |
2262 /* If I hold press-and-release the Control key and then press | |
2263 and hold down the right arrow, I want it to auto-repeat | |
2264 Control-Right. On the other hand, if I do the same but | |
2265 manually press the Right arrow a bunch of times, I want | |
2266 to see one Control-Right and then a bunch of Rights. | |
2267 This means that we need to distinguish between an | |
2268 auto-repeated key and a key pressed and released a bunch | |
2269 of times. */ | |
2270 else if ((downp && !keyp) || | |
2271 (downp && keyp && last_downkey && | |
2272 (wParam != last_downkey || | |
2273 /* the "previous key state" bit indicates autorepeat */ | |
2274 ! (lParam & (1 << 30))))) | |
2275 { | |
2276 need_to_add_mask = 0; | |
2277 last_downkey = 0; | |
2278 } | |
2279 if (downp) | |
2280 down_mask = 0; | |
2281 | |
2282 mods = need_to_add_mask; | |
2283 } | |
2284 else /* Modifier key pressed */ | |
2285 { | |
2286 /* If a non-modifier key was pressed in the middle of a bunch | |
2287 of modifiers, then it unsticks all the modifiers that were | |
2288 previously pressed. We cannot unstick the modifiers until | |
2289 now because we want to check for auto-repeat of the | |
2290 non-modifier key. */ | |
2291 | |
2292 if (last_downkey) | |
2293 { | |
2294 last_downkey = 0; | |
2295 need_to_add_mask = 0; | |
2296 } | |
2297 | |
2298 #define FROB(mask) \ | |
2299 do { \ | |
2300 if (downp && keyp) \ | |
2301 { \ | |
2302 /* If modifier key is already sticky, \ | |
2303 then unstick it. Note that we do \ | |
2304 not test down_mask to deal with the \ | |
2305 unlikely but possible case that the \ | |
2306 modifier key auto-repeats. */ \ | |
2307 if (need_to_add_mask & mask) \ | |
2308 { \ | |
2309 need_to_add_mask &= ~mask; \ | |
2310 down_mask &= ~mask; \ | |
2311 } \ | |
2312 else \ | |
2313 down_mask |= mask; \ | |
2314 } \ | |
2315 else \ | |
2316 { \ | |
2317 if (down_mask & mask) \ | |
2318 { \ | |
2319 down_mask &= ~mask; \ | |
2320 need_to_add_mask |= mask; \ | |
2321 } \ | |
2322 } \ | |
2323 } while (0) | |
2324 | |
2325 if ((wParam == VK_CONTROL && (lParam & 0x1000000)) | |
2326 || wParam == VK_RCONTROL) | |
2327 FROB (XEMSW_RCONTROL); | |
2328 if ((wParam == VK_CONTROL && !(lParam & 0x1000000)) | |
2329 || wParam == VK_LCONTROL) | |
2330 FROB (XEMSW_LCONTROL); | |
2331 | |
2332 if ((wParam == VK_SHIFT && (lParam & 0x1000000)) | |
2333 || wParam == VK_RSHIFT) | |
2334 FROB (XEMSW_RSHIFT); | |
2335 if ((wParam == VK_SHIFT && !(lParam & 0x1000000)) | |
2336 || wParam == VK_LSHIFT) | |
2337 FROB (XEMSW_LSHIFT); | |
2338 | |
2339 if ((wParam == VK_MENU && (lParam & 0x1000000)) | |
2340 || wParam == VK_RMENU) | |
2341 FROB (XEMSW_RMENU); | |
2342 if ((wParam == VK_MENU && !(lParam & 0x1000000)) | |
2343 || wParam == VK_LMENU) | |
2344 FROB (XEMSW_LMENU); | |
2345 } | |
2346 #undef FROB | |
2347 | |
2348 if (mods && downp) | |
2349 { | |
2350 BYTE keymap[256]; | |
2351 | |
2352 GetKeyboardState (keymap); | |
2353 | |
2354 if (mods & XEMSW_LCONTROL) | |
2355 { | |
2356 keymap [VK_CONTROL] |= 0x80; | |
2357 keymap [VK_LCONTROL] |= 0x80; | |
2358 } | |
2359 if (mods & XEMSW_RCONTROL) | |
2360 { | |
2361 keymap [VK_CONTROL] |= 0x80; | |
2362 keymap [VK_RCONTROL] |= 0x80; | |
2363 } | |
2364 | |
2365 if (mods & XEMSW_LSHIFT) | |
2366 { | |
2367 keymap [VK_SHIFT] |= 0x80; | |
2368 keymap [VK_LSHIFT] |= 0x80; | |
2369 } | |
2370 if (mods & XEMSW_RSHIFT) | |
2371 { | |
2372 keymap [VK_SHIFT] |= 0x80; | |
2373 keymap [VK_RSHIFT] |= 0x80; | |
2374 } | |
2375 | |
2376 if (mods & XEMSW_LMENU) | |
2377 { | |
2378 keymap [VK_MENU] |= 0x80; | |
2379 keymap [VK_LMENU] |= 0x80; | |
2380 } | |
2381 if (mods & XEMSW_RMENU) | |
2382 { | |
2383 keymap [VK_MENU] |= 0x80; | |
2384 keymap [VK_RMENU] |= 0x80; | |
2385 } | |
2386 | |
2387 SetKeyboardState (keymap); | |
2388 return 1; | |
2389 } | |
2390 | |
2391 return 0; | |
2392 } | |
2393 | |
2394 static void | |
2395 clear_sticky_modifiers (void) | |
2396 { | |
2397 need_to_add_mask = 0; | |
2398 last_downkey = 0; | |
2399 down_mask = 0; | |
2400 } | |
2401 | |
2402 #ifdef DEBUG_XEMACS | |
2403 | |
2404 #if 0 | |
2405 | |
2406 static void | |
2407 output_modifier_keyboard_state (void) | |
2408 { | |
2409 BYTE keymap[256]; | |
2410 | |
2411 GetKeyboardState (keymap); | |
2412 | |
2413 stderr_out ("GetKeyboardState VK_MENU %d %d VK_LMENU %d %d VK_RMENU %d %d\n", | |
2414 keymap[VK_MENU] & 0x80 ? 1 : 0, | |
2415 keymap[VK_MENU] & 0x1 ? 1 : 0, | |
2416 keymap[VK_LMENU] & 0x80 ? 1 : 0, | |
2417 keymap[VK_LMENU] & 0x1 ? 1 : 0, | |
2418 keymap[VK_RMENU] & 0x80 ? 1 : 0, | |
2419 keymap[VK_RMENU] & 0x1 ? 1 : 0); | |
2420 stderr_out ("GetKeyboardState VK_CONTROL %d %d VK_LCONTROL %d %d VK_RCONTROL %d %d\n", | |
2421 keymap[VK_CONTROL] & 0x80 ? 1 : 0, | |
2422 keymap[VK_CONTROL] & 0x1 ? 1 : 0, | |
2423 keymap[VK_LCONTROL] & 0x80 ? 1 : 0, | |
2424 keymap[VK_LCONTROL] & 0x1 ? 1 : 0, | |
2425 keymap[VK_RCONTROL] & 0x80 ? 1 : 0, | |
2426 keymap[VK_RCONTROL] & 0x1 ? 1 : 0); | |
2427 stderr_out ("GetKeyboardState VK_SHIFT %d %d VK_LSHIFT %d %d VK_RSHIFT %d %d\n", | |
2428 keymap[VK_SHIFT] & 0x80 ? 1 : 0, | |
2429 keymap[VK_SHIFT] & 0x1 ? 1 : 0, | |
2430 keymap[VK_LSHIFT] & 0x80 ? 1 : 0, | |
2431 keymap[VK_LSHIFT] & 0x1 ? 1 : 0, | |
2432 keymap[VK_RSHIFT] & 0x80 ? 1 : 0, | |
2433 keymap[VK_RSHIFT] & 0x1 ? 1 : 0); | |
2434 } | |
2435 | |
2436 #endif | |
2437 | |
2438 /* try to debug the stuck-alt-key problem. | |
2439 | |
2440 #### this happens only inconsistently, and may only happen when using | |
2441 StickyKeys in the Win2000 accessibility section of the control panel, | |
2442 which is extremely broken for other reasons. */ | |
2443 | |
2444 static void | |
2445 output_alt_keyboard_state (void) | |
2446 { | |
2447 BYTE keymap[256]; | |
2448 SHORT keystate[3]; | |
1242 | 2449 /* SHORT asyncstate[3]; */ |
442 | 2450 |
2451 GetKeyboardState (keymap); | |
2452 keystate[0] = GetKeyState (VK_MENU); | |
2453 keystate[1] = GetKeyState (VK_LMENU); | |
2454 keystate[2] = GetKeyState (VK_RMENU); | |
2455 /* Doing this interferes with key processing. */ | |
2456 /* asyncstate[0] = GetAsyncKeyState (VK_MENU); */ | |
2457 /* asyncstate[1] = GetAsyncKeyState (VK_LMENU); */ | |
2458 /* asyncstate[2] = GetAsyncKeyState (VK_RMENU); */ | |
2459 | |
2460 stderr_out ("GetKeyboardState VK_MENU %d %d VK_LMENU %d %d VK_RMENU %d %d\n", | |
2461 keymap[VK_MENU] & 0x80 ? 1 : 0, | |
2462 keymap[VK_MENU] & 0x1 ? 1 : 0, | |
2463 keymap[VK_LMENU] & 0x80 ? 1 : 0, | |
2464 keymap[VK_LMENU] & 0x1 ? 1 : 0, | |
2465 keymap[VK_RMENU] & 0x80 ? 1 : 0, | |
2466 keymap[VK_RMENU] & 0x1 ? 1 : 0); | |
2467 stderr_out ("GetKeyState VK_MENU %d %d VK_LMENU %d %d VK_RMENU %d %d\n", | |
2468 keystate[0] & 0x8000 ? 1 : 0, | |
2469 keystate[0] & 0x1 ? 1 : 0, | |
2470 keystate[1] & 0x8000 ? 1 : 0, | |
2471 keystate[1] & 0x1 ? 1 : 0, | |
2472 keystate[2] & 0x8000 ? 1 : 0, | |
2473 keystate[2] & 0x1 ? 1 : 0); | |
2474 /* stderr_out ("GetAsyncKeyState VK_MENU %d %d VK_LMENU %d %d VK_RMENU %d %d\n", */ | |
2475 /* asyncstate[0] & 0x8000 ? 1 : 0, */ | |
2476 /* asyncstate[0] & 0x1 ? 1 : 0, */ | |
2477 /* asyncstate[1] & 0x8000 ? 1 : 0, */ | |
2478 /* asyncstate[1] & 0x1 ? 1 : 0, */ | |
2479 /* asyncstate[2] & 0x8000 ? 1 : 0, */ | |
2480 /* asyncstate[2] & 0x1 ? 1 : 0); */ | |
2481 } | |
2482 | |
2483 #endif /* DEBUG_XEMACS */ | |
2484 | |
2485 | |
440 | 2486 /* |
428 | 2487 * The windows procedure for the window class XEMACS_CLASS |
2488 */ | |
2489 LRESULT WINAPI | |
442 | 2490 mswindows_wnd_proc (HWND hwnd, UINT message_, WPARAM wParam, LPARAM lParam) |
428 | 2491 { |
1204 | 2492 /* Note: Remember to initialize emacs_event and event before use. This |
2493 code calls code that can GC. You must GCPRO before calling such | |
2494 code. */ | |
428 | 2495 Lisp_Object emacs_event = Qnil; |
2496 Lisp_Object fobj = Qnil; | |
2497 | |
440 | 2498 Lisp_Event *event; |
428 | 2499 struct frame *frame; |
647 | 2500 struct mswindows_frame *msframe; |
428 | 2501 |
3092 | 2502 #ifndef NEW_GC |
611 | 2503 /* If you hit this, rewrite the offending API call to occur after GC, |
2504 using register_post_gc_action(). */ | |
2505 assert (!gc_in_progress); | |
3263 | 2506 #endif /* not NEW_GC */ |
593 | 2507 |
2508 #ifdef DEBUG_XEMACS | |
2509 if (debug_mswindows_events) | |
2510 debug_output_mswin_message (hwnd, message_, wParam, lParam); | |
2511 #endif /* DEBUG_XEMACS */ | |
442 | 2512 |
771 | 2513 assert (!qxeGetWindowLong (hwnd, GWL_USERDATA)); |
442 | 2514 switch (message_) |
428 | 2515 { |
442 | 2516 case WM_DESTROYCLIPBOARD: |
771 | 2517 mswindows_handle_destroyclipboard (); |
442 | 2518 break; |
2519 | |
2520 case WM_ERASEBKGND: | |
2521 /* Erase background only during non-dynamic sizing */ | |
771 | 2522 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd))); |
442 | 2523 if (msframe->sizing && !mswindows_dynamic_frame_resize) |
2524 goto defproc; | |
2525 return 1; | |
2526 | |
2527 case WM_CLOSE: | |
2528 fobj = mswindows_find_frame (hwnd); | |
853 | 2529 mswindows_enqueue_misc_user_event (fobj, Qeval, list3 (Qdelete_frame, fobj, |
2530 Qt)); | |
440 | 2531 break; |
428 | 2532 |
442 | 2533 case WM_KEYUP: |
2534 case WM_SYSKEYUP: | |
2535 | |
2536 /* See Win95 comment under WM_KEYDOWN */ | |
2537 { | |
2538 BYTE keymap[256]; | |
2539 int should_set_keymap = 0; | |
2540 | |
2541 #ifdef DEBUG_XEMACS | |
593 | 2542 if (debug_mswindows_events > 2) |
2543 output_alt_keyboard_state (); | |
442 | 2544 #endif /* DEBUG_XEMACS */ |
2545 | |
2546 mswindows_handle_sticky_modifiers (wParam, lParam, 0, 1); | |
2547 if (wParam == VK_CONTROL) | |
2548 { | |
2549 GetKeyboardState (keymap); | |
2550 keymap [(lParam & 0x1000000) ? VK_RCONTROL : VK_LCONTROL] &= ~0x80; | |
2551 should_set_keymap = 1; | |
2552 } | |
2553 else if (wParam == VK_MENU) | |
2554 { | |
2555 GetKeyboardState (keymap); | |
2556 keymap [(lParam & 0x1000000) ? VK_RMENU : VK_LMENU] &= ~0x80; | |
2557 should_set_keymap = 1; | |
2558 } | |
2559 | |
2560 if (should_set_keymap) | |
1242 | 2561 /* && (message_ != WM_SYSKEYUP */ |
2562 /* || NILP (Vmenu_accelerator_enabled))) */ | |
428 | 2563 SetKeyboardState (keymap); |
2564 | |
2565 } | |
442 | 2566 |
2567 if (key_needs_default_processing_p (wParam)) | |
2568 goto defproc; | |
2569 else | |
2570 break; | |
2571 | |
2572 case WM_KEYDOWN: | |
2573 case WM_SYSKEYDOWN: | |
2574 | |
2575 /* In some locales the right-hand Alt key is labelled AltGr. This key | |
2576 * should produce alternative characters when combined with another key. | |
2577 * eg on a German keyboard pressing AltGr+q should produce '@'. | |
2578 * AltGr generates exactly the same keystrokes as LCtrl+RAlt. But if | |
2579 * TranslateMessage() is called with *any* combination of Ctrl+Alt down, | |
2580 * it translates as if AltGr were down. | |
2581 * We get round this by removing all modifiers from the keymap before | |
2582 * calling TranslateMessage() unless AltGr is *really* down. */ | |
428 | 2583 { |
442 | 2584 BYTE keymap_trans[256]; |
2585 BYTE keymap_orig[256]; | |
2586 BYTE keymap_sticky[256]; | |
771 | 2587 /* WARNING: XEmacs code paths are far more subtle than you |
2588 think. In particular, QUIT checking will query and remove | |
2589 events, including keyboard events, from the queue. (QUIT is | |
2590 definitely invoked from TO_INTERNAL_FORMAT().) If we do | |
2591 this recursively anywhere in the following code, it will | |
2592 mess certain things up -- in particular, the OS-provided | |
2593 sticky modifier code available as part of the accessibility | |
2594 package. | |
2595 | |
2596 (Academic question: If QUIT checking is supposed to be | |
2597 triggered only every 1/4 second, why is it getting | |
2598 consistently triggered here? I saw the problem | |
2599 consistently. Answer: It appears that, currently, | |
2600 sometimes the code to pump messages is wrapped with | |
2601 begin_dont_check_for_quit() and sometimes it isn't. (#### | |
2602 FIX THIS SHIT!) cmdloop.c, for example, has it, but not | |
2603 everywhere. The current games with avoiding QUIT mean that | |
2604 the 1/4-second timer consistently fires while | |
2605 dont_check_for_quit is set [which causes the quit check to | |
2606 get deferred but the flag is still on], and so the next | |
2607 time it's unset and we call QUIT is *right here*. | |
2608 | |
2609 In my stderr-proc ws I majorly cleaned up the whole shit by | |
2610 just wrapping all the entry points in dont_check_for_quit. | |
2611 This fixed the remaining bugs with C-g getting interpreted | |
2612 wrong.) | |
2613 | |
2614 #### We should probably wrap this whole function in | |
2615 begin_dont_check_for_quit(); but then we should set this | |
2616 back to 0 when handling a menu callback, which gets invoked | |
2617 from within this function, specifically from | |
2618 DefWindowProc(). (We already do the latter in my new | |
2619 stderr-proc ws, because in that ws next_event_internal() | |
2620 calls begin_dont_check_for_quit(). */ | |
2621 | |
2622 int count = begin_dont_check_for_quit (); | |
442 | 2623 int has_AltGr = mswindows_current_layout_has_AltGr (); |
502 | 2624 int mods = 0, mods_with_shift = 0; |
442 | 2625 int extendedp = lParam & 0x1000000; |
2626 Lisp_Object keysym; | |
2627 int sticky_changed; | |
2628 | |
2629 #ifdef DEBUG_XEMACS | |
593 | 2630 if (debug_mswindows_events > 2) |
2631 output_alt_keyboard_state (); | |
442 | 2632 #endif /* DEBUG_XEMACS */ |
2633 | |
2634 GetKeyboardState (keymap_orig); | |
2635 frame = XFRAME (mswindows_find_frame (hwnd)); | |
2636 if ((sticky_changed = | |
2637 mswindows_handle_sticky_modifiers (wParam, lParam, 1, 1))) | |
428 | 2638 { |
442 | 2639 GetKeyboardState (keymap_sticky); |
2640 if (keymap_sticky[VK_MENU] & 0x80) | |
2641 { | |
2642 message_ = WM_SYSKEYDOWN; | |
2643 /* We have to set the "context bit" so that the | |
2644 TranslateMessage() call below that generates the | |
2645 SYSCHAR message does its thing; see the documentation | |
2646 on WM_SYSKEYDOWN */ | |
2647 lParam |= 1 << 29; | |
2648 } | |
428 | 2649 } |
2650 else | |
442 | 2651 memcpy (keymap_sticky, keymap_orig, 256); |
2652 | |
2653 mods = mswindows_modifier_state (keymap_sticky, (DWORD) -1, has_AltGr); | |
502 | 2654 mods_with_shift = mods; |
442 | 2655 |
2656 /* Handle non-printables */ | |
2657 if (!NILP (keysym = mswindows_key_to_emacs_keysym (wParam, mods, | |
2658 extendedp))) | |
428 | 2659 { |
442 | 2660 mswindows_enqueue_keypress_event (hwnd, keysym, mods); |
2661 if (sticky_changed) | |
2662 SetKeyboardState (keymap_orig); | |
428 | 2663 } |
442 | 2664 else /* Normal keys & modifiers */ |
428 | 2665 { |
442 | 2666 POINT pnt = { LOWORD (GetMessagePos()), HIWORD (GetMessagePos()) }; |
2667 MSG msg, tranmsg; | |
1204 | 2668 #ifdef HAVE_MENUBARS |
442 | 2669 int potential_accelerator = 0; |
1204 | 2670 #endif |
442 | 2671 int got_accelerator = 0; |
771 | 2672 /* No need to gcpro because the event is already on a |
2673 queue when we retrieve it. */ | |
2674 Lisp_Object lastev = Qnil; | |
442 | 2675 |
2676 msg.hwnd = hwnd; | |
2677 msg.message = message_; | |
2678 msg.wParam = wParam; | |
2679 msg.lParam = lParam; | |
2680 msg.time = GetMessageTime(); | |
2681 msg.pt = pnt; | |
2682 | |
2683 /* GetKeyboardState() does not work as documented on Win95. We have | |
2684 * to loosely track Left and Right modifiers on behalf of the OS, | |
2685 * without screwing up Windows NT which tracks them properly. */ | |
2686 if (wParam == VK_CONTROL) | |
2687 { | |
2688 keymap_orig[extendedp ? VK_RCONTROL : VK_LCONTROL] |= 0x80; | |
2689 keymap_sticky[extendedp ? VK_RCONTROL : VK_LCONTROL] |= 0x80; | |
2690 } | |
2691 else if (wParam == VK_MENU) | |
2692 { | |
2693 keymap_orig[extendedp ? VK_RMENU : VK_LMENU] |= 0x80; | |
2694 keymap_sticky[extendedp ? VK_RMENU : VK_LMENU] |= 0x80; | |
2695 } | |
2696 | |
827 | 2697 #ifdef HAVE_MENUBARS |
442 | 2698 if (!NILP (Vmenu_accelerator_enabled) && |
2699 !(mods & XEMACS_MOD_SHIFT) && message_ == WM_SYSKEYDOWN) | |
2700 potential_accelerator = 1; | |
827 | 2701 #endif |
442 | 2702 |
2703 /* Remove shift modifier from an ascii character */ | |
2704 mods &= ~XEMACS_MOD_SHIFT; | |
2705 | |
2706 memcpy (keymap_trans, keymap_sticky, 256); | |
2707 | |
2708 /* Clear control and alt modifiers unless AltGr is pressed */ | |
2709 keymap_trans[VK_RCONTROL] = 0; | |
2710 keymap_trans[VK_LMENU] = 0; | |
2711 if (!has_AltGr || !(keymap_trans[VK_LCONTROL] & 0x80) | |
2712 || !(keymap_trans[VK_RMENU] & 0x80)) | |
2713 { | |
2714 keymap_trans[VK_LCONTROL] = 0; | |
2715 keymap_trans[VK_CONTROL] = 0; | |
2716 keymap_trans[VK_RMENU] = 0; | |
2717 keymap_trans[VK_MENU] = 0; | |
2718 } | |
2719 SetKeyboardState (keymap_trans); | |
2720 | |
2721 /* Maybe generate some WM_[SYS]CHARs in the queue */ | |
2722 TranslateMessage (&msg); | |
2723 | |
771 | 2724 while (qxePeekMessage (&tranmsg, hwnd, WM_CHAR, WM_CHAR, PM_REMOVE) |
2725 || qxePeekMessage (&tranmsg, hwnd, WM_SYSCHAR, WM_SYSCHAR, | |
2726 PM_REMOVE)) | |
442 | 2727 { |
502 | 2728 int mods_with_quit = mods; |
771 | 2729 int length; |
2730 Extbyte extchar[4]; | |
867 | 2731 Ibyte *intchar; |
2732 Ichar ch; | |
771 | 2733 |
2734 if (XEUNICODE_P) | |
2735 { | |
2736 length = unicode_char_to_text (tranmsg.wParam, extchar); | |
2737 TO_INTERNAL_FORMAT (DATA, (extchar, length), | |
2738 C_STRING_ALLOCA, (intchar), | |
2739 Qmswindows_unicode); | |
867 | 2740 ch = itext_ichar (intchar); |
771 | 2741 } |
2742 else | |
2743 { | |
2744 length = ansi_char_to_text (tranmsg.wParam, extchar); | |
2745 intchar = (convert_multibyte_to_internal_malloc | |
2746 (extchar, length, | |
2747 mswindows_locale_to_code_page | |
2748 /* See intl-win32.c for an explanation of | |
2749 the following */ | |
2750 ((LCID) GetKeyboardLayout (0) & 0xFFFF), | |
2751 NULL)); | |
867 | 2752 ch = itext_ichar (intchar); |
1726 | 2753 xfree (intchar, Ibyte *); |
771 | 2754 } |
442 | 2755 |
593 | 2756 #ifdef DEBUG_XEMACS |
2757 if (debug_mswindows_events) | |
2758 { | |
2759 stderr_out ("-> "); | |
2760 debug_output_mswin_message (tranmsg.hwnd, tranmsg.message, | |
2761 tranmsg.wParam, | |
2762 tranmsg.lParam); | |
2763 } | |
2764 #endif /* DEBUG_XEMACS */ | |
2765 | |
827 | 2766 #ifdef HAVE_MENUBARS |
1204 | 2767 if (potential_accelerator && !got_accelerator && |
2768 mswindows_char_is_accelerator (frame, ch)) | |
442 | 2769 { |
2770 got_accelerator = 1; | |
2771 break; | |
2772 } | |
827 | 2773 #endif /* HAVE_MENUBARS */ |
2774 | |
771 | 2775 lastev = mswindows_enqueue_keypress_event (hwnd, |
2776 make_char (ch), | |
2777 mods_with_quit); | |
442 | 2778 } /* while */ |
2779 | |
771 | 2780 /* Also figure out what the character would be in other |
2781 possible keyboard layouts, in this order: | |
2782 | |
2783 -- current language environment | |
2784 -- user default language environment | |
2785 -- system default language environment | |
2786 -- same three, but checking the underlying virtual key, | |
2787 and only paying attention if it's alphabetic | |
2788 -- US ASCII | |
2789 | |
2790 See events.h, struct key_data, for why we do this. | |
2791 */ | |
2792 | |
2793 if (!NILP (lastev)) | |
2794 { | |
2795 int i; | |
2796 int scan = (lParam >> 16) && 0xFF; | |
2797 | |
2798 for (i = 0; i < KEYCHAR_LAST; i++) | |
2799 { | |
2800 int vk_only = 0; | |
2801 LCID lcid; | |
2802 int virtual_key; | |
2803 | |
2804 switch (i) | |
2805 { | |
2806 case KEYCHAR_UNDERLYING_VIRTUAL_KEY_CURRENT_LANGENV: | |
2807 vk_only = 1; | |
2808 case KEYCHAR_CURRENT_LANGENV: | |
2809 lcid = mswindows_current_locale (); | |
2810 break; | |
2811 | |
2812 case KEYCHAR_UNDERLYING_VIRTUAL_KEY_DEFAULT_USER: | |
2813 vk_only = 1; | |
2814 case KEYCHAR_DEFAULT_USER: | |
2815 lcid = GetUserDefaultLCID (); | |
2816 break; | |
2817 | |
2818 case KEYCHAR_UNDERLYING_VIRTUAL_KEY_DEFAULT_SYSTEM: | |
2819 vk_only = 1; | |
2820 case KEYCHAR_DEFAULT_SYSTEM: | |
2821 lcid = GetSystemDefaultLCID (); | |
2822 break; | |
2823 | |
2824 case KEYCHAR_QWERTY: | |
2825 lcid = MAKELANGID (LANG_ENGLISH, SUBLANG_ENGLISH_US); | |
2826 break; | |
2827 | |
2500 | 2828 default: ABORT (); lcid = 0; |
771 | 2829 } |
2830 | |
2831 /* VERY CONFUSING! See intl-win32.c. */ | |
2832 lcid = lcid & 0xFFFF; | |
2833 | |
800 | 2834 virtual_key = qxeMapVirtualKeyEx (scan, 1, (HKL) lcid); |
771 | 2835 if (!vk_only) |
2836 { | |
2837 if (XEUNICODE_P) | |
2838 { | |
2839 Extbyte received_keys[32]; | |
2840 int tounret = | |
2841 ToUnicodeEx | |
2842 (virtual_key, scan, keymap_trans, | |
2843 (LPWSTR) received_keys, | |
2844 sizeof (received_keys) / XETCHAR_SIZE, | |
2845 0, /* #### what about this flag? "if | |
2846 bit 0 is set, a menu is | |
2847 active???" */ | |
2848 (HKL) lcid); | |
2849 if (tounret > 0) | |
2850 { | |
867 | 2851 Ibyte *intchar; |
771 | 2852 |
2853 TO_INTERNAL_FORMAT | |
2854 (DATA, | |
2855 (received_keys + (tounret - 1) * 2, 2), | |
2856 C_STRING_ALLOCA, intchar, | |
2857 Qmswindows_unicode); | |
1204 | 2858 XSET_EVENT_KEY_ALT_KEYCHARS |
2859 (lastev, i, itext_ichar (intchar)); | |
771 | 2860 } |
2861 } | |
2862 else | |
2863 { | |
2864 WORD received_keys[32]; | |
2865 int tounret = | |
2866 ToAsciiEx (virtual_key, scan, keymap_trans, | |
2867 received_keys, | |
2868 0, /* #### what about this | |
2869 flag? "if bit 0 is set, a | |
2870 menu is active???" */ | |
2871 (HKL) lcid); | |
2872 if (tounret > 0) | |
2873 { | |
2874 /* #### I cannot find proper | |
2875 documentation on what format the | |
2876 return value is in. I'm assuming | |
2877 it's like WM_IME_CHAR: DBCS chars | |
2878 have the lead byte in bits 8-15 of | |
2879 the short. */ | |
867 | 2880 Ibyte *intchar; |
771 | 2881 Extbyte mbstuff[2]; |
2882 Bytecount mblength = 0; | |
2883 WORD thechar = received_keys[tounret - 1]; | |
2884 | |
2885 mbstuff[mblength++] = | |
2886 (Extbyte) (thechar & 0xFF); | |
2887 if (thechar > 0xFF) | |
2888 mbstuff[mblength++] = | |
2889 (Extbyte) ((thechar >> 8) & 0xFF); | |
2890 | |
2891 intchar = convert_multibyte_to_internal_malloc | |
2892 (mbstuff, mblength, | |
2893 mswindows_locale_to_code_page (lcid), | |
2894 NULL); | |
2895 | |
1204 | 2896 XSET_EVENT_KEY_ALT_KEYCHARS |
2897 (lastev, i, itext_ichar (intchar)); | |
1726 | 2898 xfree (intchar, Ibyte *); |
771 | 2899 } |
2900 } | |
2901 } | |
2902 else | |
2903 { | |
867 | 2904 Ichar altch; |
771 | 2905 |
2906 if (virtual_key >= 'A' && virtual_key <= 'Z') | |
2907 altch = | |
2908 virtual_key + (mods_with_shift & XEMACS_MOD_SHIFT ? | |
2909 'a' - 'A' : 0); | |
2910 else | |
2911 altch = 0; | |
2912 | |
1204 | 2913 XSET_EVENT_KEY_ALT_KEYCHARS (lastev, i, altch); |
771 | 2914 } |
2915 } | |
2916 } | |
2917 | |
442 | 2918 /* This generates WM_SYSCHAR messages, which are interpreted |
2919 by DefWindowProc as the menu selections. */ | |
2920 if (got_accelerator) | |
2921 { | |
2922 SetKeyboardState (keymap_sticky); | |
2923 TranslateMessage (&msg); | |
2924 SetKeyboardState (keymap_orig); | |
771 | 2925 unbind_to (count); |
442 | 2926 goto defproc; |
2927 } | |
2928 | |
2929 SetKeyboardState (keymap_orig); | |
2930 } /* else */ | |
771 | 2931 |
2932 if (key_needs_default_processing_p (wParam)) | |
2933 { | |
2934 unbind_to (count); | |
2935 goto defproc; | |
2936 } | |
2937 else | |
2938 { | |
2939 unbind_to (count); | |
2940 break; | |
2941 } | |
428 | 2942 } |
442 | 2943 |
2944 case WM_MBUTTONDOWN: | |
2945 case WM_MBUTTONUP: | |
2946 /* Real middle mouse button has nothing to do with emulated one: | |
2947 if one wants to exercise fingers playing chords on the mouse, | |
2948 he is allowed to do that! */ | |
2949 mswindows_enqueue_mouse_button_event (hwnd, message_, | |
2367 | 2950 XE_MAKEPOINTS (lParam), |
442 | 2951 wParam &~ MK_MBUTTON, |
2952 GetMessageTime()); | |
2953 break; | |
2954 | |
2955 case WM_LBUTTONUP: | |
771 | 2956 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd))); |
2957 msframe->last_click_time = GetMessageTime(); | |
442 | 2958 |
2959 KillTimer (hwnd, BUTTON_2_TIMER_ID); | |
2960 msframe->button2_need_lbutton = 0; | |
2961 if (msframe->ignore_next_lbutton_up) | |
2962 { | |
2963 msframe->ignore_next_lbutton_up = 0; | |
2964 } | |
2965 else if (msframe->button2_is_down) | |
2966 { | |
2967 msframe->button2_is_down = 0; | |
2968 msframe->ignore_next_rbutton_up = 1; | |
2969 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONUP, | |
2367 | 2970 XE_MAKEPOINTS (lParam), |
442 | 2971 wParam |
2972 &~ (MK_LBUTTON | MK_MBUTTON | |
2973 | MK_RBUTTON), | |
2974 GetMessageTime()); | |
2975 } | |
2976 else | |
2977 { | |
2978 if (msframe->button2_need_rbutton) | |
2979 { | |
2980 msframe->button2_need_rbutton = 0; | |
2981 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN, | |
2367 | 2982 XE_MAKEPOINTS (lParam), |
442 | 2983 wParam &~ MK_LBUTTON, |
2984 GetMessageTime()); | |
2985 } | |
2986 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONUP, | |
2367 | 2987 XE_MAKEPOINTS (lParam), |
442 | 2988 wParam &~ MK_LBUTTON, |
2989 GetMessageTime()); | |
2990 } | |
2991 break; | |
2992 | |
2993 case WM_RBUTTONUP: | |
771 | 2994 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd))); |
2995 msframe->last_click_time = GetMessageTime(); | |
442 | 2996 |
2997 KillTimer (hwnd, BUTTON_2_TIMER_ID); | |
2998 msframe->button2_need_rbutton = 0; | |
2999 if (msframe->ignore_next_rbutton_up) | |
3000 { | |
3001 msframe->ignore_next_rbutton_up = 0; | |
3002 } | |
3003 else if (msframe->button2_is_down) | |
3004 { | |
3005 msframe->button2_is_down = 0; | |
3006 msframe->ignore_next_lbutton_up = 1; | |
3007 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONUP, | |
2367 | 3008 XE_MAKEPOINTS (lParam), |
442 | 3009 wParam |
3010 &~ (MK_LBUTTON | MK_MBUTTON | |
3011 | MK_RBUTTON), | |
3012 GetMessageTime()); | |
3013 } | |
3014 else | |
3015 { | |
3016 if (msframe->button2_need_lbutton) | |
3017 { | |
3018 msframe->button2_need_lbutton = 0; | |
3019 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN, | |
2367 | 3020 XE_MAKEPOINTS (lParam), |
442 | 3021 wParam &~ MK_RBUTTON, |
3022 GetMessageTime()); | |
3023 } | |
3024 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONUP, | |
2367 | 3025 XE_MAKEPOINTS (lParam), |
442 | 3026 wParam &~ MK_RBUTTON, |
3027 GetMessageTime()); | |
3028 } | |
3029 break; | |
3030 | |
3031 case WM_LBUTTONDOWN: | |
771 | 3032 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd))); |
442 | 3033 |
3034 if (msframe->button2_need_lbutton) | |
428 | 3035 { |
3036 KillTimer (hwnd, BUTTON_2_TIMER_ID); | |
442 | 3037 msframe->button2_need_lbutton = 0; |
3038 msframe->button2_need_rbutton = 0; | |
3039 if (mswindows_button2_near_enough (msframe->last_click_point, | |
2367 | 3040 XE_MAKEPOINTS (lParam))) |
428 | 3041 { |
442 | 3042 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONDOWN, |
2367 | 3043 XE_MAKEPOINTS (lParam), |
442 | 3044 wParam |
3045 &~ (MK_LBUTTON | MK_MBUTTON | |
3046 | MK_RBUTTON), | |
3047 GetMessageTime()); | |
3048 msframe->button2_is_down = 1; | |
428 | 3049 } |
442 | 3050 else |
428 | 3051 { |
442 | 3052 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN, |
3053 msframe->last_click_point, | |
3054 msframe->last_click_mods | |
3055 &~ MK_RBUTTON, | |
3056 msframe->last_click_time); | |
3057 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN, | |
2367 | 3058 XE_MAKEPOINTS (lParam), |
442 | 3059 wParam &~ MK_LBUTTON, |
3060 GetMessageTime()); | |
428 | 3061 } |
3062 } | |
3063 else | |
442 | 3064 { |
3065 mswindows_set_chord_timer (hwnd); | |
3066 msframe->button2_need_rbutton = 1; | |
2367 | 3067 msframe->last_click_point = XE_MAKEPOINTS (lParam); |
442 | 3068 msframe->last_click_mods = wParam; |
3069 } | |
771 | 3070 msframe->last_click_time = GetMessageTime(); |
442 | 3071 break; |
3072 | |
3073 case WM_RBUTTONDOWN: | |
771 | 3074 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd))); |
442 | 3075 |
3076 if (msframe->button2_need_rbutton) | |
428 | 3077 { |
442 | 3078 KillTimer (hwnd, BUTTON_2_TIMER_ID); |
3079 msframe->button2_need_lbutton = 0; | |
3080 msframe->button2_need_rbutton = 0; | |
3081 if (mswindows_button2_near_enough (msframe->last_click_point, | |
2367 | 3082 XE_MAKEPOINTS (lParam))) |
442 | 3083 { |
3084 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONDOWN, | |
2367 | 3085 XE_MAKEPOINTS (lParam), |
442 | 3086 wParam |
3087 &~ (MK_LBUTTON | MK_MBUTTON | |
3088 | MK_RBUTTON), | |
3089 GetMessageTime()); | |
3090 msframe->button2_is_down = 1; | |
3091 } | |
3092 else | |
3093 { | |
3094 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN, | |
3095 msframe->last_click_point, | |
3096 msframe->last_click_mods | |
3097 &~ MK_LBUTTON, | |
3098 msframe->last_click_time); | |
3099 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN, | |
2367 | 3100 XE_MAKEPOINTS (lParam), |
442 | 3101 wParam &~ MK_RBUTTON, |
3102 GetMessageTime()); | |
3103 } | |
428 | 3104 } |
3105 else | |
3106 { | |
442 | 3107 mswindows_set_chord_timer (hwnd); |
3108 msframe->button2_need_lbutton = 1; | |
2367 | 3109 msframe->last_click_point = XE_MAKEPOINTS (lParam); |
442 | 3110 msframe->last_click_mods = wParam; |
3111 } | |
771 | 3112 msframe->last_click_time = GetMessageTime(); |
442 | 3113 break; |
3114 | |
3115 case WM_TIMER: | |
3116 if (wParam == BUTTON_2_TIMER_ID) | |
3117 { | |
771 | 3118 msframe = |
3119 FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd))); | |
442 | 3120 KillTimer (hwnd, BUTTON_2_TIMER_ID); |
3121 | |
3122 if (msframe->button2_need_lbutton) | |
3123 { | |
3124 msframe->button2_need_lbutton = 0; | |
3125 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN, | |
3126 msframe->last_click_point, | |
3127 msframe->last_click_mods | |
3128 &~ MK_RBUTTON, | |
3129 msframe->last_click_time); | |
3130 } | |
3131 else if (msframe->button2_need_rbutton) | |
3132 { | |
3133 msframe->button2_need_rbutton = 0; | |
3134 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN, | |
3135 msframe->last_click_point, | |
3136 msframe->last_click_mods | |
3137 &~ MK_LBUTTON, | |
3138 msframe->last_click_time); | |
3139 } | |
3140 } | |
3141 else | |
3142 assert ("Spurious timer fired" == 0); | |
3143 break; | |
3144 | |
3145 case WM_MOUSEMOVE: | |
3146 /* Optimization: don't report mouse movement while size is changing */ | |
771 | 3147 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd))); |
442 | 3148 if (!msframe->sizing) |
3149 { | |
3150 /* When waiting for the second mouse button to finish | |
3151 button2 emulation, and have moved too far, just pretend | |
3152 as if timer has expired. This improves drag-select feedback */ | |
3153 if ((msframe->button2_need_lbutton || msframe->button2_need_rbutton) | |
3154 && !mswindows_button2_near_enough (msframe->last_click_point, | |
2367 | 3155 XE_MAKEPOINTS (lParam))) |
428 | 3156 { |
442 | 3157 KillTimer (hwnd, BUTTON_2_TIMER_ID); |
771 | 3158 qxeSendMessage (hwnd, WM_TIMER, BUTTON_2_TIMER_ID, 0); |
442 | 3159 } |
3160 | |
3161 emacs_event = Fmake_event (Qnil, Qnil); | |
3162 event = XEVENT(emacs_event); | |
3163 | |
964 | 3164 XSET_EVENT_CHANNEL (emacs_event, mswindows_find_frame(hwnd)); |
3165 XSET_EVENT_TIMESTAMP (emacs_event, GetMessageTime()); | |
3166 XSET_EVENT_TYPE (emacs_event, pointer_motion_event); | |
2367 | 3167 XSET_EVENT_MOTION_X (emacs_event, XE_MAKEPOINTS (lParam).x); |
3168 XSET_EVENT_MOTION_Y (emacs_event, XE_MAKEPOINTS (lParam).y); | |
1204 | 3169 XSET_EVENT_MOTION_MODIFIERS (emacs_event, |
964 | 3170 mswindows_modifier_state (NULL, wParam, 0)); |
442 | 3171 |
3172 mswindows_enqueue_dispatch_event (emacs_event); | |
3173 } | |
3174 break; | |
3175 | |
3176 case WM_CANCELMODE: | |
3177 ReleaseCapture (); | |
3178 /* Queue a `cancel-mode-internal' misc user event, so mouse | |
3179 selection would be canceled if any */ | |
3180 mswindows_enqueue_misc_user_event (mswindows_find_frame (hwnd), | |
3181 Qcancel_mode_internal, Qnil); | |
3182 break; | |
3183 | |
3184 case WM_NOTIFY: | |
3185 { | |
647 | 3186 LPNMHDR nmhdr = (LPNMHDR) lParam; |
3187 | |
1111 | 3188 if (nmhdr->code == TTN_NEEDTEXT) |
442 | 3189 { |
3190 #ifdef HAVE_TOOLBARS | |
771 | 3191 LPTOOLTIPTEXTW tttextw = (LPTOOLTIPTEXTW) lParam; |
442 | 3192 Lisp_Object btext; |
771 | 3193 Extbyte *btextext = 0; |
442 | 3194 |
3195 /* find out which toolbar */ | |
3196 frame = XFRAME (mswindows_find_frame (hwnd)); | |
647 | 3197 btext = mswindows_get_toolbar_button_text (frame, nmhdr->idFrom); |
442 | 3198 |
771 | 3199 tttextw->hinst = NULL; |
3200 | |
3201 if (!NILP (btext)) | |
3202 LISP_STRING_TO_TSTR (btext, btextext); | |
3203 | |
3204 if (btextext) | |
442 | 3205 { |
771 | 3206 /* WARNING: We can't just write a '\0' into the 79th |
3207 "character" because tttextw->szText is in WCHAR's but we | |
3208 may be copying an ANSI string into it. Easiest to just | |
3209 zero the whole thing. */ | |
3210 xzero (*tttextw->szText); | |
2421 | 3211 qxetcsncpy ((Extbyte *) tttextw->szText, btextext, 79); |
442 | 3212 } |
771 | 3213 else |
3214 tttextw->lpszText = NULL; | |
442 | 3215 #endif |
3216 } | |
3217 /* handle tree view callbacks */ | |
1111 | 3218 else if (nmhdr->code == TVN_SELCHANGED) |
442 | 3219 { |
647 | 3220 NM_TREEVIEW *ptree = (NM_TREEVIEW *) lParam; |
442 | 3221 frame = XFRAME (mswindows_find_frame (hwnd)); |
3222 mswindows_handle_gui_wm_command (frame, 0, ptree->itemNew.lParam); | |
3223 } | |
3224 /* handle tab control callbacks */ | |
1111 | 3225 else if (nmhdr->code == TCN_SELCHANGE) |
442 | 3226 { |
3227 TC_ITEM item; | |
771 | 3228 int idx = qxeSendMessage (nmhdr->hwndFrom, TCM_GETCURSEL, 0, 0); |
442 | 3229 frame = XFRAME (mswindows_find_frame (hwnd)); |
3230 | |
3231 item.mask = TCIF_PARAM; | |
771 | 3232 qxeSendMessage (nmhdr->hwndFrom, TCM_GETITEM, (WPARAM) idx, |
3233 (LPARAM) &item); | |
442 | 3234 |
3235 mswindows_handle_gui_wm_command (frame, 0, item.lParam); | |
3236 } | |
3237 } | |
3238 break; | |
3239 | |
3240 case WM_PAINT: | |
3241 /* hdc will be NULL unless this is a subwindow - in which case we | |
3242 shouldn't have received a paint message for it here. */ | |
3243 assert (wParam == 0); | |
3244 | |
3245 /* Can't queue a magic event because windows goes modal and sends paint | |
3246 messages directly to the windows procedure when doing solid drags | |
3247 and the message queue doesn't get processed. */ | |
3248 mswindows_handle_paint (XFRAME (mswindows_find_frame (hwnd))); | |
3249 break; | |
3250 | |
903 | 3251 case WM_ACTIVATE: |
3252 { | |
3253 /* | |
3254 * If we receive a WM_ACTIVATE message that indicates that our frame | |
3255 * is being activated, make sure that the frame is marked visible | |
3256 * if the window itself is visible. This seems to fix the problem | |
3257 * where XEmacs appears to lock-up after switching desktops with | |
3258 * some virtual window managers. | |
3259 */ | |
3260 int state = (int)(short) LOWORD(wParam); | |
3261 #ifdef DEBUG_XEMACS | |
3262 if (debug_mswindows_events) | |
3263 stderr_out("state = %d\n", state); | |
3264 #endif /* DEBUG_XEMACS */ | |
3265 if (state == WA_ACTIVE || state == WA_CLICKACTIVE) | |
3266 { | |
3267 #ifdef DEBUG_XEMACS | |
3268 if (debug_mswindows_events) | |
3269 stderr_out(" activating\n"); | |
3270 #endif /* DEBUG_XEMACS */ | |
3271 | |
3272 fobj = mswindows_find_frame (hwnd); | |
3273 frame = XFRAME (fobj); | |
3274 if (IsWindowVisible (hwnd)) | |
3275 { | |
3276 #ifdef DEBUG_XEMACS | |
3277 if (debug_mswindows_events) | |
3278 stderr_out(" window is visible\n"); | |
3279 #endif /* DEBUG_XEMACS */ | |
3280 if (!FRAME_VISIBLE_P (frame)) | |
3281 { | |
3282 #ifdef DEBUG_XEMACS | |
3283 if (debug_mswindows_events) | |
3284 stderr_out(" frame is not visible\n"); | |
3285 #endif /* DEBUG_XEMACS */ | |
3286 /* | |
3287 * It seems that we have to enqueue the XM_MAPFRAME event | |
3288 * prior to setting the frame visible so that | |
3289 * suspend-or-iconify-emacs works properly. | |
3290 */ | |
3291 mswindows_enqueue_magic_event (hwnd, XM_MAPFRAME); | |
3292 FRAME_VISIBLE_P (frame) = 1; | |
3293 FRAME_ICONIFIED_P (frame) = 0; | |
3294 } | |
3295 #ifdef DEBUG_XEMACS | |
3296 else | |
3297 { | |
3298 if (debug_mswindows_events) | |
3299 stderr_out(" frame is visible\n"); | |
3300 } | |
3301 #endif /* DEBUG_XEMACS */ | |
3302 } | |
3303 #ifdef DEBUG_XEMACS | |
3304 else | |
3305 { | |
3306 if (debug_mswindows_events) | |
3307 stderr_out(" window is not visible\n"); | |
3308 } | |
3309 #endif /* DEBUG_XEMACS */ | |
3310 } | |
3311 return qxeDefWindowProc (hwnd, message_, wParam, lParam); | |
3312 } | |
3313 break; | |
3314 | |
593 | 3315 case WM_WINDOWPOSCHANGED: |
3316 /* This is sent before WM_SIZE; in fact, the processing of this | |
3317 by DefWindowProc() sends WM_SIZE. But WM_SIZE is not sent when | |
3318 a window is hidden (make-frame-invisible), so we need to process | |
3319 this and update the state flags. */ | |
3320 { | |
3321 fobj = mswindows_find_frame (hwnd); | |
3322 frame = XFRAME (fobj); | |
3323 if (IsIconic (hwnd)) | |
3324 { | |
3325 FRAME_VISIBLE_P (frame) = 0; | |
3326 FRAME_ICONIFIED_P (frame) = 1; | |
3327 } | |
3328 else if (IsWindowVisible (hwnd)) | |
3329 { | |
707 | 3330 /* APA: It's too early here to set the frame visible. |
3331 * Let's do this later, in WM_SIZE processing, after the | |
3332 * magic XM_MAPFRAME event has been sent (just like 21.1 | |
3333 * did). */ | |
3334 /* FRAME_VISIBLE_P (frame) = 1; */ | |
593 | 3335 FRAME_ICONIFIED_P (frame) = 0; |
3336 } | |
3337 else | |
3338 { | |
3339 FRAME_VISIBLE_P (frame) = 0; | |
3340 FRAME_ICONIFIED_P (frame) = 0; | |
3341 } | |
3342 | |
771 | 3343 goto defproc; |
593 | 3344 } |
3345 | |
731 | 3346 case WM_SHOWWINDOW: |
3347 /* | |
3348 The WM_SHOWWINDOW message is sent to a window when the window | |
3349 is about to be hidden or shown. | |
3350 APA: This message is also sent when switching to a virtual | |
3351 desktop under the virtuawin virtual window manager. | |
3352 | |
3353 */ | |
3354 { | |
3355 fobj = mswindows_find_frame (hwnd); | |
3356 frame = XFRAME (fobj); | |
3357 if (wParam == TRUE) | |
3358 { | |
3359 mswindows_enqueue_magic_event (hwnd, XM_MAPFRAME); | |
3360 FRAME_VISIBLE_P (frame) = 1; | |
3361 } | |
3362 else | |
3363 { | |
3364 mswindows_enqueue_magic_event (hwnd, XM_UNMAPFRAME); | |
3365 FRAME_VISIBLE_P (frame) = 0; | |
3366 } | |
3367 } | |
3368 break; | |
3369 | |
442 | 3370 case WM_SIZE: |
3371 /* We only care about this message if our size has really changed */ | |
771 | 3372 if (wParam == SIZE_RESTORED || wParam == SIZE_MAXIMIZED || |
3373 wParam == SIZE_MINIMIZED) | |
442 | 3374 { |
3375 RECT rect; | |
3376 int columns, rows; | |
3377 | |
3378 fobj = mswindows_find_frame (hwnd); | |
3379 frame = XFRAME (fobj); | |
771 | 3380 msframe = FRAME_MSWINDOWS_DATA (frame); |
442 | 3381 |
3382 /* We cannot handle frame map and unmap hooks right in | |
3383 this routine, because these may throw. We queue | |
3384 magic events to run these hooks instead - kkm */ | |
3385 | |
771 | 3386 if (wParam == SIZE_MINIMIZED) |
442 | 3387 { |
3388 /* Iconified */ | |
3389 mswindows_enqueue_magic_event (hwnd, XM_UNMAPFRAME); | |
428 | 3390 } |
3391 else | |
3392 { | |
1279 | 3393 GetClientRect (hwnd, &rect); |
3394 FRAME_PIXWIDTH (frame) = rect.right; | |
3395 FRAME_PIXHEIGHT (frame) = rect.bottom; | |
442 | 3396 |
3397 pixel_to_real_char_size (frame, rect.right, rect.bottom, | |
3398 &FRAME_MSWINDOWS_CHARWIDTH (frame), | |
3399 &FRAME_MSWINDOWS_CHARHEIGHT (frame)); | |
3400 | |
771 | 3401 pixel_to_char_size (frame, rect.right, rect.bottom, &columns, |
3402 &rows); | |
442 | 3403 change_frame_size (frame, rows, columns, 1); |
3404 | |
3405 /* If we are inside frame creation, we have to apply geometric | |
3406 properties now. */ | |
3407 if (FRAME_MSWINDOWS_TARGET_RECT (frame)) | |
3408 { | |
3409 /* Yes, we have to size again */ | |
771 | 3410 mswindows_size_frame_internal (frame, |
3411 FRAME_MSWINDOWS_TARGET_RECT | |
3412 (frame)); | |
3413 /* Reset so we do not get here again. The SetWindowPos | |
3414 * call in mswindows_size_frame_internal can cause | |
3415 * recursion here. */ | |
442 | 3416 if (FRAME_MSWINDOWS_TARGET_RECT (frame)) |
3417 { | |
1726 | 3418 xfree (FRAME_MSWINDOWS_TARGET_RECT (frame), |
3419 XEMACS_RECT_WH *); | |
442 | 3420 FRAME_MSWINDOWS_TARGET_RECT (frame) = 0; |
3421 } | |
3422 } | |
3423 else | |
3424 { | |
903 | 3425 if (!msframe->sizing && !FRAME_VISIBLE_P (frame)) |
3426 { | |
3427 mswindows_enqueue_magic_event (hwnd, XM_MAPFRAME); | |
3428 /* APA: Now that the magic XM_MAPFRAME event has | |
3429 * been sent we can mark the frame as visible (just | |
3430 * like 21.1 did). */ | |
3431 FRAME_VISIBLE_P (frame) = 1; | |
3432 } | |
442 | 3433 |
1279 | 3434 if (frame->init_finished && |
3435 (!msframe->sizing || mswindows_dynamic_frame_resize)) | |
442 | 3436 redisplay (); |
3437 } | |
428 | 3438 } |
3439 } | |
442 | 3440 break; |
3441 | |
3442 case WM_DISPLAYCHANGE: | |
3443 { | |
3444 struct device *d; | |
3445 DWORD message_tick = GetMessageTime (); | |
3446 | |
3447 fobj = mswindows_find_frame (hwnd); | |
3448 frame = XFRAME (fobj); | |
3449 d = XDEVICE (FRAME_DEVICE (frame)); | |
3450 | |
3451 /* Do this only once per message. XEmacs can receive this message | |
3452 through as many frames as it currently has open. Message time | |
3453 will be the same for all these messages. Despite extreme | |
3454 efficiency, the code below has about one in 4 billion | |
3455 probability that the HDC is not recreated, provided that | |
3456 XEmacs is running sufficiently longer than 52 days. */ | |
1279 | 3457 if (DEVICE_MSWINDOWS_UPDATE_TICK (d) != message_tick) |
442 | 3458 { |
1279 | 3459 DEVICE_MSWINDOWS_UPDATE_TICK (d) = message_tick; |
3460 DeleteDC (DEVICE_MSWINDOWS_HCDC (d)); | |
3461 DEVICE_MSWINDOWS_HCDC (d) = CreateCompatibleDC (NULL); | |
442 | 3462 } |
3463 } | |
3464 break; | |
3465 | |
3466 /* Misc magic events which only require that the frame be identified */ | |
3467 case WM_SETFOCUS: | |
3468 case WM_KILLFOCUS: | |
3469 mswindows_enqueue_magic_event (hwnd, message_); | |
3470 break; | |
3471 | |
3472 case WM_WINDOWPOSCHANGING: | |
428 | 3473 { |
442 | 3474 WINDOWPOS *wp = (LPWINDOWPOS) lParam; |
3475 WINDOWPLACEMENT wpl = { sizeof(WINDOWPLACEMENT) }; | |
3476 GetWindowPlacement(hwnd, &wpl); | |
3477 | |
3478 /* Only interested if size is changing and we're not being iconified */ | |
3479 if (wpl.showCmd != SW_SHOWMINIMIZED | |
3480 && wpl.showCmd != SW_SHOWMAXIMIZED | |
3481 && !(wp->flags & SWP_NOSIZE)) | |
428 | 3482 { |
442 | 3483 RECT ncsize = { 0, 0, 0, 0 }; |
3484 int pixwidth, pixheight; | |
771 | 3485 AdjustWindowRectEx (&ncsize, qxeGetWindowLong (hwnd, GWL_STYLE), |
442 | 3486 GetMenu(hwnd) != NULL, |
771 | 3487 qxeGetWindowLong (hwnd, GWL_EXSTYLE)); |
442 | 3488 |
3489 round_size_to_real_char (XFRAME (mswindows_find_frame (hwnd)), | |
3490 wp->cx - (ncsize.right - ncsize.left), | |
3491 wp->cy - (ncsize.bottom - ncsize.top), | |
3492 &pixwidth, &pixheight); | |
3493 | |
3494 /* Convert client sizes to window sizes */ | |
3495 pixwidth += (ncsize.right - ncsize.left); | |
3496 pixheight += (ncsize.bottom - ncsize.top); | |
3497 | |
3498 if (wpl.showCmd != SW_SHOWMAXIMIZED) | |
3499 { | |
3500 /* Adjust so that the bottom or right doesn't move if it's | |
3501 * the top or left that's being changed */ | |
3502 RECT rect; | |
3503 GetWindowRect (hwnd, &rect); | |
3504 | |
3505 if (rect.left != wp->x) | |
3506 wp->x += wp->cx - pixwidth; | |
3507 if (rect.top != wp->y) | |
3508 wp->y += wp->cy - pixheight; | |
3509 } | |
3510 | |
3511 wp->cx = pixwidth; | |
3512 wp->cy = pixheight; | |
428 | 3513 } |
442 | 3514 /* DefWindowProc sends useful WM_GETMINMAXINFO message, and adjusts |
3515 window position if the user tries to track window too small */ | |
428 | 3516 } |
442 | 3517 goto defproc; |
3518 | |
3519 case WM_ENTERSIZEMOVE: | |
771 | 3520 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd))); |
442 | 3521 msframe->sizing = 1; |
3522 return 0; | |
3523 | |
3524 case WM_EXITSIZEMOVE: | |
771 | 3525 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd))); |
442 | 3526 msframe->sizing = 0; |
3527 /* Queue noop event */ | |
3528 mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE); | |
3529 return 0; | |
428 | 3530 |
3531 #ifdef HAVE_SCROLLBARS | |
442 | 3532 case WM_VSCROLL: |
3533 case WM_HSCROLL: | |
3534 { | |
3535 /* Direction of scroll is determined by scrollbar instance. */ | |
1279 | 3536 int code = (int) LOWORD (wParam); |
3537 int pos = (short int) HIWORD (wParam); | |
442 | 3538 HWND hwndScrollBar = (HWND) lParam; |
3539 struct gcpro gcpro1, gcpro2; | |
3540 | |
3541 mswindows_handle_scrollbar_event (hwndScrollBar, code, pos); | |
3542 GCPRO2 (emacs_event, fobj); | |
853 | 3543 if (UNBOUNDP (mswindows_pump_outstanding_events ())) /* Can GC */ |
442 | 3544 { |
3545 /* Error during event pumping - cancel scroll */ | |
771 | 3546 qxeSendMessage (hwndScrollBar, WM_CANCELMODE, 0, 0); |
442 | 3547 } |
3548 UNGCPRO; | |
3549 break; | |
3550 } | |
3551 | |
3552 case WM_MOUSEWHEEL: | |
3553 { | |
3554 int keys = LOWORD (wParam); /* Modifier key flags */ | |
3555 int delta = (short) HIWORD (wParam); /* Wheel rotation amount */ | |
3556 | |
1622 | 3557 /* enqueue button4/5 events if mswindows_handle_mousewheel_event |
3558 doesn't handle the event, such as when the scrollbars are not | |
3559 displayed */ | |
3560 if (!mswindows_handle_mousewheel_event (mswindows_find_frame (hwnd), | |
464 | 3561 keys, delta, |
2367 | 3562 XE_MAKEPOINTS (lParam))) |
1622 | 3563 mswindows_enqueue_mouse_button_event (hwnd, message_, |
2367 | 3564 XE_MAKEPOINTS (lParam), |
1622 | 3565 wParam, |
3566 GetMessageTime()); | |
3567 /* We are not in a modal loop so no pumping is necessary. */ | |
3568 break; | |
442 | 3569 } |
428 | 3570 #endif |
3571 | |
3572 #ifdef HAVE_MENUBARS | |
442 | 3573 case WM_INITMENU: |
771 | 3574 if (UNBOUNDP (mswindows_handle_wm_initmenu |
3575 ((HMENU) wParam, | |
3576 XFRAME (mswindows_find_frame (hwnd))))) | |
3577 qxeSendMessage (hwnd, WM_CANCELMODE, 0, 0); | |
442 | 3578 break; |
3579 | |
3580 case WM_INITMENUPOPUP: | |
3581 if (!HIWORD(lParam)) | |
3582 { | |
771 | 3583 if (UNBOUNDP (mswindows_handle_wm_initmenupopup |
3584 ((HMENU) wParam, | |
3585 XFRAME (mswindows_find_frame (hwnd))))) | |
3586 qxeSendMessage (hwnd, WM_CANCELMODE, 0, 0); | |
442 | 3587 } |
3588 break; | |
428 | 3589 |
3590 #endif /* HAVE_MENUBARS */ | |
3591 | |
442 | 3592 case WM_COMMAND: |
3593 { | |
3594 WORD id = LOWORD (wParam); | |
3595 WORD nid = HIWORD (wParam); | |
3596 HWND cid = (HWND)lParam; | |
3597 frame = XFRAME (mswindows_find_frame (hwnd)); | |
428 | 3598 |
3599 #ifdef HAVE_TOOLBARS | |
442 | 3600 if (!NILP (mswindows_handle_toolbar_wm_command (frame, cid, id))) |
3601 break; | |
428 | 3602 #endif |
771 | 3603 /* widgets in a buffer only eval a callback for suitable events. */ |
442 | 3604 switch (nid) |
3605 { | |
3606 case BN_CLICKED: | |
3607 case EN_CHANGE: | |
3608 case CBN_EDITCHANGE: | |
3609 case CBN_SELCHANGE: | |
3610 if (!NILP (mswindows_handle_gui_wm_command (frame, cid, id))) | |
3611 return 0; | |
3612 } | |
3613 /* menubars always must come last since the hashtables do not | |
771 | 3614 always exist */ |
428 | 3615 #ifdef HAVE_MENUBARS |
442 | 3616 if (!NILP (mswindows_handle_wm_command (frame, id))) |
3617 break; | |
428 | 3618 #endif |
3619 | |
771 | 3620 goto defproc; |
3621 /* Bite me - a spurious command. This used to not be able to | |
3622 happen but with the introduction of widgets it's now | |
3623 possible. #### Andy, fix the god-damn widget code! It has | |
3624 more bugs than a termite's nest! */ | |
442 | 3625 } |
3626 break; | |
3627 | |
3628 case WM_CTLCOLORBTN: | |
3629 case WM_CTLCOLORLISTBOX: | |
3630 case WM_CTLCOLOREDIT: | |
3631 case WM_CTLCOLORSTATIC: | |
3632 case WM_CTLCOLORSCROLLBAR: | |
3633 { | |
3634 /* if we get an opportunity to paint a widget then do so if | |
3635 there is an appropriate face */ | |
771 | 3636 HWND crtlwnd = (HWND) lParam; |
3637 LONG ii = qxeGetWindowLong (crtlwnd, GWL_USERDATA); | |
442 | 3638 if (ii) |
3639 { | |
3640 Lisp_Object image_instance; | |
826 | 3641 image_instance = VOID_TO_LISP ((void *) ii); |
442 | 3642 if (IMAGE_INSTANCEP (image_instance) |
3643 && | |
3644 IMAGE_INSTANCE_TYPE_P (image_instance, IMAGE_WIDGET)) | |
3645 { | |
3646 /* set colors for the buttons */ | |
771 | 3647 HDC hdc = (HDC) wParam; |
442 | 3648 if (last_widget_brushed != ii) |
3649 { | |
3650 if (widget_brush) | |
3651 DeleteObject (widget_brush); | |
3652 widget_brush = CreateSolidBrush | |
3653 (COLOR_INSTANCE_MSWINDOWS_COLOR | |
3654 (XCOLOR_INSTANCE | |
3655 (FACE_BACKGROUND | |
3656 (XIMAGE_INSTANCE_WIDGET_FACE (image_instance), | |
3657 XIMAGE_INSTANCE_FRAME (image_instance))))); | |
3658 } | |
3659 last_widget_brushed = ii; | |
3660 SetTextColor | |
3661 (hdc, | |
3662 COLOR_INSTANCE_MSWINDOWS_COLOR | |
3663 (XCOLOR_INSTANCE | |
3664 (FACE_FOREGROUND | |
3665 (XIMAGE_INSTANCE_WIDGET_FACE (image_instance), | |
3666 XIMAGE_INSTANCE_FRAME (image_instance))))); | |
3667 SetBkMode (hdc, OPAQUE); | |
3668 SetBkColor | |
3669 (hdc, | |
3670 COLOR_INSTANCE_MSWINDOWS_COLOR | |
3671 (XCOLOR_INSTANCE | |
3672 (FACE_BACKGROUND | |
3673 (XIMAGE_INSTANCE_WIDGET_FACE (image_instance), | |
3674 XIMAGE_INSTANCE_FRAME (image_instance))))); | |
3675 return (LRESULT)widget_brush; | |
3676 } | |
3677 } | |
3678 } | |
3679 goto defproc; | |
428 | 3680 |
3681 #ifdef HAVE_DRAGNDROP | |
853 | 3682 case WM_DROPFILES: /* implementation ripped-off from event-Xt.c */ |
442 | 3683 { |
771 | 3684 UINT filecount, i; |
442 | 3685 POINT point; |
3686 | |
3687 Lisp_Object l_dndlist = Qnil, l_item = Qnil; | |
3688 struct gcpro gcpro1, gcpro2, gcpro3; | |
3689 | |
3690 emacs_event = Fmake_event (Qnil, Qnil); | |
771 | 3691 event = XEVENT (emacs_event); |
442 | 3692 |
3693 GCPRO3 (emacs_event, l_dndlist, l_item); | |
3694 | |
3695 if (!DragQueryPoint ((HDROP) wParam, &point)) | |
853 | 3696 point.x = point.y = -1; /* outside client area */ |
442 | 3697 |
964 | 3698 XSET_EVENT_TYPE (emacs_event, misc_user_event); |
3699 XSET_EVENT_CHANNEL (emacs_event, mswindows_find_frame(hwnd)); | |
3700 XSET_EVENT_TIMESTAMP (emacs_event, GetMessageTime()); | |
1204 | 3701 XSET_EVENT_MISC_USER_BUTTON (emacs_event, 1); |
3702 XSET_EVENT_MISC_USER_MODIFIERS (emacs_event, | |
964 | 3703 mswindows_modifier_state (NULL, (DWORD) -1, 0)); |
1204 | 3704 XSET_EVENT_MISC_USER_X (emacs_event, point.x); |
3705 XSET_EVENT_MISC_USER_Y (emacs_event, point.y); | |
3706 XSET_EVENT_MISC_USER_FUNCTION (emacs_event, | |
964 | 3707 Qdragdrop_drop_dispatch); |
442 | 3708 |
771 | 3709 filecount = qxeDragQueryFile ((HDROP) wParam, 0xffffffff, NULL, 0); |
3710 for (i = 0; i < filecount; i++) | |
442 | 3711 { |
867 | 3712 Ibyte *fname; |
771 | 3713 Extbyte *fname_ext; |
3714 Bytecount fnamelen; | |
3715 Charcount len = qxeDragQueryFile ((HDROP) wParam, i, NULL, 0); | |
2526 | 3716 int freeme = 0; |
442 | 3717 /* The URLs that we make here aren't correct according to section |
3718 * 3.10 of rfc1738 because they're missing the //<host>/ part and | |
3719 * because they may contain reserved characters. But that's OK - | |
3720 * they just need to be good enough to keep dragdrop.el happy. */ | |
2367 | 3721 fname_ext = alloca_extbytes ((len + 1) * XETCHAR_SIZE); |
771 | 3722 qxeDragQueryFile ((HDROP) wParam, i, fname_ext, len + 1); |
3723 | |
3724 TO_INTERNAL_FORMAT (DATA, (fname_ext, len * XETCHAR_SIZE), | |
3725 ALLOCA, (fname, fnamelen), | |
3726 Qmswindows_tstr); | |
442 | 3727 |
2526 | 3728 |
442 | 3729 /* May be a shell link aka "shortcut" - replace fname if so */ |
2367 | 3730 if (!qxestrcasecmp_ascii (fname + fnamelen - 4, ".LNK")) |
442 | 3731 { |
2526 | 3732 fname = mswindows_read_link (fname); |
3733 freeme = 1; | |
442 | 3734 } |
2526 | 3735 |
771 | 3736 { |
2526 | 3737 Ibyte *fname2 = urlify_filename (fname); |
3738 l_item = build_intstring (fname2); | |
3739 xfree (fname2, Ibyte *); | |
3740 if (freeme) | |
3741 xfree (fname, Ibyte *); | |
771 | 3742 l_dndlist = Fcons (l_item, l_dndlist); |
3743 } | |
442 | 3744 } |
771 | 3745 |
442 | 3746 DragFinish ((HDROP) wParam); |
3747 | |
1204 | 3748 SET_EVENT_MISC_USER_OBJECT (event, |
964 | 3749 Fcons (Qdragdrop_URL, l_dndlist)); |
442 | 3750 mswindows_enqueue_dispatch_event (emacs_event); |
3751 UNGCPRO; | |
3752 } | |
3753 break; | |
771 | 3754 #endif /* HAVE_DRAGNDROP */ |
3755 | |
3756 #ifdef MULE | |
3757 case WM_IME_CHAR: | |
3758 | |
3759 case WM_IME_STARTCOMPOSITION: | |
3760 mswindows_start_ime_composition (XFRAME (mswindows_find_frame (hwnd))); | |
3761 goto defproc; | |
3762 | |
3763 case WM_IME_COMPOSITION: | |
3764 if (lParam & GCS_RESULTSTR) | |
3765 { | |
3766 HIMC imc = ImmGetContext (hwnd); | |
3767 Extbyte *result; | |
3768 Bytecount len; | |
867 | 3769 Ibyte *resultint, *endptr; |
771 | 3770 Bytecount lenint; |
3771 int speccount; | |
3772 | |
3773 if (!imc) | |
3774 break; | |
3775 | |
3776 /* See WM_KEYDOWN above. */ | |
3777 speccount = begin_dont_check_for_quit (); | |
3778 | |
3779 /* Sizes always in bytes, even for unicode. | |
3780 ImmGetCompositionStringW is supported even on Windows 9x, and | |
3781 allows us to handle multiple languages. */ | |
3782 len = ImmGetCompositionStringW (imc, GCS_RESULTSTR, NULL, 0); | |
2367 | 3783 result = alloca_extbytes (len); |
771 | 3784 ImmGetCompositionStringW (imc, GCS_RESULTSTR, (WCHAR *) result, len); |
3785 ImmReleaseContext (hwnd, imc); | |
3786 | |
3787 TO_INTERNAL_FORMAT (DATA, (result, len), | |
3788 ALLOCA, (resultint, lenint), | |
3789 Qmswindows_tstr); | |
3790 | |
3791 endptr = resultint + lenint; | |
3792 | |
3793 while (resultint < endptr) | |
3794 { | |
867 | 3795 Ichar ch = itext_ichar (resultint); |
771 | 3796 if (ch == ' ') |
3797 mswindows_enqueue_keypress_event (hwnd, QKspace, 0); | |
3798 else | |
3799 mswindows_enqueue_keypress_event (hwnd, make_char (ch), 0); | |
867 | 3800 INC_IBYTEPTR (resultint); |
771 | 3801 } |
3802 | |
3803 unbind_to (speccount); | |
3804 } | |
3805 goto defproc; | |
3806 #endif /* MULE */ | |
442 | 3807 |
3808 defproc: | |
3809 default: | |
771 | 3810 return qxeDefWindowProc (hwnd, message_, wParam, lParam); |
428 | 3811 } |
3812 return (0); | |
3813 } | |
3814 | |
3815 | |
3816 /************************************************************************/ | |
3817 /* keyboard, mouse & other helpers for the windows procedure */ | |
3818 /************************************************************************/ | |
3819 static void | |
3820 mswindows_set_chord_timer (HWND hwnd) | |
3821 { | |
3822 int interval; | |
3823 | |
3824 /* We get one third half system double click threshold */ | |
3825 if (mswindows_mouse_button_tolerance <= 0) | |
3826 interval = GetDoubleClickTime () / 3; | |
3827 else | |
3828 interval = mswindows_mouse_button_tolerance; | |
3829 | |
3830 SetTimer (hwnd, BUTTON_2_TIMER_ID, interval, 0); | |
3831 } | |
3832 | |
3833 static int | |
3834 mswindows_button2_near_enough (POINTS p1, POINTS p2) | |
3835 { | |
3836 int dx, dy; | |
3837 if (mswindows_mouse_button_max_skew_x <= 0) | |
3838 dx = GetSystemMetrics (SM_CXDOUBLECLK) / 2; | |
3839 else | |
3840 dx = mswindows_mouse_button_max_skew_x; | |
3841 | |
3842 if (mswindows_mouse_button_max_skew_y <= 0) | |
3843 dy = GetSystemMetrics (SM_CYDOUBLECLK) / 2; | |
3844 else | |
3845 dy = mswindows_mouse_button_max_skew_y; | |
3846 | |
3847 return abs (p1.x - p2.x) < dx && abs (p1.y- p2.y)< dy; | |
3848 } | |
3849 | |
3850 static int | |
3851 mswindows_current_layout_has_AltGr (void) | |
3852 { | |
3853 /* This simple caching mechanism saves 10% of CPU | |
3854 time when a key typed at autorepeat rate of 30 cps! */ | |
3855 static HKL last_hkl = 0; | |
3856 static int last_hkl_has_AltGr; | |
771 | 3857 HKL current_hkl = GetKeyboardLayout (0); |
3858 | |
428 | 3859 if (current_hkl != last_hkl) |
3860 { | |
647 | 3861 int c; |
428 | 3862 last_hkl_has_AltGr = 0; |
3863 /* In this loop, we query whether a character requires | |
3864 AltGr to be down to generate it. If at least such one | |
3865 found, this means that the layout does regard AltGr */ | |
647 | 3866 for (c = ' '; c <= 255 && !last_hkl_has_AltGr; ++c) |
3867 /* #### This is not really such a good check. What about under | |
3868 CJK locales? It may not matter there, though. We always | |
3869 call VkKeyScanA so that we check the locale-specific characters | |
3870 in non-Latin-1 locales, instead of just the Latin-1 characters. */ | |
3871 if (HIBYTE (VkKeyScanA ((char) c)) == 6) | |
428 | 3872 last_hkl_has_AltGr = 1; |
3873 last_hkl = current_hkl; | |
3874 } | |
3875 return last_hkl_has_AltGr; | |
3876 } | |
3877 | |
3878 | |
3879 /* Returns the state of the modifier keys in the format expected by the | |
3880 * Lisp_Event key_data, button_data and motion_data modifiers member */ | |
442 | 3881 static int |
771 | 3882 mswindows_modifier_state (BYTE *keymap, DWORD fwKeys, int has_AltGr) |
428 | 3883 { |
3884 int mods = 0; | |
442 | 3885 int keys_is_real = 0; |
3886 BYTE keymap2[256]; | |
3887 | |
3888 if (fwKeys == (DWORD) -1) | |
3889 fwKeys = mswindows_last_mouse_button_state; | |
3890 else | |
3891 { | |
3892 keys_is_real = 1; | |
3893 mswindows_last_mouse_button_state = fwKeys; | |
3894 } | |
428 | 3895 |
3896 if (keymap == NULL) | |
3897 { | |
442 | 3898 keymap = keymap2; |
428 | 3899 GetKeyboardState (keymap); |
3900 has_AltGr = mswindows_current_layout_has_AltGr (); | |
3901 } | |
3902 | |
442 | 3903 /* #### should look at fwKeys for MK_CONTROL. I don't understand how |
3904 AltGr works. */ | |
428 | 3905 if (has_AltGr && (keymap [VK_LCONTROL] & 0x80) && (keymap [VK_RMENU] & 0x80)) |
3906 { | |
442 | 3907 mods |= (keymap [VK_LMENU] & 0x80) ? XEMACS_MOD_META : 0; |
3908 mods |= (keymap [VK_RCONTROL] & 0x80) ? XEMACS_MOD_CONTROL : 0; | |
428 | 3909 } |
3910 else | |
3911 { | |
442 | 3912 mods |= (keymap [VK_MENU] & 0x80) ? XEMACS_MOD_META : 0; |
3913 mods |= (keymap [VK_CONTROL] & 0x80) ? XEMACS_MOD_CONTROL : 0; | |
428 | 3914 } |
3915 | |
1111 | 3916 mods |= (keys_is_real ? (int) (fwKeys & MK_SHIFT) : |
3917 (keymap [VK_SHIFT] & 0x80)) ? XEMACS_MOD_SHIFT : 0; | |
442 | 3918 mods |= fwKeys & MK_LBUTTON ? XEMACS_MOD_BUTTON1 : 0; |
3919 mods |= fwKeys & MK_MBUTTON ? XEMACS_MOD_BUTTON2 : 0; | |
3920 mods |= fwKeys & MK_RBUTTON ? XEMACS_MOD_BUTTON3 : 0; | |
428 | 3921 |
3922 return mods; | |
3923 } | |
3924 | |
3925 /* | |
3926 * Translate a mswindows virtual key to a keysym. | |
3927 * Only returns non-Qnil for keys that don't generate WM_CHAR messages | |
3928 * or whose ASCII codes (like space) xemacs doesn't like. | |
3929 */ | |
2286 | 3930 Lisp_Object mswindows_key_to_emacs_keysym (int mswindows_key, |
3931 int UNUSED (mods), int extendedp) | |
428 | 3932 { |
3933 if (extendedp) /* Keys not present on a 82 key keyboard */ | |
3934 { | |
3935 switch (mswindows_key) | |
3936 { | |
442 | 3937 case VK_CANCEL: return KEYSYM ("pause"); |
428 | 3938 case VK_RETURN: return KEYSYM ("kp-enter"); |
3939 case VK_PRIOR: return KEYSYM ("prior"); | |
3940 case VK_NEXT: return KEYSYM ("next"); | |
3941 case VK_END: return KEYSYM ("end"); | |
3942 case VK_HOME: return KEYSYM ("home"); | |
3943 case VK_LEFT: return KEYSYM ("left"); | |
3944 case VK_UP: return KEYSYM ("up"); | |
3945 case VK_RIGHT: return KEYSYM ("right"); | |
3946 case VK_DOWN: return KEYSYM ("down"); | |
3947 case VK_INSERT: return KEYSYM ("insert"); | |
3948 case VK_DELETE: return QKdelete; | |
442 | 3949 #if 0 /* FSF Emacs allows these to return configurable syms/mods */ |
3950 case VK_LWIN return KEYSYM (""); | |
3951 case VK_RWIN return KEYSYM (""); | |
3952 #endif | |
3953 case VK_APPS: return KEYSYM ("menu"); | |
428 | 3954 } |
3955 } | |
3956 else | |
3957 { | |
3958 switch (mswindows_key) | |
3959 { | |
771 | 3960 |
3961 #if 0 | |
3962 VK_LBUTTON: | |
3963 VK_RBUTTON: | |
3964 VK_CANCEL: | |
3965 VK_MBUTTON: | |
3966 VK_XBUTTON1: | |
3967 VK_XBUTTON2: | |
3968 #endif /* 0 */ | |
3969 | |
428 | 3970 case VK_BACK: return QKbackspace; |
3971 case VK_TAB: return QKtab; | |
771 | 3972 /* #### Officially 0A (and 0B too) are "reserved". */ |
428 | 3973 case '\n': return QKlinefeed; |
3974 case VK_CLEAR: return KEYSYM ("clear"); | |
3975 case VK_RETURN: return QKreturn; | |
771 | 3976 |
3977 #if 0 | |
3978 VK_SHIFT: "shift" | |
3979 VK_CONTROL: "control" | |
3980 VK_MENU: "alt" | |
3981 #endif /* 0 */ | |
3982 | |
442 | 3983 case VK_PAUSE: return KEYSYM ("pause"); |
771 | 3984 |
3985 #if 0 | |
3986 VK_CAPITAL: "caps-lock" | |
3987 VK_KANA: IME Kana mode | |
3988 VK_HANGUEL: IME Hanguel mode (maintained for compatibility; use VK_HANGUL) | |
3989 VK_HANGUL: IME Hangul mode | |
3990 VK_JUNJA: IME Junja mode | |
3991 VK_FINAL: IME final mode | |
3992 VK_HANJA: IME Hanja mode | |
3993 VK_KANJI: IME Kanji mode | |
3994 #endif /* 0 */ | |
3995 | |
428 | 3996 case VK_ESCAPE: return QKescape; |
771 | 3997 |
3998 #if 0 | |
3999 VK_CONVERT: IME convert | |
4000 VK_NONCONVERT: IME nonconvert | |
4001 VK_ACCEPT: IME accept | |
4002 VK_MODECHANGE: IME mode change request | |
4003 #endif /* 0 */ | |
4004 | |
428 | 4005 case VK_SPACE: return QKspace; |
4006 case VK_PRIOR: return KEYSYM ("kp-prior"); | |
4007 case VK_NEXT: return KEYSYM ("kp-next"); | |
4008 case VK_END: return KEYSYM ("kp-end"); | |
4009 case VK_HOME: return KEYSYM ("kp-home"); | |
4010 case VK_LEFT: return KEYSYM ("kp-left"); | |
4011 case VK_UP: return KEYSYM ("kp-up"); | |
4012 case VK_RIGHT: return KEYSYM ("kp-right"); | |
4013 case VK_DOWN: return KEYSYM ("kp-down"); | |
4014 case VK_SELECT: return KEYSYM ("select"); | |
4015 case VK_PRINT: return KEYSYM ("print"); | |
4016 case VK_EXECUTE: return KEYSYM ("execute"); | |
4017 case VK_SNAPSHOT: return KEYSYM ("print"); | |
4018 case VK_INSERT: return KEYSYM ("kp-insert"); | |
4019 case VK_DELETE: return KEYSYM ("kp-delete"); | |
4020 case VK_HELP: return KEYSYM ("help"); | |
771 | 4021 #if 0 |
4022 '0' through '9': numeric keys | |
4023 'A' through 'Z': alphabetic keys | |
4024 VK_LWIN: "lwin" | |
4025 VK_RWIN: "rwin" | |
4026 VK_APPS: "apps" | |
4027 VK_SLEEP: "sleep" | |
4028 #endif /* 0 */ | |
428 | 4029 case VK_NUMPAD0: return KEYSYM ("kp-0"); |
4030 case VK_NUMPAD1: return KEYSYM ("kp-1"); | |
4031 case VK_NUMPAD2: return KEYSYM ("kp-2"); | |
4032 case VK_NUMPAD3: return KEYSYM ("kp-3"); | |
4033 case VK_NUMPAD4: return KEYSYM ("kp-4"); | |
4034 case VK_NUMPAD5: return KEYSYM ("kp-5"); | |
4035 case VK_NUMPAD6: return KEYSYM ("kp-6"); | |
4036 case VK_NUMPAD7: return KEYSYM ("kp-7"); | |
4037 case VK_NUMPAD8: return KEYSYM ("kp-8"); | |
4038 case VK_NUMPAD9: return KEYSYM ("kp-9"); | |
4039 case VK_MULTIPLY: return KEYSYM ("kp-multiply"); | |
4040 case VK_ADD: return KEYSYM ("kp-add"); | |
4041 case VK_SEPARATOR: return KEYSYM ("kp-separator"); | |
4042 case VK_SUBTRACT: return KEYSYM ("kp-subtract"); | |
4043 case VK_DECIMAL: return KEYSYM ("kp-decimal"); | |
4044 case VK_DIVIDE: return KEYSYM ("kp-divide"); | |
4045 case VK_F1: return KEYSYM ("f1"); | |
4046 case VK_F2: return KEYSYM ("f2"); | |
4047 case VK_F3: return KEYSYM ("f3"); | |
4048 case VK_F4: return KEYSYM ("f4"); | |
4049 case VK_F5: return KEYSYM ("f5"); | |
4050 case VK_F6: return KEYSYM ("f6"); | |
4051 case VK_F7: return KEYSYM ("f7"); | |
4052 case VK_F8: return KEYSYM ("f8"); | |
4053 case VK_F9: return KEYSYM ("f9"); | |
4054 case VK_F10: return KEYSYM ("f10"); | |
4055 case VK_F11: return KEYSYM ("f11"); | |
4056 case VK_F12: return KEYSYM ("f12"); | |
4057 case VK_F13: return KEYSYM ("f13"); | |
4058 case VK_F14: return KEYSYM ("f14"); | |
4059 case VK_F15: return KEYSYM ("f15"); | |
4060 case VK_F16: return KEYSYM ("f16"); | |
4061 case VK_F17: return KEYSYM ("f17"); | |
4062 case VK_F18: return KEYSYM ("f18"); | |
4063 case VK_F19: return KEYSYM ("f19"); | |
4064 case VK_F20: return KEYSYM ("f20"); | |
4065 case VK_F21: return KEYSYM ("f21"); | |
4066 case VK_F22: return KEYSYM ("f22"); | |
4067 case VK_F23: return KEYSYM ("f23"); | |
4068 case VK_F24: return KEYSYM ("f24"); | |
771 | 4069 |
4070 #if 0 | |
4071 VK_NUMLOCK: 90 NUM LOCK key | |
4072 VK_SCROLL: 91 SCROLL LOCK key | |
4073 92~96 OEM specific; | |
4074 VK_LSHIFT: | |
4075 VK_RSHIFT: | |
4076 VK_LCONTROL: | |
4077 VK_RCONTROL: | |
4078 VK_LMENU: | |
4079 VK_RMENU: | |
4080 | |
4081 #ifdef VK_BROWSER_BACK /* Windows 2000 only */ | |
4082 VK_BROWSER_BACK: Browser Back key | |
4083 VK_BROWSER_FORWARD: Browser Forward key | |
4084 VK_BROWSER_REFRESH: Browser Refresh key | |
4085 VK_BROWSER_STOP: Browser Stop key | |
4086 VK_BROWSER_SEARCH: Browser Search key | |
4087 VK_BROWSER_FAVORITES: Browser Favorites key | |
4088 VK_BROWSER_HOME: Browser Start and Home key | |
4089 VK_VOLUME_MUTE: Volume Mute key | |
4090 VK_VOLUME_DOWN: Volume Down key | |
4091 VK_VOLUME_UP: Volume Up key | |
4092 VK_MEDIA_NEXT_TRACK: Next Track key | |
4093 VK_MEDIA_PREV_TRACK: Previous Track key | |
4094 VK_MEDIA_STOP: Stop Media key | |
4095 VK_MEDIA_PLAY_PAUSE: Play/Pause Media key | |
4096 VK_LAUNCH_MAIL: Start Mail key | |
4097 VK_LAUNCH_MEDIA_SELECT: Select Media key | |
4098 VK_LAUNCH_APP1: Start Application 1 key | |
4099 VK_LAUNCH_APP2: Start Application 2 key | |
4100 B8-B9 Reserved; | |
4101 VK_OEM_1: For the US standard keyboard, the ';:' key | |
4102 VK_OEM_PLUS: For any country/region, the '+' key | |
4103 VK_OEM_COMMA: For any country/region, the ',' key | |
4104 VK_OEM_MINUS: For any country/region, the '-' key | |
4105 VK_OEM_PERIOD: For any country/region, the '.' key | |
4106 VK_OEM_2: For the US standard keyboard, the '/?' key | |
4107 VK_OEM_3: For the US standard keyboard, the '`~' key | |
4108 C1~D7 Reserved; | |
4109 D8~DA Unassigned; | |
4110 VK_OEM_4: For the US standard keyboard, the '[{' key | |
4111 VK_OEM_5: For the US standard keyboard, the '\|' key | |
4112 VK_OEM_6: For the US standard keyboard, the ']}' key | |
4113 VK_OEM_7: For the US standard keyboard, the 'single-quote/double-quote' key | |
4114 VK_OEM_8: | |
4115 E0 Reserved; | |
4116 E1 OEM specific; | |
4117 VK_OEM_102: Either the angle bracket key or the backslash key on the RT 102-key keyboard | |
4118 E3~E4 OEM specific; | |
4119 #endif /* VK_BROWSER_BACK */ | |
4120 VK_PROCESSKEY: E5 Windows 95/98, Windows NT 4.0, Windows 2000: IME PROCESS key | |
4121 E6 OEM specific; | |
4122 VK_PACKET: Used to pass Unicode characters as if they were keystrokes. The VK_PACKET key is the low word of a 32-bit Virtual Key value used for non-keyboard input methods. For more information, see Remark in KEYBDINPUT, SendInput, WM_KEYDOWN, and WM_KEYUP | |
4123 E8 Unassigned; | |
4124 E9~F5 OEM specific; | |
4125 VK_ATTN: Attn key | |
4126 VK_CRSEL: CrSel key | |
4127 VK_EXSEL: ExSel key | |
4128 VK_EREOF: Erase EOF key | |
4129 VK_PLAY: Play key | |
4130 VK_ZOOM: Zoom key | |
4131 VK_NONAME: Reserved for future use | |
4132 VK_PA1: PA1 key | |
4133 VK_OEM_CLEAR: Clear key | |
4134 #endif /* 0 */ | |
4135 | |
428 | 4136 } |
4137 } | |
4138 return Qnil; | |
4139 } | |
4140 | |
4141 /* | |
4142 * Find the console that matches the supplied mswindows window handle | |
4143 */ | |
4144 Lisp_Object | |
2286 | 4145 mswindows_find_console (HWND UNUSED (hwnd)) |
428 | 4146 { |
4147 /* We only support one console */ | |
4148 return XCAR (Vconsole_list); | |
4149 } | |
4150 | |
4151 /* | |
4152 * Find the frame that matches the supplied mswindows window handle | |
4153 */ | |
546 | 4154 Lisp_Object |
428 | 4155 mswindows_find_frame (HWND hwnd) |
4156 { | |
771 | 4157 LONG l = qxeGetWindowLong (hwnd, XWL_FRAMEOBJ); |
428 | 4158 Lisp_Object f; |
4159 if (l == 0) | |
4160 { | |
4161 /* We are in progress of frame creation. Return the frame | |
4162 being created, as it still not remembered in the window | |
4163 extra storage. */ | |
4164 assert (!NILP (Vmswindows_frame_being_created)); | |
4165 return Vmswindows_frame_being_created; | |
4166 } | |
826 | 4167 f = VOID_TO_LISP ((void *) l); |
428 | 4168 return f; |
4169 } | |
4170 | |
4171 | |
4172 /************************************************************************/ | |
4173 /* methods */ | |
4174 /************************************************************************/ | |
4175 | |
4176 static int | |
4177 emacs_mswindows_add_timeout (EMACS_TIME thyme) | |
4178 { | |
4179 int milliseconds; | |
4180 EMACS_TIME current_time; | |
4181 EMACS_GET_TIME (current_time); | |
4182 EMACS_SUB_TIME (thyme, thyme, current_time); | |
4183 milliseconds = EMACS_SECS (thyme) * 1000 + | |
4184 (EMACS_USECS (thyme) + 500) / 1000; | |
4185 if (milliseconds < 1) | |
4186 milliseconds = 1; | |
4187 ++mswindows_pending_timers_count; | |
4188 return SetTimer (NULL, 0, milliseconds, | |
4189 (TIMERPROC) mswindows_wm_timer_callback); | |
4190 } | |
4191 | |
1204 | 4192 static int |
4193 remove_timeout_mapper (Lisp_Object ev, void *data) | |
4194 { | |
4195 if (XEVENT_TYPE (ev) == timeout_event) | |
4196 { | |
4197 if ((int) data == XEVENT_TIMEOUT_INTERVAL_ID (ev)) | |
4198 return 1; | |
4199 } | |
4200 | |
4201 return 0; | |
4202 } | |
4203 | |
428 | 4204 static void |
4205 emacs_mswindows_remove_timeout (int id) | |
4206 { | |
4207 if (KillTimer (NULL, id)) | |
4208 --mswindows_pending_timers_count; | |
4209 | |
4210 /* If there is a dispatch event generated by this | |
4211 timeout in the queue, we have to remove it too. */ | |
1204 | 4212 map_event_chain_remove (remove_timeout_mapper, |
4213 &mswindows_s_dispatch_event_queue, | |
4214 &mswindows_s_dispatch_event_queue_tail, | |
4215 (void *) id, MECR_DEALLOCATE_EVENT); | |
428 | 4216 } |
4217 | |
4218 /* If `user_p' is false, then return whether there are any win32, timeout, | |
4219 * or subprocess events pending (that is, whether | |
4220 * emacs_mswindows_next_event() would return immediately without blocking). | |
4221 * | |
4222 * if `user_p' is true, then return whether there are any *user generated* | |
4223 * events available (that is, whether there are keyboard or mouse-click | |
4224 * events ready to be read). This also implies that | |
4225 * emacs_mswindows_next_event() would not block. | |
4226 */ | |
4227 static int | |
1268 | 4228 emacs_mswindows_event_pending_p (int how_many) |
428 | 4229 { |
1318 | 4230 /* This can call Lisp */ |
1268 | 4231 if (!how_many) |
4232 { | |
4233 mswindows_need_event (0); | |
4234 return (!NILP (dispatch_event_queue) | |
4235 || !NILP (mswindows_s_dispatch_event_queue)); | |
4236 } | |
4237 else | |
4238 { | |
4239 Lisp_Object event; | |
4240 int count = 0; | |
4241 | |
4242 EVENT_CHAIN_LOOP (event, dispatch_event_queue) | |
4243 count++; | |
4244 | |
4245 if (count >= how_many) | |
4246 return 1; | |
4247 | |
4248 emacs_mswindows_drain_queue (); | |
4249 | |
4250 EVENT_CHAIN_LOOP (event, dispatch_event_queue) | |
4251 count++; | |
4252 | |
4253 return count >= how_many; | |
4254 } | |
428 | 4255 } |
4256 | |
4257 /* | |
4258 * Return the next event | |
4259 */ | |
4260 static void | |
440 | 4261 emacs_mswindows_next_event (Lisp_Event *emacs_event) |
428 | 4262 { |
4263 Lisp_Object event, event2; | |
4264 | |
4265 mswindows_need_event (1); | |
4266 | |
4267 event = mswindows_dequeue_dispatch_event (); | |
793 | 4268 event2 = wrap_event (emacs_event); |
428 | 4269 Fcopy_event (event, event2); |
4270 Fdeallocate_event (event); | |
4271 } | |
4272 | |
788 | 4273 static void |
4274 emacs_mswindows_format_magic_event (Lisp_Event *emacs_event, | |
4275 Lisp_Object pstream) | |
4276 { | |
4952
19a72041c5ed
Mule-izing, various fixes related to char * arguments
Ben Wing <ben@xemacs.org>
parents:
4932
diff
changeset
|
4277 #define FROB(msg) case msg: write_ascstring (pstream, "type=" #msg); break |
788 | 4278 |
1204 | 4279 switch (EVENT_MAGIC_MSWINDOWS_EVENT (emacs_event)) |
788 | 4280 { |
4281 FROB (XM_BUMPQUEUE); | |
4282 FROB (WM_PAINT); | |
4283 FROB (WM_SETFOCUS); | |
4284 FROB (WM_KILLFOCUS); | |
4285 FROB (XM_MAPFRAME); | |
4286 FROB (XM_UNMAPFRAME); | |
4287 | |
2500 | 4288 default: ABORT (); |
788 | 4289 } |
4290 #undef FROB | |
4291 | |
4292 if (!NILP (EVENT_CHANNEL (emacs_event))) | |
4293 { | |
4952
19a72041c5ed
Mule-izing, various fixes related to char * arguments
Ben Wing <ben@xemacs.org>
parents:
4932
diff
changeset
|
4294 write_ascstring (pstream, " "); |
788 | 4295 print_internal (EVENT_CHANNEL (emacs_event), pstream, 1); |
4296 } | |
4297 } | |
4298 | |
4299 static int | |
4300 emacs_mswindows_compare_magic_event (Lisp_Event *e1, Lisp_Event *e2) | |
4301 { | |
1204 | 4302 return (EVENT_MAGIC_MSWINDOWS_EVENT (e1) == |
4303 EVENT_MAGIC_MSWINDOWS_EVENT (e2)); | |
788 | 4304 } |
4305 | |
4306 static Hashcode | |
4307 emacs_mswindows_hash_magic_event (Lisp_Event *e) | |
4308 { | |
1204 | 4309 return (EVENT_MAGIC_MSWINDOWS_EVENT (e)); |
788 | 4310 } |
4311 | |
428 | 4312 /* |
4313 * Handle a magic event off the dispatch queue. | |
4314 */ | |
4315 static void | |
440 | 4316 emacs_mswindows_handle_magic_event (Lisp_Event *emacs_event) |
428 | 4317 { |
1204 | 4318 switch (EVENT_MAGIC_MSWINDOWS_EVENT (emacs_event)) |
428 | 4319 { |
4320 case XM_BUMPQUEUE: | |
4321 break; | |
4322 | |
442 | 4323 case WM_PAINT: |
4324 { | |
4325 struct frame *f = XFRAME (EVENT_CHANNEL (emacs_event)); | |
4326 mswindows_handle_paint (f); | |
4327 (FRAME_MSWINDOWS_DATA (f))->paint_pending = 0; | |
4328 } | |
4329 break; | |
4330 | |
428 | 4331 case WM_SETFOCUS: |
4332 case WM_KILLFOCUS: | |
4333 { | |
4334 Lisp_Object frame = EVENT_CHANNEL (emacs_event); | |
4335 struct frame *f = XFRAME (frame); | |
1204 | 4336 int in_p = (EVENT_MAGIC_MSWINDOWS_EVENT (emacs_event) |
964 | 4337 == WM_SETFOCUS); |
428 | 4338 Lisp_Object conser; |
442 | 4339 struct gcpro gcpro1; |
4340 | |
4341 /* On focus change, clear all memory of sticky modifiers | |
4342 to avoid non-intuitive behavior. */ | |
4343 clear_sticky_modifiers (); | |
428 | 4344 |
4345 conser = Fcons (frame, Fcons (FRAME_DEVICE (f), in_p ? Qt : Qnil)); | |
442 | 4346 GCPRO1 (conser); |
428 | 4347 emacs_handle_focus_change_preliminary (conser); |
4348 /* Under X the stuff up to here is done in the X event handler. | |
4349 I Don't know why */ | |
4350 emacs_handle_focus_change_final (conser); | |
442 | 4351 UNGCPRO; |
428 | 4352 |
4353 } | |
4354 break; | |
4355 | |
4356 case XM_MAPFRAME: | |
4357 case XM_UNMAPFRAME: | |
4358 { | |
4359 Lisp_Object frame = EVENT_CHANNEL (emacs_event); | |
1204 | 4360 va_run_hook_with_args (EVENT_MAGIC_MSWINDOWS_EVENT (emacs_event) |
428 | 4361 == XM_MAPFRAME ? |
4362 Qmap_frame_hook : Qunmap_frame_hook, | |
4363 1, frame); | |
4364 } | |
4365 break; | |
4366 | |
4367 /* #### What about Enter & Leave */ | |
4368 #if 0 | |
4369 va_run_hook_with_args (in_p ? Qmouse_enter_frame_hook : | |
4370 Qmouse_leave_frame_hook, 1, frame); | |
4371 #endif | |
4372 | |
4373 default: | |
4374 assert(0); | |
4375 } | |
4376 } | |
4377 | |
853 | 4378 #ifndef CYGWIN |
4379 | |
428 | 4380 static HANDLE |
440 | 4381 get_process_input_waitable (Lisp_Process *process) |
428 | 4382 { |
853 | 4383 Lisp_Object instr, outstr, errstr, p; |
793 | 4384 p = wrap_process (process); |
853 | 4385 get_process_streams (process, &instr, &outstr, &errstr); |
428 | 4386 assert (!NILP (instr)); |
4387 return (network_connection_p (p) | |
4388 ? get_winsock_stream_waitable (XLSTREAM (instr)) | |
4389 : get_ntpipe_input_stream_waitable (XLSTREAM (instr))); | |
4390 } | |
4391 | |
853 | 4392 static HANDLE |
4393 get_process_stderr_waitable (Lisp_Process *process) | |
4394 { | |
4395 Lisp_Object instr, outstr, errstr; | |
4396 get_process_streams (process, &instr, &outstr, &errstr); | |
4397 if (NILP (errstr)) | |
4398 return INVALID_HANDLE_VALUE; | |
4399 return get_ntpipe_input_stream_waitable (XLSTREAM (errstr)); | |
4400 } | |
4401 | |
4402 #endif /* not CYGWIN */ | |
4403 | |
428 | 4404 static void |
853 | 4405 emacs_mswindows_select_process (Lisp_Process *process, int doin, int doerr) |
428 | 4406 { |
853 | 4407 #ifdef CYGWIN |
4408 int infd, errfd; | |
4409 | |
4410 event_stream_unixoid_select_process (process, doin, doerr, &infd, &errfd); | |
4411 #else | |
4412 HANDLE hev = INVALID_HANDLE_VALUE; | |
4413 HANDLE herr = INVALID_HANDLE_VALUE; | |
4414 | |
4415 if (doin) | |
4416 { | |
4417 hev = get_process_input_waitable (process); | |
4418 if (!add_waitable_handle (hev)) | |
4419 { | |
4420 hev = INVALID_HANDLE_VALUE; | |
4421 goto err; | |
4422 } | |
4423 } | |
4424 | |
4425 if (doerr) | |
4426 { | |
4427 herr = get_process_stderr_waitable (process); | |
4428 if (herr != INVALID_HANDLE_VALUE && !add_waitable_handle (herr)) | |
4429 { | |
4430 herr = INVALID_HANDLE_VALUE; | |
4431 goto err; | |
4432 } | |
4433 } | |
4434 | |
428 | 4435 { |
853 | 4436 /* Also select on the process handle itself, so we can receive |
4437 exit notifications. Only do this once, not each time this | |
4438 function is called (which can happen many times, e.g. if | |
4439 (set-process-filter proc t) is called and then a process filter | |
4440 is set again). It will be unselected in mswindows_need_event(). */ | |
793 | 4441 Lisp_Object p = wrap_process (process); |
4442 | |
428 | 4443 if (!network_connection_p (p)) |
4444 { | |
853 | 4445 HANDLE hprocess = get_nt_process_handle_only_first_time (process); |
4446 if (hprocess != INVALID_HANDLE_VALUE | |
4447 && !add_waitable_handle (hprocess)) | |
4448 goto err; | |
428 | 4449 } |
4450 } | |
853 | 4451 |
4452 return; | |
4453 | |
4454 err: | |
4455 if (hev != INVALID_HANDLE_VALUE) | |
4456 remove_waitable_handle (hev); | |
4457 if (herr != INVALID_HANDLE_VALUE) | |
4458 remove_waitable_handle (herr); | |
4459 invalid_operation ("Too many active processes", wrap_process (process)); | |
4460 #endif /* CYGWIN */ | |
428 | 4461 } |
4462 | |
4463 static void | |
853 | 4464 emacs_mswindows_unselect_process (Lisp_Process *process, int doin, int doerr) |
428 | 4465 { |
853 | 4466 #ifdef CYGWIN |
4467 int infd, errfd; | |
4468 | |
4469 event_stream_unixoid_unselect_process (process, doin, doerr, &infd, &errfd); | |
4470 #else | |
4471 if (doin) | |
4472 { | |
4473 /* Process handle is removed in the event loop as soon | |
4474 as it is signaled, so don't bother here about it */ | |
4475 HANDLE hev = get_process_input_waitable (process); | |
4476 remove_waitable_handle (hev); | |
4477 } | |
4478 if (doerr) | |
4479 { | |
4480 /* Process handle is removed in the event loop as soon | |
4481 as it is signaled, so don't bother here about it */ | |
4482 HANDLE herr = get_process_stderr_waitable (process); | |
4483 if (herr != INVALID_HANDLE_VALUE) | |
4484 remove_waitable_handle (herr); | |
4485 } | |
4486 #endif /* CYGWIN */ | |
428 | 4487 } |
4488 | |
4489 static void | |
2286 | 4490 emacs_mswindows_select_console (struct console *USED_IF_CYGWIN (con)) |
428 | 4491 { |
853 | 4492 #ifdef CYGWIN |
428 | 4493 if (CONSOLE_MSWINDOWS_P (con)) |
4494 return; /* mswindows consoles are automatically selected */ | |
4495 | |
4496 event_stream_unixoid_select_console (con); | |
1204 | 4497 #else |
4498 #if 0 | |
4499 /* This is an attempt to get `xemacs -batch -l dunnet' to work. | |
4500 Doesn't currently work and fucks other things up. */ | |
4501 if (CONSOLE_STREAM_P (con) && | |
4502 !UNBOUNDP (CONSOLE_STREAM_DATA (con)->instream)) | |
4503 { | |
4504 HANDLE h = | |
4505 (HANDLE) _get_osfhandle (fileno (CONSOLE_STREAM_DATA (con)->in)); | |
4506 if (PeekNamedPipe (h, 0, 0, 0, 0, 0)) | |
4507 { | |
4508 Lisp_Object lstr = make_ntpipe_input_stream (h, 0); | |
4509 HANDLE hwait = get_ntpipe_input_stream_waitable (XLSTREAM (lstr)); | |
4510 | |
4511 if (!add_waitable_handle (hwait)) | |
4512 invalid_operation ("Too many active processes", | |
4513 wrap_console (con)); | |
4514 CONSOLE_STREAM_DATA (con)->instream = lstr; | |
4515 } | |
4516 else | |
4517 /* Unable to select on this stream */ | |
4518 CONSOLE_STREAM_DATA (con)->instream = Qunbound; | |
4519 } | |
4520 #endif /* 0 */ | |
428 | 4521 #endif |
4522 } | |
4523 | |
4524 static void | |
2286 | 4525 emacs_mswindows_unselect_console (struct console *USED_IF_CYGWIN (con)) |
428 | 4526 { |
853 | 4527 #ifdef CYGWIN |
428 | 4528 if (CONSOLE_MSWINDOWS_P (con)) |
4529 return; /* mswindows consoles are automatically selected */ | |
4530 | |
4531 event_stream_unixoid_unselect_console (con); | |
1204 | 4532 #else |
4533 #if 0 /* see above */ | |
4534 if (CONSOLE_STREAM_P (con) && | |
4535 !UNBOUNDP (CONSOLE_STREAM_DATA (con)->instream)) | |
428 | 4536 { |
1204 | 4537 Lisp_Object instr = CONSOLE_STREAM_DATA (con)->instream; |
4538 HANDLE hwait; | |
4539 | |
4540 assert (!NILP (instr)); | |
4541 hwait = get_ntpipe_input_stream_waitable (XLSTREAM (instr)); | |
4542 | |
4543 remove_waitable_handle (hwait); | |
428 | 4544 } |
1204 | 4545 #endif /* 0 */ |
4546 #endif | |
428 | 4547 } |
4548 | |
853 | 4549 static void |
4550 emacs_mswindows_create_io_streams (void *inhandle, void *outhandle, | |
4551 void *errhandle, Lisp_Object *instream, | |
4552 Lisp_Object *outstream, | |
4553 Lisp_Object *errstream, | |
4554 USID *in_usid, | |
4555 USID *err_usid, | |
4556 int flags) | |
428 | 4557 { |
853 | 4558 #ifdef CYGWIN |
4559 event_stream_unixoid_create_io_streams (inhandle, outhandle, | |
4560 errhandle, instream, | |
4561 outstream, errstream, | |
4562 in_usid, err_usid, flags); | |
4563 #else | |
428 | 4564 /* Handles for streams */ |
853 | 4565 HANDLE hin, hout, herr; |
428 | 4566 /* fds. These just stored along with the streams, and are closed in |
4567 delete stream pair method, because we need to handle fake unices | |
4568 here. */ | |
853 | 4569 int fdi, fdo, fde; |
4570 | |
4571 /* Decode inhandle, outhandle, errhandle. Their meaning depends on | |
428 | 4572 the process implementation being used. */ |
4573 hin = (HANDLE) inhandle; | |
4574 hout = (HANDLE) outhandle; | |
853 | 4575 if (errhandle == (void *) -1) |
4576 herr = INVALID_HANDLE_VALUE; | |
4577 else | |
4578 herr = (HANDLE) errhandle; | |
4579 fdi = fdo = fde = -1; | |
428 | 4580 |
4581 *instream = (hin == INVALID_HANDLE_VALUE | |
4582 ? Qnil | |
4583 : flags & STREAM_NETWORK_CONNECTION | |
853 | 4584 ? make_winsock_input_stream ((SOCKET) hin, fdi) |
428 | 4585 : make_ntpipe_input_stream (hin, fdi)); |
4586 | |
853 | 4587 *errstream = (herr == INVALID_HANDLE_VALUE |
4588 ? Qnil | |
4589 : make_ntpipe_input_stream (herr, fde)); | |
4590 | |
428 | 4591 *outstream = (hout == INVALID_HANDLE_VALUE |
4592 ? Qnil | |
4593 : flags & STREAM_NETWORK_CONNECTION | |
4594 ? make_winsock_output_stream ((SOCKET)hout, fdo) | |
4595 : make_ntpipe_output_stream (hout, fdo)); | |
853 | 4596 |
4597 *in_usid = | |
4598 (NILP (*instream) | |
4599 ? USID_ERROR | |
4600 : flags & STREAM_NETWORK_CONNECTION | |
4601 ? HANDLE_TO_USID (get_winsock_stream_waitable (XLSTREAM (*instream))) | |
4602 : HANDLE_TO_USID (get_ntpipe_input_stream_waitable (XLSTREAM | |
4603 (*instream)))); | |
4604 | |
4605 *err_usid = | |
4606 (NILP (*errstream) | |
4607 ? USID_DONTHASH | |
4608 : HANDLE_TO_USID (get_ntpipe_input_stream_waitable (XLSTREAM | |
4609 (*errstream)))); | |
4610 #endif /* CYGWIN */ | |
428 | 4611 } |
4612 | |
853 | 4613 static void |
4614 emacs_mswindows_delete_io_streams (Lisp_Object instream, | |
2286 | 4615 Lisp_Object USED_IF_CYGWIN (outstream), |
853 | 4616 Lisp_Object errstream, |
4617 USID *in_usid, | |
4618 USID *err_usid) | |
428 | 4619 { |
853 | 4620 #ifdef CYGWIN |
4621 event_stream_unixoid_delete_io_streams (instream, outstream, errstream, | |
4622 in_usid, err_usid); | |
4623 #else | |
4624 *in_usid = | |
4625 (NILP (instream) | |
4626 ? USID_DONTHASH | |
4627 : LSTREAM_TYPE_P (XLSTREAM (instream), winsock) | |
4628 ? HANDLE_TO_USID (get_winsock_stream_waitable (XLSTREAM (instream))) | |
4629 : HANDLE_TO_USID (get_ntpipe_input_stream_waitable (XLSTREAM | |
4630 (instream)))); | |
4631 | |
4632 *err_usid = | |
4633 (NILP (errstream) | |
4634 ? USID_DONTHASH | |
4635 : HANDLE_TO_USID (get_ntpipe_input_stream_waitable (XLSTREAM | |
4636 (errstream)))); | |
4637 #endif /* CYGWIN */ | |
428 | 4638 } |
4639 | |
442 | 4640 static int |
2286 | 4641 emacs_mswindows_current_event_timestamp (struct console *UNUSED (c)) |
442 | 4642 { |
4643 return GetTickCount (); | |
4644 } | |
4645 | |
428 | 4646 #ifndef HAVE_X_WINDOWS |
4647 /* This is called from GC when a process object is about to be freed. | |
4648 If we've still got pointers to it in this file, we're gonna lose hard. | |
853 | 4649 */ |
4650 void debug_process_finalization (Lisp_Process *p); | |
428 | 4651 void |
2286 | 4652 debug_process_finalization (Lisp_Process *UNUSED (p)) |
428 | 4653 { |
4654 #if 0 /* #### */ | |
853 | 4655 Lisp_Object instr, outstr, errstr; |
4656 | |
4657 get_process_streams (p, &instr, &outstr, &errstr); | |
428 | 4658 /* if it still has fds, then it hasn't been killed yet. */ |
771 | 4659 assert (NILP (instr)); |
4660 assert (NILP (outstr)); | |
853 | 4661 assert (NILP (errstr)); |
428 | 4662 |
4663 /* #### More checks here */ | |
4664 #endif | |
4665 } | |
4666 #endif | |
4667 | |
593 | 4668 #ifdef DEBUG_XEMACS |
4669 | |
4670 struct mswin_message_debug | |
4671 { | |
4672 int mess; | |
4932 | 4673 const Ascbyte *string; |
593 | 4674 }; |
4675 | |
4676 #define FROB(val) { val, #val, }, | |
4677 | |
4678 struct mswin_message_debug debug_mswin_messages[] = | |
4679 { | |
4680 FROB (WM_NULL) | |
4681 FROB (WM_CREATE) | |
4682 FROB (WM_DESTROY) | |
4683 FROB (WM_MOVE) | |
4684 FROB (WM_SIZE) | |
4685 | |
4686 FROB (WM_ACTIVATE) | |
4687 | |
4688 FROB (WM_SETFOCUS) | |
4689 FROB (WM_KILLFOCUS) | |
4690 FROB (WM_ENABLE) | |
4691 FROB (WM_SETREDRAW) | |
4692 FROB (WM_SETTEXT) | |
4693 FROB (WM_GETTEXT) | |
4694 FROB (WM_GETTEXTLENGTH) | |
4695 FROB (WM_PAINT) | |
4696 FROB (WM_CLOSE) | |
4697 FROB (WM_QUERYENDSESSION) | |
4698 FROB (WM_QUIT) | |
4699 FROB (WM_QUERYOPEN) | |
4700 FROB (WM_ERASEBKGND) | |
4701 FROB (WM_SYSCOLORCHANGE) | |
4702 FROB (WM_ENDSESSION) | |
4703 FROB (WM_SHOWWINDOW) | |
4704 FROB (WM_WININICHANGE) | |
4705 #if(WINVER >= 0x0400) | |
4706 FROB (WM_SETTINGCHANGE) | |
4707 #endif /* WINVER >= 0x0400 */ | |
4708 | |
4709 FROB (WM_DEVMODECHANGE) | |
4710 FROB (WM_ACTIVATEAPP) | |
4711 FROB (WM_FONTCHANGE) | |
4712 FROB (WM_TIMECHANGE) | |
4713 FROB (WM_CANCELMODE) | |
4714 FROB (WM_SETCURSOR) | |
4715 FROB (WM_MOUSEACTIVATE) | |
4716 FROB (WM_CHILDACTIVATE) | |
4717 FROB (WM_QUEUESYNC) | |
4718 | |
4719 FROB (WM_GETMINMAXINFO) | |
4720 | |
4721 FROB (WM_PAINTICON) | |
4722 FROB (WM_ICONERASEBKGND) | |
4723 FROB (WM_NEXTDLGCTL) | |
4724 FROB (WM_SPOOLERSTATUS) | |
4725 FROB (WM_DRAWITEM) | |
4726 FROB (WM_MEASUREITEM) | |
4727 FROB (WM_DELETEITEM) | |
4728 FROB (WM_VKEYTOITEM) | |
4729 FROB (WM_CHARTOITEM) | |
4730 FROB (WM_SETFONT) | |
4731 FROB (WM_GETFONT) | |
4732 FROB (WM_SETHOTKEY) | |
4733 FROB (WM_GETHOTKEY) | |
4734 FROB (WM_QUERYDRAGICON) | |
4735 FROB (WM_COMPAREITEM) | |
1687 | 4736 #if(WINVER >= 0x0500) && defined(WM_GETOBJECT) |
593 | 4737 FROB (WM_GETOBJECT) |
4738 #endif /* WINVER >= 0x0500 */ | |
4739 FROB (WM_COMPACTING) | |
4740 FROB (WM_COMMNOTIFY) | |
4741 FROB (WM_WINDOWPOSCHANGING) | |
4742 FROB (WM_WINDOWPOSCHANGED) | |
4743 | |
4744 FROB (WM_POWER) | |
4745 | |
4746 FROB (WM_COPYDATA) | |
4747 FROB (WM_CANCELJOURNAL) | |
4748 | |
4749 #if(WINVER >= 0x0400) | |
4750 FROB (WM_NOTIFY) | |
4751 FROB (WM_INPUTLANGCHANGEREQUEST) | |
4752 FROB (WM_INPUTLANGCHANGE) | |
4753 FROB (WM_TCARD) | |
4754 FROB (WM_HELP) | |
4755 FROB (WM_USERCHANGED) | |
4756 FROB (WM_NOTIFYFORMAT) | |
4757 | |
4758 FROB (WM_CONTEXTMENU) | |
4759 FROB (WM_STYLECHANGING) | |
4760 FROB (WM_STYLECHANGED) | |
4761 FROB (WM_DISPLAYCHANGE) | |
4762 FROB (WM_GETICON) | |
4763 FROB (WM_SETICON) | |
4764 #endif /* WINVER >= 0x0400 */ | |
4765 | |
4766 FROB (WM_NCCREATE) | |
4767 FROB (WM_NCDESTROY) | |
4768 FROB (WM_NCCALCSIZE) | |
4769 FROB (WM_NCHITTEST) | |
4770 FROB (WM_NCPAINT) | |
4771 FROB (WM_NCACTIVATE) | |
4772 FROB (WM_GETDLGCODE) | |
604 | 4773 #ifdef WM_SYNCPAINT /* not in VC 5 */ |
593 | 4774 FROB (WM_SYNCPAINT) |
604 | 4775 #endif /* WM_SYNCPAINT */ |
593 | 4776 FROB (WM_NCMOUSEMOVE) |
4777 FROB (WM_NCLBUTTONDOWN) | |
4778 FROB (WM_NCLBUTTONUP) | |
4779 FROB (WM_NCLBUTTONDBLCLK) | |
4780 FROB (WM_NCRBUTTONDOWN) | |
4781 FROB (WM_NCRBUTTONUP) | |
4782 FROB (WM_NCRBUTTONDBLCLK) | |
4783 FROB (WM_NCMBUTTONDOWN) | |
4784 FROB (WM_NCMBUTTONUP) | |
4785 FROB (WM_NCMBUTTONDBLCLK) | |
4786 | |
4787 /* FROB (WM_KEYFIRST) */ | |
4788 FROB (WM_KEYDOWN) | |
4789 FROB (WM_KEYUP) | |
4790 FROB (WM_CHAR) | |
4791 FROB (WM_DEADCHAR) | |
4792 FROB (WM_SYSKEYDOWN) | |
4793 FROB (WM_SYSKEYUP) | |
4794 FROB (WM_SYSCHAR) | |
4795 FROB (WM_SYSDEADCHAR) | |
4796 FROB (WM_KEYLAST) | |
4797 | |
604 | 4798 #if(WINVER >= 0x0400) && defined (WM_IME_STARTCOMPOSITION) |
4799 /* not in Cygwin? */ | |
593 | 4800 FROB (WM_IME_STARTCOMPOSITION) |
4801 FROB (WM_IME_ENDCOMPOSITION) | |
4802 FROB (WM_IME_COMPOSITION) | |
4803 FROB (WM_IME_KEYLAST) | |
604 | 4804 #endif /* WINVER >= 0x0400 && defined (WM_IME_STARTCOMPOSITION) */ |
593 | 4805 |
4806 FROB (WM_INITDIALOG) | |
4807 FROB (WM_COMMAND) | |
4808 FROB (WM_SYSCOMMAND) | |
4809 FROB (WM_TIMER) | |
4810 FROB (WM_HSCROLL) | |
4811 FROB (WM_VSCROLL) | |
4812 FROB (WM_INITMENU) | |
4813 FROB (WM_INITMENUPOPUP) | |
4814 FROB (WM_MENUSELECT) | |
4815 FROB (WM_MENUCHAR) | |
4816 FROB (WM_ENTERIDLE) | |
4817 #if(WINVER >= 0x0500) | |
4818 FROB (WM_MENURBUTTONUP) | |
1687 | 4819 #ifdef WM_MENUDRAG |
593 | 4820 FROB (WM_MENUDRAG) |
1687 | 4821 #endif |
4822 #ifdef WM_MENUGETOBJECT | |
593 | 4823 FROB (WM_MENUGETOBJECT) |
1687 | 4824 #endif |
4825 #ifdef WM_UNINITMENUPOPUP | |
593 | 4826 FROB (WM_UNINITMENUPOPUP) |
1687 | 4827 #endif |
4828 #ifdef WM_MENUCOMMAND | |
593 | 4829 FROB (WM_MENUCOMMAND) |
1687 | 4830 #endif |
593 | 4831 #endif /* WINVER >= 0x0500 */ |
4832 | |
4833 | |
4834 FROB (WM_CTLCOLORMSGBOX) | |
4835 FROB (WM_CTLCOLOREDIT) | |
4836 FROB (WM_CTLCOLORLISTBOX) | |
4837 FROB (WM_CTLCOLORBTN) | |
4838 FROB (WM_CTLCOLORDLG) | |
4839 FROB (WM_CTLCOLORSCROLLBAR) | |
4840 FROB (WM_CTLCOLORSTATIC) | |
4841 | |
4842 | |
4843 /* FROB (WM_MOUSEFIRST) */ | |
4844 FROB (WM_MOUSEMOVE) | |
4845 FROB (WM_LBUTTONDOWN) | |
4846 FROB (WM_LBUTTONUP) | |
4847 FROB (WM_LBUTTONDBLCLK) | |
4848 FROB (WM_RBUTTONDOWN) | |
4849 FROB (WM_RBUTTONUP) | |
4850 FROB (WM_RBUTTONDBLCLK) | |
4851 FROB (WM_MBUTTONDOWN) | |
4852 FROB (WM_MBUTTONUP) | |
4853 FROB (WM_MBUTTONDBLCLK) | |
4854 | |
4855 #if (_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400) | |
4856 FROB (WM_MOUSEWHEEL) | |
4857 FROB (WM_MOUSELAST) | |
4858 #else | |
4859 FROB (WM_MOUSELAST) | |
4860 #endif /* if (_WIN32_WINNT < 0x0400) */ | |
4861 | |
4862 FROB (WM_PARENTNOTIFY) | |
4863 FROB (WM_ENTERMENULOOP) | |
4864 FROB (WM_EXITMENULOOP) | |
4865 | |
4866 #if(WINVER >= 0x0400) | |
4867 FROB (WM_NEXTMENU) | |
4868 | |
4869 FROB (WM_SIZING) | |
4870 FROB (WM_CAPTURECHANGED) | |
4871 FROB (WM_MOVING) | |
4872 FROB (WM_POWERBROADCAST) | |
4873 | |
4874 FROB (WM_DEVICECHANGE) | |
4875 | |
4876 #endif /* WINVER >= 0x0400 */ | |
4877 | |
4878 FROB (WM_MDICREATE) | |
4879 FROB (WM_MDIDESTROY) | |
4880 FROB (WM_MDIACTIVATE) | |
4881 FROB (WM_MDIRESTORE) | |
4882 FROB (WM_MDINEXT) | |
4883 FROB (WM_MDIMAXIMIZE) | |
4884 FROB (WM_MDITILE) | |
4885 FROB (WM_MDICASCADE) | |
4886 FROB (WM_MDIICONARRANGE) | |
4887 FROB (WM_MDIGETACTIVE) | |
4888 | |
4889 | |
4890 FROB (WM_MDISETMENU) | |
4891 FROB (WM_ENTERSIZEMOVE) | |
4892 FROB (WM_EXITSIZEMOVE) | |
4893 FROB (WM_DROPFILES) | |
4894 FROB (WM_MDIREFRESHMENU) | |
4895 | |
604 | 4896 #ifdef WM_IME_SETCONTEXT /* not in Cygwin? */ |
593 | 4897 |
4898 #if(WINVER >= 0x0400) | |
4899 FROB (WM_IME_SETCONTEXT) | |
4900 FROB (WM_IME_NOTIFY) | |
4901 FROB (WM_IME_CONTROL) | |
4902 FROB (WM_IME_COMPOSITIONFULL) | |
4903 FROB (WM_IME_SELECT) | |
4904 FROB (WM_IME_CHAR) | |
4905 #endif /* WINVER >= 0x0400 */ | |
1687 | 4906 #if(WINVER >= 0x0500) && defined(WM_IME_REQUEST) |
593 | 4907 FROB (WM_IME_REQUEST) |
4908 #endif /* WINVER >= 0x0500 */ | |
4909 #if(WINVER >= 0x0400) | |
4910 FROB (WM_IME_KEYDOWN) | |
4911 FROB (WM_IME_KEYUP) | |
4912 #endif /* WINVER >= 0x0400 */ | |
4913 | |
604 | 4914 #endif /* WM_IME_SETCONTEXT */ |
593 | 4915 |
4916 #if(_WIN32_WINNT >= 0x0400) | |
4917 FROB (WM_MOUSEHOVER) | |
4918 FROB (WM_MOUSELEAVE) | |
4919 #endif /* _WIN32_WINNT >= 0x0400 */ | |
4920 | |
4921 FROB (WM_CUT) | |
4922 FROB (WM_COPY) | |
4923 FROB (WM_PASTE) | |
4924 FROB (WM_CLEAR) | |
4925 FROB (WM_UNDO) | |
4926 FROB (WM_RENDERFORMAT) | |
4927 FROB (WM_RENDERALLFORMATS) | |
4928 FROB (WM_DESTROYCLIPBOARD) | |
4929 FROB (WM_DRAWCLIPBOARD) | |
4930 FROB (WM_PAINTCLIPBOARD) | |
4931 FROB (WM_VSCROLLCLIPBOARD) | |
4932 FROB (WM_SIZECLIPBOARD) | |
4933 FROB (WM_ASKCBFORMATNAME) | |
4934 FROB (WM_CHANGECBCHAIN) | |
4935 FROB (WM_HSCROLLCLIPBOARD) | |
4936 FROB (WM_QUERYNEWPALETTE) | |
4937 FROB (WM_PALETTEISCHANGING) | |
4938 FROB (WM_PALETTECHANGED) | |
4939 FROB (WM_HOTKEY) | |
4940 | |
4941 #if(WINVER >= 0x0400) | |
4942 FROB (WM_PRINT) | |
4943 FROB (WM_PRINTCLIENT) | |
4944 | |
4945 FROB (WM_HANDHELDFIRST) | |
4946 FROB (WM_HANDHELDLAST) | |
4947 | |
4948 FROB (WM_AFXFIRST) | |
4949 FROB (WM_AFXLAST) | |
4950 #endif /* WINVER >= 0x0400 */ | |
4951 | |
4952 FROB (WM_PENWINFIRST) | |
4953 FROB (WM_PENWINLAST) | |
4954 }; | |
4955 | |
4956 #undef FROB | |
4957 | |
4958 static void | |
4959 debug_output_mswin_message (HWND hwnd, UINT message_, WPARAM wParam, | |
4960 LPARAM lParam) | |
4961 { | |
4962 Lisp_Object frame = mswindows_find_frame (hwnd); | |
4963 int i; | |
4932 | 4964 const Ascbyte *str = 0; |
593 | 4965 /* struct mswin_message_debug *i_hate_cranking_out_code_like_this; */ |
4966 | |
4967 for (i = 0; i < countof (debug_mswin_messages); i++) | |
4968 { | |
647 | 4969 if (debug_mswin_messages[i].mess == (int) message_) |
593 | 4970 { |
4971 str = debug_mswin_messages[i].string; | |
4972 break; | |
4973 } | |
4974 } | |
4975 | |
4976 if (str) | |
4977 stderr_out ("%s", str); | |
4978 else | |
4979 stderr_out ("%x", message_); | |
4980 | |
4981 if (debug_mswindows_events > 1) | |
4982 { | |
4983 stderr_out (" wparam=%d lparam=%d hwnd=%x frame: ", | |
4984 wParam, (int) lParam, (unsigned int) hwnd); | |
4985 debug_print (frame); | |
903 | 4986 if (message_ == WM_WINDOWPOSCHANGED || |
4987 message_ == WM_WINDOWPOSCHANGING) | |
4988 { | |
4989 WINDOWPOS *wp = (WINDOWPOS *) lParam; | |
4990 stderr_out(" WINDOWPOS: x=%d, y=%d, h=%d, w=%d\n", | |
4991 wp->x, wp->y, wp->cx, wp->cy); | |
4992 } | |
4993 else if (message_ == WM_MOVE) | |
4994 { | |
4995 int x = (int)(short) LOWORD(lParam); /* horizontal position */ | |
4996 int y = (int)(short) HIWORD(lParam); /* vertical position */ | |
4997 stderr_out(" MOVE: x=%d, y=%d\n", x, y); | |
4998 } | |
4999 else if (message_ == WM_SIZE) | |
5000 { | |
5001 int w = (int)(short) LOWORD(lParam); /* width */ | |
5002 int h = (int)(short) HIWORD(lParam); /* height */ | |
5003 stderr_out(" SIZE: w=%d, h=%d\n", w, h); | |
5004 } | |
593 | 5005 } |
5006 else | |
5007 stderr_out ("\n"); | |
5008 } | |
5009 | |
5010 #endif /* DEBUG_XEMACS */ | |
5011 | |
428 | 5012 /************************************************************************/ |
5013 /* initialization */ | |
5014 /************************************************************************/ | |
5015 | |
5016 void | |
5017 reinit_vars_of_event_mswindows (void) | |
5018 { | |
5019 mswindows_pending_timers_count = 0; | |
5020 | |
1204 | 5021 mswindows_event_stream = xnew_and_zero (struct event_stream); |
428 | 5022 |
5023 mswindows_event_stream->event_pending_p = emacs_mswindows_event_pending_p; | |
5024 mswindows_event_stream->next_event_cb = emacs_mswindows_next_event; | |
5025 mswindows_event_stream->handle_magic_event_cb = emacs_mswindows_handle_magic_event; | |
788 | 5026 mswindows_event_stream->format_magic_event_cb = emacs_mswindows_format_magic_event; |
5027 mswindows_event_stream->compare_magic_event_cb= emacs_mswindows_compare_magic_event; | |
5028 mswindows_event_stream->hash_magic_event_cb = emacs_mswindows_hash_magic_event; | |
428 | 5029 mswindows_event_stream->add_timeout_cb = emacs_mswindows_add_timeout; |
5030 mswindows_event_stream->remove_timeout_cb = emacs_mswindows_remove_timeout; | |
1204 | 5031 mswindows_event_stream->drain_queue_cb = emacs_mswindows_drain_queue; |
428 | 5032 mswindows_event_stream->select_console_cb = emacs_mswindows_select_console; |
5033 mswindows_event_stream->unselect_console_cb = emacs_mswindows_unselect_console; | |
5034 mswindows_event_stream->select_process_cb = emacs_mswindows_select_process; | |
5035 mswindows_event_stream->unselect_process_cb = emacs_mswindows_unselect_process; | |
853 | 5036 mswindows_event_stream->create_io_streams_cb = emacs_mswindows_create_io_streams; |
5037 mswindows_event_stream->delete_io_streams_cb = emacs_mswindows_delete_io_streams; | |
442 | 5038 mswindows_event_stream->current_event_timestamp_cb = |
5039 emacs_mswindows_current_event_timestamp; | |
903 | 5040 |
5041 dde_eval_pending = 0; | |
428 | 5042 } |
5043 | |
5044 void | |
5045 vars_of_event_mswindows (void) | |
5046 { | |
5047 mswindows_s_dispatch_event_queue = Qnil; | |
5048 staticpro (&mswindows_s_dispatch_event_queue); | |
5049 mswindows_s_dispatch_event_queue_tail = Qnil; | |
1204 | 5050 dump_add_root_lisp_object (&mswindows_s_dispatch_event_queue_tail); |
428 | 5051 |
853 | 5052 mswindows_error_caught_in_modal_loop = 0; |
442 | 5053 |
903 | 5054 #ifdef HAVE_DRAGNDROP |
5055 Fprovide (Qdde); | |
5056 | |
5057 DEFVAR_LISP ("dde-advise-items", &Vdde_advise_items /* | |
5058 A list of allocated DDE advise items. | |
5059 Each item is an uninterned symbol, created using dde-alloc-advise-item. | |
5060 | |
5061 The symbol's value is the data which is returned to the DDE client when | |
5062 a request for the item is made (or a dde-advise call is made). | |
5063 | |
3025 | 5064 The symbol also has a `HSZ' property, which holds the DDE string handle |
903 | 5065 for the item, as a float. This is for internal use only, and should not |
5066 be modified. | |
5067 */ ); | |
5068 Vdde_advise_items = Qnil; | |
5069 | |
5070 dde_eval_result = Qnil; | |
5071 staticpro (&dde_eval_result); | |
5072 dde_eval_error = Qnil; | |
5073 staticpro (&dde_eval_error); | |
5074 #endif | |
5075 | |
442 | 5076 #ifdef DEBUG_XEMACS |
5077 DEFVAR_INT ("debug-mswindows-events", &debug_mswindows_events /* | |
593 | 5078 If non-zero, display debug information about Windows messages that XEmacs sees. |
442 | 5079 Information is displayed in a console window. Currently defined values are: |
5080 | |
593 | 5081 1 == non-verbose output (just the message name) |
5082 2 == verbose output (all parameters) | |
5083 3 == even more verbose output (extra debugging info) | |
442 | 5084 */ ); |
5085 debug_mswindows_events = 0; | |
5086 #endif | |
5087 | |
5088 DEFVAR_BOOL ("mswindows-alt-by-itself-activates-menu", | |
5089 &mswindows_alt_by_itself_activates_menu /* | |
5090 *Controls whether pressing and releasing the Alt key activates the menubar. | |
5091 This applies only if no intervening key was pressed. See also | |
5092 `menu-accelerator-enabled', which is probably the behavior you actually want. | |
428 | 5093 Default is t. |
5094 */ ); | |
5095 | |
442 | 5096 DEFVAR_BOOL ("mswindows-dynamic-frame-resize", |
5097 &mswindows_dynamic_frame_resize /* | |
428 | 5098 *Controls redrawing frame contents during mouse-drag or keyboard resize |
5099 operation. When non-nil, the frame is redrawn while being resized. When | |
5100 nil, frame is not redrawn, and exposed areas are filled with default | |
5101 MDI application background color. Note that this option only has effect | |
5102 if "Show window contents while dragging" is on in system Display/Plus! | |
5103 settings. | |
5104 Default is t on fast machines, nil on slow. | |
5105 */ ); | |
5106 | |
442 | 5107 DEFVAR_INT ("mswindows-mouse-button-tolerance", |
5108 &mswindows_mouse_button_tolerance /* | |
428 | 5109 *Analogue of double click interval for faking middle mouse events. |
5110 The value is the minimum time in milliseconds that must elapse between | |
5111 left/right button down events before they are considered distinct events. | |
5112 If both mouse buttons are depressed within this interval, a middle mouse | |
5113 button down event is generated instead. | |
5114 If negative or zero, currently set system default is used instead. | |
5115 */ ); | |
5116 | |
5117 DEFVAR_INT ("mswindows-num-mouse-buttons", &mswindows_num_mouse_buttons /* | |
5118 Number of physical mouse buttons. | |
5119 */ ); | |
5120 | |
442 | 5121 DEFVAR_INT ("mswindows-mouse-button-max-skew-x", |
5122 &mswindows_mouse_button_max_skew_x /* | |
428 | 5123 *Maximum horizontal distance in pixels between points in which left and |
5124 right button clicks occurred for them to be translated into single | |
5125 middle button event. Clicks must occur in time not longer than defined | |
5126 by the variable `mswindows-mouse-button-tolerance'. | |
5127 If negative or zero, currently set system default is used instead. | |
5128 */ ); | |
5129 | |
442 | 5130 DEFVAR_INT ("mswindows-mouse-button-max-skew-y", |
5131 &mswindows_mouse_button_max_skew_y /* | |
428 | 5132 *Maximum vertical distance in pixels between points in which left and |
5133 right button clicks occurred for them to be translated into single | |
5134 middle button event. Clicks must occur in time not longer than defined | |
5135 by the variable `mswindows-mouse-button-tolerance'. | |
5136 If negative or zero, currently set system default is used instead. | |
5137 */ ); | |
5138 | |
5139 mswindows_mouse_button_max_skew_x = 0; | |
5140 mswindows_mouse_button_max_skew_y = 0; | |
5141 mswindows_mouse_button_tolerance = 0; | |
442 | 5142 mswindows_alt_by_itself_activates_menu = 1; |
428 | 5143 } |
5144 | |
5145 void | |
5146 syms_of_event_mswindows (void) | |
5147 { | |
903 | 5148 #ifdef HAVE_DRAGNDROP |
5149 DEFSYMBOL(QHSZ); | |
5150 DEFSUBR(Fdde_alloc_advise_item); | |
5151 DEFSUBR(Fdde_free_advise_item); | |
5152 DEFSUBR(Fdde_advise); | |
5153 #endif | |
428 | 5154 } |
5155 | |
5156 void | |
5157 lstream_type_create_mswindows_selectable (void) | |
5158 { | |
853 | 5159 #ifndef CYGWIN |
428 | 5160 init_slurp_stream (); |
5161 init_shove_stream (); | |
5162 init_winsock_stream (); | |
5163 #endif | |
5164 } | |
5165 | |
5166 void | |
5167 init_event_mswindows_late (void) | |
5168 { | |
853 | 5169 #ifdef CYGWIN |
771 | 5170 windows_fd = retry_open ("/dev/windows", O_RDONLY | O_NONBLOCK, 0); |
814 | 5171 assert (windows_fd >= 0); |
428 | 5172 FD_SET (windows_fd, &input_wait_mask); |
814 | 5173 FD_ZERO (&zero_mask); |
428 | 5174 #endif |
5175 | |
5176 event_stream = mswindows_event_stream; | |
5177 | |
5178 mswindows_dynamic_frame_resize = !GetSystemMetrics (SM_SLOWMACHINE); | |
5179 mswindows_num_mouse_buttons = GetSystemMetrics (SM_CMOUSEBUTTONS); | |
5180 } |