On Sun, 2 Feb 2003, Angus Leeming wrote: > Oh, well done ChangGil! A Happy start to the Old New Year!
So far so good. Happy about that! > Looking at the code in input.c, I see code in handle_key: > > SPEC *sp = ob->spec; > ... > /* merge the new character */ > for (i = slen + 1; i > sp->position; i--) > sp->str[i] = sp->str[i - 1]; > sp->str[sp->position] = key; > sp->position++; > > Does this provide you with the info you need? Yes, but how can I use this in forms.c? > It's hard to debug when I'm not sure exactly which of my patches "xforms.diff$ > you are talking about. Is this the big patch that is meant to clean-up the > way xforms passes keyboard events to the widgets? Sorry I was not clear. Yes, the big xforms.diff. > Allow me to clarify things for my own benefit here: you have CJK input and > display fully working in xforms' native widgets? Wow! Yes, on the box such as "Edit->(Find & Replace)" or "Insert->Label". > is insufficient for you. Do you not need to modify it to: > if (keysym == NoSymbol && kbuflen == 0) > return; Yes, with that modification I can input Korean characters on the XWorkArea. > because for you a 'fully composed' Korean character has keysym == 0 but the > information is stored in keybuf, kbuflen. My debug says that during the composition, keysym ==0 but 'fully composed' Korean character has non-zero keysym. That is, after "shift-space" keysym with each keyboard input is zero, but hitting "space-bar" gives non-zero keysym. > Is this event passed through to fl_handle_form from do_keyboard or does it > have keysym == 0 and is therefore 'swallowed' at the moment? Add a print > statement to do_keyboard! The events pass through to "fl_handle_form" with non-zero keysym in do_keyboard. > If the event is passed through to handle_key in input.c, then how do you > handle it? I don't know. Why do you consider that? > It appears that you have found the offending code in do_keyboard. Does > modifying it as I suggest above 'do the right thing'? Yes. > It's really hard writing code this way isn't it! Life would be easier if we > were using cvs to store the xforms source. Attached is my trial patch againt the clean xforms-1.0-release.tgz. > Does any of the above help you? Not to mention, Angus. Regards, cghan
diff -urdN xforms-1.0-release/Imakefile xforms-modified/Imakefile --- xforms-1.0-release/Imakefile 2002-12-04 02:25:43.000000000 +0900 +++ xforms-modified/Imakefile 2003-02-03 07:49:49.000000000 +0900 @@ -100,7 +100,7 @@ image \ $(GL) \ fdesign \ - fd2ps \ + fd2ps \ $(DEMOS) IMAKE_DEFINES = \ diff -urdN xforms-1.0-release/X11/X11/forms.h xforms-modified/X11/X11/forms.h --- xforms-1.0-release/X11/X11/forms.h 2002-06-07 04:05:48.000000000 +0900 +++ xforms-modified/X11/X11/forms.h 2003-02-03 07:47:47.000000000 +0900 @@ -729,6 +729,11 @@ void (*pre_attach)(struct forms_ *); void *attach_data; int no_tooltip; +#ifdef XlibSpecificationRelease + XIC xic ; /* input context */ +#else + void *xic; +#endif int reserved[10]; /* future use */ } FL_FORM; @@ -891,6 +896,11 @@ FL_OBJECT *ob ); +FL_EXPORT void ol_get_composed_string( + int * ptr_kbuflen, + char const * ptr_keybuf + ); + #define fl_set_object_focus fl_set_focus_object FL_EXPORT FL_FORM_ATCLOSE fl_set_form_atclose( @@ -987,6 +997,10 @@ FL_FORMCALLBACKPTR callback, void *d ); +FL_EXPORT void fl_get_composed_string( + int * ptr_kbuflen, + char const ** ptr_keybuf + ); #define fl_set_form_call_back fl_set_form_callback @@ -1409,7 +1423,6 @@ int *height ); - #define fl_get_string_size fl_get_string_dimension FL_EXPORT void fl_get_align_xy( diff -urdN xforms-1.0-release/exports/include/X11/forms.h xforms-modified/exports/include/X11/forms.h --- xforms-1.0-release/exports/include/X11/forms.h 2002-06-07 04:05:48.000000000 +0900 +++ xforms-modified/exports/include/X11/forms.h 2003-02-03 07:47:47.000000000 +0900 @@ -729,6 +729,11 @@ void (*pre_attach)(struct forms_ *); void *attach_data; int no_tooltip; +#ifdef XlibSpecificationRelease + XIC xic ; /* input context */ +#else + void *xic; +#endif int reserved[10]; /* future use */ } FL_FORM; @@ -891,6 +896,11 @@ FL_OBJECT *ob ); +FL_EXPORT void ol_get_composed_string( + int * ptr_kbuflen, + char const * ptr_keybuf + ); + #define fl_set_object_focus fl_set_focus_object FL_EXPORT FL_FORM_ATCLOSE fl_set_form_atclose( @@ -987,6 +997,10 @@ FL_FORMCALLBACKPTR callback, void *d ); +FL_EXPORT void fl_get_composed_string( + int * ptr_kbuflen, + char const ** ptr_keybuf + ); #define fl_set_form_call_back fl_set_form_callback @@ -1409,7 +1423,6 @@ int *height ); - #define fl_get_string_size fl_get_string_dimension FL_EXPORT void fl_get_align_xy( diff -urdN xforms-1.0-release/lib/X11/X11/forms.h xforms-modified/lib/X11/X11/forms.h --- xforms-1.0-release/lib/X11/X11/forms.h 2002-06-07 04:05:48.000000000 +0900 +++ xforms-modified/lib/X11/X11/forms.h 2003-02-03 07:47:47.000000000 +0900 @@ -729,6 +729,11 @@ void (*pre_attach)(struct forms_ *); void *attach_data; int no_tooltip; +#ifdef XlibSpecificationRelease + XIC xic ; /* input context */ +#else + void *xic; +#endif int reserved[10]; /* future use */ } FL_FORM; @@ -891,6 +896,11 @@ FL_OBJECT *ob ); +FL_EXPORT void ol_get_composed_string( + int * ptr_kbuflen, + char const * ptr_keybuf + ); + #define fl_set_object_focus fl_set_focus_object FL_EXPORT FL_FORM_ATCLOSE fl_set_form_atclose( @@ -987,6 +997,10 @@ FL_FORMCALLBACKPTR callback, void *d ); +FL_EXPORT void fl_get_composed_string( + int * ptr_kbuflen, + char const ** ptr_keybuf + ); #define fl_set_form_call_back fl_set_form_callback @@ -1409,7 +1423,6 @@ int *height ); - #define fl_get_string_size fl_get_string_dimension FL_EXPORT void fl_get_align_xy( diff -urdN xforms-1.0-release/lib/exports/include/X11/forms.h xforms-modified/lib/exports/include/X11/forms.h --- xforms-1.0-release/lib/exports/include/X11/forms.h 2002-06-07 04:05:48.000000000 +0900 +++ xforms-modified/lib/exports/include/X11/forms.h 2003-02-03 07:47:47.000000000 ++0900 @@ -729,6 +729,11 @@ void (*pre_attach)(struct forms_ *); void *attach_data; int no_tooltip; +#ifdef XlibSpecificationRelease + XIC xic ; /* input context */ +#else + void *xic; +#endif int reserved[10]; /* future use */ } FL_FORM; @@ -891,6 +896,11 @@ FL_OBJECT *ob ); +FL_EXPORT void ol_get_composed_string( + int * ptr_kbuflen, + char const * ptr_keybuf + ); + #define fl_set_object_focus fl_set_focus_object FL_EXPORT FL_FORM_ATCLOSE fl_set_form_atclose( @@ -987,6 +997,10 @@ FL_FORMCALLBACKPTR callback, void *d ); +FL_EXPORT void fl_get_composed_string( + int * ptr_kbuflen, + char const ** ptr_keybuf + ); #define fl_set_form_call_back fl_set_form_callback @@ -1409,7 +1423,6 @@ int *height ); - #define fl_get_string_size fl_get_string_dimension FL_EXPORT void fl_get_align_xy( diff -urdN xforms-1.0-release/lib/flinternal.h xforms-modified/lib/flinternal.h --- xforms-1.0-release/lib/flinternal.h 2002-05-21 04:38:39.000000000 +0900 +++ xforms-modified/lib/flinternal.h 2003-02-03 07:48:14.000000000 +0900 @@ -411,10 +411,10 @@ int tooltip_time; #ifdef XlibSpecificationRelease XIM xim ; /* input method */ - XIC xic ; /* input context */ +// XIC xic ; /* input context */ #else void *xim; - void *xic; +// void *xic; #endif unsigned int navigate_mask; /* input field */ long reserverd[6]; @@ -490,6 +490,7 @@ #define IsEnd(k) (k==XK_End || k==XK_KP_End) #define IsPageDown(k) (k==XK_Next || k==XK_Page_Down || k==XK_KP_Page_Down) #define IsPageUp(k) (k==XK_Prior || k==XK_Page_Up || k==XK_KP_Page_Up) +#define IsReturn(k) (k==XK_Return || k==XK_KP_Enter) #else #define IsHome(k) (k==XK_Home || k== XK_Begin) #define IsLeft(k) (k==XK_Left) @@ -499,6 +500,7 @@ #define IsEnd(k) (k==XK_End) #define IsPageDown(k) (k==XK_Next) #define IsPageUp(k) (k==XK_Prior) +#define IsReturn(k) (k==XK_Return) #endif #define FL_HALFPAGE_UP 0x10000000 @@ -514,6 +516,15 @@ #define Is1LineUp(k) ((k)==FL_1LINE_UP) #define Is1LineDown(k) ((k)==FL_1LINE_DOWN) +#define IsFLCursorKey(k) (IsHome(k) || IsLeft(k) || \ + IsRight(k) || IsUp(k) || \ + IsDown(k) || IsEnd(k) || \ + IsPageDown(k) || IsPageUp(k) || \ + IsReturn(k) || IsHalfPageUp(k) || \ + IsHalfPageDown(k) || IsNLinesUp(k) || \ + IsNLinesDown(k) || Is1LineUp(k) || \ + Is1LineDown(k)) + extern int fl_convert_shortcut(const char *, long *); extern int fl_get_underline_pos(const char *, const char *); diff -urdN xforms-1.0-release/lib/flresource.c xforms-modified/lib/flresource.c --- xforms-1.0-release/lib/flresource.c 2002-06-02 07:09:37.000000000 +0900 +++ xforms-modified/lib/flresource.c 2003-02-03 07:48:05.000000000 +0900 @@ -947,22 +947,60 @@ fl_init_font(); fl_init_fl_context(); -#ifdef XlibSpecificationRelease - if (XSupportsLocale()) - { - XSetLocaleModifiers(""); +//#ifdef XlibSpecificationRelease + // if (XSupportsLocale()) + // { + // XSetLocaleModifiers(""); /* use the same input method throughout xforms */ - fl_context->xim = XOpenIM(fl_display, 0, 0, 0); + // fl_context->xim = XOpenIM(fl_display, 0, 0, 0); /* also use the same input context */ - if (fl_context->xim) +/* if (fl_context->xim) { - int style = XIMPreeditNothing|XIMStatusNothing; - fl_context->xic = XCreateIC(fl_context->xim, - XNInputStyle, style, - 0); - } - } -#endif + XIMStyles *styles = 0; + XIMStyle xim_style = 0; + XIMStyle xim_preferred_style = XIMPreeditPosition|XIMStatusNothing; + XGetIMValues(fl_context->xim, XNQueryInputStyle, &styles, (char *) 0, +(char *) 0 ); + if ( styles ) { + int i; + for ( i = 0; !xim_style && i < styles->count_styles; i++ ) { + if ( styles->supported_styles[i] == xim_preferred_style ) { + xim_style = xim_preferred_style; + break; + } + } + + for ( i = 0; !xim_style && i < styles->count_styles; i++ ) { + if ( styles->supported_styles[i] == (XIMPreeditNothing | + XIMStatusNothing) ) { + xim_style = XIMPreeditNothing | XIMStatusNothing; + break; + } + } + + for ( i = 0; !xim_style && i < styles->count_styles; i++ ) { + if ( styles->supported_styles[i] == (XIMPreeditNone | + XIMStatusNone) ) { + xim_style = XIMPreeditNone | XIMStatusNone; + break; + } + } + + XFree( (char *)styles ); + } + fl_context->xic = XCreateIC(fl_context->xim, + XNInputStyle, xim_style, + 0); */ + /* Clean-up on failure */ +/* if (!fl_context->xic) { + M_err("fl_initialize", "Could not create an input context"); + XCloseIM (fl_context->xim); + fl_context->xim; + } + } else + M_err("fl_initialize", "Could not create an input method");*/ + +// } +//#endif fl_default_xswa(); fl_init_stipples(); set_err_msg_func(fl_show_alert); diff -urdN xforms-1.0-release/lib/forms.c xforms-modified/lib/forms.c --- xforms-1.0-release/lib/forms.c 2002-11-20 06:06:43.000000000 +0900 +++ xforms-modified/lib/forms.c 2003-02-03 07:47:41.000000000 +0900 @@ -53,6 +53,7 @@ #define SHORT_PAUSE 10 /* check_form wait */ +#define DEFAULT_FONT_NAME "-*-*-*-r-normal--14-130-75-75-*-*" void fl_set_no_connection(int yes) @@ -543,6 +544,7 @@ long screenw, screenh; int itx = 0, ity = 0, dont_fix_size = 0; FL_Coord mx, my, nmx, nmy; + XSetWindowAttributes st_xswa; if (border == 0) border = FL_FULLBORDER; @@ -734,6 +736,114 @@ if (border == FL_FULLBORDER || (form->prop & FL_COMMAND_PROP)) fl_set_form_property(form, FL_COMMAND_PROP); + + if (XSupportsLocale()) + { + XSetLocaleModifiers(""); + /* use the same input method throughout xforms */ + fl_context->xim = XOpenIM(fl_display, 0, 0, 0); + + if (fl_context->xim) + { + char **missing_list; + int missing_count; + char *def_string; + XRectangle pre_area; + XPoint location; + XVaNestedList status_list; + XVaNestedList preedit_list; + XIMStyles *styles = 0; + XIMStyle xim_style = 0; + XIMStyle xim_preferred_style = XIMPreeditPosition|XIMStatusNothing; + + XFontSet fontset = XCreateFontSet(fl_display, DEFAULT_FONT_NAME, +&missing_list, + &missing_count, &def_string); + + XGetIMValues(fl_context->xim, XNQueryInputStyle, &styles, (char *) 0, (char +*) 0); + + if ( styles ) { + int i; + for ( i = 0; !xim_style && i < styles->count_styles; i++ ) { + if ( styles->supported_styles[i] == +xim_preferred_style ) { xim_style = +xim_preferred_style; + break; + } + } + for ( i = 0; !xim_style && i < styles->count_styles; i++ ) { + if ( styles->supported_styles[i] == (XIMPreeditNothing | + XIMStatusNothing) ) +{ + xim_style = XIMPreeditNothing | XIMStatusNothing; + break; + } + } + for ( i = 0; !xim_style && i < styles->count_styles; i++ ) { + if ( styles->supported_styles[i] == (XIMPreeditNone | + XIMStatusNone) ) +{ + xim_style = XIMPreeditNone | XIMStatusNone; + break; + } + } + XFree( (char *)styles ); + } + + pre_area.x = 0; + pre_area.y = 0; + pre_area.width = form->w; + pre_area.height = form->h; + + location.x = form->first->x; + location.y = form->first->y; + + status_list = XVaCreateNestedList( 0, + XNFontSet, fontset, + 0); + + preedit_list = XVaCreateNestedList( 0, + XNSpotLocation, &location, + XNFontSet, fontset, +// XNArea, &pre_area, + 0); + + if(preedit_list){ + form->xic = XCreateIC(fl_context->xim, + XNInputStyle, xim_style, + XNClientWindow, form->window, + XNFocusWindow, form->window, + XNPreeditAttributes, preedit_list, + XNStatusAttributes, status_list, + 0); + + XFree(preedit_list); + XFree(status_list); + }else + form->xic = XCreateIC(fl_context->xim, + XNInputStyle, xim_style, + XNClientWindow, form->window, + 0); + + if(!form->xic){ + M_err("fl_initialize", "Could not create an input context"); + (void) XSetICValues((XIC) form->xic, XNResetState, XIMPreserveState, +(char *) 0); + XCloseIM (fl_context->xim); + fl_context->xim = 0; + return; + } + + // SPEC * sp = form->focusobj->spec; + + location.x = form->focusobj->x; + location.y = form->focusobj->y; + preedit_list = XVaCreateNestedList( 0, + XNSpotLocation, &location, + XNFontSet, fontset, + 0); + XSetICValues((XIC) form->xic, XNPreeditAttributes, preedit_list, (char *) +0); + XFree(preedit_list); + } + } + + if(form->xic) + st_xswa.event_mask |= FocusChangeMask; + return form->window; } @@ -793,6 +903,8 @@ else fl_XPutBackEvent(&xev); + + XDestroyIC(form->xic); } #else /* suspend timeout and IO stuff. need to complete hide_form without @@ -1161,7 +1273,8 @@ } } - M_info("Shortcut", "win=%lu key=%d %d %d", form->window, key, key1, key2); + M_info("Shortcut", "win=%lu key=%d %d %d %d", + form->window, key, key1, key2); /* Check whether an object has this as shortcut. */ for (i = -1; obj1; obj1 = obj1->next, i = -1) @@ -1218,7 +1331,8 @@ } static void -fl_keyboard(FL_FORM * form, int key, FL_Coord x, FL_Coord y, void *xev) +fl_keyboard(int event, + FL_FORM * form, int key, FL_Coord x, FL_Coord y, void *xev) { FL_OBJECT *obj, *obj1, *special; @@ -1228,7 +1342,7 @@ /* focus policy is done as follows: Input object has the highiest priority. Next is the object that wants special keys which is followed - by mouseobj that has the lowest. Focusobj == FL_INPUT OBJ */ + by mouseobj that has the lowest. */ special = fl_find_first(form, FL_FIND_KEYSPECIAL, 0, 0); obj1 = special ? fl_find_object(special->next, FL_FIND_KEYSPECIAL, 0, 0) : 0; @@ -1239,33 +1353,30 @@ if (obj1 && obj1 != special) special = fl_mouseobj; - if (form->focusobj) + /* Focusobj == FL_INPUT OBJ */ + if (event == FL_KEYPRESS && form->focusobj) { FL_OBJECT *focusobj = form->focusobj; + int special_key = 0; - /* handle special keys first */ - if (key > 255) - { - if (IsLeft(key) || IsRight(key) || IsHome(key) || IsEnd(key)) - fl_handle_object(focusobj, FL_KEYBOARD, x, y, key, xev); - else if ((IsUp(key) || IsDown(key) || - IsPageUp(key) || IsPageDown(key)) && - (focusobj->wantkey & FL_KEY_TAB)) - fl_handle_object(focusobj, FL_KEYBOARD, x, y, key, xev); - else if (special && (special->wantkey & FL_KEY_SPECIAL)) - { - /* moving the cursor in input field that does not have focus - looks weird */ - if (special->objclass != FL_INPUT) - fl_handle_object(special, FL_KEYBOARD, x, y, key, xev); + /* Handle positioning keys first. + Let the FL_OBJECT tell us whether it has done anything. */ + if (IsFLCursorKey(key)) { + if (fl_handle_object_direct(focusobj, event, x, y, key, xev)) { + fl_object_qenter(focusobj); + return; + } + + if (special && (special->wantkey & FL_KEY_SPECIAL) && + special->objclass != FL_INPUT && + fl_handle_object_direct(special, event, x, y, key, xev)) { + fl_object_qenter(special); + return; } - else if (key == XK_BackSpace || key == XK_Delete) - fl_handle_object(focusobj, FL_KEYBOARD, x, y, key, xev); - return; } - /* dispatch tab & return switches focus if not FL_KEY_TAB */ - if ((key == 9 || key == 13) && !(focusobj->wantkey & FL_KEY_TAB)) + /* Dispatch tab & return switches focus if not FL_KEY_TAB */ + if ((IsTab(key) || IsReturn(key)) && !(focusobj->wantkey & FL_KEY_TAB)) { if ((((XKeyEvent *) xev)->state & fl_context->navigate_mask)) { @@ -1284,7 +1395,7 @@ fl_handle_object(obj, FL_FOCUS, x, y, 0, xev); } else if (focusobj->wantkey != FL_KEY_SPECIAL) - fl_handle_object(focusobj, FL_KEYBOARD, x, y, key, xev); + fl_handle_object(focusobj, event, x, y, key, xev); return; } @@ -1294,11 +1405,11 @@ /* space is an exception for browser */ if ((key > 255 || key == ' ') && (special->wantkey & FL_KEY_SPECIAL)) - fl_handle_object(special, FL_KEYBOARD, x, y, key, xev); + fl_handle_object(special, event, x, y, key, xev); else if (key < 255 && (special->wantkey & FL_KEY_NORMAL)) - fl_handle_object(special, FL_KEYBOARD, x, y, key, xev); + fl_handle_object(special, event, x, y, key, xev); else if (special->wantkey == FL_KEY_ALL) - fl_handle_object(special, FL_KEYBOARD, x, y, key, xev); + fl_handle_object(special, event, x, y, key, xev); #if FL_DEBUG >= ML_INFO M_info("KeyBoard", "(%d %d)pushing %d to %s\n", x, y, key, special->label); @@ -1424,8 +1535,9 @@ fl_pushobj = NULL; fl_handle_object(obj, FL_RELEASE, xx, yy, key, xev); break; - case FL_KEYBOARD: /* A key was pressed */ - fl_keyboard(form, key, xx, yy, xev); + case FL_KEYPRESS: /* A key was pressed */ + case FL_KEYRELEASE: /* A key was released */ + fl_keyboard(event, form, key, xx, yy, xev); break; case FL_STEP: /* A simple step */ obj1 = fl_find_first(form, FL_FIND_AUTOMATIC, 0, 0); @@ -1506,23 +1618,44 @@ #endif /* } */ +/* These vars are initialised in do_keyboard. + * They are global vars so that we can make them accessible to the outside + * world. CJK users will find them useful. + */ +static int kbuflen; +static char keybuf[256]; + +void fl_get_composed_string(int * ptr_kbuflen, char const ** ptr_keybuf) +{ + printf("len1=%d\n",kbuflen); + printf("keybuf1=%s\n",keybuf); + + if (!ptr_kbuflen) return; + *ptr_kbuflen = kbuflen; + *ptr_keybuf = keybuf; + +// printf("%s",1); + printf("keybuf2=%s\n",keybuf); +} + /* formevent is either FL_KEYPRESS or FL_KEYRELEASE */ static void do_keyboard(XEvent * xev, int formevent) { - Window win; - int kbuflen; + KeySym keysym = 0; + static KeySym last_pressed_keysym; + unsigned char * ch; - /* before doing anything, save the current modifier key for the handlers */ + /* Before doing anything, save the current modifier key for the handlers. */ win = xev->xkey.window; fl_keymask = xev->xkey.state; if (win && (!keyform || !fl_is_good_form(keyform))) keyform = fl_win_to_form(win); - /* switch keyboard input only if different top-level form */ + /* Switch keyboard input only if different top-level form. */ if (keyform && keyform->window != win) { M_warn("KeyEvent", "pointer/keybd focus differ"); @@ -1533,67 +1666,51 @@ keyform = fl_win_to_form(win); } - if ( keyform ) { - - KeySym keysym = 0; - unsigned char keybuf[227]; - - kbuflen = fl_XLookupString((XKeyEvent *) xev, (char *) keybuf, - sizeof(keybuf), &keysym); - - if (kbuflen < 0) { - - if ( kbuflen != INT_MIN ) { - - /* buffer overflow, should not happen */ - M_err("DoKeyBoard", "keyboad buffer overflow ?"); - - } else { + if (!keyform) + return; - M_err("DoKeyBoard", "fl_XLookupString failed ?"); - - } + /* Note that the behaviour of XmbLookupString is undefined on a KeyRelease + event, so we do not attempt to call fl_XLookupString. + Rather, we store the keysym of the previous FL_KEYPRESS event + and dispatch that. */ + if (formevent == FL_KEYRELEASE) { + fl_handle_form(keyform, FL_KEYRELEASE, last_pressed_keysym, xev); + return; + } + kbuflen = fl_XLookupString((XKeyEvent *) xev, (char *) keybuf, + sizeof(keybuf), &keysym); +printf("xforms_keybuflen =%d \n",kbuflen); + if (kbuflen < 0) { + if ( kbuflen != INT_MIN ) { + /* buffer overflow, should not happen */ + M_err("DoKeyBoard", "keyboad buffer overflow ?"); } else { - - /* ignore modifier keys as they don't cause action and are - taken care of by the lookupstring routine */ - - if (IsModifierKey(keysym)) - ; - else if (IsTab(keysym)) { - - /* fake a tab key. */ - /* some system shift+tab does not generate tab */ - - fl_handle_form(keyform, formevent, 9, xev); - - } -#if (FL_DEBUG >= ML_DEBUG ) - else if (keysym == XK_F10) /* && controlkey_down(fl_keymask)) */ - hack_test(); -#endif - - /* pass all keys to the handler */ - else if (IsCursorKey(keysym) || kbuflen == 0) - fl_handle_form(keyform, formevent, keysym, xev); - else { - - unsigned char *ch; - - /* all regular keys, including mapped strings */ - - for (ch = keybuf; ch < (keybuf + kbuflen) && keyform; ch++) - fl_handle_form(keyform, formevent, *ch, xev); - - } - + M_err("DoKeyBoard", "fl_XLookupString failed ?"); } - + return; } + /* keysym == NoSymbol during multi-byte char composition. + Eg, I've typed Multi_key-a but not yet ' to give á + Silently swallow these partial-compositions. */ + if (keysym == NoSymbol /*&& kbuflen == 0*/) + return; + + /* Ignore modifier keys as they don't cause action and are + taken care of by the LookupString routine. */ + if (IsModifierKey(keysym)) + return; + + /* Dispatch the key event */ + printf("TEST-HANDLE\n"); + fl_handle_form(keyform, formevent, keysym, xev); + printf("keysym =%d\n",keysym); + /* Record the keysym for the next KEYRELEASE event. */ + last_pressed_keysym = keysym; } + FL_FORM_ATCLOSE fl_set_form_atclose(FL_FORM * form, FL_FORM_ATCLOSE fmclose, void *data) { @@ -1860,10 +1977,10 @@ return; case FocusIn: - if (fl_context->xic) + if (evform->xic) { M_info("Focus", "Setting focus window for IC"); - XSetICValues(fl_context->xic, + XSetICValues(evform->xic, XNFocusWindow, st_xev.xfocus.window, XNClientWindow, st_xev.xfocus.window, 0); @@ -2785,8 +2902,16 @@ fl_XLookupString(XKeyEvent * xkey, char *buf, int buflen, KeySym * ks) { int len = INT_MIN; + FL_FORM * f; - if (!fl_context->xic) + f = fl_win_to_form(xkey->window); + + /* Note that the behaviour of XmbLookupString is undefined on a KeyRelease + event. Safest therefore to bail out in such a situation. */ +/* if (xkey->type != KeyPress) + return 0; */ + + if (!f->xic) { len = XLookupString(xkey, buf, buflen, ks, 0); } @@ -2800,14 +2925,26 @@ return 0; } - len = - XmbLookupString(fl_context->xic, xkey, buf, buflen, ks, &status); + len = XmbLookupString(f->xic, xkey, buf, buflen, ks, &status); switch (status) { case XBufferOverflow: - len = -len; +// len = -len; break; + case XLookupBoth: + break; + case XLookupChars: + *ks = NoSymbol; + break; + case XLookupKeySym: + len = 0; + break; + case XLookupNone: + *ks = NoSymbol; + len = 0; + break; + default: break; } diff -urdN xforms-1.0-release/lib/forms.h xforms-modified/lib/forms.h --- xforms-1.0-release/lib/forms.h 2002-06-07 04:05:48.000000000 +0900 +++ xforms-modified/lib/forms.h 2003-02-03 07:47:47.000000000 +0900 @@ -729,6 +729,11 @@ void (*pre_attach)(struct forms_ *); void *attach_data; int no_tooltip; +#ifdef XlibSpecificationRelease + XIC xic ; /* input context */ +#else + void *xic; +#endif int reserved[10]; /* future use */ } FL_FORM; @@ -891,6 +896,11 @@ FL_OBJECT *ob ); +FL_EXPORT void ol_get_composed_string( + int * ptr_kbuflen, + char const * ptr_keybuf + ); + #define fl_set_object_focus fl_set_focus_object FL_EXPORT FL_FORM_ATCLOSE fl_set_form_atclose( @@ -987,6 +997,10 @@ FL_FORMCALLBACKPTR callback, void *d ); +FL_EXPORT void fl_get_composed_string( + int * ptr_kbuflen, + char const ** ptr_keybuf + ); #define fl_set_form_call_back fl_set_form_callback @@ -1409,7 +1423,6 @@ int *height ); - #define fl_get_string_size fl_get_string_dimension FL_EXPORT void fl_get_align_xy( diff -urdN xforms-1.0-release/lib/input.c xforms-modified/lib/input.c --- xforms-1.0-release/lib/input.c 2002-06-04 02:57:29.000000000 +0900 +++ xforms-modified/lib/input.c 2003-02-03 07:50:42.000000000 +0900 @@ -705,7 +705,7 @@ int ret = 1, i, j; int prev = 1; - if (key == kmap.del_prev_char || key == kmap.backspace) + if (key == XK_BackSpace) { prev = -1; if (sp->endrange >= 0) @@ -717,7 +717,7 @@ else ret = 0; } - else if (key == kmap.del_next_char) + else if (key == XK_Delete) { if (sp->endrange >= 0) delete_piece(ob, sp->beginrange, sp->endrange - 1); @@ -828,6 +828,12 @@ int oldx = sp->xoffset; int oldmax = sp->max_pixels; + if ((ob->type != FL_MULTILINE_INPUT) && + (IsUp(key) || IsDown(key) || IsPageUp(key) || IsPageDown(key))) { + /* Don't want to handle this key. */ + return 0; + } + /* Extend field size if required */ slen = strlen(sp->str); if (sp->size == slen + 1) @@ -836,7 +842,7 @@ sp->str = (char *) fl_realloc(sp->str, sp->size); } - if (ob->type == FL_MULTILINE_INPUT && key == 13) + if (ob->type == FL_MULTILINE_INPUT && IsReturn(key)) key = NL; /* Compute starting position of current line */ @@ -844,7 +850,7 @@ while (startpos > 0 && sp->str[startpos - 1] != NL) startpos--; - if (controlkey_down(kmask) && key > 255) + if (controlkey_down(kmask)) key |= FL_CONTROL_MASK; if (metakey_down(kmask)) @@ -878,6 +884,12 @@ else if (key == kmap.moveto_prev_page) key = XK_PageUp; + /* ditto for the delete keys */ + if (key == kmap.del_prev_char || key == kmap.backspace) + key == XK_BackSpace; + else if (key == kmap.del_next_char) + key == XK_Delete; + if (IsRegular(key)) /* Normal keys or NL */ { int ok = FL_VALID; @@ -1713,7 +1725,7 @@ } -#define Control(c) ((c) - 'a' + 1) +#define Control(c) ((c) | FL_CONTROL_MASK) #define Meta(c) ((c) | METAMASK) #define Dump(a) fprintf(stderr,"\t%s: %ld(0x%lx)\n",#a,kmap.a,kmap.a) @@ -2240,3 +2252,4 @@ return (obj && (obj->objclass == FL_INPUT)) ? ((SPEC*)(obj->spec))->changed:0; } + diff -urdN xforms-1.0-release/lib/objects.c xforms-modified/lib/objects.c --- xforms-1.0-release/lib/objects.c 2002-06-04 02:58:23.000000000 +0900 +++ xforms-modified/lib/objects.c 2003-02-03 07:51:04.000000000 +0900 @@ -1004,7 +1004,7 @@ else if (str[i] >= 'a' && str[i] <= 'z') sc[j++] = str[i] - 'a' + 1 + offset; else if (str[i] == '[') - sc[j++] = 27 + offset; + sc[j++] = XK_Escape + offset; else sc[j++] = str[i] + offset; offset = 0; @@ -1420,17 +1420,56 @@ } /* handle tooltips */ -static void -tooltip_handler(int ID, void *data) +static +FL_OBJECT * get_parent(FL_OBJECT * obj) { - FL_OBJECT *obj = data; + if (obj) { + while (obj->parent && obj->parent != obj) + obj = obj->parent; + } + return obj; +} - if (obj->tooltip && *(obj->tooltip)) - fl_show_tooltip(obj->tooltip, obj->form->x + obj->x, +static +void tooltip_handler(int ID, void *data) +{ + FL_OBJECT * const obj = get_parent(data); + char const * const tooltip = obj->tooltip; + + if (tooltip && *(tooltip)) + fl_show_tooltip(tooltip, obj->form->x + obj->x, obj->form->y + obj->y + obj->h + 1); obj->tipID = 0; } +static +void hide_tooltip(FL_OBJECT * obj, XEvent * xev) +{ + FL_OBJECT * const parent = get_parent(obj); + char const * const tooltip = parent->tooltip; + if (tooltip && *(tooltip)) { + /* If obj is part of a composite widget, it may well be that we're + leaving a child widget but are still within the parent. + If that is the case, we don't want to hide the tooltip at all. */ + int outside_parent = 1; + if (parent != obj && xev) { + int const pointer_x = xev->xmotion.x; + int const pointer_y = xev->xmotion.y; + if (pointer_x >= parent->x && pointer_x <= parent->x + parent->w && + pointer_y >= parent->y && pointer_y <= parent->y + parent->h) + outside_parent = 0; + } + if (outside_parent) { + fl_hide_tooltip(); + if (parent->tipID) { + fl_remove_timeout(parent->tipID); + parent->tipID = 0; + } + } + } +} + + /* handles an event for an object */ static int fl_handle_it(FL_OBJECT * obj, int event, FL_Coord mx, FL_Coord my, int key, @@ -1463,31 +1502,30 @@ switch (event) { case FL_ENTER: - if (obj->tooltip && *(obj->tooltip) && !obj->form->no_tooltip) - obj->tipID = fl_add_timeout(fl_context->tooltip_time, - tooltip_handler, obj); + { + /* We assign the timer to the parent widget in the case of a + composite object as that's the thing that's actually got the tip. */ + FL_OBJECT * const parent = get_parent(obj); + if (!parent->tipID) { + char const * const tooltip = parent->tooltip; + if (tooltip && *(tooltip) && !parent->form->no_tooltip) + parent->tipID = fl_add_timeout(fl_context->tooltip_time, + tooltip_handler, parent); + } obj->belowmouse = 1; break; + } case FL_LEAVE: - if (obj->tooltip && *(obj->tooltip)) - { - fl_hide_tooltip(); - if (obj->tipID) - fl_remove_timeout(obj->tipID); - obj->tipID = 0; - } + hide_tooltip(obj, xev); obj->belowmouse = 0; break; case FL_PUSH: - if (obj->tooltip && *(obj->tooltip)) - { - fl_hide_tooltip(); - if (obj->tipID) - fl_remove_timeout(obj->tipID); - obj->tipID = 0; - } + hide_tooltip(obj, xev); obj->pushed = 1; break; + case FL_KEYPRESS: + hide_tooltip(obj, xev); + break; case FL_RELEASE: if (!obj->radio) obj->pushed = 0; diff -urdN xforms-1.0-release/lib/slider.c xforms-modified/lib/slider.c --- xforms-1.0-release/lib/slider.c 2002-05-31 01:28:07.000000000 +0900 +++ xforms-modified/lib/slider.c 2003-02-03 07:51:31.000000000 +0900 @@ -293,6 +293,7 @@ } static int timdel; +static int max_timdel = 11; static int mpos; /* < 0 below knob, 0 on knob, > 0 above knob */ /* Handle a mouse position change */ @@ -305,7 +306,7 @@ /* mouse on trough */ if (mpos && (sp->rdelta + sp->ldelta) > 0.0f) { - if (timdel++ == 0 || (timdel > 11 && (timdel & 1) == 0)) + if (timdel++ == 0) { if (key == FL_LEFT_MOUSE) newval = sp->val + mpos * sp->ldelta; @@ -313,7 +314,11 @@ newval = sp->val + mpos * sp->rdelta; } else + { + if (timdel > max_timdel) + timdel = 0; return 0; + } } else newval = get_newvalue(ob, mx, my); diff -urdN xforms-1.0-release/lib/textbox.c xforms-modified/lib/textbox.c --- xforms-1.0-release/lib/textbox.c 2002-05-20 23:35:56.000000000 +0900 +++ xforms-modified/lib/textbox.c 2003-02-03 07:51:48.000000000 +0900 @@ -1148,7 +1148,7 @@ return 1; } break; - case FL_KEYBOARD: + case FL_KEYPRESS: return handle_keyboard(ob, key, xev); case FL_RELEASE: sp->lastmy = -1; @@ -1799,7 +1799,7 @@ if (*ev == FL_RELEASE && (*key > FL_MBUTTON3)) { - *ev = FL_KEYBOARD; + *ev = FL_KEYPRESS; if (xev && shiftkey_down((((XButtonEvent *) xev)->state))) { ((XButtonEvent *) xev)->state &= ~ShiftMask; diff -urdN xforms-1.0-release/lib/thumbwheel.c xforms-modified/lib/thumbwheel.c --- xforms-1.0-release/lib/thumbwheel.c 2002-05-20 23:36:01.000000000 +0900 +++ xforms-modified/lib/thumbwheel.c 2003-02-03 07:52:10.000000000 +0900 @@ -222,7 +222,7 @@ sp->oldmx = mx; sp->oldmy = my; return fl_valuator_handle_drag(ob, value); - case FL_KEYBOARD: + case FL_KEYPRESS: value = sp->val; if (IsHome(key)) value = 0.5f * (sp->min + sp->max); diff -urdN xforms-1.0-release/lib/util.c xforms-modified/lib/util.c --- xforms-1.0-release/lib/util.c 2002-05-20 23:35:57.000000000 +0900 +++ xforms-modified/lib/util.c 2003-02-03 07:52:22.000000000 +0900 @@ -84,7 +84,7 @@ { VN(FL_ENTER), VN(FL_LEAVE), VN(FL_PUSH), VN(FL_RELEASE), VN(FL_STEP), VN(FL_SHORTCUT), VN(FL_MOUSE), VN(FL_MOTION), - VN(FL_KEYBOARD), VN(FL_DRAW), VN(FL_FOCUS), VN(FL_UNFOCUS), + VN(FL_KEYPRESS), VN(FL_DRAW), VN(FL_FOCUS), VN(FL_UNFOCUS), VN(FL_FREEMEM), VN(FL_DRAWLABEL), VN(FL_DBLCLICK), VN(FL_OTHER), VN(FL_ATTRIB), VN(-1) diff -urdN xforms-1.0-release/lib/xpopup.c xforms-modified/lib/xpopup.c --- xforms-1.0-release/lib/xpopup.c 2002-06-04 05:25:18.000000000 +0900 +++ xforms-modified/lib/xpopup.c 2003-02-03 07:48:37.000000000 +0900 @@ -1484,16 +1484,34 @@ #else fl_set_font(tfstyle, tfsize); fl_textcolor(puptcolor); - XDrawString(d, w, flx->textgc, x - 1, y - 1, s, n); - XDrawString(d, w, flx->textgc, x, y - 1, s, n); - XDrawString(d, w, flx->textgc, x + 1, y - 1, s, n); - XDrawString(d, w, flx->textgc, x - 1, y, s, n); - XDrawString(d, w, flx->textgc, x + 1, y, s, n); - XDrawString(d, w, flx->textgc, x - 1, y + 1, s, n); - XDrawString(d, w, flx->textgc, x, y + 1, s, n); - XDrawString(d, w, flx->textgc, x + 1, y + 1, s, n); + static XFontSet fset = 0; + static int junk; + char **missing_charset; + int num_missing; + static char *dd; + + if(fset == 0) + { + fset = XCreateFontSet(flx->display, + "-*-*-medium-r-normal-*-14-*-*-*-*-*-*", + &missing_charset, &num_missing, &dd); + } + if(fset == 0) + { + M_err("DrawString","Bad fontset"); + exit(0); + } + + XmbDrawString(d, w, fset, flx->textgc, x - 1, y - 1, s, n); + XmbDrawString(d, w, fset, flx->textgc, x, y - 1, s, n); + XmbDrawString(d, w, fset, flx->textgc, x + 1, y - 1, s, n); + XmbDrawString(d, w, fset, flx->textgc, x - 1, y, s, n); + XmbDrawString(d, w, fset, flx->textgc, x + 1, y, s, n); + XmbDrawString(d, w, fset, flx->textgc, x - 1, y + 1, s, n); + XmbDrawString(d, w, fset, flx->textgc, x, y + 1, s, n); + XmbDrawString(d, w, fset, flx->textgc, x + 1, y + 1, s, n); fl_textcolor(FL_WHITE); - XDrawString(d, w, flx->textgc, x, y, s, n); + XmbDrawString(d, w, fset, flx->textgc, x, y, s, n); #endif } diff -urdN xforms-1.0-release/lib/xtext.c xforms-modified/lib/xtext.c --- xforms-1.0-release/lib/xtext.c 2002-05-20 23:35:58.000000000 +0900 +++ xforms-modified/lib/xtext.c 2003-02-03 07:48:27.000000000 +0900 @@ -51,6 +51,8 @@ #define NL 10 #define LINES 1024 +#define DUMMY_FONT "-*-*-*-r-normal--14-130-75-75-*-*" + static char **lines; static int *start; /* start position of these lines */ static int *startx; /* start x-FL_coordinate of these lines */ @@ -59,6 +61,11 @@ static int nlines = LINES; static int max_pixelline; +static XFontStruct **fs_list; +static char **missing_charset; +static int num_missing; +static char *dd; + static void extend_workmem(int nl) { @@ -89,7 +96,7 @@ /* wrong, but looks nicer */ #define CDELTA (flx->fdesc/3) -typedef int (*DrawString) (Display *, Drawable, GC, int, int, const char *, int); +typedef int (*DrawString) (Display *, Drawable, XFontSet, GC, int, int, const char *, +int); /* Major text drawing routine * clip == 0: no clipping @@ -116,6 +123,10 @@ int max_pixels = 0; int cdelta; DrawString XdrawString; + XFontSet fset = XCreateFontSet(flx->display, + DUMMY_FONT, &missing_charset, &num_missing, &dd); + XFontsOfFontSet(fset,&fs_list,&missing_charset); + flx->fs = fs_list[0]; if (!startx) extend_workmem(nlines = LINES); @@ -124,7 +135,7 @@ if (curspos != 0 && (str == NULL || str[0] == '\0')) return max_pixels; - XdrawString = (DrawString) (img ? XDrawImageString : XDrawString); + XdrawString = (DrawString) (img ? XmbDrawImageString : XmbDrawString); fl_set_font(style, size); @@ -179,7 +190,7 @@ cdelta = CDELTA; for (i = topline; i < endline; i++) { - width = XTextWidth(flx->fs, lines[i], slen[i]); + width = XmbTextEscapement(fset, lines[i], slen[i]); if (width > max_pixels) { max_pixels = width; @@ -231,40 +242,21 @@ #endif lines[i] = newlabel; slen[i] = strlen(lines[i]); - startx[i] += XTextWidth(flx->fs, fl_ul_magic_char, 1) / 2; + startx[i] += XmbTextEscapement(fset, fl_ul_magic_char, 1) / 2; } /* Draw it */ fl_textcolor(forecol); -#if 2 +#if 0 XdrawString(flx->display, flx->win, flx->textgc, (int) startx[i], (int) starty[i], lines[i], slen[i]); -#else - { - static XFontSet fset = 0; - static int junk; - char **missing_charset; - int num_missing; - static char *dd; - - if(fset == 0) - { - fset = XCreateFontSet(flx->display, - "-adobe-helvetica-*-r-*--*-100-*-*-*-*-*-1", - &missing_charset, &num_missing, &dd); - } - if(fset == 0) - { - M_err("DrawString","Bad fontset"); - exit(0); - } +#else - XmbDrawString(flx->display, flx->win, fset, flx->textgc, + XdrawString(flx->display, flx->win, fset, flx->textgc, (int) startx[i], (int) starty[i], lines[i], slen[i]); - } #endif /* setup correct underline color in proper GC */ @@ -295,17 +287,21 @@ slend = selend; xsel = startx[i] + - XTextWidth(flx->fs, lines[i], slstart - start[i]); + XmbTextEscapement(fset, lines[i], slstart - start[i]); len = slend - slstart; - wsel = XTextWidth(flx->fs, str + slstart, len); + wsel = XmbTextEscapement(fset, str + slstart, len); if (wsel > w) wsel = w + 1; fl_rectf(xsel, starty[i] - height, wsel, flx->fheight, forecol); fl_textcolor(backcol); - +#if 0 XdrawString(flx->display, flx->win, flx->textgc, xsel, starty[i], str + slstart, len); +#else + XdrawString(flx->display, flx->win, fset, flx->textgc, + xsel, starty[i], str +slstart, len); +#endif } } @@ -318,7 +314,7 @@ ; i--; - tt = XTextWidth(flx->fs, lines[i], curspos - start[i]); + tt = XmbTextEscapement(fset, lines[i], curspos - start[i]); fl_set_clipping(x, y, w - 2, h); fl_rectf(startx[i] + tt, starty[i] - height, (FL_Coord) 2, flx->fheight, curscol); @@ -355,6 +351,11 @@ int xstart; /* start x-FL_coordinate of this line */ float toppos; /* y-FL_coord of the top line */ + XFontSet fset = XCreateFontSet(flx->display, + DUMMY_FONT, &missing_charset, &num_missing, &dd); + XFontsOfFontSet(fset,&fs_list,&missing_charset); + flx->fs = fs_list[0]; + /* Check whether anything has to be done */ if (!str || !*str) return 0; @@ -400,7 +401,7 @@ /* Calculate start FL_coordinate of the line */ - width = XTextWidth(flx->fs, (char *) line, + width = XmbTextEscapement(fset, (char *) line, start[theline + 1] - start[theline]); if (horalign == FL_ALIGN_LEFT) xstart = x; @@ -420,7 +421,7 @@ len = start[theline + 1] - start[theline]; for (i = i0; i < len; i++) { - if (XTextWidth(flx->fs, line, i) > xpos) + if (XmbTextEscapement(fset, line, i) > xpos) { *xp = i - 1; return start[theline] + i - 1; @@ -656,6 +657,11 @@ int ch = *(str + n); int pre; /* stuff in front of the string, such as ^H */ + XFontSet fset = XCreateFontSet(flx->display, + DUMMY_FONT, &missing_charset, &num_missing, &dd); + XFontsOfFontSet(fset,&fs_list,&missing_charset); + flx->fs = fs_list[0]; + if (UL_thickness < 0) XGetFontProperty(flx->fs, XA_UNDERLINE_THICKNESS, &ul_thickness); else @@ -671,8 +677,8 @@ of D. Of course, if UL_width == proportional, this really does not matter */ - ul_width = XTextWidth(fs, NARROW(ch) ? "h" : "D", 1); - ul_rwidth = XTextWidth(fs, str + n, 1); + ul_width = XmbTextEscapement(fset, NARROW(ch) ? "h" : "D", 1); + ul_rwidth = XmbTextEscapement(fset, str + n, 1); pre = (str[0] == *fl_ul_magic_char); @@ -715,6 +721,11 @@ unsigned long ul_pos, ul_thickness = 0; char *str = (char *) cstr; + XFontSet fset = XCreateFontSet(flx->display, + DUMMY_FONT, &missing_charset, &num_missing, &dd); + XFontsOfFontSet(fset,&fs_list,&missing_charset); + flx->fs = fs_list[0]; + if (UL_thickness < 0) XGetFontProperty(flx->fs, XA_UNDERLINE_THICKNESS, &ul_thickness); else @@ -726,7 +737,7 @@ if (!XGetFontProperty(flx->fs, XA_UNDERLINE_POSITION, &ul_pos)) ul_pos = has_desc(str) ? (1 + flx->fdesc) : 1; - ul_width = XTextWidth(flx->fs, str, n); + ul_width = XmbTextEscapement(fset, str, n); /* do it */ XFillRectangle(flx->display, flx->win, flx->gc, x, (int) (y + ul_pos), @@ -741,22 +752,26 @@ { int w, tab; const char *p, *q; + XFontSet fset = XCreateFontSet(flx->display, + DUMMY_FONT,&missing_charset, &num_missing, &dd); + XFontsOfFontSet(fset,&fs_list,&missing_charset); XFontStruct *fs = fl_get_font_struct(style, size); + fs = fs_list[0]; DrawString XdrawString; tab = fl_get_tabpixels(fs); - XdrawString = (DrawString) (img ? XDrawImageString : XDrawString); + XdrawString = (DrawString) (img ? XmbDrawImageString : XmbDrawString); XSetFont(flx->display, gc, fs->fid); for (w = 0, q = s; *q && (p = strchr(q, '\t')) && (p - s) < len; q = p + 1) { - XdrawString(flx->display, win, gc, x + w, y, (char *) q, p - q); - w += XTextWidth(fs, q, p - q); + XdrawString(flx->display, win, fset, gc, x + w, y, (char *) q, p - q); + w += XmbTextEscapement(fset, q, p - q); w = ((w / tab) + 1) * tab; } - XdrawString(flx->display, win, gc, x + w, y, (char *) q, len - (q - s)); + XdrawString(flx->display, win, fset, gc, x + w, y, (char *) q, len - (q - s)); return 0; /* w + XTextWidth(fs, q, len - (q - s)); */ }