Commit 89079179 authored by Kim F. Storm's avatar Kim F. Storm

(x_focus_changed, x_detect_focus_change): Remove

numchars arg.  Always store event into bufp arg.  Return nothing.
Callers changed accordingly.
(glyph_rect): Simplify.
(STORE_KEYSYM_FOR_DEBUG): New macro.
(SET_SAVED_MENU_EVENT): Use inev instead of bufp, etc.
(current_bufp, current_numcharsp) [USE_GTK]: Remove.
(current_hold_quit) [USE_GTK]: Add.
(event_handler_gdk): Adapt to new handle_one_xevent.
(handle_one_xevent): Remove bufp_r and numcharsp args.
Add hold_quit arg. Rework to use just one, local, inev
input_event. Store inev directly in fifo using
kbd_buffer_store_event_hold.  Update count in one place.
Postpone call to gen_help_event until inev is stored; use new
local do_help for this.
Simplify handling of keysyms (consolidate common code).  Fix bug
where count was updated with nchars instead of nbytes.
Remove local emacs_event in handing of ButtonPress event; just use
inev instead (so no reason to copy it later).
Remove `out' label.  Rename label `ret' to `done'; add various
`goto done' to clarify code flow in deeply nested blocks.
(x_dispatch_event): Simplify as handle_one_xevent now calls
kbd_buffer_store_event itself.
(XTread_socket): Remove bufp_r and numcharsp args. Add hold_quit
arg.  Call handle_one_xevent with new arglist.  Store event from
x_session_check_input in fifo.
[USE_GTK]: Setup current_hold_quit.
Decrement handling_signal before unblocking input.
(x_initialize) [USE_GTK]: Initialize current_count.
parent a6950dfa
......@@ -336,16 +336,10 @@ static void x_clear_frame P_ ((void));
static void frame_highlight P_ ((struct frame *));
static void frame_unhighlight P_ ((struct frame *));
static void x_new_focus_frame P_ ((struct x_display_info *, struct frame *));
static int x_focus_changed P_ ((int,
int,
struct x_display_info *,
struct frame *,
struct input_event *,
int));
static int x_detect_focus_change P_ ((struct x_display_info *,
XEvent *,
struct input_event *,
int));
static void x_focus_changed P_ ((int, int, struct x_display_info *,
struct frame *, struct input_event *));
static void x_detect_focus_change P_ ((struct x_display_info *,
XEvent *, struct input_event *));
static void XTframe_rehighlight P_ ((struct frame *));
static void x_frame_rehighlight P_ ((struct x_display_info *));
static void x_draw_hollow_cursor P_ ((struct window *, struct glyph_row *));
......@@ -364,11 +358,8 @@ static void x_scroll_bar_report_motion P_ ((struct frame **, Lisp_Object *,
unsigned long *));
static void x_check_fullscreen P_ ((struct frame *));
static void x_check_expected_move P_ ((struct frame *));
static int handle_one_xevent P_ ((struct x_display_info *,
XEvent *,
struct input_event **,
int *,
int *));
static int handle_one_xevent P_ ((struct x_display_info *, XEvent *,
int *, struct input_event *));
/* Flush display of frame F, or of all frames if F is null. */
......@@ -3167,20 +3158,16 @@ x_new_focus_frame (dpyinfo, frame)
/* Handle FocusIn and FocusOut state changes for FRAME.
If FRAME has focus and there exists more than one frame, puts
a FOCUS_IN_EVENT into BUFP.
Returns number of events inserted into BUFP. */
a FOCUS_IN_EVENT into *BUFP. */
static int
x_focus_changed (type, state, dpyinfo, frame, bufp, numchars)
static void
x_focus_changed (type, state, dpyinfo, frame, bufp)
int type;
int state;
struct x_display_info *dpyinfo;
struct frame *frame;
struct input_event *bufp;
int numchars;
{
int nr_events = 0;
if (type == FocusIn)
{
if (dpyinfo->x_focus_event_frame != frame)
......@@ -3190,17 +3177,12 @@ x_focus_changed (type, state, dpyinfo, frame, bufp, numchars)
/* Don't stop displaying the initial startup message
for a switch-frame event we don't need. */
if (numchars > 0
&& GC_NILP (Vterminal_frame)
if (GC_NILP (Vterminal_frame)
&& GC_CONSP (Vframe_list)
&& !GC_NILP (XCDR (Vframe_list)))
{
bufp->kind = FOCUS_IN_EVENT;
XSETFRAME (bufp->frame_or_window, frame);
bufp->arg = Qnil;
++bufp;
numchars--;
++nr_events;
}
}
......@@ -3226,27 +3208,25 @@ x_focus_changed (type, state, dpyinfo, frame, bufp, numchars)
XUnsetICFocus (FRAME_XIC (frame));
#endif
}
return nr_events;
}
/* The focus may have changed. Figure out if it is a real focus change,
by checking both FocusIn/Out and Enter/LeaveNotify events.
Returns number of events inserted into BUFP. */
Returns FOCUS_IN_EVENT event in *BUFP. */
static int
x_detect_focus_change (dpyinfo, event, bufp, numchars)
static void
x_detect_focus_change (dpyinfo, event, bufp)
struct x_display_info *dpyinfo;
XEvent *event;
struct input_event *bufp;
int numchars;
{
struct frame *frame;
int nr_events = 0;
frame = x_any_window_to_frame (dpyinfo, event->xany.window);
if (! frame) return nr_events;
if (! frame)
return;
switch (event->type)
{
......@@ -3260,29 +3240,20 @@ x_detect_focus_change (dpyinfo, event, bufp, numchars)
if (event->xcrossing.detail != NotifyInferior
&& event->xcrossing.focus
&& ! (focus_state & FOCUS_EXPLICIT))
nr_events = x_focus_changed ((event->type == EnterNotify
? FocusIn : FocusOut),
FOCUS_IMPLICIT,
dpyinfo,
frame,
bufp,
numchars);
x_focus_changed ((event->type == EnterNotify ? FocusIn : FocusOut),
FOCUS_IMPLICIT,
dpyinfo, frame, bufp);
}
break;
case FocusIn:
case FocusOut:
nr_events = x_focus_changed (event->type,
(event->xfocus.detail == NotifyPointer
? FOCUS_IMPLICIT : FOCUS_EXPLICIT),
dpyinfo,
frame,
bufp,
numchars);
x_focus_changed (event->type,
(event->xfocus.detail == NotifyPointer ?
FOCUS_IMPLICIT : FOCUS_EXPLICIT),
dpyinfo, frame, bufp);
break;
}
return nr_events;
}
......@@ -3627,35 +3598,39 @@ glyph_rect (f, x, y, rect)
XRectangle *rect;
{
Lisp_Object window;
int found = 0;
struct window *w;
struct glyph_row *r, *end_row;
window = window_from_coordinates (f, x, y, 0, &x, &y, 0);
if (!NILP (window))
{
struct window *w = XWINDOW (window);
struct glyph_row *r = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
struct glyph_row *end = r + w->current_matrix->nrows - 1;
if (NILP (window))
return 0;
for (; !found && r < end && r->enabled_p; ++r)
if (r->y >= y)
{
struct glyph *g = r->glyphs[TEXT_AREA];
struct glyph *end = g + r->used[TEXT_AREA];
int gx;
w = XWINDOW (window);
r = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
end_row = r + w->current_matrix->nrows - 1;
for (gx = r->x; !found && g < end; gx += g->pixel_width, ++g)
if (gx >= x)
{
rect->width = g->pixel_width;
rect->height = r->height;
rect->x = WINDOW_TO_FRAME_PIXEL_X (w, gx);
rect->y = WINDOW_TO_FRAME_PIXEL_Y (w, r->y);
found = 1;
}
}
for (; r < end_row && r->enabled_p; ++r)
{
if (r->y >= y)
{
struct glyph *g = r->glyphs[TEXT_AREA];
struct glyph *end = g + r->used[TEXT_AREA];
int gx = r->x;
while (g < end && gx < x)
gx += g->pixel_width, ++g;
if (g < end)
{
rect->width = g->pixel_width;
rect->height = r->height;
rect->x = WINDOW_TO_FRAME_PIXEL_X (w, gx);
rect->y = WINDOW_TO_FRAME_PIXEL_Y (w, r->y);
return 1;
}
break;
}
}
return found;
return 0;
}
......@@ -5648,6 +5623,11 @@ static XComposeStatus compose_status;
static int temp_index;
static short temp_buffer[100];
#define STORE_KEYSYM_FOR_DEBUG(keysym) \
if (temp_index == sizeof temp_buffer / sizeof (short)) \
temp_index = 0; \
temp_buffer[temp_index++] = (keysym)
/* Set this to nonzero to fake an "X I/O error"
on a particular display. */
......@@ -5667,15 +5647,8 @@ static struct x_display_info *next_noop_dpyinfo;
f->output_data.x->saved_menu_event \
= (XEvent *) xmalloc (sizeof (XEvent)); \
bcopy (&event, f->output_data.x->saved_menu_event, size); \
if (numchars >= 1) \
{ \
bufp->kind = MENU_BAR_ACTIVATE_EVENT; \
XSETFRAME (bufp->frame_or_window, f); \
bufp->arg = Qnil; \
bufp++; \
count++; \
numchars--; \
} \
inev.kind = MENU_BAR_ACTIVATE_EVENT; \
XSETFRAME (inev.frame_or_window, f); \
} \
while (0)
......@@ -5717,14 +5690,13 @@ x_filter_event (dpyinfo, event)
#endif
#ifdef USE_GTK
static struct input_event **current_bufp;
static int *current_numcharsp;
static int current_count;
static int current_finish;
static struct input_event *current_hold_quit;
/* This is the filter function invoked by the GTK event loop.
It is invoked before the XEvent is translated to a GdkEvent,
so we have a chanse to act on the event before GTK. */
so we have a chance to act on the event before GTK. */
static GdkFilterReturn
event_handler_gdk (gxev, ev, data)
GdkXEvent *gxev;
......@@ -5733,7 +5705,7 @@ event_handler_gdk (gxev, ev, data)
{
XEvent *xev = (XEvent *) gxev;
if (current_numcharsp)
if (current_count >= 0)
{
struct x_display_info *dpyinfo;
......@@ -5751,11 +5723,11 @@ event_handler_gdk (gxev, ev, data)
if (! dpyinfo)
current_finish = X_EVENT_NORMAL;
else
current_count += handle_one_xevent (dpyinfo,
xev,
current_bufp,
current_numcharsp,
&current_finish);
{
current_count +=
handle_one_xevent (dpyinfo, xev, &current_finish,
current_hold_quit);
}
}
else
current_finish = x_dispatch_event (xev, xev->xany.display);
......@@ -5774,28 +5746,29 @@ event_handler_gdk (gxev, ev, data)
*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)
handle_one_xevent (dpyinfo, eventp, finish, hold_quit)
struct x_display_info *dpyinfo;
XEvent *eventp;
/* register */ struct input_event **bufp_r;
/* register */ int *numcharsp;
int *finish;
struct input_event *hold_quit;
{
struct input_event inev;
int count = 0;
int do_help = 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;
EVENT_INIT (inev);
inev.kind = NO_EVENT;
inev.arg = Qnil;
switch (event.type)
{
case ClientMessage:
......@@ -5850,8 +5823,10 @@ handle_one_xevent (dpyinfo, eventp, bufp_r, numcharsp, finish)
}
/* Not certain about handling scroll bars here */
#endif /* 0 */
goto done;
}
else if (event.xclient.data.l[0]
if (event.xclient.data.l[0]
== dpyinfo->Xatom_wm_save_yourself)
{
/* Save state modify the WM_COMMAND property to
......@@ -5862,11 +5837,9 @@ handle_one_xevent (dpyinfo, eventp, bufp_r, numcharsp, finish)
/* 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 ()
if (! x_session_have_connection ())
#endif
)
{
f = x_top_window_to_frame (dpyinfo,
event.xclient.window);
......@@ -5881,41 +5854,36 @@ handle_one_xevent (dpyinfo, eventp, bufp_r, numcharsp, finish)
event.xclient.window,
0, 0);
}
goto done;
}
else if (event.xclient.data.l[0]
== dpyinfo->Xatom_wm_delete_window)
if (event.xclient.data.l[0]
== dpyinfo->Xatom_wm_delete_window)
{
struct frame *f
= x_any_window_to_frame (dpyinfo,
f = x_any_window_to_frame (dpyinfo,
event.xclient.window);
if (!f)
goto OTHER; /* May be a dialog that is to be removed */
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 */
inev.kind = DELETE_WINDOW_EVENT;
XSETFRAME (inev.frame_or_window, f);
goto done;
}
goto done;
}
else if (event.xclient.message_type
if (event.xclient.message_type
== dpyinfo->Xatom_wm_configure_denied)
{
goto done;
}
else if (event.xclient.message_type
== dpyinfo->Xatom_wm_window_moved)
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);
f = x_window_to_frame (dpyinfo, event.xclient.window);
new_x = event.xclient.data.s[0];
new_y = event.xclient.data.s[1];
......@@ -5925,63 +5893,55 @@ handle_one_xevent (dpyinfo, eventp, bufp_r, numcharsp, finish)
f->left_pos = new_x;
f->top_pos = new_y;
}
goto done;
}
#ifdef HACK_EDITRES
else if (event.xclient.message_type
== dpyinfo->Xatom_editres)
if (event.xclient.message_type
== dpyinfo->Xatom_editres)
{
struct frame *f
= x_any_window_to_frame (dpyinfo, event.xclient.window);
f = x_any_window_to_frame (dpyinfo, event.xclient.window);
_XEditResCheckMessages (f->output_data.x->widget, NULL,
&event, NULL);
goto done;
}
#endif /* HACK_EDITRES */
else if ((event.xclient.message_type
== dpyinfo->Xatom_DONE)
|| (event.xclient.message_type
== dpyinfo->Xatom_PAGE))
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);
f = x_window_to_frame (dpyinfo, event.xclient.window);
x_kill_gs_process (pixmap, f);
expose_frame (f, 0, 0, 0, 0);
goto done;
}
#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)
if (event.xclient.message_type
== dpyinfo->Xatom_Scrollbar)
{
x_scroll_bar_to_input_event (&event, bufp);
++bufp, ++count, --numchars;
goto out;
x_scroll_bar_to_input_event (&event, &inev);
*finish = X_EVENT_GOTO_OUT;
goto done;
}
#endif /* USE_TOOLKIT_SCROLL_BARS */
else
{
struct frame *f
= x_any_window_to_frame (dpyinfo, event.xclient.window);
if (f)
{
int ret = x_handle_dnd_message (f, &event.xclient,
dpyinfo, bufp);
if (ret > 0)
{
++bufp, ++count, --numchars;
}
f = x_any_window_to_frame (dpyinfo, event.xclient.window);
if (ret != 0)
*finish = X_EVENT_DROP;
}
else
goto OTHER;
}
if (!f)
goto OTHER;
if (x_handle_dnd_message (f, &event.xclient, dpyinfo, &inev))
*finish = X_EVENT_DROP;
}
break;
......@@ -6001,19 +5961,11 @@ handle_one_xevent (dpyinfo, eventp, bufp_r, numcharsp, finish)
{
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;
inev.kind = SELECTION_CLEAR_EVENT;
SELECTION_EVENT_DISPLAY (&inev) = eventp->display;
SELECTION_EVENT_SELECTION (&inev) = eventp->selection;
SELECTION_EVENT_TIME (&inev) = eventp->time;
inev.frame_or_window = Qnil;
}
break;
......@@ -6030,22 +5982,14 @@ handle_one_xevent (dpyinfo, eventp, bufp_r, numcharsp, finish)
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;
inev.kind = SELECTION_REQUEST_EVENT;
SELECTION_EVENT_DISPLAY (&inev) = eventp->display;
SELECTION_EVENT_REQUESTOR (&inev) = eventp->requestor;
SELECTION_EVENT_SELECTION (&inev) = eventp->selection;
SELECTION_EVENT_TARGET (&inev) = eventp->target;
SELECTION_EVENT_PROPERTY (&inev) = eventp->property;
SELECTION_EVENT_TIME (&inev) = eventp->time;
inev.frame_or_window = Qnil;
}
break;
......@@ -6075,7 +6019,6 @@ handle_one_xevent (dpyinfo, eventp, bufp_r, numcharsp, finish)
FRAME_X_DISPLAY_INFO (f)->wm_type = X_WMTYPE_UNKNOWN;
}
goto OTHER;
break;
case Expose:
f = x_window_to_frame (dpyinfo, event.xexpose.window);
......@@ -6177,12 +6120,8 @@ handle_one_xevent (dpyinfo, eventp, bufp_r, numcharsp, finish)
{
f->async_iconified = 1;
bufp->kind = ICONIFY_EVENT;
XSETFRAME (bufp->frame_or_window, f);
bufp->arg = Qnil;
bufp++;
count++;
numchars--;
inev.kind = ICONIFY_EVENT;
XSETFRAME (inev.frame_or_window, f);
}
}
goto OTHER;
......@@ -6214,12 +6153,8 @@ handle_one_xevent (dpyinfo, eventp, bufp_r, numcharsp, finish)
if (f->iconified)
{
bufp->kind = DEICONIFY_EVENT;
XSETFRAME (bufp->frame_or_window, f);
bufp->arg = Qnil;
bufp++;
count++;
numchars--;
inev.kind = DEICONIFY_EVENT;
XSETFRAME (inev.frame_or_window, f);
}
else if (! NILP (Vframe_list)
&& ! NILP (XCDR (Vframe_list)))
......@@ -6280,6 +6215,7 @@ handle_one_xevent (dpyinfo, eventp, bufp_r, numcharsp, finish)
int copy_bufsiz = sizeof (copy_buffer);
int modifiers;
Lisp_Object coding_system = Qlatin_1;
Lisp_Object c;
event.xkey.state
|= x_emacs_to_x_modifiers (FRAME_X_DISPLAY_INFO (f),
......@@ -6373,49 +6309,37 @@ handle_one_xevent (dpyinfo, eventp, bufp_r, numcharsp, finish)
orig_keysym = keysym;
if (numchars > 1)
{
Lisp_Object c;
/* Common for all keysym input events. */
XSETFRAME (inev.frame_or_window, f);
inev.modifiers
= x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f), modifiers);
inev.timestamp = event.xkey.time;
/* 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)
/* First deal with keysyms which have defined
translations to characters. */
if (keysym >= 32 && keysym < 128)
/* Avoid explicitly decoding each ASCII character. */
{
inev.kind = ASCII_KEYSTROKE_EVENT;
inev.code = keysym;
goto done_keysym;
}
/* Now non-ASCII. */
if (HASH_TABLE_P (Vx_keysym_table)
&& (NATNUMP (c = Fgethash (make_number (keysym),
Vx_keysym_table,
Qnil))))
{
inev.kind = (SINGLE_BYTE_CHAR_P (XFASTINT (c))
? ASCII_KEYSTROKE_EVENT
: MULTIBYTE_CHAR_KEYSTROKE_EVENT);
inev.code = XFASTINT (c);
goto done_keysym;
}
/* Random non-modifier sorts of keysyms. */
if (((keysym >= XK_BackSpace && keysym <= XK_Escape)
|| keysym == XK_Delete
#ifdef XK_ISO_Left_Tab
|| (keysym >= XK_ISO_Left_Tab
......@@ -6496,104 +6420,80 @@ handle_one_xevent (dpyinfo, eventp, bufp_r, numcharsp, finish)
<= 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;