Mercurial > emacs
diff src/xterm.c @ 49117:f8288cd7d1cd
*** empty log message ***
author | Jan Djärv <jan.h.d@swipnet.se> |
---|---|
date | Wed, 08 Jan 2003 20:06:05 +0000 |
parents | 6b6ac8aa78d2 |
children | 2cbb0b823e83 |
line wrap: on
line diff
--- a/src/xterm.c Wed Jan 08 20:06:05 2003 +0000 +++ b/src/xterm.c Wed Jan 08 20:06:05 2003 +0000 @@ -9934,51 +9934,6 @@ #endif /* not USE_TOOLKIT_SCROLL_BARS */ } -/* This processes Expose events from the menu-bar specific X event - loop in xmenu.c. This allows to redisplay the frame if necessary - when handling menu-bar or pop-up items. */ - -int -process_expose_from_menu (event) - XEvent event; -{ - FRAME_PTR f; - struct x_display_info *dpyinfo; - int frame_exposed_p = 0; - - BLOCK_INPUT; - - dpyinfo = x_display_info_for_display (event.xexpose.display); - f = x_window_to_frame (dpyinfo, event.xexpose.window); - if (f) - { - if (f->async_visible == 0) - { - f->async_visible = 1; - f->async_iconified = 0; - f->output_data.x->has_been_visible = 1; - SET_FRAME_GARBAGED (f); - } - else - { - expose_frame (x_window_to_frame (dpyinfo, event.xexpose.window), - event.xexpose.x, event.xexpose.y, - event.xexpose.width, event.xexpose.height); - frame_exposed_p = 1; - } - } - else - { - struct scroll_bar *bar - = x_window_to_scroll_bar (event.xexpose.window); - - if (bar) - x_scroll_bar_expose (bar, &event); - } - - UNBLOCK_INPUT; - return frame_exposed_p; -} /* Define a queue to save up SelectionRequest events for later handling. */ @@ -10107,6 +10062,1286 @@ #define SET_SAVED_BUTTON_EVENT SET_SAVED_MENU_EVENT (sizeof (XButtonEvent)) #define SET_SAVED_KEY_EVENT SET_SAVED_MENU_EVENT (sizeof (XKeyEvent)) + +enum +{ + X_EVENT_NORMAL, + X_EVENT_GOTO_OUT, + X_EVENT_DROP +}; + +/* Handles the XEvent EVENT on display DPYINFO. + + *FINISH is X_EVENT_GOTO_OUT if caller should stop reading events. + *FINISH is zero if caller should continue reading events. + *FINISH is X_EVENT_DROP if event should not be passed to the toolkit. + + Events representing keys are stored in buffer *BUFP_R, + which can hold up to *NUMCHARSP characters. + We return the number of characters stored into the buffer. */ + +static int +handle_one_xevent (dpyinfo, eventp, bufp_r, numcharsp, finish) + struct x_display_info *dpyinfo; + XEvent *eventp; + /* register */ struct input_event **bufp_r; + /* register */ int *numcharsp; + int *finish; +{ + int count = 0; + int nbytes = 0; + struct frame *f; + struct coding_system coding; + struct input_event *bufp = *bufp_r; + int numchars = *numcharsp; + XEvent event = *eventp; + + *finish = X_EVENT_NORMAL; + + switch (event.type) + { + case ClientMessage: + { + if (event.xclient.message_type + == dpyinfo->Xatom_wm_protocols + && event.xclient.format == 32) + { + if (event.xclient.data.l[0] + == dpyinfo->Xatom_wm_take_focus) + { + /* Use x_any_window_to_frame because this + could be the shell widget window + if the frame has no title bar. */ + f = x_any_window_to_frame (dpyinfo, event.xclient.window); +#ifdef HAVE_X_I18N + /* Not quite sure this is needed -pd */ + if (f && FRAME_XIC (f)) + XSetICFocus (FRAME_XIC (f)); +#endif +#if 0 /* Emacs sets WM hints whose `input' field is `true'. This + instructs the WM to set the input focus automatically for + Emacs with a call to XSetInputFocus. Setting WM_TAKE_FOCUS + tells the WM to send us a ClientMessage WM_TAKE_FOCUS after + it has set the focus. So, XSetInputFocus below is not + needed. + + The call to XSetInputFocus below has also caused trouble. In + cases where the XSetInputFocus done by the WM and the one + below are temporally close (on a fast machine), the call + below can generate additional FocusIn events which confuse + Emacs. */ + + /* Since we set WM_TAKE_FOCUS, we must call + XSetInputFocus explicitly. But not if f is null, + since that might be an event for a deleted frame. */ + if (f) + { + Display *d = event.xclient.display; + /* Catch and ignore errors, in case window has been + iconified by a window manager such as GWM. */ + int count = x_catch_errors (d); + XSetInputFocus (d, event.xclient.window, + /* The ICCCM says this is + the only valid choice. */ + RevertToParent, + event.xclient.data.l[1]); + /* This is needed to detect the error + if there is an error. */ + XSync (d, False); + x_uncatch_errors (d, count); + } + /* Not certain about handling scroll bars here */ +#endif /* 0 */ + } + else if (event.xclient.data.l[0] + == dpyinfo->Xatom_wm_save_yourself) + { + /* Save state modify the WM_COMMAND property to + something which can reinstate us. This notifies + the session manager, who's looking for such a + PropertyNotify. Can restart processing when + a keyboard or mouse event arrives. */ + /* If we have a session manager, don't set this. + KDE will then start two Emacsen, one for the + session manager and one for this. */ + if (numchars > 0 +#ifdef HAVE_X_SM + && ! x_session_have_connection () +#endif + ) + { + f = x_top_window_to_frame (dpyinfo, + event.xclient.window); + /* This is just so we only give real data once + for a single Emacs process. */ + if (f == SELECTED_FRAME ()) + XSetCommand (FRAME_X_DISPLAY (f), + event.xclient.window, + initial_argv, initial_argc); + else if (f) + XSetCommand (FRAME_X_DISPLAY (f), + event.xclient.window, + 0, 0); + } + } + else if (event.xclient.data.l[0] + == dpyinfo->Xatom_wm_delete_window) + { + struct frame *f + = x_any_window_to_frame (dpyinfo, + event.xclient.window); + + if (f) + { + if (numchars == 0) + abort (); + + bufp->kind = DELETE_WINDOW_EVENT; + XSETFRAME (bufp->frame_or_window, f); + bufp->arg = Qnil; + bufp++; + + count += 1; + numchars -= 1; + } + else + goto OTHER; /* May be a dialog that is to be removed */ + } + } + else if (event.xclient.message_type + == dpyinfo->Xatom_wm_configure_denied) + { + } + else if (event.xclient.message_type + == dpyinfo->Xatom_wm_window_moved) + { + int new_x, new_y; + struct frame *f + = x_window_to_frame (dpyinfo, event.xclient.window); + + new_x = event.xclient.data.s[0]; + new_y = event.xclient.data.s[1]; + + if (f) + { + f->output_data.x->left_pos = new_x; + f->output_data.x->top_pos = new_y; + } + } +#ifdef HACK_EDITRES + else if (event.xclient.message_type + == dpyinfo->Xatom_editres) + { + struct frame *f + = x_any_window_to_frame (dpyinfo, event.xclient.window); + _XEditResCheckMessages (f->output_data.x->widget, NULL, + &event, NULL); + } +#endif /* HACK_EDITRES */ + else if ((event.xclient.message_type + == dpyinfo->Xatom_DONE) + || (event.xclient.message_type + == dpyinfo->Xatom_PAGE)) + { + /* Ghostview job completed. Kill it. We could + reply with "Next" if we received "Page", but we + currently never do because we are interested in + images, only, which should have 1 page. */ + Pixmap pixmap = (Pixmap) event.xclient.data.l[1]; + struct frame *f + = x_window_to_frame (dpyinfo, event.xclient.window); + x_kill_gs_process (pixmap, f); + expose_frame (f, 0, 0, 0, 0); + } +#ifdef USE_TOOLKIT_SCROLL_BARS + /* Scroll bar callbacks send a ClientMessage from which + we construct an input_event. */ + else if (event.xclient.message_type + == dpyinfo->Xatom_Scrollbar) + { + x_scroll_bar_to_input_event (&event, bufp); + ++bufp, ++count, --numchars; + goto out; + } +#endif /* USE_TOOLKIT_SCROLL_BARS */ + else + goto OTHER; + } + break; + + case SelectionNotify: +#ifdef USE_X_TOOLKIT + if (! x_window_to_frame (dpyinfo, event.xselection.requestor)) + goto OTHER; +#endif /* not USE_X_TOOLKIT */ + x_handle_selection_notify (&event.xselection); + break; + + case SelectionClear: /* Someone has grabbed ownership. */ +#ifdef USE_X_TOOLKIT + if (! x_window_to_frame (dpyinfo, event.xselectionclear.window)) + goto OTHER; +#endif /* USE_X_TOOLKIT */ + { + XSelectionClearEvent *eventp = (XSelectionClearEvent *) &event; + + if (numchars == 0) + abort (); + + bufp->kind = SELECTION_CLEAR_EVENT; + SELECTION_EVENT_DISPLAY (bufp) = eventp->display; + SELECTION_EVENT_SELECTION (bufp) = eventp->selection; + SELECTION_EVENT_TIME (bufp) = eventp->time; + bufp->frame_or_window = Qnil; + bufp->arg = Qnil; + bufp++; + + count += 1; + numchars -= 1; + } + break; + + case SelectionRequest: /* Someone wants our selection. */ +#ifdef USE_X_TOOLKIT + if (!x_window_to_frame (dpyinfo, event.xselectionrequest.owner)) + goto OTHER; +#endif /* USE_X_TOOLKIT */ + if (x_queue_selection_requests) + x_queue_event (x_window_to_frame (dpyinfo, event.xselectionrequest.owner), + &event); + else + { + XSelectionRequestEvent *eventp + = (XSelectionRequestEvent *) &event; + + if (numchars == 0) + abort (); + + bufp->kind = SELECTION_REQUEST_EVENT; + SELECTION_EVENT_DISPLAY (bufp) = eventp->display; + SELECTION_EVENT_REQUESTOR (bufp) = eventp->requestor; + SELECTION_EVENT_SELECTION (bufp) = eventp->selection; + SELECTION_EVENT_TARGET (bufp) = eventp->target; + SELECTION_EVENT_PROPERTY (bufp) = eventp->property; + SELECTION_EVENT_TIME (bufp) = eventp->time; + bufp->frame_or_window = Qnil; + bufp->arg = Qnil; + bufp++; + + count += 1; + numchars -= 1; + } + break; + + case PropertyNotify: +#if 0 /* This is plain wrong. In the case that we are waiting for a + PropertyNotify used as an ACK in incremental selection + transfer, the property will be on the receiver's window. */ +#if defined USE_X_TOOLKIT + if (!x_any_window_to_frame (dpyinfo, event.xproperty.window)) + goto OTHER; +#endif +#endif + x_handle_property_notify (&event.xproperty); + goto OTHER; + + case ReparentNotify: + f = x_top_window_to_frame (dpyinfo, event.xreparent.window); + if (f) + { + int x, y; + f->output_data.x->parent_desc = event.xreparent.parent; + x_real_positions (f, &x, &y); + f->output_data.x->left_pos = x; + f->output_data.x->top_pos = y; + goto OTHER; + } + break; + + case Expose: + f = x_window_to_frame (dpyinfo, event.xexpose.window); + if (f) + { + x_check_fullscreen (f); + + if (f->async_visible == 0) + { + f->async_visible = 1; + f->async_iconified = 0; + f->output_data.x->has_been_visible = 1; + SET_FRAME_GARBAGED (f); + } + else + expose_frame (x_window_to_frame (dpyinfo, + event.xexpose.window), + event.xexpose.x, event.xexpose.y, + event.xexpose.width, event.xexpose.height); + } + else + { +#ifndef USE_TOOLKIT_SCROLL_BARS + struct scroll_bar *bar; +#endif +#if defined USE_LUCID + /* Submenus of the Lucid menu bar aren't widgets + themselves, so there's no way to dispatch events + to them. Recognize this case separately. */ + { + Widget widget + = x_window_to_menu_bar (event.xexpose.window); + if (widget) + xlwmenu_redisplay (widget); + } +#endif /* USE_LUCID */ + +#ifdef USE_TOOLKIT_SCROLL_BARS + /* Dispatch event to the widget. */ + goto OTHER; +#else /* not USE_TOOLKIT_SCROLL_BARS */ + bar = x_window_to_scroll_bar (event.xexpose.window); + + if (bar) + x_scroll_bar_expose (bar, &event); +#ifdef USE_X_TOOLKIT + else + goto OTHER; +#endif /* USE_X_TOOLKIT */ +#endif /* not USE_TOOLKIT_SCROLL_BARS */ + } + break; + + case GraphicsExpose: /* This occurs when an XCopyArea's + source area was obscured or not + available. */ + f = x_window_to_frame (dpyinfo, event.xgraphicsexpose.drawable); + if (f) + { + expose_frame (f, + event.xgraphicsexpose.x, event.xgraphicsexpose.y, + event.xgraphicsexpose.width, + event.xgraphicsexpose.height); + } +#ifdef USE_X_TOOLKIT + else + goto OTHER; +#endif /* USE_X_TOOLKIT */ + break; + + case NoExpose: /* This occurs when an XCopyArea's + source area was completely + available. */ + break; + + case UnmapNotify: + /* Redo the mouse-highlight after the tooltip has gone. */ + if (event.xmap.window == tip_window) + { + tip_window = 0; + redo_mouse_highlight (); + } + + f = x_top_window_to_frame (dpyinfo, event.xunmap.window); + if (f) /* F may no longer exist if + the frame was deleted. */ + { + /* While a frame is unmapped, display generation is + disabled; you don't want to spend time updating a + display that won't ever be seen. */ + f->async_visible = 0; + /* We can't distinguish, from the event, whether the window + has become iconified or invisible. So assume, if it + was previously visible, than now it is iconified. + But x_make_frame_invisible clears both + the visible flag and the iconified flag; + and that way, we know the window is not iconified now. */ + if (FRAME_VISIBLE_P (f) || FRAME_ICONIFIED_P (f)) + { + f->async_iconified = 1; + + bufp->kind = ICONIFY_EVENT; + XSETFRAME (bufp->frame_or_window, f); + bufp->arg = Qnil; + bufp++; + count++; + numchars--; + } + } + goto OTHER; + + case MapNotify: + if (event.xmap.window == tip_window) + /* The tooltip has been drawn already. Avoid + the SET_FRAME_GARBAGED below. */ + goto OTHER; + + /* We use x_top_window_to_frame because map events can + come for sub-windows and they don't mean that the + frame is visible. */ + f = x_top_window_to_frame (dpyinfo, event.xmap.window); + if (f) + { + /* wait_reading_process_input will notice this and update + the frame's display structures. + If we where iconified, we should not set garbaged, + because that stops redrawing on Expose events. This looks + bad if we are called from a recursive event loop + (x_dispatch_event), for example when a dialog is up. */ + if (! f->async_iconified) + SET_FRAME_GARBAGED (f); + + f->async_visible = 1; + f->async_iconified = 0; + f->output_data.x->has_been_visible = 1; + + if (f->iconified) + { + bufp->kind = DEICONIFY_EVENT; + XSETFRAME (bufp->frame_or_window, f); + bufp->arg = Qnil; + bufp++; + count++; + numchars--; + } + else if (! NILP (Vframe_list) + && ! NILP (XCDR (Vframe_list))) + /* Force a redisplay sooner or later + to update the frame titles + in case this is the second frame. */ + record_asynch_buffer_change (); + } + goto OTHER; + + case KeyPress: + + /* Dispatch KeyPress events when in menu. */ + if (popup_activated_flag) + goto OTHER; + f = x_any_window_to_frame (dpyinfo, event.xkey.window); + + if (!dpyinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight)) + { + dpyinfo->mouse_face_hidden = 1; + clear_mouse_face (dpyinfo); + } + +#if defined USE_MOTIF && defined USE_TOOLKIT_SCROLL_BARS + if (f == 0) + { + /* Scroll bars consume key events, but we want + the keys to go to the scroll bar's frame. */ + Widget widget = XtWindowToWidget (dpyinfo->display, + event.xkey.window); + if (widget && XmIsScrollBar (widget)) + { + widget = XtParent (widget); + f = x_any_window_to_frame (dpyinfo, XtWindow (widget)); + } + } +#endif /* USE_MOTIF and USE_TOOLKIT_SCROLL_BARS */ + + if (f != 0) + { + KeySym keysym, orig_keysym; + /* al%imercury@uunet.uu.net says that making this 81 + instead of 80 fixed a bug whereby meta chars made + his Emacs hang. + + It seems that some version of XmbLookupString has + a bug of not returning XBufferOverflow in + status_return even if the input is too long to + fit in 81 bytes. So, we must prepare sufficient + bytes for copy_buffer. 513 bytes (256 chars for + two-byte character set) seems to be a fairly good + approximation. -- 2000.8.10 handa@etl.go.jp */ + unsigned char copy_buffer[513]; + unsigned char *copy_bufptr = copy_buffer; + int copy_bufsiz = sizeof (copy_buffer); + int modifiers; + Lisp_Object coding_system = Qlatin_1; + + event.xkey.state + |= x_emacs_to_x_modifiers (FRAME_X_DISPLAY_INFO (f), + extra_keyboard_modifiers); + modifiers = event.xkey.state; + + /* This will have to go some day... */ + + /* make_lispy_event turns chars into control chars. + Don't do it here because XLookupString is too eager. */ + event.xkey.state &= ~ControlMask; + event.xkey.state &= ~(dpyinfo->meta_mod_mask + | dpyinfo->super_mod_mask + | dpyinfo->hyper_mod_mask + | dpyinfo->alt_mod_mask); + + /* In case Meta is ComposeCharacter, + clear its status. According to Markus Ehrnsperger + Markus.Ehrnsperger@lehrstuhl-bross.physik.uni-muenchen.de + this enables ComposeCharacter to work whether or + not it is combined with Meta. */ + if (modifiers & dpyinfo->meta_mod_mask) + bzero (&compose_status, sizeof (compose_status)); + +#ifdef HAVE_X_I18N + if (FRAME_XIC (f)) + { + Status status_return; + + coding_system = Vlocale_coding_system; + nbytes = XmbLookupString (FRAME_XIC (f), + &event.xkey, copy_bufptr, + copy_bufsiz, &keysym, + &status_return); + if (status_return == XBufferOverflow) + { + copy_bufsiz = nbytes + 1; + copy_bufptr = (char *) alloca (copy_bufsiz); + nbytes = XmbLookupString (FRAME_XIC (f), + &event.xkey, copy_bufptr, + copy_bufsiz, &keysym, + &status_return); + } + /* Xutf8LookupString is a new but already deprecated interface. -stef */ +#if 0 && defined X_HAVE_UTF8_STRING + else if (status_return == XLookupKeySym) + { /* Try again but with utf-8. */ + coding_system = Qutf_8; + nbytes = Xutf8LookupString (FRAME_XIC (f), + &event.xkey, copy_bufptr, + copy_bufsiz, &keysym, + &status_return); + if (status_return == XBufferOverflow) + { + copy_bufsiz = nbytes + 1; + copy_bufptr = (char *) alloca (copy_bufsiz); + nbytes = Xutf8LookupString (FRAME_XIC (f), + &event.xkey, + copy_bufptr, + copy_bufsiz, &keysym, + &status_return); + } + } +#endif + + if (status_return == XLookupNone) + break; + else if (status_return == XLookupChars) + { + keysym = NoSymbol; + modifiers = 0; + } + else if (status_return != XLookupKeySym + && status_return != XLookupBoth) + abort (); + } + else + nbytes = XLookupString (&event.xkey, copy_bufptr, + copy_bufsiz, &keysym, + &compose_status); +#else + nbytes = XLookupString (&event.xkey, copy_bufptr, + copy_bufsiz, &keysym, + &compose_status); +#endif + + orig_keysym = keysym; + + if (numchars > 1) + { + Lisp_Object c; + + /* First deal with keysyms which have defined + translations to characters. */ + if (keysym >= 32 && keysym < 128) + /* Avoid explicitly decoding each ASCII character. */ + { + bufp->kind = ASCII_KEYSTROKE_EVENT; + bufp->code = keysym; + XSETFRAME (bufp->frame_or_window, f); + bufp->arg = Qnil; + bufp->modifiers + = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f), + modifiers); + bufp->timestamp = event.xkey.time; + bufp++; + count++; + numchars--; + } + /* Now non-ASCII. */ + else if (HASH_TABLE_P (Vx_keysym_table) + && (NATNUMP (c = Fgethash (make_number (keysym), + Vx_keysym_table, + Qnil)))) + { + bufp->kind = (SINGLE_BYTE_CHAR_P (XFASTINT (c)) + ? ASCII_KEYSTROKE_EVENT + : MULTIBYTE_CHAR_KEYSTROKE_EVENT); + bufp->code = XFASTINT (c); + XSETFRAME (bufp->frame_or_window, f); + bufp->arg = Qnil; + bufp->modifiers + = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f), + modifiers); + bufp->timestamp = event.xkey.time; + bufp++; + count++; + numchars--; + } + /* Random non-modifier sorts of keysyms. */ + else if (((keysym >= XK_BackSpace && keysym <= XK_Escape) + || keysym == XK_Delete +#ifdef XK_ISO_Left_Tab + || (keysym >= XK_ISO_Left_Tab + && keysym <= XK_ISO_Enter) +#endif + || IsCursorKey (keysym) /* 0xff50 <= x < 0xff60 */ + || IsMiscFunctionKey (keysym) /* 0xff60 <= x < VARIES */ +#ifdef HPUX + /* This recognizes the "extended function + keys". It seems there's no cleaner way. + Test IsModifierKey to avoid handling + mode_switch incorrectly. */ + || ((unsigned) (keysym) >= XK_Select + && (unsigned)(keysym) < XK_KP_Space) +#endif +#ifdef XK_dead_circumflex + || orig_keysym == XK_dead_circumflex +#endif +#ifdef XK_dead_grave + || orig_keysym == XK_dead_grave +#endif +#ifdef XK_dead_tilde + || orig_keysym == XK_dead_tilde +#endif +#ifdef XK_dead_diaeresis + || orig_keysym == XK_dead_diaeresis +#endif +#ifdef XK_dead_macron + || orig_keysym == XK_dead_macron +#endif +#ifdef XK_dead_degree + || orig_keysym == XK_dead_degree +#endif +#ifdef XK_dead_acute + || orig_keysym == XK_dead_acute +#endif +#ifdef XK_dead_cedilla + || orig_keysym == XK_dead_cedilla +#endif +#ifdef XK_dead_breve + || orig_keysym == XK_dead_breve +#endif +#ifdef XK_dead_ogonek + || orig_keysym == XK_dead_ogonek +#endif +#ifdef XK_dead_caron + || orig_keysym == XK_dead_caron +#endif +#ifdef XK_dead_doubleacute + || orig_keysym == XK_dead_doubleacute +#endif +#ifdef XK_dead_abovedot + || orig_keysym == XK_dead_abovedot +#endif + || IsKeypadKey (keysym) /* 0xff80 <= x < 0xffbe */ + || IsFunctionKey (keysym) /* 0xffbe <= x < 0xffe1 */ + /* Any "vendor-specific" key is ok. */ + || (orig_keysym & (1 << 28)) + || (keysym != NoSymbol && nbytes == 0)) + && ! (IsModifierKey (orig_keysym) +#ifndef HAVE_X11R5 +#ifdef XK_Mode_switch + || ((unsigned)(orig_keysym) == XK_Mode_switch) +#endif +#ifdef XK_Num_Lock + || ((unsigned)(orig_keysym) == XK_Num_Lock) +#endif +#endif /* not HAVE_X11R5 */ + /* The symbols from XK_ISO_Lock + to XK_ISO_Last_Group_Lock + don't have real modifiers but + should be treated similarly to + Mode_switch by Emacs. */ +#if defined XK_ISO_Lock && defined XK_ISO_Last_Group_Lock + || ((unsigned)(orig_keysym) + >= XK_ISO_Lock + && (unsigned)(orig_keysym) + <= XK_ISO_Last_Group_Lock) +#endif + )) + { + if (temp_index == sizeof temp_buffer / sizeof (short)) + temp_index = 0; + temp_buffer[temp_index++] = keysym; + /* make_lispy_event will convert this to a symbolic + key. */ + bufp->kind = NON_ASCII_KEYSTROKE_EVENT; + bufp->code = keysym; + XSETFRAME (bufp->frame_or_window, f); + bufp->arg = Qnil; + bufp->modifiers + = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f), + modifiers); + bufp->timestamp = event.xkey.time; + bufp++; + count++; + numchars--; + } + else if (numchars > nbytes) + { /* Raw bytes, not keysym. */ + register int i; + register int c; + int nchars, len; + + /* The input should be decoded with `coding_system' + which depends on which X*LookupString function + we used just above and the locale. */ + setup_coding_system (coding_system, &coding); + coding.src_multibyte = 0; + coding.dst_multibyte = 1; + /* The input is converted to events, thus we can't + handle composition. Anyway, there's no XIM that + gives us composition information. */ + coding.composing = COMPOSITION_DISABLED; + + for (i = 0; i < nbytes; i++) + { + if (temp_index == (sizeof temp_buffer + / sizeof (short))) + temp_index = 0; + temp_buffer[temp_index++] = copy_bufptr[i]; + } + + { + /* Decode the input data. */ + int require; + unsigned char *p; + + require = decoding_buffer_size (&coding, nbytes); + p = (unsigned char *) alloca (require); + coding.mode |= CODING_MODE_LAST_BLOCK; + /* We explicitely disable composition + handling because key data should + not contain any composition + sequence. */ + coding.composing = COMPOSITION_DISABLED; + decode_coding (&coding, copy_bufptr, p, + nbytes, require); + nbytes = coding.produced; + nchars = coding.produced_char; + copy_bufptr = p; + } + + /* Convert the input data to a sequence of + character events. */ + for (i = 0; i < nbytes; i += len) + { + if (nchars == nbytes) + c = copy_bufptr[i], len = 1; + else + c = STRING_CHAR_AND_LENGTH (copy_bufptr + i, + nbytes - i, len); + + bufp->kind = (SINGLE_BYTE_CHAR_P (c) + ? ASCII_KEYSTROKE_EVENT + : MULTIBYTE_CHAR_KEYSTROKE_EVENT); + bufp->code = c; + XSETFRAME (bufp->frame_or_window, f); + bufp->arg = Qnil; + bufp->modifiers + = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f), + modifiers); + bufp->timestamp = event.xkey.time; + bufp++; + } + + count += nchars; + numchars -= nchars; + + if (keysym == NoSymbol) + break; + } + else + abort (); + } + else + abort (); + } +#ifdef HAVE_X_I18N + /* Don't dispatch this event since XtDispatchEvent calls + XFilterEvent, and two calls in a row may freeze the + client. */ + break; +#else + goto OTHER; +#endif + + case KeyRelease: +#ifdef HAVE_X_I18N + /* Don't dispatch this event since XtDispatchEvent calls + XFilterEvent, and two calls in a row may freeze the + client. */ + break; +#else + goto OTHER; +#endif + + case EnterNotify: + { + int n; + + n = x_detect_focus_change (dpyinfo, &event, bufp, numchars); + if (n > 0) + { + bufp += n, count += n, numchars -= n; + } + + f = x_any_window_to_frame (dpyinfo, event.xcrossing.window); + +#if 0 + if (event.xcrossing.focus) + { + /* Avoid nasty pop/raise loops. */ + if (f && (!(f->auto_raise) + || !(f->auto_lower) + || (event.xcrossing.time - enter_timestamp) > 500)) + { + x_new_focus_frame (dpyinfo, f); + enter_timestamp = event.xcrossing.time; + } + } + else if (f == dpyinfo->x_focus_frame) + x_new_focus_frame (dpyinfo, 0); +#endif + + /* EnterNotify counts as mouse movement, + so update things that depend on mouse position. */ + if (f && !f->output_data.x->hourglass_p) + note_mouse_movement (f, &event.xmotion); + goto OTHER; + } + + case FocusIn: + { + int n; + + n = x_detect_focus_change (dpyinfo, &event, bufp, numchars); + if (n > 0) + { + bufp += n, count += n, numchars -= n; + } + } + + goto OTHER; + + case LeaveNotify: + { + int n; + + n = x_detect_focus_change (dpyinfo, &event, bufp, numchars); + if (n > 0) + { + bufp += n, count += n, numchars -= n; + } + } + + f = x_top_window_to_frame (dpyinfo, event.xcrossing.window); + if (f) + { + if (f == dpyinfo->mouse_face_mouse_frame) + { + /* If we move outside the frame, then we're + certainly no longer on any text in the frame. */ + clear_mouse_face (dpyinfo); + dpyinfo->mouse_face_mouse_frame = 0; + } + + /* Generate a nil HELP_EVENT to cancel a help-echo. + Do it only if there's something to cancel. + Otherwise, the startup message is cleared when + the mouse leaves the frame. */ + if (any_help_event_p) + { + Lisp_Object frame; + int n; + + XSETFRAME (frame, f); + help_echo = Qnil; + n = gen_help_event (bufp, numchars, + Qnil, frame, Qnil, Qnil, 0); + bufp += n, count += n, numchars -= n; + } + + } + goto OTHER; + + case FocusOut: + { + int n; + + n = x_detect_focus_change (dpyinfo, &event, bufp, numchars); + if (n > 0) + { + bufp += n, count += n, numchars -= n; + } + } + + goto OTHER; + + case MotionNotify: + { + previous_help_echo = help_echo; + help_echo = help_echo_object = help_echo_window = Qnil; + help_echo_pos = -1; + + if (dpyinfo->grabbed && last_mouse_frame + && FRAME_LIVE_P (last_mouse_frame)) + f = last_mouse_frame; + else + f = x_window_to_frame (dpyinfo, event.xmotion.window); + + if (dpyinfo->mouse_face_hidden) + { + dpyinfo->mouse_face_hidden = 0; + clear_mouse_face (dpyinfo); + } + + if (f) + { + + /* Generate SELECT_WINDOW_EVENTs when needed. */ + if (mouse_autoselect_window) + { + Lisp_Object window; + int area; + + window = window_from_coordinates (f, + event.xmotion.x, event.xmotion.y, + &area, 0); + + /* Window will be selected only when it is not selected now and + last mouse movement event was not in it. Minibuffer window + will be selected iff it is active. */ + if (WINDOWP(window) + && !EQ (window, last_window) + && !EQ (window, selected_window) + && numchars > 0) + { + bufp->kind = SELECT_WINDOW_EVENT; + bufp->frame_or_window = window; + bufp->arg = Qnil; + ++bufp, ++count, --numchars; + } + + last_window=window; + } + note_mouse_movement (f, &event.xmotion); + } + else + { +#ifndef USE_TOOLKIT_SCROLL_BARS + struct scroll_bar *bar + = x_window_to_scroll_bar (event.xmotion.window); + + if (bar) + x_scroll_bar_note_movement (bar, &event); +#endif /* USE_TOOLKIT_SCROLL_BARS */ + + /* If we move outside the frame, then we're + certainly no longer on any text in the frame. */ + clear_mouse_face (dpyinfo); + } + + /* If the contents of the global variable help_echo + has changed, generate a HELP_EVENT. */ + if (!NILP (help_echo) + || !NILP (previous_help_echo)) + { + Lisp_Object frame; + int n; + + if (f) + XSETFRAME (frame, f); + else + frame = Qnil; + + any_help_event_p = 1; + n = gen_help_event (bufp, numchars, help_echo, frame, + help_echo_window, help_echo_object, + help_echo_pos); + bufp += n, count += n, numchars -= n; + } + + goto OTHER; + } + + case ConfigureNotify: + f = x_top_window_to_frame (dpyinfo, event.xconfigure.window); + if (f) + { +#ifndef USE_X_TOOLKIT + /* If there is a pending resize for fullscreen, don't + do this one, the right one will come later. + The toolkit version doesn't seem to need this, but we + need to reset it below. */ + int dont_resize = + ((f->output_data.x->want_fullscreen & FULLSCREEN_WAIT) + && FRAME_NEW_WIDTH (f) != 0); + int rows = PIXEL_TO_CHAR_HEIGHT (f, event.xconfigure.height); + int columns = PIXEL_TO_CHAR_WIDTH (f, event.xconfigure.width); + if (dont_resize) + goto OTHER; + + /* In the toolkit version, change_frame_size + is called by the code that handles resizing + of the EmacsFrame widget. */ + + /* Even if the number of character rows and columns has + not changed, the font size may have changed, so we need + to check the pixel dimensions as well. */ + if (columns != f->width + || rows != f->height + || event.xconfigure.width != f->output_data.x->pixel_width + || event.xconfigure.height != f->output_data.x->pixel_height) + { + change_frame_size (f, rows, columns, 0, 1, 0); + SET_FRAME_GARBAGED (f); + cancel_mouse_face (f); + } +#endif + + f->output_data.x->pixel_width = event.xconfigure.width; + f->output_data.x->pixel_height = event.xconfigure.height; + + /* What we have now is the position of Emacs's own window. + Convert that to the position of the window manager window. */ + x_real_positions (f, &f->output_data.x->left_pos, + &f->output_data.x->top_pos); + + x_check_fullscreen_move(f); + if (f->output_data.x->want_fullscreen & FULLSCREEN_WAIT) + f->output_data.x->want_fullscreen &= + ~(FULLSCREEN_WAIT|FULLSCREEN_BOTH); +#ifdef HAVE_X_I18N + if (FRAME_XIC (f) && (FRAME_XIC_STYLE (f) & XIMStatusArea)) + xic_set_statusarea (f); +#endif + + if (f->output_data.x->parent_desc != FRAME_X_DISPLAY_INFO (f)->root_window) + { + /* Since the WM decorations come below top_pos now, + we must put them below top_pos in the future. */ + f->output_data.x->win_gravity = NorthWestGravity; + x_wm_set_size_hint (f, (long) 0, 0); + } + } + goto OTHER; + + case ButtonPress: + case ButtonRelease: + { + /* If we decide we want to generate an event to be seen + by the rest of Emacs, we put it here. */ + struct input_event emacs_event; + int tool_bar_p = 0; + + emacs_event.kind = NO_EVENT; + bzero (&compose_status, sizeof (compose_status)); + + if (dpyinfo->grabbed + && last_mouse_frame + && FRAME_LIVE_P (last_mouse_frame)) + f = last_mouse_frame; + else + f = x_window_to_frame (dpyinfo, event.xbutton.window); + + if (f) + { + /* Is this in the tool-bar? */ + if (WINDOWP (f->tool_bar_window) + && XFASTINT (XWINDOW (f->tool_bar_window)->height)) + { + Lisp_Object window; + int p, x, y; + + x = event.xbutton.x; + y = event.xbutton.y; + + /* Set x and y. */ + window = window_from_coordinates (f, x, y, &p, 1); + if (EQ (window, f->tool_bar_window)) + { + x_handle_tool_bar_click (f, &event.xbutton); + tool_bar_p = 1; + } + } + + if (!tool_bar_p) + if (!dpyinfo->x_focus_frame + || f == dpyinfo->x_focus_frame) + construct_mouse_click (&emacs_event, &event, f); + } + else + { +#ifndef USE_TOOLKIT_SCROLL_BARS + struct scroll_bar *bar + = x_window_to_scroll_bar (event.xbutton.window); + + if (bar) + x_scroll_bar_handle_click (bar, &event, &emacs_event); +#endif /* not USE_TOOLKIT_SCROLL_BARS */ + } + + if (event.type == ButtonPress) + { + dpyinfo->grabbed |= (1 << event.xbutton.button); + last_mouse_frame = f; + /* Ignore any mouse motion that happened + before this event; any subsequent mouse-movement + Emacs events should reflect only motion after + the ButtonPress. */ + if (f != 0) + f->mouse_moved = 0; + + if (!tool_bar_p) + last_tool_bar_item = -1; + } + else + { + dpyinfo->grabbed &= ~(1 << event.xbutton.button); + } + + if (numchars >= 1 && emacs_event.kind != NO_EVENT) + { + bcopy (&emacs_event, bufp, sizeof (struct input_event)); + bufp++; + count++; + numchars--; + } + +#ifdef USE_X_TOOLKIT + f = x_menubar_window_to_frame (dpyinfo, event.xbutton.window); + /* For a down-event in the menu bar, + don't pass it to Xt right now. + Instead, save it away + and we will pass it to Xt from kbd_buffer_get_event. + That way, we can run some Lisp code first. */ + if (f && event.type == ButtonPress + /* Verify the event is really within the menu bar + and not just sent to it due to grabbing. */ + && event.xbutton.x >= 0 + && event.xbutton.x < f->output_data.x->pixel_width + && event.xbutton.y >= 0 + && event.xbutton.y < f->output_data.x->menubar_height + && event.xbutton.same_screen) + { + SET_SAVED_BUTTON_EVENT; + XSETFRAME (last_mouse_press_frame, f); + } + else if (event.type == ButtonPress) + { + last_mouse_press_frame = Qnil; + goto OTHER; + } + +#ifdef USE_MOTIF /* This should do not harm for Lucid, + but I am trying to be cautious. */ + else if (event.type == ButtonRelease) + { + if (!NILP (last_mouse_press_frame)) + { + f = XFRAME (last_mouse_press_frame); + if (f->output_data.x) + SET_SAVED_BUTTON_EVENT; + } + else + goto OTHER; + } +#endif /* USE_MOTIF */ + else + goto OTHER; +#endif /* USE_X_TOOLKIT */ + } + break; + + case CirculateNotify: + goto OTHER; + + case CirculateRequest: + goto OTHER; + + case VisibilityNotify: + goto OTHER; + + case MappingNotify: + /* Someone has changed the keyboard mapping - update the + local cache. */ + switch (event.xmapping.request) + { + case MappingModifier: + x_find_modifier_meanings (dpyinfo); + /* This is meant to fall through. */ + case MappingKeyboard: + XRefreshKeyboardMapping (&event.xmapping); + } + goto OTHER; + + default: + OTHER: +#ifdef USE_X_TOOLKIT + BLOCK_INPUT; + XtDispatchEvent (&event); + UNBLOCK_INPUT; +#endif /* USE_X_TOOLKIT */ + break; + } + + goto ret; + + out: + *finish = X_EVENT_GOTO_OUT; + + ret: + *bufp_r = bufp; + *numcharsp = numchars; + *eventp = event; + + return count; +} + + +/* Handles the XEvent EVENT on display DISPLAY. + This is used for event loops outside the normal event handling, + i.e. looping while a popup menu or a dialog is posted. */ +void +x_dispatch_event (event, display) + XEvent *event; + Display *display; +{ + struct x_display_info *dpyinfo; + struct input_event bufp[10]; + struct input_event *bufpp = bufp; + int numchars = 10; + int finish; + + for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next) + if (dpyinfo->display == display) + break; + + if (dpyinfo) + { + int i, events; + events = handle_one_xevent (dpyinfo, + event, + &bufpp, + &numchars, + &finish); + for (i = 0; i < events; ++i) + kbd_buffer_store_event (&bufp[i]); + } +} + + /* Read events coming from the X server. This routine is called by the SIGIO handler. We return as soon as there are no more events to be read. @@ -10128,10 +11363,8 @@ int count = 0; int nbytes = 0; XEvent event; - struct frame *f; int event_found = 0; struct x_display_info *dpyinfo; - struct coding_system coding; if (interrupt_input_blocked) { @@ -10196,6 +11429,8 @@ while (XPending (dpyinfo->display)) { + int finish; + XNextEvent (dpyinfo->display, &event); #ifdef HAVE_X_I18N @@ -10213,1198 +11448,15 @@ #endif event_found = 1; - switch (event.type) - { - case ClientMessage: - { - if (event.xclient.message_type - == dpyinfo->Xatom_wm_protocols - && event.xclient.format == 32) - { - if (event.xclient.data.l[0] - == dpyinfo->Xatom_wm_take_focus) - { - /* Use x_any_window_to_frame because this - could be the shell widget window - if the frame has no title bar. */ - f = x_any_window_to_frame (dpyinfo, event.xclient.window); -#ifdef HAVE_X_I18N - /* Not quite sure this is needed -pd */ - if (f && FRAME_XIC (f)) - XSetICFocus (FRAME_XIC (f)); -#endif -#if 0 /* Emacs sets WM hints whose `input' field is `true'. This - instructs the WM to set the input focus automatically for - Emacs with a call to XSetInputFocus. Setting WM_TAKE_FOCUS - tells the WM to send us a ClientMessage WM_TAKE_FOCUS after - it has set the focus. So, XSetInputFocus below is not - needed. - - The call to XSetInputFocus below has also caused trouble. In - cases where the XSetInputFocus done by the WM and the one - below are temporally close (on a fast machine), the call - below can generate additional FocusIn events which confuse - Emacs. */ - - /* Since we set WM_TAKE_FOCUS, we must call - XSetInputFocus explicitly. But not if f is null, - since that might be an event for a deleted frame. */ - if (f) - { - Display *d = event.xclient.display; - /* Catch and ignore errors, in case window has been - iconified by a window manager such as GWM. */ - int count = x_catch_errors (d); - XSetInputFocus (d, event.xclient.window, - /* The ICCCM says this is - the only valid choice. */ - RevertToParent, - event.xclient.data.l[1]); - /* This is needed to detect the error - if there is an error. */ - XSync (d, False); - x_uncatch_errors (d, count); - } - /* Not certain about handling scroll bars here */ -#endif /* 0 */ - } - else if (event.xclient.data.l[0] - == dpyinfo->Xatom_wm_save_yourself) - { - /* Save state modify the WM_COMMAND property to - something which can reinstate us. This notifies - the session manager, who's looking for such a - PropertyNotify. Can restart processing when - a keyboard or mouse event arrives. */ - /* If we have a session manager, don't set this. - KDE will then start two Emacsen, one for the - session manager and one for this. */ - if (numchars > 0 -#ifdef HAVE_X_SM - && ! x_session_have_connection () -#endif - ) - { - f = x_top_window_to_frame (dpyinfo, - event.xclient.window); - /* This is just so we only give real data once - for a single Emacs process. */ - if (f == SELECTED_FRAME ()) - XSetCommand (FRAME_X_DISPLAY (f), - event.xclient.window, - initial_argv, initial_argc); - else if (f) - XSetCommand (FRAME_X_DISPLAY (f), - event.xclient.window, - 0, 0); - } - } - else if (event.xclient.data.l[0] - == dpyinfo->Xatom_wm_delete_window) - { - struct frame *f - = x_any_window_to_frame (dpyinfo, - event.xclient.window); - - if (f) - { - if (numchars == 0) - abort (); - - bufp->kind = DELETE_WINDOW_EVENT; - XSETFRAME (bufp->frame_or_window, f); - bufp->arg = Qnil; - bufp++; - - count += 1; - numchars -= 1; - } - } - } - else if (event.xclient.message_type - == dpyinfo->Xatom_wm_configure_denied) - { - } - else if (event.xclient.message_type - == dpyinfo->Xatom_wm_window_moved) - { - int new_x, new_y; - struct frame *f - = x_window_to_frame (dpyinfo, event.xclient.window); - - new_x = event.xclient.data.s[0]; - new_y = event.xclient.data.s[1]; - - if (f) - { - f->output_data.x->left_pos = new_x; - f->output_data.x->top_pos = new_y; - } - } -#ifdef HACK_EDITRES - else if (event.xclient.message_type - == dpyinfo->Xatom_editres) - { - struct frame *f - = x_any_window_to_frame (dpyinfo, event.xclient.window); - _XEditResCheckMessages (f->output_data.x->widget, NULL, - &event, NULL); - } -#endif /* HACK_EDITRES */ - else if ((event.xclient.message_type - == dpyinfo->Xatom_DONE) - || (event.xclient.message_type - == dpyinfo->Xatom_PAGE)) - { - /* Ghostview job completed. Kill it. We could - reply with "Next" if we received "Page", but we - currently never do because we are interested in - images, only, which should have 1 page. */ - Pixmap pixmap = (Pixmap) event.xclient.data.l[1]; - struct frame *f - = x_window_to_frame (dpyinfo, event.xclient.window); - x_kill_gs_process (pixmap, f); - expose_frame (f, 0, 0, 0, 0); - } -#ifdef USE_TOOLKIT_SCROLL_BARS - /* Scroll bar callbacks send a ClientMessage from which - we construct an input_event. */ - else if (event.xclient.message_type - == dpyinfo->Xatom_Scrollbar) - { - x_scroll_bar_to_input_event (&event, bufp); - ++bufp, ++count, --numchars; - goto out; - } -#endif /* USE_TOOLKIT_SCROLL_BARS */ - else - goto OTHER; - } - break; - - case SelectionNotify: -#ifdef USE_X_TOOLKIT - if (! x_window_to_frame (dpyinfo, event.xselection.requestor)) - goto OTHER; -#endif /* not USE_X_TOOLKIT */ - x_handle_selection_notify (&event.xselection); - break; - - case SelectionClear: /* Someone has grabbed ownership. */ -#ifdef USE_X_TOOLKIT - if (! x_window_to_frame (dpyinfo, event.xselectionclear.window)) - goto OTHER; -#endif /* USE_X_TOOLKIT */ - { - XSelectionClearEvent *eventp = (XSelectionClearEvent *) &event; - - if (numchars == 0) - abort (); - - bufp->kind = SELECTION_CLEAR_EVENT; - SELECTION_EVENT_DISPLAY (bufp) = eventp->display; - SELECTION_EVENT_SELECTION (bufp) = eventp->selection; - SELECTION_EVENT_TIME (bufp) = eventp->time; - bufp->frame_or_window = Qnil; - bufp->arg = Qnil; - bufp++; - - count += 1; - numchars -= 1; - } - break; - - case SelectionRequest: /* Someone wants our selection. */ -#ifdef USE_X_TOOLKIT - if (!x_window_to_frame (dpyinfo, event.xselectionrequest.owner)) - goto OTHER; -#endif /* USE_X_TOOLKIT */ - if (x_queue_selection_requests) - x_queue_event (x_window_to_frame (dpyinfo, event.xselectionrequest.owner), - &event); - else - { - XSelectionRequestEvent *eventp - = (XSelectionRequestEvent *) &event; - - if (numchars == 0) - abort (); - - bufp->kind = SELECTION_REQUEST_EVENT; - SELECTION_EVENT_DISPLAY (bufp) = eventp->display; - SELECTION_EVENT_REQUESTOR (bufp) = eventp->requestor; - SELECTION_EVENT_SELECTION (bufp) = eventp->selection; - SELECTION_EVENT_TARGET (bufp) = eventp->target; - SELECTION_EVENT_PROPERTY (bufp) = eventp->property; - SELECTION_EVENT_TIME (bufp) = eventp->time; - bufp->frame_or_window = Qnil; - bufp->arg = Qnil; - bufp++; - - count += 1; - numchars -= 1; - } - break; - - case PropertyNotify: -#if 0 /* This is plain wrong. In the case that we are waiting for a - PropertyNotify used as an ACK in incremental selection - transfer, the property will be on the receiver's window. */ -#if defined USE_X_TOOLKIT - if (!x_any_window_to_frame (dpyinfo, event.xproperty.window)) - goto OTHER; -#endif -#endif - x_handle_property_notify (&event.xproperty); - goto OTHER; - - case ReparentNotify: - f = x_top_window_to_frame (dpyinfo, event.xreparent.window); - if (f) - { - int x, y; - f->output_data.x->parent_desc = event.xreparent.parent; - x_real_positions (f, &x, &y); - f->output_data.x->left_pos = x; - f->output_data.x->top_pos = y; - goto OTHER; - } - break; - - case Expose: - f = x_window_to_frame (dpyinfo, event.xexpose.window); - if (f) - { - x_check_fullscreen (f); - - if (f->async_visible == 0) - { - f->async_visible = 1; - f->async_iconified = 0; - f->output_data.x->has_been_visible = 1; - SET_FRAME_GARBAGED (f); - } - else - expose_frame (x_window_to_frame (dpyinfo, - event.xexpose.window), - event.xexpose.x, event.xexpose.y, - event.xexpose.width, event.xexpose.height); - } - else - { -#ifndef USE_TOOLKIT_SCROLL_BARS - struct scroll_bar *bar; -#endif -#if defined USE_LUCID - /* Submenus of the Lucid menu bar aren't widgets - themselves, so there's no way to dispatch events - to them. Recognize this case separately. */ - { - Widget widget - = x_window_to_menu_bar (event.xexpose.window); - if (widget) - xlwmenu_redisplay (widget); - } -#endif /* USE_LUCID */ - -#ifdef USE_TOOLKIT_SCROLL_BARS - /* Dispatch event to the widget. */ - goto OTHER; -#else /* not USE_TOOLKIT_SCROLL_BARS */ - bar = x_window_to_scroll_bar (event.xexpose.window); - - if (bar) - x_scroll_bar_expose (bar, &event); -#ifdef USE_X_TOOLKIT - else - goto OTHER; -#endif /* USE_X_TOOLKIT */ -#endif /* not USE_TOOLKIT_SCROLL_BARS */ - } - break; - - case GraphicsExpose: /* This occurs when an XCopyArea's - source area was obscured or not - available. */ - f = x_window_to_frame (dpyinfo, event.xgraphicsexpose.drawable); - if (f) - { - expose_frame (f, - event.xgraphicsexpose.x, event.xgraphicsexpose.y, - event.xgraphicsexpose.width, - event.xgraphicsexpose.height); - } -#ifdef USE_X_TOOLKIT - else - goto OTHER; -#endif /* USE_X_TOOLKIT */ - break; - - case NoExpose: /* This occurs when an XCopyArea's - source area was completely - available. */ - break; - - case UnmapNotify: - /* Redo the mouse-highlight after the tooltip has gone. */ - if (event.xmap.window == tip_window) - { - tip_window = 0; - redo_mouse_highlight (); - } - - f = x_top_window_to_frame (dpyinfo, event.xunmap.window); - if (f) /* F may no longer exist if - the frame was deleted. */ - { - /* While a frame is unmapped, display generation is - disabled; you don't want to spend time updating a - display that won't ever be seen. */ - f->async_visible = 0; - /* We can't distinguish, from the event, whether the window - has become iconified or invisible. So assume, if it - was previously visible, than now it is iconified. - But x_make_frame_invisible clears both - the visible flag and the iconified flag; - and that way, we know the window is not iconified now. */ - if (FRAME_VISIBLE_P (f) || FRAME_ICONIFIED_P (f)) - { - f->async_iconified = 1; - - bufp->kind = ICONIFY_EVENT; - XSETFRAME (bufp->frame_or_window, f); - bufp->arg = Qnil; - bufp++; - count++; - numchars--; - } - } - goto OTHER; - - case MapNotify: - if (event.xmap.window == tip_window) - /* The tooltip has been drawn already. Avoid - the SET_FRAME_GARBAGED below. */ - goto OTHER; - - /* We use x_top_window_to_frame because map events can - come for sub-windows and they don't mean that the - frame is visible. */ - f = x_top_window_to_frame (dpyinfo, event.xmap.window); - if (f) - { - f->async_visible = 1; - f->async_iconified = 0; - f->output_data.x->has_been_visible = 1; - - /* wait_reading_process_input will notice this and update - the frame's display structures. */ - SET_FRAME_GARBAGED (f); - - if (f->iconified) - { - bufp->kind = DEICONIFY_EVENT; - XSETFRAME (bufp->frame_or_window, f); - bufp->arg = Qnil; - bufp++; - count++; - numchars--; - } - else if (! NILP (Vframe_list) - && ! NILP (XCDR (Vframe_list))) - /* Force a redisplay sooner or later - to update the frame titles - in case this is the second frame. */ - record_asynch_buffer_change (); - } - goto OTHER; - - case KeyPress: - - /* Dispatch KeyPress events when in menu. */ - if (popup_activated_flag) - goto OTHER; - - f = x_any_window_to_frame (dpyinfo, event.xkey.window); - - if (!dpyinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight)) - { - dpyinfo->mouse_face_hidden = 1; - clear_mouse_face (dpyinfo); - } - -#if defined USE_MOTIF && defined USE_TOOLKIT_SCROLL_BARS - if (f == 0) - { - /* Scroll bars consume key events, but we want - the keys to go to the scroll bar's frame. */ - Widget widget = XtWindowToWidget (dpyinfo->display, - event.xkey.window); - if (widget && XmIsScrollBar (widget)) - { - widget = XtParent (widget); - f = x_any_window_to_frame (dpyinfo, XtWindow (widget)); - } - } -#endif /* USE_MOTIF and USE_TOOLKIT_SCROLL_BARS */ - - if (f != 0) - { - KeySym keysym, orig_keysym; - /* al%imercury@uunet.uu.net says that making this 81 - instead of 80 fixed a bug whereby meta chars made - his Emacs hang. - - It seems that some version of XmbLookupString has - a bug of not returning XBufferOverflow in - status_return even if the input is too long to - fit in 81 bytes. So, we must prepare sufficient - bytes for copy_buffer. 513 bytes (256 chars for - two-byte character set) seems to be a fairly good - approximation. -- 2000.8.10 handa@etl.go.jp */ - unsigned char copy_buffer[513]; - unsigned char *copy_bufptr = copy_buffer; - int copy_bufsiz = sizeof (copy_buffer); - int modifiers; - Lisp_Object coding_system = Qlatin_1; - - event.xkey.state - |= x_emacs_to_x_modifiers (FRAME_X_DISPLAY_INFO (f), - extra_keyboard_modifiers); - modifiers = event.xkey.state; - - /* This will have to go some day... */ - - /* make_lispy_event turns chars into control chars. - Don't do it here because XLookupString is too eager. */ - event.xkey.state &= ~ControlMask; - event.xkey.state &= ~(dpyinfo->meta_mod_mask - | dpyinfo->super_mod_mask - | dpyinfo->hyper_mod_mask - | dpyinfo->alt_mod_mask); - - /* In case Meta is ComposeCharacter, - clear its status. According to Markus Ehrnsperger - Markus.Ehrnsperger@lehrstuhl-bross.physik.uni-muenchen.de - this enables ComposeCharacter to work whether or - not it is combined with Meta. */ - if (modifiers & dpyinfo->meta_mod_mask) - bzero (&compose_status, sizeof (compose_status)); - -#ifdef HAVE_X_I18N - if (FRAME_XIC (f)) - { - Status status_return; - - coding_system = Vlocale_coding_system; - nbytes = XmbLookupString (FRAME_XIC (f), - &event.xkey, copy_bufptr, - copy_bufsiz, &keysym, - &status_return); - if (status_return == XBufferOverflow) - { - copy_bufsiz = nbytes + 1; - copy_bufptr = (char *) alloca (copy_bufsiz); - nbytes = XmbLookupString (FRAME_XIC (f), - &event.xkey, copy_bufptr, - copy_bufsiz, &keysym, - &status_return); - } -/* Xutf8LookupString is a new but already deprecated interface. -stef */ -#if 0 && defined X_HAVE_UTF8_STRING - else if (status_return == XLookupKeySym) - { /* Try again but with utf-8. */ - coding_system = Qutf_8; - nbytes = Xutf8LookupString (FRAME_XIC (f), - &event.xkey, copy_bufptr, - copy_bufsiz, &keysym, - &status_return); - if (status_return == XBufferOverflow) - { - copy_bufsiz = nbytes + 1; - copy_bufptr = (char *) alloca (copy_bufsiz); - nbytes = Xutf8LookupString (FRAME_XIC (f), - &event.xkey, - copy_bufptr, - copy_bufsiz, &keysym, - &status_return); - } - } -#endif - - if (status_return == XLookupNone) - break; - else if (status_return == XLookupChars) - { - keysym = NoSymbol; - modifiers = 0; - } - else if (status_return != XLookupKeySym - && status_return != XLookupBoth) - abort (); - } - else - nbytes = XLookupString (&event.xkey, copy_bufptr, - copy_bufsiz, &keysym, - &compose_status); -#else - nbytes = XLookupString (&event.xkey, copy_bufptr, - copy_bufsiz, &keysym, - &compose_status); -#endif - - orig_keysym = keysym; - - if (numchars > 1) - { - Lisp_Object c; - - /* First deal with keysyms which have defined - translations to characters. */ - if (keysym >= 32 && keysym < 128) - /* Avoid explicitly decoding each ASCII character. */ - { - bufp->kind = ASCII_KEYSTROKE_EVENT; - bufp->code = keysym; - XSETFRAME (bufp->frame_or_window, f); - bufp->arg = Qnil; - bufp->modifiers - = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f), - modifiers); - bufp->timestamp = event.xkey.time; - bufp++; - count++; - numchars--; - } - /* Now non-ASCII. */ - else if (HASH_TABLE_P (Vx_keysym_table) - && (NATNUMP (c = Fgethash (make_number (keysym), - Vx_keysym_table, - Qnil)))) - { - bufp->kind = (SINGLE_BYTE_CHAR_P (XFASTINT (c)) - ? ASCII_KEYSTROKE_EVENT - : MULTIBYTE_CHAR_KEYSTROKE_EVENT); - bufp->code = XFASTINT (c); - XSETFRAME (bufp->frame_or_window, f); - bufp->arg = Qnil; - bufp->modifiers - = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f), - modifiers); - bufp->timestamp = event.xkey.time; - bufp++; - count++; - numchars--; - } - /* Random non-modifier sorts of keysyms. */ - else if (((keysym >= XK_BackSpace && keysym <= XK_Escape) - || keysym == XK_Delete -#ifdef XK_ISO_Left_Tab - || (keysym >= XK_ISO_Left_Tab - && keysym <= XK_ISO_Enter) -#endif - || IsCursorKey (keysym) /* 0xff50 <= x < 0xff60 */ - || IsMiscFunctionKey (keysym) /* 0xff60 <= x < VARIES */ -#ifdef HPUX - /* This recognizes the "extended function - keys". It seems there's no cleaner way. - Test IsModifierKey to avoid handling - mode_switch incorrectly. */ - || ((unsigned) (keysym) >= XK_Select - && (unsigned)(keysym) < XK_KP_Space) -#endif -#ifdef XK_dead_circumflex - || orig_keysym == XK_dead_circumflex -#endif -#ifdef XK_dead_grave - || orig_keysym == XK_dead_grave -#endif -#ifdef XK_dead_tilde - || orig_keysym == XK_dead_tilde -#endif -#ifdef XK_dead_diaeresis - || orig_keysym == XK_dead_diaeresis -#endif -#ifdef XK_dead_macron - || orig_keysym == XK_dead_macron -#endif -#ifdef XK_dead_degree - || orig_keysym == XK_dead_degree -#endif -#ifdef XK_dead_acute - || orig_keysym == XK_dead_acute -#endif -#ifdef XK_dead_cedilla - || orig_keysym == XK_dead_cedilla -#endif -#ifdef XK_dead_breve - || orig_keysym == XK_dead_breve -#endif -#ifdef XK_dead_ogonek - || orig_keysym == XK_dead_ogonek -#endif -#ifdef XK_dead_caron - || orig_keysym == XK_dead_caron -#endif -#ifdef XK_dead_doubleacute - || orig_keysym == XK_dead_doubleacute -#endif -#ifdef XK_dead_abovedot - || orig_keysym == XK_dead_abovedot -#endif - || IsKeypadKey (keysym) /* 0xff80 <= x < 0xffbe */ - || IsFunctionKey (keysym) /* 0xffbe <= x < 0xffe1 */ - /* Any "vendor-specific" key is ok. */ - || (orig_keysym & (1 << 28)) - || (keysym != NoSymbol && nbytes == 0)) - && ! (IsModifierKey (orig_keysym) -#ifndef HAVE_X11R5 -#ifdef XK_Mode_switch - || ((unsigned)(orig_keysym) == XK_Mode_switch) -#endif -#ifdef XK_Num_Lock - || ((unsigned)(orig_keysym) == XK_Num_Lock) -#endif -#endif /* not HAVE_X11R5 */ - /* The symbols from XK_ISO_Lock - to XK_ISO_Last_Group_Lock - don't have real modifiers but - should be treated similarly to - Mode_switch by Emacs. */ -#if defined XK_ISO_Lock && defined XK_ISO_Last_Group_Lock - || ((unsigned)(orig_keysym) - >= XK_ISO_Lock - && (unsigned)(orig_keysym) - <= XK_ISO_Last_Group_Lock) -#endif - )) - { - if (temp_index == sizeof temp_buffer / sizeof (short)) - temp_index = 0; - temp_buffer[temp_index++] = keysym; - /* make_lispy_event will convert this to a symbolic - key. */ - bufp->kind = NON_ASCII_KEYSTROKE_EVENT; - bufp->code = keysym; - XSETFRAME (bufp->frame_or_window, f); - bufp->arg = Qnil; - bufp->modifiers - = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f), - modifiers); - bufp->timestamp = event.xkey.time; - bufp++; - count++; - numchars--; - } - else if (numchars > nbytes) - { /* Raw bytes, not keysym. */ - register int i; - register int c; - int nchars, len; - - /* The input should be decoded with `coding_system' - which depends on which X*LookupString function - we used just above and the locale. */ - setup_coding_system (coding_system, &coding); - coding.src_multibyte = 0; - coding.dst_multibyte = 1; - /* The input is converted to events, thus we can't - handle composition. Anyway, there's no XIM that - gives us composition information. */ - coding.composing = COMPOSITION_DISABLED; - - for (i = 0; i < nbytes; i++) - { - if (temp_index == (sizeof temp_buffer - / sizeof (short))) - temp_index = 0; - temp_buffer[temp_index++] = copy_bufptr[i]; - } - - { - /* Decode the input data. */ - int require; - unsigned char *p; - - require = decoding_buffer_size (&coding, nbytes); - p = (unsigned char *) alloca (require); - coding.mode |= CODING_MODE_LAST_BLOCK; - /* We explicitely disable composition - handling because key data should - not contain any composition - sequence. */ - coding.composing = COMPOSITION_DISABLED; - decode_coding (&coding, copy_bufptr, p, - nbytes, require); - nbytes = coding.produced; - nchars = coding.produced_char; - copy_bufptr = p; - } - - /* Convert the input data to a sequence of - character events. */ - for (i = 0; i < nbytes; i += len) - { - if (nchars == nbytes) - c = copy_bufptr[i], len = 1; - else - c = STRING_CHAR_AND_LENGTH (copy_bufptr + i, - nbytes - i, len); - - bufp->kind = (SINGLE_BYTE_CHAR_P (c) - ? ASCII_KEYSTROKE_EVENT - : MULTIBYTE_CHAR_KEYSTROKE_EVENT); - bufp->code = c; - XSETFRAME (bufp->frame_or_window, f); - bufp->arg = Qnil; - bufp->modifiers - = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f), - modifiers); - bufp->timestamp = event.xkey.time; - bufp++; - } - - count += nchars; - numchars -= nchars; - - if (keysym == NoSymbol) - break; - } - else - abort (); - } - else - abort (); - } -#ifdef HAVE_X_I18N - /* Don't dispatch this event since XtDispatchEvent calls - XFilterEvent, and two calls in a row may freeze the - client. */ - break; -#else - goto OTHER; -#endif - - case KeyRelease: -#ifdef HAVE_X_I18N - /* Don't dispatch this event since XtDispatchEvent calls - XFilterEvent, and two calls in a row may freeze the - client. */ - break; -#else - goto OTHER; -#endif - - case EnterNotify: - { - int n; - - n = x_detect_focus_change (dpyinfo, &event, bufp, numchars); - if (n > 0) - { - bufp += n, count += n, numchars -= n; - } - - f = x_any_window_to_frame (dpyinfo, event.xcrossing.window); - -#if 0 - if (event.xcrossing.focus) - { - /* Avoid nasty pop/raise loops. */ - if (f && (!(f->auto_raise) - || !(f->auto_lower) - || (event.xcrossing.time - enter_timestamp) > 500)) - { - x_new_focus_frame (dpyinfo, f); - enter_timestamp = event.xcrossing.time; - } - } - else if (f == dpyinfo->x_focus_frame) - x_new_focus_frame (dpyinfo, 0); -#endif - - /* EnterNotify counts as mouse movement, - so update things that depend on mouse position. */ - if (f && !f->output_data.x->hourglass_p) - note_mouse_movement (f, &event.xmotion); - goto OTHER; - } - - case FocusIn: - { - int n; - - n = x_detect_focus_change (dpyinfo, &event, bufp, numchars); - if (n > 0) - { - bufp += n, count += n, numchars -= n; - } - } - - goto OTHER; - - case LeaveNotify: - { - int n; - - n = x_detect_focus_change (dpyinfo, &event, bufp, numchars); - if (n > 0) - { - bufp += n, count += n, numchars -= n; - } - } - - f = x_top_window_to_frame (dpyinfo, event.xcrossing.window); - if (f) - { - if (f == dpyinfo->mouse_face_mouse_frame) - { - /* If we move outside the frame, then we're - certainly no longer on any text in the frame. */ - clear_mouse_face (dpyinfo); - dpyinfo->mouse_face_mouse_frame = 0; - } - - /* Generate a nil HELP_EVENT to cancel a help-echo. - Do it only if there's something to cancel. - Otherwise, the startup message is cleared when - the mouse leaves the frame. */ - if (any_help_event_p) - { - Lisp_Object frame; - int n; - - XSETFRAME (frame, f); - help_echo = Qnil; - n = gen_help_event (bufp, numchars, - Qnil, frame, Qnil, Qnil, 0); - bufp += n, count += n, numchars -= n; - } - - } - goto OTHER; - - case FocusOut: - { - int n; - - n = x_detect_focus_change (dpyinfo, &event, bufp, numchars); - if (n > 0) - { - bufp += n, count += n, numchars -= n; - } - } - - goto OTHER; - - case MotionNotify: - { - previous_help_echo = help_echo; - help_echo = help_echo_object = help_echo_window = Qnil; - help_echo_pos = -1; - - if (dpyinfo->grabbed && last_mouse_frame - && FRAME_LIVE_P (last_mouse_frame)) - f = last_mouse_frame; - else - f = x_window_to_frame (dpyinfo, event.xmotion.window); - - if (dpyinfo->mouse_face_hidden) - { - dpyinfo->mouse_face_hidden = 0; - clear_mouse_face (dpyinfo); - } - - if (f) - { - - /* Generate SELECT_WINDOW_EVENTs when needed. */ - if (mouse_autoselect_window) - { - Lisp_Object window; - int area; - - window = window_from_coordinates (f, - event.xmotion.x, event.xmotion.y, - &area, 0); - - /* Window will be selected only when it is not selected now and - last mouse movement event was not in it. Minibuffer window - will be selected iff it is active. */ - if (WINDOWP(window) - && !EQ (window, last_window) - && !EQ (window, selected_window) - && numchars > 0) - { - bufp->kind = SELECT_WINDOW_EVENT; - bufp->frame_or_window = window; - bufp->arg = Qnil; - ++bufp, ++count, --numchars; - } - - last_window=window; - } - note_mouse_movement (f, &event.xmotion); - } - else - { -#ifndef USE_TOOLKIT_SCROLL_BARS - struct scroll_bar *bar - = x_window_to_scroll_bar (event.xmotion.window); - - if (bar) - x_scroll_bar_note_movement (bar, &event); -#endif /* USE_TOOLKIT_SCROLL_BARS */ - - /* If we move outside the frame, then we're - certainly no longer on any text in the frame. */ - clear_mouse_face (dpyinfo); - } - - /* If the contents of the global variable help_echo - has changed, generate a HELP_EVENT. */ - if (!NILP (help_echo) - || !NILP (previous_help_echo)) - { - Lisp_Object frame; - int n; - - if (f) - XSETFRAME (frame, f); - else - frame = Qnil; - - any_help_event_p = 1; - n = gen_help_event (bufp, numchars, help_echo, frame, - help_echo_window, help_echo_object, - help_echo_pos); - bufp += n, count += n, numchars -= n; - } - - goto OTHER; - } - - case ConfigureNotify: - f = x_top_window_to_frame (dpyinfo, event.xconfigure.window); - if (f) - { -#ifndef USE_X_TOOLKIT - /* If there is a pending resize for fullscreen, don't - do this one, the right one will come later. - The toolkit version doesn't seem to need this, but we - need to reset it below. */ - int dont_resize = - ((f->output_data.x->want_fullscreen & FULLSCREEN_WAIT) - && FRAME_NEW_WIDTH (f) != 0); - int rows = PIXEL_TO_CHAR_HEIGHT (f, event.xconfigure.height); - int columns = PIXEL_TO_CHAR_WIDTH (f, event.xconfigure.width); - if (dont_resize) - goto OTHER; - - /* In the toolkit version, change_frame_size - is called by the code that handles resizing - of the EmacsFrame widget. */ - - /* Even if the number of character rows and columns has - not changed, the font size may have changed, so we need - to check the pixel dimensions as well. */ - if (columns != f->width - || rows != f->height - || event.xconfigure.width != f->output_data.x->pixel_width - || event.xconfigure.height != f->output_data.x->pixel_height) - { - change_frame_size (f, rows, columns, 0, 1, 0); - SET_FRAME_GARBAGED (f); - cancel_mouse_face (f); - } -#endif - - f->output_data.x->pixel_width = event.xconfigure.width; - f->output_data.x->pixel_height = event.xconfigure.height; - - /* What we have now is the position of Emacs's own window. - Convert that to the position of the window manager window. */ - x_real_positions (f, &f->output_data.x->left_pos, - &f->output_data.x->top_pos); - - x_check_fullscreen_move(f); - if (f->output_data.x->want_fullscreen & FULLSCREEN_WAIT) - f->output_data.x->want_fullscreen &= - ~(FULLSCREEN_WAIT|FULLSCREEN_BOTH); -#ifdef HAVE_X_I18N - if (FRAME_XIC (f) && (FRAME_XIC_STYLE (f) & XIMStatusArea)) - xic_set_statusarea (f); -#endif - - if (f->output_data.x->parent_desc != FRAME_X_DISPLAY_INFO (f)->root_window) - { - /* Since the WM decorations come below top_pos now, - we must put them below top_pos in the future. */ - f->output_data.x->win_gravity = NorthWestGravity; - x_wm_set_size_hint (f, (long) 0, 0); - } - } - goto OTHER; - - case ButtonPress: - case ButtonRelease: - { - /* If we decide we want to generate an event to be seen - by the rest of Emacs, we put it here. */ - struct input_event emacs_event; - int tool_bar_p = 0; - - emacs_event.kind = NO_EVENT; - bzero (&compose_status, sizeof (compose_status)); - - if (dpyinfo->grabbed - && last_mouse_frame - && FRAME_LIVE_P (last_mouse_frame)) - f = last_mouse_frame; - else - f = x_window_to_frame (dpyinfo, event.xbutton.window); - - if (f) - { - /* Is this in the tool-bar? */ - if (WINDOWP (f->tool_bar_window) - && XFASTINT (XWINDOW (f->tool_bar_window)->height)) - { - Lisp_Object window; - int p, x, y; - - x = event.xbutton.x; - y = event.xbutton.y; - - /* Set x and y. */ - window = window_from_coordinates (f, x, y, &p, 1); - if (EQ (window, f->tool_bar_window)) - { - x_handle_tool_bar_click (f, &event.xbutton); - tool_bar_p = 1; - } - } - - if (!tool_bar_p) - if (!dpyinfo->x_focus_frame - || f == dpyinfo->x_focus_frame) - construct_mouse_click (&emacs_event, &event, f); - } - else - { -#ifndef USE_TOOLKIT_SCROLL_BARS - struct scroll_bar *bar - = x_window_to_scroll_bar (event.xbutton.window); - - if (bar) - x_scroll_bar_handle_click (bar, &event, &emacs_event); -#endif /* not USE_TOOLKIT_SCROLL_BARS */ - } - - if (event.type == ButtonPress) - { - dpyinfo->grabbed |= (1 << event.xbutton.button); - last_mouse_frame = f; - /* Ignore any mouse motion that happened - before this event; any subsequent mouse-movement - Emacs events should reflect only motion after - the ButtonPress. */ - if (f != 0) - f->mouse_moved = 0; - - if (!tool_bar_p) - last_tool_bar_item = -1; - } - else - { - dpyinfo->grabbed &= ~(1 << event.xbutton.button); - } - - if (numchars >= 1 && emacs_event.kind != NO_EVENT) - { - bcopy (&emacs_event, bufp, sizeof (struct input_event)); - bufp++; - count++; - numchars--; - } - -#ifdef USE_X_TOOLKIT - f = x_menubar_window_to_frame (dpyinfo, event.xbutton.window); - /* For a down-event in the menu bar, - don't pass it to Xt right now. - Instead, save it away - and we will pass it to Xt from kbd_buffer_get_event. - That way, we can run some Lisp code first. */ - if (f && event.type == ButtonPress - /* Verify the event is really within the menu bar - and not just sent to it due to grabbing. */ - && event.xbutton.x >= 0 - && event.xbutton.x < f->output_data.x->pixel_width - && event.xbutton.y >= 0 - && event.xbutton.y < f->output_data.x->menubar_height - && event.xbutton.same_screen) - { - SET_SAVED_BUTTON_EVENT; - XSETFRAME (last_mouse_press_frame, f); - } - else if (event.type == ButtonPress) - { - last_mouse_press_frame = Qnil; - goto OTHER; - } - -#ifdef USE_MOTIF /* This should do not harm for Lucid, - but I am trying to be cautious. */ - else if (event.type == ButtonRelease) - { - if (!NILP (last_mouse_press_frame)) - { - f = XFRAME (last_mouse_press_frame); - if (f->output_data.x) - SET_SAVED_BUTTON_EVENT; - } - else - goto OTHER; - } -#endif /* USE_MOTIF */ - else - goto OTHER; -#endif /* USE_X_TOOLKIT */ - } - break; - - case CirculateNotify: - goto OTHER; - - case CirculateRequest: - goto OTHER; - - case VisibilityNotify: - goto OTHER; - - case MappingNotify: - /* Someone has changed the keyboard mapping - update the - local cache. */ - switch (event.xmapping.request) - { - case MappingModifier: - x_find_modifier_meanings (dpyinfo); - /* This is meant to fall through. */ - case MappingKeyboard: - XRefreshKeyboardMapping (&event.xmapping); - } - goto OTHER; - - default: - OTHER: -#ifdef USE_X_TOOLKIT - BLOCK_INPUT; - XtDispatchEvent (&event); - UNBLOCK_INPUT; -#endif /* USE_X_TOOLKIT */ - break; - } - } + count += handle_one_xevent (dpyinfo, + &event, + &bufp, + &numchars, + &finish); + + if (finish == X_EVENT_GOTO_OUT) + goto out; + } } out:;