Mercurial > hg > xemacs-beta
comparison src/event-Xt.c @ 412:697ef44129c6 r21-2-14
Import from CVS: tag r21-2-14
author | cvs |
---|---|
date | Mon, 13 Aug 2007 11:20:41 +0200 |
parents | de805c49cfc1 |
children | 41dbb7a9d5f2 |
comparison
equal
deleted
inserted
replaced
411:12e008d41344 | 412:697ef44129c6 |
---|---|
63 | 63 |
64 #if defined (HAVE_OFFIX_DND) | 64 #if defined (HAVE_OFFIX_DND) |
65 #include "offix.h" | 65 #include "offix.h" |
66 #endif | 66 #endif |
67 | 67 |
68 #ifdef WINDOWSNT | |
69 /* Hmm, under unix we want X modifiers, under NT we want X modifiers if | |
70 we are running X and Windows modifiers otherwise. | |
71 gak. This is a kludge until we support multiple native GUIs! | |
72 */ | |
73 #undef MOD_ALT | |
74 #undef MOD_CONTROL | |
75 #undef MOD_SHIFT | |
76 #endif | |
77 | |
68 #include "events-mod.h" | 78 #include "events-mod.h" |
69 | 79 |
70 static void handle_focus_event_1 (struct frame *f, int in_p); | 80 static void enqueue_Xt_dispatch_event (Lisp_Object event); |
71 | 81 |
72 static struct event_stream *Xt_event_stream; | 82 static struct event_stream *Xt_event_stream; |
73 | 83 |
74 /* With the new event model, all events go through XtDispatchEvent() | 84 /* With the new event model, all events go through XtDispatchEvent() |
75 and are picked up by an event handler that is added to each frame | 85 and are picked up by an event handler that is added to each frame |
84 XtAppContext Xt_app_con; | 94 XtAppContext Xt_app_con; |
85 | 95 |
86 /* Do we accept events sent by other clients? */ | 96 /* Do we accept events sent by other clients? */ |
87 int x_allow_sendevents; | 97 int x_allow_sendevents; |
88 | 98 |
99 int modifier_keys_are_sticky; | |
100 | |
89 #ifdef DEBUG_XEMACS | 101 #ifdef DEBUG_XEMACS |
90 int x_debug_events; | 102 int x_debug_events; |
91 #endif | 103 #endif |
92 | 104 |
93 static int process_events_occurred; | 105 static int process_events_occurred; |
94 static int tty_events_occurred; | 106 static int tty_events_occurred; |
95 | 107 |
96 /* Mask of bits indicating the descriptors that we wait for input on */ | 108 /* Mask of bits indicating the descriptors that we wait for input on */ |
97 extern SELECT_TYPE input_wait_mask, process_only_mask, tty_only_mask; | 109 extern SELECT_TYPE input_wait_mask, process_only_mask, tty_only_mask; |
98 | 110 |
99 static const String x_fallback_resources[] = | 111 static CONST String x_fallback_resources[] = |
100 { | 112 { |
101 /* This file is automatically generated from the app-defaults file | 113 /* This file is automatically generated from the app-defaults file |
102 in ../etc/Emacs.ad. These resources are consulted only if no | 114 in ../etc/Emacs.ad. These resources are consulted only if no |
103 app-defaults file is found at all. | 115 app-defaults file is found at all. |
104 */ | 116 */ |
106 0 | 118 0 |
107 }; | 119 }; |
108 | 120 |
109 static Lisp_Object x_keysym_to_emacs_keysym (KeySym keysym, int simple_p); | 121 static Lisp_Object x_keysym_to_emacs_keysym (KeySym keysym, int simple_p); |
110 void emacs_Xt_mapping_action (Widget w, XEvent *event); | 122 void emacs_Xt_mapping_action (Widget w, XEvent *event); |
111 void debug_process_finalization (Lisp_Process *p); | 123 void debug_process_finalization (struct Lisp_Process *p); |
112 void emacs_Xt_event_handler (Widget wid, XtPointer closure, XEvent *event, | 124 void emacs_Xt_event_handler (Widget wid, XtPointer closure, XEvent *event, |
113 Boolean *continue_to_dispatch); | 125 Boolean *continue_to_dispatch); |
114 | 126 |
115 static int last_quit_check_signal_tick_count; | 127 static int last_quit_check_signal_tick_count; |
116 | 128 |
159 | 171 |
160 Emacs detects keyboard configurations which violate the above rules, and | 172 Emacs detects keyboard configurations which violate the above rules, and |
161 prints an error message on the standard-error-output. (Perhaps it should | 173 prints an error message on the standard-error-output. (Perhaps it should |
162 use a pop-up-window instead.) | 174 use a pop-up-window instead.) |
163 */ | 175 */ |
164 | |
165 /* For every key on the keyboard that has a known character correspondence, | |
166 we define the ascii-character property of the keysym, and make the | |
167 default binding for the key be self-insert-command. | |
168 | |
169 The following magic is basically intimate knowledge of X11/keysymdef.h. | |
170 The keysym mappings defined by X11 are based on the iso8859 standards, | |
171 except for Cyrillic and Greek. | |
172 | |
173 In a non-Mule world, a user can still have a multi-lingual editor, by doing | |
174 (set-face-font "...-iso8859-2" (current-buffer)) | |
175 for all their Latin-2 buffers, etc. */ | |
176 | |
177 static Lisp_Object | |
178 x_keysym_to_character (KeySym keysym) | |
179 { | |
180 #ifdef MULE | |
181 Lisp_Object charset = Qzero; | |
182 #define USE_CHARSET(var,cs) \ | |
183 ((var) = CHARSET_BY_LEADING_BYTE (LEADING_BYTE_##cs)) | |
184 #else | |
185 #define USE_CHARSET(var,lb) | |
186 #endif /* MULE */ | |
187 int code = 0; | |
188 | |
189 if ((keysym & 0xff) < 0xa0) | |
190 return Qnil; | |
191 | |
192 switch (keysym >> 8) | |
193 { | |
194 case 0: /* ASCII + Latin1 */ | |
195 USE_CHARSET (charset, LATIN_ISO8859_1); | |
196 code = keysym & 0x7f; | |
197 break; | |
198 case 1: /* Latin2 */ | |
199 USE_CHARSET (charset, LATIN_ISO8859_2); | |
200 code = keysym & 0x7f; | |
201 break; | |
202 case 2: /* Latin3 */ | |
203 USE_CHARSET (charset, LATIN_ISO8859_3); | |
204 code = keysym & 0x7f; | |
205 break; | |
206 case 3: /* Latin4 */ | |
207 USE_CHARSET (charset, LATIN_ISO8859_4); | |
208 code = keysym & 0x7f; | |
209 break; | |
210 case 4: /* Katakana */ | |
211 USE_CHARSET (charset, KATAKANA_JISX0201); | |
212 if ((keysym & 0xff) > 0xa0) | |
213 code = keysym & 0x7f; | |
214 break; | |
215 case 5: /* Arabic */ | |
216 USE_CHARSET (charset, ARABIC_ISO8859_6); | |
217 code = keysym & 0x7f; | |
218 break; | |
219 case 6: /* Cyrillic */ | |
220 { | |
221 static unsigned char const cyrillic[] = /* 0x20 - 0x7f */ | |
222 {0x00, 0x72, 0x73, 0x71, 0x74, 0x75, 0x76, 0x77, | |
223 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x00, 0x7e, 0x7f, | |
224 0x70, 0x22, 0x23, 0x21, 0x24, 0x25, 0x26, 0x27, | |
225 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x00, 0x2e, 0x2f, | |
226 0x6e, 0x50, 0x51, 0x66, 0x54, 0x55, 0x64, 0x53, | |
227 0x65, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, | |
228 0x5f, 0x6f, 0x60, 0x61, 0x62, 0x63, 0x56, 0x52, | |
229 0x6c, 0x6b, 0x57, 0x68, 0x6d, 0x69, 0x67, 0x6a, | |
230 0x4e, 0x30, 0x31, 0x46, 0x34, 0x35, 0x44, 0x33, | |
231 0x45, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, | |
232 0x3f, 0x4f, 0x40, 0x41, 0x42, 0x43, 0x36, 0x32, | |
233 0x4c, 0x4b, 0x37, 0x48, 0x4d, 0x49, 0x47, 0x4a}; | |
234 USE_CHARSET (charset, CYRILLIC_ISO8859_5); | |
235 code = cyrillic[(keysym & 0x7f) - 0x20]; | |
236 break; | |
237 } | |
238 case 7: /* Greek */ | |
239 { | |
240 static unsigned char const greek[] = /* 0x20 - 0x7f */ | |
241 {0x00, 0x36, 0x38, 0x39, 0x3a, 0x5a, 0x00, 0x3c, | |
242 0x3e, 0x5b, 0x00, 0x3f, 0x00, 0x00, 0x35, 0x2f, | |
243 0x00, 0x5c, 0x5d, 0x5e, 0x5f, 0x7a, 0x40, 0x7c, | |
244 0x7d, 0x7b, 0x60, 0x7e, 0x00, 0x00, 0x00, 0x00, | |
245 0x00, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, | |
246 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, | |
247 0x50, 0x51, 0x53, 0x00, 0x54, 0x55, 0x56, 0x57, | |
248 0x58, 0x59, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
249 0x00, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, | |
250 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, | |
251 0x70, 0x71, 0x73, 0x72, 0x74, 0x75, 0x76, 0x77, | |
252 0x78, 0x79, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; | |
253 USE_CHARSET (charset, GREEK_ISO8859_7); | |
254 code = greek[(keysym & 0x7f) - 0x20]; | |
255 break; | |
256 } | |
257 case 8: /* Technical */ | |
258 break; | |
259 case 9: /* Special */ | |
260 break; | |
261 case 10: /* Publishing */ | |
262 break; | |
263 case 11: /* APL */ | |
264 break; | |
265 case 12: /* Hebrew */ | |
266 USE_CHARSET (charset, HEBREW_ISO8859_8); | |
267 code = keysym & 0x7f; | |
268 break; | |
269 case 13: /* Thai */ | |
270 /* #### This needs to deal with character composition. */ | |
271 USE_CHARSET (charset, THAI_TIS620); | |
272 code = keysym & 0x7f; | |
273 break; | |
274 case 14: /* Korean Hangul */ | |
275 break; | |
276 case 19: /* Latin 9 - ISO8859-15 - unsupported charset. */ | |
277 break; | |
278 case 32: /* Currency */ | |
279 break; | |
280 default: | |
281 break; | |
282 } | |
283 | |
284 if (code == 0) | |
285 return Qnil; | |
286 | |
287 #ifdef MULE | |
288 return make_char (MAKE_CHAR (charset, code, 0)); | |
289 #else | |
290 return make_char (code + 0x80); | |
291 #endif | |
292 } | |
293 | |
294 /* #### The way that keysym correspondence to characters should work: | |
295 - a Lisp_Event should contain a keysym AND a character slot. | |
296 - keybindings are tried with the keysym. If no binding can be found, | |
297 and there is a corresponding character, call self-insert-command. | |
298 | |
299 #### Nuke x-iso8859-1.el. | |
300 #### Nuke the Qascii_character property. | |
301 #### Nuke Vcharacter_set_property. | |
302 */ | |
303 static void | |
304 maybe_define_x_key_as_self_inserting_character (KeySym keysym, Lisp_Object symbol) | |
305 { | |
306 Lisp_Object character = x_keysym_to_character (keysym); | |
307 | |
308 if (CHARP (character)) | |
309 { | |
310 extern Lisp_Object Vcurrent_global_map; | |
311 extern Lisp_Object Qascii_character; | |
312 Fput (symbol, Qascii_character, character); | |
313 if (NILP (Flookup_key (Vcurrent_global_map, symbol, Qnil))) | |
314 Fdefine_key (Vcurrent_global_map, symbol, Qself_insert_command); | |
315 } | |
316 } | |
317 | |
318 static void | |
319 x_has_keysym (KeySym keysym, Lisp_Object hash_table, int with_modifiers) | |
320 { | |
321 KeySym upper_lower[2]; | |
322 int j; | |
323 | |
324 if (keysym < 0x80) /* Optimize for ASCII keysyms */ | |
325 return; | |
326 | |
327 /* If you execute: | |
328 xmodmap -e 'keysym NN = scaron' | |
329 and then press (Shift scaron), X11 will return the different | |
330 keysym `Scaron', but `xmodmap -pke' might not even mention `Scaron'. | |
331 So we "register" both `scaron' and `Scaron'. */ | |
332 #ifdef HAVE_XCONVERTCASE | |
333 XConvertCase (keysym, &upper_lower[0], &upper_lower[1]); | |
334 #else | |
335 upper_lower[0] = upper_lower[1] = keysym; | |
336 #endif | |
337 | |
338 for (j = 0; j < (upper_lower[0] == upper_lower[1] ? 1 : 2); j++) | |
339 { | |
340 char *name; | |
341 keysym = upper_lower[j]; | |
342 | |
343 name = XKeysymToString (keysym); | |
344 if (name) | |
345 { | |
346 /* X guarantees NAME to be in the Host Portable Character Encoding */ | |
347 Lisp_Object sym = x_keysym_to_emacs_keysym (keysym, 0); | |
348 Lisp_Object new_value = with_modifiers ? Qt : Qsans_modifiers; | |
349 Lisp_Object old_value = Fgethash (sym, hash_table, Qnil); | |
350 | |
351 if (! EQ (old_value, new_value) | |
352 && ! (EQ (old_value, Qsans_modifiers) && | |
353 EQ (new_value, Qt))) | |
354 { | |
355 maybe_define_x_key_as_self_inserting_character (keysym, sym); | |
356 Fputhash (build_ext_string (name, Qbinary), new_value, hash_table); | |
357 Fputhash (sym, new_value, hash_table); | |
358 } | |
359 } | |
360 } | |
361 } | |
362 | 176 |
363 static void | 177 static void |
364 x_reset_key_mapping (struct device *d) | 178 x_reset_key_mapping (struct device *d) |
365 { | 179 { |
366 Display *display = DEVICE_X_DISPLAY (d); | 180 Display *display = DEVICE_X_DISPLAY (d); |
395 int j; | 209 int j; |
396 | 210 |
397 if (keysym[0] == NoSymbol) | 211 if (keysym[0] == NoSymbol) |
398 continue; | 212 continue; |
399 | 213 |
400 x_has_keysym (keysym[0], hash_table, 0); | 214 { |
215 char *name = XKeysymToString (keysym[0]); | |
216 Lisp_Object sym = x_keysym_to_emacs_keysym (keysym[0], 0); | |
217 if (name) | |
218 { | |
219 Fputhash (build_string (name), Qsans_modifiers, hash_table); | |
220 Fputhash (sym, Qsans_modifiers, hash_table); | |
221 } | |
222 } | |
401 | 223 |
402 for (j = 1; j < keysyms_per_code; j++) | 224 for (j = 1; j < keysyms_per_code; j++) |
403 { | 225 { |
404 if (keysym[j] != keysym[0] && | 226 if (keysym[j] != keysym[0] && |
405 keysym[j] != NoSymbol) | 227 keysym[j] != NoSymbol) |
406 x_has_keysym (keysym[j], hash_table, 1); | 228 { |
229 char *name = XKeysymToString (keysym[j]); | |
230 Lisp_Object sym = x_keysym_to_emacs_keysym (keysym[j], 0); | |
231 if (name && NILP (Fgethash (sym, hash_table, Qnil))) | |
232 { | |
233 Fputhash (build_string (name), Qt, hash_table); | |
234 Fputhash (sym, Qt, hash_table); | |
235 } | |
236 } | |
407 } | 237 } |
408 } | 238 } |
409 } | 239 } |
410 | 240 |
411 static const char * | 241 static CONST char * |
412 index_to_name (int indice) | 242 index_to_name (int indice) |
413 { | 243 { |
414 switch (indice) | 244 switch (indice) |
415 { | 245 { |
416 case ShiftMapIndex: return "ModShift"; | 246 case ShiftMapIndex: return "ModShift"; |
561 interpret that bit as Meta, because we can't make XLookupString() | 391 interpret that bit as Meta, because we can't make XLookupString() |
562 not interpret it as Mode_switch; and interpreting it as both would | 392 not interpret it as Mode_switch; and interpreting it as both would |
563 be totally wrong. */ | 393 be totally wrong. */ |
564 if (mode_bit) | 394 if (mode_bit) |
565 { | 395 { |
566 const char *warn = 0; | 396 CONST char *warn = 0; |
567 if (mode_bit == meta_bit) warn = "Meta", meta_bit = 0; | 397 if (mode_bit == meta_bit) warn = "Meta", meta_bit = 0; |
568 else if (mode_bit == hyper_bit) warn = "Hyper", hyper_bit = 0; | 398 else if (mode_bit == hyper_bit) warn = "Hyper", hyper_bit = 0; |
569 else if (mode_bit == super_bit) warn = "Super", super_bit = 0; | 399 else if (mode_bit == super_bit) warn = "Super", super_bit = 0; |
570 else if (mode_bit == alt_bit) warn = "Alt", alt_bit = 0; | 400 else if (mode_bit == alt_bit) warn = "Alt", alt_bit = 0; |
571 if (warn) | 401 if (warn) |
975 Lookup_String: /* Come-From XBufferOverflow */ | 805 Lookup_String: /* Come-From XBufferOverflow */ |
976 #ifdef XIM_MOTIF | 806 #ifdef XIM_MOTIF |
977 len = XmImMbLookupString (XtWindowToWidget (event->display, event->window), | 807 len = XmImMbLookupString (XtWindowToWidget (event->display, event->window), |
978 event, bufptr, bufsiz, &keysym, &status); | 808 event, bufptr, bufsiz, &keysym, &status); |
979 #else /* XIM_XLIB */ | 809 #else /* XIM_XLIB */ |
980 if (xic) | 810 len = XmbLookupString (xic, event, bufptr, bufsiz, &keysym, &status); |
981 len = XmbLookupString (xic, event, bufptr, bufsiz, &keysym, &status); | |
982 #endif /* HAVE_XIM */ | 811 #endif /* HAVE_XIM */ |
983 | 812 |
984 #ifdef DEBUG_XEMACS | 813 #ifdef DEBUG_XEMACS |
985 if (x_debug_events > 0) | 814 if (x_debug_events > 0) |
986 { | 815 { |
1027 Emchar ch; | 856 Emchar ch; |
1028 Lisp_Object instream, fb_instream; | 857 Lisp_Object instream, fb_instream; |
1029 Lstream *istr; | 858 Lstream *istr; |
1030 struct gcpro gcpro1, gcpro2; | 859 struct gcpro gcpro1, gcpro2; |
1031 | 860 |
1032 fb_instream = make_fixed_buffer_input_stream (bufptr, len); | 861 fb_instream = |
1033 | 862 make_fixed_buffer_input_stream ((unsigned char *) bufptr, len); |
1034 /* #### Use Fget_coding_system (Vcomposed_input_coding_system) */ | 863 |
864 /* ### Use Fget_coding_system (Vcomposed_input_coding_system) */ | |
1035 instream = | 865 instream = |
1036 make_decoding_input_stream (XLSTREAM (fb_instream), | 866 make_decoding_input_stream (XLSTREAM (fb_instream), |
1037 Fget_coding_system (Qundecided)); | 867 Fget_coding_system (Qundecided)); |
1038 | 868 |
1039 istr = XLSTREAM (instream); | 869 istr = XLSTREAM (instream); |
1040 | 870 |
1041 GCPRO2 (instream, fb_instream); | 871 GCPRO2 (instream, fb_instream); |
1042 while ((ch = Lstream_get_emchar (istr)) != EOF) | 872 while ((ch = Lstream_get_emchar (istr)) != EOF) |
1043 { | 873 { |
1044 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil); | 874 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil); |
1045 Lisp_Event *ev = XEVENT (emacs_event); | 875 struct Lisp_Event *ev = XEVENT (emacs_event); |
1046 ev->channel = DEVICE_CONSOLE (d); | 876 ev->channel = DEVICE_CONSOLE (d); |
1047 ev->event_type = key_press_event; | 877 ev->event_type = key_press_event; |
1048 ev->timestamp = event->time; | 878 ev->timestamp = event->time; |
1049 ev->event.key.modifiers = 0; | 879 ev->event.key.modifiers = 0; |
1050 ev->event.key.keysym = make_char (ch); | 880 ev->event.key.keysym = make_char (ch); |
1087 } | 917 } |
1088 DEVICE_X_LAST_SERVER_TIMESTAMP (d) = t; | 918 DEVICE_X_LAST_SERVER_TIMESTAMP (d) = t; |
1089 } | 919 } |
1090 | 920 |
1091 static int | 921 static int |
1092 x_event_to_emacs_event (XEvent *x_event, Lisp_Event *emacs_event) | 922 x_event_to_emacs_event (XEvent *x_event, struct Lisp_Event *emacs_event) |
1093 { | 923 { |
1094 Display *display = x_event->xany.display; | 924 Display *display = x_event->xany.display; |
1095 struct device *d = get_device_from_display (display); | 925 struct device *d = get_device_from_display (display); |
1096 struct x_device *xd = DEVICE_X_DATA (d); | 926 struct x_device *xd = DEVICE_X_DATA (d); |
1097 | 927 |
1109 | 939 |
1110 case KeyPress: | 940 case KeyPress: |
1111 case ButtonPress: | 941 case ButtonPress: |
1112 case ButtonRelease: | 942 case ButtonRelease: |
1113 { | 943 { |
1114 int modifiers = 0; | 944 unsigned int modifiers = 0; |
1115 int shift_p, lock_p; | 945 int shift_p, lock_p; |
1116 Bool key_event_p = (x_event->type == KeyPress); | 946 Bool key_event_p = (x_event->type == KeyPress); |
1117 unsigned int *state = | 947 unsigned int *state = |
1118 key_event_p ? &x_event->xkey.state : &x_event->xbutton.state; | 948 key_event_p ? &x_event->xkey.state : &x_event->xbutton.state; |
1119 | 949 |
1136 DEVICE_X_GLOBAL_MOUSE_TIMESTAMP (d) = | 966 DEVICE_X_GLOBAL_MOUSE_TIMESTAMP (d) = |
1137 key_event_p ? x_event->xkey.time : x_event->xbutton.time; | 967 key_event_p ? x_event->xkey.time : x_event->xbutton.time; |
1138 | 968 |
1139 x_handle_sticky_modifiers (x_event, d); | 969 x_handle_sticky_modifiers (x_event, d); |
1140 | 970 |
1141 if (*state & ControlMask) modifiers |= XEMACS_MOD_CONTROL; | 971 if (*state & ControlMask) modifiers |= MOD_CONTROL; |
1142 if (*state & xd->MetaMask) modifiers |= XEMACS_MOD_META; | 972 if (*state & xd->MetaMask) modifiers |= MOD_META; |
1143 if (*state & xd->SuperMask) modifiers |= XEMACS_MOD_SUPER; | 973 if (*state & xd->SuperMask) modifiers |= MOD_SUPER; |
1144 if (*state & xd->HyperMask) modifiers |= XEMACS_MOD_HYPER; | 974 if (*state & xd->HyperMask) modifiers |= MOD_HYPER; |
1145 if (*state & xd->AltMask) modifiers |= XEMACS_MOD_ALT; | 975 if (*state & xd->AltMask) modifiers |= MOD_ALT; |
1146 | 976 |
1147 /* Ignore the Caps_Lock key if: | 977 /* Ignore the Caps_Lock key if: |
1148 - any other modifiers are down, so that Caps_Lock doesn't | 978 - any other modifiers are down, so that Caps_Lock doesn't |
1149 turn C-x into C-X, which would suck. | 979 turn C-x into C-X, which would suck. |
1150 - the event was a mouse event. */ | 980 - the event was a mouse event. */ |
1153 | 983 |
1154 shift_p = *state & ShiftMask; | 984 shift_p = *state & ShiftMask; |
1155 lock_p = *state & LockMask; | 985 lock_p = *state & LockMask; |
1156 | 986 |
1157 if (shift_p || lock_p) | 987 if (shift_p || lock_p) |
1158 modifiers |= XEMACS_MOD_SHIFT; | 988 modifiers |= MOD_SHIFT; |
1159 | 989 |
1160 if (key_event_p) | 990 if (key_event_p) |
1161 { | 991 { |
1162 Lisp_Object keysym; | 992 Lisp_Object keysym; |
1163 XKeyEvent *ev = &x_event->xkey; | 993 XKeyEvent *ev = &x_event->xkey; |
1185 /* !!#### maybe fix for Mule */ | 1015 /* !!#### maybe fix for Mule */ |
1186 if (lock_p && !shift_p && | 1016 if (lock_p && !shift_p && |
1187 ! (CHAR_OR_CHAR_INTP (keysym) | 1017 ! (CHAR_OR_CHAR_INTP (keysym) |
1188 && keysym_obeys_caps_lock_p | 1018 && keysym_obeys_caps_lock_p |
1189 ((KeySym) XCHAR_OR_CHAR_INT (keysym), d))) | 1019 ((KeySym) XCHAR_OR_CHAR_INT (keysym), d))) |
1190 modifiers &= (~XEMACS_MOD_SHIFT); | 1020 modifiers &= (~MOD_SHIFT); |
1191 | 1021 |
1192 /* If this key contains two distinct keysyms, that is, | 1022 /* If this key contains two distinct keysyms, that is, |
1193 "shift" generates a different keysym than the | 1023 "shift" generates a different keysym than the |
1194 non-shifted key, then don't apply the shift modifier | 1024 non-shifted key, then don't apply the shift modifier |
1195 bit: it's implicit. Otherwise, if there would be no | 1025 bit: it's implicit. Otherwise, if there would be no |
1197 and unshifted version of this key, apply the shift bit. | 1027 and unshifted version of this key, apply the shift bit. |
1198 Non-graphics, like Backspace and F1 get the shift bit | 1028 Non-graphics, like Backspace and F1 get the shift bit |
1199 in the modifiers slot. Neither the characters "a", | 1029 in the modifiers slot. Neither the characters "a", |
1200 "A", "2", nor "@" normally have the shift bit set. | 1030 "A", "2", nor "@" normally have the shift bit set. |
1201 However, "F1" normally does. */ | 1031 However, "F1" normally does. */ |
1202 if (modifiers & XEMACS_MOD_SHIFT) | 1032 if (modifiers & MOD_SHIFT) |
1203 { | 1033 { |
1204 int Mode_switch_p = *state & xd->ModeMask; | 1034 int Mode_switch_p = *state & xd->ModeMask; |
1205 KeySym bot = XLookupKeysym (ev, Mode_switch_p ? 2 : 0); | 1035 KeySym bot = XLookupKeysym (ev, Mode_switch_p ? 2 : 0); |
1206 KeySym top = XLookupKeysym (ev, Mode_switch_p ? 3 : 1); | 1036 KeySym top = XLookupKeysym (ev, Mode_switch_p ? 3 : 1); |
1207 if (top && bot && top != bot) | 1037 if (top && bot && top != bot) |
1208 modifiers &= ~XEMACS_MOD_SHIFT; | 1038 modifiers &= ~MOD_SHIFT; |
1209 } | 1039 } |
1210 emacs_event->event_type = key_press_event; | 1040 emacs_event->event_type = key_press_event; |
1211 emacs_event->timestamp = ev->time; | 1041 emacs_event->timestamp = ev->time; |
1212 emacs_event->event.key.modifiers = modifiers; | 1042 emacs_event->event.key.modifiers = modifiers; |
1213 emacs_event->event.key.keysym = keysym; | 1043 emacs_event->event.key.keysym = keysym; |
1214 } | 1044 } |
1215 else /* Mouse press/release event */ | 1045 else /* Mouse press/release event */ |
1216 { | 1046 { |
1217 XButtonEvent *ev = &x_event->xbutton; | 1047 XButtonEvent *ev = &x_event->xbutton; |
1218 struct frame *frame = x_window_to_frame (d, ev->window); | 1048 struct frame *frame = x_window_to_frame (d, ev->window); |
1219 | |
1220 if (! frame) | 1049 if (! frame) |
1221 return 0; /* not for us */ | 1050 return 0; /* not for us */ |
1222 XSETFRAME (emacs_event->channel, frame); | 1051 XSETFRAME (emacs_event->channel, frame); |
1223 | 1052 |
1224 emacs_event->event_type = (x_event->type == ButtonPress) ? | 1053 emacs_event->event_type = (x_event->type == ButtonPress) ? |
1227 emacs_event->event.button.modifiers = modifiers; | 1056 emacs_event->event.button.modifiers = modifiers; |
1228 emacs_event->timestamp = ev->time; | 1057 emacs_event->timestamp = ev->time; |
1229 emacs_event->event.button.button = ev->button; | 1058 emacs_event->event.button.button = ev->button; |
1230 emacs_event->event.button.x = ev->x; | 1059 emacs_event->event.button.x = ev->x; |
1231 emacs_event->event.button.y = ev->y; | 1060 emacs_event->event.button.y = ev->y; |
1232 /* because we don't seem to get a FocusIn event for button clicks | 1061 |
1233 when a widget-glyph is selected we will assume that we want the | |
1234 focus if a button gets pressed. */ | |
1235 if (x_event->type == ButtonPress) | |
1236 handle_focus_event_1 (frame, 1); | |
1237 } | 1062 } |
1238 } | 1063 } |
1239 break; | 1064 break; |
1240 | 1065 |
1241 case MotionNotify: | 1066 case MotionNotify: |
1242 { | 1067 { |
1243 XMotionEvent *ev = &x_event->xmotion; | 1068 XMotionEvent *ev = &x_event->xmotion; |
1244 struct frame *frame = x_window_to_frame (d, ev->window); | 1069 struct frame *frame = x_window_to_frame (d, ev->window); |
1245 int modifiers = 0; | 1070 unsigned int modifiers = 0; |
1246 XMotionEvent event2; | 1071 XMotionEvent event2; |
1247 | 1072 |
1248 if (! frame) | 1073 if (! frame) |
1249 return 0; /* not for us */ | 1074 return 0; /* not for us */ |
1250 | 1075 |
1269 XSETFRAME (emacs_event->channel, frame); | 1094 XSETFRAME (emacs_event->channel, frame); |
1270 emacs_event->event_type = pointer_motion_event; | 1095 emacs_event->event_type = pointer_motion_event; |
1271 emacs_event->timestamp = ev->time; | 1096 emacs_event->timestamp = ev->time; |
1272 emacs_event->event.motion.x = ev->x; | 1097 emacs_event->event.motion.x = ev->x; |
1273 emacs_event->event.motion.y = ev->y; | 1098 emacs_event->event.motion.y = ev->y; |
1274 if (ev->state & ShiftMask) modifiers |= XEMACS_MOD_SHIFT; | 1099 if (ev->state & ShiftMask) modifiers |= MOD_SHIFT; |
1275 if (ev->state & ControlMask) modifiers |= XEMACS_MOD_CONTROL; | 1100 if (ev->state & ControlMask) modifiers |= MOD_CONTROL; |
1276 if (ev->state & xd->MetaMask) modifiers |= XEMACS_MOD_META; | 1101 if (ev->state & xd->MetaMask) modifiers |= MOD_META; |
1277 if (ev->state & xd->SuperMask) modifiers |= XEMACS_MOD_SUPER; | 1102 if (ev->state & xd->SuperMask) modifiers |= MOD_SUPER; |
1278 if (ev->state & xd->HyperMask) modifiers |= XEMACS_MOD_HYPER; | 1103 if (ev->state & xd->HyperMask) modifiers |= MOD_HYPER; |
1279 if (ev->state & xd->AltMask) modifiers |= XEMACS_MOD_ALT; | 1104 if (ev->state & xd->AltMask) modifiers |= MOD_ALT; |
1280 /* Currently ignores Shift_Lock but probably shouldn't | 1105 /* Currently ignores Shift_Lock but probably shouldn't |
1281 (but it definitely should ignore Caps_Lock). */ | 1106 (but it definitely should ignore Caps_Lock). */ |
1282 emacs_event->event.motion.modifiers = modifiers; | 1107 emacs_event->event.motion.modifiers = modifiers; |
1283 } | 1108 } |
1284 break; | 1109 break; |
1290 explicitly prohibits. */ | 1115 explicitly prohibits. */ |
1291 XClientMessageEvent *ev = &x_event->xclient; | 1116 XClientMessageEvent *ev = &x_event->xclient; |
1292 #ifdef HAVE_OFFIX_DND | 1117 #ifdef HAVE_OFFIX_DND |
1293 if (DndIsDropMessage(x_event)) | 1118 if (DndIsDropMessage(x_event)) |
1294 { | 1119 { |
1295 unsigned int state; | 1120 unsigned int state, modifiers = 0, button=0; |
1296 int modifiers = 0; | |
1297 unsigned int button=0; | |
1298 struct frame *frame = x_any_window_to_frame (d, ev->window); | 1121 struct frame *frame = x_any_window_to_frame (d, ev->window); |
1299 Extbyte *data; | 1122 Extbyte *data; |
1300 unsigned long size, dtype; | 1123 unsigned long size, dtype; |
1301 Lisp_Object l_type = Qnil, l_data = Qnil; | 1124 Lisp_Object l_type = Qnil, l_data = Qnil; |
1302 Lisp_Object l_dndlist = Qnil, l_item = Qnil; | 1125 Lisp_Object l_dndlist = Qnil, l_item = Qnil; |
1311 emacs_event->event_type = misc_user_event; | 1134 emacs_event->event_type = misc_user_event; |
1312 emacs_event->timestamp = DEVICE_X_LAST_SERVER_TIMESTAMP (d); | 1135 emacs_event->timestamp = DEVICE_X_LAST_SERVER_TIMESTAMP (d); |
1313 | 1136 |
1314 state=DndDragButtons(x_event); | 1137 state=DndDragButtons(x_event); |
1315 | 1138 |
1316 if (state & ShiftMask) modifiers |= XEMACS_MOD_SHIFT; | 1139 if (state & ShiftMask) modifiers |= MOD_SHIFT; |
1317 if (state & ControlMask) modifiers |= XEMACS_MOD_CONTROL; | 1140 if (state & ControlMask) modifiers |= MOD_CONTROL; |
1318 if (state & xd->MetaMask) modifiers |= XEMACS_MOD_META; | 1141 if (state & xd->MetaMask) modifiers |= MOD_META; |
1319 if (state & xd->SuperMask) modifiers |= XEMACS_MOD_SUPER; | 1142 if (state & xd->SuperMask) modifiers |= MOD_SUPER; |
1320 if (state & xd->HyperMask) modifiers |= XEMACS_MOD_HYPER; | 1143 if (state & xd->HyperMask) modifiers |= MOD_HYPER; |
1321 if (state & xd->AltMask) modifiers |= XEMACS_MOD_ALT; | 1144 if (state & xd->AltMask) modifiers |= MOD_ALT; |
1322 | 1145 |
1323 if (state & Button5Mask) button = Button5; | 1146 if (state & Button5Mask) button = Button5; |
1324 if (state & Button4Mask) button = Button4; | 1147 if (state & Button4Mask) button = Button4; |
1325 if (state & Button3Mask) button = Button3; | 1148 if (state & Button3Mask) button = Button3; |
1326 if (state & Button2Mask) button = Button2; | 1149 if (state & Button2Mask) button = Button2; |
1359 l_type = Qdragdrop_MIME; | 1182 l_type = Qdragdrop_MIME; |
1360 l_dndlist = list1 ( list3 ( list1 ( make_string ((Bufbyte *)"text/plain", 10) ), | 1183 l_dndlist = list1 ( list3 ( list1 ( make_string ((Bufbyte *)"text/plain", 10) ), |
1361 make_string ((Bufbyte *)"8bit", 4), | 1184 make_string ((Bufbyte *)"8bit", 4), |
1362 make_ext_string ((Extbyte *)data, | 1185 make_ext_string ((Extbyte *)data, |
1363 strlen((char *)data), | 1186 strlen((char *)data), |
1364 Qctext) ) ); | 1187 FORMAT_CTEXT) ) ); |
1365 break; | 1188 break; |
1366 case DndMIME: | 1189 case DndMIME: |
1367 /* we have to parse this in some way to extract | 1190 /* we have to parse this in some way to extract |
1368 content-type and params (in the tm way) and | 1191 content-type and params (in the tm way) and |
1369 content encoding. | 1192 content encoding. |
1372 to tm... | 1195 to tm... |
1373 */ | 1196 */ |
1374 l_type = Qdragdrop_MIME; | 1197 l_type = Qdragdrop_MIME; |
1375 l_dndlist = list1 ( make_ext_string ((Extbyte *)data, | 1198 l_dndlist = list1 ( make_ext_string ((Extbyte *)data, |
1376 strlen((char *)data), | 1199 strlen((char *)data), |
1377 Qbinary) ); | 1200 FORMAT_BINARY) ); |
1378 break; | 1201 break; |
1379 case DndFile: | 1202 case DndFile: |
1380 case DndDir: | 1203 case DndDir: |
1381 case DndLink: | 1204 case DndLink: |
1382 case DndExe: | 1205 case DndExe: |
1393 case DndURL: | 1216 case DndURL: |
1394 /* as it is a real URL it should already be escaped | 1217 /* as it is a real URL it should already be escaped |
1395 and escaping again will break them (cause % is unsave) */ | 1218 and escaping again will break them (cause % is unsave) */ |
1396 l_dndlist = list1 ( make_ext_string ((Extbyte *)data, | 1219 l_dndlist = list1 ( make_ext_string ((Extbyte *)data, |
1397 strlen ((char *)data), | 1220 strlen ((char *)data), |
1398 Qfile_name) ); | 1221 FORMAT_FILENAME) ); |
1399 l_type = Qdragdrop_URL; | 1222 l_type = Qdragdrop_URL; |
1400 break; | 1223 break; |
1401 default: /* Unknown, RawData and any other type */ | 1224 default: /* Unknown, RawData and any other type */ |
1402 l_dndlist = list1 ( list3 ( list1 ( make_string ((Bufbyte *)"application/octet-stream", 24) ), | 1225 l_dndlist = list1 ( list3 ( list1 ( make_string ((Bufbyte *)"application/octet-stream", 24) ), |
1403 make_string ((Bufbyte *)"8bit", 4), | 1226 make_string ((Bufbyte *)"8bit", 4), |
1404 make_ext_string ((Extbyte *)data, | 1227 make_ext_string ((Extbyte *)data, |
1405 size, | 1228 size, |
1406 Qbinary) ) ); | 1229 FORMAT_BINARY) ) ); |
1407 l_type = Qdragdrop_MIME; | 1230 l_type = Qdragdrop_MIME; |
1408 break; | 1231 break; |
1409 } | 1232 } |
1410 | 1233 |
1411 emacs_event->event.misc.function = Qdragdrop_drop_dispatch; | 1234 emacs_event->event.misc.function = Qdragdrop_drop_dispatch; |
1450 case EnterNotify: | 1273 case EnterNotify: |
1451 case LeaveNotify: FROB(xcrossing, window); break; | 1274 case LeaveNotify: FROB(xcrossing, window); break; |
1452 case FocusIn: | 1275 case FocusIn: |
1453 case FocusOut: FROB(xfocus, window); break; | 1276 case FocusOut: FROB(xfocus, window); break; |
1454 case VisibilityNotify: FROB(xvisibility, window); break; | 1277 case VisibilityNotify: FROB(xvisibility, window); break; |
1455 case CreateNotify: FROB(xcreatewindow, window); break; | |
1456 default: | 1278 default: |
1457 w = x_event->xany.window; | 1279 w = x_event->xany.window; |
1458 *x_event_copy = *x_event; | 1280 *x_event_copy = *x_event; |
1459 break; | 1281 break; |
1460 } | 1282 } |
1480 /************************************************************************/ | 1302 /************************************************************************/ |
1481 | 1303 |
1482 static void | 1304 static void |
1483 handle_focus_event_1 (struct frame *f, int in_p) | 1305 handle_focus_event_1 (struct frame *f, int in_p) |
1484 { | 1306 { |
1485 #if XtSpecificationRelease > 5 | |
1486 Widget focus_widget = XtGetKeyboardFocusWidget (FRAME_X_TEXT_WIDGET (f)); | |
1487 #endif | |
1488 #ifdef HAVE_XIM | 1307 #ifdef HAVE_XIM |
1489 XIM_focus_event (f, in_p); | 1308 XIM_focus_event (f, in_p); |
1490 #endif /* HAVE_XIM */ | 1309 #endif /* HAVE_XIM */ |
1310 | |
1491 /* On focus change, clear all memory of sticky modifiers | 1311 /* On focus change, clear all memory of sticky modifiers |
1492 to avoid non-intuitive behavior. */ | 1312 to avoid non-intuitive behavior. */ |
1493 clear_sticky_modifiers (XDEVICE (FRAME_DEVICE (f))); | 1313 clear_sticky_modifiers (XDEVICE (FRAME_DEVICE (f))); |
1494 | 1314 |
1495 /* We don't want to handle the focus change now, because we might | 1315 /* We don't want to handle the focus change now, because we might |
1497 we enqueue it. | 1317 we enqueue it. |
1498 | 1318 |
1499 Actually, we half handle it: we handle it as far as changing the | 1319 Actually, we half handle it: we handle it as far as changing the |
1500 box cursor for redisplay, but we don't call any hooks or do any | 1320 box cursor for redisplay, but we don't call any hooks or do any |
1501 select-frame stuff until after the sit-for. | 1321 select-frame stuff until after the sit-for. |
1502 | 1322 */ |
1503 Unfortunately native widgets break the model because they grab | |
1504 the keyboard focus and nothing sets it back again. I cannot find | |
1505 any reasonable way to do this elsewhere so we assert here that | |
1506 the keyboard focus is on the emacs text widget. Menus and dialogs | |
1507 do this in their selection callback, but we don't want that since | |
1508 a button having focus is legitimate. An edit field having focus | |
1509 is mandatory. Weirdly you get a FocusOut event when you click in | |
1510 a widget-glyph but you don't get a correspondng FocusIn when you | |
1511 click in the frame. Why is this? */ | |
1512 if (in_p | |
1513 #if XtSpecificationRelease > 5 | |
1514 && FRAME_X_TEXT_WIDGET (f) != focus_widget | |
1515 #endif | |
1516 ) | |
1517 { | |
1518 lw_set_keyboard_focus (FRAME_X_SHELL_WIDGET (f), | |
1519 FRAME_X_TEXT_WIDGET (f)); | |
1520 } | |
1521 /* do the generic event-stream stuff. */ | |
1522 { | 1323 { |
1523 Lisp_Object frm; | 1324 Lisp_Object frm; |
1524 Lisp_Object conser; | 1325 Lisp_Object conser; |
1525 struct gcpro gcpro1; | 1326 struct gcpro gcpro1; |
1526 | 1327 |
1601 { | 1402 { |
1602 XWindowAttributes xwa; | 1403 XWindowAttributes xwa; |
1603 | 1404 |
1604 /* Bleagh!!!!!! Apparently some window managers (e.g. MWM) | 1405 /* Bleagh!!!!!! Apparently some window managers (e.g. MWM) |
1605 send synthetic MapNotify events when a window is first | 1406 send synthetic MapNotify events when a window is first |
1606 created, EVEN IF IT'S CREATED ICONIFIED OR INVISIBLE. | 1407 created, EVENT IF IT'S CREATED ICONIFIED OR INVISIBLE. |
1607 Or something like that. We initially tried a different | 1408 Or something like that. We initially tried a different |
1608 solution below, but that ran into a different window- | 1409 solution below, but that ran into a different window- |
1609 manager bug. | 1410 manager bug. |
1610 | 1411 |
1611 It seems that the only reliable way is to treat a | 1412 It seems that the only reliable way is to treat a |
1709 #endif | 1510 #endif |
1710 } | 1511 } |
1711 } | 1512 } |
1712 | 1513 |
1713 static void | 1514 static void |
1714 emacs_Xt_force_event_pending (struct frame* f) | 1515 emacs_Xt_handle_magic_event (struct Lisp_Event *emacs_event) |
1715 { | |
1716 XEvent event; | |
1717 | |
1718 Display* dpy = DEVICE_X_DISPLAY (XDEVICE (FRAME_DEVICE (f))); | |
1719 event.xclient.type = ClientMessage; | |
1720 event.xclient.display = dpy; | |
1721 event.xclient.message_type = XInternAtom (dpy, "BumpQueue", False); | |
1722 event.xclient.format = 32; | |
1723 event.xclient.window = 0; | |
1724 | |
1725 /* Send the drop message */ | |
1726 XSendEvent(dpy, XtWindow (FRAME_X_SHELL_WIDGET (f)), | |
1727 True, NoEventMask, &event); | |
1728 /* Force event pending to check the X queue. */ | |
1729 quit_check_signal_tick_count++; | |
1730 } | |
1731 | |
1732 static void | |
1733 emacs_Xt_handle_magic_event (Lisp_Event *emacs_event) | |
1734 { | 1516 { |
1735 /* This function can GC */ | 1517 /* This function can GC */ |
1736 XEvent *event = &emacs_event->event.magic.underlying_x_event; | 1518 XEvent *event = &emacs_event->event.magic.underlying_x_event; |
1737 struct frame *f = XFRAME (EVENT_CHANNEL (emacs_event)); | 1519 struct frame *f = XFRAME (EVENT_CHANNEL (emacs_event)); |
1738 | 1520 |
1756 case PropertyNotify: | 1538 case PropertyNotify: |
1757 x_handle_property_notify (&event->xproperty); | 1539 x_handle_property_notify (&event->xproperty); |
1758 break; | 1540 break; |
1759 | 1541 |
1760 case Expose: | 1542 case Expose: |
1761 if (!check_for_ignored_expose (f, event->xexpose.x, event->xexpose.y, | 1543 x_redraw_exposed_area (f, event->xexpose.x, event->xexpose.y, |
1762 event->xexpose.width, event->xexpose.height) | 1544 event->xexpose.width, event->xexpose.height); |
1763 && | |
1764 !find_matching_subwindow (f, event->xexpose.x, event->xexpose.y, | |
1765 event->xexpose.width, event->xexpose.height)) | |
1766 x_redraw_exposed_area (f, event->xexpose.x, event->xexpose.y, | |
1767 event->xexpose.width, event->xexpose.height); | |
1768 break; | 1545 break; |
1769 | 1546 |
1770 case GraphicsExpose: /* This occurs when an XCopyArea's source area was | 1547 case GraphicsExpose: /* This occurs when an XCopyArea's source area was |
1771 obscured or not available. */ | 1548 obscured or not available. */ |
1772 x_redraw_exposed_area (f, event->xexpose.x, event->xexpose.y, | 1549 x_redraw_exposed_area (f, event->xexpose.x, event->xexpose.y, |
1800 } | 1577 } |
1801 break; | 1578 break; |
1802 | 1579 |
1803 case FocusIn: | 1580 case FocusIn: |
1804 case FocusOut: | 1581 case FocusOut: |
1805 | |
1806 #ifdef EXTERNAL_WIDGET | 1582 #ifdef EXTERNAL_WIDGET |
1807 /* External widget lossage: Ben said: | 1583 /* External widget lossage: Ben said: |
1808 YUCK. The only way to make focus changes work properly is to | 1584 YUCK. The only way to make focus changes work properly is to |
1809 completely ignore all FocusIn/FocusOut events and depend only | 1585 completely ignore all FocusIn/FocusOut events and depend only |
1810 on notifications from the ExternalClient widget. */ | 1586 on notifications from the ExternalClient widget. */ |
1840 #ifdef HAVE_XIM | 1616 #ifdef HAVE_XIM |
1841 XIM_SetGeometry (f); | 1617 XIM_SetGeometry (f); |
1842 #endif | 1618 #endif |
1843 break; | 1619 break; |
1844 | 1620 |
1845 case CreateNotify: | |
1846 break; | |
1847 | |
1848 default: | 1621 default: |
1849 break; | 1622 break; |
1850 } | 1623 } |
1851 } | 1624 } |
1852 | 1625 |
1858 static int timeout_id_tick; | 1631 static int timeout_id_tick; |
1859 | 1632 |
1860 /* Xt interval id's might not fit into an int (they're pointers, as it | 1633 /* Xt interval id's might not fit into an int (they're pointers, as it |
1861 happens), so we need to provide a conversion list. */ | 1634 happens), so we need to provide a conversion list. */ |
1862 | 1635 |
1863 static struct Xt_timeout | 1636 struct Xt_timeout |
1864 { | 1637 { |
1865 int id; | 1638 int id; |
1866 XtIntervalId interval_id; | 1639 XtIntervalId interval_id; |
1867 struct Xt_timeout *next; | 1640 struct Xt_timeout *next; |
1868 } *pending_timeouts, *completed_timeouts; | 1641 } *pending_timeouts, *completed_timeouts; |
1869 | 1642 |
1870 static struct Xt_timeout_blocktype | 1643 struct Xt_timeout_blocktype |
1871 { | 1644 { |
1872 Blocktype_declare (struct Xt_timeout); | 1645 Blocktype_declare (struct Xt_timeout); |
1873 } *the_Xt_timeout_blocktype; | 1646 } *the_Xt_timeout_blocktype; |
1874 | 1647 |
1875 /* called by XtAppNextEvent() */ | 1648 /* called by XtAppNextEvent() */ |
1972 if (timeout) | 1745 if (timeout) |
1973 Blocktype_free (the_Xt_timeout_blocktype, timeout); | 1746 Blocktype_free (the_Xt_timeout_blocktype, timeout); |
1974 } | 1747 } |
1975 | 1748 |
1976 static void | 1749 static void |
1977 Xt_timeout_to_emacs_event (Lisp_Event *emacs_event) | 1750 Xt_timeout_to_emacs_event (struct Lisp_Event *emacs_event) |
1978 { | 1751 { |
1979 struct Xt_timeout *timeout = completed_timeouts; | 1752 struct Xt_timeout *timeout = completed_timeouts; |
1980 assert (timeout); | 1753 assert (timeout); |
1981 completed_timeouts = completed_timeouts->next; | 1754 completed_timeouts = completed_timeouts->next; |
1982 emacs_event->event_type = timeout_event; | 1755 emacs_event->event_type = timeout_event; |
2139 xfree (closure); | 1912 xfree (closure); |
2140 filedesc_to_what_closure[fd] = 0; | 1913 filedesc_to_what_closure[fd] = 0; |
2141 } | 1914 } |
2142 | 1915 |
2143 static void | 1916 static void |
2144 emacs_Xt_select_process (Lisp_Process *p) | 1917 emacs_Xt_select_process (struct Lisp_Process *p) |
2145 { | 1918 { |
2146 Lisp_Object process; | 1919 Lisp_Object process; |
2147 int infd = event_stream_unixoid_select_process (p); | 1920 int infd = event_stream_unixoid_select_process (p); |
2148 | 1921 |
2149 XSETPROCESS (process, p); | 1922 XSETPROCESS (process, p); |
2150 select_filedesc (infd, process); | 1923 select_filedesc (infd, process); |
2151 } | 1924 } |
2152 | 1925 |
2153 static void | 1926 static void |
2154 emacs_Xt_unselect_process (Lisp_Process *p) | 1927 emacs_Xt_unselect_process (struct Lisp_Process *p) |
2155 { | 1928 { |
2156 int infd = event_stream_unixoid_unselect_process (p); | 1929 int infd = event_stream_unixoid_unselect_process (p); |
2157 | 1930 |
2158 unselect_filedesc (infd); | 1931 unselect_filedesc (infd); |
2159 } | 1932 } |
2178 | 1951 |
2179 /* This is called from GC when a process object is about to be freed. | 1952 /* This is called from GC when a process object is about to be freed. |
2180 If we've still got pointers to it in this file, we're gonna lose hard. | 1953 If we've still got pointers to it in this file, we're gonna lose hard. |
2181 */ | 1954 */ |
2182 void | 1955 void |
2183 debug_process_finalization (Lisp_Process *p) | 1956 debug_process_finalization (struct Lisp_Process *p) |
2184 { | 1957 { |
2185 #if 0 /* #### */ | 1958 #if 0 /* #### */ |
2186 int i; | 1959 int i; |
2187 Lisp_Object instr, outstr; | 1960 Lisp_Object instr, outstr; |
2188 | 1961 |
2198 } | 1971 } |
2199 #endif | 1972 #endif |
2200 } | 1973 } |
2201 | 1974 |
2202 static void | 1975 static void |
2203 Xt_process_to_emacs_event (Lisp_Event *emacs_event) | 1976 Xt_process_to_emacs_event (struct Lisp_Event *emacs_event) |
2204 { | 1977 { |
2205 int i; | 1978 int i; |
1979 Lisp_Object process; | |
2206 | 1980 |
2207 assert (process_events_occurred > 0); | 1981 assert (process_events_occurred > 0); |
2208 | |
2209 for (i = 0; i < MAXDESC; i++) | 1982 for (i = 0; i < MAXDESC; i++) |
2210 { | 1983 { |
2211 Lisp_Object process = filedesc_with_input[i]; | 1984 process = filedesc_with_input[i]; |
2212 if (PROCESSP (process)) | 1985 if (PROCESSP (process)) |
2213 { | 1986 break; |
2214 filedesc_with_input[i] = Qnil; | 1987 } |
2215 process_events_occurred--; | 1988 assert (i < MAXDESC); |
2216 /* process events have nil as channel */ | 1989 filedesc_with_input[i] = Qnil; |
2217 emacs_event->event_type = process_event; | 1990 process_events_occurred--; |
2218 emacs_event->timestamp = 0; /* #### */ | 1991 /* process events have nil as channel */ |
2219 emacs_event->event.process.process = process; | 1992 emacs_event->event_type = process_event; |
2220 return; | 1993 emacs_event->timestamp = 0; /* #### */ |
2221 } | 1994 emacs_event->event.process.process = process; |
2222 } | |
2223 abort (); | |
2224 } | 1995 } |
2225 | 1996 |
2226 static void | 1997 static void |
2227 emacs_Xt_select_console (struct console *con) | 1998 emacs_Xt_select_console (struct console *con) |
2228 { | 1999 { |
2229 Lisp_Object console; | 2000 Lisp_Object console; |
2230 int infd; | 2001 int infd; |
2002 #ifdef HAVE_GPM | |
2003 int mousefd; | |
2004 #endif | |
2231 | 2005 |
2232 if (CONSOLE_X_P (con)) | 2006 if (CONSOLE_X_P (con)) |
2233 return; /* X consoles are automatically selected for when we | 2007 return; /* X consoles are automatically selected for when we |
2234 initialize them in Xt */ | 2008 initialize them in Xt */ |
2235 infd = event_stream_unixoid_select_console (con); | 2009 infd = event_stream_unixoid_select_console (con); |
2236 XSETCONSOLE (console, con); | 2010 XSETCONSOLE (console, con); |
2237 select_filedesc (infd, console); | 2011 select_filedesc (infd, console); |
2012 #ifdef HAVE_GPM | |
2013 /* On a stream device (ie: noninteractive), bad things can happen. */ | |
2014 if (EQ (CONSOLE_TYPE (con), Qtty)) { | |
2015 mousefd = CONSOLE_TTY_MOUSE_FD (con); | |
2016 /* We check filedesc_to_what_closure[fd] here because if you run | |
2017 ** XEmacs from a TTY, it will fire up GPM, select the mouse fd, then | |
2018 ** if you run gnuattach to connect to another TTY, it will fire up | |
2019 ** GPM again, and try to reselect the mouse fd. GPM uses the same | |
2020 ** fd for every connection apparently, and select_filedesc will | |
2021 ** fail its assertion if we try to select it twice. | |
2022 */ | |
2023 if ((mousefd >= 0) && !filedesc_to_what_closure[mousefd]) { | |
2024 select_filedesc (mousefd, console); | |
2025 } | |
2026 } | |
2027 #endif | |
2238 } | 2028 } |
2239 | 2029 |
2240 static void | 2030 static void |
2241 emacs_Xt_unselect_console (struct console *con) | 2031 emacs_Xt_unselect_console (struct console *con) |
2242 { | 2032 { |
2243 Lisp_Object console; | 2033 Lisp_Object console; |
2244 int infd; | 2034 int infd; |
2035 #ifdef HAVE_GPM | |
2036 int mousefd; | |
2037 #endif | |
2245 | 2038 |
2246 if (CONSOLE_X_P (con)) | 2039 if (CONSOLE_X_P (con)) |
2247 return; /* X consoles are automatically selected for when we | 2040 return; /* X consoles are automatically selected for when we |
2248 initialize them in Xt */ | 2041 initialize them in Xt */ |
2249 infd = event_stream_unixoid_unselect_console (con); | 2042 infd = event_stream_unixoid_unselect_console (con); |
2250 XSETCONSOLE (console, con); | 2043 XSETCONSOLE (console, con); |
2251 unselect_filedesc (infd); | 2044 unselect_filedesc (infd); |
2045 #ifdef HAVE_GPM | |
2046 /* On a stream device (ie: noninteractive), bad things can happen. */ | |
2047 if (EQ (CONSOLE_TYPE (con), Qtty)) { | |
2048 mousefd = CONSOLE_TTY_MOUSE_FD (con); | |
2049 if (mousefd >= 0) { | |
2050 unselect_filedesc (mousefd); | |
2051 } | |
2052 } | |
2053 #endif | |
2252 } | 2054 } |
2253 | 2055 |
2254 /* read an event from a tty, if one is available. Returns non-zero | 2056 /* read an event from a tty, if one is available. Returns non-zero |
2255 if an event was available. Note that when this function is | 2057 if an event was available. Note that when this function is |
2256 called, there should always be a tty marked as ready for input. | 2058 called, there should always be a tty marked as ready for input. |
2258 may not really be any input available. (In this case, | 2060 may not really be any input available. (In this case, |
2259 read_event_from_tty_or_stream_desc() will arrange for the TTY device | 2061 read_event_from_tty_or_stream_desc() will arrange for the TTY device |
2260 to be deleted.) */ | 2062 to be deleted.) */ |
2261 | 2063 |
2262 static int | 2064 static int |
2263 Xt_tty_to_emacs_event (Lisp_Event *emacs_event) | 2065 Xt_tty_to_emacs_event (struct Lisp_Event *emacs_event) |
2264 { | 2066 { |
2265 int i; | 2067 int i; |
2266 | 2068 |
2267 assert (tty_events_occurred > 0); | 2069 assert (tty_events_occurred > 0); |
2268 for (i = 0; i < MAXDESC; i++) | 2070 for (i = 0; i < MAXDESC; i++) |
2304 if (f) | 2106 if (f) |
2305 { | 2107 { |
2306 char *buf = alloca_array (char, XSTRING_LENGTH (f->name) + 4); | 2108 char *buf = alloca_array (char, XSTRING_LENGTH (f->name) + 4); |
2307 sprintf (buf, " \"%s\"", XSTRING_DATA (f->name)); | 2109 sprintf (buf, " \"%s\"", XSTRING_DATA (f->name)); |
2308 write_string_to_stdio_stream (stderr, 0, (Bufbyte *) buf, 0, | 2110 write_string_to_stdio_stream (stderr, 0, (Bufbyte *) buf, 0, |
2309 strlen (buf), Qterminal, 1); | 2111 strlen (buf), FORMAT_TERMINAL); |
2310 } | 2112 } |
2311 stderr_out ("\n"); | 2113 stderr_out ("\n"); |
2312 } | 2114 } |
2313 | 2115 |
2314 static const char * | 2116 static CONST char * |
2315 XEvent_mode_to_string (int mode) | 2117 XEvent_mode_to_string (int mode) |
2316 { | 2118 { |
2317 switch (mode) | 2119 switch (mode) |
2318 { | 2120 { |
2319 case NotifyNormal: return "Normal"; | 2121 case NotifyNormal: return "Normal"; |
2322 case NotifyWhileGrabbed: return "WhileGrabbed"; | 2124 case NotifyWhileGrabbed: return "WhileGrabbed"; |
2323 default: return "???"; | 2125 default: return "???"; |
2324 } | 2126 } |
2325 } | 2127 } |
2326 | 2128 |
2327 static const char * | 2129 static CONST char * |
2328 XEvent_detail_to_string (int detail) | 2130 XEvent_detail_to_string (int detail) |
2329 { | 2131 { |
2330 switch (detail) | 2132 switch (detail) |
2331 { | 2133 { |
2332 case NotifyAncestor: return "Ancestor"; | 2134 case NotifyAncestor: return "Ancestor"; |
2338 case NotifyDetailNone: return "DetailNone"; | 2140 case NotifyDetailNone: return "DetailNone"; |
2339 default: return "???"; | 2141 default: return "???"; |
2340 } | 2142 } |
2341 } | 2143 } |
2342 | 2144 |
2343 static const char * | 2145 static CONST char * |
2344 XEvent_visibility_to_string (int state) | 2146 XEvent_visibility_to_string (int state) |
2345 { | 2147 { |
2346 switch (state) | 2148 switch (state) |
2347 { | 2149 { |
2348 case VisibilityFullyObscured: return "FullyObscured"; | 2150 case VisibilityFullyObscured: return "FullyObscured"; |
2507 /* get the next event from Xt */ | 2309 /* get the next event from Xt */ |
2508 /************************************************************************/ | 2310 /************************************************************************/ |
2509 | 2311 |
2510 static Lisp_Object dispatch_event_queue, dispatch_event_queue_tail; | 2312 static Lisp_Object dispatch_event_queue, dispatch_event_queue_tail; |
2511 | 2313 |
2512 void | 2314 static void |
2513 enqueue_Xt_dispatch_event (Lisp_Object event) | 2315 enqueue_Xt_dispatch_event (Lisp_Object event) |
2514 { | 2316 { |
2515 enqueue_event (event, &dispatch_event_queue, &dispatch_event_queue_tail); | 2317 enqueue_event (event, &dispatch_event_queue, &dispatch_event_queue_tail); |
2516 } | 2318 } |
2517 | 2319 |
2543 | 2345 |
2544 enqueue_Xt_dispatch_event (event); | 2346 enqueue_Xt_dispatch_event (event); |
2545 } | 2347 } |
2546 | 2348 |
2547 static void | 2349 static void |
2548 emacs_Xt_next_event (Lisp_Event *emacs_event) | 2350 emacs_Xt_next_event (struct Lisp_Event *emacs_event) |
2549 { | 2351 { |
2550 we_didnt_get_an_event: | 2352 we_didnt_get_an_event: |
2551 | 2353 |
2552 while (NILP (dispatch_event_queue) && | 2354 while (NILP (dispatch_event_queue) && |
2553 !completed_timeouts && | 2355 !completed_timeouts && |
2928 /* This is exported by the Xt library (at least by mine). If this | 2730 /* This is exported by the Xt library (at least by mine). If this |
2929 isn't the case somewhere, rename this appropriately and remove | 2731 isn't the case somewhere, rename this appropriately and remove |
2930 the '#if 0'. Note, however, that I got "unknown structure" | 2732 the '#if 0'. Note, however, that I got "unknown structure" |
2931 errors when I tried this. */ | 2733 errors when I tried this. */ |
2932 XtConvertArgRec Const colorConvertArgs[] = { | 2734 XtConvertArgRec Const colorConvertArgs[] = { |
2933 { XtWidgetBaseOffset, (XtPointer)XtOffsetOf(WidgetRec, core.screen), | 2735 {XtWidgetBaseOffset, (XtPointer)XtOffsetOf(WidgetRec, core.screen), |
2934 sizeof (Screen *) }, | 2736 sizeof(Screen *)}, |
2935 { XtWidgetBaseOffset, (XtPointer)XtOffsetOf(WidgetRec, core.colormap), | 2737 {XtWidgetBaseOffset, (XtPointer)XtOffsetOf(WidgetRec, core.colormap), |
2936 sizeof (Colormap) } | 2738 sizeof(Colormap)} |
2937 }; | 2739 }; |
2938 | 2740 |
2939 #endif | 2741 #endif |
2940 | 2742 |
2941 #define done(type, value) \ | 2743 #define done(type, value) \ |
3073 } | 2875 } |
3074 } | 2876 } |
3075 | 2877 |
3076 | 2878 |
3077 /************************************************************************/ | 2879 /************************************************************************/ |
3078 /* handle focus changes for native widgets */ | |
3079 /************************************************************************/ | |
3080 static void | |
3081 emacs_Xt_event_widget_focus_in (Widget w, | |
3082 XEvent *event, | |
3083 String *params, | |
3084 Cardinal *num_params) | |
3085 { | |
3086 struct frame* f = | |
3087 x_any_widget_or_parent_to_frame (get_device_from_display (event->xany.display), w); | |
3088 | |
3089 XtSetKeyboardFocus (FRAME_X_SHELL_WIDGET (f), w); | |
3090 } | |
3091 | |
3092 static void | |
3093 emacs_Xt_event_widget_focus_out (Widget w, | |
3094 XEvent *event, | |
3095 String *params, | |
3096 Cardinal *num_params) | |
3097 { | |
3098 } | |
3099 | |
3100 static XtActionsRec widgetActionsList[] = | |
3101 { | |
3102 {"widget-focus-in", emacs_Xt_event_widget_focus_in }, | |
3103 {"widget-focus-out", emacs_Xt_event_widget_focus_out }, | |
3104 }; | |
3105 | |
3106 static void | |
3107 emacs_Xt_event_add_widget_actions (XtAppContext ctx) | |
3108 { | |
3109 XtAppAddActions (ctx, widgetActionsList, 2); | |
3110 } | |
3111 | |
3112 | |
3113 /************************************************************************/ | |
3114 /* initialization */ | 2880 /* initialization */ |
3115 /************************************************************************/ | 2881 /************************************************************************/ |
3116 | 2882 |
3117 void | 2883 void |
3118 syms_of_event_Xt (void) | 2884 syms_of_event_Xt (void) |
3119 { | 2885 { |
3120 defsymbol (&Qkey_mapping, "key-mapping"); | 2886 defsymbol (&Qkey_mapping, "key-mapping"); |
3121 defsymbol (&Qsans_modifiers, "sans-modifiers"); | 2887 defsymbol (&Qsans_modifiers, "sans-modifiers"); |
3122 defsymbol (&Qself_insert_command, "self-insert-command"); | |
3123 } | 2888 } |
3124 | 2889 |
3125 void | 2890 void |
3126 reinit_vars_of_event_Xt (void) | 2891 vars_of_event_Xt (void) |
3127 { | 2892 { |
2893 dispatch_event_queue = Qnil; | |
2894 staticpro (&dispatch_event_queue); | |
2895 dispatch_event_queue_tail = Qnil; | |
2896 | |
2897 /* this function only makes safe calls */ | |
2898 init_what_input_once (); | |
2899 | |
3128 Xt_event_stream = xnew (struct event_stream); | 2900 Xt_event_stream = xnew (struct event_stream); |
3129 Xt_event_stream->event_pending_p = emacs_Xt_event_pending_p; | 2901 Xt_event_stream->event_pending_p = emacs_Xt_event_pending_p; |
3130 Xt_event_stream->force_event_pending = emacs_Xt_force_event_pending; | |
3131 Xt_event_stream->next_event_cb = emacs_Xt_next_event; | 2902 Xt_event_stream->next_event_cb = emacs_Xt_next_event; |
3132 Xt_event_stream->handle_magic_event_cb = emacs_Xt_handle_magic_event; | 2903 Xt_event_stream->handle_magic_event_cb = emacs_Xt_handle_magic_event; |
3133 Xt_event_stream->add_timeout_cb = emacs_Xt_add_timeout; | 2904 Xt_event_stream->add_timeout_cb = emacs_Xt_add_timeout; |
3134 Xt_event_stream->remove_timeout_cb = emacs_Xt_remove_timeout; | 2905 Xt_event_stream->remove_timeout_cb = emacs_Xt_remove_timeout; |
3135 Xt_event_stream->select_console_cb = emacs_Xt_select_console; | 2906 Xt_event_stream->select_console_cb = emacs_Xt_select_console; |
3138 Xt_event_stream->unselect_process_cb = emacs_Xt_unselect_process; | 2909 Xt_event_stream->unselect_process_cb = emacs_Xt_unselect_process; |
3139 Xt_event_stream->quit_p_cb = emacs_Xt_quit_p; | 2910 Xt_event_stream->quit_p_cb = emacs_Xt_quit_p; |
3140 Xt_event_stream->create_stream_pair_cb = emacs_Xt_create_stream_pair; | 2911 Xt_event_stream->create_stream_pair_cb = emacs_Xt_create_stream_pair; |
3141 Xt_event_stream->delete_stream_pair_cb = emacs_Xt_delete_stream_pair; | 2912 Xt_event_stream->delete_stream_pair_cb = emacs_Xt_delete_stream_pair; |
3142 | 2913 |
3143 the_Xt_timeout_blocktype = Blocktype_new (struct Xt_timeout_blocktype); | 2914 DEFVAR_BOOL ("modifier-keys-are-sticky", &modifier_keys_are_sticky /* |
3144 | 2915 *Non-nil makes modifier keys sticky. |
3145 last_quit_check_signal_tick_count = 0; | 2916 This means that you can release the modifier key before pressing down |
3146 | 2917 the key that you wish to be modified. Although this is non-standard |
3147 /* this function only makes safe calls */ | 2918 behavior, it is recommended because it reduces the strain on your hand, |
3148 init_what_input_once (); | 2919 thus reducing the incidence of the dreaded Emacs-pinky syndrome. |
3149 } | 2920 */ ); |
3150 | 2921 modifier_keys_are_sticky = 0; |
3151 void | |
3152 vars_of_event_Xt (void) | |
3153 { | |
3154 reinit_vars_of_event_Xt (); | |
3155 | |
3156 dispatch_event_queue = Qnil; | |
3157 staticpro (&dispatch_event_queue); | |
3158 dispatch_event_queue_tail = Qnil; | |
3159 pdump_wire (&dispatch_event_queue_tail); | |
3160 | 2922 |
3161 DEFVAR_BOOL ("x-allow-sendevents", &x_allow_sendevents /* | 2923 DEFVAR_BOOL ("x-allow-sendevents", &x_allow_sendevents /* |
3162 *Non-nil means to allow synthetic events. Nil means they are ignored. | 2924 *Non-nil means to allow synthetic events. Nil means they are ignored. |
3163 Beware: allowing emacs to process SendEvents opens a big security hole. | 2925 Beware: allowing emacs to process SendEvents opens a big security hole. |
3164 */ ); | 2926 */ ); |
3172 1 == non-verbose output | 2934 1 == non-verbose output |
3173 2 == verbose output | 2935 2 == verbose output |
3174 */ ); | 2936 */ ); |
3175 x_debug_events = 0; | 2937 x_debug_events = 0; |
3176 #endif | 2938 #endif |
2939 | |
2940 the_Xt_timeout_blocktype = Blocktype_new (struct Xt_timeout_blocktype); | |
2941 | |
2942 last_quit_check_signal_tick_count = 0; | |
3177 } | 2943 } |
3178 | 2944 |
3179 /* This mess is a hack that patches the shell widget to treat visual inheritance | 2945 /* This mess is a hack that patches the shell widget to treat visual inheritance |
3180 the same as colormap and depth inheritance */ | 2946 the same as colormap and depth inheritance */ |
3181 | 2947 |
3218 /* In xselect.c */ | 2984 /* In xselect.c */ |
3219 x_selection_timeout = (XtAppGetSelectionTimeout (Xt_app_con) / 1000); | 2985 x_selection_timeout = (XtAppGetSelectionTimeout (Xt_app_con) / 1000); |
3220 XSetErrorHandler (x_error_handler); | 2986 XSetErrorHandler (x_error_handler); |
3221 XSetIOErrorHandler (x_IO_error_handler); | 2987 XSetIOErrorHandler (x_IO_error_handler); |
3222 | 2988 |
3223 #ifndef WIN32_NATIVE | 2989 #ifndef WINDOWSNT |
3224 XtAppAddInput (Xt_app_con, signal_event_pipe[0], | 2990 XtAppAddInput (Xt_app_con, signal_event_pipe[0], |
3225 (XtPointer) (XtInputReadMask /* | XtInputExceptMask */), | 2991 (XtPointer) (XtInputReadMask /* | XtInputExceptMask */), |
3226 Xt_what_callback, 0); | 2992 Xt_what_callback, 0); |
3227 #endif | 2993 #endif |
3228 | 2994 |
3235 XtAppSetTypeConverter (Xt_app_con, XtRString, XtRXimStyles, | 3001 XtAppSetTypeConverter (Xt_app_con, XtRString, XtRXimStyles, |
3236 EmacsXtCvtStringToXIMStyles, | 3002 EmacsXtCvtStringToXIMStyles, |
3237 NULL, 0, | 3003 NULL, 0, |
3238 XtCacheByDisplay, EmacsFreeXIMStyles); | 3004 XtCacheByDisplay, EmacsFreeXIMStyles); |
3239 #endif /* XIM_XLIB */ | 3005 #endif /* XIM_XLIB */ |
3240 /* Add extra actions to native widgets to handle focus and friends. */ | |
3241 emacs_Xt_event_add_widget_actions (Xt_app_con); | |
3242 | 3006 |
3243 /* insert the visual inheritance patch/hack described above */ | 3007 /* insert the visual inheritance patch/hack described above */ |
3244 orig_shell_init_proc = shellClassRec.core_class.initialize; | 3008 orig_shell_init_proc = shellClassRec.core_class.initialize; |
3245 shellClassRec.core_class.initialize = ShellVisualPatch; | 3009 shellClassRec.core_class.initialize = ShellVisualPatch; |
3246 | 3010 |