From ca616755973ea719e9ffade941473da0cf8337e9 Mon Sep 17 00:00:00 2001 From: dan Date: Thu, 28 Oct 2004 04:17:18 +0000 Subject: [PATCH] added preliminary X Input Methods support --- ChangeLog | 2 + WINGs/Tests/wtest.c | 2 + WINGs/WINGs/WINGsP.h | 17 ++++ WINGs/configuration.c | 1 - WINGs/wevent.c | 4 + WINGs/widgets.c | 6 +- WINGs/winputmethod.c | 228 +++++++++++++++++++++++++++++++++++------- WINGs/wscroller.c | 2 + WINGs/wtext.c | 2 + WINGs/wtextfield.c | 24 ++++- WINGs/wview.c | 3 +- 11 files changed, 245 insertions(+), 46 deletions(-) diff --git a/ChangeLog b/ChangeLog index 1bd05779..96419ba4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -3,6 +3,8 @@ Changes since version 0.91.0: - fixed crash with info panel and alt-tabbing - updated Japanese translations (Takeo Hashimoto ) - allow disable of switch panel when SwitchPanelImages=None +- added X Input Methods support in WINGs + Changes since version 0.90.0: ............................. diff --git a/WINGs/Tests/wtest.c b/WINGs/Tests/wtest.c index 6245f2d2..35f1cf43 100644 --- a/WINGs/Tests/wtest.c +++ b/WINGs/Tests/wtest.c @@ -1047,6 +1047,8 @@ main(int argc, char **argv) testColorPanel(scr); + testTextField(scr); + #if 0 testBox(scr); diff --git a/WINGs/WINGs/WINGsP.h b/WINGs/WINGs/WINGsP.h index 5dbab47a..ff840a51 100644 --- a/WINGs/WINGs/WINGsP.h +++ b/WINGs/WINGs/WINGsP.h @@ -385,6 +385,7 @@ typedef struct W_View { WMPixmap *dragImage; int helpContext; + XIC xic; struct { unsigned int realized:1; @@ -612,6 +613,22 @@ void W_DragDestinationInfoClear(WMDraggingInfo *info); void W_FreeViewXdndPart(WMView *view); +/* XIM */ +void W_InitIM(WMScreen *scr); + +void W_CreateIC(WMView *view); + +void W_DestroyIC(WMView *view); + +void W_FocusIC(WMView *view); + +void W_UnFocusIC(WMView *view); + +void W_SetPreeditPositon(W_View *view, int x, int y); + +int W_LookupString(W_View *view, XKeyPressedEvent *event, char *buffer, + int buflen, KeySym *keysym, Status *status); + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/WINGs/configuration.c b/WINGs/configuration.c index cb2dfb96..ebc4fc8d 100644 --- a/WINGs/configuration.c +++ b/WINGs/configuration.c @@ -53,7 +53,6 @@ W_ReadConfigurations(void) if (defaults) { char *buttonName; unsigned button; - char *str; WINGsConfiguration.systemFont = WMGetUDStringForKey(defaults, "SystemFont"); diff --git a/WINGs/wevent.c b/WINGs/wevent.c index f3b2cfef..87a6b9fb 100644 --- a/WINGs/wevent.c +++ b/WINGs/wevent.c @@ -213,6 +213,10 @@ WMHandleEvent(XEvent *event) return True; } + if (XFilterEvent(event, None) == True) { + return False; + } + mask = eventMasks[event->xany.type]; window = event->xany.window; diff --git a/WINGs/widgets.c b/WINGs/widgets.c index be571ab5..4ff5e288 100644 --- a/WINGs/widgets.c +++ b/WINGs/widgets.c @@ -631,9 +631,6 @@ WMCreateScreenWithRContext(Display *display, int screen, RContext *context) scrPtr->xftdraw = XftDrawCreate(scrPtr->display, W_DRAWABLE(scrPtr), scrPtr->visual, scrPtr->colormap); - /* create input method stuff */ - W_InitIMStuff(scrPtr); - /* Create missing CUT_BUFFERs */ { Atom *rootWinProps; @@ -773,6 +770,9 @@ WMCreateScreenWithRContext(Display *display, int screen, RContext *context) return NULL; } + /* create input method stuff */ + W_InitIM(scrPtr); + scrPtr->checkButtonImageOn = makePixmap(scrPtr, CHECK_BUTTON_ON, CHECK_BUTTON_ON_WIDTH, CHECK_BUTTON_ON_HEIGHT, False); diff --git a/WINGs/winputmethod.c b/WINGs/winputmethod.c index 303d5601..79b17fec 100644 --- a/WINGs/winputmethod.c +++ b/WINGs/winputmethod.c @@ -5,83 +5,237 @@ #include "WINGsP.h" - typedef struct W_IMContext { XIM xim; - - struct W_ICContext *icList; + XIMStyle ximstyle; } WMIMContext; -typedef struct W_ICContext { - struct W_ICContext *next; - struct W_ICContext *prev; - XIC xic; -} WMICContext; - - - -Bool -W_InitIMStuff(WMScreen *scr) +static void +instantiateIM_cb(Display *display, XPointer client_data, XPointer call_data) { - WMIMContext *ctx; + W_InitIM((W_Screen *)client_data); +} - ctx = scr->imctx = wmalloc(sizeof(WMIMContext)); - ctx->xim = XOpenIM(scr->display, NULL, NULL, NULL); - if (ctx->xim == NULL) { - wwarning("could not open IM"); - return False; +static void +destroyIM_cb(XIM xim, XPointer client_data, XPointer call_data) +{ + W_Screen *scr = (W_Screen *)client_data; + W_View *target; + + if (scr->imctx->xim != xim) + return; + + target = scr->rootView->childrenList; + while (target!=NULL) { + W_DestroyIC(target); + target = target->nextSister; } + wfree(scr->imctx); + scr->imctx = NULL; + + XRegisterIMInstantiateCallback(scr->display, NULL, NULL, NULL, + instantiateIM_cb, (XPointer)scr); } void -W_CloseIMStuff(WMScreen *scr) +W_InitIM(W_Screen *scr) { - if (!scr->imctx) + XIM xim; + + if (scr->imctx) return; - if (scr->imctx->xim) - XCloseIM(scr->imctx->xim); - wfree(scr->imctx); - scr->imctx = NULL; + xim = XOpenIM(scr->display, NULL, NULL, NULL); + + if (xim) { + XIMStyles *im_styles; + XIMCallback cb; + int i; + + scr->imctx = wmalloc(sizeof(WMIMContext)); + scr->imctx->xim = xim; + + cb.callback = destroyIM_cb; + cb.client_data = (XPointer)scr; + if (XSetIMValues(scr->imctx->xim, XNDestroyCallback, &cb, NULL)) + wwarning("could not add destroy callback for input method"); + XUnregisterIMInstantiateCallback(scr->display, NULL, NULL, NULL, + instantiateIM_cb, (XPointer)scr); + /* Get available input style */ + XGetIMValues(scr->imctx->xim, XNQueryInputStyle, &im_styles, NULL); + + scr->imctx->ximstyle = 0; + + for (i=0; icount_styles && scr->imctx->ximstyle==0; i++) { + if ((im_styles->supported_styles[i] & XIMPreeditPosition) && + (im_styles->supported_styles[i] & XIMStatusNothing)) { + scr->imctx->ximstyle = XIMPreeditPosition | XIMStatusNothing; + } else if ((im_styles->supported_styles[i] & XIMPreeditNothing) && + (im_styles->supported_styles[i] & XIMStatusNothing)) { + scr->imctx->ximstyle = XIMPreeditNothing | XIMStatusNothing; + } + } + XFree(im_styles); + } else { + XRegisterIMInstantiateCallback(scr->display, NULL, NULL, NULL, + instantiateIM_cb, (XPointer)scr); + } } - -WMICContext* +void W_CreateIC(WMView *view) { WMScreen *scr = W_VIEW_SCREEN(view); - WMICContext *ctx; + XVaNestedList preedit_attr = NULL; - ctx->prev = NULL; - ctx->next = scr->imctx->icList; - if (scr->imctx->icList) - scr->imctx->icList->prev = ctx; + if (view->xic || !view->flags.realized || !scr->imctx) + return; + if (scr->imctx->ximstyle & XIMPreeditPosition) { + XPoint spot; + XRectangle rect; + int ofs; + ofs = (view->size.height - WMFontHeight(scr->normalFont))/2; + + rect.x = ofs; + rect.y = ofs; + rect.height = WMFontHeight(scr->normalFont); + rect.width = view->size.width - ofs*2; + spot.x = rect.x; + spot.y = rect.y + rect.height; + + // this really needs to be changed, but I don't know how yet -Dan + // it used to be like this with fontsets, but no longer applies to xft + preedit_attr = XVaCreateNestedList(0, XNSpotLocation, &spot, + XNArea, &rect, XNFontInfo, + scr->normalFont->font, NULL); + } + + view->xic = XCreateIC(scr->imctx->xim, XNInputStyle, scr->imctx->ximstyle, + XNClientWindow, view->window, + preedit_attr ? XNPreeditAttributes : NULL, preedit_attr, + NULL); + + if (preedit_attr) + XFree(preedit_attr); + + if (view->xic) { + unsigned long fevent = 0; + XGetICValues(view->xic, XNFilterEvents, &fevent, NULL); + XSelectInput(scr->display, view->window, + ButtonPressMask | ButtonReleaseMask | ExposureMask | + KeyPressMask | FocusChangeMask| ButtonMotionMask |fevent); + } } void -W_DestroyIC(WMICContext *ctx) +W_DestroyIC(WMView *view) { - XDestroyIC(ctx->xic); + if (view->xic) { + XDestroyIC(view->xic); + view->xic = 0; + } +} +static void +setPreeditArea(W_View *view) +{ + WMScreen *scr = W_VIEW_SCREEN(view); + XVaNestedList preedit_attr = NULL; + + if (view->xic && (scr->imctx->ximstyle & XIMPreeditPosition)) { + XRectangle rect; + int ofs; + + ofs = (view->size.height - WMFontHeight(scr->normalFont))/2; + rect.x = ofs; + rect.y = ofs; + rect.height = WMFontHeight(scr->normalFont); + rect.width = view->size.width - ofs*2; + + preedit_attr = XVaCreateNestedList(0, XNArea, &rect, NULL); + XSetICValues(view->xic, XNPreeditAttributes, preedit_attr, NULL); + + if (preedit_attr) { + XFree(preedit_attr); + } + } +} + + +void +W_FocusIC(WMView *view) +{ + WMScreen *scr = W_VIEW_SCREEN(view); + + if (view->xic) { + XSetICFocus(view->xic); + XSetICValues(view->xic, XNFocusWindow, view->window, NULL); + + if (scr->imctx->ximstyle & XIMPreeditPosition) { + setPreeditArea(view); + } + } +} + + +void +W_UnFocusIC(WMView *view) +{ + if (view->xic) { + XUnsetICFocus(view->xic); + } +} + + +void +W_SetPreeditPositon(W_View *view, int x, int y) +{ + WMScreen *scr = W_VIEW_SCREEN(view); + XVaNestedList preedit_attr = NULL; + + if (view->xic && (scr->imctx->ximstyle & XIMPreeditPosition)) { + XPoint spot; + int ofs; + + ofs = (view->size.height - WMFontHeight(scr->normalFont))/2; + spot.x = x; + spot.y = y + view->size.height - ofs - 3; + preedit_attr = XVaCreateNestedList(0, XNSpotLocation, &spot, NULL); + XSetICValues(view->xic, XNPreeditAttributes, preedit_attr, NULL); + if (preedit_attr) { + XFree(preedit_attr); + } + } } int -W_LookupString(WMView *view, XKeyEvent *event, - char buffer, int bufsize, KeySym ksym) +W_LookupString(W_View *view, XKeyPressedEvent *event, char *buffer, int buflen, + KeySym *keysym, Status *status) { + WMScreen *scr = W_VIEW_SCREEN(view); + XSetInputFocus(scr->display, view->window, RevertToParent, CurrentTime); + + if (view->xic) { +#ifdef X_HAVE_UTF8_STRING + return Xutf8LookupString(view->xic, event, buffer, buflen, keysym, status); +#else + return XLookupString(event, buffer, buflen, keysym, (XComposeStatus *)status); +#endif + } else { + return XLookupString(event, buffer, buflen, keysym, (XComposeStatus *)status); + } } - diff --git a/WINGs/wscroller.c b/WINGs/wscroller.c index 803eed86..0197ea29 100644 --- a/WINGs/wscroller.c +++ b/WINGs/wscroller.c @@ -672,6 +672,8 @@ handlePush(Scroller *sPtr, int pushX, int pushY, int alternate) handleMotion(sPtr, pushX, pushY); */ break; + case WSDecrementWheel: + case WSIncrementWheel: case WSKnobSlot: case WSNoPart: /* dummy */ diff --git a/WINGs/wtext.c b/WINGs/wtext.c index b409d30c..02322845 100644 --- a/WINGs/wtext.c +++ b/WINGs/wtext.c @@ -2299,6 +2299,7 @@ autoSelectText(Text *tPtr, int clicks) } +# if 0 static void fontChanged(void *observerData, WMNotification *notification) { @@ -2312,6 +2313,7 @@ fontChanged(void *observerData, WMNotification *notification) if (tPtr->flags.ownsSelection) WMSetTextSelectionFont(tPtr, font); } +#endif static void diff --git a/WINGs/wtextfield.c b/WINGs/wtextfield.c index bc49a222..6090c0c0 100644 --- a/WINGs/wtextfield.c +++ b/WINGs/wtextfield.c @@ -71,7 +71,7 @@ typedef struct W_TextField { unsigned int waitingSelection:1; /* requested selection, but * didnt get yet */ - /**/ + unsigned int notIllegalMovement:1; } flags; } TextField; @@ -312,6 +312,13 @@ selectionNotification(void *observerData, WMNotification *notification) } +static void +realizeObserver(void *self, WMNotification *not) +{ + W_CreateIC(((TextField*)self)->view); +} + + WMTextField* WMCreateTextField(WMWidget *parent) { @@ -364,6 +371,8 @@ WMCreateTextField(WMWidget *parent) WMSelectionOwnerDidChangeNotification, (void*)XA_PRIMARY); + WMAddNotificationObserver(realizeObserver, tPtr, + WMViewRealizedNotification, tPtr->view); tPtr->flags.cursorOn = 1; @@ -762,8 +771,11 @@ paintCursor(TextField *tPtr) cx, tPtr->offsetWidth, cx, tPtr->view->size.height - tPtr->offsetWidth - 1); - if (tPtr->flags.secure) + W_SetPreeditPositon(tPtr->view, cx, 0); + + if (tPtr->flags.secure) { wfree(text); + } } @@ -953,9 +965,9 @@ handleEvents(XEvent *event, void *data) CHECK_CLASS(data, WC_TextField); - switch (event->type) { case FocusIn: + W_FocusIC(tPtr->view); if (W_FocusedViewOfToplevel(W_TopLevelOfView(tPtr->view))!=tPtr->view) return; tPtr->flags.focused = 1; @@ -973,6 +985,7 @@ handleEvents(XEvent *event, void *data) break; case FocusOut: + W_UnFocusIC(tPtr->view); tPtr->flags.focused = 0; #if 0 if (tPtr->timerID) @@ -1021,7 +1034,8 @@ handleTextFieldKeyPress(TextField *tPtr, XEvent *event) controled = (event->xkey.state & ControlMask ? True : False); modified = shifted || controled; - count = XLookupString(&event->xkey, buffer, 63, &ksym, NULL); + count = W_LookupString(tPtr->view, &event->xkey, buffer, 63, &ksym, NULL); + //count = XLookupString(&event->xkey, buffer, 63, &ksym, NULL); buffer[count] = '\0'; switch (ksym) { @@ -1613,6 +1627,8 @@ destroyTextField(TextField *tPtr) WMDeleteTimerHandler(tPtr->timerID); #endif + W_DestroyIC(tPtr->view); + WMReleaseFont(tPtr->font); /*// use lostSelection() instead of WMDeleteSelectionHandler here?*/ WMDeleteSelectionHandler(tPtr->view, XA_PRIMARY, CurrentTime); diff --git a/WINGs/wview.c b/WINGs/wview.c index 37685441..8eb56900 100644 --- a/WINGs/wview.c +++ b/WINGs/wview.c @@ -130,6 +130,8 @@ createView(W_Screen *screen, W_View *parent) adoptChildView(parent, view); } + view->xic = 0; + view->refCount = 1; view->eventHandlers = WMCreateArrayWithDestructor(4, wfree); @@ -213,7 +215,6 @@ W_RealizeView(W_View *view) assert(view->size.width > 0); assert(view->size.height > 0); - if (view->parent && !view->parent->flags.realized) { wwarning("trying to realize widget of unrealized parent"); return;