X-Git-Url: http://git.chise.org/gitweb/?p=chise%2Fxemacs-chise.git.1;a=blobdiff_plain;f=src%2Fevent-Xt.c;h=4345bb1593b59e40a0afb57db9bd54b525ecbb17;hp=fcc8a922e345e787631edb02da16b5c47fd86db3;hb=dbf2768f7b146e97e37a27316f70bb313f1acf15;hpb=da416a1945940b3f952144475eb1a1357430527d diff --git a/src/event-Xt.c b/src/event-Xt.c index fcc8a92..4345bb1 100644 --- a/src/event-Xt.c +++ b/src/event-Xt.c @@ -65,19 +65,8 @@ Boston, MA 02111-1307, USA. */ #include "offix.h" #endif -#ifdef WINDOWSNT -/* Hmm, under unix we want X modifiers, under NT we want X modifiers if - we are running X and Windows modifiers otherwise. - gak. This is a kludge until we support multiple native GUIs! -*/ -#undef MOD_ALT -#undef MOD_CONTROL -#undef MOD_SHIFT -#endif - #include "events-mod.h" -static void enqueue_Xt_dispatch_event (Lisp_Object event); static void handle_focus_event_1 (struct frame *f, int in_p); static struct event_stream *Xt_event_stream; @@ -97,19 +86,18 @@ XtAppContext Xt_app_con; /* Do we accept events sent by other clients? */ int x_allow_sendevents; -int modifier_keys_are_sticky; - #ifdef DEBUG_XEMACS -int x_debug_events; +Fixnum debug_x_events; #endif static int process_events_occurred; static int tty_events_occurred; +static Widget widget_with_focus; /* Mask of bits indicating the descriptors that we wait for input on */ extern SELECT_TYPE input_wait_mask, process_only_mask, tty_only_mask; -static CONST String x_fallback_resources[] = +static const String x_fallback_resources[] = { /* This file is automatically generated from the app-defaults file in ../etc/Emacs.ad. These resources are consulted only if no @@ -121,7 +109,7 @@ static CONST String x_fallback_resources[] = static Lisp_Object x_keysym_to_emacs_keysym (KeySym keysym, int simple_p); void emacs_Xt_mapping_action (Widget w, XEvent *event); -void debug_process_finalization (struct Lisp_Process *p); +void debug_process_finalization (Lisp_Process *p); void emacs_Xt_event_handler (Widget wid, XtPointer closure, XEvent *event, Boolean *continue_to_dispatch); @@ -175,6 +163,206 @@ Lisp_Object Qsans_modifiers; use a pop-up-window instead.) */ +/* For every key on the keyboard that has a known character correspondence, + we define the ascii-character property of the keysym, and make the + default binding for the key be self-insert-command. + + The following magic is basically intimate knowledge of X11/keysymdef.h. + The keysym mappings defined by X11 are based on the iso8859 standards, + except for Cyrillic and Greek. + + In a non-Mule world, a user can still have a multi-lingual editor, by doing + (set-face-font "...-iso8859-2" (current-buffer)) + for all their Latin-2 buffers, etc. */ + +static Lisp_Object +x_keysym_to_character (KeySym keysym) +{ +#ifdef MULE + Lisp_Object charset = Qzero; +#define USE_CHARSET(var,cs) \ + ((var) = CHARSET_BY_LEADING_BYTE (LEADING_BYTE_##cs)) +#else +#define USE_CHARSET(var,lb) +#endif /* MULE */ + int code = 0; + + if ((keysym & 0xff) < 0xa0) + return Qnil; + + switch (keysym >> 8) + { + case 0: /* ASCII + Latin1 */ + USE_CHARSET (charset, LATIN_ISO8859_1); + code = keysym & 0x7f; + break; + case 1: /* Latin2 */ + USE_CHARSET (charset, LATIN_ISO8859_2); + code = keysym & 0x7f; + break; + case 2: /* Latin3 */ + USE_CHARSET (charset, LATIN_ISO8859_3); + code = keysym & 0x7f; + break; + case 3: /* Latin4 */ + USE_CHARSET (charset, LATIN_ISO8859_4); + code = keysym & 0x7f; + break; + case 4: /* Katakana */ + USE_CHARSET (charset, KATAKANA_JISX0201); + if ((keysym & 0xff) > 0xa0) + code = keysym & 0x7f; + break; + case 5: /* Arabic */ + USE_CHARSET (charset, ARABIC_ISO8859_6); + code = keysym & 0x7f; + break; + case 6: /* Cyrillic */ + { + static unsigned char const cyrillic[] = /* 0x20 - 0x7f */ + {0x00, 0x72, 0x73, 0x71, 0x74, 0x75, 0x76, 0x77, + 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x00, 0x7e, 0x7f, + 0x70, 0x22, 0x23, 0x21, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x00, 0x2e, 0x2f, + 0x6e, 0x50, 0x51, 0x66, 0x54, 0x55, 0x64, 0x53, + 0x65, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, + 0x5f, 0x6f, 0x60, 0x61, 0x62, 0x63, 0x56, 0x52, + 0x6c, 0x6b, 0x57, 0x68, 0x6d, 0x69, 0x67, 0x6a, + 0x4e, 0x30, 0x31, 0x46, 0x34, 0x35, 0x44, 0x33, + 0x45, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, + 0x3f, 0x4f, 0x40, 0x41, 0x42, 0x43, 0x36, 0x32, + 0x4c, 0x4b, 0x37, 0x48, 0x4d, 0x49, 0x47, 0x4a}; + USE_CHARSET (charset, CYRILLIC_ISO8859_5); + code = cyrillic[(keysym & 0x7f) - 0x20]; + break; + } + case 7: /* Greek */ + { + static unsigned char const greek[] = /* 0x20 - 0x7f */ + {0x00, 0x36, 0x38, 0x39, 0x3a, 0x5a, 0x00, 0x3c, + 0x3e, 0x5b, 0x00, 0x3f, 0x00, 0x00, 0x35, 0x2f, + 0x00, 0x5c, 0x5d, 0x5e, 0x5f, 0x7a, 0x40, 0x7c, + 0x7d, 0x7b, 0x60, 0x7e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, + 0x50, 0x51, 0x53, 0x00, 0x54, 0x55, 0x56, 0x57, + 0x58, 0x59, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, + 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, + 0x70, 0x71, 0x73, 0x72, 0x74, 0x75, 0x76, 0x77, + 0x78, 0x79, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + USE_CHARSET (charset, GREEK_ISO8859_7); + code = greek[(keysym & 0x7f) - 0x20]; + break; + } + case 8: /* Technical */ + break; + case 9: /* Special */ + break; + case 10: /* Publishing */ + break; + case 11: /* APL */ + break; + case 12: /* Hebrew */ + USE_CHARSET (charset, HEBREW_ISO8859_8); + code = keysym & 0x7f; + break; + case 13: /* Thai */ + /* #### This needs to deal with character composition. */ + USE_CHARSET (charset, THAI_TIS620); + code = keysym & 0x7f; + break; + case 14: /* Korean Hangul */ + break; + case 19: /* Latin 9 - ISO8859-15 - unsupported charset. */ + break; + case 32: /* Currency */ + break; + default: + break; + } + + if (code == 0) + return Qnil; + +#ifdef MULE + return make_char (MAKE_CHAR (charset, code, 0)); +#else + return make_char (code + 0x80); +#endif +} + +/* #### The way that keysym correspondence to characters should work: + - a Lisp_Event should contain a keysym AND a character slot. + - keybindings are tried with the keysym. If no binding can be found, + and there is a corresponding character, call self-insert-command. + + #### Nuke x-iso8859-1.el. + #### Nuke the Qascii_character property. + #### Nuke Vcharacter_set_property. +*/ +static void +maybe_define_x_key_as_self_inserting_character (KeySym keysym, Lisp_Object symbol) +{ + Lisp_Object character = x_keysym_to_character (keysym); + + if (CHARP (character)) + { + extern Lisp_Object Vcurrent_global_map; + extern Lisp_Object Qascii_character; + if (NILP (Flookup_key (Vcurrent_global_map, symbol, Qnil))) + { + Fput (symbol, Qascii_character, character); + Fdefine_key (Vcurrent_global_map, symbol, Qself_insert_command); + } + } +} + +static void +x_has_keysym (KeySym keysym, Lisp_Object hash_table, int with_modifiers) +{ + KeySym upper_lower[2]; + int j; + + if (keysym < 0x80) /* Optimize for ASCII keysyms */ + return; + + /* If you execute: + xmodmap -e 'keysym NN = scaron' + and then press (Shift scaron), X11 will return the different + keysym `Scaron', but `xmodmap -pke' might not even mention `Scaron'. + So we "register" both `scaron' and `Scaron'. */ +#ifdef HAVE_XCONVERTCASE + XConvertCase (keysym, &upper_lower[0], &upper_lower[1]); +#else + upper_lower[0] = upper_lower[1] = keysym; +#endif + + for (j = 0; j < (upper_lower[0] == upper_lower[1] ? 1 : 2); j++) + { + char *name; + keysym = upper_lower[j]; + + name = XKeysymToString (keysym); + if (name) + { + /* X guarantees NAME to be in the Host Portable Character Encoding */ + Lisp_Object sym = x_keysym_to_emacs_keysym (keysym, 0); + Lisp_Object new_value = with_modifiers ? Qt : Qsans_modifiers; + Lisp_Object old_value = Fgethash (sym, hash_table, Qnil); + + if (! EQ (old_value, new_value) + && ! (EQ (old_value, Qsans_modifiers) && + EQ (new_value, Qt))) + { + maybe_define_x_key_as_self_inserting_character (keysym, sym); + Fputhash (build_ext_string (name, Qbinary), new_value, hash_table); + Fputhash (sym, new_value, hash_table); + } + } + } +} + static void x_reset_key_mapping (struct device *d) { @@ -212,34 +400,18 @@ x_reset_key_mapping (struct device *d) if (keysym[0] == NoSymbol) continue; - { - char *name = XKeysymToString (keysym[0]); - Lisp_Object sym = x_keysym_to_emacs_keysym (keysym[0], 0); - if (name) - { - Fputhash (build_string (name), Qsans_modifiers, hash_table); - Fputhash (sym, Qsans_modifiers, hash_table); - } - } + x_has_keysym (keysym[0], hash_table, 0); for (j = 1; j < keysyms_per_code; j++) { if (keysym[j] != keysym[0] && keysym[j] != NoSymbol) - { - char *name = XKeysymToString (keysym[j]); - Lisp_Object sym = x_keysym_to_emacs_keysym (keysym[j], 0); - if (name && NILP (Fgethash (sym, hash_table, Qnil))) - { - Fputhash (build_string (name), Qt, hash_table); - Fputhash (sym, Qt, hash_table); - } - } + x_has_keysym (keysym[j], hash_table, 1); } } } -static CONST char * +static const char * index_to_name (int indice) { switch (indice) @@ -394,7 +566,7 @@ x_reset_modifier_mapping (struct device *d) be totally wrong. */ if (mode_bit) { - CONST char *warn = 0; + const char *warn = 0; if (mode_bit == meta_bit) warn = "Meta", meta_bit = 0; else if (mode_bit == hyper_bit) warn = "Hyper", hyper_bit = 0; else if (mode_bit == super_bit) warn = "Super", super_bit = 0; @@ -518,20 +690,29 @@ x_handle_sticky_modifiers (XEvent *ev, struct device *d) { /* Not a modifier key */ Bool key_event_p = (type == KeyPress || type == KeyRelease); - if (type == KeyPress && !xd->last_downkey) - xd->last_downkey = keycode; - else if (type == ButtonPress || - (type == KeyPress && xd->last_downkey && - (keycode != xd->last_downkey || - ev->xkey.time != xd->release_time))) + if (type == ButtonPress + || (type == KeyPress + && ((xd->last_downkey + && ((keycode != xd->last_downkey + || ev->xkey.time != xd->release_time))) + || (INTP (Vmodifier_keys_sticky_time) + && ev->xkey.time + > (xd->modifier_release_time + + XINT (Vmodifier_keys_sticky_time)))))) { xd->need_to_add_mask = 0; xd->last_downkey = 0; } + else if (type == KeyPress && !xd->last_downkey) + xd->last_downkey = keycode; + if (type == KeyPress) xd->release_time = 0; if (type == KeyPress || type == ButtonPress) - xd->down_mask = 0; + { + xd->down_mask = 0; + xd->modifier_release_time = 0; + } if (key_event_p) ev->xkey.state |= xd->need_to_add_mask; @@ -553,7 +734,8 @@ x_handle_sticky_modifiers (XEvent *ev, struct device *d) So we assume that if the release and the next press occur at the same time, the key was actually auto- repeated. Under Open-Windows, at least, this works. */ - xd->release_time = key_event_p ? ev->xkey.time : ev->xbutton.time; + xd->modifier_release_time = xd->release_time + = key_event_p ? ev->xkey.time : ev->xbutton.time; } else /* Modifier key pressed */ { @@ -573,6 +755,15 @@ x_handle_sticky_modifiers (XEvent *ev, struct device *d) xd->need_to_add_mask = 0; } + if (xd->modifier_release_time + && INTP (Vmodifier_keys_sticky_time) + && (ev->xkey.time + > xd->modifier_release_time + XINT (Vmodifier_keys_sticky_time))) + { + xd->need_to_add_mask = 0; + xd->down_mask = 0; + } + #define FROB(mask) \ do { \ if (type == KeyPress) \ @@ -598,6 +789,7 @@ do { \ xd->need_to_add_mask |= mask; \ } \ } \ + xd->modifier_release_time = ev->xkey.time; \ } while (0) for (i = 0; i < xd->x_keysym_map_keysyms_per_code; i++) @@ -775,7 +967,11 @@ x_to_emacs_keysym (XKeyPressedEvent *event, int simple_p) #ifdef HAVE_XIM int len; - char buffer[64]; + /* Some implementations of XmbLookupString don't return + XBufferOverflow correctly, so increase the size of the xim input + buffer from 64 to the more reasonable size 513, as Emacs has done. + From Kenichi Handa. */ + char buffer[513]; char *bufptr = buffer; int bufsiz = sizeof (buffer); Status status; @@ -813,7 +1009,7 @@ x_to_emacs_keysym (XKeyPressedEvent *event, int simple_p) #endif /* HAVE_XIM */ #ifdef DEBUG_XEMACS - if (x_debug_events > 0) + if (debug_x_events > 0) { stderr_out (" status="); #define print_status_when(S) if (status == S) stderr_out (#S) @@ -860,10 +1056,9 @@ x_to_emacs_keysym (XKeyPressedEvent *event, int simple_p) Lstream *istr; struct gcpro gcpro1, gcpro2; - fb_instream = - make_fixed_buffer_input_stream ((unsigned char *) bufptr, len); + fb_instream = make_fixed_buffer_input_stream (bufptr, len); - /* ### Use Fget_coding_system (Vcomposed_input_coding_system) */ + /* #### Use Fget_coding_system (Vcomposed_input_coding_system) */ instream = make_decoding_input_stream (XLSTREAM (fb_instream), Fget_coding_system (Qundecided)); @@ -874,7 +1069,7 @@ x_to_emacs_keysym (XKeyPressedEvent *event, int simple_p) while ((ch = Lstream_get_emchar (istr)) != EOF) { Lisp_Object emacs_event = Fmake_event (Qnil, Qnil); - struct Lisp_Event *ev = XEVENT (emacs_event); + Lisp_Event *ev = XEVENT (emacs_event); ev->channel = DEVICE_CONSOLE (d); ev->event_type = key_press_event; ev->timestamp = event->time; @@ -921,7 +1116,7 @@ set_last_server_timestamp (struct device *d, XEvent *x_event) } static int -x_event_to_emacs_event (XEvent *x_event, struct Lisp_Event *emacs_event) +x_event_to_emacs_event (XEvent *x_event, Lisp_Event *emacs_event) { Display *display = x_event->xany.display; struct device *d = get_device_from_display (display); @@ -943,7 +1138,7 @@ x_event_to_emacs_event (XEvent *x_event, struct Lisp_Event *emacs_event) case ButtonPress: case ButtonRelease: { - unsigned int modifiers = 0; + int modifiers = 0; int shift_p, lock_p; Bool key_event_p = (x_event->type == KeyPress); unsigned int *state = @@ -970,11 +1165,30 @@ x_event_to_emacs_event (XEvent *x_event, struct Lisp_Event *emacs_event) x_handle_sticky_modifiers (x_event, d); - if (*state & ControlMask) modifiers |= MOD_CONTROL; - if (*state & xd->MetaMask) modifiers |= MOD_META; - if (*state & xd->SuperMask) modifiers |= MOD_SUPER; - if (*state & xd->HyperMask) modifiers |= MOD_HYPER; - if (*state & xd->AltMask) modifiers |= MOD_ALT; + if (*state & ControlMask) modifiers |= XEMACS_MOD_CONTROL; + if (*state & xd->MetaMask) modifiers |= XEMACS_MOD_META; + if (*state & xd->SuperMask) modifiers |= XEMACS_MOD_SUPER; + if (*state & xd->HyperMask) modifiers |= XEMACS_MOD_HYPER; + if (*state & xd->AltMask) modifiers |= XEMACS_MOD_ALT; + { + int numero_de_botao = -1; + + if (!key_event_p) + numero_de_botao = x_event->xbutton.button; + + /* the button gets noted either in the button or the modifiers + field, but not both. */ + if (numero_de_botao != 1 && (*state & Button1Mask)) + modifiers |= XEMACS_MOD_BUTTON1; + if (numero_de_botao != 2 && (*state & Button2Mask)) + modifiers |= XEMACS_MOD_BUTTON2; + if (numero_de_botao != 3 && (*state & Button3Mask)) + modifiers |= XEMACS_MOD_BUTTON3; + if (numero_de_botao != 4 && (*state & Button4Mask)) + modifiers |= XEMACS_MOD_BUTTON4; + if (numero_de_botao != 5 && (*state & Button5Mask)) + modifiers |= XEMACS_MOD_BUTTON5; + } /* Ignore the Caps_Lock key if: - any other modifiers are down, so that Caps_Lock doesn't @@ -987,7 +1201,7 @@ x_event_to_emacs_event (XEvent *x_event, struct Lisp_Event *emacs_event) lock_p = *state & LockMask; if (shift_p || lock_p) - modifiers |= MOD_SHIFT; + modifiers |= XEMACS_MOD_SHIFT; if (key_event_p) { @@ -1019,7 +1233,7 @@ x_event_to_emacs_event (XEvent *x_event, struct Lisp_Event *emacs_event) ! (CHAR_OR_CHAR_INTP (keysym) && keysym_obeys_caps_lock_p ((KeySym) XCHAR_OR_CHAR_INT (keysym), d))) - modifiers &= (~MOD_SHIFT); + modifiers &= (~XEMACS_MOD_SHIFT); /* If this key contains two distinct keysyms, that is, "shift" generates a different keysym than the @@ -1031,13 +1245,13 @@ x_event_to_emacs_event (XEvent *x_event, struct Lisp_Event *emacs_event) in the modifiers slot. Neither the characters "a", "A", "2", nor "@" normally have the shift bit set. However, "F1" normally does. */ - if (modifiers & MOD_SHIFT) + if (modifiers & XEMACS_MOD_SHIFT) { int Mode_switch_p = *state & xd->ModeMask; KeySym bot = XLookupKeysym (ev, Mode_switch_p ? 2 : 0); KeySym top = XLookupKeysym (ev, Mode_switch_p ? 3 : 1); if (top && bot && top != bot) - modifiers &= ~MOD_SHIFT; + modifiers &= ~XEMACS_MOD_SHIFT; } emacs_event->event_type = key_press_event; emacs_event->timestamp = ev->time; @@ -1074,7 +1288,7 @@ x_event_to_emacs_event (XEvent *x_event, struct Lisp_Event *emacs_event) { XMotionEvent *ev = &x_event->xmotion; struct frame *frame = x_window_to_frame (d, ev->window); - unsigned int modifiers = 0; + int modifiers = 0; XMotionEvent event2; if (! frame) @@ -1103,12 +1317,17 @@ x_event_to_emacs_event (XEvent *x_event, struct Lisp_Event *emacs_event) emacs_event->timestamp = ev->time; emacs_event->event.motion.x = ev->x; emacs_event->event.motion.y = ev->y; - if (ev->state & ShiftMask) modifiers |= MOD_SHIFT; - if (ev->state & ControlMask) modifiers |= MOD_CONTROL; - if (ev->state & xd->MetaMask) modifiers |= MOD_META; - if (ev->state & xd->SuperMask) modifiers |= MOD_SUPER; - if (ev->state & xd->HyperMask) modifiers |= MOD_HYPER; - if (ev->state & xd->AltMask) modifiers |= MOD_ALT; + if (ev->state & ShiftMask) modifiers |= XEMACS_MOD_SHIFT; + if (ev->state & ControlMask) modifiers |= XEMACS_MOD_CONTROL; + if (ev->state & xd->MetaMask) modifiers |= XEMACS_MOD_META; + if (ev->state & xd->SuperMask) modifiers |= XEMACS_MOD_SUPER; + if (ev->state & xd->HyperMask) modifiers |= XEMACS_MOD_HYPER; + if (ev->state & xd->AltMask) modifiers |= XEMACS_MOD_ALT; + if (ev->state & Button1Mask) modifiers |= XEMACS_MOD_BUTTON1; + if (ev->state & Button2Mask) modifiers |= XEMACS_MOD_BUTTON2; + if (ev->state & Button3Mask) modifiers |= XEMACS_MOD_BUTTON3; + if (ev->state & Button4Mask) modifiers |= XEMACS_MOD_BUTTON4; + if (ev->state & Button5Mask) modifiers |= XEMACS_MOD_BUTTON5; /* Currently ignores Shift_Lock but probably shouldn't (but it definitely should ignore Caps_Lock). */ emacs_event->event.motion.modifiers = modifiers; @@ -1124,7 +1343,9 @@ x_event_to_emacs_event (XEvent *x_event, struct Lisp_Event *emacs_event) #ifdef HAVE_OFFIX_DND if (DndIsDropMessage(x_event)) { - unsigned int state, modifiers = 0, button=0; + unsigned int state; + int modifiers = 0; + unsigned int button=0; struct frame *frame = x_any_window_to_frame (d, ev->window); Extbyte *data; unsigned long size, dtype; @@ -1132,10 +1353,10 @@ x_event_to_emacs_event (XEvent *x_event, struct Lisp_Event *emacs_event) Lisp_Object l_dndlist = Qnil, l_item = Qnil; struct gcpro gcpro1, gcpro2, gcpro3, gcpro4; - GCPRO4 (l_type, l_data, l_dndlist, l_item); - if (! frame) return 0; /* not for us */ + + GCPRO4 (l_type, l_data, l_dndlist, l_item); XSETFRAME (emacs_event->channel, frame); emacs_event->event_type = misc_user_event; @@ -1143,12 +1364,17 @@ x_event_to_emacs_event (XEvent *x_event, struct Lisp_Event *emacs_event) state=DndDragButtons(x_event); - if (state & ShiftMask) modifiers |= MOD_SHIFT; - if (state & ControlMask) modifiers |= MOD_CONTROL; - if (state & xd->MetaMask) modifiers |= MOD_META; - if (state & xd->SuperMask) modifiers |= MOD_SUPER; - if (state & xd->HyperMask) modifiers |= MOD_HYPER; - if (state & xd->AltMask) modifiers |= MOD_ALT; + if (state & ShiftMask) modifiers |= XEMACS_MOD_SHIFT; + if (state & ControlMask) modifiers |= XEMACS_MOD_CONTROL; + if (state & xd->MetaMask) modifiers |= XEMACS_MOD_META; + if (state & xd->SuperMask) modifiers |= XEMACS_MOD_SUPER; + if (state & xd->HyperMask) modifiers |= XEMACS_MOD_HYPER; + if (state & xd->AltMask) modifiers |= XEMACS_MOD_ALT; + if (state & Button1Mask) modifiers |= XEMACS_MOD_BUTTON1; + if (state & Button2Mask) modifiers |= XEMACS_MOD_BUTTON2; + if (state & Button3Mask) modifiers |= XEMACS_MOD_BUTTON3; + if (state & Button4Mask) modifiers |= XEMACS_MOD_BUTTON4; + if (state & Button5Mask) modifiers |= XEMACS_MOD_BUTTON5; if (state & Button5Mask) button = Button5; if (state & Button4Mask) button = Button4; @@ -1191,7 +1417,7 @@ x_event_to_emacs_event (XEvent *x_event, struct Lisp_Event *emacs_event) make_string ((Bufbyte *)"8bit", 4), make_ext_string ((Extbyte *)data, strlen((char *)data), - FORMAT_CTEXT) ) ); + Qctext) ) ); break; case DndMIME: /* we have to parse this in some way to extract @@ -1204,7 +1430,7 @@ x_event_to_emacs_event (XEvent *x_event, struct Lisp_Event *emacs_event) l_type = Qdragdrop_MIME; l_dndlist = list1 ( make_ext_string ((Extbyte *)data, strlen((char *)data), - FORMAT_BINARY) ); + Qbinary) ); break; case DndFile: case DndDir: @@ -1225,7 +1451,7 @@ x_event_to_emacs_event (XEvent *x_event, struct Lisp_Event *emacs_event) and escaping again will break them (cause % is unsave) */ l_dndlist = list1 ( make_ext_string ((Extbyte *)data, strlen ((char *)data), - FORMAT_FILENAME) ); + Qfile_name) ); l_type = Qdragdrop_URL; break; default: /* Unknown, RawData and any other type */ @@ -1233,7 +1459,7 @@ x_event_to_emacs_event (XEvent *x_event, struct Lisp_Event *emacs_event) make_string ((Bufbyte *)"8bit", 4), make_ext_string ((Extbyte *)data, size, - FORMAT_BINARY) ) ); + Qbinary) ) ); l_type = Qdragdrop_MIME; break; } @@ -1282,6 +1508,7 @@ x_event_to_emacs_event (XEvent *x_event, struct Lisp_Event *emacs_event) case FocusIn: case FocusOut: FROB(xfocus, window); break; case VisibilityNotify: FROB(xvisibility, window); break; + case CreateNotify: FROB(xcreatewindow, window); break; default: w = x_event->xany.window; *x_event_copy = *x_event; @@ -1312,11 +1539,10 @@ static void handle_focus_event_1 (struct frame *f, int in_p) { #if XtSpecificationRelease > 5 - Widget focus_widget = XtGetKeyboardFocusWidget (FRAME_X_TEXT_WIDGET (f)); + widget_with_focus = XtGetKeyboardFocusWidget (FRAME_X_TEXT_WIDGET (f)); #endif -#if defined(HAVE_XIM) && defined(XIM_XLIB) - if (FRAME_X_XIC(f)) - XIM_focus_event (f, in_p); +#ifdef HAVE_XIM + XIM_focus_event (f, in_p); #endif /* HAVE_XIM */ /* On focus change, clear all memory of sticky modifiers @@ -1334,21 +1560,27 @@ handle_focus_event_1 (struct frame *f, int in_p) Unfortunately native widgets break the model because they grab the keyboard focus and nothing sets it back again. I cannot find any reasonable way to do this elsewhere so we assert here that - the keybpard focus is on the emacs text widget. Menus and dialogs + the keyboard focus is on the emacs text widget. Menus and dialogs do this in their selection callback, but we don't want that since a button having focus is legitimate. An edit field having focus - is mandatory. Weirdly you get a FocusOut event when you glick in - a widget-glyph but you don't get a correspondng FocusIn when you + is mandatory. Weirdly you get a FocusOut event when you click in + a widget-glyph but you don't get a corresponding FocusIn when you click in the frame. Why is this? */ - if (in_p -#if XtSpecificationRelease > 5 - && FRAME_X_TEXT_WIDGET (f) != focus_widget + if (in_p +#if XtSpecificationRelease > 5 + && FRAME_X_TEXT_WIDGET (f) != widget_with_focus #endif ) { lw_set_keyboard_focus (FRAME_X_SHELL_WIDGET (f), FRAME_X_TEXT_WIDGET (f)); } + + /* We have the focus now. See comment in + emacs_Xt_handle_widget_losing_focus (). */ + if (in_p) + widget_with_focus = NULL; + /* do the generic event-stream stuff. */ { Lisp_Object frm; @@ -1365,6 +1597,23 @@ handle_focus_event_1 (struct frame *f, int in_p) } } +/* The idea here is that when a widget glyph gets unmapped we don't + want the focus to stay with it if it has focus - because it may + well just get deleted next andthen we have lost the focus until the + user does something. So handle_focus_event_1 records the widget + with keyboard focus when FocusOut is processed, and then, when a + widget gets unmapped, it calls this function to restore focus if + appropriate. */ +void emacs_Xt_handle_widget_losing_focus (struct frame* f, Widget losing_widget); +void +emacs_Xt_handle_widget_losing_focus (struct frame* f, Widget losing_widget) +{ + if (losing_widget == widget_with_focus) + { + handle_focus_event_1 (f, 1); + } +} + /* This is called from the external-widget code */ void emacs_Xt_handle_focus_event (XEvent *event); @@ -1541,8 +1790,62 @@ handle_client_message (struct frame *f, XEvent *event) } } +/* #### I'm struggling to understand how the X event loop really works. + Here is the problem: + + When widgets get mapped / changed etc the actual display updates + are done asynchronously via X events being processed - this + normally happens when XtAppProcessEvent() gets called. However, if + we are executing lisp code or even doing redisplay we won't + necessarily process X events for a very long time. This has the + effect of widgets only getting updated when XEmacs only goes into + idle, or some other event causes processing of the X event queue. + + XtAppProcessEvent can get called from the following places: + + emacs_Xt_next_event () - this is normal event processing, almost + any non-X event will take precedence and this means that we + cannot rely on it to do the right thing at the right time for + widget display. + + drain_X_queue () - this happens when SIGIO gets tripped, + processing the event queue allows C-g to be checked for. It gets + called from emacs_Xt_event_pending_p (). + + In order to solve this I have tried introducing a list primitive - + dispatch-non-command-events - which forces processing of X events + related to display. Unfortunately this has a number of problems, + one is that it is possible for event_stream_event_pending_p to + block for ever if there isn't actually an event. I guess this can + happen if we drop the synthetic event for reason. It also relies on + SIGIO processing which makes things rather fragile. + + People have seen behaviour whereby XEmacs blocks until you move the + mouse. This seems to indicate that dispatch-non-command-events is + blocking. It may be that in a SIGIO world forcing SIGIO processing + does the wrong thing. +*/ +static void +emacs_Xt_force_event_pending (struct frame* f) +{ + XEvent event; + + Display* dpy = DEVICE_X_DISPLAY (XDEVICE (FRAME_DEVICE (f))); + event.xclient.type = ClientMessage; + event.xclient.display = dpy; + event.xclient.message_type = XInternAtom (dpy, "BumpQueue", False); + event.xclient.format = 32; + event.xclient.window = 0; + + /* Send the drop message */ + XSendEvent(dpy, XtWindow (FRAME_X_SHELL_WIDGET (f)), + True, NoEventMask, &event); + /* We rely on SIGIO and friends to realise we have generated an + event. */ +} + static void -emacs_Xt_handle_magic_event (struct Lisp_Event *emacs_event) +emacs_Xt_handle_magic_event (Lisp_Event *emacs_event) { /* This function can GC */ XEvent *event = &emacs_event->event.magic.underlying_x_event; @@ -1570,8 +1873,13 @@ emacs_Xt_handle_magic_event (struct Lisp_Event *emacs_event) break; case Expose: - x_redraw_exposed_area (f, event->xexpose.x, event->xexpose.y, - event->xexpose.width, event->xexpose.height); + if (!check_for_ignored_expose (f, event->xexpose.x, event->xexpose.y, + event->xexpose.width, event->xexpose.height) + && + !find_matching_subwindow (f, event->xexpose.x, event->xexpose.y, + event->xexpose.width, event->xexpose.height)) + x_redraw_exposed_area (f, event->xexpose.x, event->xexpose.y, + event->xexpose.width, event->xexpose.height); break; case GraphicsExpose: /* This occurs when an XCopyArea's source area was @@ -1644,12 +1952,14 @@ emacs_Xt_handle_magic_event (struct Lisp_Event *emacs_event) break; case ConfigureNotify: -#if defined(HAVE_XIM) && defined(XIM_XLIB) - if (FRAME_X_XIC(f)) - XIM_SetGeometry (f); +#ifdef HAVE_XIM + XIM_SetGeometry (f); #endif break; + case CreateNotify: + break; + default: break; } @@ -1665,14 +1975,14 @@ static int timeout_id_tick; /* Xt interval id's might not fit into an int (they're pointers, as it happens), so we need to provide a conversion list. */ -struct Xt_timeout +static struct Xt_timeout { int id; XtIntervalId interval_id; struct Xt_timeout *next; } *pending_timeouts, *completed_timeouts; -struct Xt_timeout_blocktype +static struct Xt_timeout_blocktype { Blocktype_declare (struct Xt_timeout); } *the_Xt_timeout_blocktype; @@ -1779,7 +2089,7 @@ emacs_Xt_remove_timeout (int id) } static void -Xt_timeout_to_emacs_event (struct Lisp_Event *emacs_event) +Xt_timeout_to_emacs_event (Lisp_Event *emacs_event) { struct Xt_timeout *timeout = completed_timeouts; assert (timeout); @@ -1946,7 +2256,7 @@ unselect_filedesc (int fd) } static void -emacs_Xt_select_process (struct Lisp_Process *p) +emacs_Xt_select_process (Lisp_Process *p) { Lisp_Object process; int infd = event_stream_unixoid_select_process (p); @@ -1956,7 +2266,7 @@ emacs_Xt_select_process (struct Lisp_Process *p) } static void -emacs_Xt_unselect_process (struct Lisp_Process *p) +emacs_Xt_unselect_process (Lisp_Process *p) { int infd = event_stream_unixoid_unselect_process (p); @@ -1985,7 +2295,7 @@ emacs_Xt_delete_stream_pair (Lisp_Object instream, Lisp_Object outstream) If we've still got pointers to it in this file, we're gonna lose hard. */ void -debug_process_finalization (struct Lisp_Process *p) +debug_process_finalization (Lisp_Process *p) { #if 0 /* #### */ int i; @@ -2005,25 +2315,27 @@ debug_process_finalization (struct Lisp_Process *p) } static void -Xt_process_to_emacs_event (struct Lisp_Event *emacs_event) +Xt_process_to_emacs_event (Lisp_Event *emacs_event) { int i; - Lisp_Object process; assert (process_events_occurred > 0); + for (i = 0; i < MAXDESC; i++) { - process = filedesc_with_input[i]; + Lisp_Object process = filedesc_with_input[i]; if (PROCESSP (process)) - break; + { + filedesc_with_input[i] = Qnil; + process_events_occurred--; + /* process events have nil as channel */ + emacs_event->event_type = process_event; + emacs_event->timestamp = 0; /* #### */ + emacs_event->event.process.process = process; + return; + } } - assert (i < MAXDESC); - filedesc_with_input[i] = Qnil; - process_events_occurred--; - /* process events have nil as channel */ - emacs_event->event_type = process_event; - emacs_event->timestamp = 0; /* #### */ - emacs_event->event.process.process = process; + abort (); } static void @@ -2031,9 +2343,6 @@ emacs_Xt_select_console (struct console *con) { Lisp_Object console; int infd; -#ifdef HAVE_GPM - int mousefd; -#endif if (CONSOLE_X_P (con)) return; /* X consoles are automatically selected for when we @@ -2041,22 +2350,6 @@ emacs_Xt_select_console (struct console *con) infd = event_stream_unixoid_select_console (con); XSETCONSOLE (console, con); select_filedesc (infd, console); -#ifdef HAVE_GPM - /* On a stream device (ie: noninteractive), bad things can happen. */ - if (EQ (CONSOLE_TYPE (con), Qtty)) { - mousefd = CONSOLE_TTY_MOUSE_FD (con); - /* We check filedesc_to_what_closure[fd] here because if you run - ** XEmacs from a TTY, it will fire up GPM, select the mouse fd, then - ** if you run gnuattach to connect to another TTY, it will fire up - ** GPM again, and try to reselect the mouse fd. GPM uses the same - ** fd for every connection apparently, and select_filedesc will - ** fail its assertion if we try to select it twice. - */ - if ((mousefd >= 0) && !filedesc_to_what_closure[mousefd]) { - select_filedesc (mousefd, console); - } - } -#endif } static void @@ -2064,9 +2357,6 @@ emacs_Xt_unselect_console (struct console *con) { Lisp_Object console; int infd; -#ifdef HAVE_GPM - int mousefd; -#endif if (CONSOLE_X_P (con)) return; /* X consoles are automatically selected for when we @@ -2074,15 +2364,6 @@ emacs_Xt_unselect_console (struct console *con) infd = event_stream_unixoid_unselect_console (con); XSETCONSOLE (console, con); unselect_filedesc (infd); -#ifdef HAVE_GPM - /* On a stream device (ie: noninteractive), bad things can happen. */ - if (EQ (CONSOLE_TYPE (con), Qtty)) { - mousefd = CONSOLE_TTY_MOUSE_FD (con); - if (mousefd >= 0) { - unselect_filedesc (mousefd); - } - } -#endif } /* read an event from a tty, if one is available. Returns non-zero @@ -2094,7 +2375,7 @@ emacs_Xt_unselect_console (struct console *con) to be deleted.) */ static int -Xt_tty_to_emacs_event (struct Lisp_Event *emacs_event) +Xt_tty_to_emacs_event (Lisp_Event *emacs_event) { int i; @@ -2140,12 +2421,12 @@ describe_event_window (Window window, Display *display) char *buf = alloca_array (char, XSTRING_LENGTH (f->name) + 4); sprintf (buf, " \"%s\"", XSTRING_DATA (f->name)); write_string_to_stdio_stream (stderr, 0, (Bufbyte *) buf, 0, - strlen (buf), FORMAT_TERMINAL); + strlen (buf), Qterminal, 1); } stderr_out ("\n"); } -static CONST char * +static const char * XEvent_mode_to_string (int mode) { switch (mode) @@ -2158,7 +2439,7 @@ XEvent_mode_to_string (int mode) } } -static CONST char * +static const char * XEvent_detail_to_string (int detail) { switch (detail) @@ -2174,7 +2455,7 @@ XEvent_detail_to_string (int detail) } } -static CONST char * +static const char * XEvent_visibility_to_string (int state) { switch (state) @@ -2236,7 +2517,7 @@ describe_event (XEvent *event) break; case Expose: - if (x_debug_events > 1) + if (debug_x_events > 1) { XExposeEvent *ev = &event->xexpose; describe_event_window (ev->window, ev->display); @@ -2249,7 +2530,7 @@ describe_event (XEvent *event) break; case GraphicsExpose: - if (x_debug_events > 1) + if (debug_x_events > 1) { XGraphicsExposeEvent *ev = &event->xgraphicsexpose; describe_event_window (ev->drawable, ev->display); @@ -2266,7 +2547,7 @@ describe_event (XEvent *event) case EnterNotify: case LeaveNotify: - if (x_debug_events > 1) + if (debug_x_events > 1) { XCrossingEvent *ev = &event->xcrossing; describe_event_window (ev->window, ev->display); @@ -2287,7 +2568,7 @@ describe_event (XEvent *event) break; case ConfigureNotify: - if (x_debug_events > 1) + if (debug_x_events > 1) { XConfigureEvent *ev = &event->xconfigure; describe_event_window (ev->window, ev->display); @@ -2301,7 +2582,7 @@ describe_event (XEvent *event) break; case VisibilityNotify: - if (x_debug_events > 1) + if (debug_x_events > 1) { XVisibilityEvent *ev = &event->xvisibility; describe_event_window (ev->window, ev->display); @@ -2343,7 +2624,7 @@ describe_event (XEvent *event) static Lisp_Object dispatch_event_queue, dispatch_event_queue_tail; -static void +void enqueue_Xt_dispatch_event (Lisp_Object event) { enqueue_event (event, &dispatch_event_queue, &dispatch_event_queue_tail); @@ -2379,7 +2660,7 @@ signal_special_Xt_user_event (Lisp_Object channel, Lisp_Object function, } static void -emacs_Xt_next_event (struct Lisp_Event *emacs_event) +emacs_Xt_next_event (Lisp_Event *emacs_event) { we_didnt_get_an_event: @@ -2464,7 +2745,7 @@ emacs_Xt_event_handler (Widget wid /* unused */, Lisp_Object emacs_event = Fmake_event (Qnil, Qnil); #ifdef DEBUG_XEMACS - if (x_debug_events > 0) + if (debug_x_events > 0) { describe_event (event); } @@ -2730,7 +3011,11 @@ emacs_Xt_event_pending_p (int user_p) /* quit_check_signal_tick_count is volatile so try to avoid race conditions by using a temporary variable */ tick_count_val = quit_check_signal_tick_count; - if (last_quit_check_signal_tick_count != tick_count_val) + if (last_quit_check_signal_tick_count != tick_count_val +#if !defined (SIGIO) || defined (CYGWIN) + || (XtIMXEvent & XtAppPending (Xt_app_con)) +#endif + ) { last_quit_check_signal_tick_count = tick_count_val; @@ -2748,6 +3033,21 @@ emacs_Xt_event_pending_p (int user_p) return 0; } +static int +emacs_Xt_current_event_timestamp (struct console *c) +{ + /* semi-yuck. */ + Lisp_Object devs = CONSOLE_DEVICE_LIST (c); + + if (NILP (devs)) + return 0; + else + { + struct device *d = XDEVICE (XCAR (devs)); + return DEVICE_X_LAST_SERVER_TIMESTAMP (d); + } +} + /************************************************************************/ /* replacement for standard string-to-pixel converter */ @@ -2764,10 +3064,10 @@ emacs_Xt_event_pending_p (int user_p) the '#if 0'. Note, however, that I got "unknown structure" errors when I tried this. */ XtConvertArgRec Const colorConvertArgs[] = { - {XtWidgetBaseOffset, (XtPointer)XtOffsetOf(WidgetRec, core.screen), - sizeof(Screen *)}, - {XtWidgetBaseOffset, (XtPointer)XtOffsetOf(WidgetRec, core.colormap), - sizeof(Colormap)} + { XtWidgetBaseOffset, (XtPointer)XtOffsetOf(WidgetRec, core.screen), + sizeof (Screen *) }, + { XtWidgetBaseOffset, (XtPointer)XtOffsetOf(WidgetRec, core.colormap), + sizeof (Colormap) } }; #endif @@ -2845,9 +3145,9 @@ Boolean EmacsXtCvtStringToPixel ( if ((d = get_device_from_display_1(dpy))) { visual = DEVICE_X_VISUAL(d); if (colormap != DEVICE_X_COLORMAP(d)) { - XtAppWarningMsg(the_app_con, "wierdColormap", "cvtStringToPixel", + XtAppWarningMsg(the_app_con, "weirdColormap", "cvtStringToPixel", "XtToolkitWarning", - "The colormap passed to cvtStringToPixel doesn't match the one registerd to the device.\n", + "The colormap passed to cvtStringToPixel doesn't match the one registered to the device.\n", NULL, 0); status = XAllocNamedColor(dpy, colormap, (char*)str, &screenColor, &exactColor); } else { @@ -2909,6 +3209,42 @@ static void EmacsFreePixel ( /************************************************************************/ +/* handle focus changes for native widgets */ +/************************************************************************/ +static void +emacs_Xt_event_widget_focus_in (Widget w, + XEvent *event, + String *params, + Cardinal *num_params) +{ + struct frame* f = + x_any_widget_or_parent_to_frame (get_device_from_display (event->xany.display), w); + + XtSetKeyboardFocus (FRAME_X_SHELL_WIDGET (f), w); +} + +static void +emacs_Xt_event_widget_focus_out (Widget w, + XEvent *event, + String *params, + Cardinal *num_params) +{ +} + +static XtActionsRec widgetActionsList[] = +{ + {"widget-focus-in", emacs_Xt_event_widget_focus_in }, + {"widget-focus-out", emacs_Xt_event_widget_focus_out }, +}; + +static void +emacs_Xt_event_add_widget_actions (XtAppContext ctx) +{ + XtAppAddActions (ctx, widgetActionsList, 2); +} + + +/************************************************************************/ /* initialization */ /************************************************************************/ @@ -2917,20 +3253,15 @@ syms_of_event_Xt (void) { defsymbol (&Qkey_mapping, "key-mapping"); defsymbol (&Qsans_modifiers, "sans-modifiers"); + defsymbol (&Qself_insert_command, "self-insert-command"); } void -vars_of_event_Xt (void) +reinit_vars_of_event_Xt (void) { - dispatch_event_queue = Qnil; - staticpro (&dispatch_event_queue); - dispatch_event_queue_tail = Qnil; - - /* this function only makes safe calls */ - init_what_input_once (); - Xt_event_stream = xnew (struct event_stream); Xt_event_stream->event_pending_p = emacs_Xt_event_pending_p; + Xt_event_stream->force_event_pending = emacs_Xt_force_event_pending; Xt_event_stream->next_event_cb = emacs_Xt_next_event; Xt_event_stream->handle_magic_event_cb = emacs_Xt_handle_magic_event; Xt_event_stream->add_timeout_cb = emacs_Xt_add_timeout; @@ -2942,15 +3273,26 @@ vars_of_event_Xt (void) Xt_event_stream->quit_p_cb = emacs_Xt_quit_p; Xt_event_stream->create_stream_pair_cb = emacs_Xt_create_stream_pair; Xt_event_stream->delete_stream_pair_cb = emacs_Xt_delete_stream_pair; + Xt_event_stream->current_event_timestamp_cb = + emacs_Xt_current_event_timestamp; - DEFVAR_BOOL ("modifier-keys-are-sticky", &modifier_keys_are_sticky /* -*Non-nil makes modifier keys sticky. -This means that you can release the modifier key before pressing down -the key that you wish to be modified. Although this is non-standard -behavior, it is recommended because it reduces the strain on your hand, -thus reducing the incidence of the dreaded Emacs-pinky syndrome. -*/ ); - modifier_keys_are_sticky = 0; + the_Xt_timeout_blocktype = Blocktype_new (struct Xt_timeout_blocktype); + + last_quit_check_signal_tick_count = 0; + + /* this function only makes safe calls */ + init_what_input_once (); +} + +void +vars_of_event_Xt (void) +{ + reinit_vars_of_event_Xt (); + + dispatch_event_queue = Qnil; + staticpro (&dispatch_event_queue); + dispatch_event_queue_tail = Qnil; + dump_add_root_object (&dispatch_event_queue_tail); DEFVAR_BOOL ("x-allow-sendevents", &x_allow_sendevents /* *Non-nil means to allow synthetic events. Nil means they are ignored. @@ -2959,19 +3301,15 @@ Beware: allowing emacs to process SendEvents opens a big security hole. x_allow_sendevents = 0; #ifdef DEBUG_XEMACS - DEFVAR_INT ("x-debug-events", &x_debug_events /* + DEFVAR_INT ("debug-x-events", &debug_x_events /* If non-zero, display debug information about X events that XEmacs sees. Information is displayed on stderr. Currently defined values are: 1 == non-verbose output 2 == verbose output */ ); - x_debug_events = 0; + debug_x_events = 0; #endif - - the_Xt_timeout_blocktype = Blocktype_new (struct Xt_timeout_blocktype); - - last_quit_check_signal_tick_count = 0; } /* This mess is a hack that patches the shell widget to treat visual inheritance @@ -3013,12 +3351,12 @@ init_event_Xt_late (void) /* called when already initialized */ Xt_app_con = XtCreateApplicationContext (); XtAppSetFallbackResources (Xt_app_con, (String *) x_fallback_resources); - /* In xselect.c */ + /* In select-x.c */ x_selection_timeout = (XtAppGetSelectionTimeout (Xt_app_con) / 1000); XSetErrorHandler (x_error_handler); XSetIOErrorHandler (x_IO_error_handler); -#ifndef WINDOWSNT +#ifndef WIN32_NATIVE XtAppAddInput (Xt_app_con, signal_event_pipe[0], (XtPointer) (XtInputReadMask /* | XtInputExceptMask */), Xt_what_callback, 0); @@ -3035,6 +3373,8 @@ init_event_Xt_late (void) /* called when already initialized */ NULL, 0, XtCacheByDisplay, EmacsFreeXIMStyles); #endif /* XIM_XLIB */ + /* Add extra actions to native widgets to handle focus and friends. */ + emacs_Xt_event_add_widget_actions (Xt_app_con); /* insert the visual inheritance patch/hack described above */ orig_shell_init_proc = shellClassRec.core_class.initialize;