/* * @OPENGROUP_COPYRIGHT@ * COPYRIGHT NOTICE * Copyright (c) 1990, 1991, 1992, 1993 Open Software Foundation, Inc. * Copyright (c) 1996, 1997, 1998, 1999, 2000 The Open Group * ALL RIGHTS RESERVED (MOTIF). See the file named COPYRIGHT.MOTIF for * the full copyright text. * * This software is subject to an open license. It may only be * used on, with or for operating systems which are themselves open * source systems. You must contact The Open Group for a license * allowing distribution and sublicensing of this software on, with, * or for operating systems which are not Open Source programs. * * See http://www.opengroup.org/openmotif/license for full * details of the license agreement. Any use, reproduction, or * distribution of the program constitutes recipient's acceptance of * this agreement. * * EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS * PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY * WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY * OR FITNESS FOR A PARTICULAR PURPOSE * * EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT * NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE * EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. */ /* * HISTORY */ #ifdef REV_INFO #ifndef lint static char rcsid[] = "$TOG: XmIm.c /main/28 1997/10/13 14:57:31 cshi $" #endif #endif /* (c) Copyright 1987, 1988, 1989, 1990, 1991, 1992 HEWLETT-PACKARD COMPANY */ /* * (c) Copyright 1995 FUJITSU LIMITED * This is source code modified by FUJITSU LIMITED under the Joint * Development Agreement for the CDEnext PST. * This is unpublished proprietary source code of FUJITSU LIMITED */ #include #include #include #include #include #include #include /* for bzero */ #include "BaseClassI.h" #include "MessagesI.h" #include "XmI.h" #include "XmImI.h" #include # include # define Va_start(a,b) va_start(a,b) /* Data structures: * While multiple XIMs are not currently supported, some thought * was given to how they might be implemented. Currently both * XmImDisplayInfo and XmImShellInfo contain per-XIM fields. Also the * locale and XmNinputMethod are implicit in the XmImDisplayInfo. * The back-pointer for the original source of shared XICs is perhaps * overly general, but will ease XmPER_MANAGER sharing if implemented. * * If an XIC is shared among several widgets, all will reference a * single XmImXICInfo. */ typedef struct _XmImRefRec { Cardinal num_refs; /* Number of referencing widgets. */ Cardinal max_refs; /* Maximum length of refs array. */ Widget* refs; /* Array of referencing widgets. */ XtPointer **callbacks; } XmImRefRec, *XmImRefInfo; typedef struct _PreeditBufferRec { unsigned short length; wchar_t *text; XIMFeedback *feedback; int caret; XIMCaretStyle style; } PreeditBufferRec, *PreeditBuffer; typedef struct _XmImXICRec { struct _XmImXICRec *next; /* Links all have the same XIM. */ XIC xic; /* The XIC. */ Window focus_window; /* Cached information about the XIC. */ XIMStyle input_style; /* ...ditto... */ int status_width; /* ...ditto... */ int preedit_width; /* ...ditto... */ int sp_height; /* ...ditto... */ Boolean has_focus; /* Does this XIC have keyboard focus. */ Boolean anonymous; /* Do we have exclusive rights to this XIC. */ XmImRefRec widget_refs; /* Widgets referencing this XIC. */ struct _XmImXICRec **source; /* Original source of shared XICs. */ PreeditBuffer preedit_buffer; } XmImXICRec, *XmImXICInfo; typedef struct _XmImShellRec { /* per-Shell fields. */ Widget im_widget; /* Dummy widget to make intrinsics behave. */ Widget current_widget; /* Widget whose visual we're matching. */ /* per fields. */ XmImXICInfo shell_xic; /* For PER_SHELL sharing policy. */ XmImXICInfo iclist; /* All known XICs for this . */ } XmImShellRec, *XmImShellInfo; typedef struct { /* per-Display fields. */ XContext current_xics; /* Map widget -> current XmImXICInfo. */ /* per-XIM fields. */ XIM xim; /* The XIM. */ XIMStyles *styles; /* XNQueryInputStyle result. */ XmImRefRec shell_refs; /* Shells referencing this XIM. */ } XmImDisplayRec, *XmImDisplayInfo; /* * Although the current implementation of XVaNestedList is similar * to an Xt ArgList, this is not guaranteed by the spec. The only * approved interface for creating XVaNestedLists takes pairs of * (char*, XPointer) paramters. */ typedef struct { char *name; XPointer value; } VaArg; typedef struct { Cardinal count; Cardinal max; VaArg *args; } VaArgListRec, *VaArgList; /******** Static Function Declarations ********/ static int add_sp(String name, XPointer value, VaArgList slp, VaArgList plp, VaArgList vlp); static int add_p(String name, XPointer value, VaArgList slp, VaArgList plp, VaArgList vlp); static int add_fs(String name, XPointer value, VaArgList slp, VaArgList plp, VaArgList vlp); static int add_bgpxmp(String name, XPointer value, VaArgList slp, VaArgList plp, VaArgList vlp); static XIMStyle check_style(XIMStyles *styles, XIMStyle preedit_style, XIMStyle status_style); static int ImGetGeo(Widget vw, XmImXICInfo this_icp ); static void ImSetGeo(Widget vw, XmImXICInfo this_icp ); static void ImGeoReq(Widget vw); static XFontSet extract_fontset(XmFontList fl); static XmImDisplayInfo get_xim_info(Widget w); static XtPointer* get_im_info_ptr(Widget w, Boolean create); static XmImShellInfo get_im_info(Widget w, Boolean create); static void draw_separator(Widget vw); static void null_proc(Widget w, XtPointer ptr, XEvent *ev, Boolean *b); static void ImCountVaList(va_list var, int *total_count); static ArgList ImCreateArgList(va_list var, int total_count); static XmImXICInfo create_xic_info(Widget shell, XmImDisplayInfo xim_info, XmImShellInfo im_info, #if NeedWidePrototypes unsigned int input_policy); #else XmInputPolicy input_policy); #endif /*NeedWidePrototypes*/ static XmImXICInfo recreate_xic_info(XIC xic, Widget shell, XmImDisplayInfo xim_info, XmImShellInfo im_info); static void set_values(Widget w, ArgList args, Cardinal num_args, #if NeedWidePrototypes unsigned int policy); #else XmInputPolicy policy); #endif /*NeedWidePrototypes*/ static XmImXICInfo get_current_xic(XmImDisplayInfo xim_info, Widget widget); static void set_current_xic(XmImXICInfo xic_info, XmImDisplayInfo xim_info, Widget widget); static void unset_current_xic(XmImXICInfo xic_info, XmImShellInfo im_info, XmImDisplayInfo xim_info, Widget widget); static Cardinal add_ref(XmImRefInfo refs, Widget widget); static Cardinal remove_ref(XmImRefInfo refs, Widget widget); static XVaNestedList VaCopy(VaArgList list); static void VaSetArg(VaArgList list, char *name, XPointer value); static int ImPreeditStartCallback(XIC xic, XPointer client_data, XPointer call_data); static void ImPreeditDoneCallback(XIC xic, XPointer client_data, XPointer call_data); static void ImPreeditDrawCallback(XIC xic, XPointer client_data, XPointer call_data); static void ImPreeditCaretCallback(XIC xic, XPointer client_data, XPointer call_data); static void ImFreePreeditBuffer(PreeditBuffer pb); static void set_callback_values(Widget w, String name, XIMCallback *value, VaArgList vlp, XmInputPolicy input_policy); static void regist_real_callback(Widget w, XIMProc call, int swc); static XIMProc get_real_callback(Widget w, int swc, Widget *real_widget); static void move_preedit_string(XmImXICInfo icp, Widget wfrom, Widget wto); /******** End Static Function Declarations ********/ typedef int (*XmImResLProc)(String, XPointer, VaArgList, VaArgList, VaArgList); typedef struct { String xmstring; String xstring; XrmName xrmname; XmImResLProc proc; } XmImResListRec; static XmImResListRec XmImResList[] = { {XmNbackground, XNBackground, NULLQUARK, add_sp}, {XmNforeground, XNForeground, NULLQUARK, add_sp}, {XmNbackgroundPixmap, XNBackgroundPixmap, NULLQUARK, add_bgpxmp}, {XmNspotLocation, XNSpotLocation, NULLQUARK, add_p}, {XmNfontList, XNFontSet, NULLQUARK, add_fs}, {XmNrenderTable, XNFontSet, NULLQUARK, add_fs}, {XmNlineSpace, XNLineSpace, NULLQUARK, add_sp}, {XmNarea, XNArea, NULLQUARK, add_p}, {XmNpreeditStartCallback, XNPreeditStartCallback, NULLQUARK, NULL}, {XmNpreeditDoneCallback, XNPreeditDoneCallback, NULLQUARK, NULL}, {XmNpreeditDrawCallback, XNPreeditDrawCallback, NULLQUARK, NULL}, {XmNpreeditCaretCallback, XNPreeditCaretCallback, NULLQUARK, NULL}, }; #define OVERTHESPOT "overthespot" #define OFFTHESPOT "offthespot" #define ROOT "root" #define ONTHESPOT "onthespot" #define PREEDIT_START 0 #define PREEDIT_DONE 1 #define PREEDIT_DRAW 2 #define PREEDIT_CARET 3 #define SEPARATOR_HEIGHT 2 #define GEO_CHG 0x1 #define BG_CHG 0x2 #define MSG1 _XmMMsgXmIm_0000 /*ARGSUSED*/ void XmImRegister(Widget w, unsigned int reserved) /* unused */ { Widget p; XmImShellInfo im_info; XmImDisplayInfo xim_info; XmInputPolicy input_policy = XmINHERIT_POLICY; _XmWidgetToAppContext(w); _XmAppLock(app); /* Find the enclosing shell. */ p = XtParent(w); while (!XtIsShell(p)) p = XtParent(p); /* Lookup or create per-shell IM info and an XIM. */ if (((xim_info = get_xim_info(p)) == NULL) || (xim_info->xim == NULL)) { _XmAppUnlock(app); return; } if ((im_info = get_im_info(p, True)) == NULL) { _XmAppUnlock(app); return; } /* Check that this widget doesn't already have a current XIC. */ if (get_current_xic(xim_info, w) != NULL) { _XmAppUnlock(app); return; } /* See if this widget will be sharing an existing XIC. */ XtVaGetValues(p, XmNinputPolicy, &input_policy, NULL); switch (input_policy) { case XmPER_SHELL: if (im_info->shell_xic == NULL) (void) create_xic_info(p, xim_info, im_info, input_policy); set_current_xic(im_info->shell_xic, xim_info, w); break; case XmPER_WIDGET: set_current_xic(create_xic_info(p, xim_info, im_info, input_policy), xim_info, w); break; case XmINHERIT_POLICY: break; default: assert(False); } _XmAppUnlock(app); } void XmImUnregister(Widget w) { register XmImDisplayInfo xim_info; register XmImShellInfo im_info; register XmImXICInfo xic_info; XtAppContext app; /* Punt if insufficient information was provided. */ if (w == NULL) return; app = XtWidgetToApplicationContext(w); _XmAppLock(app); /* Locate this record. */ xim_info = get_xim_info(w); if ((xic_info = get_current_xic(xim_info, w)) == NULL) { _XmAppUnlock(app); return; } if ((im_info = get_im_info(w, False)) == NULL) { _XmAppUnlock(app); return; } /* Unregister this record. */ unset_current_xic(xic_info, im_info, xim_info, w); if (im_info->iclist == NULL) { Widget vw = XtParent(w); while (!XtIsShell(vw)) vw = XtParent(vw); ImGeoReq(vw); } _XmAppUnlock(app); } void XmImSetFocusValues(Widget w, ArgList args, Cardinal num_args) { register XmImXICInfo xic_info; Widget p; Pixel fg, bg; XmFontList fl=NULL; XFontSet fs=NULL; XmVendorShellExtObject ve; XmWidgetExtData extData; XmImShellInfo im_info; XVaNestedList list; Window wind; XmInputPolicy input_policy; _XmWidgetToAppContext(w); _XmAppLock(app); p = w; while (!XtIsShell(p)) p = XtParent(p); if ((xic_info = get_current_xic(get_xim_info(p), w)) == NULL) { _XmAppUnlock(app); return; } wind = xic_info->focus_window; xic_info->focus_window = XtWindow(w); set_values(w, args, num_args, XmINHERIT_POLICY); if (wind != XtWindow(w)) { /* Safe, since we have a window - so it's no gadget */ XtVaGetValues(w, XmNbackground, &bg, NULL); XtVaGetValues(w, XmNforeground, &fg, NULL); XtVaGetValues(w, XmNfontList, &fl, NULL); if (fl) fs = extract_fontset(fl); if (fs) list = XVaCreateNestedList(0, XNBackground, bg, XNForeground, fg, XNFontSet, fs, NULL); else list = XVaCreateNestedList(0, XNBackground, bg, XNForeground, fg, NULL); XSetICValues(xic_info->xic, XNFocusWindow, XtWindow(w), XNStatusAttributes, list, XNPreeditAttributes, list, NULL); XFree(list); if (xic_info->input_style & XIMPreeditCallbacks) { XtVaGetValues(p, XmNinputPolicy, &input_policy, NULL); if (input_policy == XmPER_SHELL && wind) move_preedit_string(xic_info, XtWindowToWidget(XtDisplay(w), wind), w); } } XSetICFocus(xic_info->xic); xic_info->has_focus = True; extData = _XmGetWidgetExtData((Widget)p, XmSHELL_EXTENSION); ve = (XmVendorShellExtObject) extData->widget; if (ve->vendor.im_height) { im_info = (XmImShellInfo)ve->vendor.im_info; im_info->current_widget = w; XtVaGetValues(w, XmNbackground, &bg, NULL); XtVaSetValues(p, XmNbackground, bg, NULL); draw_separator(p); } _XmAppUnlock(app); } void XmImSetValues(Widget w, ArgList args, Cardinal num_args ) { _XmWidgetToAppContext(w); _XmAppLock(app); set_values(w, args, num_args, XmINHERIT_POLICY); _XmAppUnlock(app); } void XmImUnsetFocus(Widget w) { register XmImXICInfo xic_info; _XmWidgetToAppContext(w); _XmAppLock(app); if ((xic_info = get_current_xic(get_xim_info(w), w)) == NULL) { _XmAppUnlock(app); return; } if (xic_info->xic) XUnsetICFocus(xic_info->xic); xic_info->has_focus = False; _XmAppUnlock(app); } XIM XmImGetXIM(Widget w) { XmImDisplayInfo xim_info; _XmWidgetToAppContext(w); _XmAppLock(app); xim_info = get_xim_info(w); if (xim_info != NULL) { _XmAppUnlock(app); return xim_info->xim; } else { _XmAppUnlock(app); return NULL; } } void XmImCloseXIM(Widget w) { XmDisplay xmDisplay; XmImDisplayInfo xim_info; Widget shell; XmVendorShellExtObject ve; XmWidgetExtData extData; int height, base_height; Arg args[1]; XtWidgetGeometry my_request; _XmWidgetToAppContext(w); _XmAppLock(app); /* Allow (xim_info->xim == NULL) so we can reset the "failed" flag. */ if ((xim_info = get_xim_info(w)) == NULL) { _XmAppUnlock(app); return; } /* Remove all references to all XICs */ while (xim_info->shell_refs.refs != NULL) { shell = xim_info->shell_refs.refs[0]; _XmImFreeShellData(shell, get_im_info_ptr(shell, False)); assert((xim_info->shell_refs.refs == NULL) || (xim_info->shell_refs.refs[0] != shell)); } shell = w; while (!XtIsShell(shell)) shell = XtParent(shell); extData = _XmGetWidgetExtData((Widget)shell, XmSHELL_EXTENSION); if (extData) { ve = (XmVendorShellExtObject) extData->widget; height = ve->vendor.im_height; if (height != 0){ XtSetArg(args[0], XtNbaseHeight, &base_height); XtGetValues(shell, args, 1); if (base_height > 0){ base_height -= height; XtSetArg(args[0], XtNbaseHeight, base_height); XtSetValues(shell, args, 1); } if(!(XtIsRealized(shell))) shell->core.height -= height; else { my_request.height = shell->core.height - height; my_request.request_mode = CWHeight; XtMakeGeometryRequest(shell, &my_request, NULL); } ve->vendor.im_height = 0; } } /* Close the XIM. */ if (xim_info->xim != NULL) { XCloseIM(xim_info->xim); xim_info->xim = NULL; } XFree(xim_info->styles); xim_info->styles = NULL; xmDisplay = (XmDisplay) XmGetXmDisplay(XtDisplay(w)); xmDisplay->display.xmim_info = NULL; XtFree((char *) xim_info); _XmAppUnlock(app); } int XmImMbLookupString(Widget w, XKeyPressedEvent *event, char *buf, int nbytes, KeySym *keysym, int *status ) { register XmImXICInfo icp; int ret_val; _XmWidgetToAppContext(w); _XmAppLock(app); if ((icp = get_current_xic(get_xim_info(w), w)) == NULL || icp->xic == NULL) { if (status) *status = XLookupBoth; ret_val = XLookupString(event, buf, nbytes, keysym, 0); _XmAppUnlock(app); return ret_val; } ret_val = XmbLookupString( icp->xic, event, buf, nbytes, keysym, status ); _XmAppUnlock(app); return ret_val; } XIC XmImGetXIC(Widget w, #if NeedWidePrototypes unsigned int input_policy, #else XmInputPolicy input_policy, #endif /*NeedWidePrototypes*/ ArgList args, Cardinal num_args) { XmImDisplayInfo xim_info; XmImShellInfo im_info; XmImXICInfo xic_info; Widget shell; _XmWidgetToAppContext(w); _XmAppLock(app); xim_info = get_xim_info(w); im_info = get_im_info(w, True); xic_info = get_current_xic(xim_info, w); if ((xim_info == NULL) || (xim_info->xim == NULL)) { _XmAppUnlock(app); return NULL; } /* Find the enclosing shell. */ shell = w; while (!XtIsShell(shell)) shell = XtParent(shell); /* Resolve the true input policy. */ if (input_policy == XmINHERIT_POLICY) XtVaGetValues(shell, XmNinputPolicy, &input_policy, NULL); /* If there is already a current XIC, we may want to unregister it. */ switch (input_policy) { case XmPER_SHELL: if ((xic_info != NULL) && (im_info->shell_xic != xic_info)) { unset_current_xic(xic_info, im_info, xim_info, w); xic_info = NULL; } break; case XmPER_WIDGET: if (xic_info != NULL) { unset_current_xic(xic_info, im_info, xim_info, w); xic_info = NULL; } break; default: assert(False); } /* Register an XIC with the desired input policy. */ if (xic_info == NULL) { xic_info = create_xic_info(shell, xim_info, im_info, input_policy); set_current_xic(xic_info, xim_info, w); } /* Set the values, which creates an XIC. */ set_values(w, args, num_args, input_policy); /* Return the current XIC. */ if (xic_info != NULL) { _XmAppUnlock(app); return xic_info->xic; } _XmAppUnlock(app); return NULL; } XIC XmImSetXIC(Widget widget, XIC xic) { XmImDisplayInfo xim_info; XmImShellInfo im_info; XmImXICInfo xic_info; Widget shell; _XmWidgetToAppContext(widget); _XmAppLock(app); xim_info = get_xim_info(widget); im_info = get_im_info(widget, True); xic_info = get_current_xic(xim_info, widget); if ((xim_info == NULL) || (xim_info->xim == NULL)) { _XmAppUnlock(app); return NULL; } /* This may be a simple query. */ if (xic == NULL) { /* No XIC is registered for this widget. */ if (xic_info == NULL) { _XmAppUnlock(app); return NULL; } /* Force creation of the XIC. */ if (xic_info->xic == NULL) set_values(widget, NULL, 0, XmINHERIT_POLICY); _XmAppUnlock(app); return xic_info->xic; } /* We don't support multiple IMs. */ if (XIMOfIC(xic) != xim_info->xim) { _XmAppUnlock(app); return NULL; } /* Unregister the current XIC. */ if (xic_info != NULL) { /* Setting the current XIC to itself is a no-op. */ if (xic_info->xic == xic) { _XmAppUnlock(app); return xic; } unset_current_xic(xic_info, im_info, xim_info, widget); xic_info = NULL; } /* Find the enclosing shell. */ shell = widget; while (!XtIsShell(shell)) shell = XtParent(shell); /* Get or create xic_info for this xic. */ xic_info = recreate_xic_info(xic, shell, xim_info, im_info); /* Make this the current XIC for this widget. */ set_current_xic(xic_info, xim_info, widget); _XmAppUnlock(app); return xic; } void XmImFreeXIC(Widget w, XIC context) { register int index; register XmImDisplayInfo xim_info; register XmImShellInfo im_info; register XmImXICInfo xic_info; XtAppContext app; /* Punt if insufficient information was provided. */ if (w == NULL) return; app = XtWidgetToApplicationContext(w); _XmAppLock(app); /* Locate this record. */ xim_info = get_xim_info(w); if ((xic_info = get_current_xic(xim_info, w)) == NULL) { _XmAppUnlock(app); return; } if ((im_info = get_im_info(w, False)) == NULL) { _XmAppUnlock(app); return; } if ((context != NULL) && (xic_info->xic != context)) { _XmAppUnlock(app); return; } /* Remove all references. */ index = xic_info->widget_refs.num_refs; while (--index >= 0) unset_current_xic(xic_info, im_info, xim_info, xic_info->widget_refs.refs[index]); _XmAppUnlock(app); } /********************* * Private Functions * *********************/ /* Free a VendorShellExt's im_info field. */ void _XmImFreeShellData(Widget widget, XtPointer* data) { XmImShellInfo im_info; XmImDisplayInfo xim_info; XmImXICInfo xic_info; Widget reference; if ((data == NULL) || (im_info = (XmImShellInfo) *data) == NULL) return; /* Ignore (xim_info->xim == NULL), since it is immaterial here. */ xim_info = get_xim_info(widget); if (xim_info == NULL) return; /* Remove any dangling references. */ while (im_info->iclist != NULL) { xic_info = im_info->iclist; reference = xic_info->widget_refs.refs[0]; unset_current_xic(xic_info, im_info, xim_info, reference); assert((xic_info != im_info->iclist) || (reference != xic_info->widget_refs.refs[0])); } assert(im_info->shell_xic == NULL); /* Delete the dummy widget. */ if (im_info->im_widget != NULL) { XtDestroyWidget(im_info->im_widget); im_info->im_widget = NULL; } /* Remove this shell as a reference to the XIM. */ (void) remove_ref(&xim_info->shell_refs, widget); /* Delete the data. */ XtFree((char *) im_info); *data = NULL; } void _XmImChangeManaged( Widget vw ) { XmVendorShellExtObject ve; XmWidgetExtData extData; register int height, old_height; extData = _XmGetWidgetExtData((Widget)vw, XmSHELL_EXTENSION); ve = (XmVendorShellExtObject) extData->widget; old_height = ve->vendor.im_height; height = ImGetGeo(vw, NULL); if (!ve->vendor.im_vs_height_set) { Arg args[1]; int base_height; XtSetArg(args[0], XtNbaseHeight, &base_height); XtGetValues(vw, args, 1); if (base_height > 0) { base_height += (height - old_height); XtSetArg(args[0], XtNbaseHeight, base_height); XtSetValues(vw, args, 1); } vw->core.height += (height - old_height); } } void _XmImRealize( Widget vw ) { XmImXICInfo icp; Pixel bg; XmVendorShellExtObject ve; XmWidgetExtData extData; XmImShellInfo im_info; XmImDisplayInfo xim_info; extData = _XmGetWidgetExtData((Widget)vw, XmSHELL_EXTENSION); ve = (XmVendorShellExtObject) extData->widget; xim_info = get_xim_info(vw); im_info = get_im_info(vw, False); if ((xim_info == NULL) || (im_info == NULL) || (im_info->iclist == NULL)) return; /* We need to synchronize here to make sure the server has created * the client window before the input server attempts to reparent * any windows to it */ XSync(XtDisplay(vw), False); for (icp = im_info->iclist; icp != NULL; icp = icp->next) { if (!icp->xic) continue; XSetICValues(icp->xic, XNClientWindow, XtWindow(vw), NULL); } if (ve->vendor.im_height == 0) { ShellWidget shell = (ShellWidget)(vw); Boolean resize = shell->shell.allow_shell_resize; if (!resize) shell->shell.allow_shell_resize = True; ImGeoReq(vw); if (!resize) shell->shell.allow_shell_resize = False; } else ImSetGeo(vw, NULL); /* For some reason we need to wait till now before we set the * initial background pixmap. */ if (ve->vendor.im_height && im_info->current_widget) { XtVaGetValues(im_info->current_widget, XmNbackground, &bg, NULL); XtVaSetValues(vw, XmNbackground, bg, NULL); } } void _XmImResize( Widget vw ) { ImGetGeo(vw, NULL); ImSetGeo(vw, NULL); } void _XmImRedisplay( Widget vw ) { XmVendorShellExtObject ve; XmWidgetExtData extData; if ((extData = _XmGetWidgetExtData((Widget)vw, XmSHELL_EXTENSION)) == NULL) return; ve = (XmVendorShellExtObject) extData->widget; if (ve->vendor.im_height == 0) return; draw_separator(vw); } /******************** * Static functions * ********************/ /* Locate an XmImXICInfo struct for an existing XIC. */ static XmImXICInfo recreate_xic_info(XIC xic, Widget shell, XmImDisplayInfo xim_info, XmImShellInfo im_info) { Cardinal index; XmImXICInfo xic_info; assert(xic != NULL); /* Search for an existing record in this shell's im_info. */ for (xic_info = im_info->iclist; xic_info != NULL; xic_info = xic_info->next) { if (xic_info->xic == xic) return xic_info; } /* Search for an existing record in another shell's im_info? */ for (index = 0; index < xim_info->shell_refs.num_refs; index++) if (shell != xim_info->shell_refs.refs[index]) { XmImShellInfo tmp_info = get_im_info(xim_info->shell_refs.refs[index], False); assert(tmp_info != NULL); for (xic_info = tmp_info->iclist; xic_info != NULL; xic_info = xic_info->next) { if (xic_info->xic == xic) return xic_info; } } /* This XIC must have been created by the application directly. */ xic_info = XtNew(XmImXICRec); bzero((char*) xic_info, sizeof(XmImXICRec)); (void) XGetICValues(xic, XNInputStyle, &xic_info->input_style, NULL); xic_info->next = im_info->iclist; im_info->iclist = xic_info; if (XtIsRealized (shell)) { /* If client_window hasn't been set already, set it now. */ (void) XSetICValues(xic, XNClientWindow, XtWindow(shell), NULL); /* Update cached geometry fields */ ImGetGeo(shell, xic_info); ImSetGeo(shell, xic_info); } return xic_info; } /* Attempt to create an XmImXICInfo struct. Return it or NULL. */ static XmImXICInfo create_xic_info(Widget shell, XmImDisplayInfo xim_info, XmImShellInfo im_info, #if NeedWidePrototypes unsigned int input_policy) #else XmInputPolicy input_policy) #endif /*NeedWidePrototypes*/ { XIMStyle style = 0; char tmp[BUFSIZ]; char *cp = NULL; char *tp = NULL; char *cpend = NULL; register XIMStyles *styles; XmImXICInfo xic_info; /* Determine the input style to be used for this XIC. */ styles = xim_info->styles; XtVaGetValues(shell, XmNpreeditType, &cp, NULL); if (cp != NULL) { /* Parse for the successive commas */ cp = strcpy(tmp,cp); cpend = &tmp[strlen(tmp)]; assert(strlen(tmp) < BUFSIZ); while((style == 0) && (cp < cpend)) { tp = strchr(cp,','); if (tp) *tp = 0; else tp = cpend; /* Look for an acceptable supported style. */ if (XmeNamesAreEqual(cp, OVERTHESPOT)) style = check_style(styles, XIMPreeditPosition, XIMStatusArea|XIMStatusNothing|XIMStatusNone); else if (XmeNamesAreEqual(cp, OFFTHESPOT)) style = check_style(styles, XIMPreeditArea, XIMStatusArea|XIMStatusNothing|XIMStatusNone); else if (XmeNamesAreEqual(cp, ROOT)) style = check_style(styles, XIMPreeditNothing, XIMStatusNothing|XIMStatusNone); else if (XmeNamesAreEqual(cp, ONTHESPOT)) style = check_style(styles, XIMPreeditCallbacks, XIMStatusArea|XIMStatusNothing|XIMStatusNone); cp = tp+1; } } if (style == 0) { /* Try for a fallback style, or give up and use XLookupString. */ if ((style = check_style(styles, XIMPreeditNone, XIMStatusNone)) == 0) return NULL; } /* We need to create this widget whenever there is a non-simple * input method in order to stop the intrinsics from calling * XMapSubwindows, thereby improperly mapping input method * windows which have been made children of the client or * focus windows. */ if ((im_info->im_widget == NULL) && (style & (XIMStatusArea | XIMPreeditArea | XIMPreeditPosition))) im_info->im_widget = XtVaCreateWidget("xmim_wrapper", coreWidgetClass, shell, XmNwidth, 10, XmNheight, 10, NULL); /* Create the XIC info record. */ xic_info = XtNew(XmImXICRec); bzero((char*) xic_info, sizeof(XmImXICRec)); xic_info->input_style = style; xic_info->anonymous = True; xic_info->preedit_buffer = XtNew(PreeditBufferRec); bzero((char *) xic_info->preedit_buffer, sizeof(PreeditBufferRec)); xic_info->next = im_info->iclist; im_info->iclist = xic_info; /* Setup sharing for this XIC. */ switch (input_policy) { case XmPER_SHELL: assert (im_info->shell_xic == NULL); im_info->shell_xic = xic_info; im_info->shell_xic->source = &im_info->shell_xic; break; case XmPER_WIDGET: break; case XmINHERIT_POLICY: break; default: assert(False); } return xic_info; } #define IsCallback(name) \ if (name == XrmStringToName(XmNpreeditStartCallback) || \ name == XrmStringToName(XmNpreeditDoneCallback) || \ name == XrmStringToName(XmNpreeditDrawCallback) || \ name == XrmStringToName(XmNpreeditCaretCallback)) static void set_values(Widget w, ArgList args, Cardinal num_args, #if NeedWidePrototypes unsigned int input_policy ) #else XmInputPolicy input_policy ) #endif /*NeedWidePrototypes*/ { register XmImXICInfo icp; XmImDisplayInfo xim_info; XmImResListRec *rlp; register int i, j; register ArgList argp = args; VaArgListRec status_vlist, preedit_vlist, xic_vlist; XVaNestedList va_slist, va_plist, va_vlist; XrmName name, area_name = XrmStringToName(XmNarea); Widget p; XmImShellInfo im_info; int flags = 0; Pixel bg; char *ret; unsigned long mask; Boolean unrecognized = False; p = w; while (!XtIsShell(p)) p = XtParent(p); xim_info = get_xim_info(p); if ((icp = get_current_xic(xim_info, w)) == NULL) return; im_info = get_im_info(p, False); assert(im_info != NULL); if (!XtIsRealized(p)) { /* If vendor widget not realized, then the current info * is that for the last widget to set values. */ im_info->current_widget = w; } if (icp->xic && icp->focus_window && icp->focus_window != XtWindow(w)) return; bzero((char*) &status_vlist, sizeof(VaArgListRec)); bzero((char*) &preedit_vlist, sizeof(VaArgListRec)); bzero((char*) &xic_vlist, sizeof(VaArgListRec)); for (i = num_args; i > 0; i--, argp++) { name = XrmStringToName(argp->name); if (name == area_name && !(icp->input_style & XIMPreeditPosition)) continue; IsCallback(name){ if (icp->input_style & XIMPreeditCallbacks){ set_callback_values(w, argp->name, (XIMCallback *)(argp->value), &preedit_vlist, input_policy); continue; } else continue; } _XmProcessLock(); for (rlp = XmImResList, j = XtNumber(XmImResList); j != 0; j--, rlp++) { if (rlp->xrmname == name) { flags |= (*rlp->proc)(rlp->xstring, (XPointer) argp->value, &status_vlist, &preedit_vlist, &xic_vlist); break; } } _XmProcessUnlock(); if (j == 0) { /* Simply pass unrecognized values along */ VaSetArg(&xic_vlist, argp->name, (XPointer) argp->value); unrecognized = True; } } /* We do not create the IC until the initial data is ready to be passed */ assert(xim_info != NULL); if (icp->xic == NULL) { if (XtIsRealized(p)) { XSync(XtDisplay(p), False); VaSetArg(&xic_vlist, XNClientWindow, (XPointer) XtWindow(p)); } if (icp->focus_window) { VaSetArg(&xic_vlist, XNFocusWindow, (XPointer) icp->focus_window); } VaSetArg(&xic_vlist, XNInputStyle, (XPointer) icp->input_style); va_plist = VaCopy(&preedit_vlist); if (va_plist) VaSetArg(&xic_vlist, XNPreeditAttributes, (XPointer)va_plist); va_slist = VaCopy(&status_vlist); if (va_slist) VaSetArg(&xic_vlist, XNStatusAttributes, (XPointer)va_slist); va_vlist = VaCopy(&xic_vlist); if (va_vlist) icp->xic = XCreateIC(xim_info->xim, XNVaNestedList, va_vlist, NULL); else icp->xic = XCreateIC(xim_info->xim, NULL); if (va_vlist) XFree(va_vlist); if (va_plist) XFree(va_plist); if (va_slist) XFree(va_slist); if (preedit_vlist.args) XtFree((char *)preedit_vlist.args); if (status_vlist.args) XtFree((char *)status_vlist.args); if (xic_vlist.args) XtFree((char *)xic_vlist.args); if (icp->xic == NULL) { unset_current_xic(icp, im_info, xim_info, w); return; } XGetICValues(icp->xic, XNFilterEvents, &mask, NULL); if (mask) { XtAddEventHandler(p, (EventMask)mask, False, null_proc, NULL); } if (XtIsRealized(p)) { if (XmIsDialogShell(p)) { int i; for (i = 0; i < ((CompositeWidget)p)->composite.num_children; i++) if (XtIsManaged(((CompositeWidget)p)->composite.children[i])) { ImGeoReq(p); break; } } else ImGeoReq(p); im_info->current_widget = w; } /* Is this new XIC supposed to be shared? */ switch (input_policy) { case XmPER_SHELL: assert(im_info->shell_xic == NULL); im_info->shell_xic = icp; break; case XmPER_WIDGET: break; default: assert(False); } } else { /* Try to modify the existing XIC. */ va_plist = VaCopy(&preedit_vlist); if (va_plist) VaSetArg(&xic_vlist, XNPreeditAttributes, (XPointer)va_plist); va_slist = VaCopy(&status_vlist); if (va_slist) VaSetArg(&xic_vlist, XNStatusAttributes, (XPointer)va_slist); va_vlist = VaCopy(&xic_vlist); if (va_vlist) ret = XSetICValues(icp->xic, XNVaNestedList, va_vlist, NULL); else ret = NULL; if (va_vlist) XFree(va_vlist); if (va_plist) XFree(va_plist); if (va_slist) XFree(va_slist); if (preedit_vlist.args) XtFree((char *)preedit_vlist.args); if (status_vlist.args) XtFree((char *)status_vlist.args); if (xic_vlist.args) XtFree((char *)xic_vlist.args); /* ??? Both a write-once and an unrecognized arg might be present. */ if ((ret != NULL) && unrecognized) { unsigned long status_bg, status_fg; unsigned long preedit_bg, preedit_fg; /* ??? This code assumes that the XIM hasn't changed. */ assert(XIMOfIC(icp->xic) == xim_info->xim); /* We do this in case an input method does not support * change of some value, but does allow it to be set on * create. If however the value is not one of the * standard values, this im may not support it so we * should ignore it. */ va_slist = XVaCreateNestedList(0, XNBackground, &status_bg, XNForeground, &status_fg, NULL); va_plist = XVaCreateNestedList(0, XNBackground, &preedit_bg, XNForeground, &preedit_fg, NULL); XGetICValues(icp->xic, XNStatusAttributes, va_slist, XNPreeditAttributes, va_plist, NULL); XFree(va_slist); XFree(va_plist); if (icp->anonymous) XDestroyIC(icp->xic); icp->anonymous = TRUE; icp->xic = NULL; VaSetArg(&status_vlist, XNBackground, (XPointer) status_bg); VaSetArg(&status_vlist, XNForeground, (XPointer) status_fg); VaSetArg(&preedit_vlist, XNBackground, (XPointer) preedit_bg); VaSetArg(&preedit_vlist, XNForeground, (XPointer) preedit_fg); if (XtIsRealized(p)) { XSync(XtDisplay(p), False); VaSetArg(&xic_vlist, XNClientWindow, (XPointer) XtWindow(p)); } if (icp->focus_window) { VaSetArg(&xic_vlist, XNFocusWindow, (XPointer)icp->focus_window); } VaSetArg(&xic_vlist, XNInputStyle, (XPointer) icp->input_style); va_plist = VaCopy(&preedit_vlist); if (va_plist) VaSetArg(&xic_vlist, XNPreeditAttributes, (XPointer)va_plist); va_slist = VaCopy(&status_vlist); if (va_slist) VaSetArg(&xic_vlist, XNStatusAttributes, (XPointer)va_slist); va_vlist = VaCopy(&xic_vlist); if (va_vlist) icp->xic = XCreateIC(xim_info->xim, XNVaNestedList, va_vlist, NULL); else icp->xic = XCreateIC(xim_info->xim, NULL); if (va_vlist) XFree(va_vlist); if (va_plist) XFree(va_plist); if (va_slist) XFree(va_slist); if (preedit_vlist.args) XtFree((char *)preedit_vlist.args); if (status_vlist.args) XtFree((char *)status_vlist.args); if (xic_vlist.args) XtFree((char *)xic_vlist.args); if (icp->xic == NULL) { unset_current_xic(icp, im_info, xim_info, w); return; } ImGeoReq(p); if (icp->has_focus) XSetICFocus(icp->xic); return; } if (flags & GEO_CHG) { ImGeoReq(p); if (icp->has_focus) XSetICFocus(icp->xic); } } /* Since we do not know whether a set values may have been done * on top shadow or bottom shadow (used for the separator), we * will redraw the separator in order to keep the visuals in sync * with the current text widget. Also repaint background if needed. */ if ((im_info->current_widget == w) && (flags & BG_CHG)) { XtVaGetValues(w, XmNbackground, &bg, NULL); XtVaSetValues(p, XmNbackground, bg, NULL); } } static void ImFreePreeditBuffer(PreeditBuffer pb) { if (pb->text) XtFree((char *)pb->text); if (pb->feedback) XtFree((char *)pb->feedback); XtFree((char *)pb); } static int ImPreeditStartCallback(XIC xic, XPointer client_data, XPointer call_data) { XIMProc proc; Widget real = NULL; if (!client_data){ assert(False); } proc = get_real_callback((Widget)client_data, PREEDIT_START, &real); if (proc) (*proc)(xic, (XPointer)real, call_data); return (-1); } static void ImPreeditDoneCallback(XIC xic, XPointer client_data, XPointer call_data) { XIMProc proc; Widget w = (Widget)client_data; XmImShellInfo im_info; XmImXICInfo icp; Widget real = NULL; if (!client_data){ assert(False); } if ((im_info = get_im_info(w, False)) == NULL) return; if ((icp = im_info->shell_xic) == NULL) return; proc = get_real_callback((Widget)client_data, PREEDIT_DONE, &real); if (proc) (*proc)(xic, (XPointer)real, call_data); if (icp->preedit_buffer->text) XtFree((char *)icp->preedit_buffer->text); if (icp->preedit_buffer->feedback) XtFree((char *)icp->preedit_buffer->feedback); bzero((char *)icp->preedit_buffer, sizeof(PreeditBufferRec)); } static void ImPreeditDrawCallback(XIC xic, XPointer client_data, XPointer call_data) { XIMProc proc; Widget w = (Widget)client_data; XmImShellInfo im_info; XmImXICInfo icp; PreeditBuffer pb; XIMText *text; XIMPreeditDrawCallbackStruct *data = (XIMPreeditDrawCallbackStruct *) call_data; int from=0, to=0, ml=0; wchar_t *wchar; Widget real = NULL; if (!client_data){ assert(False); } /* update the preedit buffer */ if ((im_info = get_im_info(w, False)) == NULL) return; if ((icp = im_info->shell_xic) == NULL) return; pb = icp->preedit_buffer; pb->caret = data->caret; text = data->text; if ((int)data->chg_length > (int)pb->length) data->chg_length = pb->length; if (data->text) { /* text field is non-NULL */ if (data->chg_length > 0) { /* replace */ if ((int)text->length > (int)data->chg_length) { pb->text = (wchar_t *) XtRealloc((char *)pb->text, (pb->length - data->chg_length + text->length + 1) * sizeof(wchar_t)); pb->feedback = (XIMFeedback *) XtRealloc((char *)pb->feedback, (pb->length - data->chg_length + text->length + 1) *sizeof(XIMFeedback)); } from = data->chg_first + data->chg_length; to = data->chg_first + text->length; ml = pb->length - from; } else if (data->chg_length == 0) { /* insert */ /* do we really need to change anything? */ if (data->text->length) { pb->text = (wchar_t *) XtRealloc((char *)pb->text, (pb->length + text->length +1) * sizeof(wchar_t)); pb->feedback = (XIMFeedback *) XtRealloc((char *)pb->feedback, (pb->length + text->length +1) * sizeof(XIMFeedback)); from = data->chg_first; to = data->chg_first + text->length; ml = pb->length - from; } } /* ** if preedit buffer changed, then we munge it, ** otherwise we just leave it alone */ if (from || to || ml) { /* convert multibyte to wide char */ wchar = (wchar_t *)XtMalloc ((text->length +1) * sizeof(wchar_t)); if (text->encoding_is_wchar) memcpy(wchar, text->string.wide_char, text->length * sizeof(wchar_t)); else mbstowcs(wchar, text->string.multi_byte, text->length + 1); /* make change */ memmove((char *)pb->text + to * sizeof(wchar_t), (char *)pb->text + from * sizeof(wchar_t), ml * sizeof(wchar_t)); memmove((char *)pb->feedback + to * sizeof(XIMFeedback), (char *)pb->feedback + from * sizeof(XIMFeedback), ml * sizeof(XIMFeedback)); memmove((char *)pb->text + data->chg_first * sizeof(wchar_t), (char *)wchar, text->length * sizeof(wchar_t)); /* feedback may be NULL, check for it */ if (text->feedback) memmove((char *)pb->feedback + data->chg_first * sizeof(XIMFeedback), (char *)text->feedback, text->length * sizeof(XIMFeedback)); pb->length = pb->length + text->length - data->chg_length; bzero((char *)pb->text + pb->length * sizeof(wchar_t), sizeof(wchar_t)); bzero((char *)pb->feedback + pb->length * sizeof(XIMFeedback), sizeof(XIMFeedback)); XtFree((char *) wchar); } } else { /* text field is NULL, delete */ from = data->chg_first + data->chg_length; to = data->chg_first; ml = pb->length - from; memmove((char *)pb->text + to * sizeof(wchar_t), (char *)pb->text + from * sizeof(wchar_t), ml * sizeof(wchar_t)); memmove((char *)pb->feedback + to * sizeof(XIMFeedback), (char *)pb->feedback + from * sizeof(XIMFeedback), ml * sizeof(XIMFeedback)); pb->length = pb->length - data->chg_length; bzero((char *)pb->text + pb->length * sizeof(wchar_t), data->chg_length * sizeof(wchar_t)); bzero((char *)pb->feedback + pb->length * sizeof(XIMFeedback), data->chg_length * sizeof(XIMFeedback)); } proc = get_real_callback((Widget)client_data, PREEDIT_DRAW, &real); if (proc) (*proc)(xic, (XPointer)real, call_data); } static void ImPreeditCaretCallback(XIC xic, XPointer client_data, XPointer call_data) { XIMProc proc; Widget w = (Widget)client_data; XmImShellInfo im_info; XmImXICInfo icp; PreeditBuffer pb; XIMPreeditCaretCallbackStruct *data = (XIMPreeditCaretCallbackStruct *) call_data; Widget real = NULL; if (!client_data){ assert(False); } /* update the preedit buffer */ if ((im_info = get_im_info(w, False)) == NULL) return; if ((icp = im_info->shell_xic) == NULL) return; pb = icp->preedit_buffer; pb->style = data->style; switch (data->direction) { case XIMForwardChar: pb->caret = pb->caret + 1; break; case XIMBackwardChar: pb->caret = pb->caret - 1; break; case XIMAbsolutePosition: pb->caret = data->position; break; } proc = get_real_callback((Widget)client_data, PREEDIT_CARET, &real); if (proc) (*proc)(xic, (XPointer)real, call_data); } static XIMProc get_real_callback(Widget w, int swc, Widget *real_widget) { XmImShellInfo im_info; XmImXICInfo icp; int i, target; XmImRefRec refs; if ((im_info = get_im_info(w, False)) == NULL) return (XIMProc)NULL; if ((icp = im_info->shell_xic) == NULL) return (XIMProc)NULL; if (*real_widget == NULL) *real_widget = XtWindowToWidget(XtDisplay(w), icp->focus_window); refs = icp->widget_refs; target = refs.num_refs; for (i = 0; i < refs.num_refs; i++){ if (refs.refs[i] == *real_widget){ target = i; break; } } if (target == refs.num_refs){ assert(False); } if (refs.callbacks[target]) return (XIMProc)refs.callbacks[target][swc]; else return (XIMProc)NULL; } static void regist_real_callback(Widget w, XIMProc call, int swc) { Widget p; register XmImXICInfo icp; XmImDisplayInfo xim_info; XmImRefRec refs; int i, target; p = w; while (!XtIsShell(p)) p = XtParent(p); xim_info = get_xim_info(p); if ((icp = get_current_xic(xim_info, w)) == NULL){ return; } refs = icp->widget_refs; for (i = 0; i < refs.num_refs; i++){ if (refs.refs[i] == w){ target = i; break; } } if (!refs.callbacks[target]) refs.callbacks[target] = (XtPointer *)XtMalloc(4 * sizeof(XtPointer)); refs.callbacks[target][swc] = (XtPointer)call; } static int NameToSwitch(String name) { if (!strcmp(name, XmNpreeditStartCallback)) return PREEDIT_START; if (!strcmp(name, XmNpreeditDoneCallback)) return PREEDIT_DONE; if (!strcmp(name, XmNpreeditDrawCallback)) return PREEDIT_DRAW; if (!strcmp(name, XmNpreeditCaretCallback)) return PREEDIT_CARET; return 100; } static void set_callback_values(Widget w, String name, XIMCallback *value, VaArgList vlp, XmInputPolicy input_policy) { XIMProc call = value->callback; int s = NameToSwitch(name); XmInputPolicy ip = input_policy; Widget p; if (input_policy == XmINHERIT_POLICY){ p = w; while (!XtIsShell(p)) p = XtParent(p); XtVaGetValues(p, XmNinputPolicy, &ip, NULL); } switch (s) { case PREEDIT_START : if (ip == XmPER_SHELL){ call = value->callback; regist_real_callback(w, call, s); value->client_data = (XPointer)p; value->callback = (XIMProc) ImPreeditStartCallback; VaSetArg(vlp, XNPreeditStartCallback, (XPointer)value); } else VaSetArg(vlp, XNPreeditStartCallback, (XPointer)value); break; case PREEDIT_DONE : if (ip == XmPER_SHELL){ call = value->callback; regist_real_callback(w, call, s); value->client_data = (XPointer)p; value->callback = (XIMProc) ImPreeditDoneCallback; VaSetArg(vlp, XNPreeditDoneCallback, (XPointer)value); } else VaSetArg(vlp, XNPreeditDoneCallback, (XPointer)value); break; case PREEDIT_DRAW : if (ip == XmPER_SHELL){ call = value->callback; regist_real_callback(w, call, s); value->client_data = (XPointer)p; value->callback = (XIMProc) ImPreeditDrawCallback; VaSetArg(vlp, XNPreeditDrawCallback, (XPointer)value); } else VaSetArg(vlp, XNPreeditDrawCallback, (XPointer)value); break; case PREEDIT_CARET : if (ip == XmPER_SHELL){ call = value->callback; regist_real_callback(w, call, s); value->client_data = (XPointer)p; value->callback = (XIMProc) ImPreeditCaretCallback; VaSetArg(vlp, XNPreeditCaretCallback, (XPointer)value); } else VaSetArg(vlp, XNPreeditCaretCallback, (XPointer)value); break; default : assert(False); } } static void move_preedit_string(XmImXICInfo icp, Widget wfrom, Widget wto) { PreeditBuffer pb = icp->preedit_buffer; XIMPreeditDrawCallbackStruct draw_data; XIMText text; XIMProc proc; proc = get_real_callback(wfrom, PREEDIT_DONE, &wfrom); if (proc) (*proc)(icp->xic, (XPointer)wfrom, NULL); proc = get_real_callback(wto, PREEDIT_START, &wto); if (proc) (*proc)(icp->xic, (XPointer)wto, NULL); if (pb->length == 0) return; draw_data.caret = pb->caret; draw_data.chg_first = 0; draw_data.chg_length = 0; text.length = pb->length; text.feedback = pb->feedback; text.encoding_is_wchar = True; text.string.wide_char = pb->text; draw_data.text = &text; proc = get_real_callback(wto, PREEDIT_DRAW, &wto); if (proc) (*proc)(icp->xic, (XPointer)wto, &draw_data); } /*ARGSUSED*/ static int add_sp(String name, XPointer value, VaArgList slp, VaArgList plp, VaArgList vlp ) /* unused */ { VaSetArg(slp, name, value); VaSetArg(plp, name, value); return BG_CHG; } /*ARGSUSED*/ static int add_p(String name, XPointer value, VaArgList slp, /* unused */ VaArgList plp, VaArgList vlp ) /* unused */ { VaSetArg(plp, name, value); return 0; } /*ARGSUSED*/ static int add_fs(String name, XPointer value, VaArgList slp, VaArgList plp, VaArgList vlp ) /* unused */ { XFontSet fs; if ( (fs = extract_fontset((XmFontList)value)) == NULL) return 0; VaSetArg(slp, name, (XPointer) fs); VaSetArg(plp, name, (XPointer) fs); return GEO_CHG; } static int add_bgpxmp(String name, XPointer value, VaArgList slp, VaArgList plp, VaArgList vlp ) { if ( (Pixmap)value == XtUnspecifiedPixmap ) return 0; return add_sp( name, value, slp, plp, vlp ); } static XIMStyle check_style(XIMStyles *styles, XIMStyle preedit_style, XIMStyle status_style ) { register int i; /* Is this preedit & status style combination supported? */ for (i=0; i < (int) styles->count_styles; i++) { if ((styles->supported_styles[i] & preedit_style) && (styles->supported_styles[i] & status_style)) return styles->supported_styles[i]; } return 0; } /* if this_icp is non-null, operations will only be performed on the corresponding IC. (Basically disables looping) */ static int ImGetGeo(Widget vw, XmImXICInfo this_icp ) { XmImXICInfo icp; XmVendorShellExtObject ve; XmWidgetExtData extData; int height = 0; XRectangle rect; XRectangle *rp; XmImShellInfo im_info; XVaNestedList set_list, get_list; extData = _XmGetWidgetExtData((Widget)vw, XmSHELL_EXTENSION); ve = (XmVendorShellExtObject) extData->widget; im_info = get_im_info(vw, False); if ((im_info == NULL) || (im_info->iclist == NULL)) { ve->vendor.im_height = 0; return 0; } set_list = XVaCreateNestedList(0, XNAreaNeeded, (XPointer) &rect, NULL); get_list = XVaCreateNestedList(0, XNAreaNeeded, (XPointer) &rp, NULL); for (icp = this_icp ? this_icp : im_info->iclist; icp != NULL; icp = icp->next) { if (icp->xic) { if (icp->input_style & XIMStatusArea) { rect.width = vw->core.width; rect.height = 0; XSetICValues(icp->xic, XNStatusAttributes, set_list, NULL); XGetICValues(icp->xic, XNStatusAttributes, get_list, NULL); if ((int) rp->height > height) height = rp->height; icp->status_width = MIN(rp->width, vw->core.width); icp->sp_height = rp->height; XFree(rp); } if (icp->input_style & XIMPreeditArea) { rect.width = vw->core.width; rect.height = 0; XSetICValues(icp->xic, XNPreeditAttributes, set_list, NULL); XGetICValues(icp->xic, XNPreeditAttributes, get_list, NULL); if ((int) rp->height > height) height = rp->height; icp->preedit_width = MIN((int) rp->width, (int) (vw->core.width - icp->status_width)); if (icp->sp_height < (int) rp->height) icp->sp_height = rp->height; XFree(rp); } } if (this_icp) break; } XFree(set_list); XFree(get_list); if (height) height += SEPARATOR_HEIGHT; ve->vendor.im_height = height; return height; } /* if this_icp is non-null, operations will only be performed on the corresponding IC. (Basically disables looping) */ static void ImSetGeo(Widget vw, XmImXICInfo this_icp ) { XmVendorShellExtObject ve; XmWidgetExtData extData; register XmImXICInfo icp; XRectangle rect_status; XRectangle rect_preedit; XmImShellInfo im_info; XVaNestedList va_slist, va_plist; unsigned long use_slist, use_plist; im_info = get_im_info(vw, False); if ((im_info == NULL) || (im_info->iclist == NULL)) return; extData = _XmGetWidgetExtData((Widget)vw, XmSHELL_EXTENSION); ve = (XmVendorShellExtObject) extData->widget; if (ve->vendor.im_height == 0) return; va_slist = XVaCreateNestedList(0, XNArea, &rect_status, NULL); va_plist = XVaCreateNestedList(0, XNArea, &rect_preedit, NULL); for (icp = this_icp ? this_icp : im_info->iclist; icp != NULL; icp = icp->next) { if ((use_slist = (icp->input_style & XIMStatusArea)) != 0) { rect_status.x = 0; rect_status.y = vw->core.height - icp->sp_height; rect_status.width = icp->status_width; rect_status.height = icp->sp_height; } if ((use_plist = (icp->input_style & XIMPreeditArea)) != 0) { rect_preedit.x = icp->status_width; rect_preedit.y = vw->core.height - icp->sp_height; rect_preedit.width = icp->preedit_width; rect_preedit.height = icp->sp_height; } else if ((use_plist = (icp->input_style & XIMPreeditPosition)) != 0) { unsigned int margin = ((XmPrimitiveWidget)im_info->current_widget) ->primitive.shadow_thickness + ((XmPrimitiveWidget)im_info->current_widget) ->primitive.highlight_thickness; rect_preedit.width = MIN(icp->preedit_width, XtWidth(im_info->current_widget) - 2*margin); rect_preedit.height = MIN(icp->sp_height, XtHeight(im_info->current_widget) - 2*margin); } if (use_slist && use_plist) XSetICValues(icp->xic, XNStatusAttributes, va_slist, XNPreeditAttributes, va_plist, NULL); else if (use_slist) XSetICValues(icp->xic, XNStatusAttributes, va_slist, NULL); else if (use_plist) XSetICValues(icp->xic, XNPreeditAttributes, va_plist, NULL); if (this_icp) break; } XFree(va_slist); XFree(va_plist); } static void ImGeoReq(Widget vw ) { XmVendorShellExtObject ve; XmWidgetExtData extData; XtWidgetGeometry my_request; int old_height; int delta_height; ShellWidget shell = (ShellWidget)(vw); if (!(shell->shell.allow_shell_resize) && XtIsRealized(vw)) return; extData = _XmGetWidgetExtData(vw, XmSHELL_EXTENSION); ve = (XmVendorShellExtObject) extData->widget; old_height = ve->vendor.im_height; ImGetGeo(vw, NULL); if ((delta_height = ve->vendor.im_height - old_height) != 0) { int base_height; Arg args[1]; XtSetArg(args[0], XtNbaseHeight, &base_height); XtGetValues(vw, args, 1); if (base_height > 0) { base_height += delta_height; XtSetArg(args[0], XtNbaseHeight, base_height); XtSetValues(vw, args, 1); } my_request.height = vw->core.height + delta_height; my_request.request_mode = CWHeight; XtMakeGeometryRequest(vw, &my_request, NULL); } ImSetGeo(vw, NULL); } static XFontSet extract_fontset( XmFontList fl ) { XmFontContext context; XmFontListEntry next_entry; XmFontType type_return; XtPointer tmp_font; XFontSet first_fs = NULL; char *font_tag = NULL; if (!XmFontListInitFontContext(&context, fl)) return NULL; do { next_entry = XmFontListNextEntry(context); if (next_entry) { tmp_font = XmFontListEntryGetFont(next_entry, &type_return); if (type_return == XmFONT_IS_FONTSET) { font_tag = XmFontListEntryGetTag(next_entry); if (!strcmp(font_tag, XmFONTLIST_DEFAULT_TAG)) { XmFontListFreeFontContext(context); if (font_tag) XtFree(font_tag); return (XFontSet)tmp_font; } if (font_tag) XtFree(font_tag); if (first_fs == NULL) first_fs = (XFontSet)tmp_font; } } } while (next_entry); XmFontListFreeFontContext(context); return first_fs; } /* Fetch (creating if necessary) the Display's xmim_info. */ static XmImDisplayInfo get_xim_info(Widget widget) { XmDisplay xmDisplay; char tmp[BUFSIZ]; char *cp = NULL; XmImDisplayInfo xim_info; String name, w_class; Display *dpy; Widget shell; if (widget == NULL) return NULL; /* Find the parent shell. */ shell = widget; while (!XtIsShell(shell)) shell = XtParent(shell); dpy = XtDisplay(shell); xmDisplay = (XmDisplay) XmGetXmDisplay(dpy); xim_info = (XmImDisplayInfo)xmDisplay->display.xmim_info; /* If this is a simple lookup we're done. */ if (xim_info != NULL) return xim_info; /* Create a record so that we only try XOpenIM() once. */ xim_info = XtNew(XmImDisplayRec); bzero((char*) xim_info, sizeof(XmImDisplayRec)); xmDisplay->display.xmim_info = (XtPointer)xim_info; /* Setup any specified locale modifiers. */ XtVaGetValues(shell, XmNinputMethod, &cp, NULL); if (cp != NULL) { strcpy(tmp,"@im="); strcat(tmp,cp); assert(strlen(tmp) < BUFSIZ); XSetLocaleModifiers(tmp); } XtGetApplicationNameAndClass(dpy, &name, &w_class); /* Try to open the input method. */ xim_info->xim = XOpenIM(dpy, XtDatabase(dpy), name, w_class); if (xim_info->xim == NULL) { #ifdef XOPENIM_WARNING /* Generate a warning if XOpenIM was supposed to work. */ /* Use the WMShell's XmNtitleEncoding as a shibboleth. */ Atom encoding = (Atom) 0; XtVaGetValues(shell, XmNtitleEncoding, &encoding, NULL); if (encoding != XA_STRING) XmeWarning ((Widget)widget, MSG1); #endif /* Leave the null xim_info attached to the display so we only */ /* print the warning message once. */ return xim_info; } /* Lookup the styles this input method supports. */ if (XGetIMValues(xim_info->xim, XNQueryInputStyle, &xim_info->styles, NULL) != NULL) { XCloseIM(xim_info->xim); xim_info->xim = NULL; XmeWarning ((Widget)widget, MSG1); return xim_info; } /* Initialize the list of xrm names */ { XmImResListRec *rlp; register int i; _XmProcessLock(); for (rlp = XmImResList, i = XtNumber(XmImResList); i != 0; i--, rlp++) rlp->xrmname = XrmStringToName(rlp->xmstring); _XmProcessUnlock(); } return xim_info; } static XtPointer* get_im_info_ptr(Widget w, Boolean create) { Widget p; XmVendorShellExtObject ve; XmWidgetExtData extData; XmImShellInfo im_info; XmImDisplayInfo xim_info; if (w == NULL) return NULL; p = w; while (!XtIsShell(p)) p = XtParent(p); /* Check extension data since app could be attempting to create * a text widget as child of menu shell. This is illegal, and will * be detected later, but check here so we don't core dump. */ if ((extData = _XmGetWidgetExtData((Widget)p, XmSHELL_EXTENSION)) == NULL) return NULL; ve = (XmVendorShellExtObject) extData->widget; if ((ve->vendor.im_info == NULL) && create) { im_info = XtNew(XmImShellRec); bzero((char*) im_info, sizeof(XmImShellRec)); ve->vendor.im_info = (XtPointer)im_info; xim_info = get_xim_info(p); (void) add_ref(&xim_info->shell_refs, p); } return &ve->vendor.im_info; } static XmImShellInfo get_im_info(Widget w, Boolean create) { XmImShellInfo* ptr = (XmImShellInfo *) get_im_info_ptr(w, create); if (ptr != NULL) return *ptr; else return NULL; } static void draw_separator(Widget vw ) { XmPrimitiveWidget pw; XmVendorShellExtObject ve; XmWidgetExtData extData; XmImShellInfo im_info; extData = _XmGetWidgetExtData((Widget)vw, XmSHELL_EXTENSION); ve = (XmVendorShellExtObject) extData->widget; if ((im_info = (XmImShellInfo)ve->vendor.im_info) == NULL) return; pw = (XmPrimitiveWidget)im_info->current_widget; if (!pw || !XmIsPrimitive(pw)) return; XmeDrawSeparator(XtDisplay(vw), XtWindow(vw), pw->primitive.top_shadow_GC, pw->primitive.bottom_shadow_GC, 0, 0, vw->core.height - ve->vendor.im_height, vw->core.width, SEPARATOR_HEIGHT, SEPARATOR_HEIGHT, 0, /* separator.margin */ XmHORIZONTAL, /* separator.orientation */ XmSHADOW_ETCHED_IN); /* separator.separator_type */ } /*ARGSUSED*/ static void null_proc(Widget w, /* unused */ XtPointer ptr, /* unused */ XEvent *ev, /* unused */ Boolean *b ) /* unused */ { /* This function does nothing. It is only there to allow the * event mask required by the input method to be added to * the client window. */ } /* The following section contains the varargs functions */ /*VARARGS*/ void XmImVaSetFocusValues(Widget w, ... ) { va_list var; int total_count; ArgList args; _XmWidgetToAppContext(w); _XmAppLock(app); Va_start(var,w); ImCountVaList(var, &total_count); va_end(var); Va_start(var,w); args = ImCreateArgList(var, total_count); va_end(var); XmImSetFocusValues(w, args, total_count); XtFree((char *)args); _XmAppUnlock(app); } /*VARARGS*/ void XmImVaSetValues(Widget w, ... ) { va_list var; int total_count; ArgList args; _XmWidgetToAppContext(w); _XmAppLock(app); Va_start(var,w); ImCountVaList(var, &total_count); va_end(var); Va_start(var,w); args = ImCreateArgList(var, total_count); va_end(var); XmImSetValues(w, args, total_count); XtFree((char *)args); _XmAppUnlock(app); } static void ImCountVaList(va_list var, int *total_count ) { String attr; *total_count = 0; for(attr = va_arg(var, String); attr != NULL; attr = va_arg(var, String)) { (void) va_arg(var, XPointer); ++(*total_count); } } static ArgList ImCreateArgList(va_list var, int total_count ) { ArgList args = (ArgList)XtCalloc(total_count, sizeof(Arg)); register int i; assert(args || (total_count == 0)); for (i = 0; i < total_count; i++) { args[i].name = va_arg(var,String); args[i].value = (XtArgVal)va_arg(var,XPointer); } return args; } /* Return the current xic info for a widget, or NULL. */ static XmImXICInfo get_current_xic(XmImDisplayInfo xim_info, Widget widget) { XmImXICInfo xic_info; if ((xim_info == NULL) || (xim_info->current_xics == (XContext) 0)) return NULL; if (XFindContext(XtDisplay(widget), (XID) widget, xim_info->current_xics, (XPointer*) &xic_info) != 0) return NULL; else return xic_info; } /* Set the current XIC for an unregistered widget. */ static void set_current_xic(XmImXICInfo xic_info, XmImDisplayInfo xim_info, Widget widget) { if (xic_info == NULL) return; /* Record this widget as a reference to this XIC. */ (void) add_ref(&xic_info->widget_refs, widget); /* Set the current XIC for this widget. */ if (xim_info->current_xics == (XContext) NULL) xim_info->current_xics = XUniqueContext(); (void) XSaveContext(XtDisplay(widget), (XID) widget, xim_info->current_xics, (XPointer) xic_info); } /* Unset the current XIC for a widget, freeing data as necesary. */ static void unset_current_xic(XmImXICInfo xic_info, XmImShellInfo im_info, XmImDisplayInfo xim_info, Widget widget) { /* Remove the current xic for this widget. */ assert(xim_info->current_xics != (XContext) 0); (void) XDeleteContext(XtDisplay(widget), (XID) widget, xim_info->current_xics); /* Remove this widget as a reference to this XIC. */ if (remove_ref(&xic_info->widget_refs, widget) == 0) { /* Remove this xic_info from the master list. */ XmImXICInfo *ptr; for (ptr = &(im_info->iclist); *ptr != NULL; ptr = &((*ptr)->next)) if (*ptr == xic_info) { *ptr = xic_info->next; break; } if (im_info->current_widget == widget) im_info->current_widget = NULL; /* Don't let anyone share this XIC. */ if (xic_info->source != NULL) *(xic_info->source) = NULL; /* Destroy the XIC */ if ((xic_info->anonymous) && (xic_info->xic != NULL)) XDestroyIC(xic_info->xic); ImFreePreeditBuffer (xic_info->preedit_buffer); XtFree((char *) xic_info); } } /* Add a widget to a list of references. */ static Cardinal add_ref(XmImRefInfo refs, Widget widget) { #ifdef DEBUG /* Verify that we don't already have a reference. */ register Cardinal index; for (index = 0; index < refs->num_refs; index++) assert(refs->refs[index] != widget); #endif /* Make room in the array. */ if (refs->num_refs == refs->max_refs) { if (refs->max_refs == 0) refs->max_refs = 10; else refs->max_refs += (refs->max_refs / 2); refs->refs = (Widget*) XtRealloc((char *) refs->refs, refs->max_refs * sizeof(Widget)); refs->callbacks = (XtPointer **) XtRealloc((char *) refs->callbacks, refs->max_refs * sizeof(XtPointer *)); } assert(refs->num_refs < refs->max_refs); refs->callbacks[refs->num_refs] = NULL; /* Insert this reference. */ refs->refs[refs->num_refs++] = widget; return refs->num_refs; } /* Remove a widget from a list of references. */ static Cardinal remove_ref(XmImRefInfo refs, Widget widget) { /* Is this the last reference? */ refs->num_refs--; if (refs->num_refs > 0) { /* Just remove this reference. */ int index = 0; while (index <= refs->num_refs) { if (refs->refs[index] == widget) { refs->refs[index] = refs->refs[refs->num_refs]; refs->refs[refs->num_refs] = NULL; XtFree((char *)refs->callbacks[index]); refs->callbacks[index] = refs->callbacks[refs->num_refs]; refs->callbacks[refs->num_refs] = NULL; break; } index++; } /* Free some storage from the array? */ if ((refs->num_refs * 3 < refs->max_refs) && (refs->max_refs >= 20)) { refs->max_refs /= 2; refs->refs = (Widget*) XtRealloc((char *) refs->refs, refs->max_refs * sizeof(Widget)); refs->callbacks = (XtPointer **) XtRealloc((char *) refs->callbacks, refs->max_refs * sizeof(XtPointer *)); } } else { /* Free the references array. */ XtFree((char *) refs->refs); refs->refs = NULL; XtFree((char *) refs->callbacks[0]); XtFree((char *) refs->callbacks); refs->callbacks = NULL; refs->max_refs = 0; } return refs->num_refs; } /* Convert a VaArgList into a true XVaNestedList. */ static XVaNestedList VaCopy(VaArgList list) { /* This is ugly, but it's a legal way to construct a nested */ /* list whose length is unknown at compile time. If MAXARGS is */ /* increased more parameter pairs should be added below. A */ /* recursive approach would leak memory. */ register Cardinal count = list->count; register VaArg *args = list->args; #define VA_NAME(index) (index < count ? args[index].name : NULL) #define VA_VALUE(index) (index < count ? args[index].value : NULL) assert(count <= 10); return XVaCreateNestedList(0, VA_NAME(0), VA_VALUE(0), VA_NAME(1), VA_VALUE(1), VA_NAME(2), VA_VALUE(2), VA_NAME(3), VA_VALUE(3), VA_NAME(4), VA_VALUE(4), VA_NAME(5), VA_VALUE(5), VA_NAME(6), VA_VALUE(6), VA_NAME(7), VA_VALUE(7), VA_NAME(8), VA_VALUE(8), VA_NAME(9), VA_VALUE(9), NULL); #undef VA_NAME #undef VA_VALUE } static void VaSetArg(VaArgList list, char *name, XPointer value) { if (list->max <= list->count) { list->max += 10; list->args = (VaArg*) XtRealloc((char*) list->args, list->max * sizeof(VaArg)); } list->args[list->count].name = name; list->args[list->count].value = value; list->count++; } void XmImMbResetIC( Widget w, char **mb) { register XmImXICInfo icp; _XmWidgetToAppContext(w); _XmAppLock(app); *mb = NULL; if ((icp = get_current_xic(get_xim_info(w), w)) == NULL || icp->xic == NULL) { _XmAppUnlock(app); return; } if (!(icp->input_style & XIMPreeditCallbacks)) { _XmAppUnlock(app); return; } *mb = XmbResetIC(icp->xic); _XmAppUnlock(app); }