#include "blocktype.h"
#include "buffer.h"
-#include "commands.h"
#include "console.h"
#include "console-tty.h"
#include "events.h"
#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);
+void enqueue_focus_event (Widget wants_it, Lisp_Object frame, int in_p);
+static void handle_focus_event_1 (struct frame *f, int in_p);
+static void handle_focus_event_2 (Window w, struct frame *f, int in_p);
static struct event_stream *Xt_event_stream;
/* 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
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);
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)
{
Display *display = DEVICE_X_DISPLAY (d);
struct x_device *xd = DEVICE_X_DATA (d);
KeySym *keysym, *keysym_end;
- Lisp_Object hashtable;
+ Lisp_Object hash_table;
int key_code_count, keysyms_per_code;
if (xd->x_keysym_map)
XGetKeyboardMapping (display, xd->x_keysym_map_min_code, key_code_count,
&xd->x_keysym_map_keysyms_per_code);
- hashtable = xd->x_keysym_map_hashtable;
- if (HASHTABLEP (hashtable))
- Fclrhash (hashtable);
+ hash_table = xd->x_keysym_map_hash_table;
+ if (HASH_TABLEP (hash_table))
+ Fclrhash (hash_table);
else
- xd->x_keysym_map_hashtable = hashtable =
- make_lisp_hashtable (128, HASHTABLE_NONWEAK, HASHTABLE_EQUAL);
+ xd->x_keysym_map_hash_table = hash_table =
+ make_lisp_hash_table (128, HASH_TABLE_NON_WEAK, HASH_TABLE_EQUAL);
for (keysym = xd->x_keysym_map,
keysyms_per_code = xd->x_keysym_map_keysyms_per_code,
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, hashtable);
- Fputhash (sym, Qsans_modifiers, hashtable);
- }
- }
+ 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, hashtable, Qnil)))
- {
- Fputhash (build_string (name), Qt, hashtable);
- Fputhash (sym, Qt, hashtable);
- }
- }
+ x_has_keysym (keysym[j], hash_table, 1);
}
}
}
-static CONST char *
+static const char *
index_to_name (int indice)
{
switch (indice)
xd->lock_interpretation = 0;
if (xd->x_modifier_keymap)
- XFreeModifiermap (xd->x_modifier_keymap);
+ {
+ XFreeModifiermap (xd->x_modifier_keymap);
+ /* Set it to NULL in case we receive two MappingModifier events in a
+ row, and the second is processed during some CHECK_QUITs within
+ x_reset_key_mapping. If that happens, XFreeModifierMap will be
+ called twice on the same map, and we crash. */
+ xd->x_modifier_keymap = NULL;
+ }
x_reset_key_mapping (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;
x_init_modifier_mapping (struct device *d)
{
struct x_device *xd = DEVICE_X_DATA (d);
- xd->x_keysym_map_hashtable = Qnil;
+ xd->x_keysym_map_hash_table = Qnil;
xd->x_keysym_map = NULL;
xd->x_modifier_keymap = NULL;
x_reset_modifier_mapping (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;
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 */
{
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) \
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++)
emacs_Xt_mapping_action (Widget w, XEvent* event)
{
struct device *d = get_device_from_display (event->xany.display);
+
+ if (DEVICE_X_BEING_DELETED (d))
+ return;
#if 0
/* nyet. Now this is handled by Xt. */
XRefreshKeyboardMapping (&event->xmapping);
case MappingKeyboard: x_reset_key_mapping (d); break;
case MappingModifier: x_reset_modifier_mapping (d); break;
case MappingPointer: /* Do something here? */ break;
- default: abort();
+ default: ABORT();
}
}
#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;
than passing in 0) to avoid crashes on German IRIX */
char dummy[256];
XLookupString (event, dummy, 200, &keysym, 0);
- return x_keysym_to_emacs_keysym (keysym, simple_p);
+ return (IsModifierKey (keysym) || keysym == XK_Mode_switch )
+ ? Qnil : x_keysym_to_emacs_keysym (keysym, simple_p);
}
#endif /* ! XIM_MOTIF */
len = XmImMbLookupString (XtWindowToWidget (event->display, event->window),
event, bufptr, bufsiz, &keysym, &status);
#else /* XIM_XLIB */
- len = XmbLookupString (xic, event, bufptr, bufsiz, &keysym, &status);
+ if (xic)
+ len = XmbLookupString (xic, event, bufptr, bufsiz, &keysym, &status);
#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)
{
case XLookupKeySym:
case XLookupBoth:
- return x_keysym_to_emacs_keysym (keysym, simple_p);
+ return (IsModifierKey (keysym) || keysym == XK_Mode_switch )
+ ? Qnil : x_keysym_to_emacs_keysym (keysym, simple_p);
case XLookupChars:
{
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));
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;
}
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);
struct x_device *xd = DEVICE_X_DATA (d);
+ if (DEVICE_X_BEING_DELETED (d))
+ /* #### Uh, is this 0 correct? */
+ return 0;
+
set_last_server_timestamp (d, x_event);
switch (x_event->type)
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 =
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
lock_p = *state & LockMask;
if (shift_p || lock_p)
- modifiers |= MOD_SHIFT;
+ modifiers |= XEMACS_MOD_SHIFT;
if (key_event_p)
{
Lisp_Object keysym;
XKeyEvent *ev = &x_event->xkey;
- KeyCode keycode = ev->keycode;
-
- if (x_key_is_modifier_p (keycode, d)) /* it's a modifier key */
- return 0;
-
/* This used to compute the frame from the given X window and
store it here, but we really don't care about the frame. */
emacs_event->channel = DEVICE_CONSOLE (d);
keysym = x_to_emacs_keysym (&x_event->xkey, 0);
- /* If the emacs keysym is nil, then that means that the
- X keysym was NoSymbol, which probably means that
- we're in the midst of reading a Multi_key sequence,
- or a "dead" key prefix, or XIM input. Ignore it. */
+ /* If the emacs keysym is nil, then that means that the X
+ keysym was either a Modifier or NoSymbol, which
+ probably means that we're in the midst of reading a
+ Multi_key sequence, or a "dead" key prefix, or XIM
+ input. Ignore it. */
if (NILP (keysym))
return 0;
! (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
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;
{
XButtonEvent *ev = &x_event->xbutton;
struct frame *frame = x_window_to_frame (d, ev->window);
+
if (! frame)
return 0; /* not for us */
XSETFRAME (emacs_event->channel, frame);
emacs_event->event.button.button = ev->button;
emacs_event->event.button.x = ev->x;
emacs_event->event.button.y = ev->y;
-
+ /* because we don't seem to get a FocusIn event for button clicks
+ when a widget-glyph is selected we will assume that we want the
+ focus if a button gets pressed. */
+ if (x_event->type == ButtonPress)
+ handle_focus_event_1 (frame, 1);
}
}
break;
{
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)
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;
#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;
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;
emacs_event->timestamp = DEVICE_X_LAST_SERVER_TIMESTAMP (d);
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;
l_type = Qdragdrop_MIME;
l_dndlist = list1 ( list3 ( list1 ( make_string ((Bufbyte *)"text/plain", 10) ),
make_string ((Bufbyte *)"8bit", 4),
- make_ext_string ((Extbyte *)data,
+ make_ext_string ((Extbyte *)data,
strlen((char *)data),
- FORMAT_CTEXT) ) );
+ Qctext) ) );
break;
case DndMIME:
/* we have to parse this in some way to extract
l_type = Qdragdrop_MIME;
l_dndlist = list1 ( make_ext_string ((Extbyte *)data,
strlen((char *)data),
- FORMAT_BINARY) );
+ Qbinary) );
break;
case DndFile:
case DndDir:
case DndLink:
case DndExe:
{
- char *hurl = dnd_url_hexify_string (data, "file:");
+ char *hurl = dnd_url_hexify_string ((char *) data, "file:");
l_dndlist = list1 ( make_string ((Bufbyte *)hurl,
strlen (hurl)) );
case DndURL:
/* as it is a real URL it should already be escaped
and escaping again will break them (cause % is unsave) */
- l_dndlist = list1 ( make_ext_string ((Extbyte *)data,
+ 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 */
make_string ((Bufbyte *)"8bit", 4),
make_ext_string ((Extbyte *)data,
size,
- FORMAT_BINARY) ) );
+ Qbinary) ) );
l_type = Qdragdrop_MIME;
break;
}
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;
static void
handle_focus_event_1 (struct frame *f, int in_p)
{
+ handle_focus_event_2 (XtWindow (FRAME_X_TEXT_WIDGET (f)), f, in_p);
+}
+
+static void
+handle_focus_event_2 (Window win, struct frame *f, int in_p)
+{
+ /* Although this treats focus differently for all widgets (including
+ the frame) it seems to work ok. */
+ Widget needs_it = XtWindowToWidget (FRAME_X_DISPLAY (f), win);
+
+#if XtSpecificationRelease > 5
+ widget_with_focus = XtGetKeyboardFocusWidget (FRAME_X_TEXT_WIDGET (f));
+#endif
#ifdef HAVE_XIM
XIM_focus_event (f, in_p);
#endif /* HAVE_XIM */
Actually, we half handle it: we handle it as far as changing the
box cursor for redisplay, but we don't call any hooks or do any
select-frame stuff until after the sit-for.
- */
+
+ 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 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 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
+ && needs_it != widget_with_focus
+#endif
+ )
+ {
+ lw_set_keyboard_focus (FRAME_X_SHELL_WIDGET (f), needs_it);
+ }
+
+ /* If we are focusing on a native widget then record and exit. */
+ if (needs_it != FRAME_X_TEXT_WIDGET (f)) {
+ widget_with_focus = needs_it;
+ return;
+ }
+
+ /* 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;
Lisp_Object conser;
}
}
+/* Create a synthetic X focus event. */
+void
+enqueue_focus_event (Widget wants_it, Lisp_Object frame, int in_p)
+{
+ Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
+ Lisp_Event *ev = XEVENT (emacs_event);
+ XEvent *x_event = &ev->event.magic.underlying_x_event;
+
+ x_event->type = in_p ? FocusIn : FocusOut;
+ x_event->xfocus.window = XtWindow (wants_it);
+
+ ev->channel = frame;
+ ev->event_type = magic_event;
+
+ enqueue_Xt_dispatch_event (emacs_event);
+}
+
+/* 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 and then 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);
void
emacs_Xt_handle_focus_event (XEvent *event)
{
+ struct device *d = get_device_from_display (event->xany.display);
+ struct frame *f;
+
+ if (DEVICE_X_BEING_DELETED (d))
+ return;
+
/*
* It's curious that we're using x_any_window_to_frame() instead
* of x_window_to_frame(). I don't know what the impact of this is.
*/
-
- struct frame *f =
- x_any_window_to_frame (get_device_from_display (event->xany.display),
- event->xfocus.window);
+ f = x_any_window_to_frame (d, event->xfocus.window);
if (!f)
/* focus events are sometimes generated just before
a frame is destroyed. */
/* Bleagh!!!!!! Apparently some window managers (e.g. MWM)
send synthetic MapNotify events when a window is first
- created, EVENT IF IT'S CREATED ICONIFIED OR INVISIBLE.
+ created, EVEN IF IT'S CREATED ICONIFIED OR INVISIBLE.
Or something like that. We initially tried a different
solution below, but that ran into a different window-
manager bug.
}
}
+/* #### 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;
struct frame *f = XFRAME (EVENT_CHANNEL (emacs_event));
- if (!FRAME_LIVE_P (f))
+ if (!FRAME_LIVE_P (f) || DEVICE_X_BEING_DELETED (XDEVICE (FRAME_DEVICE (f))))
return;
switch (event->type)
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
case FocusIn:
case FocusOut:
+
#ifdef EXTERNAL_WIDGET
/* External widget lossage: Ben said:
YUCK. The only way to make focus changes work properly is to
if (FRAME_X_EXTERNAL_WINDOW_P (f))
break;
#endif
- handle_focus_event_1 (f, event->type == FocusIn);
+ handle_focus_event_2 (event->xfocus.window, f, event->type == FocusIn);
break;
case ClientMessage:
handle_client_message (f, event);
break;
- case VisibilityNotify: /* window visiblity has changed */
+ case VisibilityNotify: /* window visibility has changed */
if (event->xvisibility.window == XtWindow (FRAME_X_SHELL_WIDGET (f)))
{
FRAME_X_TOTALLY_VISIBLE_P (f) =
#endif
break;
+ case CreateNotify:
+ break;
+
default:
break;
}
/* 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
+/* pending_timeouts is a set (unordered), implemented as a stack.
+ completed_timeouts* is a queue. */
+static struct Xt_timeout
{
int id;
XtIntervalId interval_id;
struct Xt_timeout *next;
-} *pending_timeouts, *completed_timeouts;
+} *pending_timeouts, *completed_timeouts_head, *completed_timeouts_tail;
-struct Xt_timeout_blocktype
+static struct Xt_timeout_blocktype
{
Blocktype_declare (struct Xt_timeout);
} *the_Xt_timeout_blocktype;
{
struct Xt_timeout *timeout = (struct Xt_timeout *) closure;
struct Xt_timeout *t2 = pending_timeouts;
- /* Remove this one from the list of pending timeouts */
+ /* Remove this one from the set of pending timeouts */
if (t2 == timeout)
pending_timeouts = pending_timeouts->next;
else
assert (t2->next);
t2->next = t2->next->next;
}
- /* Add this one to the list of completed timeouts */
- timeout->next = completed_timeouts;
- completed_timeouts = timeout;
+ /* Add this one to the queue of completed timeouts */
+ timeout->next = NULL;
+ if (completed_timeouts_head)
+ completed_timeouts_tail->next = timeout;
+ else
+ completed_timeouts_head = timeout;
+ completed_timeouts_tail = timeout;
}
static int
struct Xt_timeout *timeout, *t2;
timeout = NULL;
-
+
/* Find the timeout on the list of pending ones, if it's still there. */
if (pending_timeouts)
{
XtRemoveTimeOut (timeout->interval_id);
}
- /* It could be that the Xt call back was already called but we didn't convert
- into an Emacs event yet */
- if (!timeout && completed_timeouts)
+ /* It could be that Xt_timeout_callback was already called but we didn't
+ convert into an Emacs event yet */
+ if (!timeout && completed_timeouts_head)
{
- /* Code duplication! */
- if (id == completed_timeouts->id)
+ /* Thank God for code duplication! */
+ if (id == completed_timeouts_head->id)
{
- timeout = completed_timeouts;
- completed_timeouts = completed_timeouts->next;
+ timeout = completed_timeouts_head;
+ completed_timeouts_head = completed_timeouts_head->next;
+ /* this may not be necessary? */
+ if (!completed_timeouts_head) completed_timeouts_tail = NULL;
}
else
{
- t2 = completed_timeouts;
+ t2 = completed_timeouts_head;
while (t2->next && t2->next->id != id) t2 = t2->next;
- if ( t2->next) /*found it */
+ if (t2->next) /* found it */
{
timeout = t2->next;
t2->next = t2->next->next;
+ if (!t2->next) completed_timeouts_tail = t2;
}
}
}
}
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;
+ struct Xt_timeout *timeout = completed_timeouts_head;
assert (timeout);
- completed_timeouts = completed_timeouts->next;
+ completed_timeouts_head = completed_timeouts_head->next;
+ /* probably unnecessary */
+ if (!completed_timeouts_head) completed_timeouts_tail = NULL;
emacs_event->event_type = timeout_event;
/* timeout events have nil as channel */
emacs_event->timestamp = 0; /* #### wrong!! */
emacs_event->event.timeout.interval_id = timeout->id;
+ emacs_event->event.timeout.function = Qnil;
+ emacs_event->event.timeout.object = Qnil;
Blocktype_free (the_Xt_timeout_blocktype, timeout);
}
}
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);
}
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);
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;
}
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
{
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
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
{
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
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
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;
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)
}
}
-static CONST char *
+static const char *
XEvent_detail_to_string (int detail)
{
switch (detail)
}
}
-static CONST char *
+static const char *
XEvent_visibility_to_string (int state)
{
switch (state)
break;
case Expose:
- if (x_debug_events > 1)
+ if (debug_x_events > 1)
{
XExposeEvent *ev = &event->xexpose;
describe_event_window (ev->window, ev->display);
break;
case GraphicsExpose:
- if (x_debug_events > 1)
+ if (debug_x_events > 1)
{
XGraphicsExposeEvent *ev = &event->xgraphicsexpose;
describe_event_window (ev->drawable, ev->display);
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);
break;
case ConfigureNotify:
- if (x_debug_events > 1)
+ if (debug_x_events > 1)
{
XConfigureEvent *ev = &event->xconfigure;
describe_event_window (ev->window, ev->display);
break;
case VisibilityNotify:
- if (x_debug_events > 1)
+ if (debug_x_events > 1)
{
XVisibilityEvent *ev = &event->xvisibility;
describe_event_window (ev->window, ev->display);
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);
}
static void
-emacs_Xt_next_event (struct Lisp_Event *emacs_event)
+emacs_Xt_next_event (Lisp_Event *emacs_event)
{
we_didnt_get_an_event:
while (NILP (dispatch_event_queue) &&
- !completed_timeouts &&
+ !completed_timeouts_head &&
!fake_event_occurred &&
!process_events_occurred &&
!tty_events_occurred)
if (!Xt_tty_to_emacs_event (emacs_event))
goto we_didnt_get_an_event;
}
- else if (completed_timeouts)
+ else if (completed_timeouts_head)
Xt_timeout_to_emacs_event (emacs_event);
else if (fake_event_occurred)
{
Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
#ifdef DEBUG_XEMACS
- if (x_debug_events > 0)
+ if (debug_x_events > 0)
{
describe_event (event);
}
static void
drain_X_queue (void)
{
+ Lisp_Object devcons, concons;
+ CONSOLE_LOOP (concons)
+ {
+ struct console *con = XCONSOLE (XCAR (concons));
+ if (!con->input_enabled)
+ continue;
+
+ /* sjt sez: Have you tried the loop over devices with XtAppPending(),
+ not XEventsQueued()?
+ Ben Sigelman sez: No.
+ sjt sez: I'm guessing that the reason that your patch "works" is this:
+
+ + struct device* d;
+ + Display* display;
+ + d = XDEVICE (XCAR (devcons));
+ + if (DEVICE_X_P (d) && DEVICE_X_DISPLAY (d)) {
+
+ Ie, if the device goes down, XEmacs detects that and deletes it.
+ Then the if() fails (DEVICE_X_DISPLAY(d) is NULL), and we don't go
+ into the Xlib-of-no-return. If you know different, I'd like to hear
+ about it. ;-)
+
+ These ideas haven't been tested; the code below works for Ben.
+ */
+ CONSOLE_DEVICE_LOOP (devcons, con)
+ {
+ struct device* d;
+ Display* display;
+ d = XDEVICE (XCAR (devcons));
+ if (DEVICE_X_P (d) && DEVICE_X_DISPLAY (d)) {
+ display = DEVICE_X_DISPLAY (d);
+ while (XEventsQueued (display, QueuedAfterReading))
+ XtAppProcessEvent (Xt_app_con, XtIMXEvent);
+ }
+ }
+ }
+ /* This is the old code, before Ben Sigelman's patch. */
+ /*
while (XtAppPending (Xt_app_con) & XtIMXEvent)
XtAppProcessEvent (Xt_app_con, XtIMXEvent);
+ */
}
static int
/* 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;
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);
+ }
+}
+
\f
/************************************************************************/
/* replacement for standard string-to-pixel converter */
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
/* JH: We use this because I think there's a possibility this
is called before the device is properly set up, in which case
- I don't want to abort. */
+ I don't want to ABORT. */
extern struct device *get_device_from_display_1 (Display *dpy);
static
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 {
\f
/************************************************************************/
+/* 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);
+}
+
+\f
+/************************************************************************/
/* initialization */
/************************************************************************/
{
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;
+ 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;
+ Xt_event_stream->remove_timeout_cb = emacs_Xt_remove_timeout;
+ Xt_event_stream->select_console_cb = emacs_Xt_select_console;
+ Xt_event_stream->unselect_console_cb = emacs_Xt_unselect_console;
+ Xt_event_stream->select_process_cb = emacs_Xt_select_process;
+ Xt_event_stream->unselect_process_cb = emacs_Xt_unselect_process;
+ 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;
+
+ 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 ();
+}
- Xt_event_stream = xnew (struct event_stream);
- Xt_event_stream->event_pending_p = emacs_Xt_event_pending_p;
- 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;
- Xt_event_stream->remove_timeout_cb = emacs_Xt_remove_timeout;
- Xt_event_stream->select_console_cb = emacs_Xt_select_console;
- Xt_event_stream->unselect_console_cb = emacs_Xt_unselect_console;
- Xt_event_stream->select_process_cb = emacs_Xt_select_process;
- Xt_event_stream->unselect_process_cb = emacs_Xt_unselect_process;
- 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;
-
- 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;
+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.
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
init_event_Xt_late (void) /* called when already initialized */
{
timeout_id_tick = 1;
- pending_timeouts = 0;
- completed_timeouts = 0;
+ pending_timeouts = NULL;
+ completed_timeouts_head = NULL; /* queue is empty */
+ completed_timeouts_tail = NULL; /* just to be picky */
event_stream = Xt_event_stream;
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);
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;