Mercurial > hg > xemacs-beta
annotate src/event-Xt.c @ 5602:c9e5612f5424
Support the MP library on recent FreeBSD, have it pass relevant tests.
src/ChangeLog addition:
2011-11-26 Aidan Kehoe <kehoea@parhasard.net>
* number-mp.c (bignum_to_string):
Don't overwrite the accumulator we've just set up for this
function.
* number-mp.c (BIGNUM_TO_TYPE):
mp_itom() doesn't necessarily do what this code used to think with
negative numbers, it can treat them as unsigned ints. Subtract
numbers from bignum_zero instead of multiplying them by -1 to
convert them to their negative equivalents.
* number-mp.c (bignum_to_int):
* number-mp.c (bignum_to_uint):
* number-mp.c (bignum_to_long):
* number-mp.c (bignum_to_ulong):
* number-mp.c (bignum_to_double):
Use the changed BIGNUM_TO_TYPE() in these functions.
* number-mp.c (bignum_ceil):
* number-mp.c (bignum_floor):
In these functions, be more careful about rounding to positive and
negative infinity, respectively. Don't use the sign of QUOTIENT
when working out out whether to add or subtract one, rather use
the sign QUOTIENT would have if arbitrary-precision division were
done.
* number-mp.h:
* number-mp.h (MP_GCD):
Wrap #include <mp.h> in BEGIN_C_DECLS/END_C_DECLS.
* number.c (Fbigfloat_get_precision):
* number.c (Fbigfloat_set_precision):
Don't attempt to call XBIGFLOAT_GET_PREC if this build doesn't
support big floats.
author | Aidan Kehoe <kehoea@parhasard.net> |
---|---|
date | Sat, 26 Nov 2011 17:59:14 +0000 |
parents | 56144c8593a8 |
children | 1d1f385c9149 |
rev | line source |
---|---|
428 | 1 /* The event_stream interface for X11 with Xt, and/or tty frames. |
2 Copyright (C) 1991-5, 1997 Free Software Foundation, Inc. | |
3 Copyright (C) 1995 Sun Microsystems, Inc. | |
5018
a7a237f818d9
add comment about simultaneous window-system consoles
Ben Wing <ben@xemacs.org>
parents:
4976
diff
changeset
|
4 Copyright (C) 1996, 2001, 2002, 2003, 2010 Ben Wing. |
5080
5502045ec510
The background-placement face property.
Didier Verna <didier@lrde.epita.fr>
parents:
5018
diff
changeset
|
5 Copyright (C) 2010 Didier Verna |
428 | 6 |
7 This file is part of XEmacs. | |
8 | |
5402
308d34e9f07d
Changed bulk of GPLv2 or later files identified by script
Mats Lidell <matsl@xemacs.org>
parents:
5191
diff
changeset
|
9 XEmacs is free software: you can redistribute it and/or modify it |
428 | 10 under the terms of the GNU General Public License as published by the |
5402
308d34e9f07d
Changed bulk of GPLv2 or later files identified by script
Mats Lidell <matsl@xemacs.org>
parents:
5191
diff
changeset
|
11 Free Software Foundation, either version 3 of the License, or (at your |
308d34e9f07d
Changed bulk of GPLv2 or later files identified by script
Mats Lidell <matsl@xemacs.org>
parents:
5191
diff
changeset
|
12 option) any later version. |
428 | 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 | |
5402
308d34e9f07d
Changed bulk of GPLv2 or later files identified by script
Mats Lidell <matsl@xemacs.org>
parents:
5191
diff
changeset
|
20 along with XEmacs. If not, see <http://www.gnu.org/licenses/>. */ |
428 | 21 |
22 /* Synched up with: Not in FSF. */ | |
23 | |
5018
a7a237f818d9
add comment about simultaneous window-system consoles
Ben Wing <ben@xemacs.org>
parents:
4976
diff
changeset
|
24 /* NOTE: It would be possible to fix things so that all of GTK, Windows, X, |
a7a237f818d9
add comment about simultaneous window-system consoles
Ben Wing <ben@xemacs.org>
parents:
4976
diff
changeset
|
25 TTY and stream can have consoles at the same time. We already do lots |
a7a237f818d9
add comment about simultaneous window-system consoles
Ben Wing <ben@xemacs.org>
parents:
4976
diff
changeset
|
26 of combinations. Basically, either call select() directly or some |
a7a237f818d9
add comment about simultaneous window-system consoles
Ben Wing <ben@xemacs.org>
parents:
4976
diff
changeset
|
27 interface onto it, and select() over all the filedescs, including the |
a7a237f818d9
add comment about simultaneous window-system consoles
Ben Wing <ben@xemacs.org>
parents:
4976
diff
changeset
|
28 X and GTK socket, and under Cygwin, the Windows device. Then for whichever |
a7a237f818d9
add comment about simultaneous window-system consoles
Ben Wing <ben@xemacs.org>
parents:
4976
diff
changeset
|
29 filedesc there's an event, call the appropriate window-system-specific |
a7a237f818d9
add comment about simultaneous window-system consoles
Ben Wing <ben@xemacs.org>
parents:
4976
diff
changeset
|
30 method to pull the event(s) and store onto the dispatch queue. --ben */ |
a7a237f818d9
add comment about simultaneous window-system consoles
Ben Wing <ben@xemacs.org>
parents:
4976
diff
changeset
|
31 |
428 | 32 #include <config.h> |
33 #include "lisp.h" | |
34 | |
35 #include "blocktype.h" | |
771 | 36 #include "charset.h" |
428 | 37 #include "console.h" |
872 | 38 #include "device-impl.h" |
800 | 39 #include "elhash.h" |
428 | 40 #include "events.h" |
800 | 41 #include "file-coding.h" |
872 | 42 #include "frame-impl.h" |
800 | 43 #include "glyphs.h" |
44 #include "lstream.h" | |
428 | 45 #include "process.h" |
46 #include "redisplay.h" | |
800 | 47 #include "window.h" |
48 | |
49 #include "console-tty.h" | |
50 | |
872 | 51 #include "console-x-impl.h" |
5176
8b2f75cecb89
rename objects* (.c, .h and .el files) to fontcolor*
Ben Wing <ben@xemacs.org>
parents:
5018
diff
changeset
|
52 #include "fontcolor-x.h" |
800 | 53 #include "../lwlib/lwlib.h" |
54 #include "EmacsFrame.h" | |
55 | |
56 #include "sysproc.h" /* for MAXDESC */ | |
428 | 57 #include "systime.h" |
58 | |
59 #include "xintrinsicp.h" /* CoreP.h needs this */ | |
60 #include <X11/CoreP.h> /* Numerous places access the fields of | |
61 a core widget directly. We could | |
62 use XtGetValues(), but ... */ | |
63 #include <X11/ShellP.h> | |
64 | |
800 | 65 #if defined (HAVE_XIM) && defined (XIM_MOTIF) |
1315 | 66 #include "xmotif.h" |
428 | 67 #endif |
68 | |
69 #ifdef HAVE_DRAGNDROP | |
70 #include "dragdrop.h" | |
71 #endif | |
72 | |
1292 | 73 #ifdef WIN32_ANY |
74 extern int mswindows_is_blocking; | |
75 #endif | |
76 | |
2828 | 77 /* For Russian C-x processing. */ |
3171 | 78 Lisp_Object Vx_us_keymap_description; |
79 Fixnum Vx_us_keymap_first_keycode; | |
2699 | 80 |
1094 | 81 /* used in glyphs-x.c */ |
82 void enqueue_focus_event (Widget wants_it, Lisp_Object frame, int in_p); | |
428 | 83 static void handle_focus_event_1 (struct frame *f, int in_p); |
863 | 84 static void handle_focus_event_2 (Window w, struct frame *f, int in_p); |
428 | 85 |
86 static struct event_stream *Xt_event_stream; | |
87 | |
88 /* With the new event model, all events go through XtDispatchEvent() | |
89 and are picked up by an event handler that is added to each frame | |
90 widget. (This is how it's supposed to be.) In the old method, | |
91 Emacs sucks out events directly from XtNextEvent() and only | |
92 dispatches the events that it doesn't need to deal with. This | |
93 old way has lots of corresponding junk that is no longer | |
94 necessary: lwlib extensions, synthetic XAnyEvents, unnecessary | |
95 magic events, etc. */ | |
96 | |
97 /* The one and only one application context that Emacs uses. */ | |
98 XtAppContext Xt_app_con; | |
99 | |
100 /* Do we accept events sent by other clients? */ | |
101 int x_allow_sendevents; | |
102 | |
103 #ifdef DEBUG_XEMACS | |
458 | 104 Fixnum debug_x_events; |
428 | 105 #endif |
106 | |
107 static int process_events_occurred; | |
108 static int tty_events_occurred; | |
450 | 109 static Widget widget_with_focus; |
428 | 110 |
111 /* Mask of bits indicating the descriptors that we wait for input on */ | |
1268 | 112 extern SELECT_TYPE input_wait_mask, non_fake_input_wait_mask; |
113 extern SELECT_TYPE process_only_mask, tty_only_mask; | |
428 | 114 |
4528
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
115 /* #### This should be String, but G++ 4.3 doesn't apply the const |
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
116 specifier the same way for String (typedef'd to char*) and char*. */ |
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
117 static const char * x_fallback_resources[] = |
428 | 118 { |
119 /* This file is automatically generated from the app-defaults file | |
120 in ../etc/Emacs.ad. These resources are consulted only if no | |
121 app-defaults file is found at all. | |
122 */ | |
123 #include <Emacs.ad.h> | |
124 0 | |
125 }; | |
126 | |
127 static Lisp_Object x_keysym_to_emacs_keysym (KeySym keysym, int simple_p); | |
128 void emacs_Xt_mapping_action (Widget w, XEvent *event); | |
440 | 129 void debug_process_finalization (Lisp_Process *p); |
428 | 130 void emacs_Xt_event_handler (Widget wid, XtPointer closure, XEvent *event, |
131 Boolean *continue_to_dispatch); | |
132 | |
133 static int last_quit_check_signal_tick_count; | |
134 | |
1268 | 135 #define THIS_IS_X |
136 #include "event-xlike-inc.c" | |
137 | |
428 | 138 |
139 /************************************************************************/ | |
140 /* keymap handling */ | |
141 /************************************************************************/ | |
142 | |
2828 | 143 /* See comment near character_to_event(). */ |
440 | 144 static void |
2828 | 145 maybe_define_x_key_as_self_inserting_character (KeySym keysym, |
146 Lisp_Object symbol) | |
440 | 147 { |
148 Lisp_Object character = x_keysym_to_character (keysym); | |
149 | |
150 if (CHARP (character)) | |
151 { | |
152 extern Lisp_Object Vcurrent_global_map; | |
2828 | 153 extern Lisp_Object Qcharacter_of_keysym; |
971 | 154 if (NILP (Flookup_key (Vcurrent_global_map, symbol, Qnil))) |
155 { | |
2828 | 156 Fput (symbol, Qcharacter_of_keysym, character); |
971 | 157 Fdefine_key (Vcurrent_global_map, symbol, Qself_insert_command); |
158 } | |
440 | 159 } |
160 } | |
161 | |
2828 | 162 void |
440 | 163 x_has_keysym (KeySym keysym, Lisp_Object hash_table, int with_modifiers) |
164 { | |
165 KeySym upper_lower[2]; | |
166 int j; | |
167 | |
168 if (keysym < 0x80) /* Optimize for ASCII keysyms */ | |
169 return; | |
442 | 170 |
171 /* If you execute: | |
172 xmodmap -e 'keysym NN = scaron' | |
440 | 173 and then press (Shift scaron), X11 will return the different |
442 | 174 keysym `Scaron', but `xmodmap -pke' might not even mention `Scaron'. |
175 So we "register" both `scaron' and `Scaron'. */ | |
176 #ifdef HAVE_XCONVERTCASE | |
440 | 177 XConvertCase (keysym, &upper_lower[0], &upper_lower[1]); |
442 | 178 #else |
179 upper_lower[0] = upper_lower[1] = keysym; | |
180 #endif | |
440 | 181 |
182 for (j = 0; j < (upper_lower[0] == upper_lower[1] ? 1 : 2); j++) | |
183 { | |
2828 | 184 Extbyte *name; |
440 | 185 keysym = upper_lower[j]; |
186 | |
187 name = XKeysymToString (keysym); | |
188 if (name) | |
189 { | |
190 /* X guarantees NAME to be in the Host Portable Character Encoding */ | |
191 Lisp_Object sym = x_keysym_to_emacs_keysym (keysym, 0); | |
192 Lisp_Object new_value = with_modifiers ? Qt : Qsans_modifiers; | |
193 Lisp_Object old_value = Fgethash (sym, hash_table, Qnil); | |
194 | |
195 if (! EQ (old_value, new_value) | |
196 && ! (EQ (old_value, Qsans_modifiers) && | |
197 EQ (new_value, Qt))) | |
198 { | |
199 maybe_define_x_key_as_self_inserting_character (keysym, sym); | |
4953
304aebb79cd3
function renamings to track names of char typedefs
Ben Wing <ben@xemacs.org>
parents:
4952
diff
changeset
|
200 Fputhash (build_extstring (name, Qbinary), new_value, |
2828 | 201 hash_table); |
440 | 202 Fputhash (sym, new_value, hash_table); |
203 } | |
204 } | |
205 } | |
206 } | |
207 | |
428 | 208 static void |
209 x_reset_key_mapping (struct device *d) | |
210 { | |
211 Display *display = DEVICE_X_DISPLAY (d); | |
212 struct x_device *xd = DEVICE_X_DATA (d); | |
213 KeySym *keysym, *keysym_end; | |
214 Lisp_Object hash_table; | |
215 int key_code_count, keysyms_per_code; | |
216 | |
217 if (xd->x_keysym_map) | |
218 XFree ((char *) xd->x_keysym_map); | |
219 XDisplayKeycodes (display, | |
220 &xd->x_keysym_map_min_code, | |
221 &xd->x_keysym_map_max_code); | |
222 key_code_count = xd->x_keysym_map_max_code - xd->x_keysym_map_min_code + 1; | |
223 xd->x_keysym_map = | |
224 XGetKeyboardMapping (display, xd->x_keysym_map_min_code, key_code_count, | |
225 &xd->x_keysym_map_keysyms_per_code); | |
226 | |
227 hash_table = xd->x_keysym_map_hash_table; | |
228 if (HASH_TABLEP (hash_table)) | |
229 Fclrhash (hash_table); | |
230 else | |
231 xd->x_keysym_map_hash_table = hash_table = | |
5191
71ee43b8a74d
Add #'equalp as a hash test by default; add #'define-hash-table-test, GNU API
Aidan Kehoe <kehoea@parhasard.net>
parents:
5178
diff
changeset
|
232 make_lisp_hash_table (128, HASH_TABLE_NON_WEAK, Qequal); |
428 | 233 |
234 for (keysym = xd->x_keysym_map, | |
235 keysyms_per_code = xd->x_keysym_map_keysyms_per_code, | |
236 keysym_end = keysym + (key_code_count * keysyms_per_code); | |
237 keysym < keysym_end; | |
238 keysym += keysyms_per_code) | |
239 { | |
240 int j; | |
241 | |
242 if (keysym[0] == NoSymbol) | |
243 continue; | |
244 | |
440 | 245 x_has_keysym (keysym[0], hash_table, 0); |
428 | 246 |
247 for (j = 1; j < keysyms_per_code; j++) | |
248 { | |
249 if (keysym[j] != keysym[0] && | |
250 keysym[j] != NoSymbol) | |
440 | 251 x_has_keysym (keysym[j], hash_table, 1); |
428 | 252 } |
253 } | |
254 } | |
255 | |
2828 | 256 static const Ascbyte * |
428 | 257 index_to_name (int indice) |
258 { | |
259 switch (indice) | |
260 { | |
261 case ShiftMapIndex: return "ModShift"; | |
262 case LockMapIndex: return "ModLock"; | |
263 case ControlMapIndex: return "ModControl"; | |
264 case Mod1MapIndex: return "Mod1"; | |
265 case Mod2MapIndex: return "Mod2"; | |
266 case Mod3MapIndex: return "Mod3"; | |
267 case Mod4MapIndex: return "Mod4"; | |
268 case Mod5MapIndex: return "Mod5"; | |
269 default: return "???"; | |
270 } | |
271 } | |
272 | |
2828 | 273 /* X bogusly doesn't define the interpretations of any bits besides |
274 ModControl, ModShift, and ModLock; so the Interclient Communication | |
275 Conventions Manual says that we have to bend over backwards to figure | |
276 out what the other modifier bits mean. According to ICCCM: | |
277 | |
278 - Any keycode which is assigned ModControl is a "control" key. | |
279 | |
280 - Any modifier bit which is assigned to a keycode which generates Meta_L | |
281 or Meta_R is the modifier bit meaning "meta". Likewise for Super, Hyper, | |
282 etc. | |
283 | |
284 - Any keypress event which contains ModControl in its state should be | |
285 interpreted as a "control" character. | |
286 | |
287 - Any keypress event which contains a modifier bit in its state which is | |
288 generated by a keycode whose corresponding keysym is Meta_L or Meta_R | |
289 should be interpreted as a "meta" character. Likewise for Super, Hyper, | |
290 etc. | |
291 | |
292 - It is illegal for a keysym to be associated with more than one modifier | |
293 bit. | |
294 | |
295 This means that the only thing that emacs can reasonably interpret as a | |
296 "meta" key is a key whose keysym is Meta_L or Meta_R, and which generates | |
297 one of the modifier bits Mod1-Mod5. | |
298 | |
299 Unfortunately, many keyboards don't have Meta keys in their default | |
300 configuration. So, if there are no Meta keys, but there are "Alt" keys, | |
301 emacs will interpret Alt as Meta. If there are both Meta and Alt keys, | |
302 then the Meta keys mean "Meta", and the Alt keys mean "Alt" (it used to | |
303 mean "Symbol," but that just confused the hell out of way too many people). | |
304 | |
305 This works with the default configurations of the 19 keyboard-types I've | |
306 checked. | |
307 | |
308 Emacs detects keyboard configurations which violate the above rules, and | |
309 gives a warning. */ | |
428 | 310 |
311 static void | |
312 x_reset_modifier_mapping (struct device *d) | |
313 { | |
314 Display *display = DEVICE_X_DISPLAY (d); | |
315 struct x_device *xd = DEVICE_X_DATA (d); | |
316 int modifier_index, modifier_key, column, mkpm; | |
317 int warned_about_overlapping_modifiers = 0; | |
318 int warned_about_predefined_modifiers = 0; | |
319 int warned_about_duplicate_modifiers = 0; | |
320 int meta_bit = 0; | |
321 int hyper_bit = 0; | |
322 int super_bit = 0; | |
323 int alt_bit = 0; | |
324 int mode_bit = 0; | |
325 | |
326 xd->lock_interpretation = 0; | |
327 | |
328 if (xd->x_modifier_keymap) | |
3949 | 329 { |
330 XFreeModifiermap (xd->x_modifier_keymap); | |
331 /* Set it to NULL in case we receive two MappingModifier events in a | |
332 row, and the second is processed during some CHECK_QUITs within | |
333 x_reset_key_mapping. If that happens, XFreeModifierMap will be | |
334 called twice on the same map, and we crash. */ | |
335 xd->x_modifier_keymap = NULL; | |
336 } | |
428 | 337 |
338 x_reset_key_mapping (d); | |
339 | |
340 xd->x_modifier_keymap = XGetModifierMapping (display); | |
341 | |
342 /* Boy, I really wish C had local functions... | |
343 */ | |
344 | |
4952
19a72041c5ed
Mule-izing, various fixes related to char * arguments
Ben Wing <ben@xemacs.org>
parents:
4790
diff
changeset
|
345 #define modwarn(name,old,other) \ |
19a72041c5ed
Mule-izing, various fixes related to char * arguments
Ben Wing <ben@xemacs.org>
parents:
4790
diff
changeset
|
346 warn_when_safe (Qkey_mapping, Qwarning, \ |
19a72041c5ed
Mule-izing, various fixes related to char * arguments
Ben Wing <ben@xemacs.org>
parents:
4790
diff
changeset
|
347 "XEmacs: %s (0x%x) generates %s, which is generated by %s.", \ |
19a72041c5ed
Mule-izing, various fixes related to char * arguments
Ben Wing <ben@xemacs.org>
parents:
4790
diff
changeset
|
348 name, code, index_to_name (old), other), \ |
428 | 349 warned_about_overlapping_modifiers = 1 |
350 | |
4952
19a72041c5ed
Mule-izing, various fixes related to char * arguments
Ben Wing <ben@xemacs.org>
parents:
4790
diff
changeset
|
351 #define modbarf(name,other) \ |
19a72041c5ed
Mule-izing, various fixes related to char * arguments
Ben Wing <ben@xemacs.org>
parents:
4790
diff
changeset
|
352 warn_when_safe (Qkey_mapping, Qwarning, \ |
19a72041c5ed
Mule-izing, various fixes related to char * arguments
Ben Wing <ben@xemacs.org>
parents:
4790
diff
changeset
|
353 "XEmacs: %s (0x%x) generates %s, which is nonsensical.", \ |
19a72041c5ed
Mule-izing, various fixes related to char * arguments
Ben Wing <ben@xemacs.org>
parents:
4790
diff
changeset
|
354 name, code, other), \ |
428 | 355 warned_about_predefined_modifiers = 1 |
356 | |
4952
19a72041c5ed
Mule-izing, various fixes related to char * arguments
Ben Wing <ben@xemacs.org>
parents:
4790
diff
changeset
|
357 #define check_modifier(name,mask) \ |
19a72041c5ed
Mule-izing, various fixes related to char * arguments
Ben Wing <ben@xemacs.org>
parents:
4790
diff
changeset
|
358 if ((1<<modifier_index) != mask) \ |
19a72041c5ed
Mule-izing, various fixes related to char * arguments
Ben Wing <ben@xemacs.org>
parents:
4790
diff
changeset
|
359 warn_when_safe (Qkey_mapping, Qwarning, \ |
19a72041c5ed
Mule-izing, various fixes related to char * arguments
Ben Wing <ben@xemacs.org>
parents:
4790
diff
changeset
|
360 "XEmacs: %s (0x%x) generates %s, which is nonsensical.", \ |
19a72041c5ed
Mule-izing, various fixes related to char * arguments
Ben Wing <ben@xemacs.org>
parents:
4790
diff
changeset
|
361 name, code, index_to_name (modifier_index)), \ |
428 | 362 warned_about_predefined_modifiers = 1 |
363 | |
4952
19a72041c5ed
Mule-izing, various fixes related to char * arguments
Ben Wing <ben@xemacs.org>
parents:
4790
diff
changeset
|
364 #define store_modifier(name,old) \ |
19a72041c5ed
Mule-izing, various fixes related to char * arguments
Ben Wing <ben@xemacs.org>
parents:
4790
diff
changeset
|
365 if (old && old != modifier_index) \ |
19a72041c5ed
Mule-izing, various fixes related to char * arguments
Ben Wing <ben@xemacs.org>
parents:
4790
diff
changeset
|
366 warn_when_safe (Qkey_mapping, Qwarning, \ |
19a72041c5ed
Mule-izing, various fixes related to char * arguments
Ben Wing <ben@xemacs.org>
parents:
4790
diff
changeset
|
367 "XEmacs: %s (0x%x) generates both %s and %s, which is nonsensical.", \ |
19a72041c5ed
Mule-izing, various fixes related to char * arguments
Ben Wing <ben@xemacs.org>
parents:
4790
diff
changeset
|
368 name, code, index_to_name (old), \ |
19a72041c5ed
Mule-izing, various fixes related to char * arguments
Ben Wing <ben@xemacs.org>
parents:
4790
diff
changeset
|
369 index_to_name (modifier_index)), \ |
19a72041c5ed
Mule-izing, various fixes related to char * arguments
Ben Wing <ben@xemacs.org>
parents:
4790
diff
changeset
|
370 warned_about_duplicate_modifiers = 1; \ |
19a72041c5ed
Mule-izing, various fixes related to char * arguments
Ben Wing <ben@xemacs.org>
parents:
4790
diff
changeset
|
371 if (modifier_index == ShiftMapIndex) modbarf (name,"ModShift"); \ |
19a72041c5ed
Mule-izing, various fixes related to char * arguments
Ben Wing <ben@xemacs.org>
parents:
4790
diff
changeset
|
372 else if (modifier_index == LockMapIndex) modbarf (name,"ModLock"); \ |
428 | 373 else if (modifier_index == ControlMapIndex) modbarf (name,"ModControl"); \ |
4952
19a72041c5ed
Mule-izing, various fixes related to char * arguments
Ben Wing <ben@xemacs.org>
parents:
4790
diff
changeset
|
374 else if (sym == XK_Mode_switch) \ |
19a72041c5ed
Mule-izing, various fixes related to char * arguments
Ben Wing <ben@xemacs.org>
parents:
4790
diff
changeset
|
375 mode_bit = modifier_index; /* Mode_switch is special, see below... */ \ |
19a72041c5ed
Mule-izing, various fixes related to char * arguments
Ben Wing <ben@xemacs.org>
parents:
4790
diff
changeset
|
376 else if (modifier_index == meta_bit && old != meta_bit) \ |
19a72041c5ed
Mule-izing, various fixes related to char * arguments
Ben Wing <ben@xemacs.org>
parents:
4790
diff
changeset
|
377 modwarn (name, meta_bit, "Meta"); \ |
19a72041c5ed
Mule-izing, various fixes related to char * arguments
Ben Wing <ben@xemacs.org>
parents:
4790
diff
changeset
|
378 else if (modifier_index == super_bit && old != super_bit) \ |
19a72041c5ed
Mule-izing, various fixes related to char * arguments
Ben Wing <ben@xemacs.org>
parents:
4790
diff
changeset
|
379 modwarn (name, super_bit, "Super"); \ |
19a72041c5ed
Mule-izing, various fixes related to char * arguments
Ben Wing <ben@xemacs.org>
parents:
4790
diff
changeset
|
380 else if (modifier_index == hyper_bit && old != hyper_bit) \ |
19a72041c5ed
Mule-izing, various fixes related to char * arguments
Ben Wing <ben@xemacs.org>
parents:
4790
diff
changeset
|
381 modwarn (name, hyper_bit, "Hyper"); \ |
19a72041c5ed
Mule-izing, various fixes related to char * arguments
Ben Wing <ben@xemacs.org>
parents:
4790
diff
changeset
|
382 else if (modifier_index == alt_bit && old != alt_bit) \ |
19a72041c5ed
Mule-izing, various fixes related to char * arguments
Ben Wing <ben@xemacs.org>
parents:
4790
diff
changeset
|
383 modwarn (name, alt_bit, "Alt"); \ |
19a72041c5ed
Mule-izing, various fixes related to char * arguments
Ben Wing <ben@xemacs.org>
parents:
4790
diff
changeset
|
384 else \ |
428 | 385 old = modifier_index; |
386 | |
387 mkpm = xd->x_modifier_keymap->max_keypermod; | |
388 for (modifier_index = 0; modifier_index < 8; modifier_index++) | |
389 for (modifier_key = 0; modifier_key < mkpm; modifier_key++) { | |
390 KeySym last_sym = 0; | |
391 for (column = 0; column < 4; column += 2) { | |
392 KeyCode code = xd->x_modifier_keymap->modifiermap[modifier_index * mkpm | |
393 + modifier_key]; | |
394 KeySym sym = (code ? XKeycodeToKeysym (display, code, column) : 0); | |
395 if (sym == last_sym) continue; | |
396 last_sym = sym; | |
397 switch (sym) { | |
398 case XK_Mode_switch:store_modifier ("Mode_switch", mode_bit); break; | |
399 case XK_Meta_L: store_modifier ("Meta_L", meta_bit); break; | |
400 case XK_Meta_R: store_modifier ("Meta_R", meta_bit); break; | |
401 case XK_Super_L: store_modifier ("Super_L", super_bit); break; | |
402 case XK_Super_R: store_modifier ("Super_R", super_bit); break; | |
403 case XK_Hyper_L: store_modifier ("Hyper_L", hyper_bit); break; | |
404 case XK_Hyper_R: store_modifier ("Hyper_R", hyper_bit); break; | |
405 case XK_Alt_L: store_modifier ("Alt_L", alt_bit); break; | |
406 case XK_Alt_R: store_modifier ("Alt_R", alt_bit); break; | |
407 case XK_Control_L: check_modifier ("Control_L", ControlMask); break; | |
408 case XK_Control_R: check_modifier ("Control_R", ControlMask); break; | |
409 case XK_Shift_L: check_modifier ("Shift_L", ShiftMask); break; | |
410 case XK_Shift_R: check_modifier ("Shift_R", ShiftMask); break; | |
411 case XK_Shift_Lock: check_modifier ("Shift_Lock", LockMask); | |
412 xd->lock_interpretation = XK_Shift_Lock; break; | |
413 case XK_Caps_Lock: check_modifier ("Caps_Lock", LockMask); | |
414 xd->lock_interpretation = XK_Caps_Lock; break; | |
415 | |
416 /* It probably doesn't make any sense for a modifier bit to be | |
417 assigned to a key that is not one of the above, but OpenWindows | |
418 assigns modifier bits to a couple of random function keys for | |
419 no reason that I can discern, so printing a warning here would | |
420 be annoying. */ | |
421 } | |
422 } | |
423 } | |
424 #undef store_modifier | |
425 #undef check_modifier | |
426 #undef modwarn | |
427 #undef modbarf | |
428 | |
429 /* If there was no Meta key, then try using the Alt key instead. | |
430 If there is both a Meta key and an Alt key, then the Alt key | |
431 is not disturbed and remains an Alt key. */ | |
432 if (! meta_bit && alt_bit) | |
433 meta_bit = alt_bit, alt_bit = 0; | |
434 | |
435 /* mode_bit overrides everything, since it's processed down inside of | |
436 XLookupString() instead of by us. If Meta and Mode_switch both | |
437 generate the same modifier bit (which is an error), then we don't | |
438 interpret that bit as Meta, because we can't make XLookupString() | |
439 not interpret it as Mode_switch; and interpreting it as both would | |
440 be totally wrong. */ | |
441 if (mode_bit) | |
442 { | |
2828 | 443 const Ascbyte *warn = 0; |
428 | 444 if (mode_bit == meta_bit) warn = "Meta", meta_bit = 0; |
445 else if (mode_bit == hyper_bit) warn = "Hyper", hyper_bit = 0; | |
446 else if (mode_bit == super_bit) warn = "Super", super_bit = 0; | |
447 else if (mode_bit == alt_bit) warn = "Alt", alt_bit = 0; | |
448 if (warn) | |
449 { | |
450 warn_when_safe | |
451 (Qkey_mapping, Qwarning, | |
452 "XEmacs: %s is being used for both Mode_switch and %s.", | |
453 index_to_name (mode_bit), warn), | |
454 warned_about_overlapping_modifiers = 1; | |
455 } | |
456 } | |
457 #undef index_to_name | |
458 | |
459 xd->MetaMask = (meta_bit ? (1 << meta_bit) : 0); | |
460 xd->HyperMask = (hyper_bit ? (1 << hyper_bit) : 0); | |
461 xd->SuperMask = (super_bit ? (1 << super_bit) : 0); | |
462 xd->AltMask = (alt_bit ? (1 << alt_bit) : 0); | |
463 xd->ModeMask = (mode_bit ? (1 << mode_bit) : 0); /* unused */ | |
464 | |
465 | |
466 if (warned_about_overlapping_modifiers) | |
467 warn_when_safe (Qkey_mapping, Qwarning, "\n" | |
468 " Two distinct modifier keys (such as Meta and Hyper) cannot generate\n" | |
469 " the same modifier bit, because Emacs won't be able to tell which\n" | |
470 " modifier was actually held down when some other key is pressed. It\n" | |
471 " won't be able to tell Meta-x and Hyper-x apart, for example. Change\n" | |
472 " one of these keys to use some other modifier bit. If you intend for\n" | |
473 " these keys to have the same behavior, then change them to have the\n" | |
474 " same keysym as well as the same modifier bit."); | |
475 | |
476 if (warned_about_predefined_modifiers) | |
477 warn_when_safe (Qkey_mapping, Qwarning, "\n" | |
478 " The semantics of the modifier bits ModShift, ModLock, and ModControl\n" | |
479 " are predefined. It does not make sense to assign ModControl to any\n" | |
480 " keysym other than Control_L or Control_R, or to assign any modifier\n" | |
481 " bits to the \"control\" keysyms other than ModControl. You can't\n" | |
482 " turn a \"control\" key into a \"meta\" key (or vice versa) by simply\n" | |
483 " assigning the key a different modifier bit. You must also make that\n" | |
484 " key generate an appropriate keysym (Control_L, Meta_L, etc)."); | |
485 | |
486 /* No need to say anything more for warned_about_duplicate_modifiers. */ | |
487 | |
488 if (warned_about_overlapping_modifiers || warned_about_predefined_modifiers) | |
489 warn_when_safe (Qkey_mapping, Qwarning, "\n" | |
490 " The meanings of the modifier bits Mod1 through Mod5 are determined\n" | |
491 " by the keysyms used to control those bits. Mod1 does NOT always\n" | |
492 " mean Meta, although some non-ICCCM-compliant programs assume that."); | |
493 } | |
494 | |
495 void | |
496 x_init_modifier_mapping (struct device *d) | |
497 { | |
498 struct x_device *xd = DEVICE_X_DATA (d); | |
499 xd->x_keysym_map_hash_table = Qnil; | |
500 xd->x_keysym_map = NULL; | |
501 xd->x_modifier_keymap = NULL; | |
502 x_reset_modifier_mapping (d); | |
503 } | |
504 | |
505 static int | |
506 x_key_is_modifier_p (KeyCode keycode, struct device *d) | |
507 { | |
508 struct x_device *xd = DEVICE_X_DATA (d); | |
509 KeySym *syms; | |
510 int i; | |
511 | |
512 if (keycode < xd->x_keysym_map_min_code || | |
513 keycode > xd->x_keysym_map_max_code) | |
514 return 0; | |
515 | |
516 syms = &xd->x_keysym_map [(keycode - xd->x_keysym_map_min_code) * | |
517 xd->x_keysym_map_keysyms_per_code]; | |
518 for (i = 0; i < xd->x_keysym_map_keysyms_per_code; i++) | |
519 if (IsModifierKey (syms [i]) || | |
520 syms [i] == XK_Mode_switch) /* why doesn't IsModifierKey count this? */ | |
521 return 1; | |
522 return 0; | |
523 } | |
524 | |
525 /* key-handling code is always ugly. It just ends up working out | |
526 that way. | |
527 | |
528 Here are some pointers: | |
529 | |
530 -- DOWN_MASK indicates which modifiers should be treated as "down" | |
531 when the corresponding upstroke happens. It gets reset for | |
532 a particular modifier when that modifier goes up, and reset | |
533 for all modifiers when a non-modifier key is pressed. Example: | |
534 | |
535 I press Control-A-Shift and then release Control-A-Shift. | |
536 I want the Shift key to be sticky but not the Control key. | |
537 | |
538 -- LAST_DOWNKEY and RELEASE_TIME are used to keep track of | |
539 auto-repeat -- see below. | |
540 | |
541 -- If a modifier key is sticky, I can unstick it by pressing | |
542 the modifier key again. */ | |
543 | |
544 static void | |
545 x_handle_sticky_modifiers (XEvent *ev, struct device *d) | |
546 { | |
547 struct x_device *xd; | |
548 KeyCode keycode; | |
549 int type; | |
550 | |
551 if (!modifier_keys_are_sticky) /* Optimize for non-sticky modifiers */ | |
552 return; | |
553 | |
554 xd = DEVICE_X_DATA (d); | |
555 keycode = ev->xkey.keycode; | |
556 type = ev->type; | |
557 | |
558 if (keycode < xd->x_keysym_map_min_code || | |
559 keycode > xd->x_keysym_map_max_code) | |
560 return; | |
561 | |
562 if (! ((type == KeyPress || type == KeyRelease) && | |
563 x_key_is_modifier_p (keycode, d))) | |
564 { /* Not a modifier key */ | |
565 Bool key_event_p = (type == KeyPress || type == KeyRelease); | |
566 | |
444 | 567 if (type == ButtonPress |
568 || (type == KeyPress | |
569 && ((xd->last_downkey | |
570 && ((keycode != xd->last_downkey | |
571 || ev->xkey.time != xd->release_time))) | |
5581
56144c8593a8
Mechanically change INT to FIXNUM in our sources.
Aidan Kehoe <kehoea@parhasard.net>
parents:
5559
diff
changeset
|
572 || (FIXNUMP (Vmodifier_keys_sticky_time) |
444 | 573 && ev->xkey.time |
574 > (xd->modifier_release_time | |
5581
56144c8593a8
Mechanically change INT to FIXNUM in our sources.
Aidan Kehoe <kehoea@parhasard.net>
parents:
5559
diff
changeset
|
575 + XFIXNUM (Vmodifier_keys_sticky_time)))))) |
428 | 576 { |
577 xd->need_to_add_mask = 0; | |
578 xd->last_downkey = 0; | |
579 } | |
444 | 580 else if (type == KeyPress && !xd->last_downkey) |
581 xd->last_downkey = keycode; | |
582 | |
428 | 583 if (type == KeyPress) |
584 xd->release_time = 0; | |
585 if (type == KeyPress || type == ButtonPress) | |
444 | 586 { |
587 xd->down_mask = 0; | |
588 xd->modifier_release_time = 0; | |
589 } | |
428 | 590 |
591 if (key_event_p) | |
592 ev->xkey.state |= xd->need_to_add_mask; | |
593 else | |
594 ev->xbutton.state |= xd->need_to_add_mask; | |
595 | |
596 if (type == KeyRelease && keycode == xd->last_downkey) | |
597 /* If I hold press-and-release the Control key and then press | |
598 and hold down the right arrow, I want it to auto-repeat | |
599 Control-Right. On the other hand, if I do the same but | |
600 manually press the Right arrow a bunch of times, I want | |
601 to see one Control-Right and then a bunch of Rights. | |
602 This means that we need to distinguish between an | |
603 auto-repeated key and a key pressed and released a bunch | |
604 of times. | |
605 | |
606 Naturally, the designers of the X spec didn't see fit | |
607 to provide an obvious way to distinguish these cases. | |
608 So we assume that if the release and the next press | |
609 occur at the same time, the key was actually auto- | |
610 repeated. Under Open-Windows, at least, this works. */ | |
444 | 611 xd->modifier_release_time = xd->release_time |
612 = key_event_p ? ev->xkey.time : ev->xbutton.time; | |
428 | 613 } |
614 else /* Modifier key pressed */ | |
615 { | |
616 int i; | |
617 KeySym *syms = &xd->x_keysym_map [(keycode - xd->x_keysym_map_min_code) * | |
618 xd->x_keysym_map_keysyms_per_code]; | |
619 | |
620 /* If a non-modifier key was pressed in the middle of a bunch | |
621 of modifiers, then it unsticks all the modifiers that were | |
622 previously pressed. We cannot unstick the modifiers until | |
623 now because we want to check for auto-repeat of the | |
624 non-modifier key. */ | |
625 | |
626 if (xd->last_downkey) | |
627 { | |
628 xd->last_downkey = 0; | |
629 xd->need_to_add_mask = 0; | |
630 } | |
631 | |
444 | 632 if (xd->modifier_release_time |
5581
56144c8593a8
Mechanically change INT to FIXNUM in our sources.
Aidan Kehoe <kehoea@parhasard.net>
parents:
5559
diff
changeset
|
633 && FIXNUMP (Vmodifier_keys_sticky_time) |
444 | 634 && (ev->xkey.time |
5581
56144c8593a8
Mechanically change INT to FIXNUM in our sources.
Aidan Kehoe <kehoea@parhasard.net>
parents:
5559
diff
changeset
|
635 > xd->modifier_release_time + XFIXNUM (Vmodifier_keys_sticky_time))) |
444 | 636 { |
637 xd->need_to_add_mask = 0; | |
638 xd->down_mask = 0; | |
639 } | |
640 | |
428 | 641 #define FROB(mask) \ |
642 do { \ | |
643 if (type == KeyPress) \ | |
644 { \ | |
645 /* If modifier key is already sticky, \ | |
646 then unstick it. Note that we do \ | |
647 not test down_mask to deal with the \ | |
648 unlikely but possible case that the \ | |
649 modifier key auto-repeats. */ \ | |
650 if (xd->need_to_add_mask & mask) \ | |
651 { \ | |
652 xd->need_to_add_mask &= ~mask; \ | |
653 xd->down_mask &= ~mask; \ | |
654 } \ | |
655 else \ | |
656 xd->down_mask |= mask; \ | |
657 } \ | |
658 else \ | |
659 { \ | |
660 if (xd->down_mask & mask) \ | |
661 { \ | |
662 xd->down_mask &= ~mask; \ | |
663 xd->need_to_add_mask |= mask; \ | |
664 } \ | |
665 } \ | |
444 | 666 xd->modifier_release_time = ev->xkey.time; \ |
428 | 667 } while (0) |
668 | |
669 for (i = 0; i < xd->x_keysym_map_keysyms_per_code; i++) | |
670 switch (syms[i]) | |
671 { | |
672 case XK_Control_L: case XK_Control_R: FROB (ControlMask); break; | |
673 case XK_Shift_L: case XK_Shift_R: FROB (ShiftMask); break; | |
674 case XK_Meta_L: case XK_Meta_R: FROB (xd->MetaMask); break; | |
675 case XK_Super_L: case XK_Super_R: FROB (xd->SuperMask); break; | |
676 case XK_Hyper_L: case XK_Hyper_R: FROB (xd->HyperMask); break; | |
677 case XK_Alt_L: case XK_Alt_R: FROB (xd->AltMask); break; | |
678 } | |
679 } | |
680 #undef FROB | |
681 } | |
682 | |
683 static void | |
684 clear_sticky_modifiers (struct device *d) | |
685 { | |
686 struct x_device *xd = DEVICE_X_DATA (d); | |
687 | |
688 xd->need_to_add_mask = 0; | |
689 xd->last_downkey = 0; | |
690 xd->release_time = 0; | |
691 xd->down_mask = 0; | |
692 } | |
693 | |
694 static int | |
695 keysym_obeys_caps_lock_p (KeySym sym, struct device *d) | |
696 { | |
697 struct x_device *xd = DEVICE_X_DATA (d); | |
5559
f3ab0c29c246
Use a better, more portable approach to the shift-F11 problem.
Aidan Kehoe <kehoea@parhasard.net>
parents:
5558
diff
changeset
|
698 KeySym upper, lower; |
428 | 699 /* Eeeeevil hack. Don't apply Caps_Lock to things that aren't alphabetic |
700 characters, where "alphabetic" means something more than simply A-Z. | |
701 That is, if Caps_Lock is down, typing ESC doesn't produce Shift-ESC. | |
702 But if shift-lock is down, then it does. */ | |
703 if (xd->lock_interpretation == XK_Shift_Lock) | |
704 return 1; | |
705 | |
5559
f3ab0c29c246
Use a better, more portable approach to the shift-F11 problem.
Aidan Kehoe <kehoea@parhasard.net>
parents:
5558
diff
changeset
|
706 XConvertCase (sym, &lower, &upper); |
f3ab0c29c246
Use a better, more portable approach to the shift-F11 problem.
Aidan Kehoe <kehoea@parhasard.net>
parents:
5558
diff
changeset
|
707 |
f3ab0c29c246
Use a better, more portable approach to the shift-F11 problem.
Aidan Kehoe <kehoea@parhasard.net>
parents:
5558
diff
changeset
|
708 return !(sym == lower && sym == upper); |
428 | 709 } |
710 | |
711 /* called from EmacsFrame.c (actually from Xt itself) when a | |
712 MappingNotify event is received. In its infinite wisdom, Xt | |
713 decided that Xt event handlers never get MappingNotify events. | |
714 O'Reilly Xt Programming Manual 9.1.2 says: | |
715 | |
716 MappingNotify is automatically handled by Xt, so it isn't passed | |
717 to event handlers and you don't need to worry about it. | |
718 | |
719 Of course, we DO worry about it, so we need a special translation. */ | |
720 void | |
2286 | 721 emacs_Xt_mapping_action (Widget UNUSED (w), XEvent *event) |
428 | 722 { |
723 struct device *d = get_device_from_display (event->xany.display); | |
724 | |
725 if (DEVICE_X_BEING_DELETED (d)) | |
726 return; | |
727 #if 0 | |
728 /* nyet. Now this is handled by Xt. */ | |
729 XRefreshKeyboardMapping (&event->xmapping); | |
730 #endif | |
731 /* xmodmap generates about a billion MappingKeyboard events, followed | |
732 by a single MappingModifier event, so it might be worthwhile to | |
733 take extra MappingKeyboard events out of the queue before requesting | |
734 the current keymap from the server. */ | |
735 switch (event->xmapping.request) | |
736 { | |
737 case MappingKeyboard: x_reset_key_mapping (d); break; | |
738 case MappingModifier: x_reset_modifier_mapping (d); break; | |
739 case MappingPointer: /* Do something here? */ break; | |
2500 | 740 default: ABORT(); |
428 | 741 } |
742 } | |
743 | |
744 | |
745 /************************************************************************/ | |
746 /* X to Emacs event conversion */ | |
747 /************************************************************************/ | |
748 | |
749 static Lisp_Object | |
750 x_keysym_to_emacs_keysym (KeySym keysym, int simple_p) | |
751 { | |
2828 | 752 Extbyte *name; |
753 DECLARE_EISTRING(einame); | |
754 | |
428 | 755 if (keysym >= XK_exclam && keysym <= XK_asciitilde) |
756 /* We must assume that the X keysym numbers for the ASCII graphic | |
757 characters are the same as their ASCII codes. */ | |
758 return make_char (keysym); | |
759 | |
760 switch (keysym) | |
761 { | |
762 /* These would be handled correctly by the default case, but by | |
763 special-casing them here we don't garbage a string or call | |
764 intern(). */ | |
765 case XK_BackSpace: return QKbackspace; | |
766 case XK_Tab: return QKtab; | |
767 case XK_Linefeed: return QKlinefeed; | |
768 case XK_Return: return QKreturn; | |
769 case XK_Escape: return QKescape; | |
770 case XK_space: return QKspace; | |
771 case XK_Delete: return QKdelete; | |
772 case 0: return Qnil; | |
773 default: | |
774 if (simple_p) return Qnil; | |
775 name = XKeysymToString (keysym); | |
776 if (!name || !name[0]) | |
777 /* This happens if there is a mismatch between the Xlib of | |
778 XEmacs and the Xlib of the X server... | |
779 | |
780 Let's hard-code in some knowledge of common keysyms introduced | |
781 in recent X11 releases. Snarfed from X11/keysymdef.h | |
782 | |
783 Probably we should add some stuff here for X11R6. */ | |
784 switch (keysym) | |
785 { | |
786 case 0xFF95: return KEYSYM ("kp-home"); | |
787 case 0xFF96: return KEYSYM ("kp-left"); | |
788 case 0xFF97: return KEYSYM ("kp-up"); | |
789 case 0xFF98: return KEYSYM ("kp-right"); | |
790 case 0xFF99: return KEYSYM ("kp-down"); | |
791 case 0xFF9A: return KEYSYM ("kp-prior"); | |
792 case 0xFF9B: return KEYSYM ("kp-next"); | |
793 case 0xFF9C: return KEYSYM ("kp-end"); | |
794 case 0xFF9D: return KEYSYM ("kp-begin"); | |
795 case 0xFF9E: return KEYSYM ("kp-insert"); | |
796 case 0xFF9F: return KEYSYM ("kp-delete"); | |
797 | |
798 case 0x1005FF10: return KEYSYM ("SunF36"); /* labeled F11 */ | |
799 case 0x1005FF11: return KEYSYM ("SunF37"); /* labeled F12 */ | |
800 default: | |
801 { | |
2828 | 802 Ascbyte buf [64]; |
428 | 803 sprintf (buf, "unknown-keysym-0x%X", (int) keysym); |
804 return KEYSYM (buf); | |
805 } | |
806 } | |
2828 | 807 |
428 | 808 /* If it's got a one-character name, that's good enough. */ |
809 if (!name[1]) | |
2828 | 810 return make_char ((Ichar)name[0]); |
811 | |
812 /* In theory the Host Portable Character Set is just ASCII, but | |
813 trusting X11 implementors to get that right is likely to lead to | |
814 tears. */ | |
815 eicpy_ext(einame, name, Qbinary); | |
428 | 816 |
817 /* If it's in the "Keyboard" character set, downcase it. | |
818 The case of those keysyms is too totally random for us to | |
819 force anyone to remember them. | |
2828 | 820 The case of the other character sets is significant, however. */ |
428 | 821 if ((((unsigned int) keysym) & (~0x1FF)) == ((unsigned int) 0xFE00)) |
822 { | |
2828 | 823 Ibyte *iname; |
824 eilwr(einame); | |
825 | |
826 for (iname = eidata(einame); *iname != '\0';) | |
827 { | |
828 if (*iname == '_') | |
829 { | |
830 *iname = '-'; | |
831 } | |
832 INC_IBYTEPTR(iname); | |
428 | 833 } |
834 } | |
2837 | 835 return KEYSYM ((const CIbyte *) eidata (einame)); |
428 | 836 } |
837 } | |
838 | |
839 static Lisp_Object | |
5559
f3ab0c29c246
Use a better, more portable approach to the shift-F11 problem.
Aidan Kehoe <kehoea@parhasard.net>
parents:
5558
diff
changeset
|
840 x_to_emacs_keysym (XKeyPressedEvent *event, int simple_p, KeySym *x_keysym_out) |
428 | 841 /* simple_p means don't try too hard (ASCII only) */ |
842 { | |
5559
f3ab0c29c246
Use a better, more portable approach to the shift-F11 problem.
Aidan Kehoe <kehoea@parhasard.net>
parents:
5558
diff
changeset
|
843 KeySym keysym = NoSymbol; |
428 | 844 |
845 #ifdef HAVE_XIM | |
3072 | 846 int len = 0; |
442 | 847 /* Some implementations of XmbLookupString don't return |
848 XBufferOverflow correctly, so increase the size of the xim input | |
849 buffer from 64 to the more reasonable size 513, as Emacs has done. | |
850 From Kenichi Handa. */ | |
851 char buffer[513]; | |
428 | 852 char *bufptr = buffer; |
853 int bufsiz = sizeof (buffer); | |
854 Status status; | |
855 #ifdef XIM_XLIB | |
856 XIC xic = FRAME_X_XIC (x_any_window_to_frame | |
857 (get_device_from_display (event->display), | |
858 event->window)); | |
859 #endif /* XIM_XLIB */ | |
860 #endif /* HAVE_XIM */ | |
861 | |
5559
f3ab0c29c246
Use a better, more portable approach to the shift-F11 problem.
Aidan Kehoe <kehoea@parhasard.net>
parents:
5558
diff
changeset
|
862 *x_keysym_out = NoSymbol; |
f3ab0c29c246
Use a better, more portable approach to the shift-F11 problem.
Aidan Kehoe <kehoea@parhasard.net>
parents:
5558
diff
changeset
|
863 |
428 | 864 /* We use XLookupString if we're not using XIM, or are using |
865 XIM_XLIB but input context creation failed. */ | |
866 #if ! (defined (HAVE_XIM) && defined (XIM_MOTIF)) | |
867 #if defined (HAVE_XIM) && defined (XIM_XLIB) | |
868 if (!xic) | |
869 #endif /* XIM_XLIB */ | |
870 { | |
871 /* Apparently it's necessary to specify a dummy here (rather | |
872 than passing in 0) to avoid crashes on German IRIX */ | |
873 char dummy[256]; | |
874 XLookupString (event, dummy, 200, &keysym, 0); | |
5559
f3ab0c29c246
Use a better, more portable approach to the shift-F11 problem.
Aidan Kehoe <kehoea@parhasard.net>
parents:
5558
diff
changeset
|
875 *x_keysym_out = keysym; |
428 | 876 return (IsModifierKey (keysym) || keysym == XK_Mode_switch ) |
877 ? Qnil : x_keysym_to_emacs_keysym (keysym, simple_p); | |
878 } | |
879 #endif /* ! XIM_MOTIF */ | |
880 | |
881 #ifdef HAVE_XIM | |
882 Lookup_String: /* Come-From XBufferOverflow */ | |
883 #ifdef XIM_MOTIF | |
884 len = XmImMbLookupString (XtWindowToWidget (event->display, event->window), | |
885 event, bufptr, bufsiz, &keysym, &status); | |
886 #else /* XIM_XLIB */ | |
887 if (xic) | |
888 len = XmbLookupString (xic, event, bufptr, bufsiz, &keysym, &status); | |
1494 | 889 #endif /* XIM_MOTIF */ |
428 | 890 |
891 #ifdef DEBUG_XEMACS | |
442 | 892 if (debug_x_events > 0) |
428 | 893 { |
894 stderr_out (" status="); | |
895 #define print_status_when(S) if (status == S) stderr_out (#S) | |
896 print_status_when (XLookupKeySym); | |
897 print_status_when (XLookupBoth); | |
898 print_status_when (XLookupChars); | |
899 print_status_when (XLookupNone); | |
900 print_status_when (XBufferOverflow); | |
901 | |
902 if (status == XLookupKeySym || status == XLookupBoth) | |
903 stderr_out (" keysym=%s", XKeysymToString (keysym)); | |
904 if (status == XLookupChars || status == XLookupBoth) | |
905 { | |
3072 | 906 if (len > 1) |
428 | 907 { |
908 int j; | |
909 stderr_out (" chars=\""); | |
910 for (j=0; j<len; j++) | |
3142 | 911 { |
912 if (040 <= bufptr[j] && bufptr[j] >= 0177) | |
913 { | |
914 stderr_out ("%c", bufptr[j]); | |
915 } | |
916 else | |
917 { | |
918 stderr_out ("\\%o", (unsigned)(bufptr[j])); | |
919 } | |
920 } | |
428 | 921 stderr_out ("\""); |
922 } | |
923 else if (bufptr[0] <= 32 || bufptr[0] >= 127) | |
924 stderr_out (" char=0x%x", bufptr[0]); | |
925 else | |
926 stderr_out (" char=%c", bufptr[0]); | |
927 } | |
928 stderr_out ("\n"); | |
929 } | |
930 #endif /* DEBUG_XEMACS */ | |
931 | |
932 switch (status) | |
933 { | |
934 case XLookupKeySym: | |
935 case XLookupBoth: | |
5559
f3ab0c29c246
Use a better, more portable approach to the shift-F11 problem.
Aidan Kehoe <kehoea@parhasard.net>
parents:
5558
diff
changeset
|
936 *x_keysym_out = keysym; |
428 | 937 return (IsModifierKey (keysym) || keysym == XK_Mode_switch ) |
938 ? Qnil : x_keysym_to_emacs_keysym (keysym, simple_p); | |
939 | |
940 case XLookupChars: | |
941 { | |
942 /* Generate multiple emacs events */ | |
943 struct device *d = get_device_from_display (event->display); | |
867 | 944 Ichar ch; |
428 | 945 Lisp_Object instream, fb_instream; |
946 Lstream *istr; | |
947 struct gcpro gcpro1, gcpro2; | |
948 | |
440 | 949 fb_instream = make_fixed_buffer_input_stream (bufptr, len); |
950 | |
3142 | 951 /* [[ Use get_coding_system_for_text_file |
952 (Vcomposed_input_coding_system, 0) ]] | |
953 | |
954 Nope. If it is possible for the X libraries to have multiple IM | |
955 connections on different DISPLAYs active at once, this should be | |
956 a console-specific variable (like a TTY's coding system) but I've | |
957 seen no evidence that that is possible. Aidan Kehoe, | |
958 2005-12-17. */ | |
959 | |
428 | 960 instream = |
771 | 961 make_coding_input_stream |
3142 | 962 (XLSTREAM (fb_instream), Qkeyboard, CODING_DECODE, 0); |
428 | 963 |
964 istr = XLSTREAM (instream); | |
965 | |
966 GCPRO2 (instream, fb_instream); | |
867 | 967 while ((ch = Lstream_get_ichar (istr)) != EOF) |
428 | 968 { |
969 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil); | |
440 | 970 Lisp_Event *ev = XEVENT (emacs_event); |
428 | 971 ev->channel = DEVICE_CONSOLE (d); |
4780
2fd201d73a92
Call character_to_event on characters received from XIM, event-Xt.c
Aidan Kehoe <kehoea@parhasard.net>
parents:
4528
diff
changeset
|
972 XSET_EVENT_TYPE (emacs_event, key_press_event); |
2fd201d73a92
Call character_to_event on characters received from XIM, event-Xt.c
Aidan Kehoe <kehoea@parhasard.net>
parents:
4528
diff
changeset
|
973 /* Make sure space and linefeed and so on get the proper |
2fd201d73a92
Call character_to_event on characters received from XIM, event-Xt.c
Aidan Kehoe <kehoea@parhasard.net>
parents:
4528
diff
changeset
|
974 keysyms. */ |
2fd201d73a92
Call character_to_event on characters received from XIM, event-Xt.c
Aidan Kehoe <kehoea@parhasard.net>
parents:
4528
diff
changeset
|
975 character_to_event (ch, ev, XCONSOLE (ev->channel), |
2fd201d73a92
Call character_to_event on characters received from XIM, event-Xt.c
Aidan Kehoe <kehoea@parhasard.net>
parents:
4528
diff
changeset
|
976 latin_1_maps_to_itself, 0); |
960 | 977 ev->timestamp = event->time; |
1204 | 978 enqueue_dispatch_event (emacs_event); |
428 | 979 } |
980 Lstream_close (istr); | |
981 UNGCPRO; | |
982 Lstream_delete (istr); | |
983 Lstream_delete (XLSTREAM (fb_instream)); | |
984 return Qnil; | |
985 } | |
986 case XLookupNone: return Qnil; | |
987 case XBufferOverflow: | |
2367 | 988 /* !!#### needs work */ |
851 | 989 bufptr = (char *) ALLOCA (len+1); |
428 | 990 bufsiz = len+1; |
991 goto Lookup_String; | |
992 } | |
801 | 993 return Qnil; /* not (usually) reached */ |
428 | 994 #endif /* HAVE_XIM */ |
995 } | |
996 | |
997 static void | |
998 set_last_server_timestamp (struct device *d, XEvent *x_event) | |
999 { | |
1000 Time t; | |
1001 switch (x_event->type) | |
1002 { | |
1003 case KeyPress: | |
1004 case KeyRelease: t = x_event->xkey.time; break; | |
1005 case ButtonPress: | |
1006 case ButtonRelease: t = x_event->xbutton.time; break; | |
1007 case EnterNotify: | |
1008 case LeaveNotify: t = x_event->xcrossing.time; break; | |
1009 case MotionNotify: t = x_event->xmotion.time; break; | |
1010 case PropertyNotify: t = x_event->xproperty.time; break; | |
1011 case SelectionClear: t = x_event->xselectionclear.time; break; | |
1012 case SelectionRequest: t = x_event->xselectionrequest.time; break; | |
1013 case SelectionNotify: t = x_event->xselection.time; break; | |
1014 default: return; | |
1015 } | |
1016 DEVICE_X_LAST_SERVER_TIMESTAMP (d) = t; | |
1017 } | |
1018 | |
1019 static int | |
440 | 1020 x_event_to_emacs_event (XEvent *x_event, Lisp_Event *emacs_event) |
428 | 1021 { |
1022 Display *display = x_event->xany.display; | |
1023 struct device *d = get_device_from_display (display); | |
1024 struct x_device *xd = DEVICE_X_DATA (d); | |
1025 | |
1026 if (DEVICE_X_BEING_DELETED (d)) | |
2828 | 1027 { |
1028 /* [[ Uh, is this 0 correct? ]] | |
1029 | |
1030 Yup--it means emacs_Xt_event_handler, the only place that calls | |
1031 this, doesn't queue the emacs_event dispatch, instead immediately | |
1032 deallocating it. */ | |
1033 return 0; | |
1034 } | |
428 | 1035 |
1036 set_last_server_timestamp (d, x_event); | |
1037 | |
1038 switch (x_event->type) | |
1039 { | |
1040 case KeyRelease: | |
934 | 1041 { |
1042 x_handle_sticky_modifiers (x_event, d); | |
1043 return 0; | |
1044 } | |
428 | 1045 case KeyPress: |
1046 case ButtonPress: | |
1047 case ButtonRelease: | |
1048 { | |
442 | 1049 int modifiers = 0; |
428 | 1050 int shift_p, lock_p; |
1051 Bool key_event_p = (x_event->type == KeyPress); | |
1052 unsigned int *state = | |
1053 key_event_p ? &x_event->xkey.state : &x_event->xbutton.state; | |
1054 | |
1055 /* If this is a synthetic KeyPress or Button event, and the user | |
1056 has expressed a disinterest in this security hole, then drop | |
1057 it on the floor. */ | |
1058 if ((key_event_p | |
1059 ? x_event->xkey.send_event | |
1060 : x_event->xbutton.send_event) | |
1061 #ifdef EXTERNAL_WIDGET | |
1062 /* ben: events get sent to an ExternalShell using XSendEvent. | |
1063 This is not a perfect solution. */ | |
1064 && !FRAME_X_EXTERNAL_WINDOW_P | |
1065 (x_any_window_to_frame (d, x_event->xany.window)) | |
1066 #endif | |
1067 && !x_allow_sendevents) | |
1068 return 0; | |
1069 | |
1070 DEVICE_X_MOUSE_TIMESTAMP (d) = | |
1071 DEVICE_X_GLOBAL_MOUSE_TIMESTAMP (d) = | |
1072 key_event_p ? x_event->xkey.time : x_event->xbutton.time; | |
1073 | |
1074 x_handle_sticky_modifiers (x_event, d); | |
1075 | |
442 | 1076 if (*state & ControlMask) modifiers |= XEMACS_MOD_CONTROL; |
1077 if (*state & xd->MetaMask) modifiers |= XEMACS_MOD_META; | |
1078 if (*state & xd->SuperMask) modifiers |= XEMACS_MOD_SUPER; | |
1079 if (*state & xd->HyperMask) modifiers |= XEMACS_MOD_HYPER; | |
1080 if (*state & xd->AltMask) modifiers |= XEMACS_MOD_ALT; | |
1081 { | |
1082 int numero_de_botao = -1; | |
1083 | |
1084 if (!key_event_p) | |
1085 numero_de_botao = x_event->xbutton.button; | |
1086 | |
1087 /* the button gets noted either in the button or the modifiers | |
1088 field, but not both. */ | |
1089 if (numero_de_botao != 1 && (*state & Button1Mask)) | |
1090 modifiers |= XEMACS_MOD_BUTTON1; | |
1091 if (numero_de_botao != 2 && (*state & Button2Mask)) | |
1092 modifiers |= XEMACS_MOD_BUTTON2; | |
1093 if (numero_de_botao != 3 && (*state & Button3Mask)) | |
1094 modifiers |= XEMACS_MOD_BUTTON3; | |
1095 if (numero_de_botao != 4 && (*state & Button4Mask)) | |
1096 modifiers |= XEMACS_MOD_BUTTON4; | |
1097 if (numero_de_botao != 5 && (*state & Button5Mask)) | |
1098 modifiers |= XEMACS_MOD_BUTTON5; | |
1099 } | |
428 | 1100 |
1101 /* Ignore the Caps_Lock key if: | |
1102 - any other modifiers are down, so that Caps_Lock doesn't | |
1103 turn C-x into C-X, which would suck. | |
1104 - the event was a mouse event. */ | |
1105 if (modifiers || ! key_event_p) | |
1106 *state &= (~LockMask); | |
1107 | |
1108 shift_p = *state & ShiftMask; | |
1109 lock_p = *state & LockMask; | |
1110 | |
1111 if (shift_p || lock_p) | |
442 | 1112 modifiers |= XEMACS_MOD_SHIFT; |
428 | 1113 |
1114 if (key_event_p) | |
1115 { | |
1116 Lisp_Object keysym; | |
1117 XKeyEvent *ev = &x_event->xkey; | |
5559
f3ab0c29c246
Use a better, more portable approach to the shift-F11 problem.
Aidan Kehoe <kehoea@parhasard.net>
parents:
5558
diff
changeset
|
1118 KeySym x_keysym = NoSymbol; |
428 | 1119 /* This used to compute the frame from the given X window and |
1120 store it here, but we really don't care about the frame. */ | |
934 | 1121 SET_EVENT_CHANNEL (emacs_event, DEVICE_CONSOLE (d)); |
5559
f3ab0c29c246
Use a better, more portable approach to the shift-F11 problem.
Aidan Kehoe <kehoea@parhasard.net>
parents:
5558
diff
changeset
|
1122 keysym = x_to_emacs_keysym (&x_event->xkey, 0, &x_keysym); |
428 | 1123 |
1124 /* If the emacs keysym is nil, then that means that the X | |
1125 keysym was either a Modifier or NoSymbol, which | |
1126 probably means that we're in the midst of reading a | |
1127 Multi_key sequence, or a "dead" key prefix, or XIM | |
1128 input. Ignore it. */ | |
1129 if (NILP (keysym)) | |
1130 return 0; | |
1131 | |
3171 | 1132 /* If we have the map from keycodes to the US layout for our |
1133 keyboard available, store the US layout interpretation of | |
1134 that key in the event structure, in case a binding lookup | |
1135 fails and we want to fall back to the US layout binding. | |
1136 | |
1137 This _might_ be possible within an XKB framework, changing | |
1138 the keyboard to a US XKB layout for a moment at startup, | |
1139 storing the correspondance, and changing it back. But that | |
1140 won't work on non-XKB servers, it makes our already slow | |
1141 startup slower, and it's not clear that it's really any | |
1142 easier or more maintainable than storing a correspondence in | |
1143 Lisp. */ | |
1144 | |
1145 if (!NILP(Vx_us_keymap_description) && | |
1146 VECTORP(Vx_us_keymap_description) && | |
1147 ev->keycode >= (unsigned)Vx_us_keymap_first_keycode && | |
1148 ev->keycode | |
1149 < (unsigned)XVECTOR_LENGTH(Vx_us_keymap_description)) | |
1150 { | |
1151 Lisp_Object entr = XVECTOR_DATA(Vx_us_keymap_description) | |
1152 [ev->keycode - Vx_us_keymap_first_keycode]; | |
1153 Ichar alternate = '\0'; | |
1154 | |
1155 if (!NILP (entr)) | |
1156 { | |
1157 if (CHARP(entr)) | |
1158 { | |
1159 alternate = XCHAR(entr); | |
1160 } | |
1161 else if (VECTORP(entr)) | |
1162 { | |
1163 if (modifiers & XEMACS_MOD_SHIFT | |
1164 && XVECTOR_LENGTH(Vx_us_keymap_description) > 1) | |
1165 { | |
1166 entr = XVECTOR_DATA(entr)[1]; | |
1167 if (CHARP(entr)) | |
1168 { | |
1169 alternate = XCHAR(entr); | |
1170 } | |
1171 } | |
1172 else if (XVECTOR_LENGTH(Vx_us_keymap_description) | |
1173 > 0) | |
1174 { | |
1175 entr = XVECTOR_DATA(entr)[0]; | |
1176 if (CHARP(entr)) | |
1177 { | |
1178 alternate = XCHAR(entr); | |
1179 } | |
1180 } | |
1181 } | |
1182 if ('\0' != alternate) | |
1183 { | |
1184 SET_EVENT_KEY_ALT_KEYCHARS(emacs_event, KEYCHAR_QWERTY, | |
1185 alternate); | |
1186 } | |
1187 } | |
1188 } | |
1189 | |
428 | 1190 /* More Caps_Lock garbage: Caps_Lock should *only* add the |
1191 shift modifier to two-case keys (that is, A-Z and | |
1192 related characters). So at this point (after looking up | |
1193 the keysym) if the keysym isn't a dual-case alphabetic, | |
1194 and if the caps lock key was down but the shift key | |
1195 wasn't, then turn off the shift modifier. Gag barf */ | |
2828 | 1196 |
428 | 1197 if (lock_p && !shift_p && |
5559
f3ab0c29c246
Use a better, more portable approach to the shift-F11 problem.
Aidan Kehoe <kehoea@parhasard.net>
parents:
5558
diff
changeset
|
1198 ! (x_keysym && keysym_obeys_caps_lock_p (x_keysym, d))) |
442 | 1199 modifiers &= (~XEMACS_MOD_SHIFT); |
428 | 1200 |
1201 /* If this key contains two distinct keysyms, that is, | |
1202 "shift" generates a different keysym than the | |
1203 non-shifted key, then don't apply the shift modifier | |
1204 bit: it's implicit. Otherwise, if there would be no | |
1205 other way to tell the difference between the shifted | |
1206 and unshifted version of this key, apply the shift bit. | |
1207 Non-graphics, like Backspace and F1 get the shift bit | |
1208 in the modifiers slot. Neither the characters "a", | |
1209 "A", "2", nor "@" normally have the shift bit set. | |
1210 However, "F1" normally does. */ | |
3171 | 1211 |
442 | 1212 if (modifiers & XEMACS_MOD_SHIFT) |
428 | 1213 { |
1214 int Mode_switch_p = *state & xd->ModeMask; | |
1215 KeySym bot = XLookupKeysym (ev, Mode_switch_p ? 2 : 0); | |
5559
f3ab0c29c246
Use a better, more portable approach to the shift-F11 problem.
Aidan Kehoe <kehoea@parhasard.net>
parents:
5558
diff
changeset
|
1216 if (x_keysym && bot && x_keysym != bot) |
442 | 1217 modifiers &= ~XEMACS_MOD_SHIFT; |
428 | 1218 } |
934 | 1219 set_event_type (emacs_event, key_press_event); |
1220 SET_EVENT_TIMESTAMP (emacs_event, ev->time); | |
1204 | 1221 SET_EVENT_KEY_MODIFIERS (emacs_event, modifiers); |
1222 SET_EVENT_KEY_KEYSYM (emacs_event, keysym); | |
428 | 1223 } |
1224 else /* Mouse press/release event */ | |
1225 { | |
1226 XButtonEvent *ev = &x_event->xbutton; | |
1227 struct frame *frame = x_window_to_frame (d, ev->window); | |
1228 | |
1229 if (! frame) | |
1230 return 0; /* not for us */ | |
934 | 1231 set_event_type (emacs_event, (x_event->type == ButtonPress) ? |
1232 button_press_event : button_release_event); | |
1204 | 1233 SET_EVENT_CHANNEL (emacs_event, wrap_frame (frame)); |
1234 | |
1235 SET_EVENT_BUTTON_MODIFIERS (emacs_event, modifiers); | |
934 | 1236 SET_EVENT_TIMESTAMP (emacs_event, ev->time); |
1204 | 1237 SET_EVENT_BUTTON_BUTTON (emacs_event, ev->button); |
1238 SET_EVENT_BUTTON_X (emacs_event, ev->x); | |
1239 SET_EVENT_BUTTON_Y (emacs_event, ev->y); | |
428 | 1240 /* because we don't seem to get a FocusIn event for button clicks |
1241 when a widget-glyph is selected we will assume that we want the | |
1242 focus if a button gets pressed. */ | |
1243 if (x_event->type == ButtonPress) | |
1244 handle_focus_event_1 (frame, 1); | |
1245 } | |
1246 } | |
1247 break; | |
1248 | |
1249 case MotionNotify: | |
1250 { | |
1251 XMotionEvent *ev = &x_event->xmotion; | |
1252 struct frame *frame = x_window_to_frame (d, ev->window); | |
442 | 1253 int modifiers = 0; |
428 | 1254 XMotionEvent event2; |
1255 | |
1256 if (! frame) | |
1257 return 0; /* not for us */ | |
1258 | |
1259 /* We use MotionHintMask, so we will get only one motion event | |
1260 until the next time we call XQueryPointer or the user | |
1261 clicks the mouse. So call XQueryPointer now (meaning that | |
1262 the event will be in sync with the server just before | |
1263 Fnext_event() returns). If the mouse is still in motion, | |
1264 then the server will immediately generate exactly one more | |
1265 motion event, which will be on the queue waiting for us | |
1266 next time around. */ | |
1267 event2 = *ev; | |
1268 if (XQueryPointer (event2.display, event2.window, | |
1269 &event2.root, &event2.subwindow, | |
1270 &event2.x_root, &event2.y_root, | |
1271 &event2.x, &event2.y, | |
1272 &event2.state)) | |
1273 ev = &event2; /* only one structure copy */ | |
1274 | |
1275 DEVICE_X_MOUSE_TIMESTAMP (d) = ev->time; | |
1204 | 1276 SET_EVENT_CHANNEL (emacs_event, wrap_frame (frame)); |
934 | 1277 set_event_type (emacs_event, pointer_motion_event); |
1278 SET_EVENT_TIMESTAMP (emacs_event, ev->time); | |
1204 | 1279 SET_EVENT_MOTION_X (emacs_event, ev->x); |
1280 SET_EVENT_MOTION_Y (emacs_event, ev->y); | |
442 | 1281 if (ev->state & ShiftMask) modifiers |= XEMACS_MOD_SHIFT; |
1282 if (ev->state & ControlMask) modifiers |= XEMACS_MOD_CONTROL; | |
1283 if (ev->state & xd->MetaMask) modifiers |= XEMACS_MOD_META; | |
1284 if (ev->state & xd->SuperMask) modifiers |= XEMACS_MOD_SUPER; | |
1285 if (ev->state & xd->HyperMask) modifiers |= XEMACS_MOD_HYPER; | |
1286 if (ev->state & xd->AltMask) modifiers |= XEMACS_MOD_ALT; | |
1287 if (ev->state & Button1Mask) modifiers |= XEMACS_MOD_BUTTON1; | |
1288 if (ev->state & Button2Mask) modifiers |= XEMACS_MOD_BUTTON2; | |
1289 if (ev->state & Button3Mask) modifiers |= XEMACS_MOD_BUTTON3; | |
1290 if (ev->state & Button4Mask) modifiers |= XEMACS_MOD_BUTTON4; | |
1291 if (ev->state & Button5Mask) modifiers |= XEMACS_MOD_BUTTON5; | |
428 | 1292 /* Currently ignores Shift_Lock but probably shouldn't |
1293 (but it definitely should ignore Caps_Lock). */ | |
1204 | 1294 SET_EVENT_MOTION_MODIFIERS (emacs_event, modifiers); |
428 | 1295 } |
1296 break; | |
1297 | |
1298 case ClientMessage: | |
1299 { | |
1300 /* Patch bogus TAKE_FOCUS messages from MWM; CurrentTime is | |
1301 passed as the timestamp of the TAKE_FOCUS, which the ICCCM | |
1302 explicitly prohibits. */ | |
1303 XClientMessageEvent *ev = &x_event->xclient; | |
4790
bc4f2511bbea
Remove support for the OffiX drag-and-drop protocol. See xemacs-patches
Jerry James <james@xemacs.org>
parents:
4780
diff
changeset
|
1304 |
428 | 1305 if (ev->message_type == DEVICE_XATOM_WM_PROTOCOLS (d) |
1306 && (Atom) (ev->data.l[0]) == DEVICE_XATOM_WM_TAKE_FOCUS (d) | |
1307 && (Atom) (ev->data.l[1]) == 0) | |
1308 { | |
1309 ev->data.l[1] = DEVICE_X_LAST_SERVER_TIMESTAMP (d); | |
1310 } | |
1311 } | |
1312 /* fall through */ | |
1313 | |
1314 default: /* it's a magic event */ | |
1315 { | |
1316 struct frame *frame; | |
1317 Window w; | |
934 | 1318 XEvent *x_event_copy; |
1319 SET_EVENT_TYPE (emacs_event, magic_event); | |
1204 | 1320 x_event_copy = &EVENT_MAGIC_X_EVENT (emacs_event); |
428 | 1321 |
1322 #define FROB(event_member, window_member) \ | |
1323 x_event_copy->event_member = x_event->event_member; \ | |
1324 w = x_event->event_member.window_member | |
1325 | |
1326 switch (x_event->type) | |
1327 { | |
1328 case SelectionRequest: FROB(xselectionrequest, owner); break; | |
1329 case SelectionClear: FROB(xselectionclear, window); break; | |
1330 case SelectionNotify: FROB(xselection, requestor); break; | |
1331 case PropertyNotify: FROB(xproperty, window); break; | |
1332 case ClientMessage: FROB(xclient, window); break; | |
1333 case ConfigureNotify: FROB(xconfigure, window); break; | |
1334 case Expose: | |
1335 case GraphicsExpose: FROB(xexpose, window); break; | |
1336 case MapNotify: | |
1337 case UnmapNotify: FROB(xmap, window); break; | |
1338 case EnterNotify: | |
1339 case LeaveNotify: FROB(xcrossing, window); break; | |
1340 case FocusIn: | |
1341 case FocusOut: FROB(xfocus, window); break; | |
1342 case VisibilityNotify: FROB(xvisibility, window); break; | |
442 | 1343 case CreateNotify: FROB(xcreatewindow, window); break; |
428 | 1344 default: |
1345 w = x_event->xany.window; | |
1346 *x_event_copy = *x_event; | |
1347 break; | |
1348 } | |
1349 #undef FROB | |
1350 frame = x_any_window_to_frame (d, w); | |
1351 | |
1352 if (!frame) | |
1353 return 0; | |
1354 | |
1204 | 1355 SET_EVENT_CHANNEL (emacs_event, wrap_frame (frame)); |
428 | 1356 break; |
1357 } | |
1358 } | |
1359 return 1; | |
1360 } | |
1361 | |
1362 | |
1363 | |
1364 /************************************************************************/ | |
1365 /* magic-event handling */ | |
1366 /************************************************************************/ | |
1367 | |
1368 static void | |
1369 handle_focus_event_1 (struct frame *f, int in_p) | |
1370 { | |
863 | 1371 handle_focus_event_2 (XtWindow (FRAME_X_TEXT_WIDGET (f)), f, in_p); |
1372 } | |
1373 | |
1374 static void | |
1375 handle_focus_event_2 (Window win, struct frame *f, int in_p) | |
1376 { | |
1377 /* Although this treats focus differently for all widgets (including | |
1378 the frame) it seems to work ok. */ | |
1379 Widget needs_it = XtWindowToWidget (FRAME_X_DISPLAY (f), win); | |
1380 | |
428 | 1381 #if XtSpecificationRelease > 5 |
450 | 1382 widget_with_focus = XtGetKeyboardFocusWidget (FRAME_X_TEXT_WIDGET (f)); |
428 | 1383 #endif |
1384 #ifdef HAVE_XIM | |
1385 XIM_focus_event (f, in_p); | |
1386 #endif /* HAVE_XIM */ | |
450 | 1387 |
428 | 1388 /* On focus change, clear all memory of sticky modifiers |
1389 to avoid non-intuitive behavior. */ | |
1390 clear_sticky_modifiers (XDEVICE (FRAME_DEVICE (f))); | |
1391 | |
1392 /* We don't want to handle the focus change now, because we might | |
1393 be in an accept-process-output, sleep-for, or sit-for. So | |
1394 we enqueue it. | |
1395 | |
1396 Actually, we half handle it: we handle it as far as changing the | |
1397 box cursor for redisplay, but we don't call any hooks or do any | |
1398 select-frame stuff until after the sit-for. | |
1399 | |
1400 Unfortunately native widgets break the model because they grab | |
1401 the keyboard focus and nothing sets it back again. I cannot find | |
1402 any reasonable way to do this elsewhere so we assert here that | |
1403 the keyboard focus is on the emacs text widget. Menus and dialogs | |
1404 do this in their selection callback, but we don't want that since | |
1405 a button having focus is legitimate. An edit field having focus | |
1406 is mandatory. Weirdly you get a FocusOut event when you click in | |
442 | 1407 a widget-glyph but you don't get a corresponding FocusIn when you |
428 | 1408 click in the frame. Why is this? */ |
438 | 1409 if (in_p |
1410 #if XtSpecificationRelease > 5 | |
863 | 1411 && needs_it != widget_with_focus |
428 | 1412 #endif |
1413 ) | |
1414 { | |
863 | 1415 lw_set_keyboard_focus (FRAME_X_SHELL_WIDGET (f), needs_it); |
428 | 1416 } |
450 | 1417 |
863 | 1418 /* If we are focusing on a native widget then record and exit. */ |
1419 if (needs_it != FRAME_X_TEXT_WIDGET (f)) { | |
1420 widget_with_focus = needs_it; | |
1421 return; | |
1422 } | |
1423 | |
450 | 1424 /* We have the focus now. See comment in |
1425 emacs_Xt_handle_widget_losing_focus (). */ | |
1426 if (in_p) | |
1427 widget_with_focus = NULL; | |
1428 | |
428 | 1429 /* do the generic event-stream stuff. */ |
1430 { | |
1431 Lisp_Object frm; | |
1432 Lisp_Object conser; | |
1433 struct gcpro gcpro1; | |
1434 | |
793 | 1435 frm = wrap_frame (f); |
428 | 1436 conser = Fcons (frm, Fcons (FRAME_DEVICE (f), in_p ? Qt : Qnil)); |
1437 GCPRO1 (conser); | |
1438 emacs_handle_focus_change_preliminary (conser); | |
1439 enqueue_magic_eval_event (emacs_handle_focus_change_final, | |
1440 conser); | |
1441 UNGCPRO; | |
1442 } | |
1443 } | |
1444 | |
863 | 1445 /* Create a synthetic X focus event. */ |
1111 | 1446 void emacs_Xt_enqueue_focus_event (Widget wants_it, Lisp_Object frame, |
1447 int in_p); | |
863 | 1448 void |
1111 | 1449 emacs_Xt_enqueue_focus_event (Widget wants_it, Lisp_Object frame, int in_p) |
863 | 1450 { |
1451 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil); | |
1452 Lisp_Event *ev = XEVENT (emacs_event); | |
960 | 1453 XEvent *x_event; |
1454 | |
1455 XSET_EVENT_TYPE (emacs_event, magic_event); | |
1204 | 1456 x_event = &EVENT_MAGIC_X_EVENT (ev); |
863 | 1457 |
1458 x_event->type = in_p ? FocusIn : FocusOut; | |
1459 x_event->xfocus.window = XtWindow (wants_it); | |
1460 | |
960 | 1461 SET_EVENT_CHANNEL (ev, frame); |
1204 | 1462 |
1463 enqueue_dispatch_event (emacs_event); | |
863 | 1464 } |
1465 | |
450 | 1466 /* The idea here is that when a widget glyph gets unmapped we don't |
1467 want the focus to stay with it if it has focus - because it may | |
863 | 1468 well just get deleted next and then we have lost the focus until the |
450 | 1469 user does something. So handle_focus_event_1 records the widget |
1470 with keyboard focus when FocusOut is processed, and then, when a | |
1471 widget gets unmapped, it calls this function to restore focus if | |
1472 appropriate. */ | |
853 | 1473 void emacs_Xt_handle_widget_losing_focus (struct frame *f, Widget losing_widget); |
450 | 1474 void |
853 | 1475 emacs_Xt_handle_widget_losing_focus (struct frame *f, Widget losing_widget) |
450 | 1476 { |
1477 if (losing_widget == widget_with_focus) | |
1478 { | |
1479 handle_focus_event_1 (f, 1); | |
1480 } | |
1481 } | |
1482 | |
428 | 1483 /* This is called from the external-widget code */ |
1484 | |
1485 void emacs_Xt_handle_focus_event (XEvent *event); | |
1486 void | |
1487 emacs_Xt_handle_focus_event (XEvent *event) | |
1488 { | |
1489 struct device *d = get_device_from_display (event->xany.display); | |
1490 struct frame *f; | |
1491 | |
1492 if (DEVICE_X_BEING_DELETED (d)) | |
1493 return; | |
1494 | |
1495 /* | |
1496 * It's curious that we're using x_any_window_to_frame() instead | |
1497 * of x_window_to_frame(). I don't know what the impact of this is. | |
1498 */ | |
1499 f = x_any_window_to_frame (d, event->xfocus.window); | |
1500 if (!f) | |
1501 /* focus events are sometimes generated just before | |
1502 a frame is destroyed. */ | |
1503 return; | |
1504 handle_focus_event_1 (f, event->type == FocusIn); | |
1505 } | |
1506 | |
1507 /* both MapNotify and VisibilityNotify can cause this | |
1508 JV is_visible has the same semantics as f->visible*/ | |
1509 static void | |
1510 change_frame_visibility (struct frame *f, int is_visible) | |
1511 { | |
793 | 1512 Lisp_Object frame = wrap_frame (f); |
1513 | |
428 | 1514 |
1515 if (!FRAME_VISIBLE_P (f) && is_visible) | |
1516 { | |
1517 FRAME_VISIBLE_P (f) = is_visible; | |
872 | 1518 /* [[ This improves the double flicker when uniconifying a frame |
428 | 1519 some. A lot of it is not showing a buffer which has changed |
1520 while the frame was iconified. To fix it further requires | |
872 | 1521 the good 'ol double redisplay structure. ]] -- comment is |
1522 invalid, obviously predates 19.12, when the double redisplay | |
1523 structure (i.e. current + desired) was put back in. --ben */ | |
428 | 1524 MARK_FRAME_WINDOWS_STRUCTURE_CHANGED (f); |
1525 va_run_hook_with_args (Qmap_frame_hook, 1, frame); | |
1526 } | |
1527 else if (FRAME_VISIBLE_P (f) && !is_visible) | |
1528 { | |
1529 FRAME_VISIBLE_P (f) = 0; | |
1530 va_run_hook_with_args (Qunmap_frame_hook, 1, frame); | |
1531 } | |
1532 else if (FRAME_VISIBLE_P (f) * is_visible < 0) | |
1533 { | |
1534 FRAME_VISIBLE_P(f) = - FRAME_VISIBLE_P(f); | |
1535 if (FRAME_REPAINT_P(f)) | |
1536 MARK_FRAME_WINDOWS_STRUCTURE_CHANGED (f); | |
1537 va_run_hook_with_args (Qmap_frame_hook, 1, frame); | |
1538 } | |
1539 } | |
1540 | |
1541 static void | |
593 | 1542 update_frame_iconify_status (struct frame *f) |
1543 { | |
1544 f->iconified = (x_frame_window_state (f) == IconicState); | |
1545 } | |
1546 | |
1547 static void | |
428 | 1548 handle_map_event (struct frame *f, XEvent *event) |
1549 { | |
593 | 1550 |
1551 /* It seems that, given the multiplicity of window managers and X | |
1552 implementations, plus the fact that X was designed without | |
1553 window managers or icons in mind and this was then grafted on | |
1554 with about the skill of a drunk freshman med student attempting | |
1555 surgery with a rusty razor blade, we cannot treat any off | |
1556 MapNotify/UnmapNotify/VisibilityNotify as more than vague hints | |
1557 as to the actual situation. | |
1558 | |
1559 So we should just query the actual status. Unfortunately, things | |
1560 are worse because (a) there aren't obvious ways to query some | |
1561 of these values (e.g. "totally visible"), and (b) there may be | |
1562 race conditions (see below). | |
1563 | |
638 | 1564 However, according to the ICCCM, there's a specific way to |
593 | 1565 ask the window manager whether the state is (a) visible, |
1566 (b) iconic, (c) withdrawn. It must be one of these three. | |
1567 We already use this call to check for the iconified state. | |
1568 I'd suggest we do the same for visible (i.e. NormalState), | |
1569 and scrap most of the nasty code below. | |
1570 | |
1571 --ben | |
1572 */ | |
1573 | |
1574 update_frame_iconify_status (f); | |
1575 | |
1576 /* #### Ben suggests rewriting the code below using | |
1577 x_frame_window_state (f). */ | |
1578 | |
428 | 1579 if (event->type == MapNotify) |
1580 { | |
1581 XWindowAttributes xwa; | |
1582 | |
1583 /* Bleagh!!!!!! Apparently some window managers (e.g. MWM) | |
1584 send synthetic MapNotify events when a window is first | |
1585 created, EVEN IF IT'S CREATED ICONIFIED OR INVISIBLE. | |
1586 Or something like that. We initially tried a different | |
1587 solution below, but that ran into a different window- | |
1588 manager bug. | |
1589 | |
1590 It seems that the only reliable way is to treat a | |
1591 MapNotify event as a "hint" that the window might or | |
1592 might not be visible, and check explicitly. */ | |
1593 | |
1594 XGetWindowAttributes (event->xany.display, event->xmap.window, | |
1595 &xwa); | |
1596 if (xwa.map_state != IsViewable) | |
593 | 1597 return; |
428 | 1598 |
1599 FRAME_X_TOTALLY_VISIBLE_P (f) = 1; | |
1600 #if 0 | |
1601 /* Bleagh again!!!! We initially tried the following hack | |
1602 around the MWM problem, but it turns out that TWM | |
1603 has a race condition when you un-iconify, where it maps | |
1604 the window and then tells the server that the window | |
1605 is un-iconified. Usually, XEmacs wakes up between | |
1606 those two occurrences, and thus thinks that un-iconified | |
1607 windows are still iconified. | |
1608 | |
1609 Ah, the joys of X. */ | |
1610 | |
1611 /* By Emacs definition, a frame that is iconified is not | |
1612 visible. Marking a frame as visible will automatically cause | |
1613 frame-iconified-p to return nil, regardless of whether the | |
1614 frame is actually iconified. Therefore, we have to ignore | |
1615 MapNotify events on iconified frames. (It's not obvious | |
1616 to me why these are being sent, but it happens at startup | |
1617 with frames that are initially iconified; perhaps they are | |
1618 synthetic MapNotify events coming from the window manager.) | |
1619 Note that `frame-iconified-p' queries the server | |
1620 to determine whether the frame is currently iconified, | |
1621 rather than consulting some internal (and likely | |
1622 inaccurate) state flag. Therefore, ignoring the MapNotify | |
1623 is correct. */ | |
793 | 1624 if (!FRAME_VISIBLE_P (f) && NILP (Fframe_iconified_p (wrap_frame (f)))) |
428 | 1625 #endif /* 0 */ |
1626 change_frame_visibility (f, 1); | |
1627 } | |
1628 else | |
1629 { | |
1630 FRAME_X_TOTALLY_VISIBLE_P (f) = 0; | |
1631 change_frame_visibility (f, 0); | |
1632 } | |
1633 } | |
1634 | |
1635 static void | |
1636 handle_client_message (struct frame *f, XEvent *event) | |
1637 { | |
1638 struct device *d = XDEVICE (FRAME_DEVICE (f)); | |
793 | 1639 Lisp_Object frame = wrap_frame (f); |
428 | 1640 |
1641 if (event->xclient.message_type == DEVICE_XATOM_WM_PROTOCOLS (d) && | |
1642 (Atom) (event->xclient.data.l[0]) == DEVICE_XATOM_WM_DELETE_WINDOW (d)) | |
1643 { | |
1644 /* WM_DELETE_WINDOW is a misc-user event, but other ClientMessages, | |
1645 such as WM_TAKE_FOCUS, are eval events. That's because delete-window | |
1646 was probably executed with a mouse click, while the others could | |
1647 have been sent as a result of mouse motion or some other implicit | |
1648 action. (Call this a "heuristic"...) The reason for caring about | |
1649 this is so that clicking on the close-box will make emacs prompt | |
1650 using a dialog box instead of the minibuffer if there are unsaved | |
1651 buffers. | |
1652 */ | |
1653 enqueue_misc_user_event (frame, Qeval, | |
1654 list3 (Qdelete_frame, frame, Qt)); | |
1655 } | |
1656 else if (event->xclient.message_type == DEVICE_XATOM_WM_PROTOCOLS (d) && | |
1657 (Atom) event->xclient.data.l[0] == DEVICE_XATOM_WM_TAKE_FOCUS (d)) | |
1658 { | |
1659 handle_focus_event_1 (f, 1); | |
1660 #if 0 | |
1661 /* If there is a dialog box up, focus on it. | |
1662 | |
1663 #### Actually, we're raising it too, which is wrong. We should | |
1664 #### just focus on it, but lwlib doesn't currently give us an | |
1665 #### easy way to do that. This should be fixed. | |
1666 */ | |
1667 unsigned long take_focus_timestamp = event->xclient.data.l[1]; | |
1668 Widget widget = lw_raise_all_pop_up_widgets (); | |
1669 if (widget) | |
1670 { | |
1671 /* kludge: raise_all returns bottommost widget, but we really | |
1672 want the topmost. So just raise it for now. */ | |
1673 XMapRaised (XtDisplay (widget), XtWindow (widget)); | |
1674 /* Grab the focus with the timestamp of the TAKE_FOCUS. */ | |
1675 XSetInputFocus (XtDisplay (widget), XtWindow (widget), | |
1676 RevertToParent, take_focus_timestamp); | |
1677 } | |
1678 #endif | |
1679 } | |
1680 } | |
1681 | |
448 | 1682 /* #### I'm struggling to understand how the X event loop really works. |
1683 Here is the problem: | |
1684 | |
1685 When widgets get mapped / changed etc the actual display updates | |
1686 are done asynchronously via X events being processed - this | |
1687 normally happens when XtAppProcessEvent() gets called. However, if | |
1688 we are executing lisp code or even doing redisplay we won't | |
1689 necessarily process X events for a very long time. This has the | |
1690 effect of widgets only getting updated when XEmacs only goes into | |
1691 idle, or some other event causes processing of the X event queue. | |
1692 | |
1693 XtAppProcessEvent can get called from the following places: | |
1694 | |
1695 emacs_Xt_next_event () - this is normal event processing, almost | |
1696 any non-X event will take precedence and this means that we | |
1697 cannot rely on it to do the right thing at the right time for | |
1698 widget display. | |
1699 | |
1204 | 1700 emacs_Xt_drain_queue () - this happens when SIGIO gets tripped, |
1701 processing the event queue allows C-g to be checked for. It gets | |
1702 called from emacs_Xt_event_pending_p (). #### Update this comment. | |
448 | 1703 |
1704 In order to solve this I have tried introducing a list primitive - | |
1705 dispatch-non-command-events - which forces processing of X events | |
1706 related to display. Unfortunately this has a number of problems, | |
1707 one is that it is possible for event_stream_event_pending_p to | |
1708 block for ever if there isn't actually an event. I guess this can | |
1709 happen if we drop the synthetic event for reason. It also relies on | |
1710 SIGIO processing which makes things rather fragile. | |
1711 | |
1712 People have seen behaviour whereby XEmacs blocks until you move the | |
1713 mouse. This seems to indicate that dispatch-non-command-events is | |
1714 blocking. It may be that in a SIGIO world forcing SIGIO processing | |
1715 does the wrong thing. | |
1716 */ | |
428 | 1717 static void |
853 | 1718 emacs_Xt_force_event_pending (struct frame *f) |
442 | 1719 { |
1720 XEvent event; | |
1721 | |
853 | 1722 Display *dpy = DEVICE_X_DISPLAY (XDEVICE (FRAME_DEVICE (f))); |
442 | 1723 event.xclient.type = ClientMessage; |
1724 event.xclient.display = dpy; | |
1725 event.xclient.message_type = XInternAtom (dpy, "BumpQueue", False); | |
1726 event.xclient.format = 32; | |
1727 event.xclient.window = 0; | |
1728 | |
1729 /* Send the drop message */ | |
1730 XSendEvent(dpy, XtWindow (FRAME_X_SHELL_WIDGET (f)), | |
1731 True, NoEventMask, &event); | |
448 | 1732 /* We rely on SIGIO and friends to realise we have generated an |
1733 event. */ | |
442 | 1734 } |
1735 | |
1736 static void | |
788 | 1737 emacs_Xt_format_magic_event (Lisp_Event *event, Lisp_Object pstream) |
1738 { | |
1739 Lisp_Object console = CDFW_CONSOLE (EVENT_CHANNEL (event)); | |
1740 if (CONSOLE_X_P (XCONSOLE (console))) | |
4952
19a72041c5ed
Mule-izing, various fixes related to char * arguments
Ben Wing <ben@xemacs.org>
parents:
4790
diff
changeset
|
1741 write_ascstring |
1204 | 1742 (pstream, x_event_name ((EVENT_MAGIC_X_EVENT (event)).type)); |
788 | 1743 } |
1744 | |
1745 static int | |
1746 emacs_Xt_compare_magic_event (Lisp_Event *e1, Lisp_Event *e2) | |
1747 { | |
1748 if (CONSOLE_X_P (XCONSOLE (CDFW_CONSOLE (EVENT_CHANNEL (e1)))) && | |
1749 CONSOLE_X_P (XCONSOLE (CDFW_CONSOLE (EVENT_CHANNEL (e2))))) | |
1204 | 1750 return ((EVENT_MAGIC_X_EVENT (e1)).xany.serial == |
1751 (EVENT_MAGIC_X_EVENT (e2)).xany.serial); | |
788 | 1752 if (CONSOLE_X_P (XCONSOLE (CDFW_CONSOLE (EVENT_CHANNEL (e1)))) || |
1753 CONSOLE_X_P (XCONSOLE (CDFW_CONSOLE (EVENT_CHANNEL (e2))))) | |
1754 return 0; | |
1755 return 1; | |
1756 } | |
1757 | |
1758 static Hashcode | |
1759 emacs_Xt_hash_magic_event (Lisp_Event *e) | |
1760 { | |
1761 Lisp_Object console = CDFW_CONSOLE (EVENT_CHANNEL (e)); | |
1762 if (CONSOLE_X_P (XCONSOLE (console))) | |
1204 | 1763 return (EVENT_MAGIC_X_EVENT (e)).xany.serial; |
788 | 1764 return 0; |
1765 } | |
1766 | |
1767 static void | |
440 | 1768 emacs_Xt_handle_magic_event (Lisp_Event *emacs_event) |
428 | 1769 { |
1770 /* This function can GC */ | |
1204 | 1771 XEvent *event = &EVENT_MAGIC_X_EVENT (emacs_event); |
428 | 1772 struct frame *f = XFRAME (EVENT_CHANNEL (emacs_event)); |
1773 | |
1774 if (!FRAME_LIVE_P (f) || DEVICE_X_BEING_DELETED (XDEVICE (FRAME_DEVICE (f)))) | |
1775 return; | |
1776 | |
1777 switch (event->type) | |
1778 { | |
1779 case SelectionRequest: | |
1780 x_handle_selection_request (&event->xselectionrequest); | |
1781 break; | |
934 | 1782 |
428 | 1783 case SelectionClear: |
1784 x_handle_selection_clear (&event->xselectionclear); | |
1785 break; | |
934 | 1786 |
428 | 1787 case SelectionNotify: |
1788 x_handle_selection_notify (&event->xselection); | |
1789 break; | |
934 | 1790 |
428 | 1791 case PropertyNotify: |
1792 x_handle_property_notify (&event->xproperty); | |
1793 break; | |
934 | 1794 |
428 | 1795 case Expose: |
1796 if (!check_for_ignored_expose (f, event->xexpose.x, event->xexpose.y, | |
1318 | 1797 event->xexpose.width, |
1798 event->xexpose.height) | |
428 | 1799 && |
1800 !find_matching_subwindow (f, event->xexpose.x, event->xexpose.y, | |
1801 event->xexpose.width, event->xexpose.height)) | |
1318 | 1802 redisplay_redraw_exposed_area (f, event->xexpose.x, event->xexpose.y, |
1803 event->xexpose.width, | |
1804 event->xexpose.height); | |
428 | 1805 break; |
1806 | |
1807 case GraphicsExpose: /* This occurs when an XCopyArea's source area was | |
1808 obscured or not available. */ | |
1318 | 1809 redisplay_redraw_exposed_area (f, event->xexpose.x, event->xexpose.y, |
1810 event->xexpose.width, | |
1811 event->xexpose.height); | |
428 | 1812 break; |
1813 | |
1814 case MapNotify: | |
1815 case UnmapNotify: | |
1816 handle_map_event (f, event); | |
1817 break; | |
1818 | |
1819 case EnterNotify: | |
1820 if (event->xcrossing.detail != NotifyInferior) | |
1821 { | |
793 | 1822 Lisp_Object frame = wrap_frame (f); |
1823 | |
428 | 1824 /* FRAME_X_MOUSE_P (f) = 1; */ |
1825 va_run_hook_with_args (Qmouse_enter_frame_hook, 1, frame); | |
1826 } | |
1827 break; | |
1828 | |
1829 case LeaveNotify: | |
1830 if (event->xcrossing.detail != NotifyInferior) | |
1831 { | |
793 | 1832 Lisp_Object frame = wrap_frame (f); |
1833 | |
428 | 1834 /* FRAME_X_MOUSE_P (f) = 0; */ |
1835 va_run_hook_with_args (Qmouse_leave_frame_hook, 1, frame); | |
1836 } | |
1837 break; | |
1838 | |
1839 case FocusIn: | |
1840 case FocusOut: | |
1841 | |
1842 #ifdef EXTERNAL_WIDGET | |
1843 /* External widget lossage: Ben said: | |
1844 YUCK. The only way to make focus changes work properly is to | |
1845 completely ignore all FocusIn/FocusOut events and depend only | |
1846 on notifications from the ExternalClient widget. */ | |
1847 if (FRAME_X_EXTERNAL_WINDOW_P (f)) | |
1848 break; | |
1849 #endif | |
863 | 1850 handle_focus_event_2 (event->xfocus.window, f, event->type == FocusIn); |
428 | 1851 break; |
1852 | |
1853 case ClientMessage: | |
1854 handle_client_message (f, event); | |
1855 break; | |
1856 | |
1857 case VisibilityNotify: /* window visibility has changed */ | |
1858 if (event->xvisibility.window == XtWindow (FRAME_X_SHELL_WIDGET (f))) | |
1859 { | |
593 | 1860 /* See comment in handle_map_event */ |
1861 update_frame_iconify_status (f); | |
1862 | |
1863 /* #### Ben suggests rewriting the code below using | |
1864 x_frame_window_state (f). */ | |
428 | 1865 FRAME_X_TOTALLY_VISIBLE_P (f) = |
1866 (event->xvisibility.state == VisibilityUnobscured); | |
1867 /* Note that the fvwm pager only sends VisibilityNotify when | |
1868 changing pages. Is this all we need to do ? JV */ | |
1869 /* Nope. We must at least trigger a redisplay here. | |
1870 Since this case seems similar to MapNotify, I've | |
1871 factored out some code to change_frame_visibility(). | |
1872 This triggers the necessary redisplay and runs | |
1873 (un)map-frame-hook. - dkindred@cs.cmu.edu */ | |
1874 /* Changed it again to support the tristate visibility flag */ | |
1875 change_frame_visibility (f, (event->xvisibility.state | |
1876 != VisibilityFullyObscured) ? 1 : -1); | |
1877 } | |
1878 break; | |
1879 | |
1880 case ConfigureNotify: | |
5080
5502045ec510
The background-placement face property.
Didier Verna <didier@lrde.epita.fr>
parents:
5018
diff
changeset
|
1881 { |
5502045ec510
The background-placement face property.
Didier Verna <didier@lrde.epita.fr>
parents:
5018
diff
changeset
|
1882 XEvent xev; |
5502045ec510
The background-placement face property.
Didier Verna <didier@lrde.epita.fr>
parents:
5018
diff
changeset
|
1883 |
5502045ec510
The background-placement face property.
Didier Verna <didier@lrde.epita.fr>
parents:
5018
diff
changeset
|
1884 /* Let's eat all events of that type to avoid useless |
5502045ec510
The background-placement face property.
Didier Verna <didier@lrde.epita.fr>
parents:
5018
diff
changeset
|
1885 reconfigurations. */ |
5502045ec510
The background-placement face property.
Didier Verna <didier@lrde.epita.fr>
parents:
5018
diff
changeset
|
1886 while (XCheckTypedWindowEvent |
5502045ec510
The background-placement face property.
Didier Verna <didier@lrde.epita.fr>
parents:
5018
diff
changeset
|
1887 (DEVICE_X_DISPLAY (XDEVICE (FRAME_DEVICE (f))), |
5502045ec510
The background-placement face property.
Didier Verna <didier@lrde.epita.fr>
parents:
5018
diff
changeset
|
1888 XtWindow (FRAME_X_TEXT_WIDGET (f)), |
5502045ec510
The background-placement face property.
Didier Verna <didier@lrde.epita.fr>
parents:
5018
diff
changeset
|
1889 ConfigureNotify, |
5502045ec510
The background-placement face property.
Didier Verna <didier@lrde.epita.fr>
parents:
5018
diff
changeset
|
1890 &xev) |
5502045ec510
The background-placement face property.
Didier Verna <didier@lrde.epita.fr>
parents:
5018
diff
changeset
|
1891 == True); |
5502045ec510
The background-placement face property.
Didier Verna <didier@lrde.epita.fr>
parents:
5018
diff
changeset
|
1892 } |
5502045ec510
The background-placement face property.
Didier Verna <didier@lrde.epita.fr>
parents:
5018
diff
changeset
|
1893 /* #### NOTE: in fact, the frame faces didn't really change, but if some |
5502045ec510
The background-placement face property.
Didier Verna <didier@lrde.epita.fr>
parents:
5018
diff
changeset
|
1894 #### of them have their background-placement property set to |
5502045ec510
The background-placement face property.
Didier Verna <didier@lrde.epita.fr>
parents:
5018
diff
changeset
|
1895 #### absolute, we need a redraw. This is semantically equivalent to |
5502045ec510
The background-placement face property.
Didier Verna <didier@lrde.epita.fr>
parents:
5018
diff
changeset
|
1896 #### changing the background pixmap. -- dvl */ |
5502045ec510
The background-placement face property.
Didier Verna <didier@lrde.epita.fr>
parents:
5018
diff
changeset
|
1897 x_get_frame_text_position (f); |
5502045ec510
The background-placement face property.
Didier Verna <didier@lrde.epita.fr>
parents:
5018
diff
changeset
|
1898 MARK_FRAME_FACES_CHANGED (f); |
5502045ec510
The background-placement face property.
Didier Verna <didier@lrde.epita.fr>
parents:
5018
diff
changeset
|
1899 |
428 | 1900 #ifdef HAVE_XIM |
1901 XIM_SetGeometry (f); | |
1902 #endif | |
1903 break; | |
1904 | |
442 | 1905 case CreateNotify: |
1906 break; | |
1907 | |
428 | 1908 default: |
1909 break; | |
1910 } | |
1911 } | |
1912 | |
1913 | |
1914 /************************************************************************/ | |
1915 /* timeout events */ | |
1916 /************************************************************************/ | |
1917 | |
1918 static int timeout_id_tick; | |
1919 | |
1920 /* Xt interval id's might not fit into an int (they're pointers, as it | |
1921 happens), so we need to provide a conversion list. */ | |
1922 | |
1923 static struct Xt_timeout | |
1924 { | |
1925 int id; | |
1926 XtIntervalId interval_id; | |
1927 struct Xt_timeout *next; | |
1928 } *pending_timeouts, *completed_timeouts; | |
1929 | |
1930 static struct Xt_timeout_blocktype | |
1931 { | |
1932 Blocktype_declare (struct Xt_timeout); | |
1933 } *the_Xt_timeout_blocktype; | |
1934 | |
1935 /* called by XtAppNextEvent() */ | |
1936 static void | |
2286 | 1937 Xt_timeout_callback (XtPointer closure, XtIntervalId *UNUSED (id)) |
428 | 1938 { |
1939 struct Xt_timeout *timeout = (struct Xt_timeout *) closure; | |
1940 struct Xt_timeout *t2 = pending_timeouts; | |
1941 /* Remove this one from the list of pending timeouts */ | |
1942 if (t2 == timeout) | |
1943 pending_timeouts = pending_timeouts->next; | |
1944 else | |
1945 { | |
1946 while (t2->next && t2->next != timeout) t2 = t2->next; | |
1947 assert (t2->next); | |
1948 t2->next = t2->next->next; | |
1949 } | |
1950 /* Add this one to the list of completed timeouts */ | |
1951 timeout->next = completed_timeouts; | |
1952 completed_timeouts = timeout; | |
1953 } | |
1954 | |
1955 static int | |
1956 emacs_Xt_add_timeout (EMACS_TIME thyme) | |
1957 { | |
1958 struct Xt_timeout *timeout = Blocktype_alloc (the_Xt_timeout_blocktype); | |
1959 EMACS_TIME current_time; | |
1960 int milliseconds; | |
1961 | |
1962 timeout->id = timeout_id_tick++; | |
1963 timeout->next = pending_timeouts; | |
1964 pending_timeouts = timeout; | |
1965 EMACS_GET_TIME (current_time); | |
1966 EMACS_SUB_TIME (thyme, thyme, current_time); | |
1967 milliseconds = EMACS_SECS (thyme) * 1000 + | |
1968 EMACS_USECS (thyme) / 1000; | |
1969 if (milliseconds < 1) | |
1970 milliseconds = 1; | |
1971 timeout->interval_id = XtAppAddTimeOut (Xt_app_con, milliseconds, | |
1972 Xt_timeout_callback, | |
1973 (XtPointer) timeout); | |
1974 return timeout->id; | |
1975 } | |
1976 | |
1977 static void | |
1978 emacs_Xt_remove_timeout (int id) | |
1979 { | |
1980 struct Xt_timeout *timeout, *t2; | |
1981 | |
1982 timeout = NULL; | |
1983 | |
1984 /* Find the timeout on the list of pending ones, if it's still there. */ | |
1985 if (pending_timeouts) | |
1986 { | |
1987 if (id == pending_timeouts->id) | |
1988 { | |
1989 timeout = pending_timeouts; | |
1990 pending_timeouts = pending_timeouts->next; | |
1991 } | |
1992 else | |
1993 { | |
1994 t2 = pending_timeouts; | |
1995 while (t2->next && t2->next->id != id) t2 = t2->next; | |
1996 if ( t2->next) /*found it */ | |
1997 { | |
1998 timeout = t2->next; | |
1999 t2->next = t2->next->next; | |
2000 } | |
2001 } | |
2002 /* if it was pending, we have removed it from the list */ | |
2003 if (timeout) | |
2004 XtRemoveTimeOut (timeout->interval_id); | |
2005 } | |
2006 | |
2007 /* It could be that the Xt call back was already called but we didn't convert | |
2008 into an Emacs event yet */ | |
2009 if (!timeout && completed_timeouts) | |
2010 { | |
2011 /* Code duplication! */ | |
2012 if (id == completed_timeouts->id) | |
2013 { | |
2014 timeout = completed_timeouts; | |
2015 completed_timeouts = completed_timeouts->next; | |
2016 } | |
2017 else | |
2018 { | |
2019 t2 = completed_timeouts; | |
2020 while (t2->next && t2->next->id != id) t2 = t2->next; | |
2021 if ( t2->next) /*found it */ | |
2022 { | |
2023 timeout = t2->next; | |
2024 t2->next = t2->next->next; | |
2025 } | |
2026 } | |
2027 } | |
2028 | |
2029 /* If we found the thing on the lists of timeouts, | |
2030 and removed it, deallocate | |
2031 */ | |
2032 if (timeout) | |
2033 Blocktype_free (the_Xt_timeout_blocktype, timeout); | |
2034 } | |
2035 | |
2036 static void | |
440 | 2037 Xt_timeout_to_emacs_event (Lisp_Event *emacs_event) |
428 | 2038 { |
2039 struct Xt_timeout *timeout = completed_timeouts; | |
2040 assert (timeout); | |
2041 completed_timeouts = completed_timeouts->next; | |
934 | 2042 /* timeout events have nil as channel */ |
1204 | 2043 set_event_type (emacs_event, timeout_event); |
934 | 2044 SET_EVENT_TIMESTAMP_ZERO (emacs_event); /* #### wrong!! */ |
1204 | 2045 SET_EVENT_TIMEOUT_INTERVAL_ID (emacs_event, timeout->id); |
2046 SET_EVENT_TIMEOUT_FUNCTION (emacs_event, Qnil); | |
2047 SET_EVENT_TIMEOUT_OBJECT (emacs_event, Qnil); | |
428 | 2048 Blocktype_free (the_Xt_timeout_blocktype, timeout); |
2049 } | |
2050 | |
2051 | |
2052 /************************************************************************/ | |
2053 /* process and tty events */ | |
2054 /************************************************************************/ | |
2055 | |
2056 struct what_is_ready_closure | |
2057 { | |
2058 int fd; | |
2059 Lisp_Object what; | |
2060 XtInputId id; | |
2061 }; | |
2062 | |
2063 static Lisp_Object *filedesc_with_input; | |
2064 static struct what_is_ready_closure **filedesc_to_what_closure; | |
2065 | |
2066 static void | |
2067 init_what_input_once (void) | |
2068 { | |
2069 int i; | |
2070 | |
2071 filedesc_with_input = xnew_array (Lisp_Object, MAXDESC); | |
2072 filedesc_to_what_closure = | |
2073 xnew_array (struct what_is_ready_closure *, MAXDESC); | |
2074 | |
2075 for (i = 0; i < MAXDESC; i++) | |
2076 { | |
2077 filedesc_to_what_closure[i] = 0; | |
2078 filedesc_with_input[i] = Qnil; | |
2079 } | |
2080 | |
2081 process_events_occurred = 0; | |
2082 tty_events_occurred = 0; | |
2083 } | |
2084 | |
2085 static void | |
2086 mark_what_as_being_ready (struct what_is_ready_closure *closure) | |
2087 { | |
2088 if (NILP (filedesc_with_input[closure->fd])) | |
2089 { | |
2090 SELECT_TYPE temp_mask; | |
2091 FD_ZERO (&temp_mask); | |
2092 FD_SET (closure->fd, &temp_mask); | |
2093 /* Check to make sure there's *really* input available. | |
2094 Sometimes things seem to get confused and this gets called | |
2095 for the tty fd when there's really only input available | |
2096 on some process's fd. (It will subsequently get called | |
2097 for that process's fd, so returning without setting any | |
2098 flags will take care of it.) To see the problem, uncomment | |
2099 the stderr_out below, turn NORMAL_QUIT_CHECK_TIMEOUT_MSECS | |
2100 down to 25, do sh -c 'xemacs -nw -q -f shell 2>/tmp/log' | |
2101 and press return repeatedly. (Seen under AIX & Linux.) | |
2102 -dkindred@cs.cmu.edu */ | |
2103 if (!poll_fds_for_input (temp_mask)) | |
2104 { | |
2105 #if 0 | |
2106 stderr_out ("mark_what_as_being_ready: no input available (fd=%d)\n", | |
2107 closure->fd); | |
2108 #endif | |
2109 return; | |
2110 } | |
2111 filedesc_with_input[closure->fd] = closure->what; | |
2112 if (PROCESSP (closure->what)) | |
2113 /* Don't increment this if the current process is already marked | |
2114 * as having input. */ | |
2115 process_events_occurred++; | |
2116 else | |
2117 tty_events_occurred++; | |
2118 } | |
2119 } | |
2120 | |
2121 static void | |
2286 | 2122 Xt_what_callback (void *closure, int *UNUSED (source), XtInputId *UNUSED (id)) |
428 | 2123 { |
2124 /* If closure is 0, then we got a fake event from a signal handler. | |
2125 The only purpose of this is to make XtAppProcessEvent() stop | |
2126 blocking. */ | |
2127 if (closure) | |
2128 mark_what_as_being_ready ((struct what_is_ready_closure *) closure); | |
2129 else | |
2130 { | |
2131 fake_event_occurred++; | |
2132 drain_signal_event_pipe (); | |
2133 } | |
2134 } | |
2135 | |
2136 static void | |
2137 select_filedesc (int fd, Lisp_Object what) | |
2138 { | |
2139 struct what_is_ready_closure *closure; | |
2140 | |
2141 /* If somebody is trying to select something that's already selected | |
2142 for, then something went wrong. The generic routines ought to | |
2143 detect this and error before here. */ | |
2144 assert (!filedesc_to_what_closure[fd]); | |
2145 | |
2146 closure = xnew (struct what_is_ready_closure); | |
2147 closure->fd = fd; | |
2148 closure->what = what; | |
2149 closure->id = | |
2150 XtAppAddInput (Xt_app_con, fd, | |
2151 (XtPointer) (XtInputReadMask /* | XtInputExceptMask */), | |
2152 Xt_what_callback, closure); | |
2153 filedesc_to_what_closure[fd] = closure; | |
2154 } | |
2155 | |
2156 static void | |
2157 unselect_filedesc (int fd) | |
2158 { | |
2159 struct what_is_ready_closure *closure = filedesc_to_what_closure[fd]; | |
2160 | |
2161 assert (closure); | |
2162 if (!NILP (filedesc_with_input[fd])) | |
2163 { | |
2164 /* We are unselecting this process before we have drained the rest of | |
2165 the input from it, probably from status_notify() in the command loop. | |
2166 This can happen like so: | |
2167 | |
2168 - We are waiting in XtAppNextEvent() | |
2169 - Process generates output | |
2170 - Process is marked as being ready | |
2171 - Process dies, SIGCHLD gets generated before we return (!?) | |
2172 It could happen I guess. | |
2173 - sigchld_handler() marks process as dead | |
2174 - Somehow we end up getting a new KeyPress event on the queue | |
2175 at the same time (I'm really so sure how that happens but I'm | |
2176 not sure it can't either so let's assume it can...). | |
2177 - Key events have priority so we return that instead of the proc. | |
2178 - Before dispatching the lisp key event we call status_notify() | |
2179 - Which deselects the process that SIGCHLD marked as dead. | |
2180 | |
2181 Thus we never remove it from _with_input and turn it into a lisp | |
2182 event, so we need to do it here. But this does not mean that we're | |
2183 throwing away the last block of output - status_notify() has already | |
2184 taken care of running the proc filter or whatever. | |
2185 */ | |
2186 filedesc_with_input[fd] = Qnil; | |
2187 if (PROCESSP (closure->what)) | |
2188 { | |
2189 assert (process_events_occurred > 0); | |
2190 process_events_occurred--; | |
2191 } | |
2192 else | |
2193 { | |
2194 assert (tty_events_occurred > 0); | |
2195 tty_events_occurred--; | |
2196 } | |
2197 } | |
2198 XtRemoveInput (closure->id); | |
4976
16112448d484
Rename xfree(FOO, TYPE) -> xfree(FOO)
Ben Wing <ben@xemacs.org>
parents:
4953
diff
changeset
|
2199 xfree (closure); |
428 | 2200 filedesc_to_what_closure[fd] = 0; |
2201 } | |
2202 | |
2203 static void | |
853 | 2204 emacs_Xt_select_process (Lisp_Process *process, int doin, int doerr) |
428 | 2205 { |
853 | 2206 Lisp_Object proc; |
2207 int infd, errfd; | |
2208 | |
2209 event_stream_unixoid_select_process (process, doin, doerr, &infd, &errfd); | |
2210 | |
2211 proc = wrap_process (process); | |
2212 if (doin) | |
2213 select_filedesc (infd, proc); | |
2214 if (doerr) | |
2215 select_filedesc (errfd, proc); | |
2216 } | |
2217 | |
2218 static void | |
2219 emacs_Xt_unselect_process (Lisp_Process *process, int doin, int doerr) | |
2220 { | |
2221 int infd, errfd; | |
2222 | |
2223 event_stream_unixoid_unselect_process (process, doin, doerr, &infd, &errfd); | |
2224 | |
2225 if (doin) | |
2226 unselect_filedesc (infd); | |
2227 if (doerr) | |
2228 unselect_filedesc (errfd); | |
428 | 2229 } |
2230 | |
2231 static void | |
853 | 2232 emacs_Xt_create_io_streams (void *inhandle, void *outhandle, |
2233 void *errhandle, Lisp_Object *instream, | |
2234 Lisp_Object *outstream, | |
2235 Lisp_Object *errstream, | |
2236 USID *in_usid, | |
2237 USID *err_usid, | |
2238 int flags) | |
428 | 2239 { |
853 | 2240 event_stream_unixoid_create_io_streams |
2241 (inhandle, outhandle, errhandle, instream, outstream, | |
2242 errstream, in_usid, err_usid, flags); | |
2243 if (*in_usid != USID_ERROR) | |
2244 *in_usid = USID_DONTHASH; | |
2245 if (*err_usid != USID_ERROR) | |
2246 *err_usid = USID_DONTHASH; | |
428 | 2247 } |
2248 | |
853 | 2249 static void |
2250 emacs_Xt_delete_io_streams (Lisp_Object instream, | |
2251 Lisp_Object outstream, | |
2252 Lisp_Object errstream, | |
2253 USID *in_usid, | |
2254 USID *err_usid) | |
428 | 2255 { |
853 | 2256 event_stream_unixoid_delete_io_streams |
2257 (instream, outstream, errstream, in_usid, err_usid); | |
2258 *in_usid = USID_DONTHASH; | |
2259 *err_usid = USID_DONTHASH; | |
428 | 2260 } |
2261 | |
2262 /* This is called from GC when a process object is about to be freed. | |
2263 If we've still got pointers to it in this file, we're gonna lose hard. | |
2264 */ | |
2265 void | |
2286 | 2266 debug_process_finalization (Lisp_Process *UNUSED (p)) |
428 | 2267 { |
2268 #if 0 /* #### */ | |
2269 int i; | |
853 | 2270 Lisp_Object instr, outstr, errstr; |
2271 | |
2272 get_process_streams (p, &instr, &outstr, &errstr); | |
428 | 2273 /* if it still has fds, then it hasn't been killed yet. */ |
2274 assert (NILP(instr)); | |
2275 assert (NILP(outstr)); | |
853 | 2276 assert (NILP(errstr)); |
428 | 2277 /* Better not still be in the "with input" table; we know it's got no fds. */ |
2278 for (i = 0; i < MAXDESC; i++) | |
2279 { | |
2280 Lisp_Object process = filedesc_fds_with_input [i]; | |
2281 assert (!PROCESSP (process) || XPROCESS (process) != p); | |
2282 } | |
2283 #endif | |
2284 } | |
2285 | |
2286 static void | |
440 | 2287 Xt_process_to_emacs_event (Lisp_Event *emacs_event) |
428 | 2288 { |
2289 int i; | |
2290 | |
2291 assert (process_events_occurred > 0); | |
438 | 2292 |
428 | 2293 for (i = 0; i < MAXDESC; i++) |
2294 { | |
438 | 2295 Lisp_Object process = filedesc_with_input[i]; |
428 | 2296 if (PROCESSP (process)) |
438 | 2297 { |
2298 filedesc_with_input[i] = Qnil; | |
2299 process_events_occurred--; | |
2300 /* process events have nil as channel */ | |
934 | 2301 set_event_type (emacs_event, process_event); |
2302 SET_EVENT_TIMESTAMP_ZERO (emacs_event); /* #### */ | |
1204 | 2303 SET_EVENT_PROCESS_PROCESS (emacs_event, process); |
438 | 2304 return; |
2305 } | |
428 | 2306 } |
2500 | 2307 ABORT (); |
428 | 2308 } |
2309 | |
2310 static void | |
2311 emacs_Xt_select_console (struct console *con) | |
2312 { | |
2313 Lisp_Object console; | |
2314 int infd; | |
2315 | |
2316 if (CONSOLE_X_P (con)) | |
2317 return; /* X consoles are automatically selected for when we | |
2318 initialize them in Xt */ | |
2319 infd = event_stream_unixoid_select_console (con); | |
793 | 2320 console = wrap_console (con); |
428 | 2321 select_filedesc (infd, console); |
2322 } | |
2323 | |
2324 static void | |
2325 emacs_Xt_unselect_console (struct console *con) | |
2326 { | |
2327 int infd; | |
2328 | |
2329 if (CONSOLE_X_P (con)) | |
2330 return; /* X consoles are automatically selected for when we | |
2331 initialize them in Xt */ | |
2332 infd = event_stream_unixoid_unselect_console (con); | |
2333 unselect_filedesc (infd); | |
2334 } | |
2335 | |
2336 /* read an event from a tty, if one is available. Returns non-zero | |
2337 if an event was available. Note that when this function is | |
2338 called, there should always be a tty marked as ready for input. | |
2339 However, the input condition might actually be EOF, so there | |
2340 may not really be any input available. (In this case, | |
2341 read_event_from_tty_or_stream_desc() will arrange for the TTY device | |
2342 to be deleted.) */ | |
2343 | |
2344 static int | |
440 | 2345 Xt_tty_to_emacs_event (Lisp_Event *emacs_event) |
428 | 2346 { |
2347 int i; | |
2348 | |
2349 assert (tty_events_occurred > 0); | |
2350 for (i = 0; i < MAXDESC; i++) | |
2351 { | |
2352 Lisp_Object console = filedesc_with_input[i]; | |
2353 if (CONSOLEP (console)) | |
2354 { | |
2355 assert (tty_events_occurred > 0); | |
2356 tty_events_occurred--; | |
2357 filedesc_with_input[i] = Qnil; | |
771 | 2358 if (read_event_from_tty_or_stream_desc (emacs_event, |
2359 XCONSOLE (console))) | |
428 | 2360 return 1; |
2361 } | |
2362 } | |
2363 | |
2364 return 0; | |
2365 } | |
2366 | |
2367 | |
2368 /************************************************************************/ | |
2369 /* debugging functions to decipher an event */ | |
2370 /************************************************************************/ | |
2371 | |
2372 #ifdef DEBUG_XEMACS | |
2373 #include "xintrinsicp.h" /* only describe_event() needs this */ | |
2374 #include <X11/Xproto.h> /* only describe_event() needs this */ | |
2375 | |
2376 static void | |
788 | 2377 describe_event_window (Window window, Display *display, Lisp_Object pstream) |
428 | 2378 { |
2379 struct frame *f; | |
2380 Widget w; | |
788 | 2381 write_fmt_string (pstream, " window: 0x%lx", (unsigned long) window); |
428 | 2382 w = XtWindowToWidget (display, window); |
2383 if (w) | |
788 | 2384 write_fmt_string (pstream, " %s", |
2385 w->core.widget_class->core_class.class_name); | |
428 | 2386 f = x_any_window_to_frame (get_device_from_display (display), window); |
2387 if (f) | |
788 | 2388 write_fmt_string_lisp (pstream, " \"%s\"", 1, f->name); |
2389 write_fmt_string (pstream, "\n"); | |
428 | 2390 } |
2391 | |
442 | 2392 static const char * |
428 | 2393 XEvent_mode_to_string (int mode) |
2394 { | |
2395 switch (mode) | |
2396 { | |
2397 case NotifyNormal: return "Normal"; | |
2398 case NotifyGrab: return "Grab"; | |
2399 case NotifyUngrab: return "Ungrab"; | |
2400 case NotifyWhileGrabbed: return "WhileGrabbed"; | |
2401 default: return "???"; | |
2402 } | |
2403 } | |
2404 | |
442 | 2405 static const char * |
428 | 2406 XEvent_detail_to_string (int detail) |
2407 { | |
2408 switch (detail) | |
2409 { | |
2410 case NotifyAncestor: return "Ancestor"; | |
2411 case NotifyInferior: return "Inferior"; | |
2412 case NotifyNonlinear: return "Nonlinear"; | |
2413 case NotifyNonlinearVirtual: return "NonlinearVirtual"; | |
2414 case NotifyPointer: return "Pointer"; | |
2415 case NotifyPointerRoot: return "PointerRoot"; | |
2416 case NotifyDetailNone: return "DetailNone"; | |
2417 default: return "???"; | |
2418 } | |
2419 } | |
2420 | |
442 | 2421 static const char * |
428 | 2422 XEvent_visibility_to_string (int state) |
2423 { | |
2424 switch (state) | |
2425 { | |
2426 case VisibilityFullyObscured: return "FullyObscured"; | |
2427 case VisibilityPartiallyObscured: return "PartiallyObscured"; | |
2428 case VisibilityUnobscured: return "Unobscured"; | |
2429 default: return "???"; | |
2430 } | |
2431 } | |
2432 | |
2433 static void | |
788 | 2434 describe_event (XEvent *event, Lisp_Object pstream) |
428 | 2435 { |
4952
19a72041c5ed
Mule-izing, various fixes related to char * arguments
Ben Wing <ben@xemacs.org>
parents:
4790
diff
changeset
|
2436 Ascbyte buf[100]; |
428 | 2437 struct device *d = get_device_from_display (event->xany.display); |
2438 | |
2439 sprintf (buf, "%s%s", x_event_name (event->type), | |
2440 event->xany.send_event ? " (send)" : ""); | |
788 | 2441 write_fmt_string (pstream, "%-30s", buf); |
428 | 2442 switch (event->type) |
2443 { | |
2444 case FocusIn: | |
2445 case FocusOut: | |
2446 { | |
2447 XFocusChangeEvent *ev = &event->xfocus; | |
788 | 2448 describe_event_window (ev->window, ev->display, pstream); |
2449 write_fmt_string (pstream, " mode: %s\n", | |
2450 XEvent_mode_to_string (ev->mode)); | |
2451 write_fmt_string (pstream, " detail: %s\n", | |
2452 XEvent_detail_to_string (ev->detail)); | |
428 | 2453 break; |
2454 } | |
2455 | |
2456 case KeyPress: | |
2457 { | |
2458 XKeyEvent *ev = &event->xkey; | |
2459 unsigned int state = ev->state; | |
2460 | |
788 | 2461 describe_event_window (ev->window, ev->display, pstream); |
2462 write_fmt_string (pstream, " subwindow: %ld\n", ev->subwindow); | |
2463 write_fmt_string (pstream, " state: "); | |
428 | 2464 /* Complete list of modifier key masks */ |
788 | 2465 if (state & ShiftMask) write_fmt_string (pstream, "Shift "); |
2466 if (state & LockMask) write_fmt_string (pstream, "Lock "); | |
2467 if (state & ControlMask) write_fmt_string (pstream, "Control "); | |
2468 if (state & Mod1Mask) write_fmt_string (pstream, "Mod1 "); | |
2469 if (state & Mod2Mask) write_fmt_string (pstream, "Mod2 "); | |
2470 if (state & Mod3Mask) write_fmt_string (pstream, "Mod3 "); | |
2471 if (state & Mod4Mask) write_fmt_string (pstream, "Mod4 "); | |
2472 if (state & Mod5Mask) write_fmt_string (pstream, "Mod5 "); | |
428 | 2473 |
2474 if (! state) | |
788 | 2475 write_fmt_string (pstream, "vanilla\n"); |
428 | 2476 else |
788 | 2477 write_fmt_string (pstream, "\n"); |
428 | 2478 if (x_key_is_modifier_p (ev->keycode, d)) |
788 | 2479 write_fmt_string (pstream, " Modifier key"); |
2480 write_fmt_string (pstream, " keycode: 0x%x\n", ev->keycode); | |
428 | 2481 } |
2482 break; | |
2483 | |
2484 case Expose: | |
442 | 2485 if (debug_x_events > 1) |
428 | 2486 { |
2487 XExposeEvent *ev = &event->xexpose; | |
788 | 2488 describe_event_window (ev->window, ev->display, pstream); |
2489 write_fmt_string (pstream, | |
2490 " region: x=%d y=%d width=%d height=%d\n", | |
428 | 2491 ev->x, ev->y, ev->width, ev->height); |
788 | 2492 write_fmt_string (pstream, " count: %d\n", ev->count); |
428 | 2493 } |
2494 else | |
788 | 2495 write_fmt_string (pstream, "\n"); |
428 | 2496 break; |
2497 | |
2498 case GraphicsExpose: | |
442 | 2499 if (debug_x_events > 1) |
428 | 2500 { |
2501 XGraphicsExposeEvent *ev = &event->xgraphicsexpose; | |
788 | 2502 describe_event_window (ev->drawable, ev->display, pstream); |
2503 write_fmt_string (pstream, " major: %s\n", | |
428 | 2504 (ev ->major_code == X_CopyArea ? "CopyArea" : |
2505 (ev->major_code == X_CopyPlane ? "CopyPlane" : "?"))); | |
788 | 2506 write_fmt_string (pstream, |
2507 " region: x=%d y=%d width=%d height=%d\n", | |
428 | 2508 ev->x, ev->y, ev->width, ev->height); |
788 | 2509 write_fmt_string (pstream, " count: %d\n", ev->count); |
428 | 2510 } |
2511 else | |
788 | 2512 write_fmt_string (pstream, "\n"); |
428 | 2513 break; |
2514 | |
2515 case EnterNotify: | |
2516 case LeaveNotify: | |
442 | 2517 if (debug_x_events > 1) |
428 | 2518 { |
2519 XCrossingEvent *ev = &event->xcrossing; | |
788 | 2520 describe_event_window (ev->window, ev->display, pstream); |
428 | 2521 #if 0 |
788 | 2522 write_fmt_string (pstream, " subwindow: 0x%x\n", ev->subwindow); |
2523 write_fmt_string (pstream, " pos: %d %d\n", ev->x, ev->y); | |
2524 write_fmt_string (pstream, " root pos: %d %d\n", ev->x_root, | |
2525 ev->y_root); | |
428 | 2526 #endif |
788 | 2527 write_fmt_string (pstream, " mode: %s\n", |
2528 XEvent_mode_to_string(ev->mode)); | |
2529 write_fmt_string (pstream, " detail: %s\n", | |
2530 XEvent_detail_to_string(ev->detail)); | |
2531 write_fmt_string (pstream, " focus: %d\n", ev->focus); | |
428 | 2532 #if 0 |
788 | 2533 write_fmt_string (pstream, " state: 0x%x\n", ev->state); |
428 | 2534 #endif |
2535 } | |
2536 else | |
788 | 2537 write_fmt_string (pstream, "\n"); |
428 | 2538 break; |
2539 | |
2540 case ConfigureNotify: | |
442 | 2541 if (debug_x_events > 1) |
428 | 2542 { |
2543 XConfigureEvent *ev = &event->xconfigure; | |
788 | 2544 describe_event_window (ev->window, ev->display, pstream); |
2545 write_fmt_string (pstream, " above: 0x%lx\n", ev->above); | |
2546 write_fmt_string (pstream, " size: %d %d %d %d\n", ev->x, ev->y, | |
428 | 2547 ev->width, ev->height); |
788 | 2548 write_fmt_string (pstream, " redirect: %d\n", |
2549 ev->override_redirect); | |
428 | 2550 } |
2551 else | |
788 | 2552 write_fmt_string (pstream, "\n"); |
428 | 2553 break; |
2554 | |
2555 case VisibilityNotify: | |
442 | 2556 if (debug_x_events > 1) |
428 | 2557 { |
2558 XVisibilityEvent *ev = &event->xvisibility; | |
788 | 2559 describe_event_window (ev->window, ev->display, pstream); |
2560 write_fmt_string (pstream, " state: %s\n", | |
2561 XEvent_visibility_to_string (ev->state)); | |
428 | 2562 } |
2563 else | |
788 | 2564 write_fmt_string (pstream, "\n"); |
428 | 2565 break; |
2566 | |
2567 case ClientMessage: | |
2568 { | |
2569 XClientMessageEvent *ev = &event->xclient; | |
2570 char *name = XGetAtomName (ev->display, ev->message_type); | |
788 | 2571 write_fmt_string (pstream, "%s", name); |
2572 if (!strcmp (name, "WM_PROTOCOLS")) | |
2573 { | |
2574 char *protname = XGetAtomName (ev->display, ev->data.l[0]); | |
2575 write_fmt_string (pstream, "(%s)", protname); | |
2576 XFree (protname); | |
2577 } | |
428 | 2578 XFree (name); |
788 | 2579 write_fmt_string (pstream, "\n"); |
428 | 2580 break; |
2581 } | |
2582 | |
2583 default: | |
788 | 2584 write_fmt_string (pstream, "\n"); |
428 | 2585 break; |
2586 } | |
2587 | |
2588 fflush (stdout); | |
2589 } | |
2590 | |
2591 #endif /* include describe_event definition */ | |
2592 | |
2593 | |
2594 /************************************************************************/ | |
2595 /* get the next event from Xt */ | |
2596 /************************************************************************/ | |
2597 | |
2598 /* This business exists because menu events "happen" when | |
2599 menubar_selection_callback() is called from somewhere deep | |
2600 within XtAppProcessEvent in emacs_Xt_next_event(). The | |
2601 callback needs to terminate the modal loop in that function | |
2602 or else it will continue waiting until another event is | |
2603 received. | |
2604 | |
2605 Same business applies to scrollbar events. */ | |
2606 | |
2607 void | |
2608 signal_special_Xt_user_event (Lisp_Object channel, Lisp_Object function, | |
2609 Lisp_Object object) | |
2610 { | |
2611 Lisp_Object event = Fmake_event (Qnil, Qnil); | |
2612 | |
934 | 2613 XSET_EVENT_TYPE (event, misc_user_event); |
2614 XSET_EVENT_CHANNEL (event, channel); | |
1204 | 2615 XSET_EVENT_MISC_USER_FUNCTION (event, function); |
2616 XSET_EVENT_MISC_USER_OBJECT (event, object); | |
2617 enqueue_dispatch_event (event); | |
428 | 2618 } |
2619 | |
2620 static void | |
440 | 2621 emacs_Xt_next_event (Lisp_Event *emacs_event) |
428 | 2622 { |
2623 we_didnt_get_an_event: | |
2624 | |
2625 while (NILP (dispatch_event_queue) && | |
2626 !completed_timeouts && | |
2627 !fake_event_occurred && | |
2628 !process_events_occurred && | |
2629 !tty_events_occurred) | |
2630 { | |
1268 | 2631 if (in_modal_loop) |
2632 { | |
2633 /* in_modal_loop gets set when we are in the process of | |
2634 dispatching an event (more specifically, when we are inside of | |
2635 a menu callback -- if we get here, it means we called a filter | |
2636 and the filter did something that tried to fetch an event, | |
2637 e.g. sit-for). In such a case, we cannot safely dispatch any | |
2638 more events. This is because those dispatching those events | |
2639 could cause lwlib to be entered reentranty, specifically if | |
2640 they are menu events. lwlib is not designed for this and will | |
2641 crash. We used to see this crash constantly as a result of | |
2642 QUIT checking, but QUIT will not now function in a modal loop. | |
2643 However, we can't just not process any events at all, because | |
2644 that will make sit-for etc. hang. So we go ahead and process | |
2645 the non-X kinds of events. */ | |
1292 | 2646 #ifdef WIN32_ANY |
2647 mswindows_is_blocking = 1; | |
2648 #endif | |
2649 XtAppProcessEvent (Xt_app_con, XtIMTimer | XtIMAlternateInput); | |
2650 #ifdef WIN32_ANY | |
2651 mswindows_is_blocking = 0; | |
2652 #endif | |
1268 | 2653 } |
428 | 2654 else |
2655 { | |
1268 | 2656 /* Stupid logic in XtAppProcessEvent() dictates that, if process |
2657 events and X events are both available, the process event gets | |
2658 taken first. This will cause an infinite loop if we're being | |
2659 called from Fdiscard_input(). | |
2660 */ | |
2661 | |
2662 if (XtAppPending (Xt_app_con) & XtIMXEvent) | |
2663 XtAppProcessEvent (Xt_app_con, XtIMXEvent); | |
2664 else | |
428 | 2665 { |
1268 | 2666 Lisp_Object devcons, concons; |
2667 | |
2668 /* We're about to block. Xt has a bug in it (big surprise, | |
2669 there) in that it blocks using select() and doesn't | |
2670 flush the Xlib output buffers (XNextEvent() does this | |
2671 automatically before blocking). So it's necessary | |
2672 for us to do this ourselves. If we don't do it, then | |
2673 display output may not be seen until the next time | |
2674 an X event is received. (This happens esp. with | |
2675 subprocess output that gets sent to a visible buffer.) | |
2676 | |
2677 #### The above comment may not have any validity. */ | |
2678 | |
2679 DEVICE_LOOP_NO_BREAK (devcons, concons) | |
2680 { | |
2681 struct device *d; | |
2682 d = XDEVICE (XCAR (devcons)); | |
2683 | |
2684 if (DEVICE_X_P (d) && DEVICE_X_DISPLAY (d)) | |
2685 /* emacs may be exiting */ | |
2686 XFlush (DEVICE_X_DISPLAY (d)); | |
2687 } | |
1292 | 2688 #ifdef WIN32_ANY |
2689 mswindows_is_blocking = 1; | |
2690 #endif | |
1268 | 2691 XtAppProcessEvent (Xt_app_con, XtIMAll); |
1292 | 2692 #ifdef WIN32_ANY |
2693 mswindows_is_blocking = 0; | |
2694 #endif | |
428 | 2695 } |
2696 } | |
2697 } | |
2698 | |
2699 if (!NILP (dispatch_event_queue)) | |
2700 { | |
2701 Lisp_Object event, event2; | |
793 | 2702 event2 = wrap_event (emacs_event); |
1204 | 2703 event = dequeue_dispatch_event (); |
428 | 2704 Fcopy_event (event, event2); |
2705 Fdeallocate_event (event); | |
2706 } | |
2707 else if (tty_events_occurred) | |
2708 { | |
2709 if (!Xt_tty_to_emacs_event (emacs_event)) | |
2710 goto we_didnt_get_an_event; | |
2711 } | |
2712 else if (completed_timeouts) | |
2713 Xt_timeout_to_emacs_event (emacs_event); | |
2714 else if (fake_event_occurred) | |
2715 { | |
2716 /* A dummy event, so that a cycle of the command loop will occur. */ | |
2717 fake_event_occurred = 0; | |
2718 /* eval events have nil as channel */ | |
934 | 2719 set_event_type (emacs_event, eval_event); |
1204 | 2720 SET_EVENT_EVAL_FUNCTION (emacs_event, Qidentity); |
2721 SET_EVENT_EVAL_OBJECT (emacs_event, Qnil); | |
428 | 2722 } |
2723 else /* if (process_events_occurred) */ | |
2724 Xt_process_to_emacs_event (emacs_event); | |
2725 | |
2726 /* No need to call XFilterEvent; Xt does it for us */ | |
2727 } | |
2728 | |
2729 void | |
2286 | 2730 emacs_Xt_event_handler (Widget UNUSED (wid), |
2731 XtPointer UNUSED (closure), | |
428 | 2732 XEvent *event, |
2286 | 2733 Boolean *UNUSED (continue_to_dispatch)) |
428 | 2734 { |
2735 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil); | |
2736 | |
2737 #ifdef DEBUG_XEMACS | |
442 | 2738 if (debug_x_events > 0) |
788 | 2739 describe_event (event, Qexternal_debugging_output); |
428 | 2740 #endif /* DEBUG_XEMACS */ |
2741 if (x_event_to_emacs_event (event, XEVENT (emacs_event))) | |
1204 | 2742 enqueue_dispatch_event (emacs_event); |
428 | 2743 else |
2744 Fdeallocate_event (emacs_event); | |
2745 } | |
2746 | |
2747 | |
2748 /************************************************************************/ | |
1204 | 2749 /* input pending */ |
428 | 2750 /************************************************************************/ |
2751 | |
2752 static void | |
1204 | 2753 emacs_Xt_drain_queue (void) |
428 | 2754 { |
2755 Lisp_Object devcons, concons; | |
1268 | 2756 if (!in_modal_loop) |
428 | 2757 { |
1268 | 2758 CONSOLE_LOOP (concons) |
428 | 2759 { |
1268 | 2760 struct console *con = XCONSOLE (XCAR (concons)); |
2761 if (!con->input_enabled) | |
2762 continue; | |
2763 | |
2764 CONSOLE_DEVICE_LOOP (devcons, con) | |
1204 | 2765 { |
1268 | 2766 struct device *d; |
2767 Display *display; | |
2768 d = XDEVICE (XCAR (devcons)); | |
2769 if (DEVICE_X_P (d) && DEVICE_X_DISPLAY (d)) | |
2770 { | |
2771 display = DEVICE_X_DISPLAY (d); | |
2772 while (XEventsQueued (display, QueuedAfterReading)) | |
2773 XtAppProcessEvent (Xt_app_con, XtIMXEvent); | |
2774 } | |
1204 | 2775 } |
428 | 2776 } |
1268 | 2777 /* |
2778 while (XtAppPending (Xt_app_con) & XtIMXEvent) | |
2779 XtAppProcessEvent (Xt_app_con, XtIMXEvent); | |
2780 */ | |
428 | 2781 } |
1268 | 2782 |
2783 #ifdef HAVE_TTY | |
1204 | 2784 drain_tty_devices (); |
428 | 2785 #endif |
2786 } | |
2787 | |
1204 | 2788 int |
2789 check_if_pending_expose_event (struct device *dev) | |
2790 { | |
2791 Display *d = DEVICE_X_DISPLAY (dev); | |
2792 Lisp_Object event; | |
2793 | |
2794 emacs_Xt_drain_queue (); | |
2795 | |
2796 EVENT_CHAIN_LOOP (event, dispatch_event_queue) | |
2797 if (XEVENT_TYPE (event) == magic_event) | |
2798 { | |
2799 XEvent *xev = &XEVENT_MAGIC_X_EVENT (event); | |
2800 if (xev->type == Expose && | |
2801 xev->xexpose.display == d) | |
2802 return 1; | |
2803 } | |
2804 | |
2805 return 0; | |
2806 } | |
2807 | |
442 | 2808 static int |
2809 emacs_Xt_current_event_timestamp (struct console *c) | |
2810 { | |
2811 /* semi-yuck. */ | |
2812 Lisp_Object devs = CONSOLE_DEVICE_LIST (c); | |
2813 | |
2814 if (NILP (devs)) | |
2815 return 0; | |
2816 else | |
2817 { | |
2818 struct device *d = XDEVICE (XCAR (devs)); | |
2819 return DEVICE_X_LAST_SERVER_TIMESTAMP (d); | |
2820 } | |
2821 } | |
2822 | |
428 | 2823 |
2824 /************************************************************************/ | |
2825 /* replacement for standard string-to-pixel converter */ | |
2826 /************************************************************************/ | |
2827 | |
2828 /* This was constructed by ripping off the standard string-to-pixel | |
2829 converter from Converters.c in the Xt source code and modifying | |
2830 appropriately. */ | |
2831 | |
2832 #if 0 | |
2833 | |
2834 /* This is exported by the Xt library (at least by mine). If this | |
2835 isn't the case somewhere, rename this appropriately and remove | |
2836 the '#if 0'. Note, however, that I got "unknown structure" | |
2837 errors when I tried this. */ | |
2838 XtConvertArgRec Const colorConvertArgs[] = { | |
440 | 2839 { XtWidgetBaseOffset, (XtPointer)XtOffsetOf(WidgetRec, core.screen), |
2840 sizeof (Screen *) }, | |
2841 { XtWidgetBaseOffset, (XtPointer)XtOffsetOf(WidgetRec, core.colormap), | |
2842 sizeof (Colormap) } | |
428 | 2843 }; |
2844 | |
2845 #endif | |
2846 | |
2847 #define done(type, value) \ | |
2848 if (toVal->addr != NULL) { \ | |
2849 if (toVal->size < sizeof(type)) { \ | |
2850 toVal->size = sizeof(type); \ | |
2851 return False; \ | |
2852 } \ | |
2853 *(type*)(toVal->addr) = (value); \ | |
2854 } else { \ | |
2855 static type static_val; \ | |
2856 static_val = (value); \ | |
2857 toVal->addr = (XPointer)&static_val; \ | |
2858 } \ | |
2859 toVal->size = sizeof(type); \ | |
2860 return True /* Caller supplies `;' */ | |
2861 | |
2862 /* JH: We use this because I think there's a possibility this | |
2863 is called before the device is properly set up, in which case | |
2864 I don't want to abort. */ | |
2865 extern struct device *get_device_from_display_1 (Display *dpy); | |
2866 | |
2867 static | |
2868 Boolean EmacsXtCvtStringToPixel ( | |
2869 Display *dpy, | |
2870 XrmValuePtr args, | |
2871 Cardinal *num_args, | |
2872 XrmValuePtr fromVal, | |
2873 XrmValuePtr toVal, | |
2874 XtPointer *closure_ret) | |
2875 { | |
2876 String str = (String)fromVal->addr; | |
2877 XColor screenColor; | |
2878 XColor exactColor; | |
2879 Screen *screen; | |
2880 Colormap colormap; | |
2881 Visual *visual; | |
2882 struct device *d; | |
2883 Status status; | |
2884 String params[1]; | |
2885 Cardinal num_params = 1; | |
2886 XtAppContext the_app_con = XtDisplayToApplicationContext (dpy); | |
2887 | |
2888 if (*num_args != 2) { | |
2889 XtAppWarningMsg(the_app_con, "wrongParameters", "cvtStringToPixel", | |
2890 "XtToolkitError", | |
2891 "String to pixel conversion needs screen and colormap arguments", | |
2892 (String *)NULL, (Cardinal *)NULL); | |
2893 return False; | |
2894 } | |
2895 | |
2896 screen = *((Screen **) args[0].addr); | |
2897 colormap = *((Colormap *) args[1].addr); | |
2898 | |
2899 /* The original uses the private function CompareISOLatin1(). | |
2900 Use XmuCompareISOLatin1() if you want, but I don't think it | |
2901 makes any difference here. */ | |
2902 if (strcmp(str, XtDefaultBackground) == 0) { | |
2903 *closure_ret = False; | |
2904 /* This refers to the display's "*reverseVideo" resource. | |
2905 These display resources aren't documented anywhere that | |
2906 I can find, so I'm going to ignore this. */ | |
2907 /* if (pd->rv) done(Pixel, BlackPixelOfScreen(screen)) else */ | |
2908 done(Pixel, WhitePixelOfScreen(screen)); | |
2909 } | |
2910 if (strcmp(str, XtDefaultForeground) == 0) { | |
2911 *closure_ret = False; | |
2912 /* if (pd->rv) done(Pixel, WhitePixelOfScreen(screen)) else */ | |
2913 done(Pixel, BlackPixelOfScreen(screen)); | |
2914 } | |
2915 | |
2916 /* Originally called XAllocNamedColor() here. */ | |
2917 if ((d = get_device_from_display_1(dpy))) { | |
2918 visual = DEVICE_X_VISUAL(d); | |
2919 if (colormap != DEVICE_X_COLORMAP(d)) { | |
442 | 2920 XtAppWarningMsg(the_app_con, "weirdColormap", "cvtStringToPixel", |
428 | 2921 "XtToolkitWarning", |
442 | 2922 "The colormap passed to cvtStringToPixel doesn't match the one registered to the device.\n", |
428 | 2923 NULL, 0); |
2924 status = XAllocNamedColor(dpy, colormap, (char*)str, &screenColor, &exactColor); | |
2925 } else { | |
2926 status = XParseColor (dpy, colormap, (char*)str, &screenColor); | |
2927 if (status) { | |
3094 | 2928 status = x_allocate_nearest_color (dpy, colormap, visual, &screenColor); |
428 | 2929 } |
2930 } | |
2931 } else { | |
2932 /* We haven't set up this device totally yet, so just punt */ | |
2933 status = XAllocNamedColor(dpy, colormap, (char*)str, &screenColor, &exactColor); | |
2934 } | |
2935 if (status == 0) { | |
2936 params[0] = str; | |
2937 /* Server returns a specific error code but Xlib discards it. Ugh */ | |
2938 if (XLookupColor(DisplayOfScreen(screen), colormap, (char*) str, | |
2939 &exactColor, &screenColor)) { | |
2940 XtAppWarningMsg(the_app_con, "noColormap", "cvtStringToPixel", | |
2941 "XtToolkitError", | |
2942 "Cannot allocate colormap entry for \"%s\"", | |
2943 params, &num_params); | |
2944 | |
2945 } else { | |
2946 XtAppWarningMsg(the_app_con, "badValue", "cvtStringToPixel", | |
2947 "XtToolkitError", | |
2948 "Color name \"%s\" is not defined", params, &num_params); | |
2949 } | |
2950 | |
2951 *closure_ret = False; | |
2952 return False; | |
2953 } else { | |
2954 *closure_ret = (char*)True; | |
2955 done(Pixel, screenColor.pixel); | |
2956 } | |
2957 } | |
2958 | |
2959 /* ARGSUSED */ | |
2960 static void EmacsFreePixel ( | |
2961 XtAppContext app, | |
2962 XrmValuePtr toVal, | |
2963 XtPointer closure, | |
2964 XrmValuePtr args, | |
2965 Cardinal *num_args) | |
2966 { | |
2967 if (*num_args != 2) { | |
2968 XtAppWarningMsg(app, "wrongParameters","freePixel","XtToolkitError", | |
2969 "Freeing a pixel requires screen and colormap arguments", | |
2970 (String *)NULL, (Cardinal *)NULL); | |
2971 return; | |
2972 } | |
2973 | |
2974 if (closure) { | |
2975 Screen *screen = *((Screen **) args[0].addr); | |
2976 Colormap colormap = *((Colormap *) args[1].addr); | |
2977 XFreeColors(DisplayOfScreen(screen), colormap, | |
2978 (unsigned long*)toVal->addr, 1, (unsigned long)0); | |
2979 } | |
2980 } | |
2981 | |
2982 | |
2983 /************************************************************************/ | |
442 | 2984 /* handle focus changes for native widgets */ |
2985 /************************************************************************/ | |
2986 static void | |
2987 emacs_Xt_event_widget_focus_in (Widget w, | |
2988 XEvent *event, | |
2286 | 2989 String *UNUSED (params), |
2990 Cardinal *UNUSED (num_params)) | |
442 | 2991 { |
853 | 2992 struct frame *f = |
442 | 2993 x_any_widget_or_parent_to_frame (get_device_from_display (event->xany.display), w); |
2994 | |
2995 XtSetKeyboardFocus (FRAME_X_SHELL_WIDGET (f), w); | |
2996 } | |
2997 | |
2998 static void | |
2286 | 2999 emacs_Xt_event_widget_focus_out (Widget UNUSED (w), |
3000 XEvent *UNUSED (event), | |
3001 String *UNUSED (params), | |
3002 Cardinal *UNUSED (num_params)) | |
442 | 3003 { |
3004 } | |
3005 | |
3006 static XtActionsRec widgetActionsList[] = | |
3007 { | |
4528
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
3008 { (String) "widget-focus-in", emacs_Xt_event_widget_focus_in }, |
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
3009 { (String) "widget-focus-out", emacs_Xt_event_widget_focus_out }, |
442 | 3010 }; |
3011 | |
3012 static void | |
3013 emacs_Xt_event_add_widget_actions (XtAppContext ctx) | |
3014 { | |
3015 XtAppAddActions (ctx, widgetActionsList, 2); | |
3016 } | |
3017 | |
3018 | |
3019 /************************************************************************/ | |
428 | 3020 /* initialization */ |
3021 /************************************************************************/ | |
3022 | |
3023 void | |
3024 syms_of_event_Xt (void) | |
3025 { | |
3026 } | |
3027 | |
3028 void | |
3029 reinit_vars_of_event_Xt (void) | |
3030 { | |
1204 | 3031 Xt_event_stream = xnew_and_zero (struct event_stream); |
428 | 3032 Xt_event_stream->event_pending_p = emacs_Xt_event_pending_p; |
1204 | 3033 Xt_event_stream->force_event_pending_cb= emacs_Xt_force_event_pending; |
428 | 3034 Xt_event_stream->next_event_cb = emacs_Xt_next_event; |
3035 Xt_event_stream->handle_magic_event_cb = emacs_Xt_handle_magic_event; | |
788 | 3036 Xt_event_stream->format_magic_event_cb = emacs_Xt_format_magic_event; |
3037 Xt_event_stream->compare_magic_event_cb= emacs_Xt_compare_magic_event; | |
3038 Xt_event_stream->hash_magic_event_cb = emacs_Xt_hash_magic_event; | |
428 | 3039 Xt_event_stream->add_timeout_cb = emacs_Xt_add_timeout; |
3040 Xt_event_stream->remove_timeout_cb = emacs_Xt_remove_timeout; | |
3041 Xt_event_stream->select_console_cb = emacs_Xt_select_console; | |
3042 Xt_event_stream->unselect_console_cb = emacs_Xt_unselect_console; | |
3043 Xt_event_stream->select_process_cb = emacs_Xt_select_process; | |
3044 Xt_event_stream->unselect_process_cb = emacs_Xt_unselect_process; | |
1204 | 3045 Xt_event_stream->drain_queue_cb = emacs_Xt_drain_queue; |
853 | 3046 Xt_event_stream->create_io_streams_cb = emacs_Xt_create_io_streams; |
3047 Xt_event_stream->delete_io_streams_cb = emacs_Xt_delete_io_streams; | |
442 | 3048 Xt_event_stream->current_event_timestamp_cb = |
3049 emacs_Xt_current_event_timestamp; | |
428 | 3050 |
3051 the_Xt_timeout_blocktype = Blocktype_new (struct Xt_timeout_blocktype); | |
3052 | |
3053 last_quit_check_signal_tick_count = 0; | |
3054 | |
3055 /* this function only makes safe calls */ | |
3056 init_what_input_once (); | |
3057 } | |
3058 | |
3059 void | |
3060 vars_of_event_Xt (void) | |
3061 { | |
3062 DEFVAR_BOOL ("x-allow-sendevents", &x_allow_sendevents /* | |
3063 *Non-nil means to allow synthetic events. Nil means they are ignored. | |
3064 Beware: allowing emacs to process SendEvents opens a big security hole. | |
3065 */ ); | |
3066 x_allow_sendevents = 0; | |
3067 | |
3068 #ifdef DEBUG_XEMACS | |
442 | 3069 DEFVAR_INT ("debug-x-events", &debug_x_events /* |
428 | 3070 If non-zero, display debug information about X events that XEmacs sees. |
3071 Information is displayed on stderr. Currently defined values are: | |
3072 | |
3073 1 == non-verbose output | |
3074 2 == verbose output | |
3075 */ ); | |
442 | 3076 debug_x_events = 0; |
428 | 3077 #endif |
3171 | 3078 DEFVAR_LISP ("x-us-keymap-description", &Vx_us_keymap_description /* |
3079 X11-specific vector describing the current keyboard hardware, and how to map | |
3080 from its keycodes to those alphanumeric and punctuation characters that | |
3081 would be produced by it if a US layout were configured in software. | |
3082 | |
3083 We use this to make possible the usage of standard key bindings on keyboards | |
3084 where the keys that those bindings assume are not available; for example, on | |
3085 a Russian keyboard, one can type C-Cyrillic_che C-Cyrillic_a and have XEmacs | |
3086 use the binding for C-x C-f, rather than give an error message that | |
3087 C-Cyrillic_che C-Cyrillic_a is not bound. | |
3088 | |
3089 Entries are either nil, which means the corresponding key code does not map | |
3090 to a non-function key in the US layout, a single character, meaning it maps to | |
3091 that character, or a vector of two characters, the first indicating the | |
3092 unshifted mapping, the second the shifted mapping for the US layout. | |
3093 | |
3094 `x-us-keymap-first-keycode' tells XEmacs the keycode of the first entry in | |
3095 this vector. | |
3096 */ ); | |
3097 Vx_us_keymap_description = Qnil; | |
3098 | |
3099 DEFVAR_INT ("x-us-keymap-first-keycode", &Vx_us_keymap_first_keycode /* | |
3100 The X11 keycode that the first entry in `x-us-keymap-description' | |
3101 corresponds to. See the documentation for that variable. | |
3102 | |
3103 The X11 documentation for XDisplayKeycodes says this can never be less than | |
3104 8, but XEmacs doesn't enforce any limitation on what you set it to. | |
3105 */ ); | |
3106 Vx_us_keymap_first_keycode = 0; | |
428 | 3107 } |
3108 | |
3109 /* This mess is a hack that patches the shell widget to treat visual inheritance | |
3110 the same as colormap and depth inheritance */ | |
3111 | |
3112 static XtInitProc orig_shell_init_proc; | |
3113 | |
2956 | 3114 static void ShellVisualPatch(Widget wanted, Widget new_, |
428 | 3115 ArgList args, Cardinal *num_args) |
3116 { | |
3117 Widget p; | |
2956 | 3118 ShellWidget w = (ShellWidget) new_; |
428 | 3119 |
3120 /* first, call the original setup */ | |
2956 | 3121 (*orig_shell_init_proc)(wanted, new_, args, num_args); |
428 | 3122 |
3123 /* if the visual isn't explicitly set, grab it from the nearest shell ancestor */ | |
3124 if (w->shell.visual == CopyFromParent) { | |
3125 p = XtParent(w); | |
3126 while (p && !XtIsShell(p)) p = XtParent(p); | |
3127 if (p) w->shell.visual = ((ShellWidget)p)->shell.visual; | |
3128 } | |
3129 } | |
3130 | |
3131 void | |
3132 init_event_Xt_late (void) /* called when already initialized */ | |
3133 { | |
3134 timeout_id_tick = 1; | |
3135 pending_timeouts = 0; | |
3136 completed_timeouts = 0; | |
3137 | |
3138 event_stream = Xt_event_stream; | |
3139 | |
3140 XtToolkitInitialize (); | |
3141 Xt_app_con = XtCreateApplicationContext (); | |
3142 XtAppSetFallbackResources (Xt_app_con, (String *) x_fallback_resources); | |
3143 | |
442 | 3144 /* In select-x.c */ |
428 | 3145 x_selection_timeout = (XtAppGetSelectionTimeout (Xt_app_con) / 1000); |
3146 XSetErrorHandler (x_error_handler); | |
3147 XSetIOErrorHandler (x_IO_error_handler); | |
3148 | |
442 | 3149 #ifndef WIN32_NATIVE |
428 | 3150 XtAppAddInput (Xt_app_con, signal_event_pipe[0], |
3151 (XtPointer) (XtInputReadMask /* | XtInputExceptMask */), | |
3152 Xt_what_callback, 0); | |
3153 #endif | |
3154 | |
3155 XtAppSetTypeConverter (Xt_app_con, XtRString, XtRPixel, | |
3156 EmacsXtCvtStringToPixel, | |
3157 (XtConvertArgList) colorConvertArgs, | |
3158 2, XtCacheByDisplay, EmacsFreePixel); | |
3159 | |
3160 #ifdef XIM_XLIB | |
3161 XtAppSetTypeConverter (Xt_app_con, XtRString, XtRXimStyles, | |
3162 EmacsXtCvtStringToXIMStyles, | |
3163 NULL, 0, | |
3164 XtCacheByDisplay, EmacsFreeXIMStyles); | |
3165 #endif /* XIM_XLIB */ | |
442 | 3166 /* Add extra actions to native widgets to handle focus and friends. */ |
3167 emacs_Xt_event_add_widget_actions (Xt_app_con); | |
428 | 3168 |
3169 /* insert the visual inheritance patch/hack described above */ | |
3170 orig_shell_init_proc = shellClassRec.core_class.initialize; | |
3171 shellClassRec.core_class.initialize = ShellVisualPatch; | |
3172 | |
3173 } |